Merge pull request #342 from cdburkard/devel/startup

improve startup performance, largely by removing unnecessary ifconfigs
This commit is contained in:
lantz
2014-08-26 19:59:12 -07:00
5 changed files with 67 additions and 32 deletions
+39 -13
View File
@@ -32,7 +32,7 @@ class Intf( object ):
"Basic interface object that can configure itself."
def __init__( self, name, node=None, port=None, link=None, **params ):
def __init__( self, name, node=None, port=None, link=None, mac=None, **params ):
"""name: interface name (e.g. h1-eth0)
node: owning node (where this intf most likely lives)
link: parent link if we're part of a link
@@ -40,7 +40,13 @@ class Intf( object ):
self.node = node
self.name = name
self.link = link
self.mac, self.ip, self.prefixLen = None, None, None
self.mac = mac
self.ip, self.prefixLen = None, None
# if interface is lo, we know the ip is 127.0.0.1.
# This saves an ifconfig command per node
if self.name == 'lo':
self.ip = '127.0.0.1'
# Add to node (and move ourselves if necessary )
node.addIntf( self, port=port )
# Save params for future reference
@@ -91,6 +97,19 @@ class Intf( object ):
self.mac = macs[ 0 ] if macs else None
return self.mac
# Instead of updating ip and mac separately,
# use one ifconfig call to do it simultaneously.
# This saves an ifconfig command, which improves performance.
def updateAddr( self ):
"Return IP address and MAC address based on ifconfig."
ifconfig = self.ifconfig()
ips = self._ipMatchRegex.findall( ifconfig )
macs = self._macMatchRegex.findall( ifconfig )
self.ip = ips[ 0 ] if ips else None
self.mac = macs[ 0 ] if macs else None
return self.ip, self.mac
def IP( self ):
"Return IP address"
return self.ip
@@ -102,8 +121,15 @@ class Intf( object ):
def isUp( self, setUp=False ):
"Return whether interface is up"
if setUp:
self.ifconfig( 'up' )
return "UP" in self.ifconfig()
cmdOutput = self.ifconfig( 'up' )
# no output indicates success
if cmdOutput:
error( "Error setting %s up: %s " % ( self.name, cmdOutput ) )
return False
else:
return True
else:
return "UP" in self.ifconfig()
def rename( self, newname ):
"Rename interface"
@@ -154,8 +180,6 @@ class Intf( object ):
self.setParam( r, 'setIP', ip=ip )
self.setParam( r, 'isUp', up=up )
self.setParam( r, 'ifconfig', ifconfig=ifconfig )
self.updateIP()
self.updateMAC()
return r
def delete( self ):
@@ -328,7 +352,7 @@ class Link( object ):
Other types of links could be tunnels, link emulators, etc.."""
def __init__( self, node1, node2, port1=None, port2=None,
intfName1=None, intfName2=None,
intfName1=None, intfName2=None, addr1=None, addr2=None,
intf=Intf, cls1=None, cls2=None, params1=None,
params2=None ):
"""Create veth link to another node, making two new interfaces.
@@ -354,7 +378,7 @@ class Link( object ):
if not intfName2:
intfName2 = self.intfName( node2, port2 )
self.makeIntfPair( intfName1, intfName2 )
self.makeIntfPair( intfName1, intfName2, addr1, addr2 )
if not cls1:
cls1 = intf
@@ -366,9 +390,9 @@ class Link( object ):
params2 = {}
intf1 = cls1( name=intfName1, node=node1, port=port1,
link=self, **params1 )
link=self, mac=addr1, **params1 )
intf2 = cls2( name=intfName2, node=node2, port=port2,
link=self, **params2 )
link=self, mac=addr2, **params2 )
# All we are is dust in the wind, and our two interfaces
self.intf1, self.intf2 = intf1, intf2
@@ -379,13 +403,13 @@ class Link( object ):
return node.name + '-eth' + repr( n )
@classmethod
def makeIntfPair( cls, intf1, intf2 ):
def makeIntfPair( cls, intf1, intf2, addr1=None, addr2=None ):
"""Create pair of interfaces
intf1: name of interface 1
intf2: name of interface 2
(override this class method [and possibly delete()]
to change link type)"""
makeIntfPair( intf1, intf2 )
makeIntfPair( intf1, intf2, addr1, addr2 )
def delete( self ):
"Delete this link"
@@ -398,10 +422,12 @@ class Link( object ):
class TCLink( Link ):
"Link with symmetric TC interfaces configured via opts"
def __init__( self, node1, node2, port1=None, port2=None,
intfName1=None, intfName2=None, **params ):
intfName1=None, intfName2=None,
addr1=None, addr2=None, **params ):
Link.__init__( self, node1, node2, port1=port1, port2=port2,
intfName1=intfName1, intfName2=intfName2,
cls1=TCIntf,
cls2=TCIntf,
addr1=addr1, addr2=addr2,
params1=params,
params2=params)
+5 -1
View File
@@ -90,6 +90,7 @@ import os
import re
import select
import signal
import random
import copy
from time import sleep
from itertools import chain, groupby
@@ -326,8 +327,12 @@ class Mininet( object ):
port1: source port
port2: dest port
returns: link object"""
mac1 = macColonHex( random.randint(1, 2**48 - 1) & 0xfeffffffffff | 0x020000000000 )
mac2 = macColonHex( random.randint(1, 2**48 - 1) & 0xfeffffffffff | 0x020000000000 )
defaults = { 'port1': port1,
'port2': port2,
'addr1': mac1,
'addr2': mac2,
'intf': self.intf }
defaults.update( params )
if not cls:
@@ -350,7 +355,6 @@ class Mininet( object ):
# quietRun( 'renice +18 -p ' + repr( host.pid ) )
# This may not be the right place to do this, but
# it needs to be done somewhere.
host.cmd( 'ifconfig lo up' )
info( '\n' )
def buildFromTopo( self, topo=None ):
-7
View File
@@ -924,7 +924,6 @@ class UserSwitch( Switch ):
for c in controllers ] )
ofdlog = '/tmp/' + self.name + '-ofd.log'
ofplog = '/tmp/' + self.name + '-ofp.log'
self.cmd( 'ifconfig lo up' )
intfs = [ str( i ) for i in self.intfList() if not i.IP() ]
self.cmd( 'ofdatapath -i ' + ','.join( intfs ) +
' punix:/tmp/' + self.name + ' -d %s ' % self.dpid +
@@ -975,7 +974,6 @@ class OVSLegacyKernelSwitch( Switch ):
def start( self, controllers ):
"Start up kernel datapath."
ofplog = '/tmp/' + self.name + '-ofp.log'
quietRun( 'ifconfig lo up' )
# Delete local datapath if it exists;
# then create a new one monitoring the given interfaces
self.cmd( 'ovs-dpctl del-dp ' + self.dp )
@@ -1093,9 +1091,6 @@ class OVSSwitch( Switch ):
if self.inNamespace:
raise Exception(
'OVS kernel switch does not work in a namespace' )
# We should probably call config instead, but this
# requires some rethinking...
self.cmd( 'ifconfig lo up' )
# Annoyingly, --if-exists option seems not to work
self.cmd( 'ovs-vsctl del-br', self )
int( self.dpid, 16 ) # DPID must be a hex string
@@ -1200,7 +1195,6 @@ class IVSSwitch(Switch):
logfile = '/tmp/ivs.%s.log' % self.name
self.cmd( 'ifconfig lo up' )
self.cmd( ' '.join(args) + ' >' + logfile + ' 2>&1 </dev/null &' )
def stop( self ):
@@ -1240,7 +1234,6 @@ class Controller( Node ):
self.protocol = protocol
Node.__init__( self, name, inNamespace=inNamespace,
ip=ip, **params )
self.cmd( 'ifconfig lo up' ) # Shouldn't be necessary
self.checkListening()
def checkListening( self ):
+12 -6
View File
@@ -45,7 +45,7 @@ class testOptionsTopoCommon( object ):
mn = Mininet( topo=SingleSwitchOptionsTopo( n=n, hopts=hopts,
lopts=lopts ),
host=CPULimitedHost, link=TCLink,
switch=self.switchClass )
switch=self.switchClass, waitConnected=True )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
@@ -67,7 +67,8 @@ class testOptionsTopoCommon( object ):
#self.runOptionsTopoTest( N, hopts=hopts )
mn = Mininet( SingleSwitchOptionsTopo( n=N, hopts=hopts ),
host=CPULimitedHost, switch=self.switchClass )
host=CPULimitedHost, switch=self.switchClass,
waitConnected=True )
mn.start()
results = mn.runCpuLimitTest( cpu=CPU_FRACTION )
mn.stop()
@@ -77,13 +78,16 @@ class testOptionsTopoCommon( object ):
def testLinkBandwidth( self ):
"Verify that link bandwidths are accurate within a bound."
BW = .5 # Mbps
if self.switchClass is UserSwitch:
self.skipTest ( 'UserSwitch has very poor performance, so skip for now' )
BW = 5 # Mbps
BW_TOLERANCE = 0.8 # BW fraction below which test should fail
# Verify ability to create limited-link topo first;
lopts = { 'bw': BW, 'use_htb': True }
# Also verify correctness of limit limitng within a bound.
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
link=TCLink, switch=self.switchClass )
link=TCLink, switch=self.switchClass,
waitConnected=True )
bw_strs = mn.run( mn.iperf, format='m' )
for bw_str in bw_strs:
bw = float( bw_str.split(' ')[0] )
@@ -95,7 +99,8 @@ class testOptionsTopoCommon( object ):
DELAY_TOLERANCE = 0.8 # Delay fraction below which test should fail
lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True }
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
link=TCLink, switch=self.switchClass, autoStaticArp=True )
link=TCLink, switch=self.switchClass, autoStaticArp=True,
waitConnected=True )
ping_delays = mn.run( mn.pingFull )
test_outputs = ping_delays[0]
# Ignore unused variables below
@@ -117,7 +122,8 @@ class testOptionsTopoCommon( object ):
lopts = { 'loss': LOSS_PERCENT, 'use_htb': True }
mn = Mininet( topo=SingleSwitchOptionsTopo( n=N, lopts=lopts ),
host=CPULimitedHost, link=TCLink,
switch=self.switchClass )
switch=self.switchClass,
waitConnected=True )
# Drops are probabilistic, but the chance of no dropped packets is
# 1 in 100 million with 4 hops for a link w/99% loss.
dropped_total = 0
+11 -5
View File
@@ -145,7 +145,7 @@ isShellBuiltin.builtIns = None
# live in the root namespace and thus do not have to be
# explicitly moved.
def makeIntfPair( intf1, intf2 ):
def makeIntfPair( intf1, intf2, addr1=None, addr2=None ):
"""Make a veth pair connecting intf1 and intf2.
intf1: string, interface
intf2: string, interface
@@ -154,7 +154,11 @@ def makeIntfPair( intf1, intf2 ):
quietRun( 'ip link del ' + intf1 )
quietRun( 'ip link del ' + intf2 )
# Create new pair
cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
if addr1 is None and addr2 is None:
cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
else:
cmd = ( 'ip link add name ' + intf1 + ' address ' + addr1 +
' type veth peer name ' + intf2 + ' address ' + addr2 )
cmdOutput = quietRun( cmd )
if cmdOutput == '':
return True
@@ -185,10 +189,12 @@ def moveIntfNoRetry( intf, dstNode, srcNode=None, printError=False ):
intf = str( intf )
cmd = 'ip link set %s netns %s' % ( intf, dstNode.pid )
if srcNode:
srcNode.cmd( cmd )
cmdOutput = srcNode.cmd( cmd )
else:
quietRun( cmd )
if ( ' %s:' % intf ) not in dstNode.cmd( 'ip link show', intf ):
cmdOutput = quietRun( cmd )
# If ip link set does not produce any output, then we can assume
# that the link has been moved successfully.
if cmdOutput:
if printError:
error( '*** Error: moveIntf: ' + intf +
' not successfully moved to ' + dstNode.name + '\n' )