Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ 0a9358c9

History | View | Annotate | Download (9.64 KB)

1
#!/usr/bin/env python
2

    
3
"""
4
Mininet runner
5
author: Brandon Heller (brandonh@stanford.edu)
6

    
7
To see options:
8
  sudo mn -h
9

    
10
Example to pull custom params (topo, switch, etc.) from a file:
11
  sudo mn --custom ~/mininet/custom/custom_example.py
12
"""
13

    
14
from optparse import OptionParser
15
import os.path
16
import sys
17
import time
18

    
19
from mininet.clean import cleanup
20
from mininet.cli import CLI
21
from mininet.log import lg, LEVELS, info
22
from mininet.net import Mininet, init
23
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
24
from mininet.node import RemoteController, UserSwitch, OVSKernelSwitch
25
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
26
from mininet.topolib import TreeTopo
27
from mininet.util import makeNumeric
28

    
29
# built in topologies, created only when run
30
TOPODEF = 'minimal'
31
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
32
         'linear': LinearTopo,
33
         'reversed': SingleSwitchReversedTopo,
34
         'single': SingleSwitchTopo,
35
         'tree': TreeTopo }
36

    
37
SWITCHDEF = 'ovsk'
38
SWITCHES = { 'kernel': KernelSwitch,
39
            'user': UserSwitch,
40
            'ovsk': OVSKernelSwitch }
41

    
42
HOSTDEF = 'process'
43
HOSTS = { 'process': Host }
44

    
45
CONTROLLERDEF = 'ref'
46
# a and b are the name and inNamespace params.
47
CONTROLLERS = { 'ref': Controller,
48
               'nox_dump': lambda name: NOX( name, 'packetdump' ),
49
               'nox_pysw': lambda name: NOX( name, 'pyswitch' ),
50
               'remote': lambda name: None,
51
               'none': lambda name: None }
52

    
53
# optional tests to run
54
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
55
         'none' ]
56

    
57
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
58
    'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp' }
59

    
60
def buildTopo( topo ):
61
    "Create topology from string with format (object, arg1, arg2,...)."
62
    topo_split = topo.split( ',' )
63
    topo_name = topo_split[ 0 ]
64
    topo_params = topo_split[ 1: ]
65

    
66
    # Convert int and float args; removes the need for every topology to
67
    # be flexible with input arg formats.
68
    topo_seq_params = [ s for s in topo_params if '=' not in s ]
69
    topo_seq_params = [ makeNumeric( s ) for s in topo_seq_params ]
70
    topo_kw_params = {}
71
    for s in [ p for p in topo_params if '=' in p ]:
72
        key, val = s.split( '=' )
73
        topo_kw_params[ key ] = makeNumeric( val )
74

    
75
    if topo_name not in TOPOS.keys():
76
        raise Exception( 'Invalid topo_name %s' % topo_name )
77
    return TOPOS[ topo_name ]( *topo_seq_params, **topo_kw_params )
78

    
79

    
80
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
81
    """Convenience function to add choices dicts to OptionParser.
82
       opts: OptionParser instance
83
       choicesDict: dictionary of valid choices, must include default
84
       default: default choice key
85
       name: long option name
86
       help: string"""
87
    if default not in choicesDict:
88
        raise Exception( 'Invalid  default %s for choices dict: %s' %
89
                        ( default, name ) )
90
    if not helpStr:
91
        helpStr = '[' + ' '.join( choicesDict.keys() ) + ']'
92
    opts.add_option( '--' + name,
93
                    type='choice',
94
                    choices=choicesDict.keys(),
95
                    default = default,
96
                    help = helpStr )
97

    
98

    
99
class MininetRunner( object ):
100
    "Build, setup, and run Mininet."
101

    
102
    def __init__( self ):
103
        "Init."
104
        self.options = None
105
        self.args = None  # May be used someday for more CLI scripts
106
        self.validate = None
107

    
108
        self.parseArgs()
109
        self.setup()
110
        self.begin()
111

    
112
    def setCustom( self, name, value ):
113
        "Set custom parameters for MininetRunner."
114
        if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
115
            # Update dictionaries
116
            param = name.upper()
117
            globals()[ param ].update( value )
118
        elif name == 'validate':
119
            # Add custom validate function
120
            self.validate = value
121
        else:
122
            # Add or modify global variable or class
123
            globals()[ name ] = value
124

    
125
    def parseCustomFile( self, fileName ):
126
        "Parse custom file and add params before parsing cmd-line options."
127
        custom = {}
128
        if os.path.isfile( fileName ):
129
            execfile( fileName, custom, custom )
130
            for name in custom:
131
                self.setCustom( name, custom[ name ] )
132
        else:
133
            raise Exception( 'could not find custom file: %s' % fileName )
134

    
135
    def parseArgs( self ):
136
        """Parse command-line args and return options object.
137
           returns: opts parse options dict"""
138
        if '--custom' in sys.argv:
139
            print "custom in sys.argv"
140
            index = sys.argv.index( '--custom' )
141
            if len( sys.argv ) > index + 1:
142
                custom = sys.argv[ index + 1 ]
143
                self.parseCustomFile( custom )
144
            else:
145
                raise Exception( 'Custom file name not found' )
146

    
147
        opts = OptionParser()
148
        addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
149
        addDictOption( opts, HOSTS, HOSTDEF, 'host' )
150
        addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
151

    
152
        opts.add_option( '--topo', type='string', default=TOPODEF,
153
                        help='[' + ' '.join( TOPOS.keys() ) + '],arg1,arg2,'
154
                        '...argN')
155
        opts.add_option( '--clean', '-c', action='store_true',
156
                        default=False, help='clean and exit' )
157
        opts.add_option( '--custom', type='string', default=None,
158
                        help='read custom topo and node params from .py file' )
159
        opts.add_option( '--test', type='choice', choices=TESTS,
160
                        default=TESTS[ 0 ],
161
                        help='[' + ' '.join( TESTS ) + ']' )
162
        opts.add_option( '--xterms', '-x', action='store_true',
163
                        default=False, help='spawn xterms for each node' )
164
        opts.add_option( '--mac', action='store_true',
165
                        default=False, help='set MACs equal to DPIDs' )
166
        opts.add_option( '--arp', action='store_true',
167
                        default=False, help='set all-pairs ARP entries' )
168
        opts.add_option( '--verbosity', '-v', type='choice',
169
                        choices=LEVELS.keys(), default = 'info',
170
                        help = '[' + ' '.join( LEVELS.keys() ) + ']' )
171
        opts.add_option( '--ip', type='string', default='127.0.0.1',
172
                        help='[ip address as a dotted decimal string for a'
173
                        'remote controller]' )
174
        opts.add_option( '--port', type='int', default=6633,
175
                        help='[port integer for a listening remote'
176
                        ' controller]' )
177
        opts.add_option( '--innamespace', action='store_true',
178
                        default=False, help='sw and ctrl in namespace?' )
179
        opts.add_option( '--listenport', type='int', default=6634,
180
                        help='[base port for passive switch listening'
181
                        ' controller]' )
182
        opts.add_option( '--nolistenport', action='store_true',
183
                        default=False, help="don't use passive listening port")
184
        opts.add_option( '--pre', type='string', default=None,
185
                        help='[CLI script to run before tests]' )
186
        opts.add_option( '--post', type='string', default=None,
187
                        help='[CLI script to run after tests]' )
188

    
189
        self.options, self.args = opts.parse_args()
190

    
191
    def setup( self ):
192
        "Setup and validate environment."
193

    
194
        # set logging verbosity
195
        if LEVELS[self.options.verbosity] > LEVELS['output']:
196
            print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
197
                    'output!\n'
198
                    'Please restart Mininet with -v [debug, info, output].' )
199
        lg.setLogLevel( self.options.verbosity )
200

    
201
        # validate environment setup
202
        init()
203

    
204
    def begin( self ):
205
        "Create and run mininet."
206

    
207
        if self.options.clean:
208
            cleanup()
209
            exit()
210

    
211
        start = time.time()
212

    
213
        topo = buildTopo( self.options.topo )
214
        switch = SWITCHES[ self.options.switch ]
215
        host = HOSTS[ self.options.host ]
216
        controller = CONTROLLERS[ self.options.controller ]
217
        if self.options.controller == 'remote':
218
            controller = lambda a: RemoteController( a,
219
                             defaultIP=self.options.ip,
220
                             port=self.options.port )
221

    
222
        if self.validate:
223
            self.validate( self.options )
224

    
225
        controllerParams = ControllerParams( '10.0.0.0', 8 )
226
        inNamespace = self.options.innamespace
227
        xterms = self.options.xterms
228
        mac = self.options.mac
229
        arp = self.options.arp
230
        listenPort = None
231
        if not self.options.nolistenport:
232
            listenPort = self.options.listenport
233
        mn = Mininet( topo, switch, host, controller, controllerParams,
234
                     inNamespace=inNamespace,
235
                     xterms=xterms, autoSetMacs=mac,
236
                     autoStaticArp=arp, listenPort=listenPort )
237
        if self.options.pre:
238
            CLI( mn, script=self.options.pre )
239

    
240
        test = self.options.test
241
        test = ALTSPELLING.get( test, test )
242

    
243
        mn.start()
244

    
245
        if test == 'none':
246
            pass
247
        elif test == 'all':
248
            mn.start()
249
            mn.ping()
250
            mn.iperf()
251
        elif test == 'cli':
252
            CLI( mn )
253
        elif test != 'build':
254
            getattr( mn, test )()
255

    
256
        if self.options.post:
257
            CLI( mn, script=self.options.post )
258

    
259
        mn.stop()
260

    
261
        elapsed = float( time.time() - start )
262
        info( 'completed in %0.3f seconds\n' % elapsed )
263

    
264

    
265
if __name__ == "__main__":
266
    MininetRunner()