Statistics
| Branch: | Tag: | Revision:

mininet / mininet / cli.py @ e0cfcdd5

History | View | Annotate | Download (5.56 KB)

1 496b5f9e Bob Lantz
"""
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 64c451e0 Bob Lantz
('net') and to check connectivity ('pingall', 'pingpair')
26 496b5f9e Bob Lantz
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 114dcd56 Brandon Heller
from cmd import Cmd
40 496b5f9e Bob Lantz
41 64c451e0 Bob Lantz
from mininet.log import info, warn
42 496b5f9e Bob Lantz
43 114dcd56 Brandon Heller
class CLI( Cmd ):
44 496b5f9e Bob Lantz
    "Simple command-line interface to talk to nodes."
45
46 114dcd56 Brandon Heller
    prompt = 'mininet> '
47 496b5f9e Bob Lantz
48
    def __init__( self, mininet ):
49
        self.mn = mininet
50 2235f216 Bob Lantz
        self.nodelist = self.mn.hosts + self.mn.switches + self.mn.controllers
51 496b5f9e Bob Lantz
        self.nodemap = {} # map names to Node objects
52 78073e1b Bob Lantz
        for node in self.nodelist:
53 496b5f9e Bob Lantz
            self.nodemap[ node.name ] = node
54 114dcd56 Brandon Heller
        Cmd.__init__( self )
55 64c451e0 Bob Lantz
        warn( '*** Starting CLI:\n' )
56 114dcd56 Brandon Heller
        self.cmdloop()
57 496b5f9e Bob Lantz
58
    # Disable pylint "Unused argument: 'arg's'" messages.
59
    # Each CLI function needs the same interface.
60
    # pylint: disable-msg=W0613
61
62 64c451e0 Bob Lantz
    def do_help( self, args ):
63 114dcd56 Brandon Heller
        "Describe available CLI commands."
64 64c451e0 Bob Lantz
        Cmd.do_help( self, args )
65 114dcd56 Brandon Heller
        helpStr = ( 'You may also send a command to a node using:\n'
66 496b5f9e Bob Lantz
                   '  <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 114dcd56 Brandon Heller
                   'for node names when a node is the first arg, so command'
73
                   ' like\n'
74 496b5f9e Bob Lantz
                   '  mininet> h0 ping -c1 h1\n'
75
                   'should work.\n'
76 64c451e0 Bob Lantz
                   '\n'
77 496b5f9e Bob Lantz
                   '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 64c451e0 Bob Lantz
        if args is "":
82
            self.stdout.write( helpStr )
83 496b5f9e Bob Lantz
84 114dcd56 Brandon Heller
    def do_nodes( self, args ):
85 496b5f9e Bob Lantz
        "List all nodes."
86
        nodes = ' '.join( [ node.name for node in sorted( self.nodelist ) ] )
87 64c451e0 Bob Lantz
        info( 'available nodes are: \n%s\n' % nodes )
88 496b5f9e Bob Lantz
89 114dcd56 Brandon Heller
    def do_net( self, args ):
90 496b5f9e Bob Lantz
        "List network connections."
91 c3a44400 Bob Lantz
        for switch in self.mn.switches:
92 64c451e0 Bob Lantz
            info( '%s <->', switch.name )
93 496b5f9e Bob Lantz
            for intf in switch.intfs:
94 e0cfcdd5 Bob Lantz
                name = switch.connection[ intf ][ 1 ]
95
                info( ' %s' % name )
96 64c451e0 Bob Lantz
            info( '\n' )
97 496b5f9e Bob Lantz
98 114dcd56 Brandon Heller
    def do_sh( self, args ):
99 496b5f9e Bob Lantz
        "Run an external shell command"
100 64c451e0 Bob Lantz
        call( args, shell=True )
101 496b5f9e Bob Lantz
102 64c451e0 Bob Lantz
    def do_pingall( self, args ):
103 496b5f9e Bob Lantz
        "Ping between all hosts."
104
        self.mn.pingAll()
105
106 64c451e0 Bob Lantz
    def do_pingpair( self, args ):
107 496b5f9e Bob Lantz
        "Ping between first two hosts, useful for testing."
108
        self.mn.pingPair()
109
110 114dcd56 Brandon Heller
    def do_iperf( self, args ):
111 496b5f9e Bob Lantz
        "Simple iperf TCP test between two hosts."
112
        self.mn.iperf()
113
114 64c451e0 Bob Lantz
    def do_iperfudp( self, args ):
115 496b5f9e Bob Lantz
        "Simple iperf UDP test between two hosts."
116
        udpBw = args[ 0 ] if len( args ) else '10M'
117
        self.mn.iperfUdp( udpBw )
118
119 114dcd56 Brandon Heller
    def do_intfs( self, args ):
120 496b5f9e Bob Lantz
        "List interfaces."
121 2235f216 Bob Lantz
        for node in self.nodelist:
122 64c451e0 Bob Lantz
            info( '%s: %s\n' % ( node.name, ' '.join( node.intfs ) ) )
123 496b5f9e Bob Lantz
124 114dcd56 Brandon Heller
    def do_dump( self, args ):
125 496b5f9e Bob Lantz
        "Dump node info."
126 2235f216 Bob Lantz
        for node in self.nodelist:
127 64c451e0 Bob Lantz
            info( '%s\n' % node )
128 496b5f9e Bob Lantz
129 114dcd56 Brandon Heller
    def do_exit( self, args ):
130
        "Exit"
131
        return 'exited by user command'
132 496b5f9e Bob Lantz
133 114dcd56 Brandon Heller
    def do_quit( self, args ):
134
        "Exit"
135 64c451e0 Bob Lantz
        return self.do_exit( args )
136
137
    def do_EOF( self, args ):
138
        "Exit"
139
        return self.do_exit( args )
140 114dcd56 Brandon Heller
141
    def default( self, line ):
142
        """Called on an input line when the command prefix is not recognized.
143
        Overridden to run shell commands when a node is the first CLI argument.
144
        Past the first CLI argument, node names are automatically replaced with
145 64c451e0 Bob Lantz
        corresponding IP addrs."""
146 31b43002 Bob Lantz
147 114dcd56 Brandon Heller
        first, args, line = self.parseline( line )
148
        if len(args) > 0 and args[ -1 ] == '\n':
149 64c451e0 Bob Lantz
            args = args[ :-1 ]
150 114dcd56 Brandon Heller
        rest = args.split( ' ' )
151
152
        if first in self.nodemap:
153
            node = self.nodemap[ first ]
154
            # Substitute IP addresses for node names in command
155
            rest = [ self.nodemap[ arg ].IP()
156 496b5f9e Bob Lantz
                    if arg in self.nodemap else arg
157
                    for arg in rest ]
158 114dcd56 Brandon Heller
            rest = ' '.join( rest )
159
            # Run cmd on node:
160
            node.sendCmd( rest )
161
            while True:
162
                try:
163
                    done, data = node.monitor()
164 64c451e0 Bob Lantz
                    info( '%s\n' % data )
165 114dcd56 Brandon Heller
                    if done:
166
                        break
167
                except KeyboardInterrupt:
168
                    node.sendInt()
169
        else:
170 64c451e0 Bob Lantz
            self.stdout.write( '*** Unknown syntax: %s\n' % line )
171 114dcd56 Brandon Heller
172
    # Re-enable pylint "Unused argument: 'arg's'" messages.
173
    # pylint: enable-msg=W0613