Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ ccca871a

History | View | Annotate | Download (9.43 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( '--pre', type='string', default=None,
183
                        help='[CLI script to run before tests]' )
184
        opts.add_option( '--post', type='string', default=None,
185
                        help='[CLI script to run after tests]' )
186

    
187
        self.options, self.args = opts.parse_args()
188

    
189
    def setup( self ):
190
        "Setup and validate environment."
191

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

    
199
        # validate environment setup
200
        init()
201

    
202
    def begin( self ):
203
        "Create and run mininet."
204

    
205
        if self.options.clean:
206
            cleanup()
207
            exit()
208

    
209
        start = time.time()
210

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

    
220
        if self.validate:
221
            self.validate( self.options )
222

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

    
236
        test = self.options.test
237
        test = ALTSPELLING.get( test, test )
238

    
239
        mn.start()
240

    
241
        if test == 'none':
242
            pass
243
        elif test == 'all':
244
            mn.start()
245
            mn.ping()
246
            mn.iperf()
247
        elif test == 'cli':
248
            CLI( mn )
249
        elif test != 'build':
250
            getattr( mn, test )()
251

    
252
        if self.options.post:
253
            CLI( mn, script=self.options.post )
254

    
255
        mn.stop()
256

    
257
        elapsed = float( time.time() - start )
258
        info( 'completed in %0.3f seconds\n' % elapsed )
259

    
260

    
261
if __name__ == "__main__":
262
    MininetRunner()