Statistics
| Branch: | Tag: | Revision:

mininet / mininet / cli.py @ 68f97b74

History | View | Annotate | Download (7.19 KB)

1
"""
2
A simple command-line interface for Mininet.
3

4
The Mininet CLI provides a simple control console which
5
makes it easy to talk to nodes. For example, the command
6

7
mininet> h27 ifconfig
8

9
runs 'ifconfig' on host h27.
10

11
Having a single console rather than, for example, an xterm for each
12
node is particularly convenient for networks of any reasonable
13
size.
14

15
The CLI automatically substitutes IP addresses for node names,
16
so commands like
17

18
mininet> h2 ping h3
19

20
should work correctly and allow host h2 to ping host h3
21

22
Several useful commands are provided, including the ability to
23
list all nodes ('nodes'), to print out the network topology
24
('net') and to check connectivity ('pingall', 'pingpair')
25
and bandwidth ('iperf'.)
26

27
Bugs/limitations:
28

29
- Interactive commands are not supported at the moment
30

31
"""
32

    
33
from subprocess import call
34
from cmd import Cmd
35

    
36
from mininet.log import info, output, error
37
from mininet.term import makeTerms
38

    
39
        
40
class CLI( Cmd ):
41
    "Simple command-line interface to talk to nodes."
42

    
43
    prompt = 'mininet> '
44

    
45
    def __init__( self, mininet ):
46
        self.mn = mininet
47
        self.nodelist = self.mn.controllers + self.mn.switches + self.mn.hosts
48
        self.nodemap = {}  # map names to Node objects
49
        for node in self.nodelist:
50
            self.nodemap[ node.name ] = node
51
        Cmd.__init__( self )
52
        info( '*** Starting CLI:\n' )
53
        while True:
54
            try:
55
                self.cmdloop()
56
                break
57
            except KeyboardInterrupt:
58
                info( 'Interrupt\n' )
59
                for node in self.nodelist:
60
                    waitForNode( node )
61

    
62
    def emptyline( self ):
63
        "Don't repeat last command when you hit return."
64
        pass
65

    
66
    # Disable pylint "Unused argument: 'arg's'" messages, as well as
67
    # "method could be a function" warning, since each CLI function
68
    # must have the same interface
69
    # pylint: disable-msg=W0613,R0201
70

    
71
    def do_help( self, args ):
72
        "Describe available CLI commands."
73
        Cmd.do_help( self, args )
74
        helpStr = ( 'You may also send a command to a node using:\n'
75
                   '  <node> command {args}\n'
76
                   'For example:\n'
77
                   '  mininet> h0 ifconfig\n'
78
                   '\n'
79
                   'The interpreter automatically substitutes IP '
80
                   'addresses\n'
81
                   'for node names when a node is the first arg, so commands'
82
                   ' like\n'
83
                   ' mininet> h2 ping h3\n'
84
                   'should work.\n'
85
                   '\n'
86
                   'Interactive commands that require user input are '
87
                   'not (yet) supported.\n\n' )
88
        if args is "":
89
            self.stdout.write( helpStr )
90

    
91
    def do_nodes( self, args ):
92
        "List all nodes."
93
        nodes = ' '.join( [ node.name for node in sorted( self.nodelist ) ] )
94
        output( 'available nodes are: \n%s\n' % nodes )
95

    
96
    def do_net( self, args ):
97
        "List network connections."
98
        for switch in self.mn.switches:
99
            output( switch.name, '<->' )
100
            for intf in switch.intfs.values():
101
                name = switch.connection[ intf ][ 1 ]
102
                output( ' %s' % name )
103
            output( '\n' )
104

    
105
    def do_sh( self, args ):
106
        "Run an external shell command"
107
        call( args, shell=True )
108

    
109
    # do_py() needs to catch any exception during eval()
110
    # pylint: disable-msg=W0703
111

    
112
    def do_py( self, args ):
113
        """Evaluate a Python expression.
114
           Node names may be used, e.g.: h1.cmd('ls')"""
115
        try:
116
            result = eval( args, globals(), self.nodemap )
117
            if not result:
118
                return
119
            elif isinstance( result, str ):
120
                info( result + '\n' )
121
            else:
122
                info( repr( result ) + '\n' )
123
        except Exception, e:
124
            info( str( e ) + '\n' )
125

    
126
    # pylint: enable-msg=W0703
127

    
128
    def do_pingall( self, args ):
129
        "Ping between all hosts."
130
        self.mn.pingAll()
131

    
132
    def do_pingpair( self, args ):
133
        "Ping between first two hosts, useful for testing."
134
        self.mn.pingPair()
135

    
136
    def do_iperf( self, args ):
137
        "Simple iperf TCP test between two hosts."
138
        self.mn.iperf()
139

    
140
    def do_iperfudp( self, args ):
141
        "Simple iperf UDP test between two hosts."
142
        udpBw = args[ 0 ] if len( args ) else '10M'
143
        self.mn.iperfUdp( udpBw )
144

    
145
    def do_intfs( self, args ):
146
        "List interfaces."
147
        for node in self.nodelist:
148
            output( '%s: %s\n' %
149
                ( node.name, ' '.join( sorted( node.intfs.values() ) ) ) )
150

    
151
    def do_dump( self, args ):
152
        "Dump node info."
153
        for node in self.nodelist:
154
            output( '%s\n' % node )
155

    
156
    def do_link( self, args ):
157
        "Bring link(s) between two nodes up or down."
158
        args = args.split()
159
        if len(args) != 3:
160
            error( 'invalid number of args: link end1 end2 [up down]\n' )
161
        elif args[ 2 ] not in [ 'up', 'down' ]:
162
            error( 'invalid type: link end1 end2 [up down]\n' )
163
        else:
164
            self.mn.configLinkStatus( *args )
165

    
166
    def do_xterm( self, args, term='xterm' ):
167
        "Spawn xterm(s) for the given node(s)."
168
        args = args.split()
169
        if not args:
170
            info( 'usage: %s node1 node2 ...\n' % term )
171
        else:
172
            for arg in args:
173
                if arg not in self.nodemap:
174
                    error( "node '%s' not in network\n" % arg )
175
                else:
176
                    node = self.nodemap[ arg ]
177
                    self.mn.terms += makeTerms( [ node ], term = term )
178

    
179
    def do_gterm( self, args ):
180
        "Spawn gnome-terminal(s) for the given node(s)."
181
        self.do_xterm( args, term='gterm' )
182

    
183
    def do_exit( self, args ):
184
        "Exit"
185
        return 'exited by user command'
186

    
187
    def do_quit( self, args ):
188
        "Exit"
189
        return self.do_exit( args )
190

    
191
    def do_EOF( self, args ):
192
        "Exit"
193
        return self.do_exit( args )
194

    
195
    def default( self, line ):
196
        """Called on an input line when the command prefix is not recognized.
197
        Overridden to run shell commands when a node is the first CLI argument.
198
        Past the first CLI argument, node names are automatically replaced with
199
        corresponding IP addrs."""
200

    
201
        first, args, line = self.parseline( line )
202
        if len(args) > 0 and args[ -1 ] == '\n':
203
            args = args[ :-1 ]
204
        rest = args.split( ' ' )
205

    
206
        if first in self.nodemap:
207
            node = self.nodemap[ first ]
208
            # Substitute IP addresses for node names in command
209
            rest = [ self.nodemap[ arg ].IP()
210
                    if arg in self.nodemap else arg
211
                    for arg in rest ]
212
            rest = ' '.join( rest )
213
            # Run cmd on node:
214
            node.sendCmd( rest, printPid=True )
215
            waitForNode( node )
216
        else:
217
            self.stdout.write( '*** Unknown syntax: %s\n' % line )
218

    
219
    # pylint: enable-msg=W0613,R0201
220

    
221

    
222
# This function may be a candidate for util.py
223

    
224
def waitForNode( node ):
225
    "Wait for a node to finish, and  print its output."
226
    while node.waiting:
227
        try:
228
            data = node.monitor()
229
            info( '%s' % data )
230
        except KeyboardInterrupt:
231
            node.sendInt()
232