Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ bb941950

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

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

    
33
SWITCHDEF = 'kernel'
34
SWITCHES = { 'kernel': KernelSwitch,
35
            'user': UserSwitch,
36
            'ovsk': OVSKernelSwitch }
37

    
38
HOSTDEF = 'process'
39
HOSTS = { 'process': Host }
40

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

    
49
# optional tests to run
50
TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', 'iperfUdp' ]
51

    
52

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

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

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

    
72

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

    
91

    
92
class MininetRunner( object ):
93
    "Build, setup, and run Mininet."
94

    
95
    def __init__( self ):
96
        "Init."
97
        self.options = None
98
        self.validate = None
99

    
100
        self.parseArgs()
101
        self.setup()
102
        self.begin()
103

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

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

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

    
139
        opts = OptionParser()
140
        addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
141
        addDictOption( opts, HOSTS, HOSTDEF, 'host' )
142
        addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
143

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

    
171
    def setup( self ):
172
        "Setup and validate environment."
173

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

    
181
        # validate environment setup
182
        init()
183

    
184
    def begin( self ):
185
        "Create and run mininet."
186

    
187
        start = time.time()
188

    
189
        topo = buildTopo( self.options.topo )
190
        switch = SWITCHES[ self.options.switch ]
191
        host = HOSTS[ self.options.host ]
192
        controller = CONTROLLERS[ self.options.controller ]
193
        if self.options.controller == 'remote':
194
            controller = lambda a, b: RemoteController( a, b,
195
                             ipAddress=self.options.ip,
196
                             port=self.options.port )
197

    
198
        if self.validate:
199
            self.validate( self.options )
200

    
201
        controllerParams = ControllerParams( '10.0.0.0', 8 )
202
        inNamespace = self.options.inNamespace
203
        xterms = self.options.xterms
204
        mac = self.options.mac
205
        arp = self.options.arp
206
        mn = Mininet( topo, switch, host, controller, controllerParams,
207
                     inNamespace=inNamespace,
208
                     xterms=xterms, autoSetMacs=mac,
209
                     autoStaticArp=arp )
210

    
211
        test = self.options.test
212
        if test != 'build':
213
            if test == 'cli':
214
                mn.interact()
215
            elif test == 'all':
216
                mn.start()
217
                mn.ping()
218
                mn.iperf()
219
                mn.stop()
220
            else:
221
                mn.run( test )
222

    
223
        elapsed = float( time.time() - start )
224
        print ( 'completed in %0.3f seconds' % elapsed )
225

    
226

    
227
if __name__ == "__main__":
228
    MininetRunner()