From f95c4a47123a91a6ff9d0cd2b439eda6f87d687d Mon Sep 17 00:00:00 2001 From: Bob Date: Sun, 2 Dec 2012 15:00:46 -0800 Subject: [PATCH 01/77] Update INSTALL: git clone from github.com Thanks to @xdhanz for the catch, and pull request closes #84 --- INSTALL | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/INSTALL b/INSTALL index 9168bd7..6aaac7e 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,3 @@ - Mininet Installation/Configuration Notes Mininet 2.0.0 @@ -45,7 +44,7 @@ remove the old OVS from /usr/local: If you're reading this, you've probably already done so, but the command to download the Mininet source code is; - git clone git://openflow.org/mininet.git + git clone git://github.com/mininet/mininet.git If you are running Ubuntu, you may be able to use our handy install.sh script, which is in mininet/util. From ee66d53c547638aae834ede0b2af684f2c7d42e3 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Sun, 2 Dec 2012 15:29:53 -0800 Subject: [PATCH 02/77] Clean up INSTALL and make it markdown-friendly Also fixed a few errors like the time it takes to install, some references to NOX, etc.. Left in noxcore ref, since you can still install it. --- INSTALL | 131 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/INSTALL b/INSTALL index 6aaac7e..2e46569 100644 --- a/INSTALL +++ b/INSTALL @@ -1,116 +1,119 @@ + Mininet Installation/Configuration Notes +---------------------------------------- Mininet 2.0.0 - --- -The supported installation methods for Mininet are 1) using -a pre-built VM image, and 2) native installation on Ubuntu. You -can also easily create your own Mininet VM image (3). +The supported installation methods for Mininet are 1) using a +pre-built VM image, and 2) native installation on Ubuntu. You can also +easily create your own Mininet VM image (4). (Other distributions may be supported in the future - if you would like to contribute an installation script, we would welcome it!) 1. Easiest "installation" - use our pre-built VM image! -The easiest way to get Mininet running is to start with one of our pre-built -virtual machine images from http://openflow.org/mininet + The easiest way to get Mininet running is to start with one of our + pre-built virtual machine images from -Boot up the VM image, log in, and follow the instructions on the wiki page. + Boot up the VM image, log in, and follow the instructions on the + Mininet web site. -One advantage of using the VM image is that it doesn't mess with -your native OS installation or damage it in any way. + One advantage of using the VM image is that it doesn't mess with + your native OS installation or damage it in any way. -Although a single Mininet instance can simulate multiple networks with -multiple controllers, only one Mininet instance may currently be run at -a time, and Mininet requires root access in the machine it's running on. -Therefore, if you have a multiuser system, you may wish to consider -running Mininet in a VM. + Although a single Mininet instance can simulate multiple networks + with multiple controllers, only one Mininet instance may currently + be run at a time, and Mininet requires root access in the machine + it's running on. Therefore, if you have a multiuser system, you + may wish to consider running Mininet in a VM. 2. Next-easiest option: use our Ubuntu package! -To install Mininet itself (i.e. mn and the Python API) on Ubuntu 12.10+ + To install Mininet itself (i.e. `mn` and the Python API) on Ubuntu + 12.10+: - sudo apt-get install mininet + sudo apt-get install mininet -Note: if you are upgrading from an older version of Mininet, make sure you -remove the old OVS from /usr/local: + Note: if you are upgrading from an older version of Mininet, make + sure you remove the old OVS from `/usr/local`: - sudo rm /usr/local/bin/ovs* - sudo rm /usr/local/sbin/ovs* + sudo rm /usr/local/bin/ovs* + sudo rm /usr/local/sbin/ovs* 3. Native installation from source on Ubuntu 11.10+ -If you're reading this, you've probably already done so, but the command to -download the Mininet source code is; - - git clone git://github.com/mininet/mininet.git + If you're reading this, you've probably already done so, but the + command to download the Mininet source code is; -If you are running Ubuntu, you may be able to use our handy install.sh script, -which is in mininet/util. + git clone git://github.com/mininet/mininet.git -WARNING: USE AT YOUR OWN RISK! + If you are running Ubuntu, you may be able to use our handy + `install.sh` script, which is in `mininet/util`. -install.sh is a bit intrusive and may possibly damage your OS and/or -home directory, by creating/modifying several directories such as -mininet, openflow, openvswitch and noxcore. Although we hope it won't -do anything completely terrible, you may want to look at the script -before you run it, and you should make sure your system and home -directory are backed up just in case! + *WARNING: USE AT YOUR OWN RISK!* -To install Mininet itself, the OpenFlow reference implementation, and -Open vSwitch, you may use: + `install.sh` is a bit intrusive and may possibly damage your OS + and/or home directory, by creating/modifying several directories + such as `mininet`, `openflow`, `oftest`, `pox`, or `noxcosre`. + Although we hope it won't do anything completely terrible, you may + want to look at the script before you run it, and you should make + sure your system and home directory are backed up just in case! -$ mininet/util/install.sh -fnv + To install Mininet itself, the OpenFlow reference implementation, and + Open vSwitch, you may use: -This should be reasonably quick and the following command should work -after the installation: + mininet/util/install.sh -fnv -$ sudo mn --test pingall + This should be reasonably quick, and the following command should + work after the installation: -To install ALL of the software which we use for OpenFlow tutorials, -including NOX classic, the OpenFlow WireShark dissector, the oftest -framework, and other potentially useful software (and to add some stuff -to /etc/sysctl.conf which may or may not be useful) you may use + sudo mn --test pingall -$ mininet/util/install.sh -a + To install ALL of the software which we use for OpenFlow tutorials, + including POX, the OpenFlow WireShark dissector, the `oftest` + framework, and other potentially useful software (and to add some + stuff to `/etc/sysctl.conf` which may or may not be useful) you may + use -This takes about 20 minutes on our test system. + mininet/util/install.sh -a + + This takes about 4 minutes on our test system. 4. Creating your own Mininet/OpenFlow tutorial VM -Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial -is easy! First, create a new Ubuntu VM. Then, run + Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial + is easy! First, create a new Ubuntu VM. Then, run -$ wget https://raw.github.com/mininet/mininet/util/vm/install-mininet-vm.sh -$ time install-mininet-vm.sh + wget https://raw.github.com/mininet/mininet/master/util/vm/install-mininet-vm.sh + time install-mininet-vm.sh 5. Installation on other Linux distributions -Although we don't support other Linux distributions directly, it should be -possible to install and run Mininet with some degree of manual effort. + Although we don't support other Linux distributions directly, it + should be possible to install and run Mininet with some degree of + manual effort. -In general, you must have: + In general, you must have: -* A Linux kernel compiled with network namespace support enabled + * A Linux kernel compiled with network namespace support enabled -* An OpenFlow implementation (either the reference user or kernel - space implementations, or Open vSwitch.) Appropriate kernel modules - (e.g. tun and ofdatapath for the reference kernel implementation) must - be loaded. + * An OpenFlow implementation (either the reference user or kernel + space implementations, or Open vSwitch.) Appropriate kernel + modules (e.g. tun and ofdatapath for the reference kernel + implementation) must be loaded. -* Python, `bash`, `ping`, `iperf`, etc. + * Python, `bash`, `ping`, `iperf`, etc.` -* Root privileges (required for network device access) + * Root privileges (required for network device access) + + We encourage contribution of patches to the `install.sh` script to + support other Linux distributions. -We encourage contribution of patches to the `install.sh` script to support -other Linux distributions. Good luck! Mininet Team --- - - - From 5879c492d84820a537ce4718aca195c3707e1912 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Sun, 2 Dec 2012 15:39:17 -0800 Subject: [PATCH 03/77] Minor clarifications. --- INSTALL | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/INSTALL b/INSTALL index 2e46569..d3e4695 100644 --- a/INSTALL +++ b/INSTALL @@ -45,7 +45,7 @@ like to contribute an installation script, we would welcome it!) 3. Native installation from source on Ubuntu 11.10+ If you're reading this, you've probably already done so, but the - command to download the Mininet source code is; + command to download the Mininet source code is: git clone git://github.com/mininet/mininet.git @@ -75,7 +75,7 @@ like to contribute an installation script, we would welcome it!) including POX, the OpenFlow WireShark dissector, the `oftest` framework, and other potentially useful software (and to add some stuff to `/etc/sysctl.conf` which may or may not be useful) you may - use + use: mininet/util/install.sh -a @@ -84,11 +84,15 @@ like to contribute an installation script, we would welcome it!) 4. Creating your own Mininet/OpenFlow tutorial VM Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial - is easy! First, create a new Ubuntu VM. Then, run + is easy! First, create a new Ubuntu VM. Next, run two commands in it: wget https://raw.github.com/mininet/mininet/master/util/vm/install-mininet-vm.sh time install-mininet-vm.sh + Finally, verify that Mininet is installed and working in the VM: + + sudo mn --test pingall + 5. Installation on other Linux distributions Although we don't support other Linux distributions directly, it From 0aefb0e0362fb886745e82b826942b3beb9e2e9b Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 19 Dec 2012 16:09:17 -0800 Subject: [PATCH 04/77] Fix Node.MAC(intf) to return intf.MAC() rather than intf.IP() Fixes #89 ; Thanks to Nikhil S. Menon for the bug report --- mininet/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/node.py b/mininet/node.py index 023c1e1..4779022 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -447,7 +447,7 @@ class Node( object ): def MAC( self, intf=None ): "Return MAC address of a node or specific interface." - return self.intf( intf ).IP() + return self.intf( intf ).MAC() def intfIsUp( self, intf=None ): "Check if an interface is up." From 8b8bb375982729a21a2f1c418e233ef361a789ae Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 28 Feb 2013 17:39:20 -0800 Subject: [PATCH 05/77] Remove unnecessary addHost() function, and clarify things a bit. Fixes #102 --- examples/controllers.py | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/examples/controllers.py b/examples/controllers.py index 6eeef0e..b7c417e 100755 --- a/examples/controllers.py +++ b/examples/controllers.py @@ -1,30 +1,24 @@ #!/usr/bin/python """ -This example creates a multi-controller network from -semi-scratch; note a topo object could also be used and -would be passed into the Mininet() constructor. +This example creates a multi-controller network from semi-scratch by +using the net.add*() API and manually starting the switches and controllers. + +Note that one could also create a custom switch class and pass it into +the Mininet() constructor. """ from mininet.net import Mininet -from mininet.node import Controller, OVSKernelSwitch +from mininet.node import Controller, OVSSwitch from mininet.cli import CLI from mininet.log import setLogLevel -Switch = OVSKernelSwitch - -def addHost( net, N ): - "Create host hN and add to net." - name = 'h%d' % N - ip = '10.0.0.%d' % N - return net.addHost( name, ip=ip ) - def multiControllerNet(): - "Create a network with multiple controllers." + "Create a network from semi-scratch with multiple controllers." - net = Mininet( controller=Controller, switch=Switch) + net = Mininet( controller=Controller, switch=OVSSwitch, build=False ) - print "*** Creating controllers" + print "*** Creating (reference) controllers" c1 = net.addController( 'c1', port=6633 ) c2 = net.addController( 'c2', port=6634 ) @@ -33,8 +27,8 @@ def multiControllerNet(): s2 = net.addSwitch( 's2' ) print "*** Creating hosts" - hosts1 = [ addHost( net, n ) for n in 3, 4 ] - hosts2 = [ addHost( net, n ) for n in 5, 6 ] + hosts1 = [ net.addHost( 'h%d' % n ) for n in 3, 4 ] + hosts2 = [ net.addHost( 'h%d' % n ) for n in 5, 6 ] print "*** Creating links" for h in hosts1: From 31e1ff71541aca2e494b2dabaf2ef39d9945943f Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 28 Feb 2013 17:55:41 -0800 Subject: [PATCH 06/77] Rename controllers.py to controllers2.py since it's less convenient. --- examples/{controllers.py => controllers2.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{controllers.py => controllers2.py} (100%) diff --git a/examples/controllers.py b/examples/controllers2.py similarity index 100% rename from examples/controllers.py rename to examples/controllers2.py From ad09c1e086ba349501999198252411d1aacdc957 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 28 Feb 2013 17:56:36 -0800 Subject: [PATCH 07/77] Add new example of making a custom Switch() class. --- examples/controllers.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 examples/controllers.py diff --git a/examples/controllers.py b/examples/controllers.py new file mode 100755 index 0000000..c26f436 --- /dev/null +++ b/examples/controllers.py @@ -0,0 +1,28 @@ +#!/usr/bin/python + +""" +Create a network where different switches are connected to +different controllers, by creating a custom Switch() subclass. +""" + +from mininet.net import Mininet +from mininet.node import OVSSwitch, Controller +from mininet.topolib import TreeTopo +from mininet.cli import CLI + +c0 = Controller( 'c0' ) +c1 = Controller( 'c1', ip='127.0.0.2' ) +cmap = { 's1': c0, 's2': c1, 's3': c1 } + +class MultiSwitch( OVSSwitch ): + "Custom Switch() subclass that connects to different controllers" + def start( self, controllers ): + return OVSSwitch.start( self, [ cmap[ self.name ] ] ) + +topo = TreeTopo( depth=2, fanout=2 ) +net = Mininet( topo=topo, switch=MultiSwitch, build=False ) +net.controllers = [ c0, c1 ] +net.build() +net.start() +CLI( net ) +net.stop() From f01813720751c6a601337b3559caaf219e1cb371 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 28 Feb 2013 17:59:14 -0800 Subject: [PATCH 08/77] Updated to reflect new controllers.py and old controllers2.py --- examples/README | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/README b/examples/README index dd71bea..80b46d4 100644 --- a/examples/README +++ b/examples/README @@ -19,7 +19,14 @@ graphical monitoring. controllers.py: -This example creates a network and adds multiple controllers to it. +This example creates a network with multiple controllers, by +using a custom Switch() subclass. + +controllers2.py: + +This example creates a network with multiple controllers by +creating an empty network, adding nodes to it, and manually +starting the switches. cpu.py: From 23c70f609d82ac280da282d5801e7acffc9b5db5 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 28 Feb 2013 19:14:37 -0800 Subject: [PATCH 09/77] Add px command which uses exec() vs. py's eval() This is necessary since exec() isn't really a function, and eval can't evaluate statements. fixes #104 --- mininet/cli.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/mininet/cli.py b/mininet/cli.py index efb1808..91f44e9 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -121,12 +121,12 @@ class CLI( Cmd ): "Run an external shell command" call( line, shell=True ) - # do_py() needs to catch any exception during eval() + # do_py() and do_px() need to catch any exception during eval()/exec() # pylint: disable-msg=W0703 def do_py( self, line ): """Evaluate a Python expression. - Node names may be used, e.g.: h1.cmd('ls')""" + Node names may be used, e.g.: py h1.cmd('ls')""" try: result = eval( line, globals(), self.locals ) if not result: @@ -138,7 +138,18 @@ class CLI( Cmd ): except Exception, e: output( str( e ) + '\n' ) - # pylint: enable-msg=W0703 + # We are in fact using the exec() pseudo-function + # pylint: disable-msg=W0122 + + def do_px( self, line ): + """Execute a Python statement. + Node names may be used, e.g.: px print h1.cmd('ls')""" + try: + exec( line, globals(), self.locals ) + except Exception, e: + output( str( e ) + '\n' ) + + # pylint: enable-msg=W0703,W0122 def do_pingall( self, _line ): "Ping between all hosts." From 9734d9d7fa4da3d92ee4b3ca08b2471fcca93fb0 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 6 Mar 2013 16:06:59 -0800 Subject: [PATCH 10/77] Add configuration to disable IPv6, since old method no longer works. fixes #108 --- util/sysctl_addon | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/util/sysctl_addon b/util/sysctl_addon index e26eecc..43b57f3 100644 --- a/util/sysctl_addon +++ b/util/sysctl_addon @@ -15,3 +15,8 @@ net.ipv4.neigh.default.gc_thresh3 = 16384 # Mininet: increase routing table size net.ipv4.route.max_size=32768 + +# Mininet: disable IPv6 +net.ipv6.conf.all.disable_ipv6 = 1 +net.ipv6.conf.default.disable_ipv6 = 1 +net.ipv6.conf.lo.disable_ipv6 = 1 From dcb3036b70f520d7cfcfdf2416feccc360322261 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 6 Mar 2013 16:55:47 -0800 Subject: [PATCH 11/77] Change to use addLink() interface for symmetry/consistency. --- examples/controllers2.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/controllers2.py b/examples/controllers2.py index b7c417e..0836533 100755 --- a/examples/controllers2.py +++ b/examples/controllers2.py @@ -4,6 +4,9 @@ This example creates a multi-controller network from semi-scratch by using the net.add*() API and manually starting the switches and controllers. +This is the "mid-level" API, which is an alternative to the "high-level" +Topo() API which supports parametrized topology classes. + Note that one could also create a custom switch class and pass it into the Mininet() constructor. """ @@ -32,10 +35,10 @@ def multiControllerNet(): print "*** Creating links" for h in hosts1: - s1.linkTo( h ) + net.addLink( s1, h ) for h in hosts2: - s2.linkTo( h ) - s1.linkTo( s2 ) + net.addLink( s2, h ) + net.addLink( s1, s2 ) print "*** Starting network" net.build() From 31fe4f1bd0f915d8f891974734bd9227d59d8af0 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 6 Mar 2013 17:26:52 -0800 Subject: [PATCH 12/77] Fix pmonitor() to not return blank lines on EOF fixes #109 (hopefully) --- mininet/util.py | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/mininet/util.py b/mininet/util.py index ff75b10..2461210 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -4,7 +4,7 @@ from mininet.log import output, info, error, warn from time import sleep from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE -from select import poll, POLLIN +from select import poll, POLLIN, POLLHUP from subprocess import call, check_call, Popen, PIPE, STDOUT import re from fcntl import fcntl, F_GETFL, F_SETFL @@ -326,27 +326,24 @@ def pmonitor(popens, timeoutms=500, readline=True, # Use non-blocking reads flags = fcntl( fd, F_GETFL ) fcntl( fd, F_SETFL, flags | O_NONBLOCK ) - while True: + while popens: fds = poller.poll( timeoutms ) if fds: - for fd, _event in fds: + for fd, event in fds: host = fdToHost[ fd ] popen = popens[ host ] - if readline: - # Attempt to read a line of output - # This blocks until we receive a newline! - line = popen.stdout.readline() - else: - line = popen.stdout.read( readmax ) - yield host, line + if event & POLLIN: + if readline: + # Attempt to read a line of output + # This blocks until we receive a newline! + line = popen.stdout.readline() + else: + line = popen.stdout.read( readmax ) + yield host, line # Check for EOF - if not line: - popen.poll() - if popen.returncode is not None: - poller.unregister( fd ) - del popens[ host ] - if not popens: - return + elif event & POLLHUP: + poller.unregister( fd ) + del popens[ host ] else: yield None, '' From bd558875f3653f757664631e04e14443733ed843 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Fri, 8 Mar 2013 16:56:44 -0800 Subject: [PATCH 13/77] Add net['h1'] and for node in net support thanks to Brian O'Connor for reminder + suggestion closes #114 --- mininet/net.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mininet/net.py b/mininet/net.py index b31a10c..161af5e 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -91,6 +91,7 @@ import re import select import signal from time import sleep +from itertools import chain from mininet.cli import CLI from mininet.log import info, error, debug, output @@ -216,8 +217,8 @@ class Mininet( object ): self.nameToNode[ name ] = controller_new return controller_new - # BL: is this better than just using nameToNode[] ? - # Should it have a better name? + # BL: We now have four ways to look up nodes + # This may (should?) be cleaned up in the future. def getNodeByName( self, *args ): "Return node(s) with given name(s)" if len( args ) == 1: @@ -228,6 +229,15 @@ class Mininet( object ): "Convenience alias for getNodeByName" return self.getNodeByName( *args ) + # Even more convenient syntax for node lookup and iteration + def __getitem__( self, *args ): + """net [ name ] operator: Return node(s) with given name(s)""" + return self.getNodeByName( *args ) + + def __iter__( self ): + "return iterator over nodes" + return chain( self.hosts, self.switches, self.controllers ) + def addLink( self, node1, node2, port1=None, port2=None, cls=None, **params ): """"Add a link from node1 to node2 From 8204a1b694ae945d24b88b46edf74b29eb0022e6 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 13 Mar 2013 16:16:20 -0700 Subject: [PATCH 14/77] fix --ipbase: fix ipAdd() and remove unused default from ipStr() --- mininet/util.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mininet/util.py b/mininet/util.py index 2461210..8ae96b5 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -242,9 +242,8 @@ def macColonHex( mac ): def ipStr( ip ): """Generate IP address string from an unsigned int. ip: unsigned int of form w << 24 | x << 16 | y << 8 | z - returns: ip address string w.x.y.z, or 10.x.y.z if w==0""" + returns: ip address string w.x.y.z""" w = ( ip >> 24 ) & 0xff - w = 10 if w == 0 else w x = ( ip >> 16 ) & 0xff y = ( ip >> 8 ) & 0xff z = ip & 0xff @@ -261,10 +260,10 @@ def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ): prefixLen: optional IP prefix length ipBaseNum: option base IP address as int returns IP address as string""" - # Ugly but functional - assert i < ( 1 << ( 32 - prefixLen ) ) - mask = 0xffffffff ^ ( ( 1 << prefixLen ) - 1 ) - ipnum = i + ( ipBaseNum & mask ) + imax = 0xffffffff >> prefixLen + assert i <= imax + mask = 0xffffffff ^ imax + ipnum = ( ipBaseNum & mask ) + i return ipStr( ipnum ) def ipParse( ip ): From 8838c30ea135df030a86628382358f0d02e04576 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 13 Mar 2013 16:18:04 -0700 Subject: [PATCH 15/77] Remove non-functional --prefixlen (use --ipbase instead) --- bin/mn | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bin/mn b/bin/mn index 0fb5bae..b0ad9e0 100755 --- a/bin/mn +++ b/bin/mn @@ -71,8 +71,7 @@ TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp', ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair', 'iperfudp': 'iperfUdp', - 'iperfUDP': 'iperfUdp', - 'prefixlen': 'prefixLen' } + 'iperfUDP': 'iperfUdp' } def addDictOption( opts, choicesDict, default, name, helpStr=None ): @@ -190,9 +189,6 @@ class MininetRunner( object ): help='CLI script to run before tests' ) opts.add_option( '--post', type='string', default=None, help='CLI script to run after tests' ) - opts.add_option( '--prefixlen', type='int', default=8, - help='prefix length (e.g. /8) for automatic ' - 'network configuration' ) opts.add_option( '--pin', action='store_true', default=False, help="pin hosts to CPU cores " "(requires --host cfs or --host rt)" ) From 356e9d8a929fce1f1405e6822d677b9caa7e7e6a Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 15 Mar 2013 10:38:57 +0900 Subject: [PATCH 16/77] tools/install.sh: update oftest Since oftest removed tools/munger directory, install.sh fails as follows > mininet/util/install.sh: line 399: cd: tools/mnuger: No such file or directory oftest change set > commit be8503a69d609d0aee844a91f3f5d66f4e2666c7 > Author: Rich Lane > Date: Tue Mar 12 10:16:33 2013 -0700 > > remove pylibopenflow tools Signed-off-by: Isaku Yamahata --- util/install.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/util/install.sh b/util/install.sh index 8bd7cac..ff32b2c 100755 --- a/util/install.sh +++ b/util/install.sh @@ -395,9 +395,6 @@ function oftest { # Install oftest: cd ~/ git clone git://github.com/floodlight/oftest - cd oftest - cd tools/munger - sudo make install } # Install cbench From eca5a151a46a27e021f5afc90193cc551d7a2484 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 21 Mar 2013 14:35:34 -0700 Subject: [PATCH 17/77] Fix usage message to note correct options and OS compatibility. closes #85 --- util/install.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/install.sh b/util/install.sh index ff32b2c..6e9ebc1 100755 --- a/util/install.sh +++ b/util/install.sh @@ -502,11 +502,11 @@ function vm_clean { } function usage { - printf 'Usage: %s [-acdfhkmntvxy]\n\n' $(basename $0) >&2 + printf 'Usage: %s [-abcdfhkmnprtvwx]\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 10.04, 11.10\n' >&2 - printf 'and Debian 5.0 (Lenny). If you run into trouble, try\n' >&2 + printf 'for Mininet. It should (hopefully) work on Ubuntu 11.10+\n' >&2 + printf 'If you run into trouble, try\n' >&2 printf 'installing one thing at a time, and looking at the \n' >&2 printf 'specific installation function in this script.\n\n' >&2 @@ -520,12 +520,12 @@ function usage { 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 + printf -- ' -p: install (P)OX OpenFlow Controller\n' >&2 printf -- ' -r: remove existing Open vSwitch packages\n' >&2 printf -- ' -t: install o(T)her stuff\n' >&2 printf -- ' -v: install open (V)switch\n' >&2 printf -- ' -w: install OpenFlow (w)ireshark dissector\n' >&2 printf -- ' -x: install NO(X) OpenFlow controller\n' >&2 - printf -- ' -y: install (A)ll packages\n' >&2 exit 2 } From 5b14cc2937855af09f07911c75ddde34c973e1b8 Mon Sep 17 00:00:00 2001 From: ederlf Date: Thu, 20 Dec 2012 14:17:56 -0200 Subject: [PATCH 18/77] Add options to install OpenFlow 1.3 switch and compatible NOX controller. Signed-off-by: Bob Lantz --- util/install.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/util/install.sh b/util/install.sh index 6e9ebc1..f6319d5 100755 --- a/util/install.sh +++ b/util/install.sh @@ -180,6 +180,37 @@ function of { cd ~ } +function of13 { + echo "Installing OpenFlow 1.3 soft switch implementation..." + cd ~/ + $install git-core autoconf automake autotools-dev pkg-config \ + make gcc g++ libtool libc6-dev cmake libpcap-dev libxerces-c2-dev \ + unzip libpcre3-dev flex bison libboost-dev + + if [ ! -d "ofsoftswitch13" ]; then + git clone https://github.com/CPqD/ofsoftswitch13.git + fi + + # Install netbee + wget -nc http://www.nbee.org/download/nbeesrc-12-05-16.zip + unzip nbeesrc-12-05-16.zip + cd ~/nbeesrc/src + cmake . + make + cd ~/ + cp nbeesrc/bin/libn*.so /usr/local/lib + ldconfig + cp -R nbeesrc/include/ /usr/ + + # Resume the install: + cd ~/ofsoftswitch13 + ./boot.sh + ./configure + make + sudo make install + cd ~ +} + function wireshark { echo "Installing Wireshark dissector..." @@ -378,6 +409,40 @@ function nox { #./nox_core -v -i ptcp: } +# Install NOX 1.3 with tutorial files +function nox13 { + echo "Installing NOX w/tutorial files..." + + # Install NOX deps: + $install autoconf automake g++ libtool python python-twisted \ + swig libssl-dev make + if [ "$DIST" = "Debian" ]; then + $install libboost1.35-dev + elif [ "$DIST" = "Ubuntu" ]; then + $install python-dev libboost-dev + $install libboost-filesystem-dev + $install libboost-test-dev + fi + + # Fetch NOX destiny + cd ~/ + git clone https://github.com/CPqD/nox13oflib.git + cd nox13oflib + + # Build + ./boot.sh + mkdir build + cd build + ../configure + make -j3 + #make check + + # To verify this install: + #cd ~/nox13oflib/build/src + #./nox_core -v -i ptcp: +} + + # "Install" POX function pox { echo "Installing POX into $HOME/pox..." @@ -534,18 +599,25 @@ if [ $# -eq 0 ] then all else - while getopts 'abcdfhkmnprtvwx' OPTION + while getopts 'abcdfghkmnoprtvwx' OPTION do case $OPTION in a) all;; b) cbench;; c) kernel_clean;; d) vm_clean;; - f) of;; + f) echo -n "OpenFlow version to install? [1.0 or 1.3]: " + read ver + case $ver in + 1.0) of;; + 1.3) of13;; + *) echo "Invalid option";; + esac;; h) usage;; k) kernel;; m) modprobe;; n) mn_deps;; + o) nox13;; p) pox;; r) remove_ovs;; t) other;; From 4b8b4b73e19e082326867e4f40a598a3f5696497 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 21 Mar 2013 16:44:44 -0700 Subject: [PATCH 19/77] Clean up options and fix of13 to use sudo for netbee --- util/install.sh | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/util/install.sh b/util/install.sh index f6319d5..1621c40 100755 --- a/util/install.sh +++ b/util/install.sh @@ -198,9 +198,9 @@ function of13 { cmake . make cd ~/ - cp nbeesrc/bin/libn*.so /usr/local/lib - ldconfig - cp -R nbeesrc/include/ /usr/ + sudo cp nbeesrc/bin/libn*.so /usr/local/lib + sudo ldconfig + sudo cp -R nbeesrc/include/ /usr/ # Resume the install: cd ~/ofsoftswitch13 @@ -409,7 +409,7 @@ function nox { #./nox_core -v -i ptcp: } -# Install NOX 1.3 with tutorial files +# Install NOX Classic/Zaku for OpenFlow 1.3 function nox13 { echo "Installing NOX w/tutorial files..." @@ -567,7 +567,7 @@ function vm_clean { } function usage { - printf 'Usage: %s [-abcdfhkmnprtvwx]\n\n' $(basename $0) >&2 + printf '\nUsage: %s [-abcdfhkmnprtvwx03]\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 @@ -590,40 +590,46 @@ function usage { printf -- ' -t: install o(T)her stuff\n' >&2 printf -- ' -v: install open (V)switch\n' >&2 printf -- ' -w: install OpenFlow (w)ireshark dissector\n' >&2 - printf -- ' -x: install NO(X) OpenFlow controller\n' >&2 - + printf -- ' -x: install NO(X) Classic OpenFlow controller\n' >&2 + printf -- ' -0: (default) -0[fx] installs OpenFlow 1.0 versions\n' >&2 + printf -- ' -3: -3[fx] installs OpenFlow 1.3 versions\n' >&2 exit 2 } +OF_VERSION=1.0 + if [ $# -eq 0 ] then all else - while getopts 'abcdfghkmnoprtvwx' OPTION + while getopts 'abcdfhkmnprtvwx03' OPTION do case $OPTION in a) all;; b) cbench;; c) kernel_clean;; d) vm_clean;; - f) echo -n "OpenFlow version to install? [1.0 or 1.3]: " - read ver - case $ver in + f) case $OF_VERSION in 1.0) of;; 1.3) of13;; - *) echo "Invalid option";; + *) echo "Invalid OpenFlow version $OF_VERSION";; esac;; h) usage;; k) kernel;; m) modprobe;; n) mn_deps;; - o) nox13;; p) pox;; r) remove_ovs;; t) other;; v) ovs;; w) wireshark;; - x) nox;; + x) case $OF_VERSION in + 1.0) nox;; + 1.3) nox13;; + *) echo "Invalid OpenFlow version $OF_VERSION";; + esac;; + 0) OF_VERSION=1.0;; + 3) OF_VERSION=1.3;; ?) usage;; esac done From a0f69d98dfc66e5c7c55ea7cf7aa8c12c9cb707e Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 20 Mar 2013 19:00:45 -0700 Subject: [PATCH 20/77] Change makeTerm() to tunnel X11 using socat if needed For local display, allow local root access For remote display, tunnel with socat/mnexec This should enable *wireshark in hosts* and fix #119 --- debian/control | 2 +- mininet/clean.py | 2 +- mininet/term.py | 70 +++++++++++++++++++++++++++--------------------- util/install.sh | 2 +- 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/debian/control b/debian/control index fb289dc..bde8bf2 100644 --- a/debian/control +++ b/debian/control @@ -22,7 +22,7 @@ Depends: ${misc:Depends}, ${python:Depends}, ${shlibs:Depends} -Recommends: iperf, openvswitch-controller +Recommends: iperf, openvswitch-controller, socat Description: Process-based network emulator Mininet is a network emulator which uses lightweight virtualization to create virtual networks for rapid diff --git a/mininet/clean.py b/mininet/clean.py index eac8fda..56ff6ff 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -36,7 +36,7 @@ def cleanup(): info( "*** Removing junk from /tmp\n" ) sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' ) - info( "*** Removing old screen sessions\n" ) + info( "*** Removing old X11 tunnels\n" ) cleanUpScreens() info( "*** Removing excess kernel datapaths\n" ) diff --git a/mininet/term.py b/mininet/term.py index 3cd70f2..46ba607 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -1,60 +1,68 @@ """ Terminal creation and cleanup. -Utility functions to run a term (connected via screen(1)) on each host. +Utility functions to run a terminal (connected via socat(1)) on each host. -Requires GNU screen(1) and xterm(1). +Requires socat(1) and xterm(1). Optionally uses gnome-terminal. """ -import re from subprocess import Popen +from os import environ from mininet.log import error -from mininet.util import quietRun +from mininet.util import quietRun, errRun -def quoteArg( arg ): - "Quote an argument if it contains spaces." - return repr( arg ) if ' ' in arg else arg +def tunnelX11( node, display=None): + """Create an X11 tunnel from node:6000 to the root host + display: display on root host (optional) + returns: node $DISPLAY, Popen object for tunnel""" + if display is None: + display = environ[ 'DISPLAY' ] + host, screen = display.split( ':' ) + # Unix sockets should work + if not host or host == 'unix': + # GDM3 doesn't put credentials in .Xauthority, + # so allow root to just connect + quietRun( 'xhost +si:localuser:root' ) + return display, None + else: + # Create a tunnel for the TCP connection + port = 6000 + int( float ( screen ) ) + connection = r'TCP\:%s\:%s' % ( host, port ) + cmd = [ "socat", "TCP-LISTEN:%d,fork,reuseaddr" % port, + "EXEC:'mnexec -a 1 socat STDIO %s'" % connection ] + return 'localhost:' + screen, node.popen( cmd ) -def makeTerm( node, title='Node', term='xterm' ): - """Run screen on a node, and hook up a terminal. +def makeTerm( node, title='Node', term='xterm', display=None ): + """Create an X11 tunnel to the node and start up a terminal. node: Node object title: base title term: 'xterm' or 'gterm' - returns: process created""" + returns: two Popen objects, tunnel and terminal""" title += ': ' + node.name if not node.inNamespace: title += ' (root)' cmds = { - 'xterm': [ 'xterm', '-title', title, '-e' ], - 'gterm': [ 'gnome-terminal', '--title', title, '-e' ] + 'xterm': [ 'xterm', '-title', title, '-display' ], + 'gterm': [ 'gnome-terminal', '--title', title, '--display' ] } if term not in cmds: error( 'invalid terminal type: %s' % term ) return - if not node.execed: - node.cmd( 'screen -dmS ' + 'mininet.' + node.name) - args = [ 'screen', '-D', '-RR', '-S', 'mininet.' + node.name ] - else: - args = [ 'sh', '-c', 'exec tail -f /tmp/' + node.name + '*.log' ] - if term == 'gterm': - # Compress these for gnome-terminal, which expects one token - # to follow the -e option - args = [ ' '.join( [ quoteArg( arg ) for arg in args ] ) ] - return Popen( cmds[ term ] + args ) + display, tunnel = tunnelX11( node, display ) + term = node.popen( cmds[ term ] + [ display ] ) + return [ tunnel, term ] if tunnel else [ term ] def cleanUpScreens(): - "Remove moldy old screen sessions." - r = r'(\d+\.mininet\.[hsc]\d+)' - output = quietRun( 'screen -ls' ).split( '\n' ) - for line in output: - m = re.search( r, line ) - if m: - quietRun( 'screen -S ' + m.group( 1 ) + ' -X quit' ) + "Remove moldy socat X11 tunnels." + errRun( "pkill -9 -f mnexec.*socat" ) def makeTerms( nodes, title='Node', term='xterm' ): """Create terminals. nodes: list of Node objects title: base title for each - returns: list of created terminal processes""" - return [ makeTerm( node, title, term ) for node in nodes ] + returns: list of created tunnel/terminal processes""" + terms = [] + for node in nodes: + terms += makeTerm( node, title, term ) + return terms diff --git a/util/install.sh b/util/install.sh index 1621c40..8f9eb56 100755 --- a/util/install.sh +++ b/util/install.sh @@ -122,7 +122,7 @@ function kernel_clean { # Install Mininet deps function mn_deps { echo "Installing Mininet dependencies" - $install gcc make screen psmisc xterm ssh iperf iproute telnet \ + $install gcc make socat psmisc xterm ssh iperf iproute telnet \ python-setuptools python-networkx cgroup-bin ethtool help2man \ pyflakes pylint pep8 From 1bf1a4d5e94600c67f22c814c899da7398d80d54 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Fri, 22 Mar 2013 18:33:37 -0700 Subject: [PATCH 21/77] Tag node bash processes and add attach script Try invoking bash processes with -s mininet:host, for easy identification of hosts. This enables easy attachment using the util/m script. closes #121 --- mininet/clean.py | 5 ++++- mininet/node.py | 3 ++- util/m | 30 ++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100755 util/m diff --git a/mininet/clean.py b/mininet/clean.py index 56ff6ff..07b4d6b 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -27,12 +27,15 @@ def cleanup(): info("*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes" "\n") zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core ' - zombies += 'ovs-openflowd udpbwtest' + zombies += 'ovs-openflowd udpbwtest mnexec' # 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. sh( 'killall -9 ' + zombies + ' 2> /dev/null' ) + # And kill off sudo mnexec + sh( 'pkill -9 -f "sudo mnexec"') + info( "*** Removing junk from /tmp\n" ) sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' ) diff --git a/mininet/node.py b/mininet/node.py index 4779022..6275f0c 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -118,7 +118,8 @@ class Node( object ): if self.inNamespace: opts += 'n' # bash -m: enable job control - cmd = [ 'mnexec', opts, 'bash', '-m' ] + # -s: pass $* to shell, and make process easy to find in ps + cmd = [ 'mnexec', opts, 'bash', '-ms', 'mininet:' + self.name ] self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True ) self.stdin = self.shell.stdin diff --git a/util/m b/util/m new file mode 100755 index 0000000..9757c2c --- /dev/null +++ b/util/m @@ -0,0 +1,30 @@ +#!/bin/bash + +# Attach to a Mininet host and run a command + +if [ -z $1 ]; then + echo "usage: $0 host cmd [args...]" + exit 1 +else + host=$1 +fi + +pid=`pgrep -f mininet:$host` +if [ "$pid" == "" ]; then + echo "Could not find Mininet host $host" + exit 2 +fi + +if [ -z $2 ]; then + cmd='bash' +else + shift + cmd=$* +fi + +cgroup=/sys/fs/cgroup/cpu/$host +if [ -d "$cgroup" ]; then + cg="-g $host" +fi + +exec sudo mnexec -a $pid $cg $cmd From 3482d941e11d3a8fda7802f62609d6059616a3c5 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Sun, 24 Mar 2013 14:48:20 -0700 Subject: [PATCH 22/77] Fix code check. --- mininet/term.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mininet/term.py b/mininet/term.py index 46ba607..2132d01 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -6,7 +6,6 @@ Requires socat(1) and xterm(1). Optionally uses gnome-terminal. """ -from subprocess import Popen from os import environ from mininet.log import error From 477e84adba03a389f877da25615f73201c48cf2f Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Sun, 24 Mar 2013 15:58:48 -0700 Subject: [PATCH 23/77] More code check nits. --- mininet/term.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mininet/term.py b/mininet/term.py index 2132d01..6d8704f 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -26,9 +26,9 @@ def tunnelX11( node, display=None): return display, None else: # Create a tunnel for the TCP connection - port = 6000 + int( float ( screen ) ) + port = 6000 + int( float( screen ) ) connection = r'TCP\:%s\:%s' % ( host, port ) - cmd = [ "socat", "TCP-LISTEN:%d,fork,reuseaddr" % port, + cmd = [ "socat", "TCP-LISTEN:%d,fork,reuseaddr" % port, "EXEC:'mnexec -a 1 socat STDIO %s'" % connection ] return 'localhost:' + screen, node.popen( cmd ) From c771b2d75aec973253674bc15fef6bdd3d11b5b4 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Sun, 24 Mar 2013 16:14:04 -0700 Subject: [PATCH 24/77] Add source node option to moveIntf() (note: low-level API!!) In the future we may wish to enable moving interfaces across nodes which are not in the root NS, and this would provide the low-level mechanism to do so. closes #122 --- mininet/util.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/mininet/util.py b/mininet/util.py index 8ae96b5..da55eaa 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -171,27 +171,35 @@ def retry( retries, delaySecs, fn, *args, **keywords ): error( "*** gave up after %i retries\n" % tries ) exit( 1 ) -def moveIntfNoRetry( intf, node, printError=False ): +def moveIntfNoRetry( intf, dstNode, srcNode=None, printError=False ): """Move interface to node, without retrying. intf: string, interface - node: Node object - printError: if true, print error""" - cmd = 'ip link set ' + intf + ' netns ' + repr( node.pid ) - quietRun( cmd ) - links = node.cmd( 'ip link show' ) + dstNode: destination Node + srcNode: source Node or None (default) for root ns + printError: if true, print error""" + intf = str( intf ) + cmd = 'ip link set %s netns %s' % ( intf, dstNode.pid ) + if srcNode: + srcNode.cmd( cmd ) + else: + quietRun( cmd ) + links = dstNode.cmd( 'ip link show' ) if not ( ' %s:' % intf ) in links: if printError: error( '*** Error: moveIntf: ' + intf + - ' not successfully moved to ' + node.name + '\n' ) + ' not successfully moved to ' + dstNode.name + '\n' ) return False return True -def moveIntf( intf, node, printError=False, retries=3, delaySecs=0.001 ): +def moveIntf( intf, dstNode, srcNode=None, printError=False, + retries=3, delaySecs=0.001 ): """Move interface to node, retrying on failure. intf: string, interface - node: Node object + dstNode: destination Node + srcNode: source Node or None (default) for root ns printError: if true, print error""" - retry( retries, delaySecs, moveIntfNoRetry, intf, node, printError ) + retry( retries, delaySecs, moveIntfNoRetry, intf, dstNode, + srcNode=srcNode, printError=printError ) # Support for dumping network From e5a15ced017f8a44f3f6298ffe2e12a6952fc8e9 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 28 Mar 2013 18:14:24 -0700 Subject: [PATCH 25/77] Change popen() to detach from terminal/process group. This may or may not be the right thing to do - an alternative would be to ignore SIGINT, but that would make the popen() job unkillable by normal means! So we'll try this and see how well it works. Fixes #124 --- mininet/node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 6275f0c..fc24ad2 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -291,7 +291,7 @@ class Node( object ): kwargs: Popen() keyword args""" defaults = { 'stdout': PIPE, 'stderr': PIPE, 'mncmd': - [ 'mnexec', '-a', str( self.pid ) ] } + [ 'mnexec', '-da', str( self.pid ) ] } defaults.update( kwargs ) if len( args ) == 1: if type( args[ 0 ] ) is list: @@ -605,7 +605,7 @@ class CPULimitedHost( Host ): args: Popen() args, single list, or string kwargs: Popen() keyword args""" # Tell mnexec to execute command in our cgroup - mncmd = [ 'mnexec', '-a', str( self.pid ), + mncmd = [ 'mnexec', '-da', str( self.pid ), '-g', self.name ] if self.sched == 'rt': mncmd += [ '-r', str( self.rtprio ) ] From e09254eea3552ceea6d8eedde17d6715144bc369 Mon Sep 17 00:00:00 2001 From: Andrew Ferguson Date: Wed, 29 Aug 2012 13:21:43 -0700 Subject: [PATCH 26/77] Adjust numbering to support tc-based switch QoS both the reference switch and Open vSwitch assume ids with major 1 can be used for tc-based QoS --- mininet/link.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/mininet/link.py b/mininet/link.py index 21e18ba..2f90d4e 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -196,36 +196,36 @@ class TCIntf( Intf ): # are specifying the correct sizes. For now I have used # the same settings we had in the mininet-hifi code. if use_hfsc: - cmds += [ '%s qdisc add dev %s root handle 1:0 hfsc default 1', - '%s class add dev %s parent 1:0 classid 1:1 hfsc sc ' + cmds += [ '%s qdisc add dev %s root handle 5:0 hfsc default 1', + '%s class add dev %s parent 5:0 classid 5:1 hfsc sc ' + 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ] elif use_tbf: if latency_ms is None: latency_ms = 15 * 8 / bw - cmds += [ '%s qdisc add dev %s root handle 1: tbf ' + + cmds += [ '%s qdisc add dev %s root handle 5: tbf ' + 'rate %fMbit burst 15000 latency %fms' % ( bw, latency_ms ) ] else: - cmds += [ '%s qdisc add dev %s root handle 1:0 htb default 1', - '%s class add dev %s parent 1:0 classid 1:1 htb ' + + cmds += [ '%s qdisc add dev %s root handle 5:0 htb default 1', + '%s class add dev %s parent 5:0 classid 5:1 htb ' + 'rate %fMbit burst 15k' % bw ] - parent = ' parent 1:1 ' + parent = ' parent 5:1 ' # ECN or RED if enable_ecn: cmds += [ '%s qdisc add dev %s' + parent + - 'handle 10: red limit 1000000 ' + + 'handle 6: red limit 1000000 ' + 'min 30000 max 35000 avpkt 1500 ' + 'burst 20 ' + 'bandwidth %fmbit probability 1 ecn' % bw ] - parent = ' parent 10: ' + parent = ' parent 6: ' elif enable_red: cmds += [ '%s qdisc add dev %s' + parent + - 'handle 10: red limit 1000000 ' + + 'handle 6: red limit 1000000 ' + 'min 30000 max 35000 avpkt 1500 ' + 'burst 20 ' + 'bandwidth %fmbit probability 1' % bw ] - parent = ' parent 10: ' + parent = ' parent 6: ' return cmds, parent @staticmethod @@ -251,7 +251,8 @@ class TCIntf( Intf ): cmds = [ '%s qdisc add dev %s ' + parent + ' handle 10: netem ' + netemargs ] - return cmds + parent = ' parent 10:1 ' + return cmds, parent def tc( self, cmd, tc='tc' ): "Execute tc command for our interface" @@ -289,9 +290,10 @@ class TCIntf( Intf ): cmds += bwcmds # Delay/jitter/loss/max_queue_size using netem - cmds += self.delayCmds( delay=delay, jitter=jitter, loss=loss, + delaycmds, parent = self.delayCmds( delay=delay, jitter=jitter, loss=loss, max_queue_size=max_queue_size, parent=parent ) + cmds += delaycmds # Ugly but functional: display configuration info stuff = ( ( [ '%.2fMbit' % bw ] if bw is not None else [] ) + @@ -308,6 +310,7 @@ class TCIntf( Intf ): debug( "cmds:", cmds, '\n' ) debug( "outputs:", tcoutputs, '\n' ) result[ 'tcoutputs'] = tcoutputs + result[ 'parent' ] = parent return result From 33c7e46492e7335396d5b47873c4db3eb1ae86cc Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 9 Apr 2013 19:36:02 -0700 Subject: [PATCH 27/77] Use __NR_setns so that setns has the right syscall # in 32-bit mode fixes #127 --- mnexec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mnexec.c b/mnexec.c index 42a9cf6..bd7b1b1 100644 --- a/mnexec.c +++ b/mnexec.c @@ -46,7 +46,7 @@ void usage(char *name) int setns(int fd, int nstype) { - return syscall(308, fd, nstype); + return syscall(__NR_setns, fd, nstype); } /* Validate alphanumeric path foo1/bar2/baz */ From 0f6bf4ce840eccbf47d1261593b1dc1fadea7e7e Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 9 Apr 2013 20:10:55 -0700 Subject: [PATCH 28/77] start xterm with TERM=ansi to preserve title from bash.bashrc fixes #128 --- mininet/term.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/term.py b/mininet/term.py index 6d8704f..c99a824 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -49,7 +49,7 @@ def makeTerm( node, title='Node', term='xterm', display=None ): error( 'invalid terminal type: %s' % term ) return display, tunnel = tunnelX11( node, display ) - term = node.popen( cmds[ term ] + [ display ] ) + term = node.popen( cmds[ term ] + [ display, '-e', 'env TERM=ansi bash'] ) return [ tunnel, term ] if tunnel else [ term ] def cleanUpScreens(): From c3f975aef8e84f009cafd1b43e3e9cf331cc2967 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 9 Apr 2013 22:46:49 -0700 Subject: [PATCH 29/77] Move IPv6 disable to 'other', and fix X11 forwarding should fix #128 --- util/install.sh | 50 ++++++++++++++++++++++++++++++----------------- util/sysctl_addon | 4 ---- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/util/install.sh b/util/install.sh index 8f9eb56..21c3976 100755 --- a/util/install.sh +++ b/util/install.sh @@ -133,8 +133,10 @@ function mn_deps { # Add sysctl parameters as noted in the INSTALL file to increase kernel # limits to support larger setups: - sudo su -c "cat $HOME/mininet/util/sysctl_addon >> /etc/sysctl.conf" - + if ! grep Mininet /etc/sysctl.conf; then + echo "Adding Mininet sysctl settings" + sudo su -c "cat $HOME/mininet/util/sysctl_addon >> /etc/sysctl.conf" + fi # Load new sysctl settings: sudo sysctl -p @@ -165,18 +167,6 @@ function of { ./configure make sudo make install - - # Remove avahi-daemon, which may cause unwanted discovery packets to be - # sent during tests, near link status changes: - $remove avahi-daemon - - # Disable IPv6. Add to /etc/modprobe.d/blacklist: - if [ "$DIST" = "Ubuntu" ]; then - BLACKLIST=/etc/modprobe.d/blacklist.conf - else - BLACKLIST=/etc/modprobe.d/blacklist - fi - sudo sh -c "echo 'blacklist net-pf-10\nblacklist ipv6' >> $BLACKLIST" cd ~ } @@ -214,7 +204,7 @@ function of13 { function wireshark { echo "Installing Wireshark dissector..." - sudo apt-get install -y wireshark libgtk2.0-dev + sudo apt-get install -y wireshark tshark libgtk2.0-dev if [ "$DIST" = "Ubuntu" ] && [ "$RELEASE" != "10.04" ]; then # Install newer version @@ -478,14 +468,38 @@ function cbench { } function other { - echo "Doing other setup tasks..." + echo "Doing other Mininet VM setup tasks..." + + # Remove avahi-daemon, which may cause unwanted discovery packets to be + # sent during tests, near link status changes: + echo "Removing avahi-daemon" + $remove avahi-daemon + + # was: Disable IPv6. Add to /etc/modprobe.d/blacklist: + #echo "Attempting to disable IPv6" + #if [ "$DIST" = "Ubuntu" ]; then + # BLACKLIST=/etc/modprobe.d/blacklist.conf + #else + # BLACKLIST=/etc/modprobe.d/blacklist + #fi + #sudo sh -c "echo 'blacklist net-pf-10\nblacklist ipv6' >> $BLACKLIST" + + # Disable IPv6 + if ! grep 'disable IPv6' /etc/sysctl.conf; then + echo 'Disabling IPv6' + echo ' +# Mininet: disable IPv6 +net.ipv6.conf.all.disable_ipv6 = 1 +net.ipv6.conf.default.disable_ipv6 = 1 +net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee /etc/sysctl.conf > /dev/null + fi # Enable command auto completion using sudo; modify ~/.bashrc: sed -i -e 's|# for examples$|&\ncomplete -cf sudo|' ~/.bashrc - # Install tcpdump and tshark, cmd-line packet dump tools. Also install gitk, + # Install tcpdump, cmd-line packet dump tool. Also install gitk, # a graphical git history viewer. - $install tcpdump tshark gitk + $install tcpdump gitk # Install common text editors $install vim nano emacs diff --git a/util/sysctl_addon b/util/sysctl_addon index 43b57f3..d413964 100644 --- a/util/sysctl_addon +++ b/util/sysctl_addon @@ -16,7 +16,3 @@ net.ipv4.neigh.default.gc_thresh3 = 16384 # Mininet: increase routing table size net.ipv4.route.max_size=32768 -# Mininet: disable IPv6 -net.ipv6.conf.all.disable_ipv6 = 1 -net.ipv6.conf.default.disable_ipv6 = 1 -net.ipv6.conf.lo.disable_ipv6 = 1 From 7bc10ebc7a9ac7f3f17f1cedbc5d55ea82a47e3e Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 9 Apr 2013 23:21:43 -0700 Subject: [PATCH 30/77] Fix X11 forwarding (broken by no IPv6) for real --- util/install.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/util/install.sh b/util/install.sh index 21c3976..255ca3c 100755 --- a/util/install.sh +++ b/util/install.sh @@ -491,7 +491,14 @@ function other { # Mininet: disable IPv6 net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 -net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee /etc/sysctl.conf > /dev/null +net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee -a /etc/sysctl.conf > /dev/null + fi + # Disabling IPv6 breaks X11 forwarding via ssh + line='AddressFamily inet' + file='/etc/ssh/sshd_config' + echo "Adding $line to $file" + if ! grep "$line" $file > /dev/null; then + echo "$line" | sudo tee -a $file > /dev/null fi # Enable command auto completion using sudo; modify ~/.bashrc: From 6c22e057cc45e9bda5c110815aeee12bfc7e2be5 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Fri, 12 Apr 2013 13:30:50 -0700 Subject: [PATCH 31/77] Avoid false matches and detect multiple host processes --- util/m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/util/m b/util/m index 9757c2c..002557e 100755 --- a/util/m +++ b/util/m @@ -9,10 +9,16 @@ else host=$1 fi -pid=`pgrep -f mininet:$host` +pid=`ps ax | grep mininet:$host | grep bash | awk '{print $1};'` + +if echo $pid | grep -q ' '; then + echo "Error: found multiple mininet:$host processes" + exit 2 +fi + if [ "$pid" == "" ]; then echo "Could not find Mininet host $host" - exit 2 + exit 3 fi if [ -z $2 ]; then From e7f45ca90e1cdc6fe324416c8d2415a38d9937b8 Mon Sep 17 00:00:00 2001 From: Andrew Ferguson Date: Thu, 25 Apr 2013 13:22:46 -0400 Subject: [PATCH 32/77] tiny fix to vm script --- util/vm/install-mininet-vm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 382945e..3c80a17 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -31,7 +31,7 @@ time mininet/util/install.sh #if ! grep NOX_CORE_DIR .bashrc; then # echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc #fi -echo < Date: Fri, 26 Apr 2013 13:11:39 -0400 Subject: [PATCH 33/77] actually, drop comment as per Bob Lantz --- util/vm/install-mininet-vm.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 3c80a17..bd970c0 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -31,10 +31,4 @@ time mininet/util/install.sh #if ! grep NOX_CORE_DIR .bashrc; then # echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc #fi -cat < Date: Mon, 29 Apr 2013 14:04:46 -0700 Subject: [PATCH 34/77] Change OVSSwitch.dpctl() to call ovs-ofctl This should fix the problem of dump-flows not showing the OpenFlow flow table flows and only showing cached kernel flow table flows. fixes #136 --- mininet/cli.py | 2 +- mininet/node.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mininet/cli.py b/mininet/cli.py index 91f44e9..59713cc 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -289,7 +289,7 @@ class CLI( Cmd ): self.inputFile = None def do_dpctl( self, line ): - "Run dpctl command on all switches." + "Run dpctl (or ovs-ofctl) command on all switches." args = line.split() if len(args) < 1: error( 'usage: dpctl command [arg1] [arg2] ...\n' ) diff --git a/mininet/node.py b/mininet/node.py index fc24ad2..8460b39 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -924,8 +924,8 @@ class OVSSwitch( Switch ): exit( 1 ) def dpctl( self, *args ): - "Run ovs-dpctl command" - return self.cmd( 'ovs-dpctl', args[ 0 ], self, *args[ 1: ] ) + "Run ovs-ofctl command" + return self.cmd( 'ovs-ofctl', args[ 0 ], self, *args[ 1: ] ) @staticmethod def TCReapply( intf ): From 76c5b9d0217290edd76a7cb3ee509f63c372bfc6 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 22 May 2013 15:03:48 -0700 Subject: [PATCH 35/77] Add ovs-controller to shutdown list --- mininet/clean.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/clean.py b/mininet/clean.py index 07b4d6b..66103bd 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 udpbwtest mnexec' + zombies += 'ovs-openflowd ovs-controller udpbwtest mnexec' # 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 1ea5c91fcc16e508721051b4840357ac1f28678c Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 22 May 2013 15:06:10 -0700 Subject: [PATCH 36/77] Update host's IP address during name-IP substitution fixes #139 --- mininet/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/cli.py b/mininet/cli.py index 59713cc..ea72f8d 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -321,7 +321,7 @@ class CLI( Cmd ): if first in self.nodemap: node = self.nodemap[ first ] # Substitute IP addresses for node names in command - rest = [ self.nodemap[ arg ].IP() + rest = [ self.nodemap[ arg ].defaultIntf().updateIP() if arg in self.nodemap else arg for arg in rest ] rest = ' '.join( rest ) From 65c35b659505f7deff4c1579bd0072be6676934d Mon Sep 17 00:00:00 2001 From: ryanc Date: Tue, 26 Feb 2013 21:12:33 -0800 Subject: [PATCH 37/77] Remove networkx dependency Conflicts: util/install.sh closes #100 --- debian/control | 4 +--- mininet/topo.py | 28 +++++++++++++++++++++++----- setup.py | 3 +-- util/install.sh | 7 +------ 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/debian/control b/debian/control index bde8bf2..e2297ae 100644 --- a/debian/control +++ b/debian/control @@ -9,15 +9,13 @@ Build-Depends: help2man, python-dev, python-pkg-resources, - python-setuptools, - python-networkx + python-setuptools Homepage: http://openflow.org/mininet Package: mininet Architecture: any Depends: openvswitch-switch, - python-networkx, telnet, ${misc:Depends}, ${python:Depends}, diff --git a/mininet/topo.py b/mininet/topo.py index fff9604..3ff0e8e 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -11,13 +11,31 @@ A Topo object can be a topology database for NOX, can represent a physical setup for testing, and can even be emulated with the Mininet package. ''' -# BL: we may have to fix compatibility here. -# networkx is also a fairly heavyweight dependency -# from networkx.classes.graph import Graph - -from networkx import Graph from mininet.util import irange, natural, naturalSeq +class Graph(object): + "Utility class to track nodes and edges " + + def __init__(self): + self.data = {} + + def add_node(self,node): + if node not in self.data.keys(): + self.data[node] = [] + + def add_edge(self,src,dest): + self.add_node(src) + self.add_node(dest) + self.data[src].append(dest) + + def nodes(self): + return self.data.keys() + + def edges(self): + for src in self.data.keys(): + for dest in self.data[src]: + yield (src,dest) + class Topo(object): "Data center network representation for structured multi-trees." diff --git a/setup.py b/setup.py index 3f9f0eb..9cee655 100644 --- a/setup.py +++ b/setup.py @@ -37,8 +37,7 @@ setup( keywords='networking emulator protocol Internet OpenFlow SDN', license='BSD', install_requires=[ - 'setuptools', - 'networkx' + 'setuptools' ], scripts=scripts, ) diff --git a/util/install.sh b/util/install.sh index 255ca3c..a1d0b1d 100755 --- a/util/install.sh +++ b/util/install.sh @@ -123,14 +123,9 @@ function kernel_clean { function mn_deps { echo "Installing Mininet dependencies" $install gcc make socat psmisc xterm ssh iperf iproute telnet \ - python-setuptools python-networkx cgroup-bin ethtool help2man \ + python-setuptools cgroup-bin ethtool help2man \ pyflakes pylint pep8 - if [ "$DIST" = "Ubuntu" ] && [ "$RELEASE" = "10.04" ]; then - echo "Upgrading networkx to avoid deprecation warning" - sudo easy_install --upgrade networkx - fi - # Add sysctl parameters as noted in the INSTALL file to increase kernel # limits to support larger setups: if ! grep Mininet /etc/sysctl.conf; then From 2485d57f662df251fb1c8c940a2faccc2ad637d5 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 22 May 2013 15:40:12 -0700 Subject: [PATCH 38/77] Edits to pass code check and make style consistent. --- mininet/link.py | 4 ++-- mininet/topo.py | 31 ++++++++++++++++++------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/mininet/link.py b/mininet/link.py index 2f90d4e..24028ac 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -290,8 +290,8 @@ class TCIntf( Intf ): cmds += bwcmds # Delay/jitter/loss/max_queue_size using netem - delaycmds, parent = self.delayCmds( delay=delay, jitter=jitter, loss=loss, - max_queue_size=max_queue_size, + delaycmds, parent = self.delayCmds( delay=delay, jitter=jitter, + loss=loss, max_queue_size=max_queue_size, parent=parent ) cmds += delaycmds diff --git a/mininet/topo.py b/mininet/topo.py index 3ff0e8e..cae1c04 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -13,28 +13,33 @@ setup for testing, and can even be emulated with the Mininet package. from mininet.util import irange, natural, naturalSeq -class Graph(object): - "Utility class to track nodes and edges " +class Graph( object ): + "Utility class to track nodes and edges - replaces networkx.Graph" - def __init__(self): + def __init__( self ): self.data = {} - def add_node(self,node): + def add_node( self, node ): + "Add node to graph" if node not in self.data.keys(): - self.data[node] = [] + self.data[ node ] = [] - def add_edge(self,src,dest): - self.add_node(src) - self.add_node(dest) - self.data[src].append(dest) + def add_edge( self, src, dest ): + "Add edge to graph" + self.add_node( src ) + self.add_node( dest ) + self.data[ src ].append( dest ) - def nodes(self): + def nodes( self ): + "Return list of graph nodes" return self.data.keys() - def edges(self): + def edges( self ): + "Iterator: return graph edges" for src in self.data.keys(): - for dest in self.data[src]: - yield (src,dest) + for dest in self.data[ src ]: + yield ( src, dest ) + class Topo(object): "Data center network representation for structured multi-trees." From 294bbad407c830ce858947712780875ba8972216 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 22 May 2013 18:03:09 -0700 Subject: [PATCH 39/77] Display usage information if there are extra arguments Fixes #130 --- bin/mn | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/mn b/bin/mn index b0ad9e0..bba2353 100755 --- a/bin/mn +++ b/bin/mn @@ -196,6 +196,11 @@ class MininetRunner( object ): self.options, self.args = opts.parse_args() + # We don't accept extra arguments after the options + if self.args: + opts.print_help() + exit() + def setup( self ): "Setup and validate environment." From e5754ae96ff798744fdf3c6be8a93ae987f9db76 Mon Sep 17 00:00:00 2001 From: Shaun Crampton Date: Thu, 23 May 2013 14:31:27 -0600 Subject: [PATCH 40/77] Fix method name mismatch for setDefaultRoute. --- mininet/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/node.py b/mininet/node.py index 8460b39..84464df 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -493,7 +493,7 @@ class Node( object ): r = {} self.setParam( r, 'setMAC', mac=mac ) self.setParam( r, 'setIP', ip=ip ) - self.setParam( r, 'defaultRoute', defaultRoute=defaultRoute ) + self.setParam( r, 'setDefaultRoute', defaultRoute=defaultRoute ) # This should be examined self.cmd( 'ifconfig lo ' + lo ) return r From e3d07bc1a0132feea8f356814ae4acbdea1d1d63 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 28 May 2013 22:10:27 -0700 Subject: [PATCH 41/77] Add 'x' command to open an X11 tunnel (and run a client) fixes #142 --- mininet/cli.py | 13 ++++++++++++- mininet/term.py | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mininet/cli.py b/mininet/cli.py index ea72f8d..a89051d 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -33,7 +33,7 @@ import sys import time from mininet.log import info, output, error -from mininet.term import makeTerms +from mininet.term import makeTerms, runX11 from mininet.util import quietRun, isShellBuiltin, dumpNodeConnections class CLI( Cmd ): @@ -241,6 +241,17 @@ class CLI( Cmd ): node = self.nodemap[ arg ] self.mn.terms += makeTerms( [ node ], term = term ) + def do_x( self, line ): + """Create an X11 tunnel to the given node, + optionally starting a client.""" + args = line.split() + if not args: + error( 'usage: x node [cmd args]...\n' ) + else: + node = self.mn[ args[ 0 ] ] + cmd = args[ 1: ] + self.mn.terms += runX11( node, cmd ) + def do_gterm( self, line ): "Spawn gnome-terminal(s) for the given node(s)." self.do_xterm( line, term='gterm' ) diff --git a/mininet/term.py b/mininet/term.py index c99a824..4c6370c 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -52,6 +52,12 @@ def makeTerm( node, title='Node', term='xterm', display=None ): term = node.popen( cmds[ term ] + [ display, '-e', 'env TERM=ansi bash'] ) return [ tunnel, term ] if tunnel else [ term ] +def runX11( node, cmd ): + "Run an X11 client on a node" + display, tunnel = tunnelX11( node ) + popen = node.popen( cmd ) + return [ tunnel, popen ] + def cleanUpScreens(): "Remove moldy socat X11 tunnels." errRun( "pkill -9 -f mnexec.*socat" ) From 5fae96eb6e1947ebd4b7f3c5a86ef2c86a8b1d6d Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Mon, 3 Jun 2013 15:37:56 -0700 Subject: [PATCH 42/77] Change to only split once so that cargs='--foo=1 --bar=2' works. fixes #144 --- mininet/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/util.py b/mininet/util.py index da55eaa..9cb1a53 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -423,7 +423,7 @@ def splitArgs( argstr ): args = [ makeNumeric( s ) for s in params if '=' not in s ] kwargs = {} for s in [ p for p in params if '=' in p ]: - key, val = s.split( '=' ) + key, val = s.split( '=', 1 ) kwargs[ key ] = makeNumeric( val ) return fn, args, kwargs From 2a079911b5189e8507597200bbd1ef3cd714e455 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Mon, 3 Jun 2013 17:10:12 -0700 Subject: [PATCH 43/77] Clarify controllers.py and add RemoteController --- examples/controllers.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/controllers.py b/examples/controllers.py index c26f436..ac86429 100755 --- a/examples/controllers.py +++ b/examples/controllers.py @@ -6,13 +6,20 @@ different controllers, by creating a custom Switch() subclass. """ from mininet.net import Mininet -from mininet.node import OVSSwitch, Controller +from mininet.node import OVSSwitch, Controller, RemoteController from mininet.topolib import TreeTopo +from mininet.log import setLogLevel from mininet.cli import CLI +setLogLevel( 'info' ) + +# Two local and one "external" controller (which is actually c0) +# Ignore the warning message that the remote isn't (yet) running c0 = Controller( 'c0' ) -c1 = Controller( 'c1', ip='127.0.0.2' ) -cmap = { 's1': c0, 's2': c1, 's3': c1 } +c1 = Controller( 'c1' ) +c2 = RemoteController( 'c2', ip='127.0.0.1' ) + +cmap = { 's1': c0, 's2': c1, 's3': c2 } class MultiSwitch( OVSSwitch ): "Custom Switch() subclass that connects to different controllers" From 3582facd342ae1375df16735aa23f063bd3393a8 Mon Sep 17 00:00:00 2001 From: Brandon Heller Date: Tue, 4 Jun 2013 22:58:43 -0700 Subject: [PATCH 44/77] install.sh: Use newer Netbee location for OF1.3 install The previous version (12-05-16) does not compile on Ubuntu 12.10. Also use a local variable to reduce duplication. --- util/install.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/util/install.sh b/util/install.sh index a1d0b1d..981928f 100755 --- a/util/install.sh +++ b/util/install.sh @@ -177,15 +177,16 @@ function of13 { fi # Install netbee - wget -nc http://www.nbee.org/download/nbeesrc-12-05-16.zip - unzip nbeesrc-12-05-16.zip - cd ~/nbeesrc/src + NBEESRC="nbeesrc-jan-10-2013" + wget -nc http://www.nbee.org/download/${NBEESRC}.zip + unzip ${NBEESRC}.zip + cd ${NBEESRC}/src cmake . make cd ~/ - sudo cp nbeesrc/bin/libn*.so /usr/local/lib + sudo cp ${NBEESRC}/bin/libn*.so /usr/local/lib sudo ldconfig - sudo cp -R nbeesrc/include/ /usr/ + sudo cp -R ${NBEESRC}/include/ /usr/ # Resume the install: cd ~/ofsoftswitch13 From 153d598df3f62f6dfe2514c02c1ab5834c185fa0 Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Thu, 6 Jun 2013 16:23:56 -0700 Subject: [PATCH 45/77] node: Allow OVSSwitch to run in userspace mode This adds a datapath parameter to OVSSwitch which allows one to tell OVS to run in userspace mode rather than kernel mode. From the commandline, this is --switch=ovsk,datapath=user. Note that this makes "ovsk" and the OVSKernelSwitch alias misnomers. Since the default behavior is still kernel mode, this is hopefully harmless. This is the second version of this patch, which changes the argument name and values according to Bob's suggestion. --- mininet/node.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 84464df..43f0d69 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -896,12 +896,14 @@ class OVSLegacyKernelSwitch( Switch ): class OVSSwitch( Switch ): "Open vSwitch switch. Depends on ovs-vsctl." - def __init__( self, name, failMode='secure', **params ): + def __init__( self, name, failMode='secure', datapath='kernel', **params ): """Init. name: name for switch - failMode: controller loss behavior (secure|open)""" + failMode: controller loss behavior (secure|open) + datapath: userspace or kernel mode (kernel|user)""" Switch.__init__( self, name, **params ) self.failMode = failMode + self.datapath = datapath @classmethod def setup( cls ): @@ -956,6 +958,8 @@ class OVSSwitch( Switch ): # Annoyingly, --if-exists option seems not to work self.cmd( 'ovs-vsctl del-br', self ) self.cmd( 'ovs-vsctl add-br', self ) + if self.datapath == 'user': + self.cmd( 'ovs-vsctl set bridge', self,'datapath_type=netdev' ) self.cmd( 'ovs-vsctl -- set Bridge', self, 'other_config:datapath-id=' + self.dpid ) self.cmd( 'ovs-vsctl set-fail-mode', self, self.failMode ) From 3df07feb118e41c3ec20696e7192fdd3d2bd7fba Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Thu, 6 Jun 2013 16:28:13 -0700 Subject: [PATCH 46/77] node: Make OVS switches reconnect quickly Ordinarily, OVS switches back off when they can't reach their controllers. Under the type of scenarios where Mininet is used, I think this is probably just inconvenient. This patch set controllers to attempt to reconnect every second. --- mininet/node.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mininet/node.py b/mininet/node.py index 84464df..ddacb3f 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -968,6 +968,19 @@ class OVSSwitch( Switch ): if self.listenPort: clist += ' ptcp:%s' % self.listenPort self.cmd( 'ovs-vsctl set-controller', self, clist ) + # Set controllers to reconnect quickly + controllers = self.cmd( 'ovs-vsctl --columns=controller find Bridge ' + 'name=' + str(self) ).split(':',2)[-1].strip() + + if controllers.startswith('[') and controllers.endswith(']'): + controllers = [c.strip() for c in controllers[1:-1].split(',')] + for uuid in controllers: + if uuid.count('-') != 4: + # Doesn't look like a UUID + continue + uuid = uuid.strip() + self.cmd( 'ovs-vsctl set Controller', uuid, + 'max_backoff=1000' ) def stop( self ): "Terminate OVS switch." From 3484389dcd86ca9569c1b4a5d101c18d63a1aa1b Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 12 Jun 2013 14:56:46 -0700 Subject: [PATCH 47/77] Add NAT script to examples. --- examples/README | 6 +++ examples/nat.py | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100755 examples/nat.py diff --git a/examples/README b/examples/README index 80b46d4..e4ca892 100644 --- a/examples/README +++ b/examples/README @@ -68,6 +68,12 @@ multitest.py: This example creates a network and runs multiple tests on it. +nat.py: + +This example shows how to connect a Mininet network to the Internet +using NAT. It also answers the eternal question "why can't I ping +google?" + popen.py: This example monitors a number of hosts using host.popen() and diff --git a/examples/nat.py b/examples/nat.py new file mode 100755 index 0000000..292d2a3 --- /dev/null +++ b/examples/nat.py @@ -0,0 +1,114 @@ +#!/usr/bin/python + +""" +Example to create a Mininet topology and connect it to the internet via NAT +through eth0 on the host. + +Glen Gibb, February 2011 + +(slight modifications by BL, 5/13) +""" + +from mininet.cli import CLI +from mininet.log import lg, info +from mininet.node import Node +from mininet.topolib import TreeNet +from mininet.util import quietRun + +################################# +def startNAT( root, inetIntf='eth0', subnet='10.0/8' ): + """Start NAT/forwarding between Mininet and external network + root: node to access iptables from + inetIntf: interface for internet access + subnet: Mininet subnet (default 10.0/8)=""" + + # Identify the interface connecting to the mininet network + localIntf = root.defaultIntf() + + # Flush any currently active rules + root.cmd( 'iptables -F' ) + root.cmd( 'iptables -t nat -F' ) + + # Create default entries for unmatched traffic + root.cmd( 'iptables -P INPUT ACCEPT' ) + root.cmd( 'iptables -P OUTPUT ACCEPT' ) + root.cmd( 'iptables -P FORWARD DROP' ) + + # Configure NAT + root.cmd( 'iptables -I FORWARD -i', localIntf, '-d', subnet, '-j DROP' ) + root.cmd( 'iptables -A FORWARD -i', localIntf, '-s', subnet, '-j ACCEPT' ) + root.cmd( 'iptables -A FORWARD -i', inetIntf, '-d', subnet, '-j ACCEPT' ) + root.cmd( 'iptables -t nat -A POSTROUTING -o ', inetIntf, '-j MASQUERADE' ) + + # Instruct the kernel to perform forwarding + root.cmd( 'sysctl net.ipv4.ip_forward=1' ) + +def stopNAT( root ): + """Stop NAT/forwarding between Mininet and external network""" + # Flush any currently active rules + root.cmd( 'iptables -F' ) + root.cmd( 'iptables -t nat -F' ) + + # Instruct the kernel to stop forwarding + root.cmd( 'sysctl net.ipv4.ip_forward=0' ) + +def fixNetworkManager( root, intf ): + """Prevent network-manager from messing with our interface, + by specifying manual configuration in /etc/network/interfaces + root: a node in the root namespace (for running commands) + intf: interface name""" + cfile = '/etc/network/interfaces' + line = '\niface %s inet manual\n' % intf + config = open( cfile ).read() + if ( line ) not in config: + print '*** Adding', line.strip(), 'to', cfile + with open( cfile, 'a' ) as f: + f.write( line ) + # Probably need to restart network-manager to be safe - + # hopefully this won't disconnect you + root.cmd( 'service network-manager restart' ) + +def connectToInternet( network, switch='s1', rootip='10.254', subnet='10.0/8'): + """Connect the network to the internet + switch: switch to connect to root namespace + rootip: address for interface in root namespace + subnet: Mininet subnet""" + switch = network.get( switch ) + prefixLen = subnet.split( '/' )[ 1 ] + routes = [ subnet ] # host networks to route to + + # Create a node in root namespace + root = Node( 'root', inNamespace=False ) + + # Prevent network-manager from interfering with our interface + fixNetworkManager( root, 'root-eth0' ) + + # Create link between root NS and switch + link = network.addLink( root, switch ) + link.intf1.setIP( rootip, prefixLen ) + + # Start network that now includes link to root namespace + network.start() + + # Start NAT and establish forwarding + startNAT( root ) + + # Establish routes from end hosts + for host in network.hosts: + host.cmd( 'ip route flush root 0/0' ) + host.cmd( 'route add -net', subnet, 'dev', host.defaultIntf() ) + host.cmd( 'route add default gw', rootip ) + + return root + +if __name__ == '__main__': + lg.setLogLevel( 'info') + net = TreeNet( depth=1, fanout=4 ) + # Configure and start NATted connectivity + rootnode = connectToInternet( net ) + print "*** Hosts are running and should have internet connectivity" + print "*** Type 'exit' or control-D to shut down network" + CLI( net ) + # Shut down NAT + stopNAT( rootnode ) + net.stop() From dd21df3ce4b356695dc339c792877ee19abf986c Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Mon, 17 Jun 2013 17:09:54 -0700 Subject: [PATCH 48/77] Don't flush ALL routes and enable OPTIONAL default route/gw fixes #152 hopefully --- mininet/net.py | 2 +- mininet/node.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/mininet/net.py b/mininet/net.py index 161af5e..d056843 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -260,7 +260,7 @@ class Mininet( object ): info( host.name + ' ' ) intf = host.defaultIntf() if intf: - host.configDefault( defaultRoute=intf ) + host.configDefault() else: # Don't configure nonexistent intf host.configDefault( ip=None, mac=None ) diff --git a/mininet/node.py b/mininet/node.py index 43f0d69..10bf547 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -418,11 +418,18 @@ class Node( object ): def setDefaultRoute( self, intf=None ): """Set the default route to go through intf. - intf: string, interface name""" - if not intf: - intf = self.defaultIntf() - self.cmd( 'ip route flush root 0/0' ) - return self.cmd( 'route add default %s' % intf ) + intf: Intf or {dev via ...}""" + # Note setParam won't call us if intf is none + # See if interface is an actual interface + intf = self.intf( intf ) + if intf in self.ports: + params = 'dev %s' % intf + elif type( intf ) is str: + params = intf + else: + raise ValueError( 'intf or param string required' ) + self.cmd( 'ip route del default' ) + return self.cmd( 'ip route add default dev %s' % intf ) # Convenience and configuration methods From 949e0b3afffb2259047aa66c69072ba68fd2ff56 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 19 Jun 2013 16:32:54 -0700 Subject: [PATCH 49/77] Separate VM finalization as install.sh -tc --- util/install.sh | 10 +++------- util/vm/install-mininet-vm.sh | 2 ++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/util/install.sh b/util/install.sh index 981928f..0c187f4 100755 --- a/util/install.sh +++ b/util/install.sh @@ -463,7 +463,7 @@ function cbench { sudo make install || true # make install fails; force past this } -function other { +function vm_other { echo "Doing other Mininet VM setup tasks..." # Remove avahi-daemon, which may cause unwanted discovery packets to be @@ -550,8 +550,6 @@ function all { pox oftest cbench - other - echo "Please reboot, then run ./mininet/util/install.sh -c to remove unneeded packages." echo "Enjoy Mininet!" } @@ -579,8 +577,6 @@ function vm_clean { git config --global user.name "None" git config --global user.email "None" - # Remove mininet install script - rm -f install-mininet.sh } function usage { @@ -604,7 +600,7 @@ function usage { printf -- ' -n: install mini(N)et dependencies + core files\n' >&2 printf -- ' -p: install (P)OX OpenFlow Controller\n' >&2 printf -- ' -r: remove existing Open vSwitch packages\n' >&2 - printf -- ' -t: install o(T)her stuff\n' >&2 + printf -- ' -t: complete o(T)her Mininet VM setup tasks\n' >&2 printf -- ' -v: install open (V)switch\n' >&2 printf -- ' -w: install OpenFlow (w)ireshark dissector\n' >&2 printf -- ' -x: install NO(X) Classic OpenFlow controller\n' >&2 @@ -637,7 +633,7 @@ else n) mn_deps;; p) pox;; r) remove_ovs;; - t) other;; + t) vm_other;; v) ovs;; w) wireshark;; x) case $OF_VERSION in diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index bd970c0..9cb3295 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -27,6 +27,8 @@ git clone git://github.com/mininet/mininet cd mininet cd time mininet/util/install.sh +# Finalize VM +time mininet/util/install.sh -tc # Ignoring this since NOX classic is deprecated #if ! grep NOX_CORE_DIR .bashrc; then # echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc From 8f113b48cc69b7203290dfcfafeb2bde9c45c292 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 19 Jun 2013 16:58:00 -0700 Subject: [PATCH 50/77] vm_cleanup: add apt-get autoremove, and zero disk blocks --- util/install.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/install.sh b/util/install.sh index 0c187f4..1908904 100755 --- a/util/install.sh +++ b/util/install.sh @@ -557,6 +557,7 @@ function all { function vm_clean { echo "Cleaning VM..." sudo apt-get clean + sudo apt-get autoremove sudo rm -rf /tmp/* sudo rm -rf openvswitch*.tar.gz @@ -577,6 +578,9 @@ function vm_clean { git config --global user.name "None" git config --global user.email "None" + echo "Zeroing out file blocks for efficient compaction" + time sudo cp /dev/zero /tmp/; sync ; sleep 1 ; sync ; sudo rm -f /tmp/zero + } function usage { From 5c5a1eae8adcfad79c648113d7dd758417f6a55f Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 19 Jun 2013 17:26:39 -0700 Subject: [PATCH 51/77] Use dd to zero out disk space (hopefully faster) --- util/install.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/util/install.sh b/util/install.sh index 1908904..cb39ef9 100755 --- a/util/install.sh +++ b/util/install.sh @@ -578,8 +578,11 @@ function vm_clean { git config --global user.name "None" git config --global user.email "None" - echo "Zeroing out file blocks for efficient compaction" - time sudo cp /dev/zero /tmp/; sync ; sleep 1 ; sync ; sudo rm -f /tmp/zero + # Note: you can shrink the .vmdk in vmware using + # vmware-vdiskmanager -k *.vmdk + echo "Zeroing out file blocks for efficient compaction..." + time sudo dd if=/dev/zero of=/tmp/zero bs=1M + sync ; sleep 1 ; sync ; sudo rm -f /tmp/zero } From 2de621cda015d9fba768b0d938e755d3bafd9252 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 19 Jun 2013 17:27:33 -0700 Subject: [PATCH 52/77] "file blocks" -> "disk blocks" --- util/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/install.sh b/util/install.sh index cb39ef9..eabc33d 100755 --- a/util/install.sh +++ b/util/install.sh @@ -580,7 +580,7 @@ function vm_clean { # Note: you can shrink the .vmdk in vmware using # vmware-vdiskmanager -k *.vmdk - echo "Zeroing out file blocks for efficient compaction..." + echo "Zeroing out disk blocks for efficient compaction..." time sudo dd if=/dev/zero of=/tmp/zero bs=1M sync ; sleep 1 ; sync ; sudo rm -f /tmp/zero From 40b13c28b81323058ea74162770e2687bc8fc837 Mon Sep 17 00:00:00 2001 From: Brandon Heller Date: Thu, 20 Jun 2013 15:57:23 -0700 Subject: [PATCH 53/77] install.sh: Make OF1.3 Netbee location cmd-line configurable If NBEEURL is defined when running install.sh, use that location. Enables use of a local mirror for netbee download. Thanks to David Erickson for the code. --- util/install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/install.sh b/util/install.sh index eabc33d..82f5014 100755 --- a/util/install.sh +++ b/util/install.sh @@ -178,7 +178,8 @@ function of13 { # Install netbee NBEESRC="nbeesrc-jan-10-2013" - wget -nc http://www.nbee.org/download/${NBEESRC}.zip + NBEEURL=${NBEEURL:-http://www.nbee.org/download/} + wget -nc ${NBEEURL}${NBEESRC}.zip unzip ${NBEESRC}.zip cd ${NBEESRC}/src cmake . From 4e1630e126a4e942d7836a8717d9af1798109f07 Mon Sep 17 00:00:00 2001 From: Brandon Heller Date: Thu, 20 Jun 2013 16:27:13 -0700 Subject: [PATCH 54/77] topo: add __getitem__ for Graph Commit 65c35b65 'Remove networkx dependency' broke this line from RipL: nodes = [n for n in self.g[name] if self.layer(n) == layer] To work around this, RipL code would have to be changed to something like this: nodes = [n for n in self.g.data[name] if self.layer(n) == layer] ...which would use an internal variable, data. It seems cleaner to add this one little feature from NetworkX Graph objects. --- mininet/topo.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mininet/topo.py b/mininet/topo.py index cae1c04..d09004c 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -40,6 +40,10 @@ class Graph( object ): for dest in self.data[ src ]: yield ( src, dest ) + def __getitem__( self, node ): + "Return link dict for the given node" + return self.data[node] + class Topo(object): "Data center network representation for structured multi-trees." From e5d7b3801df2769ef291cd17917b099f990edaa6 Mon Sep 17 00:00:00 2001 From: Brandon Heller Date: Thu, 20 Jun 2013 18:47:27 -0700 Subject: [PATCH 55/77] topo: make new minimal Graph object a Graph, not a DiGraph Fixes another Graph regression relative to NetworkX. RipL broke because the NetworkX Graph object that was used previously for topologies is an undirected graph: >>> import networkx as nx >>> g=nx.Graph() >>> g.add_edge(0,1) >>> g[1] {0: {}} >>> g[0] {1: {}} There is a separate DiGraph object in NetworkX for directed behavior. The minimal replacement previously implemented DiGraph behavior. >>> from mininet.topo import Graph >>> g2=Graph() >>> g2.add_edge(0,1) >>> g2[0] [1] >>> g2[1] [] This commit restores undirected graph behavior. --- mininet/topo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mininet/topo.py b/mininet/topo.py index d09004c..fa20e19 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -29,6 +29,7 @@ class Graph( object ): self.add_node( src ) self.add_node( dest ) self.data[ src ].append( dest ) + self.data[ dest ].append( src ) def nodes( self ): "Return list of graph nodes" From 226eae97cbb6212d4bc3de72ba4547a577ef12a5 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 24 Jun 2013 14:34:53 -0600 Subject: [PATCH 56/77] Add script completion message --- util/vm/install-mininet-vm.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 9cb3295..894c5b5 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -33,4 +33,5 @@ time mininet/util/install.sh -tc #if ! grep NOX_CORE_DIR .bashrc; then # echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc #fi +echo "Done preparing Mininet VM." From 400bbbac11c58b4a2630607855f9ca876207a67c Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 25 Jun 2013 01:04:45 -0600 Subject: [PATCH 57/77] Update archive for 13.04 --- util/vm/install-mininet-vm.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 894c5b5..3e55351 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -13,7 +13,8 @@ sudo sed -i -e 's/quiet splash/text/' /etc/default/grub sudo update-grub sudo sed -i -e 's/us.archive.ubuntu.com/mirrors.kernel.org/' \ /etc/apt/sources.list -sudo apt-get update +sudo sed -i -e 's/\/archive.ubuntu.com/\/mirrors.kernel.org/' \ + /etc/apt/sources.listsudo apt-get update # Clean up vmware easy install junk if present if [ -e /etc/issue.backup ]; then sudo mv /etc/issue.backup /etc/issue From 9aaf87c19b7d501c0b41925468cce0ac77add371 Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 25 Jun 2013 01:06:00 -0600 Subject: [PATCH 58/77] Fix typo. --- util/vm/install-mininet-vm.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 3e55351..91b8a49 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -14,7 +14,8 @@ sudo update-grub sudo sed -i -e 's/us.archive.ubuntu.com/mirrors.kernel.org/' \ /etc/apt/sources.list sudo sed -i -e 's/\/archive.ubuntu.com/\/mirrors.kernel.org/' \ - /etc/apt/sources.listsudo apt-get update + /etc/apt/sources.list +sudo apt-get update # Clean up vmware easy install junk if present if [ -e /etc/issue.backup ]; then sudo mv /etc/issue.backup /etc/issue From 12758046e18030f43f780e9b0220190de2283cd8 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 25 Jun 2013 12:51:08 -0700 Subject: [PATCH 59/77] Fix setDefaultRoute to work with passed parameters. --- mininet/node.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index c4efd3a..ca5d8b7 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -371,7 +371,7 @@ class Node( object ): """ if not intf: return self.defaultIntf() - elif type( intf) is str: + elif type( intf ) is str: return self.nameToIntf[ intf ] else: return intf @@ -420,16 +420,12 @@ class Node( object ): """Set the default route to go through intf. intf: Intf or {dev via ...}""" # Note setParam won't call us if intf is none - # See if interface is an actual interface - intf = self.intf( intf ) - if intf in self.ports: - params = 'dev %s' % intf - elif type( intf ) is str: + if type( intf ) is str and ' ' in intf: params = intf else: - raise ValueError( 'intf or param string required' ) + params = 'dev %s' % intf self.cmd( 'ip route del default' ) - return self.cmd( 'ip route add default dev %s' % intf ) + return self.cmd( 'ip route add default', params ) # Convenience and configuration methods From 307d60a0c8c541b13a0f0233b3189f48474d1f84 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 25 Jun 2013 16:35:26 -0700 Subject: [PATCH 60/77] Replace /etc/hostname entirely; clarify sources.list edit --- util/vm/install-mininet-vm.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 91b8a49..aa93de4 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -4,15 +4,17 @@ # a brand-new Ubuntu virtual machine, # to create a fully usable "tutorial" VM. set -e -echo `whoami` ALL=NOPASSWD: ALL | sudo tee -a /etc/sudoers +echo `whoami` ALL=NOPASSWD: ALL | sudo tee -a /etc/sudoers > /dev/null sudo sed -i -e 's/Default/#Default/' /etc/sudoers -sudo sed -i -e 's/ubuntu/mininet-vm/' /etc/hostname +echo mininet-vm | sudo tee /etc/hostname > /dev/null sudo sed -i -e 's/ubuntu/mininet-vm/g' /etc/hosts sudo hostname `cat /etc/hostname` sudo sed -i -e 's/quiet splash/text/' /etc/default/grub sudo update-grub +# 12.10 and earlier sudo sed -i -e 's/us.archive.ubuntu.com/mirrors.kernel.org/' \ /etc/apt/sources.list +# 13.04 and later sudo sed -i -e 's/\/archive.ubuntu.com/\/mirrors.kernel.org/' \ /etc/apt/sources.list sudo apt-get update From bdd43beaf315b210216334fc907d32e1a3e8ac76 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 25 Jun 2013 19:31:27 -0700 Subject: [PATCH 61/77] Clean up (and fix) OVSSwitch fast reconnect --- mininet/node.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index ca5d8b7..3308121 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -976,12 +976,12 @@ class OVSSwitch( Switch ): clist += ' ptcp:%s' % self.listenPort self.cmd( 'ovs-vsctl set-controller', self, clist ) # Set controllers to reconnect quickly - controllers = self.cmd( 'ovs-vsctl --columns=controller find Bridge ' - 'name=' + str(self) ).split(':',2)[-1].strip() - - if controllers.startswith('[') and controllers.endswith(']'): - controllers = [c.strip() for c in controllers[1:-1].split(',')] - for uuid in controllers: + controllers = self.cmd( 'ovs-vsctl -- get Bridge', self, + 'Controller' ).strip() + if controllers.startswith( '[' ) and controllers.endswith( ']' ): + controllers = controllers[ 1 : -1 ] + uuids = [ c.strip() for c in controllers.split( ',' ) ] + for uuid in uuids: if uuid.count('-') != 4: # Doesn't look like a UUID continue From 877e7efb5f085611e41b530e91ac53bb3c09bb74 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 25 Jun 2013 19:39:53 -0700 Subject: [PATCH 62/77] Minor comment change and text change. --- mininet/node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 3308121..0beb5bb 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -975,14 +975,14 @@ class OVSSwitch( Switch ): if self.listenPort: clist += ' ptcp:%s' % self.listenPort self.cmd( 'ovs-vsctl set-controller', self, clist ) - # Set controllers to reconnect quickly + # Reconnect quickly to controllers (1s vs. 15s max_backoff) controllers = self.cmd( 'ovs-vsctl -- get Bridge', self, 'Controller' ).strip() if controllers.startswith( '[' ) and controllers.endswith( ']' ): controllers = controllers[ 1 : -1 ] uuids = [ c.strip() for c in controllers.split( ',' ) ] for uuid in uuids: - if uuid.count('-') != 4: + if uuid.count( '-' ) != 4: # Doesn't look like a UUID continue uuid = uuid.strip() From 538a856c2f4a4fc1a9e4cf98e59fca57e524106a Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 25 Jun 2013 20:16:25 -0700 Subject: [PATCH 63/77] Add Switch.connected() and OVSSwitch.controllerUUIDs() --- mininet/node.py | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 0beb5bb..b323db6 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -49,6 +49,7 @@ import re import signal import select from subprocess import Popen, PIPE, STDOUT +from operator import or_ from mininet.log import info, error, warn, debug from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin, @@ -784,6 +785,10 @@ class Switch( Node ): error( '*** Error: %s has execed and cannot accept commands' % self.name ) + def connected( self ): + "Is the switch connected to a controller? (override this method)" + return False + def __repr__( self ): "More informative string representation" intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() ) @@ -819,6 +824,10 @@ class UserSwitch( Switch ): return self.cmd( 'dpctl ' + ' '.join( args ) + ' tcp:127.0.0.1:%i' % self.listenPort ) + def connected( self ): + "Is the switch connected to a controller?" + return 'remote.is-connected=true' in self.dpctl( 'status' ) + def start( self, controllers ): """Start OpenFlow reference user datapath. Log to /tmp/sN-{ofd,ofp}.log. @@ -950,6 +959,23 @@ class OVSSwitch( Switch ): "Disconnect a data port" self.cmd( 'ovs-vsctl del-port', self, intf ) + def controllerUUIDs( self ): + "Return ovsdb UUIDs for our controllers" + uuids = [] + controllers = self.cmd( 'ovs-vsctl -- get Bridge', self, + 'Controller' ).strip() + if controllers.startswith( '[' ) and controllers.endswith( ']' ): + controllers = controllers[ 1 : -1 ] + uuids = [ c.strip() for c in controllers.split( ',' ) ] + return uuids + + def connected( self ): + "Are we connected to at least one of our controllers?" + results = [ 'true' in self.cmd( 'ovs-vsctl -- get Controller', + uuid, 'is_connected' ) + for uuid in self.controllerUUIDs() ] + return reduce( or_, results, False ) + def start( self, controllers ): "Start up a new OVS OpenFlow switch using ovs-vsctl" if self.inNamespace: @@ -976,18 +1002,13 @@ class OVSSwitch( Switch ): clist += ' ptcp:%s' % self.listenPort self.cmd( 'ovs-vsctl set-controller', self, clist ) # Reconnect quickly to controllers (1s vs. 15s max_backoff) - controllers = self.cmd( 'ovs-vsctl -- get Bridge', self, - 'Controller' ).strip() - if controllers.startswith( '[' ) and controllers.endswith( ']' ): - controllers = controllers[ 1 : -1 ] - uuids = [ c.strip() for c in controllers.split( ',' ) ] - for uuid in uuids: - if uuid.count( '-' ) != 4: - # Doesn't look like a UUID - continue - uuid = uuid.strip() - self.cmd( 'ovs-vsctl set Controller', uuid, - 'max_backoff=1000' ) + for uuid in self.controllerUUIDs(): + if uuid.count( '-' ) != 4: + # Doesn't look like a UUID + continue + uuid = uuid.strip() + self.cmd( 'ovs-vsctl set Controller', uuid, + 'max_backoff=1000' ) def stop( self ): "Terminate OVS switch." From 33e39a2471d013e5c198884fa61d99bce372507b Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 25 Jun 2013 20:26:06 -0700 Subject: [PATCH 64/77] Fix some pylint messages. --- examples/nat.py | 4 +--- mininet/clean.py | 2 +- mininet/log.py | 18 ++++++++---------- mininet/node.py | 4 ++-- mininet/term.py | 2 +- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/examples/nat.py b/examples/nat.py index 292d2a3..fcad85c 100755 --- a/examples/nat.py +++ b/examples/nat.py @@ -10,10 +10,9 @@ Glen Gibb, February 2011 """ from mininet.cli import CLI -from mininet.log import lg, info +from mininet.log import lg from mininet.node import Node from mininet.topolib import TreeNet -from mininet.util import quietRun ################################# def startNAT( root, inetIntf='eth0', subnet='10.0/8' ): @@ -75,7 +74,6 @@ def connectToInternet( network, switch='s1', rootip='10.254', subnet='10.0/8'): subnet: Mininet subnet""" switch = network.get( switch ) prefixLen = subnet.split( '/' )[ 1 ] - routes = [ subnet ] # host networks to route to # Create a node in root namespace root = Node( 'root', inNamespace=False ) diff --git a/mininet/clean.py b/mininet/clean.py index 66103bd..c5ef1ab 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -55,7 +55,7 @@ def cleanup(): sh( 'ovs-vsctl del-br ' + dp ) info( "*** Removing all links of the pattern foo-ethX\n" ) - links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' ) + links = sh( r"ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' ) for link in links: if link != '': sh( "ip link del " + link ) diff --git a/mininet/log.py b/mininet/log.py index cd00821..a046f50 100644 --- a/mininet/log.py +++ b/mininet/log.py @@ -60,18 +60,16 @@ class Singleton( type ): See http://en.wikipedia.org/wiki/SingletonPattern#Python Intended to be used as a __metaclass_ param, as shown for the class - below. + below.""" - Changed cls first args to mcs to satisfy pylint.""" + def __init__( cls, name, bases, dict_ ): + super( Singleton, cls ).__init__( name, bases, dict_ ) + cls.instance = None - def __init__( mcs, name, bases, dict_ ): - super( Singleton, mcs ).__init__( name, bases, dict_ ) - mcs.instance = None - - def __call__( mcs, *args, **kw ): - if mcs.instance is None: - mcs.instance = super( Singleton, mcs ).__call__( *args, **kw ) - return mcs.instance + def __call__( cls, *args, **kw ): + if cls.instance is None: + cls.instance = super( Singleton, cls ).__call__( *args, **kw ) + return cls.instance class MininetLogger( Logger, object ): diff --git a/mininet/node.py b/mininet/node.py index b323db6..d6a66ba 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -759,7 +759,7 @@ class Switch( Node ): def defaultDpid( self ): "Derive dpid from switch name, s1 -> 1" try: - dpid = int( re.findall( '\d+', self.name )[ 0 ] ) + dpid = int( re.findall( r'\d+', self.name )[ 0 ] ) dpid = hex( dpid )[ 2: ] dpid = '0' * ( self.dpidLen - len( dpid ) ) + dpid return dpid @@ -787,7 +787,7 @@ class Switch( Node ): def connected( self ): "Is the switch connected to a controller? (override this method)" - return False + return False and self # satisfy pylint def __repr__( self ): "More informative string representation" diff --git a/mininet/term.py b/mininet/term.py index 4c6370c..5857fa8 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -54,7 +54,7 @@ def makeTerm( node, title='Node', term='xterm', display=None ): def runX11( node, cmd ): "Run an X11 client on a node" - display, tunnel = tunnelX11( node ) + _display, tunnel = tunnelX11( node ) popen = node.popen( cmd ) return [ tunnel, popen ] From 1a658054ab0b594e577cb59595a70b4817772f72 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 26 Jun 2013 05:00:30 -0700 Subject: [PATCH 65/77] Ensure dpid is a valid hex string in OVSSwitch --- mininet/node.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mininet/node.py b/mininet/node.py index d6a66ba..9656499 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -989,6 +989,7 @@ class OVSSwitch( Switch ): self.cmd( 'ovs-vsctl add-br', self ) if self.datapath == 'user': self.cmd( 'ovs-vsctl set bridge', self,'datapath_type=netdev' ) + int( self.dpid, 16 ) # DPID must be a hex string self.cmd( 'ovs-vsctl -- set Bridge', self, 'other_config:datapath-id=' + self.dpid ) self.cmd( 'ovs-vsctl set-fail-mode', self, self.failMode ) From 804c4bbfa6e7cf5e3d48f712fd2dbe3031f80fb0 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 26 Jun 2013 06:14:43 -0700 Subject: [PATCH 66/77] Workaround: add dpopts to UserSwitch Currently, slicing on the user switch breaks bandwidth limits. We don't yet have a good way of using both of them at the same time. I'm inclined to turn off slicing by default, but I have to think about it and also see if any one is using it... --- mininet/node.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 9656499..8e93af9 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -801,7 +801,7 @@ class UserSwitch( Switch ): dpidLen = 12 - def __init__( self, name, **kwargs ): + def __init__( self, name, dpopts='', **kwargs ): """Init. name: name for the switch""" Switch.__init__( self, name, **kwargs ) @@ -810,6 +810,7 @@ class UserSwitch( Switch ): '(openflow.org)' ) if self.listenPort: self.opts += ' --listen=ptcp:%i ' % self.listenPort + self.dpopts = dpopts @classmethod def setup( cls ): @@ -840,7 +841,8 @@ class UserSwitch( Switch ): self.cmd( 'ifconfig lo up' ) intfs = [ str( i ) for i in self.intfList() if not i.IP() ] self.cmd( 'ofdatapath -i ' + ','.join( intfs ) + - ' punix:/tmp/' + self.name + ' -d ' + self.dpid + + ' punix:/tmp/' + self.name + ' -d %s ' % self.dpid + + self.dpopts + ' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' ) self.cmd( 'ofprotocol unix:/tmp/' + self.name + ' ' + clist + From aa554d985dcc372fb047f23f293ee8b62719eb00 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Wed, 26 Jun 2013 06:21:59 -0700 Subject: [PATCH 67/77] Workaround: add default dpopts='--no-slicing' to UserSwitch This disables slicing by default but fixes bandwidth limits. Eventually we want to enable both to work together, but for now this enables one or the other depending on the dpopts setting. --- mininet/node.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 8e93af9..ccf9179 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -801,9 +801,10 @@ class UserSwitch( Switch ): dpidLen = 12 - def __init__( self, name, dpopts='', **kwargs ): + def __init__( self, name, dpopts='--no-slicing', **kwargs ): """Init. - name: name for the switch""" + name: name for the switch + dpopts: additional arguments to ofdatapath (--no-slicing)""" Switch.__init__( self, name, **kwargs ) pathCheck( 'ofdatapath', 'ofprotocol', moduleName='the OpenFlow reference user switch' + From 32502bbd1ae4dcd519f6c41266c7e7318a0c3bbc Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 4 Jul 2013 00:41:30 -0700 Subject: [PATCH 68/77] Add controlnet.py example. --- examples/README | 5 ++ examples/controlnet.py | 117 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100755 examples/controlnet.py diff --git a/examples/README b/examples/README index e4ca892..841486e 100644 --- a/examples/README +++ b/examples/README @@ -28,6 +28,11 @@ This example creates a network with multiple controllers by creating an empty network, adding nodes to it, and manually starting the switches. +controlnet.py: + +This examples shows how you can model the control network as well +as the data network, by actually creating two Mininet objects. + cpu.py: This example tests iperf bandwidth for varying CPU limits. diff --git a/examples/controlnet.py b/examples/controlnet.py new file mode 100755 index 0000000..d8b039b --- /dev/null +++ b/examples/controlnet.py @@ -0,0 +1,117 @@ +#!/usr/bin/python + +""" +controlnet.py: Mininet with a custom control network + +We create two Mininet() networks, a control network +and a data network, running four DataControllers on the +control network to control the data network. + +Since we're using UserSwitch on the data network, +it should correctly fail over to a backup controller. + +We also hack/subclass the CLI slightly so it can talk to +both the control and data networks. +""" + +from mininet.net import Mininet +from mininet.node import Controller, UserSwitch +from mininet.cli import CLI +from mininet.topo import Topo +from mininet.topolib import TreeTopo +from mininet.log import setLogLevel, info + +# Some minor hacks + +class DataController( Controller ): + """Data Network Controller. + patched to avoid checkListening error""" + def checkListening( self ): + "Ignore spurious error" + pass + + +class CLI2( CLI ): + "CLI that can talk to two networks" + + def __init__( self, *args, **kwargs ): + "cnet: second network" + self.cnet = kwargs.pop( 'cnet' ) + CLI.__init__( self, *args, **kwargs ) + + def updateVars( self ): + "Update variables to include cnet" + cnet = self.cnet + nodes2 = cnet.controllers + cnet.switches + cnet.hosts + self.nodelist += nodes2 + for node in nodes2: + self.nodemap[ node.name ] = node + self.locals[ 'cnet' ] = cnet + self.locals.update( self.nodemap ) + + def cmdloop( self, *args, **kwargs ): + "Patch to add cnet if needed" + if 'cnet' not in self.locals: + self.updateVars() + CLI.cmdloop( self, *args, **kwargs ) + + +# A real control network! + +class ControlNetwork( Topo ): + "Control Network Topology" + def __init__( self, n, dataController=DataController, **kwargs ): + """n: number of data network controller nodes + dataController: class for data network controllers""" + Topo.__init__( self, **kwargs ) + # Connect everything to a single switch + cs0 = self.addSwitch( 'cs0' ) + # Add hosts which will serve as data network controllers + for i in range( 0, n ): + c = self.addHost( 'c%s' % i, cls=dataController, + inNamespace=True ) + self.addLink( c, cs0 ) + # Connect switch to root namespace so that data network + # switches will be able to talk to us + root = self.addHost( 'root', inNamespace=False ) + self.addLink( root, cs0 ) + + +# Make it Happen!! + +setLogLevel( 'info' ) + +info( '* Creating Control Network\n' ) +ctopo = ControlNetwork( n=4, dataController=DataController ) +cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', build=False ) +info( '* Adding Control Network Controller\n') +cnet.addController( 'cc0' ) +info( '* Starting Control Network\n') +cnet.build() +cnet.start() +dataControllers = cnet.hosts[ : -1 ] # ignore 'root' node + +info( '* Creating Data Network\n' ) +topo = TreeTopo( depth=2, fanout=2 ) +# UserSwitch so we can easily test failover +net = Mininet( topo=topo, switch=UserSwitch, build=False ) +info( '* Adding Controllers to Data Network\n' ) +net.controllers = dataControllers +net.build() +info( '* Starting Data Network\n') +net.start() + +CLI2( net, cnet=cnet ) + +info( '* Stopping Data Network\n' ) +net.stop() + +info( '* Stopping Control Network\n' ) +net.hosts = [] # Avoid stopping controllers twice +cnet.stop() + + + + + + From fcdb6d8a54c627f02b2c6c676076c42d6a920809 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 4 Jul 2013 00:45:08 -0700 Subject: [PATCH 69/77] Remove unneeded line. --- examples/controlnet.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/controlnet.py b/examples/controlnet.py index d8b039b..3632460 100755 --- a/examples/controlnet.py +++ b/examples/controlnet.py @@ -107,7 +107,6 @@ info( '* Stopping Data Network\n' ) net.stop() info( '* Stopping Control Network\n' ) -net.hosts = [] # Avoid stopping controllers twice cnet.stop() From 10be691b86eba48fd7c730c4a52849c6a7b8843c Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Thu, 4 Jul 2013 19:27:57 -0700 Subject: [PATCH 70/77] Clean up intfs in root NS, and avoid deleting HW intfs It appears that under certain conditions, such as when a namespace exits, both ends of a veth pair may get dumped into the root namespace. We therefore now remove an interface both from its home namespace and from the root namespace. --- mininet/link.py | 7 ++++--- mininet/net.py | 10 +++++----- mininet/node.py | 19 +++++++++++-------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/mininet/link.py b/mininet/link.py index 24028ac..56bf3e6 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -25,7 +25,7 @@ Link: basic link class for creating veth pairs """ from mininet.log import info, error, debug -from mininet.util import makeIntfPair +from mininet.util import makeIntfPair, quietRun from time import sleep import re @@ -162,8 +162,9 @@ class Intf( object ): def delete( self ): "Delete interface" self.cmd( 'ip link del ' + self.name ) - # Does it help to sleep to let things run? - sleep( 0.001 ) + if self.node.inNamespace: + # Link may have been dumped into root NS + quietRun( 'ip link del ' + self.name ) def __repr__( self ): return '<%s %s>' % ( self.__class__.__name__, self.name ) diff --git a/mininet/net.py b/mininet/net.py index d056843..71c8ec0 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -372,16 +372,16 @@ class Mininet( object ): if self.terms: info( '*** Stopping %i terms\n' % len( self.terms ) ) self.stopXterms() - info( '*** Stopping %i hosts\n' % len( self.hosts ) ) - for host in self.hosts: - info( host.name + ' ' ) - host.terminate() - info( '\n' ) info( '*** Stopping %i switches\n' % len( self.switches ) ) for switch in self.switches: info( switch.name + ' ' ) switch.stop() info( '\n' ) + info( '*** Stopping %i hosts\n' % len( self.hosts ) ) + for host in self.hosts: + info( host.name + ' ' ) + host.terminate() + info( '\n' ) info( '*** Stopping %i controllers\n' % len( self.controllers ) ) for controller in self.controllers: info( controller.name + ' ' ) diff --git a/mininet/node.py b/mininet/node.py index ccf9179..ff87ca0 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -141,10 +141,10 @@ class Node( object ): def cleanup( self ): "Help python collect its garbage." - if not self.inNamespace: - for intfName in self.intfNames(): - if self.name in intfName: - quietRun( 'ip link del ' + intfName ) + # Intfs may end up in root NS + for intfName in self.intfNames(): + if self.name in intfName: + quietRun( 'ip link del ' + intfName ) self.shell = None # Subshell I/O, commands and control @@ -391,16 +391,19 @@ class Node( object ): connections += [ ( intf, link.intf1 ) ] return connections - def deleteIntfs( self ): - "Delete all of our interfaces." + def deleteIntfs( self, checkName=True ): + """Delete all of our interfaces. + checkName: only delete interfaces that contain our name""" # In theory the interfaces should go away after we shut down. # However, this takes time, so we're better off removing them # explicitly so that we won't get errors if we run before they # have been removed by the kernel. Unfortunately this is very slow, # at least with Linux kernels before 2.6.33 for intf in self.intfs.values(): - intf.delete() - info( '.' ) + # Protect against deleting hardware interfaces + if ( self.name in intf.name ) or ( not checkName ): + intf.delete() + info( '.' ) # Routing support From e2eb95a29f4134e0bab552398b08df518ea7aa23 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Sat, 6 Jul 2013 14:14:25 -0700 Subject: [PATCH 71/77] Add $ to avoid h1 matching h10 --- util/m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/m b/util/m index 002557e..786dcce 100755 --- a/util/m +++ b/util/m @@ -9,7 +9,7 @@ else host=$1 fi -pid=`ps ax | grep mininet:$host | grep bash | awk '{print $1};'` +pid=`ps ax | grep "mininet:$host$" | grep bash | awk '{print $1};'` if echo $pid | grep -q ' '; then echo "Error: found multiple mininet:$host processes" From 679a3f191504e31577dd94e89f1352484eaeb1b5 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Tue, 9 Jul 2013 14:34:37 -0700 Subject: [PATCH 72/77] Don't stop data network controllers twice. --- examples/controlnet.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/controlnet.py b/examples/controlnet.py index 3632460..3d5dd9d 100755 --- a/examples/controlnet.py +++ b/examples/controlnet.py @@ -107,6 +107,8 @@ info( '* Stopping Data Network\n' ) net.stop() info( '* Stopping Control Network\n' ) +# dataControllers have already been stopped +cnet.hosts = list( set( cnet.hosts ) - set( dataControllers ) ) cnet.stop() From 5c019d2aeff1ff561c0ad7c1cbf601b6d85e8673 Mon Sep 17 00:00:00 2001 From: Brian O'Connor Date: Tue, 9 Jul 2013 15:48:48 -0700 Subject: [PATCH 73/77] CPULimitedHost cleanup() calls superclass method fixes #161 --- mininet/node.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mininet/node.py b/mininet/node.py index ff87ca0..afc09b4 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -619,6 +619,7 @@ class CPULimitedHost( Host ): return Host.popen( self, *args, mncmd=mncmd, **kwargs ) def cleanup( self ): + super(CPULimitedHost, self).cleanup() "Clean up our cgroup" retry( retries=3, delaySecs=1, fn=self.cgroupDel ) From 59eeeadbacfa24fc546c25d9c48077a6421f7f78 Mon Sep 17 00:00:00 2001 From: Brian O'Connor Date: Tue, 9 Jul 2013 16:30:29 -0700 Subject: [PATCH 74/77] Style changes in mininet/node.py and removing used import in mininet/link.py --- mininet/link.py | 2 +- mininet/node.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mininet/link.py b/mininet/link.py index 56bf3e6..f7fea3d 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -26,7 +26,7 @@ Link: basic link class for creating veth pairs from mininet.log import info, error, debug from mininet.util import makeIntfPair, quietRun -from time import sleep +#from time import sleep import re class Intf( object ): diff --git a/mininet/node.py b/mininet/node.py index afc09b4..639bae2 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -619,8 +619,8 @@ class CPULimitedHost( Host ): return Host.popen( self, *args, mncmd=mncmd, **kwargs ) def cleanup( self ): - super(CPULimitedHost, self).cleanup() - "Clean up our cgroup" + "Clean up Node, then clean up our cgroup" + super( CPULimitedHost, self ).cleanup() retry( retries=3, delaySecs=1, fn=self.cgroupDel ) def chrt( self ): From 5d529edfb1dcf7ade8c1d6cd9a09f58b9d56a7db Mon Sep 17 00:00:00 2001 From: Brian O'Connor Date: Tue, 9 Jul 2013 16:34:02 -0700 Subject: [PATCH 75/77] Removing unused import in mininet/link.py --- mininet/link.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mininet/link.py b/mininet/link.py index f7fea3d..be73d52 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -26,7 +26,6 @@ Link: basic link class for creating veth pairs from mininet.log import info, error, debug from mininet.util import makeIntfPair, quietRun -#from time import sleep import re class Intf( object ): From adf391fdec0d14d5ff4451ead7f70a50ea8f5490 Mon Sep 17 00:00:00 2001 From: Brian O'Connor Date: Tue, 9 Jul 2013 19:23:29 -0700 Subject: [PATCH 76/77] Fixed install.sh script to allow Mininet to be installed from any directory (not just ~/) Fixes #94 --- util/install.sh | 74 ++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/util/install.sh b/util/install.sh index 82f5014..424d0ac 100755 --- a/util/install.sh +++ b/util/install.sh @@ -9,6 +9,18 @@ set -e # Fail on unset var usage set -o nounset +# Get directory containing mininet folder +MININET_DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )" + +# Set up build directory, which by default is the working directory +# unless the working directory is a subdirectory of mininet, +# in which case we use the directory containing mininet +BUILD_DIR=$PWD +case $PWD in + $MININET_DIR/*) BUILD_DIR=$MININET_DIR;; # currect directory is a subdirectory + *) BUILD_DIR=$PWD;; +esac + # Location of CONFIG_NET_NS-enabled kernel(s) KERNEL_LOC=http://www.openflow.org/downloads/mininet @@ -72,7 +84,7 @@ OVS_RELEASE=1.4.0 OVS_PACKAGE_LOC=https://github.com/downloads/mininet/mininet OVS_BUILDSUFFIX=-ignore # was -2 OVS_PACKAGE_NAME=ovs-$OVS_RELEASE-core-$DIST_LC-$RELEASE-$ARCH$OVS_BUILDSUFFIX.tar -OVS_SRC=~/openvswitch +OVS_SRC=$BUILD_DIR/openvswitch OVS_TAG=v$OVS_RELEASE OVS_BUILD=$OVS_SRC/build-$KERNEL_NAME OVS_KMODS=($OVS_BUILD/datapath/linux/{openvswitch_mod.ko,brcompat_mod.ko}) @@ -116,7 +128,7 @@ function kernel_clean { fi # Also remove downloaded packages: - rm -f ~/linux-headers-* ~/linux-image-* + rm -f $HOME/linux-headers-* $HOME/linux-image-* } # Install Mininet deps @@ -130,13 +142,13 @@ function mn_deps { # limits to support larger setups: if ! grep Mininet /etc/sysctl.conf; then echo "Adding Mininet sysctl settings" - sudo su -c "cat $HOME/mininet/util/sysctl_addon >> /etc/sysctl.conf" + sudo su -c "cat $MININET_DIR/mininet/util/sysctl_addon >> /etc/sysctl.conf" fi # Load new sysctl settings: sudo sysctl -p echo "Installing Mininet core" - pushd ~/mininet + pushd $MININET_DIR/mininet sudo make install popd } @@ -148,26 +160,26 @@ function mn_deps { # ... modified to use Debian Lenny rather than unstable. function of { echo "Installing OpenFlow reference implementation..." - cd ~/ + cd $BUILD_DIR/ $install git-core autoconf automake autotools-dev pkg-config \ make gcc libtool libc6-dev git clone git://openflowswitch.org/openflow.git - cd ~/openflow + cd $BUILD_DIR/openflow # Patch controller to handle more than 16 switches - patch -p1 < ~/mininet/util/openflow-patches/controller.patch + patch -p1 < $MININET_DIR/mininet/util/openflow-patches/controller.patch # Resume the install: ./boot.sh ./configure make sudo make install - cd ~ + cd $BUILD_DIR } function of13 { echo "Installing OpenFlow 1.3 soft switch implementation..." - cd ~/ + cd $BUILD_DIR/ $install git-core autoconf automake autotools-dev pkg-config \ make gcc g++ libtool libc6-dev cmake libpcap-dev libxerces-c2-dev \ unzip libpcre3-dev flex bison libboost-dev @@ -184,18 +196,18 @@ function of13 { cd ${NBEESRC}/src cmake . make - cd ~/ + cd $BUILD_DIR/ sudo cp ${NBEESRC}/bin/libn*.so /usr/local/lib sudo ldconfig sudo cp -R ${NBEESRC}/include/ /usr/ # Resume the install: - cd ~/ofsoftswitch13 + cd $BUILD_DIR/ofsoftswitch13 ./boot.sh ./configure make sudo make install - cd ~ + cd $BUILD_DIR } function wireshark { @@ -207,7 +219,7 @@ function wireshark { # Install newer version sudo apt-get install -y scons mercurial libglib2.0-dev sudo apt-get install -y libwiretap-dev libwireshark-dev - cd ~ + cd $BUILD_DIR hg clone https://bitbucket.org/barnstorm/of-dissector cd of-dissector/src export WIRESHARK=/usr/include/wireshark @@ -219,14 +231,14 @@ function wireshark { echo "Copied openflow plugin to $WSPLUGDIR" else # Install older version from reference source - cd ~/openflow/utilities/wireshark_dissectors/openflow + cd $BUILD_DIR/openflow/utilities/wireshark_dissectors/openflow make sudo make install fi # Copy coloring rules: OF is white-on-blue: - mkdir -p ~/.wireshark - cp ~/mininet/util/colorfilters ~/.wireshark + mkdir -p $HOME/.wireshark + cp $MININET_DIR/mininet/util/colorfilters $HOME/.wireshark } @@ -284,7 +296,7 @@ function ovs { if [ $ovspresent = 1 ]; then echo "Done (hopefully) installing packages" - cd ~ + cd $BUILD_DIR return fi @@ -307,7 +319,7 @@ function ovs { fi # Install OVS from release - cd ~/ + cd $BUILD_DIR/ git clone git://openvswitch.org/openvswitch $OVS_SRC cd $OVS_SRC git checkout $OVS_TAG @@ -366,7 +378,7 @@ function nox { $install libsqlite3-dev python-simplejson # Fetch NOX destiny - cd ~/ + cd $BUILD_DIR/ git clone https://github.com/noxrepo/nox-classic.git noxcore cd noxcore if ! git checkout -b destiny remotes/origin/destiny ; then @@ -375,9 +387,9 @@ function nox { # Apply patches git checkout -b tutorial-destiny - git am ~/mininet/util/nox-patches/*tutorial-port-nox-destiny*.patch + git am $MININET_DIR/mininet/util/nox-patches/*tutorial-port-nox-destiny*.patch if [ "$DIST" = "Ubuntu" ] && [ `expr $RELEASE '>=' 12.04` = 1 ]; then - git am ~/mininet/util/nox-patches/*nox-ubuntu12-hacks.patch + git am $MININET_DIR/mininet/util/nox-patches/*nox-ubuntu12-hacks.patch fi # Build @@ -389,7 +401,7 @@ function nox { #make check # Add NOX_CORE_DIR env var: - sed -i -e 's|# for examples$|&\nexport NOX_CORE_DIR=~/noxcore/build/src|' ~/.bashrc + sed -i -e 's|# for examples$|&\nexport NOX_CORE_DIR=$BUILD_DIR/noxcore/build/src|' ~/.bashrc # To verify this install: #cd ~/noxcore/build/src @@ -412,7 +424,7 @@ function nox13 { fi # Fetch NOX destiny - cd ~/ + cd $BUILD_DIR/ git clone https://github.com/CPqD/nox13oflib.git cd nox13oflib @@ -432,8 +444,8 @@ function nox13 { # "Install" POX function pox { - echo "Installing POX into $HOME/pox..." - cd ~ + echo "Installing POX into $BUILD_DIR/pox..." + cd $BUILD_DIR git clone https://github.com/noxrepo/pox.git } @@ -445,7 +457,7 @@ function oftest { $install tcpdump python-scapy # Install oftest: - cd ~/ + cd $BUILD_DIR/ git clone git://github.com/floodlight/oftest } @@ -454,12 +466,12 @@ function cbench { echo "Installing cbench..." $install libsnmp-dev libpcap-dev libconfig-dev - cd ~/ + cd $BUILD_DIR/ git clone git://openflow.org/oflops.git cd oflops sh boot.sh || true # possible error in autoreconf, so run twice sh boot.sh - ./configure --with-openflow-src-dir=$HOME/openflow + ./configure --with-openflow-src-dir=$BUILD_DIR/openflow make sudo make install || true # make install fails; force past this } @@ -614,6 +626,7 @@ function usage { printf -- ' -x: install NO(X) Classic OpenFlow controller\n' >&2 printf -- ' -0: (default) -0[fx] installs OpenFlow 1.0 versions\n' >&2 printf -- ' -3: -3[fx] installs OpenFlow 1.3 versions\n' >&2 + printf -- ' -i < directory >: sets the (I)nstallation directory for Mininet dependencies\n' >&2 exit 2 } @@ -623,7 +636,7 @@ if [ $# -eq 0 ] then all else - while getopts 'abcdfhkmnprtvwx03' OPTION + while getopts 'abcdfhkmnprtvwx03i:' OPTION do case $OPTION in a) all;; @@ -651,6 +664,9 @@ else esac;; 0) OF_VERSION=1.0;; 3) OF_VERSION=1.3;; + i) mkdir -p $OPTARG; # ensure the directory is created + BUILD_DIR="$( cd -P "$OPTARG" && pwd )"; # get the full path of the directory + echo "Dependency installation directory: $BUILD_DIR";; ?) usage;; esac done From c188bee3e389257fa13950039b877ea6c334c7d1 Mon Sep 17 00:00:00 2001 From: Brian O'Connor Date: Thu, 11 Jul 2013 11:17:46 -0700 Subject: [PATCH 77/77] Fixed divide by 0 error in ping command when no packets are sent fixes #143 --- mininet/net.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mininet/net.py b/mininet/net.py index 71c8ec0..db594c3 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -468,9 +468,13 @@ class Mininet( object ): lost += sent - received output( ( '%s ' % dest.name ) if received else 'X ' ) output( '\n' ) + if packets > 0: ploss = 100 * lost / packets - output( "*** Results: %i%% dropped (%d/%d lost)\n" % - ( ploss, lost, packets ) ) + output( "*** Results: %i%% dropped (%d/%d lost)\n" % + ( ploss, lost, packets ) ) + else: + ploss = 0 + output( "*** Warning: No packets sent\n" ) return ploss @staticmethod