Statistics
| Branch: | Tag: | Revision:

mininet / bin / mn @ edf60032

History | View | Annotate | Download (9.95 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
16
import sys
17
import time
18

    
19
# Fix setuptools' evil madness, and open up (more?) security holes
20
if 'PYTHONPATH' in os.environ:
21
    sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
22

    
23
from mininet.clean import cleanup
24
from mininet.cli import CLI
25
from mininet.log import lg, LEVELS, info
26
from mininet.net import Mininet, MininetWithControlNet, VERSION
27
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
28
                           NOX, RemoteController, UserSwitch, OVSKernelSwitch,
29
                           OVSLegacyKernelSwitch )
30
from mininet.link import Link, TCLink
31
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
32
from mininet.topolib import TreeTopo
33
from mininet.util import custom, customConstructor
34
from mininet.util import buildTopo
35

    
36

    
37
# built in topologies, created only when run
38
TOPODEF = 'minimal'
39
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
40
          'linear': LinearTopo,
41
          'reversed': SingleSwitchReversedTopo,
42
          'single': SingleSwitchTopo,
43
          'tree': TreeTopo }
44

    
45
SWITCHDEF = 'ovsk'
46
SWITCHES = { 'user': UserSwitch,
47
             'ovsk': OVSKernelSwitch,
48
             'ovsl': OVSLegacyKernelSwitch }
49

    
50
HOSTDEF = 'proc'
51
HOSTS = { 'proc': Host,
52
          'rt': custom( CPULimitedHost, sched='rt' ),
53
          'cfs': custom( CPULimitedHost, sched='cfs' ) }
54

    
55
CONTROLLERDEF = 'ovsc'
56
CONTROLLERS = { 'ref': Controller,
57
                'ovsc': OVSController,
58
                'nox': NOX,
59
                'remote': RemoteController,
60
                'none': lambda name: None }
61

    
62
LINKDEF = 'default'
63
LINKS = { 'default': Link,
64
          'tc': TCLink }
65

    
66

    
67
# optional tests to run
68
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
69
          'none' ]
70

    
71
ALTSPELLING = { 'pingall': 'pingAll',
72
                'pingpair': 'pingPair',
73
                'iperfudp': 'iperfUdp',
74
                'iperfUDP': 'iperfUdp',
75
                'prefixlen': 'prefixLen' }
76

    
77

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

    
96

    
97
def version( *_args ):
98
    "Print Mininet version and exit"
99
    print "%s" % VERSION
100
    exit()
101

    
102
class MininetRunner( object ):
103
    "Build, setup, and run Mininet."
104

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

    
111
        self.parseArgs()
112
        self.setup()
113
        self.begin()
114

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

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

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

    
149
        desc = ( "The %prog utility creates Mininet network from the\n"
150
                 "command line. It can create parametrized topologies,\n"
151
                 "invoke the Mininet CLI, and run tests." )
152

    
153
        usage = ( '%prog [options]\n'
154
                  '(type %prog -h for details)' )
155

    
156
        opts = OptionParser( description=desc, usage=usage )
157
        addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
158
        addDictOption( opts, HOSTS, HOSTDEF, 'host' )
159
        addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
160
        addDictOption( opts, LINKS, LINKDEF, 'link' )
161
        addDictOption( opts, TOPOS, TOPODEF, 'topo' )
162

    
163
        opts.add_option( '--clean', '-c', action='store_true',
164
                         default=False, help='clean and exit' )
165
        opts.add_option( '--custom', type='string', default=None,
166
                         help='read custom topo and node params from .py file' )
167
        opts.add_option( '--test', type='choice', choices=TESTS,
168
                         default=TESTS[ 0 ],
169
                         help='|'.join( TESTS ) )
170
        opts.add_option( '--xterms', '-x', action='store_true',
171
                         default=False, help='spawn xterms for each node' )
172
        opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
173
                         help='base IP address for hosts' )
174
        opts.add_option( '--mac', action='store_true',
175
                         default=False, help='automatically set host MACs' )
176
        opts.add_option( '--arp', action='store_true',
177
                         default=False, help='set all-pairs ARP entries' )
178
        opts.add_option( '--verbosity', '-v', type='choice',
179
                         choices=LEVELS.keys(), default = 'info',
180
                         help = '|'.join( LEVELS.keys() )  )
181
        opts.add_option( '--innamespace', action='store_true',
182
                         default=False, help='sw and ctrl in namespace?' )
183
        opts.add_option( '--listenport', type='int', default=6635,
184
                         help='base port for passive switch listening' )
185
        opts.add_option( '--nolistenport', action='store_true',
186
                         default=False, help="don't use passive listening port")
187
        opts.add_option( '--pre', type='string', default=None,
188
                         help='CLI script to run before tests' )
189
        opts.add_option( '--post', type='string', default=None,
190
                         help='CLI script to run after tests' )
191
        opts.add_option( '--prefixlen', type='int', default=8,
192
                         help='prefix length (e.g. /8) for automatic '
193
                         'network configuration' )
194
        opts.add_option( '--pin', action='store_true',
195
                         default=False, help="pin hosts to CPU cores "
196
                         "(requires --host cfs or --host rt)" )
197
        opts.add_option( '--version', action='callback', callback=version )
198

    
199
        self.options, self.args = opts.parse_args()
200

    
201
    def setup( self ):
202
        "Setup and validate environment."
203

    
204
        # set logging verbosity
205
        if LEVELS[self.options.verbosity] > LEVELS['output']:
206
            print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
207
                    'output!\n'
208
                    'Please restart Mininet with -v [debug, info, output].'
209
                    % self.options.verbosity )
210
        lg.setLogLevel( self.options.verbosity )
211

    
212
    def begin( self ):
213
        "Create and run mininet."
214

    
215
        if self.options.clean:
216
            cleanup()
217
            exit()
218

    
219
        start = time.time()
220

    
221
        topo = buildTopo( TOPOS, self.options.topo )
222
        switch = customConstructor( SWITCHES, self.options.switch )
223
        host = customConstructor( HOSTS, self.options.host )
224
        controller = customConstructor( CONTROLLERS, self.options.controller )
225
        link = customConstructor( LINKS, self.options.link )
226

    
227
        if self.validate:
228
            self.validate( self.options )
229

    
230
        inNamespace = self.options.innamespace
231
        Net = MininetWithControlNet if inNamespace else Mininet
232
        ipBase = self.options.ipbase
233
        xterms = self.options.xterms
234
        mac = self.options.mac
235
        arp = self.options.arp
236
        pin = self.options.pin
237
        listenPort = None
238
        if not self.options.nolistenport:
239
            listenPort = self.options.listenport
240
        mn = Net( topo=topo,
241
                  switch=switch, host=host, controller=controller,
242
                  link=link,
243
                  ipBase=ipBase,
244
                  inNamespace=inNamespace,
245
                  xterms=xterms, autoSetMacs=mac,
246
                  autoStaticArp=arp, autoPinCpus=pin,
247
                  listenPort=listenPort )
248

    
249
        if self.options.pre:
250
            CLI( mn, script=self.options.pre )
251

    
252
        test = self.options.test
253
        test = ALTSPELLING.get( test, test )
254

    
255
        mn.start()
256

    
257
        if test == 'none':
258
            pass
259
        elif test == 'all':
260
            mn.start()
261
            mn.ping()
262
            mn.iperf()
263
        elif test == 'cli':
264
            CLI( mn )
265
        elif test != 'build':
266
            getattr( mn, test )()
267

    
268
        if self.options.post:
269
            CLI( mn, script=self.options.post )
270

    
271
        mn.stop()
272

    
273
        elapsed = float( time.time() - start )
274
        info( 'completed in %0.3f seconds\n' % elapsed )
275

    
276

    
277
if __name__ == "__main__":
278
    MininetRunner()