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