Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ca49a78de | |||
| c703bafd9c | |||
| a2f659de57 | |||
| 4a08ccdf5a | |||
| 6525cd90bd |
@@ -1 +0,0 @@
|
||||
*.py diff=python
|
||||
+2
-8
@@ -1,14 +1,8 @@
|
||||
mnexec
|
||||
*.pyc
|
||||
*~
|
||||
*.1
|
||||
*.xcodeproj
|
||||
*.xcworkspace
|
||||
\#*\#
|
||||
mininet.egg-info
|
||||
build
|
||||
dist
|
||||
doc/html
|
||||
doc/latex
|
||||
trunk
|
||||
build/*
|
||||
dist/*
|
||||
|
||||
|
||||
@@ -1,54 +1,29 @@
|
||||
|
||||
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 (3).
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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!
|
||||
|
||||
To install Mininet itself (i.e. mn and the Python API) on Ubuntu 12.10+
|
||||
|
||||
sudo apt-get install mininet
|
||||
|
||||
Note: if you are upgrading from an older version of Mininet, make sure you
|
||||
remove the old OVS from /usr/local:
|
||||
|
||||
sudo rm /usr/local/bin/ovs*
|
||||
sudo rm /usr/local/sbin/ovs*
|
||||
|
||||
3. Native installation from source on Ubuntu 11.10+
|
||||
|
||||
If you're reading this, you've probably already done so, but the command to
|
||||
download the Mininet source code is;
|
||||
|
||||
git clone git://openflow.org/mininet.git
|
||||
|
||||
If you are running Ubuntu, you may be able to use our handy install.sh script,
|
||||
which is in mininet/util.
|
||||
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.
|
||||
|
||||
WARNING: USE AT YOUR OWN RISK!
|
||||
|
||||
@@ -59,59 +34,240 @@ do anything completely terrible, you may want to look at the script
|
||||
before you run it, and you should make sure your system and home
|
||||
directory are backed up just in case!
|
||||
|
||||
To install Mininet itself, the OpenFlow reference implementation, and
|
||||
Open vSwitch, you may use:
|
||||
|
||||
$ mininet/util/install.sh -fnv
|
||||
|
||||
This should be reasonably quick and the following command should work
|
||||
after the installation:
|
||||
|
||||
$ sudo mn --test pingall
|
||||
|
||||
To install ALL of the software which we use for OpenFlow tutorials,
|
||||
including NOX classic, the OpenFlow WireShark dissector, the oftest
|
||||
framework, and other potentially useful software (and to add some stuff
|
||||
to /etc/sysctl.conf which may or may not be useful) you may use
|
||||
you may use
|
||||
|
||||
$ mininet/util/install.sh -a
|
||||
$ mininet/util/install.sh
|
||||
|
||||
This takes about 20 minutes on our test system.
|
||||
This takes about 20-30 minutes.
|
||||
|
||||
4. Creating your own Mininet/OpenFlow tutorial VM
|
||||
Alternately, you can install just the pieces you need.
|
||||
|
||||
Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial
|
||||
is easy! First, create a new Ubuntu VM. Then, run
|
||||
We recommend the following steps, in order:
|
||||
|
||||
$ wget https://raw.github.com/mininet/mininet/util/vm/install-mininet-vm.sh
|
||||
$ time install-mininet-vm.sh
|
||||
[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.]
|
||||
|
||||
5. Installation on other Linux distributions
|
||||
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
|
||||
|
||||
Although we don't support other Linux distributions directly, it should be
|
||||
possible to install and run Mininet with some degree of manual effort.
|
||||
d) Install Open vSwitch and its kernel module
|
||||
$ mininet/util/install.sh -vm
|
||||
|
||||
In general, you must have:
|
||||
e) If you wish to install the version of NOX we use in the tutorial:
|
||||
$ mininet/util/install.sh -x
|
||||
|
||||
* A Linux kernel compiled with network namespace support enabled
|
||||
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.
|
||||
|
||||
* 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.
|
||||
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.
|
||||
|
||||
* Python, `bash`, `ping`, `iperf`, etc.
|
||||
|
||||
* Root privileges (required for network device access)
|
||||
|
||||
We encourage contribution of patches to the `install.sh` script to support
|
||||
other Linux distributions.
|
||||
|
||||
Good luck!
|
||||
|
||||
Mininet Team
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
Mininet Manual Installation Notes
|
||||
|
||||
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.)
|
||||
|
||||
If you wish to try to create a VM to run Mininet, you may also wish
|
||||
to look at the Wiki page:
|
||||
|
||||
http://openflow.org/foswiki/bin/view/OpenFlow/MininetVMCreationNotes
|
||||
|
||||
0. Obtaining Mininet
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
To install Mininet itself, with root privileges:
|
||||
|
||||
# cd mininet
|
||||
# make install
|
||||
|
||||
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
|
||||
|
||||
2. Installation script for Ubuntu/Debian Lenny
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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!
|
||||
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -12,39 +12,35 @@ 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 makeNumeric, custom, customConstructor, splitArgs
|
||||
from mininet.util import buildTopo
|
||||
|
||||
|
||||
# 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 +48,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,13 +62,10 @@ 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',
|
||||
'prefixlen': 'prefixLen' }
|
||||
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
|
||||
'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' }
|
||||
|
||||
|
||||
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
|
||||
@@ -84,21 +77,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."
|
||||
|
||||
@@ -146,14 +134,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' )
|
||||
@@ -161,42 +142,39 @@ 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( '--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' )
|
||||
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()
|
||||
|
||||
|
||||
+24
-13
@@ -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() ) }
|
||||
|
||||
Vendored
-13
@@ -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
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
9
|
||||
Vendored
-30
@@ -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
|
||||
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.
|
||||
Vendored
-37
@@ -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
@@ -1 +0,0 @@
|
||||
README.md
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
examples/*
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
mnexec /usr/bin
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
*.1
|
||||
Vendored
-12
@@ -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
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
3.0 (quilt)
|
||||
Vendored
-3
@@ -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)
|
||||
@@ -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.
|
||||
@@ -21,24 +21,11 @@ controllers.py:
|
||||
|
||||
This example creates a network and adds multiple controllers to it.
|
||||
|
||||
cpu.py:
|
||||
|
||||
This example tests iperf bandwidth for varying CPU limits.
|
||||
|
||||
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
|
||||
@@ -61,11 +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
|
||||
|
||||
@@ -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
@@ -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' )
|
||||
|
||||
+2
-2
@@ -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
@@ -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
@@ -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 ):
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -14,12 +14,32 @@ from subprocess import Popen, PIPE
|
||||
|
||||
from mininet.log import info
|
||||
from mininet.term import cleanUpScreens
|
||||
import os
|
||||
|
||||
def sh( cmd ):
|
||||
"Print a command and send it to the shell"
|
||||
info( cmd + '\n' )
|
||||
return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
|
||||
|
||||
CGROUPS_LOC='/mnt/cgroups'
|
||||
|
||||
def kill_cgroups(cgroups = None):
|
||||
"""cgroups is a list of cgroup names."""
|
||||
if not cgroups:
|
||||
cpudir = os.path.join(CGROUPS_LOC, 'cpu')
|
||||
if not os.path.exists(cpudir):
|
||||
return
|
||||
else:
|
||||
cgroups = os.listdir(cpudir)
|
||||
info( "killing cgroups: %s" % " ".join(cgroups) )
|
||||
for g in cgroups:
|
||||
if 'sysdefault' in g:
|
||||
continue
|
||||
for resource in os.listdir(CGROUPS_LOC):
|
||||
cgdir = "%s/%s/%s" % (CGROUPS_LOC, resource, g)
|
||||
if os.path.exists(cgdir):
|
||||
sh( "sudo rmdir %s" % cgdir )
|
||||
|
||||
def cleanup():
|
||||
"""Clean up junk which might be left over from old runs;
|
||||
do fast stuff before slow dp and link removal!"""
|
||||
@@ -57,4 +77,6 @@ def cleanup():
|
||||
if link != '':
|
||||
sh( "ip link del " + link )
|
||||
|
||||
kill_cgroups()
|
||||
|
||||
info( "*** Cleanup complete.\n" )
|
||||
|
||||
+3
-11
@@ -148,14 +148,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()
|
||||
@@ -200,7 +192,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."
|
||||
@@ -311,8 +303,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 )
|
||||
|
||||
+26
-33
@@ -178,13 +178,13 @@ 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 '
|
||||
|
||||
if bw and ( bw < 0 or bw > 1000 ):
|
||||
error( 'Bandwidth', bw, 'is outside range 0..1000 Mbps\n' )
|
||||
if bw and ( bw < 0 or bw > 10000 ):
|
||||
warn( 'Bandwidth', bw, 'is outside range 0..10000 Mbps\n' )
|
||||
|
||||
elif bw is not None:
|
||||
# BL: this seems a bit brittle...
|
||||
@@ -200,15 +200,14 @@ class TCIntf( Intf ):
|
||||
'%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 1: 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 1:0 htb default 1',
|
||||
'%s class add dev %s parent 1:0 classid 1:1 htb ' +
|
||||
'rate %fMbit burst 15k' % bw ]
|
||||
'%s class add dev %s parent 1:0 classid 1:1 htb ' +
|
||||
'rate %fMbit burst 15k' % bw ]
|
||||
parent = ' parent 1:1 '
|
||||
|
||||
# ECN or RED
|
||||
@@ -229,28 +228,25 @@ class TCIntf( Intf ):
|
||||
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 ]
|
||||
netemargs ]
|
||||
return cmds
|
||||
|
||||
def tc( self, cmd, tc='tc' ):
|
||||
@@ -259,10 +255,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)
|
||||
@@ -282,23 +277,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
|
||||
cmds += self.delayCmds( delay=delay, jitter=jitter, loss=loss,
|
||||
max_queue_size=max_queue_size,
|
||||
parent=parent )
|
||||
# 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 ) + ') ' )
|
||||
|
||||
|
||||
+6
-6
@@ -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:
|
||||
|
||||
@@ -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 )
|
||||
|
||||
+21
-129
@@ -96,22 +96,19 @@ from mininet.cli import CLI
|
||||
from mininet.log import info, error, debug, output
|
||||
from mininet.node import Host, OVSKernelSwitch, Controller
|
||||
from mininet.link import Link, Intf
|
||||
from mininet.util import quietRun, fixLimits, numCores, ensureRoot
|
||||
from mininet.util import quietRun, 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"
|
||||
|
||||
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
|
||||
@@ -278,11 +275,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():
|
||||
@@ -307,7 +300,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."
|
||||
@@ -421,17 +414,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
|
||||
@@ -444,10 +436,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:
|
||||
@@ -463,61 +452,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"""
|
||||
@@ -529,17 +463,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.
|
||||
@@ -585,11 +508,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()
|
||||
@@ -600,42 +523,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 ):
|
||||
@@ -677,7 +564,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
|
||||
|
||||
@@ -718,7 +610,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 ]
|
||||
|
||||
+87
-97
@@ -49,12 +49,15 @@ import re
|
||||
import signal
|
||||
import select
|
||||
from subprocess import Popen, PIPE, STDOUT
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
from mininet.log import info, error, warn, debug
|
||||
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||
numCores, retry, mountCgroups )
|
||||
numCores, retry, mountCgroups, errFailTemp )
|
||||
from mininet.moduledeps import moduleDeps, pathCheck, OVS_KMOD, OF_KMOD, TUN
|
||||
from mininet.link import Link, Intf, TCIntf
|
||||
from mininet.clean import kill_cgroups
|
||||
|
||||
class Node( object ):
|
||||
"""A virtual network node is simply a shell in a network namespace.
|
||||
@@ -83,8 +86,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 = ''
|
||||
|
||||
@@ -120,7 +123,7 @@ class Node( object ):
|
||||
# bash -m: enable job control
|
||||
cmd = [ 'mnexec', opts, 'bash', '-m' ]
|
||||
self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
|
||||
close_fds=True )
|
||||
close_fds=True )
|
||||
self.stdin = self.shell.stdin
|
||||
self.stdout = self.shell.stdout
|
||||
self.pid = self.shell.pid
|
||||
@@ -145,8 +148,6 @@ class Node( object ):
|
||||
quietRun( 'ip link del ' + intfName )
|
||||
self.shell = None
|
||||
|
||||
# Subshell I/O, commands and control
|
||||
|
||||
def read( self, maxbytes=1024 ):
|
||||
"""Buffered read from node, non-blocking.
|
||||
maxbytes: maximum number of bytes to return"""
|
||||
@@ -169,7 +170,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
|
||||
|
||||
@@ -357,23 +358,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."
|
||||
@@ -433,7 +428,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
|
||||
@@ -521,9 +516,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"
|
||||
@@ -564,10 +559,18 @@ class CPULimitedHost( Host ):
|
||||
CPULimitedHost.init()
|
||||
# Create a cgroup and move shell into it
|
||||
self.cgroup = 'cpu,cpuacct,cpuset:/' + self.name
|
||||
errFail( 'cgcreate -g ' + self.cgroup )
|
||||
cmd_to_run = 'cgcreate -g ' + self.cgroup
|
||||
error("creating group using command: %s\n" % cmd_to_run)
|
||||
errFail( cmd_to_run )
|
||||
# We don't add ourselves to a cpuset because you must
|
||||
# specify the cpu and memory placement first
|
||||
errFail( 'cgclassify -g cpu,cpuacct:/%s %s' % ( self.name, self.pid ) )
|
||||
#self.pid = 12345
|
||||
#error("nap time!")
|
||||
time.sleep(0.1)
|
||||
cmd_to_run = 'cgclassify -g cpu,cpuacct:/%s %s' % ( self.name, self.pid )
|
||||
errFailTemp( cmd_to_run )
|
||||
#error("nap time over.")
|
||||
#exit
|
||||
# BL: Setting the correct period/quota is tricky, particularly
|
||||
# for RT. RT allows very small quotas, but the overhead
|
||||
# seems to be high. CFS has a mininimum quota of 1 ms, but
|
||||
@@ -581,7 +584,7 @@ class CPULimitedHost( Host ):
|
||||
cmd = 'cgset -r %s.%s=%s /%s' % (
|
||||
resource, param, value, self.name )
|
||||
quietRun( cmd )
|
||||
nvalue = int( self.cgroupGet( param, resource ) )
|
||||
nvalue = int( self.cgroupGet2( param, resource ) )
|
||||
if nvalue != value:
|
||||
error( '*** error: cgroupSet: %s set to %s instead of %s\n'
|
||||
% ( param, nvalue, value ) )
|
||||
@@ -591,13 +594,35 @@ class CPULimitedHost( Host ):
|
||||
"Return value of cgroup parameter"
|
||||
cmd = 'cgget -r %s.%s /%s' % (
|
||||
resource, param, self.name )
|
||||
return int( quietRun( cmd ).split()[ -1 ] )
|
||||
cmd_output = quietRun( cmd )
|
||||
return int( cmd_output.split()[ -1 ] )
|
||||
|
||||
def cgroupGet2( self, param, resource='cpu' ):
|
||||
"Return value of cgroup parameter"
|
||||
# TEMP: cgget not in 10.04 cgroup-bin. Oops!
|
||||
# Can get same stuff by reading files.
|
||||
filename = resource + '.' + param
|
||||
filepath = os.path.join("/mnt/cgroups/", resource, self.name, filename)
|
||||
#cmd = 'cgget -r %s.%s /%s' % (
|
||||
# resource, param, self.name )
|
||||
if not os.path.exists(filepath):
|
||||
raise Exception("%s not found." % filename)
|
||||
# TEMP below
|
||||
f = open(filepath)
|
||||
cmd_output = f.readlines()[0]
|
||||
f.close()
|
||||
#cmd_output = subprocess.check_output(cmd, shell=True)
|
||||
#quietRun( cmd )
|
||||
return int( cmd_output.split()[ -1 ] )
|
||||
|
||||
def cgroupDel( self ):
|
||||
"Clean up our cgroup"
|
||||
# info( '*** deleting cgroup', self.cgroup, '\n' )
|
||||
_out, _err, exitcode = errRun( 'cgdelete -r ' + self.cgroup )
|
||||
return exitcode != 0
|
||||
# TEMP out
|
||||
kill_cgroups([self.name])
|
||||
#_out, _err, exitcode = errRun( 'cgdelete -r ' + self.cgroup )
|
||||
#return exitcode != 0
|
||||
return True
|
||||
|
||||
def popen( self, *args, **kwargs ):
|
||||
"""Return a Popen() object in node's namespace
|
||||
@@ -691,7 +716,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
|
||||
@@ -778,14 +803,14 @@ 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."
|
||||
@@ -797,8 +822,7 @@ class UserSwitch( Switch ):
|
||||
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
|
||||
|
||||
@@ -819,20 +843,19 @@ 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 ):
|
||||
"Stop OpenFlow reference user datapath."
|
||||
@@ -855,14 +878,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 ):
|
||||
@@ -876,13 +899,12 @@ 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 ):
|
||||
@@ -906,10 +928,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 +
|
||||
@@ -962,10 +982,8 @@ class OVSSwitch( Switch ):
|
||||
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 ):
|
||||
@@ -981,35 +999,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.
|
||||
@@ -1019,7 +1017,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 ):
|
||||
@@ -1038,8 +1036,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 ):
|
||||
@@ -1067,24 +1065,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):
|
||||
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, ip=ip, port=port,
|
||||
**kwargs )
|
||||
|
||||
def start( self ):
|
||||
"Overridden to do nothing."
|
||||
@@ -1093,11 +1091,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 ) )
|
||||
|
||||
@@ -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
-26
@@ -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.
|
||||
@@ -180,10 +180,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 +201,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 +222,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
@@ -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
|
||||
|
||||
|
||||
+17
-25
@@ -1,6 +1,6 @@
|
||||
"Utility functions for Mininet."
|
||||
|
||||
from mininet.log import output, info, error, warn
|
||||
from mininet.log import output, info, error
|
||||
|
||||
from time import sleep
|
||||
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
|
||||
@@ -47,7 +47,7 @@ def oldQuietRun( *cmd ):
|
||||
break
|
||||
out += data
|
||||
popen.poll()
|
||||
if popen.returncode is not None:
|
||||
if popen.returncode != None:
|
||||
break
|
||||
return out
|
||||
|
||||
@@ -112,6 +112,10 @@ def errFail( *cmd, **kwargs ):
|
||||
% ( cmd, ret, err ) )
|
||||
return out, err, ret
|
||||
|
||||
def errFailTemp( *cmd, **kwargs ):
|
||||
import os
|
||||
os.system(" ".join(cmd))
|
||||
|
||||
def quietRun( cmd, **kwargs ):
|
||||
"Run a command and return merged stdout and stderr"
|
||||
return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ]
|
||||
@@ -182,7 +186,7 @@ def moveIntfNoRetry( intf, node, printError=False ):
|
||||
if not ( ' %s:' % intf ) in links:
|
||||
if printError:
|
||||
error( '*** Error: moveIntf: ' + intf +
|
||||
' not successfully moved to ' + node.name + '\n' )
|
||||
' not successfully moved to ' + node.name + '\n' )
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -224,7 +228,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 ):
|
||||
@@ -253,7 +257,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
|
||||
@@ -358,12 +362,14 @@ def fixLimits():
|
||||
setrlimit( RLIMIT_NOFILE, ( 16384, 16384 ) )
|
||||
|
||||
def mountCgroups():
|
||||
return
|
||||
"Make sure cgroups file system is mounted"
|
||||
mounts = quietRun( 'mount' )
|
||||
cgdir = '/sys/fs/cgroup'
|
||||
#cgdir = '/sys/fs/cgroup'
|
||||
# BDH temp for 10.04
|
||||
cgdir = '/mnt/cgroups'
|
||||
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 )
|
||||
@@ -397,14 +403,10 @@ 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 ):
|
||||
@@ -425,6 +427,7 @@ def splitArgs( argstr ):
|
||||
|
||||
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.
|
||||
"""
|
||||
@@ -433,11 +436,10 @@ def customConstructor( constructors, argStr ):
|
||||
|
||||
if not constructor:
|
||||
raise Exception( "error: %s is unknown - please specify one of %s" %
|
||||
( cname, constructors.keys() ) )
|
||||
( 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 )
|
||||
@@ -446,24 +448,14 @@ def customConstructor( constructors, argStr ):
|
||||
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
|
||||
|
||||
@@ -23,23 +23,17 @@
|
||||
#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",
|
||||
printf("Execution utility for Mininet.\n"
|
||||
"usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\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",
|
||||
name);
|
||||
}
|
||||
|
||||
@@ -98,7 +92,7 @@ int main(int argc, char *argv[])
|
||||
int nsid;
|
||||
int pid;
|
||||
static struct sched_param sp;
|
||||
while ((c = getopt(argc, argv, "+cdnpa:g:r:vh")) != -1)
|
||||
while ((c = getopt(argc, argv, "+cdnpa:g:r:")) != -1)
|
||||
switch(c) {
|
||||
case 'c':
|
||||
/* close file descriptors except stdin/out/error */
|
||||
@@ -158,15 +152,9 @@ int main(int argc, char *argv[])
|
||||
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) {
|
||||
|
||||
@@ -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'
|
||||
|
||||
+24
-37
@@ -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,22 +122,21 @@ function kernel_clean {
|
||||
# Install Mininet deps
|
||||
function mn_deps {
|
||||
echo "Installing Mininet dependencies"
|
||||
$install gcc make screen psmisc xterm ssh iperf iproute telnet \
|
||||
python-setuptools python-networkx cgroup-bin ethtool help2man \
|
||||
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:
|
||||
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
|
||||
@@ -153,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
|
||||
|
||||
@@ -166,7 +165,7 @@ function of {
|
||||
make
|
||||
sudo make install
|
||||
|
||||
# Remove avahi-daemon, which may cause unwanted discovery packets to be
|
||||
# Remove avahi-daemon, which may cause unwanted discovery packets to be
|
||||
# sent during tests, near link status changes:
|
||||
$remove avahi-daemon
|
||||
|
||||
@@ -255,7 +254,7 @@ function ovs {
|
||||
ovspresent=1
|
||||
fi
|
||||
|
||||
# Switch can run on its own, but
|
||||
# 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
|
||||
@@ -285,8 +284,8 @@ function ovs {
|
||||
sudo apt-get -y --force-yes -t lenny-backports install autoconf
|
||||
fi
|
||||
else
|
||||
$install git
|
||||
fi
|
||||
$install git-core
|
||||
fi
|
||||
|
||||
# Install OVS from release
|
||||
cd ~/
|
||||
@@ -340,7 +339,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
|
||||
@@ -349,11 +348,9 @@ 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
|
||||
@@ -378,13 +375,6 @@ function nox {
|
||||
#./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..."
|
||||
@@ -394,7 +384,7 @@ 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
|
||||
@@ -403,7 +393,7 @@ function oftest {
|
||||
# Install cbench
|
||||
function cbench {
|
||||
echo "Installing cbench..."
|
||||
|
||||
|
||||
$install libsnmp-dev libpcap-dev libconfig-dev
|
||||
cd ~/
|
||||
git clone git://openflow.org/oflops.git
|
||||
@@ -466,9 +456,7 @@ function all {
|
||||
of
|
||||
wireshark
|
||||
ovs
|
||||
# NOX-classic is deprecated, but you can install it manually if desired.
|
||||
# nox
|
||||
pox
|
||||
nox
|
||||
oftest
|
||||
cbench
|
||||
other
|
||||
@@ -506,7 +494,7 @@ function vm_clean {
|
||||
|
||||
function usage {
|
||||
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 10.04, 11.10\n' >&2
|
||||
printf 'and Debian 5.0 (Lenny). If you run into trouble, try\n' >&2
|
||||
@@ -517,7 +505,7 @@ 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
|
||||
@@ -528,8 +516,8 @@ function usage {
|
||||
printf -- ' -v: install open (V)switch\n' >&2
|
||||
printf -- ' -w: install OpenFlow (w)ireshark dissector\n' >&2
|
||||
printf -- ' -x: install NO(X) OpenFlow controller\n' >&2
|
||||
printf -- ' -y: install (A)ll packages\n' >&2
|
||||
|
||||
printf -- ' -y: install (A)ll packages\n' >&2
|
||||
|
||||
exit 2
|
||||
}
|
||||
|
||||
@@ -537,7 +525,7 @@ if [ $# -eq 0 ]
|
||||
then
|
||||
all
|
||||
else
|
||||
while getopts 'abcdfhkmnprtvwx' OPTION
|
||||
while getopts 'abcdfhkmnrtvwx' OPTION
|
||||
do
|
||||
case $OPTION in
|
||||
a) all;;
|
||||
@@ -549,7 +537,6 @@ else
|
||||
k) kernel;;
|
||||
m) modprobe;;
|
||||
n) mn_deps;;
|
||||
p) pox;;
|
||||
r) remove_ovs;;
|
||||
t) other;;
|
||||
v) ovs;;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user