Changed setIP to accept numeric prefix len. Added Node.deleteIntfs().

This commit is contained in:
Bob Lantz
2010-03-04 16:53:39 -08:00
parent 48a8d297d1
commit 086ef80e8e
2 changed files with 70 additions and 69 deletions
+20 -24
View File
@@ -82,7 +82,8 @@ 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 KernelSwitch, OVSKernelSwitch from mininet.node import Host, KernelSwitch, OVSKernelSwitch, Controller
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
from mininet.xterm import cleanUpScreens, makeXterms from mininet.xterm import cleanUpScreens, makeXterms
@@ -105,7 +106,9 @@ def init():
class Mininet( object ): class Mininet( object ):
"Network emulation with hosts spawned in network namespaces." "Network emulation with hosts spawned in network namespaces."
def __init__( self, topo, switch, host, controller, cparams, def __init__( self, topo, switch=KernelSwitch, host=Host,
controller=Controller,
cparams=ControllerParams( '10.0.0.0', 8 ),
build=True, xterms=False, cleanup=False, build=True, xterms=False, cleanup=False,
inNamespace=False, inNamespace=False,
autoSetMacs=False, autoStaticArp=False ): autoSetMacs=False, autoStaticArp=False ):
@@ -143,29 +146,24 @@ class Mininet( object ):
if topo and build: if topo and build:
self.buildFromTopo( self.topo ) self.buildFromTopo( self.topo )
def addHost( self, name, defaultMac=None, defaultIp=None ): def addHost( self, name, mac=None, ip=None ):
"""Add host. """Add host.
name: name of host to add name: name of host to add
defaultMac: default MAC address for intf 0 mac: default MAC address for intf 0
defaultIp: default IP address for intf 0 ip: default IP address for intf 0
returns: added host""" returns: added host"""
host = self.host( name ) host = self.host( name, defaultMAC=mac, defaultIP=ip )
self.hosts.append( host ) self.hosts.append( host )
self.nameToNode[ name ] = host self.nameToNode[ name ] = host
# May wish to add this to actual object
if defaultMac:
host.defaultMac = defaultMac
if defaultIp:
host.defaultIP = defaultIp
return host return host
def addSwitch( self, name, defaultMac=None ): def addSwitch( self, name, mac=None ):
"""Add switch. """Add switch.
name: name of switch to add name: name of switch to add
defaultMac: 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 is KernelSwitch or self.switch is OVSKernelSwitch:
sw = self.switch( name, dp=self.dps, defaultMac=defaultMac ) sw = self.switch( name, dp=self.dps, defaultMAC=mac )
self.dps += 1 self.dps += 1
else: else:
sw = self.switch( name ) sw = self.switch( name )
@@ -225,9 +223,8 @@ class Mininet( object ):
'controller' % 'controller' %
switch.name ) switch.name )
exit( 1 ) exit( 1 )
controller.setIP( cintf, self.cparams.ip, '/' + controller.setIP( cintf, self.cparams.ip, self.cparams.prefixLen )
self.cparams.subnetSize ) switch.setIP( sintf, sip, self.cparams.prefixLen )
switch.setIP( sintf, sip, '/' + self.cparams.subnetSize )
controller.setHostRoute( sip, cintf ) controller.setHostRoute( sip, cintf )
switch.setHostRoute( self.cparams.ip, sintf ) switch.setHostRoute( self.cparams.ip, sintf )
info( '\n' ) info( '\n' )
@@ -251,12 +248,11 @@ class Mininet( object ):
# params were: hosts, ips # params were: hosts, ips
for host in self.hosts: for host in self.hosts:
hintf = host.intfs[ 0 ] hintf = host.intfs[ 0 ]
host.setIP( hintf, host.defaultIP, host.setIP( hintf, host.defaultIP, self.cparams.prefixLen )
'/' + str( self.cparams.subnetSize ) )
host.setDefaultRoute( hintf ) host.setDefaultRoute( hintf )
# You're low priority, dude! # You're low priority, dude!
quietRun( 'renice +18 -p ' + repr( host.pid ) ) quietRun( 'renice +18 -p ' + repr( host.pid ) )
info( '%s ', host.name ) info( host.name + ' ' )
info( '\n' ) info( '\n' )
def buildFromTopo( self, topo ): def buildFromTopo( self, topo ):
@@ -274,14 +270,14 @@ class Mininet( object ):
name = 'h' + topo.name( hostId ) name = 'h' + topo.name( hostId )
mac = macColonHex( hostId ) if self.setMacs else None mac = macColonHex( hostId ) if self.setMacs else None
ip = topo.ip( hostId ) ip = topo.ip( hostId )
host = self.addHost( name, defaultIp=ip, defaultMac=mac ) host = self.addHost( name, ip=ip, mac=mac )
self.idToNode[ hostId ] = host self.idToNode[ hostId ] = host
info( name + ' ' ) 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 ) name = 's' + topo.name( switchId )
mac = macColonHex( switchId) if self.setMacs else None mac = macColonHex( switchId) if self.setMacs else None
switch = self.addSwitch( name, defaultMac=mac ) switch = self.addSwitch( name, mac=mac )
self.idToNode[ switchId ] = switch self.idToNode[ switchId ] = switch
info( name + ' ' ) info( name + ' ' )
info( '\n*** Adding edges:\n' ) info( '\n*** Adding edges:\n' )
@@ -325,14 +321,14 @@ class Mininet( object ):
"""Set MAC addrs to correspond to datapath IDs on hosts. """Set MAC addrs to correspond to datapath IDs on hosts.
Assume that the host only has one interface.""" Assume that the host only has one interface."""
for host in self.hosts: for host in self.hosts:
host.setMAC( host.intfs[ 0 ], host.defaultMac ) host.setMAC( host.intfs[ 0 ], host.defaultMAC )
def staticArp( self ): def staticArp( self ):
"Add all-pairs ARP entries to remove the need to handle broadcast." "Add all-pairs ARP entries to remove the need to handle broadcast."
for src in self.hosts: for src in self.hosts:
for dst in self.hosts: for dst in self.hosts:
if src != dst: if src != dst:
src.setARP( ip=dst.IP(), mac=dst.defaultMac ) src.setARP( ip=dst.IP(), mac=dst.defaultMAC )
def start( self ): def start( self ):
"Start controller and switches" "Start controller and switches"
+50 -45
View File
@@ -39,6 +39,7 @@ from subprocess import Popen, PIPE, STDOUT
import os import os
import signal import signal
import select import select
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, moveIntf
@@ -51,7 +52,12 @@ class Node( object ):
inToNode = {} # mapping of input fds to nodes inToNode = {} # mapping of input fds to nodes
outToNode = {} # mapping of output fds to nodes outToNode = {} # mapping of output fds to nodes
def __init__( self, name, inNamespace=True ): def __init__( self, name, inNamespace=True,
defaultMAC=None, defaultIP=None ):
"""name: name of node
inNamespace: in network namespace?
defaultMAC: default MAC address for intf 0
defaultIP: default IP address for intf 0"""
self.name = name self.name = name
closeFds = False # speed vs. memory use closeFds = False # speed vs. memory use
# xpg_echo is needed so we can echo our sentinel in sendCmd # xpg_echo is needed so we can echo our sentinel in sendCmd
@@ -79,6 +85,8 @@ class Node( object ):
self.connection = {} # remote node connected to each interface self.connection = {} # remote node connected to each interface
self.waiting = False self.waiting = False
self.execed = False self.execed = False
self.defaultIP = defaultIP
self.defaultMAC = defaultMAC
@classmethod @classmethod
def fdToNode( cls, fd ): def fdToNode( cls, fd ):
@@ -213,6 +221,19 @@ class Node( object ):
"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 )
def deleteIntfs( self ):
"Delete all of our interfaces."
# In theory the interfaces should go away after we shut down.
# However, this takes time, so we're better off removing them
# explicitly so that we won't get errors if we run before they
# have been removed by the kernel. Unfortunately this is very slow.
self.cmd( 'kill %ofprotocol' )
for intf in self.intfs.values():
quietRun( 'ip link del ' + intf )
info( '.' )
# Does it help to sleep to let things run?
sleep( 0.001 )
def setMAC( self, intf, mac ): def setMAC( self, intf, mac ):
"""Set the MAC address for an interface. """Set the MAC address for an interface.
mac: MAC address as string""" mac: MAC address as string"""
@@ -228,12 +249,13 @@ 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, bits ): def setIP( self, intf, ip, prefixLen ):
"""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
bits: prefix length of form /24""" prefixLen: prefix length, e.g. 8 for /8 or 16M addrs"""
result = self.cmd( [ 'ifconfig', intf, ip + bits, 'up' ] ) ipSub = '%s/%d' % ( ip, prefixLen )
result = self.cmd( [ 'ifconfig', intf, ipSub, 'up' ] )
self.ips[ intf ] = ip self.ips[ intf ] = ip
return result return result
@@ -297,10 +319,10 @@ class UserSwitch( Switch ):
"""User-space switch. """User-space switch.
Currently only works in the root namespace.""" Currently only works in the root namespace."""
def __init__( self, name ): def __init__( self, name, *args, **kwargs ):
"""Init. """Init.
name: name for the switch""" name: name for the switch"""
Switch.__init__( self, name, inNamespace=False ) Switch.__init__( self, name, inNamespace=False, **kwargs )
def start( self, controllers ): def start( self, controllers ):
"""Start OpenFlow reference user datapath. """Start OpenFlow reference user datapath.
@@ -323,20 +345,19 @@ class UserSwitch( Switch ):
"Stop OpenFlow reference user datapath." "Stop OpenFlow reference user datapath."
self.cmd( 'kill %ofdatapath' ) self.cmd( 'kill %ofdatapath' )
self.cmd( 'kill %ofprotocol' ) self.cmd( 'kill %ofprotocol' )
self.deleteIntfs()
class KernelSwitch( Switch ): class KernelSwitch( Switch ):
"""Kernel-space switch. """Kernel-space switch.
Currently only works in the root namespace.""" Currently only works in the root namespace."""
def __init__( self, name, dp=None, defaultMac=None ): 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 ) Switch.__init__( self, name, inNamespace=False, **kwargs )
self.dp = dp self.dp = dp
self.defaultMac = defaultMac
def start( self, controllers ): def start( self, controllers ):
"Start up reference kernel datapath." "Start up reference kernel datapath."
@@ -346,9 +367,9 @@ class KernelSwitch( Switch ):
# then create a new one monitoring the given interfaces # then create a new one monitoring the given interfaces
quietRun( 'dpctl deldp nl:%i' % self.dp ) quietRun( 'dpctl deldp nl:%i' % self.dp )
self.cmd( 'dpctl adddp nl:%i' % self.dp ) self.cmd( 'dpctl adddp nl:%i' % self.dp )
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'
@@ -367,28 +388,19 @@ class KernelSwitch( Switch ):
def stop( self ): def stop( self ):
"Terminate kernel datapath." "Terminate kernel datapath."
quietRun( 'dpctl deldp nl:%i' % self.dp ) quietRun( 'dpctl deldp nl:%i' % self.dp )
# In theory the interfaces should go away after we shut down. self.deleteIntfs()
# However, this takes time, so we're better off removing them
# explicitly so that we won't get errors if we run before they
# have been removed by the kernel. Unfortunately this is very slow.
self.cmd( 'kill %ofprotocol' )
for intf in self.intfs.values():
quietRun( 'ip link del ' + intf )
info( '.' )
class OVSKernelSwitch( Switch ): class OVSKernelSwitch( Switch ):
"""Open VSwitch kernel-space switch. """Open VSwitch kernel-space switch.
Currently only works in the root namespace.""" Currently only works in the root namespace."""
def __init__( self, name, dp=None, defaultMac=None ): def __init__( self, name, dp=None, **kwargs ):
"""Init. """Init.
name: name:
dp: netlink id (0, 1, 2, ...) dp: netlink id (0, 1, 2, ...)
dpid: datapath ID as unsigned int; random value if None""" dpid: datapath ID as unsigned int; random value if None"""
Switch.__init__( self, name, inNamespace=False ) Switch.__init__( self, name, inNamespace=False, **kwargs )
self.dp = dp self.dp = dp
self.defaultMac = defaultMac
def start( self, controllers ): def start( self, controllers ):
"Start up kernel datapath." "Start up kernel datapath."
@@ -398,9 +410,9 @@ class OVSKernelSwitch( Switch ):
# then create a new one monitoring the given interfaces # then create a new one monitoring the given interfaces
quietRun( 'ovs-dpctl del-dp dp%i' % self.dp ) quietRun( 'ovs-dpctl del-dp dp%i' % self.dp )
self.cmd( 'ovs-dpctl add-dp dp%i' % self.dp ) self.cmd( 'ovs-dpctl add-dp dp%i' % self.dp )
if self.defaultMac: if self.defaultMAC:
intf = 'dp' % self.dp intf = 'dp' % self.dp
mac = self.defaultMac mac = self.defaultMAC
self.cmd( [ 'ifconfig', intf, 'hw', 'ether', mac ] ) self.cmd( [ 'ifconfig', intf, 'hw', 'ether', mac ] )
if len( self.intfs ) != max( self.intfs ) + 1: if len( self.intfs ) != max( self.intfs ) + 1:
@@ -419,14 +431,7 @@ class OVSKernelSwitch( Switch ):
def stop( self ): def stop( self ):
"Terminate kernel datapath." "Terminate kernel datapath."
quietRun( 'ovs-dpctl del-dp dp%i' % self.dp ) quietRun( 'ovs-dpctl del-dp dp%i' % self.dp )
# In theory the interfaces should go away after we shut down. self.deleteIntfs()
# However, this takes time, so we're better off removing them
# explicitly so that we won't get errors if we run before they
# have been removed by the kernel. Unfortunately this is very slow.
self.cmd( 'kill %ovs-openflowd' )
for intf in self.intfs.values():
quietRun( 'ip link del ' + intf )
info( '.' )
class Controller( Node ): class Controller( Node ):
@@ -434,14 +439,14 @@ class Controller( Node ):
OpenFlow controller.""" OpenFlow controller."""
def __init__( self, name, inNamespace=False, controller='controller', def __init__( self, name, inNamespace=False, controller='controller',
cargs='-v ptcp:', cdir=None, ipAddress="127.0.0.1", cargs='-v ptcp:', cdir=None, defaultIP="127.0.0.1",
port=6633 ): port=6633 ):
self.controller = controller self.controller = controller
self.cargs = cargs self.cargs = cargs
self.cdir = cdir self.cdir = cdir
self.ipAddress = ipAddress
self.port = port self.port = port
Node.__init__( self, name, inNamespace=inNamespace ) Node.__init__( self, name, inNamespace=inNamespace,
defaultIP=defaultIP )
def start( self ): def start( self ):
"""Start <controller> <args> on controller. """Start <controller> <args> on controller.
@@ -460,18 +465,18 @@ class Controller( Node ):
def IP( self ): def IP( self ):
"Return IP address of the Controller" "Return IP address of the Controller"
return self.ipAddress return self.defaultIP
class ControllerParams( object ): class ControllerParams( object ):
"Container for controller IP parameters." "Container for controller IP parameters."
def __init__( self, ip, subnetSize ): def __init__( self, ip, prefixLen ):
"""Init. """Init.
ip: integer, controller IP ip: string, controller IP address
subnetSize: integer, ex 8 for slash-8, covering 17M""" prefixLen: prefix length, e.g. 8 for /8, covering 16M"""
self.ip = ip self.ip = ip
self.subnetSize = subnetSize self.prefixLen = prefixLen
class NOX( Controller ): class NOX( Controller ):
@@ -500,14 +505,14 @@ class NOX( Controller ):
class RemoteController( Controller ): class RemoteController( Controller ):
"Controller running outside of Mininet's control." "Controller running outside of Mininet's control."
def __init__( self, name, inNamespace=False, ipAddress='127.0.0.1', def __init__( self, name, inNamespace=False, defaultIP='127.0.0.1',
port=6633 ): port=6633 ):
"""Init. """Init.
name: name to give controller name: name to give controller
ipAddress: the IP address where the remote controller is ipAddress: the IP address where the remote controller is
listening listening
port: the port where the remote controller is listening""" port: the port where the remote controller is listening"""
Controller.__init__( self, name, ipAddress=ipAddress, port=port ) Controller.__init__( self, name, defaultIP=defaultIP, port=port )
def start( self ): def start( self ):
"Overridden to do nothing." "Overridden to do nothing."