New configuration scheme and support for CPU limits (RT).

This commit is contained in:
Bob Lantz
2012-03-06 23:52:00 -08:00
parent 94c02695fd
commit 84a91a14a4
3 changed files with 434 additions and 275 deletions
+129 -120
View File
@@ -94,8 +94,7 @@ from time import sleep
from mininet.cli import CLI
from mininet.log import info, error, debug, output
from mininet.node import Host, UserSwitch, OVSKernelSwitch, Controller
from mininet.node import ControllerParams
from mininet.node import Host, OVSKernelSwitch, Controller
from mininet.link import Link
from mininet.util import quietRun, fixLimits
from mininet.util import createLink, macColonHex, ipStr, ipParse
@@ -106,7 +105,6 @@ class Mininet( object ):
def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
controller=Controller, link=Link,
cparams=ControllerParams( '10.0.0.0', 8 ),
build=True, xterms=False, cleanup=False,
inNamespace=False,
autoSetMacs=False, autoStaticArp=False, listenPort=None ):
@@ -116,12 +114,12 @@ class Mininet( object ):
host: default Host class/constructor
controller: default Controller class/constructor
link: default Link class/constructor
cparams: ControllerParams object
ipBase: base IP address for hosts,
build: build now from topo?
xterms: if build now, spawn xterms?
cleanup: if build now, cleanup before creating?
inNamespace: spawn switches and controller in net namespaces?
autoSetMacs: set MAC addrs from topo?
autoSetMacs: set MAC addrs from topo dpid?
autoStaticArp: set all-pairs static MAC addrs?
listenPort: base listening port to open; will be incremented for
each additional switch in the net if inNamespace=False"""
@@ -129,7 +127,6 @@ class Mininet( object ):
self.host = host
self.controller = controller
self.link = link
self.cparams = cparams
self.topo = topo
self.inNamespace = inNamespace
self.xterms = xterms
@@ -141,13 +138,13 @@ class Mininet( object ):
self.hosts = []
self.switches = []
self.controllers = []
self.nameToNode = {} # name to Node (Host/Switch) objects
self.idToNode = {} # dpid to Node (Host/Switch) objects
self.dps = 0 # number of created kernel datapaths
self.terms = [] # list of spawned xterm processes
init()
switch.setup()
init() # Initialize Mininet if necessary
self.built = False
if topo and build:
@@ -157,17 +154,15 @@ class Mininet( object ):
# The specific items for host/switch/etc. should probably be
# handled in the node classes rather than here!!
def addHost( self, name, mac=None, ip=None, host=None, **params ):
def addHost( self, name, host=None, **params ):
"""Add host.
name: name of host to add
mac: default MAC address for intf 0
ip: default IP address for intf 0
host: custom host constructor (optional)
params: parameters for host
returns: added host"""
if not host:
host = self.host
defaults = { 'defaultMAC': mac, 'defaultIP': ip }
defaults.update( params )
h = host( name, **defaults)
h = host( name, **params)
self.hosts.append( h )
self.nameToNode[ name ] = h
return h
@@ -175,19 +170,17 @@ class Mininet( object ):
def addSwitch( self, name, switch=None, **params ):
"""Add switch.
name: name of switch to add
switch: custom switch constructor (optional)
returns: added switch
side effect: increments listenPort and dps ivars."""
side effect: increments listenPort ivar ."""
defaults = { 'listenPort': self.listenPort,
'inNamespace': self.inNamespace }
defaults.update( params )
if not switch:
switch = self.switch
if switch != UserSwitch:
defaults[ 'dps' ] = self.dps
defaults.update( params )
sw = self.switch( name, **defaults )
if not self.inNamespace and self.listenPort:
self.listenPort += 1
self.dps += 1
self.switches.append( sw )
self.nameToNode[ name ] = sw
return sw
@@ -203,122 +196,81 @@ class Mininet( object ):
self.nameToNode[ name ] = controller_new
return controller_new
# Control network support:
#
# Create an explicit control network. Currently this is only
# used by the user datapath configuration.
#
# Notes:
#
# 1. If the controller and switches are in the same (e.g. root)
# namespace, they can just use the loopback connection.
#
# 2. If we can get unix domain sockets to work, we can use them
# instead of an explicit control network.
#
# 3. Instead of routing, we could bridge or use 'in-band' control.
#
# 4. Even if we dispense with this in general, it could still be
# useful for people who wish to simulate a separate control
# network (since real networks may need one!)
#
# 5. Basically nobody ever uses this method, so perhaps it should be moved
# out of this core class.
def configureControlNetwork( self ):
"Configure control network."
self.configureRoutedControlNetwork()
# We still need to figure out the right way to pass
# in the control network location.
def configureRoutedControlNetwork( self, ip='192.168.123.1',
prefixLen=16 ):
"""Configure a routed control network on controller and switches.
For use with the user datapath only right now."""
controller = self.controllers[ 0 ]
info( controller.name + ' <->' )
cip = ip
snum = ipParse( ip )
for switch in self.switches:
info( ' ' + switch.name )
sintf, cintf = createLink( switch, controller )
snum += 1
while snum & 0xff in [ 0, 255 ]:
snum += 1
sip = ipStr( snum )
controller.setIP( cintf, cip, prefixLen )
switch.setIP( sintf, sip, prefixLen )
controller.setHostRoute( sip, cintf )
switch.setHostRoute( cip, sintf )
info( '\n' )
info( '*** Testing control network\n' )
while not controller.intfIsUp( cintf ):
info( '*** Waiting for', cintf, 'to come up\n' )
sleep( 1 )
for switch in self.switches:
while not switch.intfIsUp( sintf ):
info( '*** Waiting for', sintf, 'to come up\n' )
sleep( 1 )
if self.ping( hosts=[ switch, controller ] ) != 0:
error( '*** Error: control network test failed\n' )
exit( 1 )
info( '\n' )
def configHosts( self ):
"Configure a set of hosts."
# params were: hosts, ips
for host in self.hosts:
hintf = host.defaultIntf()
host.setIP( host.defaultIP, self.cparams.prefixLen, hintf )
host.setDefaultRoute( hintf )
host.configDefault( defaultRoute=host.defaultIntf )
# You're low priority, dude!
quietRun( 'renice +18 -p ' + repr( host.pid ) )
# BL: do we want to do this here or not?
# May not make sense if we have CPU lmiting...
# quietRun( 'renice +18 -p ' + repr( host.pid ) )
info( host.name + ' ' )
info( '\n' )
def buildFromTopo( self, topo ):
def buildFromTopo( self, topo=None ):
"""Build mininet from a topology object
At the end of this function, everything should be connected
and up."""
if not topo:
topo = self.topo()
def addNode( prefix, addMethod, nodeId ):
"Add a host or a switch."
"Add a host or a switch from topo"
name = prefix + topo.name( nodeId )
# MAC and IP should probably be from nodeInfo...
mac = macColonHex( nodeId ) if self.setMacs else None
ip = topo.ip( nodeId )
ni = topo.nodeInfo( nodeId )
node = addMethod( name, cls=ni.cls, mac=mac, ip=ip, **ni.params )
# Default IP and MAC addresses
defaults = { 'ip': topo.ip( nodeId ) }
if self.autoSetMacs:
defaults[ 'mac'] = macColonHex( nodeId )
defaults.update( ni.params )
node = addMethod( name, cls=ni.cls, **defaults )
self.idToNode[ nodeId ] = node
info( name + ' ' )
def addLink( srcId, dstId, link=None ):
"Add a link from topo"
src, dst = self.idToNode[ srcId ], self.idToNode[ dstId ]
srcPort, dstPort = topo.port( srcId, dstId )
ei = topo.edgeInfo( srcId, dstId )
link = getattr( ei, 'cls', link )
params = ei.params
if not link:
link = self.link
info( '(%s, %s) ' % ( src.name, dst.name ) )
link( src, dst, srcPort, dstPort, **params )
# Possibly we should clean up here and/or validate
# the topo
if self.cleanup:
pass
info( '*** Adding controller\n' )
self.addController( 'c0' )
info( '*** Creating network\n' )
if not self.controllers:
# Add a default controller
info( '*** Adding controller\n' )
self.addController( 'c0' )
info( '*** Adding hosts:\n' )
for hostId in sorted( topo.hosts() ):
addNode( 'h', self.addHost, hostId )
info( '\n*** Adding switches:\n' )
for switchId in sorted( topo.switches() ):
addNode( 's', self.addSwitch, switchId)
addNode( 's', self.addSwitch, switchId )
info( '\n*** Adding links:\n' )
for srcId, dstId in sorted( topo.edges() ):
src, dst = self.idToNode[ srcId ], self.idToNode[ dstId ]
srcPort, dstPort = topo.port( srcId, dstId )
ei = topo.edgeInfo( srcId, dstId )
link, params = ei.cls, ei.params
if not link:
link = self.link
link( src, dst, srcPort, dstPort, **params )
info( '(%s, %s) ' % ( src.name, dst.name ) )
addLink( srcId, dstId )
info( '\n' )
def configureControlNetwork( self ):
error( "configureControlNetwork: override in subclass, or use"
"MininetWithControlNet class" )
def build( self ):
"Build mininet."
if self.topo:
@@ -330,8 +282,6 @@ class Mininet( object ):
self.configHosts()
if self.xterms:
self.startTerms()
if self.autoSetMacs:
self.setMacs()
if self.autoStaticArp:
self.staticArp()
self.built = True
@@ -346,17 +296,10 @@ class Mininet( object ):
def stopXterms( self ):
"Kill each xterm."
# Kill xterms
for term in self.terms:
os.kill( term.pid, signal.SIGKILL )
cleanUpScreens()
def setMacs( self ):
"""Set MAC addrs to correspond to default MACs on hosts.
Assume that the host only has one interface."""
for host in self.hosts:
host.setMAC( host.intfs[ 0 ], host.defaultMAC )
def staticArp( self ):
"Add all-pairs ARP entries to remove the need to handle broadcast."
for src in self.hosts:
@@ -384,18 +327,19 @@ class Mininet( object ):
self.stopXterms()
info( '*** Stopping %i hosts\n' % len( self.hosts ) )
for host in self.hosts:
info( '%s ' % host.name )
info( host.name + ' ' )
host.terminate()
info( '\n' )
info( '*** Stopping %i switches\n' % len( self.switches ) )
for switch in self.switches:
info( switch.name )
info( switch.name + ' ' )
switch.stop()
info( '\n' )
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
for controller in self.controllers:
info( controller.name + ' ' )
controller.stop()
info( '*** Done\n' )
info( '\n*** Done\n' )
def run( self, test, *args, **kwargs ):
"Perform a complete start/test/stop cycle."
@@ -429,6 +373,9 @@ class Mininet( object ):
if not ready and timeoutms >= 0:
yield None, None
# XXX These test methods should be moved out of this class.
# Probably we should create a tests.py for them
@staticmethod
def _parsePing( pingOutput ):
"Parse ping output and return packets sent, received."
@@ -543,6 +490,8 @@ class Mininet( object ):
output( '*** Results: %s\n' % result )
return result
# BL: I think this can be rewritten now that we have
# a real link class.
def configLinkStatus( self, src, dst, status ):
"""Change status of src <-> dst links.
src: node name
@@ -573,6 +522,70 @@ class Mininet( object ):
return result
class MininetWithControlNet( Mininet ):
"""Control network support:
Create an explicit control network. Currently this is only
used/usable with the user datapath.
Notes:
1. If the controller and switches are in the same (e.g. root)
namespace, they can just use the loopback connection.
2. If we can get unix domain sockets to work, we can use them
instead of an explicit control network.
3. Instead of routing, we could bridge or use 'in-band' control.
4. Even if we dispense with this in general, it could still be
useful for people who wish to simulate a separate control
network (since real networks may need one!)
5. Basically nobody ever used this code, so it has been moved
into its own class."""
def configureControlNetwork( self ):
"Configure control network."
self.configureRoutedControlNetwork()
# We still need to figure out the right way to pass
# in the control network location.
def configureRoutedControlNetwork( self, ip='192.168.123.1',
prefixLen=16 ):
"""Configure a routed control network on controller and switches.
For use with the user datapath only right now."""
controller = self.controllers[ 0 ]
info( controller.name + ' <->' )
cip = ip
snum = ipParse( ip )
for switch in self.switches:
info( ' ' + switch.name )
sintf, cintf = createLink( switch, controller )
snum += 1
while snum & 0xff in [ 0, 255 ]:
snum += 1
sip = ipStr( snum )
controller.setIP( cintf, cip, prefixLen )
switch.setIP( sintf, sip, prefixLen )
controller.setHostRoute( sip, cintf )
switch.setHostRoute( cip, sintf )
info( '\n' )
info( '*** Testing control network\n' )
while not controller.intfIsUp( cintf ):
info( '*** Waiting for', cintf, 'to come up\n' )
sleep( 1 )
for switch in self.switches:
while not switch.intfIsUp( sintf ):
info( '*** Waiting for', sintf, 'to come up\n' )
sleep( 1 )
if self.ping( hosts=[ switch, controller ] ) != 0:
error( '*** Error: control network test failed\n' )
exit( 1 )
info( '\n' )
# pylint thinks inited is unused
# pylint: disable-msg=W0612
@@ -585,10 +598,6 @@ def init():
# Perhaps we should do so automatically!
print "*** Mininet must run as root."
exit( 1 )
# If which produces no output, then mnexec is not in the path.
# May want to loosen this to handle mnexec in the current dir.
if not quietRun( 'which mnexec' ):
raise Exception( "Could not find mnexec - check $PATH" )
fixLimits()
init.inited = True