Statistics
| Branch: | Tag: | Revision:

mininet / mininet / cli.py @ b924c5b5

History | View | Annotate | Download (6.17 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> h0 ping -c1 h31
19

20
should work correctly and allow host h0 to ping host h31.
21
Note the '-c1' argument as per the Bugs/limitations section below!
22

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

28
Bugs/limitations:
29

30
- Interactive commands are not supported at the moment;
31
  notably, if you type 'ping h1', you can control-C it, but
32
  it breaks the CLI and your network. ;-(
33
  For now, we recommend limiting CLI use to non-interactive
34
  commands which terminate in a reasonable amount of time.
35

36
"""
37

    
38
from subprocess import call
39
from cmd import Cmd
40

    
41
from mininet.log import info, warn
42

    
43
class CLI( Cmd ):
44
    "Simple command-line interface to talk to nodes."
45

    
46
    prompt = 'mininet> '
47

    
48
    def __init__( self, mininet ):
49
        self.mn = mininet
50
        self.nodelist = self.mn.controllers + self.mn.switches + self.mn.hosts
51
        self.nodemap = {} # map names to Node objects
52
        for node in self.nodelist:
53
            self.nodemap[ node.name ] = node
54
        Cmd.__init__( self )
55
        warn( '*** Starting CLI:\n' )
56
        self.cmdloop()
57

    
58
    # Disable pylint "Unused argument: 'arg's'" messages.
59
    # Each CLI function needs the same interface.
60
    # pylint: disable-msg=W0613
61

    
62
    def do_help( self, args ):
63
        "Describe available CLI commands."
64
        Cmd.do_help( self, args )
65
        helpStr = ( 'You may also send a command to a node using:\n'
66
                   '  <node> command {args}\n'
67
                   'For example:\n'
68
                   '  mininet> h0 ifconfig\n'
69
                   '\n'
70
                   'The interpreter automatically substitutes IP '
71
                   'addresses\n'
72
                   'for node names when a node is the first arg, so commands'
73
                   ' like\n'
74
                   ' mininet> h0 ping -c1 h1\n'
75
                   'should work.\n'
76
                   '\n'
77
                   'Interactive commands are not really supported yet,\n'
78
                   'so please limit commands to ones that do not\n'
79
                   'require user interaction and will terminate\n'
80
                   'after a reasonable amount of time.\n' )
81
        if args is "":
82
            self.stdout.write( helpStr )
83

    
84
    def do_nodes( self, args ):
85
        "List all nodes."
86
        nodes = ' '.join( [ node.name for node in sorted( self.nodelist ) ] )
87
        info( 'available nodes are: \n%s\n' % nodes )
88

    
89
    def do_net( self, args ):
90
        "List network connections."
91
        for switch in self.mn.switches:
92
            info( switch.name, '<->' )
93
            for intf in switch.intfs.values():
94
                name = switch.connection[ intf ][ 1 ]
95
                info( ' %s' % name )
96
            info( '\n' )
97

    
98
    def do_sh( self, args ):
99
        "Run an external shell command"
100
        call( args, shell=True )
101

    
102
    # do_py() needs to catch any exception during eval()
103
    # pylint: disable-msg=W0703
104

    
105
    def do_py( self, args ):
106
        """Evaluate a Python expression.
107
           Node names may be used, e.g.: h1.cmd('ls')"""
108
        try:
109
            result = eval( args, globals(), self.nodemap )
110
            if not result:
111
                return
112
            elif isinstance( result, str ):
113
                info( result + '\n' )
114
            else:
115
                info( repr( result ) + '\n' )
116
        except Exception, e:
117
            info( str( e ) + '\n' )
118

    
119
    # pylint: enable-msg=W0703
120

    
121
    def do_pingall( self, args ):
122
        "Ping between all hosts."
123
        self.mn.pingAll()
124

    
125
    def do_pingpair( self, args ):
126
        "Ping between first two hosts, useful for testing."
127
        self.mn.pingPair()
128

    
129
    def do_iperf( self, args ):
130
        "Simple iperf TCP test between two hosts."
131
        self.mn.iperf()
132

    
133
    def do_iperfudp( self, args ):
134
        "Simple iperf UDP test between two hosts."
135
        udpBw = args[ 0 ] if len( args ) else '10M'
136
        self.mn.iperfUdp( udpBw )
137

    
138
    def do_intfs( self, args ):
139
        "List interfaces."
140
        for node in self.nodelist:
141
            info( '%s: %s\n' %
142
                ( node.name, ' '.join( sorted( node.intfs.values() ) ) ) )
143

    
144
    def do_dump( self, args ):
145
        "Dump node info."
146
        for node in self.nodelist:
147
            info( '%s\n' % node )
148

    
149
    def do_exit( self, args ):
150
        "Exit"
151
        return 'exited by user command'
152

    
153
    def do_quit( self, args ):
154
        "Exit"
155
        return self.do_exit( args )
156

    
157
    def do_EOF( self, args ):
158
        "Exit"
159
        return self.do_exit( args )
160

    
161
    def default( self, line ):
162
        """Called on an input line when the command prefix is not recognized.
163
        Overridden to run shell commands when a node is the first CLI argument.
164
        Past the first CLI argument, node names are automatically replaced with
165
        corresponding IP addrs."""
166

    
167
        first, args, line = self.parseline( line )
168
        if len(args) > 0 and args[ -1 ] == '\n':
169
            args = args[ :-1 ]
170
        rest = args.split( ' ' )
171

    
172
        if first in self.nodemap:
173
            node = self.nodemap[ first ]
174
            # Substitute IP addresses for node names in command
175
            rest = [ self.nodemap[ arg ].IP()
176
                    if arg in self.nodemap else arg
177
                    for arg in rest ]
178
            rest = ' '.join( rest )
179
            # Run cmd on node:
180
            node.sendCmd( rest )
181
            while True:
182
                try:
183
                    done, data = node.monitor()
184
                    info( '%s\n' % data )
185
                    if done:
186
                        break
187
                except KeyboardInterrupt:
188
                    node.sendInt()
189
        else:
190
            self.stdout.write( '*** Unknown syntax: %s\n' % line )
191

    
192
    # Re-enable pylint "Unused argument: 'arg's'" messages.
193
    # pylint: enable-msg=W0613