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
author: Bob Lantz (rlantz@cs.stanford.edu)
Unfortunately, Mininet and OpenFlow don't always clean up
properly after themselves. Until they do (or until cleanup
functionality is integrated into the python code), this
script may be used to get rid of unwanted garbage. It may
also get rid of 'false positives', but hopefully nothing
irreplaceable!
Unfortunately, Mininet and OpenFlow (and the Linux kernel)
don't always clean up properly after themselves. Until they do
(or until cleanup functionality is integrated into the Python
code), this script may be used to get rid of unwanted garbage.
It may also get rid of 'false positives', but hopefully
nothing irreplaceable!
"""
from subprocess import Popen, PIPE
@@ -28,7 +28,7 @@ def cleanup():
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
zombies += 'udpbwtest'
# 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.
sh( 'killall -9 ' + zombies + ' 2> /dev/null' )
+12 -13
View File
@@ -27,7 +27,7 @@ import sys
flush = sys.stdout.flush
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.log import lg
@@ -40,21 +40,21 @@ class LinearTestTopo( Topo ):
super( LinearTestTopo, self ).__init__()
# Create switch and host nodes
hosts = range( 1, N+1 )
switches = range( N+1, N+N )
for id in hosts:
self._add_node( id, Node( is_switch=False ) )
for id in switches:
self._add_node( id, Node( is_switch=True ) )
hosts = range( 1, N + 1 )
switches = range( N + 1 , N + N )
for h in hosts:
self.add_node( h, Node( is_switch=False ) )
for s in switches:
self.add_node( s, Node( is_switch=True ) )
# Wire up switches
for s in switches[ :-1 ]:
self._add_edge( s, s + 1 )
self.add_edge( s, s + 1 )
# Wire up hosts
self._add_edge( hosts[ 0 ], switches[ 0 ] )
self.add_edge( hosts[ 0 ], switches[ 0 ] )
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'
self.enable_all()
@@ -81,7 +81,8 @@ def linearBandwidthTest( lengths ):
src, dst = net.hosts[ 0 ], net.hosts[ n ]
print "testing", src.name, "<->", dst.name
bandwidth = net.iperf( [ src, dst ] )
print bandwidth ; flush()
print bandwidth
flush()
results[ datapath ] += [ ( n, bandwidth ) ]
net.stop()
@@ -102,5 +103,3 @@ if __name__ == '__main__':
init()
print "*** Running linearBandwidthTest"
linearBandwidthTest( [ 1, 10, 20 ] )
+4 -5
View File
@@ -6,14 +6,13 @@ This is more complicated than using the higher-level classes,
but it exposes the configuration details and allows customization.
"""
import logging
from mininet.net import init
from mininet.node import Node
from mininet.util import createLink
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" )
controller = Node( 'c0', inNamespace=False )
@@ -37,13 +36,13 @@ def scratchNet( cname='controller', cargs='ptcp:'):
switch.cmd( 'dpctl adddp nl:0' )
for intf in switch.intfs.values():
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" )
h0.cmdPrint( 'ping -c1 ' + h1.IP() )
info( "*** Stopping network\n" )
controller.cmd( 'kill %' + cname)
controller.cmd( 'kill %' + cname )
switch.cmd( 'dpctl deldp nl:0' )
switch.cmd( 'kill %ofprotocol' )
switch.deleteIntfs()
+3 -2
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,
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
@@ -14,7 +14,8 @@ from mininet.util import createLink
from mininet.log import lg, info
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
# to be in separate namespaces. For performance, they probably
# should be in the root namespace. However, it's interesting to
+10 -7
View File
@@ -44,8 +44,8 @@ def connectToRootNS( network, switch, ip, prefixLen, routes ):
network.start()
intf = root.intfs[ 0 ]
# Add routes from root ns to hosts
for net in routes:
root.cmd( 'route add -net ' + net + ' dev ' + intf )
for route in routes:
root.cmd( 'route add -net ' + route + ' dev ' + intf )
def sshd( network, cmd='/usr/sbin/sshd', opts='-D' ):
"Start a network, connect it to root ns, and run sshd on all hosts."
@@ -53,19 +53,22 @@ def sshd( network, cmd='/usr/sbin/sshd', opts='-D' ):
ip = '10.123.123.1' # our IP address on host network
routes = [ '10.0.0.0/8' ] # host networks to route to
connectToRootNS( network, switch, ip, 8, routes )
for host in network.hosts: host.cmd( cmd + ' ' + opts + '&' )
for host in network.hosts:
host.cmd( cmd + ' ' + opts + '&' )
print
print "*** Hosts are running sshd at the following addresses:"
print
for host in network.hosts: print host.name, host.IP()
for host in network.hosts:
print host.name, host.IP()
print
print "*** Type 'exit' or control-D to shut down network"
CLI( network )
for host in network.hosts: host.cmd( 'kill %' + cmd )
for host in network.hosts:
host.cmd( 'kill %' + cmd )
network.stop()
if __name__ == '__main__':
lg.setLogLevel( 'info')
init()
network = TreeNet( depth=1, fanout=4, switch=KernelSwitch )
sshd( network )
net = TreeNet( depth=1, fanout=4, switch=KernelSwitch )
sshd( net )
+48 -26
View File
@@ -20,25 +20,26 @@ import os
import re
import select
import sys
import time
from time import time
flush = sys.stdout.flush
from mininet.log import lg
from mininet.net import init, Mininet
from mininet.node import Host, KernelSwitch
from mininet.node import KernelSwitch
from mininet.topolib import TreeTopo
from mininet.util import quietRun
# 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."
buffer += host.read( 1024 )
if '\n' not in buffer: return None, buffer
pos = buffer.find( '\n' )
line = buffer[ 0 : pos ]
rest = buffer[ pos + 1 :]
buf += host.read( 1024 )
if '\n' not in buffer:
return None, buffer
pos = buf.find( '\n' )
line = buf[ 0 : pos ]
rest = buf[ pos + 1: ]
return line, rest
def monitor( hosts, seconds ):
@@ -49,27 +50,39 @@ def monitor( hosts, seconds ):
for host in hosts:
poller.register( host.stdout )
buffers[ host ] = ''
quitTime = time.time() + seconds
while time.time() < quitTime:
quitTime = time() + seconds
while time() < quitTime:
ready = poller.poll()
for fd, event in ready:
host = Node.fdToNode( fd )
if event & select.POLLIN:
line, buffers[ host ] = readline( host, buffers[ host ] )
if line: yield host, line
if line:
yield host, line
yield None, ''
# bwtest support
def parsebwtest( line,
r=re.compile( r'(\d+) s: in ([\d\.]+) Mbps, out ([\d\.]+) Mbps' ) ):
"Parse udpbwtest.c output, returning seconds, inbw, outbw."
match = r.match( line )
return match.group( 1, 2, 3 ) if match else ( None, None, None )
if match:
seconds, inbw, outbw = match.group( 1, 2, 3 )
return int( seconds ), float( inbw ), float( outbw )
return None, None, None
def printTotalHeader():
"Print header for bandwidth stats."
print
print "time(s)\thosts\ttotal in/out (Mbps)\tavg in/out (Mbps)"
def printTotal( time=None, result=None ):
# 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:
@@ -77,17 +90,23 @@ def printTotal( time=None, result=None ):
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 )
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 udpbwtest( net, seconds ):
"Start up and monitor udpbwtest on each of our hosts."
hosts, switches = net.hosts, net.switches
hosts = net.hosts
hostCount = len( hosts )
print "*** Starting udpbwtest on hosts"
for host in hosts:
ips = [ h.IP() for h in hosts if h != host ]
print host.name, ; flush()
print host.name,
flush()
host.cmd( './udpbwtest ' + ' '.join( ips ) + ' &' )
print
results = {}
@@ -95,13 +114,14 @@ def udpbwtest( net, seconds ):
output = monitor( hosts, seconds )
while True:
host, line = output.next()
if host is None: break
time, inbw, outbw = parsebwtest( line )
if time is not None:
time, inbw, outbw = int( time ), float( inbw ), float( outbw )
result = results.get( time, [] ) + [ ( host, inbw, outbw ) ]
if len( result ) == hostCount: printTotal( time, result )
results[ time ] = result
if host is None:
break
seconds, inbw, outbw = parsebwtest( line )
if seconds is not None:
result = results.get( seconds, [] ) + [ ( host, inbw, outbw ) ]
if len( result ) == hostCount:
printTotal( seconds, result )
results[ seconds ] = result
print "*** Stopping udpbwtest processes"
# We *really* don't want these things hanging around!
quietRun( 'killall -9 udpbwtest' )
@@ -109,10 +129,12 @@ def udpbwtest( net, seconds ):
print "*** Results:"
printTotalHeader()
times = sorted( results.keys() )
for time in times:
printTotal( time - times[ 0 ] , results[ time ] )
for t in times:
printTotal( t - t[ 0 ] , results[ t ] )
print
# pylint: enable-msg=E1101
if __name__ == '__main__':
lg.setLogLevel( 'info' )
if not os.path.exists( './udpbwtest' ):
+1 -1
View File
@@ -133,7 +133,7 @@ def makeListCompatible( fn ):
newfn( 'a', 1, 'b' )"""
def newfn( *args ):
"Generated function."
"Generated function. Closure-ish."
if len( args ) == 1:
return fn( *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:
Host nodes are named h0-hN
Switch nodes are named s0-sN
Host nodes are named h1-hN
Switch nodes are named s1-sN
Controller nodes are named c0-cN
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
constructs a simulated network based on a network topology created
using a topology object (e.g. LinearTopo) from topo.py and a Controller
node which the switches will connect to. Several
configuration options are provided for functions such as
using a topology object (e.g. LinearTopo) from mininet.topo or
mininet.topolib, and a Controller which the switches will connect
to. Several configuration options are provided for functions such as
automatically setting MAC addresses, populating the ARP table, or
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
of useful tasks maybe performed, including basic connectivity and
bandwidth tests and running the mininet CLI.
After the network is created, it can be started using start(), and a
variety of useful tasks maybe performed, including basic connectivity
and bandwidth tests and running the mininet CLI.
Once the network is up and running, test code can easily get access
to host and switch objects, which can then be used
for arbitrary experiments, typically involving running a series of
commands on the hosts.
to host and switch objects which can then be used for arbitrary
experiments, typically involving running a series of commands on the
hosts.
After all desired tests or activities have been completed, the stop()
method may be called to shut down the network.
@@ -187,10 +194,8 @@ class Mininet( object ):
#
# 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.
# 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
# instead of an explicit control network.
@@ -244,7 +249,7 @@ class Mininet( object ):
exit( 1 )
info( '\n' )
def _configHosts( self ):
def configHosts( self ):
"Configure a set of hosts."
# params were: hosts, ips
for host in self.hosts:
@@ -294,7 +299,7 @@ class Mininet( object ):
self._configureControlNetwork()
info( '*** Configuring hosts\n' )
self._configHosts()
self.configHosts()
if self.xterms:
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
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
+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.id_gen = NodeID # class used to generate dpid
def _add_node(self, dpid, node):
def add_node(self, dpid, node):
'''Add Node to graph.
@param dpid dpid
@@ -107,7 +107,7 @@ class Topo(object):
self.g.add_node(dpid)
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.
@param src src dpid
@@ -119,9 +119,9 @@ class Topo(object):
if not edge:
edge = 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.
@param src source switch DPID
@@ -329,11 +329,11 @@ class SingleSwitchTopo(Topo):
self.k = k
self._add_node(1, Node())
self.add_node(1, Node())
hosts = range(2, k + 2)
for h in hosts:
self._add_node(h, Node(is_switch = False))
self._add_edge(h, 1, Edge())
self.add_node(h, Node(is_switch = False))
self.add_edge(h, 1, Edge())
if enable_all:
self.enable_all()
@@ -388,12 +388,12 @@ class LinearTopo(Topo):
switches = range(1, k + 1)
for s in switches:
h = s + k
self._add_node(s, Node())
self._add_node(h, Node(is_switch = False))
self._add_edge(s, h, Edge())
self.add_node(s, Node())
self.add_node(h, Node(is_switch = False))
self.add_edge(s, h, Edge())
for s in switches:
if s != k:
self._add_edge(s, s + 1, Edge())
self.add_edge(s, s + 1, Edge())
if enable_all:
self.enable_all()
+2 -2
View File
@@ -20,11 +20,11 @@ class TreeTopo( Topo ):
returns: last node added"""
me = n
isSwitch = depth > 0
self._add_node( me, Node( is_switch=isSwitch ) )
self.add_node( me, Node( is_switch=isSwitch ) )
if isSwitch:
for i in range( 0, fanout ):
child = n + 1
self._add_edge( me, child )
self.add_edge( me, child )
n = self.addTree( child, depth-1, fanout )
return n
+1 -1
View File
@@ -141,7 +141,7 @@ def macColonHex( mac ):
return _colonHex( mac, 6 )
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
returns: ip address string 10.x.y.z """
hi = ( ip & 0xff0000 ) >> 16