Merge branch 'master' of git://github.com/mininet/mininet into devel/startup
This commit is contained in:
@@ -25,11 +25,13 @@ from mininet.cli import CLI
|
|||||||
from mininet.log import lg, LEVELS, info, debug, error
|
from mininet.log import lg, LEVELS, info, debug, error
|
||||||
from mininet.net import Mininet, MininetWithControlNet, VERSION
|
from mininet.net import Mininet, MininetWithControlNet, VERSION
|
||||||
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
|
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
|
||||||
NOX, RemoteController, UserSwitch, OVSKernelSwitch,
|
NOX, RemoteController, DefaultController,
|
||||||
|
UserSwitch, OVSSwitch,
|
||||||
OVSLegacyKernelSwitch, IVSSwitch )
|
OVSLegacyKernelSwitch, IVSSwitch )
|
||||||
|
from mininet.nodelib import LinuxBridge
|
||||||
from mininet.link import Link, TCLink
|
from mininet.link import Link, TCLink
|
||||||
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
||||||
from mininet.topolib import TreeTopo
|
from mininet.topolib import TreeTopo, TorusTopo
|
||||||
from mininet.util import custom, customConstructor
|
from mininet.util import custom, customConstructor
|
||||||
from mininet.util import buildTopo
|
from mininet.util import buildTopo
|
||||||
|
|
||||||
@@ -40,24 +42,29 @@ TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
|
|||||||
'linear': LinearTopo,
|
'linear': LinearTopo,
|
||||||
'reversed': SingleSwitchReversedTopo,
|
'reversed': SingleSwitchReversedTopo,
|
||||||
'single': SingleSwitchTopo,
|
'single': SingleSwitchTopo,
|
||||||
'tree': TreeTopo }
|
'tree': TreeTopo,
|
||||||
|
'torus': TorusTopo }
|
||||||
|
|
||||||
SWITCHDEF = 'ovsk'
|
SWITCHDEF = 'ovsk'
|
||||||
SWITCHES = { 'user': UserSwitch,
|
SWITCHES = { 'user': UserSwitch,
|
||||||
'ovsk': OVSKernelSwitch,
|
'ovs': OVSSwitch,
|
||||||
|
# Keep ovsk for compatibility with 2.0
|
||||||
|
'ovsk': OVSSwitch,
|
||||||
'ovsl': OVSLegacyKernelSwitch,
|
'ovsl': OVSLegacyKernelSwitch,
|
||||||
'ivs': IVSSwitch }
|
'ivs': IVSSwitch,
|
||||||
|
'lxbr': LinuxBridge }
|
||||||
|
|
||||||
HOSTDEF = 'proc'
|
HOSTDEF = 'proc'
|
||||||
HOSTS = { 'proc': Host,
|
HOSTS = { 'proc': Host,
|
||||||
'rt': custom( CPULimitedHost, sched='rt' ),
|
'rt': custom( CPULimitedHost, sched='rt' ),
|
||||||
'cfs': custom( CPULimitedHost, sched='cfs' ) }
|
'cfs': custom( CPULimitedHost, sched='cfs' ) }
|
||||||
|
|
||||||
CONTROLLERDEF = 'ovsc'
|
CONTROLLERDEF = 'default'
|
||||||
CONTROLLERS = { 'ref': Controller,
|
CONTROLLERS = { 'ref': Controller,
|
||||||
'ovsc': OVSController,
|
'ovsc': OVSController,
|
||||||
'nox': NOX,
|
'nox': NOX,
|
||||||
'remote': RemoteController,
|
'remote': RemoteController,
|
||||||
|
'default': DefaultController,
|
||||||
'none': lambda name: None }
|
'none': lambda name: None }
|
||||||
|
|
||||||
LINKDEF = 'default'
|
LINKDEF = 'default'
|
||||||
@@ -261,12 +268,14 @@ class MininetRunner( object ):
|
|||||||
if test == 'none':
|
if test == 'none':
|
||||||
pass
|
pass
|
||||||
elif test == 'all':
|
elif test == 'all':
|
||||||
|
mn.waitConnected()
|
||||||
mn.start()
|
mn.start()
|
||||||
mn.ping()
|
mn.ping()
|
||||||
mn.iperf()
|
mn.iperf()
|
||||||
elif test == 'cli':
|
elif test == 'cli':
|
||||||
CLI( mn )
|
CLI( mn )
|
||||||
elif test != 'build':
|
elif test != 'build':
|
||||||
|
mn.waitConnected()
|
||||||
getattr( mn, test )()
|
getattr( mn, test )()
|
||||||
|
|
||||||
if self.options.post:
|
if self.options.post:
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ of switches, this example demonstrates:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from mininet.net import Mininet
|
from mininet.net import Mininet
|
||||||
from mininet.node import UserSwitch, OVSKernelSwitch
|
from mininet.node import UserSwitch, OVSKernelSwitch, Controller
|
||||||
from mininet.topo import Topo
|
from mininet.topo import Topo
|
||||||
from mininet.log import lg
|
from mininet.log import lg
|
||||||
from mininet.util import irange
|
from mininet.util import irange
|
||||||
@@ -76,7 +76,7 @@ def linearBandwidthTest( lengths ):
|
|||||||
print "*** testing", datapath, "datapath"
|
print "*** testing", datapath, "datapath"
|
||||||
Switch = switches[ datapath ]
|
Switch = switches[ datapath ]
|
||||||
results[ datapath ] = []
|
results[ datapath ] = []
|
||||||
net = Mininet( topo=topo, switch=Switch )
|
net = Mininet( topo=topo, switch=Switch, controller=Controller, waitConnected=True )
|
||||||
net.start()
|
net.start()
|
||||||
print "*** testing basic connectivity"
|
print "*** testing basic connectivity"
|
||||||
for n in lengths:
|
for n in lengths:
|
||||||
|
|||||||
+55
-14
@@ -90,12 +90,13 @@ import os
|
|||||||
import re
|
import re
|
||||||
import select
|
import select
|
||||||
import signal
|
import signal
|
||||||
|
import copy
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from itertools import chain, groupby
|
from itertools import chain, groupby
|
||||||
|
|
||||||
from mininet.cli import CLI
|
from mininet.cli import CLI
|
||||||
from mininet.log import info, error, debug, output
|
from mininet.log import info, error, debug, output, warn
|
||||||
from mininet.node import Host, OVSKernelSwitch, Controller
|
from mininet.node import Host, OVSKernelSwitch, DefaultController, Controller
|
||||||
from mininet.link import Link, Intf
|
from mininet.link import Link, Intf
|
||||||
from mininet.util import quietRun, fixLimits, numCores, ensureRoot
|
from mininet.util import quietRun, fixLimits, numCores, ensureRoot
|
||||||
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
|
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
|
||||||
@@ -109,11 +110,11 @@ class Mininet( object ):
|
|||||||
"Network emulation with hosts spawned in network namespaces."
|
"Network emulation with hosts spawned in network namespaces."
|
||||||
|
|
||||||
def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
|
def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
|
||||||
controller=Controller, link=Link, intf=Intf,
|
controller=DefaultController, link=Link, intf=Intf,
|
||||||
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
|
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
|
||||||
inNamespace=False,
|
inNamespace=False,
|
||||||
autoSetMacs=False, autoStaticArp=False, autoPinCpus=False,
|
autoSetMacs=False, autoStaticArp=False, autoPinCpus=False,
|
||||||
listenPort=None ):
|
listenPort=None, waitConnected=False ):
|
||||||
"""Create Mininet object.
|
"""Create Mininet object.
|
||||||
topo: Topo (topology) object or None
|
topo: Topo (topology) object or None
|
||||||
switch: default Switch class
|
switch: default Switch class
|
||||||
@@ -149,6 +150,7 @@ class Mininet( object ):
|
|||||||
self.numCores = numCores()
|
self.numCores = numCores()
|
||||||
self.nextCore = 0 # next core for pinning hosts to CPUs
|
self.nextCore = 0 # next core for pinning hosts to CPUs
|
||||||
self.listenPort = listenPort
|
self.listenPort = listenPort
|
||||||
|
self.waitConn = waitConnected
|
||||||
|
|
||||||
self.hosts = []
|
self.hosts = []
|
||||||
self.switches = []
|
self.switches = []
|
||||||
@@ -166,6 +168,37 @@ class Mininet( object ):
|
|||||||
if topo and build:
|
if topo and build:
|
||||||
self.build()
|
self.build()
|
||||||
|
|
||||||
|
|
||||||
|
def waitConnected( self, timeout=None, delay=.5 ):
|
||||||
|
"""wait for each switch to connect to a controller,
|
||||||
|
up to 5 seconds
|
||||||
|
timeout: time to wait, or None to wait indefinitely
|
||||||
|
delay: seconds to sleep per iteration
|
||||||
|
returns: True if all switches are connected"""
|
||||||
|
info( '*** Waiting for switches to connect\n' )
|
||||||
|
time = 0
|
||||||
|
remaining = list( self.switches )
|
||||||
|
while True:
|
||||||
|
for switch in tuple( remaining ):
|
||||||
|
if switch.connected():
|
||||||
|
info( '%s ' % switch )
|
||||||
|
remaining.remove( switch )
|
||||||
|
if not remaining:
|
||||||
|
info( '\n' )
|
||||||
|
return True
|
||||||
|
if time > timeout and timeout is not None:
|
||||||
|
break
|
||||||
|
sleep( delay )
|
||||||
|
time += delay
|
||||||
|
warn( 'Timed out after %d seconds\n' % time )
|
||||||
|
for switch in remaining:
|
||||||
|
if not switch.connected():
|
||||||
|
warn( 'Warning: %s is not connected to a controller\n'
|
||||||
|
% switch.name )
|
||||||
|
else:
|
||||||
|
remaining.remove( switch )
|
||||||
|
return not remaining
|
||||||
|
|
||||||
def addHost( self, name, cls=None, **params ):
|
def addHost( self, name, cls=None, **params ):
|
||||||
"""Add host.
|
"""Add host.
|
||||||
name: name of host to add
|
name: name of host to add
|
||||||
@@ -216,7 +249,7 @@ class Mininet( object ):
|
|||||||
if not controller:
|
if not controller:
|
||||||
controller = self.controller
|
controller = self.controller
|
||||||
# Construct new controller if one is not given
|
# Construct new controller if one is not given
|
||||||
if isinstance(name, Controller):
|
if isinstance( name, Controller ):
|
||||||
controller_new = name
|
controller_new = name
|
||||||
# Pylint thinks controller is a str()
|
# Pylint thinks controller is a str()
|
||||||
# pylint: disable=E1103
|
# pylint: disable=E1103
|
||||||
@@ -225,7 +258,7 @@ class Mininet( object ):
|
|||||||
else:
|
else:
|
||||||
controller_new = controller( name, **params )
|
controller_new = controller( name, **params )
|
||||||
# Add new controller to net
|
# Add new controller to net
|
||||||
if controller_new: # allow controller-less setups
|
if controller_new: # allow controller-less setups
|
||||||
self.controllers.append( controller_new )
|
self.controllers.append( controller_new )
|
||||||
self.nameToNode[ name ] = controller_new
|
self.nameToNode[ name ] = controller_new
|
||||||
return controller_new
|
return controller_new
|
||||||
@@ -327,7 +360,11 @@ class Mininet( object ):
|
|||||||
if type( classes ) is not list:
|
if type( classes ) is not list:
|
||||||
classes = [ classes ]
|
classes = [ classes ]
|
||||||
for i, cls in enumerate( classes ):
|
for i, cls in enumerate( classes ):
|
||||||
self.addController( 'c%d' % i, cls )
|
# Allow Controller objects because nobody understands currying
|
||||||
|
if isinstance( cls, Controller ):
|
||||||
|
self.addController( cls )
|
||||||
|
else:
|
||||||
|
self.addController( 'c%d' % i, cls )
|
||||||
|
|
||||||
info( '*** Adding hosts:\n' )
|
info( '*** Adding hosts:\n' )
|
||||||
for hostName in topo.hosts():
|
for hostName in topo.hosts():
|
||||||
@@ -408,9 +445,16 @@ class Mininet( object ):
|
|||||||
info( switch.name + ' ')
|
info( switch.name + ' ')
|
||||||
switch.start( self.controllers )
|
switch.start( self.controllers )
|
||||||
info( '\n' )
|
info( '\n' )
|
||||||
|
if self.waitConn:
|
||||||
|
self.waitConnected()
|
||||||
|
|
||||||
def stop( self ):
|
def stop( self ):
|
||||||
"Stop the controller(s), switches and hosts"
|
"Stop the controller(s), switches and hosts"
|
||||||
|
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
|
||||||
|
for controller in self.controllers:
|
||||||
|
info( controller.name + ' ' )
|
||||||
|
controller.stop()
|
||||||
|
info( '\n' )
|
||||||
if self.terms:
|
if self.terms:
|
||||||
info( '*** Stopping %i terms\n' % len( self.terms ) )
|
info( '*** Stopping %i terms\n' % len( self.terms ) )
|
||||||
self.stopXterms()
|
self.stopXterms()
|
||||||
@@ -426,11 +470,6 @@ class Mininet( object ):
|
|||||||
for host in self.hosts:
|
for host in self.hosts:
|
||||||
info( host.name + ' ' )
|
info( host.name + ' ' )
|
||||||
host.terminate()
|
host.terminate()
|
||||||
info( '\n' )
|
|
||||||
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
|
|
||||||
for controller in self.controllers:
|
|
||||||
info( controller.name + ' ' )
|
|
||||||
controller.stop()
|
|
||||||
info( '\n*** Done\n' )
|
info( '\n*** Done\n' )
|
||||||
|
|
||||||
def run( self, test, *args, **kwargs ):
|
def run( self, test, *args, **kwargs ):
|
||||||
@@ -623,7 +662,7 @@ class Mininet( object ):
|
|||||||
|
|
||||||
# XXX This should be cleaned up
|
# XXX This should be cleaned up
|
||||||
|
|
||||||
def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
|
def iperf( self, hosts=None, l4Type='TCP', udpBw='10M', format=None ):
|
||||||
"""Run iperf between two hosts.
|
"""Run iperf between two hosts.
|
||||||
hosts: list of hosts; if None, uses opposite hosts
|
hosts: list of hosts; if None, uses opposite hosts
|
||||||
l4Type: string, one of [ TCP, UDP ]
|
l4Type: string, one of [ TCP, UDP ]
|
||||||
@@ -646,6 +685,8 @@ class Mininet( object ):
|
|||||||
bwArgs = '-b ' + udpBw + ' '
|
bwArgs = '-b ' + udpBw + ' '
|
||||||
elif l4Type != 'TCP':
|
elif l4Type != 'TCP':
|
||||||
raise Exception( 'Unexpected l4 type: %s' % l4Type )
|
raise Exception( 'Unexpected l4 type: %s' % l4Type )
|
||||||
|
if format:
|
||||||
|
iperfArgs += '-f %s ' %format
|
||||||
server.sendCmd( iperfArgs + '-s', printPid=True )
|
server.sendCmd( iperfArgs + '-s', printPid=True )
|
||||||
servout = ''
|
servout = ''
|
||||||
while server.lastPid is None:
|
while server.lastPid is None:
|
||||||
@@ -653,7 +694,7 @@ class Mininet( object ):
|
|||||||
if l4Type == 'TCP':
|
if l4Type == 'TCP':
|
||||||
while 'Connected' not in client.cmd(
|
while 'Connected' not in client.cmd(
|
||||||
'sh -c "echo A | telnet -e A %s 5001"' % server.IP()):
|
'sh -c "echo A | telnet -e A %s 5001"' % server.IP()):
|
||||||
output('waiting for iperf to start up...')
|
info( 'Waiting for iperf to start up...' )
|
||||||
sleep(.5)
|
sleep(.5)
|
||||||
cliout = client.cmd( iperfArgs + '-t 5 -c ' + server.IP() + ' ' +
|
cliout = client.cmd( iperfArgs + '-t 5 -c ' + server.IP() + ' ' +
|
||||||
bwArgs )
|
bwArgs )
|
||||||
|
|||||||
+15
-2
@@ -1277,13 +1277,19 @@ class Controller( Node ):
|
|||||||
return '<%s %s: %s:%s pid=%s> ' % (
|
return '<%s %s: %s:%s pid=%s> ' % (
|
||||||
self.__class__.__name__, self.name,
|
self.__class__.__name__, self.name,
|
||||||
self.IP(), self.port, self.pid )
|
self.IP(), self.port, self.pid )
|
||||||
|
@classmethod
|
||||||
|
def isAvailable( self ):
|
||||||
|
return quietRun( 'which controller' )
|
||||||
|
|
||||||
class OVSController( Controller ):
|
class OVSController( Controller ):
|
||||||
"Open vSwitch controller"
|
"Open vSwitch controller"
|
||||||
def __init__( self, name, command='ovs-controller', **kwargs ):
|
def __init__( self, name, command='ovs-controller', **kwargs ):
|
||||||
|
if quietRun( 'which test-controller' ):
|
||||||
|
command = 'test-controller'
|
||||||
Controller.__init__( self, name, command=command, **kwargs )
|
Controller.__init__( self, name, command=command, **kwargs )
|
||||||
|
@classmethod
|
||||||
|
def isAvailable( self ):
|
||||||
|
return quietRun( 'which ovs-controller' ) or quietRun( 'which test-controller' )
|
||||||
|
|
||||||
class NOX( Controller ):
|
class NOX( Controller ):
|
||||||
"Controller to run a NOX application."
|
"Controller to run a NOX application."
|
||||||
@@ -1338,3 +1344,10 @@ class RemoteController( Controller ):
|
|||||||
if 'Connected' not in listening:
|
if 'Connected' not in listening:
|
||||||
warn( "Unable to contact the remote controller"
|
warn( "Unable to contact the remote controller"
|
||||||
" at %s:%d\n" % ( self.ip, self.port ) )
|
" at %s:%d\n" % ( self.ip, self.port ) )
|
||||||
|
|
||||||
|
|
||||||
|
def DefaultController( name, order=[ Controller, OVSController ], **kwargs ):
|
||||||
|
"find any controller that is available and run it"
|
||||||
|
for controller in order:
|
||||||
|
if controller.isAvailable():
|
||||||
|
return controller( name, **kwargs )
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
"""
|
||||||
|
Node Library for Mininet
|
||||||
|
|
||||||
|
This contains additional Node types which you may find to be useful
|
||||||
|
"""
|
||||||
|
|
||||||
|
from mininet.net import Mininet
|
||||||
|
from mininet.topo import Topo
|
||||||
|
from mininet.node import Switch
|
||||||
|
from mininet.log import setLogLevel, info
|
||||||
|
|
||||||
|
|
||||||
|
class LinuxBridge( Switch ):
|
||||||
|
"Linux Bridge (with optional spanning tree)"
|
||||||
|
|
||||||
|
nextPrio = 100 # next bridge priority for spanning tree
|
||||||
|
|
||||||
|
def __init__( self, name, stp=False, prio=None, **kwargs ):
|
||||||
|
"""stp: use spanning tree protocol? (default False)
|
||||||
|
prio: optional explicit bridge priority for STP"""
|
||||||
|
self.stp = stp
|
||||||
|
if prio:
|
||||||
|
self.prio = prio
|
||||||
|
else:
|
||||||
|
self.prio = LinuxBridge.nextPrio
|
||||||
|
LinuxBridge.nextPrio += 1
|
||||||
|
Switch.__init__( self, name, **kwargs )
|
||||||
|
|
||||||
|
def connected( self ):
|
||||||
|
"Are we forwarding yet?"
|
||||||
|
if self.stp:
|
||||||
|
return 'forwarding' in self.cmd( 'brctl showstp', self )
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def start( self, controllers ):
|
||||||
|
self.cmd( 'ifconfig', self, 'down' )
|
||||||
|
self.cmd( 'brctl delbr', self )
|
||||||
|
self.cmd( 'brctl addbr', self )
|
||||||
|
if self.stp:
|
||||||
|
self.cmd( 'brctl setbridgeprio', self.prio )
|
||||||
|
self.cmd( 'brctl stp', self, 'on' )
|
||||||
|
for i in self.intfList():
|
||||||
|
if self.name in i.name:
|
||||||
|
self.cmd( 'brctl addif', self, i )
|
||||||
|
self.cmd( 'ifconfig', self, 'up' )
|
||||||
|
|
||||||
|
def stop( self ):
|
||||||
|
self.cmd( 'ifconfig', self, 'down' )
|
||||||
|
self.cmd( 'brctl delbr', self )
|
||||||
|
|
||||||
@@ -55,6 +55,9 @@ class testOptionsTopoCommon( object ):
|
|||||||
"""
|
"""
|
||||||
self.assertGreaterEqual( float(measured),
|
self.assertGreaterEqual( float(measured),
|
||||||
float(expected) * tolerance_frac )
|
float(expected) * tolerance_frac )
|
||||||
|
self.assertLessEqual( float( measured ),
|
||||||
|
float(expected) + (1-tolerance_frac)
|
||||||
|
* float( expected ) )
|
||||||
|
|
||||||
def testCPULimits( self ):
|
def testCPULimits( self ):
|
||||||
"Verify topology creation with CPU limits set for both schedulers."
|
"Verify topology creation with CPU limits set for both schedulers."
|
||||||
@@ -68,19 +71,20 @@ class testOptionsTopoCommon( object ):
|
|||||||
mn.start()
|
mn.start()
|
||||||
results = mn.runCpuLimitTest( cpu=CPU_FRACTION )
|
results = mn.runCpuLimitTest( cpu=CPU_FRACTION )
|
||||||
mn.stop()
|
mn.stop()
|
||||||
for cpu in results:
|
for pct in results:
|
||||||
self.assertWithinTolerance( cpu, CPU_FRACTION, CPU_TOLERANCE )
|
#divide cpu by 100 to convert from percentage to fraction
|
||||||
|
self.assertWithinTolerance( pct/100, CPU_FRACTION, CPU_TOLERANCE )
|
||||||
|
|
||||||
def testLinkBandwidth( self ):
|
def testLinkBandwidth( self ):
|
||||||
"Verify that link bandwidths are accurate within a bound."
|
"Verify that link bandwidths are accurate within a bound."
|
||||||
BW = 5 # Mbps
|
BW = .5 # Mbps
|
||||||
BW_TOLERANCE = 0.8 # BW fraction below which test should fail
|
BW_TOLERANCE = 0.8 # BW fraction below which test should fail
|
||||||
# Verify ability to create limited-link topo first;
|
# Verify ability to create limited-link topo first;
|
||||||
lopts = { 'bw': BW, 'use_htb': True }
|
lopts = { 'bw': BW, 'use_htb': True }
|
||||||
# Also verify correctness of limit limitng within a bound.
|
# Also verify correctness of limit limitng within a bound.
|
||||||
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
|
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
|
||||||
link=TCLink, switch=self.switchClass )
|
link=TCLink, switch=self.switchClass )
|
||||||
bw_strs = mn.run( mn.iperf )
|
bw_strs = mn.run( mn.iperf, format='m' )
|
||||||
for bw_str in bw_strs:
|
for bw_str in bw_strs:
|
||||||
bw = float( bw_str.split(' ')[0] )
|
bw = float( bw_str.split(' ')[0] )
|
||||||
self.assertWithinTolerance( bw, BW, BW_TOLERANCE )
|
self.assertWithinTolerance( bw, BW, BW_TOLERANCE )
|
||||||
@@ -91,7 +95,7 @@ class testOptionsTopoCommon( object ):
|
|||||||
DELAY_TOLERANCE = 0.8 # Delay fraction below which test should fail
|
DELAY_TOLERANCE = 0.8 # Delay fraction below which test should fail
|
||||||
lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True }
|
lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True }
|
||||||
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
|
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
|
||||||
link=TCLink, switch=self.switchClass )
|
link=TCLink, switch=self.switchClass, autoStaticArp=True )
|
||||||
ping_delays = mn.run( mn.pingFull )
|
ping_delays = mn.run( mn.pingFull )
|
||||||
test_outputs = ping_delays[0]
|
test_outputs = ping_delays[0]
|
||||||
# Ignore unused variables below
|
# Ignore unused variables below
|
||||||
@@ -102,9 +106,10 @@ class testOptionsTopoCommon( object ):
|
|||||||
# pylint: enable-msg=W0612
|
# pylint: enable-msg=W0612
|
||||||
for rttval in [rttmin, rttavg, rttmax]:
|
for rttval in [rttmin, rttavg, rttmax]:
|
||||||
# Multiply delay by 4 to cover there & back on two links
|
# Multiply delay by 4 to cover there & back on two links
|
||||||
self.assertWithinTolerance( rttval, DELAY_MS * 4.0,
|
self.assertWithinTolerance( rttval, DELAY_MS * 4.0,
|
||||||
DELAY_TOLERANCE)
|
DELAY_TOLERANCE)
|
||||||
|
|
||||||
|
|
||||||
def testLinkLoss( self ):
|
def testLinkLoss( self ):
|
||||||
"Verify that we see packet drops with a high configured loss rate."
|
"Verify that we see packet drops with a high configured loss rate."
|
||||||
LOSS_PERCENT = 99
|
LOSS_PERCENT = 99
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class testLinearCommon( object ):
|
|||||||
|
|
||||||
def testLinear5( self ):
|
def testLinear5( self ):
|
||||||
"Ping test on a 5-switch topology"
|
"Ping test on a 5-switch topology"
|
||||||
mn = Mininet( LinearTopo( k=5 ), self.switchClass, Host, Controller )
|
mn = Mininet( LinearTopo( k=5 ), self.switchClass, Host, Controller, waitConnected=True )
|
||||||
dropped = mn.run( mn.ping )
|
dropped = mn.run( mn.ping )
|
||||||
self.assertEqual( dropped, 0 )
|
self.assertEqual( dropped, 0 )
|
||||||
|
|
||||||
|
|||||||
+13
-6
@@ -48,18 +48,25 @@ class MultiGraph( object ):
|
|||||||
class Topo(object):
|
class Topo(object):
|
||||||
"Data center network representation for structured multi-trees."
|
"Data center network representation for structured multi-trees."
|
||||||
|
|
||||||
def __init__(self, hopts=None, sopts=None, lopts=None):
|
def __init__(self, *args, **params):
|
||||||
"""Topo object:
|
"""Topo object.
|
||||||
|
Optional named parameters:
|
||||||
hinfo: default host options
|
hinfo: default host options
|
||||||
sopts: default switch options
|
sopts: default switch options
|
||||||
lopts: default link options"""
|
lopts: default link options
|
||||||
|
calls build()"""
|
||||||
self.g = MultiGraph()
|
self.g = MultiGraph()
|
||||||
self.node_info = {}
|
self.node_info = {}
|
||||||
self.link_info = {} # (src, dst) tuples hash to EdgeInfo objects
|
self.link_info = {} # (src, dst) tuples hash to EdgeInfo objects
|
||||||
self.hopts = {} if hopts is None else hopts
|
self.hopts = params.pop( 'hopts', {} )
|
||||||
self.sopts = {} if sopts is None else sopts
|
self.sopts = params.pop( 'sopts', {} )
|
||||||
self.lopts = {} if lopts is None else lopts
|
self.lopts = params.pop( 'lopts', {} )
|
||||||
self.ports = {} # ports[src][dst] is port on src that connects to dst
|
self.ports = {} # ports[src][dst] is port on src that connects to dst
|
||||||
|
self.build( *args, **params )
|
||||||
|
|
||||||
|
def build( self, *args, **params ):
|
||||||
|
"Override this method to build your topology."
|
||||||
|
pass
|
||||||
|
|
||||||
def addNode(self, name, **opts):
|
def addNode(self, name, **opts):
|
||||||
"""Add Node to graph.
|
"""Add Node to graph.
|
||||||
|
|||||||
@@ -34,3 +34,37 @@ def TreeNet( depth=1, fanout=2, **kwargs ):
|
|||||||
"Convenience function for creating tree networks."
|
"Convenience function for creating tree networks."
|
||||||
topo = TreeTopo( depth, fanout )
|
topo = TreeTopo( depth, fanout )
|
||||||
return Mininet( topo, **kwargs )
|
return Mininet( topo, **kwargs )
|
||||||
|
|
||||||
|
|
||||||
|
class TorusTopo( Topo ):
|
||||||
|
"""2-D Torus topology
|
||||||
|
WARNING: this topology has LOOPS and WILL NOT WORK
|
||||||
|
with the default controller or any Ethernet bridge
|
||||||
|
without STP turned on! It can be used with STP, e.g.:
|
||||||
|
# mn --topo torus,3,3 --switch lxbr,stp=1 --test pingall"""
|
||||||
|
def __init__( self, x, y, *args, **kwargs ):
|
||||||
|
Topo.__init__( self, *args, **kwargs )
|
||||||
|
if x < 3 or y < 3:
|
||||||
|
raise Exception( 'Please use 3x3 or greater for compatibility '
|
||||||
|
'with 2.1' )
|
||||||
|
hosts, switches, dpid = {}, {}, 0
|
||||||
|
# Create and wire interior
|
||||||
|
for i in range( 0, x ):
|
||||||
|
for j in range( 0, y ):
|
||||||
|
loc = '%dx%d' % ( i + 1, j + 1 )
|
||||||
|
# dpid cannot be zero for OVS
|
||||||
|
dpid = ( i + 1 ) * 256 + ( j + 1 )
|
||||||
|
switch = switches[ i, j ] = self.addSwitch( 's' + loc, dpid='%016x' % dpid )
|
||||||
|
host = hosts[ i, j ] = self.addHost( 'h' + loc )
|
||||||
|
self.addLink( host, switch )
|
||||||
|
# Connect switches
|
||||||
|
for i in range( 0, x ):
|
||||||
|
for j in range( 0, y ):
|
||||||
|
sw1 = switches[ i, j ]
|
||||||
|
sw2 = switches[ i, ( j + 1 ) % y ]
|
||||||
|
sw3 = switches[ ( i + 1 ) % x, j ]
|
||||||
|
self.addLink( sw1, sw2 )
|
||||||
|
self.addLink( sw1, sw3 )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,12 @@ isoURLs = {
|
|||||||
'trusty64server':
|
'trusty64server':
|
||||||
'http://mirrors.kernel.org/ubuntu-releases/14.04/'
|
'http://mirrors.kernel.org/ubuntu-releases/14.04/'
|
||||||
'ubuntu-14.04-server-amd64.iso',
|
'ubuntu-14.04-server-amd64.iso',
|
||||||
|
'utopic32server':
|
||||||
|
'http://mirrors.kernel.org/ubuntu-releases/14.10/'
|
||||||
|
'ubuntu-14.10-server-i386.iso',
|
||||||
|
'utopic64server':
|
||||||
|
'http://mirrors.kernel.org/ubuntu-releases/14.10/'
|
||||||
|
'ubuntu-14.10-server-amd64.iso',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user