diff --git a/bin/mn b/bin/mn index 0fc3374..b31b22e 100755 --- a/bin/mn +++ b/bin/mn @@ -21,7 +21,7 @@ if 'PYTHONPATH' in os.environ: sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path from mininet.clean import cleanup -from mininet.cli import CLI +from mininet.cli import CLI as CLI from mininet.log import lg, LEVELS, info, debug, warn, error from mininet.net import Mininet, MininetWithControlNet, VERSION from mininet.node import ( Host, CPULimitedHost, Controller, OVSController, @@ -87,16 +87,48 @@ LINKS = { 'default': Link, 'tc': TCLink, 'ovs': OVSLink } +# TESTS dict can contain functions and/or Mininet() method names +# XXX: it would be nice if we could specify a default test, but +# this may be tricky +TESTS = { name: True + for name in ( 'pingall', 'pingpair', 'iperf', 'iperfudp' ) } -# Names of tests that are Mininet() methods -TESTNAMES = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp', - 'none' ] -# Map to alternate functions and/or spellings of Mininet() methods -TESTS = { 'pingall': 'pingAll', - 'pingpair': 'pingPair', - 'iperfudp': 'iperfUdp', - 'iperfUDP': 'iperfUdp' } +# Locally defined tests +def allTest( net ): + "Run ping and iperf tests" + net.waitConnected() + net.start() + net.ping() + net.iperf() +def nullTest( net ): + "Null 'test' (does nothing)" + pass +TESTS.update( all=allTest, none=nullTest, build=nullTest ) + +# Map to alternate spellings of Mininet() methods +ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair', + 'iperfudp': 'iperfUdp' } + +def runTests( mn, options ): + """Run tests + mn: Mininet object + option: list of test optinos """ + # Split option into test name and parameters + for option in options: + # Multiple tests may be separated by '+' for now + for test in option.split( '+' ): + test, args, kwargs = splitArgs( test ) + test = ALTSPELLING.get( test.lower(), test ) + testfn = TESTS.get( test, test ) + if callable( testfn ): + testfn( mn, *args, **kwargs ) + elif hasattr( mn, test ): + mn.waitConnected() + getattr( mn, test )( *args, **kwargs ) + else: + raise Exception( 'Test %s is unknown - please specify one of ' + '%s ' % ( test, TESTS.keys() ) ) def addDictOption( opts, choicesDict, default, name, **kwargs ): @@ -117,7 +149,7 @@ def addDictOption( opts, choicesDict, default, name, **kwargs ): def version( *_args ): "Print Mininet version and exit" - print( "%s" % VERSION ) + info( "%s\n" % VERSION ) exit() @@ -210,9 +242,8 @@ class MininetRunner( object ): type='string', help='read custom classes or params from .py file(s)' ) - testList = TESTNAMES + TESTS.keys() opts.add_option( '--test', default=[], action='append', - dest='tests', help='|'.join( testList ) ) + dest='test', help='|'.join( TESTS.keys() ) ) opts.add_option( '--xterms', '-x', action='store_true', default=False, help='spawn xterms for each node' ) opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8', @@ -269,9 +300,9 @@ class MininetRunner( object ): # set logging verbosity if LEVELS[self.options.verbosity] > LEVELS['output']: - print( '*** WARNING: selected verbosity level (%s) will hide CLI ' + warn( '*** WARNING: selected verbosity level (%s) will hide CLI ' 'output!\n' - 'Please restart Mininet with -v [debug, info, output].' + 'Please restart Mininet with -v [debug, info, output].\n' % self.options.verbosity ) lg.setLogLevel( self.options.verbosity ) @@ -281,108 +312,84 @@ class MininetRunner( object ): def begin( self ): "Create and run mininet." - if self.options.cluster: - servers = self.options.cluster.split( ',' ) + opts = self.options + + if opts.cluster: + servers = opts.cluster.split( ',' ) for server in servers: ClusterCleanup.add( server ) - if self.options.clean: + if opts.clean: cleanup() exit() start = time.time() - if not self.options.controller: + if not opts.controller: # Update default based on available controllers CONTROLLERS[ 'default' ] = findController() - self.options.controller = [ 'default' ] + opts.controller = [ 'default' ] if not CONTROLLERS[ 'default' ]: - self.options.controller = [ 'none' ] - if self.options.switch == 'default': + opts.controller = [ 'none' ] + if opts.switch == 'default': info( '*** No default OpenFlow controller found ' 'for default switch!\n' ) info( '*** Falling back to OVS Bridge\n' ) - self.options.switch = 'ovsbr' - elif self.options.switch not in ( 'ovsbr', 'lxbr' ): + opts.switch = 'ovsbr' + elif opts.switch not in ( 'ovsbr', 'lxbr' ): raise Exception( "Could not find a default controller " "for switch %s" % - self.options.switch ) + opts.switch ) - topo = buildTopo( TOPOS, self.options.topo ) - switch = customClass( SWITCHES, self.options.switch ) - host = customClass( HOSTS, self.options.host ) + topo = buildTopo( TOPOS, opts.topo ) + switch = customClass( SWITCHES, opts.switch ) + host = customClass( HOSTS, opts.host ) controller = [ customClass( CONTROLLERS, c ) - for c in self.options.controller ] - link = customClass( LINKS, self.options.link ) + for c in opts.controller ] + link = customClass( LINKS, opts.link ) if self.validate: - self.validate( self.options ) + self.validate( opts ) - ipBase = self.options.ipbase - xterms = self.options.xterms - mac = self.options.mac - arp = self.options.arp - pin = self.options.pin - listenPort = None - if not self.options.nolistenport: - listenPort = self.options.listenport + if opts.nolistenport: + opts.listenport = None - # Handle inNamespace, cluster options - inNamespace = self.options.innamespace - cluster = self.options.cluster - if inNamespace and cluster: - print( "Please specify --innamespace OR --cluster" ) + # Handle innamespace, cluster options + if opts.innamespace and opts.cluster: + error( "Please specify --innamespace OR --cluster\n" ) exit() - Net = MininetWithControlNet if inNamespace else Mininet - cli = ClusterCLI if cluster else CLI - if cluster: + Net = MininetWithControlNet if opts.innamespace else Mininet + if opts.cluster: warn( '*** WARNING: Experimental cluster mode!\n' '*** Using RemoteHost, RemoteOVSSwitch, RemoteLink\n' ) host, switch, link = RemoteHost, RemoteOVSSwitch, RemoteLink Net = partial( MininetCluster, servers=servers, - placement=PLACEMENT[ self.options.placement ] ) + placement=PLACEMENT[ opts.placement ] ) + global CLI + CLI = ClusterCLI mn = Net( topo=topo, - switch=switch, host=host, controller=controller, - link=link, - ipBase=ipBase, - inNamespace=inNamespace, - xterms=xterms, autoSetMacs=mac, - autoStaticArp=arp, autoPinCpus=pin, - listenPort=listenPort ) + switch=switch, host=host, controller=controller, link=link, + ipBase=opts.ipbase, inNamespace=opts.innamespace, + xterms=opts.xterms, autoSetMacs=opts.mac, + autoStaticArp=opts.arp, autoPinCpus=opts.pin, + listenPort=opts.listenport ) - if self.options.ensure_value( 'nat', False ): - nat = mn.addNAT( *self.options.nat_args, - **self.options.nat_kwargs ) - nat.configDefault() + if opts.ensure_value( 'nat', False ): + mn.addNAT( *opts.nat_args, **opts.nat_kwargs ).configDefault() - if self.options.pre: - cli( mn, script=self.options.pre ) + if opts.pre: + CLI( mn, script=opts.pre ) mn.start() - if not self.options.tests: - cli( mn ) + if opts.test: + runTests( mn, opts.test ) + else: + CLI( mn ) - for test in self.options.tests: - test = TESTS.get( test, test ) - if callable( test ): # user added TESTMAP={'mytest': testfn} - test( mn ) - elif test == 'none': - pass - elif test == 'all': - mn.waitConnected() - mn.start() - mn.ping() - mn.iperf() - elif test == 'cli': - cli( mn ) - elif test != 'build': - mn.waitConnected() - getattr( mn, test )() - - if self.options.post: - cli( mn, script=self.options.post ) + if opts.post: + CLI( mn, script=opts.post ) mn.stop()