From 27da832d6ddf70703ae3503f3322072c414a9c40 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Thu, 27 Jun 2013 14:15:28 -0700 Subject: [PATCH 01/11] add support for the IVS virtual switch IVS is an open source virtual switch available for download at https://github.com/floodlight/ivs. It uses the openvswitch kernel module. --- bin/mn | 5 ++-- mininet/node.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/bin/mn b/bin/mn index bba2353..5e1c2e9 100755 --- a/bin/mn +++ b/bin/mn @@ -26,7 +26,7 @@ from mininet.log import lg, LEVELS, info from mininet.net import Mininet, MininetWithControlNet, VERSION from mininet.node import ( Host, CPULimitedHost, Controller, OVSController, NOX, RemoteController, UserSwitch, OVSKernelSwitch, - OVSLegacyKernelSwitch ) + OVSLegacyKernelSwitch, IVSSwitch ) from mininet.link import Link, TCLink from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo from mininet.topolib import TreeTopo @@ -45,7 +45,8 @@ TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ), SWITCHDEF = 'ovsk' SWITCHES = { 'user': UserSwitch, 'ovsk': OVSKernelSwitch, - 'ovsl': OVSLegacyKernelSwitch } + 'ovsl': OVSLegacyKernelSwitch, + 'ivs': IVSSwitch } HOSTDEF = 'proc' HOSTS = { 'proc': Host, diff --git a/mininet/node.py b/mininet/node.py index d6a66ba..edb46de 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1018,6 +1018,71 @@ class OVSSwitch( Switch ): OVSKernelSwitch = OVSSwitch +class IVSSwitch(Switch): + """IVS virtual switch + Currently only works in the root namespace. + """ + + def __init__( self, name, **kwargs ): + Switch.__init__( self, name, **kwargs ) + self.process = None + if self.inNamespace: + error( "IVSSwitch currently only works" + " in the root namespace.\n" ) + exit( 1 ) + + @classmethod + def setup( cls ): + "Make sure IVS is installed" + pathCheck( 'ivs-ctl', 'ivs', + moduleName="Indigo Virtual Switch (projectfloodlight.org)" ) + out, err, exitcode = errRun( 'ivs-ctl show' ) + if exitcode: + error( out + err + + 'ivs-ctl exited with code %d\n' % exitcode + + '*** The openvswitch kernel module might ' + 'not be loaded. Try modprobe openvswitch.\n' ) + exit( 1 ) + + def start( self, controllers ): + "Start up a new IVS switch" + args = ['ivs'] + args.extend( ['--name', self.name] ) + args.extend( ['--dpid', self.dpid] ) + args.extend( ['--verbose'] ) + for intf in self.intfs.values(): + if not intf.IP(): + args.extend( ['-i', intf.name] ) + for c in controllers: + args.extend( ['-c', '%s:%d' % (c.IP(), c.port)] ) + + with open( '/tmp/ivs.%s.log' % self.name, 'w' ) as logfile: + with open( '/dev/null', 'w' ) as nullfile: + self.process = Popen( args, stdout=logfile, stderr=STDOUT, + stdin=nullfile, preexec_fn=os.setsid ) + self.execed = False + + def stop( self ): + "Terminate IVS switch." + if self.process: + self.process.terminate() + self.process.wait() + self.process = None + self.deleteIntfs() + + def attach( self, intf ): + "Connect a data port" + self.cmd( 'ivs-ctl', 'add-port', '--datapath', self.name, intf ) + + def detach( self, intf ): + "Disconnect a data port" + self.cmd( 'ivs-ctl', 'del-port', '--datapath', self.name, intf ) + + def dpctl( self, *args ): + "Run dpctl command" + return "dpctl not supported\n" or args or self # satisfy pylint + + class Controller( Node ): """A Controller is a Node that is running (or has execed?) an OpenFlow controller.""" From 812c91cc9e9c0acfa80d15e288a76b738b6d3b29 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Thu, 27 Jun 2013 14:49:19 -0700 Subject: [PATCH 02/11] test_hifi: use SWITCH to pick the switch class --- mininet/test/test_hifi.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mininet/test/test_hifi.py b/mininet/test/test_hifi.py index ace7bb5..5ef8599 100755 --- a/mininet/test/test_hifi.py +++ b/mininet/test/test_hifi.py @@ -39,7 +39,7 @@ class testOptionsTopo( unittest.TestCase ): "Generic topology-with-options test runner." mn = Mininet( topo=SingleSwitchOptionsTopo( n=n, hopts=hopts, lopts=lopts ), - host=CPULimitedHost, link=TCLink ) + host=CPULimitedHost, link=TCLink, switch=SWITCH ) dropped = mn.run( mn.ping ) self.assertEqual( dropped, 0 ) @@ -58,7 +58,7 @@ class testOptionsTopo( unittest.TestCase ): #self.runOptionsTopoTest( N, hopts=hopts ) mn = Mininet( SingleSwitchOptionsTopo( n=N, hopts=hopts ), - host=CPULimitedHost ) + host=CPULimitedHost, switch=SWITCH ) mn.start() results = mn.runCpuLimitTest( cpu=CPU_FRACTION ) mn.stop() @@ -73,7 +73,7 @@ class testOptionsTopo( unittest.TestCase ): lopts = { 'bw': BW, 'use_htb': True } # Also verify correctness of limit limitng within a bound. mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ), - link=TCLink ) + link=TCLink, switch=SWITCH ) bw_strs = mn.run( mn.iperf ) for bw_str in bw_strs: bw = float( bw_str.split(' ')[0] ) @@ -85,7 +85,7 @@ class testOptionsTopo( unittest.TestCase ): DELAY_TOLERANCE = 0.8 # Delay fraction below which test should fail lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True } mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ), - link=TCLink ) + link=TCLink, switch=SWITCH ) ping_delays = mn.run( mn.pingFull ) test_outputs = ping_delays[0] # Ignore unused variables below @@ -105,7 +105,7 @@ class testOptionsTopo( unittest.TestCase ): REPS = 1 lopts = { 'loss': LOSS_PERCENT, 'use_htb': True } mn = Mininet( topo=SingleSwitchOptionsTopo( n=N, lopts=lopts ), - host=CPULimitedHost, link=TCLink ) + host=CPULimitedHost, link=TCLink, switch=SWITCH ) # Drops are probabilistic, but the chance of no dropped packets is # 1 in 100 million with 4 hops for a link w/99% loss. dropped_total = 0 From 91261b275754e848c153da5369ada8e103f0601f Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Thu, 27 Jun 2013 17:56:46 -0700 Subject: [PATCH 03/11] IVSSwitch: add support for dpctl dpctl is not included with IVS. The user will need to obtain it from the OpenFlow reference repository. --- mininet/node.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mininet/node.py b/mininet/node.py index edb46de..0b67a00 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1055,6 +1055,8 @@ class IVSSwitch(Switch): args.extend( ['-i', intf.name] ) for c in controllers: args.extend( ['-c', '%s:%d' % (c.IP(), c.port)] ) + if self.listenPort: + args.extend( ['--listen', '127.0.0.1:%i' % self.listenPort] ) with open( '/tmp/ivs.%s.log' % self.name, 'w' ) as logfile: with open( '/dev/null', 'w' ) as nullfile: @@ -1080,7 +1082,10 @@ class IVSSwitch(Switch): def dpctl( self, *args ): "Run dpctl command" - return "dpctl not supported\n" or args or self # satisfy pylint + if not self.listenPort: + return "can't run dpctl without passive listening port" + return self.cmd( 'dpctl ' + ' '.join( args ) + + ' tcp:127.0.0.1:%i' % self.listenPort ) class Controller( Node ): From 8ee4aa6de49c9e500d64d58461dae2d142ee5303 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Thu, 27 Jun 2013 18:03:52 -0700 Subject: [PATCH 04/11] install.sh: add support for IVS --- util/install.sh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/util/install.sh b/util/install.sh index 82f5014..48deea5 100755 --- a/util/install.sh +++ b/util/install.sh @@ -77,6 +77,9 @@ OVS_TAG=v$OVS_RELEASE OVS_BUILD=$OVS_SRC/build-$KERNEL_NAME OVS_KMODS=($OVS_BUILD/datapath/linux/{openvswitch_mod.ko,brcompat_mod.ko}) +IVS_TAG=v0.3 +IVS_SRC=~/ivs + function kernel { echo "Install Mininet-compatible kernel if necessary" sudo apt-get update @@ -348,6 +351,18 @@ function remove_ovs { echo "Done removing OVS" } +function ivs { + # Install dependencies + $install git pkg-config gcc make libnl-3-dev libnl-route-3-dev libnl-genl-3-dev + + # Install IVS from source + cd ~/ + git clone git://github.com/floodlight/ivs $IVS_SRC -b $IVS_TAG --recursive + cd $IVS_SRC + make + sudo make install +} + # Install NOX with tutorial files function nox { echo "Installing NOX w/tutorial files..." @@ -551,6 +566,7 @@ function all { pox oftest cbench + ivs echo "Enjoy Mininet!" } @@ -588,7 +604,7 @@ function vm_clean { } function usage { - printf '\nUsage: %s [-abcdfhkmnprtvwx03]\n\n' $(basename $0) >&2 + printf '\nUsage: %s [-abcdfhikmnprtvwx03]\n\n' $(basename $0) >&2 printf 'This install script attempts to install useful packages\n' >&2 printf 'for Mininet. It should (hopefully) work on Ubuntu 11.10+\n' >&2 @@ -603,6 +619,7 @@ function usage { printf -- ' -d: (D)elete some sensitive files from a VM image\n' >&2 printf -- ' -f: install open(F)low\n' >&2 printf -- ' -h: print this (H)elp message\n' >&2 + printf -- ' -i: install Indigo (V)irtual Switch\n' >&2 printf -- ' -k: install new (K)ernel\n' >&2 printf -- ' -m: install Open vSwitch kernel (M)odule from source dir\n' >&2 printf -- ' -n: install mini(N)et dependencies + core files\n' >&2 @@ -623,7 +640,7 @@ if [ $# -eq 0 ] then all else - while getopts 'abcdfhkmnprtvwx03' OPTION + while getopts 'abcdfhikmnprtvwx03' OPTION do case $OPTION in a) all;; @@ -636,6 +653,7 @@ else *) echo "Invalid OpenFlow version $OF_VERSION";; esac;; h) usage;; + i) ivs;; k) kernel;; m) modprobe;; n) mn_deps;; From 803c0a6e224a302c73d5fc231b9fe4d22b67527a Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Sat, 29 Jun 2013 18:11:15 -0700 Subject: [PATCH 05/11] IVSSwitch: use ovs-ofctl for dpctl functionality --- mininet/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/node.py b/mininet/node.py index 0b67a00..71ac9a0 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1084,7 +1084,7 @@ class IVSSwitch(Switch): "Run dpctl command" if not self.listenPort: return "can't run dpctl without passive listening port" - return self.cmd( 'dpctl ' + ' '.join( args ) + + return self.cmd( 'ovs-ofctl ' + ' '.join( args ) + ' tcp:127.0.0.1:%i' % self.listenPort ) From 71ffb0028e017cfd041b37668dbb15e6784e28b1 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Mon, 1 Jul 2013 16:05:52 -0700 Subject: [PATCH 06/11] IVSSwitch: remove namespace warnings IVS works fine using --innamespace. --- mininet/node.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 71ac9a0..3cd8a1f 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1019,17 +1019,11 @@ OVSKernelSwitch = OVSSwitch class IVSSwitch(Switch): - """IVS virtual switch - Currently only works in the root namespace. - """ + """IVS virtual switch""" def __init__( self, name, **kwargs ): Switch.__init__( self, name, **kwargs ) self.process = None - if self.inNamespace: - error( "IVSSwitch currently only works" - " in the root namespace.\n" ) - exit( 1 ) @classmethod def setup( cls ): From 94ff77f2f2e39bb05a329451c8f0af012608fd65 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Tue, 9 Jul 2013 08:34:33 -0700 Subject: [PATCH 07/11] clean: don't wait forever for ovsdb This could happen if OVS was installed but not running. --- mininet/clean.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/clean.py b/mininet/clean.py index c5ef1ab..2911edb 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -49,7 +49,7 @@ def cleanup(): sh( 'dpctl deldp ' + dp ) info( "*** Removing OVS datapaths" ) - dps = sh("ovs-vsctl list-br").split( '\n' ) + dps = sh("ovs-vsctl --timeout=1 list-br").split( '\n' ) for dp in dps: if dp: sh( 'ovs-vsctl del-br ' + dp ) From 60abb344974217362d0847572df43da8ced0fece Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Tue, 9 Jul 2013 08:36:36 -0700 Subject: [PATCH 08/11] clean: kill ivs processes --- mininet/clean.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/clean.py b/mininet/clean.py index 2911edb..10f0cf8 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -27,7 +27,7 @@ def cleanup(): info("*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes" "\n") zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core ' - zombies += 'ovs-openflowd ovs-controller udpbwtest mnexec' + zombies += 'ovs-openflowd ovs-controller udpbwtest mnexec ivs' # Note: real zombie processes can't actually be killed, since they # are already (un)dead. Then again, # you can't connect to them either, so they're mostly harmless. From 0e2cc609dfb03341924d9c64c6f007c9abf8fb49 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Wed, 10 Jul 2013 11:19:25 -0700 Subject: [PATCH 09/11] tests: run all tests with OVS, IVS, and userspace switches Each switch gets its own class so that the test results are listed separately. --- mininet/test/test_hifi.py | 31 ++++++++++++------ mininet/test/test_nets.py | 67 +++++++++++++++++++++++++-------------- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/mininet/test/test_hifi.py b/mininet/test/test_hifi.py index 5ef8599..e881f3a 100755 --- a/mininet/test/test_hifi.py +++ b/mininet/test/test_hifi.py @@ -6,14 +6,12 @@ import unittest from mininet.net import Mininet -from mininet.node import OVSKernelSwitch +from mininet.node import OVSKernelSwitch, UserSwitch, IVSSwitch from mininet.node import CPULimitedHost from mininet.link import TCLink from mininet.topo import Topo from mininet.log import setLogLevel - -SWITCH = OVSKernelSwitch # Number of hosts for each test N = 2 @@ -32,14 +30,16 @@ class SingleSwitchOptionsTopo(Topo): self.addLink(host, switch) -class testOptionsTopo( unittest.TestCase ): - "Verify ability to create networks with host and link options." +class testOptionsTopoCommon( object ): + "Verify ability to create networks with host and link options (common code)." + + switchClass = None # overridden in subclasses def runOptionsTopoTest( self, n, hopts=None, lopts=None ): "Generic topology-with-options test runner." mn = Mininet( topo=SingleSwitchOptionsTopo( n=n, hopts=hopts, lopts=lopts ), - host=CPULimitedHost, link=TCLink, switch=SWITCH ) + host=CPULimitedHost, link=TCLink, switch=self.switchClass ) dropped = mn.run( mn.ping ) self.assertEqual( dropped, 0 ) @@ -58,7 +58,7 @@ class testOptionsTopo( unittest.TestCase ): #self.runOptionsTopoTest( N, hopts=hopts ) mn = Mininet( SingleSwitchOptionsTopo( n=N, hopts=hopts ), - host=CPULimitedHost, switch=SWITCH ) + host=CPULimitedHost, switch=self.switchClass ) mn.start() results = mn.runCpuLimitTest( cpu=CPU_FRACTION ) mn.stop() @@ -73,7 +73,7 @@ class testOptionsTopo( unittest.TestCase ): lopts = { 'bw': BW, 'use_htb': True } # Also verify correctness of limit limitng within a bound. mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ), - link=TCLink, switch=SWITCH ) + link=TCLink, switch=self.switchClass ) bw_strs = mn.run( mn.iperf ) for bw_str in bw_strs: bw = float( bw_str.split(' ')[0] ) @@ -85,7 +85,7 @@ class testOptionsTopo( unittest.TestCase ): DELAY_TOLERANCE = 0.8 # Delay fraction below which test should fail lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True } mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ), - link=TCLink, switch=SWITCH ) + link=TCLink, switch=self.switchClass ) ping_delays = mn.run( mn.pingFull ) test_outputs = ping_delays[0] # Ignore unused variables below @@ -105,7 +105,7 @@ class testOptionsTopo( unittest.TestCase ): REPS = 1 lopts = { 'loss': LOSS_PERCENT, 'use_htb': True } mn = Mininet( topo=SingleSwitchOptionsTopo( n=N, lopts=lopts ), - host=CPULimitedHost, link=TCLink, switch=SWITCH ) + host=CPULimitedHost, link=TCLink, switch=self.switchClass ) # Drops are probabilistic, but the chance of no dropped packets is # 1 in 100 million with 4 hops for a link w/99% loss. dropped_total = 0 @@ -121,6 +121,17 @@ class testOptionsTopo( unittest.TestCase ): hopts = { 'cpu': 0.5 / N } self.runOptionsTopoTest( N, hopts=hopts, lopts=lopts ) +class testOptionsTopoOVSKernel( testOptionsTopoCommon, unittest.TestCase ): + "Verify ability to create networks with host and link options (OVS kernel switch)." + switchClass = OVSKernelSwitch + +class testOptionsTopoIVS( testOptionsTopoCommon, unittest.TestCase ): + "Verify ability to create networks with host and link options (IVS switch)." + switchClass = IVSSwitch + +class testOptionsTopoUserspace( testOptionsTopoCommon, unittest.TestCase ): + "Verify ability to create networks with host and link options (Userspace switch)." + switchClass = UserSwitch if __name__ == '__main__': setLogLevel( 'warning' ) diff --git a/mininet/test/test_nets.py b/mininet/test/test_nets.py index fde8e87..027bdd4 100755 --- a/mininet/test/test_nets.py +++ b/mininet/test/test_nets.py @@ -7,42 +7,63 @@ import unittest from mininet.net import Mininet from mininet.node import Host, Controller -from mininet.node import UserSwitch, OVSKernelSwitch +from mininet.node import UserSwitch, OVSKernelSwitch, IVSSwitch from mininet.topo import SingleSwitchTopo, LinearTopo from mininet.log import setLogLevel -SWITCHES = { 'user': UserSwitch, - 'ovsk': OVSKernelSwitch, -} +class testSingleSwitchCommon( object ): + "Test ping with single switch topology (common code)." -class testSingleSwitch( unittest.TestCase ): - "For each datapath type, test ping with single switch topologies." + switchClass = None # overridden in subclasses def testMinimal( self ): - "Ping test with both datapaths on minimal topology" - for switch in SWITCHES.values(): - mn = Mininet( SingleSwitchTopo(), switch, Host, Controller ) - dropped = mn.run( mn.ping ) - self.assertEqual( dropped, 0 ) + "Ping test on minimal topology" + mn = Mininet( SingleSwitchTopo(), self.switchClass, Host, Controller ) + dropped = mn.run( mn.ping ) + self.assertEqual( dropped, 0 ) def testSingle5( self ): - "Ping test with both datapaths on 5-host single-switch topology" - for switch in SWITCHES.values(): - mn = Mininet( SingleSwitchTopo( k=5 ), switch, Host, Controller ) - dropped = mn.run( mn.ping ) - self.assertEqual( dropped, 0 ) + "Ping test on 5-host single-switch topology" + mn = Mininet( SingleSwitchTopo( k=5 ), self.switchClass, Host, Controller ) + dropped = mn.run( mn.ping ) + self.assertEqual( dropped, 0 ) + +class testSingleSwitchOVSKernel( testSingleSwitchCommon, unittest.TestCase ): + "Test ping with single switch topology (OVS kernel switch)." + switchClass = OVSKernelSwitch + +class testSingleSwitchIVS( testSingleSwitchCommon, unittest.TestCase ): + "Test ping with single switch topology (IVS switch)." + switchClass = IVSSwitch + +class testSingleSwitchUserspace( testSingleSwitchCommon, unittest.TestCase ): + "Test ping with single switch topology (Userspace switch)." + switchClass = UserSwitch -class testLinear( unittest.TestCase ): - "For each datapath type, test all-pairs ping with LinearNet." +class testLinearCommon( object ): + "Test all-pairs ping with LinearNet (common code)." + + switchClass = None # overridden in subclasses def testLinear5( self ): - "Ping test with both datapaths on a 5-switch topology" - for switch in SWITCHES.values(): - mn = Mininet( LinearTopo( k=5 ), switch, Host, Controller ) - dropped = mn.run( mn.ping ) - self.assertEqual( dropped, 0 ) + "Ping test on a 5-switch topology" + mn = Mininet( LinearTopo( k=5 ), self.switchClass, Host, Controller ) + dropped = mn.run( mn.ping ) + self.assertEqual( dropped, 0 ) + +class testLinearOVSKernel( testLinearCommon, unittest.TestCase ): + "Test all-pairs ping with LinearNet (OVS kernel switch)." + switchClass = OVSKernelSwitch + +class testLinearIVS( testLinearCommon, unittest.TestCase ): + "Test all-pairs ping with LinearNet (IVS switch)." + switchClass = IVSSwitch + +class testLinearUserspace( testLinearCommon, unittest.TestCase ): + "Test all-pairs ping with LinearNet (Userspace switch)." + switchClass = UserSwitch if __name__ == '__main__': From 5c24263779aef139ee5a3fa9d17790f4e0705681 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Thu, 18 Jul 2013 13:50:20 -0700 Subject: [PATCH 10/11] clean: send SIGTERM before SIGKILL IVS needs to be sent SIGTERM so it has a chance to clean up the kernel datapath. --- mininet/clean.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mininet/clean.py b/mininet/clean.py index 10f0cf8..5162bf3 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -11,6 +11,7 @@ nothing irreplaceable! """ from subprocess import Popen, PIPE +import time from mininet.log import info from mininet.term import cleanUpScreens @@ -31,6 +32,9 @@ def cleanup(): # Note: real zombie processes can't actually be killed, since they # are already (un)dead. Then again, # you can't connect to them either, so they're mostly harmless. + # Send SIGTERM first to give processes a chance to shutdown cleanly. + sh( 'killall ' + zombies + ' 2> /dev/null' ) + time.sleep(1) sh( 'killall -9 ' + zombies + ' 2> /dev/null' ) # And kill off sudo mnexec From 0a543602119aaadc180ec9301cd85bcefc31b0b0 Mon Sep 17 00:00:00 2001 From: Rich Lane Date: Thu, 18 Jul 2013 17:50:52 -0700 Subject: [PATCH 11/11] IVSSwitch: support running IVS in a namespace This change uses the `Node.cmd` method instead of `Popen`. The `cmd` method sends the input to a shell which may be in another namespace (if --innamespace is in use), while `Popen` would always run in the root namespace. --- mininet/node.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 3cd8a1f..131c9f7 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1023,7 +1023,6 @@ class IVSSwitch(Switch): def __init__( self, name, **kwargs ): Switch.__init__( self, name, **kwargs ) - self.process = None @classmethod def setup( cls ): @@ -1052,18 +1051,13 @@ class IVSSwitch(Switch): if self.listenPort: args.extend( ['--listen', '127.0.0.1:%i' % self.listenPort] ) - with open( '/tmp/ivs.%s.log' % self.name, 'w' ) as logfile: - with open( '/dev/null', 'w' ) as nullfile: - self.process = Popen( args, stdout=logfile, stderr=STDOUT, - stdin=nullfile, preexec_fn=os.setsid ) - self.execed = False + logfile = '/tmp/ivs.%s.log' % self.name + + self.cmd( ' '.join(args) + ' >' + logfile + ' 2>&1