diff --git a/mininet/net.py b/mininet/net.py index 96da89971fb89d0fa61e36afcc6427e64522fca5..097fbd75735403798b3f32d35834d8befb4a67b9 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -82,7 +82,8 @@ from mininet.cli import CLI 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 createLink, macColonHex from mininet.xterm import cleanUpScreens, makeXterms @@ -105,7 +106,9 @@ def init(): class Mininet( object ): "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, inNamespace=False, autoSetMacs=False, autoStaticArp=False ): @@ -143,29 +146,24 @@ def __init__( self, topo, switch, host, controller, cparams, if topo and build: self.buildFromTopo( self.topo ) - def addHost( self, name, defaultMac=None, defaultIp=None ): + def addHost( self, name, mac=None, ip=None ): """Add host. name: name of host to add - defaultMac: default MAC address for intf 0 - defaultIp: default IP address for intf 0 + mac: default MAC address for intf 0 + ip: default IP address for intf 0 returns: added host""" - host = self.host( name ) + host = self.host( name, defaultMAC=mac, defaultIP=ip ) self.hosts.append( 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 - def addSwitch( self, name, defaultMac=None ): + def addSwitch( self, name, mac=None ): """Add switch. 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""" 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 else: sw = self.switch( name ) @@ -225,9 +223,8 @@ def _configureRoutedControlNetwork( self ): 'controller' % switch.name ) exit( 1 ) - controller.setIP( cintf, self.cparams.ip, '/' + - self.cparams.subnetSize ) - switch.setIP( sintf, sip, '/' + self.cparams.subnetSize ) + controller.setIP( cintf, self.cparams.ip, self.cparams.prefixLen ) + switch.setIP( sintf, sip, self.cparams.prefixLen ) controller.setHostRoute( sip, cintf ) switch.setHostRoute( self.cparams.ip, sintf ) info( '\n' ) @@ -251,12 +248,11 @@ def _configHosts( self ): # params were: hosts, ips for host in self.hosts: hintf = host.intfs[ 0 ] - host.setIP( hintf, host.defaultIP, - '/' + str( self.cparams.subnetSize ) ) + host.setIP( hintf, host.defaultIP, self.cparams.prefixLen ) host.setDefaultRoute( hintf ) # You're low priority, dude! quietRun( 'renice +18 -p ' + repr( host.pid ) ) - info( '%s ', host.name ) + info( host.name + ' ' ) info( '\n' ) def buildFromTopo( self, topo ): @@ -274,14 +270,14 @@ def buildFromTopo( self, topo ): name = 'h' + topo.name( hostId ) mac = macColonHex( hostId ) if self.setMacs else None ip = topo.ip( hostId ) - host = self.addHost( name, defaultIp=ip, defaultMac=mac ) + host = self.addHost( name, ip=ip, mac=mac ) self.idToNode[ hostId ] = host info( name + ' ' ) info( '\n*** Adding switches:\n' ) for switchId in sorted( topo.switches() ): name = 's' + topo.name( switchId ) mac = macColonHex( switchId) if self.setMacs else None - switch = self.addSwitch( name, defaultMac=mac ) + switch = self.addSwitch( name, mac=mac ) self.idToNode[ switchId ] = switch info( name + ' ' ) info( '\n*** Adding edges:\n' ) @@ -325,14 +321,14 @@ def setMacs( self ): """Set MAC addrs to correspond to datapath IDs on hosts. Assume that the host only has one interface.""" for host in self.hosts: - host.setMAC( host.intfs[ 0 ], host.defaultMac ) + 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: for dst in self.hosts: if src != dst: - src.setARP( ip=dst.IP(), mac=dst.defaultMac ) + src.setARP( ip=dst.IP(), mac=dst.defaultMAC ) def start( self ): "Start controller and switches" diff --git a/mininet/node.py b/mininet/node.py index 99935c6f2c0e7f64ea5f556cb8db8b3b6ca7352e..19a4babd69068fa1ce00564de866ab0e3e73a5a0 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -39,6 +39,7 @@ import os import signal import select +from time import sleep from mininet.log import info, error, debug from mininet.util import quietRun, moveIntf @@ -51,7 +52,12 @@ class Node( object ): inToNode = {} # mapping of input 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 closeFds = False # speed vs. memory use # xpg_echo is needed so we can echo our sentinel in sendCmd @@ -79,6 +85,8 @@ def __init__( self, name, inNamespace=True ): self.connection = {} # remote node connected to each interface self.waiting = False self.execed = False + self.defaultIP = defaultIP + self.defaultMAC = defaultMAC @classmethod def fdToNode( cls, fd ): @@ -213,6 +221,19 @@ def connect( self, intf, dstNode, dstIntf ): "Register connection of intf to dstIntf on dstNode." 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 ): """Set the MAC address for an interface. mac: MAC address as string""" @@ -228,12 +249,13 @@ def setARP( self, ip, mac ): result = self.cmd( [ 'arp', '-s', ip, mac ] ) return result - def setIP( self, intf, ip, bits ): + def setIP( self, intf, ip, prefixLen ): """Set the IP address for an interface. intf: interface name ip: IP address as a string - bits: prefix length of form /24""" - result = self.cmd( [ 'ifconfig', intf, ip + bits, 'up' ] ) + prefixLen: prefix length, e.g. 8 for /8 or 16M addrs""" + ipSub = '%s/%d' % ( ip, prefixLen ) + result = self.cmd( [ 'ifconfig', intf, ipSub, 'up' ] ) self.ips[ intf ] = ip return result @@ -297,10 +319,10 @@ class UserSwitch( Switch ): """User-space switch. Currently only works in the root namespace.""" - def __init__( self, name ): + def __init__( self, name, *args, **kwargs ): """Init. name: name for the switch""" - Switch.__init__( self, name, inNamespace=False ) + Switch.__init__( self, name, inNamespace=False, **kwargs ) def start( self, controllers ): """Start OpenFlow reference user datapath. @@ -323,20 +345,19 @@ def stop( self ): "Stop OpenFlow reference user datapath." self.cmd( 'kill %ofdatapath' ) self.cmd( 'kill %ofprotocol' ) - + self.deleteIntfs() class KernelSwitch( Switch ): """Kernel-space switch. Currently only works in the root namespace.""" - def __init__( self, name, dp=None, defaultMac=None ): + def __init__( self, name, dp=None, **kwargs ): """Init. name: dp: netlink id (0, 1, 2, ...) - defaultMac: default MAC as string; random value if None""" - Switch.__init__( self, name, inNamespace=False ) + defaultMAC: default MAC as string; random value if None""" + Switch.__init__( self, name, inNamespace=False, **kwargs ) self.dp = dp - self.defaultMac = defaultMac def start( self, controllers ): "Start up reference kernel datapath." @@ -346,9 +367,9 @@ def start( self, controllers ): # then create a new one monitoring the given interfaces quietRun( 'dpctl deldp nl:%i' % self.dp ) self.cmd( 'dpctl adddp nl:%i' % self.dp ) - if self.defaultMac: + if self.defaultMAC: 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: raise Exception( 'only contiguous, zero-indexed port ranges' @@ -367,28 +388,19 @@ def start( self, controllers ): def stop( self ): "Terminate kernel datapath." quietRun( 'dpctl deldp nl:%i' % self.dp ) - # 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( '.' ) - + self.deleteIntfs() class OVSKernelSwitch( Switch ): """Open VSwitch kernel-space switch. Currently only works in the root namespace.""" - def __init__( self, name, dp=None, defaultMac=None ): + def __init__( self, name, dp=None, **kwargs ): """Init. name: dp: netlink id (0, 1, 2, ...) 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.defaultMac = defaultMac def start( self, controllers ): "Start up kernel datapath." @@ -398,9 +410,9 @@ def start( self, controllers ): # then create a new one monitoring the given interfaces quietRun( 'ovs-dpctl del-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 - mac = self.defaultMac + mac = self.defaultMAC self.cmd( [ 'ifconfig', intf, 'hw', 'ether', mac ] ) if len( self.intfs ) != max( self.intfs ) + 1: @@ -419,14 +431,7 @@ def start( self, controllers ): def stop( self ): "Terminate kernel datapath." quietRun( 'ovs-dpctl del-dp dp%i' % self.dp ) - # 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 %ovs-openflowd' ) - for intf in self.intfs.values(): - quietRun( 'ip link del ' + intf ) - info( '.' ) + self.deleteIntfs() class Controller( Node ): @@ -434,14 +439,14 @@ class Controller( Node ): OpenFlow 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 ): self.controller = controller self.cargs = cargs self.cdir = cdir - self.ipAddress = ipAddress self.port = port - Node.__init__( self, name, inNamespace=inNamespace ) + Node.__init__( self, name, inNamespace=inNamespace, + defaultIP=defaultIP ) def start( self ): """Start <controller> <args> on controller. @@ -460,18 +465,18 @@ def stop( self ): def IP( self ): "Return IP address of the Controller" - return self.ipAddress + return self.defaultIP class ControllerParams( object ): "Container for controller IP parameters." - def __init__( self, ip, subnetSize ): + def __init__( self, ip, prefixLen ): """Init. - ip: integer, controller IP - subnetSize: integer, ex 8 for slash-8, covering 17M""" + ip: string, controller IP address + prefixLen: prefix length, e.g. 8 for /8, covering 16M""" self.ip = ip - self.subnetSize = subnetSize + self.prefixLen = prefixLen class NOX( Controller ): @@ -500,14 +505,14 @@ def __init__( self, name, inNamespace=False, noxArgs=None, **kwargs ): class RemoteController( Controller ): "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 ): """Init. name: name to give controller ipAddress: the IP address 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 ): "Overridden to do nothing."