Compare commits

..

11 Commits

Author SHA1 Message Date
Nikhil Handigol d8137a9219 do system monitoring only if net.set_debug() is called 2012-05-02 01:02:48 +00:00
Nikhil Handigol 891ea4854d create output dir only upon starting monitoring 2012-05-02 00:55:42 +00:00
Nikhil Handigol 2e0e2d97ec cwnd monitoring via tcp_probe 2012-04-27 03:38:50 +00:00
Nikhil Handigol 71b3128122 move obsolete functions to the bottom 2012-04-27 03:21:32 +00:00
Nikhil Handigol 5ca1fb7e0f monitoring output dir name change 2012-04-27 03:14:20 +00:00
Nikhil Handigol 18a0b7e4ac cpuacct monitoring 2012-04-27 03:13:53 +00:00
Nikhil Handigol e27673aeec cleanup afterwards 2012-04-27 02:56:04 +00:00
Nikhil Handigol 035d4d20fe integrating monitoring code into net -- tested 2012-04-27 02:42:22 +00:00
Nikhil Handigol 550ee2469e code to monitor cpuacct 2012-04-17 06:59:21 +00:00
Nikhil Handigol d8d9035242 move monitoring functions to a separate class 2012-04-16 21:05:54 +00:00
Nikhil Handigol f1aca0d9a6 basic monitoring script 2012-04-16 21:05:22 +00:00
63 changed files with 1119 additions and 3790 deletions
-1
View File
@@ -1 +0,0 @@
*.py diff=python
+2 -8
View File
@@ -1,14 +1,8 @@
mnexec
*.pyc
*~
*.1
*.xcodeproj
*.xcworkspace
\#*\#
mininet.egg-info
build
dist
doc/html
doc/latex
trunk
build/*
dist/*
+225 -75
View File
@@ -1,123 +1,273 @@
Mininet Installation/Configuration Notes
----------------------------------------
Mininet 2.0.0
Mininet 1.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 (4).
The supported installation methods for Mininet are 1) using
a pre-built VM image, and 2) native installation on Ubuntu or Debian.
(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!
1. Easiest "install" - 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
Mininet web site.
Boot up the VM image, log in, and follow the instructions on the wiki page.
One advantage of using the VM image is that it doesn't mess with
your native OS installation or damage it in any way.
An additional 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.
2. Native installation (experimental!) for Ubuntu 10.04 LTS
2. Next-easiest option: use our Ubuntu package!
If you are running Ubuntu 10.04 LTS (or possibly Debian 5), you may be
able to use our handy install.sh script, which is in mininet/util.
To install Mininet itself (i.e. `mn` and the Python API) on Ubuntu
12.10+:
WARNING: USE AT YOUR OWN RISK!
sudo apt-get install mininet
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!
Note: if you are upgrading from an older version of Mininet, make
sure you remove the old OVS from `/usr/local`:
To install ALL of the software which we use for OpenFlow tutorials,
you may use
sudo rm /usr/local/bin/ovs*
sudo rm /usr/local/sbin/ovs*
$ mininet/util/install.sh
3. Native installation from source on Ubuntu 11.10+
This takes about 20-30 minutes.
If you're reading this, you've probably already done so, but the
command to download the Mininet source code is:
Alternately, you can install just the pieces you need.
git clone git://github.com/mininet/mininet.git
We recommend the following steps, in order:
If you are running Ubuntu, you may be able to use our handy
`install.sh` script, which is in `mininet/util`.
[a) On Debian 5, first install a Mininet-compatible kernel:
$ mininet/util/install.sh -k
Reboot and run 'uname -r' to make sure you're running the new kernel.]
*WARNING: USE AT YOUR OWN RISK!*
b) Install mininet and its dependencies:
$ mininet/util/install.sh -n
c) Install OpenFlow 1.0 and associated useful software
$ mininet/util/install.sh -f
`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!
d) Install Open vSwitch and its kernel module
$ mininet/util/install.sh -vm
To install Mininet itself, the OpenFlow reference implementation, and
Open vSwitch, you may use:
e) If you wish to install the version of NOX we use in the tutorial:
$ mininet/util/install.sh -x
mininet/util/install.sh -fnv
Note: NOX development is progressing over time, so after you complete
the tutorial you may wish to install the latest and greatest NOX from
noxrepo.org.
This should be reasonably quick, and the following command should
work after the installation:
Good luck! Some additional installation notes are provided below, for
the brave and/or Linux-savvy, or those who are trying to understand what
is installed and why.
sudo mn --test pingall
p.s. Note that only one instance of Mininet is currently supported on a single
machine - that's one reason we recommend using a VM to run it.
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:
---
mininet/util/install.sh -a
Mininet Manual Installation Notes
This takes about 4 minutes on our test system.
These installation notes assume you understand how to do things like
compile kernels, apply patches, configure networks, write code, etc.. If
this is unfamiliar territory, or if you run into trouble, we recommend
using one of our pre-built virtual machine images (see above.)
4. Creating your own Mininet/OpenFlow tutorial VM
If you wish to try to create a VM to run Mininet, you may also wish
to look at the Wiki page:
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:
http://openflow.org/foswiki/bin/view/OpenFlow/MininetVMCreationNotes
wget https://raw.github.com/mininet/mininet/master/util/vm/install-mininet-vm.sh
time install-mininet-vm.sh
0. Obtaining Mininet
Finally, verify that Mininet is installed and working in the VM:
If you're reading this, you've already done it, but the command to
download mininet is:
git clone git://openflow.org/mininet.git
1. Core Mininet installation
sudo mn --test pingall
The core Mininet installation requires gcc, make, python,
and setuptools. On Ubuntu and Debian you may install them with:
# aptitude install gcc make python setuptools
5. Installation on other Linux distributions
To install Mininet itself, with root privileges:
# cd mininet
# make install
Although we don't support other Linux distributions directly, it
should be possible to install and run Mininet with some degree of
manual effort.
This places the mininet package in /usr/lib/python-*/site-packages/,
so that 'import mininet' will work, and installs the primary mn
script (mn) as well as its helper utility (mnexec.)
On Ubuntu and Debian, Mininet's dependencies and core files may also be
installed using mininet/util/install.sh -n
In general, you must have:
2. Installation script for Ubuntu/Debian Lenny
* A Linux kernel compiled with network namespace support enabled
If you are running Ubuntu 10.04 or Debian Lenny, you may be able to use the
util/install.sh script to install a compatible Linux kernel as well as
other software including the OpenFlow reference implementation, the Open
vSwitch switch implementation, and the NOX OpenFlow controller.
* 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.
Many different installation options are possible by passing different
options to install.sh; install.sh -h lists them all.
Assuming the mininet source tree is installed in ~/mininet, the steps to run
install.sh to install EVERYTHING we use for OpenFlow tutorials are:
% cd
% time ~/mininet/util/install.sh # installs tons of stuff
% sudo reboot # to load new kernel
% ~/mininet/util/install.sh -c # to clean out unneeded kernel stuff
* Python, `bash`, `ping`, `iperf`, etc.`
This installs a lot of useful software, but it will take a while (30
minutes or more, depending on your network connection, computer, etc..)
Probably the minimal semi-useful configuration would be to install
Mininet itself, kernel support if necessary, and either the
reference OpenFlow switch or Open vSwitch. This could be installed
as follows:
% sudo ~/mininet/util/install.sh -knvm
Respectively, this installs kernel support, core mininet dependencies,
Open vSwitch, and the Open vSwitch kernel module. If a new kernel was
installed, then a reboot may be required.
* Root privileges (required for network device access)
If install.sh cannot be used for some reason (e.g. you're on Fedora
or some other Linux - please don't say CentOS) or if you don't want to
install all of these components (they're useful!), the kernel and
OpenFlow software requirements are described in steps [3] and [4],
which follow.
We encourage contribution of patches to the `install.sh` script to
support other Linux distributions.
If you successfully used install.sh, congratulations! You're basically
done. Proceed to step [6] for additional advice.
3. Linux Kernel requirements
Mininet requires a kernel built with network namespace support enabled,
i.e. with CONFIG_NET_NS=Y, such as the kernel shipped with
Ubuntu 10.04 LTS, currently 2.6.32. On Ubuntu 10.04, you should not need
to install or build a custom kernel, although 2.6.33+ is faster at
tearing down virtual ethernet pairs.
For Ubuntu and Debian, we provide a 2.6.33 kernel package which you may be
able to install using "util/install.sh -k". Note our kernel package
requires an ext2 or ext3 root file system, so it won't work if you have
a default Ubuntu install, which uses ext4.
If your kernel wasn't compiled with CONFIG_NET_NS=Y, you will need to
build and install a kernel that does! >= 2.6.33 works better, but may
be harder to get working, depending on your Linux distribution.
A script for building Debian packages for 2.6.33.1 is provided in
mininet/util/kbuild. You may wish to read it, as it applies patches
to enable 2.6.33.1 to build under debian-stable, and to enable the
tun driver to work correctly with Mininet.
Earlier kernels (e.g. 2.6.29) work with CONFIG_NET_NS enabled and no
additional patches, but are much slower at removing veth interfaces,
resulting in much slower switch shutdown.
For scalable configurations, you might need to increase some of your
kernel limits. Sample params are in util/sysctl_addon, which can be
appended to /etc/sysctl.conf (and modified as necessary for your
desired configuration):
sudo su -c "cat sysctl_addon >> /etc/sysctl.conf"
To save the config change, run:
sudo sysctl -p
4. OpenFlow software and configuration requirements
Mininet requires either the reference OpenFlow switch implementation
(from openflowswitch.org) or Open vSwitch (openvswitch.org) to be
installed. "make test" requires the reference user space
implementations as well as Open vSwitch. Note the reference kernel
implementation is not currently included in OpenFlow 1.0.
On Ubuntu and Debian, the install.sh script may be used with the '-f'
option to install the OpenFlow reference implementation, the '-v' option
to build Open vSwitch, and the '-m' option to install the Open vSwitch
kernel module into /lib/modules (note: you must build Open vSwitch first!)
Mininet will automatically load and remove kernel module dependencies
for supported switch types, using modprobe and rmmod - but these
modules must be in a location where modprobe can find them (e.g.
something like /lib/modules/`uname -r`/kernel/drivers/net/)
The reference OpenFlow controller (controller(8)) only supports 16
switches by default! If you wish to run a network with more than 16
switches, please recompile controller(8) with larger limits, or use a
different controller such as nox. A patch to controller(8) is included
as util/openflow-patches/controller.patch.
5. Other software dependencies
On Ubuntu and Debian, other Mininet dependencies may be installed using
the '-n' option of the install.sh script.
To run the iperf test, you need to install iperf:
sudo aptitude/yum install iperf
We assume you already have ping installed. ;-)
To use xterm or sshd with Mininet, you need the following:
sudo aptitude/yum install sshd xterm screen
Some examples may have additional requirements - consult the specific
example file for details.
The install.sh script has an '-x' option to install the version of
NOX from the OpenFlow tutorial.
6. Other notes and recommendations
If you did not install certain useful packages and you wish to later,
it may be possible to install them using install.sh.
Mininet should be run either on a machine with
no other important processes, or on a virtual machine (recommended!)
Multiple concurrent Mininet instances are not supported!
Good luck!
Mininet Team
---
Historical information on OpenFlow 0.8.9 and the reference kernel module:
The kernel reference implementation has been deprecated, but it may
be possible to get it work with Mininet.
To switch to the most recent OpenFlow 0.8.9 release branch (the most
recent one with full NOX support and kernel datapath support) in your
OpenFlow git tree:
git checkout -b release/0.8.9 remotes/origin/release/0.8.9
A patch to enable datapath.c to compile with recent kernels
is included in util/openflow-patches/datapath.patch.
In OpenFlow 1.0, switch port numbering starts at 1 (for better or for worse.)
To run with previous versions of OpenFlow, it may be necessary
to change SWITCH_PORT_BASE from 1 to 0 in node.py.
+2 -6
View File
@@ -1,10 +1,6 @@
Mininet 2.0.0 License
Mininet 1.0.0 License
Copyright (c) 2012 Open Networking Laboratory
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
The Leland Stanford Junior University
Original authors: Bob Lantz and Brandon Heller
Copyright (c) 2009-2011 Bob Lantz and Brandon Heller
We are making Mininet available for public use and benefit with the
expectation that others will use, modify and enhance the Software and
+8 -34
View File
@@ -1,25 +1,18 @@
MININET = mininet/*.py
TEST = mininet/test/*.py
EXAMPLES = examples/*.py
MN = bin/mn
BIN = $(MN)
BIN = bin/mn
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
MNEXEC = mnexec
MANPAGES = mn.1 mnexec.1
P8IGN = E251,E201,E302,E202
BINDIR = /usr/bin
MANDIR = /usr/share/man/man1
DOCDIRS = doc/html doc/latex
PDF = doc/latex/refman.pdf
all: codecheck test
clean:
rm -rf build dist *.egg-info *.pyc $(MNEXEC) $(MANPAGES) $(DOCDIRS)
rm -rf build dist *.egg-info *.pyc $(MNEXEC)
codecheck: $(PYSRC)
-echo "Running code check"
util/versioncheck.py
pyflakes $(PYSRC)
pylint --rcfile=.pylint $(PYSRC)
pep8 --repeat --ignore=$(P8IGN) $(PYSRC)
@@ -32,34 +25,15 @@ errcheck: $(PYSRC)
test: $(MININET) $(TEST)
-echo "Running tests"
mininet/test/test_nets.py
mininet/test/test_hifi.py
mnexec: mnexec.c $(MN) mininet/net.py
cc $(CFLAGS) $(LDFLAGS) -DVERSION=\"`PYTHONPATH=. $(MN) --version`\" $< -o $@
install: $(MNEXEC) $(MANPAGES)
install $(MNEXEC) $(BINDIR)
install $(MANPAGES) $(MANDIR)
install: $(MNEXEC)
install $(MNEXEC) /usr/local/bin/
python setup.py install
develop: $(MNEXEC) $(MANPAGES)
# Perhaps we should link these as well
install $(MNEXEC) $(BINDIR)
install $(MANPAGES) $(MANDIR)
develop: $(MNEXEC)
install $(MNEXEC) /usr/local/bin/
python setup.py develop
man: $(MANPAGES)
doc:
doxygen doxygen.cfg
mn.1: $(MN)
PYTHONPATH=. help2man -N -n "create a Mininet network." \
--no-discard-stderr $< -o $@
mnexec.1: mnexec
help2man -N -n "execution utility for Mininet." \
-h "-h" -v "-v" --no-discard-stderr ./$< -o $@
.PHONY: doc
doc: man
doxygen doc/doxygen.cfg
make -C doc/latex
+86
View File
@@ -0,0 +1,86 @@
Mininet: A Simple Virtual Testbed for OpenFlow/SDN
or
How to Squeeze a 1024-node OpenFlow Network onto your Laptop
Mininet 1.0.0
---
Welcome to Mininet!
Mininet creates OpenFlow test networks by using process-based
virtualization and network namespaces.
Simulated hosts (as well as switches and controllers with the user
datapath) are created as processes in separate network namespaces. This
allows a complete OpenFlow network to be simulated on top of a single
Linux kernel.
Mininet may be invoked directly from the command line, and also provides a
handy Python API for creating networks of varying sizes and topologies.
Mininet is currently in *limited alpha release*. We encourage you to
experiment with it and hope that you will provide us with feedback on
features, documentation, and how you're using it. We plan to make it
available publicly via a GPL or BSD license (probably in April), but please
don't distribute the code or URLs yet! The feedback you provide will help
us improve Mininet for general release.
In order to run Mininet, you must have:
* A Linux 2.6.26 or greater kernel compiled with network namespace support
enabled (see INSTALL for additional information.)
* 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.
* Root privileges (required for network device access)
Currently Mininet includes:
- A simple node infrastructure (Host, Switch, Controller classes) for
creating virtual OpenFlow networks
- A simple network infrastructure (Mininet class) supporting parametrized
topologies (Topo subclasses.) For example, a tree network may be created
with the command
# mn --topo tree,depth=2,fanout=3
- Basic tests, including connectivity (ping) and bandwidth (iperf)
- A command-line interface (CLI class) which provides useful
diagnostic commands, as well as the ability to send a command to a
node. For example,
mininet> h11 ifconfig -a
tells host h11 to run the command 'ifconfig -a'
- A 'cleanup' command to get rid of junk (interfaces, processes, files in
/tmp, etc.) which might be left around by Mininet or Linux. Try this if
things stop working!
# mn -c
- Examples (in the examples/ directory) to help you get started.
Batteries are not included (yet!)
However, some preliminary installation notes are included in the INSTALL
file.
Additionally, much useful information, including a Mininet tutorial,
is available on the Mininet wiki:
http://openflow.org/mininet
Enjoy, and good luck!
---
Bob Lantz
rlantz@cs.stanford.edu
-134
View File
@@ -1,134 +0,0 @@
Mininet: Rapid Prototyping for Software Defined Networks
========================================================
*The best way to emulate almost any network on your laptop!*
Version 2.0.0
### What is Mininet?
Mininet emulates a complete network of hosts, links, and switches
on a single machine. To create a sample two-host, one-switch network,
just run:
`sudo mn`
Mininet is useful for interactive development, testing, and demos,
especially those using OpenFlow and SDN. OpenFlow-based network
controllers prototyped in Mininet can usually be transferred to
hardware with minimal changes for full line-rate execution.
### How does it work?
Mininet creates virtual networks using process-based virtualization
and network namespaces - features that are available in recent Linux
kernels. In Mininet, hosts are emulated as `bash` processes running in
a network namespace, so any code that would normally run on a Linux
server (like a web server or client program) should run just fine
within a Mininet "Host". The Mininet "Host" will have its own private
network interface and can only see its own processes. Switches in
Mininet are software-based switches like Open vSwitch or the OpenFlow
reference switch. Links are virtual ethernet pairs, which live in the
Linux kernel and connect our emulated switches to emulated hosts
(processes).
### Features
Mininet includes:
* A command-line launcher (`mn`) to instantiate networks.
* A handy Python API for creating networks of varying sizes and
topologies.
* Examples (in the `examples/` directory) to help you get started.
* Full API documentation via Python `help()` docstrings, as well as
the ability to generate PDF/HTML documentation with `make doc`.
* Parametrized topologies (`Topo` subclasses) using the Mininet
object. For example, a tree network may be created with the
command:
`mn --topo tree,depth=2,fanout=3`
* A command-line interface (`CLI` class) which provides useful
diagnostic commands (like `iperf` and `ping`), as well as the
ability to run a command to a node. For example,
`mininet> h11 ifconfig -a`
tells host h11 to run the command `ifconfig -a`
* A "cleanup" command to get rid of junk (interfaces, processes, files
in /tmp, etc.) which might be left around by Mininet or Linux. Try
this if things stop working!
`mn -c`
### New features in 2.0.0
Mininet 2.0.0 is a major upgrade and provides
a number of enhancements and new features, including:
* "Mininet-HiFi" functionality:
* Link bandwidth limits using `tc` (`TCIntf` and `TCLink` classes)
* CPU isolation and bandwidth limits (`CPULimitedHost` class)
* Support for Open vSwitch 1.4+ (including Ubuntu OVS packages)
* Debian packaging (and `apt-get install mininet` in Ubuntu 12.10)
* First-class Interface (`Intf`) and Link (`Link`) classes for easier
extensibility
* An upgraded Topology (`Topo`) class which supports node and link
customization
* Man pages for the `mn` and `mnexec` utilities.
[Since the API (most notably the topology) has changed, existing code
that runs in Mininet 1.0 will need to be changed to run with Mininet
2.0. This is the primary reason for the major version number change.]
### Installation
See `INSTALL` for installation instructions and details.
### Documentation
In addition to the API documentation (`make doc`), much useful
information, including a Mininet walkthrough and an introduction
to the Python API, is available on the
[Mininet Web Site](http://openflow.org/mininet).
There is also a wiki which you are encouraged to read and to
contribute to, particularly the Frequently Asked Questions (FAQ.)
### Support
Mininet is community-supported. We encourage you to join the
Mininet mailing list, `mininet-discuss` at:
<https://mailman.stanford.edu/mailman/listinfo/mininet-discuss>
### Contributing
Mininet is an open-source project and is currently hosted at
<https://github.com/mininet>. You are encouraged to download the code,
examine it, modify it, and submit bug reports, bug fixes, feature
requests, and enhancements!
Best wishes, and we look forward to seeing what you can do with
Mininet to change the networking world!
### Credits
The Mininet Team:
* Bob Lantz
* Brandon Heller
* Nikhil Handigol
* Vimal Jeyakumar
+91 -60
View File
@@ -12,39 +12,56 @@ Example to pull custom params (topo, switch, etc.) from a file:
"""
from optparse import OptionParser
import os
import os.path
import sys
import time
# Fix setuptools' evil madness, and open up (more?) security holes
if 'PYTHONPATH' in os.environ:
sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
from mininet.clean import cleanup
from mininet.cli import CLI
from mininet.log import lg, LEVELS, info
from mininet.net import Mininet, MininetWithControlNet, VERSION
from mininet.log import lg, LEVELS, info, warn
from mininet.net import Mininet, MininetWithControlNet
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
NOX, RemoteController, UserSwitch, OVSKernelSwitch,
OVSLegacyKernelSwitch )
from mininet.link import Link, TCLink
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
from mininet.topolib import TreeTopo
from mininet.util import custom, customConstructor
from mininet.util import buildTopo
from mininet.util import makeNumeric, custom
def customNode( constructors, argStr ):
"Return custom Node constructor based on argStr"
cname, newargs, kwargs = splitArgs( argStr )
constructor = constructors.get( cname, None )
if not constructor:
raise Exception( "error: %s is unknown - please specify one of %s" %
( cname, constructors.keys() ) )
def customized( name, *args, **params ):
"Customized Node constructor"
params.update( kwargs )
if not newargs:
return constructor( name, *args, **params )
if args:
warn( 'warning: %s replacing %s with %s\n' % (
constructor, args, newargs ) )
return constructor( name, *newargs, **params )
return customized
# built in topologies, created only when run
TOPODEF = 'minimal'
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
'linear': LinearTopo,
'reversed': SingleSwitchReversedTopo,
'single': SingleSwitchTopo,
'tree': TreeTopo }
'linear': LinearTopo,
'reversed': SingleSwitchReversedTopo,
'single': SingleSwitchTopo,
'tree': TreeTopo }
SWITCHDEF = 'ovsk'
SWITCHES = { 'user': UserSwitch,
'ovsk': OVSKernelSwitch,
'ovsk': OVSKernelSwitch,
'ovsl': OVSLegacyKernelSwitch }
HOSTDEF = 'proc'
@@ -52,7 +69,7 @@ HOSTS = { 'proc': Host,
'rt': custom( CPULimitedHost, sched='rt' ),
'cfs': custom( CPULimitedHost, sched='cfs' ) }
CONTROLLERDEF = 'ovsc'
CONTROLLERDEF = 'ref'
CONTROLLERS = { 'ref': Controller,
'ovsc': OVSController,
'nox': NOX,
@@ -66,12 +83,35 @@ LINKS = { 'default': Link,
# optional tests to run
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
'none' ]
'none' ]
ALTSPELLING = { 'pingall': 'pingAll',
'pingpair': 'pingPair',
'iperfudp': 'iperfUdp',
'iperfUDP': 'iperfUdp' }
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' }
def splitArgs( argstr ):
"""Split argument string into usable python arguments
argstr: argument string with format fn,arg2,kw1=arg3...
returns: fn, args, kwargs"""
split = argstr.split( ',' )
fn = split[ 0 ]
params = split[ 1: ]
# Convert int and float args; removes the need for function
# to be flexible with input arg formats.
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( '=' )
kwargs[ key ] = makeNumeric( val )
return fn, args, kwargs
def buildTopo( topoStr ):
"Create topology from string with format (object, arg1, arg2,...)."
topo, args, kwargs = splitArgs( topoStr )
if topo not in TOPOS:
raise Exception( 'Invalid topo name %s' % topo )
return TOPOS[ topo ]( *args, **kwargs )
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
@@ -83,21 +123,16 @@ def addDictOption( opts, choicesDict, default, name, helpStr=None ):
help: string"""
if default not in choicesDict:
raise Exception( 'Invalid default %s for choices dict: %s' %
( default, name ) )
( default, name ) )
if not helpStr:
helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
'[,param=value...]' )
'[,param=value...]' )
opts.add_option( '--' + name,
type='string',
default = default,
help = helpStr )
type='string',
default = default,
help = helpStr )
def version( *_args ):
"Print Mininet version and exit"
print "%s" % VERSION
exit()
class MininetRunner( object ):
"Build, setup, and run Mininet."
@@ -145,14 +180,7 @@ class MininetRunner( object ):
else:
raise Exception( 'Custom file name not found' )
desc = ( "The %prog utility creates Mininet network from the\n"
"command line. It can create parametrized topologies,\n"
"invoke the Mininet CLI, and run tests." )
usage = ( '%prog [options]\n'
'(type %prog -h for details)' )
opts = OptionParser( description=desc, usage=usage )
opts = OptionParser()
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
@@ -160,39 +188,42 @@ class MininetRunner( object ):
addDictOption( opts, TOPOS, TOPODEF, 'topo' )
opts.add_option( '--clean', '-c', action='store_true',
default=False, help='clean and exit' )
default=False, help='clean and exit' )
opts.add_option( '--custom', type='string', default=None,
help='read custom topo and node params from .py' +
'file' )
help='read custom topo and node params from .py file' )
opts.add_option( '--test', type='choice', choices=TESTS,
default=TESTS[ 0 ],
help='|'.join( TESTS ) )
default=TESTS[ 0 ],
help='|'.join( TESTS ) )
opts.add_option( '--xterms', '-x', action='store_true',
default=False, help='spawn xterms for each node' )
default=False, help='spawn xterms for each node' )
opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
help='base IP address for hosts' )
opts.add_option( '--mac', action='store_true',
default=False, help='automatically set host MACs' )
default=False, help='automatically set host MACs' )
opts.add_option( '--arp', action='store_true',
default=False, help='set all-pairs ARP entries' )
default=False, help='set all-pairs ARP entries' )
opts.add_option( '--verbosity', '-v', type='choice',
choices=LEVELS.keys(), default = 'info',
help = '|'.join( LEVELS.keys() ) )
choices=LEVELS.keys(), default = 'info',
help = '|'.join( LEVELS.keys() ) )
opts.add_option( '--ip', type='string', default='127.0.0.1',
help='ip address as a dotted decimal string for a'
'remote controller' )
opts.add_option( '--innamespace', action='store_true',
default=False, help='sw and ctrl in namespace?' )
opts.add_option( '--listenport', type='int', default=6634,
default=False, help='sw and ctrl in namespace?' )
opts.add_option( '--listenport', type='int', default=6635,
help='base port for passive switch listening' )
opts.add_option( '--nolistenport', action='store_true',
default=False, help="don't use passive listening " +
"port")
default=False, help="don't use passive listening port")
opts.add_option( '--pre', type='string', default=None,
help='CLI script to run before tests' )
help='CLI script to run before tests' )
opts.add_option( '--post', type='string', default=None,
help='CLI script to run after tests' )
help='CLI script to run after tests' )
opts.add_option( '--prefixlen', type='int', default=8,
help='prefix length (e.g. /8) for automatic '
'network configuration' )
opts.add_option( '--pin', action='store_true',
default=False, help="pin hosts to CPU cores "
"(requires --host cfs or --host rt)" )
opts.add_option( '--version', action='callback', callback=version )
self.options, self.args = opts.parse_args()
@@ -216,11 +247,11 @@ class MininetRunner( object ):
start = time.time()
topo = buildTopo( TOPOS, self.options.topo )
switch = customConstructor( SWITCHES, self.options.switch )
host = customConstructor( HOSTS, self.options.host )
controller = customConstructor( CONTROLLERS, self.options.controller )
link = customConstructor( LINKS, self.options.link )
topo = buildTopo( self.options.topo )
switch = customNode( SWITCHES, self.options.switch )
host = customNode( HOSTS, self.options.host )
controller = customNode( CONTROLLERS, self.options.controller )
link = customNode( LINKS, self.options.link )
if self.validate:
self.validate( self.options )
+24 -13
View File
@@ -1,5 +1,7 @@
"""Custom topology example
author: Brandon Heller (brandonh@stanford.edu)
Two directly connected switches plus a host for each switch:
host --- switch --- switch --- host
@@ -8,27 +10,36 @@ Adding the 'topos' dict with a key/value pair to generate our newly defined
topology enables one to pass in '--topo=mytopo' from the command line.
"""
from mininet.topo import Topo
from mininet.topo import Topo, Node
class MyTopo( Topo ):
"Simple topology example."
def __init__( self ):
def __init__( self, enable_all = True ):
"Create custom topo."
# Initialize topology
Topo.__init__( self )
# Add default members to class.
super( MyTopo, self ).__init__()
# Add hosts and switches
leftHost = self.addHost( 'h1' )
rightHost = self.addHost( 'h2' )
leftSwitch = self.addSwitch( 's3' )
rightSwitch = self.addSwitch( 's4' )
# Set Node IDs for hosts and switches
leftHost = 1
leftSwitch = 2
rightSwitch = 3
rightHost = 4
# Add links
self.addLink( leftHost, leftSwitch )
self.addLink( leftSwitch, rightSwitch )
self.addLink( rightSwitch, rightHost )
# Add nodes
self.add_node( leftSwitch, Node( is_switch=True ) )
self.add_node( rightSwitch, Node( is_switch=True ) )
self.add_node( leftHost, Node( is_switch=False ) )
self.add_node( rightHost, Node( is_switch=False ) )
# Add edges
self.add_edge( leftHost, leftSwitch )
self.add_edge( leftSwitch, rightSwitch )
self.add_edge( rightSwitch, rightHost )
# Consider all switches and hosts 'on'
self.enable_all()
topos = { 'mytopo': ( lambda: MyTopo() ) }
-13
View File
@@ -1,13 +0,0 @@
mininet (2.0.0~rc1-0ubuntu1) quantal; urgency=low
* New upstream release.
* Update copyright to match upstream release
* Fix this message
-- Bob Lantz <rlantz@cs.stanford.edu> Sun, 18 Nov 2012 00:15:09 -0800
mininet (2.0.0~d4-0ubuntu1) quantal; urgency=low
* Initial release.
-- Bob Lantz <rlantz@cs.stanford.edu> Tue, 07 Aug 2012 14:11:27 -0700
-1
View File
@@ -1 +0,0 @@
9
-30
View File
@@ -1,30 +0,0 @@
Source: mininet
Section: net
Priority: extra
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
XSBC-Original-Maintainer: Bob Lantz <rlantz@cs.stanford.edu>
Standards-Version: 3.9.3
Build-Depends:
debhelper (>= 9~),
help2man,
python-dev,
python-pkg-resources,
python-setuptools,
python-networkx
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, socat
Description: Process-based network emulator
Mininet is a network emulator which uses lightweight
virtualization to create virtual networks for rapid
prototyping of Software-Defined Network (SDN) designs
using OpenFlow.
-37
View File
@@ -1,37 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0
Upstream-Name: mininet
Source: https://github.com/mininet/mininet
Files: *
Copyright: 2012 Open Networking Laboratory,
2009-2012 Bob Lantz,
2009-2012 The Board of Trustees of the Leland Stanford Junior
University
License:
Original authors: Bob Lantz and Brandon Heller
.
We are making Mininet available for public use and benefit with the
expectation that others will use, modify and enhance the Software and
contribute those enhancements back to the community. However, since we
would like to make the Software available for broadest use, with as few
restrictions as possible permission is hereby granted, free of charge, to
any person obtaining a copy of this Software to deal in the Software
under the copyrights without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
.
The name and trademarks of copyright holder(s) may NOT be used in
advertising or publicity pertaining to the Software or any derivatives
without specific, written prior permission.
Vendored
-1
View File
@@ -1 +0,0 @@
README.md
-1
View File
@@ -1 +0,0 @@
examples/*
-1
View File
@@ -1 +0,0 @@
mnexec /usr/bin
-1
View File
@@ -1 +0,0 @@
*.1
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/make -f
%:
dh $@ --buildsystem=python_distutils --with=python2
override_dh_auto_build:
make man
make mnexec
dh_auto_build
get-orig-source:
uscan --force-download --rename
-1
View File
@@ -1 +0,0 @@
3.0 (quilt)
-3
View File
@@ -1,3 +0,0 @@
version=3
opts=filenamemangle=s/(.*)\/archive/$1/,uversionmangle=s/([abdr].*)\.tar\.gz/~$1/ \
https://github.com/mininet/mininet/tags .*/archive\/(\d.*\.tar\.gz)
+3 -3
View File
@@ -25,7 +25,7 @@ DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
PROJECT_NAME = "Mininet Python API Reference Manual"
PROJECT_NAME = Mininet
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
@@ -114,7 +114,7 @@ FULL_PATH_NAMES = YES
# If left blank the directory from which doxygen is run is used as the
# path to strip.
STRIP_FROM_PATH =
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
@@ -919,7 +919,7 @@ COMPACT_LATEX = NO
# by the printer. Possible values are: a4, a4wide, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = letter
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
+1 -31
View File
@@ -19,33 +19,13 @@ graphical monitoring.
controllers.py:
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:
This example tests iperf bandwidth for varying CPU limits.
This example creates a network and adds multiple controllers to it.
emptynet.py:
This example demonstrates creating an empty network (i.e. with no
topology object) and adding nodes to it.
hwintf.py:
This example shows how to add an interface (for example a real
hardware interface) to a network after the network is created.
limit.py:
This example shows how to use link and CPU limits.
linearbandwidth.py:
This example shows how to create a custom topology programatically
@@ -68,16 +48,6 @@ multitest.py:
This example creates a network and runs multiple tests on it.
popen.py:
This example monitors a number of hosts using host.popen() and
pmonitor().
popenpoll.py:
This example demonstrates monitoring output from multiple hosts using
the node.popen() interface (which returns Popen objects) and pmonitor().
scratchnet.py, scratchnetuser.py:
These two examples demonstrate how to create a network by using the lowest-
-3
View File
@@ -3,9 +3,6 @@
"This example doesn't use OpenFlow, but attempts to run sshd in a namespace."
from mininet.node import Host
from mininet.util import ensureRoot
ensureRoot()
print "*** Creating nodes"
h1 = Host( 'h1' )
+12 -9
View File
@@ -74,11 +74,11 @@ class Console( Frame ):
"Pop up a new terminal window for a node."
net.terms += makeTerms( [ node ], title )
label = Button( self, text=self.node.name, command=newTerm,
**self.buttonStyle )
**self.buttonStyle )
label.pack( side='top', fill='x' )
text = Text( self, wrap='word', **self.textStyle )
ybar = Scrollbar( self, orient='vertical', width=7,
command=text.yview )
command=text.yview )
text.configure( yscrollcommand=ybar.set )
text.pack( side='left', expand=True, fill='both' )
ybar.pack( side='right', fill='y' )
@@ -95,7 +95,7 @@ class Console( Frame ):
# way to trigger a file event handler from Tk's
# event loop!
self.tk.createfilehandler( self.node.stdout, READABLE,
self.handleReadable )
self.handleReadable )
# We're not a terminal (yet?), so we ignore the following
# control characters other than [\b\n\r]
@@ -169,8 +169,11 @@ class Graph( Frame ):
"Graph that we can add bars to over time."
def __init__( self, parent=None, bg = 'white', gheight=200, gwidth=500,
barwidth=10, ymax=3.5,):
def __init__( self, parent=None,
bg = 'white',
gheight=200, gwidth=500,
barwidth=10,
ymax=3.5,):
Frame.__init__( self, parent )
@@ -192,7 +195,7 @@ class Graph( Frame ):
width = 25
ymax = self.ymax
scale = Canvas( self, width=width, height=height,
background=self.bg )
background=self.bg )
opts = { 'fill': 'red' }
# Draw scale line
scale.create_line( width - 1, height, width - 1, 0, **opts )
@@ -208,7 +211,7 @@ class Graph( Frame ):
ofs = 20
height = self.gheight + ofs
self.graph.configure( scrollregion=( 0, -ofs,
self.xpos * self.barwidth, height ) )
self.xpos * self.barwidth, height ) )
self.scale.configure( scrollregion=( 0, -ofs, 0, height ) )
def yview( self, *args ):
@@ -228,7 +231,7 @@ class Graph( Frame ):
xbar = Scrollbar( self, orient='horizontal', command=graph.xview )
ybar = Scrollbar( self, orient='vertical', command=self.yview )
graph.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set,
scrollregion=(0, 0, width, height ) )
scrollregion=(0, 0, width, height ) )
scale.configure( yscrollcommand=ybar.set )
# Layout
@@ -249,7 +252,7 @@ class Graph( Frame ):
x1 = x0 + self.barwidth
y0 = self.gheight
y1 = ( 1 - percent ) * self.gheight
c.create_rectangle( x0, y0, x1, y1, fill='green' )
c.create_rectangle( x0 , y0, x1, y1, fill='green' )
self.xpos += 1
self.updateScrollRegions()
self.graph.xview( 'moveto', '1.0' )
+54 -18
View File
@@ -1,28 +1,64 @@
#!/usr/bin/python
"""
Create a network where different switches are connected to
different controllers, by creating a custom Switch() subclass.
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.
"""
from mininet.net import Mininet
from mininet.node import OVSSwitch, Controller
from mininet.topolib import TreeTopo
from mininet.node import Controller, OVSKernelSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel
c0 = Controller( 'c0' )
c1 = Controller( 'c1', ip='127.0.0.2' )
cmap = { 's1': c0, 's2': c1, 's3': c1 }
Switch = OVSKernelSwitch
class MultiSwitch( OVSSwitch ):
"Custom Switch() subclass that connects to different controllers"
def start( self, controllers ):
return OVSSwitch.start( self, [ cmap[ self.name ] ] )
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 )
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()
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()
-61
View File
@@ -1,61 +0,0 @@
#!/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()
+2 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/python
"""
cpu.py: test iperf bandwidth for varying cpu limits
cpu.py: test iperf bandwidth for varying cpu limtis
"""
from mininet.net import Mininet
@@ -46,7 +46,7 @@ def bwtest( cpuLimits, period_us=100000, seconds=5 ):
server.cmd( 'iperf -s -p 5001 &' )
waitListening( client, server, 5001 )
result = client.cmd( 'iperf -yc -t %s -c %s' % (
seconds, server.IP() ) ).split( ',' )
seconds, server.IP() ) ).split( ',' )
bps = float( result[ -1 ] )
server.cmdPrint( 'kill %iperf' )
net.stop()
+6 -11
View File
@@ -10,7 +10,6 @@ import re
from mininet.cli import CLI
from mininet.log import setLogLevel, info, error
from mininet.net import Mininet
from mininet.link import Intf
from mininet.topolib import TreeTopo
from mininet.util import quietRun
@@ -22,26 +21,22 @@ def checkIntf( intf ):
ips = re.findall( r'\d+\.\d+\.\d+\.\d+', quietRun( 'ifconfig ' + intf ) )
if ips:
error( 'Error:', intf, 'has an IP address,'
'and is probably in use!\n' )
'and is probably in use!\n' )
exit( 1 )
if __name__ == '__main__':
setLogLevel( 'info' )
intfName = 'eth1'
info( '*** Checking', intfName, '\n' )
checkIntf( intfName )
newIntf = 'eth1'
info( '*** Checking', newIntf, '\n' )
checkIntf( newIntf )
info( '*** Creating network\n' )
net = Mininet( topo=TreeTopo( depth=1, fanout=2 ) )
switch = net.switches[ 0 ]
info( '*** Adding hardware interface', intfName, 'to switch',
switch.name, '\n' )
_intf = Intf( intfName, node=switch )
info( '*** Note: you may need to reconfigure the interfaces for '
'the Mininet hosts:\n', net.hosts, '\n' )
info( '*** Adding', newIntf, 'to switch', switch.name, '\n' )
switch.addIntf( newIntf )
net.start()
CLI( net )
+20 -4
View File
@@ -8,17 +8,33 @@ from mininet.net import Mininet
from mininet.link import TCIntf
from mininet.node import CPULimitedHost
from mininet.topolib import TreeTopo
from mininet.util import custom
from mininet.util import custom, quietRun
from mininet.log import setLogLevel
from time import sleep
def testLinkLimit( net, bw ):
"Run bandwidth limit test"
print '*** Testing network %.2f Mbps bandwidth limit' % bw
net.iperf( )
def testCpuLimit( net, cpu ):
"run CPU limit test"
pct = cpu * 100
print '*** Testing CPU %.0f%% bandwidth limit' % pct
h1, h2 = net.hosts
h1.cmd( 'while true; do a=1; done &' )
h2.cmd( 'while true; do a=1; done &' )
pid1 = h1.cmd( 'echo $!' ).strip()
pid2 = h2.cmd( 'echo $!' ).strip()
cmd = 'ps -p %s,%s -o pid,%%cpu,args' % ( pid1, pid2 )
# It's a shame that this is what pylint prefers
for _ in range( 5 ):
sleep( 1 )
print quietRun( cmd ).strip()
h1.cmd( 'kill %1')
h2.cmd( 'kill %1')
def limit( bw=10, cpu=.1 ):
def limit( bw=10, cpu=.4 ):
"""Example/test of link and CPU bandwidth limits
bw: interface bandwidth limit in Mbps
cpu: cpu limit as fraction of overall CPU time"""
@@ -30,7 +46,7 @@ def limit( bw=10, cpu=.1 ):
net = Mininet( topo=myTopo, intf=intf, host=host )
net.start()
testLinkLimit( net, bw=bw )
net.runCpuLimitTest( cpu=cpu )
testCpuLimit( net, cpu=cpu )
net.stop()
def verySimpleLimit( bw=150 ):
+6 -6
View File
@@ -41,22 +41,22 @@ class LinearTestTopo( Topo ):
Topo.__init__( self, **params )
# Create switches and hosts
hosts = [ self.addHost( 'h%s' % h )
hosts = [ self.add_host( 'h%s' % h )
for h in irange( 1, N ) ]
switches = [ self.addSwitch( 's%s' % s )
switches = [ self.add_switch( 's%s' % s )
for s in irange( 1, N - 1 ) ]
# Wire up switches
last = None
for switch in switches:
if last:
self.addLink( last, switch )
self.add_link( last, switch )
last = switch
# Wire up hosts
self.addLink( hosts[ 0 ], switches[ 0 ] )
self.add_link( hosts[ 0 ], switches[ 0 ] )
for host, switch in zip( hosts[ 1: ], switches ):
self.addLink( host, switch )
self.add_link( host, switch )
def linearBandwidthTest( lengths ):
@@ -68,7 +68,7 @@ def linearBandwidthTest( lengths ):
hostCount = switchCount + 1
switches = { 'reference user': UserSwitch,
'Open vSwitch kernel': OVSKernelSwitch }
'Open vSwitch kernel': OVSKernelSwitch }
topo = LinearTestTopo( hostCount )
+12 -12
View File
@@ -112,7 +112,7 @@ class MiniEdit( Frame ):
appMenu = Menu( mbar, tearoff=False )
mbar.add_cascade( label=self.appName, font=font, menu=appMenu )
appMenu.add_command( label='About MiniEdit', command=self.about,
font=font)
font=font)
appMenu.add_separator()
appMenu.add_command( label='Quit', command=self.quit, font=font )
@@ -127,7 +127,7 @@ class MiniEdit( Frame ):
editMenu = Menu( mbar, tearoff=False )
mbar.add_cascade( label="Edit", font=font, menu=editMenu )
editMenu.add_command( label="Cut", font=font,
command=lambda: self.deleteSelection( None ) )
command=lambda: self.deleteSelection( None ) )
runMenu = Menu( mbar, tearoff=False )
mbar.add_cascade( label="Run", font=font, menu=runMenu )
@@ -143,7 +143,7 @@ class MiniEdit( Frame ):
f = Frame( self )
canvas = Canvas( f, width=self.cwidth, height=self.cheight,
bg=self.bg )
bg=self.bg )
# Scroll bars
xbar = Scrollbar( f, orient='horizontal', command=canvas.xview )
@@ -177,7 +177,7 @@ class MiniEdit( Frame ):
bbox = self.canvas.bbox( 'all' )
if bbox is not None:
self.canvas.configure( scrollregion=( 0, 0, bbox[ 2 ],
bbox[ 3 ] ) )
bbox[ 3 ] ) )
def canvasx( self, x_root ):
"Convert root x coordinate to canvas coordinate."
@@ -223,7 +223,7 @@ class MiniEdit( Frame ):
for cmd, color in [ ( 'Stop', 'darkRed' ), ( 'Run', 'darkGreen' ) ]:
doCmd = getattr( self, 'do' + cmd )
b = Button( toolbar, text=cmd, font=self.smallFont,
fg=color, command=doCmd )
fg=color, command=doCmd )
b.pack( fill='x', side='bottom' )
return toolbar
@@ -289,7 +289,7 @@ class MiniEdit( Frame ):
def deleteItem( self, item ):
"Delete an item."
# Don't delete while network is running
if self.buttons[ 'Select' ][ 'state' ] == 'disabled':
if self.buttons[ 'Select' ][ 'state' ] == 'disabled' :
return
# Delete from model
if item in self.links:
@@ -308,7 +308,7 @@ class MiniEdit( Frame ):
def nodeIcon( self, node, name ):
"Create a new node icon."
icon = Button( self.canvas, image=self.images[ node ],
text=name, compound='top' )
text=name, compound='top' )
# Unfortunately bindtags wants a tuple
bindtags = [ str( self.nodeBindings ) ]
bindtags += list( icon.bindtags() )
@@ -322,8 +322,8 @@ class MiniEdit( Frame ):
self.nodeCount += 1
name = self.nodePrefixes[ node ] + str( self.nodeCount )
icon = self.nodeIcon( node, name )
item = self.canvas.create_window( x, y, anchor='c', window=icon,
tags=node )
item = self.canvas.create_window( x, y, anchor='c',
window=icon, tags=node )
self.widgetToItem[ icon ] = item
self.itemToWidget[ item ] = icon
self.selectItem( item )
@@ -437,7 +437,7 @@ class MiniEdit( Frame ):
item = self.widgetToItem[ w ]
x, y = self.canvas.coords( item )
self.link = self.canvas.create_line( x, y, x, y, width=4,
fill='blue', tag='link' )
fill='blue', tag='link' )
self.linkx, self.linky = x, y
self.linkWidget = w
self.linkItem = item
@@ -475,7 +475,7 @@ class MiniEdit( Frame ):
target = self.findItem( x, y )
dest = self.itemToWidget.get( target, None )
if ( source is None or dest is None or source == dest
or dest in source.links or source in dest.links ):
or dest in source.links or source in dest.links ):
self.releaseLink( event )
return
# For now, don't allow hosts to be directly linked
@@ -591,7 +591,7 @@ class MiniEdit( Frame ):
cleanUpScreens()
self.net = None
def xterm( self, _ignore=None ):
def xterm( self, _=None ):
"Make an xterm when a button is pressed."
if ( self.selection is None or
self.net is None or
+2 -2
View File
@@ -18,7 +18,7 @@ from time import time
def chunks( l, n ):
"Divide list l into chunks of size n - thanks Stackoverflow"
return [ l[ i: i + n ] for i in range( 0, len( l ), n ) ]
return [ l[ i : i + n ] for i in range( 0, len( l ), n ) ]
def startpings( host, targetips ):
"Tell host to repeatedly ping targets"
@@ -40,7 +40,7 @@ def startpings( host, targetips ):
'done &' )
print ( '*** Host %s (%s) will be pinging ips: %s' %
( host.name, host.IP(), targetips ) )
( host.name, host.IP(), targetips ) )
host.cmd( cmd )
+1 -1
View File
@@ -19,7 +19,7 @@ def monitorFiles( outfiles, seconds, timeoutms ):
tails, fdToFile, fdToHost = {}, {}, {}
for h, outfile in outfiles.iteritems():
tail = Popen( [ 'tail', '-f', outfile ],
stdout=PIPE, stderr=devnull )
stdout=PIPE, stderr=devnull )
fd = tail.stdout.fileno()
tails[ h ] = tail
fdToFile[ fd ] = tail.stdout
-36
View File
@@ -1,36 +0,0 @@
#!/usr/bin/python
"""
This example monitors a number of hosts using host.popen() and
pmonitor()
"""
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel
from mininet.util import custom, pmonitor
def monitorhosts( hosts=5, sched='cfs' ):
"Start a bunch of pings and monitor them using popen"
mytopo = SingleSwitchTopo( hosts )
cpu = .5 / hosts
myhost = custom( CPULimitedHost, cpu=cpu, sched=sched )
net = Mininet( topo=mytopo, host=myhost )
net.start()
# Start a bunch of pings
popens = {}
last = net.hosts[ -1 ]
for host in net.hosts:
popens[ host ] = host.popen( "ping -c5 %s" % last.IP() )
last = host
# Monitor them and print output
for host, line in pmonitor( popens ):
if host:
print "<%s>: %s" % ( host.name, line.strip() )
# Done
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
monitorhosts( hosts=5 )
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/python
"Monitor multiple hosts using popen()/pmonitor()"
from mininet.net import Mininet
from mininet.topo import SingleSwitchTopo
from mininet.util import pmonitor
from time import time
from signal import SIGINT
def pmonitorTest( N=3, seconds=10 ):
"Run pings and monitor multiple hosts using pmonitor"
topo = SingleSwitchTopo( N )
net = Mininet( topo )
net.start()
hosts = net.hosts
print "Starting test..."
server = hosts[ 0 ]
popens = {}
for h in hosts:
popens[ h ] = h.popen('ping', server.IP() )
print "Monitoring output for", seconds, "seconds"
endTime = time() + seconds
for h, line in pmonitor( popens, timeoutms=500 ):
if h:
print '%s: %s' % ( h.name, line ),
if time() >= endTime:
for p in popens.values():
p.send_signal( SIGINT )
net.stop()
if __name__ == '__main__':
pmonitorTest()
+4 -4
View File
@@ -38,12 +38,12 @@ def scratchNetUser( cname='controller', cargs='ptcp:' ):
h1intf, sintf2 = linkIntfs( h1, switch )
info( '*** Configuring control network\n' )
controller.setIP( '10.0.123.1/24', intf=cintf )
switch.setIP( '10.0.123.2/24', intf=sintf)
controller.setIP( '10.0.123.1/24', cintf )
switch.setIP( '10.0.123.2/24', sintf)
info( '*** Configuring hosts\n' )
h0.setIP( '192.168.123.1/24', intf=h0intf )
h1.setIP( '192.168.123.2/24', intf=h1intf )
h0.setIP( '192.168.123.1/24', h0intf )
h1.setIP( '192.168.123.2/24', h1intf )
info( '*** Network state:\n' )
for node in controller, switch, h0, h1:
Executable → Regular
+5 -10
View File
@@ -2,11 +2,6 @@
"""
Simple example of setting network and CPU parameters
NOTE: link params limit BW, add latency, and loss.
There is a high chance that pings WILL fail and that
iperf will hang indefinitely if the TCP handshake fails
to complete.
"""
from mininet.topo import Topo
@@ -20,14 +15,14 @@ class SingleSwitchTopo(Topo):
"Single switch connected to n hosts."
def __init__(self, n=2, **opts):
Topo.__init__(self, **opts)
switch = self.addSwitch('s1')
switch = self.add_switch('s1')
for h in range(n):
# Each host gets 50%/n of system CPU
host = self.addHost('h%s' % (h + 1),
cpu=.5 / n)
host = self.add_host('h%s' % (h + 1),
cpu=.5 / n)
# 10 Mbps, 5ms delay, 10% loss
self.addLink(host, switch,
bw=10, delay='5ms', loss=10, use_htb=True)
self.add_link(host, switch,
bw=10, delay='5ms', loss=10, use_htb=True)
def perfTest():
"Create network and run simple performance test"
+2 -2
View File
@@ -11,8 +11,8 @@ def treePing64():
results = {}
switches = { # 'reference kernel': KernelSwitch,
'reference user': UserSwitch,
'Open vSwitch kernel': OVSKernelSwitch }
'reference user': UserSwitch,
'Open vSwitch kernel': OVSKernelSwitch }
for name in switches:
print "*** Testing", name, "datapath"
+18 -50
View File
@@ -10,83 +10,51 @@ It may also get rid of 'false positives', but hopefully
nothing irreplaceable!
"""
from subprocess import Popen, PIPE, STDOUT, check_output as co
from sys import stdout, exit
from time import sleep
from subprocess import Popen, PIPE
from mininet.log import info, error
from mininet.log import info
from mininet.term import cleanUpScreens
def sh( cmd ):
"Run a command in the shell and return non-empty output lines"
"Print a command and send it to the shell"
info( cmd + '\n' )
output = ( Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE )
.communicate()[ 0 ]
.strip()
.split( '\n' ) )
return [ s for s in output if s ]
return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
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 ovs-controller udpbwtest mnexec'
zombies += 'ovs-openflowd udpbwtest'
# 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 X11 tunnels\n" )
info( "*** Removing old screen sessions\n" )
cleanUpScreens()
info( "*** Removing excess kernel datapaths\n" )
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" )
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" ).split( '\n' )
for dp in dps:
sh( 'dpctl deldp ' + dp )
if dp != '':
sh( 'dpctl deldp ' + dp )
info( "*** Removing OVS datapaths\n" )
dps = sh("ovs-vsctl list-br")
info( "*** Removing OVS datapaths" )
dps = sh("ovs-vsctl list-br").split( '\n' )
for dp in dps:
sh( 'ovs-vsctl del-br ' + dp )
if co( 'ovs-vsctl list-br', shell=True ):
raise Excpetion( "Error: could not remove all OVS datapaths" )
if dp:
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+)'" )
links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' )
for link in links:
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 )
if link != '':
sh( "ip link del " + link )
info( "*** Cleanup complete.\n" )
+8 -35
View File
@@ -30,7 +30,6 @@ from cmd import Cmd
from os import isatty
from select import poll, POLLIN
import sys
import time
from mininet.log import info, output, error
from mininet.term import makeTerms
@@ -121,12 +120,12 @@ class CLI( Cmd ):
"Run an external shell command"
call( line, shell=True )
# do_py() and do_px() need to catch any exception during eval()/exec()
# do_py() needs to catch any exception during eval()
# pylint: disable-msg=W0703
def do_py( self, line ):
"""Evaluate a Python expression.
Node names may be used, e.g.: py h1.cmd('ls')"""
Node names may be used, e.g.: h1.cmd('ls')"""
try:
result = eval( line, globals(), self.locals )
if not result:
@@ -138,18 +137,7 @@ class CLI( Cmd ):
except Exception, e:
output( str( e ) + '\n' )
# 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
# pylint: enable-msg=W0703
def do_pingall( self, _line ):
"Ping between all hosts."
@@ -159,14 +147,6 @@ class CLI( Cmd ):
"Ping between first two hosts, useful for testing."
self.mn.pingPair()
def do_pingallfull( self, _line ):
"Ping between first two hosts, returns all ping results."
self.mn.pingAllFull()
def do_pingpairfull( self, _line ):
"Ping between first two hosts, returns all ping results."
self.mn.pingPairFull()
def do_iperf( self, line ):
"Simple iperf TCP test between two (optionally specified) hosts."
args = line.split()
@@ -211,7 +191,7 @@ class CLI( Cmd ):
"List interfaces."
for node in self.nodelist:
output( '%s: %s\n' %
( node.name, ','.join( node.intfNames() ) ) )
( node.name, ','.join( node.intfNames() ) ) )
def do_dump( self, _line ):
"Dump node info."
@@ -298,13 +278,6 @@ class CLI( Cmd ):
output( '*** ' + sw.name + ' ' + ('-' * 72) + '\n' )
output( sw.dpctl( *args ) )
def do_time( self, line ):
"Measure time taken for any command in Mininet."
start = time.time()
self.onecmd(line)
elapsed = time.time() - start
self.stdout.write("*** Elapsed time: %0.6f secs\n" % elapsed)
def default( self, line ):
"""Called on an input line when the command prefix is not recognized.
Overridden to run shell commands when a node is the first CLI argument.
@@ -322,8 +295,8 @@ class CLI( Cmd ):
node = self.nodemap[ first ]
# Substitute IP addresses for node names in command
rest = [ self.nodemap[ arg ].IP()
if arg in self.nodemap else arg
for arg in rest ]
if arg in self.nodemap else arg
for arg in rest ]
rest = ' '.join( rest )
# Run cmd on node:
builtin = isShellBuiltin( first )
@@ -340,8 +313,8 @@ class CLI( Cmd ):
nodePoller = poll()
nodePoller.register( node.stdout )
bothPoller = poll()
bothPoller.register( self.stdin, POLLIN )
bothPoller.register( node.stdout, POLLIN )
bothPoller.register( self.stdin )
bothPoller.register( node.stdout )
if self.isatty():
# Buffer by character, so that interactive
# commands sort of work
+43 -64
View File
@@ -25,7 +25,7 @@ Link: basic link class for creating veth pairs
"""
from mininet.log import info, error, debug
from mininet.util import makeIntfPair, errFail, quietRun
from mininet.util import makeIntfPair
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 dev', self.name, 'name', newname )
result = self.cmd( 'ip link set', self.name, 'name', newname )
self.name = newname
self.ifconfig( 'up' )
return result
@@ -178,7 +178,7 @@ class TCIntf( Intf ):
as well as delay, loss and max queue length"""
def bwCmds( self, bw=None, speedup=0, use_hfsc=False, use_tbf=False,
latency_ms=None, enable_ecn=False, enable_red=False ):
enable_ecn=False, enable_red=False ):
"Return tc commands to set bandwidth"
cmds, parent = [], ' root '
@@ -196,63 +196,59 @@ 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 5:0 hfsc default 1',
'%s class add dev %s parent 5:0 classid 5:1 hfsc sc '
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 '
+ '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 5: tbf ' +
'rate %fMbit burst 15000 latency %fms' %
( bw, latency_ms ) ]
latency_us = 10 * 1500 * 8 / bw
cmds = ['%s qdisc add dev %s root handle 1: tbf ' +
'rate %fMbit burst 15000 latency %fus' %
( bw, latency_us ) ]
else:
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 5:1 '
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 ' +
'rate %fMbit burst 15k' % bw ]
parent = ' parent 1:1 '
# ECN or RED
if enable_ecn:
cmds += [ '%s qdisc add dev %s' + parent +
'handle 6: red limit 1000000 ' +
'min 30000 max 35000 avpkt 1500 ' +
cmds = [ '%s qdisc add dev %s' + parent +
'handle 10: red limit 1000000 ' +
'min 20000 max 25000 avpkt 1000 ' +
'burst 20 ' +
'bandwidth %fmbit probability 1 ecn' % bw ]
parent = ' parent 6: '
parent = ' parent 10: '
elif enable_red:
cmds += [ '%s qdisc add dev %s' + parent +
'handle 6: red limit 1000000 ' +
'min 30000 max 35000 avpkt 1500 ' +
cmds = [ '%s qdisc add dev %s' + parent +
'handle 10: red limit 1000000 ' +
'min 20000 max 25000 avpkt 1000 ' +
'burst 20 ' +
'bandwidth %fmbit probability 1' % bw ]
parent = ' parent 6: '
parent = ' parent 10: '
return cmds, parent
@staticmethod
def delayCmds( parent, delay=None, jitter=None,
loss=None, max_queue_size=None ):
def delayCmds( parent, delay=None, loss=None,
max_queue_size=None ):
"Internal method: return tc commands for delay and loss"
cmds = []
if delay and delay < 0:
error( 'Negative delay', delay, '\n' )
elif jitter and jitter < 0:
error( 'Negative jitter', jitter, '\n' )
elif loss and ( loss < 0 or loss > 100 ):
error( 'Bad loss percentage', loss, '%%\n' )
else:
# Delay/jitter/loss/max queue size
netemargs = '%s%s%s%s' % (
# Delay/loss/max queue size
netemargs = '%s%s%s' % (
'delay %s ' % delay if delay is not None else '',
'%s ' % jitter if jitter is not None else '',
'loss %d ' % loss if loss is not None else '',
'limit %d' % max_queue_size if max_queue_size is not None
else '' )
else '' )
if netemargs:
cmds = [ '%s qdisc add dev %s ' + parent +
' handle 10: netem ' +
netemargs ]
parent = ' parent 10:1 '
return cmds, parent
netemargs ]
return cmds
def tc( self, cmd, tc='tc' ):
"Execute tc command for our interface"
@@ -260,10 +256,9 @@ class TCIntf( Intf ):
debug(" *** executing command: %s\n" % c)
return self.cmd( c )
def config( self, bw=None, delay=None, jitter=None, loss=None,
disable_gro=True, speedup=0, use_hfsc=False, use_tbf=False,
latency_ms=None, enable_ecn=False, enable_red=False,
max_queue_size=None, **params ):
def config( self, bw=None, delay=None, loss=None, disable_gro=True,
speedup=0, use_hfsc=False, use_tbf=False, enable_ecn=False,
enable_red=False, max_queue_size=None, **params ):
"Configure the port and set its properties."
result = Intf.config( self, **params)
@@ -283,24 +278,21 @@ class TCIntf( Intf ):
# Bandwidth limits via various methods
bwcmds, parent = self.bwCmds( bw=bw, speedup=speedup,
use_hfsc=use_hfsc, use_tbf=use_tbf,
latency_ms=latency_ms,
enable_ecn=enable_ecn,
enable_red=enable_red )
use_hfsc=use_hfsc, use_tbf=use_tbf,
enable_ecn=enable_ecn,
enable_red=enable_red )
cmds += bwcmds
# Delay/jitter/loss/max_queue_size using netem
delaycmds, parent = self.delayCmds( delay=delay, jitter=jitter, loss=loss,
max_queue_size=max_queue_size,
parent=parent )
cmds += delaycmds
# Delay/loss/max_queue_size using netem
cmds += self.delayCmds( delay=delay, loss=loss,
max_queue_size=max_queue_size,
parent=parent )
# Ugly but functional: display configuration info
stuff = ( ( [ '%.2fMbit' % bw ] if bw is not None else [] ) +
( [ '%s delay' % delay ] if delay is not None else [] ) +
( [ '%s jitter' % jitter ] if jitter is not None else [] ) +
( ['%d%% loss' % loss ] if loss is not None else [] ) +
( [ 'ECN' ] if enable_ecn else [ 'RED' ]
( [ 'ECN' ] if enable_ecn else [ 'RED' ]
if enable_red else [] ) )
info( '(' + ' '.join( stuff ) + ') ' )
@@ -310,7 +302,6 @@ class TCIntf( Intf ):
debug( "cmds:", cmds, '\n' )
debug( "outputs:", tcoutputs, '\n' )
result[ 'tcoutputs'] = tcoutputs
result[ 'parent' ] = parent
return result
@@ -347,7 +338,7 @@ class Link( object ):
if not intfName2:
intfName2 = self.intfName( node2, port2 )
self.makeIntfPair( intfName1, intfName2, node1, node2 )
self.makeIntfPair( intfName1, intfName2 )
if not cls1:
cls1 = intf
@@ -372,24 +363,13 @@ class Link( object ):
return node.name + '-eth' + repr( n )
@classmethod
def makeIntfPair( cls, intf1, intf2, node1=None, node2=None ):
def makeIntfPair( cls, intf1, intf2 ):
"""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)"""
# 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 ) )
makeIntfPair( intf1, intf2 )
def delete( self ):
"Delete this link"
@@ -399,7 +379,6 @@ 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,
+6 -6
View File
@@ -11,11 +11,11 @@ import types
OUTPUT = 25
LEVELS = { 'debug': logging.DEBUG,
'info': logging.INFO,
'output': OUTPUT,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL }
'info': logging.INFO,
'output': OUTPUT,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL }
# change this to logging.INFO to get printouts when running unit tests
LOGLEVELDEFAULT = OUTPUT
@@ -117,7 +117,7 @@ class MininetLogger( Logger, object ):
Convenience function to support lowercase names.
levelName: level name from LEVELS"""
level = LOGLEVELDEFAULT
if levelname is not None:
if levelname != None:
if levelname not in LEVELS:
raise Exception( 'unknown levelname seen in setLogLevel' )
else:
+5 -5
View File
@@ -19,7 +19,7 @@ def modprobe( mod ):
return quietRun( [ 'modprobe', mod ] )
OF_KMOD = 'ofdatapath'
OVS_KMOD = 'openvswitch_mod' # Renamed 'openvswitch' in OVS 1.7+/Linux 3.5+
OVS_KMOD = 'openvswitch_mod'
TUN = 'tun'
def moduleDeps( subtract=None, add=None ):
@@ -48,8 +48,8 @@ def moduleDeps( subtract=None, add=None ):
modprobeOutput = modprobe( mod )
if modprobeOutput:
error( 'Error inserting ' + mod +
' - is it installed and available via modprobe?\n' +
'Error was: "%s"\n' % modprobeOutput )
' - is it installed and available via modprobe?\n' +
'Error was: "%s"\n' % modprobeOutput )
if mod not in lsmod():
error( 'Failed to insert ' + mod + ' - quitting.\n' )
exit( 1 )
@@ -63,6 +63,6 @@ def pathCheck( *args, **kwargs ):
for arg in args:
if not quietRun( 'which ' + arg ):
error( 'Cannot find required executable %s.\n' % arg +
'Please make sure that %s is installed ' % moduleName +
'and available in your $PATH:\n(%s)\n' % environ[ 'PATH' ] )
'Please make sure that %s is installed ' % moduleName +
'and available in your $PATH:\n(%s)\n' % environ[ 'PATH' ] )
exit( 1 )
+145
View File
@@ -0,0 +1,145 @@
from time import sleep, time
from subprocess import Popen, PIPE
from multiprocessing import Process
import re
import os
from mininet.log import info, error, debug, output
from mininet.util import quietRun
class Monitor(object):
def __init__(self, output_dir='/tmp'):
self.monitors = []
self.output_dir = output_dir
# Add general process monitors
# Bandwidth monitor
self.monitors.append(Process(target=self.monitor_devs_ng,
args=('%s/bwm.txt' % self.output_dir, 1.0)))
# CPU monitor
self.monitors.append(Process(target=self.monitor_cpu,
args=('%s/cpu.txt' % self.output_dir, )))
# cwnd monitor: tcp_probe
self.monitors.append(Process(target=self.monitor_cwnd,
args=('%s/tcp_probe.txt' % self.output_dir, )))
def start(self):
'''Start all the system monitors'''
# Set output directory
self.set_output_dir(self.output_dir)
# Start the monitors
for m in self.monitors:
m.start()
def stop(self):
'''Terminate all the system monitors'''
# Stop the monitors
for m in self.monitors:
m.terminate()
self.monitors = []
Popen("killall -9 bwm-ng top", shell=True).wait()
Popen("killall -9 cat; rmmod tcp_probe > /dev/null 2>&1;", shell=True).wait()
def set_output_dir(self, output_dir):
# Create output directory if it doesn't exist already
self.output_dir = output_dir
debug('Monitoring output dir: %s' % self.output_dir)
if not os.path.isdir(self.output_dir):
os.makedirs(self.output_dir)
def monitor_qlen(self, iface, interval_sec = 0.01, fname='%s/qlen.txt' % '.'):
pat_queued = re.compile(r'backlog\s[^\s]+\s([\d]+)p')
cmd = "tc -s qdisc show dev %s" % (iface)
ret = []
open(fname, 'w').write('')
while 1:
p = Popen(cmd, shell=True, stdout=PIPE)
output = p.stdout.read()
# Not quite right, but will do for now
matches = pat_queued.findall(output)
if matches and len(matches) > 1:
ret.append(matches[1])
t = "%f" % time()
open(fname, 'a').write(t + ',' + matches[1] + '\n')
sleep(interval_sec)
return
def monitor_cwnd(self, fname='%s/tcp_probe.txt' % '.'):
Popen("rmmod tcp_probe > /dev/null 2>&1; modprobe tcp_probe;", shell=True).wait()
Popen("cat /proc/net/tcpprobe > %s" % fname, shell=True).wait()
def monitor_devs_ng(self, fname="%s/txrate.txt" % '.', interval_sec=0.01):
"""Uses bwm-ng tool to collect iface tx rate stats. Very reliable."""
cmd = "sleep 1; bwm-ng -t %s -o csv -u bits -T rate -C ',' > %s" % (interval_sec * 1000, fname)
Popen(cmd, shell=True).wait()
def monitor_cpu(self, fname="%s/cpu.txt" % '.'):
cmd = "(top -b -p 1 -d 1 | grep --line-buffered \"^Cpu\") > %s" % fname
Popen(cmd, shell=True).wait()
def monitor_cpuacct(self, hosts, fname="%s/cpuacct.txt" % '.', interval_sec=1.0):
prereqs = ['cgget']
for p in prereqs:
if not quietRun('which ' + p):
error('Could not find %s... not monitoring cpuacct' % p)
return
hnames = ' '.join([h.name for h in hosts])
cpuacct_cmd = 'cgget -g cpuacct %s >> %s' % (hnames, fname)
prev_time = time()
while 1:
sleep(interval_sec - (time() - prev_time))
prev_time = time()
cpu_usage = Popen(cpuacct_cmd, shell=True).wait()
return
# Obsolete: Use bwm-ng instead (monitor_devs_ng), for reliable stats
def monitor_count(self, ipt_args="--src 10.0.0.0/8", interval_sec=0.01, fname='%s/bytes_sent.txt' % '.', chain="OUTPUT"):
cmd = "iptables -I %(chain)s 1 %(filter)s -j RETURN" % {
"filter": ipt_args,
"chain": chain,
}
# We always erase the first rule; will fix this later
Popen("iptables -D %s 1" % chain, shell=True).wait()
# Add our rule
Popen(cmd, shell=True).wait()
open(fname, 'w').write('')
cmd = "iptables -vnL %s 1 -Z" % (chain)
while 1:
p = Popen(cmd, shell=True, stdout=PIPE)
output = p.stdout.read().strip()
values = output.split(' ')
if len(values) > 2:
t = "%f" % time()
pkts, bytes = values[0], values[1]
open(fname, 'a').write(','.join([t, pkts, bytes]) + '\n')
sleep(interval_sec)
return
# Obsolete: Use bwm-ng instead (monitor_devs_ng), for reliable stats
def monitor_devs(self, dev_pattern='^sw', fname="%s/bytes_sent.txt" % '.', interval_sec=0.01):
"""Aggregates (sums) all txed bytes and rate (in Mbps) from devices whose name
matches @dev_pattern and writes to @fname"""
pat = re.compile(dev_pattern)
spaces = re.compile('\s+')
open(fname, 'w').write('')
prev_tx = {}
while 1:
lines = open('/proc/net/dev').read().split('\n')
t = str(time())
total = 0
for line in lines:
line = spaces.split(line.strip())
iface = line[0]
if pat.match(iface) and len(line) > 9:
tx_bytes = int(line[9])
total += tx_bytes - prev_tx.get(iface, tx_bytes)
prev_tx[iface] = tx_bytes
open(fname, 'a').write(','.join([t, str(total * 8 / interval_sec / 1e6), str(total)]) + "\n")
sleep(interval_sec)
return
+58 -181
View File
@@ -91,28 +91,27 @@ import re
import select
import signal
from time import sleep
from itertools import chain
from datetime import datetime
from multiprocessing import Process
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, errFail, fixLimits, numCores, ensureRoot
from mininet.util import quietRun, fixLimits, numCores
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
from mininet.term import cleanUpScreens, makeTerms
# Mininet version: should be consistent with README and LICENSE
VERSION = "2.0.0"
from mininet.monitor import Monitor
class Mininet( object ):
"Network emulation with hosts spawned in network namespaces."
def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
controller=Controller, link=Link, intf=Intf,
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
inNamespace=False,
autoSetMacs=False, autoStaticArp=False, autoPinCpus=False,
listenPort=None ):
controller=Controller, link=Link, intf=Intf,
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
inNamespace=False,
autoSetMacs=False, autoStaticArp=False, autoPinCpus=False,
listenPort=None ):
"""Create Mininet object.
topo: Topo (topology) object or None
switch: default Switch class
@@ -148,12 +147,12 @@ class Mininet( object ):
self.numCores = numCores()
self.nextCore = 0 # next core for pinning hosts to CPUs
self.listenPort = listenPort
self.monitoring = None
self.hosts = []
self.switches = []
self.controllers = []
self.links = []
self.nameToNode = {} # name to Node (Host/Switch) objects
self.terms = [] # list of spawned xterm processes
@@ -164,6 +163,13 @@ class Mininet( object ):
if topo and build:
self.build()
def set_debug(self, output_dir=None):
'''Enable debugging, with output to the specified directory'''
dt = datetime.now()
if not output_dir:
output_dir = '/tmp/mininet-%s-%s' % (str(dt.date()), str(dt.time()))
self.monitoring = Monitor(output_dir=output_dir)
def addHost( self, name, cls=None, **params ):
"""Add host.
name: name of host to add
@@ -173,8 +179,7 @@ class Mininet( object ):
# Default IP and MAC addresses
defaults = { 'ip': ipAdd( self.nextIP,
ipBaseNum=self.ipBaseNum,
prefixLen=self.prefixLen ) +
'/%s' % self.prefixLen }
prefixLen=self.prefixLen ) }
if self.autoSetMacs:
defaults[ 'mac'] = macColonHex( self.nextIP )
if self.autoPinCpus:
@@ -218,27 +223,14 @@ class Mininet( object ):
self.nameToNode[ name ] = controller_new
return controller_new
# BL: We now have four ways to look up nodes
# This may (should?) be cleaned up in the future.
# BL: is this better than just using nameToNode[] ?
# Should it have a better name?
def getNodeByName( self, *args ):
"Return node(s) with given name(s)"
if len( args ) == 1:
return self.nameToNode[ args[ 0 ] ]
return [ self.nameToNode[ n ] for n in args ]
def get( self, *args ):
"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
@@ -253,20 +245,13 @@ class Mininet( object ):
defaults.update( params )
if not cls:
cls = self.link
link = cls( node1, node2, **defaults )
self.links.append( link )
return link
return cls( node1, node2, **defaults )
def configHosts( self ):
"Configure a set of hosts."
for host in self.hosts:
info( host.name + ' ' )
intf = host.defaultIntf()
if intf:
host.configDefault( defaultRoute=intf )
else:
# Don't configure nonexistent intf
host.configDefault( ip=None, mac=None )
host.configDefault( defaultRoute=host.defaultIntf() )
# You're low priority, dude!
# BL: do we want to do this here or not?
# May not make sense if we have CPU lmiting...
@@ -291,11 +276,7 @@ class Mininet( object ):
if not self.controllers:
# Add a default controller
info( '*** Adding controller\n' )
classes = self.controller
if type( classes ) is not list:
classes = [ classes ]
for i, cls in enumerate( classes ):
self.addController( 'c%d' % i, cls )
self.addController( 'c0' )
info( '*** Adding hosts:\n' )
for hostName in topo.hosts():
@@ -320,7 +301,7 @@ class Mininet( object ):
def configureControlNetwork( self ):
"Control net config hook: override in subclass"
raise Exception( 'configureControlNetwork: '
'should be overriden in subclass', self )
'should be overriden in subclass', self )
def build( self ):
"Build mininet."
@@ -369,40 +350,37 @@ class Mininet( object ):
info( switch.name + ' ')
switch.start( self.controllers )
info( '\n' )
info( '*** Starting system monitor\n' )
if self.monitoring:
m = self.monitoring
m.monitors.append(Process(target=m.monitor_cpuacct,
args=(self.hosts, '%s/cpuacct.txt' % m.output_dir)))
m.start()
info( 'Logging monitoring info in: %s\n' % m.output_dir )
def stop( self ):
"Stop the controller(s), switches and hosts"
info( '*** Stopping system monitor\n' )
if self.monitoring:
self.monitoring.stop()
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' )
nses = quietRun( 'ip netns list').strip().split()
info( '*** Removing namespaces' )
for ns in nses:
errFail( 'ip netns del ' + ns )
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()
info( '\n' )
info( '\n*** Done\n' )
def run( self, test, *args, **kwargs ):
@@ -448,17 +426,16 @@ class Mininet( object ):
return (1, 0)
r = r'(\d+) packets transmitted, (\d+) received'
m = re.search( r, pingOutput )
if m is None:
if m == None:
error( '*** Error: could not parse ping output: %s\n' %
pingOutput )
pingOutput )
return (1, 0)
sent, received = int( m.group( 1 ) ), int( m.group( 2 ) )
return sent, received
def ping( self, hosts=None, timeout=None ):
def ping( self, hosts=None ):
"""Ping between all specified hosts.
hosts: list of hosts
timeout: time to wait for a response, as string
returns: ploss packet loss percentage"""
# should we check if running?
packets = 0
@@ -471,10 +448,7 @@ class Mininet( object ):
output( '%s -> ' % node.name )
for dest in hosts:
if node != dest:
opts = ''
if timeout:
opts = '-W %s' % timeout
result = node.cmd( 'ping -c1 %s %s' % (opts, dest.IP()) )
result = node.cmd( 'ping -c1 ' + dest.IP() )
sent, received = self._parsePing( result )
packets += sent
if received > sent:
@@ -490,61 +464,6 @@ class Mininet( object ):
( ploss, lost, packets ) )
return ploss
@staticmethod
def _parsePingFull( pingOutput ):
"Parse ping output and return all data."
# Check for downed link
if 'connect: Network is unreachable' in pingOutput:
return (1, 0)
r = r'(\d+) packets transmitted, (\d+) received'
m = re.search( r, pingOutput )
if m is None:
error( '*** Error: could not parse ping output: %s\n' %
pingOutput )
return (1, 0, 0, 0, 0, 0)
sent, received = int( m.group( 1 ) ), int( m.group( 2 ) )
r = r'rtt min/avg/max/mdev = '
r += r'(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+) ms'
m = re.search( r, pingOutput )
rttmin = float( m.group( 1 ) )
rttavg = float( m.group( 2 ) )
rttmax = float( m.group( 3 ) )
rttdev = float( m.group( 4 ) )
return sent, received, rttmin, rttavg, rttmax, rttdev
def pingFull( self, hosts=None, timeout=None ):
"""Ping between all specified hosts and return all data.
hosts: list of hosts
timeout: time to wait for a response, as string
returns: all ping data; see function body."""
# should we check if running?
# Each value is a tuple: (src, dsd, [all ping outputs])
all_outputs = []
if not hosts:
hosts = self.hosts
output( '*** Ping: testing ping reachability\n' )
for node in hosts:
output( '%s -> ' % node.name )
for dest in hosts:
if node != dest:
opts = ''
if timeout:
opts = '-W %s' % timeout
result = node.cmd( 'ping -c1 %s %s' % (opts, dest.IP()) )
outputs = self._parsePingFull( result )
sent, received, rttmin, rttavg, rttmax, rttdev = outputs
all_outputs.append( (node, dest, outputs) )
output( ( '%s ' % dest.name ) if received else 'X ' )
output( '\n' )
output( "*** Results: \n" )
for outputs in all_outputs:
src, dest, ping_outputs = outputs
sent, received, rttmin, rttavg, rttmax, rttdev = ping_outputs
output( " %s->%s: %s/%s, " % (src, dest, sent, received ) )
output( "rtt min/avg/max/mdev %0.3f/%0.3f/%0.3f/%0.3f ms\n" %
(rttmin, rttavg, rttmax, rttdev) )
return all_outputs
def pingAll( self ):
"""Ping between all hosts.
returns: ploss packet loss percentage"""
@@ -556,17 +475,6 @@ class Mininet( object ):
hosts = [ self.hosts[ 0 ], self.hosts[ 1 ] ]
return self.ping( hosts=hosts )
def pingAllFull( self ):
"""Ping between all hosts.
returns: ploss packet loss percentage"""
return self.pingFull()
def pingPairFull( self ):
"""Ping between first two hosts, useful for testing.
returns: ploss packet loss percentage"""
hosts = [ self.hosts[ 0 ], self.hosts[ 1 ] ]
return self.pingFull( hosts=hosts )
@staticmethod
def _parseIperf( iperfOutput ):
"""Parse iperf output and return bandwidth.
@@ -612,11 +520,11 @@ class Mininet( object ):
servout += server.monitor()
if l4Type == 'TCP':
while 'Connected' not in client.cmd(
'sh -c "echo A | telnet -e A %s 5001"' % server.IP()):
'sh -c "echo A | telnet -e A %s 5001"' % server.IP()):
output('waiting for iperf to start up...')
sleep(.5)
cliout = client.cmd( iperfArgs + '-t 5 -c ' + server.IP() + ' ' +
bwArgs )
bwArgs )
debug( 'Client output: %s\n' % cliout )
server.sendInt()
servout += server.waitOutput()
@@ -627,42 +535,6 @@ class Mininet( object ):
output( '*** Results: %s\n' % result )
return result
def runCpuLimitTest( self, cpu, duration=5 ):
"""run CPU limit test with 'while true' processes.
cpu: desired CPU fraction of each host
duration: test duration in seconds
returns a single list of measured CPU fractions as floats.
"""
pct = cpu * 100
info('*** Testing CPU %.0f%% bandwidth limit\n' % pct)
hosts = self.hosts
for h in hosts:
h.cmd( 'while true; do a=1; done &' )
pids = [h.cmd( 'echo $!' ).strip() for h in hosts]
pids_str = ",".join(["%s" % pid for pid in pids])
cmd = 'ps -p %s -o pid,%%cpu,args' % pids_str
# It's a shame that this is what pylint prefers
outputs = []
for _ in range( duration ):
sleep( 1 )
outputs.append( quietRun( cmd ).strip() )
for h in hosts:
h.cmd( 'kill %1' )
cpu_fractions = []
for test_output in outputs:
# Split by line. Ignore first line, which looks like this:
# PID %CPU COMMAND\n
for line in test_output.split('\n')[1:]:
r = r'\d+\s*(\d+\.\d+)'
m = re.search( r, line )
if m is None:
error( '*** Error: could not extract CPU fraction: %s\n' %
line )
return None
cpu_fractions.append( float( m.group( 1 ) ) )
output( '*** Results: %s\n' % cpu_fractions )
return cpu_fractions
# BL: I think this can be rewritten now that we have
# a real link class.
def configLinkStatus( self, src, dst, status ):
@@ -704,7 +576,12 @@ class Mininet( object ):
"Initialize Mininet"
if cls.inited:
return
ensureRoot()
if os.getuid() != 0:
# Note: this script must be run as root
# Probably we should only sudo when we need
# to as per Big Switch's patch
print "*** Mininet must run as root."
exit( 1 )
fixLimits()
cls.inited = True
@@ -745,7 +622,7 @@ class MininetWithControlNet( Mininet ):
# in the control network location.
def configureRoutedControlNetwork( self, ip='192.168.123.1',
prefixLen=16 ):
prefixLen=16 ):
"""Configure a routed control network on controller and switches.
For use with the user datapath only right now."""
controller = self.controllers[ 0 ]
+80 -196
View File
@@ -49,12 +49,10 @@ 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,
numCores, retry, mountCgroups )
numCores, retry, mountCgroups )
from mininet.moduledeps import moduleDeps, pathCheck, OVS_KMOD, OF_KMOD, TUN
from mininet.link import Link, Intf, TCIntf
@@ -85,8 +83,8 @@ class Node( object ):
# Make pylint happy
( self.shell, self.execed, self.pid, self.stdin, self.stdout,
self.lastPid, self.lastCmd, self.pollOut ) = (
None, None, None, None, None, None, None, None )
self.lastPid, self.lastCmd, self.pollOut ) = (
None, None, None, None, None, None, None, None )
self.waiting = False
self.readbuf = ''
@@ -109,27 +107,20 @@ 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
# bash -m: enable job control
# -s: pass $* to shell, and make process easy to find in ps
cmd = [ 'bash', '-ms', 'mininet:' + self.name ]
# mnexec: (c)lose descriptors, (d)etach from tty,
# (p)rint pid, and run in (n)amespace
opts = '-cdp'
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 )
opts += 'n'
# bash -m: enable job control
cmd = [ 'mnexec', opts, 'bash', '-m' ]
self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
close_fds=True )
self.stdin = self.shell.stdin
self.stdout = self.shell.stdout
self.pid = self.shell.pid
@@ -148,16 +139,11 @@ class Node( object ):
def cleanup( self ):
"Help python collect its garbage."
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
if not self.inNamespace:
for intfName in self.intfNames():
if self.name in intfName:
quietRun( 'ip link del ' + intfName )
self.shell = None
def read( self, maxbytes=1024 ):
"""Buffered read from node, non-blocking.
@@ -181,7 +167,7 @@ class Node( object ):
if '\n' not in self.readbuf:
return None
pos = self.readbuf.find( '\n' )
line = self.readbuf[ 0: pos ]
line = self.readbuf[ 0 : pos ]
self.readbuf = self.readbuf[ pos + 1: ]
return line
@@ -296,43 +282,6 @@ class Node( object ):
cmd: string"""
return self.cmd( *args, **{ 'verbose': True } )
def popen( self, *args, **kwargs ):
"""Return a Popen() object in our namespace
args: Popen() args, single list, or string
kwargs: Popen() keyword args"""
defaults = { 'stdout': PIPE, 'stderr': PIPE,
'mncmd':
[ 'mnexec', '-da', str( self.pid ) ] }
defaults.update( kwargs )
if len( args ) == 1:
if type( args[ 0 ] ) is list:
# popen([cmd, arg1, arg2...])
cmd = args[ 0 ]
elif type( args[ 0 ] ) is str:
# popen("cmd arg1 arg2...")
cmd = args[ 0 ].split()
else:
raise Exception( 'popen() requires a string or list' )
elif len( args ) > 0:
# popen( cmd, arg1, arg2... )
cmd = list( args )
# Attach to our namespace using mnexec -a
mncmd = defaults[ 'mncmd' ]
del defaults[ 'mncmd' ]
cmd = mncmd + cmd
# Shell requires a string, not a list!
if defaults.get( 'shell', False ):
cmd = ' '.join( cmd )
return self._popen( cmd, **defaults )
def pexec( self, *args, **kwargs ):
"""Execute a command using popen
returns: out, err, exitcode"""
popen = self.popen( *args, **kwargs)
out, err = popen.communicate()
exitcode = popen.wait()
return out, err, exitcode
# Interface management, configuration, and routing
# BL notes: This might be a bit redundant or over-complicated.
@@ -357,8 +306,10 @@ 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"
@@ -367,23 +318,17 @@ class Node( object ):
return self.intfs[ min( ports ) ]
else:
warn( '*** defaultIntf: warning:', self.name,
'has no interfaces\n' )
'has no interfaces\n' )
def intf( self, intf='' ):
"""Return our interface object with given string name,
default intf if name is falsy (None, empty string, etc).
or the input intf arg.
Having this fcn return its arg for Intf objects makes it
easier to construct functions with flexible input args for
interfaces (those that accept both string names and Intf objects).
"""
"""Return our interface object with given name,
or default intf if name is empty"""
if not intf:
return self.defaultIntf()
elif type( intf) is str:
return self.nameToIntf[ intf ]
else:
return intf
return None
def connectionsTo( self, node):
"Return [ intf1, intf2... ] for all intfs that connect self to node."
@@ -409,7 +354,6 @@ class Node( object ):
for intf in self.intfs.values():
intf.delete()
info( '.' )
stdout.flush()
# Routing support
@@ -444,7 +388,7 @@ class Node( object ):
def setIP( self, ip, prefixLen=8, intf=None ):
"""Set the IP address for an interface.
intf: intf or intf name
intf: interface name
ip: IP address as a string
prefixLen: prefix length, e.g. 8 for /8 or 16M addrs"""
# This should probably be rethought
@@ -458,7 +402,7 @@ class Node( object ):
def MAC( self, intf=None ):
"Return MAC address of a node or specific interface."
return self.intf( intf ).MAC()
return self.intf( intf ).IP()
def intfIsUp( self, intf=None ):
"Check if an interface is up."
@@ -532,9 +476,9 @@ class Node( object ):
def __repr__( self ):
"More informative string representation"
intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() )
for i in self.intfList() ] ) )
for i in self.intfList() ] ) )
return '<%s %s: %s pid=%s> ' % (
self.__class__.__name__, self.name, intfs, self.pid )
self.__class__.__name__, self.name, intfs, self.pid )
def __str__( self ):
"Abbreviated string representation"
@@ -585,7 +529,6 @@ class CPULimitedHost( Host ):
# still does better with larger period values.
self.period_us = kwargs.get( 'period_us', 100000 )
self.sched = sched
self.rtprio = 20
def cgroupSet( self, param, value, resource='cpu' ):
"Set a cgroup parameter and return its value"
@@ -610,24 +553,13 @@ class CPULimitedHost( Host ):
_out, _err, exitcode = errRun( 'cgdelete -r ' + self.cgroup )
return exitcode != 0
def popen( self, *args, **kwargs ):
"""Return a Popen() object in node's namespace
args: Popen() args, single list, or string
kwargs: Popen() keyword args"""
# Tell mnexec to execute command in our cgroup
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"
retry( retries=3, delaySecs=1, fn=self.cgroupDel )
def chrt( self ):
def chrt( self, prio=20 ):
"Set RT scheduling priority"
quietRun( 'chrt -p %s %s' % ( self.rtprio, self.pid ) )
quietRun( 'chrt -p %s %s' % ( prio, self.pid ) )
result = quietRun( 'chrt -p %s' % self.pid )
firstline = result.split( '\n' )[ 0 ]
lastword = firstline.split( ' ' )[ -1 ]
@@ -686,7 +618,7 @@ class CPULimitedHost( Host ):
self.cgroupSet( qstr, quota )
if sched == 'rt':
# Set RT priority if necessary
self.chrt()
self.chrt( prio=20 )
info( '(%s %d/%dus) ' % ( sched, quota, period ) )
def setCPUs( self, cores, mems=0 ):
@@ -702,7 +634,7 @@ class CPULimitedHost( Host ):
# We have to do this here after we've specified
# cpus and mems
errFail( 'cgclassify -g cpuset:/%s %s' % (
self.name, self.pid ) )
self.name, self.pid ) )
def config( self, cpu=None, cores=None, **params ):
"""cpu: desired overall system CPU fraction
@@ -749,10 +681,9 @@ class Switch( Node ):
an OpenFlow switch."""
portBase = 1 # Switches start with port 1 in OpenFlow
dpidLen = 16 # digits in dpid passed to switch
def __init__( self, name, dpid=None, opts='', listenPort=None, **params):
"""dpid: dpid for switch (or None to derive from name, e.g. s1 -> 1)
"""dpid: dpid for switch (or None for default)
opts: additional switch options
listenPort: port to listen on for dpctl connections"""
Node.__init__( self, name, **params )
@@ -764,15 +695,10 @@ class Switch( Node ):
def defaultDpid( self ):
"Derive dpid from switch name, s1 -> 1"
try:
dpid = int( re.findall( '\d+', self.name )[ 0 ] )
dpid = hex( dpid )[ 2: ]
dpid = '0' * ( self.dpidLen - len( dpid ) ) + dpid
return dpid
except IndexError:
raise Exception( 'Unable to derive default datapath ID - '
'please either specify a dpid or use a '
'canonical switch name such as s23.' )
dpid = int( re.findall( '\d+', self.name )[ 0 ] )
dpid = hex( dpid )[ 2: ]
dpid = '0' * ( 16 - len( dpid ) ) + dpid
return dpid
def defaultIntf( self ):
"Return control interface"
@@ -789,27 +715,24 @@ class Switch( Node ):
return Node.sendCmd( self, *cmd, **kwargs )
else:
error( '*** Error: %s has execed and cannot accept commands' %
self.name )
self.name )
def __repr__( self ):
"More informative string representation"
intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() )
for i in self.intfList() ] ) )
for i in self.intfList() ] ) )
return '<%s %s: %s pid=%s> ' % (
self.__class__.__name__, self.name, intfs, self.pid )
self.__class__.__name__, self.name, intfs, self.pid )
class UserSwitch( Switch ):
"User-space switch."
dpidLen = 12
def __init__( self, name, **kwargs ):
"""Init.
name: name for the switch"""
Switch.__init__( self, name, **kwargs )
pathCheck( 'ofdatapath', 'ofprotocol',
moduleName='the OpenFlow reference user switch' +
'(openflow.org)' )
moduleName='the OpenFlow reference user switch (openflow.org)' )
if self.listenPort:
self.opts += ' --listen=ptcp:%i ' % self.listenPort
@@ -830,27 +753,25 @@ class UserSwitch( Switch ):
"""Start OpenFlow reference user datapath.
Log to /tmp/sN-{ofd,ofp}.log.
controllers: list of controller objects"""
# Add controllers
clist = ','.join( [ 'tcp:%s:%d' % ( c.IP(), c.port )
for c in controllers ] )
controller = controllers[ 0 ]
ofdlog = '/tmp/' + self.name + '-ofd.log'
ofplog = '/tmp/' + self.name + '-ofp.log'
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 +
' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
' punix:/tmp/' + self.name + ' -d ' + self.dpid +
' --no-slicing ' +
' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
self.cmd( 'ofprotocol unix:/tmp/' + self.name +
' ' + clist +
' --fail=closed ' + self.opts +
' 1> ' + ofplog + ' 2>' + ofplog + ' &' )
' tcp:%s:%d' % ( controller.IP(), controller.port ) +
' --fail=closed ' + self.opts +
' 1> ' + ofplog + ' 2>' + ofplog + ' &' )
def stop( self, deleteIntfs=True ):
def stop( self ):
"Stop OpenFlow reference user datapath."
self.cmd( 'kill %ofdatapath' )
self.cmd( 'kill %ofprotocol' )
if deleteIntfs:
self.deleteIntfs()
self.deleteIntfs()
class OVSLegacyKernelSwitch( Switch ):
@@ -867,14 +788,14 @@ class OVSLegacyKernelSwitch( Switch ):
self.intf = self.dp
if self.inNamespace:
error( "OVSKernelSwitch currently only works"
" in the root namespace.\n" )
" in the root namespace.\n" )
exit( 1 )
@classmethod
def setup( cls ):
"Ensure any dependencies are loaded; if not, try to load them."
pathCheck( 'ovs-dpctl', 'ovs-openflowd',
moduleName='Open vSwitch (openvswitch.org)')
moduleName='Open vSwitch (openvswitch.org)')
moduleDeps( subtract=OF_KMOD, add=OVS_KMOD )
def start( self, controllers ):
@@ -888,21 +809,19 @@ class OVSLegacyKernelSwitch( Switch ):
intfs = [ str( i ) for i in self.intfList() if not i.IP() ]
self.cmd( 'ovs-dpctl', 'add-if', self.dp, ' '.join( intfs ) )
# Run protocol daemon
clist = ','.join( [ 'tcp:%s:%d' % ( c.IP(), c.port )
for c in controllers ] )
controller = controllers[ 0 ]
self.cmd( 'ovs-openflowd ' + self.dp +
' ' + clist +
' --fail=secure ' + self.opts +
' --datapath-id=' + self.dpid +
' 1>' + ofplog + ' 2>' + ofplog + '&' )
' tcp:%s:%d' % ( controller.IP(), controller.port ) +
' --fail=secure ' + self.opts +
' --datapath-id=' + self.dpid +
' 1>' + ofplog + ' 2>' + ofplog + '&' )
self.execed = False
def stop( self, deleteIntfs=True ):
def stop( self ):
"Terminate kernel datapath."
quietRun( 'ovs-dpctl del-dp ' + self.dp )
self.cmd( 'kill %ovs-openflowd' )
if deleteIntfs:
self.deleteIntfs()
self.deleteIntfs()
class OVSSwitch( Switch ):
@@ -919,10 +838,8 @@ class OVSSwitch( Switch ):
def setup( cls ):
"Make sure Open vSwitch is installed and working"
pathCheck( 'ovs-vsctl',
moduleName='Open vSwitch (openvswitch.org)')
# This should no longer be needed, and it breaks
# with OVS 1.7 which has renamed the kernel module:
# moduleDeps( subtract=OF_KMOD, add=OVS_KMOD )
moduleName='Open vSwitch (openvswitch.org)')
moduleDeps( subtract=OF_KMOD, add=OVS_KMOD )
out, err, exitcode = errRun( 'ovs-vsctl -t 1 show' )
if exitcode:
error( out + err +
@@ -968,24 +885,19 @@ 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 )
self.cmd( 'ovs-vsctl -- set Bridge', self,
'other_config:datapath-id=' + self.dpid )
self.cmd( 'ovs-vsctl set-fail-mode', self, self.failMode )
for intf in self.intfList():
if not intf.IP():
self.attach( intf )
# Add controllers
clist = ' '.join( [ 'tcp:%s:%d' % ( c.IP(), c.port )
clist = ','.join( [ 'tcp:%s:%d' % ( c.IP(), c.port )
for c in controllers ] )
if self.listenPort:
clist += ' ptcp:%s' % self.listenPort
self.cmd( 'ovs-vsctl set-controller', self, clist )
def stop( self, deleteIntfs=True ):
"Stop OVS switch."
def stop( self ):
"Terminate OVS switch."
self.cmd( 'ovs-vsctl del-br', self )
if deleteIntfs:
self.deleteIntfs()
self.deleteIntfs()
OVSKernelSwitch = OVSSwitch
@@ -995,35 +907,15 @@ class Controller( Node ):
OpenFlow controller."""
def __init__( self, name, inNamespace=False, command='controller',
cargs='-v ptcp:%d', cdir=None, ip="127.0.0.1",
port=6633, **params ):
cargs='-v ptcp:%d', cdir=None, ip="127.0.0.1",
port=6633, **params ):
self.command = command
self.cargs = cargs
self.cdir = cdir
self.ip = ip
self.port = port
Node.__init__( self, name, inNamespace=inNamespace,
ip=ip, **params )
self.cmd( 'ifconfig lo up' ) # Shouldn't be necessary
self.checkListening()
def checkListening( self ):
"Make sure no controllers are running on our port"
# Verify that Telnet is installed first:
out, _err, returnCode = errRun( "which telnet" )
if 'telnet' not in out or returnCode != 0:
raise Exception( "Error running telnet to check for listening "
"controllers; please check that it is "
"installed." )
listening = self.cmd( "echo A | telnet -e A %s %d" %
( self.ip, self.port ) )
if 'Unable' not in listening:
servers = self.cmd( 'netstat -atp' ).split( '\n' )
pstr = ':%d ' % self.port
clist = servers[ 0:1 ] + [ s for s in servers if pstr in s ]
raise Exception( "Please shut down the controller which is"
" running on port %d:\n" % self.port +
'\n'.join( clist ) )
ip=ip, **params )
def start( self ):
"""Start <controller> <args> on controller.
@@ -1033,7 +925,7 @@ class Controller( Node ):
if self.cdir is not None:
self.cmd( 'cd ' + self.cdir )
self.cmd( self.command + ' ' + self.cargs % self.port +
' 1>' + cout + ' 2>' + cout + '&' )
' 1>' + cout + ' 2>' + cout + '&' )
self.execed = False
def stop( self ):
@@ -1052,8 +944,8 @@ class Controller( Node ):
def __repr__( self ):
"More informative string representation"
return '<%s %s: %s:%s pid=%s> ' % (
self.__class__.__name__, self.name,
self.IP(), self.port, self.pid )
self.__class__.__name__, self.name,
self.IP(), self.port, self.pid )
class OVSController( Controller ):
@@ -1081,24 +973,24 @@ class NOX( Controller ):
noxCoreDir = os.environ[ 'NOX_CORE_DIR' ]
Controller.__init__( self, name,
command=noxCoreDir + '/nox_core',
cargs='--libdir=/usr/local/lib -v -i ptcp:%s ' +
' '.join( noxArgs ),
cdir=noxCoreDir,
**kwargs )
command=noxCoreDir + '/nox_core',
cargs='--libdir=/usr/local/lib -v -i ptcp:%s ' +
' '.join( noxArgs ),
cdir=noxCoreDir, **kwargs )
class RemoteController( Controller ):
"Controller running outside of Mininet's control."
def __init__( self, name, ip='127.0.0.1',
port=6633, **kwargs):
def __init__( self, name, defaultIP='127.0.0.1',
port=6633, **kwargs):
"""Init.
name: name to give controller
ip: the IP address where the remote controller is
defaultIP: the IP address where the remote controller is
listening
port: the port where the remote controller is listening"""
Controller.__init__( self, name, ip=ip, port=port, **kwargs )
Controller.__init__( self, name, defaultIP=defaultIP, port=port,
**kwargs )
def start( self ):
"Overridden to do nothing."
@@ -1107,11 +999,3 @@ class RemoteController( Controller ):
def stop( self ):
"Overridden to do nothing."
return
def checkListening( self ):
"Warn if remote controller is not accessible"
listening = self.cmd( "echo A | telnet -e A %s %d" %
( self.ip, self.port ) )
if 'Unable' in listening:
warn( "Unable to contact the remote controller"
" at %s:%d\n" % ( self.ip, self.port ) )
+32 -39
View File
@@ -1,67 +1,60 @@
"""
Terminal creation and cleanup.
Utility functions to run a terminal (connected via socat(1)) on each host.
Utility functions to run a term (connected via screen(1)) on each host.
Requires socat(1) and xterm(1).
Requires GNU screen(1) and xterm(1).
Optionally uses gnome-terminal.
"""
from os import environ
import re
from subprocess import Popen
from mininet.log import error
from mininet.util import quietRun, errRun
from mininet.util import quietRun
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 quoteArg( arg ):
"Quote an argument if it contains spaces."
return repr( arg ) if ' ' in arg else arg
def makeTerm( node, title='Node', term='xterm', display=None ):
"""Create an X11 tunnel to the node and start up a terminal.
def makeTerm( node, title='Node', term='xterm' ):
"""Run screen on a node, and hook up a terminal.
node: Node object
title: base title
term: 'xterm' or 'gterm'
returns: two Popen objects, tunnel and terminal"""
returns: process created"""
title += ': ' + node.name
if not node.inNamespace:
title += ' (root)'
cmds = {
'xterm': [ 'xterm', '-title', title, '-display' ],
'gterm': [ 'gnome-terminal', '--title', title, '--display' ]
'xterm': [ 'xterm', '-title', title, '-e' ],
'gterm': [ 'gnome-terminal', '--title', title, '-e' ]
}
if term not in cmds:
error( 'invalid terminal type: %s' % term )
return
display, tunnel = tunnelX11( node, display )
term = node.popen( cmds[ term ] + [ display, '-e', 'env TERM=ansi bash'] )
return [ tunnel, term ] if tunnel else [ term ]
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 )
def cleanUpScreens():
"Remove moldy socat X11 tunnels."
errRun( "pkill -9 -f mnexec.*socat" )
"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' )
def makeTerms( nodes, title='Node', term='xterm' ):
"""Create terminals.
nodes: list of Node objects
title: base title for each
returns: list of created tunnel/terminal processes"""
terms = []
for node in nodes:
terms += makeTerm( node, title, term )
return terms
returns: list of created terminal processes"""
return [ makeTerm( node, title, term ) for node in nodes ]
-127
View File
@@ -1,127 +0,0 @@
#!/usr/bin/env python
"""Package: mininet
Test creation and pings for topologies with link and/or CPU options."""
import unittest
from mininet.net import Mininet
from mininet.node import OVSKernelSwitch
from mininet.node import CPULimitedHost
from mininet.link import TCLink
from mininet.topo import Topo
from mininet.log import setLogLevel
SWITCH = OVSKernelSwitch
# Number of hosts for each test
N = 2
class SingleSwitchOptionsTopo(Topo):
"Single switch connected to n hosts."
def __init__(self, n=2, hopts=None, lopts=None):
if not hopts:
hopts = {}
if not lopts:
lopts = {}
Topo.__init__(self, hopts=hopts, lopts=lopts)
switch = self.addSwitch('s1')
for h in range(n):
host = self.addHost('h%s' % (h + 1))
self.addLink(host, switch)
class testOptionsTopo( unittest.TestCase ):
"Verify ability to create networks with host and link options."
def runOptionsTopoTest( self, n, hopts=None, lopts=None ):
"Generic topology-with-options test runner."
mn = Mininet( topo=SingleSwitchOptionsTopo( n=n, hopts=hopts,
lopts=lopts ),
host=CPULimitedHost, link=TCLink )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
def assertWithinTolerance(self, measured, expected, tolerance_frac):
"""Check that a given value is within a tolerance of expected
tolerance_frac: less-than-1.0 value; 0.8 would yield 20% tolerance.
"""
self.assertTrue( float(measured) >= float(expected) * tolerance_frac )
self.assertTrue( float(measured) >= float(expected) * tolerance_frac )
def testCPULimits( self ):
"Verify topology creation with CPU limits set for both schedulers."
CPU_FRACTION = 0.1
CPU_TOLERANCE = 0.8 # CPU fraction below which test should fail
hopts = { 'cpu': CPU_FRACTION }
#self.runOptionsTopoTest( N, hopts=hopts )
mn = Mininet( SingleSwitchOptionsTopo( n=N, hopts=hopts ),
host=CPULimitedHost )
mn.start()
results = mn.runCpuLimitTest( cpu=CPU_FRACTION )
mn.stop()
for cpu in results:
self.assertWithinTolerance( cpu, CPU_FRACTION, CPU_TOLERANCE )
def testLinkBandwidth( self ):
"Verify that link bandwidths are accurate within a bound."
BW = 5 # Mbps
BW_TOLERANCE = 0.8 # BW fraction below which test should fail
# Verify ability to create limited-link topo first;
lopts = { 'bw': BW, 'use_htb': True }
# Also verify correctness of limit limitng within a bound.
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
link=TCLink )
bw_strs = mn.run( mn.iperf )
for bw_str in bw_strs:
bw = float( bw_str.split(' ')[0] )
self.assertWithinTolerance( bw, BW, BW_TOLERANCE )
def testLinkDelay( self ):
"Verify that link delays are accurate within a bound."
DELAY_MS = 15
DELAY_TOLERANCE = 0.8 # Delay fraction below which test should fail
lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True }
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
link=TCLink )
ping_delays = mn.run( mn.pingFull )
test_outputs = ping_delays[0]
# Ignore unused variables below
# pylint: disable-msg=W0612
node, dest, ping_outputs = test_outputs
sent, received, rttmin, rttavg, rttmax, rttdev = ping_outputs
self.assertEqual( sent, received )
# pylint: enable-msg=W0612
for rttval in [rttmin, rttavg, rttmax]:
# Multiply delay by 4 to cover there & back on two links
self.assertWithinTolerance( rttval, DELAY_MS * 4.0,
DELAY_TOLERANCE)
def testLinkLoss( self ):
"Verify that we see packet drops with a high configured loss rate."
LOSS_PERCENT = 99
REPS = 1
lopts = { 'loss': LOSS_PERCENT, 'use_htb': True }
mn = Mininet( topo=SingleSwitchOptionsTopo( n=N, lopts=lopts ),
host=CPULimitedHost, link=TCLink )
# Drops are probabilistic, but the chance of no dropped packets is
# 1 in 100 million with 4 hops for a link w/99% loss.
dropped_total = 0
mn.start()
for _ in range(REPS):
dropped_total += mn.ping(timeout='1')
mn.stop()
self.assertTrue(dropped_total > 0)
def testMostOptions( self ):
"Verify topology creation with most link options and CPU limits."
lopts = { 'bw': 10, 'delay': '5ms', 'use_htb': True }
hopts = { 'cpu': 0.5 / N }
self.runOptionsTopoTest( N, hopts=hopts, lopts=lopts )
if __name__ == '__main__':
setLogLevel( 'warning' )
unittest.main()
+26 -31
View File
@@ -34,7 +34,7 @@ class Topo(object):
self.lopts = {} if lopts is None else lopts
self.ports = {} # ports[src][dst] is port on src that connects to dst
def addNode(self, name, **opts):
def add_node(self, name, **opts):
"""Add Node to graph.
name: name
opts: node options
@@ -43,40 +43,40 @@ class Topo(object):
self.node_info[name] = opts
return name
def addHost(self, name, **opts):
def add_host(self, name, **opts):
"""Convenience method: Add host to graph.
name: host name
opts: host options
returns: host name"""
if not opts and self.hopts:
opts = self.hopts
return self.addNode(name, **opts)
return self.add_node(name, **opts)
def addSwitch(self, name, **opts):
def add_switch(self, name, **opts):
"""Convenience method: Add switch to graph.
name: switch name
opts: switch options
returns: switch name"""
if not opts and self.sopts:
opts = self.sopts
result = self.addNode(name, isSwitch=True, **opts)
result = self.add_node(name, is_switch=True, **opts)
return result
def addLink(self, node1, node2, port1=None, port2=None,
**opts):
def add_link(self, node1, node2, port1=None, port2=None,
**opts):
"""node1, node2: nodes to link together
port1, port2: ports (optional)
opts: link options (optional)
returns: link info key"""
if not opts and self.lopts:
opts = self.lopts
self.addPort(node1, node2, port1, port2)
self.add_port(node1, node2, port1, port2)
key = tuple(self.sorted([node1, node2]))
self.link_info[key] = opts
self.g.add_edge(*key)
return key
def addPort(self, src, dst, sport=None, dport=None):
def add_port(self, src, dst, sport=None, dport=None):
'''Generate port mapping for new edge.
@param src source switch name
@param dst destination switch name
@@ -84,8 +84,8 @@ class Topo(object):
self.ports.setdefault(src, {})
self.ports.setdefault(dst, {})
# New port: number of outlinks + base
src_base = 1 if self.isSwitch(src) else 0
dst_base = 1 if self.isSwitch(dst) else 0
src_base = 1 if self.is_switch(src) else 0
dst_base = 1 if self.is_switch(dst) else 0
if sport is None:
sport = len(self.ports[src]) + src_base
if dport is None:
@@ -100,24 +100,24 @@ class Topo(object):
else:
return self.g.nodes()
def isSwitch(self, n):
def is_switch(self, n):
'''Returns true if node is a switch.'''
info = self.node_info[n]
return info and info.get('isSwitch', False)
return info and info.get('is_switch', False)
def switches(self, sort=True):
'''Return switches.
sort: sort switches alphabetically
@return dpids list of dpids
'''
return [n for n in self.nodes(sort) if self.isSwitch(n)]
return [n for n in self.nodes(sort) if self.is_switch(n)]
def hosts(self, sort=True):
'''Return hosts.
sort: sort hosts alphabetically
@return dpids list of dpids
'''
return [n for n in self.nodes(sort) if not self.isSwitch(n)]
return [n for n in self.nodes(sort) if not self.is_switch(n)]
def links(self, sort=True):
'''Return links.
@@ -148,11 +148,6 @@ class Topo(object):
src, dst = self.sorted([src, dst])
return self.link_info[(src, dst)]
def setlinkInfo( self, src, dst, info ):
"Set link metadata"
src, dst = self.sorted([src, dst])
self.link_info[(src, dst)] = info
def nodeInfo( self, name ):
"Return metadata (dict) for node"
info = self.node_info[ name ]
@@ -180,10 +175,10 @@ class SingleSwitchTopo(Topo):
self.k = k
switch = self.addSwitch('s1')
switch = self.add_switch('s1')
for h in irange(1, k):
host = self.addHost('h%s' % h)
self.addLink(host, switch)
host = self.add_host('h%s' % h)
self.add_link(host, switch)
class SingleSwitchReversedTopo(Topo):
@@ -201,11 +196,11 @@ class SingleSwitchReversedTopo(Topo):
'''
super(SingleSwitchReversedTopo, self).__init__(**opts)
self.k = k
switch = self.addSwitch('s1')
switch = self.add_switch('s1')
for h in irange(1, k):
host = self.addHost('h%s' % h)
self.addLink(host, switch,
port1=0, port2=(k - h + 1))
host = self.add_host('h%s' % h)
self.add_link(host, switch,
port1=0, port2=(k - h + 1))
class LinearTopo(Topo):
"Linear topology of k switches, with one host per switch."
@@ -222,9 +217,9 @@ class LinearTopo(Topo):
lastSwitch = None
for i in irange(1, k):
host = self.addHost('h%s' % i)
switch = self.addSwitch('s%s' % i)
self.addLink( host, switch)
host = self.add_host('h%s' % i)
switch = self.add_switch('s%s' % i)
self.add_link( host, switch)
if lastSwitch:
self.addLink( switch, lastSwitch)
self.add_link( switch, lastSwitch)
lastSwitch = switch
+3 -3
View File
@@ -19,13 +19,13 @@ class TreeTopo( Topo ):
returns: last node added"""
isSwitch = depth > 0
if isSwitch:
node = self.addSwitch( 's%s' % self.switchNum )
node = self.add_switch( 's%s' % self.switchNum )
self.switchNum += 1
for _ in range( fanout ):
child = self.addTree( depth - 1, fanout )
self.addLink( node, child )
self.add_link( node, child )
else:
node = self.addHost( 'h%s' % self.hostNum )
node = self.add_host( 'h%s' % self.hostNum )
self.hostNum += 1
return node
+34 -153
View File
@@ -1,15 +1,11 @@
"Utility functions for Mininet."
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, POLLHUP
from select import poll, POLLIN
from subprocess import call, check_call, Popen, PIPE, STDOUT
from mininet.log import output, info, error
import re
from fcntl import fcntl, F_GETFL, F_SETFL
from os import O_NONBLOCK
import os
# Command execution support
@@ -47,13 +43,13 @@ def oldQuietRun( *cmd ):
break
out += data
popen.poll()
if popen.returncode is not None:
if popen.returncode != None:
break
return out
# This is a bit complicated, but it enables us to
# monitor command output as it is happening
# monitor commount output as it is happening
def errRun( *cmd, **kwargs ):
"""Run a command and return stdout, stderr and return code
@@ -75,33 +71,31 @@ def errRun( *cmd, **kwargs ):
# cmd goes to stderr, output goes to stdout
info( cmd, '\n' )
popen = Popen( cmd, stdout=PIPE, stderr=stderr, shell=shell )
# We use poll() because select() doesn't work with large fd numbers,
# and thus communicate() doesn't work either
# We use poll() because select() doesn't work with large fd numbers
out, err = '', ''
poller = poll()
poller.register( popen.stdout, POLLIN )
fdtofile = { popen.stdout.fileno(): popen.stdout }
outDone, errDone = False, True
if popen.stderr:
fdtofile[ popen.stderr.fileno() ] = popen.stderr
poller.register( popen.stderr, POLLIN )
errDone = False
while not outDone or not errDone:
while True:
readable = poller.poll()
for fd, _event in readable:
# Tell pylint to ignore unused variable event
# pylint: disable-msg=W0612
for fd, event in readable:
# pylint: enable-msg=W0612
f = fdtofile[ fd ]
data = f.read( 1024 )
if echo:
output( data )
if f == popen.stdout:
out += data
if data == '':
outDone = True
elif f == popen.stderr:
err += data
if data == '':
errDone = True
returncode = popen.wait()
returncode = popen.poll()
if returncode is not None:
break
return out, err, returncode
def errFail( *cmd, **kwargs ):
@@ -117,7 +111,7 @@ def quietRun( cmd, **kwargs ):
return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ]
# pylint: enable-msg=E1103
# pylint: disable-msg=E1101
# pylint: disable-msg=E1101,W0612
def isShellBuiltin( cmd ):
"Return True if cmd is a bash builtin."
@@ -130,7 +124,7 @@ def isShellBuiltin( cmd ):
isShellBuiltin.builtIns = None
# pylint: enable-msg=E1101
# pylint: enable-msg=E1101,W0612
# Interface management
#
@@ -171,35 +165,27 @@ def retry( retries, delaySecs, fn, *args, **keywords ):
error( "*** gave up after %i retries\n" % tries )
exit( 1 )
def moveIntfNoRetry( intf, dstNode, srcNode=None, printError=False ):
def moveIntfNoRetry( intf, node, printError=False ):
"""Move interface to node, without retrying.
intf: string, interface
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' )
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' )
if not ( ' %s:' % intf ) in links:
if printError:
error( '*** Error: moveIntf: ' + intf +
' not successfully moved to ' + dstNode.name + '\n' )
' not successfully moved to ' + node.name + '\n' )
return False
return True
def moveIntf( intf, dstNode, srcNode=None, printError=False,
retries=3, delaySecs=0.001 ):
def moveIntf( intf, node, printError=False, retries=3, delaySecs=0.001 ):
"""Move interface to node, retrying on failure.
intf: string, interface
dstNode: destination Node
srcNode: source Node or None (default) for root ns
node: Node object
printError: if true, print error"""
retry( retries, delaySecs, moveIntfNoRetry, intf, dstNode,
srcNode=srcNode, printError=printError )
retry( retries, delaySecs, moveIntfNoRetry, intf, node, printError )
# Support for dumping network
@@ -232,7 +218,7 @@ def dumpNetConnections( net ):
def _colonHex( val, bytecount ):
"""Generate colon-hex string.
val: input as unsigned int
bytecount: number of bytes to convert
bytescount: number of bytes to convert
returns: chStr colon-hex string"""
pieces = []
for i in range( bytecount - 1, -1, -1 ):
@@ -250,8 +236,9 @@ 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"""
returns: ip address string w.x.y.z, or 10.x.y.z if w==0"""
w = ( ip >> 24 ) & 0xff
w = 10 if w == 0 else w
x = ( ip >> 16 ) & 0xff
y = ( ip >> 8 ) & 0xff
z = ip & 0xff
@@ -260,7 +247,7 @@ def ipStr( ip ):
def ipNum( w, x, y, z ):
"""Generate unsigned int from components of IP address
returns: w << 24 | x << 16 | y << 8 | z"""
return ( w << 24 ) | ( x << 16 ) | ( y << 8 ) | z
return ( w << 24 ) | ( x << 16 ) | ( y << 8 ) | z
def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ):
"""Return IP address string from ints
@@ -268,10 +255,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"""
imax = 0xffffffff >> prefixLen
assert i <= imax
mask = 0xffffffff ^ imax
ipnum = ( ipBaseNum & mask ) + i
# Ugly but functional
assert i < ( 1 << ( 32 - prefixLen ) )
mask = 0xffffffff ^ ( ( 1 << prefixLen ) - 1 )
ipnum = i + ( ipBaseNum & mask )
return ipStr( ipnum )
def ipParse( ip ):
@@ -313,46 +300,6 @@ def makeNumeric( s ):
else:
return s
# Popen support
def pmonitor(popens, timeoutms=500, readline=True,
readmax=1024 ):
"""Monitor dict of hosts to popen objects
a line at a time
timeoutms: timeout for poll()
readline: return single line of output
yields: host, line/output (if any)
terminates: when all EOFs received"""
poller = poll()
fdToHost = {}
for host, popen in popens.iteritems():
fd = popen.stdout.fileno()
fdToHost[ fd ] = host
poller.register( fd, POLLIN )
if not readline:
# Use non-blocking reads
flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
while popens:
fds = poller.poll( timeoutms )
if fds:
for fd, event in fds:
host = fdToHost[ fd ]
popen = popens[ host ]
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
elif event & POLLHUP:
poller.unregister( fd )
del popens[ host ]
else:
yield None, ''
# Other stuff we use
@@ -366,8 +313,7 @@ def mountCgroups():
mounts = quietRun( 'mount' )
cgdir = '/sys/fs/cgroup'
csdir = cgdir + '/cpuset'
if ('cgroup on %s' % cgdir not in mounts and
'cgroups on %s' % cgdir not in mounts):
if 'cgroups on %s' % cgdir not in mounts:
raise Exception( "cgroups not mounted on " + cgdir )
if 'cpuset on %s' % csdir not in mounts:
errRun( 'mkdir -p ' + csdir )
@@ -401,73 +347,8 @@ def irange(start, end):
def custom( cls, **params ):
"Returns customized constructor for class cls."
# Note: we may wish to see if we can use functools.partial() here
# and in customConstructor
def customized( *args, **kwargs):
"Customized constructor"
kwargs = kwargs.copy()
kwargs.update( params )
return cls( *args, **kwargs )
customized.__name__ = 'custom(%s,%s)' % ( cls, params )
return customized
def splitArgs( argstr ):
"""Split argument string into usable python arguments
argstr: argument string with format fn,arg2,kw1=arg3...
returns: fn, args, kwargs"""
split = argstr.split( ',' )
fn = split[ 0 ]
params = split[ 1: ]
# Convert int and float args; removes the need for function
# to be flexible with input arg formats.
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( '=' )
kwargs[ key ] = makeNumeric( val )
return fn, args, kwargs
def customConstructor( constructors, argStr ):
"""Return custom constructor based on argStr
The args and key/val pairs in argsStr will be automatically applied
when the generated constructor is later used.
"""
cname, newargs, kwargs = splitArgs( argStr )
constructor = constructors.get( cname, None )
if not constructor:
raise Exception( "error: %s is unknown - please specify one of %s" %
( cname, constructors.keys() ) )
def customized( name, *args, **params ):
"Customized constructor, useful for Node, Link, and other classes"
params = params.copy()
params.update( kwargs )
if not newargs:
return constructor( name, *args, **params )
if args:
warn( 'warning: %s replacing %s with %s\n' % (
constructor, args, newargs ) )
return constructor( name, *newargs, **params )
customized.__name__ = 'customConstructor(%s)' % argStr
return customized
def buildTopo( topos, topoStr ):
"""Create topology from string with format (object, arg1, arg2,...).
input topos is a dict of topo names to constructors, possibly w/args.
"""
topo, args, kwargs = splitArgs( topoStr )
if topo not in topos:
raise Exception( 'Invalid topo name %s' % topo )
return topos[ topo ]( *args, **kwargs )
def ensureRoot():
"""Ensure that we are running as root.
Probably we should only sudo when needed as per Big Switch's patch.
"""
if os.getuid() != 0:
print "*** Mininet must run as root."
exit( 1 )
return
+13 -113
View File
@@ -7,8 +7,6 @@
* - detaching from a controlling tty using setsid
* - running in a network namespace
* - printing out the pid of a process so we can identify it later
* - attaching to a namespace and cgroup
* - setting RT scheduling
*
* Partially based on public domain setsid(1)
*/
@@ -16,89 +14,23 @@
#include <stdio.h>
#include <linux/sched.h>
#include <unistd.h>
#include <limits.h>
#include <syscall.h>
#include <fcntl.h>
#include <stdlib.h>
#include <limits.h>
#include <sched.h>
#if !defined(VERSION)
#define VERSION "(devel)"
#endif
void usage(char *name)
{
printf("Execution utility for Mininet\n\n"
"Usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n\n"
"Options:\n"
" -c: close all file descriptors except stdin/out/error\n"
" -d: detach from tty by calling setsid()\n"
" -n: run in new network namespace\n"
" -p: print ^A + pid\n"
" -a pid: attach to pid's network namespace\n"
" -g group: add to cgroup\n"
" -r rtprio: run with SCHED_RR (usually requires -g)\n"
" -v: print version\n",
name);
}
int setns(int fd, int nstype)
{
return syscall(__NR_setns, fd, nstype);
}
/* Validate alphanumeric path foo1/bar2/baz */
void validate(char *path)
{
char *s;
for (s=path; *s; s++) {
if (!isalnum(*s) && *s != '/') {
fprintf(stderr, "invalid path: %s\n", path);
exit(1);
}
}
}
/* Add our pid to cgroup */
int cgroup(char *gname)
{
static char path[PATH_MAX];
static char *groups[] = {
"cpu", "cpuacct", "cpuset", NULL
};
char **gptr;
pid_t pid = getpid();
int count = 0;
validate(gname);
for (gptr = groups; *gptr; gptr++) {
FILE *f;
snprintf(path, PATH_MAX, "/sys/fs/cgroup/%s/%s/tasks",
*gptr, gname);
f = fopen(path, "w");
if (f) {
count++;
fprintf(f, "%d\n", pid);
fclose(f);
}
}
if (!count) {
fprintf(stderr, "cgroup: could not add to cgroup %s\n",
gname);
exit(1);
}
printf("Execution utility for Mininet.\n"
"usage: %s [-cdnp]\n"
"-c: close all file descriptors except stdin/out/error\n"
"-d: detach from tty by calling setsid()\n"
"-n: run in new network namespace\n"
"-p: print ^A + pid\n", name);
}
int main(int argc, char *argv[])
{
char c;
int fd;
char path[PATH_MAX];
int nsid;
int pid;
static struct sched_param sp;
while ((c = getopt(argc, argv, "+cdnpa:g:r:vh")) != -1)
while ((c = getopt(argc, argv, "+cdnp")) != -1)
switch(c) {
case 'c':
/* close file descriptors except stdin/out/error */
@@ -132,48 +64,16 @@ int main(int argc, char *argv[])
printf("\001%d\n", getpid());
fflush(stdout);
break;
case 'a':
/* Attach to pid's network namespace */
pid = atoi(optarg);
sprintf(path, "/proc/%d/ns/net", pid );
nsid = open(path, O_RDONLY);
if (nsid < 0) {
perror(path);
return 1;
}
if (setns(nsid, 0) != 0) {
perror("setns");
return 1;
}
break;
case 'g':
/* Attach to cgroup */
cgroup(optarg);
break;
case 'r':
/* Set RT scheduling priority */
sp.sched_priority = atoi(optarg);
if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
perror("sched_setscheduler");
return 1;
}
break;
case 'v':
printf("%s\n", VERSION);
exit(0);
case 'h':
usage(argv[0]);
exit(0);
default:
usage(argv[0]);
exit(1);
break;
}
if (optind < argc) {
execvp(argv[optind], &argv[optind]);
perror(argv[optind]);
return 1;
}
execvp(argv[optind], &argv[optind]);
perror(argv[optind]);
return 1;
}
usage(argv[0]);
}
+7 -15
View File
@@ -5,37 +5,29 @@
from setuptools import setup, find_packages
from os.path import join
# Get version number from source tree
import sys
sys.path.append( '.' )
from mininet.net import VERSION
scripts = [ join( 'bin', filename ) for filename in [ 'mn' ] ]
modname = distname = 'mininet'
setup(
name=distname,
version=VERSION,
version='0.0.0',
description='Process-based OpenFlow emulator',
author='Bob Lantz',
author_email='rlantz@cs.stanford.edu',
packages=find_packages(exclude='test'),
long_description="""
Mininet is a network emulator which uses lightweight
virtualization to create virtual networks for rapid
prototyping of Software-Defined Network (SDN) designs
using OpenFlow. http://openflow.org/mininet
""",
Insert longer description here.
""",
classifiers=[
"License :: OSI Approved :: BSD License",
"License :: OSI Approved :: GNU General Public License (GPL)",
"Programming Language :: Python",
"Development Status :: 2 - Pre-Alpha",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Topic :: Internet",
],
keywords='networking emulator protocol Internet OpenFlow SDN',
license='BSD',
keywords='networking protocol Internet OpenFlow',
license='unspecified',
install_requires=[
'setuptools',
'networkx'
+62 -185
View File
@@ -5,7 +5,7 @@
# Fail on error
set -e
# Fail on unset var usage
set -o nounset
@@ -33,7 +33,7 @@ if [ "$DIST" = "Ubuntu" ] || [ "$DIST" = "Debian" ]; then
fi
if ! which bc &> /dev/null; then
$install bc
fi
fi
fi
if which lsb_release &> /dev/null; then
DIST=`lsb_release -is`
@@ -97,11 +97,11 @@ function kernel {
if ! test -e /boot/initrd.img-${KERNEL_NAME}; then
sudo update-initramfs -c -k ${KERNEL_NAME}
fi
# Ensure /boot/grub/menu.lst boots with initrd image:
sudo update-grub
# The default should be the new kernel. Otherwise, you may need to modify
# The default should be the new kernel. Otherwise, you may need to modify
# /boot/grub/menu.lst to set the default to the entry corresponding to the
# kernel you just installed.
fi
@@ -122,24 +122,21 @@ function kernel_clean {
# Install Mininet deps
function mn_deps {
echo "Installing Mininet dependencies"
$install gcc make socat psmisc xterm ssh iperf iproute telnet \
python-setuptools python-networkx cgroup-bin ethtool help2man \
pyflakes pylint pep8
$install gcc make screen psmisc xterm ssh iperf iproute \
python-setuptools python-networkx cgroup-bin ethtool
if [ "$DIST" = "Ubuntu" ] && [ "$RELEASE" = "10.04" ]; then
echo "Upgrading networkx to avoid deprecation warning"
sudo easy_install --upgrade networkx
fi
# Add sysctl parameters as noted in the INSTALL file to increase kernel
# Add sysctl parameters as noted in the INSTALL file to increase kernel
# limits to support larger setups:
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
sudo su -c "cat $HOME/mininet/util/sysctl_addon >> /etc/sysctl.conf"
# Load new sysctl settings:
sudo sysctl -p
echo "Installing Mininet core"
pushd ~/mininet
sudo make install
@@ -155,7 +152,7 @@ function of {
echo "Installing OpenFlow reference implementation..."
cd ~/
$install git-core autoconf automake autotools-dev pkg-config \
make gcc libtool libc6-dev
make gcc libtool libc6-dev
git clone git://openflowswitch.org/openflow.git
cd ~/openflow
@@ -167,51 +164,32 @@ function of {
./configure
make
sudo make install
cd ~
}
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
# Remove avahi-daemon, which may cause unwanted discovery packets to be
# sent during tests, near link status changes:
$remove avahi-daemon
if [ ! -d "ofsoftswitch13" ]; then
git clone https://github.com/CPqD/ofsoftswitch13.git
# Disable IPv6. Add to /etc/modprobe.d/blacklist:
if [ "$DIST" = "Ubuntu" ]; then
BLACKLIST=/etc/modprobe.d/blacklist.conf
else
BLACKLIST=/etc/modprobe.d/blacklist
fi
# 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
sudo sh -c "echo 'blacklist net-pf-10\nblacklist ipv6' >> $BLACKLIST"
cd ~
}
function wireshark {
echo "Installing Wireshark dissector..."
sudo apt-get install -y wireshark tshark libgtk2.0-dev
sudo apt-get install -y wireshark 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 ~
hg clone https://bitbucket.org/barnstorm/of-dissector
hg clone https://bitbucket.org/onlab/of-dissector
cd of-dissector/src
export WIRESHARK=/usr/include/wireshark
scons
@@ -235,19 +213,16 @@ function wireshark {
# Install Open vSwitch
# Instructions derived from OVS INSTALL, INSTALL.OpenFlow and README files.
function ovs {
echo "Installing Open vSwitch..."
# Required for module build/dkms install
$install $KERNEL_HEADERS
ovspresent=0
# First see if we have packages
# XXX wget -c seems to fail from github/amazon s3
cd /tmp
if wget $OVS_PACKAGE_LOC/$OVS_PACKAGE_NAME 2> /dev/null; then
if wget $OVS_PACKAGE_LOC/$OVS_PACKAGE_NAME; then
$install patch dkms fakeroot python-argparse
tar xf $OVS_PACKAGE_NAME
orig=`tar tf $OVS_PACKAGE_NAME`
@@ -259,11 +234,21 @@ function ovs {
# Annoyingly, things seem to be missing without this flag
$pkginst --force-confmiss $pkg
done
ovspresent=1
# Switch can run on its own, but
# Mininet should control the controller
if [ -e /etc/init.d/openvswitch-controller ]; then
if sudo service openvswitch-controller stop; then
echo "Stopped running controller"
fi
sudo update-rc.d openvswitch-controller disable
fi
echo "Done (hopefully) installing packages"
cd ~
return
fi
# Otherwise try distribution's OVS packages
if [ "$DIST" = "Ubuntu" ] && [ `expr $RELEASE '>=' 11.10` = 1 ]; then
if [ "$DIST" = "Ubuntu" ] && [ `echo "$RELEASE >= 11.10" | bc` = 1 ]; then
if ! dpkg --get-selections | grep openvswitch-datapath; then
# If you've already installed a datapath, assume you
# know what you're doing and don't need dkms datapath.
@@ -271,28 +256,10 @@ function ovs {
$install openvswitch-datapath-dkms
fi
if $install openvswitch-switch openvswitch-controller; then
echo "Ignoring error installing openvswitch-controller"
return
fi
ovspresent=1
fi
# Switch can run on its own, but
# Mininet should control the controller
if [ -e /etc/init.d/openvswitch-controller ]; then
if sudo service openvswitch-controller stop; then
echo "Stopped running controller"
fi
sudo update-rc.d openvswitch-controller disable
fi
if [ $ovspresent = 1 ]; then
echo "Done (hopefully) installing packages"
cd ~
return
fi
# Otherwise attempt to install from source
$install pkg-config gcc make python-dev libssl-dev libtool
if [ "$DIST" = "Debian" ]; then
@@ -307,7 +274,7 @@ function ovs {
fi
else
$install git
fi
fi
# Install OVS from release
cd ~/
@@ -361,7 +328,7 @@ function nox {
if [ "$DIST" = "Debian" ]; then
$install libboost1.35-dev
elif [ "$DIST" = "Ubuntu" ]; then
$install python-dev libboost-dev
$install python-dev libboost-dev
$install libboost-filesystem-dev
$install libboost-test-dev
fi
@@ -370,18 +337,13 @@ function nox {
# Fetch NOX destiny
cd ~/
git clone https://github.com/noxrepo/nox-classic.git noxcore
git clone git://noxrepo.org/nox noxcore
cd noxcore
if ! git checkout -b destiny remotes/origin/destiny ; then
echo "Did not check out a new destiny branch - assuming current branch is destiny"
fi
git checkout -b destiny remotes/origin/destiny
# Apply patches
git checkout -b tutorial-destiny
git am ~/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
fi
git am ~/mininet/util/nox-patches/*.patch
# Build
./boot.sh
@@ -399,47 +361,6 @@ 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..."
cd ~
git clone https://github.com/noxrepo/pox.git
}
# Install OFtest
function oftest {
echo "Installing oftest..."
@@ -449,14 +370,17 @@ function oftest {
# Install oftest:
cd ~/
git clone git://github.com/floodlight/oftest
git clone git://openflow.org/oftest
cd oftest
cd tools/munger
sudo make install
}
# Install cbench
function cbench {
echo "Installing cbench..."
$install libsnmp-dev libpcap-dev libconfig-dev
$install libsnmp-dev libpcap-dev
cd ~/
git clone git://openflow.org/oflops.git
cd oflops
@@ -468,45 +392,14 @@ function cbench {
}
function 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
echo "Doing other setup tasks..."
# Enable command auto completion using sudo; modify ~/.bashrc:
sed -i -e 's|# for examples$|&\ncomplete -cf sudo|' ~/.bashrc
# Install tcpdump, cmd-line packet dump tool. Also install gitk,
# Install tcpdump and tshark, cmd-line packet dump tools. Also install gitk,
# a graphical git history viewer.
$install tcpdump gitk
$install tcpdump tshark gitk
# Install common text editors
$install vim nano emacs
@@ -549,9 +442,7 @@ function all {
of
wireshark
ovs
# NOX-classic is deprecated, but you can install it manually if desired.
# nox
pox
nox
oftest
cbench
other
@@ -588,11 +479,11 @@ function vm_clean {
}
function usage {
printf '\nUsage: %s [-abcdfhkmnprtvwx03]\n\n' $(basename $0) >&2
printf 'Usage: %s [-acdfhkmntvxy]\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 11.10+\n' >&2
printf 'If you run into trouble, try\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 'installing one thing at a time, and looking at the \n' >&2
printf 'specific installation function in this script.\n\n' >&2
@@ -600,57 +491,43 @@ function usage {
printf -- ' -a: (default) install (A)ll packages - good luck!\n' >&2
printf -- ' -b: install controller (B)enchmark (oflops)\n' >&2
printf -- ' -c: (C)lean up after kernel install\n' >&2
printf -- ' -d: (D)elete some sensitive files from a VM image\n' >&2
printf -- ' -d: (D)elete some sensitive files from a VM image\n' >&2
printf -- ' -f: install open(F)low\n' >&2
printf -- ' -h: print this (H)elp message\n' >&2
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) 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 -- ' -x: install NO(X) OpenFlow controller\n' >&2
printf -- ' -y: install (A)ll packages\n' >&2
exit 2
}
OF_VERSION=1.0
if [ $# -eq 0 ]
then
all
else
while getopts 'abcdfhkmnprtvwx03' OPTION
while getopts 'abcdfhkmnrtvwx' OPTION
do
case $OPTION in
a) all;;
b) cbench;;
c) kernel_clean;;
d) vm_clean;;
f) case $OF_VERSION in
1.0) of;;
1.3) of13;;
*) echo "Invalid OpenFlow version $OF_VERSION";;
esac;;
f) of;;
h) usage;;
k) kernel;;
m) modprobe;;
n) mn_deps;;
p) pox;;
r) remove_ovs;;
t) other;;
v) ovs;;
w) wireshark;;
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;;
x) nox;;
?) usage;;
esac
done
-26
View File
@@ -1,26 +0,0 @@
#!/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
@@ -1,175 +0,0 @@
From 166693d7cb640d4a41251b87e92c52d9c688196b Mon Sep 17 00:00:00 2001
From: Bob Lantz <rlantz@cs.stanford.edu>
Date: Mon, 14 May 2012 15:30:44 -0700
Subject: [PATCH] Hacks to get NOX classic/destiny to compile under Ubuntu
12.04
Thanks to Srinivasu R. Kanduru for the initial patch.
Apologies for the hacks - it is my hope that this will be fixed
upstream eventually.
---
config/ac_pkg_swig.m4 | 7 ++++---
src/Make.vars | 2 +-
src/nox/coreapps/pyrt/deferredcallback.cc | 2 +-
src/nox/coreapps/pyrt/pyglue.cc | 2 +-
src/nox/coreapps/pyrt/pyrt.cc | 2 +-
src/nox/netapps/authenticator/auth.i | 2 ++
src/nox/netapps/authenticator/flow_util.i | 1 +
src/nox/netapps/routing/routing.i | 2 ++
.../switch_management/pyswitch_management.i | 2 ++
src/nox/netapps/tests/tests.cc | 2 +-
src/nox/netapps/topology/pytopology.i | 2 ++
11 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/config/ac_pkg_swig.m4 b/config/ac_pkg_swig.m4
index d12556e..9b608f2 100644
--- a/config/ac_pkg_swig.m4
+++ b/config/ac_pkg_swig.m4
@@ -78,9 +78,10 @@ AC_DEFUN([AC_PROG_SWIG],[
if test -z "$available_patch" ; then
[available_patch=0]
fi
- if test $available_major -ne $required_major \
- -o $available_minor -ne $required_minor \
- -o $available_patch -lt $required_patch ; then
+ major_done=`test $available_major -gt $required_major`
+ minor_done=`test $available_minor -gt $required_minor`
+ if test !$major_done -a !$minor_done \
+ -a $available_patch -lt $required_patch ; then
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version. You should look at http://www.swig.org])
SWIG=''
else
diff --git a/src/Make.vars b/src/Make.vars
index d70d6aa..93b2879 100644
--- a/src/Make.vars
+++ b/src/Make.vars
@@ -53,7 +53,7 @@ AM_LDFLAGS += -export-dynamic
endif
# set python runtimefiles to be installed in the same directory as pkg
-pkglib_SCRIPTS = $(NOX_RUNTIMEFILES) $(NOX_PYBUILDFILES)
+pkgdata_SCRIPTS = $(NOX_RUNTIMEFILES) $(NOX_PYBUILDFILES)
BUILT_SOURCES = $(NOX_PYBUILDFILES)
# Runtime-files build and clean rules
diff --git a/src/nox/coreapps/pyrt/deferredcallback.cc b/src/nox/coreapps/pyrt/deferredcallback.cc
index 3a40fa7..111a586 100644
--- a/src/nox/coreapps/pyrt/deferredcallback.cc
+++ b/src/nox/coreapps/pyrt/deferredcallback.cc
@@ -69,7 +69,7 @@ DeferredCallback::get_instance(const Callback& c)
DeferredCallback* cb = new DeferredCallback(c);
// flag as used in *_wrap.cc....correct?
- return SWIG_Python_NewPointerObj(cb, s, SWIG_POINTER_OWN | 0);
+ return SWIG_Python_NewPointerObj(m, cb, s, SWIG_POINTER_OWN | 0);
}
bool
diff --git a/src/nox/coreapps/pyrt/pyglue.cc b/src/nox/coreapps/pyrt/pyglue.cc
index 48b9716..317fd04 100644
--- a/src/nox/coreapps/pyrt/pyglue.cc
+++ b/src/nox/coreapps/pyrt/pyglue.cc
@@ -874,7 +874,7 @@ to_python(const Flow& flow)
if (!s) {
throw std::runtime_error("Could not find Flow SWIG type_info");
}
- return SWIG_Python_NewPointerObj(f, s, SWIG_POINTER_OWN | 0);
+ return SWIG_Python_NewPointerObj(m, f, s, SWIG_POINTER_OWN | 0);
// PyObject* dict = PyDict_New();
// if (!dict) {
diff --git a/src/nox/coreapps/pyrt/pyrt.cc b/src/nox/coreapps/pyrt/pyrt.cc
index fbda461..8ec05d6 100644
--- a/src/nox/coreapps/pyrt/pyrt.cc
+++ b/src/nox/coreapps/pyrt/pyrt.cc
@@ -776,7 +776,7 @@ Python_event_manager::create_python_context(const Context* ctxt,
pretty_print_python_exception());
}
- PyObject* pyctxt = SWIG_Python_NewPointerObj(p, s, 0);
+ PyObject* pyctxt = SWIG_Python_NewPointerObj(m, p, s, 0);
Py_INCREF(pyctxt); // XXX needed?
//Py_DECREF(m);
diff --git a/src/nox/netapps/authenticator/auth.i b/src/nox/netapps/authenticator/auth.i
index 1de1a17..bfa04e2 100644
--- a/src/nox/netapps/authenticator/auth.i
+++ b/src/nox/netapps/authenticator/auth.i
@@ -18,6 +18,8 @@
%module "nox.netapps.authenticator.pyauth"
+// Hack to get it to compile -BL
+%include "std_list.i"
%{
#include "core_events.hh"
#include "pyrt/pycontext.hh"
diff --git a/src/nox/netapps/authenticator/flow_util.i b/src/nox/netapps/authenticator/flow_util.i
index f67c3ef..2a314e2 100644
--- a/src/nox/netapps/authenticator/flow_util.i
+++ b/src/nox/netapps/authenticator/flow_util.i
@@ -32,6 +32,7 @@ using namespace vigil::applications;
%}
%include "common-defs.i"
+%include "std_list.i"
%import "netinet/netinet.i"
%import "pyrt/event.i"
diff --git a/src/nox/netapps/routing/routing.i b/src/nox/netapps/routing/routing.i
index 44ccb3d..f9221a2 100644
--- a/src/nox/netapps/routing/routing.i
+++ b/src/nox/netapps/routing/routing.i
@@ -17,6 +17,8 @@
*/
%module "nox.netapps.routing.pyrouting"
+// Hack to get it to compile -BL
+%include "std_list.i"
%{
#include "pyrouting.hh"
#include "routing.hh"
diff --git a/src/nox/netapps/switch_management/pyswitch_management.i b/src/nox/netapps/switch_management/pyswitch_management.i
index 72bfed4..ad2c90d 100644
--- a/src/nox/netapps/switch_management/pyswitch_management.i
+++ b/src/nox/netapps/switch_management/pyswitch_management.i
@@ -18,6 +18,8 @@
%module "nox.netapps.pyswitch_management"
+// Hack to get it to compile -BL
+%include "std_list.i"
%{
#include "switch_management_proxy.hh"
#include "pyrt/pycontext.hh"
diff --git a/src/nox/netapps/tests/tests.cc b/src/nox/netapps/tests/tests.cc
index 20e900d..f027028 100644
--- a/src/nox/netapps/tests/tests.cc
+++ b/src/nox/netapps/tests/tests.cc
@@ -306,7 +306,7 @@ private:
throw runtime_error("Could not find PyContext SWIG type_info.");
}
- PyObject* pyctxt = SWIG_Python_NewPointerObj(p, s, 0);
+ PyObject* pyctxt = SWIG_Python_NewPointerObj(m, p, s, 0);
assert(pyctxt);
Py_DECREF(m);
diff --git a/src/nox/netapps/topology/pytopology.i b/src/nox/netapps/topology/pytopology.i
index 94a9f4b..7a8cd94 100644
--- a/src/nox/netapps/topology/pytopology.i
+++ b/src/nox/netapps/topology/pytopology.i
@@ -18,6 +18,8 @@
%module "nox.netapps.topology"
+// Hack to get it to compile -BL
+%include "std_list.i"
%{
#include "pytopology.hh"
#include "pyrt/pycontext.hh"
--
1.7.5.4
+1 -2
View File
@@ -1,2 +1 @@
0001: This patch adds the OpenFlow tutorial module source code to nox-destiny.
0002: This patch hacks nox-destiny to compile on Ubuntu 12.04.
This patch adds the OpenFlow tutorial module source code to nox-destiny.
-11
View File
@@ -1,11 +0,0 @@
obj-m = sch_htb.o
KVERSION = $(shell uname -r)
all:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
install:
test -e /lib/modules/$(KVERSION)/kernel/net/sched/sch_htb.ko.bak || mv /lib/modules/$(KVERSION)/kernel/net/sched/sch_htb.ko /lib/modules/$(KVERSION)/kernel/net/sched/sch_htb.ko.bak
cp sch_htb.ko /lib/modules/$(KVERSION)/kernel/net/sched/sch_htb.ko
rmmod sch_htb
modprobe sch_htb
clean:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
-10
View File
@@ -1,10 +0,0 @@
Modified sch_htb implementation with ofbuf support.
To compile, just type make. To use this module instead
of regular sch_htb, do:
0. make
1. rmmod sch_htb
2. insmod ./sch_htb.ko
To revert, just rmmod sch_htb.
File diff suppressed because it is too large Load Diff
-1
View File
@@ -15,4 +15,3 @@ net.ipv4.neigh.default.gc_thresh3 = 16384
# Mininet: increase routing table size
net.ipv4.route.max_size=32768
-24
View File
@@ -1,24 +0,0 @@
#!/usr/bin/python
from subprocess import check_output as co
from sys import exit
# Actually run bin/mn rather than importing via python path
version = 'Mininet ' + co( 'PYTHONPATH=. bin/mn --version', shell=True )
version = version.strip()
# Find all Mininet path references
lines = co( "grep -or 'Mininet \w\.\w\.\w\w*' *", shell=True )
error = False
for line in lines.split( '\n' ):
if line and 'Binary' not in line:
fname, fversion = line.split( ':' )
if version != fversion:
print "%s: incorrect version '%s' (should be '%s')" % (
fname, fversion, version )
error = True
if error:
exit( 1 )
Executable → Regular
+10 -14
View File
@@ -1,10 +1,13 @@
#!/bin/bash
# This script is intended to install Mininet into
# a brand-new Ubuntu virtual machine,
# a brand-new Ubuntu (10.04 or 11.10) virtual machine,
# to create a fully usable "tutorial" VM.
set -e
echo `whoami` ALL=NOPASSWD: ALL | sudo tee -a /etc/sudoers
sudo sh -c 'cat >> /etc/sudoers' <<EOF
openflow ALL=NOPASSWD: ALL
EOF
sudo sed -i -e 's/Default/#Default/' /etc/sudoers
sudo sed -i -e 's/ubuntu/mininet-vm/' /etc/hostname
sudo sed -i -e 's/ubuntu/mininet-vm/g' /etc/hosts
@@ -14,23 +17,16 @@ sudo update-grub
sudo sed -i -e 's/us.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
sudo mv /etc/issue.backup /etc/issue
fi
if [ -e /etc/rc.local.backup ]; then
sudo mv /etc/rc.local.backup /etc/rc.local
fi
# Install Mininet
sudo apt-get -y install git-core openssh-server
git clone git://github.com/mininet/mininet
cd mininet
# Check out branch for cs244
git checkout -b cs244 origin/class/cs244
cd
time mininet/util/install.sh
# Ignoring this since NOX classic is deprecated
#if ! grep NOX_CORE_DIR .bashrc; then
# echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc
#fi
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