Skip to content
Snippets Groups Projects
Commit 9bda9848 authored by Bob Lantz's avatar Bob Lantz
Browse files

Add OVSBatch class (experimental)

This implements batch startup for OVS switches.
parent c68e4e76
No related branches found
No related tags found
No related merge requests found
...@@ -27,7 +27,7 @@ from mininet.net import Mininet, MininetWithControlNet, VERSION ...@@ -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, ...@@ -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 }
......
...@@ -481,6 +481,13 @@ def start( self ): ...@@ -481,6 +481,13 @@ def start( self ):
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()
......
...@@ -1106,16 +1106,26 @@ def isOldOVS( cls ): ...@@ -1106,16 +1106,26 @@ def isOldOVS( cls ):
@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 @@ def TCReapply( intf ): ...@@ -1126,19 +1136,19 @@ def TCReapply( intf ):
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 @@ def controllerUUIDs( self, update=False ): ...@@ -1150,8 +1160,8 @@ def controllerUUIDs( self, update=False ):
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 @@ def patchOpts( intf ): ...@@ -1163,8 +1173,8 @@ def patchOpts( intf ):
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 @@ def start( self, controllers ): ...@@ -1177,7 +1187,7 @@ def start( self, controllers ):
# 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 @@ def start( self, controllers ): ...@@ -1187,43 +1197,43 @@ def start( self, controllers ):
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 @@ def connected( self ): ...@@ -1260,6 +1270,45 @@ def connected( self ):
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"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment