Statistics
| Branch: | Tag: | Revision:

mininet / mininet / cli.py @ e0cfcdd5

History | View | Annotate | Download (5.56 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.hosts + self.mn.switches + self.mn.controllers
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 command'
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( '%s <->', switch.name )
93
            for intf in switch.intfs:
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
    def do_pingall( self, args ):
103
        "Ping between all hosts."
104
        self.mn.pingAll()
105

    
106
    def do_pingpair( self, args ):
107
        "Ping between first two hosts, useful for testing."
108
        self.mn.pingPair()
109

    
110
    def do_iperf( self, args ):
111
        "Simple iperf TCP test between two hosts."
112
        self.mn.iperf()
113

    
114
    def do_iperfudp( self, args ):
115
        "Simple iperf UDP test between two hosts."
116
        udpBw = args[ 0 ] if len( args ) else '10M'
117
        self.mn.iperfUdp( udpBw )
118

    
119
    def do_intfs( self, args ):
120
        "List interfaces."
121
        for node in self.nodelist:
122
            info( '%s: %s\n' % ( node.name, ' '.join( node.intfs ) ) )
123

    
124
    def do_dump( self, args ):
125
        "Dump node info."
126
        for node in self.nodelist:
127
            info( '%s\n' % node )
128

    
129
    def do_exit( self, args ):
130
        "Exit"
131
        return 'exited by user command'
132

    
133
    def do_quit( self, args ):
134
        "Exit"
135
        return self.do_exit( args )
136

    
137
    def do_EOF( self, args ):
138
        "Exit"
139
        return self.do_exit( args )
140

    
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
        corresponding IP addrs."""
146

    
147
        first, args, line = self.parseline( line )
148
        if len(args) > 0 and args[ -1 ] == '\n':
149
            args = args[ :-1 ]
150
        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
                    if arg in self.nodemap else arg
157
                    for arg in rest ]
158
            rest = ' '.join( rest )
159
            # Run cmd on node:
160
            node.sendCmd( rest )
161
            while True:
162
                try:
163
                    done, data = node.monitor()
164
                    info( '%s\n' % data )
165
                    if done:
166
                        break
167
                except KeyboardInterrupt:
168
                    node.sendInt()
169
        else:
170
            self.stdout.write( '*** Unknown syntax: %s\n' % line )
171

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