Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ c8641d7d

History | View | Annotate | Download (8.5 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 a, b: NOX( a, b, 'packetdump' ),
48
               'nox_pysw': lambda a, b: NOX( a, b, 'pyswitch' ),
49
               'remote': lambda a, b: None,
50
               'none': lambda a, b: None }
51

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

    
55

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

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

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

    
75

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

    
94

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

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

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

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

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

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

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

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

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

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

    
186
        # validate environment setup
187
        init()
188

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

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

    
196
        start = time.time()
197

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

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

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

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

    
232
        elapsed = float( time.time() - start )
233
        info( 'completed in %0.3f seconds\n' % elapsed )
234

    
235

    
236
if __name__ == "__main__":
237
    MininetRunner()