Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ f32a5468

History | View | Annotate | Download (8.56 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.log import lg, LEVELS, info
21
from mininet.net import Mininet, init
22
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
23
from mininet.node import RemoteController, UserSwitch, OVSKernelSwitch
24
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
25
from mininet.topolib import TreeTopo
26
from mininet.util import makeNumeric
27

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

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

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

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

    
52
# optional tests to run
53
TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', 'iperfUdp',
54
         'none' ]
55

    
56

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

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

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

    
76

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

    
95

    
96
class MininetRunner( object ):
97
    "Build, setup, and run Mininet."
98

    
99
    def __init__( self ):
100
        "Init."
101
        self.options = None
102
        self.validate = None
103

    
104
        self.parseArgs()
105
        self.setup()
106
        self.begin()
107

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

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

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

    
143
        opts = OptionParser()
144
        addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
145
        addDictOption( opts, HOSTS, HOSTDEF, 'host' )
146
        addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
147

    
148
        opts.add_option( '--topo', type='string', default=TOPODEF,
149
                        help='[' + ' '.join( TOPOS.keys() ) + '],arg1,arg2,'
150
                        '...argN')
151
        opts.add_option( '--clean', '-c', action='store_true',
152
                        default=False, help='clean and exit' )
153
        opts.add_option( '--custom', type='string', default=None,
154
                        help='read custom topo and node params from .py file' )
155
        opts.add_option( '--test', type='choice', choices=TESTS,
156
                        default=TESTS[ 0 ],
157
                        help='[' + ' '.join( TESTS ) + ']' )
158
        opts.add_option( '--xterms', '-x', action='store_true',
159
                        default=False, help='spawn xterms for each node' )
160
        opts.add_option( '--mac', action='store_true',
161
                        default=False, help='set MACs equal to DPIDs' )
162
        opts.add_option( '--arp', action='store_true',
163
                        default=False, help='set all-pairs ARP entries' )
164
        opts.add_option( '--verbosity', '-v', type='choice',
165
                        choices=LEVELS.keys(), default = 'info',
166
                        help = '[' + ' '.join( LEVELS.keys() ) + ']' )
167
        opts.add_option( '--ip', type='string', default='127.0.0.1',
168
                        help='[ip address as a dotted decimal string for a'
169
                        'remote controller]' )
170
        opts.add_option( '--port', type='string', default=6633,
171
                        help='[port integer for a listening remote'
172
                        ' controller]' )
173
        opts.add_option( '--inNamespace', action='store_true',
174
                        default=False, help='sw and ctrl in namespace?' )
175
        self.options = opts.parse_args()[ 0 ]
176

    
177
    def setup( self ):
178
        "Setup and validate environment."
179

    
180
        # set logging verbosity
181
        if LEVELS[self.options.verbosity] > LEVELS['output']:
182
            print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
183
                    'output!\n'
184
                    'Please restart Mininet with -v [debug, info, output].' )
185
        lg.setLogLevel( self.options.verbosity )
186

    
187
        # validate environment setup
188
        init()
189

    
190
    def begin( self ):
191
        "Create and run mininet."
192

    
193
        if self.options.clean:
194
            cleanup()
195
            exit()
196

    
197
        start = time.time()
198

    
199
        topo = buildTopo( self.options.topo )
200
        switch = SWITCHES[ self.options.switch ]
201
        host = HOSTS[ self.options.host ]
202
        controller = CONTROLLERS[ self.options.controller ]
203
        if self.options.controller == 'remote':
204
            controller = lambda a, b: RemoteController( a, b,
205
                             defaultIP=self.options.ip,
206
                             port=self.options.port )
207

    
208
        if self.validate:
209
            self.validate( self.options )
210

    
211
        controllerParams = ControllerParams( '10.0.0.0', 8 )
212
        inNamespace = self.options.inNamespace
213
        xterms = self.options.xterms
214
        mac = self.options.mac
215
        arp = self.options.arp
216
        mn = Mininet( topo, switch, host, controller, controllerParams,
217
                     inNamespace=inNamespace,
218
                     xterms=xterms, autoSetMacs=mac,
219
                     autoStaticArp=arp )
220

    
221
        test = self.options.test
222
        if test == 'none':
223
            mn.start()
224
            mn.stop()
225
        elif test == 'cli':
226
            mn.interact()
227
        elif test == 'all':
228
            mn.start()
229
            mn.ping()
230
            mn.iperf()
231
            mn.stop()
232
        elif test != 'build':
233
            mn.run( getattr( mn, test ) )
234

    
235
        elapsed = float( time.time() - start )
236
        info( 'completed in %0.3f seconds\n' % elapsed )
237

    
238

    
239
if __name__ == "__main__":
240
    MininetRunner()