diff --git a/examples/README.md b/examples/README.md index 4be55642493702d3562d32ab8f6e4a43e5359a28..96e30d75c6f7d69c062fee50bbd1080db4029cf3 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/numberedports.py b/examples/numberedports.py new file mode 100755 index 0000000000000000000000000000000000000000..82205506ca36416b292af72136a3a16a07104518 --- /dev/null +++ b/examples/numberedports.py @@ -0,0 +1,76 @@ +#!/usr/bin/python + +""" +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.log import setLogLevel, info, warn +from mininet.node import Node + +def validatePort( switch, intf ): + "Validate intf's OF port number" + ofport = int( switch.cmd( 'ovs-vsctl get Interface', intf, + 'ofport' ) ) + if ofport != switch.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' ) + # 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 ) # specify a different port to connect host 5 to on the switch. + + root = Node( 'root', inNamespace=False ) + info( '*** Starting network\n' ) + net.start() + + # 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": + 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' + + # test the network with pingall + net.pingAll() + print '\n' + + info( '*** Stopping network' ) + net.stop() + +if __name__ == '__main__': + setLogLevel( 'info' ) + net() + diff --git a/examples/test/test_numberedports.py b/examples/test/test_numberedports.py new file mode 100755 index 0000000000000000000000000000000000000000..b565d3ed79d6ea7f35e400c963f35e6a69c0dfa4 --- /dev/null +++ b/examples/test/test_numberedports.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +""" +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' ) + 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: + break + self.assertNotEqual( 0, count_intfs ) + +if __name__ == '__main__': + unittest.main() diff --git a/mininet/node.py b/mininet/node.py index 638433592662de023731fc0bf3ced09472f556fe..422ea15dcdeb352f08fb7c59c6d5956792d4aaf9 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -57,6 +57,8 @@ 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,13 @@ def setup( cls ): 'You may wish to try ' '"service openvswitch-switch start".\n' ) exit( 1 ) + info = quietRun( 'ovs-vsctl --version' ) + cls.OVSVersion = findall( '\d+\.\d+', info )[ 0 ] + + @classmethod + def isOldOVS( cls ): + return ( StrictVersion( cls.OVSVersion ) < + StrictVersion( '1.10' ) ) @classmethod def batchShutdown( cls, switches ): @@ -1046,19 +1055,32 @@ def start( self, controllers ): 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 ' % ( 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 ) if self.listenPort: clist += ' ptcp:%s' % self.listenPort - # Construct big ovs-vsctl command - cmd = ( 'ovs-vsctl add-br %s ' % self + - '-- set Bridge %s ' % self + + # Construct big ovs-vsctl command for new versions of OVS + if not self.isOldOVS(): + 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: + 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 ) ) if not self.inband: cmd += ( '-- set bridge %s ' 'other-config:disable-in-band=true ' % self ) @@ -1282,4 +1304,3 @@ def checkListening( self ): if 'Connected' not in listening: warn( "Unable to contact the remote controller" " at %s:%d\n" % ( self.ip, self.port ) ) -