Compare commits
42 Commits
2.0.0
...
devel/iplink
| Author | SHA1 | Date | |
|---|---|---|---|
| 703c6b102f | |||
| b6a1084326 | |||
| 93085f1cad | |||
| f69664cd90 | |||
| 1e41c8342c | |||
| 99f08f98e2 | |||
| 947337c1dc | |||
| 0a176439ab | |||
| 0de8d94673 | |||
| 6c22e057cc | |||
| 7bc10ebc7a | |||
| c3f975aef8 | |||
| 0f6bf4ce84 | |||
| 33c7e46492 | |||
| 7c920edc29 | |||
| e09254eea3 | |||
| e5a15ced01 | |||
| c771b2d75a | |||
| 477e84adba | |||
| 3482d941e1 | |||
| 1bf1a4d5e9 | |||
| a0f69d98df | |||
| 4b8b4b73e1 | |||
| 5b14cc2937 | |||
| eca5a151a4 | |||
| 4efd372223 | |||
| 356e9d8a92 | |||
| 8838c30ea1 | |||
| 8204a1b694 | |||
| bd558875f3 | |||
| 31fe4f1bd0 | |||
| dcb3036b70 | |||
| 9734d9d7fa | |||
| 23c70f609d | |||
| f018137207 | |||
| ad09c1e086 | |||
| 31e1ff7154 | |||
| 8b8bb37598 | |||
| 0aefb0e036 | |||
| 5879c492d8 | |||
| ee66d53c54 | |||
| f95c4a4712 |
@@ -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
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)" )
|
||||
|
||||
Vendored
+1
-1
@@ -22,7 +22,7 @@ Depends:
|
||||
${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
|
||||
|
||||
+8
-1
@@ -19,7 +19,14 @@ 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.
|
||||
|
||||
cpu.py:
|
||||
|
||||
|
||||
+18
-54
@@ -1,64 +1,28 @@
|
||||
#!/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.node import OVSSwitch, Controller
|
||||
from mininet.topolib import TreeTopo
|
||||
from mininet.cli import CLI
|
||||
from mininet.log import setLogLevel
|
||||
|
||||
Switch = OVSKernelSwitch
|
||||
c0 = Controller( 'c0' )
|
||||
c1 = Controller( 'c1', ip='127.0.0.2' )
|
||||
cmap = { 's1': c0, 's2': c1, 's3': c1 }
|
||||
|
||||
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 )
|
||||
class MultiSwitch( OVSSwitch ):
|
||||
"Custom Switch() subclass that connects to different controllers"
|
||||
def start( self, controllers ):
|
||||
return OVSSwitch.start( self, [ cmap[ self.name ] ] )
|
||||
|
||||
def multiControllerNet():
|
||||
"Create a network with multiple controllers."
|
||||
|
||||
net = Mininet( controller=Controller, switch=Switch)
|
||||
|
||||
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()
|
||||
|
||||
Executable
+61
@@ -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()
|
||||
+50
-18
@@ -10,51 +10,83 @@ It may also get rid of 'false positives', but hopefully
|
||||
nothing irreplaceable!
|
||||
"""
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
from subprocess import Popen, PIPE, STDOUT, check_output as co
|
||||
from sys import stdout, exit
|
||||
from time import sleep
|
||||
|
||||
from mininet.log import info
|
||||
from mininet.log import info, error
|
||||
from mininet.term import cleanUpScreens
|
||||
|
||||
def sh( cmd ):
|
||||
"Print a command and send it to the shell"
|
||||
"Run a command in the shell and return non-empty output lines"
|
||||
info( cmd + '\n' )
|
||||
return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
|
||||
output = ( Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE )
|
||||
.communicate()[ 0 ]
|
||||
.strip()
|
||||
.split( '\n' ) )
|
||||
return [ s for s in output if s ]
|
||||
|
||||
def cleanup():
|
||||
"""Clean up junk which might be left over from old runs;
|
||||
do fast stuff before slow dp and link removal!"""
|
||||
|
||||
info("*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
|
||||
"\n")
|
||||
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" )
|
||||
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" ).split( '\n' )
|
||||
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" )
|
||||
for dp in dps:
|
||||
if dp != '':
|
||||
sh( 'dpctl deldp ' + dp )
|
||||
sh( 'dpctl deldp ' + dp )
|
||||
|
||||
info( "*** Removing OVS datapaths" )
|
||||
dps = sh("ovs-vsctl list-br").split( '\n' )
|
||||
info( "*** Removing OVS datapaths\n" )
|
||||
dps = sh("ovs-vsctl list-br")
|
||||
for dp in dps:
|
||||
if dp:
|
||||
sh( 'ovs-vsctl del-br ' + dp )
|
||||
sh( 'ovs-vsctl del-br ' + dp )
|
||||
if co( 'ovs-vsctl list-br', shell=True ):
|
||||
raise Excpetion( "Error: could not remove all OVS datapaths" )
|
||||
|
||||
info( "*** Removing all links of the pattern foo-ethX\n" )
|
||||
links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' )
|
||||
links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" )
|
||||
for link in links:
|
||||
if link != '':
|
||||
sh( "ip link del " + link )
|
||||
sh( "ip link del " + link )
|
||||
if sh( "ip link show | egrep -o '(\w+-eth\w+)'" ):
|
||||
raise Exception( "Error could not remove stale links")
|
||||
|
||||
info( "*** Killing stale mininet node processes\n" )
|
||||
sh( 'pkill -9 -f mininet:' )
|
||||
# Make sure they are gone
|
||||
while True:
|
||||
try:
|
||||
pids = co( 'pgrep -f mininet:'.split() )
|
||||
except:
|
||||
pids = ''
|
||||
if pids:
|
||||
sh( 'pkill -f 9 mininet:' )
|
||||
sleep( .5 )
|
||||
else:
|
||||
break
|
||||
|
||||
info( "*** Removing stale namespaces\n" )
|
||||
nses = sh( "ip netns list" )
|
||||
for ns in nses:
|
||||
sh( "ip netns del " + ns )
|
||||
if co( "ip netns list", shell=True ):
|
||||
error( "Error: could not remove all namespaces - exiting\n" )
|
||||
exit( 1 )
|
||||
|
||||
info( "*** Cleanup complete.\n" )
|
||||
|
||||
+14
-3
@@ -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."
|
||||
|
||||
+32
-17
@@ -25,7 +25,7 @@ Link: basic link class for creating veth pairs
|
||||
"""
|
||||
|
||||
from mininet.log import info, error, debug
|
||||
from mininet.util import makeIntfPair
|
||||
from mininet.util import makeIntfPair, errFail, quietRun
|
||||
from time import sleep
|
||||
import re
|
||||
|
||||
@@ -109,7 +109,7 @@ class Intf( object ):
|
||||
def rename( self, newname ):
|
||||
"Rename interface"
|
||||
self.ifconfig( 'down' )
|
||||
result = self.cmd( 'ip link set', self.name, 'name', newname )
|
||||
result = self.cmd( 'ip link set dev', self.name, 'name', newname )
|
||||
self.name = newname
|
||||
self.ifconfig( 'up' )
|
||||
return result
|
||||
@@ -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,
|
||||
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
|
||||
|
||||
@@ -344,7 +347,7 @@ class Link( object ):
|
||||
if not intfName2:
|
||||
intfName2 = self.intfName( node2, port2 )
|
||||
|
||||
self.makeIntfPair( intfName1, intfName2 )
|
||||
self.makeIntfPair( intfName1, intfName2, node1, node2 )
|
||||
|
||||
if not cls1:
|
||||
cls1 = intf
|
||||
@@ -369,13 +372,24 @@ class Link( object ):
|
||||
return node.name + '-eth' + repr( n )
|
||||
|
||||
@classmethod
|
||||
def makeIntfPair( cls, intf1, intf2 ):
|
||||
def makeIntfPair( cls, intf1, intf2, node1=None, node2=None ):
|
||||
"""Create pair of interfaces
|
||||
intf1: name of interface 1
|
||||
intf2: name of interface 2
|
||||
(override this class method [and possibly delete()]
|
||||
to change link type)"""
|
||||
makeIntfPair( intf1, intf2 )
|
||||
# To be compatible with pid namespaces and chroot in the future
|
||||
# we create links in the root namespace and then move
|
||||
# the ends as needed.
|
||||
# First, make sure there aren't stale links sitting around
|
||||
quietRun( 'ip link delete %s type veth' % intf1 )
|
||||
quietRun( 'ip link delete %s type veth' % intf2 )
|
||||
cmd = 'ip link add %s type veth peer name %s' % ( intf1, intf2 )
|
||||
if node2 and node2.inNamespace:
|
||||
cmd += ' netns %s' % node2
|
||||
errFail( cmd )
|
||||
if node1 and node1.inNamespace:
|
||||
errFail( 'ip link set dev %s netns %s' % ( intf1, node1 ) )
|
||||
|
||||
def delete( self ):
|
||||
"Delete this link"
|
||||
@@ -385,6 +399,7 @@ class Link( object ):
|
||||
def __str__( self ):
|
||||
return '%s<->%s' % ( self.intf1, self.intf2 )
|
||||
|
||||
|
||||
class TCLink( Link ):
|
||||
"Link with symmetric TC interfaces configured via opts"
|
||||
def __init__( self, node1, node2, port1=None, port2=None,
|
||||
|
||||
+41
-14
@@ -91,12 +91,13 @@ 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
|
||||
from mininet.node import Host, OVSKernelSwitch, Controller
|
||||
from mininet.link import Link, Intf
|
||||
from mininet.util import quietRun, fixLimits, numCores, ensureRoot
|
||||
from mininet.util import quietRun, errFail, fixLimits, numCores, ensureRoot
|
||||
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
|
||||
from mininet.term import cleanUpScreens, makeTerms
|
||||
|
||||
@@ -151,7 +152,8 @@ class Mininet( object ):
|
||||
self.hosts = []
|
||||
self.switches = []
|
||||
self.controllers = []
|
||||
|
||||
self.links = []
|
||||
|
||||
self.nameToNode = {} # name to Node (Host/Switch) objects
|
||||
|
||||
self.terms = [] # list of spawned xterm processes
|
||||
@@ -216,8 +218,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 +230,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
|
||||
@@ -242,7 +253,9 @@ class Mininet( object ):
|
||||
defaults.update( params )
|
||||
if not cls:
|
||||
cls = self.link
|
||||
return cls( node1, node2, **defaults )
|
||||
link = cls( node1, node2, **defaults )
|
||||
self.links.append( link )
|
||||
return link
|
||||
|
||||
def configHosts( self ):
|
||||
"Configure a set of hosts."
|
||||
@@ -362,20 +375,34 @@ class Mininet( object ):
|
||||
if self.terms:
|
||||
info( '*** Stopping %i terms\n' % len( self.terms ) )
|
||||
self.stopXterms()
|
||||
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
|
||||
for controller in self.controllers:
|
||||
info( controller.name + ' ' )
|
||||
controller.stop()
|
||||
info( '\n' )
|
||||
info( '*** Stopping %i switches\n' % len( self.switches ) )
|
||||
for switch in self.switches:
|
||||
info( switch.name + ' ' )
|
||||
switch.stop( deleteIntfs=False )
|
||||
info( '\n' )
|
||||
info( '*** Removing links\n' )
|
||||
for link in self.links:
|
||||
info( '.' )
|
||||
link.delete()
|
||||
info( '\n*** Terminating switches\n' )
|
||||
for switch in self.switches:
|
||||
info( '.' )
|
||||
switch.terminate()
|
||||
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 switches\n' % len( self.switches ) )
|
||||
for switch in self.switches:
|
||||
info( switch.name + ' ' )
|
||||
switch.stop()
|
||||
info( '\n' )
|
||||
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
|
||||
for controller in self.controllers:
|
||||
info( controller.name + ' ' )
|
||||
controller.stop()
|
||||
nses = quietRun( 'ip netns list').strip().split()
|
||||
info( '*** Removing namespaces' )
|
||||
for ns in nses:
|
||||
errFail( 'ip netns del ' + ns )
|
||||
info( '\n*** Done\n' )
|
||||
|
||||
def run( self, test, *args, **kwargs ):
|
||||
|
||||
+40
-26
@@ -49,6 +49,8 @@ import re
|
||||
import signal
|
||||
import select
|
||||
from subprocess import Popen, PIPE, STDOUT
|
||||
from sys import stdout
|
||||
from time import sleep
|
||||
|
||||
from mininet.log import info, error, warn, debug
|
||||
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||
@@ -107,19 +109,26 @@ class Node( object ):
|
||||
|
||||
# Command support via shell process in namespace
|
||||
|
||||
def _popen( self, *args, **kwargs ):
|
||||
"Internal wrapper for Popen"
|
||||
old = signal.signal( signal.SIGINT, signal.SIG_IGN )
|
||||
result = Popen( *args, **kwargs )
|
||||
signal.signal( signal.SIGINT, old )
|
||||
return result
|
||||
|
||||
def startShell( self ):
|
||||
"Start a shell process for running commands"
|
||||
if self.shell:
|
||||
error( "%s: shell is already running" )
|
||||
return
|
||||
# mnexec: (c)lose descriptors, (d)etach from tty,
|
||||
# (p)rint pid, and run in (n)amespace
|
||||
opts = '-cdp'
|
||||
if self.inNamespace:
|
||||
opts += 'n'
|
||||
# bash -m: enable job control
|
||||
cmd = [ 'mnexec', opts, 'bash', '-m' ]
|
||||
self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
|
||||
# -s: pass $* to shell, and make process easy to find in ps
|
||||
cmd = [ 'bash', '-ms', 'mininet:' + self.name ]
|
||||
if self.inNamespace:
|
||||
quietRun( 'ip netns del ' + self.name )
|
||||
errFail( 'ip netns add ' + self.name )
|
||||
cmd = [ 'ip', 'netns', 'exec', self.name ] + cmd
|
||||
self.shell = self._popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
|
||||
close_fds=True )
|
||||
self.stdin = self.shell.stdin
|
||||
self.stdout = self.shell.stdout
|
||||
@@ -139,11 +148,14 @@ 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 )
|
||||
self.shell = None
|
||||
if self.shell:
|
||||
self.shell.terminate()
|
||||
self.shell.wait()
|
||||
self.shell = None
|
||||
if self.inNamespace:
|
||||
# Note: this will only work if there are no other
|
||||
# processes running in namespaces, but we'll do it anyway
|
||||
quietRun( 'ip netns del ' + self.name )
|
||||
|
||||
# Subshell I/O, commands and control
|
||||
|
||||
@@ -290,7 +302,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:
|
||||
@@ -311,7 +323,7 @@ class Node( object ):
|
||||
# Shell requires a string, not a list!
|
||||
if defaults.get( 'shell', False ):
|
||||
cmd = ' '.join( cmd )
|
||||
return Popen( cmd, **defaults )
|
||||
return self._popen( cmd, **defaults )
|
||||
|
||||
def pexec( self, *args, **kwargs ):
|
||||
"""Execute a command using popen
|
||||
@@ -345,10 +357,8 @@ class Node( object ):
|
||||
self.ports[ intf ] = port
|
||||
self.nameToIntf[ intf.name ] = intf
|
||||
debug( '\n' )
|
||||
assert intf.name in self.cmd( 'ip link show' )
|
||||
debug( 'added intf %s:%d to node %s\n' % ( intf, port, self.name ) )
|
||||
if self.inNamespace:
|
||||
debug( 'moving', intf, 'into namespace for', self.name, '\n' )
|
||||
moveIntf( intf.name, self )
|
||||
|
||||
def defaultIntf( self ):
|
||||
"Return interface for lowest port"
|
||||
@@ -399,6 +409,7 @@ class Node( object ):
|
||||
for intf in self.intfs.values():
|
||||
intf.delete()
|
||||
info( '.' )
|
||||
stdout.flush()
|
||||
|
||||
# Routing support
|
||||
|
||||
@@ -447,7 +458,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."
|
||||
@@ -604,7 +615,7 @@ 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 ) ]
|
||||
@@ -834,11 +845,12 @@ class UserSwitch( Switch ):
|
||||
' --fail=closed ' + self.opts +
|
||||
' 1> ' + ofplog + ' 2>' + ofplog + ' &' )
|
||||
|
||||
def stop( self ):
|
||||
def stop( self, deleteIntfs=True ):
|
||||
"Stop OpenFlow reference user datapath."
|
||||
self.cmd( 'kill %ofdatapath' )
|
||||
self.cmd( 'kill %ofprotocol' )
|
||||
self.deleteIntfs()
|
||||
if deleteIntfs:
|
||||
self.deleteIntfs()
|
||||
|
||||
|
||||
class OVSLegacyKernelSwitch( Switch ):
|
||||
@@ -885,11 +897,12 @@ class OVSLegacyKernelSwitch( Switch ):
|
||||
' 1>' + ofplog + ' 2>' + ofplog + '&' )
|
||||
self.execed = False
|
||||
|
||||
def stop( self ):
|
||||
def stop( self, deleteIntfs=True ):
|
||||
"Terminate kernel datapath."
|
||||
quietRun( 'ovs-dpctl del-dp ' + self.dp )
|
||||
self.cmd( 'kill %ovs-openflowd' )
|
||||
self.deleteIntfs()
|
||||
if deleteIntfs:
|
||||
self.deleteIntfs()
|
||||
|
||||
|
||||
class OVSSwitch( Switch ):
|
||||
@@ -968,10 +981,11 @@ class OVSSwitch( Switch ):
|
||||
clist += ' ptcp:%s' % self.listenPort
|
||||
self.cmd( 'ovs-vsctl set-controller', self, clist )
|
||||
|
||||
def stop( self ):
|
||||
"Terminate OVS switch."
|
||||
def stop( self, deleteIntfs=True ):
|
||||
"Stop OVS switch."
|
||||
self.cmd( 'ovs-vsctl del-br', self )
|
||||
self.deleteIntfs()
|
||||
if deleteIntfs:
|
||||
self.deleteIntfs()
|
||||
|
||||
OVSKernelSwitch = OVSSwitch
|
||||
|
||||
|
||||
+39
-32
@@ -1,60 +1,67 @@
|
||||
"""
|
||||
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 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
|
||||
|
||||
+37
-33
@@ -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, ''
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+124
-28
@@ -122,7 +122,7 @@ function kernel_clean {
|
||||
# Install Mininet deps
|
||||
function mn_deps {
|
||||
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 \
|
||||
pyflakes pylint pep8
|
||||
|
||||
@@ -133,8 +133,10 @@ function mn_deps {
|
||||
|
||||
# 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 $HOME/mininet/util/sysctl_addon >> /etc/sysctl.conf"
|
||||
fi
|
||||
# Load new sysctl settings:
|
||||
sudo sysctl -p
|
||||
|
||||
@@ -165,25 +167,44 @@ function of {
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
cd ~
|
||||
}
|
||||
|
||||
# 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 ~/
|
||||
$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"
|
||||
|
||||
# Install netbee
|
||||
wget -nc http://www.nbee.org/download/nbeesrc-12-05-16.zip
|
||||
unzip nbeesrc-12-05-16.zip
|
||||
cd ~/nbeesrc/src
|
||||
cmake .
|
||||
make
|
||||
cd ~/
|
||||
sudo cp nbeesrc/bin/libn*.so /usr/local/lib
|
||||
sudo ldconfig
|
||||
sudo cp -R nbeesrc/include/ /usr/
|
||||
|
||||
# Resume the install:
|
||||
cd ~/ofsoftswitch13
|
||||
./boot.sh
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
cd ~
|
||||
}
|
||||
|
||||
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
|
||||
@@ -378,6 +399,40 @@ function nox {
|
||||
#./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 ~/
|
||||
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..."
|
||||
@@ -395,9 +450,6 @@ function oftest {
|
||||
# Install oftest:
|
||||
cd ~/
|
||||
git clone git://github.com/floodlight/oftest
|
||||
cd oftest
|
||||
cd tools/munger
|
||||
sudo make install
|
||||
}
|
||||
|
||||
# Install cbench
|
||||
@@ -416,14 +468,45 @@ function cbench {
|
||||
}
|
||||
|
||||
function 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:
|
||||
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
|
||||
@@ -505,11 +588,11 @@ function vm_clean {
|
||||
}
|
||||
|
||||
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,28 +606,35 @@ 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 -- ' -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
|
||||
exit 2
|
||||
}
|
||||
|
||||
OF_VERSION=1.0
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
all
|
||||
else
|
||||
while getopts 'abcdfhkmnprtvwx' OPTION
|
||||
while getopts 'abcdfhkmnprtvwx03' 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;;
|
||||
@@ -554,7 +644,13 @@ else
|
||||
t) 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;;
|
||||
?) usage;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/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
|
||||
|
||||
if [ -z $2 ]; then
|
||||
cmd='bash'
|
||||
else
|
||||
shift
|
||||
cmd=$*
|
||||
fi
|
||||
|
||||
# We could do this in this script, and we may want to eventually,
|
||||
# but for now we'll use mnexec to attach to the host's cgroup
|
||||
cgroup=/sys/fs/cgroup/cpu/$host
|
||||
if [ -d "$cgroup" ]; then
|
||||
cg="mnexec -g $host"
|
||||
fi
|
||||
|
||||
exec sudo ip netns exec $host $cg $cmd
|
||||
@@ -15,3 +15,4 @@ net.ipv4.neigh.default.gc_thresh3 = 16384
|
||||
|
||||
# Mininet: increase routing table size
|
||||
net.ipv4.route.max_size=32768
|
||||
|
||||
|
||||
Reference in New Issue
Block a user