Newer
Older
"""
Mininet runner
author: Brandon Heller (brandonh@stanford.edu)
To see options:
sudo mn -h
Example to pull custom params (topo, switch, etc.) from a file:
sudo mn --custom ~/mininet/custom/custom_example.py
from optparse import OptionParser
from mininet.clean import cleanup
from mininet.log import lg, LEVELS, info
from mininet.net import Mininet, init
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
from mininet.node import RemoteController, UserSwitch, OVSKernelSwitch
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
from mininet.util import makeNumeric
# built in topologies, created only when run
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
'linear': LinearTopo,
'reversed': SingleSwitchReversedTopo,
'single': SingleSwitchTopo,
'tree': TreeTopo }
SWITCHDEF = 'kernel'
SWITCHES = { 'kernel': KernelSwitch,
HOSTDEF = 'process'
HOSTS = { 'process': Host }
# a and b are the name and inNamespace params.
'nox_dump': lambda name: NOX( name, 'packetdump' ),
'nox_pysw': lambda name: NOX( name, 'pyswitch' ),
'remote': lambda name: None,
'none': lambda name: None }
TESTS = [ 'cli', 'build', 'pingAll', 'pingPair', 'iperf', 'all', 'iperfUdp',
'none' ]
def buildTopo( topo ):
"Create topology from string with format (object, arg1, arg2,...)."
topo_split = topo.split( ',' )
topo_name = topo_split[ 0 ]
topo_params = topo_split[ 1: ]
# Convert int and float args; removes the need for every topology to
# be flexible with input arg formats.
topo_seq_params = [ s for s in topo_params if '=' not in s ]
topo_seq_params = [ makeNumeric( s ) for s in topo_seq_params ]
topo_kw_params = {}
key, val = s.split( '=' )
topo_kw_params[ key ] = makeNumeric( val )
if topo_name not in TOPOS.keys():
raise Exception( 'Invalid topo_name %s' % topo_name )
return TOPOS[ topo_name ]( *topo_seq_params, **topo_kw_params )
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
"""Convenience function to add choices dicts to OptionParser.
opts: OptionParser instance
choicesDict: dictionary of valid choices, must include default
default: default choice key
name: long option name
help: string"""
if default not in choicesDict:
raise Exception( 'Invalid default %s for choices dict: %s' %
( default, name ) )
if not helpStr:
helpStr = '[' + ' '.join( choicesDict.keys() ) + ']'
opts.add_option( '--' + name,
type='choice',
choices=choicesDict.keys(),
class MininetRunner( object ):
"Build, setup, and run Mininet."
def setCustom( self, name, value ):
if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
# Update dictionaries
param = name.upper()
globals()[ param ].update( value )
elif name == 'validate':
# Add custom validate function
self.validate = value
else:
# Add or modify global variable or class
globals()[ name ] = value
def parseCustomFile( self, fileName ):
"Parse custom file and add params before parsing cmd-line options."
custom = {}
if os.path.isfile( fileName ):
execfile( fileName, custom, custom )
for name in custom:
self.setCustom( name, custom[ name ] )
raise Exception( 'could not find custom file: %s' % fileName )
def parseArgs( self ):
"""Parse command-line args and return options object.
returns: opts parse options dict"""
if '--custom' in sys.argv:
print "custom in sys.argv"
index = sys.argv.index( '--custom' )
if len( sys.argv ) > index + 1:
custom = sys.argv[ index + 1 ]
self.parseCustomFile( custom )
else:
raise Exception( 'Custom file name not found' )
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
opts.add_option( '--topo', type='string', default=TOPODEF,
help='[' + ' '.join( TOPOS.keys() ) + '],arg1,arg2,'
'...argN')
opts.add_option( '--clean', '-c', action='store_true',
default=False, help='clean and exit' )
opts.add_option( '--custom', type='string', default=None,
help='read custom topo and node params from .py file' )
opts.add_option( '--test', type='choice', choices=TESTS,
default=TESTS[ 0 ],
help='[' + ' '.join( TESTS ) + ']' )
opts.add_option( '--xterms', '-x', action='store_true',
default=False, help='spawn xterms for each node' )
opts.add_option( '--mac', action='store_true',
default=False, help='set MACs equal to DPIDs' )
opts.add_option( '--arp', action='store_true',
default=False, help='set all-pairs ARP entries' )
opts.add_option( '--verbosity', '-v', type='choice',
choices=LEVELS.keys(), default = 'info',
help = '[' + ' '.join( LEVELS.keys() ) + ']' )
opts.add_option( '--ip', type='string', default='127.0.0.1',
help='[ip address as a dotted decimal string for a'
'remote controller]' )
opts.add_option( '--port', type='int', default=6633,
help='[port integer for a listening remote'
' controller]' )
opts.add_option( '--inNamespace', action='store_true',
default=False, help='sw and ctrl in namespace?' )
self.options = opts.parse_args()[ 0 ]
def setup( self ):
"Setup and validate environment."
if LEVELS[self.options.verbosity] > LEVELS['output']:
print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
'output!\n'
'Please restart Mininet with -v [debug, info, output].' )
lg.setLogLevel( self.options.verbosity )
# validate environment setup
init()
def begin( self ):
"Create and run mininet."
if self.options.clean:
cleanup()
exit()
topo = buildTopo( self.options.topo )
switch = SWITCHES[ self.options.switch ]
host = HOSTS[ self.options.host ]
controller = CONTROLLERS[ self.options.controller ]
if self.options.controller == 'remote':
self.validate( self.options )
controllerParams = ControllerParams( '10.0.0.0', 8 )
inNamespace = self.options.inNamespace
mac = self.options.mac
arp = self.options.arp
mn = Mininet( topo, switch, host, controller, controllerParams,
inNamespace=inNamespace,
xterms=xterms, autoSetMacs=mac,
autoStaticArp=arp )
if test == 'none':
mn.start()
mn.stop()
elif test == 'cli':
mn.interact()
elif test == 'all':
mn.start()
mn.ping()
mn.iperf()
mn.stop()
elif test != 'build':
elapsed = float( time.time() - start )
info( 'completed in %0.3f seconds\n' % elapsed )
if __name__ == "__main__":