From f1e42ba5fa8d5a34d95abcf7683577757b6dee67 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 28 May 2014 11:50:13 -0700 Subject: [PATCH 01/10] adding ovs version detection to fix port numbering bug --- mininet/node.py | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 27d1e16..4366362 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -57,6 +57,8 @@ from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin, numCores, retry, mountCgroups ) from mininet.moduledeps import moduleDeps, pathCheck, OVS_KMOD, OF_KMOD, TUN from mininet.link import Link, Intf, TCIntf +from re import findall +from distutils.version import StrictVersion class Node( object ): """A virtual network node is simply a shell in a network namespace. @@ -987,6 +989,15 @@ class OVSSwitch( Switch ): 'You may wish to try ' '"service openvswitch-switch start".\n' ) exit( 1 ) + info = quietRun( 'ovs-vsctl --version' ) + cls.OVSVersion = findall( '\d+\.\d+', info )[ 0 ] + if cls.isOldOVS(): + print "using old version of ovs so startup will be slower" + + @classmethod + def isOldOVS( cls ): + return ( StrictVersion( cls.OVSVersion ) < + StrictVersion( '1.10' ) ) @classmethod def batchShutdown( cls, switches ): @@ -1044,21 +1055,34 @@ class OVSSwitch( Switch ): self.cmd( 'ifconfig lo up' ) # Annoyingly, --if-exists option seems not to work self.cmd( 'ovs-vsctl del-br', self ) - int( self.dpid, 16 ) # DPID must be a hex string # Interfaces and controllers - intfs = ' '.join( '-- add-port %s %s ' % ( self, intf ) + intfs = ' '.join( '-- add-port %s %s -- set Interface %s ofport_request=%s ' % ( self, intf, intf, self.ports[intf] ) for intf in self.intfList() if not intf.IP() ) clist = ' '.join( '%s:%s:%d' % ( c.protocol, c.IP(), c.port ) for c in controllers ) if self.listenPort: clist += ' ptcp:%s' % self.listenPort - # Construct big ovs-vsctl command - cmd = ( 'ovs-vsctl add-br %s ' % self + - '-- set Bridge %s ' % self + + # configure old version ov ovs + if self.isOldOVS(): + self.cmd( 'ovs-vsctl add-br', self ) + for intf in self.intfList(): + if not intf.IP(): + self.cmd('ovs-vsctl add-port', self, intf) + cmd = ('ovs-vsctl set Bridge %s ' % self + 'other_config:datapath-id=%s ' % self.dpid + '-- set-fail-mode %s %s ' % ( self, self.failMode ) + - intfs + - '-- set-controller %s %s ' % (self, clist ) ) + '-- set-controller %s %s ' % (self, clist )) + + int( self.dpid, 16 ) # DPID must be a hex string + # Construct big ovs-vsctl command + if not self.isOldOVS(): + print "using a newer ovs version so startup will be faster" + cmd = ( 'ovs-vsctl add-br %s ' % self + + '-- set Bridge %s ' % self + + 'other_config:datapath-id=%s ' % self.dpid + + '-- set-fail-mode %s %s ' % ( self, self.failMode ) + + intfs + + '-- set-controller %s %s ' % (self, clist ) ) if not self.inband: cmd += ( '-- set bridge %s ' 'other-config:disable-in-band=true ' % self ) @@ -1274,4 +1298,3 @@ class RemoteController( Controller ): if 'Connected' not in listening: warn( "Unable to contact the remote controller" " at %s:%d\n" % ( self.ip, self.port ) ) - From ba43451bd637ac530e2118b9d0045dff74f0b633 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 28 May 2014 12:42:48 -0700 Subject: [PATCH 02/10] rearranged code for elegance --- mininet/node.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 4366362..0630aae 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -991,8 +991,6 @@ class OVSSwitch( Switch ): exit( 1 ) info = quietRun( 'ovs-vsctl --version' ) cls.OVSVersion = findall( '\d+\.\d+', info )[ 0 ] - if cls.isOldOVS(): - print "using old version of ovs so startup will be slower" @classmethod def isOldOVS( cls ): @@ -1055,6 +1053,7 @@ class OVSSwitch( Switch ): self.cmd( 'ifconfig lo up' ) # Annoyingly, --if-exists option seems not to work self.cmd( 'ovs-vsctl del-br', self ) + int( self.dpid, 16 ) # DPID must be a hex string # Interfaces and controllers intfs = ' '.join( '-- add-port %s %s -- set Interface %s ofport_request=%s ' % ( self, intf, intf, self.ports[intf] ) for intf in self.intfList() if not intf.IP() ) @@ -1062,8 +1061,18 @@ class OVSSwitch( Switch ): for c in controllers ) if self.listenPort: clist += ' ptcp:%s' % self.listenPort - # configure old version ov ovs - if self.isOldOVS(): + # Construct big ovs-vsctl command for new versions of OVS + if not self.isOldOVS(): + print "\nusing a newer ovs version" + cmd = ( 'ovs-vsctl add-br %s ' % self + + '-- set Bridge %s ' % self + + 'other_config:datapath-id=%s ' % self.dpid + + '-- set-fail-mode %s %s ' % ( self, self.failMode ) + + intfs + + '-- set-controller %s %s ' % (self, clist ) ) + # Construct ovs-vsctl commands for old versions of OVS + else: + print "\nusing an older ovs version" self.cmd( 'ovs-vsctl add-br', self ) for intf in self.intfList(): if not intf.IP(): @@ -1072,17 +1081,6 @@ class OVSSwitch( Switch ): 'other_config:datapath-id=%s ' % self.dpid + '-- set-fail-mode %s %s ' % ( self, self.failMode ) + '-- set-controller %s %s ' % (self, clist )) - - int( self.dpid, 16 ) # DPID must be a hex string - # Construct big ovs-vsctl command - if not self.isOldOVS(): - print "using a newer ovs version so startup will be faster" - cmd = ( 'ovs-vsctl add-br %s ' % self + - '-- set Bridge %s ' % self + - 'other_config:datapath-id=%s ' % self.dpid + - '-- set-fail-mode %s %s ' % ( self, self.failMode ) + - intfs + - '-- set-controller %s %s ' % (self, clist ) ) if not self.inband: cmd += ( '-- set bridge %s ' 'other-config:disable-in-band=true ' % self ) From 32d3c2bc7994aa7428ca06a33beedffaf1b0f70a Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 28 May 2014 12:56:24 -0700 Subject: [PATCH 03/10] removing debugging messages --- mininet/node.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 0630aae..02d16b8 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1063,7 +1063,6 @@ class OVSSwitch( Switch ): clist += ' ptcp:%s' % self.listenPort # Construct big ovs-vsctl command for new versions of OVS if not self.isOldOVS(): - print "\nusing a newer ovs version" cmd = ( 'ovs-vsctl add-br %s ' % self + '-- set Bridge %s ' % self + 'other_config:datapath-id=%s ' % self.dpid + @@ -1072,7 +1071,6 @@ class OVSSwitch( Switch ): '-- set-controller %s %s ' % (self, clist ) ) # Construct ovs-vsctl commands for old versions of OVS else: - print "\nusing an older ovs version" self.cmd( 'ovs-vsctl add-br', self ) for intf in self.intfList(): if not intf.IP(): From 4579b303e6dba3f6d21646f6bb36e761770cbf77 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 28 May 2014 13:46:55 -0700 Subject: [PATCH 04/10] conforming to mininet python style --- mininet/node.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 02d16b8..e5e8cb1 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1055,7 +1055,9 @@ class OVSSwitch( Switch ): self.cmd( 'ovs-vsctl del-br', self ) int( self.dpid, 16 ) # DPID must be a hex string # Interfaces and controllers - intfs = ' '.join( '-- add-port %s %s -- set Interface %s ofport_request=%s ' % ( self, intf, intf, self.ports[intf] ) + intfs = ' '.join( '-- add-port %s %s ' % ( self, intf ) + + '-- set Interface %s ' % intf + + 'ofport_request=%s ' % self.ports[ intf ] for intf in self.intfList() if not intf.IP() ) clist = ' '.join( '%s:%s:%d' % ( c.protocol, c.IP(), c.port ) for c in controllers ) @@ -1068,17 +1070,17 @@ class OVSSwitch( Switch ): 'other_config:datapath-id=%s ' % self.dpid + '-- set-fail-mode %s %s ' % ( self, self.failMode ) + intfs + - '-- set-controller %s %s ' % (self, clist ) ) + '-- set-controller %s %s ' % ( self, clist ) ) # Construct ovs-vsctl commands for old versions of OVS else: self.cmd( 'ovs-vsctl add-br', self ) for intf in self.intfList(): if not intf.IP(): - self.cmd('ovs-vsctl add-port', self, intf) + self.cmd('ovs-vsctl add-port', self, intf ) cmd = ('ovs-vsctl set Bridge %s ' % self + 'other_config:datapath-id=%s ' % self.dpid + '-- set-fail-mode %s %s ' % ( self, self.failMode ) + - '-- set-controller %s %s ' % (self, clist )) + '-- set-controller %s %s ' % ( self, clist ) ) if not self.inband: cmd += ( '-- set bridge %s ' 'other-config:disable-in-band=true ' % self ) From 586a9bb631a8499b02c64a2cb16824f7fa30f865 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 28 May 2014 17:46:19 -0700 Subject: [PATCH 05/10] adding example to test functionality of port numbering --- examples/numberedports.py | 75 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100755 examples/numberedports.py diff --git a/examples/numberedports.py b/examples/numberedports.py new file mode 100755 index 0000000..510fec1 --- /dev/null +++ b/examples/numberedports.py @@ -0,0 +1,75 @@ +#!/usr/bin/python + +""" +Create a network with 5 hosts, numbered 1-4 and 9. +""" + +from mininet.net import Mininet +from mininet.node import Controller +from mininet.cli import CLI +from mininet.log import setLogLevel, info +#from mininet.topo import Topo +from mininet.node import Node + +def validatePort( self, intf ): + "Validate intf's OF port number" + ofport = int( self.cmd( 'ovs-vsctl get Interface', intf, + 'ofport' ) ) + if ofport != self.ports[ intf ]: + warn( 'WARNING: ofport for', intf, 'is actually', ofport, + '\n' ) + return 0 + else: + return 1 + +def net(): + + "Create a network with 5 hosts." + + net = Mininet( controller=Controller ) + + info( '*** Adding controller\n' ) + net.addController( 'c0' ) + + info( '*** Adding hosts\n' ) + h1 = net.addHost( 'h1', ip='10.0.0.1' ) + h2 = net.addHost( 'h2', ip='10.0.0.2' ) + h3 = net.addHost( 'h3', ip='10.0.0.3' ) + h4 = net.addHost( 'h4', ip='10.0.0.4' ) + h5 = net.addHost( 'h5', ip='10.0.0.5' ) + + info( '*** Adding switch\n' ) + s1 = net.addSwitch( 's1' ) + + info( '*** Creating links\n' ) + net.addLink( h1, s1 ) + net.addLink( h2, s1 ) + net.addLink( h3, s1 ) + net.addLink( h4, s1 ) + net.addLink( h5, s1, port1 = 1, port2 = 9 ) + + root = Node( 'root', inNamespace=False ) + info( '*** Starting network\n' ) + net.start() + #info( s1.intfs, "\n" ) + # print the interfaces, their port numbers, and the port requests + info( '\n*** printing and validating the ports running on each interface\n' ) + for intfs in s1.intfList(): + if not intfs.name == "lo": + info( intfs, ': ', root.cmd( 'ovs-vsctl get Interface', intfs, 'ofport' ) ) + info ( 'Validating ', intfs, '... ' ) + if validatePort( s1, intfs ): + info( 'Validated.\n' ) + print '\n' + + #info( root.cmd( 'ovs-vsctl list interface | grep -A 2 s1 ' ) ) + net.pingAll() + print '\n' + + info( '*** Stopping network' ) + net.stop() + +if __name__ == '__main__': + setLogLevel( 'info' ) + net() + From 3641723193dee42661da528d9e3ab02dc23d47f5 Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 29 May 2014 11:11:12 -0700 Subject: [PATCH 06/10] explaining test --- examples/numberedports.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/numberedports.py b/examples/numberedports.py index 510fec1..6603b3b 100755 --- a/examples/numberedports.py +++ b/examples/numberedports.py @@ -2,13 +2,14 @@ """ Create a network with 5 hosts, numbered 1-4 and 9. +Validate that the port numbers match to the interface name, +and that the ovs ports match the mininet ports. """ from mininet.net import Mininet from mininet.node import Controller from mininet.cli import CLI from mininet.log import setLogLevel, info -#from mininet.topo import Topo from mininet.node import Node def validatePort( self, intf ): @@ -42,17 +43,18 @@ def net(): s1 = net.addSwitch( 's1' ) info( '*** Creating links\n' ) + # host 1-4 connect to ports 1-4 on the switch net.addLink( h1, s1 ) net.addLink( h2, s1 ) net.addLink( h3, s1 ) net.addLink( h4, s1 ) - net.addLink( h5, s1, port1 = 1, port2 = 9 ) + net.addLink( h5, s1, port1 = 1, port2 = 9 ) # specify a different port to connect host 5 to on the switch. root = Node( 'root', inNamespace=False ) info( '*** Starting network\n' ) net.start() - #info( s1.intfs, "\n" ) - # print the interfaces, their port numbers, and the port requests + + # print the interfaces and their port numbers info( '\n*** printing and validating the ports running on each interface\n' ) for intfs in s1.intfList(): if not intfs.name == "lo": @@ -62,7 +64,7 @@ def net(): info( 'Validated.\n' ) print '\n' - #info( root.cmd( 'ovs-vsctl list interface | grep -A 2 s1 ' ) ) + # test the network with pingall net.pingAll() print '\n' From 50f5080912cfb08154c74fcc8d2898d59f6d2cc8 Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 29 May 2014 11:52:56 -0700 Subject: [PATCH 07/10] corrected code --- examples/numberedports.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/numberedports.py b/examples/numberedports.py index 6603b3b..ba56998 100755 --- a/examples/numberedports.py +++ b/examples/numberedports.py @@ -8,17 +8,16 @@ and that the ovs ports match the mininet ports. from mininet.net import Mininet from mininet.node import Controller -from mininet.cli import CLI from mininet.log import setLogLevel, info from mininet.node import Node -def validatePort( self, intf ): +def validatePort( switch, intf ): "Validate intf's OF port number" - ofport = int( self.cmd( 'ovs-vsctl get Interface', intf, + ofport = int( switch.cmd( 'ovs-vsctl get Interface', intf, 'ofport' ) ) - if ofport != self.ports[ intf ]: + if ofport != switch.ports[ intf ]: warn( 'WARNING: ofport for', intf, 'is actually', ofport, - '\n' ) + '\n' ) return 0 else: return 1 @@ -58,8 +57,9 @@ def net(): info( '\n*** printing and validating the ports running on each interface\n' ) for intfs in s1.intfList(): if not intfs.name == "lo": - info( intfs, ': ', root.cmd( 'ovs-vsctl get Interface', intfs, 'ofport' ) ) - info ( 'Validating ', intfs, '... ' ) + info( intfs, ': ', s1.ports[intfs], + '\n' ) + info ( 'Validating that', intfs, 'is actually on port', s1.ports[intfs], '... ' ) if validatePort( s1, intfs ): info( 'Validated.\n' ) print '\n' From 87b6021428f7251209358b3102a528fd987e77ea Mon Sep 17 00:00:00 2001 From: Cody Date: Thu, 29 May 2014 17:26:40 -0700 Subject: [PATCH 08/10] restructured code and added a test for the numberedports.py example --- examples/README.md | 5 +++ examples/test/test_numberedports.py | 51 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100755 examples/test/test_numberedports.py diff --git a/examples/README.md b/examples/README.md index 4be5564..96e30d7 100644 --- a/examples/README.md +++ b/examples/README.md @@ -117,3 +117,8 @@ memory and `sysctl` configuration (see `INSTALL`.) This example creates a 64-host tree network, and attempts to check full connectivity using `ping`, for different switch/datapath types. + +#### numberedports.py + +This example verifies the mininet ofport numbers match up to the ovs port numbers. +It also verifies that the port numbers match up to the interface numbers diff --git a/examples/test/test_numberedports.py b/examples/test/test_numberedports.py new file mode 100755 index 0000000..f92e482 --- /dev/null +++ b/examples/test/test_numberedports.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +""" +Test for numberedports.py +""" + +import unittest +import pexpect +from collections import defaultdict + + +class testNumberedports( unittest.TestCase ): + + def testConsistency( self ): + """verify consistency between mininet and ovs ports""" + p = pexpect.spawn( 'python -m mininet.examples.numberedports' ) + opts = [ 'Validating that s1-eth\d is actually on port \d ... Validated.', + 'Validating that s1-eth\d is actually on port \d ... WARNING', + pexpect.EOF ] + correct_ports = True + count = 0 + while True: + index = p.expect( opts ) + if index == 0: + count += 1 + elif index == 1: + correct_ports = False + elif index == 2: + self.assertNotEqual( 0, count ) + break + self.assertTrue( correct_ports ) + + def testNumbering( self ): + """verify that all of the port numbers are printed correctly and consistent with their interface""" + p = pexpect.spawn( 'python -m mininet.examples.numberedports' ) + opts = [ 's1-eth(\d+) : (\d+)', + pexpect.EOF ] + count_intfs = 0 + while True: + index = p.expect( opts ) + if index == 0: + count_intfs += 1 + intfport = p.match.group( 1 ) + ofport = p.match.group( 2 ) + self.assertEqual( intfport, ofport ) + elif index == 1: + self.assertNotEqual( 0, count_intfs ) + break + +if __name__ == '__main__': + unittest.main() From de41192ea7dd1db8477e16326c8215b45952fbe7 Mon Sep 17 00:00:00 2001 From: Cody Burkard Date: Tue, 10 Jun 2014 21:50:40 -0700 Subject: [PATCH 09/10] imported warn from mininet.log --- examples/numberedports.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/numberedports.py b/examples/numberedports.py index ba56998..8220550 100755 --- a/examples/numberedports.py +++ b/examples/numberedports.py @@ -8,7 +8,7 @@ and that the ovs ports match the mininet ports. from mininet.net import Mininet from mininet.node import Controller -from mininet.log import setLogLevel, info +from mininet.log import setLogLevel, info, warn from mininet.node import Node def validatePort( switch, intf ): @@ -16,8 +16,7 @@ def validatePort( switch, intf ): ofport = int( switch.cmd( 'ovs-vsctl get Interface', intf, 'ofport' ) ) if ofport != switch.ports[ intf ]: - warn( 'WARNING: ofport for', intf, 'is actually', ofport, - '\n' ) + warn( 'WARNING: ofport for', intf, 'is actually', ofport, '\n' ) return 0 else: return 1 From 29e5bee34ea38028bae5afb3577f679afd7a793e Mon Sep 17 00:00:00 2001 From: Cody Burkard Date: Tue, 10 Jun 2014 22:15:49 -0700 Subject: [PATCH 10/10] fixed issue with AssertTrue and skip first test if using old OVS version --- examples/test/test_numberedports.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/test/test_numberedports.py b/examples/test/test_numberedports.py index f92e482..b565d3e 100755 --- a/examples/test/test_numberedports.py +++ b/examples/test/test_numberedports.py @@ -7,10 +7,11 @@ Test for numberedports.py import unittest import pexpect from collections import defaultdict - +from mininet.node import OVSSwitch class testNumberedports( unittest.TestCase ): + @unittest.skipIf( OVSSwitch.setup() or OVSSwitch.isOldOVS(), "old version of OVS" ) def testConsistency( self ): """verify consistency between mininet and ovs ports""" p = pexpect.spawn( 'python -m mininet.examples.numberedports' ) @@ -28,7 +29,7 @@ class testNumberedports( unittest.TestCase ): elif index == 2: self.assertNotEqual( 0, count ) break - self.assertTrue( correct_ports ) + self.assertTrue( correct_ports ) def testNumbering( self ): """verify that all of the port numbers are printed correctly and consistent with their interface""" @@ -44,8 +45,8 @@ class testNumberedports( unittest.TestCase ): ofport = p.match.group( 2 ) self.assertEqual( intfport, ofport ) elif index == 1: - self.assertNotEqual( 0, count_intfs ) break + self.assertNotEqual( 0, count_intfs ) if __name__ == '__main__': unittest.main()