From e8623fdc91b3b936b68812a9570487aaa2e7ff70 Mon Sep 17 00:00:00 2001 From: Tomasz Buchert Date: Wed, 13 Aug 2014 16:45:40 +0200 Subject: [PATCH 1/2] introducing OVSBridge --- bin/mn | 3 ++- mininet/node.py | 66 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/bin/mn b/bin/mn index edd4d98..e94515d 100755 --- a/bin/mn +++ b/bin/mn @@ -26,7 +26,7 @@ from mininet.log import lg, LEVELS, info, debug, error from mininet.net import Mininet, MininetWithControlNet, VERSION from mininet.node import ( Host, CPULimitedHost, Controller, OVSController, NOX, RemoteController, DefaultController, - UserSwitch, OVSSwitch, + UserSwitch, OVSBridge, OVSSwitch, OVSLegacyKernelSwitch, IVSSwitch ) from mininet.nodelib import LinuxBridge from mininet.link import Link, TCLink @@ -48,6 +48,7 @@ TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ), SWITCHDEF = 'ovsk' SWITCHES = { 'user': UserSwitch, 'ovs': OVSSwitch, + 'ovsb' : OVSBridge, # Keep ovsk for compatibility with 2.0 'ovsk': OVSSwitch, 'ovsl': OVSLegacyKernelSwitch, diff --git a/mininet/node.py b/mininet/node.py index d5b3036..a10abbf 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -996,20 +996,8 @@ class OVSLegacyKernelSwitch( Switch ): self.deleteIntfs() -class OVSSwitch( Switch ): - "Open vSwitch switch. Depends on ovs-vsctl." - - def __init__( self, name, failMode='secure', datapath='kernel', - inband=False, **params ): - """Init. - name: name for switch - failMode: controller loss behavior (secure|open) - datapath: userspace or kernel mode (kernel|user) - inband: use in-band control (False)""" - Switch.__init__( self, name, **params ) - self.failMode = failMode - self.datapath = datapath - self.inband = inband +class OVSSwitchBase( Switch ): + 'a base class for OVS switches; does not contain OpenFlow code at all' @classmethod def setup( cls ): @@ -1045,10 +1033,6 @@ class OVSSwitch( Switch ): ' -- '.join( '--if-exists del-br %s' % s for s in switches ) ) - def dpctl( self, *args ): - "Run ovs-ofctl command" - return self.cmd( 'ovs-ofctl', args[ 0 ], self, *args[ 1: ] ) - @staticmethod def TCReapply( intf ): """Unfortunately OVS and Mininet are fighting @@ -1067,6 +1051,52 @@ class OVSSwitch( Switch ): "Disconnect a data port" self.cmd( 'ovs-vsctl del-port', self, intf ) + +class OVSBridge( OVSSwitchBase ): + "OpenVSwitch Bridge (similar to OVSSwitch, but no OpenFlow)" + + def __init__( self, name, **kwargs ): + OVSSwitchBase.__init__( self, name, **kwargs ) + + def connected( self ): + return True + + def start( self, controllers ): + if self.inNamespace: + raise Exception( + 'OVS kernel switch does not work in a namespace' ) + self.cmd( 'ovs-vsctl del-br', self ) + intfs = ' '.join( '-- add-port %s %s ' % ( self, intf ) + for intf in self.intfList() if not intf.IP() ) + cmd = ( 'ovs-vsctl add-br %s ' % self + intfs ) + self.cmd( cmd ) + for intf in self.intfList(): + self.TCReapply( intf ) + + def stop( self ): + self.cmd( 'ovs-vsctl del-br', self ) + self.deleteIntfs() + + +class OVSSwitch( OVSSwitchBase ): + "Open vSwitch switch using OpenFlow controller. Depends on ovs-vsctl." + + def __init__( self, name, failMode='secure', datapath='kernel', + inband=False, **params ): + """Init. + name: name for switch + failMode: controller loss behavior (secure|open) + datapath: userspace or kernel mode (kernel|user) + inband: use in-band control (False)""" + OVSSwitchBase.__init__( self, name, **params ) + self.failMode = failMode + self.datapath = datapath + self.inband = inband + + def dpctl( self, *args ): + "Run ovs-ofctl command" + return self.cmd( 'ovs-ofctl', args[ 0 ], self, *args[ 1: ] ) + def controllerUUIDs( self ): "Return ovsdb UUIDs for our controllers" uuids = [] From 39a3b73f856f4df1a4d6064473ed4099cbeff895 Mon Sep 17 00:00:00 2001 From: Tomasz Buchert Date: Wed, 13 Aug 2014 16:51:41 +0200 Subject: [PATCH 2/2] fallback to ovsb when no OF controller is unavailable --- bin/mn | 16 ++++++++++++++-- mininet/node.py | 12 +++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/bin/mn b/bin/mn index e94515d..0263995 100755 --- a/bin/mn +++ b/bin/mn @@ -27,7 +27,8 @@ from mininet.net import Mininet, MininetWithControlNet, VERSION from mininet.node import ( Host, CPULimitedHost, Controller, OVSController, NOX, RemoteController, DefaultController, UserSwitch, OVSBridge, OVSSwitch, - OVSLegacyKernelSwitch, IVSSwitch ) + OVSLegacyKernelSwitch, IVSSwitch, + getAvailableController ) from mininet.nodelib import LinuxBridge from mininet.link import Link, TCLink from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo @@ -65,7 +66,7 @@ CONTROLLERS = { 'ref': Controller, 'ovsc': OVSController, 'nox': NOX, 'remote': RemoteController, - 'default': DefaultController, + 'default': None, 'none': lambda name: None } LINKDEF = 'default' @@ -230,6 +231,17 @@ class MininetRunner( object ): start = time.time() + if self.options.controller == "default": + controller_name = getAvailableController() + if controller_name is not None: + self.options.controller = controller_name + else: + # fallback to OVS Bridge switch, which does not use OF controller + info('*** No default OpenFlow implementation found!\n') + info(' Fallback to ovsb switch implementation.\n') + self.options.switch = 'ovsb' + self.options.controller = 'none' + topo = buildTopo( TOPOS, self.options.topo ) switch = customConstructor( SWITCHES, self.options.switch ) host = customConstructor( HOSTS, self.options.host ) diff --git a/mininet/node.py b/mininet/node.py index a10abbf..922b442 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1382,9 +1382,19 @@ class RemoteController( Controller ): warn( "Unable to contact the remote controller" " at %s:%d\n" % ( self.ip, self.port ) ) +DEFAULT_CONTROLLERS = [ ('ref', Controller), ('ovsc', OVSController) ] +DEFAULT_CONTROLLERS_CLASSES = [ klass for _, klass in DEFAULT_CONTROLLERS ] -def DefaultController( name, order=[ Controller, OVSController ], **kwargs ): +def getAvailableController(): + "find name of any default controller that is available; None if nothing is available" + for name, controller in DEFAULT_CONTROLLERS: + if controller.isAvailable(): + return name + return None + +def DefaultController( name, order = DEFAULT_CONTROLLERS_CLASSES, **kwargs ): "find any controller that is available and run it" for controller in order: if controller.isAvailable(): return controller( name, **kwargs ) + return None