Merge OVSBatch into OVSSwitch

Note that we are changing the interface of batchStartup/Shutdown
slightly so that the method can choose not to start some of the
switches. We might wish to refine this a bit...
This commit is contained in:
Bob Lantz
2015-01-26 18:01:20 -08:00
parent 574d634fc2
commit bdad3e8c8e
4 changed files with 86 additions and 82 deletions
+1 -2
View File
@@ -27,7 +27,7 @@ from mininet.net import Mininet, MininetWithControlNet, VERSION
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController, from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
RYU, NOX, RemoteController, findController, RYU, NOX, RemoteController, findController,
DefaultController, DefaultController,
UserSwitch, OVSSwitch, OVSBridge, OVSBatch, UserSwitch, OVSSwitch, OVSBridge,
OVSLegacyKernelSwitch, IVSSwitch ) OVSLegacyKernelSwitch, IVSSwitch )
from mininet.nodelib import LinuxBridge from mininet.nodelib import LinuxBridge
from mininet.link import Link, TCLink, OVSLink from mininet.link import Link, TCLink, OVSLink
@@ -62,7 +62,6 @@ SWITCHES = { 'user': UserSwitch,
# Keep ovsk for compatibility with 2.0 # Keep ovsk for compatibility with 2.0
'ovsk': OVSSwitch, 'ovsk': OVSSwitch,
'ovsl': OVSLegacyKernelSwitch, 'ovsl': OVSLegacyKernelSwitch,
'ovsbatch': OVSBatch, # experimental!!'
'ivs': IVSSwitch, 'ivs': IVSSwitch,
'lxbr': LinuxBridge, 'lxbr': LinuxBridge,
'default': OVSSwitch } 'default': OVSSwitch }
+11 -1
View File
@@ -280,6 +280,11 @@ class RemoteOVSSwitch( RemoteMixin, OVSSwitch ):
OVSVersions = {} OVSVersions = {}
def __init__( self, *args, **kwargs ):
# No batch startup yet
kwargs.update( batch=False )
super( RemoteOVSSwitch, self ).__init__( *args, **kwargs )
def isOldOVS( self ): def isOldOVS( self ):
"Is remote switch using an old OVS version?" "Is remote switch using an old OVS version?"
cls = type( self ) cls = type( self )
@@ -292,10 +297,15 @@ class RemoteOVSSwitch( RemoteMixin, OVSSwitch ):
return ( StrictVersion( cls.OVSVersions[ self.server ] ) < return ( StrictVersion( cls.OVSVersions[ self.server ] ) <
StrictVersion( '1.10' ) ) StrictVersion( '1.10' ) )
@classmethod
def batchStartup( cls, *_args, **_kwargs ):
"Not implemented yet"
return [] # no switches started
@classmethod @classmethod
def batchShutdown( cls, *_args, **_kwargs ): def batchShutdown( cls, *_args, **_kwargs ):
"Not implemented yet" "Not implemented yet"
return False return [] # no switchest stopped
class RemoteLink( Link ): class RemoteLink( Link ):
+8 -6
View File
@@ -485,9 +485,11 @@ class Mininet( object ):
for swclass, switches in groupby( for swclass, switches in groupby(
sorted( self.switches, key=type ), type ): sorted( self.switches, key=type ), type ):
switches = tuple( switches ) switches = tuple( switches )
if ( hasattr( swclass, 'batchStartup' ) and if hasattr( swclass, 'batchStartup' ):
swclass.batchStartup( switches ) ): print "STARTING", switches
started.update( { s: s for s in switches } ) success = swclass.batchStartup( switches )
print "STARTED", success
started.update( { s: s for s in success } )
info( '\n' ) info( '\n' )
if self.waitConn: if self.waitConn:
self.waitConnected() self.waitConnected()
@@ -512,9 +514,9 @@ class Mininet( object ):
for swclass, switches in groupby( for swclass, switches in groupby(
sorted( self.switches, key=type ), type ): sorted( self.switches, key=type ), type ):
switches = tuple( switches ) switches = tuple( switches )
if ( hasattr( swclass, 'batchShutdown' ) and if hasattr( swclass, 'batchShutdown' ):
swclass.batchShutdown( switches ) ): success = swclass.batchShutdown( switches )
stopped.update( { s: s for s in switches } ) stopped.update( { s: s for s in success } )
for switch in self.switches: for switch in self.switches:
info( switch.name + ' ' ) info( switch.name + ' ' )
if switch not in stopped: if switch not in stopped:
+66 -73
View File
@@ -1059,7 +1059,7 @@ class OVSSwitch( Switch ):
def __init__( self, name, failMode='secure', datapath='kernel', def __init__( self, name, failMode='secure', datapath='kernel',
inband=False, protocols=None, inband=False, protocols=None,
reconnectms=1000, stp=False, **params ): reconnectms=1000, stp=False, batch=True, **params ):
"""name: name for switch """name: name for switch
failMode: controller loss behavior (secure|open) failMode: controller loss behavior (secure|open)
datapath: userspace or kernel mode (kernel|user) datapath: userspace or kernel mode (kernel|user)
@@ -1067,7 +1067,8 @@ class OVSSwitch( Switch ):
protocols: use specific OpenFlow version(s) (e.g. OpenFlow13) protocols: use specific OpenFlow version(s) (e.g. OpenFlow13)
Unspecified (or old OVS version) uses OVS default Unspecified (or old OVS version) uses OVS default
reconnectms: max reconnect timeout in ms (0/None for default) reconnectms: max reconnect timeout in ms (0/None for default)
stp: enable STP (False, requires failMode=standalone)""" stp: enable STP (False, requires failMode=standalone)
batch: enable batch startup (True)"""
Switch.__init__( self, name, **params ) Switch.__init__( self, name, **params )
self.failMode = failMode self.failMode = failMode
self.datapath = datapath self.datapath = datapath
@@ -1076,6 +1077,8 @@ class OVSSwitch( Switch ):
self.reconnectms = reconnectms self.reconnectms = reconnectms
self.stp = stp self.stp = stp
self._uuids = [] # controller UUIDs self._uuids = [] # controller UUIDs
self.batch = batch
self.commands = [] # saved commands for batch startup
@classmethod @classmethod
def setup( cls ): def setup( cls ):
@@ -1105,29 +1108,17 @@ class OVSSwitch( Switch ):
return ( StrictVersion( cls.OVSVersion ) < return ( StrictVersion( cls.OVSVersion ) <
StrictVersion( '1.10' ) ) StrictVersion( '1.10' ) )
@classmethod
def batchShutdown( cls, switches ):
"Shut down a list of OVS switches"
delcmd = 'del-br %s'
if not cls.isOldOVS():
delcmd = '--if-exists ' + delcmd
# First, delete them all from ovsdb
quietRun( 'ovs-vsctl ' +
' -- '.join( delcmd % s for s in switches ) )
# Next, shut down all of the processes
pids = ' '.join( str( switch.pid ) for switch in switches )
quietRun( 'kill -HUP ' + pids )
for switch in switches:
switch.shell = None
return True
def dpctl( self, *args ): def dpctl( self, *args ):
"Run ovs-ofctl command" "Run ovs-ofctl command"
return self.cmd( 'ovs-ofctl', args[ 0 ], self, *args[ 1: ] ) return self.cmd( 'ovs-ofctl', args[ 0 ], self, *args[ 1: ] )
def vsctl( self, *args, **kwargs ): def vsctl( self, *args, **kwargs ):
"Run ovs-vsctl command" "Run ovs-vsctl command (or queue for later execution)"
return self.cmd( 'ovs-vsctl', *args, **kwargs ) if self.batch:
cmd = ' '.join( str( arg ).strip() for arg in args )
self.commands.append( cmd )
else:
return self.cmd( 'ovs-vsctl', *args, **kwargs )
@staticmethod @staticmethod
def TCReapply( intf ): def TCReapply( intf ):
@@ -1217,7 +1208,7 @@ class OVSSwitch( Switch ):
if self.reconnectms: if self.reconnectms:
ccmd += ' max_backoff=%d' % self.reconnectms ccmd += ' max_backoff=%d' % self.reconnectms
cargs = ' '.join( ccmd % ( name, target ) cargs = ' '.join( ccmd % ( name, target )
for name, target in clist ) for name, target in clist )
# Controller ID list # Controller ID list
cids = ','.join( '@%s' % name for name, _target in clist ) cids = ','.join( '@%s' % name for name, _target in clist )
# Try to delete any existing bridges with the same name # Try to delete any existing bridges with the same name
@@ -1229,10 +1220,43 @@ class OVSSwitch( Switch ):
' -- set bridge %s controller=[%s]' % ( self, cids ) + ' -- set bridge %s controller=[%s]' % ( self, cids ) +
self.bridgeOpts() + self.bridgeOpts() +
intfs ) intfs )
# XXX BROKEN - need to fix this!!
# If necessary, restore TC config overwritten by OVS # If necessary, restore TC config overwritten by OVS
# for intf in self.intfList(): if not self.batch:
# self.TCReapply( intf ) for intf in self.intfList():
self.TCReapply( intf )
# This should be ~ int( quietRun( 'getconf ARG_MAX' ) ),
# but the real limit seems to be much lower
argmax = 128000
@classmethod
def batchStartup( cls, switches, run=errRun ):
"""Batch startup for OVS
switches: switches to start up
run: function to run commands (errRun)"""
info( '...' )
cmds = 'ovs-vsctl'
for switch in switches:
if switch.isOldOVS():
# Ideally we'd optimize this also
run( 'ovs-vsctl del-br %s' % switch )
for cmd in switch.commands:
cmd = cmd.strip()
# Don't exceed ARG_MAX
if len( cmds ) + len( cmd ) >= cls.argmax:
run( cmds, shell=True )
cmds = 'ovs-vsctl'
cmds += ' ' + cmd
switch.cmds = []
switch.batch = False
if cmds:
run( cmds, shell=True )
# Reapply link config if necessary...
for switch in switches:
for intf in switch.intfs.itervalues():
if isinstance( intf, TCIntf ):
intf.config( **intf.params )
return switches
def stop( self, deleteIntfs=True ): def stop( self, deleteIntfs=True ):
"""Terminate OVS switch. """Terminate OVS switch.
@@ -1242,6 +1266,22 @@ class OVSSwitch( Switch ):
self.cmd( 'ip link del', self ) self.cmd( 'ip link del', self )
super( OVSSwitch, self ).stop( deleteIntfs ) super( OVSSwitch, self ).stop( deleteIntfs )
@classmethod
def batchShutdown( cls, switches, run=errRun ):
"Shut down a list of OVS switches"
delcmd = 'del-br %s'
if not cls.isOldOVS():
delcmd = '--if-exists ' + delcmd
# First, delete them all from ovsdb
run( 'ovs-vsctl ' +
' -- '.join( delcmd % s for s in switches ) )
# Next, shut down all of the processes
pids = ' '.join( str( switch.pid ) for switch in switches )
run( 'kill -HUP ' + pids )
for switch in switches:
switch.shell = None
return switches
OVSKernelSwitch = OVSSwitch OVSKernelSwitch = OVSSwitch
@@ -1265,54 +1305,6 @@ class OVSBridge( OVSSwitch ):
return True return True
class OVSBatch( OVSSwitch ):
"Experiment: batch startup of OVS switches"
# This should be ~ int( quietRun( 'getconf ARG_MAX' ) ),
# but the real limit seems to be much lower
argmax = 128000
def __init__( self, *args, **kwargs ):
self.commands = []
self.started = False
super( OVSBatch, self ).__init__( *args, **kwargs )
@classmethod
def batchStartup( cls, switches ):
"Batch startup for OVS"
info( '...' )
cmds = 'ovs-vsctl'
for switch in switches:
if cls.isOldOVS():
quietRun( 'ovs-vsctl del-br %s' % switch )
for cmd in switch.commands:
cmd = cmd.strip()
# Don't exceed ARG_MAX
if len( cmds ) + len( cmd ) >= cls.argmax:
errRun( cmds, shell=True )
cmds = 'ovs-vsctl'
cmds += ' ' + cmd
switch.started = True
if cmds:
errRun( cmds, shell=True )
return True
def vsctl( self, *args, **kwargs ):
"Append ovs-vsctl command to list for later execution"
if self.started:
return super( OVSBatch, self).vsctl( *args, **kwargs )
cmd = ' '.join( str( arg ).strip() for arg in args )
self.commands.append( cmd )
def start( self, *args, **kwargs ):
super( OVSBatch, self ).start( *args, **kwargs )
self.started = True
def stop( self, *args, **kwargs ):
super( OVSBatch, self ).stop( *args, **kwargs )
self.started = False
class IVSSwitch( Switch ): class IVSSwitch( Switch ):
"Indigo Virtual Switch" "Indigo Virtual Switch"
@@ -1338,6 +1330,7 @@ class IVSSwitch( Switch ):
"Kill each IVS switch, to be waited on later in stop()" "Kill each IVS switch, to be waited on later in stop()"
for switch in switches: for switch in switches:
switch.cmd( 'kill %ivs' ) switch.cmd( 'kill %ivs' )
return switches
def start( self, controllers ): def start( self, controllers ):
"Start up a new IVS switch" "Start up a new IVS switch"
@@ -1556,4 +1549,4 @@ def DefaultController( name, controllers=DefaultControllers, **kwargs ):
controller = findController( controllers ) controller = findController( controllers )
if not controller: if not controller:
raise Exception( 'Could not find a default OpenFlow controller' ) raise Exception( 'Could not find a default OpenFlow controller' )
return controller( name, **kwargs ) return contr