Reinstantiated inNamespace and routed control network.
We need to figure out how to specify the IP addresses for the routed control network. For now I'm going back to 192.168.12x.y Also changed controller params to use IP strings rather than numbers. However, we still need to clarify what ControllerParams is actually for.
This commit is contained in:
+58
-54
@@ -90,10 +90,10 @@ from time import sleep
|
|||||||
|
|
||||||
from mininet.cli import CLI
|
from mininet.cli import CLI
|
||||||
from mininet.log import info, error, debug
|
from mininet.log import info, error, debug
|
||||||
from mininet.node import Host, KernelSwitch, OVSKernelSwitch, Controller
|
from mininet.node import Host, UserSwitch, KernelSwitch, Controller
|
||||||
from mininet.node import ControllerParams
|
from mininet.node import ControllerParams
|
||||||
from mininet.util import quietRun, fixLimits
|
from mininet.util import quietRun, fixLimits
|
||||||
from mininet.util import createLink, macColonHex
|
from mininet.util import createLink, macColonHex, ipStr, ipParse
|
||||||
from mininet.xterm import cleanUpScreens, makeXterms
|
from mininet.xterm import cleanUpScreens, makeXterms
|
||||||
|
|
||||||
DATAPATHS = [ 'kernel' ] #[ 'user', 'kernel' ]
|
DATAPATHS = [ 'kernel' ] #[ 'user', 'kernel' ]
|
||||||
@@ -130,7 +130,7 @@ class Mininet( object ):
|
|||||||
xterms: if build now, spawn xterms?
|
xterms: if build now, spawn xterms?
|
||||||
cleanup: if build now, cleanup before creating?
|
cleanup: if build now, cleanup before creating?
|
||||||
inNamespace: spawn switches and controller in net namespaces?
|
inNamespace: spawn switches and controller in net namespaces?
|
||||||
autoSetMacs: set MAC addrs to DPIDs?
|
autoSetMacs: set MAC addrs from topo?
|
||||||
autoStaticArp: set all-pairs static MAC addrs?"""
|
autoStaticArp: set all-pairs static MAC addrs?"""
|
||||||
self.switch = switch
|
self.switch = switch
|
||||||
self.host = host
|
self.host = host
|
||||||
@@ -151,8 +151,8 @@ class Mininet( object ):
|
|||||||
self.dps = 0 # number of created kernel datapaths
|
self.dps = 0 # number of created kernel datapaths
|
||||||
self.terms = [] # list of spawned xterm processes
|
self.terms = [] # list of spawned xterm processes
|
||||||
|
|
||||||
if topo and build:
|
if build:
|
||||||
self.buildFromTopo( self.topo )
|
self.build()
|
||||||
|
|
||||||
def addHost( self, name, mac=None, ip=None ):
|
def addHost( self, name, mac=None, ip=None ):
|
||||||
"""Add host.
|
"""Add host.
|
||||||
@@ -165,16 +165,18 @@ class Mininet( object ):
|
|||||||
self.nameToNode[ name ] = host
|
self.nameToNode[ name ] = host
|
||||||
return host
|
return host
|
||||||
|
|
||||||
def addSwitch( self, name, mac=None ):
|
def addSwitch( self, name, mac=None, ip=None ):
|
||||||
"""Add switch.
|
"""Add switch.
|
||||||
name: name of switch to add
|
name: name of switch to add
|
||||||
mac: default MAC address for kernel/OVS switch intf 0
|
mac: default MAC address for kernel/OVS switch intf 0
|
||||||
returns: added switch"""
|
returns: added switch"""
|
||||||
if self.switch is KernelSwitch or self.switch is OVSKernelSwitch:
|
if self.switch == UserSwitch:
|
||||||
sw = self.switch( name, dp=self.dps, defaultMAC=mac )
|
sw = self.switch( name, defaultMAC=mac, defaultIP=ip,
|
||||||
self.dps += 1
|
inNamespace=self.inNamespace )
|
||||||
else:
|
else:
|
||||||
sw = self.switch( name )
|
sw = self.switch( name, defaultMAC=mac, defaultIP=ip, dp=self.dps,
|
||||||
|
inNamespace=self.inNamespace )
|
||||||
|
self.dps += 1
|
||||||
self.switches.append( sw )
|
self.switches.append( sw )
|
||||||
self.nameToNode[ name ] = sw
|
self.nameToNode[ name ] = sw
|
||||||
return sw
|
return sw
|
||||||
@@ -206,43 +208,41 @@ class Mininet( object ):
|
|||||||
# useful for people who wish to simulate a separate control
|
# useful for people who wish to simulate a separate control
|
||||||
# network (since real networks may need one!)
|
# network (since real networks may need one!)
|
||||||
|
|
||||||
def _configureControlNetwork( self ):
|
def configureControlNetwork( self ):
|
||||||
"Configure control network."
|
"Configure control network."
|
||||||
self._configureRoutedControlNetwork()
|
self.configureRoutedControlNetwork()
|
||||||
|
|
||||||
def _configureRoutedControlNetwork( self ):
|
# 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.
|
"""Configure a routed control network on controller and switches.
|
||||||
For use with the user datapath only right now.
|
For use with the user datapath only right now.
|
||||||
TODO( brandonh ) test this code!
|
|
||||||
"""
|
"""
|
||||||
# params were: controller, switches, ips
|
|
||||||
|
|
||||||
controller = self.controllers[ 0 ]
|
controller = self.controllers[ 0 ]
|
||||||
info( '%s <-> ' % controller.name )
|
info( controller.name + ' <->' )
|
||||||
|
cip = ip
|
||||||
|
snum = ipParse( ip )
|
||||||
for switch in self.switches:
|
for switch in self.switches:
|
||||||
info( '%s ' % switch.name )
|
info( ' ' + switch.name )
|
||||||
sip = switch.defaultIP
|
sintf, cintf = createLink( switch, controller )
|
||||||
sintf = switch.intfs[ 0 ]
|
snum += 1
|
||||||
node, cintf = switch.connection[ sintf ]
|
while snum & 0xff in [ 0, 255 ]:
|
||||||
if node != controller:
|
snum += 1
|
||||||
error( '*** Error: switch %s not connected to correct'
|
sip = ipStr( snum )
|
||||||
'controller' %
|
controller.setIP( cintf, cip, prefixLen )
|
||||||
switch.name )
|
switch.setIP( sintf, sip, prefixLen )
|
||||||
exit( 1 )
|
|
||||||
controller.setIP( cintf, self.cparams.ip, self.cparams.prefixLen )
|
|
||||||
switch.setIP( sintf, sip, self.cparams.prefixLen )
|
|
||||||
controller.setHostRoute( sip, cintf )
|
controller.setHostRoute( sip, cintf )
|
||||||
switch.setHostRoute( self.cparams.ip, sintf )
|
switch.setHostRoute( cip, sintf )
|
||||||
info( '\n' )
|
info( '\n' )
|
||||||
info( '*** Testing control network\n' )
|
info( '*** Testing control network\n' )
|
||||||
while not controller.intfIsUp( controller.intfs[ 0 ] ):
|
while not controller.intfIsUp( cintf ):
|
||||||
info( '*** Waiting for %s to come up\n',
|
info( '*** Waiting for', cintf, 'to come up\n' )
|
||||||
controller.intfs[ 0 ] )
|
|
||||||
sleep( 1 )
|
sleep( 1 )
|
||||||
for switch in self.switches:
|
for switch in self.switches:
|
||||||
while not switch.intfIsUp( switch.intfs[ 0 ] ):
|
while not switch.intfIsUp( sintf ):
|
||||||
info( '*** Waiting for %s to come up\n' %
|
info( '*** Waiting for', sintf, 'to come up\n' )
|
||||||
switch.intfs[ 0 ] )
|
|
||||||
sleep( 1 )
|
sleep( 1 )
|
||||||
if self.ping( hosts=[ switch, controller ] ) != 0:
|
if self.ping( hosts=[ switch, controller ] ) != 0:
|
||||||
error( '*** Error: control network test failed\n' )
|
error( '*** Error: control network test failed\n' )
|
||||||
@@ -265,42 +265,47 @@ class Mininet( object ):
|
|||||||
"""Build mininet from a topology object
|
"""Build mininet from a topology object
|
||||||
At the end of this function, everything should be connected
|
At the end of this function, everything should be connected
|
||||||
and up."""
|
and up."""
|
||||||
|
|
||||||
|
def addNode( prefix, addMethod, nodeId ):
|
||||||
|
"Add a host or a switch."
|
||||||
|
name = prefix + topo.name( nodeId )
|
||||||
|
mac = macColonHex( nodeId ) if self.setMacs else None
|
||||||
|
ip = topo.ip( nodeId )
|
||||||
|
node = addMethod( name, mac=mac, ip=ip )
|
||||||
|
self.idToNode[ nodeId ] = node
|
||||||
|
info( name + ' ' )
|
||||||
|
|
||||||
|
# Possibly we should clean up here and/or validate
|
||||||
|
# the topo
|
||||||
if self.cleanup:
|
if self.cleanup:
|
||||||
pass # cleanup
|
pass
|
||||||
# validate topo?
|
|
||||||
info( '*** Adding controller\n' )
|
info( '*** Adding controller\n' )
|
||||||
self.addController( self.controller )
|
self.addController( self.controller )
|
||||||
info( '*** Creating network\n' )
|
info( '*** Creating network\n' )
|
||||||
info( '*** Adding hosts:\n' )
|
info( '*** Adding hosts:\n' )
|
||||||
for hostId in sorted( topo.hosts() ):
|
for hostId in sorted( topo.hosts() ):
|
||||||
name = 'h' + topo.name( hostId )
|
addNode( 'h', self.addHost, hostId )
|
||||||
mac = macColonHex( hostId ) if self.setMacs else None
|
|
||||||
ip = topo.ip( hostId )
|
|
||||||
host = self.addHost( name, ip=ip, mac=mac )
|
|
||||||
self.idToNode[ hostId ] = host
|
|
||||||
info( name + ' ' )
|
|
||||||
info( '\n*** Adding switches:\n' )
|
info( '\n*** Adding switches:\n' )
|
||||||
for switchId in sorted( topo.switches() ):
|
for switchId in sorted( topo.switches() ):
|
||||||
name = 's' + topo.name( switchId )
|
addNode( 's', self.addSwitch, switchId )
|
||||||
mac = macColonHex( switchId) if self.setMacs else None
|
|
||||||
switch = self.addSwitch( name, mac=mac )
|
|
||||||
self.idToNode[ switchId ] = switch
|
|
||||||
info( name + ' ' )
|
|
||||||
info( '\n*** Adding edges:\n' )
|
info( '\n*** Adding edges:\n' )
|
||||||
for srcId, dstId in sorted( topo.edges() ):
|
for srcId, dstId in sorted( topo.edges() ):
|
||||||
src, dst = self.idToNode[ srcId ], self.idToNode[ dstId ]
|
src, dst = self.idToNode[ srcId ], self.idToNode[ dstId ]
|
||||||
srcPort, dstPort = topo.port( srcId, dstId )
|
srcPort, dstPort = topo.port( srcId, dstId )
|
||||||
createLink( src, srcPort, dst, dstPort )
|
createLink( src, dst, srcPort, dstPort )
|
||||||
info( '(%s, %s) ' % ( src.name, dst.name ) )
|
info( '(%s, %s) ' % ( src.name, dst.name ) )
|
||||||
info( '\n' )
|
info( '\n' )
|
||||||
|
|
||||||
|
def build( self ):
|
||||||
|
"Build mininet."
|
||||||
|
if self.topo:
|
||||||
|
self.buildFromTopo( self.topo )
|
||||||
if self.inNamespace:
|
if self.inNamespace:
|
||||||
info( '*** Configuring control network\n' )
|
info( '*** Configuring control network\n' )
|
||||||
self._configureControlNetwork()
|
self.configureControlNetwork()
|
||||||
|
|
||||||
info( '*** Configuring hosts\n' )
|
info( '*** Configuring hosts\n' )
|
||||||
self.configHosts()
|
self.configHosts()
|
||||||
|
|
||||||
if self.xterms:
|
if self.xterms:
|
||||||
self.startXterms()
|
self.startXterms()
|
||||||
if self.autoSetMacs:
|
if self.autoSetMacs:
|
||||||
@@ -391,8 +396,7 @@ class Mininet( object ):
|
|||||||
"""Ping between all specified hosts.
|
"""Ping between all specified hosts.
|
||||||
hosts: list of hosts
|
hosts: list of hosts
|
||||||
returns: ploss packet loss percentage"""
|
returns: ploss packet loss percentage"""
|
||||||
#self.start()
|
# should we check if running?
|
||||||
# check if running - only then, start?
|
|
||||||
packets = 0
|
packets = 0
|
||||||
lost = 0
|
lost = 0
|
||||||
ploss = None
|
ploss = None
|
||||||
|
|||||||
+72
-37
@@ -49,8 +49,7 @@ from subprocess import Popen, PIPE, STDOUT
|
|||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
from mininet.log import info, error, debug
|
from mininet.log import info, error, debug
|
||||||
from mininet.util import quietRun, moveIntf
|
from mininet.util import quietRun, makeIntfPair, moveIntf
|
||||||
|
|
||||||
|
|
||||||
class Node( object ):
|
class Node( object ):
|
||||||
"""A virtual network node is simply a shell in a network namespace.
|
"""A virtual network node is simply a shell in a network namespace.
|
||||||
@@ -84,7 +83,6 @@ class Node( object ):
|
|||||||
self.outToNode[ self.stdout.fileno() ] = self
|
self.outToNode[ self.stdout.fileno() ] = self
|
||||||
self.inToNode[ self.stdin.fileno() ] = self
|
self.inToNode[ self.stdin.fileno() ] = self
|
||||||
self.pid = self.shell.pid
|
self.pid = self.shell.pid
|
||||||
self.intfCount = 0
|
|
||||||
self.intfs = {} # dict of port numbers to interface names
|
self.intfs = {} # dict of port numbers to interface names
|
||||||
self.ports = {} # dict of interface names to port numbers
|
self.ports = {} # dict of interface names to port numbers
|
||||||
# replace with Port objects, eventually ?
|
# replace with Port objects, eventually ?
|
||||||
@@ -206,11 +204,11 @@ class Node( object ):
|
|||||||
"Construct a canonical interface name node-ethN for interface n."
|
"Construct a canonical interface name node-ethN for interface n."
|
||||||
return self.name + '-eth' + repr( n )
|
return self.name + '-eth' + repr( n )
|
||||||
|
|
||||||
def newIntf( self ):
|
def newPort( self ):
|
||||||
"Reserve and return a new interface name."
|
"Return the next port number to allocate."
|
||||||
intfName = self.intfName( self.intfCount )
|
if len( self.ports ) > 0:
|
||||||
self.intfCount += 1
|
return max( self.ports.values() ) + 1
|
||||||
return intfName
|
return 0
|
||||||
|
|
||||||
def addIntf( self, intf, port ):
|
def addIntf( self, intf, port ):
|
||||||
"""Add an interface.
|
"""Add an interface.
|
||||||
@@ -219,21 +217,47 @@ class Node( object ):
|
|||||||
self.intfs[ port ] = intf
|
self.intfs[ port ] = intf
|
||||||
self.ports[ intf ] = port
|
self.ports[ intf ] = port
|
||||||
#info( '\n' )
|
#info( '\n' )
|
||||||
#info( 'added intf %s to node %x\n' % ( srcIntf, src ) )
|
#info( 'added intf %s:%d to node %s\n' % ( intf,port, self.name ) )
|
||||||
if self.inNamespace:
|
if self.inNamespace:
|
||||||
#info( 'moving w/inNamespace set\n' )
|
#info( 'moving w/inNamespace set\n' )
|
||||||
moveIntf( intf, self )
|
moveIntf( intf, self )
|
||||||
|
|
||||||
def connect( self, intf, dstNode, dstIntf ):
|
def registerIntf( self, intf, dstNode, dstIntf ):
|
||||||
"Register connection of intf to dstIntf on dstNode."
|
"Register connection of intf to dstIntf on dstNode."
|
||||||
self.connection[ intf ] = ( dstNode, dstIntf )
|
self.connection[ intf ] = ( dstNode, dstIntf )
|
||||||
|
|
||||||
|
# This is a symmetric operation, but it makes sense to put
|
||||||
|
# the code here since it is tightly coupled to routines in
|
||||||
|
# this class. For a more symmetric API, you can use
|
||||||
|
# mininet.util.createLink()
|
||||||
|
|
||||||
|
def linkTo( self, node2, port1=None, port2=None ):
|
||||||
|
"""Create link to another node, making two new interfaces.
|
||||||
|
node2: Node to link us to
|
||||||
|
port1: our port number (optional)
|
||||||
|
port2: node2 port number (optional)
|
||||||
|
returns: intf1 name, intf2 name"""
|
||||||
|
node1 = self
|
||||||
|
if port1 is None:
|
||||||
|
port1 = node1.newPort()
|
||||||
|
if port2 is None:
|
||||||
|
port2 = node2.newPort()
|
||||||
|
intf1 = node1.intfName( port1 )
|
||||||
|
intf2 = node2.intfName( port2 )
|
||||||
|
makeIntfPair( intf1, intf2 )
|
||||||
|
node1.addIntf( intf1, port1 )
|
||||||
|
node2.addIntf( intf2, port2 )
|
||||||
|
node1.registerIntf( intf1, node2, intf2 )
|
||||||
|
node2.registerIntf( intf2, node1, intf1 )
|
||||||
|
return intf1, intf2
|
||||||
|
|
||||||
def deleteIntfs( self ):
|
def deleteIntfs( self ):
|
||||||
"Delete all of our interfaces."
|
"Delete all of our interfaces."
|
||||||
# In theory the interfaces should go away after we shut down.
|
# In theory the interfaces should go away after we shut down.
|
||||||
# However, this takes time, so we're better off removing them
|
# However, this takes time, so we're better off removing them
|
||||||
# explicitly so that we won't get errors if we run before they
|
# explicitly so that we won't get errors if we run before they
|
||||||
# have been removed by the kernel. Unfortunately this is very slow.
|
# have been removed by the kernel. Unfortunately this is very slow,
|
||||||
|
# at least with Linux kernels before 2.6.33
|
||||||
for intf in self.intfs.values():
|
for intf in self.intfs.values():
|
||||||
quietRun( 'ip link del ' + intf )
|
quietRun( 'ip link del ' + intf )
|
||||||
info( '.' )
|
info( '.' )
|
||||||
@@ -255,7 +279,7 @@ class Node( object ):
|
|||||||
result = self.cmd( [ 'arp', '-s', ip, mac ] )
|
result = self.cmd( [ 'arp', '-s', ip, mac ] )
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def setIP( self, intf, ip, prefixLen ):
|
def setIP( self, intf, ip, prefixLen=8 ):
|
||||||
"""Set the IP address for an interface.
|
"""Set the IP address for an interface.
|
||||||
intf: interface name
|
intf: interface name
|
||||||
ip: IP address as a string
|
ip: IP address as a string
|
||||||
@@ -277,23 +301,25 @@ class Node( object ):
|
|||||||
self.cmd( 'ip route flush' )
|
self.cmd( 'ip route flush' )
|
||||||
return self.cmd( 'route add default ' + intf )
|
return self.cmd( 'route add default ' + intf )
|
||||||
|
|
||||||
def IP( self ):
|
def IP( self, intf=None ):
|
||||||
"Return IP address of interface 0"
|
"Return IP address of a node or specific interface."
|
||||||
return self.ips.get( self.intfs.get( 0 , None ), None )
|
if len( self.ips ) == 1:
|
||||||
|
return self.ips.values()[ 0 ]
|
||||||
|
if intf:
|
||||||
|
return self.ips.get( intf, None )
|
||||||
|
|
||||||
def MAC( self ):
|
def MAC( self, intf=None ):
|
||||||
"Return MAC address of interface 0"
|
"Return MAC address of a node or specific interface."
|
||||||
ifconfig = self.cmd( 'ifconfig ' + self.intfs[ 0 ] )
|
if intf is None and len( self.intfs ) == 1:
|
||||||
|
intf = self.intfs.values()[ 0 ]
|
||||||
|
ifconfig = self.cmd( 'ifconfig ' + intf )
|
||||||
macs = re.findall( '..:..:..:..:..:..', ifconfig )
|
macs = re.findall( '..:..:..:..:..:..', ifconfig )
|
||||||
if len( macs ) > 0:
|
if len( macs ) > 0:
|
||||||
return macs[ 0 ]
|
return macs[ 0 ]
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def intfIsUp( self, port ):
|
def intfIsUp( self, intf ):
|
||||||
"""Check if interface for a given port number is up.
|
"Check if an interface is up."
|
||||||
port: port number"""
|
return 'UP' in self.cmd( 'ifconfig ' + intf )
|
||||||
return 'UP' in self.cmd( 'ifconfig ' + self.intfs[ port ] )
|
|
||||||
|
|
||||||
# Other methods
|
# Other methods
|
||||||
def __str__( self ):
|
def __str__( self ):
|
||||||
@@ -331,13 +357,12 @@ class Switch( Node ):
|
|||||||
|
|
||||||
|
|
||||||
class UserSwitch( Switch ):
|
class UserSwitch( Switch ):
|
||||||
"""User-space switch.
|
"User-space switch."
|
||||||
Currently only works in the root namespace."""
|
|
||||||
|
|
||||||
def __init__( self, name, *args, **kwargs ):
|
def __init__( self, name, *args, **kwargs ):
|
||||||
"""Init.
|
"""Init.
|
||||||
name: name for the switch"""
|
name: name for the switch"""
|
||||||
Switch.__init__( self, name, inNamespace=False, **kwargs )
|
Switch.__init__( self, name, **kwargs )
|
||||||
|
|
||||||
def start( self, controllers ):
|
def start( self, controllers ):
|
||||||
"""Start OpenFlow reference user datapath.
|
"""Start OpenFlow reference user datapath.
|
||||||
@@ -348,7 +373,8 @@ class UserSwitch( Switch ):
|
|||||||
ofplog = '/tmp/' + self.name + '-ofp.log'
|
ofplog = '/tmp/' + self.name + '-ofp.log'
|
||||||
self.cmd( 'ifconfig lo up' )
|
self.cmd( 'ifconfig lo up' )
|
||||||
intfs = sorted( self.intfs.values() )
|
intfs = sorted( self.intfs.values() )
|
||||||
|
if self.inNamespace:
|
||||||
|
intfs = intfs[ :-1 ]
|
||||||
self.cmd( 'ofdatapath -i ' + ','.join( intfs ) +
|
self.cmd( 'ofdatapath -i ' + ','.join( intfs ) +
|
||||||
' punix:/tmp/' + self.name +
|
' punix:/tmp/' + self.name +
|
||||||
' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
|
' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
|
||||||
@@ -364,15 +390,19 @@ class UserSwitch( Switch ):
|
|||||||
|
|
||||||
class KernelSwitch( Switch ):
|
class KernelSwitch( Switch ):
|
||||||
"""Kernel-space switch.
|
"""Kernel-space switch.
|
||||||
Currently only works in the root namespace."""
|
Currently only works in root namespace."""
|
||||||
|
|
||||||
def __init__( self, name, dp=None, **kwargs ):
|
def __init__( self, name, dp=None, **kwargs ):
|
||||||
"""Init.
|
"""Init.
|
||||||
name:
|
name:
|
||||||
dp: netlink id (0, 1, 2, ...)
|
dp: netlink id (0, 1, 2, ...)
|
||||||
defaultMAC: default MAC as string; random value if None"""
|
defaultMAC: default MAC as string; random value if None"""
|
||||||
Switch.__init__( self, name, inNamespace=False, **kwargs )
|
Switch.__init__( self, name, **kwargs )
|
||||||
self.dp = dp
|
self.dp = dp
|
||||||
|
if self.inNamespace:
|
||||||
|
error( "KernelSwitch currently only works"
|
||||||
|
" in the root namespace." )
|
||||||
|
exit( 1 )
|
||||||
|
|
||||||
def start( self, controllers ):
|
def start( self, controllers ):
|
||||||
"Start up reference kernel datapath."
|
"Start up reference kernel datapath."
|
||||||
@@ -385,7 +415,6 @@ class KernelSwitch( Switch ):
|
|||||||
if self.defaultMAC:
|
if self.defaultMAC:
|
||||||
intf = 'of%i' % self.dp
|
intf = 'of%i' % self.dp
|
||||||
self.cmd( [ 'ifconfig', intf, 'hw', 'ether', self.defaultMAC ] )
|
self.cmd( [ 'ifconfig', intf, 'hw', 'ether', self.defaultMAC ] )
|
||||||
|
|
||||||
if len( self.intfs ) != max( self.intfs ) + 1:
|
if len( self.intfs ) != max( self.intfs ) + 1:
|
||||||
raise Exception( 'only contiguous, zero-indexed port ranges'
|
raise Exception( 'only contiguous, zero-indexed port ranges'
|
||||||
'supported: %s' % self.intfs )
|
'supported: %s' % self.intfs )
|
||||||
@@ -412,11 +441,15 @@ class OVSKernelSwitch( Switch ):
|
|||||||
|
|
||||||
def __init__( self, name, dp=None, **kwargs ):
|
def __init__( self, name, dp=None, **kwargs ):
|
||||||
"""Init.
|
"""Init.
|
||||||
name:
|
name: name of switch
|
||||||
dp: netlink id (0, 1, 2, ...)
|
dp: netlink id (0, 1, 2, ...)
|
||||||
dpid: datapath ID as unsigned int; random value if None"""
|
defaultMAC: default MAC as unsigned int; random value if None"""
|
||||||
Switch.__init__( self, name, inNamespace=False, **kwargs )
|
Switch.__init__( self, name, **kwargs )
|
||||||
self.dp = dp
|
self.dp = dp
|
||||||
|
if self.inNamespace:
|
||||||
|
error( "OVSKernelSwitch currently only works"
|
||||||
|
" in the root namespace." )
|
||||||
|
exit( 1 )
|
||||||
|
|
||||||
def start( self, controllers ):
|
def start( self, controllers ):
|
||||||
"Start up kernel datapath."
|
"Start up kernel datapath."
|
||||||
@@ -480,10 +513,12 @@ class Controller( Node ):
|
|||||||
self.cmd( 'kill %' + self.controller )
|
self.cmd( 'kill %' + self.controller )
|
||||||
self.terminate()
|
self.terminate()
|
||||||
|
|
||||||
def IP( self ):
|
def IP( self, intf=None ):
|
||||||
"Return IP address of the Controller"
|
"Return IP address of the Controller"
|
||||||
return self.defaultIP
|
ip = Node.IP( self, intf=intf )
|
||||||
|
if ip is None:
|
||||||
|
ip = self.defaultIP
|
||||||
|
return ip
|
||||||
|
|
||||||
class ControllerParams( object ):
|
class ControllerParams( object ):
|
||||||
"Container for controller IP parameters."
|
"Container for controller IP parameters."
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class testSingleSwitch( unittest.TestCase ):
|
|||||||
"Ping test with both datapaths on minimal topology"
|
"Ping test with both datapaths on minimal topology"
|
||||||
init()
|
init()
|
||||||
for switch in SWITCHES.values():
|
for switch in SWITCHES.values():
|
||||||
controllerParams = ControllerParams( 0x0a000000, 8 ) # 10.0.0.0/8
|
controllerParams = ControllerParams( '10.0.0.0', 8 )
|
||||||
mn = Mininet( SingleSwitchTopo(), switch, Host, Controller,
|
mn = Mininet( SingleSwitchTopo(), switch, Host, Controller,
|
||||||
controllerParams )
|
controllerParams )
|
||||||
dropped = mn.run( 'ping' )
|
dropped = mn.run( 'ping' )
|
||||||
@@ -30,7 +30,7 @@ class testSingleSwitch( unittest.TestCase ):
|
|||||||
"Ping test with both datapaths on 5-host single-switch topology"
|
"Ping test with both datapaths on 5-host single-switch topology"
|
||||||
init()
|
init()
|
||||||
for switch in SWITCHES.values():
|
for switch in SWITCHES.values():
|
||||||
controllerParams = ControllerParams( 0x0a000000, 8 ) # 10.0.0.0/8
|
controllerParams = ControllerParams( '10.0.0.0', 8 )
|
||||||
mn = Mininet( SingleSwitchTopo( k=5 ), switch, Host, Controller,
|
mn = Mininet( SingleSwitchTopo( k=5 ), switch, Host, Controller,
|
||||||
controllerParams )
|
controllerParams )
|
||||||
dropped = mn.run( 'ping' )
|
dropped = mn.run( 'ping' )
|
||||||
@@ -44,7 +44,7 @@ class testLinear( unittest.TestCase ):
|
|||||||
"Ping test with both datapaths on a 5-switch topology"
|
"Ping test with both datapaths on a 5-switch topology"
|
||||||
init()
|
init()
|
||||||
for switch in SWITCHES.values():
|
for switch in SWITCHES.values():
|
||||||
controllerParams = ControllerParams( 0x0a000000, 8 ) # 10.0.0.0/8
|
controllerParams = ControllerParams( '10.0.0.0', 8 )
|
||||||
mn = Mininet( LinearTopo( k=5 ), switch, Host, Controller,
|
mn = Mininet( LinearTopo( k=5 ), switch, Host, Controller,
|
||||||
controllerParams )
|
controllerParams )
|
||||||
dropped = mn.run( 'ping' )
|
dropped = mn.run( 'ping' )
|
||||||
|
|||||||
+23
-18
@@ -101,21 +101,14 @@ def moveIntf( intf, node, printError=False, retries=3, delaySecs=0.001 ):
|
|||||||
printError: if true, print error"""
|
printError: if true, print error"""
|
||||||
retry( retries, delaySecs, moveIntfNoRetry, intf, node, printError )
|
retry( retries, delaySecs, moveIntfNoRetry, intf, node, printError )
|
||||||
|
|
||||||
def createLink( node1, port1, node2, port2 ):
|
def createLink( node1, node2, port1=None, port2=None ):
|
||||||
"""Create a link between nodes, making an interface for each.
|
"""Create a link between nodes, making an interface for each.
|
||||||
node1: Node object
|
node1: Node object
|
||||||
port1: node1 port number
|
|
||||||
node2: Node object
|
node2: Node object
|
||||||
port2: node2 port number
|
port1: node1 port number (optional)
|
||||||
|
port2: node2 port number (optional)
|
||||||
returns: intf1 name, intf2 name"""
|
returns: intf1 name, intf2 name"""
|
||||||
intf1 = node1.intfName( port1 )
|
return node1.linkTo( node2, port1, port2 )
|
||||||
intf2 = node2.intfName( port2 )
|
|
||||||
makeIntfPair( intf1, intf2 )
|
|
||||||
node1.addIntf( intf1, port1 )
|
|
||||||
node2.addIntf( intf2, port2 )
|
|
||||||
node1.connect( intf1, node2, intf2 )
|
|
||||||
node2.connect( intf2, node1, intf1 )
|
|
||||||
return intf1, intf2
|
|
||||||
|
|
||||||
def fixLimits():
|
def fixLimits():
|
||||||
"Fix ridiculously small resource limits."
|
"Fix ridiculously small resource limits."
|
||||||
@@ -141,10 +134,22 @@ def macColonHex( mac ):
|
|||||||
return _colonHex( mac, 6 )
|
return _colonHex( mac, 6 )
|
||||||
|
|
||||||
def ipStr( ip ):
|
def ipStr( ip ):
|
||||||
"""Generate IP address string from an unsigned int
|
"""Generate IP address string from an unsigned int.
|
||||||
ip: unsigned int of form x << 16 | y << 8 | z
|
ip: unsigned int of form w << 24 | x << 16 | y << 8 | z
|
||||||
returns: ip address string 10.x.y.z """
|
returns: ip address string w.x.y.z, or 10.x.y.z if w==0"""
|
||||||
hi = ( ip & 0xff0000 ) >> 16
|
w = ( ip & 0xff000000 ) >> 24
|
||||||
mid = ( ip & 0xff00 ) >> 8
|
w = 10 if w == 0 else w
|
||||||
lo = ip & 0xff
|
x = ( ip & 0xff0000 ) >> 16
|
||||||
return "10.%i.%i.%i" % ( hi, mid, lo )
|
y = ( ip & 0xff00 ) >> 8
|
||||||
|
z = ip & 0xff
|
||||||
|
return "%i.%i.%i.%i" % ( w, x, y, z )
|
||||||
|
|
||||||
|
def ipNum( w, x, y, z ):
|
||||||
|
"""Generate unsigned int from components ofIP address
|
||||||
|
returns: w << 24 | x << 16 | y << 8 | z"""
|
||||||
|
return ( w << 24 ) | ( x << 16 ) | ( y << 8 ) | z
|
||||||
|
|
||||||
|
def ipParse( ip ):
|
||||||
|
"Parse an IP address and return an unsigned int."
|
||||||
|
args = [ int( arg ) for arg in ip.split( '.' ) ]
|
||||||
|
return ipNum( *args )
|
||||||
|
|||||||
Reference in New Issue
Block a user