Statistics
| Branch: | Tag: | Revision:

mininet / mininet / cli.py @ 83097ff9

History | View | Annotate | Download (6.11 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 ('ping_all', 'ping_pair')
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
- We don't (yet) support command line history editing. This is
37
  coming soon.
38

39
"""
40

    
41
from subprocess import call
42
import sys
43

    
44
from mininet.log import lg
45

    
46
class CLI( object ):
47
    "Simple command-line interface to talk to nodes."
48

    
49
    cmds = [ '?', 'help', 'nodes', 'net', 'sh', 'pingAll', 'exit',
50
            'pingPair', 'iperf', 'iperfUdp', 'intfs', 'dump' ]
51

    
52
    def __init__( self, mininet ):
53
        self.mn = mininet
54
        self.nodemap = {} # map names to Node objects
55
        for node in self.mn.nodes.values():
56
            self.nodemap[ node.name ] = node
57
        for cname, cnode in self.mn.controllers.iteritems():
58
            self.nodemap[ cname ] = cnode
59
        self.nodelist = self.nodemap.values()
60
        self.run()
61

    
62
    # Disable pylint "Unused argument: 'arg's'" messages.
63
    # Each CLI function needs the same interface.
64
    # pylint: disable-msg=W0613
65

    
66
    # Commands
67
    def help( self, args ):
68
        "Semi-useful help for CLI."
69
        helpStr = ( 'Available commands are:' + str( self.cmds ) + '\n'
70
                   'You may also send a command to a node using:\n'
71
                   '  <node> command {args}\n'
72
                   'For example:\n'
73
                   '  mininet> h0 ifconfig\n'
74
                   '\n'
75
                   'The interpreter automatically substitutes IP '
76
                   'addresses\n'
77
                   'for node names, so commands like\n'
78
                   '  mininet> h0 ping -c1 h1\n'
79
                   'should work.\n'
80
                   '\n\n'
81
                   'Interactive commands are not really supported yet,\n'
82
                   'so please limit commands to ones that do not\n'
83
                   'require user interaction and will terminate\n'
84
                   'after a reasonable amount of time.\n' )
85
        print( helpStr )
86

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

    
92
    def net( self, args ):
93
        "List network connections."
94
        for switchDpid in self.mn.topo.switches():
95
            switch = self.mn.nodes[ switchDpid ]
96
            lg.info( '%s <->', switch.name )
97
            for intf in switch.intfs:
98
                node = switch.connection[ intf ]
99
                lg.info( ' %s' % node.name )
100
            lg.info( '\n' )
101

    
102
    def sh( self, args ):
103
        "Run an external shell command"
104
        call( [ 'sh', '-c' ] + args )
105

    
106
    def pingAll( self, args ):
107
        "Ping between all hosts."
108
        self.mn.pingAll()
109

    
110
    def pingPair( self, args ):
111
        "Ping between first two hosts, useful for testing."
112
        self.mn.pingPair()
113

    
114
    def iperf( self, args ):
115
        "Simple iperf TCP test between two hosts."
116
        self.mn.iperf()
117

    
118
    def iperfUdp( self, args ):
119
        "Simple iperf UDP test between two hosts."
120
        udpBw = args[ 0 ] if len( args ) else '10M'
121
        self.mn.iperfUdp( udpBw )
122

    
123
    def intfs( self, args ):
124
        "List interfaces."
125
        for node in self.mn.nodes.values():
126
            lg.info( '%s: %s\n' % ( node.name, ' '.join( node.intfs ) ) )
127

    
128
    def dump( self, args ):
129
        "Dump node info."
130
        for node in self.mn.nodes.values():
131
            lg.info( '%s\n' % node )
132

    
133
    # Re-enable pylint "Unused argument: 'arg's'" messages.
134
    # pylint: enable-msg=W0613
135

    
136
    def run( self ):
137
        "Read and execute commands."
138
        lg.warn( '*** Starting CLI:\n' )
139
        while True:
140
            lg.warn( 'mininet> ' )
141
            inputLine = sys.stdin.readline()
142
            if inputLine == '':
143
                break
144
            if inputLine[ -1 ] == '\n':
145
                inputLine = inputLine[ :-1 ]
146
            cmd = inputLine.split( ' ' )
147
            first = cmd[ 0 ]
148
            rest = cmd[ 1: ]
149
            if first in self.cmds and hasattr( self, first ):
150
                getattr( self, first )( rest )
151
            elif first in self.nodemap and rest != []:
152
                node = self.nodemap[ first ]
153
                # Substitute IP addresses for node names in command
154
                rest = [ self.nodemap[ arg ].IP()
155
                    if arg in self.nodemap else arg
156
                    for arg in rest ]
157
                rest = ' '.join( rest )
158
                # Interactive commands don't work yet, and
159
                # there are still issues with control-c
160
                lg.warn( '*** %s: running %s\n' % ( node.name, rest ) )
161
                node.sendCmd( rest )
162
                while True:
163
                    try:
164
                        done, data = node.monitor()
165
                        lg.info( '%s\n' % data )
166
                        if done:
167
                            break
168
                    except KeyboardInterrupt:
169
                        node.sendInt()
170
            elif first == '':
171
                pass
172
            elif first in [ 'exit', 'quit' ]:
173
                break
174
            elif first == '?':
175
                self.help( rest )
176
            else:
177
                lg.error( 'CLI: unknown node or command: < %s >\n' % first )
178
            #lg.info( '*** CLI: command complete\n' )
179
        return 'exited by user command'