Compare commits

..
Author SHA1 Message Date
Bob Lantz 9bd75bdfb6 Fix typo 2018-11-02 14:29:18 -07:00
Bob Lantz fd97ab4462 Set hostname and update X11 credentials when needed 2018-05-12 00:17:26 +00:00
Bob Lantz 5ee31199c1 Remove obsolete private root dir check.
mnexec should check and attach to the proper root fs either
using mount namespaces or chroot.
2018-05-12 00:17:26 +00:00
Bob Lantz 2ecc637ff4 Cleanup and reorganization
Creating a new process group in a pidns child doesn't seem to
work, so we create it in the parent. This may have the side
effect of SIGKILL rather than SIGHUP being sent to processes
in a pid ns, but it doesn't seem to work otherwise.

We also try to avoid forking twice.
2018-05-12 00:17:26 +00:00
Bob Lantz 62d1121be7 Load topology dictionary, and add grid topo
Topolib should export topologies the same way custom
files do. We should probably do the same thing for
other classes such as hosts, switches, links, controllers,
etc..
2018-05-12 00:17:26 +00:00
Bob Lantz c522ba2cee Kill self.pid, which will be subprocess for Server 2018-05-12 00:17:26 +00:00
Bob Lantz a598baf943 Fix undefined SIGKILL 2018-05-12 00:17:26 +00:00
Bob Lantz 79aa54096e Raise exception if we don't have a compatible mnexec. 2018-05-12 00:17:26 +00:00
Bob Lantz 5175bc7b9a Avoid forking twice.
Also minor cleanups:
- don't redefine setns() if it's defined
- clarify when we want to make a new session or pgrp
2018-05-12 00:17:26 +00:00
Bob Lantz 8badfe4879 Use send_signal to kill (possibly remote) xterms 2018-05-12 00:17:26 +00:00
Bob Lantz 98bd9ad2f2 Add command line argument for cluster size 2018-05-12 00:17:26 +00:00
Bob Lantz 21506f909c Change sendInt() to kill the process group
Note this will work with pid namespaces.
2018-05-12 00:17:26 +00:00
Bob Lantz 72c1275078 Set self.ns correctly 2018-05-12 00:17:26 +00:00
Bob Lantz e3ac746a39 More changes to use ns param
You can either specify the old inNamespace parameter, in which case
you'll get a net + mnt namespace, or the new ns parameter, which
allows you to pick namespaces explicitly.

inNamespace is set to true if you're in a network namespace.
2018-05-12 00:17:26 +00:00
Bob Lantz a114eb78a0 Fix to use self.ns 2018-05-12 00:17:26 +00:00
Bob Lantz 7924b15331 Change to ns=['net','mnt'] and deprecate inNamespace 2018-05-12 00:17:26 +00:00
Bob Lantz 48131b13b8 Check for /var/log and /var/run in overlay dirs 2018-05-12 00:17:26 +00:00
Bob Lantz 277e4d2e09 Move Server to nodelib and add --host server option 2018-05-12 00:17:25 +00:00
Bob Lantz 81da901b6b Enable control path 2018-05-12 00:16:45 +00:00
Bob Lantz 5916830268 Delete junk at end of file 2018-05-12 00:16:45 +00:00
Bob Lantz 6f00369dff 8 servers + LinuxBridge 2018-05-12 00:16:45 +00:00
Bob Lantz 7c83f036df debug -> info 2018-05-12 00:16:45 +00:00
Bob Lantz b340488fdc Add /etc/openvswitch to private dirs 2018-05-12 00:16:45 +00:00
Bob Lantz fc462e3bdd Specify runCmd, and update controller IP correctly 2018-05-12 00:16:45 +00:00
Bob Lantz 76f3db36a2 Fix ^c on cluster edition; still broken for pid ns 2018-05-12 00:16:45 +00:00
Bob Lantz 160b665d09 still working on this... 2018-05-12 00:16:45 +00:00
Bob Lantz 29f15487ea Revert a bit to node.py from master 2018-05-12 00:14:53 +00:00
Bob Lantz a9c3844830 use runCmd 2018-05-12 00:14:53 +00:00
Bob Lantz eea5d0b602 Allow runCmd 2018-05-12 00:14:53 +00:00
Bob Lantz 1687605cf0 Remove debug print 2018-05-12 00:14:53 +00:00
Bob Lantz 0a5c1f6026 Create new pgrp so that we can use killpg 2018-05-12 00:14:53 +00:00
Bob Lantz c46608710f Remove debug print 2018-05-12 00:14:53 +00:00
Bob Lantz 020f276d10 Respect runCmd in makeIntfPair() 2018-05-12 00:14:53 +00:00
Bob Lantz 43aa659e08 Still working on it. 2018-05-12 00:14:53 +00:00
Bob Lantz 034c16d95a Change to sudo -E to preserve ssh forwarding 2018-05-12 00:14:52 +00:00
Bob Lantz d30f7bd931 Add API and mn support for --host proc,ns=[net,mnt,pid] 2018-05-12 00:14:52 +00:00
Bob Lantz 90281b1d44 First attempt fixing x11 to work with pid namespace 2018-05-12 00:14:52 +00:00
Bob Lantz b141594a29 Fix pid namespace by making sure we fork on attach 2018-05-12 00:14:52 +00:00
Bob Lantz 9b86b5b7de First crack at a pid namespace-capable mnexec
The detach is a bit ugly because we fork twice, which shouldn't be
necessary!!
2018-05-12 00:14:52 +00:00
Bob Lantz 1d2ce39a01 Experiments with pid ns 2018-05-12 00:14:52 +00:00
Bob Lantz 7dee9ce563 Avoid expanding a string into a list of chars 2018-05-12 00:14:52 +00:00
Bob Lantz 24dd285b1a Use ['/etc/foo'] vs. ('/etc/foo',) to avoid deleted comma problem 2018-05-12 00:14:52 +00:00
Bob Lantz 2b7eb2ed99 Use motd instead of ssh banner message 2018-05-12 00:14:52 +00:00
Bob Lantz 7dae4e4b44 Clarify comment 2018-05-12 00:14:52 +00:00
Bob Lantz 5960e4ef89 Add docstring for terminate() 2018-05-12 00:14:52 +00:00
Bob Lantz 4d4d4719ff Document config params 2018-05-12 00:14:52 +00:00
Bob Lantz e67c9d9ea7 add private btmp 2018-05-12 00:14:52 +00:00
Bob Lantz 4c70429587 Comment changes 2018-05-12 00:14:52 +00:00
Bob Lantz d830b2331b Add documentation for overlayDirs 2018-05-12 00:14:52 +00:00
Bob Lantz c616476c33 Change to super() call in __init__ 2018-05-12 00:14:52 +00:00
Bob Lantz 1c1fa3af96 Simplify startup/shutdown, and a few comments 2018-05-12 00:14:52 +00:00
Bob Lantz 0a9a5af67b Private utmp and wtmp for w and last 2018-05-12 00:14:52 +00:00
Bob Lantz 57ba8bcd2e Minor changes 2018-05-12 00:14:52 +00:00
Bob Lantz c447d17362 Clarify parameter processing for overlayDirs 2018-05-12 00:14:52 +00:00
Bob Lantz 7ff615acea Fake cluster example 2018-05-12 00:14:52 +00:00
Bob Lantz 7263c16e89 Add overlayDirs 2018-05-12 00:14:52 +00:00
103 changed files with 2296 additions and 3635 deletions

No files matched your search

+2 -2
View File
@@ -1,7 +1,7 @@
**Mininet uses GitHub issues for bug reports and feature requests only.**
Mininet uses GitHub issues for bug reports and feature requests only.
These issues can be viewed at bugs.mininet.org
If you have a question that is not a **bug report** or a **feature request**,
If you have a question that is not a bug report or a feature request,
please use the documentation at docs.mininet.org, the FAQ
at faq.mininet.org, and the mininet-discuss mailing list.
-22
View File
@@ -1,22 +0,0 @@
name: code-check
on: [push, pull_request]
jobs:
code-check:
name: Mininet Code Check
runs-on: ubuntu-latest
steps:
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
python-version: 3.x
- name: Check out Mininet source
uses: actions/checkout@v2
- name: Install Mininet code check dependencies
run: |
PYTHON=`which python` util/install.sh -n
python -m pip install pylint==2.4.4
- name: Run code check
run: make codecheck
-51
View File
@@ -1,51 +0,0 @@
name: mininet-tests
on: [push, pull_request]
jobs:
test:
name: Mininet Tests
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04]
python-version: [3.x, 2.x]
steps:
- name: Check out Mininet source
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Mininet and base dependencies
run: |
sudo apt-get update -qq
# This seems too slow unfortunately:
# sudo apt-get upgrade -y -qq
PYTHON=`which python` util/install.sh -nv
- name: Sanity test
run: |
export sudo="sudo env PATH=$PATH"
# Verify major python-version number matches python and mininet
export PYVER=`echo ${{ matrix.python-version }} | cut -d . -f 1`
export CHKVER='px import platform; print(platform.python_version())'
python --version |& grep " $PYVER\."
echo $CHKVER | $sudo mn -v output | grep " $PYVER\."
# Newer OvS tries OpenFlow15 which crashes ovsc on ubuntu-20.04
$sudo mn --switch ovs,protocols=OpenFlow13 --test pingall
- name: Install test dependencies
run: |
sudo apt-get install -qq vlan
pip install pexpect
util/install.sh -fw
- name: Run core tests
run: |
export sudo="sudo env PATH=$PATH"
export PYTHON=`which python`
$sudo $PYTHON mininet/test/runner.py -v
- name: Run examples tests (quick)
run: |
export sudo="sudo env PATH=$PATH"
export PYTHON=`which python`
$sudo $PYTHON examples/test/runner.py -v -quick
+2 -8
View File
@@ -41,16 +41,10 @@ load-plugins=
# can either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once).
#
# Note: we may want to re-enable some of these at some point, but many of them
# are just style issues rather than errors.
#
disable=pointless-except, invalid-name, super-init-not-called, fixme, star-args,
too-many-instance-attributes, too-few-public-methods,
too-many-instance-attributes, too-few-public-methods, too-many-arguments,
too-many-locals, too-many-public-methods, duplicate-code, bad-whitespace,
locally-disabled, locally-enabled, bad-continuation,
useless-object-inheritance, unnecessary-pass, no-else-return,
no-else-raise, no-else-continue, super-with-arguments
locally-disabled, locally-enabled
# bad-continuation, wrong-import-order
+31
View File
@@ -0,0 +1,31 @@
language: python
sudo: required
matrix:
include:
- dist: trusty
env: dist="14.04 LTS trusty"
# - dist: xenial
# env: dist="16.04 LTS xenial"
# Travis-CI only proposes 14.04 LTS Trusty and there is no plan to update to 16.04 xenial
# (c.f. https://github.com/travis-ci/travis-ci/issues/5821)
# It is useless to add a second job because it will run in the same Ubuntu version (14.04)
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq vlan
- sudo util/install.sh -n
install:
- bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi"
- sudo util/install.sh -fnvw
script:
- sudo mn --test pingall
- sudo python mininet/test/runner.py -v -quick
- sudo python examples/test/runner.py -v -quick
notifications:
email:
on_success: never
# More details: https://docs.travis-ci.com/user/notifications#Configuring-email-notifications
+1 -30
View File
@@ -18,63 +18,34 @@ Cody Burkard
Additional Mininet Contributors
Joseph Beshay
M S Vishwanath Bhat
Muhammad Umair Bhatti
Arie Bregman
Tomasz Buchert
Gustavo Pantuza Coelho Pinto
Fernando Cappi
HW Chiu
Ryan Cox
Shaun Crampton
Jason Croft
Hantao Cui
Nirmoy Das
Lenoardo D'avila
Giuseppe Di Lena
David Erickson
Juan Gascon
Glen Gibb
Andrew Ferguson
Eder Leao Fernandes
Julian Filter
Ben Frankel
Tim Gates
Gregory Gee
Jon Hall
Roan Huang
Vitaly Ivanov
Theo Jepsen
Mathieu Jadin
Babis Kaidos
Rich Lane
Rémy Léone
Xiaozhou Li
Zi Shen Lim
David Mahler
Felix Maurer
Murphy McCauley
Alex Moijes
Felician Nemeth
José Pedro Oliveira
James Page
Gustavo Pantuza Coelho Pinto
Ramon Pujianto
Stempha Reiter
Damien Saucez
Shan Sikdar
Angad Singh
Piyush Srivastava
Ed Swierk
Darshan Thaker
Olivier Tl]ilmans
Niels van Adrichem
Brad Walker
Andreas Wundsam
Vikas Yadav
Isaku Yamahata
Baohua Yang
Zhuo
Thanks also to everyone who has submitted issues and pull
requests on github, and to our friendly mininet-discuss
+39 -70
View File
@@ -2,7 +2,7 @@
Mininet Installation/Configuration Notes
----------------------------------------
Mininet 2.3.0rc2
Mininet 2.3.0d1
---
The supported installation methods for Mininet are 1) using a
@@ -32,21 +32,19 @@ like to contribute an installation script, we would welcome it!)
2. Next-easiest option: use our Ubuntu package!
To install Mininet itself (i.e. `mn` and the Python API) on Ubuntu
16.04+:
12.10+:
sudo apt-get install mininet
Note: this may install an older version of Mininet which may not
support Python 3. If you would like the latest version of Mininet,
consider installing from source as described in the next section.
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
If you are running Ubuntu, Debian, or Fedora, you may be able to use
our handy `install.sh` script, which is in `util/`. Please read the
following sections first.
3.1. Obtaining the Mininet source code
3.1. Native installation from source on Ubuntu 12.04+
If you're reading this, you've probably already done so, but the
command to download the Mininet source code is:
@@ -54,9 +52,8 @@ like to contribute an installation script, we would welcome it!)
git clone git://github.com/mininet/mininet.git
Note that the above git command will check out the latest and greatest
Mininet (which we recommend!) If you want to run the last
tagged/released version of Mininet, you can look at the release tags
using
Mininet (which we recommend!) If you want to run the last tagged/released
version of Mininet, you can look at the release tags using
cd mininet
git tag
@@ -67,38 +64,21 @@ like to contribute an installation script, we would welcome it!)
where <release tag> is the release you want to check out.
3.1.1 *CAUTION: USE AT YOUR OWN RISK!*
If you are running Ubuntu, Debian, or Fedora, you may be able to use
our handy `install.sh` script, which is in `util/`.
`install.sh` can be a bit intrusive and may possibly damage your OS
*WARNING: USE AT YOUR OWN RISK!*
`install.sh` is a bit intrusive and may possibly damage your OS
and/or home directory, by creating/modifying several directories
such as `mininet`, `openflow`, `oftest`, `pox`, etc.. We recommend
trying it in a VM before trying it on a system you use from day to
day.
trying it in a VM before trying it on a system you use from day to day.
Although we hope it won't do anything completely terrible, you may
want to look at the script before you run it, and you should make
sure your system and home directory are backed up just in case!
You can change the directory where the dependencies are installed
using the -s <directory> flag.
util/install.sh -s <directory> ...
3.1.2 Running `install.sh`
Installing a "minimal" version of Mininet with Open vSwitch should
be reasonably non-perturbing since it should not create directories
for other tools:
util/install.sh -nv
Note this will not install a controller, so you will have to either
install your own controller, or use a switch such OVSBridge that does
not require a controller:
sudo mn --switch ovsbr --test pingall
To install Mininet itself, the OpenFlow reference controller, and
To install Mininet itself, the OpenFlow reference implementation, and
Open vSwitch, you may use:
util/install.sh -fnv
@@ -108,27 +88,6 @@ like to contribute an installation script, we would welcome it!)
sudo mn --test pingall
3.1.3 Python 3 and Python 2 support
Mininet supports Python 3 and Python 2. By default, `install.sh`
will use whatever `python` is on your system. To specify a
specific version of Pythonm, you can set the PYTHON environment
variable:
PYTHON=python3 util/install.sh -fnv
You can install Mininet for both Python 3 and Python 2:
PYTHON=python2 util/install.sh -fnv
PYTHON=python3 util/install.sh -n
Whichever version was installed last will be the default for `mn`.
As long as Mininet is installed for the appropriate version of
Python, you can run it using that versinon of Python:
python3 `which mn`
python2 `which mn`
To install ALL of the software which we use for OpenFlow tutorials,
including POX, the OpenFlow WireShark dissector, the `oftest`
framework, and other potentially useful software, you may use:
@@ -137,7 +96,12 @@ like to contribute an installation script, we would welcome it!)
This takes about 4 minutes on our test system.
3.2. (Experimental) Native installation from source on Fedora:
You can change the directory where the dependencies are installed using
the -s <directory> flag.
util/install.sh -s <directory> -a
3.2. Native installation from source on Fedora 18+.
As root execute the following operations:
@@ -145,6 +109,18 @@ like to contribute an installation script, we would welcome it!)
yum install git
* create an user account (e.g. mininet) and add it to the wheel group
useradd [...] mininet
usermod -a -G wheel mininet
* change the SElinux setting to permissive. It can be done
temporarily with:
setenforce 0
then login with the new account (e.g. mininet) and do the following:
* clone the Mininet repository
git clone git://github.com/mininet/mininet.git
@@ -163,10 +139,7 @@ like to contribute an installation script, we would welcome it!)
sudo mn --test pingall
Note that `install.sh -fnv `may not install all dependencies on Fedora,
and many tests may still fail.
4. Creating your own Mininet/OpenFlow tutorial VM on Ubuntu/Debian
4. Creating your own Mininet/OpenFlow tutorial VM
Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial
is easy! First, create a new Ubuntu VM. Next, run two commands in it:
@@ -182,8 +155,7 @@ like to contribute an installation script, we would welcome it!)
Although we don't support other Linux distributions directly, it
should be possible to install and run Mininet with some degree of
manual effort. People have even gotten `mn --switch user` to run
in a ChromeOS container.
manual effort.
In general, you must have:
@@ -200,11 +172,8 @@ like to contribute an installation script, we would welcome it!)
support other Linux distributions.
As always, please feel free to submit issues or pull requests for
installation-related features.
Good luck!
Good luck, and have fun!
Mininet Developers
Mininet Team
---
+2 -2
View File
@@ -1,6 +1,6 @@
Mininet 2.3.0rc2 License
Mininet 2.3.0d1 License
Copyright (c) 2013-2020 Open Networking Foundation
Copyright (c) 2013-2016 Open Networking Laboratory
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
The Leland Stanford Junior University
+10 -20
View File
@@ -2,19 +2,16 @@ MININET = mininet/*.py
TEST = mininet/test/*.py
EXAMPLES = mininet/examples/*.py
MN = bin/mn
PYTHON ?= python
PYMN = $(PYTHON) -B bin/mn
PYMN = python -B bin/mn
BIN = $(MN)
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
MNEXEC = mnexec
MANPAGES = mn.1 mnexec.1
P8IGN = E251,E201,E302,E202,E126,E127,E203,E226,E402,W504,W503,E731
PREFIX ?= /usr
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man/man1
P8IGN = E251,E201,E302,E202,E126,E127,E203,E226
BINDIR = /usr/bin
MANDIR = /usr/share/man/man1
DOCDIRS = doc/html doc/latex
PDF = doc/latex/refman.pdf
CC ?= cc
CFLAGS += -Wall -Wextra
@@ -47,25 +44,18 @@ slowtest: $(MININET)
mininet/examples/test/runner.py -v
mnexec: mnexec.c $(MN) mininet/net.py
$(CC) $(CFLAGS) $(LDFLAGS) -DVERSION=\"`PYTHONPATH=. $(PYMN) --version`\" $< -o $@
cc $(CFLAGS) $(LDFLAGS) -DVERSION=\"`PYTHONPATH=. $(PYMN) --version`\" $< -o $@
install-mnexec: $(MNEXEC)
install -D $(MNEXEC) $(BINDIR)/$(MNEXEC)
install-manpages: $(MANPAGES)
install -D -t $(MANDIR) $(MANPAGES)
install: install-mnexec install-manpages
# This seems to work on all pip versions
$(PYTHON) -m pip uninstall -y mininet || true
$(PYTHON) -m pip install .
install: $(MNEXEC) $(MANPAGES)
install $(MNEXEC) $(BINDIR)
install $(MANPAGES) $(MANDIR)
python setup.py install
develop: $(MNEXEC) $(MANPAGES)
# Perhaps we should link these as well
install $(MNEXEC) $(BINDIR)
install $(MANPAGES) $(MANDIR)
$(PYTHON) -m pip uninstall -y mininet || true
$(PYTHON) -m pip install -e . --no-binary :all:
python setup.py develop
man: $(MANPAGES)
+24 -30
View File
@@ -2,10 +2,9 @@ Mininet: Rapid Prototyping for Software Defined Networks
========================================================
*The best way to emulate almost any network on your laptop!*
Mininet 2.3.0rc2
[![Build Status][1]](https://github.com/mininet/mininet/actions)
Mininet 2.3.0d1
[![Build Status][1]](https://travis-ci.org/mininet/mininet)
### What is Mininet?
@@ -68,31 +67,27 @@ Mininet includes:
`mn -c`
### Python 3 Support
### New features in this release
- Mininet 2.3.0rc2 supports Python 3 and Python 2!
This is primarily a performance improvement and bug fix release.
- You can install both the Python 3 and Python 2 versions of
Mininet side by side, but the most recent installation will
determine which Python version is used by default by `mn`.
- Batch startup has been implemented for Open vSwitch, improving
startup performance.
- You can run `mn` directly with Python 2 or Python 3,
as long as the appropriate version of Mininet is installed,
e.g.
- OVS patch links have been implemented via OVSLink and --link ovs
$ sudo python2 `which mn`
Warning! These links have *serious limitations* compared to
virtual Ethernet pairs: they are not attached to real Linux
interfaces so you cannot use tcpdump or wireshark with them;
they also cannot be used in long chains - we don't recommend more
than 64 OVSLinks, for example --linear,64. However, they can offer
significantly better performance than veth pairs, for certain
configurations.
- More information regarding Python 3 and Python 2 support
may be found in the release notes on http://docs.mininet.org.
- You can now easily install Mininet on a Raspberry Pi ;-)
### Other Enhancements and Information
- Support for Ubuntu 20.04 LTS (and 18.04 and 16.04)
- More reliable testing and CI via github actions
- Additional information about this release and previous releases
may be found in the release notes on http://docs.mininet.org.
- Additional information for this release and previous releases
may be found in the release notes on docs.mininet.org
### Installation
@@ -105,8 +100,7 @@ information, including a Mininet walkthrough and an introduction
to the Python API, is available on the
[Mininet Web Site](http://mininet.org).
There is also a wiki which you are encouraged to read and to
contribute to, particularly the Frequently Asked Questions
(FAQ) at http://faq.mininet.org.
contribute to, particularly the Frequently Asked Questions (FAQ.)
### Support
@@ -117,7 +111,7 @@ Mininet mailing list, `mininet-discuss` at:
### Join Us
Thanks again to all of the Mininet contributors and users!
Thanks again to all of the Mininet contributors!
Mininet is an open source project and is currently hosted
at <https://github.com/mininet>. You are encouraged to download
@@ -129,10 +123,10 @@ hard work that Mininet continues to grow and improve.
### Enjoy Mininet
Have fun! We look forward to seeing what you will do with Mininet
to change the networking world.
Best wishes, and we look forward to seeing what you can do with
Mininet to change the networking world!
Bob Lantz,
on behalf of the Mininet Contributors
Bob Lantz
Mininet Core Team
[1]: https://github.com/mininet/mininet/workflows/mininet-tests/badge.svg
[1]: https://travis-ci.org/mininet/mininet.svg?branch=master
+17 -36
View File
@@ -11,20 +11,15 @@ Example to pull custom params (topo, switch, etc.) from a file:
sudo mn --custom ~/mininet/custom/custom_example.py
"""
from optparse import OptionParser
import os
import sys
import time
from functools import partial
from optparse import OptionParser # pylint: disable=deprecated-module
from sys import exit # pylint: disable=redefined-builtin
# Fix setuptools' evil madness, and open up (more?) security holes
if 'PYTHONPATH' in os.environ:
sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
# pylint: disable=wrong-import-position
from mininet.clean import cleanup
import mininet.cli
from mininet.log import lg, LEVELS, info, debug, warn, error, output
@@ -34,12 +29,15 @@ from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
DefaultController, NullController,
UserSwitch, OVSSwitch, OVSBridge,
IVSSwitch )
from mininet.nodelib import LinuxBridge
from mininet.nodelib import LinuxBridge, Server
from mininet.link import Link, TCLink, TCULink, OVSLink
from mininet.topo import ( SingleSwitchTopo, LinearTopo,
SingleSwitchReversedTopo, MinimalTopo )
from mininet.topolib import TreeTopo, TorusTopo
from mininet.util import customClass, specialClass, splitArgs, buildTopo
import mininet.topolib
from mininet.util import customClass, specialClass, splitArgs
from mininet.util import buildTopo
from functools import partial
# Experimental! cluster edition prototype
from mininet.examples.cluster import ( MininetCluster, RemoteHost,
@@ -48,7 +46,6 @@ from mininet.examples.cluster import ( MininetCluster, RemoteHost,
ClusterCleanup )
from mininet.examples.clustercli import ClusterCLI
PLACEMENT = { 'block': SwitchBinPlacer, 'random': RandomPlacer }
# built in topologies, created only when run
@@ -56,9 +53,8 @@ TOPODEF = 'minimal'
TOPOS = { 'minimal': MinimalTopo,
'linear': LinearTopo,
'reversed': SingleSwitchReversedTopo,
'single': SingleSwitchTopo,
'tree': TreeTopo,
'torus': TorusTopo }
'single': SingleSwitchTopo }
TOPOS.update( mininet.topolib.topos)
SWITCHDEF = 'default'
SWITCHES = { 'user': UserSwitch,
@@ -72,6 +68,7 @@ SWITCHES = { 'user': UserSwitch,
HOSTDEF = 'proc'
HOSTS = { 'proc': Host,
'server': Server,
'rt': specialClass( CPULimitedHost, defaults=dict( sched='rt' ) ),
'cfs': specialClass( CPULimitedHost, defaults=dict( sched='cfs' ) ) }
@@ -101,6 +98,7 @@ CLI = None # Set below if needed
# Locally defined tests
def allTest( net ):
"Run ping and iperf tests"
net.waitConnected()
net.start()
net.ping()
net.iperf()
@@ -109,7 +107,6 @@ def nullTest( _net ):
"Null 'test' (does nothing)"
pass
TESTS.update( all=allTest, none=nullTest, build=nullTest )
# Map to alternate spellings of Mininet() methods
@@ -130,6 +127,7 @@ def runTests( mn, options ):
if callable( testfn ):
testfn( mn, *args, **kwargs )
elif hasattr( mn, test ):
mn.waitConnected()
getattr( mn, test )( *args, **kwargs )
else:
raise Exception( 'Test %s is unknown - please specify one of '
@@ -188,10 +186,8 @@ class MininetRunner( object ):
for fileName in files:
customs = {}
if os.path.isfile( fileName ):
# pylint: disable=exec-used
exec( compile( open( fileName ).read(), fileName, 'exec' ),
customs, customs )
for name, val in customs.items():
execfile( fileName, customs, customs )
for name, val in customs.iteritems():
self.setCustom( name, val )
else:
raise Exception( 'could not find custom file: %s' % fileName )
@@ -260,7 +256,7 @@ class MininetRunner( object ):
opts.add_option( '--arp', action='store_true',
default=False, help='set all-pairs ARP entries' )
opts.add_option( '--verbosity', '-v', type='choice',
choices=list( LEVELS.keys() ), default = 'info',
choices=LEVELS.keys(), default = 'info',
help = '|'.join( LEVELS.keys() ) )
opts.add_option( '--innamespace', action='store_true',
default=False, help='sw and ctrl in namespace?' )
@@ -286,16 +282,11 @@ class MininetRunner( object ):
" Mininet's IP subnet, see the --ipbase option." )
opts.add_option( '--version', action='callback', callback=version,
help='prints the version and exits' )
opts.add_option( '--wait', '-w', action='store_true',
default=False, help='wait for switches to connect' )
opts.add_option( '--twait', '-t', action='store', type='int',
dest='wait',
help='timed wait (s) for switches to connect' )
opts.add_option( '--cluster', type='string', default=None,
metavar='server1,server2...',
help=( 'run on multiple servers (experimental!)' ) )
opts.add_option( '--placement', type='choice',
choices=list( PLACEMENT.keys() ), default='block',
choices=PLACEMENT.keys(), default='block',
metavar='block|random',
help=( 'node placement for --cluster '
'(experimental!) ' ) )
@@ -387,24 +378,14 @@ class MininetRunner( object ):
placement=PLACEMENT[ opts.placement ] )
mininet.cli.CLI = ClusterCLI
# Wait for controllers to connect unless we're running null test
if ( opts.test and opts.test != [ 'none' ] and
isinstance( opts.wait, bool ) ):
opts.wait = True
mn = Net( topo=topo,
switch=switch, host=host, controller=controller, link=link,
ipBase=opts.ipbase, inNamespace=opts.innamespace,
xterms=opts.xterms, autoSetMacs=opts.mac,
autoStaticArp=opts.arp, autoPinCpus=opts.pin,
waitConnected=opts.wait,
listenPort=opts.listenport )
if opts.ensure_value( 'nat', False ):
with open( '/etc/resolv.conf' ) as f:
if 'nameserver 127.' in f.read():
warn( '*** Warning: loopback address in /etc/resolv.conf '
'may break host DNS over NAT\n')
mn.addNAT( *opts.nat_args, **opts.nat_kwargs ).configDefault()
# --custom files can set CLI or change mininet.cli.CLI
@@ -435,7 +416,7 @@ if __name__ == "__main__":
except KeyboardInterrupt:
info( "\n\nKeyboard Interrupt. Shutting down and cleaning up...\n\n")
cleanup()
except Exception: # pylint: disable=broad-except
except Exception:
# Print exception
type_, val_, trace_ = sys.exc_info()
errorMsg = ( "-"*80 + "\n" +
+4 -1
View File
@@ -13,9 +13,12 @@ from mininet.topo import Topo
class MyTopo( Topo ):
"Simple topology example."
def build( self ):
def __init__( self ):
"Create custom topo."
# Initialize topology
Topo.__init__( self )
# Add hosts and switches
leftHost = self.addHost( 'h1' )
rightHost = self.addHost( 'h2' )
+830 -1936
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"This example doesn't use OpenFlow, but attempts to run sshd in a namespace."
+4 -5
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
bind.py: Bind mount example
@@ -34,14 +34,14 @@ and '/var/run'. It also has a temporary private directory mounted
on '/var/mn'
"""
from functools import partial
from mininet.net import Mininet
from mininet.node import Host
from mininet.cli import CLI
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel, info
from functools import partial
# Sample usage
@@ -53,7 +53,7 @@ def testHostWithPrivateDirs():
'/var/mn' ]
host = partial( Host,
privateDirs=privateDirs )
net = Mininet( topo=topo, host=host, waitConnected=True )
net = Mininet( topo=topo, host=host )
net.start()
directories = [ directory[ 0 ] if isinstance( directory, tuple )
else directory for directory in privateDirs ]
@@ -61,7 +61,6 @@ def testHostWithPrivateDirs():
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
testHostWithPrivateDirs()
+61 -109
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
cluster.py: prototyping/experimentation for distributed Mininet,
@@ -74,6 +74,17 @@ Things to do:
- hifi support (e.g. delay compensation)
"""
from mininet.node import Node, Host, OVSSwitch, Controller
from mininet.link import Link, Intf
from mininet.net import Mininet
from mininet.topo import LinearTopo
from mininet.topolib import TreeTopo
from mininet.util import quietRun, errRun
from mininet.examples.clustercli import CLI
from mininet.log import setLogLevel, debug, info, error
from mininet.clean import addCleanupCallback
from signal import signal, SIGINT, SIG_IGN
from subprocess import Popen, PIPE, STDOUT
import os
@@ -84,18 +95,6 @@ from itertools import groupby
from operator import attrgetter
from distutils.version import StrictVersion
from mininet.node import Node, Host, OVSSwitch, Controller
from mininet.link import Link, Intf
from mininet.net import Mininet
from mininet.topo import LinearTopo
from mininet.topolib import TreeTopo
from mininet.util import quietRun, errRun, decode
from mininet.examples.clustercli import CLI
from mininet.log import setLogLevel, debug, info, error
from mininet.clean import addCleanupCallback
# pylint: disable=too-many-arguments
def findUser():
"Try to return logged-in (usually non-root) user"
@@ -127,7 +126,7 @@ class ClusterCleanup( object ):
def cleanup( cls ):
"Clean up"
info( '*** Cleaning up cluster\n' )
for server, user in cls.serveruser.items():
for server, user in cls.serveruser.iteritems():
if server == 'localhost':
# Handled by mininet.clean.cleanup()
continue
@@ -158,7 +157,7 @@ class RemoteMixin( object ):
'-o', 'ForwardAgent=yes', '-tt' ]
def __init__( self, name, server='localhost', user=None, serverIP=None,
controlPath=False, splitInit=False, **kwargs):
controlPath=True, splitInit=False, **kwargs):
"""Instantiate a remote node
name: name of remote node
server: remote server (optional)
@@ -214,7 +213,7 @@ class RemoteMixin( object ):
def startShell( self, *args, **kwargs ):
"Start a shell process for running commands"
if self.isRemote:
kwargs.update( mnopts='-c' )
kwargs.update( mnopts='-cp' )
super( RemoteMixin, self ).startShell( *args, **kwargs )
# Optional split initialization
self.sendCmd( 'echo $$' )
@@ -247,7 +246,7 @@ class RemoteMixin( object ):
result = ''
while True:
poll = popen.poll()
result += decode( popen.stdout.read() )
result += popen.stdout.read()
if poll is not None:
break
return result
@@ -262,7 +261,7 @@ class RemoteMixin( object ):
cmd: remote command to run (list)
**params: parameters to Popen()
returns: Popen() object"""
if isinstance( cmd, str):
if type( cmd ) is str:
cmd = cmd.split()
if self.isRemote:
if sudo:
@@ -290,7 +289,6 @@ class RemoteMixin( object ):
def addIntf( self, *args, **kwargs ):
"Override: use RemoteLink.moveIntf"
# kwargs.update( moveIntfFn=RemoteLink.moveIntf )
# pylint: disable=useless-super-delegation
return super( RemoteMixin, self).addIntf( *args, **kwargs )
@@ -327,7 +325,6 @@ class RemoteOVSSwitch( RemoteMixin, OVSSwitch ):
StrictVersion( '1.10' ) )
@classmethod
# pylint: disable=arguments-differ
def batchStartup( cls, switches, **_kwargs ):
"Start up switches in per-server batches"
key = attrgetter( 'server' )
@@ -339,7 +336,6 @@ class RemoteOVSSwitch( RemoteMixin, OVSSwitch ):
return switches
@classmethod
# pylint: disable=arguments-differ
def batchShutdown( cls, switches, **_kwargs ):
"Stop switches in per-server batches"
key = attrgetter( 'server' )
@@ -390,7 +386,8 @@ class RemoteLink( Link ):
if server1 == server2:
# Link within same server
return Link.makeIntfPair( intfname1, intfname2, addr1, addr2,
node1, node2, deleteIntfs=deleteIntfs )
node1, node2, deleteIntfs=deleteIntfs,
runCmd=None )
# Otherwise, make a tunnel
self.tunnel = self.makeTunnel( node1, node2, intfname1, intfname2,
addr1, addr2 )
@@ -417,9 +414,8 @@ class RemoteLink( Link ):
# And we can't ssh into this server remotely as 'localhost',
# so try again swappping node1 and node2
if node2.server == 'localhost':
return self.makeTunnel( node1=node2, node2=node1,
intfname1=intfname2, intfname2=intfname1,
addr1=addr2, addr2=addr1 )
return self.makeTunnel( node2, node1, intfname2, intfname1,
addr2, addr1 )
debug( '\n*** Make SSH tunnel ' + node1.server + ':' + intfname1 +
' == ' + node2.server + ':' + intfname2 )
# 1. Create tap interfaces
@@ -440,16 +436,13 @@ class RemoteLink( Link ):
# When we receive the character '@', it means that our
# tunnel should be set up
debug( 'Waiting for tunnel to come up...\n' )
ch = decode( tunnel.stdout.read( 1 ) )
ch = tunnel.stdout.read( 1 )
if ch != '@':
ch += decode( tunnel.stdout.read() )
cmd = ' '.join( cmd )
raise Exception( 'makeTunnel:\n'
'Tunnel setup failed for '
'%s:%s' % ( node1, node1.dest ) + ' to '
'%s:%s\n' % ( node2, node2.dest ) +
'command was: %s' % cmd + '\n' +
'result was: ' + ch )
raise Exception( 'makeTunnel:\n',
'Tunnel setup failed for',
'%s:%s' % ( node1, node1.dest ), 'to',
'%s:%s\n' % ( node2, node2.dest ),
'command was:', cmd, '\n' )
# 3. Move interfaces if necessary
for node in node1, node2:
if not self.moveIntf( 'tap9', node ):
@@ -534,9 +527,8 @@ class RemoteGRELink( RemoteLink ):
# We should never try to create a tunnel to ourselves!
assert node1.server != node2.server
if node2.server == 'localhost':
return self.makeTunnel( node1=node2, node2=node1,
intfname1=intfname2, intfname2=intfname1,
addr1=addr2, addr2=addr1 )
return self.makeTunnel( node2, node1, intfname2, intfname1,
addr2, addr1 )
IP1, IP2 = node1.serverIP, node2.serverIP
# GRE tunnel needs to be set up with the IP of the local interface
# that connects the remote node, NOT '127.0.0.1' of localhost
@@ -564,7 +556,6 @@ class RemoteGRELink( RemoteLink ):
node.rcmd('ip link set dev %s mtu 1450' % intfname)
if not self.moveIntf(intfname, node):
raise Exception('interface move failed on node %s' % node)
return None # May want to return something useful here
# Some simple placement algorithms for MininetCluster
@@ -599,10 +590,10 @@ class Placer( object ):
class RandomPlacer( Placer ):
"Random placement"
def place( self, node ):
def place( self, nodename ):
"""Random placement function
node: node"""
assert node # please pylint
nodename: node name"""
assert nodename # please pylint
# This may be slow with lots of servers
return self.servers[ randrange( 0, len( self.servers ) ) ]
@@ -616,10 +607,10 @@ class RoundRobinPlacer( Placer ):
Placer.__init__( self, *args, **kwargs )
self.next = 0
def place( self, node ):
def place( self, nodename ):
"""Round-robin placement function
node: node"""
assert node # please pylint
nodename: node name"""
assert nodename # please pylint
# This may be slow with lots of servers
server = self.servers[ self.next ]
self.next = ( self.next + 1 ) % len( self.servers )
@@ -657,7 +648,7 @@ class SwitchBinPlacer( Placer ):
tickets = sum( [ binsizes[ server ] * [ server ]
for server in servers ], [] )
# And assign one ticket to each node
return dict( zip( nodes, tickets ) )
return { node: ticket for node, ticket in zip( nodes, tickets ) }
def calculatePlacement( self ):
"Pre-calculate node placement"
@@ -714,21 +705,21 @@ class HostSwitchBinPlacer( Placer ):
self.cset = frozenset( self.controllers )
self.hind, self.sind, self.cind = 0, 0, 0
def place( self, node ):
def place( self, nodename ):
"""Simple placement algorithm:
place nodes into evenly sized bins"""
# Place nodes into bins
if node in self.hset:
if nodename in self.hset:
server = self.servdict[ self.hind / self.hbin ]
self.hind += 1
elif node in self.sset:
elif nodename in self.sset:
server = self.servdict[ self.sind / self.sbin ]
self.sind += 1
elif node in self.cset:
elif nodename in self.cset:
server = self.servdict[ self.cind / self.cbin ]
self.cind += 1
else:
info( 'warning: unknown node', node )
info( 'warning: unknown node', nodename )
server = self.servdict[ 0 ]
return server
@@ -774,7 +765,6 @@ class MininetCluster( Mininet ):
# Make sure control directory exists
self.cdir = os.environ[ 'HOME' ] + '/.ssh/mn'
errRun( [ 'mkdir', '-p', self.cdir ] )
# pylint: disable=unexpected-keyword-arg
Mininet.__init__( self, *args, **params )
def popen( self, cmd ):
@@ -851,43 +841,19 @@ class MininetCluster( Mininet ):
if cfile:
config.setdefault( 'controlPath', cfile )
@staticmethod
def isLoopback( ipaddr ):
"Is ipaddr an IPv4 loopback address?"
return ipaddr.startswith( '127.' )
# pylint: disable=arguments-differ,signature-differs
def addController( self, *args, **kwargs ):
"Patch to update IP address to global IP address"
controller = Mininet.addController( self, *args, **kwargs )
controllerIP = controller.IP()
if ( not isinstance( controller, Controller ) or
not self.isLoopback( controller.IP() ) ):
return controller
# Find route to a different server IP address
serverIPs = [ ip for ip in self.serverIP.values()
if ip != controllerIP ]
if not serverIPs:
return None # no remote servers - loopback is fine
for remoteIP in serverIPs:
# Route should contain 'dev <intfname>'
route = controller.cmd( 'ip route get', remoteIP,
r'| egrep -o "dev\s[^[:space:]]+"' )
if not route:
raise Exception('addController: no route from', controller,
'to', remoteIP )
intf = route.split()[ 1 ].strip()
if intf != 'lo':
break
if intf == 'lo':
raise Exception( 'addController: could not find external '
'interface/IP for %s' % controller )
debug( 'adding', intf, 'to', controller )
Intf( intf, node=controller ).updateIP()
debug( controller, 'IP address updated to', controller.IP() )
# Update IP address for controller that may not be local
if ( isinstance( controller, Controller )
and controller.IP() == '127.0.0.1' ):
links = controller.cmd( 'ip link show' )
eth0 = re.findall( ' (.*eth0):', links )
if not eth0:
raise Exception( 'Cannot find IP address for controller eth0' )
Intf( eth0[ 0 ], node=controller ).updateIP()
return controller
# pylint: disable=arguments-differ,signature-differs
def buildFromTopo( self, *args, **kwargs ):
"Start network"
info( '*** Placing nodes\n' )
@@ -896,12 +862,9 @@ class MininetCluster( Mininet ):
Mininet.buildFromTopo( self, *args, **kwargs )
# Default remote server for tests
remoteServer = 'ubuntu2'
def testNsTunnels( remote=remoteServer, link=RemoteGRELink ):
def testNsTunnels( remote='ubuntu2', link=RemoteGRELink ):
"Test tunnels between nodes in namespaces"
net = Mininet( host=RemoteHost, link=link, waitConnected=True )
net = Mininet( host=RemoteHost, link=link )
h1 = net.addHost( 'h1')
h2 = net.addHost( 'h2', server=remote )
net.addLink( h1, h2 )
@@ -914,14 +877,13 @@ def testNsTunnels( remote=remoteServer, link=RemoteGRELink ):
# This shows how node options may be used to manage
# cluster placement using the net.add*() API
def testRemoteNet( remote=remoteServer, link=RemoteGRELink ):
def testRemoteNet( remote='ubuntu2', link=RemoteGRELink ):
"Test remote Node classes"
info( '*** Remote Node Test\n' )
net = Mininet( host=RemoteHost, switch=RemoteOVSSwitch,
link=link, controller=ClusterController,
waitConnected=True )
net = Mininet( host=RemoteHost, switch=RemoteOVSSwitch, link=link )
c0 = net.addController( 'c0' )
# Make sure controller knows its non-loopback address
Intf( 'eth0', node=c0 ).updateIP()
info( "*** Creating local h1\n" )
h1 = net.addHost( 'h1' )
info( "*** Creating remote h2\n" )
@@ -953,7 +915,7 @@ def testRemoteNet( remote=remoteServer, link=RemoteGRELink ):
remoteHosts = [ 'h2' ]
remoteSwitches = [ 's2' ]
remoteServer = 'ubuntu2'
def HostPlacer( name, *args, **params ):
"Custom Host() constructor which places hosts on servers"
@@ -970,21 +932,10 @@ def SwitchPlacer( name, *args, **params ):
return RemoteOVSSwitch( name, *args, **params )
def ClusterController( *args, **kwargs):
"Custom Controller() constructor which updates its intf IP address"
intf = kwargs.pop( 'intf', '' )
"Custom Controller() constructor which updates its eth0 IP address"
controller = Controller( *args, **kwargs )
# Find out its IP address so that cluster switches can connect
if not intf:
output = controller.cmd(
r"ip a | egrep -o '\w+:\s\w+'" ).split( '\n' )
for line in output:
intf = line.split()[ -1 ]
if intf != 'lo':
break
if intf == 'lo':
raise Exception( 'Could not find non-loopback interface'
'for %s' % controller )
Intf( intf, node=controller ).updateIP()
Intf( 'eth0', node=controller ).updateIP()
return controller
def testRemoteTopo( link=RemoteGRELink ):
@@ -1001,7 +952,7 @@ def testRemoteTopo( link=RemoteGRELink ):
# do random switch placement rather than completely random
# host placement.
def testRemoteSwitches( remote=remoteServer, link=RemoteGRELink ):
def testRemoteSwitches( remote='ubuntu2', link=RemoteGRELink ):
"Test with local hosts and remote switches"
servers = [ 'localhost', remote]
topo = TreeTopo( depth=4, fanout=2 )
@@ -1019,7 +970,7 @@ def testRemoteSwitches( remote=remoteServer, link=RemoteGRELink ):
# functions, for maximum ease of use. MininetCluster() also
# pre-flights and multiplexes server connections.
def testMininetCluster( remote=remoteServer, link=RemoteGRELink ):
def testMininetCluster( remote='ubuntu2', link=RemoteGRELink ):
"Test MininetCluster()"
servers = [ 'localhost', remote ]
topo = TreeTopo( depth=3, fanout=3 )
@@ -1029,7 +980,7 @@ def testMininetCluster( remote=remoteServer, link=RemoteGRELink ):
net.pingAll()
net.stop()
def signalTest( remote=remoteServer):
def signalTest( remote='ubuntu2'):
"Make sure hosts are robust to signals"
h = RemoteHost( 'h0', server=remote )
h.shell.send_signal( SIGINT )
@@ -1044,6 +995,7 @@ def signalTest( remote=remoteServer):
if __name__ == '__main__':
setLogLevel( 'info' )
remoteServer = 'ubuntu2'
remoteLink = RemoteSSHLink
testRemoteTopo(link=remoteLink)
testNsTunnels( remote=remoteServer, link=remoteLink )
-1
View File
@@ -17,7 +17,6 @@ def clusterSanity():
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
clusterSanity()
+3 -4
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"CLI for Mininet Cluster Edition prototype demo"
@@ -30,8 +30,7 @@ class ClusterCLI( CLI ):
global nx, plt, graphviz_layout
if not nx:
try:
# pylint: disable=import-error,no-member
# pylint: disable=import-outside-toplevel
# pylint: disable=import-error
import networkx
nx = networkx # satisfy pylint
from matplotlib import pyplot
@@ -43,7 +42,7 @@ class ClusterCLI( CLI ):
graphviz_layout = nx.graphviz_layout
else:
graphviz_layout = nx.drawing.nx_agraph.graphviz_layout
# pylint: enable=import-error,no-member
# pylint: enable=import-error
except ImportError:
error( 'plot requires networkx, matplotlib and pygraphviz - '
'please install them and try again\n' )
+2 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"clusterdemo.py: demo of Mininet Cluster Edition prototype"
@@ -13,13 +13,12 @@ def demo():
"Simple Demo of Cluster Mode"
servers = [ 'localhost', 'ubuntu2', 'ubuntu3' ]
topo = TreeTopo( depth=3, fanout=3 )
net = MininetCluster( topo=topo, servers=servers, link=RemoteLink,
net = MininetCluster( topo=topo, servers=servers, Link=RemoteLink,
placement=SwitchBinPlacer )
net.start()
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
demo()
+2 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"clusterperf.py compare the maximum throughput between SSH and GRE tunnels"
@@ -8,7 +8,7 @@ from mininet.log import setLogLevel
def perf(Link):
"Test connectivity nand performance over Link"
net = Mininet( host=RemoteHost, link=Link, waitConnected=True )
net = Mininet( host=RemoteHost, link=Link )
h1 = net.addHost( 'h1')
h2 = net.addHost( 'h2', server='ubuntu2' )
net.addLink( h1, h2 )
@@ -17,7 +17,6 @@ def perf(Link):
net.iperf()
net.stop()
if __name__ == '__main__':
setLogLevel('info')
perf( RemoteSSHLink )
+2 -6
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
consoles.py: bring up a bunch of miniature consoles on a virtual network
@@ -27,7 +27,6 @@ Bob Lantz, April 2010
import re
# pylint: disable=import-error
from Tkinter import Frame, Button, Label, Text, Scrollbar, Canvas, Wm, READABLE
from mininet.log import setLogLevel
@@ -35,9 +34,6 @@ from mininet.topolib import TreeNet
from mininet.term import makeTerms, cleanUpScreens
from mininet.util import quietRun
# pylint: disable=too-many-arguments
class Console( Frame ):
"A simple console on a host."
@@ -323,7 +319,7 @@ class ConsoleApp( Frame ):
if not m:
return
val, units = float( m.group( 1 ) ), m.group( 2 )
# convert to Gbps
#convert to Gbps
if units[0] == 'M':
val *= 10 ** -3
elif units[0] == 'K':
+2 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Create a network where different switches are connected to
@@ -26,9 +26,8 @@ class MultiSwitch( OVSSwitch ):
def start( self, controllers ):
return OVSSwitch.start( self, [ cmap[ self.name ] ] )
topo = TreeTopo( depth=2, fanout=2 )
net = Mininet( topo=topo, switch=MultiSwitch, build=False, waitConnected=True )
net = Mininet( topo=topo, switch=MultiSwitch, build=False )
for c in [ c0, c1 ]:
net.addController(c)
net.build()
+2 -4
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
This example creates a multi-controller network from semi-scratch by
@@ -20,8 +20,7 @@ from mininet.log import setLogLevel, info
def multiControllerNet():
"Create a network from semi-scratch with multiple controllers."
net = Mininet( controller=Controller, switch=OVSSwitch,
waitConnected=True )
net = Mininet( controller=Controller, switch=OVSSwitch )
info( "*** Creating (reference) controllers\n" )
c1 = net.addController( 'c1', port=6633 )
@@ -58,7 +57,6 @@ def multiControllerNet():
info( "*** Stopping network\n" )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' ) # for CLI output
multiControllerNet()
+8 -11
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
controlnet.py: Mininet with a custom control network
@@ -49,7 +49,7 @@ class MininetFacade( object ):
args: unnamed networks passed as arguments
kwargs: named networks passed as arguments"""
self.net = net
self.nets = [ net ] + list( args ) + list( kwargs.values() )
self.nets = [ net ] + list( args ) + kwargs.values()
self.nameToNet = kwargs
self.nameToNet['net'] = net
@@ -59,14 +59,13 @@ class MininetFacade( object ):
def __getitem__( self, key ):
"returns primary/named networks or node from any net"
# search kwargs for net named key
#search kwargs for net named key
if key in self.nameToNet:
return self.nameToNet[ key ]
# search each net for node named key
#search each net for node named key
for net in self.nets:
if key in net:
return net[ key ]
return None
def __iter__( self ):
"Iterate through all nodes in all Mininet objects"
@@ -101,10 +100,10 @@ class MininetFacade( object ):
class ControlNetwork( Topo ):
"Control Network Topology"
# pylint: disable=arguments-differ
def build( self, n, dataController=DataController, **_kwargs ):
def __init__( self, n, dataController=DataController, **kwargs ):
"""n: number of data network controller nodes
dataController: class for data network controllers"""
Topo.__init__( self, **kwargs )
# Connect everything to a single switch
cs0 = self.addSwitch( 'cs0' )
# Add hosts which will serve as data network controllers
@@ -125,8 +124,7 @@ def run():
info( '* Creating Control Network\n' )
ctopo = ControlNetwork( n=4, dataController=DataController )
cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24',
controller=None, waitConnected=True )
cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', controller=None )
info( '* Adding Control Network Controller\n')
cnet.addController( 'cc0', controller=Controller )
info( '* Starting Control Network\n')
@@ -136,8 +134,7 @@ def run():
topo = TreeTopo( depth=2, fanout=2 )
# UserSwitch so we can easily test failover
sw = partial( UserSwitch, opts='--inactivity-probe=1 --max-backoff=1' )
net = Mininet( topo=topo, switch=sw, controller=None,
waitConnected=True )
net = Mininet( topo=topo, switch=sw, controller=None )
info( '* Adding Controllers to Data Network\n' )
for host in cnet.hosts:
if isinstance(host, Controller):
+7 -8
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
cpu.py: test iperf bandwidth for varying cpu limits
@@ -31,9 +31,9 @@ rate includes buffering.
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.topolib import TreeTopo
from mininet.util import custom, waitListening, decode
from mininet.util import custom, waitListening
from mininet.log import setLogLevel, info
from mininet.clean import cleanup
def bwtest( cpuLimits, period_us=100000, seconds=10 ):
"""Example/test of link and CPU bandwidth limits
@@ -52,11 +52,10 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ):
period_us=period_us,
cpu=.5*cpu )
try:
net = Mininet( topo=topo, host=host, waitConnected=True )
net = Mininet( topo=topo, host=host )
# pylint: disable=bare-except
except: # noqa
info( '*** Skipping scheduler %s and cleaning up\n' % sched )
cleanup()
except:
info( '*** Skipping scheduler %s\n' % sched )
break
net.start()
net.pingAll()
@@ -71,7 +70,7 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ):
# ignore empty result from waitListening/telnet
popen.stdout.readline()
client.cmd( 'iperf -yc -t %s -c %s' % ( seconds, server.IP() ) )
result = decode( popen.stdout.readline() ).split( ',' )
result = popen.stdout.readline().split( ',' )
bps = float( result[ -1 ] )
popen.terminate()
net.stop()
+2 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
This example shows how to create an empty Mininet object
@@ -14,7 +14,7 @@ def emptyNet():
"Create an empty network and add nodes to it."
net = Mininet( controller=Controller, waitConnected=True )
net = Mininet( controller=Controller )
info( '*** Adding controller\n' )
net.addController( 'c0' )
@@ -39,7 +39,6 @@ def emptyNet():
info( '*** Stopping network' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
emptyNet()
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/python
"""
fakecluster.py: a fake cluster for testing Mininet cluster edition!!!
We are going to self-host Mininet by creating a virtual cluster
for cluster edition.
Note: ssh is kind of a mess - you end up having to do things
like h1 sudo -E -u openflow ssh 10.2
"""
from mininet.net import Mininet
from mininet.nodelib import LinuxBridge, Server
from mininet.cli import CLI
from mininet.topo import Topo, SingleSwitchTopo
from mininet.log import setLogLevel, warn
from mininet.util import errRun, quietRun
from mininet.link import Link
from functools import partial
from sys import argv
class MininetServer( Server ):
"A server (for nested Mininet) that runs ssh and ovs"
privateDirs = [ '/var/run/sshd', '/etc/openvswitch',
'/var/run/openvswitch', '/var/log/openvswitch' ]
def __init__( self, *args, **kwargs ):
"Turn on ovs by default"
kwargs.setdefault( 'ovs', True )
super( MininetServer, self ).__init__( *args, **kwargs )
def config( self, **kwargs ):
"""Configure/start sshd and other stuff
ovs: start Open vSwitch?"""
self.ovs = kwargs.get( 'ovs' )
super( MininetServer, self ).config( **kwargs )
if self.ovs:
self.service( 'openvswitch-switch start' )
def terminate( self, *args, **kwargs ):
"Shut down services and terminate server"
if self.ovs:
self.service( 'openvswitch-switch stop' )
super( MininetServer, self ).terminate( *args, **kwargs )
class ServerLink( Link ):
def intfName( self, node, n ):
"Override to avoid destruction by cleanup!"
# This is kind of ugly... for some reason 'eth0' fails so
# we just use 'm1eth0'; however, this should nest reasonably.
return ( node.name + 'eth' + repr( n ) if isinstance( node, Server )
else node.name + '-eth' + repr( n ) )
def makeIntfPair( self, *args, **kwargs ):
"Override to use quietRun"
kwargs.update( runCmd=quietRun )
super( ServerLink, self ).makeIntfPair( *args, **kwargs )
class ClusterTopo( Topo ):
"Cluster topology: m1..mN"
def build( self, n ):
ms1 = self.addSwitch( 'ms1' )
for i in range( 1, n + 1 ):
h = self.addHost( 'm%d' % i )
self.addLink( h, ms1, cls=ServerLink )
def test( serverCount ):
"Test this setup"
setLogLevel( 'info' )
topo = ClusterTopo( serverCount )
host = partial( MininetServer, ssh=True, ovs=True)
net = Mininet( topo=topo, host=host, switch=LinuxBridge, ipBase='10.0/24' )
MininetServer.updateHostsFiles( net.hosts )
# addNAT().configDefault() also connects root namespace to Mininet
net.addNAT().configDefault()
net.start()
CLI( net )
net.stop()
if __name__ == '__main__':
n = 8 if len( argv ) != 2 else int( argv[ 1 ] )
test( n )
+2 -6
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
This example shows how to add an interface (for example a real
@@ -8,8 +8,6 @@ hardware interface) to a network after the network is created.
import re
import sys
from sys import exit # pylint: disable=redefined-builtin
from mininet.cli import CLI
from mininet.log import setLogLevel, info, error
from mininet.net import Mininet
@@ -17,7 +15,6 @@ from mininet.link import Intf
from mininet.topolib import TreeTopo
from mininet.util import quietRun
def checkIntf( intf ):
"Make sure intf exists and is not configured."
config = quietRun( 'ifconfig %s 2>/dev/null' % intf, shell=True )
@@ -30,7 +27,6 @@ def checkIntf( intf ):
'and is probably in use!\n' )
exit( 1 )
if __name__ == '__main__':
setLogLevel( 'info' )
@@ -42,7 +38,7 @@ if __name__ == '__main__':
checkIntf( intfName )
info( '*** Creating network\n' )
net = Mininet( topo=TreeTopo( depth=1, fanout=2 ), waitConnected=True )
net = Mininet( topo=TreeTopo( depth=1, fanout=2 ) )
switch = net.switches[ 0 ]
info( '*** Adding hardware interface', intfName, 'to switch',
+5 -6
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
'''
example of using various TCIntf options.
@@ -13,7 +13,7 @@ from mininet.link import TCLink
def intfOptions():
"run various traffic control commands on a single interface"
net = Mininet( autoStaticArp=True, waitConnected=True )
net = Mininet( autoStaticArp=True )
net.addController( 'c0' )
h1 = net.addHost( 'h1' )
h2 = net.addHost( 'h2' )
@@ -25,10 +25,10 @@ def intfOptions():
# flush out latency from reactive forwarding delay
net.pingAll()
info( '\n*** Configuring one intf with bandwidth of 10 Mb\n' )
link1.intf1.config( bw=10 )
info( '\n*** Configuring one intf with bandwidth of 5 Mb\n' )
link1.intf1.config( bw=5 )
info( '\n*** Running iperf to test\n' )
net.iperf( seconds=10 )
net.iperf()
info( '\n*** Configuring one intf with loss of 50%\n' )
link1.intf1.config( loss=50 )
@@ -43,7 +43,6 @@ def intfOptions():
info( '\n*** Done testing\n' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
intfOptions()
+3 -4
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
limit.py: example of using link and CPU limits
@@ -34,7 +34,7 @@ def limit( bw=10, cpu=.1 ):
'Skipping this test\n' )
continue
host = custom( CPULimitedHost, sched=sched, cpu=cpu )
net = Mininet( topo=myTopo, intf=intf, host=host, waitConnected=True )
net = Mininet( topo=myTopo, intf=intf, host=host )
net.start()
testLinkLimit( net, bw=bw )
net.runCpuLimitTest( cpu=cpu )
@@ -43,7 +43,7 @@ def limit( bw=10, cpu=.1 ):
def verySimpleLimit( bw=150 ):
"Absurdly simple limiting test"
intf = custom( TCIntf, bw=bw )
net = Mininet( intf=intf, waitConnected=True )
net = Mininet( intf=intf )
h1, h2 = net.addHost( 'h1' ), net.addHost( 'h2' )
net.addLink( h1, h2 )
net.start()
@@ -55,7 +55,6 @@ def verySimpleLimit( bw=150 ):
h2.cmdPrint( 'tc -d class show dev', h2.defaultIntf() )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
limit()
+15 -16
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Test bandwidth (using iperf) on linear networks of varying size,
@@ -24,25 +24,25 @@ of switches, this example demonstrates:
"""
import sys
from functools import partial
from mininet.net import Mininet
from mininet.node import UserSwitch, OVSKernelSwitch, Controller
from mininet.topo import Topo
from mininet.log import lg, info
from mininet.util import irange, quietRun
from mininet.link import TCLink
from functools import partial
import sys
flush = sys.stdout.flush
class LinearTestTopo( Topo ):
"Topology for a string of N hosts and N-1 switches."
# pylint: disable=arguments-differ
def build( self, N, **params ):
def __init__( self, N, **params ):
# Initialize topology
Topo.__init__( self, **params )
# Create switches and hosts
hosts = [ self.addHost( 'h%s' % h )
for h in irange( 1, N ) ]
@@ -83,14 +83,14 @@ def linearBandwidthTest( lengths ):
output = quietRun( 'sysctl -w net.ipv4.tcp_congestion_control=reno' )
assert 'reno' in output
for datapath in switches:
for datapath in switches.keys():
info( "*** testing", datapath, "datapath\n" )
Switch = switches[ datapath ]
results[ datapath ] = []
link = partial( TCLink, delay='30ms', bw=100 )
link = partial( TCLink, delay='2ms', bw=10 )
net = Mininet( topo=topo, switch=Switch,
controller=Controller, link=link,
waitConnected=True )
controller=Controller, waitConnected=True,
link=link )
net.start()
info( "*** testing basic connectivity\n" )
for n in lengths:
@@ -103,13 +103,13 @@ def linearBandwidthTest( lengths ):
src.cmd( 'telnet', dst.IP(), '5001' )
info( "testing", src.name, "<->", dst.name, '\n' )
# serverbw = received; _clientbw = buffered
serverbw, _clientbw = net.iperf( [ src, dst ], seconds=5 )
serverbw, _clientbw = net.iperf( [ src, dst ], seconds=10 )
info( serverbw, '\n' )
flush()
results[ datapath ] += [ ( n, serverbw ) ]
net.stop()
for datapath in switches:
for datapath in switches.keys():
info( "\n*** Linear network results for", datapath, "datapath:\n" )
result = results[ datapath ]
info( "SwitchCount\tiperf Results\n" )
@@ -119,9 +119,8 @@ def linearBandwidthTest( lengths ):
info( '\n')
info( '\n' )
if __name__ == '__main__':
lg.setLogLevel( 'info' )
sizes = [ 1, 2, 3, 4 ]
sizes = [ 1, 10, 20, 40, 60, 80 ]
info( "*** Running linearBandwidthTest", sizes, '\n' )
linearBandwidthTest( sizes )
+2 -6
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
linuxrouter.py: Example network with Linux IP router
@@ -38,7 +38,6 @@ from mininet.cli import CLI
class LinuxRouter( Node ):
"A Node with IP forwarding enabled."
# pylint: disable=arguments-differ
def config( self, **params ):
super( LinuxRouter, self).config( **params )
# Enable forwarding on the router
@@ -52,7 +51,6 @@ class LinuxRouter( Node ):
class NetworkTopo( Topo ):
"A LinuxRouter connecting three IP subnets"
# pylint: disable=arguments-differ
def build( self, **_opts ):
defaultIP = '192.168.1.1/24' # IP address for r0-eth1
@@ -81,15 +79,13 @@ class NetworkTopo( Topo ):
def run():
"Test linux router"
topo = NetworkTopo()
net = Mininet( topo=topo,
waitConnected=True ) # controller is used by s1-s3
net = Mininet( topo=topo ) # controller is used by s1-s3
net.start()
info( '*** Routing Table on Router:\n' )
info( net[ 'r0' ].cmd( 'route' ) )
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
run()
+80 -99
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
MiniEdit: a simple network editor for Mininet
@@ -13,72 +13,57 @@ Controller icon from http://semlabs.co.uk/
OpenFlow icon from https://www.opennetworking.org/
"""
import json
import os
import re
import sys
# Miniedit needs some work in order to pass pylint...
# pylint: disable=line-too-long,too-many-branches
# pylint: disable=too-many-statements,attribute-defined-outside-init
# pylint: disable=missing-docstring
MINIEDIT_VERSION = '2.2.0.1'
from distutils.version import StrictVersion
from functools import partial
from optparse import OptionParser
# from Tkinter import *
from Tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu, Checkbutton,
Menu, Toplevel, Button, BitmapImage, PhotoImage, Canvas,
Scrollbar, Wm, TclError, StringVar, IntVar,
E, W, EW, NW, Y, VERTICAL, SOLID, CENTER,
RIGHT, LEFT, BOTH, TRUE, FALSE )
from ttk import Notebook
from tkMessageBox import showerror
from subprocess import call
from sys import exit # pylint: disable=redefined-builtin
import tkFont
import tkFileDialog
import tkSimpleDialog
import re
import json
from distutils.version import StrictVersion
import os
import sys
from functools import partial
if 'PYTHONPATH' in os.environ:
sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
# someday: from ttk import *
from mininet.log import info, debug, warn, setLogLevel
from mininet.net import Mininet, VERSION
from mininet.util import (netParse, ipAdd, quietRun,
buildTopo, custom, customClass )
from mininet.util import netParse, ipAdd, quietRun
from mininet.util import buildTopo
from mininet.util import custom, customClass
from mininet.term import makeTerm, cleanUpScreens
from mininet.node import (Controller, RemoteController, NOX, OVSController,
CPULimitedHost, Host, Node,
OVSSwitch, UserSwitch, IVSSwitch )
from mininet.node import Controller, RemoteController, NOX, OVSController
from mininet.node import CPULimitedHost, Host, Node
from mininet.node import OVSSwitch, UserSwitch
from mininet.link import TCLink, Intf, Link
from mininet.cli import CLI
from mininet.moduledeps import moduleDeps
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
from mininet.topolib import TreeTopo
# pylint: disable=import-error
if sys.version_info[0] == 2:
from Tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu,
Checkbutton, Menu, Toplevel, Button, BitmapImage,
PhotoImage, Canvas, Scrollbar, Wm, TclError,
StringVar, IntVar, E, W, EW, NW, Y, VERTICAL, SOLID,
CENTER, RIGHT, LEFT, BOTH, TRUE, FALSE )
from ttk import Notebook
from tkMessageBox import showerror
import tkFont
import tkFileDialog
import tkSimpleDialog
else:
from tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu,
Checkbutton, Menu, Toplevel, Button, BitmapImage,
PhotoImage, Canvas, Scrollbar, Wm, TclError,
StringVar, IntVar, E, W, EW, NW, Y, VERTICAL, SOLID,
CENTER, RIGHT, LEFT, BOTH, TRUE, FALSE )
from tkinter.ttk import Notebook
from tkinter.messagebox import showerror
from tkinter import font as tkFont
from tkinter import simpledialog as tkSimpleDialog
from tkinter import filedialog as tkFileDialog
# someday: from ttk import *
# pylint: enable=import-error
# Miniedit still needs work in order to pass pylint...
# pylint: disable=line-too-long,too-many-branches
# pylint: disable=too-many-statements,attribute-defined-outside-init
# pylint: disable=missing-docstring,too-many-ancestors
# pylint: disable=too-many-nested-blocks,too-many-arguments
MINIEDIT_VERSION = '2.2.0.1'
if 'PYTHONPATH' in os.environ:
sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
info( 'MiniEdit running against Mininet '+VERSION, '\n' )
MININET_VERSION = re.sub(r'[^\d\.]', '', VERSION)
if StrictVersion(MININET_VERSION) > StrictVersion('2.0'):
from mininet.node import IVSSwitch
TOPODEF = 'none'
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
@@ -138,7 +123,6 @@ class LegacyRouter( Node ):
def __init__( self, name, inNamespace=True, **params ):
Node.__init__( self, name, inNamespace, **params )
# pylint: disable=arguments-differ
def config( self, **_params ):
if self.intfs:
self.setParam( _params, 'setIP', ip='0.0.0.0' )
@@ -819,8 +803,8 @@ class VerticalScrolledTable(LabelFrame):
* This frame only allows vertical scrolling
"""
def __init__(self, parent, rows=2, columns=2, title=None, **kw):
LabelFrame.__init__(self, parent, text=title, padx=5, pady=5, **kw)
def __init__(self, parent, rows=2, columns=2, title=None, *args, **kw):
LabelFrame.__init__(self, parent, text=title, padx=5, pady=5, *args, **kw)
# create a canvas object and a vertical scrollbar for scrolling it
vscrollbar = Scrollbar(self, orient=VERTICAL)
@@ -856,6 +840,8 @@ class VerticalScrolledTable(LabelFrame):
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
canvas.bind('<Configure>', _configure_canvas)
return
class TableFrame(Frame):
def __init__(self, parent, rows=2, columns=2):
@@ -887,7 +873,7 @@ class TableFrame(Frame):
label.grid(row=self.rows, column=column, sticky="wens", padx=1, pady=1)
if value is not None:
label.insert(0, value[column])
if readonly:
if readonly == True:
label.configure(state='readonly')
current_row.append(label)
self._widgets.append(current_row)
@@ -1400,11 +1386,11 @@ class MiniEdit( Frame ):
def addNode( self, node, nodeNum, x, y, name=None):
"Add a new node to our canvas."
if node == 'Switch':
if 'Switch' == node:
self.switchCount += 1
if node == 'Host':
if 'Host' == node:
self.hostCount += 1
if node == 'Controller':
if 'Controller' == node:
self.controllerCount += 1
if name is None:
name = self.nodePrefixes[ node ] + nodeNum
@@ -1421,17 +1407,14 @@ class MiniEdit( Frame ):
def convertJsonUnicode(self, text):
"Some part of Mininet don't like Unicode"
try:
unicode
except NameError:
return text
if isinstance(text, dict):
return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.items()}
if isinstance(text, list):
return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.iteritems()}
elif isinstance(text, list):
return [self.convertJsonUnicode(element) for element in text]
if isinstance(text, unicode): # pylint: disable=undefined-variable
elif isinstance(text, unicode):
return text.encode('utf-8')
return text
else:
return text
def loadTopology( self ):
"Load command."
@@ -1442,7 +1425,7 @@ class MiniEdit( Frame ):
('All Files','*'),
]
f = tkFileDialog.askopenfile(filetypes=myFormats, mode='rb')
if f is None:
if f == None:
return
self.newTopology()
loadedTopology = self.convertJsonUnicode(json.load(f))
@@ -1603,11 +1586,10 @@ class MiniEdit( Frame ):
for widget in self.widgetToItem:
if name == widget[ 'text' ]:
return widget
return None
def newTopology( self ):
"New command."
for widget in self.widgetToItem:
for widget in self.widgetToItem.keys():
self.deleteItem( self.widgetToItem[ widget ] )
self.hostCount = 0
self.switchCount = 0
@@ -1704,7 +1686,7 @@ class MiniEdit( Frame ):
# debug( "Now saving under %s\n" % fileName )
f = open(fileName, 'wb')
f.write("#!/usr/bin/env python\n")
f.write("#!/usr/bin/python\n")
f.write("\n")
f.write("from mininet.net import Mininet\n")
f.write("from mininet.node import Controller, RemoteController, OVSController\n")
@@ -1728,7 +1710,7 @@ class MiniEdit( Frame ):
if controllerType == 'inband':
inBandCtrl = True
if inBandCtrl:
if inBandCtrl == True:
f.write("\n")
f.write("class InbandController( RemoteController ):\n")
f.write("\n")
@@ -1853,7 +1835,7 @@ class MiniEdit( Frame ):
# Save Links
f.write(" info( '*** Add links\\n')\n")
for key,linkDetail in self.links.items():
for key,linkDetail in self.links.iteritems():
tags = self.canvas.gettags(key)
if 'data' in tags:
optsExist = False
@@ -2125,7 +2107,7 @@ class MiniEdit( Frame ):
c = self.canvas
x, y = c.canvasx( event.x ), c.canvasy( event.y )
name = self.nodePrefixes[ node ]
if node == 'Switch':
if 'Switch' == node:
self.switchCount += 1
name = self.nodePrefixes[ node ] + str( self.switchCount )
self.switchOpts[name] = {}
@@ -2133,14 +2115,14 @@ class MiniEdit( Frame ):
self.switchOpts[name]['hostname']=name
self.switchOpts[name]['switchType']='default'
self.switchOpts[name]['controllers']=[]
if node == 'LegacyRouter':
if 'LegacyRouter' == node:
self.switchCount += 1
name = self.nodePrefixes[ node ] + str( self.switchCount )
self.switchOpts[name] = {}
self.switchOpts[name]['nodeNum']=self.switchCount
self.switchOpts[name]['hostname']=name
self.switchOpts[name]['switchType']='legacyRouter'
if node == 'LegacySwitch':
if 'LegacySwitch' == node:
self.switchCount += 1
name = self.nodePrefixes[ node ] + str( self.switchCount )
self.switchOpts[name] = {}
@@ -2148,13 +2130,13 @@ class MiniEdit( Frame ):
self.switchOpts[name]['hostname']=name
self.switchOpts[name]['switchType']='legacySwitch'
self.switchOpts[name]['controllers']=[]
if node == 'Host':
if 'Host' == node:
self.hostCount += 1
name = self.nodePrefixes[ node ] + str( self.hostCount )
self.hostOpts[name] = {'sched':'host'}
self.hostOpts[name]['nodeNum']=self.hostCount
self.hostOpts[name]['hostname']=name
if node == 'Controller':
if 'Controller' == node:
name = self.nodePrefixes[ node ] + str( self.controllerCount )
ctrlr = { 'controllerType': 'ref',
'hostname': name,
@@ -2172,15 +2154,15 @@ class MiniEdit( Frame ):
self.itemToWidget[ item ] = icon
self.selectItem( item )
icon.links = {}
if node == 'Switch':
if 'Switch' == node:
icon.bind('<Button-3>', self.do_switchPopup )
if node == 'LegacyRouter':
if 'LegacyRouter' == node:
icon.bind('<Button-3>', self.do_legacyRouterPopup )
if node == 'LegacySwitch':
if 'LegacySwitch' == node:
icon.bind('<Button-3>', self.do_legacySwitchPopup )
if node == 'Host':
if 'Host' == node:
icon.bind('<Button-3>', self.do_hostPopup )
if node == 'Controller':
if 'Controller' == node:
icon.bind('<Button-3>', self.do_controllerPopup )
def clickController( self, event ):
@@ -2250,7 +2232,7 @@ class MiniEdit( Frame ):
def clickNode( self, event ):
"Node click handler."
if self.active == 'NetLink':
if self.active is 'NetLink':
self.startLink( event )
else:
self.selectNode( event )
@@ -2258,14 +2240,14 @@ class MiniEdit( Frame ):
def dragNode( self, event ):
"Node drag handler."
if self.active == 'NetLink':
if self.active is 'NetLink':
self.dragNetLink( event )
else:
self.dragNodeAround( event )
def releaseNode( self, event ):
"Node release handler."
if self.active == 'NetLink':
if self.active is 'NetLink':
self.finishLink( event )
# Specific node handlers
@@ -2377,8 +2359,6 @@ class MiniEdit( Frame ):
# For now, don't allow hosts to be directly linked
stags = self.canvas.gettags( self.widgetToItem[ source ] )
dtags = self.canvas.gettags( target )
# TODO: Make this less confusing
# pylint: disable=too-many-boolean-expressions
if (('Host' in stags and 'Host' in dtags) or
('Controller' in dtags and 'LegacyRouter' in stags) or
('Controller' in stags and 'LegacyRouter' in dtags) or
@@ -2662,7 +2642,7 @@ class MiniEdit( Frame ):
linkopts = {}
source.links[ dest ] = self.link
dest.links[ source ] = self.link
self.links[ self.link ] = {'type':linktype,
self.links[ self.link ] = {'type' :linktype,
'src':source,
'dest':dest,
'linkOpts':linkopts}
@@ -2703,13 +2683,14 @@ class MiniEdit( Frame ):
tags = self.canvas.gettags(item)
if 'Controller' in tags:
# remove from switch controller lists
for searchwidget in self.widgetToItem:
name = searchwidget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ searchwidget ] )
for serachwidget in self.widgetToItem:
name = serachwidget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ serachwidget ] )
if 'Switch' in tags:
if widget['text'] in self.switchOpts[name]['controllers']:
self.switchOpts[name]['controllers'].remove(widget['text'])
for link in tuple( widget.links.values() ):
for link in widget.links.values():
# Delete from view and model
self.deleteItem( link )
del self.itemToWidget[ item ]
@@ -2894,7 +2875,7 @@ class MiniEdit( Frame ):
def buildLinks( self, net):
# Make links
info( "Getting Links.\n" )
for key,link in self.links.items():
for key,link in self.links.iteritems():
tags = self.canvas.gettags(key)
if 'data' in tags:
src=link['src']
@@ -3015,7 +2996,7 @@ class MiniEdit( Frame ):
## NOTE: MAKE SURE THIS IS LAST THING CALLED
# Start the CLI if enabled
if self.appPrefs['startCLI'] == '1':
info( "\n\n NOTE: PLEASE REMEMBER TO EXIT THE CLI BEFORE YOU PRESS THE STOP BUTTON. Not exiting will prevent MiniEdit from quitting and will prevent you from starting the network again during this session.\n\n")
info( "\n\n NOTE: PLEASE REMEMBER TO EXIT THE CLI BEFORE YOU PRESS THE STOP BUTTON. Not exiting will prevent MiniEdit from quitting and will prevent you from starting the network again during this sessoin.\n\n")
CLI(self.net)
def start( self ):
@@ -3229,9 +3210,8 @@ class MiniEdit( Frame ):
"Parse custom file and add params before parsing cmd-line options."
customs = {}
if os.path.isfile( fileName ):
with open( fileName, 'r' ) as f:
exec( f.read() ) # pylint: disable=exec-used
for name, val in customs.items():
execfile( fileName, customs, customs )
for name, val in customs.iteritems():
self.setCustom( name, val )
else:
raise Exception( 'could not find custom file: %s' % fileName )
@@ -3597,7 +3577,8 @@ def addDictOption( opts, choicesDict, default, name, helpStr=None ):
if __name__ == '__main__':
setLogLevel( 'info' )
app = MiniEdit()
app.parseArgs()
### import topology if specified ###
app.parseArgs()
app.importTopo()
app.mainloop()
+4 -6
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Simple example of Mobility with Mininet
@@ -19,13 +19,14 @@ to-do:
- think about clearing last hop - why doesn't that work?
"""
from random import randint
from mininet.net import Mininet
from mininet.node import OVSSwitch
from mininet.topo import LinearTopo
from mininet.log import info, output, warn, setLogLevel
from random import randint
class MobilitySwitch( OVSSwitch ):
"Switch that can reattach and rename interfaces"
@@ -37,7 +38,6 @@ class MobilitySwitch( OVSSwitch ):
del self.intfs[ port ]
del self.nameToIntf[ intf.name ]
# pylint: disable=arguments-differ
def addIntf( self, intf, rename=False, **kwargs ):
"Add (and reparent) an interface"
OVSSwitch.addIntf( self, intf, **kwargs )
@@ -107,8 +107,7 @@ def moveHost( host, oldSwitch, newSwitch, newPort=None ):
def mobilityTest():
"A simple test of mobility"
info( '* Simple mobility test\n' )
net = Mininet( topo=LinearTopo( 3 ), switch=MobilitySwitch,
waitConnected=True )
net = Mininet( topo=LinearTopo( 3 ), switch=MobilitySwitch )
info( '* Starting network:\n' )
net.start()
printConnections( net.switches )
@@ -132,7 +131,6 @@ def mobilityTest():
old = new
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
mobilityTest()
+5 -5
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
This is a simple example that demonstrates multiple links
@@ -13,7 +13,7 @@ from mininet.topo import Topo
def runMultiLink():
"Create and run multiple link network"
topo = simpleMultiLinkTopo( n=2 )
net = Mininet( topo=topo, waitConnected=True )
net = Mininet( topo=topo )
net.start()
CLI( net )
net.stop()
@@ -21,8 +21,9 @@ def runMultiLink():
class simpleMultiLinkTopo( Topo ):
"Simple topology with multiple links"
# pylint: disable=arguments-differ
def build( self, n, **_kwargs ):
def __init__( self, n, **kwargs ):
Topo.__init__( self, **kwargs )
h1, h2 = self.addHost( 'h1' ), self.addHost( 'h2' )
s1 = self.addSwitch( 's1' )
@@ -30,7 +31,6 @@ class simpleMultiLinkTopo( Topo ):
self.addLink( s1, h1 )
self.addLink( s1, h2 )
if __name__ == '__main__':
setLogLevel( 'info' )
runMultiLink()
+5 -5
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
multiping.py: monitor multiple sets of hosts using ping
@@ -8,14 +8,14 @@ multiple hosts and monitor their output interactively for a period=
of time.
"""
from select import poll, POLLIN
from time import time
from mininet.net import Mininet
from mininet.node import Node
from mininet.topo import SingleSwitchTopo
from mininet.log import info, setLogLevel
from select import poll, POLLIN
from time import time
def chunks( l, n ):
"Divide list l into chunks of size n - thanks Stackoverflow"
@@ -45,7 +45,7 @@ def multiping( netsize, chunksize, seconds):
# Create network and identify subnets
topo = SingleSwitchTopo( netsize )
net = Mininet( topo=topo, waitConnected=True )
net = Mininet( topo=topo )
net.start()
hosts = net.hosts
subnets = chunks( hosts, chunksize )
@@ -59,7 +59,7 @@ def multiping( netsize, chunksize, seconds):
# Start pings
for subnet in subnets:
ips = [ host.IP() for host in subnet ]
# adding bogus to generate packet loss
#adding bogus to generate packet loss
ips.append( '10.0.0.200' )
for host in subnet:
startpings( host, ips )
+8 -9
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Simple example of sending output to multiple files and
@@ -6,21 +6,20 @@ monitoring them
"""
from time import time
from select import poll, POLLIN
from subprocess import Popen, PIPE
from mininet.topo import SingleSwitchTopo
from mininet.net import Mininet
from mininet.log import info, setLogLevel
from mininet.util import decode
from time import time
from select import poll, POLLIN
from subprocess import Popen, PIPE
def monitorFiles( outfiles, seconds, timeoutms ):
"Monitor set of files and return [(host, line)...]"
devnull = open( '/dev/null', 'w' )
tails, fdToFile, fdToHost = {}, {}, {}
for h, outfile in outfiles.items():
for h, outfile in outfiles.iteritems():
tail = Popen( [ 'tail', '-f', outfile ],
stdout=PIPE, stderr=devnull )
fd = tail.stdout.fileno()
@@ -41,7 +40,7 @@ def monitorFiles( outfiles, seconds, timeoutms ):
host = fdToHost[ fd ]
# Wait for a line of output
line = f.readline().strip()
yield host, decode( line )
yield host, line
else:
# If we timed out, return nothing
yield None, ''
@@ -53,7 +52,7 @@ def monitorFiles( outfiles, seconds, timeoutms ):
def monitorTest( N=3, seconds=3 ):
"Run pings and monitor multiple hosts"
topo = SingleSwitchTopo( N )
net = Mininet( topo, waitConnected=True )
net = Mininet( topo )
net.start()
hosts = net.hosts
info( "Starting test...\n" )
+2 -4
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
This example shows how to create a network and run multiple tests.
@@ -17,14 +17,12 @@ def ifconfigTest( net ):
for host in hosts:
info( host.cmd( 'ifconfig' ) )
if __name__ == '__main__':
lg.setLogLevel( 'info' )
info( "*** Initializing Mininet and kernel modules\n" )
OVSKernelSwitch.setup()
info( "*** Creating network\n" )
network = Mininet( TreeTopo( depth=2, fanout=2), switch=OVSKernelSwitch,
waitConnected=True )
network = Mininet( TreeTopo( depth=2, fanout=2 ), switch=OVSKernelSwitch )
info( "*** Starting network\n" )
network.start()
info( "*** Running ping test\n" )
+2 -2
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Example to create a Mininet topology and connect it to the internet via NAT
@@ -12,7 +12,7 @@ from mininet.topolib import TreeNet
if __name__ == '__main__':
lg.setLogLevel( 'info')
net = TreeNet( depth=1, fanout=4, waitConnected=True )
net = TreeNet( depth=1, fanout=4 )
# Add NAT connectivity
net.addNAT().configDefault()
net.start()
+5 -5
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
natnet.py: Example network with NATs
@@ -27,8 +27,9 @@ from mininet.util import irange
class InternetTopo(Topo):
"Single switch connected to n hosts."
# pylint: disable=arguments-differ
def build(self, n=2, **_kwargs ):
def __init__(self, n=2, **opts):
Topo.__init__(self, **opts)
# set up inet switch
inetSwitch = self.addSwitch('s0')
# add inet host
@@ -58,12 +59,11 @@ class InternetTopo(Topo):
def run():
"Create network and run the CLI"
topo = InternetTopo()
net = Mininet(topo=topo, waitConnected=True )
net = Mininet(topo=topo)
net.start()
CLI(net)
net.stop()
if __name__ == '__main__':
setLogLevel('info')
run()
+2 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Create a network with 5 hosts, numbered 1-4 and 9.
@@ -28,7 +28,7 @@ def testPortNumbering():
mid-level API) and check that implicit and
explicit port numbering works as expected."""
net = Mininet( controller=Controller, waitConnected=True )
net = Mininet( controller=Controller )
info( '*** Adding controller\n' )
net.addController( 'c0' )
@@ -75,7 +75,6 @@ def testPortNumbering():
info( '*** Stopping network\n' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
testPortNumbering()
+8 -5
View File
@@ -1,19 +1,23 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
This example monitors a number of hosts using host.popen() and
pmonitor()
"""
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel, info
from mininet.util import pmonitor
from mininet.util import custom, pmonitor
def monitorhosts( hosts=5 ):
def monitorhosts( hosts=5, sched='cfs' ):
"Start a bunch of pings and monitor them using popen"
mytopo = SingleSwitchTopo( hosts )
net = Mininet( topo=mytopo, waitConnected=True )
cpu = .5 / hosts
myhost = custom( CPULimitedHost, cpu=cpu, sched=sched )
net = Mininet( topo=mytopo, host=myhost )
net.start()
# Start a bunch of pings
popens = {}
@@ -28,7 +32,6 @@ def monitorhosts( hosts=5 ):
# Done
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
monitorhosts( hosts=5 )
+4 -6
View File
@@ -1,20 +1,19 @@
#!/usr/bin/env python
#!/usr/bin/python
"Monitor multiple hosts using popen()/pmonitor()"
from time import time
from signal import SIGINT
from mininet.net import Mininet
from mininet.topo import SingleSwitchTopo
from mininet.util import pmonitor
from mininet.log import setLogLevel, info
from time import time
from signal import SIGINT
def pmonitorTest( N=3, seconds=10 ):
"Run pings and monitor multiple hosts using pmonitor"
topo = SingleSwitchTopo( N )
net = Mininet( topo, waitConnected=True )
net = Mininet( topo )
net.start()
hosts = net.hosts
info( "Starting test...\n" )
@@ -32,7 +31,6 @@ def pmonitorTest( N=3, seconds=10 ):
p.send_signal( SIGINT )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
pmonitorTest()
+2 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Build a simple network from scratch, using mininet primitives.
@@ -8,7 +8,6 @@ but it exposes the configuration details and allows customization.
For most tasks, the higher-level API will be preferable.
"""
from time import sleep
from mininet.net import Mininet
from mininet.node import Node
@@ -16,6 +15,7 @@ from mininet.link import Link
from mininet.log import setLogLevel, info
from mininet.util import quietRun
from time import sleep
def scratchNet( cname='controller', cargs='-v ptcp:' ):
"Create network from scratch using Open vSwitch."
@@ -62,7 +62,6 @@ def scratchNet( cname='controller', cargs='-v ptcp:' ):
switch.deleteIntfs()
info( '\n' )
if __name__ == '__main__':
setLogLevel( 'info' )
info( '*** Scratch network demo (kernel datapath)\n' )
+1 -2
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Build a simple network from scratch, using mininet primitives.
@@ -66,7 +66,6 @@ def scratchNetUser( cname='controller', cargs='ptcp:' ):
switch.deleteIntfs()
info( '\n' )
if __name__ == '__main__':
setLogLevel( 'info' )
info( '*** Scratch network demo (user datapath)\n' )
+2 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Simple example of setting network and CPU parameters
@@ -9,7 +9,6 @@ iperf will hang indefinitely if the TCP handshake fails
to complete.
"""
from sys import argv
from mininet.topo import Topo
from mininet.net import Mininet
@@ -18,6 +17,7 @@ from mininet.link import TCLink
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel, info
from sys import argv
# It would be nice if we didn't have to do this:
# pylint: disable=arguments-differ
@@ -54,7 +54,6 @@ def perfTest( lossy=True ):
net.iperf( ( h1, h4 ), l4Type='UDP' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
# Prevent test_simpleperf from failing due to packet loss
+2 -4
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Create a network and start sshd(8) on each host.
@@ -29,7 +29,7 @@ from mininet.util import waitListening
def TreeNet( depth=1, fanout=2, **kwargs ):
"Convenience function for creating tree networks."
topo = TreeTopo( depth, fanout )
return Mininet( topo, waitConnected=True, **kwargs )
return Mininet( topo, **kwargs )
def connectToRootNS( network, switch, ip, routes ):
"""Connect hosts to root namespace via switch. Starts network.
@@ -47,7 +47,6 @@ def connectToRootNS( network, switch, ip, routes ):
for route in routes:
root.cmd( 'route add -net ' + route + ' dev ' + str( intf ) )
# pylint: disable=too-many-arguments
def sshd( network, cmd='/usr/sbin/sshd', opts='-D',
ip='10.123.123.1/32', routes=None, switch=None ):
"""Start a network, connect it to root ns, and run sshd on all hosts.
@@ -74,7 +73,6 @@ def sshd( network, cmd='/usr/sbin/sshd', opts='-D',
host.cmd( 'kill %' + cmd )
network.stop()
if __name__ == '__main__':
lg.setLogLevel( 'info')
net = TreeNet( depth=1, fanout=4 )
+3 -7
View File
@@ -5,9 +5,8 @@ Tests for baresshd.py
"""
import unittest
from mininet.util import pexpect
import pexpect
from mininet.clean import cleanup, sh
from sys import stdout
class testBareSSHD( unittest.TestCase ):
@@ -15,9 +14,7 @@ class testBareSSHD( unittest.TestCase ):
def connected( self ):
"Log into ssh server, check banner, then exit"
p = pexpect.spawn( 'ssh 10.0.0.1 -o ConnectTimeout=1 '
'-o StrictHostKeyChecking=no '
'-i /tmp/ssh/test_rsa exit' )
p = pexpect.spawn( 'ssh 10.0.0.1 -o StrictHostKeyChecking=no -i /tmp/ssh/test_rsa exit' )
while True:
index = p.expect( self.opts )
if index == 0:
@@ -25,7 +22,6 @@ class testBareSSHD( unittest.TestCase ):
else:
return False
def setUp( self ):
# verify that sshd is not running
self.assertFalse( self.connected() )
@@ -59,7 +55,7 @@ class testBareSSHD( unittest.TestCase ):
def tearDown( self ):
# kill the ssh process
sh( "ps aux | grep ssh |grep Banner| awk '{ print $2 }' | xargs kill" )
sh( "ps aux | grep 'ssh.*Banner' | awk '{ print $2 }' | xargs kill" )
cleanup()
# remove public key pair
sh( 'rm -rf /tmp/ssh' )
+1 -1
View File
@@ -5,7 +5,7 @@ Tests for bind.py
"""
import unittest
from mininet.util import pexpect
import pexpect
class testBind( unittest.TestCase ):
+1 -3
View File
@@ -5,7 +5,7 @@ A simple sanity check test for cluster edition
'''
import unittest
from mininet.util import pexpect
import pexpect
class clusterSanityCheck( unittest.TestCase ):
@@ -14,8 +14,6 @@ class clusterSanityCheck( unittest.TestCase ):
def testClusterPingAll( self ):
p = pexpect.spawn( 'python -m mininet.examples.clusterSanity' )
p.expect( self.prompt )
p.sendline( 'py net.waitConnected()' )
p.expect( self.prompt )
p.sendline( 'pingall' )
p.expect ( '(\d+)% dropped' )
percent = int( p.match.group( 1 ) ) if p.match else -1
+1 -1
View File
@@ -5,7 +5,7 @@ Tests for controllers.py and controllers2.py
"""
import unittest
from mininet.util import pexpect
import pexpect
class testControllers( unittest.TestCase ):
+4 -6
View File
@@ -5,9 +5,7 @@ Test for controlnet.py
"""
import unittest
from mininet.util import pexpect
from sys import stdout
import pexpect
class testControlNet( unittest.TestCase ):
@@ -15,7 +13,7 @@ class testControlNet( unittest.TestCase ):
def testPingall( self ):
"Simple pingall test that verifies 0% packet drop in data network"
p = pexpect.spawn( 'python -m mininet.examples.controlnet', logfile=stdout)
p = pexpect.spawn( 'python -m mininet.examples.controlnet' )
p.expect( self.prompt )
p.sendline( 'pingall' )
p.expect ( '(\d+)% dropped' )
@@ -28,9 +26,9 @@ class testControlNet( unittest.TestCase ):
def testFailover( self ):
"Kill controllers and verify that switch, s1, fails over properly"
count = 1
p = pexpect.spawn( 'python -m mininet.examples.controlnet', logfile=stdout )
p = pexpect.spawn( 'python -m mininet.examples.controlnet' )
p.expect( self.prompt )
lp = pexpect.spawn( 'tail -f /tmp/s1-ofp.log', logfile=stdout )
lp = pexpect.spawn( 'tail -f /tmp/s1-ofp.log' )
lp.expect( 'tcp:\d+\.\d+\.\d+\.(\d+):\d+: connected' )
ip = int( lp.match.group( 1 ) )
self.assertEqual( count, ip )
+1 -1
View File
@@ -15,7 +15,7 @@ cfs 10% 1.29e+09
"""
import unittest
from mininet.util import pexpect
import pexpect
import sys
class testCPU( unittest.TestCase ):
+1 -1
View File
@@ -5,7 +5,7 @@ Test for emptynet.py
"""
import unittest
from mininet.util import pexpect
import pexpect
class testEmptyNet( unittest.TestCase ):
+1 -1
View File
@@ -7,7 +7,7 @@ Test for hwintf.py
import unittest
import re
from mininet.util import pexpect
import pexpect
from mininet.log import setLogLevel
from mininet.node import Node
+5 -7
View File
@@ -5,7 +5,7 @@ Test for intfOptions.py
"""
import unittest
from mininet.util import pexpect
import pexpect
import sys
class testIntfOptions( unittest.TestCase ):
@@ -13,7 +13,7 @@ class testIntfOptions( unittest.TestCase ):
def testIntfOptions( self ):
"verify that intf.config is correctly limiting traffic"
p = pexpect.spawn( 'python -m mininet.examples.intfoptions ' )
tolerance = .25 # plus or minus 25% for cloud CI tests
tolerance = .2 # plus or minus 20%
opts = [ "Results: \['([\d\.]+) .bits/sec",
"Results: \['10M', '([\d\.]+) .bits/sec",
"h(\d+)->h(\d+): (\d)/(\d),"
@@ -22,7 +22,7 @@ class testIntfOptions( unittest.TestCase ):
while True:
index = p.expect( opts, timeout=600 )
if index == 0:
BW = 10
BW = 5
bw = float( p.match.group( 1 ) )
self.assertGreaterEqual( bw, BW * ( 1 - tolerance ) )
self.assertLessEqual( bw, BW * ( 1 + tolerance ) )
@@ -30,10 +30,8 @@ class testIntfOptions( unittest.TestCase ):
BW = 10
measuredBw = float( p.match.group( 1 ) )
loss = ( measuredBw / BW ) * 100
self.assertGreaterEqual( loss, 50 * ( 1 - tolerance ),
'loss of %d%% << 50%%' % loss )
self.assertLessEqual( loss, 50 * ( 1 + tolerance ),
'loss of %d%% >> 50%%' % loss )
self.assertGreaterEqual( loss, 50 * ( 1 - tolerance ) )
self.assertLessEqual( loss, 50 * ( 1 + tolerance ) )
elif index == 2:
delay = float( p.match.group( 6 ) )
self.assertGreaterEqual( delay, 15 * ( 1 - tolerance ) )
+1 -1
View File
@@ -5,7 +5,7 @@ Test for limit.py
"""
import unittest
from mininet.util import pexpect
import pexpect
import sys
class testLimit( unittest.TestCase ):
+1 -1
View File
@@ -5,7 +5,7 @@ Test for linearbandwidth.py
"""
import unittest
from mininet.util import pexpect
import pexpect
import sys
class testLinearBandwidth( unittest.TestCase ):
+1 -1
View File
@@ -5,7 +5,7 @@ Test for linuxrouter.py
"""
import unittest
from mininet.util import pexpect
import pexpect
from mininet.util import quietRun
class testLinuxRouter( unittest.TestCase ):
+1 -1
View File
@@ -6,7 +6,7 @@ validates mininet interfaces against systems interfaces
'''
import unittest
from mininet.util import pexpect
import pexpect
class testMultiLink( unittest.TestCase ):
+5 -7
View File
@@ -5,7 +5,7 @@ Test for multiping.py
"""
import unittest
from mininet.util import pexpect
import pexpect
from collections import defaultdict
class testMultiPing( unittest.TestCase ):
@@ -31,20 +31,18 @@ class testMultiPing( unittest.TestCase ):
target = p.match.group(3)
received = int( p.match.group(4) )
if target == '10.0.0.200':
self.assertEqual( received, 0, p.match.group(0) + '\n' +
target + ' received %d != 0 packets' % received )
self.assertEqual( received, 0 )
else:
self.assertEqual( received, 1, p.match.group(0) + '\n' +
target + ' received %d != 1 packets' % received )
self.assertEqual( received, 1 )
try:
pings[ name ].remove( target )
except:
pass
else:
break
self.assertTrue( len( pings ) > 0, 'too few pings' )
self.assertTrue( len( pings ) > 0 )
for t in pings.values():
self.assertEqual( len( t ), 0, 'missed ping target(s): %s' % t )
self.assertEqual( len( t ), 0 )
if __name__ == '__main__':
unittest.main()
+1 -1
View File
@@ -5,7 +5,7 @@ Test for multipoll.py
"""
import unittest
from mininet.util import pexpect
import pexpect
class testMultiPoll( unittest.TestCase ):
+1 -1
View File
@@ -5,7 +5,7 @@ Test for multitest.py
"""
import unittest
from mininet.util import pexpect
import pexpect
class testMultiTest( unittest.TestCase ):
+1 -1
View File
@@ -5,7 +5,7 @@ Test for nat.py
"""
import unittest
from mininet.util import pexpect
import pexpect
from mininet.util import quietRun
destIP = '8.8.8.8' # Google DNS
Executable → Regular
+1 -1
View File
@@ -5,7 +5,7 @@ Test for natnet.py
"""
import unittest
from mininet.util import pexpect
import pexpect
from mininet.util import quietRun
class testNATNet( unittest.TestCase ):
+1 -1
View File
@@ -5,7 +5,7 @@ Test for numberedports.py
"""
import unittest
from mininet.util import pexpect
import pexpect
from collections import defaultdict
from mininet.node import OVSSwitch
+1 -1
View File
@@ -5,7 +5,7 @@ Test for popen.py and popenpoll.py
"""
import unittest
from mininet.util import pexpect
import pexpect
class testPopen( unittest.TestCase ):
+1 -2
View File
@@ -5,7 +5,7 @@ Test for scratchnet.py
"""
import unittest
from mininet.util import pexpect
import pexpect
class testScratchNet( unittest.TestCase ):
@@ -16,7 +16,6 @@ class testScratchNet( unittest.TestCase ):
p = pexpect.spawn( 'python -m %s' % name )
index = p.expect( self.opts, timeout=120 )
self.assertEqual( index, 0 )
p.wait()
def testPingKernel( self ):
self.pingTest( 'mininet.examples.scratchnet' )
+2 -2
View File
@@ -5,7 +5,7 @@ Test for simpleperf.py
"""
import unittest
from mininet.util import pexpect
import pexpect
import sys
from mininet.log import setLogLevel
@@ -18,7 +18,7 @@ class testSimplePerf( unittest.TestCase ):
"Run the example and verify iperf results"
# 10 Mb/s, plus or minus 20% tolerance
BW = 10
TOLERANCE = .2
TOLERANCE = .2
p = pexpect.spawn( 'python -m mininet.examples.simpleperf testmode' )
# check iperf results
p.expect( "Results: \['10M', '([\d\.]+) .bits/sec", timeout=480 )
+3 -3
View File
@@ -5,7 +5,7 @@ Test for sshd.py
"""
import unittest
from mininet.util import pexpect
import pexpect
from mininet.clean import sh
class testSSHD( unittest.TestCase ):
@@ -16,8 +16,7 @@ class testSSHD( unittest.TestCase ):
"Log into ssh server, check banner, then exit"
# Note: this test will fail if "Welcome" is not in the sshd banner
# and '#'' or '$'' are not in the prompt
ssh = 'ssh -o StrictHostKeyChecking=no -i /tmp/ssh/test_rsa ' + ip
p = pexpect.spawn( ssh, timeout=5 )
p = pexpect.spawn( 'ssh -i /tmp/ssh/test_rsa %s' % ip, timeout=10 )
while True:
index = p.expect( self.opts )
if index == 0:
@@ -58,3 +57,4 @@ class testSSHD( unittest.TestCase ):
if __name__ == '__main__':
unittest.main()
+1 -1
View File
@@ -5,7 +5,7 @@ Test for tree1024.py
"""
import unittest
from mininet.util import pexpect
import pexpect
import sys
class testTree1024( unittest.TestCase ):
+1 -1
View File
@@ -5,7 +5,7 @@ Test for treeping64.py
"""
import unittest
from mininet.util import pexpect
import pexpect
import sys
class testTreePing64( unittest.TestCase ):
Executable → Regular
+1 -1
View File
@@ -5,7 +5,7 @@ Test for vlanhost.py
"""
import unittest
from mininet.util import pexpect
import pexpect
import sys
from mininet.util import quietRun
+2 -4
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python
"""
Create a 1024-host network, and run the CLI on it.
@@ -11,10 +11,8 @@ from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.node import OVSSwitch
from mininet.topolib import TreeNet
from mininet.examples.treeping64 import HostV4
if __name__ == '__main__':
setLogLevel( 'info' )
network = TreeNet( depth=2, fanout=32, host=HostV4,
switch=OVSSwitch, waitConnected=True)
network = TreeNet( depth=2, fanout=32, switch=OVSSwitch )
network.run( CLI, network )
+6 -18
View File
@@ -1,35 +1,24 @@
#!/usr/bin/env python
#!/usr/bin/python
"Create a 64-node tree network, and test connectivity using ping."
from mininet.log import setLogLevel, info
from mininet.node import UserSwitch, OVSKernelSwitch, Host
from mininet.node import UserSwitch, OVSKernelSwitch # , KernelSwitch
from mininet.topolib import TreeNet
class HostV4( Host ):
"Try to IPv6 and its awful neighbor discovery"
def __init__( self, *args, **kwargs ):
super( HostV4, self ).__init__( *args, **kwargs )
cfgs = [ 'all.disable_ipv6=1', 'default.disable_ipv6=1',
'default.autoconf=0', 'lo.autoconf=0' ]
for cfg in cfgs:
self.cmd( 'sysctl -w net.ipv6.conf.' + cfg )
def treePing64():
"Run ping test on 64-node tree networks."
results = {}
switches = { 'reference user': UserSwitch,
'Open vSwitch kernel': OVSKernelSwitch }
switches = { # 'reference kernel': KernelSwitch,
'reference user': UserSwitch,
'Open vSwitch kernel': OVSKernelSwitch }
for name in switches:
info( "*** Testing", name, "datapath\n" )
switch = switches[ name ]
network = TreeNet( depth=2, fanout=8, switch=switch,
waitConnected=True )
network = TreeNet( depth=2, fanout=8, switch=switch )
result = network.run( network.pingAll )
results[ name ] = result
@@ -38,7 +27,6 @@ def treePing64():
info( "%s: %d%% packet loss\n" % ( name, results[ name ] ) )
info( '\n' )
if __name__ == '__main__':
setLogLevel( 'info' )
treePing64()
+2 -8
View File
@@ -24,18 +24,14 @@ Usage (example uses VLAN ID=1000):
"""
from sys import exit # pylint: disable=redefined-builtin
from mininet.node import Host
from mininet.topo import Topo
from mininet.util import quietRun
from mininet.log import error
class VLANHost( Host ):
"Host connected to VLAN interface"
# pylint: disable=arguments-differ
def config( self, vlan=100, **params ):
"""Configure VLANHost according to (optional) parameters:
vlan: VLAN ID for default interface"""
@@ -58,7 +54,6 @@ class VLANHost( Host ):
return r
hosts = { 'vlan': VLANHost }
@@ -70,7 +65,7 @@ def exampleAllHosts( vlan ):
# Start a basic network using our VLANHost
topo = SingleSwitchTopo( k=2 )
net = Mininet( host=host, topo=topo, waitConnected=True )
net = Mininet( host=host, topo=topo )
net.start()
CLI( net )
net.stop()
@@ -101,12 +96,11 @@ class VLANStarTopo( Topo ):
def exampleCustomTags():
"""Simple example that exercises VLANStarTopo"""
net = Mininet( topo=VLANStarTopo(), waitConnected=True )
net = Mininet( topo=VLANStarTopo() )
net.start()
CLI( net )
net.stop()
if __name__ == '__main__':
import sys
from functools import partial
+8 -8
View File
@@ -16,25 +16,24 @@ import time
from mininet.log import info
from mininet.term import cleanUpScreens
from mininet.util import decode
def sh( cmd ):
"Print a command and send it to the shell"
info( cmd + '\n' )
result = Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
return decode( result )
return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
def killprocs( pattern ):
"Reliably terminate processes matching a pattern (including args)"
sh( 'pkill -9 -f %s' % pattern )
# Make sure they are gone
while True:
try:
pids = co( [ 'pgrep', '-f', pattern ] )
pids = co( [ 'pgrep', '-f', pattern ] ).split( '\n' )
except CalledProcessError:
pids = ''
pids = []
# Don't kill init
pids = [ pid for pid in pids if pid and pid != '1' ]
if pids:
sh( 'pkill -9 -f %s' % pattern )
sh( "kill -9 %s" % ' '.join( pids ) )
time.sleep( .5 )
else:
break
@@ -77,6 +76,7 @@ class Cleanup( object ):
for dp in dps:
if dp:
sh( 'dpctl deldp ' + dp )
info( "*** Removing OVS datapaths\n" )
dps = sh("ovs-vsctl --timeout=1 list-br").strip().splitlines()
if dps:
+7 -31
View File
@@ -29,8 +29,6 @@ from subprocess import call
from cmd import Cmd
from os import isatty
from select import poll, POLLIN
import select
import errno
import sys
import time
import os
@@ -46,8 +44,7 @@ class CLI( Cmd ):
prompt = 'mininet> '
def __init__( self, mininet, stdin=sys.stdin, script=None,
**kwargs ):
def __init__( self, mininet, stdin=sys.stdin, script=None ):
"""Start and run interactive or batch mode CLI
mininet: Mininet network object
stdin: standard input for CLI
@@ -56,10 +53,11 @@ class CLI( Cmd ):
# Local variable bindings for py command
self.locals = { 'net': mininet }
# Attempt to handle input
self.stdin = stdin
self.inPoller = poll()
self.inPoller.register( stdin )
self.inputFile = script
Cmd.__init__( self, stdin=stdin, **kwargs )
Cmd.__init__( self )
info( '*** Starting CLI:\n' )
if self.inputFile:
@@ -79,7 +77,6 @@ class CLI( Cmd ):
return
cls.readlineInited = True
try:
# pylint: disable=import-outside-toplevel
from readline import ( read_history_file, write_history_file,
set_history_length )
except ImportError:
@@ -89,15 +86,7 @@ class CLI( Cmd ):
if os.path.isfile( history_path ):
read_history_file( history_path )
set_history_length( 1000 )
def writeHistory():
"Write out history file"
try:
write_history_file( history_path )
except IOError:
# Ignore probably spurious IOError
pass
atexit.register( writeHistory )
atexit.register( lambda: write_history_file( history_path ) )
def run( self ):
"Run our cmdloop(), catching KeyboardInterrupt"
@@ -150,10 +139,10 @@ class CLI( Cmd ):
' mininet> xterm h2\n\n'
)
def do_help( self, line ): # pylint: disable=arguments-differ
def do_help( self, line ):
"Describe available CLI commands."
Cmd.do_help( self, line )
if line == '':
if line is '':
output( self.helpStr )
def do_nodes( self, _line ):
@@ -182,7 +171,6 @@ class CLI( Cmd ):
"""Evaluate a Python expression.
Node names may be used, e.g.: py h1.cmd('ls')"""
try:
# pylint: disable=eval-used
result = eval( line, globals(), self.getLocals() )
if not result:
return
@@ -409,10 +397,6 @@ class CLI( Cmd ):
error( 'invalid command: '
'switch <switch name> {start, stop}\n' )
def do_wait( self, _line ):
"Wait until all switches have connected to a controller"
self.mn.waitConnected()
def default( self, line ):
"""Called on an input line when the command prefix is not recognized.
Overridden to run shell commands when a node is the first
@@ -458,7 +442,7 @@ class CLI( Cmd ):
# XXX BL: this doesn't quite do what we want.
if False and self.inputFile:
key = self.inputFile.read( 1 )
if key != '':
if key is not '':
node.write( key )
else:
self.inputFile = None
@@ -475,13 +459,6 @@ class CLI( Cmd ):
# it's possible to interrupt ourselves after we've
# read data but before it has been printed.
node.sendInt()
except select.error as e:
# pylint: disable=unpacking-non-sequence
# pylint: disable=unbalanced-tuple-unpacking
errno_, errmsg = e.args
if errno_ != errno.EINTR:
error( "select.error: %s, %s" % (errno_, errmsg) )
node.sendInt()
def precmd( self, line ):
"allow for comments in the cli"
@@ -498,4 +475,3 @@ def isReadable( poller ):
mask = fdmask[ 1 ]
if mask & POLLIN:
return True
return False
+37 -40
View File
@@ -24,14 +24,11 @@ TCIntf: interface with bandwidth limiting and delay via tc
Link: basic link class for creating veth pairs
"""
import re
from mininet.log import info, error, debug
from mininet.util import makeIntfPair
# Make pylint happy:
# pylint: disable=too-many-arguments
from mininet.util import makeIntfPair, quietRun
import mininet.node
import re
class Intf( object ):
@@ -151,9 +148,6 @@ class Intf( object ):
def rename( self, newname ):
"Rename interface"
if self.node and self.name in self.node.nameToIntf:
# rename intf in node's nameToIntf
self.node.nameToIntf[newname] = self.node.nameToIntf.pop(self.name)
self.ifconfig( 'down' )
result = self.cmd( 'ip link set', self.name, 'name', newname )
self.name = newname
@@ -172,10 +166,10 @@ class Intf( object ):
method: config method name
param: arg=value (ignore if value=None)
value may also be list or dict"""
name, value = list( param.items() )[ 0 ]
name, value = param.items()[ 0 ]
f = getattr( self, method, None )
if not f or value is None:
return None
return
if isinstance( value, list ):
result = f( *value )
elif isinstance( value, dict ):
@@ -293,14 +287,18 @@ class TCIntf( Intf ):
loss=None, max_queue_size=None ):
"Internal method: return tc commands for delay and loss"
cmds = []
if loss and ( loss < 0 or loss > 100 ):
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 %s ' % delay if delay is not None else '',
'%s ' % jitter if jitter is not None else '',
'loss %.5f ' % loss if (loss is not None and loss > 0) else '',
'loss %.5f ' % loss if loss is not None else '',
'limit %d' % max_queue_size if max_queue_size is not None
else '' )
if netemargs:
@@ -316,7 +314,6 @@ class TCIntf( Intf ):
debug(" *** executing command: %s\n" % c)
return self.cmd( c )
# pylint: disable=arguments-differ
def config( self, bw=None, delay=None, jitter=None, loss=None,
gro=False, txo=True, rxo=True,
speedup=0, use_hfsc=False, use_tbf=False,
@@ -357,7 +354,7 @@ class TCIntf( Intf ):
# Question: what happens if we want to reset things?
if ( bw is None and not delay and not loss
and max_queue_size is None ):
return None
return
# Clear existing configuration
tcoutput = self.tc( '%s qdisc show dev %s' )
@@ -413,7 +410,7 @@ class Link( object ):
def __init__( self, node1, node2, port1=None, port2=None,
intfName1=None, intfName2=None, addr1=None, addr2=None,
intf=Intf, cls1=None, cls2=None, params1=None,
params2=None, fast=True, **params ):
params2=None, fast=True ):
"""Create veth link to another node, making two new interfaces.
node1: first node
node2: second node
@@ -423,15 +420,18 @@ class Link( object ):
cls1, cls2: optional interface-specific constructors
intfName1: node1 interface name (optional)
intfName2: node2 interface name (optional)
params1: parameters for interface 1 (optional)
params2: parameters for interface 2 (optional)
**params: additional parameters for both interfaces"""
params1: parameters for interface 1
params2: parameters for interface 2"""
# This is a bit awkward; it seems that having everything in
# params is more orthogonal, but being able to specify
# in-line arguments is more convenient! So we support both.
params1 = dict( params1 ) if params1 else {}
params2 = dict( params2 ) if params2 else {}
if params1 is None:
params1 = {}
if params2 is None:
params2 = {}
# Allow passing in params1=params2
if params2 is params1:
params2 = dict( params1 )
if port1 is not None:
params1[ 'port' ] = port1
if port2 is not None:
@@ -445,10 +445,6 @@ class Link( object ):
if not intfName2:
intfName2 = self.intfName( node2, params2[ 'port' ] )
# Update with remaining parameter list
params1.update( params )
params2.update( params )
self.fast = fast
if fast:
params1.setdefault( 'moveIntfFn', self._ignore )
@@ -470,7 +466,6 @@ class Link( object ):
# All we are is dust in the wind, and our two interfaces
self.intf1, self.intf2 = intf1, intf2
# pylint: enable=too-many-branches
@staticmethod
@@ -486,7 +481,8 @@ class Link( object ):
@classmethod
def makeIntfPair( cls, intfname1, intfname2, addr1=None, addr2=None,
node1=None, node2=None, deleteIntfs=True ):
node1=None, node2=None, deleteIntfs=True,
runCmd=quietRun ):
"""Create pair of interfaces
intfname1: name for interface 1
intfname2: name for interface 2
@@ -499,7 +495,7 @@ class Link( object ):
# Leave this as a class method for now
assert cls
return makeIntfPair( intfname1, intfname2, addr1, addr2, node1, node2,
deleteIntfs=deleteIntfs )
deleteIntfs=deleteIntfs, runCmd=runCmd )
def delete( self ):
"Delete this link"
@@ -539,11 +535,7 @@ class OVSLink( Link ):
def __init__( self, node1, node2, **kwargs ):
"See Link.__init__() for options"
try:
OVSSwitch
except NameError:
# pylint: disable=import-outside-toplevel,cyclic-import
from mininet.node import OVSSwitch
from mininet.node import OVSSwitch
self.isPatchLink = False
if ( isinstance( node1, OVSSwitch ) and
isinstance( node2, OVSSwitch ) ):
@@ -551,7 +543,6 @@ class OVSLink( Link ):
kwargs.update( cls1=OVSIntf, cls2=OVSIntf )
Link.__init__( self, node1, node2, **kwargs )
# pylint: disable=arguments-differ, signature-differs
def makeIntfPair( self, *args, **kwargs ):
"Usually delegated to OVSSwitch"
if self.isPatchLink:
@@ -561,11 +552,17 @@ class OVSLink( Link ):
class TCLink( Link ):
"Link with TC interfaces"
def __init__( self, *args, **kwargs):
kwargs.setdefault( 'cls1', TCIntf )
kwargs.setdefault( 'cls2', TCIntf )
Link.__init__( self, *args, **kwargs)
"Link with symmetric TC interfaces configured via opts"
def __init__( self, node1, node2, port1=None, port2=None,
intfName1=None, intfName2=None,
addr1=None, addr2=None, **params ):
Link.__init__( self, node1, node2, port1=port1, port2=port2,
intfName1=intfName1, intfName2=intfName2,
cls1=TCIntf,
cls2=TCIntf,
addr1=addr1, addr2=addr2,
params1=params,
params2=params )
class TCULink( TCLink ):
+29 -24
View File
@@ -4,7 +4,6 @@ import logging
from logging import Logger
import types
# Create a new loglevel, 'CLI info', which enables a Mininet user to see only
# the output of the commands they execute, plus any errors or warnings. This
# level is in between info and warning. CLI info-level commands should not be
@@ -15,14 +14,13 @@ LEVELS = { 'debug': logging.DEBUG,
'info': logging.INFO,
'output': OUTPUT,
'warning': logging.WARNING,
'warn': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL }
# change this to logging.INFO to get printouts when running unit tests
LOGLEVELDEFAULT = OUTPUT
# default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
#default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
LOGMSGFORMAT = '%(message)s'
@@ -53,7 +51,7 @@ class StreamHandlerNoNewline( logging.StreamHandler ):
self.flush()
except ( KeyboardInterrupt, SystemExit ):
raise
except: # noqa pylint: disable=bare-except
except:
self.handleError( record )
@@ -97,9 +95,9 @@ class MininetLogger( Logger, object ):
__metaclass__ = Singleton
def __init__( self, name="mininet" ):
def __init__( self ):
Logger.__init__( self, name )
Logger.__init__( self, "mininet" )
# create console handler
ch = StreamHandlerNoNewline()
@@ -107,22 +105,30 @@ class MininetLogger( Logger, object ):
formatter = logging.Formatter( LOGMSGFORMAT )
# add formatter to ch
ch.setFormatter( formatter )
# add ch to lg and initialize log level
# add ch to lg
self.addHandler( ch )
self.ch = ch
self.setLogLevel()
def setLogLevel( self, levelname=None ):
"""Setup loglevel.
Convenience function to support lowercase names.
levelName: level name from LEVELS"""
if levelname and levelname not in LEVELS:
print(LEVELS)
raise Exception( 'setLogLevel: unknown levelname %s' % levelname )
level = LEVELS.get( levelname, LOGLEVELDEFAULT )
self.setLevel( level )
self.ch.setLevel( level )
level = LOGLEVELDEFAULT
if levelname is not None:
if levelname not in LEVELS:
raise Exception( 'unknown levelname seen in setLogLevel' )
else:
level = LEVELS.get( levelname, level )
self.setLevel( level )
self.handlers[ 0 ].setLevel( level )
# pylint: disable=method-hidden
# "An attribute inherited from mininet.log hide this method" (sic)
# Not sure why this is occurring - this function definitely gets called.
# See /usr/lib/python2.5/logging/__init__.py; modified from warning()
def output( self, msg, *args, **kwargs ):
"""Log 'msg % args' with severity 'OUTPUT'.
@@ -131,11 +137,14 @@ class MininetLogger( Logger, object ):
logger.warning("Houston, we have a %s", "cli output", exc_info=1)
"""
if getattr( self.manager, 'disabled', 0 ) >= OUTPUT:
if self.manager.disable >= OUTPUT:
return
if self.isEnabledFor( OUTPUT ):
self._log( OUTPUT, msg, args, kwargs )
# pylint: enable=method-hidden
lg = MininetLogger()
# Make things a bit more convenient by adding aliases
# (info, warn, error, debug) and allowing info( 'this', 'is', 'OK' )
@@ -159,14 +168,10 @@ def makeListCompatible( fn ):
setattr( newfn, '__doc__', fn.__doc__ )
return newfn
_loggers = lg.info, lg.output, lg.warn, lg.error, lg.debug
_loggers = tuple( makeListCompatible( logger )
for logger in _loggers )
lg.info, lg.output, lg.warn, lg.error, lg.debug = _loggers
info, output, warn, error, debug = _loggers
# Initialize logger and logging functions
logging.setLoggerClass( MininetLogger )
lg = logging.getLogger( "mininet" )
_loggers = lg.info, lg.output, lg.warning, lg.error, lg.debug
_loggers = tuple( makeListCompatible( logger ) for logger in _loggers )
lg.info, lg.output, lg.warning, lg.error, lg.debug = _loggers
info, output, warning, error, debug = _loggers
warn = warning # alternate/old name
setLogLevel = lg.setLogLevel
+4 -8
View File
@@ -1,11 +1,8 @@
"Module dependency utility functions for Mininet."
from os import environ
from sys import exit # pylint: disable=redefined-builtin
from mininet.util import quietRun, BaseString
from mininet.util import quietRun
from mininet.log import info, error, debug
from os import environ
def lsmod():
"Return output of lsmod."
@@ -21,7 +18,6 @@ def modprobe( mod ):
mod: module string"""
return quietRun( [ 'modprobe', mod ] )
OF_KMOD = 'ofdatapath'
OVS_KMOD = 'openvswitch_mod' # Renamed 'openvswitch' in OVS 1.7+/Linux 3.5+
TUN = 'tun'
@@ -32,9 +28,9 @@ def moduleDeps( subtract=None, add=None ):
add: string or list of module names to add, if not already loaded"""
subtract = subtract if subtract is not None else []
add = add if add is not None else []
if isinstance( subtract, BaseString ):
if isinstance( subtract, basestring ):
subtract = [ subtract ]
if isinstance( add, BaseString ):
if isinstance( add, basestring ):
add = [ add ]
for mod in subtract:
if mod in lsmod():
+15 -23
View File
@@ -89,10 +89,9 @@ method may be called to shut down the network.
import os
import re
import select
import signal
from signal import SIGKILL
import random
from sys import exit # pylint: disable=redefined-builtin
from time import sleep
from itertools import chain, groupby
from math import ceil
@@ -105,16 +104,15 @@ from mininet.nodelib import NAT
from mininet.link import Link, Intf
from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
macColonHex, ipStr, ipParse, netParse, ipAdd,
waitListening, BaseString )
waitListening )
from mininet.term import cleanUpScreens, makeTerms
# Mininet version: should be consistent with README and LICENSE
VERSION = "2.3.0rc2"
VERSION = "2.3.0d1"
class Mininet( object ):
"Network emulation with hosts spawned in network namespaces."
# pylint: disable=too-many-arguments
def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
controller=DefaultController, link=Link, intf=Intf,
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
@@ -137,9 +135,7 @@ class Mininet( object ):
autoStaticArp: set all-pairs static MAC addrs?
autoPinCpus: pin hosts to (real) cores (requires CPULimitedHost)?
listenPort: base listening port to open; will be incremented for
each additional switch in the net if inNamespace=False
waitConnected: wait for switches to Connect?
(False; True/None=wait indefinitely; time(s)=timed wait)"""
each additional switch in the net if inNamespace=False"""
self.topo = topo
self.switch = switch
self.host = host
@@ -178,16 +174,14 @@ class Mininet( object ):
self.build()
def waitConnected( self, timeout=None, delay=.5 ):
"""wait for each switch to connect to a controller
timeout: time to wait, or None or True to wait indefinitely
"""wait for each switch to connect to a controller,
up to 5 seconds
timeout: time to wait, or None to wait indefinitely
delay: seconds to sleep per iteration
returns: True if all switches are connected"""
info( '*** Waiting for switches to connect\n' )
time = 0.0
time = 0
remaining = list( self.switches )
# False: 0s timeout; None: wait forever (preserve 2.2 behavior)
if isinstance( timeout, bool ):
timeout = None if timeout else 0
while True:
for switch in tuple( remaining ):
if switch.connected():
@@ -196,7 +190,7 @@ class Mininet( object ):
if not remaining:
info( '\n' )
return True
if timeout is not None and time >= timeout:
if time > timeout and timeout is not None:
break
sleep( delay )
time += delay
@@ -389,8 +383,8 @@ class Mininet( object ):
params: additional link params (optional)
returns: link object"""
# Accept node objects or names
node1 = node1 if not isinstance( node1, BaseString ) else self[ node1 ]
node2 = node2 if not isinstance( node2, BaseString ) else self[ node2 ]
node1 = node1 if not isinstance( node1, basestring ) else self[ node1 ]
node2 = node2 if not isinstance( node2, basestring ) else self[ node2 ]
options = dict( params )
# Port is optional
if port1 is not None:
@@ -530,7 +524,7 @@ class Mininet( object ):
def stopXterms( self ):
"Kill each xterm."
for term in self.terms:
os.kill( term.pid, signal.SIGKILL )
term.send_signal( SIGKILL )
cleanUpScreens()
def staticArp( self ):
@@ -555,15 +549,14 @@ class Mininet( object ):
switch.start( self.controllers )
started = {}
for swclass, switches in groupby(
sorted( self.switches,
key=lambda s: str( type( s ) ) ), type ):
sorted( self.switches, key=type ), type ):
switches = tuple( switches )
if hasattr( swclass, 'batchStartup' ):
success = swclass.batchStartup( switches )
started.update( { s: s for s in success } )
info( '\n' )
if self.waitConn:
self.waitConnected( self.waitConn )
self.waitConnected()
def stop( self ):
"Stop the controller(s), switches and hosts"
@@ -583,8 +576,7 @@ class Mininet( object ):
info( '*** Stopping %i switches\n' % len( self.switches ) )
stopped = {}
for swclass, switches in groupby(
sorted( self.switches,
key=lambda s: str( type( s ) ) ), type ):
sorted( self.switches, key=type ), type ):
switches = tuple( switches )
if hasattr( swclass, 'batchShutdown' ):
success = swclass.batchShutdown( switches )
+168 -140
View File
@@ -57,22 +57,16 @@ import pty
import re
import signal
import select
from distutils.version import StrictVersion
from re import findall
from subprocess import Popen, PIPE
from sys import exit # pylint: disable=redefined-builtin
from time import sleep
from mininet.log import info, error, warn, debug
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
numCores, retry, mountCgroups, BaseString, decode,
encode, getincrementaldecoder, Python3, which )
numCores, retry, mountCgroups )
from mininet.moduledeps import moduleDeps, pathCheck, TUN
from mininet.link import Link, Intf, TCIntf, OVSIntf
# pylint: disable=too-many-arguments
from re import findall
from distutils.version import StrictVersion
class Node( object ):
"""A virtual network node is simply a shell in a network namespace.
@@ -80,10 +74,11 @@ class Node( object ):
portBase = 0 # Nodes always start with eth0/port0, even in OF 1.0
def __init__( self, name, inNamespace=True, **params ):
def __init__( self, name, **params ):
"""name: name of node
inNamespace: in network namespace?
ns: private namespaces to use ['net','mnt']
privateDirs: list of private directory strings or tuples
overlayDirs: list of overlay directory strings or tuples
params: Node parameters (see config() for details)"""
# Make sure class actually works
@@ -91,21 +86,21 @@ class Node( object ):
self.name = params.get( 'name', name )
self.privateDirs = params.get( 'privateDirs', [] )
self.inNamespace = params.get( 'inNamespace', inNamespace )
self.overlayDirs = params.get( 'overlayDirs', [] )
# Python 3 complains if we don't wait for shell exit
self.waitExited = params.get( 'waitExited', Python3 )
# Support old inNamespace param
self.ns = params.get( 'ns', ( 'net', 'mnt' ) )
inNamespace = params.get( 'inNamespace', True )
if not inNamespace:
self.ns = []
self.inNamespace = 'net' in self.ns
# Stash configuration parameters for future reference
self.params = params
# dict of port numbers to interfacse
self.intfs = {}
# dict of interfaces to port numbers
# todo: replace with Port objects, eventually ?
self.ports = {}
self.intfs = {} # dict of port numbers to interfaces
self.ports = {} # dict of interfaces to port numbers
# replace with Port objects, eventually ?
self.nameToIntf = {} # dict of interface names to Intfs
# Make pylint happy
@@ -115,12 +110,9 @@ class Node( object ):
self.waiting = False
self.readbuf = ''
# Incremental decoder for buffered reading
self.decoder = getincrementaldecoder()
# Start command interpreter shell
self.master, self.slave = None, None # pylint
# Start command interpreter shell and mount any local dirs
self.startShell()
self.mountOverlayDirs()
self.mountPrivateDirs()
# File descriptor to node mapping support
@@ -137,33 +129,33 @@ class Node( object ):
node = cls.outToNode.get( fd )
return node or cls.inToNode.get( fd )
_marker = re.compile( chr( 1 ) + r'(\d+)\r\n' )
# Command support via shell process in namespace
def startShell( self, mnopts=None ):
"Start a shell process for running commands"
if self.shell:
error( "%s: shell is already running\n" % self.name )
return
# mnexec: (c)lose descriptors, (d)etach from tty,
# (p)rint pid, and run in (n)amespace
opts = '-cd' if mnopts is None else mnopts
if self.inNamespace:
opts += 'n'
# mnexec: (c)lose descriptors
# (p)rint pid, and run in (n)etwork and (m)ount namespace
opts = '-cdp' if mnopts is None else mnopts
# Handle additional namespaces if specified
nsmap = { 'pid': 'P', 'mnt': 'm', 'net': 'n', 'uts': 'u' }
chars = [ nsmap.get( ns, '' ) for ns in self.ns ]
opts += ''.join( chars )
# bash -i: force interactive
# -s: pass $* to shell, and make process easy to find in ps
# prompt is set to sentinel chr( 127 )
cmd = [ 'mnexec', opts, 'env', 'PS1=' + chr( 127 ),
'bash', '--norc', '--noediting',
'-is', 'mininet:' + self.name ]
'bash', '--norc', '-is', 'mininet:' + self.name ]
# Spawn a shell subprocess in a pseudo-tty, to disable buffering
# in the subprocess and insulate it from signals (e.g. SIGINT)
# received by the parent
self.master, self.slave = pty.openpty()
self.shell = self._popen( cmd, stdin=self.slave, stdout=self.slave,
stderr=self.slave, close_fds=False )
# XXX BL: This doesn't seem right, and we should also probably
# close our files when we exit...
self.stdin = os.fdopen( self.master, 'r' )
master, slave = pty.openpty()
self.shell = self._popen( cmd, stdin=slave, stdout=slave, stderr=slave,
close_fds=False )
self.stdin = os.fdopen( master, 'rw' )
self.stdout = self.stdin
self.pid = self.shell.pid
self.pollOut = select.poll()
@@ -178,19 +170,21 @@ class Node( object ):
self.lastPid = None
self.readbuf = ''
# Wait for prompt
while True:
data = self.read( 1024 )
if data[ -1 ] == chr( 127 ):
break
self.pollOut.poll()
self.waiting = False
self.waiting = True
self.waitOutput()
if 'P' in opts:
assert self.lastPid is not None
self.pid = self.lastPid
# +m: disable job control notification
self.cmd( 'unset HISTFILE; stty -echo; set +m' )
initcmd = 'unset HISTFILE; stty -echo; set +m'
if 'uts' in self.ns:
initcmd += '; hostname ' + self.name
self.cmd( initcmd )
def mountPrivateDirs( self ):
"mount private directories"
"Mount private directories"
# Avoid expanding a string into a list of chars
assert not isinstance( self.privateDirs, BaseString )
assert not isinstance( self.privateDirs, basestring )
for directory in self.privateDirs:
if isinstance( directory, tuple ):
# mount given private directory
@@ -206,22 +200,68 @@ class Node( object ):
self.cmd( 'mount -n -t tmpfs tmpfs %s' % directory )
def unmountPrivateDirs( self ):
"mount private directories"
"Unmount private and overlay directories"
for directory in self.privateDirs:
if isinstance( directory, tuple ):
self.cmd( 'umount ', directory[ 0 ] )
else:
self.cmd( 'umount ', directory )
# XXX We should make overlayDirs as consistent as possible
# with privateDirs.
def _overlayFrom( self, entry ):
"Helper function: return mountpaint, overlay, tmpfs from entry"
if type( entry ) is str:
# '/mountpoint'
mountpoint, overlay = entry, None
elif len( entry ) is 1:
# [ '/mountpoint' ]
mountpoint, overlay = entry[ 0 ], None
else:
# [ '/mountpoint', '/overlay' ]
mountpoint, overlay = entry
tmpfs = None if overlay else '/tmp/%s/%s' % ( self, mountpoint )
return mountpoint, overlay, tmpfs
def mountOverlayDirs( self ):
"""Mount overlay directories. Overlay directories are similar
to private directories except they are copy-on-write copies
of directories in the host file system.
overlayDirs is of the form ((mountpoint,overlaydir), ...)
much like privateDirs. If overlaydir doesn't exist, we
mount a tmpfs at the specified mount point."""
# Avoid expanding a string into a list of chars
assert not isinstance( self.overlayDirs, basestring )
for entry in self.overlayDirs:
mountpoint, overlay, tmpfs = self._overlayFrom( entry )
# Create tmpfs if overlay dir is not specified
if not overlay:
overlay = tmpfs
self.cmd( 'mkdir -p', overlay )
self.cmd( 'mount -t tmpfs tmpfs', overlay )
# Mount overlay dir at mount point
self.cmd( ( 'mount -t overlayfs -o upperdir=%s,lowerdir=%s'
' overlayfs %s' ) % ( overlay, mountpoint, mountpoint ) )
def unmountOverlayDirs( self ):
"Unmount overlay directories"
for entry in self.overlayDirs:
mountpoint, overlay, tmpfs = self._overlayFrom( entry )
# Unfortunately these umounts can fail if the mount point
# is in use, possibly leaving tmpfs garbage in the root
# mount namespace / file system
self.cmd( 'umount', mountpoint )
if not overlay:
self.cmd( 'umount', tmpfs )
def _popen( self, cmd, **params ):
"""Internal method: spawn and return a process
cmd: command to run (list)
params: parameters to Popen()"""
# Leave this is as an instance method for now
assert self
popen = Popen( cmd, **params )
debug( '_popen', cmd, popen.pid )
return popen
return Popen( cmd, **params )
def cleanup( self ):
"Help python collect its garbage."
@@ -230,30 +270,23 @@ class Node( object ):
# for intfName in self.intfNames():
# if self.name in intfName:
# quietRun( 'ip link del ' + intfName )
if self.shell:
# Close ptys
self.stdin.close()
os.close(self.slave)
if self.waitExited:
debug( 'waiting for', self.pid, 'to terminate\n' )
self.shell.wait()
self.shell = None
# Subshell I/O, commands and control
def read( self, size=1024 ):
def read( self, maxbytes=1024 ):
"""Buffered read from node, potentially blocking.
size: maximum number of characters to return"""
maxbytes: maximum number of bytes to return"""
count = len( self.readbuf )
if count < size:
data = os.read( self.stdout.fileno(), size - count )
self.readbuf += self.decoder.decode( data )
if size >= len( self.readbuf ):
if count < maxbytes:
data = os.read( self.stdout.fileno(), maxbytes - count )
self.readbuf += data
if maxbytes >= len( self.readbuf ):
result = self.readbuf
self.readbuf = ''
else:
result = self.readbuf[ :size ]
self.readbuf = self.readbuf[ size: ]
result = self.readbuf[ :maxbytes ]
self.readbuf = self.readbuf[ maxbytes: ]
return result
def readline( self ):
@@ -270,14 +303,15 @@ class Node( object ):
def write( self, data ):
"""Write data to node.
data: string"""
os.write( self.stdin.fileno(), encode( data ) )
os.write( self.stdin.fileno(), data )
def terminate( self ):
"Send kill signal to Node and clean up after it."
self.unmountPrivateDirs()
self.unmountOverlayDirs()
if self.shell:
if self.shell.poll() is None:
os.killpg( self.shell.pid, signal.SIGHUP )
os.killpg( self.pid, signal.SIGHUP )
self.cleanup()
def stop( self, deleteIntfs=False ):
@@ -293,7 +327,6 @@ class Node( object ):
returns: result of poll()"""
if len( self.readbuf ) == 0:
return self.pollOut.poll( timeoutms )
return None
def sendCmd( self, *args, **kwargs ):
"""Send a command, followed by a command to echo a sentinel,
@@ -325,10 +358,10 @@ class Node( object ):
self.lastPid = None
self.waiting = True
def sendInt( self, intr=chr( 3 ) ):
def sendInt( self, signal=signal.SIGINT ):
"Interrupt running command."
debug( 'sendInt: writing chr(%d)\n' % ord( intr ) )
self.write( intr )
debug( "sending signal %d to pgrp %d" % ( signal, self.pid ) )
os.killpg( self.pid, signal )
def monitor( self, timeoutms=None, findPid=True ):
"""Monitor and return the output of a command.
@@ -341,18 +374,18 @@ class Node( object ):
data = self.read( 1024 )
pidre = r'\[\d+\] \d+\r\n'
# Look for PID
marker = chr( 1 ) + r'\d+\r\n'
if findPid and chr( 1 ) in data:
# suppress the job and PID of a backgrounded command
if re.findall( pidre, data ):
data = re.sub( pidre, '', data )
# Marker can be read in chunks; continue until all of it is read
while not re.findall( marker, data ):
while True:
markers = self._marker.findall( data )
if markers:
self.lastPid = int( markers[ -1 ] )
data = self._marker.sub( '', data )
break
data += self.read( 1024 )
markers = re.findall( marker, data )
if markers:
self.lastPid = int( markers[ 0 ][ 1: ] )
data = re.sub( marker, '', data )
# Look for sentinel/EOF
if len( data ) > 0 and data[ -1 ] == chr( 127 ):
self.waiting = False
@@ -387,7 +420,6 @@ class Node( object ):
return self.waitOutput( verbose )
else:
warn( '(%s exited - ignoring cmd%s)\n' % ( self, args ) )
return None
def cmdPrint( self, *args):
"""Call cmd and printing its output
@@ -402,23 +434,24 @@ class Node( object ):
'mncmd':
[ 'mnexec', '-da', str( self.pid ) ] }
defaults.update( kwargs )
shell = defaults.pop( 'shell', False )
if len( args ) == 1:
if isinstance( args[ 0 ], list ):
# popen([cmd, arg1, arg2...])
cmd = args[ 0 ]
elif isinstance( args[ 0 ], BaseString ):
elif isinstance( args[ 0 ], basestring ):
# popen("cmd arg1 arg2...")
cmd = [ args[ 0 ] ] if shell else args[ 0 ].split()
cmd = args[ 0 ].split()
else:
raise Exception( 'popen() requires a string or list' )
elif len( args ) > 0:
# popen( cmd, arg1, arg2... )
cmd = list( args )
if shell:
cmd = [ os.environ[ 'SHELL' ], '-c' ] + [ ' '.join( cmd ) ]
# Attach to our namespace using mnexec -a
cmd = defaults.pop( 'mncmd' ) + cmd
# Shell requires a string, not a list!
if defaults.get( 'shell', False ):
cmd = ' '.join( cmd )
debug( cmd, defaults )
popen = self._popen( cmd, **defaults )
return popen
@@ -430,7 +463,7 @@ class Node( object ):
# Warning: this can fail with large numbers of fds!
out, err = popen.communicate()
exitcode = popen.wait()
return decode( out ), decode( err ), exitcode
return out, err, exitcode
# Interface management, configuration, and routing
@@ -480,7 +513,6 @@ class Node( object ):
else:
warn( '*** defaultIntf: warning:', self.name,
'has no interfaces\n' )
return None
def intf( self, intf=None ):
"""Return our interface object with given string name,
@@ -493,7 +525,7 @@ class Node( object ):
"""
if not intf:
return self.defaultIntf()
elif isinstance( intf, BaseString):
elif isinstance( intf, basestring):
return self.nameToIntf[ intf ]
else:
return intf
@@ -520,7 +552,7 @@ class Node( object ):
# explicitly so that we won't get errors if we run before they
# have been removed by the kernel. Unfortunately this is very slow,
# at least with Linux kernels before 2.6.33
for intf in list( self.intfs.values() ):
for intf in self.intfs.values():
# Protect against deleting hardware interfaces
if ( self.name in intf.name ) or ( not checkName ):
intf.delete()
@@ -545,7 +577,7 @@ class Node( object ):
"""Set the default route to go through intf.
intf: Intf or {dev <intfname> via <gw-ip> ...}"""
# Note setParam won't call us if intf is none
if isinstance( intf, BaseString ) and ' ' in intf:
if isinstance( intf, basestring ) and ' ' in intf:
params = intf
else:
params = 'dev %s' % intf
@@ -592,12 +624,12 @@ class Node( object ):
method: config method name
param: arg=value (ignore if value=None)
value may also be list or dict"""
name, value = list( param.items() )[ 0 ]
name, value = param.items()[ 0 ]
if value is None:
return None
return
f = getattr( self, method, None )
if not f:
return None
return
if isinstance( value, list ):
result = f( *value )
elif isinstance( value, dict ):
@@ -641,7 +673,7 @@ class Node( object ):
def intfList( self ):
"List of our interfaces sorted by port number"
return [ self.intfs[ p ] for p in sorted( self.intfs.keys() ) ]
return [ self.intfs[ p ] for p in sorted( self.intfs.iterkeys() ) ]
def intfNames( self ):
"The names of our interfaces sorted by port number"
@@ -665,17 +697,18 @@ class Node( object ):
@classmethod
def checkSetup( cls ):
"Make sure our class and superclasses are set up"
clas = cls
while clas and not getattr( clas, 'isSetup', True ):
clas.setup()
clas.isSetup = True
while cls and not getattr( cls, 'isSetup', True ):
cls.setup()
cls.isSetup = True
# Make pylint happy
clas = getattr( type( clas ), '__base__', None )
cls = getattr( type( cls ), '__base__', None )
@classmethod
def setup( cls ):
"Make sure our class dependencies are available"
pathCheck( 'mnexec', 'ifconfig', moduleName='Mininet')
if '-m:' not in quietRun( 'mnexec -h' ):
raise Exception( 'Please update mnexec (e.g. make install)' )
class Host( Node ):
"A host is simply a Node"
@@ -851,7 +884,6 @@ class CPULimitedHost( Host ):
errFail( 'cgclassify -g cpuset:/%s %s' % (
self.name, self.pid ) )
# pylint: disable=arguments-differ
def config( self, cpu=-1, cores=None, **params ):
"""cpu: desired overall system CPU fraction
cores: (real) core(s) this host can run on
@@ -907,14 +939,14 @@ class Switch( Node ):
self.dpid = self.defaultDpid( dpid )
self.opts = opts
self.listenPort = listenPort
if not self.inNamespace:
if 'net' not in self.ns:
self.controlIntf = Intf( 'lo', self, port=0 )
def defaultDpid( self, dpid=None ):
"Return correctly formatted dpid from dpid or switch name (s1 -> 1)"
if dpid:
# Remove any colons and make sure it's a good hex number
dpid = dpid.replace( ':', '' )
dpid = dpid.translate( None, ':' )
assert len( dpid ) <= self.dpidLen and int( dpid, 16 ) >= 0
else:
# Use hex of the first number in the switch name
@@ -922,7 +954,6 @@ class Switch( Node ):
if nums:
dpid = hex( int( nums[ 0 ] ) )[ 2: ]
else:
self.terminate() # Python 3.6 crash workaround
raise Exception( 'Unable to derive default datapath ID - '
'please either specify a dpid or use a '
'canonical switch name such as s23.' )
@@ -944,7 +975,6 @@ class Switch( Node ):
else:
error( '*** Error: %s has execed and cannot accept commands' %
self.name )
return None
def connected( self ):
"Is the switch connected to a controller? (override this method)"
@@ -1115,10 +1145,9 @@ class OVSSwitch( Switch ):
version = quietRun( 'ovs-vsctl --version' )
cls.OVSVersion = findall( r'\d+\.\d+', version )[ 0 ]
@classmethod
def isOldOVS( cls ):
def isOldOVS( self ):
"Is OVS ersion < 1.10?"
return ( StrictVersion( cls.OVSVersion ) <
return ( StrictVersion( self.OVSVersion ) <
StrictVersion( '1.10' ) )
def dpctl( self, *args ):
@@ -1130,7 +1159,6 @@ class OVSSwitch( Switch ):
if self.batch:
cmd = ' '.join( str( arg ).strip() for arg in args )
self.commands.append( cmd )
return None
else:
return self.cmd( 'ovs-vsctl', *args, **kwargs )
@@ -1205,7 +1233,7 @@ class OVSSwitch( Switch ):
"Start up a new OVS OpenFlow switch using ovs-vsctl"
if self.inNamespace:
raise Exception(
'OVS kernel switch does not work in a namespace' )
'OVS kernel switch does not work in a network namespace' )
int( self.dpid, 16 ) # DPID must be a hex string
# Command to add interfaces
intfs = ''.join( ' -- add-port %s %s' % ( self, intf ) +
@@ -1268,7 +1296,7 @@ class OVSSwitch( Switch ):
run( cmds, shell=True )
# Reapply link config if necessary...
for switch in switches:
for intf in switch.intfs.values():
for intf in switch.intfs.itervalues():
if isinstance( intf, TCIntf ):
intf.config( **intf.params )
return switches
@@ -1294,7 +1322,7 @@ class OVSSwitch( Switch ):
pids = ' '.join( str( switch.pid ) for switch in switches )
run( 'kill -HUP ' + pids )
for switch in switches:
switch.terminate()
switch.shell = None
return switches
@@ -1318,7 +1346,7 @@ class OVSBridge( OVSSwitch ):
"Are we forwarding yet?"
if self.stp:
status = self.dpctl( 'show' )
return 'STP_FORWARD' in status and 'STP_LEARN' not in status
return 'STP_FORWARD' in status and not 'STP_LEARN' in status
else:
return True
@@ -1398,12 +1426,10 @@ class Controller( Node ):
OpenFlow controller."""
def __init__( self, name, inNamespace=False, command='controller',
cargs='ptcp:%d', cdir=None, ip="127.0.0.1",
port=6653, protocol='tcp', verbose=False, **params ):
cargs='-v ptcp:%d', cdir=None, ip="127.0.0.1",
port=6653, protocol='tcp', **params ):
self.command = command
self.cargs = cargs
if verbose:
cargs = '-v ' + cargs
self.cdir = cdir
# Accept 'ip:port' syntax as shorthand
if ':' in ip:
@@ -1445,7 +1471,6 @@ class Controller( Node ):
' 1>' + cout + ' 2>' + cout + ' &' )
self.execed = False
# pylint: disable=arguments-differ,signature-differs
def stop( self, *args, **kwargs ):
"Stop controller."
self.cmd( 'kill %' + self.command )
@@ -1469,7 +1494,7 @@ class Controller( Node ):
@classmethod
def isAvailable( cls ):
"Is controller available?"
return which( 'controller' )
return quietRun( 'which controller' )
class OVSController( Controller ):
@@ -1481,9 +1506,9 @@ class OVSController( Controller ):
@classmethod
def isAvailable( cls ):
return (which( 'ovs-controller' ) or
which( 'test-controller' ) or
which( 'ovs-testcontroller' ))
return ( quietRun( 'which ovs-controller' ) or
quietRun( 'which test-controller' ) or
quietRun( 'which ovs-testcontroller' ) ).strip()
class NOX( Controller ):
"Controller to run a NOX application."
@@ -1496,7 +1521,7 @@ class NOX( Controller ):
warn( 'warning: no NOX modules specified; '
'running packetdump only\n' )
noxArgs = [ 'packetdump' ]
elif not isinstance( noxArgs, ( list, tuple ) ):
elif type( noxArgs ) not in ( list, tuple ):
noxArgs = [ noxArgs ]
if 'NOX_CORE_DIR' not in os.environ:
@@ -1505,26 +1530,32 @@ class NOX( Controller ):
Controller.__init__( self, name,
command=noxCoreDir + '/nox_core',
cargs='--libdir=/usr/local/lib -v '
'-i ptcp:%s ' +
cargs='--libdir=/usr/local/lib -v -i ptcp:%s ' +
' '.join( noxArgs ),
cdir=noxCoreDir,
**kwargs )
class Ryu( Controller ):
"Ryu OpenFlow Controller"
def __init__( self, name, ryuArgs='ryu.app.simple_switch',
command='ryu run', **kwargs ):
"Controller to run Ryu application"
def __init__( self, name, *ryuArgs, **kwargs ):
"""Init.
name: name to give controller.
ryuArgs: modules to pass to Ryu (ryu.app.simple_switch)
command: comand to run Ryu ('ryu run')"""
if isinstance( ryuArgs, ( list, tuple ) ):
ryuArgs = ' '.join( ryuArgs )
cargs = kwargs.pop(
'cargs', ryuArgs + ' --ofp-tcp-listen-port %s' )
Controller.__init__( self, name, command=command,
cargs=cargs, **kwargs )
name: name to give controller.
ryuArgs: arguments and modules to pass to Ryu"""
homeDir = quietRun( 'printenv HOME' ).strip( '\r\n' )
ryuCoreDir = '%s/ryu/ryu/app/' % homeDir
if not ryuArgs:
warn( 'warning: no Ryu modules specified; '
'running simple_switch only\n' )
ryuArgs = [ ryuCoreDir + 'simple_switch.py' ]
elif type( ryuArgs ) not in ( list, tuple ):
ryuArgs = [ ryuArgs ]
Controller.__init__( self, name,
command='ryu-manager',
cargs='--ofp-tcp-listen-port %s ' +
' '.join( ryuArgs ),
cdir=ryuCoreDir,
**kwargs )
class RemoteController( Controller ):
@@ -1543,7 +1574,6 @@ class RemoteController( Controller ):
"Overridden to do nothing."
return
# pylint: disable=arguments-differ
def stop( self ):
"Overridden to do nothing."
return
@@ -1575,7 +1605,6 @@ class RemoteController( Controller ):
else:
return True
DefaultControllers = ( Controller, OVSController )
def findController( controllers=DefaultControllers ):
@@ -1583,7 +1612,6 @@ def findController( controllers=DefaultControllers ):
for controller in controllers:
if controller.isAvailable():
return controller
return None
def DefaultController( name, controllers=DefaultControllers, **kwargs ):
"Find a controller that is available and instantiate it"
+101 -25
View File
@@ -4,11 +4,14 @@ Node Library for Mininet
This contains additional Node types which you may find to be useful.
"""
from mininet.node import Node, Switch
from mininet.node import Node, Host, Switch
from mininet.log import info, warn
from mininet.moduledeps import pathCheck
from mininet.util import quietRun
import re
from tempfile import NamedTemporaryFile
class LinuxBridge( Switch ):
"Linux Bridge (with optional spanning tree)"
@@ -84,36 +87,13 @@ class NAT( Node ):
self.flush = flush
self.forwardState = self.cmd( 'sysctl -n net.ipv4.ip_forward' ).strip()
def setManualConfig( self, intf ):
"""Prevent network-manager/networkd from messing with our interface
by specifying manual configuration in /etc/network/interfaces"""
cfile = '/etc/network/interfaces'
line = '\niface %s inet manual\n' % intf
try:
with open( cfile ) as f:
config = f.read()
except IOError:
config = ''
if ( line ) not in config:
info( '*** Adding "' + line.strip() + '" to ' + cfile + '\n' )
with open( cfile, 'a' ) as f:
f.write( line )
# Probably need to restart network manager to be safe -
# hopefully this won't disconnect you
self.cmd( 'service network-manager restart || netplan apply' )
# pylint: disable=arguments-differ
def config( self, **params ):
"""Configure the NAT and iptables"""
super( NAT, self).config( **params )
if not self.localIntf:
self.localIntf = self.defaultIntf()
self.setManualConfig( self.localIntf )
# Now we can configure manually without interference
super( NAT, self).config( **params )
if self.flush:
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
self.cmd( 'iptables -F' )
@@ -137,6 +117,20 @@ class NAT( Node ):
# Instruct the kernel to perform forwarding
self.cmd( 'sysctl net.ipv4.ip_forward=1' )
# Prevent network-manager from messing with our interface
# by specifying manual configuration in /etc/network/interfaces
intf = self.localIntf
cfile = '/etc/network/interfaces'
line = '\niface %s inet manual\n' % intf
config = open( cfile ).read()
if ( line ) not in config:
info( '*** Adding "' + line.strip() + '" to ' + cfile + '\n' )
with open( cfile, 'a' ) as f:
f.write( line )
# Probably need to restart network-manager to be safe -
# hopefully this won't disconnect you
self.cmd( 'service network-manager restart' )
def terminate( self ):
"Stop NAT/forwarding between Mininet and external network"
# Remote NAT rules
@@ -152,3 +146,85 @@ class NAT( Node ):
# Put the forwarding state back to what it was
self.cmd( 'sysctl net.ipv4.ip_forward=%s' % self.forwardState )
super( NAT, self ).terminate()
class Server( Host ):
"Run sshd in a net/mnt/pid/uts namespace, with private /etc/hosts"
ns = [ 'net', 'mnt', 'pid', 'uts' ]
overlayDirs = [ '/etc', '/var/run', '/var/log' ]
privateDirs = [ '/var/run/sshd', ]
def __init__( self, *args, **kwargs ):
"""Add overlay dirs and private dirs, and change permissions
ssh: run sshd? (True)"""
kwargs.setdefault( 'inNamespace', True )
kwargs.setdefault( 'ns', self.ns )
kwargs.setdefault( 'privateDirs', self.privateDirs )
kwargs.setdefault( 'overlayDirs', self.overlayDirs )
kwargs.setdefault( 'ssh', True )
super( Server, self ).__init__( *args, **kwargs )
# Change permissions, mainly for ssh
for pdir in self.privateDirs:
self.cmd( 'chown root:root', pdir )
self.cmd( 'chmod 755', pdir )
@staticmethod
def updateHostsFiles( servers, tmpdirs=[ '/tmp', '/var/tmp' ] ):
"""Update local hosts files on a list of servers
servers: list of servers
tmpdir: tmp dir shared between mn and servers"""
# For large configurations it will be more efficient
# to use a DNS server
hosts = ( '# Mininet hosts file\n'
'127.0.0.1 localhost %s\n' +
''.join( '%s %s\n' % ( t.IP(), t )
for t in servers ) )
for s in servers:
dirs = ( getattr( s, 'overlayDirs', [] ) +
getattr( s, 'privateDirs', [] ) )
if '/etc' in dirs:
tmpdirs = [ d for d in tmpdirs if d not in dirs ]
if tmpdirs:
with NamedTemporaryFile( dir=tmpdirs[ 0 ] ) as tmpfile:
tmpfile.write( hosts % s )
tmpfile.flush()
s.cmd( 'cp', tmpfile.name, '/etc/hosts' )
else:
warn( 'not updating hosts file on %s\n' % s )
def service( self, cmd ):
"""Start or stop a service
usage: service( 'ssh stop' )"""
self.cmd( '/etc/init.d/%s' % cmd )
def motd( self ):
"Return login message as a string"
return 'Welcome to Mininet host %s at %s' % ( self, self.IP() )
def startSSH( self, motdPath='/var/run/motd.dynamic' ):
"Update motd, Clear out utmp/wtmp/btmp, and start sshd"
# Note: /var/run and /var/log must be overlays!
assert ( '/var/run' in ( self.overlayDirs + self.privateDirs ) and
'/var/log' in ( self.overlayDirs + self.privateDirs ) )
self.cmd( "echo '%s' > %s" % ( self.motd(), motdPath ) )
self.cmd( 'truncate -s0 /var/run/utmp /var/log/wtmp* /var/log/btmp*' )
# sshd.pid should really be in /var/run/sshd instead of /var/run
self.cmd( 'rm /var/run/sshd.pid' )
self.cmd( '/etc/init.d/ssh start' )
def config( self, **kwargs ):
"""Configure/start sshd and other stuff
ssh: start sshd? (True )"""
super( Server, self ).config( **kwargs )
self.ssh = kwargs.get( 'ssh' )
if self.ssh:
self.startSSH()
if 'uts' in self.ns:
self.cmd( 'hostname', self )
def terminate( self, *args, **kwargs ):
"Shut down services and terminate server"
if self.ssh:
self.service( 'ssh stop' )
super( Server, self ).terminate( *args, **kwargs )
+65 -14
View File
@@ -5,13 +5,43 @@ Utility functions to run a terminal (connected via socat(1)) on each host.
Requires socat(1) and xterm(1).
Optionally uses gnome-terminal.
"""
from os import environ
from mininet.log import error
from mininet.util import quietRun, errRun
def tunnelX11( node, display=None):
from os import environ, getpid, path, setsid
from subprocess import Popen, PIPE, STDOUT
from tempfile import NamedTemporaryFile
def getAuthX11( display ):
"Return X11 credentials for display"
host, screen = display.split( ':' )
host = host.split( '/' )[ 0 ]
hostname = quietRun( 'hostname' ).strip()
# First, try hostname:display
if host == 'localhost':
host = hostname
result = quietRun( 'xauth list %s:%s' % ( host, screen ) )
# Otherwise, try hostname/unix:display
if not result:
result = quietRun( 'xauth list %s/unix:%s' % ( host, screen ) )
items = result.strip().split()
if len( items ) != 3:
raise Exception( "getAuthX11: could not fetch credentials for " +
display )
return items
# This is tricky with uts and pid namespaces
# For uts namespaces, we create and use a private $XAUTHORITY
# and add credentials for the node's hostname.
# To enable pid namespaces to work, we proxy the X11
# socket twice using socat - first with a shared socket in /tmp, and
# second with a TCP listener in the host network namespace.
# Note that this will fail if /tmp is not shared - we should
# probably think about this some more. We could potentially
# specify a globally shared directory somehow if /tmp is
# private.
def tunnelX11( node, display=None ):
"""Create an X11 tunnel from node:6000 to the root host
display: display on root host (optional)
returns: node $DISPLAY, Popen object for tunnel"""
@@ -28,11 +58,30 @@ def tunnelX11( node, display=None):
quietRun( 'xhost +si:localuser:root' )
return display, None
else:
# Create a tunnel for the TCP connection
hostname = quietRun( 'hostname' ).strip()
port = 6000 + int( float( screen ) )
connection = r'TCP\:%s\:%s' % ( host, port )
cmd = [ "socat", "TCP-LISTEN:%d,fork,reuseaddr" % port,
"EXEC:'mnexec -a 1 socat STDIO %s'" % connection ]
if 'uts' in node.ns and ( hostname in display or
'localhost' in display ):
# Use private xauth file, and add credentials
# for this hostname
if not hasattr( node, 'xauthFile' ):
node.xauthFile = NamedTemporaryFile()
_display, proto, cookie = getAuthX11( display )
creds = '%s %s %s' % ( '%s/unix:%s' % ( node.name, screen ),
proto, cookie )
node.cmd( 'export XAUTHORITY=' + node.xauthFile.name )
node.cmd( 'xauth -f $XAUTHORITY add ' + creds )
# Create a shared unix socket in /tmp
# This can conflict if we are running nested Mininet
# in a pid namespace, and it will also fail if /tmp is not
# shared
socket = '/tmp/mininet.x11.%d' % getpid()
if not hasattr( tunnelX11, 'socket' ):
cmd = ( 'socat unix-listen:%s,fork tcp:localhost:%d' %
( socket, port ) ).split()
tunnelX11.socket = Popen( cmd )
# Create a tunnel for the TCP connection
cmd = 'socat tcp-listen:%d,fork,reuseaddr unix:%s' % ( port, socket )
return 'localhost:' + screen, node.popen( cmd )
def makeTerm( node, title='Node', term='xterm', display=None, cmd='bash'):
@@ -45,17 +94,19 @@ def makeTerm( node, title='Node', term='xterm', display=None, cmd='bash'):
if not node.inNamespace:
title += ' (root)'
cmds = {
'xterm': [ 'xterm', '-title', title, '-display' ],
'gterm': [ 'gnome-terminal', '--title', title, '--display' ]
'xterm': [ 'xterm', '-title', title ],
'gterm': [ 'gnome-terminal', '--title', title ]
}
if term not in cmds:
error( 'invalid terminal type: %s' % term )
return None
return
display, tunnel = tunnelX11( node, display )
if display is None:
return []
term = node.popen( cmds[ term ] +
[ display, '-e', 'env TERM=ansi %s' % cmd ] )
env = [ 'env', 'TERM=ansi', 'DISPLAY=%s' % display ]
if hasattr( node, 'xauthFile' ):
env += [ 'XAUTHORITY=%s' % node.xauthFile.name ]
term = node.popen( env + cmds[ term ] + [ '-e', cmd ] )
return [ tunnel, term ] if tunnel else [ term ]
def runX11( node, cmd ):
@@ -68,7 +119,7 @@ def runX11( node, cmd ):
def cleanUpScreens():
"Remove moldy socat X11 tunnels."
errRun( "pkill -9 -f mnexec.*socat" )
errRun( "pkill -9 -f socat.*mininet" )
def makeTerms( nodes, title='Node', term='xterm' ):
"""Create terminals.
-1
View File
@@ -25,7 +25,6 @@ def runTests( testDir, verbosity=1 ):
.run( testSuite ).wasSuccessful() )
sys.exit( 0 if success else 1 )
if __name__ == '__main__':
setLogLevel( 'warning' )
# get the directory containing example tests
+3 -4
View File
@@ -45,7 +45,7 @@ class testOptionsTopoCommon( object ):
@staticmethod
def tearDown():
"Clean up if necessary"
if sys.exc_info() != ( None, None, None ):
if sys.exc_info != ( None, None, None ):
cleanup()
def runOptionsTopoTest( self, n, msg, hopts=None, lopts=None ):
@@ -95,7 +95,7 @@ class testOptionsTopoCommon( object ):
CPU_FRACTION = 0.1
CPU_TOLERANCE = 0.8 # CPU fraction below which test should fail
hopts = { 'cpu': CPU_FRACTION }
# self.runOptionsTopoTest( N, hopts=hopts )
#self.runOptionsTopoTest( N, hopts=hopts )
mn = Mininet( SingleSwitchOptionsTopo( n=N, hopts=hopts ),
host=CPULimitedHost, switch=self.switchClass,
@@ -118,7 +118,7 @@ class testOptionsTopoCommon( object ):
% ( CPU_FRACTION * 100, hostUsage, N, hoptsStr,
self.switchClass ) )
for pct in results:
# divide cpu by 100 to convert from percentage to fraction
#divide cpu by 100 to convert from percentage to fraction
self.assertWithinTolerance( pct/100, CPU_FRACTION,
CPU_TOLERANCE, msg )
@@ -263,7 +263,6 @@ class testOptionsTopoUserspace( testOptionsTopoCommon, unittest.TestCase ):
longMessage = True
switchClass = UserSwitch
if __name__ == '__main__':
setLogLevel( 'warning' )
unittest.main()
+1 -1
View File
@@ -26,7 +26,7 @@ class testSingleSwitchCommon( object ):
@staticmethod
def tearDown():
"Clean up if necessary"
if sys.exc_info() != ( None, None, None ):
if sys.exc_info != ( None, None, None ):
cleanup()
def testMinimal( self ):
-32
View File
@@ -1,32 +0,0 @@
#!/usr/bin/env python
"""
Regression test for pty leak in Node()
"""
import unittest
from mininet.net import Mininet
from mininet.clean import cleanup
from mininet.topo import SingleSwitchTopo
class TestPtyLeak( unittest.TestCase ):
"Verify that there is no pty leakage"
@staticmethod
def testPtyLeak():
"Test for pty leakage"
net = Mininet( SingleSwitchTopo() )
net.start()
host = net[ 'h1' ]
for _ in range( 0, 10 ):
oldptys = host.slave, host.master
net.delHost( host )
host = net.addHost( 'h1' )
assert ( host.slave, host.master ) == oldptys
net.stop()
if __name__ == '__main__':
unittest.main()
cleanup()
+14 -19
View File
@@ -24,16 +24,16 @@ class TestSwitchDpidAssignmentOVS( unittest.TestCase ):
"Clean up if necessary"
# satisfy pylint
assert self
if sys.exc_info() != ( None, None, None ):
if sys.exc_info != ( None, None, None ):
cleanup()
def testDefaultDpid( self ):
"""Verify that the default dpid is assigned using a valid provided
canonical switchname if no dpid is passed in switch creation."""
net = Mininet( Topo(), self.switchClass, Host, Controller )
switch = net.addSwitch( 's1' )
switch = Mininet( Topo(),
self.switchClass,
Host, Controller ).addSwitch( 's1' )
self.assertEqual( switch.defaultDpid(), switch.dpid )
net.stop()
def dpidFrom( self, num ):
"Compute default dpid from number"
@@ -44,34 +44,31 @@ class TestSwitchDpidAssignmentOVS( unittest.TestCase ):
"""Verify that Switch dpid is the actual dpid assigned if dpid is
passed in switch creation."""
dpid = self.dpidFrom( 0xABCD )
net = Mininet( Topo(), self.switchClass, Host, Controller )
switch = net.addSwitch( 's1', dpid=dpid )
switch = Mininet( Topo(), self.switchClass,
Host, Controller ).addSwitch(
's1', dpid=dpid )
self.assertEqual( switch.dpid, dpid )
net.stop()
def testDefaultDpidAssignmentFailure( self ):
"""Verify that Default dpid assignment raises an Exception if the
name of the switch does not contin a digit. Also verify the
exception message."""
net = Mininet( Topo(), self.switchClass, Host, Controller )
with self.assertRaises( Exception ) as raises_cm:
net.addSwitch( 'A' )
self.assertTrue( 'Unable to derive '
Mininet( Topo(), self.switchClass,
Host, Controller ).addSwitch( 'A' )
self.assertEqual(raises_cm.exception.message, 'Unable to derive '
'default datapath ID - please either specify a dpid '
'or use a canonical switch name such as s23.'
in str( raises_cm.exception ) )
net.stop()
'or use a canonical switch name such as s23.')
def testDefaultDpidLen( self ):
"""Verify that Default dpid length is 16 characters consisting of
16 - len(hex of first string of contiguous digits passed in switch
name) 0's followed by hex of first string of contiguous digits passed
in switch name."""
net = Mininet( Topo(), self.switchClass, Host, Controller )
switch = net.addSwitch( 's123' )
self.assertEqual( switch.dpid, self.dpidFrom( 123 ) )
net.stop()
switch = Mininet( Topo(), self.switchClass,
Host, Controller ).addSwitch( 's123' )
self.assertEqual( switch.dpid, self.dpidFrom( 123 ) )
class OVSUser( OVSSwitch):
"OVS User Switch convenience class"
@@ -95,8 +92,6 @@ class testSwitchUserspace( TestSwitchDpidAssignmentOVS ):
"Test dpid assignment of Userspace switch."
switchClass = UserSwitch
if __name__ == '__main__':
setLogLevel( 'warning' )
unittest.main()
cleanup()
-40
View File
@@ -1,40 +0,0 @@
#!/usr/bin/env python
"""Package: mininet
Test functions defined in mininet.util."""
import unittest
from mininet.util import quietRun
class testQuietRun( unittest.TestCase ):
"""Test quietRun that runs a command and returns its merged output from
STDOUT and STDIN"""
@staticmethod
def getEchoCmd( n ):
"Return a command that will print n characters"
return "echo -n " + "x" * n
def testEmpty( self ):
"Run a command that prints nothing"
output = quietRun(testQuietRun.getEchoCmd( 0 ) )
self.assertEqual( 0, len( output ) )
def testOneRead( self ):
"""Run a command whose output is entirely read on the first call if
each call reads at most 1024 characters
"""
for n in [ 42, 1024 ]:
output = quietRun( testQuietRun.getEchoCmd( n ) )
self.assertEqual( n, len( output ) )
def testMultipleReads( self ):
"Run a command whose output is not entirely read on the first read"
for n in [ 1025, 4242 ]:
output = quietRun(testQuietRun.getEchoCmd( n ) )
self.assertEqual( n, len( output ) )
if __name__ == "__main__":
unittest.main()
+25 -45
View File
@@ -6,16 +6,13 @@ Tests for the Mininet Walkthrough
TODO: missing xterm test
"""
import unittest
import pexpect
import os
import re
import unittest
from mininet.util import quietRun
from distutils.version import StrictVersion
from sys import stdout
from mininet.util import quietRun, pexpect
from mininet.clean import cleanup
from time import sleep
def tsharkVersion():
"Return tshark version"
@@ -31,11 +28,6 @@ class testWalkthrough( unittest.TestCase ):
prompt = 'mininet>'
@staticmethod
def setup():
"Be paranoid and run cleanup() before each test"
cleanup()
# PART 1
def testHelp( self ):
"Check the usage message"
@@ -51,18 +43,17 @@ class testWalkthrough( unittest.TestCase ):
tshark = pexpect.spawn( 'tshark -i lo -R of' )
else:
tshark = pexpect.spawn( 'tshark -i lo -Y openflow_v1' )
tshark.expect( [ 'Capturing on lo', "Capturing on 'Loopback" ] )
tshark.expect( [ 'Capturing on lo', "Capturing on 'Loopback'" ] )
mn = pexpect.spawn( 'mn --test pingall' )
mn.expect( '0% dropped' )
tshark.expect( [ '74 Hello', '74 of_hello', '74 Type: OFPT_HELLO' ] )
tshark.sendintr()
mn.expect( pexpect.EOF )
tshark.expect( 'aptured' ) # 'xx packets captured'
tshark.expect( pexpect.EOF )
def testBasic( self ):
"Test basic CLI commands (help, nodes, net, dump)"
p = pexpect.spawn( 'mn -w' )
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
# help command
p.sendline( 'help' )
@@ -76,7 +67,7 @@ class testWalkthrough( unittest.TestCase ):
p.expect( self.prompt )
# net command
p.sendline( 'net' )
expected = list( nodes )
expected = [ x for x in nodes ]
while len( expected ) > 0:
index = p.expect( expected )
node = p.match.group( 0 )
@@ -101,18 +92,17 @@ class testWalkthrough( unittest.TestCase ):
def testHostCommands( self ):
"Test ifconfig and ps on h1 and s1"
p = pexpect.spawn( 'mn -w' )
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
# Third pattern is a local interface beginning with 'eth' or 'en'
interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]',
r'[^-](eth|en)\w*\d[:\s]', r'lo[:\s]',
interfaces = [ 'h1-eth0', 's1-eth1', r'[^-](eth|en)\w*\d', 'lo',
self.prompt ]
# h1 ifconfig
p.sendline( 'h1 ifconfig -a' )
ifcount = 0
while True:
index = p.expect( interfaces )
if index in (0, 3):
if index == 0 or index == 3:
ifcount += 1
elif index == 1:
self.fail( 's1 interface displayed in "h1 ifconfig"' )
@@ -128,11 +118,11 @@ class testWalkthrough( unittest.TestCase ):
index = p.expect( interfaces )
if index == 0:
self.fail( 'h1 interface displayed in "s1 ifconfig"' )
elif index in (1, 2, 3):
elif index == 1 or index == 2 or index == 3:
ifcount += 1
else:
break
self.assertTrue( ifcount <= 3, 'Missing interfaces on s1')
self.assertTrue( ifcount >= 3, 'Missing interfaces on s1')
# h1 ps
p.sendline( "h1 ps -a | egrep -v 'ps|grep'" )
p.expect( self.prompt )
@@ -153,7 +143,7 @@ class testWalkthrough( unittest.TestCase ):
def testConnectivity( self ):
"Test ping and pingall"
p = pexpect.spawn( 'mn -w' )
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
p.sendline( 'h1 ping -c 1 h2' )
p.expect( '1 packets transmitted, 1 received' )
@@ -166,20 +156,14 @@ class testWalkthrough( unittest.TestCase ):
def testSimpleHTTP( self ):
"Start an HTTP server on h1 and wget from h2"
if 'Python 2' in quietRun( 'python --version' ):
httpserver = 'SimpleHTTPServer'
else:
httpserver = 'http.server'
p = pexpect.spawn( 'mn -w', logfile=stdout )
p.expect( self.prompt )
p.sendline( 'h1 python -m %s 80 >& /dev/null &' % httpserver )
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
p.sendline( 'h1 python -m SimpleHTTPServer 80 &' )
# The walkthrough doesn't specify a delay here, and
# we also don't read the output (also a possible problem),
# but for now let's wait a number of seconds to make
# but for now let's wait a couple of seconds to make
# it less likely to fail due to the race condition.
p.sendline( 'px from mininet.util import waitListening;'
'waitListening(h1, port=80, timeout=30)' )
sleep( 2 )
p.expect( self.prompt )
p.sendline( ' h2 wget -O - h1' )
p.expect( '200 OK' )
@@ -224,9 +208,7 @@ class testWalkthrough( unittest.TestCase ):
def testLinkChange( self ):
"Test TCLink bw and delay"
p = pexpect.spawn( 'mn -w --link tc,bw=10,delay=10ms' )
p.expect( self.prompt )
p.sendline( 'h1 route && ping -c1 h2' )
p = pexpect.spawn( 'mn --link tc,bw=10,delay=10ms' )
# test bw
p.expect( self.prompt )
p.sendline( 'iperf' )
@@ -240,8 +222,8 @@ class testWalkthrough( unittest.TestCase ):
p.expect( r'rtt min/avg/max/mdev = '
r'([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms' )
delay = float( p.match.group( 2 ) )
self.assertTrue( delay >= 40, 'Delay < 40ms' )
self.assertTrue( delay <= 50, 'Delay > 50ms' )
self.assertTrue( delay > 40, 'Delay < 40ms' )
self.assertTrue( delay < 45, 'Delay > 40ms' )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
@@ -278,7 +260,7 @@ class testWalkthrough( unittest.TestCase ):
p.expect( self.prompt )
for i in range( 1, 3 ):
p.sendline( 'h%d ifconfig' % i )
p.expect( r'\s00:00:00:00:00:0%d\s' % i )
p.expect( 'HWaddr 00:00:00:00:00:0%d' % i )
p.expect( self.prompt )
p.sendline( 'exit' )
p.expect( pexpect.EOF )
@@ -304,14 +286,12 @@ class testWalkthrough( unittest.TestCase ):
"Test running user switch in its own namespace"
p = pexpect.spawn( 'mn --innamespace --switch user' )
p.expect( self.prompt )
interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]',
r'[^-](eth|en)\w*\d[:\s]', r'lo[:\s]',
self.prompt ]
interfaces = [ 'h1-eth0', 's1-eth1', '[^-]eth0', 'lo', self.prompt ]
p.sendline( 's1 ifconfig -a' )
ifcount = 0
while True:
index = p.expect( interfaces )
if index in (1, 3):
if index == 1 or index == 3:
ifcount += 1
elif index == 0:
self.fail( 'h1 interface displayed in "s1 ifconfig"' )
@@ -332,7 +312,7 @@ class testWalkthrough( unittest.TestCase ):
# PART 3
def testPythonInterpreter( self ):
"Test py and px by checking IP for h1 and adding h3"
p = pexpect.spawn( 'mn -w' )
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
# test host IP
p.sendline( 'py h1.IP()' )
@@ -354,7 +334,7 @@ class testWalkthrough( unittest.TestCase ):
def testLink( self ):
"Test link CLI command using ping"
p = pexpect.spawn( 'mn -w' )
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
p.sendline( 'link s1 h1 down' )
p.expect( self.prompt )
+7 -9
View File
@@ -13,9 +13,6 @@ setup for testing, and can even be emulated with the Mininet package.
from mininet.util import irange, natural, naturalSeq
# pylint: disable=too-many-arguments
class MultiGraph( object ):
"Utility class to track nodes and edges - replaces networkx.MultiGraph"
@@ -37,7 +34,7 @@ class MultiGraph( object ):
key: optional key
attr_dict: optional attribute dict
attrs: more attributes
warning: updates attr_dict with attrs"""
warning: udpates attr_dict with attrs"""
attr_dict = {} if attr_dict is None else attr_dict
attr_dict.update( attrs )
self.node.setdefault( src, {} )
@@ -59,13 +56,13 @@ class MultiGraph( object ):
return self.node.items() if data else self.node.keys()
def edges_iter( self, data=False, keys=False ):
"Iterator: return graph edges, optionally with data and keys"
for src, entry in self.edge.items():
for dst, entrykeys in entry.items():
"Iterator: return graph edges"
for src, entry in self.edge.iteritems():
for dst, keys in entry.iteritems():
if src > dst:
# Skip duplicate edges
continue
for k, attrs in entrykeys.items():
for k, attrs in keys.iteritems():
if data:
if keys:
yield( src, dst, k, attrs )
@@ -159,7 +156,8 @@ class Topo( object ):
port1, port2 = self.addPort( node1, node2, port1, port2 )
opts = dict( opts )
opts.update( node1=node1, node2=node2, port1=port1, port2=port2 )
return self.g.add_edge(node1, node2, key, opts )
self.g.add_edge(node1, node2, key, opts )
return key
def nodes( self, sort=True ):
"Return nodes in graph"
+33 -10
View File
@@ -45,10 +45,11 @@ class TorusTopo( Topo ):
without STP turned on! It can be used with STP, e.g.:
# mn --topo torus,3,3 --switch lxbr,stp=1 --test pingall"""
def build( self, x, y, n=1 ):
"""x: dimension of torus in x-direction
y: dimension of torus in y-direction
n: number of hosts per switch"""
def build( self, x, y, n=1, wrap=True ):
"""x: number of switches per row
y: number of rows
n: number of hosts per switch
wrap: torus rather than grid? (True)"""
if x < 3 or y < 3:
raise Exception( 'Please use 3x3 or greater for compatibility '
'with 2.1' )
@@ -72,11 +73,33 @@ class TorusTopo( Topo ):
self.addLink( host, switch )
# Connect switches
for i in range( 0, x ):
for j in range( 0, y ):
sw1 = switches[ i, j ]
sw2 = switches[ i, ( j + 1 ) % y ]
sw3 = switches[ ( i + 1 ) % x, j ]
self.addLink( sw1, sw2 )
self.addLink( sw1, sw3 )
for j in range( 0, y):
sw = switches[ i, j ]
right = switches[ ( i + 1 ) % x, j ]
down = switches[ i, ( j + 1 ) % y ]
if wrap or i + 1 < x:
self.addLink( sw, right )
if wrap or j + 1 < y:
self.addLink( sw, down )
class GridTopo( TorusTopo ):
"""2-D Grid topology
WARNING: this topology has LOOPS and WILL NOT WORK
with the default controller or any Ethernet bridge
without STP turned on! It can be used with STP, e.g.:
# mn --topo grid,3,3 --switch lxbr,stp=1 --test pingall"""
def build( self, x, y, n=1, wrap=False ):
"""x: number of switches per row
y: number of rows
n: number of hosts per switch
wrap: torus rather than grid (False)"""
super( GridTopo, self ).build( x, y, n, wrap )
topos = { 'tree': TreeTopo,
'torus': TorusTopo,
'grid': GridTopo }
# pylint: enable=arguments-differ
+84 -141
View File
@@ -1,79 +1,17 @@
"Utility functions for Mininet."
import codecs
import os
import re
import sys
from fcntl import fcntl, F_GETFL, F_SETFL
from functools import partial
from os import O_NONBLOCK
from resource import getrlimit, setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
from select import poll, POLLIN, POLLHUP
from subprocess import call, check_call, Popen, PIPE, STDOUT
from sys import exit # pylint: disable=redefined-builtin
from time import sleep
from mininet.log import output, info, error, warn, debug
# pylint: disable=too-many-arguments
# Python 2/3 compatibility
Python3 = sys.version_info[0] == 3
BaseString = str if Python3 else getattr( str, '__base__' )
Encoding = 'utf-8' if Python3 else None
class NullCodec( object ):
"Null codec for Python 2"
@staticmethod
def decode( buf ):
"Null decode"
return buf
@staticmethod
def encode( buf ):
"Null encode"
return buf
if Python3:
def decode( buf ):
"Decode buffer for Python 3"
return buf.decode( Encoding )
def encode( buf ):
"Encode buffer for Python 3"
return buf.encode( Encoding )
getincrementaldecoder = codecs.getincrementaldecoder( Encoding )
else:
decode, encode = NullCodec.decode, NullCodec.encode
def getincrementaldecoder():
"Return null codec for Python 2"
return NullCodec
try:
# pylint: disable=import-error
oldpexpect = None
import pexpect as oldpexpect
# pylint: enable=import-error
class Pexpect( object ):
"Custom pexpect that is compatible with str"
@staticmethod
def spawn( *args, **kwargs):
"pexpect.spawn that is compatible with str"
if Python3 and 'encoding' not in kwargs:
kwargs.update( encoding='utf-8' )
return oldpexpect.spawn( *args, **kwargs )
def __getattr__( self, name ):
return getattr( oldpexpect, name )
pexpect = Pexpect()
except ImportError:
pass
from time import sleep
from resource import getrlimit, setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
from select import poll, POLLIN, POLLHUP
from subprocess import call, check_call, Popen, PIPE, STDOUT
import re
from fcntl import fcntl, F_GETFL, F_SETFL
from os import O_NONBLOCK
import os
from functools import partial
# Command execution support
@@ -95,7 +33,7 @@ def oldQuietRun( *cmd ):
cmd: list of command params"""
if len( cmd ) == 1:
cmd = cmd[ 0 ]
if isinstance( cmd, BaseString ):
if isinstance( cmd, str ):
cmd = cmd.split( ' ' )
popen = Popen( cmd, stdout=PIPE, stderr=STDOUT )
# We can't use Popen.communicate() because it uses
@@ -119,7 +57,7 @@ def oldQuietRun( *cmd ):
# This is a bit complicated, but it enables us to
# monitor command output as it is happening
# pylint: disable=too-many-branches,too-many-statements
# pylint: disable=too-many-branches
def errRun( *cmd, **kwargs ):
"""Run a command and return stdout, stderr and return code
cmd: string or list of command and args
@@ -136,7 +74,7 @@ def errRun( *cmd, **kwargs ):
if len( cmd ) == 1:
cmd = cmd[ 0 ]
# Allow passing in a list or a string
if isinstance( cmd, BaseString ) and not shell:
if isinstance( cmd, str ) and not shell:
cmd = cmd.split( ' ' )
cmd = [ str( arg ) for arg in cmd ]
elif isinstance( cmd, list ) and shell:
@@ -148,21 +86,18 @@ def errRun( *cmd, **kwargs ):
out, err = '', ''
poller = poll()
poller.register( popen.stdout, POLLIN )
fdToFile = { popen.stdout.fileno(): popen.stdout }
fdToDecoder = { popen.stdout.fileno(): getincrementaldecoder() }
fdtofile = { popen.stdout.fileno(): popen.stdout }
outDone, errDone = False, True
if popen.stderr:
fdToFile[ popen.stderr.fileno() ] = popen.stderr
fdToDecoder[ popen.stderr.fileno() ] = getincrementaldecoder()
fdtofile[ popen.stderr.fileno() ] = popen.stderr
poller.register( popen.stderr, POLLIN )
errDone = False
while not outDone or not errDone:
readable = poller.poll()
for fd, event in readable:
f = fdToFile[ fd ]
decoder = fdToDecoder[ fd ]
if event & ( POLLIN | POLLHUP ):
data = decoder.decode( f.read( 1024 ) )
f = fdtofile[ fd ]
if event & POLLIN:
data = f.read( 1024 )
if echo:
output( data )
if f == popen.stdout:
@@ -173,7 +108,7 @@ def errRun( *cmd, **kwargs ):
err += data
if data == '':
errDone = True
else: # something unexpected
else: # POLLHUP or something unexpected
if f == popen.stdout:
outDone = True
elif f == popen.stderr:
@@ -181,10 +116,6 @@ def errRun( *cmd, **kwargs ):
poller.unregister( fd )
returncode = popen.wait()
# Python 3 complains if we don't explicitly close these
popen.stdout.close()
if stderr == PIPE:
popen.stderr.close()
debug( out, err, returncode )
return out, err, returncode
# pylint: enable=too-many-branches
@@ -201,26 +132,19 @@ def quietRun( cmd, **kwargs ):
"Run a command and return merged stdout and stderr"
return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ]
def which(cmd, **kwargs ):
"Run a command and return merged stdout and stderr"
out, _, ret = errRun( ["which", cmd], stderr=STDOUT, **kwargs )
return out.rstrip() if ret == 0 else None
# pylint: enable=maybe-no-member
def isShellBuiltin( cmd ):
"Return True if cmd is a bash builtin."
if isShellBuiltin.builtIns is None:
isShellBuiltin.builtIns = set(quietRun( 'bash -c enable' ).split())
isShellBuiltin.builtIns = quietRun( 'bash -c enable' )
space = cmd.find( ' ' )
if space > 0:
cmd = cmd[ :space]
return cmd in isShellBuiltin.builtIns
isShellBuiltin.builtIns = None
# Interface management
#
# Interfaces are managed as strings which are simply the
@@ -254,18 +178,19 @@ def makeIntfPair( intf1, intf2, addr1=None, addr2=None, node1=None, node2=None,
runCmd( 'ip link del ' + intf1 )
runCmd2( 'ip link del ' + intf2 )
# Create new pair
netns = 1 if not node2 else node2.pid
ns1 = 1 if not node1 else node1.pid
ns2 = 1 if not node2 else node2.pid
if addr1 is None and addr2 is None:
cmdOutput = runCmd( 'ip link add name %s '
cmdOutput = runCmd( 'ip link add name %s netns %s '
'type veth peer name %s '
'netns %s' % ( intf1, intf2, netns ) )
'netns %s' % ( intf1, ns1, intf2, ns2 ) )
else:
cmdOutput = runCmd( 'ip link add name %s '
'address %s '
'address %s netns %s '
'type veth peer name %s '
'address %s '
'netns %s' %
( intf1, addr1, intf2, addr2, netns ) )
( intf1, addr1, ns1, intf2, addr2, ns2 ) )
if cmdOutput:
raise Exception( "Error creating interface pair (%s,%s): %s " %
( intf1, intf2, cmdOutput ) )
@@ -407,7 +332,7 @@ def netParse( ipstr ):
if '/' in ipstr:
ip, pf = ipstr.split( '/' )
prefixLen = int( pf )
# if no prefix is specified, set the prefix to 24
#if no prefix is specified, set the prefix to 24
else:
ip = ipstr
prefixLen = 24
@@ -450,34 +375,30 @@ def pmonitor(popens, timeoutms=500, readline=True,
terminates: when all EOFs received"""
poller = poll()
fdToHost = {}
fdToDecoder = {}
for host, popen in popens.items():
for host, popen in popens.iteritems():
fd = popen.stdout.fileno()
fdToHost[ fd ] = host
fdToDecoder[ fd ] = getincrementaldecoder()
poller.register( fd, POLLIN )
flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
# pylint: disable=too-many-nested-blocks
if not readline:
# Use non-blocking reads
flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
while popens:
fds = poller.poll( timeoutms )
if fds:
for fd, event in fds:
host = fdToHost[ fd ]
decoder = fdToDecoder[ fd ]
popen = popens[ host ]
if event & ( POLLIN | POLLHUP ):
while True:
try:
f = popen.stdout
line = decoder.decode( f.readline() if readline
else f.read( readmax ) )
except IOError:
line = ''
if line == '':
break
yield host, line
if event & POLLHUP:
if event & POLLIN:
if readline:
# Attempt to read a line of output
# This blocks until we receive a newline!
line = popen.stdout.readline()
else:
line = popen.stdout.read( readmax )
yield host, line
# Check for EOF
elif event & POLLHUP:
poller.unregister( fd )
del popens[ host ]
else:
@@ -486,19 +407,19 @@ def pmonitor(popens, timeoutms=500, readline=True,
# Other stuff we use
def sysctlTestAndSet( name, limit ):
"Helper function to set sysctl limits"
# convert non-directory names into directory names
#convert non-directory names into directory names
if '/' not in name:
name = '/proc/sys/' + name.replace( '.', '/' )
# read limit
#read limit
with open( name, 'r' ) as readFile:
oldLimit = readFile.readline()
if isinstance( limit, int ):
# compare integer limits before overriding
#compare integer limits before overriding
if int( oldLimit ) < limit:
with open( name, 'w' ) as writeFile:
writeFile.write( "%d" % limit )
else:
# overwrite non-integer limits
#overwrite non-integer limits
with open( name, 'w' ) as writeFile:
writeFile.write( limit )
@@ -515,21 +436,21 @@ def fixLimits():
try:
rlimitTestAndSet( RLIMIT_NPROC, 8192 )
rlimitTestAndSet( RLIMIT_NOFILE, 16384 )
# Increase open file limit
#Increase open file limit
sysctlTestAndSet( 'fs.file-max', 10000 )
# Increase network buffer space
#Increase network buffer space
sysctlTestAndSet( 'net.core.wmem_max', 16777216 )
sysctlTestAndSet( 'net.core.rmem_max', 16777216 )
sysctlTestAndSet( 'net.ipv4.tcp_rmem', '10240 87380 16777216' )
sysctlTestAndSet( 'net.ipv4.tcp_wmem', '10240 87380 16777216' )
sysctlTestAndSet( 'net.core.netdev_max_backlog', 5000 )
# Increase arp cache size
#Increase arp cache size
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh1', 4096 )
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh2', 8192 )
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh3', 16384 )
# Increase routing table size
#Increase routing table size
sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 )
# Increase number of PTYs for nodes
#Increase number of PTYs for nodes
sysctlTestAndSet( 'kernel.pty.max', 20000 )
# pylint: disable=broad-except
except Exception:
@@ -540,7 +461,7 @@ def fixLimits():
def mountCgroups():
"Make sure cgroups file system is mounted"
mounts = quietRun( 'grep cgroup /proc/mounts' )
mounts = quietRun( 'cat /proc/mounts' )
cgdir = '/sys/fs/cgroup'
csdir = cgdir + '/cpuset'
if ('cgroup %s' % cgdir not in mounts and
@@ -588,21 +509,42 @@ def custom( cls, **params ):
customized.__name__ = 'custom(%s,%s)' % ( cls, params )
return customized
def splitArgs( argstr ):
"""Split argument string into usable python arguments
argstr: argument string with format fn,arg2,kw1=arg3...
returns: fn, args, kwargs"""
split = argstr.split( ',' )
fn = split[ 0 ]
params = split[ 1: ]
def parseArgs( argstr ):
"""Parse argument string
returns args, kwargs"""
# One step at a time: support param=[a,b,c]
paramre = r'\[[^\]]*\]|[^,\[\]]+'
paramre = r'\w+=\[[^\]]*\]|\w+\[^,\[\]]+' + paramre
params = re.findall( paramre, argstr )
# Parse lists
for i, arg in enumerate( params ):
if arg.startswith( '[' ) and arg.endswith( ']' ):
arg = arg[ 1 : -1 ]
print "recurse on", arg
params[ i ] = parseArgs( args )
# Convert int and float args; removes the need for function
# to be flexible with input arg formats.
args = [ makeNumeric( s ) for s in params if '=' not in s ]
kwargs = {}
for s in [ p for p in params if '=' in p ]:
key, val = s.split( '=', 1 )
kwargs[ key ] = makeNumeric( val )
return fn, args, kwargs
key, arg = s.split( '=', 1 )
if arg.startswith( '[' ) and arg.endswith( ']' ):
arg = arg[ 1 : -1 ]
print 'recurse on', arg
arg = parseArgs( arg )[ 0 ]
else:
arg = makeNumeric( arg )
kwargs[ key ] = arg
return args, kwargs
def splitArgs( argstr ):
"""Split argument string into usable python arguments
argstr: argument string with format fn,arg2,kw1=arg3...
returns: fn, args, kwargs"""
args, kwargs = parseArgs( argstr )
return args[ 0 ], args[ 1: ], kwargs
def customClass( classes, argStr ):
"""Return customized class based on argStr
@@ -670,6 +612,7 @@ def ensureRoot():
if os.getuid() != 0:
error( '*** Mininet must run as root.\n' )
exit( 1 )
return
def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ):
"""Wait until server is listening on port.
@@ -679,7 +622,7 @@ def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ):
if not runCmd( 'which telnet' ):
raise Exception('Could not find telnet' )
# pylint: disable=maybe-no-member
serverIP = server if isinstance( server, BaseString ) else server.IP()
serverIP = server if isinstance( server, basestring ) else server.IP()
cmd = ( 'echo A | telnet -e A %s %s' % ( serverIP, port ) )
time = 0
result = runCmd( cmd )
+196 -108
View File
@@ -5,9 +5,9 @@
*
* - closing all file descriptors except stdin/out/error
* - detaching from a controlling tty using setsid
* - running in network and mount namespaces
* - running in network and other namespaces
* - printing out the pid of a process so we can identify it later
* - attaching to a namespace and cgroup
* - attaching to namespace(s) and cgroup
* - setting RT scheduling
*
* Partially based on public domain setsid(1)
@@ -24,21 +24,29 @@
#include <sched.h>
#include <ctype.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <assert.h>
#include <string.h>
#include <sys/stat.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"
"Usage: %s [-cdmnPpu] [-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 and mount namespaces\n"
" -m: run in a new mount namespace\n"
" -n: run in a new network namespace\n"
" -P: run in a new pid namespace (implies -m)\n"
" -u: run in a new UTS (ipc, hostname) namespace\n"
" -p: print ^A + pid\n"
" -a pid: attach to pid's network and mount namespaces\n"
" -a pid: attach to pid's namespaces\n"
" -g group: add to cgroup\n"
" -r rtprio: run with SCHED_RR (usually requires -g)\n"
" -v: print version\n",
@@ -46,10 +54,13 @@ void usage(char *name)
}
#if !defined(setns)
int setns(int fd, int nstype)
{
return syscall(__NR_setns, fd, nstype);
}
#endif
/* Validate alphanumeric path foo1/bar2/baz */
void validate(char *path)
@@ -63,6 +74,7 @@ void validate(char *path)
}
}
/* Add our pid to cgroup */
void cgroup(char *gname)
{
@@ -92,117 +104,193 @@ void cgroup(char *gname)
}
}
/* Attach to ns 'name' if present; return 1 if pidns */
int attachns( pid_t pid, char *name ) {
char path[PATH_MAX];
int nsid, err;
int pidns = 0;
snprintf(path, PATH_MAX, "/proc/%d/ns/%s", pid, name) ;
if ((nsid = open(path, O_RDONLY)) < 0)
return nsid;
if (strcmp(name, "pid") == 0) {
struct stat buf1, buf2;
int stat1 = stat(path, &buf1);
int stat2 = stat("/proc/self/ns/pid", &buf2);
/* Don't reattach to the same pid ns */
if (stat1 == 0 && stat2 == 0 &&
buf1.st_dev == buf2.st_dev &&
buf1.st_ino == buf2.st_ino)
return 0;
pidns = 1;
}
if ((err = setns(nsid, 0)) < 0) {
perror("setns");
return err;
}
return pidns;
}
/* Attach to pid's namespaces - returns 1 if pidns */
int attach(int pid) {
char *cwd = get_current_dir_name();
char path[PATH_MAX];
int pidns = 0;
attachns(pid, "net");
attachns(pid, "uts");
if (attachns(pid, "pid") == 1)
pidns = 1;
if (attachns(pid, "mnt") != 0) {
/* Plan B: chroot into pid's root file system */
sprintf(path, "/proc/%d/root", pid);
if (chroot(path) < 0) {
perror(path);
}
}
/* chdir to correct working directory */
if (chdir(cwd) != 0)
perror(cwd);
return pidns;
}
int main(int argc, char *argv[])
{
int c;
int fd;
char path[PATH_MAX];
int nsid;
int pid;
char *cwd = get_current_dir_name();
static struct sched_param sp;
while ((c = getopt(argc, argv, "+cdnpa:g:r:vh")) != -1)
/* Argument flags */
int flags = 0;
int closefds = 0;
int attachpid = 0;
char *cgrouparg = NULL;
int detachtty = 0;
int printpid = 0;
int rtprio = 0;
int pidns = 0;
int dofork = 0;
while ((c = getopt(argc, argv, "+cdmnPpa:g:r:uvh")) != -1)
switch(c) {
case 'c':
/* close file descriptors except stdin/out/error */
for (fd = getdtablesize(); fd > 2; fd--)
close(fd);
break;
case 'd':
/* detach from tty */
if (getpgrp() == getpid()) {
switch(fork()) {
case -1:
perror("fork");
return 1;
case 0: /* child */
break;
default: /* parent */
return 0;
}
}
setsid();
break;
case 'n':
/* run in network and mount namespaces */
if (unshare(CLONE_NEWNET|CLONE_NEWNS) == -1) {
perror("unshare");
return 1;
}
case 'c': closefds = 1; break;
case 'd': detachtty = 1; break;
case 'm': flags |= CLONE_NEWNS; break;
case 'n': flags |= CLONE_NEWNET; break;
case 'p': printpid = 1; break;
case 'P': flags |= CLONE_NEWPID | CLONE_NEWNS; break;
case 'a': attachpid = atoi(optarg);break;
case 'g': cgrouparg = optarg ; break;
case 'r': rtprio = atoi(optarg); break;
case 'u': flags |= CLONE_NEWUTS; break;
case 'v': printf("%s\n", VERSION); exit(0);
case 'h': usage(argv[0]); exit(0);
default: usage(argv[0]); exit(1);
}
/* Mark our whole hierarchy recursively as private, so that our
* mounts do not propagate to other processes.
*/
if (closefds) {
/* close file descriptors except stdin/out/error */
int fd;
for (fd = getdtablesize(); fd > 2; fd--) close(fd);
}
if (mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) == -1) {
perror("remount");
return 1;
}
/* mount sysfs to pick up the new network namespace */
if (mount("sysfs", "/sys", "sysfs", MS_MGC_VAL, NULL) == -1) {
perror("mount");
return 1;
}
break;
case 'p':
/* print pid */
printf("\001%d\n", getpid());
fflush(stdout);
break;
case 'a':
/* Attach to pid's network namespace and mount namespace */
pid = atoi(optarg);
sprintf(path, "/proc/%d/ns/net", pid);
nsid = open(path, O_RDONLY);
if (nsid < 0) {
perror(path);
return 1;
}
if (setns(nsid, 0) != 0) {
perror("setns");
return 1;
}
/* Plan A: call setns() to attach to mount namespace */
sprintf(path, "/proc/%d/ns/mnt", pid);
nsid = open(path, O_RDONLY);
if (nsid < 0 || setns(nsid, 0) != 0) {
/* Plan B: chroot/chdir into pid's root file system */
sprintf(path, "/proc/%d/root", pid);
if (chroot(path) < 0) {
perror(path);
return 1;
}
}
/* chdir to correct working directory */
if (chdir(cwd) != 0) {
perror(cwd);
return 1;
}
break;
case 'g':
/* Attach to cgroup */
cgroup(optarg);
break;
case 'r':
/* Set RT scheduling priority */
sp.sched_priority = atoi(optarg);
if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
perror("sched_setscheduler");
return 1;
}
break;
case 'v':
printf("%s\n", VERSION);
exit(0);
case 'h':
usage(argv[0]);
exit(0);
default:
usage(argv[0]);
exit(1);
if (attachpid)
/* Attach to existing namespace(s) */
pidns = attach(attachpid);
else {
/* Create new namespace(s) */
if (unshare(flags) == -1) {
perror("unshare");
return 1;
}
}
if (flags & CLONE_NEWPID || pidns)
/* pidns requires fork/wait; child will be pid 1 */
dofork = 1;
if (detachtty && getpgrp() == getpid())
/* Fork so that we will no longer be pgroup leader */
dofork = 1;
else
/* We don't need a new session, only a new pgroup */
detachtty = 0;
if (detachtty)
/* Create a new session - and by implication a new process group */
setsid();
else
/* Use a new process group (in the current session)
* so Mininet can use killpg without unintended effects */
setpgid(0, 0);
if (dofork) {
/* Fork and then wait if necessary */
pid_t pid = fork();
switch(pid) {
int status;
case -1:
perror("fork");
return 1;
case 0:
/* Child continues below */
break;
default:
/* We print the *child pid* in *parent's pidns* if needed */
if (printpid) {
printf("\001%d\n", pid);
fflush(stdout);
}
/* For pid namespace, we need to fork and wait for child ;-( */
if (flags & CLONE_NEWPID || pidns) {
wait(&status);
}
return 0;
}
}
if (printpid && !dofork) {
/* Print child pid if we didn't fork/aren't in a pidns */
assert(!pidns);
printf("\001%d\n", getpid());
fflush(stdout);
}
if (flags & CLONE_NEWPID) {
/* Child remounts /proc for ps */
if (mount("proc", "/proc", "proc", MS_MGC_VAL, NULL) == -1) {
perror("mountproc");
}
}
/* Attach to cgroup if necessary */
if (cgrouparg) cgroup(cgrouparg);
if (flags & CLONE_NEWNET & CLONE_NEWNS) {
/* Mount sysfs to pick up the new network namespace */
if (mount("sysfs", "/sys", "sysfs", MS_MGC_VAL, NULL) == -1) {
perror("mount");
return 1;
}
}
if (rtprio != 0) {
/* Set RT scheduling priority */
static struct sched_param sp;
sp.sched_priority = atoi(optarg);
if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
perror("sched_setscheduler");
return 1;
}
}
if (optind < argc) {
execvp(argv[optind], &argv[optind]);
+5 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python2
#!/usr/bin/python
"""
Convert simple documentation to epydoc/pydoctor-compatible markup
@@ -83,3 +83,7 @@ if __name__ == '__main__':
infile.close()
os.close( outfid )
call( [ 'doxypy', outname ] )
+54 -111
View File
@@ -1,7 +1,7 @@
#!/bin/bash
#!/usr/bin/env bash
# Mininet install script for Ubuntu and Debian
# Original author: Brandon Heller
# Mininet install script for Ubuntu (and Debian Wheezy+)
# Brandon Heller (brandonh@stanford.edu)
# Fail on error
set -e
@@ -102,26 +102,6 @@ function version_ge {
[ "$1" == "$latest" ]
}
# Attempt to detect Python version
PYTHON=${PYTHON:-python}
PRINTVERSION='import sys; print(sys.version_info)'
PYTHON_VERSION=unknown
for python in $PYTHON python2 python3; do
if $python -c "$PRINTVERSION" |& grep 'major=2'; then
PYTHON=$python; PYTHON_VERSION=2; PYPKG=python
break
elif $python -c "$PRINTVERSION" |& grep 'major=3'; then
PYTHON=$python; PYTHON_VERSION=3; PYPKG=python3
break
fi
done
if [ "$PYTHON_VERSION" == unknown ]; then
echo "Can't find a working python command ('$PYTHON' doesn't work.)"
echo "You may wish to export PYTHON or install a working 'python'."
exit 1
fi
echo "Detected Python (${PYTHON}) version ${PYTHON_VERSION}"
# Kernel Deb pkg to be removed:
KERNEL_IMAGE_OLD=linux-image-2.6.26-33-generic
@@ -164,54 +144,30 @@ function mn_deps {
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
$install gcc make socat psmisc xterm openssh-clients iperf \
iproute telnet python-setuptools libcgroup-tools \
ethtool help2man net-tools
$install ${PYPKG}-pyflakes pylint ${PYPKG}-pep8-naming \
${PYPKG}-pexpect
elif [ "$DIST" = "SUSE LINUX" ]; then
ethtool help2man pyflakes pylint python-pep8 python-pexpect
elif [ "$DIST" = "SUSE LINUX" ]; then
$install gcc make socat psmisc xterm openssh iperf \
iproute telnet ${PYPKG}-setuptools libcgroup-tools \
ethtool help2man python-pyflakes python3-pylint \
python-pep8 ${PYPKG}-pexpect ${PYPKG}-tk
else # Debian/Ubuntu
pf=pyflakes
# Starting around 20.04, installing pyflakes instead of pyflakes3
# causes Python 2 to be installed, which is exactly NOT what we want.
if [ `expr $RELEASE '>=' 20.04` = "1" ]; then
pf=pyflakes3
fi
$install gcc make socat psmisc xterm ssh iperf telnet \
ethtool help2man $pf pylint pep8 \
net-tools \
${PYPKG}-pexpect ${PYPKG}-tk
# Install pip
$install ${PYPKG}-pip || $install ${PYPKG}-pip-whl
if ! ${PYTHON} -m pip -V; then
if [ $PYTHON_VERSION == 2 ]; then
wget https://bootstrap.pypa.io/2.6/get-pip.py
else
wget https://bootstrap.pypa.io/get-pip.py
fi
sudo ${PYTHON} get-pip.py
rm get-pip.py
fi
$install iproute2 || $install iproute
$install cgroup-tools || $install cgroup-bin
iproute telnet python-setuptools libcgroup-tools \
ethtool help2man python-pyflakes python3-pylint python-pep8 python-pexpect
else
$install gcc make socat psmisc xterm ssh iperf iproute2 telnet \
python-setuptools cgroup-bin ethtool help2man \
pyflakes pylint pep8 python-pexpect
fi
echo "Installing Mininet core"
pushd $MININET_DIR/mininet
sudo PYTHON=${PYTHON} make install
sudo make install
popd
}
# Install Mininet documentation dependencies
function mn_doc {
echo "Installing Mininet documentation dependencies"
$install doxygen texlive-fonts-recommended
# Install Mininet developer dependencies
function mn_dev {
echo "Installing Mininet developer dependencies"
$install doxygen doxypy texlive-fonts-recommended
if ! $install doxygen-latex; then
echo "doxygen-latex not needed"
fi
sudo pip install doxypy
}
# The following will cause a full OF install, covering:
@@ -248,14 +204,10 @@ function of {
function of13 {
echo "Installing OpenFlow 1.3 soft switch implementation..."
cd $BUILD_DIR/
$install git-core autoconf automake autotools-dev pkg-config \
make gcc g++ libtool libc6-dev cmake libpcap-dev \
$install git-core autoconf automake autotools-dev pkg-config \
make gcc g++ libtool libc6-dev cmake libpcap-dev libxerces-c2-dev \
unzip libpcre3-dev flex bison libboost-dev
if [ "$DIST" = "Ubuntu" ] && version_le $RELEASE 16.04; then
$install libxerces-c2-dev
else
$install libxerces-c-dev
fi
if [ ! -d "ofsoftswitch13" ]; then
git clone https://github.com/CPqD/ofsoftswitch13.git
if [[ -n "$OF13_SWITCH_REV" ]]; then
@@ -266,17 +218,24 @@ function of13 {
fi
# Install netbee
if [ ! -d "netbee" ]; then
git clone https://github.com/netgroup-polito/netbee.git
if [ "$DIST" = "Ubuntu" ] && version_ge $RELEASE 14.04; then
NBEESRC="nbeesrc-feb-24-2015"
NBEEDIR="netbee"
else
NBEESRC="nbeesrc-jan-10-2013"
NBEEDIR="nbeesrc-jan-10-2013"
fi
cd netbee/src
NBEEURL=${NBEEURL:-http://www.nbee.org/download/}
wget -nc ${NBEEURL}${NBEESRC}.zip
unzip ${NBEESRC}.zip
cd ${NBEEDIR}/src
cmake .
make
cd $BUILD_DIR
sudo cp netbee/bin/libn*.so /usr/local/lib
cd $BUILD_DIR/
sudo cp ${NBEEDIR}/bin/libn*.so /usr/local/lib
sudo ldconfig
sudo cp -R netbee/include/ /usr/
sudo cp -R ${NBEEDIR}/include/ /usr/
# Resume the install:
cd $BUILD_DIR/ofsoftswitch13
@@ -372,8 +331,8 @@ function ubuntuOvs {
# Get build deps
$install build-essential fakeroot debhelper autoconf automake libssl-dev \
pkg-config bzip2 openssl ${PYPKG}-all procps ${PYPKG}-qt4 \
${PYPKG}-zopeinterface ${PYPKG}-twisted-conch dkms dh-python dh-autoreconf \
pkg-config bzip2 openssl python-all procps python-qt4 \
python-zopeinterface python-twisted-conch dkms dh-python dh-autoreconf \
uuid-runtime
# Build OVS
@@ -410,10 +369,7 @@ function ovs {
echo "Installing Open vSwitch..."
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
$install openvswitch
if ! $install openvswitch-controller; then
echo "openvswitch-controller not installed"
fi
$install openvswitch openvswitch-controller
return
fi
@@ -446,19 +402,13 @@ function ovs {
# Switch can run on its own, but
# Mininet should control the controller
# This appears to only be an issue on Ubuntu/Debian
if sudo service $OVSC stop 2>/dev/null; then
if sudo service $OVSC stop; then
echo "Stopped running controller"
fi
if [ -e /etc/init.d/$OVSC ]; then
sudo update-rc.d $OVSC disable
fi
fi
# This service seems to hang on 20.04
if systemctl list-units | \
grep status netplan-ovs-cleanup.service>&/dev/null; then
echo 'TimeoutSec=10' | sudo EDITOR='tee -a' \
sudo systemctl edit --full netplan-ovs-cleanup.service
fi
}
function remove_ovs {
@@ -512,7 +462,7 @@ function ryu {
# install Ryu dependencies"
$install autoconf automake g++ libtool python make
if [ "$DIST" = "Ubuntu" -o "$DIST" = "Debian" ]; then
$install gcc ${PYPKG}-pip ${PYPKG}-dev libffi-dev libssl-dev \
$install gcc python-pip python-dev libffi-dev libssl-dev \
libxml2-dev libxslt1-dev zlib1g-dev
fi
@@ -535,17 +485,17 @@ function nox {
echo "Installing NOX w/tutorial files..."
# Install NOX deps:
$install autoconf automake g++ libtool python ${PYPKG}-twisted \
$install autoconf automake g++ libtool python python-twisted \
swig libssl-dev make
if [ "$DIST" = "Debian" ]; then
$install libboost1.35-dev
elif [ "$DIST" = "Ubuntu" ]; then
$install ${PYPKG}-dev libboost-dev
$install python-dev libboost-dev
$install libboost-filesystem-dev
$install libboost-test-dev
fi
# Install NOX optional deps:
$install libsqlite3-dev ${PYPKG}-simplejson
$install libsqlite3-dev python-simplejson
# Fetch NOX destiny
cd $BUILD_DIR/
@@ -583,12 +533,12 @@ function nox13 {
echo "Installing NOX w/tutorial files..."
# Install NOX deps:
$install autoconf automake g++ libtool python ${PYPKG}-twisted \
$install autoconf automake g++ libtool python python-twisted \
swig libssl-dev make
if [ "$DIST" = "Debian" ]; then
$install libboost1.35-dev
elif [ "$DIST" = "Ubuntu" ]; then
$install ${PYPKG}-dev libboost-dev
$install python-dev libboost-dev
$install libboost-filesystem-dev
$install libboost-test-dev
fi
@@ -624,8 +574,7 @@ function oftest {
echo "Installing oftest..."
# Install deps:
$install tcpdump
$install ${PYPKG}-scapy || sudo $PYTHON -m pip install scapy
$install tcpdump python-scapy
# Install oftest:
cd $BUILD_DIR/
@@ -651,7 +600,6 @@ function cbench {
sh boot.sh || true # possible error in autoreconf, so run twice
sh boot.sh
./configure --with-openflow-src-dir=$BUILD_DIR/openflow
make liboflops_test.la
make
sudo make install || true # make install fails; force past this
}
@@ -683,10 +631,9 @@ net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee -a /etc/sysctl.conf > /dev/null
fi
# Since the above doesn't disable neighbor discovery, also do this:
# disable via boot line, and also restore eth0 naming for VM use
if ! grep 'ipv6.disable' /etc/default/grub; then
sudo sed -i -e \
's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 net.ifnames=0 /' \
's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 /' \
/etc/default/grub
sudo update-grub
fi
@@ -764,8 +711,8 @@ function all {
echo "Installing all packages except for -eix (doxypy, ivs, nox-classic)..."
kernel
mn_deps
# Skip mn_doc (doxypy/texlive/fonts/etc.) because it's huge
# mn_doc
# Skip mn_dev (doxypy/texlive/fonts/etc.) because it's huge
# mn_dev
of
install_wireshark
ovs
@@ -796,12 +743,8 @@ function vm_clean {
# Remove SSH keys and regenerate on boot
echo 'Removing SSH keys from /etc/ssh/'
sudo rm -f /etc/ssh/*key*
if [ ! -e /etc/rc.local ]; then
echo '#!/bin/bash' | sudo tee /etc/rc.local
sudo chmod +x /etc/rc.local
fi
if ! grep mininet /etc/rc.local >& /dev/null; then
sudo sed -i -e "s/exit 0//" /etc/rc.local || true
sudo sed -i -e "s/exit 0//" /etc/rc.local
echo '
# mininet: regenerate ssh keys if we deleted them
if ! stat -t /etc/ssh/*key* >/dev/null 2>&1; then
@@ -809,15 +752,15 @@ if ! stat -t /etc/ssh/*key* >/dev/null 2>&1; then
fi
exit 0
' | sudo tee -a /etc/rc.local > /dev/null
sudo chmod +x /etc/rc.local
fi
# Remove Mininet files
#sudo rm -f /lib/modules/python2.5/site-packages/mininet*
#sudo rm -f /usr/bin/mnexec
# Clear optional dev script for SSH keychain load on boot
rm -f ~/.bash_profile
# Remove leftover install script if any
rm -f install-mininet-vm.sh
# Clear git changes
git config --global user.name "None"
git config --global user.email "None"
@@ -844,7 +787,7 @@ function usage {
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 -- ' -e: install Mininet documentation/LaT(e)X dependencies\n' >&2
printf -- ' -e: install Mininet d(E)veloper dependencies\n' >&2
printf -- ' -f: install Open(F)low\n' >&2
printf -- ' -h: print this (H)elp message\n' >&2
printf -- ' -i: install (I)ndigo Virtual Switch\n' >&2
@@ -878,7 +821,7 @@ else
b) cbench;;
c) kernel_clean;;
d) vm_clean;;
e) mn_doc;;
e) mn_dev;;
f) case $OF_VERSION in
1.0) of;;
1.3) of13;;
+1 -8
View File
@@ -33,12 +33,5 @@ if [ -d "$cgroup" ]; then
cg="-g $host"
fi
# Check whether host should be running in a chroot dir
rootdir="/var/run/mn/$host/root"
if [ -d $rootdir -a -x $rootdir/bin/bash ]; then
cmd="'cd `pwd`; exec $cmd'"
cmd="chroot $rootdir /bin/bash -c $cmd"
fi
cmd="exec sudo mnexec $cg -a $pid $cmd"
cmd="exec sudo -E mnexec $cg -a $pid $cmd"
eval $cmd
+15 -15
View File
@@ -1,7 +1,7 @@
#!/usr/bin/python2
#!/usr/bin/python
"""
Translate from PEP8 Python style to Mininet (i.e. Arista-like)
Translate from PEP8 Python style to Mininet (i.e. Arista-like)
Python style
usage: unpep8 < old.py > new.py
@@ -51,7 +51,7 @@ def fixUnderscoreTriplet( match ):
def reinstateCapWords( text ):
underscoreTriplet = re.compile( r'[A-Za-z0-9]_[A-Za-z0-9]' )
return underscoreTriplet.sub( fixUnderscoreTriplet, text )
def replaceTripleApostrophes( text ):
"Replace triple apostrophes with triple quotes."
return text.replace( "'''", '"""')
@@ -60,7 +60,7 @@ def simplifyTripleQuotes( text ):
"Fix single-line doc strings."
r = re.compile( r'"""([^\"\n]+)"""' )
return r.sub( r'"\1"', text )
def insertExtraSpaces( text ):
"Insert extra spaces inside of parentheses and brackets/curly braces."
lparen = re.compile( r'\((?![\s\)])' )
@@ -76,9 +76,9 @@ def insertExtraSpaces( text ):
lcurly = re.compile( r'\{(?![\s\}])' )
text = lcurly.sub( r'{ ', text )
rcurly = re.compile( r'([^\s\{])(?=\})' )
text = rcurly.sub( r'\1 ', text)
text = rcurly.sub( r'\1 ', text)
return text
def fixDoxygen( text ):
"""Translate @param foo to foo:, @return bar to returns: bar, and
@author me to author: me"""
@@ -96,11 +96,11 @@ def removeCommentFirstBlankLine( text ):
"Remove annoying blank lines after first line in comments."
line = re.compile( r'("""[^\n]*\n)\s*\n', re.MULTILINE )
return line.sub( r'\1', text )
def fixArgs( match, kwarg = re.compile( r'(\w+) = ' ) ):
"Replace foo = bar with foo=bar."
return kwarg.sub( r'\1=', match.group() )
def fixKeywords( text ):
"Change keyword argumentsfrom foo = bar to foo=bar."
args = re.compile( r'\(([^\)]+)\)', re.MULTILINE )
@@ -115,7 +115,7 @@ def fixKeywords( text ):
def lineIter( text ):
"Simple iterator over lines in text."
for line in text.splitlines(): yield line
def stringIter( strList ):
"Yield strings in strList."
for s in strList: yield s
@@ -134,7 +134,7 @@ def restoreRegex( regex, old, new ):
# This is a cheap hack, and it may not work 100%, since
# it doesn't handle multiline strings.
# However, it should be mostly harmless...
def restoreStrings( oldText, newText ):
"Restore strings from oldText into newText, returning result."
oldLines, newLines = lineIter( oldText ), lineIter( newText )
@@ -149,13 +149,13 @@ def restoreStrings( oldText, newText ):
newLine = restoreRegex( tickStrings, oldLine, newLine )
result += newLine + '\n'
return result
# This might be slightly controversial, since it uses
# three spaces to line up multiline comments. However,
# I much prefer it. Limitations: if you have deeper
# indents in comments, they will be eliminated. ;-(
def fixComment( match,
def fixComment( match,
indentExp=re.compile( r'\n([ ]*)(?=[^/s])', re.MULTILINE ),
trailingQuotes=re.compile( r'\s+"""' ) ):
"Re-indent comment, and join trailing quotes."
@@ -166,17 +166,17 @@ def fixComment( match,
if len( originalIndent ) is not 0: indent += ' '
comment = indentExp.sub( indent, comment )
return originalIndent + trailingQuotes.sub( '"""', comment )
def fixCommentIndents( text ):
"Fix multiline comment indentation."
comments = re.compile( r'^([ ]*)("""[^"]*""")$', re.MULTILINE )
return comments.sub( fixComment, text )
def removeBogusLinefeeds( text ):
"Remove extra linefeeds at the end of single-line comments."
bogusLfs = re.compile( r'"([^"\n]*)\n"', re.MULTILINE )
return bogusLfs.sub( '"\1"', text)
def convertFromPep8( program ):
oldProgram = program
# Program text transforms
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff. Show more