Removed underscores for public Node methods. Minor cleanup & comments.

This commit is contained in:
Bob Lantz
2010-03-08 15:32:41 -08:00
parent 2626693241
commit 80be564274
12 changed files with 223 additions and 188 deletions
+7 -7
View File
@@ -4,12 +4,12 @@
Mininet Cleanup Mininet Cleanup
author: Bob Lantz (rlantz@cs.stanford.edu) author: Bob Lantz (rlantz@cs.stanford.edu)
Unfortunately, Mininet and OpenFlow don't always clean up Unfortunately, Mininet and OpenFlow (and the Linux kernel)
properly after themselves. Until they do (or until cleanup don't always clean up properly after themselves. Until they do
functionality is integrated into the python code), this (or until cleanup functionality is integrated into the Python
script may be used to get rid of unwanted garbage. It may code), this script may be used to get rid of unwanted garbage.
also get rid of 'false positives', but hopefully nothing It may also get rid of 'false positives', but hopefully
irreplaceable! nothing irreplaceable!
""" """
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
@@ -28,7 +28,7 @@ def cleanup():
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core ' zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
zombies += 'udpbwtest' zombies += 'udpbwtest'
# Note: real zombie processes can't actually be killed, since they # Note: real zombie processes can't actually be killed, since they
# are already ( un )dead. Then again, # are already (un)dead. Then again,
# you can't connect to them either, so they're mostly harmless. # you can't connect to them either, so they're mostly harmless.
sh( 'killall -9 ' + zombies + ' 2> /dev/null' ) sh( 'killall -9 ' + zombies + ' 2> /dev/null' )
+23 -24
View File
@@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
""" """
Test bandwidth (using iperf) on linear networks of varying size, Test bandwidth (using iperf) on linear networks of varying size,
using both kernel and user datapaths. using both kernel and user datapaths.
We construct a network of N hosts and N-1 switches, connected as follows: We construct a network of N hosts and N-1 switches, connected as follows:
@@ -9,7 +9,7 @@ We construct a network of N hosts and N-1 switches, connected as follows:
h1 <-> sN+1 <-> sN+2 .. sN+N-1 h1 <-> sN+1 <-> sN+2 .. sN+N-1
| | | | | |
h2 h3 hN h2 h3 hN
Note: by default, the reference controller only supports 16 Note: by default, the reference controller only supports 16
switches, so this test WILL NOT WORK unless you have recompiled switches, so this test WILL NOT WORK unless you have recompiled
your controller to support 100 switches (or more.) your controller to support 100 switches (or more.)
@@ -25,9 +25,9 @@ of switches, this example demonstrates:
import sys import sys
flush = sys.stdout.flush flush = sys.stdout.flush
from mininet.net import init, Mininet from mininet.net import init, Mininet
from mininet.node import Host, KernelSwitch, UserSwitch from mininet.node import KernelSwitch, UserSwitch
from mininet.topo import Topo, Node from mininet.topo import Topo, Node
from mininet.log import lg from mininet.log import lg
@@ -35,26 +35,26 @@ class LinearTestTopo( Topo ):
"Topology for a string of N hosts and N-1 switches." "Topology for a string of N hosts and N-1 switches."
def __init__( self, N ): def __init__( self, N ):
# Add default members to class. # Add default members to class.
super( LinearTestTopo, self ).__init__() super( LinearTestTopo, self ).__init__()
# Create switch and host nodes # Create switch and host nodes
hosts = range( 1, N+1 ) hosts = range( 1, N + 1 )
switches = range( N+1, N+N ) switches = range( N + 1 , N + N )
for id in hosts: for h in hosts:
self._add_node( id, Node( is_switch=False ) ) self.add_node( h, Node( is_switch=False ) )
for id in switches: for s in switches:
self._add_node( id, Node( is_switch=True ) ) self.add_node( s, Node( is_switch=True ) )
# Wire up switches # Wire up switches
for s in switches[ :-1 ]: for s in switches[ :-1 ]:
self._add_edge( s, s + 1 ) self.add_edge( s, s + 1 )
# Wire up hosts # Wire up hosts
self._add_edge( hosts[ 0 ], switches[ 0 ] ) self.add_edge( hosts[ 0 ], switches[ 0 ] )
for h in hosts[ 1: ]: for h in hosts[ 1: ]:
self._add_edge( h, h+N-1 ) self.add_edge( h, h + N - 1 )
# Consider all switches and hosts 'on' # Consider all switches and hosts 'on'
self.enable_all() self.enable_all()
@@ -81,26 +81,25 @@ def linearBandwidthTest( lengths ):
src, dst = net.hosts[ 0 ], net.hosts[ n ] src, dst = net.hosts[ 0 ], net.hosts[ n ]
print "testing", src.name, "<->", dst.name print "testing", src.name, "<->", dst.name
bandwidth = net.iperf( [ src, dst ] ) bandwidth = net.iperf( [ src, dst ] )
print bandwidth ; flush() print bandwidth
flush()
results[ datapath ] += [ ( n, bandwidth ) ] results[ datapath ] += [ ( n, bandwidth ) ]
net.stop() net.stop()
for datapath in datapaths: for datapath in datapaths:
print print
print "*** Linear network results for", datapath, "datapath:" print "*** Linear network results for", datapath, "datapath:"
print print
result = results[ datapath ] result = results[ datapath ]
print "SwitchCount\tiperf Results" print "SwitchCount\tiperf Results"
for switchCount, bandwidth in result: for switchCount, bandwidth in result:
print switchCount, '\t\t', print switchCount, '\t\t',
print bandwidth[ 0 ], 'server, ', bandwidth[ 1 ], 'client' print bandwidth[ 0 ], 'server, ', bandwidth[ 1 ], 'client'
print print
print print
if __name__ == '__main__': if __name__ == '__main__':
lg.setLogLevel( 'info' ) lg.setLogLevel( 'info' )
init() init()
print "*** Running linearBandwidthTest" print "*** Running linearBandwidthTest"
linearBandwidthTest( [ 1, 10, 20 ] ) linearBandwidthTest( [ 1, 10, 20 ] )
+10 -11
View File
@@ -6,21 +6,20 @@ This is more complicated than using the higher-level classes,
but it exposes the configuration details and allows customization. but it exposes the configuration details and allows customization.
""" """
import logging
from mininet.net import init from mininet.net import init
from mininet.node import Node from mininet.node import Node
from mininet.util import createLink from mininet.util import createLink
from mininet.log import lg, info from mininet.log import lg, info
def scratchNet( cname='controller', cargs='ptcp:'): def scratchNet( cname='controller', cargs='ptcp:' ):
"Create network from scratch using kernel switch."
info( "*** Creating nodes\n" ) info( "*** Creating nodes\n" )
controller = Node( 'c0', inNamespace=False ) controller = Node( 'c0', inNamespace=False )
switch = Node( 's0', inNamespace=False ) switch = Node( 's0', inNamespace=False )
h0 = Node( 'h0' ) h0 = Node( 'h0' )
h1 = Node( 'h1' ) h1 = Node( 'h1' )
info( "*** Creating links\n" ) info( "*** Creating links\n" )
createLink( node1=h0, port1=0, node2=switch, port2=0 ) createLink( node1=h0, port1=0, node2=switch, port2=0 )
createLink( node1=h1, port1=0, node2=switch, port2=1 ) createLink( node1=h1, port1=0, node2=switch, port2=1 )
@@ -30,25 +29,25 @@ def scratchNet( cname='controller', cargs='ptcp:'):
h1.setIP( h1.intfs[ 0 ], '192.168.123.2', 24 ) h1.setIP( h1.intfs[ 0 ], '192.168.123.2', 24 )
info( str( h0 ) + '\n' ) info( str( h0 ) + '\n' )
info( str( h1 ) + '\n' ) info( str( h1 ) + '\n' )
info( "*** Starting network using kernel datapath\n" ) info( "*** Starting network using kernel datapath\n" )
controller.cmd( cname + ' ' + cargs + '&' ) controller.cmd( cname + ' ' + cargs + '&' )
switch.cmd( 'dpctl deldp nl:0' ) switch.cmd( 'dpctl deldp nl:0' )
switch.cmd( 'dpctl adddp nl:0' ) switch.cmd( 'dpctl adddp nl:0' )
for intf in switch.intfs.values(): for intf in switch.intfs.values():
switch.cmd( 'dpctl addif nl:0 ' + intf ) switch.cmd( 'dpctl addif nl:0 ' + intf )
switch.cmd( 'ofprotocol nl:0 tcp:localhost &') switch.cmd( 'ofprotocol nl:0 tcp:localhost &' )
info( "*** Running test\n" ) info( "*** Running test\n" )
h0.cmdPrint( 'ping -c1 ' + h1.IP() ) h0.cmdPrint( 'ping -c1 ' + h1.IP() )
info( "*** Stopping network\n" ) info( "*** Stopping network\n" )
controller.cmd( 'kill %' + cname) controller.cmd( 'kill %' + cname )
switch.cmd( 'dpctl deldp nl:0' ) switch.cmd( 'dpctl deldp nl:0' )
switch.cmd( 'kill %ofprotocol' ) switch.cmd( 'kill %ofprotocol' )
switch.deleteIntfs() switch.deleteIntfs()
info( '\n' ) info( '\n' )
if __name__ == '__main__': if __name__ == '__main__':
lg.setLogLevel( 'info' ) lg.setLogLevel( 'info' )
info( '*** Scratch network demo (kernel datapath)\n' ) info( '*** Scratch network demo (kernel datapath)\n' )
+8 -7
View File
@@ -5,7 +5,7 @@ Build a simple network from scratch, using mininet primitives.
This is more complicated than using the higher-level classes, This is more complicated than using the higher-level classes,
but it exposes the configuration details and allows customization. but it exposes the configuration details and allows customization.
This version uses the user datapath. This version uses the user datapath and an explicit control network.
""" """
from mininet.net import init from mininet.net import init
@@ -14,7 +14,8 @@ from mininet.util import createLink
from mininet.log import lg, info from mininet.log import lg, info
def scratchNetUser( cname='controller', cargs='ptcp:' ): def scratchNetUser( cname='controller', cargs='ptcp:' ):
# Create Network "Create network from scratch using user switch."
# It's not strictly necessary for the controller and switches # It's not strictly necessary for the controller and switches
# to be in separate namespaces. For performance, they probably # to be in separate namespaces. For performance, they probably
# should be in the root namespace. However, it's interesting to # should be in the root namespace. However, it's interesting to
@@ -32,15 +33,15 @@ def scratchNetUser( cname='controller', cargs='ptcp:' ):
info( '*** Configuring control network\n' ) info( '*** Configuring control network\n' )
controller.setIP( controller.intfs[ 0 ], '10.0.123.1', 24 ) controller.setIP( controller.intfs[ 0 ], '10.0.123.1', 24 )
switch.setIP( switch.intfs[ 0 ], '10.0.123.2', 24 ) switch.setIP( switch.intfs[ 0 ], '10.0.123.2', 24 )
info( '*** Configuring hosts\n' ) info( '*** Configuring hosts\n' )
h0.setIP( h0.intfs[ 0 ], '192.168.123.1', 24 ) h0.setIP( h0.intfs[ 0 ], '192.168.123.1', 24 )
h1.setIP( h1.intfs[ 0 ], '192.168.123.2', 24 ) h1.setIP( h1.intfs[ 0 ], '192.168.123.2', 24 )
info( '*** Network state:\n' ) info( '*** Network state:\n' )
for node in controller, switch, h0, h1: for node in controller, switch, h0, h1:
info( str( node ) + '\n' ) info( str( node ) + '\n' )
info( '*** Starting controller and user datapath\n' ) info( '*** Starting controller and user datapath\n' )
controller.cmd( cname + ' ' + cargs + '&' ) controller.cmd( cname + ' ' + cargs + '&' )
switch.cmd( 'ifconfig lo 127.0.0.1' ) switch.cmd( 'ifconfig lo 127.0.0.1' )
@@ -57,9 +58,9 @@ def scratchNetUser( cname='controller', cargs='ptcp:' ):
switch.cmd( 'kill %ofprotocol' ) switch.cmd( 'kill %ofprotocol' )
switch.deleteIntfs() switch.deleteIntfs()
info( '\n' ) info( '\n' )
if __name__ == '__main__': if __name__ == '__main__':
lg.setLogLevel( 'info' ) lg.setLogLevel( 'info' )
info( '*** Scratch network demo (user datapath)\n' ) info( '*** Scratch network demo (user datapath)\n' )
init() init()
scratchNetUser() scratchNetUser()
+36 -33
View File
@@ -27,45 +27,48 @@ 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 )
def connectToRootNS( network, switch, ip, prefixLen, routes ): def connectToRootNS( network, switch, ip, prefixLen, routes ):
"""Connect hosts to root namespace via switch. Starts network. """Connect hosts to root namespace via switch. Starts network.
network: Mininet() network object network: Mininet() network object
switch: switch to connect to root namespace switch: switch to connect to root namespace
ip: IP address for root namespace node ip: IP address for root namespace node
prefixLen: IP address prefix length (e.g. 8, 16, 24) prefixLen: IP address prefix length (e.g. 8, 16, 24)
routes: host networks to route to""" routes: host networks to route to"""
# Create a node in root namespace and link to switch 0 # Create a node in root namespace and link to switch 0
root = Node( 'root', inNamespace=False ) root = Node( 'root', inNamespace=False )
port = max( switch.ports.values() ) + 1 port = max( switch.ports.values() ) + 1
createLink( root, 0, switch, port ) createLink( root, 0, switch, port )
root.setIP( root.intfs[ 0 ], ip, prefixLen ) root.setIP( root.intfs[ 0 ], ip, prefixLen )
# Start network that now includes link to root namespace # Start network that now includes link to root namespace
network.start() network.start()
intf = root.intfs[ 0 ] intf = root.intfs[ 0 ]
# Add routes from root ns to hosts # Add routes from root ns to hosts
for net in routes: for route in routes:
root.cmd( 'route add -net ' + net + ' dev ' + intf ) root.cmd( 'route add -net ' + route + ' dev ' + intf )
def sshd( network, cmd='/usr/sbin/sshd', opts='-D' ): def sshd( network, cmd='/usr/sbin/sshd', opts='-D' ):
"Start a network, connect it to root ns, and run sshd on all hosts." "Start a network, connect it to root ns, and run sshd on all hosts."
switch = network.switches[ 0 ] # switch to use switch = network.switches[ 0 ] # switch to use
ip = '10.123.123.1' # our IP address on host network ip = '10.123.123.1' # our IP address on host network
routes = [ '10.0.0.0/8' ] # host networks to route to routes = [ '10.0.0.0/8' ] # host networks to route to
connectToRootNS( network, switch, ip, 8, routes ) connectToRootNS( network, switch, ip, 8, routes )
for host in network.hosts: host.cmd( cmd + ' ' + opts + '&' ) for host in network.hosts:
print host.cmd( cmd + ' ' + opts + '&' )
print "*** Hosts are running sshd at the following addresses:" print
print print "*** Hosts are running sshd at the following addresses:"
for host in network.hosts: print host.name, host.IP() print
print for host in network.hosts:
print "*** Type 'exit' or control-D to shut down network" print host.name, host.IP()
CLI( network ) print
for host in network.hosts: host.cmd( 'kill %' + cmd ) print "*** Type 'exit' or control-D to shut down network"
network.stop() CLI( network )
for host in network.hosts:
host.cmd( 'kill %' + cmd )
network.stop()
if __name__ == '__main__': if __name__ == '__main__':
lg.setLogLevel( 'info') lg.setLogLevel( 'info')
init() init()
network = TreeNet( depth=1, fanout=4, switch=KernelSwitch ) net = TreeNet( depth=1, fanout=4, switch=KernelSwitch )
sshd( network ) sshd( net )
+97 -75
View File
@@ -20,99 +20,121 @@ import os
import re import re
import select import select
import sys import sys
import time from time import time
flush = sys.stdout.flush flush = sys.stdout.flush
from mininet.log import lg from mininet.log import lg
from mininet.net import init, Mininet from mininet.net import init, Mininet
from mininet.node import Host, KernelSwitch from mininet.node import KernelSwitch
from mininet.topolib import TreeTopo from mininet.topolib import TreeTopo
from mininet.util import quietRun from mininet.util import quietRun
# Some useful stuff: buffered readline and host monitoring # Some useful stuff: buffered readline and host monitoring
def readline( host, buffer ): def readline( host, buf ):
"Read a line from a host, buffering with buffer." "Read a line from a host, buffering with buffer."
buffer += host.read( 1024 ) buf += host.read( 1024 )
if '\n' not in buffer: return None, buffer if '\n' not in buffer:
pos = buffer.find( '\n' ) return None, buffer
line = buffer[ 0 : pos ] pos = buf.find( '\n' )
rest = buffer[ pos + 1 :] line = buf[ 0 : pos ]
return line, rest rest = buf[ pos + 1: ]
return line, rest
def monitor( hosts, seconds ): def monitor( hosts, seconds ):
"Monitor a set of hosts and yield their output." "Monitor a set of hosts and yield their output."
poller = select.poll() poller = select.poll()
Node = hosts[ 0 ] # so we can call class method fdToNode Node = hosts[ 0 ] # so we can call class method fdToNode
buffers = {} buffers = {}
for host in hosts: for host in hosts:
poller.register( host.stdout ) poller.register( host.stdout )
buffers[ host ] = '' buffers[ host ] = ''
quitTime = time.time() + seconds quitTime = time() + seconds
while time.time() < quitTime: while time() < quitTime:
ready = poller.poll() ready = poller.poll()
for fd, event in ready: for fd, event in ready:
host = Node.fdToNode( fd ) host = Node.fdToNode( fd )
line, buffers[ host ] = readline( host, buffers[ host ] ) if event & select.POLLIN:
if line: yield host, line line, buffers[ host ] = readline( host, buffers[ host ] )
yield None, '' if line:
yield host, line
yield None, ''
# bwtest support # bwtest support
def parsebwtest( line, def parsebwtest( line,
r=re.compile( r'(\d+) s: in ([\d\.]+) Mbps, out ([\d\.]+) Mbps' ) ): r=re.compile( r'(\d+) s: in ([\d\.]+) Mbps, out ([\d\.]+) Mbps' ) ):
match = r.match( line ) "Parse udpbwtest.c output, returning seconds, inbw, outbw."
return match.group( 1, 2, 3 ) if match else ( None, None, None ) match = r.match( line )
if match:
seconds, inbw, outbw = match.group( 1, 2, 3 )
return int( seconds ), float( inbw ), float( outbw )
return None, None, None
def printTotalHeader(): def printTotalHeader():
print "Print header for bandwidth stats."
print "time(s)\thosts\ttotal in/out (Mbps)\tavg in/out (Mbps)" print
print "time(s)\thosts\ttotal in/out (Mbps)\tavg in/out (Mbps)"
# Annoyingly, pylint isn't smart enough to notice
# when an unused variable is an iteration tuple
# pylint: disable-msg=W0612
def printTotal( seconds=None, result=None ):
"Compute and print total bandwidth for given results set."
intotal = outtotal = 0.0
count = len( result )
for host, inbw, outbw in result:
intotal += inbw
outtotal += outbw
inavg = intotal / count if count > 0 else 0
outavg = outtotal / count if count > 0 else 0
print '%d\t%d\t%.2f/%.2f\t\t%.2f/%.2f' % ( seconds, count,
intotal, outtotal, inavg, outavg )
# pylint: enable-msg=W0612
# Pylint also isn't smart enough to understand iterator.next()
# pylint: disable-msg=E1101
def printTotal( time=None, result=None ):
intotal = outtotal = 0.0
count = len( result )
for host, inbw, outbw in result:
intotal += inbw
outtotal += outbw
inavg = intotal / count if count > 0 else 0
outavg = outtotal / count if count > 0 else 0
print '%d\t%d\t%.2f/%.2f\t\t%.2f/%.2f' % ( time, count, intotal, outtotal,
inavg, outavg )
def udpbwtest( net, seconds ): def udpbwtest( net, seconds ):
"Start up and monitor udpbwtest on each of our hosts." "Start up and monitor udpbwtest on each of our hosts."
hosts, switches = net.hosts, net.switches hosts = net.hosts
hostCount = len( hosts ) hostCount = len( hosts )
print "*** Starting udpbwtest on hosts" print "*** Starting udpbwtest on hosts"
for host in hosts: for host in hosts:
ips = [ h.IP() for h in hosts if h != host ] ips = [ h.IP() for h in hosts if h != host ]
print host.name, ; flush() print host.name,
host.cmd( './udpbwtest ' + ' '.join( ips ) + ' &' ) flush()
print host.cmd( './udpbwtest ' + ' '.join( ips ) + ' &' )
results = {} print
print "*** Monitoring hosts" results = {}
output = monitor( hosts, seconds ) print "*** Monitoring hosts"
while True: output = monitor( hosts, seconds )
host, line = output.next() while True:
if host is None: break host, line = output.next()
time, inbw, outbw = parsebwtest( line ) if host is None:
if time is not None: break
time, inbw, outbw = int( time ), float( inbw ), float( outbw ) seconds, inbw, outbw = parsebwtest( line )
result = results.get( time, [] ) + [ ( host, inbw, outbw ) ] if seconds is not None:
if len( result ) == hostCount: printTotal( time, result ) result = results.get( seconds, [] ) + [ ( host, inbw, outbw ) ]
results[ time ] = result if len( result ) == hostCount:
print "*** Stopping udpbwtest processes" printTotal( seconds, result )
# We *really* don't want these things hanging around! results[ seconds ] = result
quietRun( 'killall -9 udpbwtest' ) print "*** Stopping udpbwtest processes"
print # We *really* don't want these things hanging around!
print "*** Results:" quietRun( 'killall -9 udpbwtest' )
printTotalHeader() print
times = sorted( results.keys() ) print "*** Results:"
for time in times: printTotalHeader()
printTotal( time - times[ 0 ] , results[ time ] ) times = sorted( results.keys() )
print for t in times:
printTotal( t - t[ 0 ] , results[ t ] )
print
# pylint: enable-msg=E1101
if __name__ == '__main__': if __name__ == '__main__':
lg.setLogLevel( 'info' ) lg.setLogLevel( 'info' )
if not os.path.exists( './udpbwtest' ): if not os.path.exists( './udpbwtest' ):
+1 -1
View File
@@ -133,7 +133,7 @@ def makeListCompatible( fn ):
newfn( 'a', 1, 'b' )""" newfn( 'a', 1, 'b' )"""
def newfn( *args ): def newfn( *args ):
"Generated function." "Generated function. Closure-ish."
if len( args ) == 1: if len( args ) == 1:
return fn( *args ) return fn( *args )
args = ' '.join( [ str( arg ) for arg in args ] ) args = ' '.join( [ str( arg ) for arg in args ] )
+21 -16
View File
@@ -49,27 +49,34 @@ which interfaces belong to which node.
The basic naming scheme is as follows: The basic naming scheme is as follows:
Host nodes are named h0-hN Host nodes are named h1-hN
Switch nodes are named s0-sN Switch nodes are named s1-sN
Controller nodes are named c0-cN Controller nodes are named c0-cN
Interfaces are named {nodename}-eth0 .. {nodename}-ethN Interfaces are named {nodename}-eth0 .. {nodename}-ethN
Note: If the network topology is created using mininet.topo, then
node numbers are unique among hosts and switches (e.g. we have
h1..hN and SN..SN+M) and also correspond to their default IP addresses
of 10.x.y.z/8 where x.y.z is the base-256 representation of N for
hN. This mapping allows easy determination of a node's IP
address from its name, e.g. h1 -> 10.0.0.1, h257 -> 10.0.1.1.
Currently we wrap the entire network in a 'mininet' object, which Currently we wrap the entire network in a 'mininet' object, which
constructs a simulated network based on a network topology created constructs a simulated network based on a network topology created
using a topology object (e.g. LinearTopo) from topo.py and a Controller using a topology object (e.g. LinearTopo) from mininet.topo or
node which the switches will connect to. Several mininet.topolib, and a Controller which the switches will connect
configuration options are provided for functions such as to. Several configuration options are provided for functions such as
automatically setting MAC addresses, populating the ARP table, or automatically setting MAC addresses, populating the ARP table, or
even running a set of xterms to allow direct interaction with nodes. even running a set of xterms to allow direct interaction with nodes.
After the mininet is created, it can be started using start(), and a variety After the network is created, it can be started using start(), and a
of useful tasks maybe performed, including basic connectivity and variety of useful tasks maybe performed, including basic connectivity
bandwidth tests and running the mininet CLI. and bandwidth tests and running the mininet CLI.
Once the network is up and running, test code can easily get access Once the network is up and running, test code can easily get access
to host and switch objects, which can then be used to host and switch objects which can then be used for arbitrary
for arbitrary experiments, typically involving running a series of experiments, typically involving running a series of commands on the
commands on the hosts. hosts.
After all desired tests or activities have been completed, the stop() After all desired tests or activities have been completed, the stop()
method may be called to shut down the network. method may be called to shut down the network.
@@ -187,10 +194,8 @@ class Mininet( object ):
# #
# Notes: # Notes:
# #
# 1. If the controller and switches are in the same ( e.g. root ) # 1. If the controller and switches are in the same (e.g. root)
# namespace, they can just use the loopback connection. # namespace, they can just use the loopback connection.
# We may wish to do this for the user datapath as well as the
# kernel datapath.
# #
# 2. If we can get unix domain sockets to work, we can use them # 2. If we can get unix domain sockets to work, we can use them
# instead of an explicit control network. # instead of an explicit control network.
@@ -244,7 +249,7 @@ class Mininet( object ):
exit( 1 ) exit( 1 )
info( '\n' ) info( '\n' )
def _configHosts( self ): def configHosts( self ):
"Configure a set of hosts." "Configure a set of hosts."
# params were: hosts, ips # params were: hosts, ips
for host in self.hosts: for host in self.hosts:
@@ -294,7 +299,7 @@ class Mininet( object ):
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()
+6
View File
@@ -33,6 +33,12 @@ RemoteController: a remote controller node, which may use any
arbitrary OpenFlow-compatible controller, and which is not arbitrary OpenFlow-compatible controller, and which is not
created or managed by mininet. created or managed by mininet.
Future enhancements:
- Possibly make Node, Switch and Controller more abstract so that
they can be used for both local and remote nodes
- Create proxy objects for remote nodes (Mininet: Cluster Edition)
""" """
import os import os
+11 -11
View File
@@ -98,7 +98,7 @@ class Topo(object):
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.id_gen = NodeID # class used to generate dpid self.id_gen = NodeID # class used to generate dpid
def _add_node(self, dpid, node): def add_node(self, dpid, node):
'''Add Node to graph. '''Add Node to graph.
@param dpid dpid @param dpid dpid
@@ -107,7 +107,7 @@ class Topo(object):
self.g.add_node(dpid) self.g.add_node(dpid)
self.node_info[dpid] = node self.node_info[dpid] = node
def _add_edge(self, src, dst, edge = None): def add_edge(self, src, dst, edge = None):
'''Add edge (Node, Node) to graph. '''Add edge (Node, Node) to graph.
@param src src dpid @param src src dpid
@@ -119,9 +119,9 @@ class Topo(object):
if not edge: if not edge:
edge = Edge() edge = Edge()
self.edge_info[(src, dst)] = edge self.edge_info[(src, dst)] = edge
self._add_port(src, dst) self.add_port(src, dst)
def _add_port(self, src, dst): def add_port(self, src, dst):
'''Generate port mapping for new edge. '''Generate port mapping for new edge.
@param src source switch DPID @param src source switch DPID
@@ -329,11 +329,11 @@ class SingleSwitchTopo(Topo):
self.k = k self.k = k
self._add_node(1, Node()) self.add_node(1, Node())
hosts = range(2, k + 2) hosts = range(2, k + 2)
for h in hosts: for h in hosts:
self._add_node(h, Node(is_switch = False)) self.add_node(h, Node(is_switch = False))
self._add_edge(h, 1, Edge()) self.add_edge(h, 1, Edge())
if enable_all: if enable_all:
self.enable_all() self.enable_all()
@@ -388,12 +388,12 @@ class LinearTopo(Topo):
switches = range(1, k + 1) switches = range(1, k + 1)
for s in switches: for s in switches:
h = s + k h = s + k
self._add_node(s, Node()) self.add_node(s, Node())
self._add_node(h, Node(is_switch = False)) self.add_node(h, Node(is_switch = False))
self._add_edge(s, h, Edge()) self.add_edge(s, h, Edge())
for s in switches: for s in switches:
if s != k: if s != k:
self._add_edge(s, s + 1, Edge()) self.add_edge(s, s + 1, Edge())
if enable_all: if enable_all:
self.enable_all() self.enable_all()
+2 -2
View File
@@ -20,11 +20,11 @@ class TreeTopo( Topo ):
returns: last node added""" returns: last node added"""
me = n me = n
isSwitch = depth > 0 isSwitch = depth > 0
self._add_node( me, Node( is_switch=isSwitch ) ) self.add_node( me, Node( is_switch=isSwitch ) )
if isSwitch: if isSwitch:
for i in range( 0, fanout ): for i in range( 0, fanout ):
child = n + 1 child = n + 1
self._add_edge( me, child ) self.add_edge( me, child )
n = self.addTree( child, depth-1, fanout ) n = self.addTree( child, depth-1, fanout )
return n return n
+1 -1
View File
@@ -141,7 +141,7 @@ def macColonHex( mac ):
return _colonHex( mac, 6 ) return _colonHex( mac, 6 )
def ipStr( ip ): def ipStr( ip ):
"""Generate IP address string """Generate IP address string from an unsigned int
ip: unsigned int of form x << 16 | y << 8 | z ip: unsigned int of form x << 16 | y << 8 | z
returns: ip address string 10.x.y.z """ returns: ip address string 10.x.y.z """
hi = ( ip & 0xff0000 ) >> 16 hi = ( ip & 0xff0000 ) >> 16