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 Installation/Configuration Notes
----------------------------------------
Mininet 2.0.0 Mininet 2.0.0
--- ---
The supported installation methods for Mininet are 1) using The supported installation methods for Mininet are 1) using a
a pre-built VM image, and 2) native installation on Ubuntu. You pre-built VM image, and 2) native installation on Ubuntu. You can also
can also easily create your own Mininet VM image (3). easily create your own Mininet VM image (4).
(Other distributions may be supported in the future - if you would (Other distributions may be supported in the future - if you would
like to contribute an installation script, we would welcome it!) like to contribute an installation script, we would welcome it!)
1. Easiest "installation" - use our pre-built VM image! 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 The easiest way to get Mininet running is to start with one of our
virtual machine images from http://openflow.org/mininet 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 One advantage of using the VM image is that it doesn't mess with
your native OS installation or damage it in any way. your native OS installation or damage it in any way.
Although a single Mininet instance can simulate multiple networks with Although a single Mininet instance can simulate multiple networks
multiple controllers, only one Mininet instance may currently be run at with multiple controllers, only one Mininet instance may currently
a time, and Mininet requires root access in the machine it's running on. be run at a time, and Mininet requires root access in the machine
Therefore, if you have a multiuser system, you may wish to consider it's running on. Therefore, if you have a multiuser system, you
running Mininet in a VM. may wish to consider running Mininet in a VM.
2. Next-easiest option: use our Ubuntu package! 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 Note: if you are upgrading from an older version of Mininet, make
remove the old OVS from /usr/local: sure you remove the old OVS from `/usr/local`:
sudo rm /usr/local/bin/ovs* sudo rm /usr/local/bin/ovs*
sudo rm /usr/local/sbin/ovs* sudo rm /usr/local/sbin/ovs*
3. Native installation from source on Ubuntu 11.10+ 3. Native installation from source on Ubuntu 11.10+
If you're reading this, you've probably already done so, but the command to If you're reading this, you've probably already done so, but the
download the Mininet source code is; command to download the Mininet source code is:
git clone git://openflow.org/mininet.git
If you are running Ubuntu, you may be able to use our handy install.sh script, git clone git://github.com/mininet/mininet.git
which is in mininet/util.
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 *WARNING: USE AT YOUR OWN RISK!*
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!
To install Mininet itself, the OpenFlow reference implementation, and `install.sh` is a bit intrusive and may possibly damage your OS
Open vSwitch, you may use: 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 mininet/util/install.sh -fnv
after the installation:
$ 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, sudo mn --test pingall
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
$ 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 4. Creating your own Mininet/OpenFlow tutorial VM
Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial
is easy! First, create a new Ubuntu VM. Then, run 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 wget https://raw.github.com/mininet/mininet/master/util/vm/install-mininet-vm.sh
$ time 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 5. Installation on other Linux distributions
Although we don't support other Linux distributions directly, it should be Although we don't support other Linux distributions directly, it
possible to install and run Mininet with some degree of manual effort. 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 * An OpenFlow implementation (either the reference user or kernel
space implementations, or Open vSwitch.) Appropriate kernel modules space implementations, or Open vSwitch.) Appropriate kernel
(e.g. tun and ofdatapath for the reference kernel implementation) must modules (e.g. tun and ofdatapath for the reference kernel
be loaded. 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! Good luck!
Mininet Team Mininet Team
--- ---
+6 -5
View File
@@ -71,8 +71,7 @@ TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
ALTSPELLING = { 'pingall': 'pingAll', ALTSPELLING = { 'pingall': 'pingAll',
'pingpair': 'pingPair', 'pingpair': 'pingPair',
'iperfudp': 'iperfUdp', 'iperfudp': 'iperfUdp',
'iperfUDP': 'iperfUdp', 'iperfUDP': 'iperfUdp' }
'prefixlen': 'prefixLen' }
def addDictOption( opts, choicesDict, default, name, helpStr=None ): def addDictOption( opts, choicesDict, default, name, helpStr=None ):
@@ -190,9 +189,6 @@ class MininetRunner( object ):
help='CLI script to run before tests' ) help='CLI script to run before tests' )
opts.add_option( '--post', type='string', default=None, opts.add_option( '--post', type='string', default=None,
help='CLI script to run after tests' ) 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', opts.add_option( '--pin', action='store_true',
default=False, help="pin hosts to CPU cores " default=False, help="pin hosts to CPU cores "
"(requires --host cfs or --host rt)" ) "(requires --host cfs or --host rt)" )
@@ -200,6 +196,11 @@ class MininetRunner( object ):
self.options, self.args = opts.parse_args() 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 ): def setup( self ):
"Setup and validate environment." "Setup and validate environment."
+2 -4
View File
@@ -9,20 +9,18 @@ Build-Depends:
help2man, help2man,
python-dev, python-dev,
python-pkg-resources, python-pkg-resources,
python-setuptools, python-setuptools
python-networkx
Homepage: http://openflow.org/mininet Homepage: http://openflow.org/mininet
Package: mininet Package: mininet
Architecture: any Architecture: any
Depends: Depends:
openvswitch-switch, openvswitch-switch,
python-networkx,
telnet, telnet,
${misc:Depends}, ${misc:Depends},
${python:Depends}, ${python:Depends},
${shlibs:Depends} ${shlibs:Depends}
Recommends: iperf, openvswitch-controller Recommends: iperf, openvswitch-controller, socat
Description: Process-based network emulator Description: Process-based network emulator
Mininet is a network emulator which uses lightweight Mininet is a network emulator which uses lightweight
virtualization to create virtual networks for rapid virtualization to create virtual networks for rapid
+19 -1
View File
@@ -19,7 +19,19 @@ graphical monitoring.
controllers.py: 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: cpu.py:
@@ -61,6 +73,12 @@ multitest.py:
This example creates a network and runs multiple tests on it. 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: popen.py:
This example monitors a number of hosts using host.popen() and This example monitors a number of hosts using host.popen() and
+23 -52
View File
@@ -1,64 +1,35 @@
#!/usr/bin/python #!/usr/bin/python
""" """
This example creates a multi-controller network from Create a network where different switches are connected to
semi-scratch; note a topo object could also be used and different controllers, by creating a custom Switch() subclass.
would be passed into the Mininet() constructor.
""" """
from mininet.net import Mininet from mininet.net import Mininet
from mininet.node import Controller, OVSKernelSwitch from mininet.node import OVSSwitch, Controller, RemoteController
from mininet.cli import CLI from mininet.topolib import TreeTopo
from mininet.log import setLogLevel from mininet.log import setLogLevel
from mininet.cli import CLI
Switch = OVSKernelSwitch setLogLevel( 'info' )
def addHost( net, N ): # Two local and one "external" controller (which is actually c0)
"Create host hN and add to net." # Ignore the warning message that the remote isn't (yet) running
name = 'h%d' % N c0 = Controller( 'c0' )
ip = '10.0.0.%d' % N c1 = Controller( 'c1' )
return net.addHost( name, ip=ip ) c2 = RemoteController( 'c2', ip='127.0.0.1' )
def multiControllerNet(): cmap = { 's1': c0, 's2': c1, 's3': c2 }
"Create a network with multiple controllers."
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" topo = TreeTopo( depth=2, fanout=2 )
c1 = net.addController( 'c1', port=6633 ) net = Mininet( topo=topo, switch=MultiSwitch, build=False )
c2 = net.addController( 'c2', port=6634 ) net.controllers = [ c0, c1 ]
net.build()
print "*** Creating switches" net.start()
s1 = net.addSwitch( 's1' ) CLI( net )
s2 = net.addSwitch( 's2' ) net.stop()
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()
+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" info("*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
"\n") "\n")
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core ' 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 # 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' )
# And kill off sudo mnexec
sh( 'pkill -9 -f "sudo mnexec"')
info( "*** Removing junk from /tmp\n" ) info( "*** Removing junk from /tmp\n" )
sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' ) sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' )
info( "*** Removing old screen sessions\n" ) info( "*** Removing old X11 tunnels\n" )
cleanUpScreens() cleanUpScreens()
info( "*** Removing excess kernel datapaths\n" ) info( "*** Removing excess kernel datapaths\n" )
@@ -52,7 +55,7 @@ def cleanup():
sh( 'ovs-vsctl del-br ' + dp ) sh( 'ovs-vsctl del-br ' + dp )
info( "*** Removing all links of the pattern foo-ethX\n" ) 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: for link in links:
if link != '': if link != '':
sh( "ip link del " + link ) sh( "ip link del " + link )
+28 -6
View File
@@ -33,7 +33,7 @@ import sys
import time import time
from mininet.log import info, output, error 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 from mininet.util import quietRun, isShellBuiltin, dumpNodeConnections
class CLI( Cmd ): class CLI( Cmd ):
@@ -121,12 +121,12 @@ class CLI( Cmd ):
"Run an external shell command" "Run an external shell command"
call( line, shell=True ) 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 # pylint: disable-msg=W0703
def do_py( self, line ): def do_py( self, line ):
"""Evaluate a Python expression. """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: try:
result = eval( line, globals(), self.locals ) result = eval( line, globals(), self.locals )
if not result: if not result:
@@ -138,7 +138,18 @@ class CLI( Cmd ):
except Exception, e: except Exception, e:
output( str( e ) + '\n' ) 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 ): def do_pingall( self, _line ):
"Ping between all hosts." "Ping between all hosts."
@@ -230,6 +241,17 @@ class CLI( Cmd ):
node = self.nodemap[ arg ] node = self.nodemap[ arg ]
self.mn.terms += makeTerms( [ node ], term = term ) 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 ): def do_gterm( self, line ):
"Spawn gnome-terminal(s) for the given node(s)." "Spawn gnome-terminal(s) for the given node(s)."
self.do_xterm( line, term='gterm' ) self.do_xterm( line, term='gterm' )
@@ -278,7 +300,7 @@ class CLI( Cmd ):
self.inputFile = None self.inputFile = None
def do_dpctl( self, line ): def do_dpctl( self, line ):
"Run dpctl command on all switches." "Run dpctl (or ovs-ofctl) command on all switches."
args = line.split() args = line.split()
if len(args) < 1: if len(args) < 1:
error( 'usage: dpctl command [arg1] [arg2] ...\n' ) error( 'usage: dpctl command [arg1] [arg2] ...\n' )
@@ -310,7 +332,7 @@ class CLI( Cmd ):
if first in self.nodemap: if first in self.nodemap:
node = self.nodemap[ first ] node = self.nodemap[ first ]
# Substitute IP addresses for node names in command # 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 if arg in self.nodemap else arg
for arg in rest ] for arg in rest ]
rest = ' '.join( 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.log import info, error, debug
from mininet.util import makeIntfPair from mininet.util import makeIntfPair, quietRun
from time import sleep
import re import re
class Intf( object ): class Intf( object ):
@@ -162,8 +161,9 @@ class Intf( object ):
def delete( self ): def delete( self ):
"Delete interface" "Delete interface"
self.cmd( 'ip link del ' + self.name ) self.cmd( 'ip link del ' + self.name )
# Does it help to sleep to let things run? if self.node.inNamespace:
sleep( 0.001 ) # Link may have been dumped into root NS
quietRun( 'ip link del ' + self.name )
def __repr__( self ): def __repr__( self ):
return '<%s %s>' % ( self.__class__.__name__, self.name ) 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 # are specifying the correct sizes. For now I have used
# the same settings we had in the mininet-hifi code. # the same settings we had in the mininet-hifi code.
if use_hfsc: if use_hfsc:
cmds += [ '%s qdisc add dev %s root handle 1:0 hfsc default 1', cmds += [ '%s qdisc add dev %s root handle 5:0 hfsc default 1',
'%s class add dev %s parent 1:0 classid 1:1 hfsc sc ' '%s class add dev %s parent 5:0 classid 5:1 hfsc sc '
+ 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ] + 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ]
elif use_tbf: elif use_tbf:
if latency_ms is None: if latency_ms is None:
latency_ms = 15 * 8 / bw 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' % 'rate %fMbit burst 15000 latency %fms' %
( bw, latency_ms ) ] ( bw, latency_ms ) ]
else: else:
cmds += [ '%s qdisc add dev %s root handle 1:0 htb default 1', cmds += [ '%s qdisc add dev %s root handle 5:0 htb default 1',
'%s class add dev %s parent 1:0 classid 1:1 htb ' + '%s class add dev %s parent 5:0 classid 5:1 htb ' +
'rate %fMbit burst 15k' % bw ] 'rate %fMbit burst 15k' % bw ]
parent = ' parent 1:1 ' parent = ' parent 5:1 '
# ECN or RED # ECN or RED
if enable_ecn: if enable_ecn:
cmds += [ '%s qdisc add dev %s' + parent + cmds += [ '%s qdisc add dev %s' + parent +
'handle 10: red limit 1000000 ' + 'handle 6: red limit 1000000 ' +
'min 30000 max 35000 avpkt 1500 ' + 'min 30000 max 35000 avpkt 1500 ' +
'burst 20 ' + 'burst 20 ' +
'bandwidth %fmbit probability 1 ecn' % bw ] 'bandwidth %fmbit probability 1 ecn' % bw ]
parent = ' parent 10: ' parent = ' parent 6: '
elif enable_red: elif enable_red:
cmds += [ '%s qdisc add dev %s' + parent + cmds += [ '%s qdisc add dev %s' + parent +
'handle 10: red limit 1000000 ' + 'handle 6: red limit 1000000 ' +
'min 30000 max 35000 avpkt 1500 ' + 'min 30000 max 35000 avpkt 1500 ' +
'burst 20 ' + 'burst 20 ' +
'bandwidth %fmbit probability 1' % bw ] 'bandwidth %fmbit probability 1' % bw ]
parent = ' parent 10: ' parent = ' parent 6: '
return cmds, parent return cmds, parent
@staticmethod @staticmethod
@@ -251,7 +251,8 @@ class TCIntf( Intf ):
cmds = [ '%s qdisc add dev %s ' + parent + cmds = [ '%s qdisc add dev %s ' + parent +
' handle 10: netem ' + ' handle 10: netem ' +
netemargs ] netemargs ]
return cmds parent = ' parent 10:1 '
return cmds, parent
def tc( self, cmd, tc='tc' ): def tc( self, cmd, tc='tc' ):
"Execute tc command for our interface" "Execute tc command for our interface"
@@ -289,9 +290,10 @@ class TCIntf( Intf ):
cmds += bwcmds cmds += bwcmds
# Delay/jitter/loss/max_queue_size using netem # Delay/jitter/loss/max_queue_size using netem
cmds += self.delayCmds( delay=delay, jitter=jitter, loss=loss, delaycmds, parent = self.delayCmds( delay=delay, jitter=jitter,
max_queue_size=max_queue_size, loss=loss, max_queue_size=max_queue_size,
parent=parent ) parent=parent )
cmds += delaycmds
# Ugly but functional: display configuration info # Ugly but functional: display configuration info
stuff = ( ( [ '%.2fMbit' % bw ] if bw is not None else [] ) + stuff = ( ( [ '%.2fMbit' % bw ] if bw is not None else [] ) +
@@ -308,6 +310,7 @@ class TCIntf( Intf ):
debug( "cmds:", cmds, '\n' ) debug( "cmds:", cmds, '\n' )
debug( "outputs:", tcoutputs, '\n' ) debug( "outputs:", tcoutputs, '\n' )
result[ 'tcoutputs'] = tcoutputs result[ 'tcoutputs'] = tcoutputs
result[ 'parent' ] = parent
return result return result
+8 -10
View File
@@ -60,18 +60,16 @@ class Singleton( type ):
See http://en.wikipedia.org/wiki/SingletonPattern#Python See http://en.wikipedia.org/wiki/SingletonPattern#Python
Intended to be used as a __metaclass_ param, as shown for the class 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_ ): def __call__( cls, *args, **kw ):
super( Singleton, mcs ).__init__( name, bases, dict_ ) if cls.instance is None:
mcs.instance = None cls.instance = super( Singleton, cls ).__call__( *args, **kw )
return cls.instance
def __call__( mcs, *args, **kw ):
if mcs.instance is None:
mcs.instance = super( Singleton, mcs ).__call__( *args, **kw )
return mcs.instance
class MininetLogger( Logger, object ): class MininetLogger( Logger, object ):
+24 -10
View File
@@ -91,6 +91,7 @@ import re
import select import select
import signal import signal
from time import sleep from time import sleep
from itertools import chain
from mininet.cli import CLI from mininet.cli import CLI
from mininet.log import info, error, debug, output from mininet.log import info, error, debug, output
@@ -216,8 +217,8 @@ class Mininet( object ):
self.nameToNode[ name ] = controller_new self.nameToNode[ name ] = controller_new
return controller_new return controller_new
# BL: is this better than just using nameToNode[] ? # BL: We now have four ways to look up nodes
# Should it have a better name? # This may (should?) be cleaned up in the future.
def getNodeByName( self, *args ): def getNodeByName( self, *args ):
"Return node(s) with given name(s)" "Return node(s) with given name(s)"
if len( args ) == 1: if len( args ) == 1:
@@ -228,6 +229,15 @@ class Mininet( object ):
"Convenience alias for getNodeByName" "Convenience alias for getNodeByName"
return self.getNodeByName( *args ) 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, def addLink( self, node1, node2, port1=None, port2=None,
cls=None, **params ): cls=None, **params ):
""""Add a link from node1 to node2 """"Add a link from node1 to node2
@@ -250,7 +260,7 @@ class Mininet( object ):
info( host.name + ' ' ) info( host.name + ' ' )
intf = host.defaultIntf() intf = host.defaultIntf()
if intf: if intf:
host.configDefault( defaultRoute=intf ) host.configDefault()
else: else:
# Don't configure nonexistent intf # Don't configure nonexistent intf
host.configDefault( ip=None, mac=None ) host.configDefault( ip=None, mac=None )
@@ -362,16 +372,16 @@ class Mininet( object ):
if self.terms: if self.terms:
info( '*** Stopping %i terms\n' % len( self.terms ) ) info( '*** Stopping %i terms\n' % len( self.terms ) )
self.stopXterms() self.stopXterms()
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 ) ) info( '*** Stopping %i switches\n' % len( self.switches ) )
for switch in self.switches: for switch in self.switches:
info( switch.name + ' ' ) info( switch.name + ' ' )
switch.stop() switch.stop()
info( '\n' ) 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 ) ) info( '*** Stopping %i controllers\n' % len( self.controllers ) )
for controller in self.controllers: for controller in self.controllers:
info( controller.name + ' ' ) info( controller.name + ' ' )
@@ -458,9 +468,13 @@ class Mininet( object ):
lost += sent - received lost += sent - received
output( ( '%s ' % dest.name ) if received else 'X ' ) output( ( '%s ' % dest.name ) if received else 'X ' )
output( '\n' ) output( '\n' )
if packets > 0:
ploss = 100 * lost / packets ploss = 100 * lost / packets
output( "*** Results: %i%% dropped (%d/%d lost)\n" % output( "*** Results: %i%% dropped (%d/%d lost)\n" %
( ploss, lost, packets ) ) ( ploss, lost, packets ) )
else:
ploss = 0
output( "*** Warning: No packets sent\n" )
return ploss return ploss
@staticmethod @staticmethod
+78 -28
View File
@@ -49,6 +49,7 @@ import re
import signal import signal
import select import select
from subprocess import Popen, PIPE, STDOUT from subprocess import Popen, PIPE, STDOUT
from operator import or_
from mininet.log import info, error, warn, debug from mininet.log import info, error, warn, debug
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin, from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
@@ -118,7 +119,8 @@ class Node( object ):
if self.inNamespace: if self.inNamespace:
opts += 'n' opts += 'n'
# bash -m: enable job control # 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, self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
close_fds=True ) close_fds=True )
self.stdin = self.shell.stdin self.stdin = self.shell.stdin
@@ -139,10 +141,10 @@ class Node( object ):
def cleanup( self ): def cleanup( self ):
"Help python collect its garbage." "Help python collect its garbage."
if not self.inNamespace: # Intfs may end up in root NS
for intfName in self.intfNames(): for intfName in self.intfNames():
if self.name in intfName: if self.name in intfName:
quietRun( 'ip link del ' + intfName ) quietRun( 'ip link del ' + intfName )
self.shell = None self.shell = None
# Subshell I/O, commands and control # Subshell I/O, commands and control
@@ -290,7 +292,7 @@ class Node( object ):
kwargs: Popen() keyword args""" kwargs: Popen() keyword args"""
defaults = { 'stdout': PIPE, 'stderr': PIPE, defaults = { 'stdout': PIPE, 'stderr': PIPE,
'mncmd': 'mncmd':
[ 'mnexec', '-a', str( self.pid ) ] } [ 'mnexec', '-da', str( self.pid ) ] }
defaults.update( kwargs ) defaults.update( kwargs )
if len( args ) == 1: if len( args ) == 1:
if type( args[ 0 ] ) is list: if type( args[ 0 ] ) is list:
@@ -370,7 +372,7 @@ class Node( object ):
""" """
if not intf: if not intf:
return self.defaultIntf() return self.defaultIntf()
elif type( intf) is str: elif type( intf ) is str:
return self.nameToIntf[ intf ] return self.nameToIntf[ intf ]
else: else:
return intf return intf
@@ -389,16 +391,19 @@ class Node( object ):
connections += [ ( intf, link.intf1 ) ] connections += [ ( intf, link.intf1 ) ]
return connections return connections
def deleteIntfs( self ): def deleteIntfs( self, checkName=True ):
"Delete all of our interfaces." """Delete all of our interfaces.
checkName: only delete interfaces that contain our name"""
# In theory the interfaces should go away after we shut down. # In theory the interfaces should go away after we shut down.
# However, this takes time, so we're better off removing them # However, this takes time, so we're better off removing them
# explicitly so that we won't get errors if we run before they # explicitly so that we won't get errors if we run before they
# have been removed by the kernel. Unfortunately this is very slow, # have been removed by the kernel. Unfortunately this is very slow,
# at least with Linux kernels before 2.6.33 # at least with Linux kernels before 2.6.33
for intf in self.intfs.values(): for intf in self.intfs.values():
intf.delete() # Protect against deleting hardware interfaces
info( '.' ) if ( self.name in intf.name ) or ( not checkName ):
intf.delete()
info( '.' )
# Routing support # Routing support
@@ -417,11 +422,14 @@ class Node( object ):
def setDefaultRoute( self, intf=None ): def setDefaultRoute( self, intf=None ):
"""Set the default route to go through intf. """Set the default route to go through intf.
intf: string, interface name""" intf: Intf or {dev <intfname> via <gw-ip> ...}"""
if not intf: # Note setParam won't call us if intf is none
intf = self.defaultIntf() if type( intf ) is str and ' ' in intf:
self.cmd( 'ip route flush root 0/0' ) params = intf
return self.cmd( 'route add default %s' % intf ) else:
params = 'dev %s' % intf
self.cmd( 'ip route del default' )
return self.cmd( 'ip route add default', params )
# Convenience and configuration methods # Convenience and configuration methods
@@ -447,7 +455,7 @@ class Node( object ):
def MAC( self, intf=None ): def MAC( self, intf=None ):
"Return MAC address of a node or specific interface." "Return MAC address of a node or specific interface."
return self.intf( intf ).IP() return self.intf( intf ).MAC()
def intfIsUp( self, intf=None ): def intfIsUp( self, intf=None ):
"Check if an interface is up." "Check if an interface is up."
@@ -492,7 +500,7 @@ class Node( object ):
r = {} r = {}
self.setParam( r, 'setMAC', mac=mac ) self.setParam( r, 'setMAC', mac=mac )
self.setParam( r, 'setIP', ip=ip ) self.setParam( r, 'setIP', ip=ip )
self.setParam( r, 'defaultRoute', defaultRoute=defaultRoute ) self.setParam( r, 'setDefaultRoute', defaultRoute=defaultRoute )
# This should be examined # This should be examined
self.cmd( 'ifconfig lo ' + lo ) self.cmd( 'ifconfig lo ' + lo )
return r return r
@@ -604,14 +612,15 @@ class CPULimitedHost( Host ):
args: Popen() args, single list, or string args: Popen() args, single list, or string
kwargs: Popen() keyword args""" kwargs: Popen() keyword args"""
# Tell mnexec to execute command in our cgroup # Tell mnexec to execute command in our cgroup
mncmd = [ 'mnexec', '-a', str( self.pid ), mncmd = [ 'mnexec', '-da', str( self.pid ),
'-g', self.name ] '-g', self.name ]
if self.sched == 'rt': if self.sched == 'rt':
mncmd += [ '-r', str( self.rtprio ) ] mncmd += [ '-r', str( self.rtprio ) ]
return Host.popen( self, *args, mncmd=mncmd, **kwargs ) return Host.popen( self, *args, mncmd=mncmd, **kwargs )
def cleanup( self ): 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 ) retry( retries=3, delaySecs=1, fn=self.cgroupDel )
def chrt( self ): def chrt( self ):
@@ -754,7 +763,7 @@ class Switch( Node ):
def defaultDpid( self ): def defaultDpid( self ):
"Derive dpid from switch name, s1 -> 1" "Derive dpid from switch name, s1 -> 1"
try: try:
dpid = int( re.findall( '\d+', self.name )[ 0 ] ) dpid = int( re.findall( r'\d+', self.name )[ 0 ] )
dpid = hex( dpid )[ 2: ] dpid = hex( dpid )[ 2: ]
dpid = '0' * ( self.dpidLen - len( dpid ) ) + dpid dpid = '0' * ( self.dpidLen - len( dpid ) ) + dpid
return dpid return dpid
@@ -780,6 +789,10 @@ class Switch( Node ):
error( '*** Error: %s has execed and cannot accept commands' % error( '*** Error: %s has execed and cannot accept commands' %
self.name ) self.name )
def connected( self ):
"Is the switch connected to a controller? (override this method)"
return False and self # satisfy pylint
def __repr__( self ): def __repr__( self ):
"More informative string representation" "More informative string representation"
intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() ) intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() )
@@ -792,15 +805,17 @@ class UserSwitch( Switch ):
dpidLen = 12 dpidLen = 12
def __init__( self, name, **kwargs ): def __init__( self, name, dpopts='--no-slicing', **kwargs ):
"""Init. """Init.
name: name for the switch""" name: name for the switch
dpopts: additional arguments to ofdatapath (--no-slicing)"""
Switch.__init__( self, name, **kwargs ) Switch.__init__( self, name, **kwargs )
pathCheck( 'ofdatapath', 'ofprotocol', pathCheck( 'ofdatapath', 'ofprotocol',
moduleName='the OpenFlow reference user switch' + moduleName='the OpenFlow reference user switch' +
'(openflow.org)' ) '(openflow.org)' )
if self.listenPort: if self.listenPort:
self.opts += ' --listen=ptcp:%i ' % self.listenPort self.opts += ' --listen=ptcp:%i ' % self.listenPort
self.dpopts = dpopts
@classmethod @classmethod
def setup( cls ): def setup( cls ):
@@ -815,6 +830,10 @@ class UserSwitch( Switch ):
return self.cmd( 'dpctl ' + ' '.join( args ) + return self.cmd( 'dpctl ' + ' '.join( args ) +
' tcp:127.0.0.1:%i' % self.listenPort ) ' 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 ): def start( self, controllers ):
"""Start OpenFlow reference user datapath. """Start OpenFlow reference user datapath.
Log to /tmp/sN-{ofd,ofp}.log. Log to /tmp/sN-{ofd,ofp}.log.
@@ -827,7 +846,8 @@ class UserSwitch( Switch ):
self.cmd( 'ifconfig lo up' ) self.cmd( 'ifconfig lo up' )
intfs = [ str( i ) for i in self.intfList() if not i.IP() ] intfs = [ str( i ) for i in self.intfList() if not i.IP() ]
self.cmd( 'ofdatapath -i ' + ','.join( intfs ) + 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 + ' &' ) ' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
self.cmd( 'ofprotocol unix:/tmp/' + self.name + self.cmd( 'ofprotocol unix:/tmp/' + self.name +
' ' + clist + ' ' + clist +
@@ -895,12 +915,14 @@ class OVSLegacyKernelSwitch( Switch ):
class OVSSwitch( Switch ): class OVSSwitch( Switch ):
"Open vSwitch switch. Depends on ovs-vsctl." "Open vSwitch switch. Depends on ovs-vsctl."
def __init__( self, name, failMode='secure', **params ): def __init__( self, name, failMode='secure', datapath='kernel', **params ):
"""Init. """Init.
name: name for switch 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 ) Switch.__init__( self, name, **params )
self.failMode = failMode self.failMode = failMode
self.datapath = datapath
@classmethod @classmethod
def setup( cls ): def setup( cls ):
@@ -923,8 +945,8 @@ class OVSSwitch( Switch ):
exit( 1 ) exit( 1 )
def dpctl( self, *args ): def dpctl( self, *args ):
"Run ovs-dpctl command" "Run ovs-ofctl command"
return self.cmd( 'ovs-dpctl', args[ 0 ], self, *args[ 1: ] ) return self.cmd( 'ovs-ofctl', args[ 0 ], self, *args[ 1: ] )
@staticmethod @staticmethod
def TCReapply( intf ): def TCReapply( intf ):
@@ -944,6 +966,23 @@ class OVSSwitch( Switch ):
"Disconnect a data port" "Disconnect a data port"
self.cmd( 'ovs-vsctl del-port', self, intf ) 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 ): def start( self, controllers ):
"Start up a new OVS OpenFlow switch using ovs-vsctl" "Start up a new OVS OpenFlow switch using ovs-vsctl"
if self.inNamespace: if self.inNamespace:
@@ -955,6 +994,9 @@ class OVSSwitch( Switch ):
# Annoyingly, --if-exists option seems not to work # Annoyingly, --if-exists option seems not to work
self.cmd( 'ovs-vsctl del-br', self ) self.cmd( 'ovs-vsctl del-br', self )
self.cmd( 'ovs-vsctl add-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, self.cmd( 'ovs-vsctl -- set Bridge', self,
'other_config:datapath-id=' + self.dpid ) 'other_config:datapath-id=' + self.dpid )
self.cmd( 'ovs-vsctl set-fail-mode', self, self.failMode ) self.cmd( 'ovs-vsctl set-fail-mode', self, self.failMode )
@@ -967,6 +1009,14 @@ class OVSSwitch( Switch ):
if self.listenPort: if self.listenPort:
clist += ' ptcp:%s' % self.listenPort clist += ' ptcp:%s' % self.listenPort
self.cmd( 'ovs-vsctl set-controller', self, clist ) 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 ): def stop( self ):
"Terminate OVS switch." "Terminate OVS switch."
+45 -32
View File
@@ -1,60 +1,73 @@
""" """
Terminal creation and cleanup. 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. Optionally uses gnome-terminal.
""" """
import re from os import environ
from subprocess import Popen
from mininet.log import error from mininet.log import error
from mininet.util import quietRun from mininet.util import quietRun, errRun
def quoteArg( arg ): def tunnelX11( node, display=None):
"Quote an argument if it contains spaces." """Create an X11 tunnel from node:6000 to the root host
return repr( arg ) if ' ' in arg else arg 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' ): def makeTerm( node, title='Node', term='xterm', display=None ):
"""Run screen on a node, and hook up a terminal. """Create an X11 tunnel to the node and start up a terminal.
node: Node object node: Node object
title: base title title: base title
term: 'xterm' or 'gterm' term: 'xterm' or 'gterm'
returns: process created""" returns: two Popen objects, tunnel and terminal"""
title += ': ' + node.name title += ': ' + node.name
if not node.inNamespace: if not node.inNamespace:
title += ' (root)' title += ' (root)'
cmds = { cmds = {
'xterm': [ 'xterm', '-title', title, '-e' ], 'xterm': [ 'xterm', '-title', title, '-display' ],
'gterm': [ 'gnome-terminal', '--title', title, '-e' ] 'gterm': [ 'gnome-terminal', '--title', title, '--display' ]
} }
if term not in cmds: if term not in cmds:
error( 'invalid terminal type: %s' % term ) error( 'invalid terminal type: %s' % term )
return return
if not node.execed: display, tunnel = tunnelX11( node, display )
node.cmd( 'screen -dmS ' + 'mininet.' + node.name) term = node.popen( cmds[ term ] + [ display, '-e', 'env TERM=ansi bash'] )
args = [ 'screen', '-D', '-RR', '-S', 'mininet.' + node.name ] return [ tunnel, term ] if tunnel else [ term ]
else:
args = [ 'sh', '-c', 'exec tail -f /tmp/' + node.name + '*.log' ] def runX11( node, cmd ):
if term == 'gterm': "Run an X11 client on a node"
# Compress these for gnome-terminal, which expects one token _display, tunnel = tunnelX11( node )
# to follow the -e option popen = node.popen( cmd )
args = [ ' '.join( [ quoteArg( arg ) for arg in args ] ) ] return [ tunnel, popen ]
return Popen( cmds[ term ] + args )
def cleanUpScreens(): def cleanUpScreens():
"Remove moldy old screen sessions." "Remove moldy socat X11 tunnels."
r = r'(\d+\.mininet\.[hsc]\d+)' errRun( "pkill -9 -f mnexec.*socat" )
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' )
def makeTerms( nodes, title='Node', term='xterm' ): def makeTerms( nodes, title='Node', term='xterm' ):
"""Create terminals. """Create terminals.
nodes: list of Node objects nodes: list of Node objects
title: base title for each title: base title for each
returns: list of created terminal processes""" returns: list of created tunnel/terminal processes"""
return [ makeTerm( node, title, term ) for node in nodes ] 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. 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 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): class Topo(object):
"Data center network representation for structured multi-trees." "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 time import sleep
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE 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 from subprocess import call, check_call, Popen, PIPE, STDOUT
import re import re
from fcntl import fcntl, F_GETFL, F_SETFL 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 ) error( "*** gave up after %i retries\n" % tries )
exit( 1 ) exit( 1 )
def moveIntfNoRetry( intf, node, printError=False ): def moveIntfNoRetry( intf, dstNode, srcNode=None, printError=False ):
"""Move interface to node, without retrying. """Move interface to node, without retrying.
intf: string, interface intf: string, interface
node: Node object dstNode: destination Node
printError: if true, print error""" srcNode: source Node or None (default) for root ns
cmd = 'ip link set ' + intf + ' netns ' + repr( node.pid ) printError: if true, print error"""
quietRun( cmd ) intf = str( intf )
links = node.cmd( 'ip link show' ) 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 not ( ' %s:' % intf ) in links:
if printError: if printError:
error( '*** Error: moveIntf: ' + intf + error( '*** Error: moveIntf: ' + intf +
' not successfully moved to ' + node.name + '\n' ) ' not successfully moved to ' + dstNode.name + '\n' )
return False return False
return True 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. """Move interface to node, retrying on failure.
intf: string, interface intf: string, interface
node: Node object dstNode: destination Node
srcNode: source Node or None (default) for root ns
printError: if true, print error""" 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 # Support for dumping network
@@ -242,9 +250,8 @@ def macColonHex( mac ):
def ipStr( ip ): def ipStr( ip ):
"""Generate IP address string from an unsigned int. """Generate IP address string from an unsigned int.
ip: unsigned int of form w << 24 | x << 16 | y << 8 | z 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 = ( ip >> 24 ) & 0xff
w = 10 if w == 0 else w
x = ( ip >> 16 ) & 0xff x = ( ip >> 16 ) & 0xff
y = ( ip >> 8 ) & 0xff y = ( ip >> 8 ) & 0xff
z = ip & 0xff z = ip & 0xff
@@ -261,10 +268,10 @@ def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ):
prefixLen: optional IP prefix length prefixLen: optional IP prefix length
ipBaseNum: option base IP address as int ipBaseNum: option base IP address as int
returns IP address as string""" returns IP address as string"""
# Ugly but functional imax = 0xffffffff >> prefixLen
assert i < ( 1 << ( 32 - prefixLen ) ) assert i <= imax
mask = 0xffffffff ^ ( ( 1 << prefixLen ) - 1 ) mask = 0xffffffff ^ imax
ipnum = i + ( ipBaseNum & mask ) ipnum = ( ipBaseNum & mask ) + i
return ipStr( ipnum ) return ipStr( ipnum )
def ipParse( ip ): def ipParse( ip ):
@@ -326,27 +333,24 @@ def pmonitor(popens, timeoutms=500, readline=True,
# Use non-blocking reads # Use non-blocking reads
flags = fcntl( fd, F_GETFL ) flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK ) fcntl( fd, F_SETFL, flags | O_NONBLOCK )
while True: while popens:
fds = poller.poll( timeoutms ) fds = poller.poll( timeoutms )
if fds: if fds:
for fd, _event in fds: for fd, event in fds:
host = fdToHost[ fd ] host = fdToHost[ fd ]
popen = popens[ host ] popen = popens[ host ]
if readline: if event & POLLIN:
# Attempt to read a line of output if readline:
# This blocks until we receive a newline! # Attempt to read a line of output
line = popen.stdout.readline() # This blocks until we receive a newline!
else: line = popen.stdout.readline()
line = popen.stdout.read( readmax ) else:
yield host, line line = popen.stdout.read( readmax )
yield host, line
# Check for EOF # Check for EOF
if not line: elif event & POLLHUP:
popen.poll() poller.unregister( fd )
if popen.returncode is not None: del popens[ host ]
poller.unregister( fd )
del popens[ host ]
if not popens:
return
else: else:
yield None, '' yield None, ''
@@ -419,7 +423,7 @@ def splitArgs( argstr ):
args = [ makeNumeric( s ) for s in params if '=' not in s ] args = [ makeNumeric( s ) for s in params if '=' not in s ]
kwargs = {} kwargs = {}
for s in [ p for p in params if '=' in p ]: for s in [ p for p in params if '=' in p ]:
key, val = s.split( '=' ) key, val = s.split( '=', 1 )
kwargs[ key ] = makeNumeric( val ) kwargs[ key ] = makeNumeric( val )
return fn, args, kwargs return fn, args, kwargs
+1 -1
View File
@@ -46,7 +46,7 @@ void usage(char *name)
int setns(int fd, int nstype) int setns(int fd, int nstype)
{ {
return syscall(308, fd, nstype); return syscall(__NR_setns, fd, nstype);
} }
/* Validate alphanumeric path foo1/bar2/baz */ /* Validate alphanumeric path foo1/bar2/baz */
+1 -2
View File
@@ -37,8 +37,7 @@ setup(
keywords='networking emulator protocol Internet OpenFlow SDN', keywords='networking emulator protocol Internet OpenFlow SDN',
license='BSD', license='BSD',
install_requires=[ install_requires=[
'setuptools', 'setuptools'
'networkx'
], ],
scripts=scripts, scripts=scripts,
) )
+175 -63
View File
@@ -9,6 +9,18 @@ set -e
# Fail on unset var usage # Fail on unset var usage
set -o nounset 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) # Location of CONFIG_NET_NS-enabled kernel(s)
KERNEL_LOC=http://www.openflow.org/downloads/mininet 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_PACKAGE_LOC=https://github.com/downloads/mininet/mininet
OVS_BUILDSUFFIX=-ignore # was -2 OVS_BUILDSUFFIX=-ignore # was -2
OVS_PACKAGE_NAME=ovs-$OVS_RELEASE-core-$DIST_LC-$RELEASE-$ARCH$OVS_BUILDSUFFIX.tar 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_TAG=v$OVS_RELEASE
OVS_BUILD=$OVS_SRC/build-$KERNEL_NAME OVS_BUILD=$OVS_SRC/build-$KERNEL_NAME
OVS_KMODS=($OVS_BUILD/datapath/linux/{openvswitch_mod.ko,brcompat_mod.ko}) OVS_KMODS=($OVS_BUILD/datapath/linux/{openvswitch_mod.ko,brcompat_mod.ko})
@@ -116,30 +128,27 @@ function kernel_clean {
fi fi
# Also remove downloaded packages: # Also remove downloaded packages:
rm -f ~/linux-headers-* ~/linux-image-* rm -f $HOME/linux-headers-* $HOME/linux-image-*
} }
# Install Mininet deps # Install Mininet deps
function mn_deps { function mn_deps {
echo "Installing Mininet dependencies" echo "Installing Mininet dependencies"
$install gcc make screen psmisc xterm ssh iperf iproute telnet \ $install gcc make socat psmisc xterm ssh iperf iproute telnet \
python-setuptools python-networkx cgroup-bin ethtool help2man \ python-setuptools cgroup-bin ethtool help2man \
pyflakes pylint pep8 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 # Add sysctl parameters as noted in the INSTALL file to increase kernel
# limits to support larger setups: # 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: # Load new sysctl settings:
sudo sysctl -p sudo sysctl -p
echo "Installing Mininet core" echo "Installing Mininet core"
pushd ~/mininet pushd $MININET_DIR/mininet
sudo make install sudo make install
popd popd
} }
@@ -151,45 +160,66 @@ function mn_deps {
# ... modified to use Debian Lenny rather than unstable. # ... modified to use Debian Lenny rather than unstable.
function of { function of {
echo "Installing OpenFlow reference implementation..." echo "Installing OpenFlow reference implementation..."
cd ~/ cd $BUILD_DIR/
$install git-core autoconf automake autotools-dev pkg-config \ $install git-core autoconf automake autotools-dev pkg-config \
make gcc libtool libc6-dev make gcc libtool libc6-dev
git clone git://openflowswitch.org/openflow.git git clone git://openflowswitch.org/openflow.git
cd ~/openflow cd $BUILD_DIR/openflow
# Patch controller to handle more than 16 switches # 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: # Resume the install:
./boot.sh ./boot.sh
./configure ./configure
make make
sudo make install sudo make install
cd $BUILD_DIR
}
# Remove avahi-daemon, which may cause unwanted discovery packets to be function of13 {
# sent during tests, near link status changes: echo "Installing OpenFlow 1.3 soft switch implementation..."
$remove avahi-daemon 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 [ ! -d "ofsoftswitch13" ]; then
if [ "$DIST" = "Ubuntu" ]; then git clone https://github.com/CPqD/ofsoftswitch13.git
BLACKLIST=/etc/modprobe.d/blacklist.conf
else
BLACKLIST=/etc/modprobe.d/blacklist
fi 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 { function wireshark {
echo "Installing Wireshark dissector..." 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 if [ "$DIST" = "Ubuntu" ] && [ "$RELEASE" != "10.04" ]; then
# Install newer version # Install newer version
sudo apt-get install -y scons mercurial libglib2.0-dev sudo apt-get install -y scons mercurial libglib2.0-dev
sudo apt-get install -y libwiretap-dev libwireshark-dev sudo apt-get install -y libwiretap-dev libwireshark-dev
cd ~ cd $BUILD_DIR
hg clone https://bitbucket.org/barnstorm/of-dissector hg clone https://bitbucket.org/barnstorm/of-dissector
cd of-dissector/src cd of-dissector/src
export WIRESHARK=/usr/include/wireshark export WIRESHARK=/usr/include/wireshark
@@ -201,14 +231,14 @@ function wireshark {
echo "Copied openflow plugin to $WSPLUGDIR" echo "Copied openflow plugin to $WSPLUGDIR"
else else
# Install older version from reference source # Install older version from reference source
cd ~/openflow/utilities/wireshark_dissectors/openflow cd $BUILD_DIR/openflow/utilities/wireshark_dissectors/openflow
make make
sudo make install sudo make install
fi fi
# Copy coloring rules: OF is white-on-blue: # Copy coloring rules: OF is white-on-blue:
mkdir -p ~/.wireshark mkdir -p $HOME/.wireshark
cp ~/mininet/util/colorfilters ~/.wireshark cp $MININET_DIR/mininet/util/colorfilters $HOME/.wireshark
} }
@@ -266,7 +296,7 @@ function ovs {
if [ $ovspresent = 1 ]; then if [ $ovspresent = 1 ]; then
echo "Done (hopefully) installing packages" echo "Done (hopefully) installing packages"
cd ~ cd $BUILD_DIR
return return
fi fi
@@ -289,7 +319,7 @@ function ovs {
fi fi
# Install OVS from release # Install OVS from release
cd ~/ cd $BUILD_DIR/
git clone git://openvswitch.org/openvswitch $OVS_SRC git clone git://openvswitch.org/openvswitch $OVS_SRC
cd $OVS_SRC cd $OVS_SRC
git checkout $OVS_TAG git checkout $OVS_TAG
@@ -348,7 +378,7 @@ function nox {
$install libsqlite3-dev python-simplejson $install libsqlite3-dev python-simplejson
# Fetch NOX destiny # Fetch NOX destiny
cd ~/ cd $BUILD_DIR/
git clone https://github.com/noxrepo/nox-classic.git noxcore git clone https://github.com/noxrepo/nox-classic.git noxcore
cd noxcore cd noxcore
if ! git checkout -b destiny remotes/origin/destiny ; then if ! git checkout -b destiny remotes/origin/destiny ; then
@@ -357,9 +387,9 @@ function nox {
# Apply patches # Apply patches
git checkout -b tutorial-destiny 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 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 fi
# Build # Build
@@ -371,17 +401,51 @@ function nox {
#make check #make check
# Add NOX_CORE_DIR env var: # 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: # To verify this install:
#cd ~/noxcore/build/src #cd ~/noxcore/build/src
#./nox_core -v -i ptcp: #./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 # "Install" POX
function pox { function pox {
echo "Installing POX into $HOME/pox..." echo "Installing POX into $BUILD_DIR/pox..."
cd ~ cd $BUILD_DIR
git clone https://github.com/noxrepo/pox.git git clone https://github.com/noxrepo/pox.git
} }
@@ -393,11 +457,8 @@ function oftest {
$install tcpdump python-scapy $install tcpdump python-scapy
# Install oftest: # Install oftest:
cd ~/ cd $BUILD_DIR/
git clone git://github.com/floodlight/oftest git clone git://github.com/floodlight/oftest
cd oftest
cd tools/munger
sudo make install
} }
# Install cbench # Install cbench
@@ -405,25 +466,56 @@ function cbench {
echo "Installing cbench..." echo "Installing cbench..."
$install libsnmp-dev libpcap-dev libconfig-dev $install libsnmp-dev libpcap-dev libconfig-dev
cd ~/ cd $BUILD_DIR/
git clone git://openflow.org/oflops.git git clone git://openflow.org/oflops.git
cd oflops cd oflops
sh boot.sh || true # possible error in autoreconf, so run twice sh boot.sh || true # possible error in autoreconf, so run twice
sh boot.sh sh boot.sh
./configure --with-openflow-src-dir=$HOME/openflow ./configure --with-openflow-src-dir=$BUILD_DIR/openflow
make make
sudo make install || true # make install fails; force past this sudo make install || true # make install fails; force past this
} }
function other { function vm_other {
echo "Doing other setup tasks..." 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: # Enable command auto completion using sudo; modify ~/.bashrc:
sed -i -e 's|# for examples$|&\ncomplete -cf sudo|' ~/.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. # a graphical git history viewer.
$install tcpdump tshark gitk $install tcpdump gitk
# Install common text editors # Install common text editors
$install vim nano emacs $install vim nano emacs
@@ -471,8 +563,6 @@ function all {
pox pox
oftest oftest
cbench cbench
other
echo "Please reboot, then run ./mininet/util/install.sh -c to remove unneeded packages."
echo "Enjoy Mininet!" echo "Enjoy Mininet!"
} }
@@ -480,6 +570,7 @@ function all {
function vm_clean { function vm_clean {
echo "Cleaning VM..." echo "Cleaning VM..."
sudo apt-get clean sudo apt-get clean
sudo apt-get autoremove
sudo rm -rf /tmp/* sudo rm -rf /tmp/*
sudo rm -rf openvswitch*.tar.gz sudo rm -rf openvswitch*.tar.gz
@@ -500,16 +591,20 @@ function vm_clean {
git config --global user.name "None" git config --global user.name "None"
git config --global user.email "None" git config --global user.email "None"
# Remove mininet install script # Note: you can shrink the .vmdk in vmware using
rm -f install-mininet.sh # 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 { 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 '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 'for Mininet. It should (hopefully) work on Ubuntu 11.10+\n' >&2
printf 'and Debian 5.0 (Lenny). If you run into trouble, try\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 'installing one thing at a time, and looking at the \n' >&2
printf 'specific installation function in this script.\n\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 -- ' -k: install new (K)ernel\n' >&2
printf -- ' -m: install Open vSwitch kernel (M)odule from source dir\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 -- ' -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 -- ' -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 -- ' -v: install open (V)switch\n' >&2
printf -- ' -w: install OpenFlow (w)ireshark dissector\n' >&2 printf -- ' -w: install OpenFlow (w)ireshark dissector\n' >&2
printf -- ' -x: install NO(X) OpenFlow controller\n' >&2 printf -- ' -x: install NO(X) Classic OpenFlow controller\n' >&2
printf -- ' -y: install (A)ll packages\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 exit 2
} }
OF_VERSION=1.0
if [ $# -eq 0 ] if [ $# -eq 0 ]
then then
all all
else else
while getopts 'abcdfhkmnprtvwx' OPTION while getopts 'abcdfhkmnprtvwx03i:' OPTION
do do
case $OPTION in case $OPTION in
a) all;; a) all;;
b) cbench;; b) cbench;;
c) kernel_clean;; c) kernel_clean;;
d) vm_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;; h) usage;;
k) kernel;; k) kernel;;
m) modprobe;; m) modprobe;;
n) mn_deps;; n) mn_deps;;
p) pox;; p) pox;;
r) remove_ovs;; r) remove_ovs;;
t) other;; t) vm_other;;
v) ovs;; v) ovs;;
w) wireshark;; 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;; ?) usage;;
esac esac
done 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 # Mininet: increase routing table size
net.ipv4.route.max_size=32768 net.ipv4.route.max_size=32768
+9 -8
View File
@@ -4,15 +4,19 @@
# a brand-new Ubuntu virtual machine, # a brand-new Ubuntu virtual machine,
# to create a fully usable "tutorial" VM. # to create a fully usable "tutorial" VM.
set -e 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/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 sed -i -e 's/ubuntu/mininet-vm/g' /etc/hosts
sudo hostname `cat /etc/hostname` sudo hostname `cat /etc/hostname`
sudo sed -i -e 's/quiet splash/text/' /etc/default/grub sudo sed -i -e 's/quiet splash/text/' /etc/default/grub
sudo update-grub sudo update-grub
# 12.10 and earlier
sudo sed -i -e 's/us.archive.ubuntu.com/mirrors.kernel.org/' \ sudo sed -i -e 's/us.archive.ubuntu.com/mirrors.kernel.org/' \
/etc/apt/sources.list /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 sudo apt-get update
# Clean up vmware easy install junk if present # Clean up vmware easy install junk if present
if [ -e /etc/issue.backup ]; then if [ -e /etc/issue.backup ]; then
@@ -27,14 +31,11 @@ git clone git://github.com/mininet/mininet
cd mininet cd mininet
cd cd
time mininet/util/install.sh time mininet/util/install.sh
# Finalize VM
time mininet/util/install.sh -tc
# Ignoring this since NOX classic is deprecated # Ignoring this since NOX classic is deprecated
#if ! grep NOX_CORE_DIR .bashrc; then #if ! grep NOX_CORE_DIR .bashrc; then
# echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc # echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc
#fi #fi
echo <<EOF echo "Done preparing Mininet VM."
You may need to reboot and then:
sudo dpkg-reconfigure openvswitch-datapath-dkms
sudo service openvswitch-switch start
EOF