Munged mn and mnclean into mininet style.

This commit is contained in:
Bob Lantz
2010-02-08 15:42:31 -08:00
parent 7c371cf32a
commit 8895862acf
2 changed files with 130 additions and 133 deletions
Executable → Regular
+118 -119
View File
@@ -1,8 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
'''Mininet runner
@author Brandon Heller (brandonh@stanford.edu) """
''' Mininet runner
author: Brandon Heller (brandonh@stanford.edu)
"""
from optparse import OptionParser from optparse import OptionParser
import os.path import os.path
@@ -10,9 +11,9 @@ import time
try: try:
from ripcord.dctopo import TreeTopo, FatTreeTopo, VL2Topo from ripcord.dctopo import TreeTopo, FatTreeTopo, VL2Topo
USE_RIPCORD = True USERIPCORD = True
except ImportError: except ImportError:
USE_RIPCORD = False USERIPCORD = False
from mininet.log import lg, LEVELS from mininet.log import lg, LEVELS
from mininet.net import Mininet, init from mininet.net import Mininet, init
@@ -21,164 +22,162 @@ from mininet.node import RemoteController, UserSwitch, OVSKernelSwitch
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
# built in topologies, created only when run # built in topologies, created only when run
TOPO_DEF = 'minimal' TOPODEF = 'minimal'
TOPOS = {'minimal': (lambda: SingleSwitchTopo(k = 2)), TOPOS = { 'minimal': ( lambda: SingleSwitchTopo( k=2 ) ),
'reversed': (lambda: SingleSwitchReversedTopo(k = 2)), 'reversed': ( lambda: SingleSwitchReversedTopo( k=2 ) ),
'single4': (lambda: SingleSwitchTopo(k = 4)), 'single4': ( lambda: SingleSwitchTopo( k=4 ) ),
'single100': (lambda: SingleSwitchTopo(k = 100)), 'single100': ( lambda: SingleSwitchTopo( k=100 ) ),
'linear2': (lambda: LinearTopo(k = 2)), 'linear2': ( lambda: LinearTopo( k=2 ) ),
'linear100': (lambda: LinearTopo(k = 100))} 'linear100': ( lambda: LinearTopo( k=100 ) ) }
if USE_RIPCORD: if USERIPCORD:
TOPOS_RIPCORD = { TOPOSRIPCORD = {
'tree16': (lambda: TreeTopo(depth = 3, fanout = 4)), 'tree16': ( lambda: TreeTopo( depth=3, fanout=4 ) ),
'tree64': (lambda: TreeTopo(depth = 4, fanout = 4)), 'tree64': ( lambda: TreeTopo( depth=4, fanout=4 ) ),
'tree1024': (lambda: TreeTopo(depth = 3, fanout = 32)), 'tree1024': ( lambda: TreeTopo( depth=3, fanout=32 ) ),
'fattree4': (lambda: FatTreeTopo(k = 4)), 'fattree4': ( lambda: FatTreeTopo( k=4 ) ),
'fattree6': (lambda: FatTreeTopo(k = 6)), 'fattree6': ( lambda: FatTreeTopo( k=6 ) ),
'vl2': (lambda: VL2Topo(da = 4, di = 4)), 'vl2': ( lambda: VL2Topo( da=4, di=4 ) ),
'vl2reduced': (lambda: VL2Topo(da = 4, di = 4, edge_down = 1))} 'vl2reduced': ( lambda: VL2Topo( da=4, di=4, edgeDown=1 ) ) }
TOPOS.update(TOPOS_RIPCORD) TOPOS.update( TOPOSRIPCORD )
SWITCH_DEF = 'kernel' SWITCHDEF = 'kernel'
SWITCHES = {'kernel': KernelSwitch, SWITCHES = { 'kernel': KernelSwitch,
'user': UserSwitch, 'user': UserSwitch,
'ovsk': OVSKernelSwitch} 'ovsk': OVSKernelSwitch }
HOST_DEF = 'process' HOSTDEF = 'process'
HOSTS = {'process': Host} HOSTS = { 'process': Host }
CONTROLLER_DEF = 'ref' CONTROLLERDEF = 'ref'
# a and b are the name and inNamespace params. # a and b are the name and inNamespace params.
CONTROLLERS = {'ref': Controller, CONTROLLERS = { 'ref': Controller,
'nox_dump': lambda a, b: NOX(a, b, 'packetdump'), 'nox_dump': lambda a, b: NOX( a, b, 'packetdump' ),
'nox_pysw': lambda a, b: NOX(a, b, 'pyswitch'), 'nox_pysw': lambda a, b: NOX( a, b, 'pyswitch' ),
'remote': lambda a, b: None, 'remote': lambda a, b: None,
'none': lambda a, b: None} 'none': lambda a, b: None }
# optional tests to run # optional tests to run
TESTS = ['cli', 'build', 'ping_all', 'ping_pair', 'iperf', 'all', 'iperf_udp'] TESTS = [ 'cli', 'build', 'ping_all', 'ping_pair', 'iperf', 'all',
'iperf_udp' ]
def add_dict_option(opts, choices_dict, default, name, help_str = None): def addDictOption( opts, choicesDict, default, name, helpStr=None ):
'''Convenience function to add choices dicts to OptionParser. """Convenience function to add choices dicts to OptionParser.
opts: OptionParser instance
@param opts OptionParser instance choicesDict: dictionary of valid choices, must include default
@param choices_dict dictionary of valid choices, must include default default: default choice key
@param default default choice key name: long option name
@param name long option name help: string"""
@param help string if default not in choicesDict:
''' raise Exception( 'Invalid default %s for choices dict: %s' %
if default not in choices_dict: ( default, name ) )
raise Exception('Invalid default %s for choices dict: %s' % if not helpStr:
(default, name)) helpStr = '[' + ' '.join( choicesDict.keys() ) + ']'
if not help_str: opts.add_option( '--' + name,
help_str = '[' + ' '.join(choices_dict.keys()) + ']' type='choice',
opts.add_option('--' + name, choices=choicesDict.keys(),
type = 'choice',
choices = choices_dict.keys(),
default = default, default = default,
help = help_str) help = helpStr )
class MininetRunner(object): class MininetRunner( object ):
'''Build, setup, and run Mininet.''' "Build, setup, and run Mininet."
def __init__(self): def __init__( self ):
'''Init.''' "Init."
self.options = None self.options = None
self.parse_args() self.parseArgs()
self.setup() self.setup()
self.begin() self.begin()
def parse_args(self): def parseArgs( self ):
'''Parse command-line args and return options object. """Parse command-line args and return options object.
returns: opts parse options dict"""
@return opts parse options dict
'''
opts = OptionParser() opts = OptionParser()
add_dict_option(opts, TOPOS, TOPO_DEF, 'topo') addDictOption( opts, TOPOS, TOPODEF, 'topo' )
add_dict_option(opts, SWITCHES, SWITCH_DEF, 'switch') addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
add_dict_option(opts, HOSTS, HOST_DEF, 'host') addDictOption( opts, HOSTS, HOSTDEF, 'host' )
add_dict_option(opts, CONTROLLERS, CONTROLLER_DEF, 'controller') addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
opts.add_option('--custom', type = 'string', default = None, opts.add_option( '--custom', type='string', default=None,
help = 'read custom mininet from current dir') help='read custom mininet from current dir' )
opts.add_option('--test', type = 'choice', choices = TESTS, opts.add_option( '--test', type='choice', choices=TESTS,
default = TESTS[0], default=TESTS[ 0 ],
help = '[' + ' '.join(TESTS) + ']') help='[' + ' '.join( TESTS ) + ']' )
opts.add_option('--xterms', '-x', action = 'store_true', opts.add_option( '--xterms', '-x', action='store_true',
default = False, help = 'spawn xterms for each node') default=False, help='spawn xterms for each node' )
opts.add_option('--mac', action = 'store_true', opts.add_option( '--mac', action='store_true',
default = False, help = 'set MACs equal to DPIDs') default=False, help='set MACs equal to DPIDs' )
opts.add_option('--arp', action = 'store_true', opts.add_option( '--arp', action='store_true',
default = False, help = 'set all-pairs ARP entries') default=False, help='set all-pairs ARP entries' )
opts.add_option('--verbosity', '-v', type = 'choice', opts.add_option( '--verbosity', '-v', type='choice',
choices = LEVELS.keys(), default = 'info', choices=LEVELS.keys(), default = 'info',
help = '[' + ' '.join(LEVELS.keys()) + ']') help = '[' + ' '.join( LEVELS.keys() ) + ']' )
opts.add_option('--ip', type = 'string', default = '127.0.0.1', opts.add_option( '--ip', type='string', default='127.0.0.1',
help = '[ip address as a dotted decimal string for a' help='[ip address as a dotted decimal string for a'
'remote controller]') 'remote controller]' )
opts.add_option('--port', type = 'string', default = 6633, opts.add_option( '--port', type='string', default=6633,
help = '[port integer for a listening remote' help='[port integer for a listening remote'
' controller]') ' controller]' )
opts.add_option('--in_namespace', action = 'store_true', opts.add_option( '--in_namespace', action='store_true',
default = False, help = 'sw and ctrl in namespace?') default=False, help='sw and ctrl in namespace?' )
self.options = opts.parse_args()[0] self.options = opts.parse_args()[ 0 ]
def setup(self): def setup( self ):
'''Setup and validate environment.''' "Setup and validate environment."
# set logging verbosity # set logging verbosity
lg.setLogLevel(self.options.verbosity) lg.setLogLevel( self.options.verbosity )
# validate environment setup # validate environment setup
init() init()
# check for invalid combinations # check for invalid combinations
if self.options.controller == 'ref' and \ if ( self.options.controller == 'ref' and
(('fattree' in self.options.topo) or ('vl2' in self.options.topo)): ( ( 'fattree' in self.options.topo ) or
raise Exception('multipath topos require multipath-capable ' ( 'vl2' in self.options.topo ) ) ):
'controller.') raise Exception( 'multipath topos require multipath-capable '
'controller.' )
if self.options.custom: if self.options.custom:
if not os.path.isfile(self.options.custom): if not os.path.isfile( self.options.custom ):
raise Exception('could not find custom file: %s' % raise Exception( 'could not find custom file: %s' %
self.options.custom) self.options.custom )
def begin(self): def begin( self ):
'''Create and run mininet.''' "Create and run mininet."
start = time.time() start = time.time()
topo = TOPOS[self.options.topo]() # build topology object topo = TOPOS[ self.options.topo ]() # build topology object
switch = SWITCHES[self.options.switch] switch = SWITCHES[ self.options.switch ]
host = HOSTS[self.options.host] host = HOSTS[ self.options.host ]
controller = CONTROLLERS[self.options.controller] controller = CONTROLLERS[ self.options.controller ]
if self.options.controller == 'remote': if self.options.controller == 'remote':
controller = lambda a, b: RemoteController(a, b, controller = lambda a, b: RemoteController( a, b,
ip_address = self.options.ip, ipAddress=self.options.ip,
port = self.options.port) port=self.options.port )
controller_params = ControllerParams(0x0a000000, 8) # 10.0.0.0/8 controllerParams = ControllerParams( 0x0a000000, 8 ) # 10.0.0.0/8
in_namespace = self.options.in_namespace inNamespace = self.options.inNamespace
xterms = self.options.xterms xterms = self.options.xterms
mac = self.options.mac mac = self.options.mac
arp = self.options.arp arp = self.options.arp
mn = None mn = None
if not self.options.custom: if not self.options.custom:
mn = Mininet(topo, switch, host, controller, controller_params, mn = Mininet( topo, switch, host, controller, controllerParams,
in_namespace = in_namespace, inNamespace=inNamespace,
xterms = xterms, auto_set_macs = mac, xterms=xterms, autoSetMacs=mac,
auto_static_arp = arp) autoStaticArp=arp )
else: else:
globals_ = {} globals_ = {}
locals_ = {} locals_ = {}
execfile(self.options.custom, globals_, locals_) execfile( self.options.custom, globals_, locals_ )
if 'mn' not in locals_: if 'mn' not in locals_:
raise Exception('could not find mn var in custom file') raise Exception( 'could not find mn var in custom file' )
else: else:
mn = locals_['mn'] mn = locals_[ 'mn' ]
test = self.options.test test = self.options.test
if test != 'build': if test != 'build':
@@ -190,10 +189,10 @@ class MininetRunner(object):
mn.iperf() mn.iperf()
mn.stop() mn.stop()
else: else:
mn.run(test) mn.run( test )
elapsed = float(time.time() - start) elapsed = float( time.time() - start )
print ('completed in %0.3f seconds' % elapsed) print ( 'completed in %0.3f seconds' % elapsed )
if __name__ == "__main__": if __name__ == "__main__":
Executable → Regular
+12 -14
View File
@@ -1,7 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
"""Mininet Cleanup
@author Bob Lantz (rlantz@cs.stanford.edu) """
Mininet Cleanup
author: Bob Lantz (rlantz@cs.stanford.edu)
Unfortunately, Mininet and OpenFlow don't always clean up Unfortunately, Mininet and OpenFlow don't always clean up
properly after themselves. Until they do (or until cleanup properly after themselves. Until they do (or until cleanup
@@ -15,42 +16,39 @@ from subprocess import Popen, PIPE
from mininet.xterm import cleanUpScreens from mininet.xterm import cleanUpScreens
def sh( cmd ):
def sh(cmd):
"Print a command and send it to the shell" "Print a command and send it to the shell"
print cmd print cmd
return Popen(['/bin/sh', '-c', cmd], stdout=PIPE).communicate()[0] return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
def cleanup(): def cleanup():
"""Clean up junk which might be left over from old runs; """Clean up junk which might be left over from old runs;
do fast stuff before slow dp and link removal!""" do fast stuff before slow dp and link removal!"""
print "*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes" print "*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core ' zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
zombies += 'udpbwtest' zombies += 'udpbwtest'
# Note: real zombie processes can't actually be killed, since they # Note: real zombie processes can't actually be killed, since they
# are already (un)dead. Then again, # are already ( un )dead. Then again,
# you can't connect to them either, so they're mostly harmless. # you can't connect to them either, so they're mostly harmless.
sh('killall -9 ' + zombies + ' 2> /dev/null') sh( 'killall -9 ' + zombies + ' 2> /dev/null' )
print "*** Removing junk from /tmp" print "*** Removing junk from /tmp"
sh('rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log') sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' )
print "*** Removing old screen sessions" print "*** Removing old screen sessions"
cleanUpScreens() cleanUpScreens()
print "*** Removing excess kernel datapaths" print "*** Removing excess kernel datapaths"
dps = sh("ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'").split('\n') dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" ).split( '\n' )
for dp in dps: for dp in dps:
if dp != '': if dp != '':
sh('dpctl deldp ' + dp) sh( 'dpctl deldp ' + dp )
print "*** Removing all links of the pattern foo-ethX" print "*** Removing all links of the pattern foo-ethX"
links = sh("ip link show | egrep -o '(\w+-eth\w+)'").split('\n') links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' )
for link in links: for link in links:
if link != '': if link != '':
sh("ip link del " + link) sh( "ip link del " + link )
print "*** Cleanup complete." print "*** Cleanup complete."