Merge branch 'master' of github.com:pantuza/mininet

This commit is contained in:
Gustavo Pantuza Coelho Pinto
2013-07-18 18:34:21 -07:00
23 changed files with 914 additions and 345 deletions
+70 -64
View File
@@ -1,117 +1,123 @@
Mininet Installation/Configuration Notes
----------------------------------------
Mininet 2.0.0
---
The supported installation methods for Mininet are 1) using
a pre-built VM image, and 2) native installation on Ubuntu. You
can also easily create your own Mininet VM image (3).
The supported installation methods for Mininet are 1) using a
pre-built VM image, and 2) native installation on Ubuntu. You can also
easily create your own Mininet VM image (4).
(Other distributions may be supported in the future - if you would
like to contribute an installation script, we would welcome it!)
1. Easiest "installation" - use our pre-built VM image!
The easiest way to get Mininet running is to start with one of our pre-built
virtual machine images from http://openflow.org/mininet
The easiest way to get Mininet running is to start with one of our
pre-built virtual machine images from <http://openflow.org/mininet>
Boot up the VM image, log in, and follow the instructions on the wiki page.
Boot up the VM image, log in, and follow the instructions on the
Mininet web site.
One advantage of using the VM image is that it doesn't mess with
your native OS installation or damage it in any way.
One advantage of using the VM image is that it doesn't mess with
your native OS installation or damage it in any way.
Although a single Mininet instance can simulate multiple networks with
multiple controllers, only one Mininet instance may currently be run at
a time, and Mininet requires root access in the machine it's running on.
Therefore, if you have a multiuser system, you may wish to consider
running Mininet in a VM.
Although a single Mininet instance can simulate multiple networks
with multiple controllers, only one Mininet instance may currently
be run at a time, and Mininet requires root access in the machine
it's running on. Therefore, if you have a multiuser system, you
may wish to consider running Mininet in a VM.
2. Next-easiest option: use our Ubuntu package!
To install Mininet itself (i.e. mn and the Python API) on Ubuntu 12.10+
To install Mininet itself (i.e. `mn` and the Python API) on Ubuntu
12.10+:
sudo apt-get install mininet
sudo apt-get install mininet
Note: if you are upgrading from an older version of Mininet, make sure you
remove the old OVS from /usr/local:
Note: if you are upgrading from an older version of Mininet, make
sure you remove the old OVS from `/usr/local`:
sudo rm /usr/local/bin/ovs*
sudo rm /usr/local/sbin/ovs*
sudo rm /usr/local/bin/ovs*
sudo rm /usr/local/sbin/ovs*
3. Native installation from source on Ubuntu 11.10+
If you're reading this, you've probably already done so, but the command to
download the Mininet source code is;
git clone git://openflow.org/mininet.git
If you're reading this, you've probably already done so, but the
command to download the Mininet source code is:
If you are running Ubuntu, you may be able to use our handy install.sh script,
which is in mininet/util.
git clone git://github.com/mininet/mininet.git
WARNING: USE AT YOUR OWN RISK!
If you are running Ubuntu, you may be able to use our handy
`install.sh` script, which is in `mininet/util`.
install.sh is a bit intrusive and may possibly damage your OS and/or
home directory, by creating/modifying several directories such as
mininet, openflow, openvswitch and noxcore. Although we hope it won't
do anything completely terrible, you may want to look at the script
before you run it, and you should make sure your system and home
directory are backed up just in case!
*WARNING: USE AT YOUR OWN RISK!*
To install Mininet itself, the OpenFlow reference implementation, and
Open vSwitch, you may use:
`install.sh` is a bit intrusive and may possibly damage your OS
and/or home directory, by creating/modifying several directories
such as `mininet`, `openflow`, `oftest`, `pox`, or `noxcosre`.
Although we hope it won't do anything completely terrible, you may
want to look at the script before you run it, and you should make
sure your system and home directory are backed up just in case!
$ mininet/util/install.sh -fnv
To install Mininet itself, the OpenFlow reference implementation, and
Open vSwitch, you may use:
This should be reasonably quick and the following command should work
after the installation:
mininet/util/install.sh -fnv
$ sudo mn --test pingall
This should be reasonably quick, and the following command should
work after the installation:
To install ALL of the software which we use for OpenFlow tutorials,
including NOX classic, the OpenFlow WireShark dissector, the oftest
framework, and other potentially useful software (and to add some stuff
to /etc/sysctl.conf which may or may not be useful) you may use
sudo mn --test pingall
$ mininet/util/install.sh -a
To install ALL of the software which we use for OpenFlow tutorials,
including POX, the OpenFlow WireShark dissector, the `oftest`
framework, and other potentially useful software (and to add some
stuff to `/etc/sysctl.conf` which may or may not be useful) you may
use:
This takes about 20 minutes on our test system.
mininet/util/install.sh -a
This takes about 4 minutes on our test system.
4. Creating your own Mininet/OpenFlow tutorial VM
Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial
is easy! First, create a new Ubuntu VM. Then, run
Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial
is easy! First, create a new Ubuntu VM. Next, run two commands in it:
$ wget https://raw.github.com/mininet/mininet/util/vm/install-mininet-vm.sh
$ time install-mininet-vm.sh
wget https://raw.github.com/mininet/mininet/master/util/vm/install-mininet-vm.sh
time install-mininet-vm.sh
Finally, verify that Mininet is installed and working in the VM:
sudo mn --test pingall
5. Installation on other Linux distributions
Although we don't support other Linux distributions directly, it should be
possible to install and run Mininet with some degree of manual effort.
Although we don't support other Linux distributions directly, it
should be possible to install and run Mininet with some degree of
manual effort.
In general, you must have:
In general, you must have:
* A Linux kernel compiled with network namespace support enabled
* A Linux kernel compiled with network namespace support enabled
* An OpenFlow implementation (either the reference user or kernel
space implementations, or Open vSwitch.) Appropriate kernel modules
(e.g. tun and ofdatapath for the reference kernel implementation) must
be loaded.
* An OpenFlow implementation (either the reference user or kernel
space implementations, or Open vSwitch.) Appropriate kernel
modules (e.g. tun and ofdatapath for the reference kernel
implementation) must be loaded.
* Python, `bash`, `ping`, `iperf`, etc.
* Python, `bash`, `ping`, `iperf`, etc.`
* Root privileges (required for network device access)
* Root privileges (required for network device access)
We encourage contribution of patches to the `install.sh` script to
support other Linux distributions.
We encourage contribution of patches to the `install.sh` script to support
other Linux distributions.
Good luck!
Mininet Team
---
+6 -5
View File
@@ -71,8 +71,7 @@ TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
ALTSPELLING = { 'pingall': 'pingAll',
'pingpair': 'pingPair',
'iperfudp': 'iperfUdp',
'iperfUDP': 'iperfUdp',
'prefixlen': 'prefixLen' }
'iperfUDP': 'iperfUdp' }
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
@@ -190,9 +189,6 @@ class MininetRunner( object ):
help='CLI script to run before tests' )
opts.add_option( '--post', type='string', default=None,
help='CLI script to run after tests' )
opts.add_option( '--prefixlen', type='int', default=8,
help='prefix length (e.g. /8) for automatic '
'network configuration' )
opts.add_option( '--pin', action='store_true',
default=False, help="pin hosts to CPU cores "
"(requires --host cfs or --host rt)" )
@@ -200,6 +196,11 @@ class MininetRunner( object ):
self.options, self.args = opts.parse_args()
# We don't accept extra arguments after the options
if self.args:
opts.print_help()
exit()
def setup( self ):
"Setup and validate environment."
+2 -4
View File
@@ -9,20 +9,18 @@ Build-Depends:
help2man,
python-dev,
python-pkg-resources,
python-setuptools,
python-networkx
python-setuptools
Homepage: http://openflow.org/mininet
Package: mininet
Architecture: any
Depends:
openvswitch-switch,
python-networkx,
telnet,
${misc:Depends},
${python:Depends},
${shlibs:Depends}
Recommends: iperf, openvswitch-controller
Recommends: iperf, openvswitch-controller, socat
Description: Process-based network emulator
Mininet is a network emulator which uses lightweight
virtualization to create virtual networks for rapid
+19 -1
View File
@@ -19,7 +19,19 @@ graphical monitoring.
controllers.py:
This example creates a network and adds multiple controllers to it.
This example creates a network with multiple controllers, by
using a custom Switch() subclass.
controllers2.py:
This example creates a network with multiple controllers by
creating an empty network, adding nodes to it, and manually
starting the switches.
controlnet.py:
This examples shows how you can model the control network as well
as the data network, by actually creating two Mininet objects.
cpu.py:
@@ -61,6 +73,12 @@ multitest.py:
This example creates a network and runs multiple tests on it.
nat.py:
This example shows how to connect a Mininet network to the Internet
using NAT. It also answers the eternal question "why can't I ping
google?"
popen.py:
This example monitors a number of hosts using host.popen() and
+23 -52
View File
@@ -1,64 +1,35 @@
#!/usr/bin/python
"""
This example creates a multi-controller network from
semi-scratch; note a topo object could also be used and
would be passed into the Mininet() constructor.
Create a network where different switches are connected to
different controllers, by creating a custom Switch() subclass.
"""
from mininet.net import Mininet
from mininet.node import Controller, OVSKernelSwitch
from mininet.cli import CLI
from mininet.node import OVSSwitch, Controller, RemoteController
from mininet.topolib import TreeTopo
from mininet.log import setLogLevel
from mininet.cli import CLI
Switch = OVSKernelSwitch
setLogLevel( 'info' )
def addHost( net, N ):
"Create host hN and add to net."
name = 'h%d' % N
ip = '10.0.0.%d' % N
return net.addHost( name, ip=ip )
# Two local and one "external" controller (which is actually c0)
# Ignore the warning message that the remote isn't (yet) running
c0 = Controller( 'c0' )
c1 = Controller( 'c1' )
c2 = RemoteController( 'c2', ip='127.0.0.1' )
def multiControllerNet():
"Create a network with multiple controllers."
cmap = { 's1': c0, 's2': c1, 's3': c2 }
net = Mininet( controller=Controller, switch=Switch)
class MultiSwitch( OVSSwitch ):
"Custom Switch() subclass that connects to different controllers"
def start( self, controllers ):
return OVSSwitch.start( self, [ cmap[ self.name ] ] )
print "*** Creating controllers"
c1 = net.addController( 'c1', port=6633 )
c2 = net.addController( 'c2', port=6634 )
print "*** Creating switches"
s1 = net.addSwitch( 's1' )
s2 = net.addSwitch( 's2' )
print "*** Creating hosts"
hosts1 = [ addHost( net, n ) for n in 3, 4 ]
hosts2 = [ addHost( net, n ) for n in 5, 6 ]
print "*** Creating links"
for h in hosts1:
s1.linkTo( h )
for h in hosts2:
s2.linkTo( h )
s1.linkTo( s2 )
print "*** Starting network"
net.build()
c1.start()
c2.start()
s1.start( [ c1 ] )
s2.start( [ c2 ] )
print "*** Testing network"
net.pingAll()
print "*** Running CLI"
CLI( net )
print "*** Stopping network"
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' ) # for CLI output
multiControllerNet()
topo = TreeTopo( depth=2, fanout=2 )
net = Mininet( topo=topo, switch=MultiSwitch, build=False )
net.controllers = [ c0, c1 ]
net.build()
net.start()
CLI( net )
net.stop()
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/python
"""
This example creates a multi-controller network from semi-scratch by
using the net.add*() API and manually starting the switches and controllers.
This is the "mid-level" API, which is an alternative to the "high-level"
Topo() API which supports parametrized topology classes.
Note that one could also create a custom switch class and pass it into
the Mininet() constructor.
"""
from mininet.net import Mininet
from mininet.node import Controller, OVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel
def multiControllerNet():
"Create a network from semi-scratch with multiple controllers."
net = Mininet( controller=Controller, switch=OVSSwitch, build=False )
print "*** Creating (reference) controllers"
c1 = net.addController( 'c1', port=6633 )
c2 = net.addController( 'c2', port=6634 )
print "*** Creating switches"
s1 = net.addSwitch( 's1' )
s2 = net.addSwitch( 's2' )
print "*** Creating hosts"
hosts1 = [ net.addHost( 'h%d' % n ) for n in 3, 4 ]
hosts2 = [ net.addHost( 'h%d' % n ) for n in 5, 6 ]
print "*** Creating links"
for h in hosts1:
net.addLink( s1, h )
for h in hosts2:
net.addLink( s2, h )
net.addLink( s1, s2 )
print "*** Starting network"
net.build()
c1.start()
c2.start()
s1.start( [ c1 ] )
s2.start( [ c2 ] )
print "*** Testing network"
net.pingAll()
print "*** Running CLI"
CLI( net )
print "*** Stopping network"
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' ) # for CLI output
multiControllerNet()
+118
View File
@@ -0,0 +1,118 @@
#!/usr/bin/python
"""
controlnet.py: Mininet with a custom control network
We create two Mininet() networks, a control network
and a data network, running four DataControllers on the
control network to control the data network.
Since we're using UserSwitch on the data network,
it should correctly fail over to a backup controller.
We also hack/subclass the CLI slightly so it can talk to
both the control and data networks.
"""
from mininet.net import Mininet
from mininet.node import Controller, UserSwitch
from mininet.cli import CLI
from mininet.topo import Topo
from mininet.topolib import TreeTopo
from mininet.log import setLogLevel, info
# Some minor hacks
class DataController( Controller ):
"""Data Network Controller.
patched to avoid checkListening error"""
def checkListening( self ):
"Ignore spurious error"
pass
class CLI2( CLI ):
"CLI that can talk to two networks"
def __init__( self, *args, **kwargs ):
"cnet: second network"
self.cnet = kwargs.pop( 'cnet' )
CLI.__init__( self, *args, **kwargs )
def updateVars( self ):
"Update variables to include cnet"
cnet = self.cnet
nodes2 = cnet.controllers + cnet.switches + cnet.hosts
self.nodelist += nodes2
for node in nodes2:
self.nodemap[ node.name ] = node
self.locals[ 'cnet' ] = cnet
self.locals.update( self.nodemap )
def cmdloop( self, *args, **kwargs ):
"Patch to add cnet if needed"
if 'cnet' not in self.locals:
self.updateVars()
CLI.cmdloop( self, *args, **kwargs )
# A real control network!
class ControlNetwork( Topo ):
"Control Network Topology"
def __init__( self, n, dataController=DataController, **kwargs ):
"""n: number of data network controller nodes
dataController: class for data network controllers"""
Topo.__init__( self, **kwargs )
# Connect everything to a single switch
cs0 = self.addSwitch( 'cs0' )
# Add hosts which will serve as data network controllers
for i in range( 0, n ):
c = self.addHost( 'c%s' % i, cls=dataController,
inNamespace=True )
self.addLink( c, cs0 )
# Connect switch to root namespace so that data network
# switches will be able to talk to us
root = self.addHost( 'root', inNamespace=False )
self.addLink( root, cs0 )
# Make it Happen!!
setLogLevel( 'info' )
info( '* Creating Control Network\n' )
ctopo = ControlNetwork( n=4, dataController=DataController )
cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', build=False )
info( '* Adding Control Network Controller\n')
cnet.addController( 'cc0' )
info( '* Starting Control Network\n')
cnet.build()
cnet.start()
dataControllers = cnet.hosts[ : -1 ] # ignore 'root' node
info( '* Creating Data Network\n' )
topo = TreeTopo( depth=2, fanout=2 )
# UserSwitch so we can easily test failover
net = Mininet( topo=topo, switch=UserSwitch, build=False )
info( '* Adding Controllers to Data Network\n' )
net.controllers = dataControllers
net.build()
info( '* Starting Data Network\n')
net.start()
CLI2( net, cnet=cnet )
info( '* Stopping Data Network\n' )
net.stop()
info( '* Stopping Control Network\n' )
# dataControllers have already been stopped
cnet.hosts = list( set( cnet.hosts ) - set( dataControllers ) )
cnet.stop()
+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/python
"""
Example to create a Mininet topology and connect it to the internet via NAT
through eth0 on the host.
Glen Gibb, February 2011
(slight modifications by BL, 5/13)
"""
from mininet.cli import CLI
from mininet.log import lg
from mininet.node import Node
from mininet.topolib import TreeNet
#################################
def startNAT( root, inetIntf='eth0', subnet='10.0/8' ):
"""Start NAT/forwarding between Mininet and external network
root: node to access iptables from
inetIntf: interface for internet access
subnet: Mininet subnet (default 10.0/8)="""
# Identify the interface connecting to the mininet network
localIntf = root.defaultIntf()
# Flush any currently active rules
root.cmd( 'iptables -F' )
root.cmd( 'iptables -t nat -F' )
# Create default entries for unmatched traffic
root.cmd( 'iptables -P INPUT ACCEPT' )
root.cmd( 'iptables -P OUTPUT ACCEPT' )
root.cmd( 'iptables -P FORWARD DROP' )
# Configure NAT
root.cmd( 'iptables -I FORWARD -i', localIntf, '-d', subnet, '-j DROP' )
root.cmd( 'iptables -A FORWARD -i', localIntf, '-s', subnet, '-j ACCEPT' )
root.cmd( 'iptables -A FORWARD -i', inetIntf, '-d', subnet, '-j ACCEPT' )
root.cmd( 'iptables -t nat -A POSTROUTING -o ', inetIntf, '-j MASQUERADE' )
# Instruct the kernel to perform forwarding
root.cmd( 'sysctl net.ipv4.ip_forward=1' )
def stopNAT( root ):
"""Stop NAT/forwarding between Mininet and external network"""
# Flush any currently active rules
root.cmd( 'iptables -F' )
root.cmd( 'iptables -t nat -F' )
# Instruct the kernel to stop forwarding
root.cmd( 'sysctl net.ipv4.ip_forward=0' )
def fixNetworkManager( root, intf ):
"""Prevent network-manager from messing with our interface,
by specifying manual configuration in /etc/network/interfaces
root: a node in the root namespace (for running commands)
intf: interface name"""
cfile = '/etc/network/interfaces'
line = '\niface %s inet manual\n' % intf
config = open( cfile ).read()
if ( line ) not in config:
print '*** Adding', line.strip(), 'to', cfile
with open( cfile, 'a' ) as f:
f.write( line )
# Probably need to restart network-manager to be safe -
# hopefully this won't disconnect you
root.cmd( 'service network-manager restart' )
def connectToInternet( network, switch='s1', rootip='10.254', subnet='10.0/8'):
"""Connect the network to the internet
switch: switch to connect to root namespace
rootip: address for interface in root namespace
subnet: Mininet subnet"""
switch = network.get( switch )
prefixLen = subnet.split( '/' )[ 1 ]
# Create a node in root namespace
root = Node( 'root', inNamespace=False )
# Prevent network-manager from interfering with our interface
fixNetworkManager( root, 'root-eth0' )
# Create link between root NS and switch
link = network.addLink( root, switch )
link.intf1.setIP( rootip, prefixLen )
# Start network that now includes link to root namespace
network.start()
# Start NAT and establish forwarding
startNAT( root )
# Establish routes from end hosts
for host in network.hosts:
host.cmd( 'ip route flush root 0/0' )
host.cmd( 'route add -net', subnet, 'dev', host.defaultIntf() )
host.cmd( 'route add default gw', rootip )
return root
if __name__ == '__main__':
lg.setLogLevel( 'info')
net = TreeNet( depth=1, fanout=4 )
# Configure and start NATted connectivity
rootnode = connectToInternet( net )
print "*** Hosts are running and should have internet connectivity"
print "*** Type 'exit' or control-D to shut down network"
CLI( net )
# Shut down NAT
stopNAT( rootnode )
net.stop()
+6 -3
View File
@@ -27,16 +27,19 @@ def cleanup():
info("*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
"\n")
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
zombies += 'ovs-openflowd udpbwtest'
zombies += 'ovs-openflowd ovs-controller udpbwtest mnexec'
# Note: real zombie processes can't actually be killed, since they
# 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' )
# And kill off sudo mnexec
sh( 'pkill -9 -f "sudo mnexec"')
info( "*** Removing junk from /tmp\n" )
sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' )
info( "*** Removing old screen sessions\n" )
info( "*** Removing old X11 tunnels\n" )
cleanUpScreens()
info( "*** Removing excess kernel datapaths\n" )
@@ -52,7 +55,7 @@ def cleanup():
sh( 'ovs-vsctl del-br ' + dp )
info( "*** Removing all links of the pattern foo-ethX\n" )
links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' )
links = sh( r"ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' )
for link in links:
if link != '':
sh( "ip link del " + link )
+28 -6
View File
@@ -33,7 +33,7 @@ import sys
import time
from mininet.log import info, output, error
from mininet.term import makeTerms
from mininet.term import makeTerms, runX11
from mininet.util import quietRun, isShellBuiltin, dumpNodeConnections
class CLI( Cmd ):
@@ -121,12 +121,12 @@ class CLI( Cmd ):
"Run an external shell command"
call( line, shell=True )
# do_py() needs to catch any exception during eval()
# do_py() and do_px() need to catch any exception during eval()/exec()
# pylint: disable-msg=W0703
def do_py( self, line ):
"""Evaluate a Python expression.
Node names may be used, e.g.: h1.cmd('ls')"""
Node names may be used, e.g.: py h1.cmd('ls')"""
try:
result = eval( line, globals(), self.locals )
if not result:
@@ -138,7 +138,18 @@ class CLI( Cmd ):
except Exception, e:
output( str( e ) + '\n' )
# pylint: enable-msg=W0703
# We are in fact using the exec() pseudo-function
# pylint: disable-msg=W0122
def do_px( self, line ):
"""Execute a Python statement.
Node names may be used, e.g.: px print h1.cmd('ls')"""
try:
exec( line, globals(), self.locals )
except Exception, e:
output( str( e ) + '\n' )
# pylint: enable-msg=W0703,W0122
def do_pingall( self, _line ):
"Ping between all hosts."
@@ -230,6 +241,17 @@ class CLI( Cmd ):
node = self.nodemap[ arg ]
self.mn.terms += makeTerms( [ node ], term = term )
def do_x( self, line ):
"""Create an X11 tunnel to the given node,
optionally starting a client."""
args = line.split()
if not args:
error( 'usage: x node [cmd args]...\n' )
else:
node = self.mn[ args[ 0 ] ]
cmd = args[ 1: ]
self.mn.terms += runX11( node, cmd )
def do_gterm( self, line ):
"Spawn gnome-terminal(s) for the given node(s)."
self.do_xterm( line, term='gterm' )
@@ -278,7 +300,7 @@ class CLI( Cmd ):
self.inputFile = None
def do_dpctl( self, line ):
"Run dpctl command on all switches."
"Run dpctl (or ovs-ofctl) command on all switches."
args = line.split()
if len(args) < 1:
error( 'usage: dpctl command [arg1] [arg2] ...\n' )
@@ -310,7 +332,7 @@ class CLI( Cmd ):
if first in self.nodemap:
node = self.nodemap[ first ]
# Substitute IP addresses for node names in command
rest = [ self.nodemap[ arg ].IP()
rest = [ self.nodemap[ arg ].defaultIntf().updateIP()
if arg in self.nodemap else arg
for arg in rest ]
rest = ' '.join( rest )
+20 -17
View File
@@ -25,8 +25,7 @@ Link: basic link class for creating veth pairs
"""
from mininet.log import info, error, debug
from mininet.util import makeIntfPair
from time import sleep
from mininet.util import makeIntfPair, quietRun
import re
class Intf( object ):
@@ -162,8 +161,9 @@ class Intf( object ):
def delete( self ):
"Delete interface"
self.cmd( 'ip link del ' + self.name )
# Does it help to sleep to let things run?
sleep( 0.001 )
if self.node.inNamespace:
# Link may have been dumped into root NS
quietRun( 'ip link del ' + self.name )
def __repr__( self ):
return '<%s %s>' % ( self.__class__.__name__, self.name )
@@ -196,36 +196,36 @@ class TCIntf( Intf ):
# are specifying the correct sizes. For now I have used
# the same settings we had in the mininet-hifi code.
if use_hfsc:
cmds += [ '%s qdisc add dev %s root handle 1:0 hfsc default 1',
'%s class add dev %s parent 1:0 classid 1:1 hfsc sc '
cmds += [ '%s qdisc add dev %s root handle 5:0 hfsc default 1',
'%s class add dev %s parent 5:0 classid 5:1 hfsc sc '
+ 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ]
elif use_tbf:
if latency_ms is None:
latency_ms = 15 * 8 / bw
cmds += [ '%s qdisc add dev %s root handle 1: tbf ' +
cmds += [ '%s qdisc add dev %s root handle 5: tbf ' +
'rate %fMbit burst 15000 latency %fms' %
( bw, latency_ms ) ]
else:
cmds += [ '%s qdisc add dev %s root handle 1:0 htb default 1',
'%s class add dev %s parent 1:0 classid 1:1 htb ' +
cmds += [ '%s qdisc add dev %s root handle 5:0 htb default 1',
'%s class add dev %s parent 5:0 classid 5:1 htb ' +
'rate %fMbit burst 15k' % bw ]
parent = ' parent 1:1 '
parent = ' parent 5:1 '
# ECN or RED
if enable_ecn:
cmds += [ '%s qdisc add dev %s' + parent +
'handle 10: red limit 1000000 ' +
'handle 6: red limit 1000000 ' +
'min 30000 max 35000 avpkt 1500 ' +
'burst 20 ' +
'bandwidth %fmbit probability 1 ecn' % bw ]
parent = ' parent 10: '
parent = ' parent 6: '
elif enable_red:
cmds += [ '%s qdisc add dev %s' + parent +
'handle 10: red limit 1000000 ' +
'handle 6: red limit 1000000 ' +
'min 30000 max 35000 avpkt 1500 ' +
'burst 20 ' +
'bandwidth %fmbit probability 1' % bw ]
parent = ' parent 10: '
parent = ' parent 6: '
return cmds, parent
@staticmethod
@@ -251,7 +251,8 @@ class TCIntf( Intf ):
cmds = [ '%s qdisc add dev %s ' + parent +
' handle 10: netem ' +
netemargs ]
return cmds
parent = ' parent 10:1 '
return cmds, parent
def tc( self, cmd, tc='tc' ):
"Execute tc command for our interface"
@@ -289,9 +290,10 @@ class TCIntf( Intf ):
cmds += bwcmds
# Delay/jitter/loss/max_queue_size using netem
cmds += self.delayCmds( delay=delay, jitter=jitter, loss=loss,
max_queue_size=max_queue_size,
delaycmds, parent = self.delayCmds( delay=delay, jitter=jitter,
loss=loss, max_queue_size=max_queue_size,
parent=parent )
cmds += delaycmds
# Ugly but functional: display configuration info
stuff = ( ( [ '%.2fMbit' % bw ] if bw is not None else [] ) +
@@ -308,6 +310,7 @@ class TCIntf( Intf ):
debug( "cmds:", cmds, '\n' )
debug( "outputs:", tcoutputs, '\n' )
result[ 'tcoutputs'] = tcoutputs
result[ 'parent' ] = parent
return result
+8 -10
View File
@@ -60,18 +60,16 @@ class Singleton( type ):
See http://en.wikipedia.org/wiki/SingletonPattern#Python
Intended to be used as a __metaclass_ param, as shown for the class
below.
below."""
Changed cls first args to mcs to satisfy pylint."""
def __init__( cls, name, bases, dict_ ):
super( Singleton, cls ).__init__( name, bases, dict_ )
cls.instance = None
def __init__( mcs, name, bases, dict_ ):
super( Singleton, mcs ).__init__( name, bases, dict_ )
mcs.instance = None
def __call__( mcs, *args, **kw ):
if mcs.instance is None:
mcs.instance = super( Singleton, mcs ).__call__( *args, **kw )
return mcs.instance
def __call__( cls, *args, **kw ):
if cls.instance is None:
cls.instance = super( Singleton, cls ).__call__( *args, **kw )
return cls.instance
class MininetLogger( Logger, object ):
+24 -10
View File
@@ -91,6 +91,7 @@ import re
import select
import signal
from time import sleep
from itertools import chain
from mininet.cli import CLI
from mininet.log import info, error, debug, output
@@ -216,8 +217,8 @@ class Mininet( object ):
self.nameToNode[ name ] = controller_new
return controller_new
# BL: is this better than just using nameToNode[] ?
# Should it have a better name?
# BL: We now have four ways to look up nodes
# This may (should?) be cleaned up in the future.
def getNodeByName( self, *args ):
"Return node(s) with given name(s)"
if len( args ) == 1:
@@ -228,6 +229,15 @@ class Mininet( object ):
"Convenience alias for getNodeByName"
return self.getNodeByName( *args )
# Even more convenient syntax for node lookup and iteration
def __getitem__( self, *args ):
"""net [ name ] operator: Return node(s) with given name(s)"""
return self.getNodeByName( *args )
def __iter__( self ):
"return iterator over nodes"
return chain( self.hosts, self.switches, self.controllers )
def addLink( self, node1, node2, port1=None, port2=None,
cls=None, **params ):
""""Add a link from node1 to node2
@@ -250,7 +260,7 @@ class Mininet( object ):
info( host.name + ' ' )
intf = host.defaultIntf()
if intf:
host.configDefault( defaultRoute=intf )
host.configDefault()
else:
# Don't configure nonexistent intf
host.configDefault( ip=None, mac=None )
@@ -362,16 +372,16 @@ class Mininet( object ):
if self.terms:
info( '*** Stopping %i terms\n' % len( self.terms ) )
self.stopXterms()
info( '*** Stopping %i hosts\n' % len( self.hosts ) )
for host in self.hosts:
info( host.name + ' ' )
host.terminate()
info( '\n' )
info( '*** Stopping %i switches\n' % len( self.switches ) )
for switch in self.switches:
info( switch.name + ' ' )
switch.stop()
info( '\n' )
info( '*** Stopping %i hosts\n' % len( self.hosts ) )
for host in self.hosts:
info( host.name + ' ' )
host.terminate()
info( '\n' )
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
for controller in self.controllers:
info( controller.name + ' ' )
@@ -458,9 +468,13 @@ class Mininet( object ):
lost += sent - received
output( ( '%s ' % dest.name ) if received else 'X ' )
output( '\n' )
if packets > 0:
ploss = 100 * lost / packets
output( "*** Results: %i%% dropped (%d/%d lost)\n" %
( ploss, lost, packets ) )
output( "*** Results: %i%% dropped (%d/%d lost)\n" %
( ploss, lost, packets ) )
else:
ploss = 0
output( "*** Warning: No packets sent\n" )
return ploss
@staticmethod
+78 -28
View File
@@ -49,6 +49,7 @@ import re
import signal
import select
from subprocess import Popen, PIPE, STDOUT
from operator import or_
from mininet.log import info, error, warn, debug
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
@@ -118,7 +119,8 @@ class Node( object ):
if self.inNamespace:
opts += 'n'
# bash -m: enable job control
cmd = [ 'mnexec', opts, 'bash', '-m' ]
# -s: pass $* to shell, and make process easy to find in ps
cmd = [ 'mnexec', opts, 'bash', '-ms', 'mininet:' + self.name ]
self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
close_fds=True )
self.stdin = self.shell.stdin
@@ -139,10 +141,10 @@ class Node( object ):
def cleanup( self ):
"Help python collect its garbage."
if not self.inNamespace:
for intfName in self.intfNames():
if self.name in intfName:
quietRun( 'ip link del ' + intfName )
# Intfs may end up in root NS
for intfName in self.intfNames():
if self.name in intfName:
quietRun( 'ip link del ' + intfName )
self.shell = None
# Subshell I/O, commands and control
@@ -290,7 +292,7 @@ class Node( object ):
kwargs: Popen() keyword args"""
defaults = { 'stdout': PIPE, 'stderr': PIPE,
'mncmd':
[ 'mnexec', '-a', str( self.pid ) ] }
[ 'mnexec', '-da', str( self.pid ) ] }
defaults.update( kwargs )
if len( args ) == 1:
if type( args[ 0 ] ) is list:
@@ -370,7 +372,7 @@ class Node( object ):
"""
if not intf:
return self.defaultIntf()
elif type( intf) is str:
elif type( intf ) is str:
return self.nameToIntf[ intf ]
else:
return intf
@@ -389,16 +391,19 @@ class Node( object ):
connections += [ ( intf, link.intf1 ) ]
return connections
def deleteIntfs( self ):
"Delete all of our interfaces."
def deleteIntfs( self, checkName=True ):
"""Delete all of our interfaces.
checkName: only delete interfaces that contain our name"""
# 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,
# at least with Linux kernels before 2.6.33
for intf in self.intfs.values():
intf.delete()
info( '.' )
# Protect against deleting hardware interfaces
if ( self.name in intf.name ) or ( not checkName ):
intf.delete()
info( '.' )
# Routing support
@@ -417,11 +422,14 @@ class Node( object ):
def setDefaultRoute( self, intf=None ):
"""Set the default route to go through intf.
intf: string, interface name"""
if not intf:
intf = self.defaultIntf()
self.cmd( 'ip route flush root 0/0' )
return self.cmd( 'route add default %s' % intf )
intf: Intf or {dev <intfname> via <gw-ip> ...}"""
# Note setParam won't call us if intf is none
if type( intf ) is str and ' ' in intf:
params = intf
else:
params = 'dev %s' % intf
self.cmd( 'ip route del default' )
return self.cmd( 'ip route add default', params )
# Convenience and configuration methods
@@ -447,7 +455,7 @@ class Node( object ):
def MAC( self, intf=None ):
"Return MAC address of a node or specific interface."
return self.intf( intf ).IP()
return self.intf( intf ).MAC()
def intfIsUp( self, intf=None ):
"Check if an interface is up."
@@ -492,7 +500,7 @@ class Node( object ):
r = {}
self.setParam( r, 'setMAC', mac=mac )
self.setParam( r, 'setIP', ip=ip )
self.setParam( r, 'defaultRoute', defaultRoute=defaultRoute )
self.setParam( r, 'setDefaultRoute', defaultRoute=defaultRoute )
# This should be examined
self.cmd( 'ifconfig lo ' + lo )
return r
@@ -604,14 +612,15 @@ class CPULimitedHost( Host ):
args: Popen() args, single list, or string
kwargs: Popen() keyword args"""
# Tell mnexec to execute command in our cgroup
mncmd = [ 'mnexec', '-a', str( self.pid ),
mncmd = [ 'mnexec', '-da', str( self.pid ),
'-g', self.name ]
if self.sched == 'rt':
mncmd += [ '-r', str( self.rtprio ) ]
return Host.popen( self, *args, mncmd=mncmd, **kwargs )
def cleanup( self ):
"Clean up our cgroup"
"Clean up Node, then clean up our cgroup"
super( CPULimitedHost, self ).cleanup()
retry( retries=3, delaySecs=1, fn=self.cgroupDel )
def chrt( self ):
@@ -754,7 +763,7 @@ class Switch( Node ):
def defaultDpid( self ):
"Derive dpid from switch name, s1 -> 1"
try:
dpid = int( re.findall( '\d+', self.name )[ 0 ] )
dpid = int( re.findall( r'\d+', self.name )[ 0 ] )
dpid = hex( dpid )[ 2: ]
dpid = '0' * ( self.dpidLen - len( dpid ) ) + dpid
return dpid
@@ -780,6 +789,10 @@ class Switch( Node ):
error( '*** Error: %s has execed and cannot accept commands' %
self.name )
def connected( self ):
"Is the switch connected to a controller? (override this method)"
return False and self # satisfy pylint
def __repr__( self ):
"More informative string representation"
intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() )
@@ -792,15 +805,17 @@ class UserSwitch( Switch ):
dpidLen = 12
def __init__( self, name, **kwargs ):
def __init__( self, name, dpopts='--no-slicing', **kwargs ):
"""Init.
name: name for the switch"""
name: name for the switch
dpopts: additional arguments to ofdatapath (--no-slicing)"""
Switch.__init__( self, name, **kwargs )
pathCheck( 'ofdatapath', 'ofprotocol',
moduleName='the OpenFlow reference user switch' +
'(openflow.org)' )
if self.listenPort:
self.opts += ' --listen=ptcp:%i ' % self.listenPort
self.dpopts = dpopts
@classmethod
def setup( cls ):
@@ -815,6 +830,10 @@ class UserSwitch( Switch ):
return self.cmd( 'dpctl ' + ' '.join( args ) +
' tcp:127.0.0.1:%i' % self.listenPort )
def connected( self ):
"Is the switch connected to a controller?"
return 'remote.is-connected=true' in self.dpctl( 'status' )
def start( self, controllers ):
"""Start OpenFlow reference user datapath.
Log to /tmp/sN-{ofd,ofp}.log.
@@ -827,7 +846,8 @@ class UserSwitch( Switch ):
self.cmd( 'ifconfig lo up' )
intfs = [ str( i ) for i in self.intfList() if not i.IP() ]
self.cmd( 'ofdatapath -i ' + ','.join( intfs ) +
' punix:/tmp/' + self.name + ' -d ' + self.dpid +
' punix:/tmp/' + self.name + ' -d %s ' % self.dpid +
self.dpopts +
' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
self.cmd( 'ofprotocol unix:/tmp/' + self.name +
' ' + clist +
@@ -895,12 +915,14 @@ class OVSLegacyKernelSwitch( Switch ):
class OVSSwitch( Switch ):
"Open vSwitch switch. Depends on ovs-vsctl."
def __init__( self, name, failMode='secure', **params ):
def __init__( self, name, failMode='secure', datapath='kernel', **params ):
"""Init.
name: name for switch
failMode: controller loss behavior (secure|open)"""
failMode: controller loss behavior (secure|open)
datapath: userspace or kernel mode (kernel|user)"""
Switch.__init__( self, name, **params )
self.failMode = failMode
self.datapath = datapath
@classmethod
def setup( cls ):
@@ -923,8 +945,8 @@ class OVSSwitch( Switch ):
exit( 1 )
def dpctl( self, *args ):
"Run ovs-dpctl command"
return self.cmd( 'ovs-dpctl', args[ 0 ], self, *args[ 1: ] )
"Run ovs-ofctl command"
return self.cmd( 'ovs-ofctl', args[ 0 ], self, *args[ 1: ] )
@staticmethod
def TCReapply( intf ):
@@ -944,6 +966,23 @@ class OVSSwitch( Switch ):
"Disconnect a data port"
self.cmd( 'ovs-vsctl del-port', self, intf )
def controllerUUIDs( self ):
"Return ovsdb UUIDs for our controllers"
uuids = []
controllers = self.cmd( 'ovs-vsctl -- get Bridge', self,
'Controller' ).strip()
if controllers.startswith( '[' ) and controllers.endswith( ']' ):
controllers = controllers[ 1 : -1 ]
uuids = [ c.strip() for c in controllers.split( ',' ) ]
return uuids
def connected( self ):
"Are we connected to at least one of our controllers?"
results = [ 'true' in self.cmd( 'ovs-vsctl -- get Controller',
uuid, 'is_connected' )
for uuid in self.controllerUUIDs() ]
return reduce( or_, results, False )
def start( self, controllers ):
"Start up a new OVS OpenFlow switch using ovs-vsctl"
if self.inNamespace:
@@ -955,6 +994,9 @@ class OVSSwitch( Switch ):
# Annoyingly, --if-exists option seems not to work
self.cmd( 'ovs-vsctl del-br', self )
self.cmd( 'ovs-vsctl add-br', self )
if self.datapath == 'user':
self.cmd( 'ovs-vsctl set bridge', self,'datapath_type=netdev' )
int( self.dpid, 16 ) # DPID must be a hex string
self.cmd( 'ovs-vsctl -- set Bridge', self,
'other_config:datapath-id=' + self.dpid )
self.cmd( 'ovs-vsctl set-fail-mode', self, self.failMode )
@@ -967,6 +1009,14 @@ class OVSSwitch( Switch ):
if self.listenPort:
clist += ' ptcp:%s' % self.listenPort
self.cmd( 'ovs-vsctl set-controller', self, clist )
# Reconnect quickly to controllers (1s vs. 15s max_backoff)
for uuid in self.controllerUUIDs():
if uuid.count( '-' ) != 4:
# Doesn't look like a UUID
continue
uuid = uuid.strip()
self.cmd( 'ovs-vsctl set Controller', uuid,
'max_backoff=1000' )
def stop( self ):
"Terminate OVS switch."
+45 -32
View File
@@ -1,60 +1,73 @@
"""
Terminal creation and cleanup.
Utility functions to run a term (connected via screen(1)) on each host.
Utility functions to run a terminal (connected via socat(1)) on each host.
Requires GNU screen(1) and xterm(1).
Requires socat(1) and xterm(1).
Optionally uses gnome-terminal.
"""
import re
from subprocess import Popen
from os import environ
from mininet.log import error
from mininet.util import quietRun
from mininet.util import quietRun, errRun
def quoteArg( arg ):
"Quote an argument if it contains spaces."
return repr( arg ) if ' ' in arg else arg
def tunnelX11( node, display=None):
"""Create an X11 tunnel from node:6000 to the root host
display: display on root host (optional)
returns: node $DISPLAY, Popen object for tunnel"""
if display is None:
display = environ[ 'DISPLAY' ]
host, screen = display.split( ':' )
# Unix sockets should work
if not host or host == 'unix':
# GDM3 doesn't put credentials in .Xauthority,
# so allow root to just connect
quietRun( 'xhost +si:localuser:root' )
return display, None
else:
# Create a tunnel for the TCP connection
port = 6000 + int( float( screen ) )
connection = r'TCP\:%s\:%s' % ( host, port )
cmd = [ "socat", "TCP-LISTEN:%d,fork,reuseaddr" % port,
"EXEC:'mnexec -a 1 socat STDIO %s'" % connection ]
return 'localhost:' + screen, node.popen( cmd )
def makeTerm( node, title='Node', term='xterm' ):
"""Run screen on a node, and hook up a terminal.
def makeTerm( node, title='Node', term='xterm', display=None ):
"""Create an X11 tunnel to the node and start up a terminal.
node: Node object
title: base title
term: 'xterm' or 'gterm'
returns: process created"""
returns: two Popen objects, tunnel and terminal"""
title += ': ' + node.name
if not node.inNamespace:
title += ' (root)'
cmds = {
'xterm': [ 'xterm', '-title', title, '-e' ],
'gterm': [ 'gnome-terminal', '--title', title, '-e' ]
'xterm': [ 'xterm', '-title', title, '-display' ],
'gterm': [ 'gnome-terminal', '--title', title, '--display' ]
}
if term not in cmds:
error( 'invalid terminal type: %s' % term )
return
if not node.execed:
node.cmd( 'screen -dmS ' + 'mininet.' + node.name)
args = [ 'screen', '-D', '-RR', '-S', 'mininet.' + node.name ]
else:
args = [ 'sh', '-c', 'exec tail -f /tmp/' + node.name + '*.log' ]
if term == 'gterm':
# Compress these for gnome-terminal, which expects one token
# to follow the -e option
args = [ ' '.join( [ quoteArg( arg ) for arg in args ] ) ]
return Popen( cmds[ term ] + args )
display, tunnel = tunnelX11( node, display )
term = node.popen( cmds[ term ] + [ display, '-e', 'env TERM=ansi bash'] )
return [ tunnel, term ] if tunnel else [ term ]
def runX11( node, cmd ):
"Run an X11 client on a node"
_display, tunnel = tunnelX11( node )
popen = node.popen( cmd )
return [ tunnel, popen ]
def cleanUpScreens():
"Remove moldy old screen sessions."
r = r'(\d+\.mininet\.[hsc]\d+)'
output = quietRun( 'screen -ls' ).split( '\n' )
for line in output:
m = re.search( r, line )
if m:
quietRun( 'screen -S ' + m.group( 1 ) + ' -X quit' )
"Remove moldy socat X11 tunnels."
errRun( "pkill -9 -f mnexec.*socat" )
def makeTerms( nodes, title='Node', term='xterm' ):
"""Create terminals.
nodes: list of Node objects
title: base title for each
returns: list of created terminal processes"""
return [ makeTerm( node, title, term ) for node in nodes ]
returns: list of created tunnel/terminal processes"""
terms = []
for node in nodes:
terms += makeTerm( node, title, term )
return terms
+33 -5
View File
@@ -11,13 +11,41 @@ A Topo object can be a topology database for NOX, can represent a physical
setup for testing, and can even be emulated with the Mininet package.
'''
# BL: we may have to fix compatibility here.
# networkx is also a fairly heavyweight dependency
# from networkx.classes.graph import Graph
from networkx import Graph
from mininet.util import irange, natural, naturalSeq
class Graph( object ):
"Utility class to track nodes and edges - replaces networkx.Graph"
def __init__( self ):
self.data = {}
def add_node( self, node ):
"Add node to graph"
if node not in self.data.keys():
self.data[ node ] = []
def add_edge( self, src, dest ):
"Add edge to graph"
self.add_node( src )
self.add_node( dest )
self.data[ src ].append( dest )
self.data[ dest ].append( src )
def nodes( self ):
"Return list of graph nodes"
return self.data.keys()
def edges( self ):
"Iterator: return graph edges"
for src in self.data.keys():
for dest in self.data[ src ]:
yield ( src, dest )
def __getitem__( self, node ):
"Return link dict for the given node"
return self.data[node]
class Topo(object):
"Data center network representation for structured multi-trees."
+38 -34
View File
@@ -4,7 +4,7 @@ from mininet.log import output, info, error, warn
from time import sleep
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
from select import poll, POLLIN
from select import poll, POLLIN, POLLHUP
from subprocess import call, check_call, Popen, PIPE, STDOUT
import re
from fcntl import fcntl, F_GETFL, F_SETFL
@@ -171,27 +171,35 @@ def retry( retries, delaySecs, fn, *args, **keywords ):
error( "*** gave up after %i retries\n" % tries )
exit( 1 )
def moveIntfNoRetry( intf, node, printError=False ):
def moveIntfNoRetry( intf, dstNode, srcNode=None, printError=False ):
"""Move interface to node, without retrying.
intf: string, interface
node: Node object
printError: if true, print error"""
cmd = 'ip link set ' + intf + ' netns ' + repr( node.pid )
quietRun( cmd )
links = node.cmd( 'ip link show' )
dstNode: destination Node
srcNode: source Node or None (default) for root ns
printError: if true, print error"""
intf = str( intf )
cmd = 'ip link set %s netns %s' % ( intf, dstNode.pid )
if srcNode:
srcNode.cmd( cmd )
else:
quietRun( cmd )
links = dstNode.cmd( 'ip link show' )
if not ( ' %s:' % intf ) in links:
if printError:
error( '*** Error: moveIntf: ' + intf +
' not successfully moved to ' + node.name + '\n' )
' not successfully moved to ' + dstNode.name + '\n' )
return False
return True
def moveIntf( intf, node, printError=False, retries=3, delaySecs=0.001 ):
def moveIntf( intf, dstNode, srcNode=None, printError=False,
retries=3, delaySecs=0.001 ):
"""Move interface to node, retrying on failure.
intf: string, interface
node: Node object
dstNode: destination Node
srcNode: source Node or None (default) for root ns
printError: if true, print error"""
retry( retries, delaySecs, moveIntfNoRetry, intf, node, printError )
retry( retries, delaySecs, moveIntfNoRetry, intf, dstNode,
srcNode=srcNode, printError=printError )
# Support for dumping network
@@ -242,9 +250,8 @@ def macColonHex( mac ):
def ipStr( ip ):
"""Generate IP address string from an unsigned int.
ip: unsigned int of form w << 24 | x << 16 | y << 8 | z
returns: ip address string w.x.y.z, or 10.x.y.z if w==0"""
returns: ip address string w.x.y.z"""
w = ( ip >> 24 ) & 0xff
w = 10 if w == 0 else w
x = ( ip >> 16 ) & 0xff
y = ( ip >> 8 ) & 0xff
z = ip & 0xff
@@ -261,10 +268,10 @@ def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ):
prefixLen: optional IP prefix length
ipBaseNum: option base IP address as int
returns IP address as string"""
# Ugly but functional
assert i < ( 1 << ( 32 - prefixLen ) )
mask = 0xffffffff ^ ( ( 1 << prefixLen ) - 1 )
ipnum = i + ( ipBaseNum & mask )
imax = 0xffffffff >> prefixLen
assert i <= imax
mask = 0xffffffff ^ imax
ipnum = ( ipBaseNum & mask ) + i
return ipStr( ipnum )
def ipParse( ip ):
@@ -326,27 +333,24 @@ def pmonitor(popens, timeoutms=500, readline=True,
# Use non-blocking reads
flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
while True:
while popens:
fds = poller.poll( timeoutms )
if fds:
for fd, _event in fds:
for fd, event in fds:
host = fdToHost[ fd ]
popen = popens[ host ]
if readline:
# Attempt to read a line of output
# This blocks until we receive a newline!
line = popen.stdout.readline()
else:
line = popen.stdout.read( readmax )
yield host, line
if event & POLLIN:
if readline:
# Attempt to read a line of output
# This blocks until we receive a newline!
line = popen.stdout.readline()
else:
line = popen.stdout.read( readmax )
yield host, line
# Check for EOF
if not line:
popen.poll()
if popen.returncode is not None:
poller.unregister( fd )
del popens[ host ]
if not popens:
return
elif event & POLLHUP:
poller.unregister( fd )
del popens[ host ]
else:
yield None, ''
@@ -419,7 +423,7 @@ def splitArgs( argstr ):
args = [ makeNumeric( s ) for s in params if '=' not in s ]
kwargs = {}
for s in [ p for p in params if '=' in p ]:
key, val = s.split( '=' )
key, val = s.split( '=', 1 )
kwargs[ key ] = makeNumeric( val )
return fn, args, kwargs
+1 -1
View File
@@ -46,7 +46,7 @@ void usage(char *name)
int setns(int fd, int nstype)
{
return syscall(308, fd, nstype);
return syscall(__NR_setns, fd, nstype);
}
/* Validate alphanumeric path foo1/bar2/baz */
+1 -2
View File
@@ -37,8 +37,7 @@ setup(
keywords='networking emulator protocol Internet OpenFlow SDN',
license='BSD',
install_requires=[
'setuptools',
'networkx'
'setuptools'
],
scripts=scripts,
)
+175 -63
View File
@@ -9,6 +9,18 @@ set -e
# Fail on unset var usage
set -o nounset
# Get directory containing mininet folder
MININET_DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
# Set up build directory, which by default is the working directory
# unless the working directory is a subdirectory of mininet,
# in which case we use the directory containing mininet
BUILD_DIR=$PWD
case $PWD in
$MININET_DIR/*) BUILD_DIR=$MININET_DIR;; # currect directory is a subdirectory
*) BUILD_DIR=$PWD;;
esac
# Location of CONFIG_NET_NS-enabled kernel(s)
KERNEL_LOC=http://www.openflow.org/downloads/mininet
@@ -72,7 +84,7 @@ OVS_RELEASE=1.4.0
OVS_PACKAGE_LOC=https://github.com/downloads/mininet/mininet
OVS_BUILDSUFFIX=-ignore # was -2
OVS_PACKAGE_NAME=ovs-$OVS_RELEASE-core-$DIST_LC-$RELEASE-$ARCH$OVS_BUILDSUFFIX.tar
OVS_SRC=~/openvswitch
OVS_SRC=$BUILD_DIR/openvswitch
OVS_TAG=v$OVS_RELEASE
OVS_BUILD=$OVS_SRC/build-$KERNEL_NAME
OVS_KMODS=($OVS_BUILD/datapath/linux/{openvswitch_mod.ko,brcompat_mod.ko})
@@ -116,30 +128,27 @@ function kernel_clean {
fi
# Also remove downloaded packages:
rm -f ~/linux-headers-* ~/linux-image-*
rm -f $HOME/linux-headers-* $HOME/linux-image-*
}
# Install Mininet deps
function mn_deps {
echo "Installing Mininet dependencies"
$install gcc make screen psmisc xterm ssh iperf iproute telnet \
python-setuptools python-networkx cgroup-bin ethtool help2man \
$install gcc make socat psmisc xterm ssh iperf iproute telnet \
python-setuptools cgroup-bin ethtool help2man \
pyflakes pylint pep8
if [ "$DIST" = "Ubuntu" ] && [ "$RELEASE" = "10.04" ]; then
echo "Upgrading networkx to avoid deprecation warning"
sudo easy_install --upgrade networkx
fi
# Add sysctl parameters as noted in the INSTALL file to increase kernel
# limits to support larger setups:
sudo su -c "cat $HOME/mininet/util/sysctl_addon >> /etc/sysctl.conf"
if ! grep Mininet /etc/sysctl.conf; then
echo "Adding Mininet sysctl settings"
sudo su -c "cat $MININET_DIR/mininet/util/sysctl_addon >> /etc/sysctl.conf"
fi
# Load new sysctl settings:
sudo sysctl -p
echo "Installing Mininet core"
pushd ~/mininet
pushd $MININET_DIR/mininet
sudo make install
popd
}
@@ -151,45 +160,66 @@ function mn_deps {
# ... modified to use Debian Lenny rather than unstable.
function of {
echo "Installing OpenFlow reference implementation..."
cd ~/
cd $BUILD_DIR/
$install git-core autoconf automake autotools-dev pkg-config \
make gcc libtool libc6-dev
git clone git://openflowswitch.org/openflow.git
cd ~/openflow
cd $BUILD_DIR/openflow
# Patch controller to handle more than 16 switches
patch -p1 < ~/mininet/util/openflow-patches/controller.patch
patch -p1 < $MININET_DIR/mininet/util/openflow-patches/controller.patch
# Resume the install:
./boot.sh
./configure
make
sudo make install
cd $BUILD_DIR
}
# Remove avahi-daemon, which may cause unwanted discovery packets to be
# sent during tests, near link status changes:
$remove avahi-daemon
function of13 {
echo "Installing OpenFlow 1.3 soft switch implementation..."
cd $BUILD_DIR/
$install git-core autoconf automake autotools-dev pkg-config \
make gcc g++ libtool libc6-dev cmake libpcap-dev libxerces-c2-dev \
unzip libpcre3-dev flex bison libboost-dev
# Disable IPv6. Add to /etc/modprobe.d/blacklist:
if [ "$DIST" = "Ubuntu" ]; then
BLACKLIST=/etc/modprobe.d/blacklist.conf
else
BLACKLIST=/etc/modprobe.d/blacklist
if [ ! -d "ofsoftswitch13" ]; then
git clone https://github.com/CPqD/ofsoftswitch13.git
fi
sudo sh -c "echo 'blacklist net-pf-10\nblacklist ipv6' >> $BLACKLIST"
cd ~
# Install netbee
NBEESRC="nbeesrc-jan-10-2013"
NBEEURL=${NBEEURL:-http://www.nbee.org/download/}
wget -nc ${NBEEURL}${NBEESRC}.zip
unzip ${NBEESRC}.zip
cd ${NBEESRC}/src
cmake .
make
cd $BUILD_DIR/
sudo cp ${NBEESRC}/bin/libn*.so /usr/local/lib
sudo ldconfig
sudo cp -R ${NBEESRC}/include/ /usr/
# Resume the install:
cd $BUILD_DIR/ofsoftswitch13
./boot.sh
./configure
make
sudo make install
cd $BUILD_DIR
}
function wireshark {
echo "Installing Wireshark dissector..."
sudo apt-get install -y wireshark libgtk2.0-dev
sudo apt-get install -y wireshark tshark libgtk2.0-dev
if [ "$DIST" = "Ubuntu" ] && [ "$RELEASE" != "10.04" ]; then
# Install newer version
sudo apt-get install -y scons mercurial libglib2.0-dev
sudo apt-get install -y libwiretap-dev libwireshark-dev
cd ~
cd $BUILD_DIR
hg clone https://bitbucket.org/barnstorm/of-dissector
cd of-dissector/src
export WIRESHARK=/usr/include/wireshark
@@ -201,14 +231,14 @@ function wireshark {
echo "Copied openflow plugin to $WSPLUGDIR"
else
# Install older version from reference source
cd ~/openflow/utilities/wireshark_dissectors/openflow
cd $BUILD_DIR/openflow/utilities/wireshark_dissectors/openflow
make
sudo make install
fi
# Copy coloring rules: OF is white-on-blue:
mkdir -p ~/.wireshark
cp ~/mininet/util/colorfilters ~/.wireshark
mkdir -p $HOME/.wireshark
cp $MININET_DIR/mininet/util/colorfilters $HOME/.wireshark
}
@@ -266,7 +296,7 @@ function ovs {
if [ $ovspresent = 1 ]; then
echo "Done (hopefully) installing packages"
cd ~
cd $BUILD_DIR
return
fi
@@ -289,7 +319,7 @@ function ovs {
fi
# Install OVS from release
cd ~/
cd $BUILD_DIR/
git clone git://openvswitch.org/openvswitch $OVS_SRC
cd $OVS_SRC
git checkout $OVS_TAG
@@ -348,7 +378,7 @@ function nox {
$install libsqlite3-dev python-simplejson
# Fetch NOX destiny
cd ~/
cd $BUILD_DIR/
git clone https://github.com/noxrepo/nox-classic.git noxcore
cd noxcore
if ! git checkout -b destiny remotes/origin/destiny ; then
@@ -357,9 +387,9 @@ function nox {
# Apply patches
git checkout -b tutorial-destiny
git am ~/mininet/util/nox-patches/*tutorial-port-nox-destiny*.patch
git am $MININET_DIR/mininet/util/nox-patches/*tutorial-port-nox-destiny*.patch
if [ "$DIST" = "Ubuntu" ] && [ `expr $RELEASE '>=' 12.04` = 1 ]; then
git am ~/mininet/util/nox-patches/*nox-ubuntu12-hacks.patch
git am $MININET_DIR/mininet/util/nox-patches/*nox-ubuntu12-hacks.patch
fi
# Build
@@ -371,17 +401,51 @@ function nox {
#make check
# Add NOX_CORE_DIR env var:
sed -i -e 's|# for examples$|&\nexport NOX_CORE_DIR=~/noxcore/build/src|' ~/.bashrc
sed -i -e 's|# for examples$|&\nexport NOX_CORE_DIR=$BUILD_DIR/noxcore/build/src|' ~/.bashrc
# To verify this install:
#cd ~/noxcore/build/src
#./nox_core -v -i ptcp:
}
# Install NOX Classic/Zaku for OpenFlow 1.3
function nox13 {
echo "Installing NOX w/tutorial files..."
# Install NOX deps:
$install autoconf automake g++ libtool python python-twisted \
swig libssl-dev make
if [ "$DIST" = "Debian" ]; then
$install libboost1.35-dev
elif [ "$DIST" = "Ubuntu" ]; then
$install python-dev libboost-dev
$install libboost-filesystem-dev
$install libboost-test-dev
fi
# Fetch NOX destiny
cd $BUILD_DIR/
git clone https://github.com/CPqD/nox13oflib.git
cd nox13oflib
# Build
./boot.sh
mkdir build
cd build
../configure
make -j3
#make check
# To verify this install:
#cd ~/nox13oflib/build/src
#./nox_core -v -i ptcp:
}
# "Install" POX
function pox {
echo "Installing POX into $HOME/pox..."
cd ~
echo "Installing POX into $BUILD_DIR/pox..."
cd $BUILD_DIR
git clone https://github.com/noxrepo/pox.git
}
@@ -393,11 +457,8 @@ function oftest {
$install tcpdump python-scapy
# Install oftest:
cd ~/
cd $BUILD_DIR/
git clone git://github.com/floodlight/oftest
cd oftest
cd tools/munger
sudo make install
}
# Install cbench
@@ -405,25 +466,56 @@ function cbench {
echo "Installing cbench..."
$install libsnmp-dev libpcap-dev libconfig-dev
cd ~/
cd $BUILD_DIR/
git clone git://openflow.org/oflops.git
cd oflops
sh boot.sh || true # possible error in autoreconf, so run twice
sh boot.sh
./configure --with-openflow-src-dir=$HOME/openflow
./configure --with-openflow-src-dir=$BUILD_DIR/openflow
make
sudo make install || true # make install fails; force past this
}
function other {
echo "Doing other setup tasks..."
function vm_other {
echo "Doing other Mininet VM setup tasks..."
# Remove avahi-daemon, which may cause unwanted discovery packets to be
# sent during tests, near link status changes:
echo "Removing avahi-daemon"
$remove avahi-daemon
# was: Disable IPv6. Add to /etc/modprobe.d/blacklist:
#echo "Attempting to disable IPv6"
#if [ "$DIST" = "Ubuntu" ]; then
# BLACKLIST=/etc/modprobe.d/blacklist.conf
#else
# BLACKLIST=/etc/modprobe.d/blacklist
#fi
#sudo sh -c "echo 'blacklist net-pf-10\nblacklist ipv6' >> $BLACKLIST"
# Disable IPv6
if ! grep 'disable IPv6' /etc/sysctl.conf; then
echo 'Disabling IPv6'
echo '
# Mininet: disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee -a /etc/sysctl.conf > /dev/null
fi
# Disabling IPv6 breaks X11 forwarding via ssh
line='AddressFamily inet'
file='/etc/ssh/sshd_config'
echo "Adding $line to $file"
if ! grep "$line" $file > /dev/null; then
echo "$line" | sudo tee -a $file > /dev/null
fi
# Enable command auto completion using sudo; modify ~/.bashrc:
sed -i -e 's|# for examples$|&\ncomplete -cf sudo|' ~/.bashrc
# Install tcpdump and tshark, cmd-line packet dump tools. Also install gitk,
# Install tcpdump, cmd-line packet dump tool. Also install gitk,
# a graphical git history viewer.
$install tcpdump tshark gitk
$install tcpdump gitk
# Install common text editors
$install vim nano emacs
@@ -471,8 +563,6 @@ function all {
pox
oftest
cbench
other
echo "Please reboot, then run ./mininet/util/install.sh -c to remove unneeded packages."
echo "Enjoy Mininet!"
}
@@ -480,6 +570,7 @@ function all {
function vm_clean {
echo "Cleaning VM..."
sudo apt-get clean
sudo apt-get autoremove
sudo rm -rf /tmp/*
sudo rm -rf openvswitch*.tar.gz
@@ -500,16 +591,20 @@ function vm_clean {
git config --global user.name "None"
git config --global user.email "None"
# Remove mininet install script
rm -f install-mininet.sh
# Note: you can shrink the .vmdk in vmware using
# vmware-vdiskmanager -k *.vmdk
echo "Zeroing out disk blocks for efficient compaction..."
time sudo dd if=/dev/zero of=/tmp/zero bs=1M
sync ; sleep 1 ; sync ; sudo rm -f /tmp/zero
}
function usage {
printf 'Usage: %s [-acdfhkmntvxy]\n\n' $(basename $0) >&2
printf '\nUsage: %s [-abcdfhkmnprtvwx03]\n\n' $(basename $0) >&2
printf 'This install script attempts to install useful packages\n' >&2
printf 'for Mininet. It should (hopefully) work on Ubuntu 10.04, 11.10\n' >&2
printf 'and Debian 5.0 (Lenny). If you run into trouble, try\n' >&2
printf 'for Mininet. It should (hopefully) work on Ubuntu 11.10+\n' >&2
printf 'If you run into trouble, try\n' >&2
printf 'installing one thing at a time, and looking at the \n' >&2
printf 'specific installation function in this script.\n\n' >&2
@@ -523,38 +618,55 @@ function usage {
printf -- ' -k: install new (K)ernel\n' >&2
printf -- ' -m: install Open vSwitch kernel (M)odule from source dir\n' >&2
printf -- ' -n: install mini(N)et dependencies + core files\n' >&2
printf -- ' -p: install (P)OX OpenFlow Controller\n' >&2
printf -- ' -r: remove existing Open vSwitch packages\n' >&2
printf -- ' -t: install o(T)her stuff\n' >&2
printf -- ' -t: complete o(T)her Mininet VM setup tasks\n' >&2
printf -- ' -v: install open (V)switch\n' >&2
printf -- ' -w: install OpenFlow (w)ireshark dissector\n' >&2
printf -- ' -x: install NO(X) OpenFlow controller\n' >&2
printf -- ' -y: install (A)ll packages\n' >&2
printf -- ' -x: install NO(X) Classic OpenFlow controller\n' >&2
printf -- ' -0: (default) -0[fx] installs OpenFlow 1.0 versions\n' >&2
printf -- ' -3: -3[fx] installs OpenFlow 1.3 versions\n' >&2
printf -- ' -i < directory >: sets the (I)nstallation directory for Mininet dependencies\n' >&2
exit 2
}
OF_VERSION=1.0
if [ $# -eq 0 ]
then
all
else
while getopts 'abcdfhkmnprtvwx' OPTION
while getopts 'abcdfhkmnprtvwx03i:' OPTION
do
case $OPTION in
a) all;;
b) cbench;;
c) kernel_clean;;
d) vm_clean;;
f) of;;
f) case $OF_VERSION in
1.0) of;;
1.3) of13;;
*) echo "Invalid OpenFlow version $OF_VERSION";;
esac;;
h) usage;;
k) kernel;;
m) modprobe;;
n) mn_deps;;
p) pox;;
r) remove_ovs;;
t) other;;
t) vm_other;;
v) ovs;;
w) wireshark;;
x) nox;;
x) case $OF_VERSION in
1.0) nox;;
1.3) nox13;;
*) echo "Invalid OpenFlow version $OF_VERSION";;
esac;;
0) OF_VERSION=1.0;;
3) OF_VERSION=1.3;;
i) mkdir -p $OPTARG; # ensure the directory is created
BUILD_DIR="$( cd -P "$OPTARG" && pwd )"; # get the full path of the directory
echo "Dependency installation directory: $BUILD_DIR";;
?) usage;;
esac
done
Executable
+36
View File
@@ -0,0 +1,36 @@
#!/bin/bash
# Attach to a Mininet host and run a command
if [ -z $1 ]; then
echo "usage: $0 host cmd [args...]"
exit 1
else
host=$1
fi
pid=`ps ax | grep "mininet:$host$" | grep bash | awk '{print $1};'`
if echo $pid | grep -q ' '; then
echo "Error: found multiple mininet:$host processes"
exit 2
fi
if [ "$pid" == "" ]; then
echo "Could not find Mininet host $host"
exit 3
fi
if [ -z $2 ]; then
cmd='bash'
else
shift
cmd=$*
fi
cgroup=/sys/fs/cgroup/cpu/$host
if [ -d "$cgroup" ]; then
cg="-g $host"
fi
exec sudo mnexec -a $pid $cg $cmd
+1
View File
@@ -15,3 +15,4 @@ net.ipv4.neigh.default.gc_thresh3 = 16384
# Mininet: increase routing table size
net.ipv4.route.max_size=32768
+9 -8
View File
@@ -4,15 +4,19 @@
# a brand-new Ubuntu virtual machine,
# to create a fully usable "tutorial" VM.
set -e
echo `whoami` ALL=NOPASSWD: ALL | sudo tee -a /etc/sudoers
echo `whoami` ALL=NOPASSWD: ALL | sudo tee -a /etc/sudoers > /dev/null
sudo sed -i -e 's/Default/#Default/' /etc/sudoers
sudo sed -i -e 's/ubuntu/mininet-vm/' /etc/hostname
echo mininet-vm | sudo tee /etc/hostname > /dev/null
sudo sed -i -e 's/ubuntu/mininet-vm/g' /etc/hosts
sudo hostname `cat /etc/hostname`
sudo sed -i -e 's/quiet splash/text/' /etc/default/grub
sudo update-grub
# 12.10 and earlier
sudo sed -i -e 's/us.archive.ubuntu.com/mirrors.kernel.org/' \
/etc/apt/sources.list
# 13.04 and later
sudo sed -i -e 's/\/archive.ubuntu.com/\/mirrors.kernel.org/' \
/etc/apt/sources.list
sudo apt-get update
# Clean up vmware easy install junk if present
if [ -e /etc/issue.backup ]; then
@@ -27,14 +31,11 @@ git clone git://github.com/mininet/mininet
cd mininet
cd
time mininet/util/install.sh
# Finalize VM
time mininet/util/install.sh -tc
# Ignoring this since NOX classic is deprecated
#if ! grep NOX_CORE_DIR .bashrc; then
# echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc
#fi
echo <<EOF
You may need to reboot and then:
sudo dpkg-reconfigure openvswitch-datapath-dkms
sudo service openvswitch-switch start
EOF
echo "Done preparing Mininet VM."