Add OVSBatch class (experimental)

This implements batch startup for OVS switches.
This commit is contained in:
Bob Lantz
2015-01-26 14:06:22 -08:00
parent c68e4e76f4
commit 9bda98486d
3 changed files with 87 additions and 30 deletions
+2 -1
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, UserSwitch, OVSSwitch, OVSBridge, OVSBatch,
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,6 +62,7 @@ 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 }
+7
View File
@@ -481,6 +481,13 @@ class Mininet( object ):
for switch in self.switches: for switch in self.switches:
info( switch.name + ' ') info( switch.name + ' ')
switch.start( self.controllers ) switch.start( self.controllers )
started = {}
for swclass, switches in groupby(
sorted( self.switches, key=type ), type ):
switches = tuple( switches )
if ( hasattr( swclass, 'batchStartup' ) and
swclass.batchStartup( switches ) ):
started.update( { s: s for s in switches } )
info( '\n' ) info( '\n' )
if self.waitConn: if self.waitConn:
self.waitConnected() self.waitConnected()
+78 -29
View File
@@ -1106,16 +1106,26 @@ class OVSSwitch( Switch ):
@classmethod @classmethod
def batchShutdown( cls, switches ): def batchShutdown( cls, switches ):
"Call ovs-vsctl del-br on all OVSSwitches in a list" "Shut down a list of OVS switches"
# First, delete them all from ovsdb
quietRun( 'ovs-vsctl ' + quietRun( 'ovs-vsctl ' +
' -- '.join( '--if-exists del-br %s' % s ' -- '.join( '--if-exists del-br %s' % s
for s in switches ) ) 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 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 ):
"Run ovs-vsctl command"
return self.cmd( 'ovs-vsctl', *args, **kwargs )
@staticmethod @staticmethod
def TCReapply( intf ): def TCReapply( intf ):
"""Unfortunately OVS and Mininet are fighting """Unfortunately OVS and Mininet are fighting
@@ -1126,19 +1136,19 @@ class OVSSwitch( Switch ):
def attach( self, intf ): def attach( self, intf ):
"Connect a data port" "Connect a data port"
self.cmd( 'ovs-vsctl add-port', self, intf ) self.vsctl( 'add-port', self, intf )
self.cmd( 'ifconfig', intf, 'up' ) self.cmd( 'ifconfig', intf, 'up' )
self.TCReapply( intf ) self.TCReapply( intf )
def detach( self, intf ): def detach( self, intf ):
"Disconnect a data port" "Disconnect a data port"
self.cmd( 'ovs-vsctl del-port', self, intf ) self.vsctl( 'del-port', self, intf )
def controllerUUIDs( self, update=False ): def controllerUUIDs( self, update=False ):
"""Return ovsdb UUIDs for our controllers """Return ovsdb UUIDs for our controllers
update: update cached value""" update: update cached value"""
if not self._uuids or update: if not self._uuids or update:
controllers = self.cmd( 'ovs-vsctl -- get Bridge', self, controllers = self.vsctl( '-- get Bridge', self,
'Controller' ).strip() 'Controller' ).strip()
if controllers.startswith( '[' ) and controllers.endswith( ']' ): if controllers.startswith( '[' ) and controllers.endswith( ']' ):
controllers = controllers[ 1 : -1 ] controllers = controllers[ 1 : -1 ]
@@ -1150,8 +1160,8 @@ class OVSSwitch( Switch ):
def connected( self ): def connected( self ):
"Are we connected to at least one of our controllers?" "Are we connected to at least one of our controllers?"
for uuid in self.controllerUUIDs(): for uuid in self.controllerUUIDs():
if 'true' in self.cmd( 'ovs-vsctl -- get Controller', if 'true' in self.vsctl( '-- get Controller',
uuid, 'is_connected' ): uuid, 'is_connected' ):
return True return True
return self.failMode == 'standalone' return self.failMode == 'standalone'
@@ -1163,8 +1173,8 @@ class OVSSwitch( Switch ):
return '' return ''
intf1, intf2 = intf.link.intf1, intf.link.intf2 intf1, intf2 = intf.link.intf1, intf.link.intf2
peer = intf1 if intf1 != intf else intf2 peer = intf1 if intf1 != intf else intf2
return ( '-- set Interface %s type=patch ' return ( ' -- set Interface %s type=patch'
'-- set Interface %s options:peer=%s ' % ' -- set Interface %s options:peer=%s ' %
( intf, intf, peer ) ) ( intf, intf, peer ) )
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
@@ -1177,7 +1187,7 @@ class OVSSwitch( Switch ):
# Interfaces and controllers # Interfaces and controllers
intfs = ' '.join( '-- add-port %s %s ' % ( self, intf ) + intfs = ' '.join( '-- add-port %s %s ' % ( self, intf ) +
'-- set Interface %s ' % intf + '-- set Interface %s ' % intf +
'ofport_request=%s ' % self.ports[ intf ] 'ofport_request=%s' % self.ports[ intf ]
+ self.patchOpts( intf ) + self.patchOpts( intf )
for intf in self.intfList() for intf in self.intfList()
if self.ports[ intf ] and not intf.IP() ) if self.ports[ intf ] and not intf.IP() )
@@ -1187,43 +1197,43 @@ class OVSSwitch( Switch ):
clist += ' ptcp:%s' % self.listenPort clist += ' ptcp:%s' % self.listenPort
# Construct big ovs-vsctl command for new versions of OVS # Construct big ovs-vsctl command for new versions of OVS
if not self.isOldOVS(): if not self.isOldOVS():
cmd = ( 'ovs-vsctl --if-exists del-br %s ' % self + cmd = ( '-- --if-exists del-br %s' % self +
'-- add-br %s ' % self + ' -- add-br %s' % self +
'-- set Bridge %s ' % self + ' -- set Bridge %s' % self +
'other_config:datapath-id=%s ' % self.dpid + ' other_config:datapath-id=%s' % self.dpid +
'-- set-fail-mode %s %s ' % ( self, self.failMode ) + ' -- set-fail-mode %s %s ' % ( self, self.failMode ) +
intfs + intfs +
'-- set-controller %s %s ' % ( self, clist ) ) ' -- set-controller %s %s' % ( self, clist ) )
# Construct ovs-vsctl commands for old versions of OVS # Construct ovs-vsctl commands for old versions of OVS
else: else:
# Annoyingly, --if-exists option seems not to work # Annoyingly, --if-exists option seems not to work
self.cmd( 'ovs-vsctl del-br', self ) self.vsctl( 'del-br', self )
self.cmd( 'ovs-vsctl add-br', self ) self.vsctl( 'add-br', self )
for intf in self.intfList(): for intf in self.intfList():
if not intf.IP(): if not intf.IP():
self.cmd( 'ovs-vsctl add-port', self, intf ) self.vsctl( 'add-port', self, intf )
cmd = ( 'ovs-vsctl set Bridge %s ' % self + cmd = ( 'set Bridge %s' % self +
'other_config:datapath-id=%s ' % self.dpid + ' other_config:datapath-id=%s' % self.dpid +
'-- set-fail-mode %s %s ' % ( self, self.failMode ) + ' -- set-fail-mode %s %s ' % ( self, self.failMode ) +
'-- set-controller %s %s ' % ( self, clist ) ) ' -- set-controller %s %s ' % ( self, clist ) )
if not self.inband: if not self.inband:
cmd += ( '-- set bridge %s ' cmd += ( ' -- set bridge %s '
'other-config:disable-in-band=true ' % self ) 'other-config:disable-in-band=true' % self )
if self.datapath == 'user': if self.datapath == 'user':
cmd += '-- set bridge %s datapath_type=netdev ' % self cmd += ' -- set bridge %s datapath_type=netdev' % self
if self.protocols and not self.isOldOVS(): if self.protocols and not self.isOldOVS():
cmd += '-- set bridge %s protocols=%s ' % ( self, self.protocols ) cmd += ' -- set bridge %s protocols=%s' % ( self, self.protocols )
if self.stp and self.failMode == 'standalone': if self.stp and self.failMode == 'standalone':
cmd += '-- set bridge %s stp_enable=true ' % self cmd += ' -- set bridge %s stp_enable=true' % self
# Do it!! # Do it!!
self.cmd( cmd ) self.vsctl( cmd )
# Reconnect quickly to controllers (1s vs. 15s max_backoff) # Reconnect quickly to controllers (1s vs. 15s max_backoff)
if self.reconnectms: if self.reconnectms:
uuids = [ '-- set Controller %s max_backoff=%d' % uuids = [ '-- set Controller %s max_backoff=%d' %
( uuid, self.reconnectms ) ( uuid, self.reconnectms )
for uuid in self.controllerUUIDs() ] for uuid in self.controllerUUIDs() ]
if uuids: if uuids:
self.cmd( 'ovs-vsctl', *uuids ) self.vsctl( *uuids )
# If necessary, restore TC config overwritten by OVS # If necessary, restore TC config overwritten by OVS
for intf in self.intfList(): for intf in self.intfList():
self.TCReapply( intf ) self.TCReapply( intf )
@@ -1260,6 +1270,45 @@ class OVSBridge( OVSSwitch ):
return True return True
class OVSBatch( OVSSwitch ):
"Experiment: batch startup of OVS switches"
def __init__( self, *args, **kwargs ):
kwargs.update( reconnectms=None )
self.commands = []
self.started = False
super( OVSBatch, self ).__init__( *args, **kwargs )
@classmethod
def batchStartup( cls, switches ):
"Batch startup for OVS"
if cls.isOldOVS():
return False
info( '...' )
cmds = ''
for switch in switches:
for cmd in switch.commands:
cmds += ' ' + cmd.strip()
# Split into 1 MB blocks
if len( cmds ) > 1000000:
print quietRun( 'ovs-vsctl' + cmds )
cmds = ''
switch.started = True
if cmds:
quietRun( 'ovs-vsctl' + cmds )
return True
def vsctl( self, *args, **kwargs ):
"Append ovs-vsctl command to list for later execution"
if self.started:
return OVSSwitch.vsctl( self, *args, **kwargs )
cmd = ' '.join( str( arg ) for arg in args ).strip()
self.commands.append( cmd )
def cleanup( self):
"Don't bother to clean up"
return
class IVSSwitch( Switch ): class IVSSwitch( Switch ):
"Indigo Virtual Switch" "Indigo Virtual Switch"