Compare commits

..

1125 Commits

Author SHA1 Message Date
Bob Lantz 1969669f51 pass code check 2018-08-23 13:06:16 -07:00
Bob Lantz c639f342e5 2.3.0d4 2018-08-23 11:43:45 -07:00
Bob Lantz 6e887d0788 Close pty to avoid leak 2018-08-23 11:43:43 -07:00
Bob Lantz 092863f113 2.3.0d3 2018-08-15 23:13:20 -07:00
Bob Lantz 5100a38fcd pmonitor() fixes
pmonitor() is hard to get right, but this seems like
a reasonable improvement:

1. non-blocking I/O so we can drain buffer with impunity
2. drain buffer after poll
3. unregister fd on POLLHUP

Note we may have a unicode splitting problem since we're
decoding chunks of bytes, but that is a problem for another
day I think.
2018-08-02 12:45:35 -07:00
Bob Lantz 3bcecd8e08 Fix popen() to work properly with shell=True 2018-08-02 06:56:18 -07:00
Bob Lantz 486676d617 2.3.0d2 2018-07-26 14:04:08 -07:00
lantz 9e5280b4d1 Python 3 Compatibility (Merge pull request #817 from lantz/py3-compat)
Changes for compatibility with Python 3.

The approach is to make as few changes as possible to maintain compatibility with both Python 2 and Python 3.

We use whatever python is installed, and also support a PYTHON environment variable for installing another version.

For simplicity, we provide mininet.util.pexpect which works out of the box with Python 3 utf-8 strings.

Thanks to @cuihantao for looking at this as well and also for changes to MiniEdit.

Closes #794
2018-07-26 14:03:34 -07:00
Bob Lantz b70eed69d3 Fix typo (50s -> 50ms) 2018-07-26 13:52:15 -07:00
Bob Lantz d96b35694a Use appropriate python version 2018-07-26 13:40:12 -07:00
Bob Lantz c7deeae11c Add sanity check for python mn version 2018-07-26 13:40:12 -07:00
Bob Lantz 323989953b Try to fix pylint errors ;-p 2018-07-26 13:40:12 -07:00
Bob Lantz 17f9756e5c sudo interferes with travis python 3 environment 2018-07-26 13:40:12 -07:00
Bob Lantz 71f3931f2f Remove redundancies in miniedit; pass code check 2018-07-26 13:40:12 -07:00
Bob Lantz 1e9ca5f7fc Fix missing quote in .travis.yml 2018-07-26 13:40:12 -07:00
Bob Lantz 8933c996cb Add python-tk/python3-tk 2018-07-26 13:40:06 -07:00
Bob Lantz afa83cd5ae Restore python 2 compatibility 2018-07-26 13:40:03 -07:00
Hantao Cui 3e81ea7455 miniedit.py changes for Python 3 2018-07-26 13:39:49 -07:00
Bob Lantz 8102704726 Pass code check (14.04) 2018-07-25 21:30:05 -07:00
Bob Lantz f4490069ca Add PYTHON and python2/python3 support
Perhaps we should have an option for py2/p3, but for
now we detect the default python version and it can
also be specified via the PYTHON env var.
2018-07-25 19:44:46 -07:00
Bob Lantz 2ac4f92af3 Add PYTHON variable for python2/python3 make install 2018-07-25 19:44:46 -07:00
Bob Lantz f98154a323 Decode subprocess output for python3 2018-07-25 19:44:46 -07:00
Bob Lantz 7b48460e9e Change pexpect hackery to use a custom class
So the original pexpect is unperturbed
2018-07-25 19:44:46 -07:00
Bob Lantz 3a0ef258d1 grep cgroup /proc/mounts in mountCgroup 2018-07-25 19:44:45 -07:00
Bob Lantz 0d9a6796df Add Python 2.7 and Python 3.6 2018-07-25 19:44:45 -07:00
Bob Lantz 08a59783f4 Decode readline() and call cleanup() for python 3
Python 3.6 crashes if there are leftover processes, even
if they shut down later...
2018-07-25 19:44:45 -07:00
Bob Lantz e37afe996b First crack at Python 3 compatibility
Mostly we just use mininet.util.pexpect so that we can use
unicode strings without changing calls to pexpect.spawn()
2018-07-25 19:44:45 -07:00
Bob Lantz 6a387faa04 Fix whitespace error 2018-07-25 19:44:45 -07:00
Bob Lantz 1a134cb4d2 80 columns 2018-07-25 19:44:45 -07:00
Bob Lantz af4921adc5 Minor changes for Python 3
items() vs. iteritems() and decode() bytes in monitorFiles

Probably not strictly correct if bytes are split - we still
need to deal with this properly.
2018-07-25 19:44:45 -07:00
Bob Lantz f94ee8ec97 Redesign pmonitor()
This is tricky to get right, but I think it is correct
to drain the buffers like this.
2018-07-25 19:44:45 -07:00
Bob Lantz 356b024d6b Wrap reads in pmonitor() for python3 2018-07-25 19:44:45 -07:00
Bob Lantz 2283bb01e6 Python3 compat and add timeout for connect 2018-07-25 19:44:45 -07:00
Bob Lantz 3eef584c6b Python 3 compatibility
And some Ubuntu 18 compat:

- ifconfig's output has changed
- relaxing timing as it seems first ping is slower
2018-07-25 19:44:45 -07:00
Bob Lantz 2e00a7de97 Python 3 compatibility 2018-07-25 19:44:45 -07:00
Bob Lantz e28348f6cd Indent error. 2018-07-25 19:44:44 -07:00
Bob Lantz 4b744d1fb0 Fix dynamic Python items() in deleteIntfs() 2018-07-25 19:44:44 -07:00
Bob Lantz 2822998cad A couple of missed py3 items: execfile, iteritems 2018-07-25 19:44:44 -07:00
Bob Lantz 853815500d Create util.pexpect which is compatible with Python 3 strings
Unfortunately pexpect isn't compatible with Python 3 strings
unless you specify unicode encoding, which isn't the default.

With this helper code, you can import pexpect from mininet.util
and get default pexpect.spawn() behavior that works with Python 3
strings.
2018-07-25 19:44:44 -07:00
Bob Lantz 1a2925923f translate() -> replace() for Python 3 compatibility
str.translate() works differently in Python 3
2018-07-25 19:44:44 -07:00
Bob Lantz cac884a85e Wait for Node() shell to exit on Python 3
I'm not a fan of this, but Python 3's subprocess module
complains otherwise.

For now we're only doing this on Python 3. We should probably
quantify the slowdown however.
2018-07-25 19:44:44 -07:00
Bob Lantz f314a6626a Missed one instance of basestring 2018-07-25 19:44:44 -07:00
Bob Lantz bf83f4f343 Don't bother checking for negative delay/jitter
It's kind of pointless. However technically the argument should
be a number and not a string - it's always in ms.
2018-07-25 19:44:44 -07:00
Bob Lantz 1ef12e450a Apparently Python 3 types aren't ordered 2018-07-25 19:44:44 -07:00
Bob Lantz 56fc6c3955 Close popen stdout and stderr
They should get cleaned up anyway, but Python 3 gives
us an error message. This silences it.
2018-07-25 19:44:44 -07:00
Bob Lantz 88cbf4ec42 Kinder, gentler Python 3 compatibility
Looking at trying to minimize code changes for Python 3.

For now we are keeping byte str() in py2 and unicode str()
in py3. It's a pain to rewrite all string code to usee
u'' for py2 compatibility. However we may need to revisit
this for pexpect().

Created compatibility wrappers in util.py:

BaseString (replacement for basestring)
decode() (optionally decode utf-8 for py3)
encode() (optionally encode utf-8 for py3)

Also we've switched from the .iter*() flavors to their
static alternatives for py2 (note they are iterators in py3!)

Changed util.errRun and clean.sh to call decode()
2018-07-25 19:44:44 -07:00
Bob Lantz 26b3959968 Fix keys parameter in edges_iter
Fixes #813
2018-07-11 23:36:11 +00:00
Bob Lantz 966dd20b4b waitConnected: don't compare timeout if it is None 2018-07-11 23:29:19 +00:00
Bob Lantz 82998cac8b waitConnected and debug output for testMultiPing
This test fails periodically on Travis (#714)

Hopefully waiting for connection will make it more reliable,
and if not then the debug output will help.
2018-07-10 07:41:19 -07:00
lantz 34b1f4161a Merge pull request #803 from teto/nixos_clean
Merge in nixos changes:
1. More flexible makefile
2. Fix problems from setting vi-ins-mode-string in .inputrc (fixes #799)
2018-06-25 19:49:22 -07:00
lantz dfb297901f Update copyright date in LICENSE
It's 2018. ;-)
2018-06-18 09:59:11 -07:00
Bob Lantz 67236e9db3 Update ofsoftswitch build
Changed netbee URL.
Changed libxerces package for Ubuntu 18.04
2018-06-03 17:20:18 -07:00
Matthieu Coudron 8a00c3abf8 bash: run with --noediting
Having "set editing-mode vi" in ~/.inputrc can output characters that
may induce mininet into (wrongly) thinking a process has failed.
2018-06-03 09:54:50 +09:00
Matthieu Coudron 037f7f5921 Makefile: make it more flexible
- let the user choose where to install (via PREFIX)
- added targets install-mnexec/install-manpages
2018-06-03 09:54:13 +09:00
Bob Lantz 8af3f28b67 iproute -> iproute2 for Ubuntu 18.04
This should also be backward compatible to 14.04.
2018-04-28 01:48:36 +00:00
lantz c5b2efd839 Merge pull request #780 from nemethf/set_dp_desc
Set the datapath desciption (dp-desc) of OVS switches
2018-02-28 12:20:20 -08:00
Felician Nemeth a638e0b085 Set the datapath desciption (dp-desc) of OVS switches 2017-12-07 12:17:50 +01:00
lantz f65e1ab936 Merge pull request #767 from juangascon/travis_yml
Remove '- dist: xenial' until Travis gets their act together and supports the current LTS
2017-10-10 16:12:50 -07:00
juan 70d14db881 Remove '- dist: xenial' because both jobs are run in the same Ubuntu version (14.04) as I have seen in the build logs.
The travis-CI docs confirm the OS environment is 'Ubuntu 14.04 LTS trusty'.
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 environment.
2017-10-10 21:36:29 +02:00
Bob Lantz b142cf32ec Pass code check (14.04 LTS: pyflakes 0.8.1, pylint 1.1.0)
Was no longer passing due to pyflakes.
2017-09-25 16:07:47 -07:00
Bob Lantz 87e26ef931 Restore CLI=MyCLI customization in --custom files
fixes #746
2017-06-02 14:11:36 -07:00
Bob Lantz 7366645c81 Fix plot() command for newer networkx
Networkx moved graphviz_layout, so we look for it in two different
places.

Also plot() should be fixed for regular Mininet(), which doesn't have
a .servers list.
2017-05-30 15:37:10 -07:00
Bob Lantz 2437aba984 Change to if to avoid breaking travis build on 16.04 2017-05-24 17:17:25 -07:00
Bob Lantz a6627cd928 Don't call node.addIntf() if node is None
fixes #716
2017-05-24 15:11:03 -07:00
IWASE Yusuke aa8901268d Fix Ryu installation
Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
2017-05-22 15:56:46 -07:00
Bob Lantz 9d306ad53a Allow passing mncmd to CPULimitedHost.popen()
This is not not really intended as an external API (and
it currently isn't documented) but this makes it consistent.

Fixes #743
2017-05-22 15:36:23 -07:00
lantz 69b6c05970 Merge pull request #736 from hwchiu/FIX_TBF_LINK
Modify the default latency type from int to float if tbf is enabled.
Fixes #729
2017-05-09 15:10:39 -07:00
Bob Lantz e55e18e4ce Treat Raspbian as Debian; add $DISTS.
Fixes #713
2017-05-09 14:41:10 -07:00
hwchiu f86db75b79 Modify the default latency from int to float if tbf is enabled.
- the original version will caluse the latency to 0 when bandwidth
  is bigger than 200;
- the TC command doesn't allow use the 0.00ms as input for latency field

Signed-off-by: hwchiu <sppsorrg@gmail.com>
2017-04-28 09:29:17 +08:00
lantz 5728fcbf40 Merge pull request #727 from leonardodavila/master
Fix ryu installation
2017-04-27 16:31:37 -07:00
lantz 23f4f4a998 Merge pull request #734 from akoshibe/upstream
Allow match on 'packets received' in ping results
2017-04-23 23:59:05 -07:00
akoshibe ba2d91b489 Allow match on 'packets received' in ping results
Fix typo and remove redundant call to nproc
2017-04-22 16:17:35 -08:00
Leonardo D'Avila 40e2c374d0 Merge pull request #1 from leonardodavila/fix-ryu-install
update install.sh fixing ryu install
2017-03-28 23:43:48 -03:00
Leonardo D'Avila ce8feb7bfa update install.sh fixing ryu install 2017-03-28 23:43:27 -03:00
lantz e823c4f93c Fix line break
Beware of emacs eating trailing spaces!
2017-03-22 14:34:23 -07:00
lantz 497a342c27 Update README.md 2017-03-22 14:32:44 -07:00
Bob Lantz 32565765c1 For now, install dependencies before make codecheck 2017-03-15 16:19:31 -07:00
Bob Lantz c1d07835bd Rearrange code check 2017-03-15 15:49:26 -07:00
Bob Lantz 65acef533a Run bash explicitly in codecheck conditional 2017-03-15 15:09:06 -07:00
Bob Lantz bf2bb4c88c Sadly pylint isn't backward compatible; comment out newer options
Also slightly adjust some valid name conventions
2017-03-15 15:03:47 -07:00
Bob Lantz bfc00c567c Add more ignores for plint 1.5.2 2017-03-15 14:50:01 -07:00
Bob Lantz 92d57db0d0 Run codecheck on 14.04 only and after install (for deps) 2017-03-14 15:47:46 -07:00
Bob Lantz 13331d0ffd Add "make codecheck" 2017-03-14 15:43:47 -07:00
Bob Lantz 359b1feb5a code check 2017-03-14 15:43:41 -07:00
Bob Lantz a77ddba607 code check 2017-03-14 15:43:28 -07:00
Bob Lantz caf23f078e code check 2017-03-13 19:09:24 -07:00
Bob Lantz d5cb865aaa code check 2017-03-13 19:08:39 -07:00
Bob Lantz 1c0aeb699f code check 2017-03-13 19:08:26 -07:00
Bob Lantz c458c9e2b4 code check 2017-03-13 18:56:21 -07:00
Bob Lantz 26a0e351f3 satisfy code check 2017-03-13 17:11:05 -07:00
Bob Lantz 742f5b9af9 satisfy code check 2017-03-13 17:10:14 -07:00
Bob Lantz 40e4546c48 satisfy code check 2017-03-13 17:09:19 -07:00
Bob Lantz 5479117584 pass code check 2017-03-13 17:06:53 -07:00
Bob Lantz 02453b02b0 Remove relative import 2017-03-13 17:05:50 -07:00
Bob Lantz d282c55831 pass code check; make GRE_KEY a class var 2017-03-13 17:03:11 -07:00
Bob Lantz 6977633de1 pass code check 2017-03-13 16:36:50 -07:00
Bob Lantz bc0a72e2f9 pass code check 2017-03-13 16:36:41 -07:00
Bob Lantz ef5c80abb3 pass code check 2017-03-13 16:34:38 -07:00
Bob Lantz 35a33fc617 print() -> error() 2017-03-13 16:31:17 -07:00
Bob Lantz 494840c908 satisfy codecheck 2017-03-13 13:57:41 -07:00
Bob Lantz b7d9fdd5bd Satisfy codecheck 2017-03-13 13:56:46 -07:00
Bob Lantz 32299a6808 Restore incorrectly placed docstring 2017-03-13 13:48:50 -07:00
Bob Lantz d7cfb729c3 Pass code check and add ovs-testcontroller to zombies 2017-03-13 13:46:51 -07:00
Bob Lantz 348b526212 Satisfy pylint 2017-02-15 18:35:45 -08:00
Bob Lantz 18bfa1d6b3 warn() was undefined 2017-02-15 18:30:09 -08:00
Bob Lantz 5d2dfa9f40 Handle version string sent to stderr
An unfortunate side effect of switching from print to output() is
that all output() goes to stderr. We should probably carefully
consider whether this is the right thing to do.
2017-02-15 18:26:18 -08:00
Bob Lantz 0b5d24148b default(): add CR to error(); also clean up docstring 2017-02-08 16:30:36 -08:00
Bob Lantz dfb2594793 testLinkChange: report bandwidth on error 2017-02-07 15:01:05 -08:00
lantz b5b6beacb0 Multiple builds: trusty and xenial 2017-01-31 15:34:27 -08:00
Brian O'Connor 213563583d Updating .travis.yml to suppress success notifications 2017-01-12 18:44:45 -08:00
Brian O'Connor 9c7638a015 Updating README
Moving Travis logo down and using image reference to declutter.
2017-01-12 17:01:26 -08:00
Brian O'Connor fef7e0521c Merge pull request #710 from bocon13/travisci
Setting up .travis.yml for automated builds on Travis CI
2017-01-12 16:29:54 -08:00
Brian O'Connor 335cb1bdf3 Adding TravisCI build static icon to README 2017-01-12 16:13:20 -08:00
Brian O'Connor 0b2d8461fd Updating hwintf test to call host.stop()
host.terminate() does not remove the interfaces
2017-01-12 16:11:24 -08:00
Brian O'Connor 9376ccbedd Updating runner to exit 1 on failure 2017-01-12 16:11:24 -08:00
Brian O'Connor 03b1cbb347 Update example runner to exit 1 on failure 2017-01-12 16:11:24 -08:00
Brian O'Connor 51f50e8b8f Adding .travis.yml for Travis CI 2017-01-12 16:11:13 -08:00
lantz 2e9a79a375 Merge pull request #618 from BhattiMarry/master
UPDATE command made generic. Obsolete kernel() function was breaking Fedora/RHEL install.
2017-01-11 15:50:53 -08:00
lantz 86a26e0baf Merge pull request #602 from youf3/patch-1
Added ryu to be clean up in clean.py
2017-01-10 14:08:16 -08:00
lantz 6f2981134d Merge pull request #606 from oliviertilmans/patch-2
link: Fix circular import
2017-01-06 15:26:47 -08:00
lantz e58cc37c49 Merge pull request #699 from NvanAdrichem/MiniEdit-OVSVersion
Changed verifying the OVS version to not require root in MiniEdit.
2017-01-06 14:57:59 -08:00
lantz baebce8b05 Merge pull request #672 from nirmoy/opensuse_installation
RFC: add installation support for SUSE based distros
2017-01-06 14:55:11 -08:00
lantz 2bfaec75e0 Merge pull request #685 from maufl/fix-ping-parse-regex
Fix regex for ping result parsing, supporting optional 'packets' word in ping output
2017-01-06 14:53:42 -08:00
lantz 36c2e7cd79 Added "Additional Information" section. 2017-01-06 14:37:11 -08:00
lantz 3284b04f2b Merge pull request #704 from mininet/devel/ipBase
Updating Mininet to start with host IP request in ipBase
2017-01-03 16:55:37 -08:00
Brian O'Connor 8c662d63bf Updating Mininet to start with host IP request in ipBase 2017-01-03 15:11:38 -08:00
Niels van Adrichem 3cb387ebd0 Changed verifying the OVS version to not require root in MiniEdit. 2016-12-21 11:59:55 +01:00
lantz e90a4a74cb Update ISSUE_TEMPLATE 2016-12-09 16:02:29 -08:00
Bob Lantz d338b4425b Added GitHub issue template. 2016-12-09 15:55:48 -08:00
Felix Konstantin Maurer c128712d4d Fix regex for ping result parsing 2016-11-14 14:16:07 +01:00
Bob Lantz 8b2881b0c2 Changes for OVS 2.6.0 + Ubuntu 16.04 + Debian 8.6 2016-10-28 18:16:25 -07:00
Bob Lantz 3a9081b5b1 Add small wait before wget in web test.
Although the walkthrough doesn't specify waiting, it is a race
condition that we occasionally hit in tests. Adding a 2 second
delay seems realistic (for when a human is doing the walkthrough)
and should reduce the likelihood of hitting the race condition.
2016-10-21 15:31:33 -07:00
Bob Lantz 54bd4e4d3a For 10Mb/s links, we should certainly be network-limited rather
than CPU-limited, which should expose the feature we are trying
to demonstrate (TCP data rate slowing down as latency increases
due to congestion control.)
2016-10-21 13:25:40 -07:00
lantz cc1cd9619f Merge pull request #671 from vik-y/master
Changes override method from __init__ to build
2016-09-28 20:45:35 -07:00
Nirmoy Das 007261d19e add installation support for SUSE based distros 2016-09-28 12:08:32 +02:00
vik_y dc22b0a877 Changes override method from __init__ to build 2016-09-27 13:19:08 +05:30
Bob Lantz 4178333174 Wait for exit in testWireshark()
If mn doesn't shut down cleanly, the subsequent test may fail.
2016-09-23 16:07:12 -07:00
Bob Lantz f012dac2cb Clean shutdown for testStaticMAC
Without waiting for mn to exit, OVS keeps listening on the
static listening port, which prevents UserSwitch from listening
on it (and starting up) in the next test.
2016-09-21 13:25:04 -07:00
Bob Lantz 8def6752f3 Add TCULink and make it the default for --switch user
For some time, UserSwitch has suffered from abysmal performance due
to rx and tx offload settings. In the latest Ubuntu 16.04/Linux 4.4
kernel, it simply doesn't work with the default settings, since
packets with bad TCP checksums are generated at one end, passed through
the user switch, and dropped at the other. It doesn't seem to be
something we can fix in UserSwitch itself although it may be possible
to do something in the C code of the Stanford reference switch and
CPqD switch.
2016-09-20 12:43:27 -07:00
Bob Lantz 0f9c1b33c7 Change default --listenport to 6654
Previously the standard OpenFlow poort (6653) that Controller()
may be listening at would conflict with the default listenPort
for switch 20 (usually UserSwitch 20), breaking waitConnected()
and disconnecting that switch from the network in general.

Fixes #668
2016-09-14 00:38:35 -07:00
Bob Lantz f530c99415 testHostCommands: accept both ethX and en.*X interfaces
systemd (Ubuntu 16) names interfaces like this:
enp1s3 for "ethernet, PCI bus 1, slot 3"

We now accept both in testHostCommands

Fixes #665
2016-09-09 14:54:38 -07:00
Bob Lantz 5470415bfc Fix mn -v by using output() rather than info()
info() doesn't produce any output if it's called at
this point; bug was introduced when we tried to eliminate
print().
2016-09-01 23:25:14 -07:00
Bob Lantz 7e5324c80e Add TESTS parameters, multiple tests with +
It's very useful to be able to pass parameters to tests.
Unfortunately, our previous --test argument syntax didn't
permit it, because , was used as a delimiter for multiple
tests. With this change, we change , to become a delimiter
for arguments, as it is with other options to mn.  For now,
we introduce + as a separator, as it is legal in filenames
and therefore shouldn't conflict with special characters
used by Unix shells.

We also reorganize mn a bit to make it hopefully slightly
clearer.
2016-08-30 02:44:38 -07:00
Bob Lantz e893fc9da4 Try specifying timeout in pexpect.spawn() + adjust error msg
Unfortunately pexpect() seems to be timing out with a 30 second
timeout rather than the 600 seconds we are passing in. How
could this even be working normally? It is puzzling. We are
going to try specifying the timeout in the spawn() call.

Also if the test fails, we use %e format for readability.
2016-08-29 23:57:17 -07:00
Bob Lantz b2e1907c3a Increase link delay to 2ms for more robust effect
With a 1 ms delay, the performance tests periodically fails
under nested virtualization, which is how we are testing it.
Increasing the delay should make the effect (lower TCP
data rates as latency increases, due to TCP's congestion
control algorithm) more pronounced and robust.
2016-08-25 03:55:28 -07:00
Bob Lantz 21086cd79e Reduce CPU so that iperf client is CPU bound
If we want to observe a monotonic affect, we should
make sure that we are in fact CPU limited where it
matters. In this case, we are CPU limiting the hosts,
and the iperf client uses a lot of CPU. We need to
reduce the CPU allocation so that iperf is in fact
CPU bound.

We also correct the CPU allocation so that the client
and server each receive 50% of the total. Previously
we were specifying the per-host CPU allocation, so
45% meant we were allocating 90% of the overall CPU,
which seems a bit confusing. On the other hand, now
at 40% each host gets 20% of the CPU, which could also
be considered slightly confusing!

Although the client transmit rate is going to be the
limiting factor, we still measure the received data
rate at the server, because that is more interesting
than the initial burst of buffering at the client.
Measuring at the server becomes more important as
we reduce the iperf time.

The output is also changed slightly, and the test has
been updated appropriately.
2016-08-24 23:59:02 -07:00
Bob Lantz ee15ce2243 print -> info; end the horror of print vs. print()
Although we could use print() from __future__, this messes
up scripts which use examples as modules.

The simple, if not nicest for 2.7, solution is to use
info(), output() and other mininet.log functions. The disadvantage
is that we may have to adjust things if we change info() to
add automatic newlines, but we can burn that bridge in Mininet
3.x.
2016-08-23 01:54:54 -07:00
Bob Lantz 1eb6f65e40 Increase scratchnet timeout to see if it's just slow. 2016-08-22 23:18:58 -07:00
lantz 238ffe64a7 Merge pull request #659 from jhall11/links_output
Restore links output format
2016-08-23 12:28:58 -07:00
Jon Hall cea176fa9f Restore links output format
In the change from print -> print() -> output() we lost the new lines
which makes it hard to read the output
2016-08-23 10:49:36 -07:00
Bob Lantz 3276e3fef5 Allow some diffs in h1 ps vs. h2 ps
Presumably daemons, race conditions, or ephemeral processes
can cause the ps output to vary slightly. We allow up to
two differing lines to account for this.

Fixes #651
2016-08-22 15:59:49 -07:00
Bob Lantz e40d9b8c0d print -> info; also clarify signalTest output 2016-08-15 22:54:21 -07:00
lantz 30d08cfbb2 Merge pull request #641 from xiaozhou/master
add a new type of RemoteLink in cluster edition that uses GRE tunnels
2016-08-16 15:05:59 -07:00
Bob Lantz 29d902918d Change tshark version check for compatibility
The version string changed in tshark 2.0.2 in Ubuntu 16.
Perhaps we should just check for the version string itself
to be more robust but this is probably OK for now.
2016-08-11 14:33:41 -07:00
Bob Lantz f89a5bcf70 Use output()/error() instead of print
We shouldn't be using print in the core API, with
the possible (?) exception of error/abort messages.
2016-08-08 15:32:31 -07:00
Bob Lantz 8ac077a721 Remove "from __future__ import print"
This was well-intentioned, but it causes more trouble
than it's worth.

Fixes #652
2016-08-08 15:28:52 -07:00
lantz 666635c969 Merge pull request #636 from mininet/devel/add-del
Add net.delNode(), net.delLink() and associated methods
2016-08-04 17:10:08 -07:00
Bob Lantz 4c1cfcf6f3 14.04.3 -> 14.04.4
We should probably do this in a more automatic way.
2016-08-03 15:17:08 -07:00
Bob Lantz 76c8afde8a Fixes for Unbuntu 16.04/Xenial
- add xenial
- partx returns an error (warn rather than fail)
- remove dnsmasq build.py dependency (not really needed, side effects)
2016-08-02 15:27:53 -07:00
lantz 5714495f8c Merge pull request #603 from oliviertilmans/patch-1
TCIntf: Don't delete a non-existing root qdisc
2016-08-01 15:24:20 -07:00
Xiaozhou Li d8371615ce fix typo 2016-07-29 09:57:30 -07:00
Xiaozhou Li 7630861fde fix typo 2016-07-11 21:15:04 -07:00
Xiaozhou Li da594dcecd add a new type of RemoteLink in cluster edition that uses GRE tunnels 2016-07-11 21:05:01 -07:00
lantz 4fe5a19221 Merge pull request #598 from croft/master
Set limit on command history length
2016-06-21 16:40:55 -07:00
lantz 330a466503 Merge pull request #611 from jue-jiang/master
modify loss type of tclink to simulate loss rate under 1%
2016-06-21 16:37:38 -07:00
lantz c0b8eddadb Merge pull request #623 from bradmwalker/ivs-install
Fix/speed up IVS install and build on Fedora/RH
2016-06-21 16:36:39 -07:00
Bob Lantz 76b54e3e44 Merge branch 'bradmwalker-py3-part1'
py3 low-hanging fruit

closes #621
2016-06-21 16:34:12 -07:00
Bob Lantz 36489c7470 Change xrange to range for py3 compatibility 2016-06-21 16:31:46 -07:00
Brad Walker dd8adda3ff Use "Exception as _" instead of "Exception, _"
Requires Python 2.6+
2016-06-21 16:27:04 -07:00
Brad Walker fb1f0dca2a Make some tuples explicit to pass parsing in py3 2016-06-21 16:27:04 -07:00
Brad Walker 70fcc45893 Use print function 2016-06-21 16:27:04 -07:00
Bob Lantz 511d71a110 Add net.delNode(), net.delLink() and associated methods
This makes the mid-level net.add*() API symmetric.
You can now delete hosts, switches, controllers and links using
a new net.del*() API, as well as del net[ 'nodename' ].
2016-06-03 23:59:27 -07:00
Bob Lantz 57abd9baef Use correct command name in OVSController 2016-05-24 17:40:00 -07:00
Bob Lantz e6b0430a87 Enable TESTS={'mytest':test} in --custom files 2016-05-11 19:30:18 -07:00
Brad Walker 6f286033c5 Checkout only first level of IVS submodules
The submodules have submodules with authenticated URLs which breaks anonymous,
automated builds. Excluding them also decreases build time.

git -C is not available in git 1.8 (CentOS 7)
2016-04-30 19:13:27 -04:00
Brad Walker 1600b10131 Specify RPM dependencies for IVS 2016-04-30 19:13:27 -04:00
Bob Lantz 475bb4d911 2.3.0d1 2016-04-26 15:13:14 -07:00
Bob Lantz c5517f7872 2.2.1 -> 2.2.2b1 2016-04-26 15:10:06 -07:00
Bob Lantz 40353c9150 Split lines to make pylint happy 2016-04-26 14:48:06 -07:00
lantz c7e23ccedf Merge pull request #617 from oliviertilmans/patch-3
link: Set prefixLen for loopback address
2016-04-22 13:30:16 -07:00
Muhammad Umair Bhatti 361beab0b0 UPDATE command made generic.
Update command was hard-coded for debian or ubuntu based systems which was 'apt-get'. Setting an update variable accordingly solves this problem.
2016-04-18 16:45:44 +05:00
Olivier Tilmans 07fbc894e7 link: Set prefixLen for loopback address
The prefixLen for a loopback address is well-defined (/8),
and as such the variable is set accordingly.

Signed-off-by: Olivier Tilmans <olivier.tilmans@uclouvain.be>
2016-04-17 23:07:34 +02:00
zhuo 098b39d07a modify loss type of tclink to simulate loss rate under 1% 2016-04-09 19:27:52 +08:00
Olivier Tilmans 60e537f9bc link: Fix circular import
Having an 'import mininet.node' in the link module causes
a circular import as the node module also has a top-level
import for the link module.

In order to break the cycle, the import for the node module
is delayed and executed only if using the sole class that
actually needs it in the link module.
2016-03-25 00:32:52 +01:00
Olivier Tilmans 5cfc9f84b8 TCIntf: Don't delete a non-existing root qdisc
In recent kernels, virtual interfaces come without any associated
qdisc, resulting in errors when spawning the network.
Checking for "noqueue" in the tc output, enables to detect that
case and thus avoid deleting the non-existent qdisc.
2016-03-11 13:36:56 +01:00
youf3 6ddce0ac92 Added ryu to be clean up in clean.py
'ryu-manager' is included in zombies list so Ryu controller is cleaned up properly.
2016-03-11 16:47:35 +13:00
Jason Croft e87ee10f8b Set limit on command history length 2016-02-25 03:50:22 -06:00
lantz e171aba8b5 Merge pull request #597 from nemethf/doc_fix
Fix documentation of failMode in OVSSwitch
2016-02-19 14:42:38 -08:00
Felician Nemeth 1bd0e927d2 Fix documentation of failMode in OVSSwitch 2016-02-19 01:26:00 -08:00
Bob Lantz e113f8ed12 Add error message to shed light on why this sometimes fails 2016-02-02 23:32:03 -08:00
Bob Lantz 336958352a Only use 80 hosts for linearbandwidth.py for now
In the long run, we should debug the performance issues
with kvm and Ubuntu 15. For now, however, we're relaxing
the constraints.

Closes #594
2016-01-26 15:40:59 -08:00
Bob Lantz 5dc15aeaaf Tolerate slow startup/lost pings for now
In the long run we should troubleshoot the performance issue
on kvm/Ubuntu15, but for now we are relaxing the constraint.

Closes #593
2016-01-26 15:40:56 -08:00
Bob Lantz 9a22e2b737 Use ifconfig for interface verification.
Previously we were using both ip link and ifconfig - not only is
this inconsistent and redundant, but it also broke when newer
ip link changed the reported names of certain interfacs to
"h1-eth0@36:".

Fixes #592
2016-01-25 14:27:34 -08:00
Bob Lantz 76d3252cd0 Fix error exit from dd/block zeroing 2016-01-22 16:47:23 -08:00
Bob Lantz 9756c9a392 vm_clean: delete keys from from /etc/ssh/ before shipping vm
It's a bad idea for all Mininet VMs to share the same SSH keys.
Certainly users can regenerate their own keys, but it's better
if we don't ship a key and simply regenerate it on boot.
2016-01-22 16:02:55 -08:00
Bob Lantz 0fac568a19 Rewrite tolerance to be saner (plus or minus 20%) 2016-01-22 13:52:15 -08:00
Bob Lantz 04897513cd Collect all server output in iperf()
This still isn't ideal - this was breaking UDP iperf, which
can take a bit of time to print its output after you control-c it.
2016-01-22 13:33:33 -08:00
Bob Lantz 5365831de8 Use 0% loss when testing examples/simpleperf.py
Also clarified the code in test_simpleperf.py.

Fixes #590
2016-01-21 17:07:39 -08:00
Bob Lantz 6a69c3c743 Fix UDP iperf. 2016-01-21 16:59:18 -08:00
Bob Lantz c0793cb58b Add "run" alias for "use" and integrate build/test options
Keeping "use" for now even though it seems harder to remember
than "run". And the build/test options are probably much
clearer being inline in the help.
2016-01-20 17:33:00 -08:00
Bob Lantz 327af97ccc Try to fix iperf race condition
This is more complicated than it should be. We are also relying on
the fact that waitOutput should eat extra prompts most of the time.
Still not perfect - it's hard to get this exactly right, and we
should try to make it easier!

Fixes #589
2016-01-20 17:32:49 -08:00
Bob Lantz b78b99b695 monitor() should return on timeout; docstring changes
It appears that read() has been blocking for some time,
so for now it makes sense to change the documentation to
match the functionality!

It's not entirely clear if monitor() expects this functionality.
However, with the current blocking read() semantics, it should
definitely return (and not call read()) on a poll timeout.

So, we now return the poll() result from waitReadable() (which
should have done this already probably) and check it. In the
fullness of time, we still need to revisit the whole I/O API
and make sure that it is consistent, sane, correctly documented,
and used correctly in the examples.

See #588 for more comments.
2016-01-20 13:33:54 -08:00
Bob Lantz a1bff4b035 Add python-pexpect to dependencies
It's used by tests and isn't large.
Fixes #587
2016-01-19 13:24:36 -08:00
Bob Lantz 0b673d7cb6 Update Ryu dependencies. 2016-01-19 13:23:43 -08:00
Bob Lantz db134f36ae Allow RemoteController to connect to correct port.
Fixes #584
2016-01-13 22:40:41 -08:00
Bob Lantz f873068a2c Add chown argument to change build dir owner
This allows Jenkins to delete a sudo build.
2016-01-13 17:16:07 -08:00
Bob Lantz 38a4000a97 Update to recent LTS and ubuntu releases.
Perhaps we should make this more algorithmic...
2016-01-12 01:16:26 -08:00
Bob Lantz 0f5e05c088 Handle openvswitch-testcontroller in ubuntu 15 2016-01-12 01:00:34 -08:00
Bob Lantz 65000d3245 Non-interactive installation on debian (respect -y flag!) 2016-01-11 19:18:15 -08:00
Bob Lantz 312ed1a4a5 Use our github forks of openflow, oflops for now
This enables us to test our changes for Ubuntu 15 (new gcc/c99)
before pushing upstream if desired.
2016-01-11 17:24:17 -08:00
lantz ce5738b4a6 Merge pull request #533 from pichuang/node
Check for ovs-testcontroller in OVSController
2016-01-11 16:58:40 -08:00
lantz 447db4c77c Merge pull request #526 from msvbhat/master
Fixing the install.sh in INSTALL file
2016-01-11 16:56:48 -08:00
lantz b47aa5dadc Merge pull request #558 from bregman-arie/master
Update install.sh to support RedHat distrubtion
2015-11-30 16:09:15 -08:00
lantz af0215fb9f Merge pull request #536 from jonohart/buildcpu
Add parameter for number of CPU cores to use in VM builds
2015-11-23 15:40:46 -08:00
lantz 2791333c70 Merge pull request #566 from moz/master
addNAT always use first switch
2015-11-23 15:33:12 -08:00
Tomasz Buchert 96ea5367db mnexec: properly setup the mount namespace
Systemd's default is to mark the root mount as shared and it is
inherited as such by the new mount namespace. This means that any
mounts performed inthe new namespace will be visible by the rest of
the system, breaking privateDirs.

To restore a more sane behaviour, we explicitly mark all mounts
recursively as private, meaning that we will no longer see new mounts
from the root namespace, and our mounts will also not propagate to the
rest of the system.

Fixes #565
2015-11-18 11:47:50 -08:00
Rahman Pujianto 0298e9be7d addNAT always use first switch
addNAT always use first switch even though another switch specified
2015-11-09 11:48:12 +07:00
Bob Lantz 7c6d645a0a Workaround for cgdelete deleting cgroup but returning error
fixes #513
2015-10-22 16:34:05 -07:00
Arie Bregman 0c2fbaf187 Update install.sh to support RedHat distrubtion
Mininet installation will also work on RedHat distribution
2015-10-18 10:40:11 +03:00
Brian O'Connor d254d7496c Removing unnecessary braces in RemoteController 2015-09-23 16:02:55 -07:00
lantz 2c5d86f197 Merge pull request #555 from mininet/devel/of-port
Updating OpenFlow default port to 6653 (in Controller and RemoteController)
2015-09-23 15:36:04 -07:00
Brian O'Connor 8df24304d8 Updating OpenFlow default port to 6653
- Pass 6653 to controllers that Mininet starts
- Try to connect first on 6653 for RemoteController, then fallback to 6633

fixes #545
2015-09-22 17:29:50 -07:00
lantz 93b123761b Merge pull request #541 from thinred/master
don't generate .pyc files on some makefile targets
2015-07-29 13:25:32 -07:00
Tomasz Buchert cdbbb5b7a6 don't generate .pyc files on some makefile targets 2015-07-29 17:13:01 +02:00
Jonathan Hart 86af067e42 Add option for number of CPU cores to use for VM builds 2015-07-15 10:40:45 -07:00
Roan Huang db3bffa971 Check for ovs-testcontroller in OVSController
The programe name changed from test-controller to ovs-testcontroller

Reference:
openvswitch/ovs 0bc1b46a38cca06023fdfa5d500c738ccdfa94e7
2015-07-07 00:11:57 +08:00
Bob Lantz 2cb17590c2 Remove blank line
I'm not sure whether we really need to turn off ip_forward before
flushing iptables, but it might possibly be useful to avoid certain
unexpected behavior.
2015-06-25 15:42:22 -07:00
Bob Lantz f7601da006 Change quoting for '!' 2015-06-25 15:38:50 -07:00
lantz 65a0e5f3b6 Merge pull request #528 from pichuang/cluster
Fixed `whoami` output problem in cluster.py
2015-06-25 13:36:21 -07:00
Roan Huang d5d66f1276 Fixed whoami output problem in cluster.py
Remove the last character when use `whoami`
2015-06-25 05:37:20 +00:00
Bob Lantz 9ed14fa0f4 Remove explicit NAT code and use built-in NAT functionality.
This API isn't great - we should try to improve it in the future.
2015-06-23 15:17:58 -07:00
lantz f24ebc438e Merge pull request #530 from jonohart/master
Enable NAT to use all interfaces.
2015-06-23 15:08:47 -07:00
Jonathan Hart 90d50dcbc4 Enable NAT to use all interfaces.
Also put the net.ipv4.ip_forward option back to what it was before on exit,
rather than always setting back to 0.
2015-06-23 13:57:19 -07:00
M S Vishwanath Bhat ce2458c1df INSTALL: Another trivial install.sh path fix
Signed-off-by: M S Vishwanath Bhat <msvbhat@gmail.com>
2015-06-14 14:12:23 +05:30
M S Vishwanath Bhat 8871893993 INSTALL: Fixing the path of install.sh
Signed-off-by: M S Vishwanath Bhat <msvbhat@gmail.com>
2015-06-14 14:02:31 +05:30
Bob Lantz 5f68be2273 Remove debug print 2015-06-11 00:16:55 -07:00
Bob Lantz 68ae67dc58 Support custom links in custom file 2015-06-10 20:35:53 -07:00
Bob Lantz c4a85ab1d1 Add flush option to disable flushing iptables 2015-06-10 20:09:29 -07:00
Bob Lantz ef3c885630 Add help regarding --nat [option=val...] 2015-06-10 20:08:44 -07:00
Bob Lantz bb35d04102 Fix TorusTopo for UserSwitch
UserSwitch requires a 12-digit dpid.
2015-06-07 22:10:18 -07:00
Bob Lantz ba05fd363b Warn if bridge netfilter (firewall) is enabled
Newer linux kernels enable filtering on the linux bridge;
this can prevent it from working in mininet!
2015-06-05 16:10:21 -07:00
Brian O'Connor e988b0f660 Merge pull request #522 from mininet/devel/torus
Adding number of hosts per switch option to torus topo
2015-06-05 01:45:01 -07:00
Brian O'Connor b27cce08af Adding number of hosts per switch option to torus topo 2015-05-27 23:45:19 -07:00
Bob Lantz a38896c254 Avoid expanding a string into a list of chars 2015-05-16 08:24:15 -07:00
Bob Lantz 63ae13fcf9 Fix #520 2015-05-12 23:50:37 -07:00
Bob Lantz c5f6d0ff17 Restore use of self.intf (if present) in addLink
fixes #515
2015-05-02 13:16:48 -07:00
Bob Lantz ab8c4e9198 2.2.1rc1 -> 2.2.1 2015-04-16 16:05:30 -07:00
Bob Lantz 8daa4193c7 Fix typo 2015-04-15 16:21:55 -07:00
Bob Lantz 5c895eaad8 Added note on Raspberry Pi ;-) 2015-04-14 14:40:27 -07:00
Bob Lantz 435d0d68b3 -> 2.2.1rc1 2015-04-14 14:33:08 -07:00
Bob Lantz 66e9845f05 Add babisk 2015-04-13 17:58:47 -07:00
Bob Lantz fe3340077c Add dmahler and pichuang 2015-04-13 17:56:11 -07:00
lantz c589660e17 Merge pull request #494 from pichuang/master
Modify directory path in clustersetup.sh
2015-04-13 17:52:06 -07:00
Bob Lantz d9117c77e1 Merge branch 'dmahler-master' 2015-04-13 17:35:52 -07:00
Bob Lantz 6cb68f26c9 Simply use class names as option help
The justification for this is that 1) the options are
already documented in the API documentation and 2) the
class names are fairly self-explanatory, so adding short
descriptions doesn't add much.

In the future, however, we could add a short description
by simply using the first line or sentence of the docstring;
note that docstrings would have to be canonicalized, which
they aren't now.
2015-04-13 17:30:55 -07:00
David Mahler c60764c34f Update to mn --help to provide details on options 2015-04-11 06:20:42 +00:00
lantz ba723826b7 Merge pull request #489 from BabisK/master
New netbee lib, fixes need for very old bison
2015-04-10 17:06:05 -07:00
Bob Lantz 0165d7bdff Implement Switch.stop(), which doesn't call terminate
When I changed the switch implementations to call super().stop(),
I neglected to include a Switch.stop() method which didn't call
terminate(). This broke switch s1 stop and s1.stop().

Fixes #497
2015-04-09 23:19:40 -07:00
Bob Lantz 1df1f9a1c5 Fix sorting & remove duplicate 2015-04-09 17:56:37 -07:00
Roan Huang 2c916acc06 Modify cluster help information 2015-04-07 03:37:53 +00:00
Roan Huang 0a810b226c Modify SSHDIR and USERDIR path 2015-04-06 11:19:26 +00:00
Roan Huang 57c8f5934f Fixed code indentation 2015-04-06 11:12:27 +00:00
Bob Lantz 125e669723 Support multiple --controller arguments 2015-03-30 20:40:07 -07:00
Bob Lantz a2486a6d66 Allow node.setIP() to pass extra arguments to intf.setIP() 2015-03-30 19:43:51 -07:00
Bob Lantz 15f2898f26 Add a space after ipv6.disable=1 so as not to break text boot 2015-03-30 16:26:05 -07:00
Bob Lantz 1c4adde1b6 Remove redundant processing for '/' 2015-03-24 15:22:55 -07:00
Bob Lantz 4d22991245 Allow install.sh -V on debian 2015-03-23 18:48:30 -07:00
Bob Lantz 90ea6c6bd1 Usually kernel install is unnecessary, so don't quit if it fails 2015-03-23 17:42:51 -07:00
Bob Lantz 269cecd3ee openvswitch-datapath-dkms is no longer needed for 14.04+ 2015-03-23 17:15:59 -07:00
Bob Lantz c2be20f09e Rename node.RYU to node.Ryu
Perhaps it should be RyuController, but just Ryu for now.
RYU made no sense because it's not an acronym.
2015-03-18 16:00:28 -07:00
Bob Lantz df56fa2716 2.2.1d1 -> 2.2.1d2 2015-03-18 15:47:53 -07:00
Bob Lantz f49e2539b7 Minor formatting, pass code check 2015-03-18 15:32:21 -07:00
Bob Lantz 4da7b3b7f0 Fix exception for unknown class 2015-03-18 15:31:40 -07:00
Bob Lantz e5a5cd0070 customConstructor -> customClass 2015-03-18 15:18:02 -07:00
Bob Lantz c5779deeb6 Pass code check 2015-03-18 15:17:33 -07:00
Bob Lantz 79c944aef4 Remove obsolete OVSLegacyKernelSwitch 2015-03-18 15:12:09 -07:00
Bob Lantz a23c6a2871 Fix undefined constructors in customClass() 2015-03-18 15:10:20 -07:00
Babis Kaidos 7acc693277 New netbee library is installed for Ubuntu 14.04 and newer. For older releases or for other OSs the old netbee is installed 2015-03-18 17:59:29 +02:00
Babis Kaidos 889698f7bd New netbee lib, fixes need for very old bison 2015-03-16 15:28:20 +02:00
Bob Lantz f6f6d9282b CustomConstructor -> CustomClass, which calls specialClass
specialClass is an analog of functools.partial but for classes.
We can now use it instead of partial() in mn, so that Mininet
can introspect on the actual base class.

Fixes #488
2015-03-13 21:17:43 -07:00
lantz 5224884e5e Merge pull request #473 from joerango/master
Support for running arbitrary command when starting terminal
2015-03-13 15:09:11 -07:00
lantz f063b023bd Merge pull request #478 from rlane/fix-readline-history
cli: don't read/write readline history more than once
2015-03-02 14:22:19 -08:00
Rich Lane a1edb167b1 Merge pull request #1 from lantz/devel/fix-readline-history
Move cmdloop() wrapper into a new run() method
2015-03-02 14:20:11 -08:00
Bob Lantz 613fac4bab Move cmdloop() wrapper into a new run() method
I also added another try/catch block so that interrupting
the 'Interrupt' message should no longer occur.
2015-02-20 16:46:18 -08:00
Rich Lane e0cd11ab21 cli: don't read/write readline history more than once
Previously, when creating multiple CLI objects, each one would append the
~/.mininet_history file to readline's internal list. When writing the file back
it would be duplicated for each CLI object created. So, over a few mininet runs
the history file would grow exponentially.

This change moves the readline setup code out of the CLI constructor into a
class method and adds a flag to prevent it from being executed more than once.
2015-02-20 10:47:43 -08:00
Joseph Beshay 5b818ad75c Support for running arbitrary command when starting terminal (other than bash) 2015-02-09 12:55:25 -06:00
Bob Lantz 17ba6a7c4d Add ip:port shorthand to Controller
Fixes #475
2015-02-04 11:16:42 -08:00
Bob Lantz f77a8b9e17 Fix customConstructor to work correctly with newargs 2015-02-04 10:56:32 -08:00
Bob Lantz 3dd8c2cda6 A controller should delete its interfaces if necessary
This was causing controlnet.py to not clean up its interfaces, since
those interfaces were linked from the controller to the switch
rather than vice-versa!!

deleteIntfs already will only delete interfaces whose names match
our name, which should usually prevent us from accidentally deleting
a hardware interface from the root namespace!
2015-02-04 10:30:26 -08:00
Bob Lantz 48a8ed857e 2.2.0+ -> 2.2.1d1 2015-02-04 05:27:51 -08:00
Bob Lantz 74c3511d5c pass code check 2015-02-04 05:27:14 -08:00
Bob Lantz 5ac113cfaa Batch link delete commands (and minor edits) 2015-02-04 05:21:15 -08:00
Bob Lantz cd02954c91 pass code check 2015-02-04 04:45:46 -08:00
Bob Lantz 93be1d0401 Fix OVS protocols option 2015-02-04 04:44:55 -08:00
Bob Lantz 6a38811f1a Clarify makeIntfPair behavior and pass code check 2015-02-04 04:44:14 -08:00
Bob Lantz 4ac45a3967 Fix super() arg in DataController 2015-02-04 04:43:23 -08:00
Bob Lantz d7e01bb821 Pass code check 2015-02-04 04:43:02 -08:00
Bob Lantz 340bf3cb7a Remove now-unused quietRun import 2015-02-04 04:29:08 -08:00
Bob Lantz 5f8547a5e0 Remove now-unused Link import 2015-02-04 04:28:57 -08:00
Bob Lantz 09e9c0550a Indent one line for consistency 2015-02-04 04:27:31 -08:00
Bob Lantz c1dc80571a Correctly group switches for batch operations 2015-02-04 04:26:58 -08:00
Bob Lantz ec9b23ba9c Delete tap9 for CE
In the future, we should probably not hardwire this,
or should at least make it a constant!!
2015-02-04 04:15:19 -08:00
Bob Lantz 7c0b56f9ba Delete both tunnel interfaces
We also clean things up a bit and check for error messages,
which now can cause exceptions which should invoke cleanup.
2015-02-04 04:14:40 -08:00
Bob Lantz d90a45514f node shell: remove unnecessary -m and unset HISTFILE
Since we already disable job notification with +m, it doesn't
make sense to set it in the original invocation!

It's also annoying if all of the host commands end up overwriting
your regular bash_history!!
2015-02-03 22:02:29 -08:00
Bob Lantz b2fe0778dc Change iperf() to use waitListening() 2015-02-03 21:44:21 -08:00
lantz 3e4f254573 Merge pull request #474 from mininet/devel/ovsbatch
Batch startup support for OVS

Currently, every ovs-vsctl command requires reading the entire OVS
configuration database. This means that its performance gets linearly
slower as more switches and ports are added. To mitigate this, we
batch multiple configuration operations into individual, long,
ovs-vsctl commands.

This patch set makes a couple of other notable changes, including
setting printPid=False by default (avoids using mnexec unnecessarily)
and running certain commands using errRun rather than quietRun.
Additionally we no longer look for leftover links in the root
namespace, so code relying on that functionality may have to change
slightly (as in controlnet.py and sshd.py for example.) It also adds
cluster support to mn -c.

The performance result is that mn --topo linear,200 --test none now
completes in 60 seconds rather than 95 seconds (on my laptop) without
the patch (vs. 101 seconds in 2.2.0).

This is still slower than I would like - we should be able to make
some additional improvements.
2015-02-03 19:24:03 -08:00
Bob Lantz 2e4dd13482 Turn off printPid by default to avoid mnexec fork/exec 2015-02-03 17:40:20 -08:00
Bob Lantz 19331ca287 use net.addLink() so that link is cleaned up 2015-02-03 16:02:07 -08:00
Bob Lantz 9483f6378f Make sure DataController's interfaces are deleted 2015-02-03 15:30:16 -08:00
Bob Lantz a4e933688a Set batch=False in OVSSwitch for low-level API
If you try to use the low-level API, you are probably
not going to call batchStartup()! So, we set batch=False
by default. This means that buildFromTopo() needs to set
it to True, so we add a bit of irritatingly complex machinery
to allow this to happen. The good fallout of this is that
now customConstructor() returns a real subclass, not simply
a constructor function! We also detect errors where people
are incorrectly attempting to give parameters to a lambda
function - since none of our lambdas accept parameters!!

Note that this is a bit like functools.partial for classes -
it would be nice if functools had a true subclassing function.
2015-01-29 00:26:15 -08:00
Bob Lantz c11e9f3316 Fix OVS user switch (remove unnecessary % parameter) 2015-01-28 17:04:58 -08:00
Bob Lantz acdcf9b6ae cluster: add batchStartup/Shutdown, cleanup 2015-01-27 15:27:26 -08:00
Bob Lantz c702840a0a Remove debug print lines 2015-01-27 15:24:29 -08:00
Bob Lantz 254fae2dc9 Clarify which intf pair failed and raise exception 2015-01-27 15:23:48 -08:00
Bob Lantz bdad3e8c8e Merge OVSBatch into OVSSwitch
Note that we are changing the interface of batchStartup/Shutdown
slightly so that the method can choose not to start some of the
switches. We might wish to refine this a bit...
2015-01-26 18:01:20 -08:00
Bob Lantz 574d634fc2 Don't clean up links that may have been dumped into root NS.
This should rarely happen - in the usual case, either the
links will be shut down by Mininet.stop(), or the interfaces
will be deleted by node.stop( deleteIntfs=True ), or the
links or interfaces will be explicitly deleted or stopped
using the low-level API.

Cases that are relying on links being automatically deleted
in cleanup() will potentially find that they are now no longer
deleted, but these cases should be rare.
2015-01-26 14:06:23 -08:00
Bob Lantz eafbd2a597 Change to OVSSwitch 2015-01-26 14:06:23 -08:00
Bob Lantz 7485b035af make 'ovs-vsctl' string symmetric 2015-01-26 14:06:23 -08:00
Bob Lantz 8014a7023c Fix super() typo 2015-01-26 14:06:23 -08:00
Bob Lantz bec34e7227 Clean up - TCReapply still broken! 2015-01-26 14:06:23 -08:00
Bob Lantz 9ca6322603 Remove shared reconnectms, improve self.started
We still need to set it in batchShutdown()
2015-01-26 14:06:23 -08:00
Bob Lantz 957fe1db93 Refactor for compatibility with isOldOVS() == True 2015-01-26 14:06:23 -08:00
Bob Lantz 3b4738c2ca First crack at setting controller backoff in single command 2015-01-26 14:06:23 -08:00
Bob Lantz 30ebb852a3 errRun: add debug( results ) 2015-01-26 14:06:22 -08:00
Bob Lantz 959586bc8f Add debug(cmd) to errRun() 2015-01-26 14:06:22 -08:00
Bob Lantz 9bda98486d Add OVSBatch class (experimental)
This implements batch startup for OVS switches.
2015-01-26 14:06:22 -08:00
Bob Lantz c68e4e76f4 Clarify bandwidth limit for TCIntfs
In the future, we would like to support higher bandwidth
limits for TCIntfs, but we'll probably need to adjust some
of the parameters dynamically.
2015-01-26 13:55:38 -08:00
Bob Lantz 98a8231cef Exit poll loop on POLLHUP or anything unexpected
In my opinion, we really shouldn't even get POLLHUP, but
we do. In case we get anything else odd, quite polling on
that fd.
2015-01-23 16:43:49 -08:00
Bob Lantz 28ce13d18e Fix polling in errRun
It's tricky to get this right, but basically we want to read
if there is something to read; if not, we want to check for
EOF.
2015-01-23 16:41:29 -08:00
Bob Lantz ef59cd88dc Return correct success condition in cgroupDel
Without this, we end up retrying until we fail, instead
of returning immediately on success!
2015-01-23 16:39:50 -08:00
Bob Lantz 9db6cdc261 Call delete() in link.stop() ; warn on exited node.cmd()
We should think a bit about the semantics that we want here.
The comments say "stop and clean up link" so perhaps that's
what we want. However, we could also imagine stop stopping
forwarding on the link (and possibly allowing restarts).

We warn on exited node.cmd() because we terminate the controller
before stopping/deleting the links. This makes sense to avoid a
storm of link/port down events, but since the controller's
shell has exited we cannot call link.stop() on any of its
links. We may want to simply stop the controller and not
terminate it, but at least it doesn't hang for now.
2015-01-22 03:22:43 -08:00
Bob Lantz f7b29333f5 2.2.0 -> 2.2.0+ 2015-01-18 23:35:54 -08:00
Bob Lantz 24520fc982 Allow + in version number 2015-01-18 23:35:29 -08:00
Bob Lantz b93cc989f4 Pass code check 2015-01-18 23:35:12 -08:00
Bob Lantz a8cc243aa7 Add stp param to OVS and connected() to OVSBridge
This allows --switch ovsbr,stp=True to work correctly
2015-01-18 22:59:21 -08:00
Bob Lantz e65dc4c6d6 OVSLink: use isinstance() to detect OVSSwitch subclasses 2015-01-18 21:56:38 -08:00
Bob Lantz d4be92713a Merge del-br into cmd, and add reconnectms param
With newer versions of OVS, this allows us to set up a switch
with a single OVS command (if reconnectms is zero.) If reconnectms
is specified, then it slows things down slightly (but not much.)
2015-01-18 16:09:02 -08:00
Bob Lantz 79f5d39db5 Comment edits and pass code check 2015-01-17 13:56:37 -08:00
Bob Lantz 6da3fcdef1 Add bridges s1-s3 to topology and explain some details 2015-01-17 13:38:55 -08:00
Bob Lantz 026130bd5f pass code check 2015-01-17 13:33:59 -08:00
Bob Lantz c1b48fb5c8 Stub out RemoteOVSSwitch.batchShutdown()
Eventually we should implement true batch shutdown.
In the mean time, we just ignore it. Note there's no good
way that I know of for a subclass to remove a superclass
method, so we changed the protocol a bit to require a return
value of True.
2015-01-15 02:43:38 -08:00
Bob Lantz b1983548aa Fix indentation error 2015-01-15 02:36:34 -08:00
Bob Lantz c62812a944 Update cluster.py for new makeIntfPair 2015-01-15 02:29:51 -08:00
Bob Lantz d66b96260a Don't stop switches that we've already stopped.
Note that this also changes the way that links are deleted;
the reason is that the batch shutdown doesn't currently delete
the links, but OVSSwitch.stop() does. We may wish to revisit
this in the future.
2015-01-15 02:07:00 -08:00
Bob Lantz d7e9c3bbfd Add comment about redundant intf.delete() 2015-01-15 02:07:00 -08:00
Bob Lantz 7a4a865bdb customize makeIntfPair to eliminate fastIntfPair 2015-01-15 02:07:00 -08:00
Bob Lantz da4dcf3753 Add addresses to fastIntfPair() and fix codecheck 2015-01-15 02:07:00 -08:00
Bob Lantz 5383b0e603 Update comment to reflect OVS patch link limits 2015-01-15 02:07:00 -08:00
Bob Lantz 9d2e6404b3 add fastIntfPair to speed up link creation 2015-01-15 02:07:00 -08:00
Bob Lantz 91a73bd191 use isinstance( intf, OVSIntf ) 2015-01-15 02:07:00 -08:00
Bob Lantz c069542c5c Add OVSLink/--link ovs, which uses OVS patch links when possible 2015-01-15 02:07:00 -08:00
Bob Lantz 127f35a9bc Revert to using OVS default OpenFlow versions.
It makes sense to follow Open vSwitch's lead here.
OVS 2.3 enables OpenFlow 1.0 through 1.3 by default.
OVS 2.0 has incomplete support for 1.3, but you can enable
it with protocols=OpenFlow13
2015-01-14 14:18:53 -08:00
Bob Lantz 171e815122 Set OVSSwitch default protocols to OpenFlow10,OpenFlow13
For OVS versions 1.9 or earlier, this setting is ignored.
2015-01-14 14:15:14 -08:00
Bob Lantz 3ac5cafe53 Fix code minor code check errors 2015-01-06 16:26:33 -08:00
Bob Lantz a7ad739036 Disable IPv6 via grub command line
Unfortunately disabling IPv6 via sysctl doesn't actually
disable it on all of the interfaces by default. Disabling
it via grub disables it entirely in the VM.

Helps with #454
2014-12-17 13:49:12 -08:00
Bob Lantz a84bec9709 Disable splash and quiet individually (more robust) 2014-12-17 13:48:43 -08:00
Bob Lantz 05dbf82edb Correctly set controller backoff for OVS.
Also report connected in standalone/bridge mode

Fixes #460

Conflicts:
	mininet/node.py
2014-12-11 17:03:49 -08:00
Bob Lantz c75eb47158 2.2.0rc1 -> 2.2.0 2014-12-09 13:37:43 -08:00
Bob Lantz 9945864a32 2.2.0rc1 -> 2.2.0rc2
Basically no changes except for whitespace and satisfying pep8.
2014-12-08 15:37:50 -08:00
Bob Lantz beeea4b292 Exclude miniedit from pep8 checking for now
(Also untabbed comment lines, flagged by emacs et al.)
2014-12-08 15:27:13 -08:00
Bob Lantz 7a3159c9af Spacing tweaks for pep8 checker 2014-12-08 15:10:32 -08:00
Bob Lantz ccd6b5cd7d version -> 2.2.0rc1 and update copyright date 2014-12-04 09:28:19 -08:00
Bob Lantz 908e85d9f9 Remove PLFMT since options are moved to .pylint 2014-12-04 09:27:53 -08:00
Bob Lantz e341526f46 Raise line limit to 4000 for miniedit.py (see note)
Future versions of pylint will allow this to be disabled
in the file itself, so we can drop the limit back to
1500 or something more reasonable!!
2014-12-04 09:26:11 -08:00
Bob Lantz 03461ce908 Add 'slowtest' make target to test walkthrough, examples 2014-12-04 09:17:13 -08:00
Bob Lantz 8c37975d44 Remove erroneous self.cmd = None 2014-12-04 09:03:46 -08:00
Bob Lantz 4d55ef1132 Restore missing space in RT_GROUP_SCHED message 2014-12-04 08:57:28 -08:00
Bob Lantz 342d47cfb5 call to run() should be to runCmd() 2014-12-04 08:56:08 -08:00
Bob Lantz 554abdd57a warn -> debug in connected; change IVS class comment 2014-12-04 08:38:54 -08:00
Bob Lantz 061598f011 Change from numeric to symbolic pylint error codes 2014-12-04 08:21:53 -08:00
Bob Lantz d754a7ceea Call super(deleteIntfs)
Maybe this is better - maybe not. ;-p
2014-12-04 07:36:53 -08:00
Bob Lantz 643c9f912f More pylint changes... 2014-12-04 05:55:57 -08:00
Bob Lantz 4965421215 More pylint fixes... 2014-12-04 02:57:36 -08:00
Bob Lantz 18aab5b786 More pylint changes 2014-12-04 00:51:05 -08:00
Bob Lantz b905dddf19 Reorganize and pass pylint 2014-12-02 20:26:34 -08:00
Bob Lantz 11a9c46904 Fix missing imports 2014-12-02 23:22:56 -08:00
Bob Lantz b1ec912db5 Fixing pylint errors 2014-12-02 23:00:50 -08:00
Bob Lantz db45b7c644 Parseable output format for newer pylint 2014-12-02 23:00:14 -08:00
Bob Lantz 2256a53830 Fix pylint error 2014-12-02 22:59:32 -08:00
Bob Lantz 03ef55672d Add cleanup and fix pylint errors 2014-12-02 22:58:57 -08:00
Bob Lantz c45bfab318 Add cleanup 2014-12-02 22:58:38 -08:00
Bob Lantz b2fcab827d Add cleanup and fix pylint errors 2014-12-02 22:58:10 -08:00
Bob Lantz 1471da95a9 Fix pylint errors 2014-12-02 22:57:32 -08:00
Bob Lantz 5a530af189 Remove trailing whitespace. ;-/ 2014-12-01 15:39:44 -08:00
Bob Lantz 3c9f5ad56e Disable pep8 whitespace errors 2014-12-01 15:38:38 -08:00
Bob Lantz c5d9e0e03c Set default route in one cmd line to avoid dc'ing root NS
Usually you won't want to create a node in the root namespace,
and usually you won't want to use the Mininet API to set your
(real) default route, but if you do then you will probably want
to use a single command line to avoid disconnecting an SSH
session while we wait for the reulst of the 'ip route del default
command.
2014-12-01 15:10:44 -08:00
Brian O'Connor 0094997aa1 fixing install-mininet-vm.sh 2014-11-25 17:18:49 -08:00
lantz 7a411b6bb5 Merge pull request #453 from cdburkard/master
update examples README with new examples
2014-11-25 13:01:31 -08:00
cody burkard c2341cd47a update examples README with new examples 2014-11-24 19:43:15 -08:00
Bob Lantz 4219b22978 2.2.0b2 2014-11-24 19:35:34 -08:00
lantz 08ab7e8de7 Merge pull request #452 from mininet/nat-cmd
Updating NAT class to use gateway interface
2014-11-24 19:13:33 -08:00
lantz 3ef6bcface Additional info about --nat and LinuxRouter 2014-11-24 19:04:15 -08:00
Brian O'Connor ab97dfa19c fixing no --nat issue 2014-11-24 18:36:57 -08:00
Brian O'Connor af1ccf93a5 Updating NAT class to use gateway interface
Also, passing CLI args to NAT constructor

fixes #437
2014-11-24 18:16:57 -08:00
lantz 015cd9e776 Merge pull request #443 from cdburkard/devel/cluster
use rcmd instead of quietRun when shutting down remote nodes
2014-11-24 12:30:52 -08:00
Bob Lantz 3d44bcdcc4 MiniNet -> Mininet 2014-11-23 17:32:11 -08:00
Bob Lantz 1817cbc3a4 Pass pyflakes 2014-11-23 17:31:43 -08:00
Bob Lantz e0bf8ece3c Minor code cleanup 2014-11-23 17:17:21 -08:00
Bob Lantz 37bdf14b49 Rename examples.{intfOptions,multiLink} -> {intfoptions,multilink} 2014-11-23 17:11:06 -08:00
Bob Lantz 292e69f89a Renamed to intfoptions.py for consistency 2014-11-23 17:07:32 -08:00
Bob Lantz dd876e69c8 DemoCLI -> ClusterCLI 2014-11-23 17:04:07 -08:00
lantz 4e644d7465 Merge pull request #450 from mininet/sw-cmd
adding deleteIntfs option to switches and corresponding CLI command
2014-11-24 11:27:59 -08:00
lantz 596fd9d0c6 Merge pull request #449 from cdburkard/devel/cluster_controlPaths
use ControlPersist ssh option to fix ControlPath shutdown
2014-11-23 14:59:11 -08:00
Bob Lantz 474f68600e Make pylint happier for no particular reason 2014-11-23 11:13:54 -08:00
Bob Lantz 50774e407c Remove unused imports 2014-11-23 11:11:03 -08:00
Bob Lantz 8e63e2c540 Fix undefined sleep() 2014-11-23 11:10:43 -08:00
Bob Lantz 273c4e9403 Fix typo. ;-p 2014-11-23 11:09:21 -08:00
Bob Lantz c273f49077 type( foo ) is bar -> isinstance( foo, bar ) 2014-11-23 11:06:12 -08:00
Bob Lantz 9a8bdfd765 use isinstance( obj, basestring) to allow unicode strings
fixes #448
2014-11-23 10:59:08 -08:00
Brian O'Connor 23dfbe4ae2 explicit param call in cli command 2014-11-21 18:35:37 -08:00
Brian O'Connor b57e5d93b8 adding deleteIntfs option to switches and corresponding CLI command 2014-11-21 18:33:06 -08:00
Bob Lantz f0f9907b9d Add setup() and dpctl() methods for LinuxBridge
Also adds docstrings.
Fixes #422
2014-11-19 09:32:56 -08:00
Bob Lantz c4fc630413 Correctly call cli() rather than CLI() 2014-11-19 09:18:05 -08:00
Bob Lantz aabbf29542 Revert to old "Adding controller" message 2014-11-19 08:58:17 -08:00
backb1 b7898befef raise exception when no prefixLen is set 2014-11-19 08:58:17 -08:00
backb1 6721f0655e Some clarifications 2014-11-19 08:58:17 -08:00
lantz d37d6ecd99 Merge pull request #241 from moijes12/fix44
(pending) Create test_switchdpidassignment.py
2014-11-20 14:14:14 -08:00
Bob Lantz e4db698184 Fix indentation error so we don't wait forever. 2014-11-19 05:58:36 -08:00
lantz e661a4b1c3 Merge pull request #447 from rlane/ivs-verbose-off
IVSSwitch: turn off verbose logging by default
2014-11-20 11:56:42 -08:00
Rich Lane f5164f86b7 IVSSwitch: turn off verbose logging by default
Most users don't need this much logging and it slows down the switch.
2014-11-19 18:24:49 -08:00
Bob Lantz 9e0c1549f4 Only uninstall ntpd on COW disk. 2014-11-19 04:59:23 -08:00
Bob Lantz 55b455e9ae Fix typo in depend() 2014-11-19 03:20:48 -08:00
cody burkard 34933ef741 use ControlPersist ssh option to create a ControlMaster connection that will not die when a node dies 2014-11-18 17:22:06 -08:00
cody burkard bbf94cdb63 use rcmd instead of quietRun when shutting down remote nodes 2014-11-17 17:55:06 -08:00
Brian O'Connor 593fc365d0 fixing --custom in mn (there was one two many selfs) 2014-11-17 17:46:24 -08:00
Brian O'Connor 1edf3515e3 Merge pull request #439 from cdburkard/patches/sudoers
fix sudoers file to allow -u option
2014-11-17 17:01:50 -08:00
cody burkard 0d271f9477 fix sudoers file to allow -u option 2014-11-17 16:19:28 -08:00
Bob Lantz 3534f77761 Remove extra git clone line 2014-11-12 18:31:10 -08:00
Bob Lantz 64bbaeccc4 Add doxygen-latex if needed (14.04+) 2014-11-12 17:45:36 -08:00
Bob Lantz de002b0d9a Remove ^S which was in this file (thanks emacs bindings) 2014-11-12 17:39:50 -08:00
Bob Lantz 307302ed32 Clarify dependencies 2014-11-12 15:52:53 -08:00
Bob Lantz a60f77ad36 Clarify checking out a version, and add Debian/Fedora 2014-11-12 15:50:41 -08:00
Bob Lantz 383c3fb3e4 in-line documentation link 2014-11-12 15:50:24 -08:00
Bob Lantz a64f8c28bd Don't blow away parameters that aren't specified in node.config() 2014-11-12 15:17:17 -08:00
Bob Lantz 377d1b1cd8 2.2.0b0 -> 2.2.0b1 2014-11-12 13:33:34 -08:00
Bob Lantz dde2263fe7 Disable shared SSH connections by default.
Note that we do still provide a default if you specify
ControlPath=True
2014-11-12 13:29:58 -08:00
Bob Lantz 434619053a Satisfy pyflakes by making a local cli variable 2014-11-12 13:12:22 -08:00
Bob Lantz b739cd11c8 Remove obsolete util.custom(), and make custom() a method 2014-11-12 13:08:36 -08:00
lantz bc6ef0dad8 Merge pull request #435 from mininet/devel/custom
Adding support for multiple custom files
2014-11-12 12:25:46 -08:00
Brian O'Connor 3ac0dd7093 Adding support for multiple custom files
Works in a few ways:
 * a single file: --custom foo.py (as before)
 * comma-separated list: --custom foo.py,bar.py
 * multiple custom args: --custom foo.py --custom bar.py
2014-11-11 03:14:46 -08:00
Bob Lantz 0f0fe82350 Fix typo, ugh. 2014-11-11 00:14:11 -08:00
Bob Lantz 6be4bfd026 Avoid mirrors.kernel.org for now 2014-11-10 23:31:08 -08:00
Bob Lantz d9d209f34d Update from official archive since mirror seems to be failing 2014-11-10 23:00:56 -08:00
Bob Lantz 2059786f7b Use sudo -n when talking to VM 2014-11-10 22:45:42 -08:00
lantz 6008f987d3 Merge pull request #436 from cdburkard/patches/plot
fix plot command to work when standard classes are present
2014-11-11 11:54:56 -08:00
Bob Lantz 635e8f11f3 Add -q option to apt-get for quieter logging 2014-11-10 19:37:11 -08:00
Bob Lantz 9b5fa1d7ed Always chdir() to current working directory. 2014-11-10 16:57:12 -08:00
Bob Lantz 1955e90493 Minor cleanup. 2014-11-10 16:50:24 -08:00
Bob Lantz 222e87daeb Rearrange init code slightly. 2014-11-10 16:48:20 -08:00
Bob Lantz a89ccb789e Fix problem of ssh'ing into "localhost" on a remote node. 2014-11-10 16:46:43 -08:00
lantz 2013b7ae81 Merge pull request #428 from cdburkard/patches/cluster_servers
standardize on localhost for local server's name
2014-11-10 16:23:59 -08:00
Bob Lantz 3e1100b71a Clarify MultiTopo docstrs and copy addLInk opts
Note: it's a bit confusing, but we need to copy the link
parameter dicts (since we update them with node info), but we
can share the node dicts. Perhaps we should copy the node
dicts as well...
2014-11-10 15:18:05 -08:00
lantz 086afe852b Merge pull request #434 from cdburkard/patches/cluster_x11
wrap the title string in quotes so that bash interprets it correctly
2014-11-10 14:12:39 -08:00
Bob Lantz abcdf18547 Uninstall ntpd to disable it more reliably 2014-11-10 14:09:35 -08:00
Bob Lantz 4a304688f4 Select TCP Reno and run iperf for a longer time interval
The hope is that this will make the results a bit more consistent
when running in a VM environment.
2014-11-10 12:39:55 -08:00
Bob Lantz d3377bf911 Add seconds option to iperf() 2014-11-10 12:37:54 -08:00
Bob Lantz 481cbea10c Update mininet docs ref to markdown format 2014-11-07 15:23:18 -08:00
Bob Lantz b817cbc0ed Update documentation link 2014-11-07 15:12:12 -08:00
lantz 15275048b6 Merge pull request #433 from mininet/devel/update-version-2.2b0
Initial update of README, text files and versions for 2.2.0b0
2014-11-07 16:58:12 -08:00
lantz 3baccfee3a Merge pull request #416 from mininet/devel/multitopo
Multi-link topology support
2014-11-07 16:16:25 -08:00
Bob Lantz bb76c21275 Use 2.2.0b0 for consistency with earlier Mininet releases 2014-11-07 15:08:15 -08:00
Bob Lantz c92c4efb66 Add a few clarifying comments 2014-11-07 13:47:03 -08:00
Bob Lantz 39203484a6 Make port1, port2 truly optional and don't pass them to Link() 2014-11-07 13:42:50 -08:00
Bob Lantz 2a2d605074 Get rid of paramDict and simplify things a bit 2014-11-07 13:40:00 -08:00
cody burkard 0676346aeb fix plot command to work when standard classes are present 2014-11-07 05:10:06 -08:00
cody burkard 93fdb69ee3 standardize on localhost for local server's name 2014-11-07 02:32:42 -08:00
Brian O'Connor c7921fe402 Merge pull request #432 from mininet/devel/fallback
Fall back to OVSBridge if no controller is available for default switch
2014-11-07 01:29:06 -08:00
cody burkard 3660e6d02f wrap the title string in quotes so that bash interprets it correctly 2014-11-07 01:11:40 -08:00
Bob Lantz 083322a217 Draft update for Mininet 2.2b0 2014-11-06 12:05:55 -08:00
Bob Lantz 8225105cf2 Fix to allow more flexible version numbers 2014-11-06 12:05:33 -08:00
Bob Lantz ccd3276dcf Raise exception if DefaultController cannot find a controller 2014-11-05 18:43:58 -08:00
Bob Lantz f51eddef6d Return controller correctly. 2014-11-05 18:41:00 -08:00
Bob Lantz 4f8aa1d8a0 Don't check rt_runtime_us for CFS scheduler 2014-11-05 16:49:28 -08:00
Bob Lantz 060d46a282 Set VM date based on host date.
This should fix #398 for real; note that if we try to shut down ntpd
right at boot, it doesn't work! ;-(

However, setting the Unix time in the traditional manner using seconds
since 1970 should do the trick!
2014-11-05 16:18:13 -08:00
Bob Lantz 820c3be7df Reorganize CFS and RT default/error conditions. 2014-11-04 17:20:35 -08:00
Bob Lantz a562ca1be3 Move RT check into its own method, and save value. 2014-11-04 16:27:34 -08:00
lantz 658761d953 Merge pull request #419 from cdburkard/patches/rt_failure_output
fix silent failures when rt cannot be assigned - will follow up on this
2014-11-04 16:09:25 -08:00
Bob Lantz 1b69ea13f5 Merge branch 'fallback' of https://github.com/thinred/mininet into thinred-fallback
Conflicts:
	bin/mn
	mininet/node.py
2014-11-04 03:24:16 -08:00
Bob Lantz 6e5ac34bc2 Update module comment. 2014-11-03 20:01:22 -08:00
lantz ec9f02c7ab Merge pull request #424 from cdburkard/devel/mergePrivate
merge HostWithPrivateDirs into Node
2014-11-04 15:09:20 -08:00
lantz f75bee62b5 Merge pull request #429 from cdburkard/patches/cluster_m
ensure we retrieve a single PID when run on a cluster node
2014-11-04 12:49:08 -08:00
Bob Lantz e77123cf0e Remove unnecessary 0 2014-11-03 14:25:09 -08:00
Bob Lantz 8dea57d271 Ignore link info when sorting links. 2014-11-03 14:20:01 -08:00
Bob Lantz 634761b8a7 Fix edges() and add convertTo() to Topo() (with keys option) 2014-11-03 12:59:53 -08:00
Bob Lantz 01aac350fa Remove unused edgeinfo 2014-11-03 12:43:52 -08:00
Cody Burkard 08d611f49b fix silent failures when rt cannot be assigned 2014-10-31 20:30:36 -07:00
Bob Lantz f6de358b06 Try to prime the pump to avoid PACKET_INs during iperf test
Background: the reference controller is reactive and installs exact
match rules. By attempting to start a telnet session we make sure that
the ARP caches and TCP flow rules are set up (in one direction at
least) before the test starts.

This is intended to help with #413
2014-10-31 15:06:15 -07:00
cody burkard f66904ab90 ensure we retrieve a single PID when run on a cluster node 2014-10-31 08:23:00 -07:00
cody burkard 6a363f65e3 unmount private directories after use 2014-10-31 04:59:35 -07:00
cody burkard 736db20c9f merge HostWithPrivateDirs into Host 2014-10-31 04:43:10 -07:00
Bob Lantz ba8ea8f0cc Return (src, dst) in original order, and allow keys + data 2014-10-28 20:43:10 -07:00
Bob Lantz eab4ea3fb9 Minor fixes 2014-10-28 17:05:00 -07:00
cody burkard 06d9e4bba7 add example and test for multiple links 2014-10-28 16:10:46 -07:00
Bob Lantz 38ce329e7e Allow Mininet() to accept multi-link topos w/correct params. 2014-10-28 16:06:53 -07:00
Bob Lantz 94f088d7e8 Allow natural sort to accept non-strings. 2014-10-28 16:06:53 -07:00
Bob Lantz 89fb081983 First crack at fixing multiple links
* Makes MultiGraph more like networkx.multigraph
* Adds converTo method
* Synchronizes node1 with xxx1 in link options
2014-10-28 15:50:06 -07:00
lantz aae0affae4 Merge pull request #411 from cdburkard/devel/cli_usage
add cli usage information
2014-10-14 13:42:40 -07:00
lantz 8190e81ba8 Merge pull request #410 from cdburkard/patches/tshark_walkthrough_1404
support wireshark versions greater than 1.11 in test_walkthrough
2014-10-14 13:36:24 -07:00
lantz 16a2a6dc55 Merge pull request #400 from cdburkard/patches/fixEmptyPing
Mininet crashes when running ping between two hosts with no interfaces
2014-10-13 18:11:19 -07:00
lantz b7999978f9 Merge pull request #409 from cdburkard/patches/cleanup_tests
if a test fails or exits with an error, run cleanup as a precaution
2014-10-13 18:06:44 -07:00
Bob Lantz e1711f357a Use server receive rate rather than client send()/buffering rate
Fixes #412
2014-10-13 17:52:47 -07:00
Bob Lantz 501eb4f916 Add more information for test condition failure 2014-10-13 13:52:43 -07:00
Cody Burkard f341159300 support wireshark versions greater than 1.11 2014-10-13 10:52:37 -07:00
cody burkard cac98f5fd5 add cli usage information 2014-10-10 20:32:15 -07:00
lantz 5eca0802d2 Merge pull request #407 from cdburkard/patches/baresshd_waitListening
wait for sshd to start in baresshd example
2014-10-10 12:33:45 -07:00
Bob Lantz 6159e923e6 Add VM port forwarding option: --forward tcp:2222:22 2014-10-09 14:30:09 -07:00
Bob Lantz 2ceb57915a Merge branch 'cdburkard-patches/test_walkthrough' 2014-10-07 16:11:03 -07:00
Bob Lantz 61c144b9f6 Minor fixes to wireshark test 2014-10-07 16:08:57 -07:00
lantz 8537e8d9fa Merge pull request #404 from cdburkard/patches/default_cli
use node.pexec() to update IP address of intf instead of node.cmd()
2014-10-07 14:27:46 -07:00
cody burkard 33d42e25e6 if a test fails or exits with an error, run cleanup as a precaution 2014-10-03 09:50:39 -07:00
cody burkard 7c5d2771f7 wait for sshd to start in example 2014-10-03 04:52:21 -07:00
Bob Lantz 098bede0ec Wait for controller shutdown.
Unfortunately, this can slow things down a bit - perhaps
100-200 ms in the case of ovs-controller, but I am hoping that
it may help slightly with #399.
2014-10-02 20:09:17 -07:00
Bob Lantz 629e58ca5b Add 'use' test for using VM interactively 2014-10-02 18:45:54 -07:00
cody burkard e3ab3fc239 fix a few small issues with walkthrough tests 2014-10-02 11:10:17 -07:00
cody burkard f1123e71ae update interface IP address with pexec so that backgrounded process output from the cli cannot interfere 2014-10-02 09:19:07 -07:00
cody burkard 778267aa75 if there are no interfaces to ping, there are no packets sent 2014-10-01 23:05:34 -07:00
Bob Lantz d6da13d4e3 ntpd doesn't take a server argument 2014-10-01 17:32:15 -07:00
Bob Lantz 92a4f2ddbf Try using ntpd since ntpdate doesn't always work 2014-10-01 17:29:04 -07:00
Bob Lantz ded25a9ef8 disableNtpd: wait 1 second and print out date just to be sure 2014-10-01 14:42:43 -07:00
Bob Lantz 1bae1aab03 Turn of ntpd and set date manually before tests
This should fix the problem where we see the first test
taking negative time, as well as possibly other issues
with performance tests which may be sensitive to changes
in wall clock time.

Fixes #398
2014-10-01 14:20:59 -07:00
lantz 01a1e8e400 Merge pull request #397 from cdburkard/patches/test_nets
wait for switches to connect during test_nets
2014-09-30 15:19:54 -07:00
Bob Lantz 9487cb508d Fix typo 2014-09-29 19:57:26 -07:00
Bob Lantz 461751e5cd Merge branch 'cdburkard-patches/linear_bw' 2014-09-29 19:06:31 -07:00
Bob Lantz 762479c15b Merge branch 'patches/linear_bw' of https://github.com/cdburkard/mininet into cdburkard-patches/linear_bw 2014-09-29 19:06:08 -07:00
Bob Lantz c8607467bd Merge branch 'cdburkard-patches/fix_sshd' 2014-09-29 18:51:00 -07:00
Bob Lantz f8e98d6a7f Merge branch 'patches/fix_sshd' of https://github.com/cdburkard/mininet into cdburkard-patches/fix_sshd 2014-09-29 18:50:41 -07:00
lantz 4aa0b82381 Merge pull request #395 from cdburkard/patches/vlan_fail_output
check for vlan dependency
2014-09-29 18:33:38 -07:00
lantz f9522b30dc Merge pull request #394 from cdburkard/patches/cpu_test
continue to test cfs if rt is not enabled in kernel
2014-09-29 17:41:07 -07:00
Bob Lantz ec26c7492d Install vconfig in VM for VLAN example
This should help with #393 although it doesn't solve
the root issue of the example failing silently when
vconfig is missing.
2014-09-29 16:30:24 -07:00
cody burkard 684092bae1 wait for switches to connect during test_nets 2014-09-27 06:43:39 -07:00
cody burkard 9cbf4688b2 add 1ms delay to all links to exaggerate TCP bandwidth decrease across an increasing number of links 2014-09-27 04:48:57 -07:00
cody burkard 74857ba474 remove User Switch from linearBandwidth due to poor performance 2014-09-27 04:47:56 -07:00
cody burkard f1b61c629a Merge branch 'master' of github.com:mininet/mininet into patches/fix_sshd
Conflicts:
	examples/cpu.py
2014-09-27 04:31:46 -07:00
cody burkard a565bdd57d fix popen to work with shell 2014-09-27 04:30:16 -07:00
cody burkard cf5bbd597a promote waitListening to util.py 2014-09-27 04:30:16 -07:00
cody burkard c0d8fc0d37 wait until sshd has started on each host 2014-09-27 04:30:16 -07:00
cody burkard eef43402b6 check for vlan dependency 2014-09-27 04:24:27 -07:00
cody burkard 54bd9e6112 continue to test cfs if rt is not enabled in kernel 2014-09-27 03:20:07 -07:00
lantz fa7edec7c8 Merge pull request #391 from cdburkard/patches/fix_popen
workaround: attach to cgroup first, then mount namespace
2014-09-26 16:47:06 -07:00
lantz 89cc29b4c2 Merge pull request #367 from cdburkard/devel/Ryu
add Ryu controller support to Mininet
2014-09-26 16:41:45 -07:00
cody burkard 686a9993f5 add Ryu controller to mininet 2014-09-26 15:42:15 -07:00
cody burkard e16c5fe905 attach to cgroup first, then mount namespace 2014-09-25 22:51:48 -07:00
Bob Lantz dedb06b2f5 Wait for crlf after OK/FAILED for better -v output 2014-09-25 18:43:07 -07:00
lantz 5fc3f57ede Merge pull request #386 from cdburkard/patches/cpu_test
Skip test_cpu.py if RT_GROUP_SCHED is not enabled
2014-09-25 14:19:55 -07:00
lantz 5789dae8be Merge pull request #387 from cdburkard/patches/iperf_bw
use udp with iperf to measure loss. pings are not reliable
2014-09-25 14:17:09 -07:00
lantz 0efde9c4ed Merge pull request #388 from cdburkard/patches/intfOptions
measure loss with udp iperf
2014-09-25 14:16:26 -07:00
cody burkard 7eeaed992c use udp with iperf to measure loss. pings are not reliable 2014-09-25 13:09:24 -07:00
cody burkard f0ce6f501d measure loss with udp iperf 2014-09-25 12:39:42 -07:00
cody burkard 823d1b9990 skip test if RT_GROUP_SCHED is not enabled 2014-09-25 10:16:55 -07:00
Bob Lantz 61760eabc5 Make sure we 'sudo kill' our sudo pexpect process in close().
This should more reliably shut down pexpect subprocesses when
build.py exits before completion.
2014-09-24 11:57:46 -07:00
Bob Lantz 12095a12f4 Try to install openvswitch-testcontroller if needed 2014-09-23 17:49:46 -07:00
Bob Lantz 412726d39c Fix -a 2014-09-23 17:18:59 -07:00
Bob Lantz 136c959191 Fix wireshark namespace conflict and don't reinstall 2014-09-23 16:32:30 -07:00
lantz 2ac4cd43da Merge pull request #384 from mininet/devel/loxigen
Switch to loxigen-built openflow.lua wireshark plugin
2014-09-23 14:09:02 -07:00
Bob Lantz f603052b35 Install coloring rules regardless of plugin. Also don't clobber. 2014-09-23 14:01:40 -07:00
Bob Lantz 47be38e63c Don't install lua plugin for wireshark 1.12+
Apparently there is a conflict where the lua plugin
conflicts with the built-in dissector for openflow
that is included with 1.12 and up. For now, we will
just not install the plugin. This should fix the
14.10 VM build.

Additionally, I have added a handy function,
version_ge, which compares version numbers in
canonical x.y.z format. Thanks to stackoverflow for
pointing out the incredibly useful sort -V option!
2014-09-23 13:45:20 -07:00
Bob Lantz 9ca775cba3 Switch to loxigen-built openflow.lua wireshark plugin
The older wireshark dissectors were not well-maintained
and were a pain to build. They also added tons of extra junk
into our VM images! The ones built into the current
wireshark are deficient for 1.3. The solution for the
future is almost certainly to go with the lua-based plugin,
since it is architecture-independent and should be much
easier to maintain and upgrade.
2014-09-22 15:54:58 -07:00
lantz e4d49e6df7 Merge pull request #229 from mininet/devel/mobility-example
A simple mobility API and example
2014-09-22 12:31:31 -07:00
Bob Lantz 02bf34aa96 Remove setup/isOldOVS which have been merged into OVSSwitch 2014-09-22 12:27:49 -07:00
Brian O'Connor 73ef3e9a39 Merge pull request #375 from cdburkard/patches/multi_core_rt
fix host --rt
2014-09-21 00:43:25 -07:00
Brian O'Connor 55ef99b667 Merge pull request #379 from cdburkard/devel/show_ports
adding 'ports' command to cli
2014-09-21 00:13:58 -07:00
Brian O'Connor 57686d3149 Merge pull request #381 from cdburkard/examples/interfaces
adding example and test for intf.config()
2014-09-20 23:31:30 -07:00
Brian O'Connor 8396960ec0 Merge pull request #380 from cdburkard/devel/cli_comments
parse comments out of CLI
2014-09-20 23:27:33 -07:00
Brian O'Connor 3e8df323b3 Merge pull request #374 from cdburkard/patches/rt
check if RT_GROUP_SCHED is enabled in kernel
2014-09-20 23:21:06 -07:00
cody burkard 706229da77 adding example and test for intf.config 2014-09-17 12:55:59 -07:00
lantz 2c10a8e687 Merge pull request #376 from cdburkard/patches/pingOutput
if we do not receive a ping and cannot parse output, return errorTuple
2014-09-16 13:43:06 -07:00
lantz e4c4891a47 Merge pull request #359 from mininet/devel/cluster
Cluster Support Prototype
2014-09-16 13:40:45 -07:00
Bob Lantz 80d647a9b0 add findUser() to clean up user identification 2014-09-16 13:31:51 -07:00
cody burkard c5e8f09b10 adding comments to CLI 2014-09-15 15:52:14 -07:00
cody burkard 08643fe679 adding 'ports' command to cli 2014-09-15 15:33:58 -07:00
cody burkard 3df3610199 adding sanity check for cluster edition 2014-09-09 22:30:20 -07:00
cody burkard 00cbb348a7 if we do not receive a ping and cannot parse output, return errorTuple 2014-09-09 13:59:41 -07:00
lantz cde6c3aaf4 Merge pull request #369 from cdburkard/patches/hifi_multicore
Fix runCpuLimitTest with multiple cores
2014-09-05 15:44:23 -07:00
Bob Lantz c265deedef Cluster edition prototype: remote nodes and links.
We add a new experimental feature to allow Mininet to run across
a cluster of machines. This is currently implemented via a set
mix-in classes that provide remote nodes that are implemented
via a connection to a remote shell, and remote links which are
tunnels across servers. In this preliminary implementation,
both control and data connections are made via ssh, but this
could change in the future.

A MininetCluster class is provided which allows existing code
to be used with minimal modification - all that is required is
to provide a list of servers to use. A customizable placement
algorithm may also be specified. An experimental CLI subclass
is also provided to make it easier to examine node placement;
status and links commands can also check whether nodes and
tunnels are still running.

Although this is an experimental feature, it does include a
--cluster option to make it convenient to start up a Mininet
simulation over a cluster, and a script to assist with setting
up the prerequisite authentication via ssh key pairs.

The cluster feature is preliminary and missing some obvious
important features, such as parallel startup and multiple tunnel
types, which we hope to add in the future.
2014-09-04 23:07:01 -07:00
Bob Lantz 0333d3dbf4 qcow2size(): use qemu-image instead of file
file no longer returns image size on 14.04
fixes #373
2014-09-04 21:51:21 -07:00
cody burkard 58324bdc50 check if RT_GROUP_SCHED is enabled in kernel 2014-09-04 12:24:18 -07:00
cody burkard 04c1c098ed wall clock time makes rt quota independent of nprocs 2014-09-04 10:46:57 -07:00
Bob Lantz f2458d1dcf Accept 'ISO' or 'boot' in file *.iso command output
Fixes #372
2014-09-04 06:50:54 -07:00
cody burkard ce781a1832 use cgroups to calculate percentage of cpu used 2014-09-04 04:21:25 -07:00
Bob Lantz b85943dc0a chdir() to correct path after calling chroot()
Since chroot() doesn't chdir() by default, we are left in
an unreachable directory in node.pexec() (and in xterms.)

fixes #370
2014-09-04 02:22:13 -07:00
Brian O'Connor d4ca1db60b Merge pull request #364 from cdburkard/patches/testCPULimit
Fix output of backgrounded processes
2014-08-29 19:34:32 -07:00
Brian O'Connor 47d567e53c Merge pull request #365 from cdburkard/devel/test_output
print useful output for tests upon failure
2014-08-29 18:47:30 -07:00
Brian O'Connor 6b8d3538ef adding comment to VLANStarTopo in vlanhost.py 2014-08-28 05:57:10 -07:00
Brian O'Connor 05f3fbae73 Merge pull request #362 from mininet/devel/vlanhost
Adding VLANHost to Examples
2014-08-28 17:49:25 -07:00
Brian O'Connor 65e33fed9b Merge pull request #361 from mininet/devel/linuxrouter
Adding LinuxRouter to Examples
2014-08-28 17:49:07 -07:00
Brian O'Connor d334c1ccfe adding test for vlanhost.py and adding vlantopo example 2014-08-28 02:48:46 -07:00
Brian O'Connor fe8358add2 chmod +x vlanhost.py 2014-08-27 23:07:37 -07:00
Brian O'Connor 2c76ab718b linuxrouter.py: changing name, printing routing table, and some more documentation 2014-08-27 22:43:04 -07:00
Brian O'Connor aa4dfda44c adding documentation and test for linuxrouter.py 2014-08-27 22:01:18 -07:00
lantz 66ae58de17 Merge pull request #363 from cdburkard/patches/testLinkDelay
Fix UserSwitch.connected() as well as testLinkDelay() in test_hifi
We need more than one iteration since the first iteration may show reactive forwarding and ARP delay; currently we have three for good measure, although two is probably enough.
2014-08-27 16:36:30 -07:00
cody burkard ce1673803f clean up logic for backgrounded processes 2014-08-27 11:07:22 -07:00
cody burkard 73adba8b81 print useful output for tests upon failure 2014-08-27 10:55:08 -07:00
cody burkard c11d577349 parse pid printed when backgrounding a process 2014-08-27 08:44:08 -07:00
Brian O'Connor be1ed10363 adding vlanhost.py 2014-08-27 03:58:36 -07:00
Brian O'Connor 8a987b9c55 adding linuxrouter.py 2014-08-27 03:57:38 -07:00
cody burkard c75ff7ecd9 fixes for LinkDelay test in test_hifi 2014-08-26 22:34:34 -07:00
lantz 92075113d8 Merge pull request #342 from cdburkard/devel/startup
improve startup performance, largely by removing unnecessary ifconfigs
2014-08-26 19:59:12 -07:00
Bob Lantz 13bdd914dc Pass rename correctly in moveSwitch() 2014-08-26 19:55:48 -07:00
Bob Lantz 60b0c7a914 Fix version check. 2014-08-26 19:55:48 -07:00
Bob Lantz 212399feaf Allow port selection in addIntf() and moveIntf() 2014-08-26 19:55:48 -07:00
Bob Lantz 08d83d136d Rename intfs, and add simple moveHost() function 2014-08-26 19:55:48 -07:00
Bob Lantz dd6424fee8 Simple mobility example. 2014-08-26 19:55:48 -07:00
cody burkard 720a846cf8 use kernel's mac generation 2014-08-26 18:48:08 -07:00
Bob Lantz bfdbb7089a Fall back to chroot() if setns() fails for mnt namespace
fixes #347
2014-08-26 14:09:40 -07:00
lantz 16a384ab4b Merge pull request #353 from mininet/devel/nat
Adding NAT class to NodeLib
2014-08-21 14:16:41 -05:00
lantz a3e1a9a44d Merge pull request #354 from darshanthaker/link_exception
Raise exception when link incorrectly formatted
2014-08-20 22:08:46 -05:00
lantz 6a69c2f699 Merge pull request #356 from cdburkard/patches/stop_controller
fix for controller shutdown - send SIGHUP rather than SIGKILL
2014-08-20 22:04:51 -05:00
lantz db888fa5d4 Merge pull request #348 from ggee/miniedit2109
Update to MiniEdit 2.2.0.1
2014-08-20 22:03:21 -05:00
cody burkard c9b844a721 added controller.stop() back in 2014-08-18 23:51:29 -07:00
cody burkard 604ad455ee kill all child processes to avoid race condition and no controller shutdown 2014-08-18 23:24:18 -07:00
Gregory Gee 8d493b686e Update to MiniEdit 2.2.0.1
- Replace custom code to set OF protocols with new Mininet available API to set.
2014-08-16 01:00:25 -04:00
lantz c0e7e34916 Merge pull request #337 from ggee/ovsProtocol
Add parameter to set protocol list in OVSSwitch.
2014-08-15 14:44:33 -07:00
Gregory Gee 1a53141502 Update to MiniEdit 2.2.0.0
- Updated for new Mininet 2.2.0
- Support TCP or SSL for remote controller
- Support HostWithPrivateDirs Hosts
2014-08-14 21:41:45 -04:00
Brian O'Connor 1285fb22dc updaing build.py to use 12.04.5 and extract kernel using noload 2014-08-14 15:38:31 -07:00
Darshan Thaker 4550fff1af Raise exception when link incorrectly formatted 2014-08-14 13:50:59 -07:00
Brian O'Connor 7c4e5b14cb adding line to natnet.py 2014-08-14 01:07:44 -07:00
cody burkard f72d3dfa32 Merge branch 'master' of github.com:mininet/mininet 2014-08-14 01:07:24 -07:00
Brian O'Connor e67539752e updaing build.py to use 12.04.5 and extract kernel using noload 2014-08-14 00:18:37 -07:00
Brian O'Connor db0f36f431 Fixing Node.monitor() to read entire prompt marker.
Applying @cdburkard fix to #322
2014-08-14 00:18:37 -07:00
lip.z 7e9d3f2b50 fix Singleton.__call__ error
fix Singleton.__call__ error
2014-08-14 00:18:37 -07:00
Brian O'Connor 4015e0666e moving NAT to nodelib 2014-08-13 22:09:24 -07:00
Brian O'Connor cee62eb28e adding natnet example test 2014-08-13 22:08:15 -07:00
Brian O'Connor 735080a84b Merge branch 'master' into nat 2014-08-13 19:51:12 -07:00
Brian O'Connor 161e7997fa Fixing Node.monitor() to read entire prompt marker.
Applying @cdburkard fix to #322
2014-08-13 19:49:08 -07:00
cody burkard 417d79780f merging master 2014-08-13 17:35:34 -07:00
cody burkard 41a54f05cb adding comments and removing random access spaces 2014-08-13 17:33:00 -07:00
cody burkard 84c1c24ce2 skip this because of poor UserSwitch performance 2014-08-13 17:06:00 -07:00
cody burkard af4c9719b3 autostaticarp is broken without this 2014-08-13 15:08:04 -07:00
Tomasz Buchert 39a3b73f85 fallback to ovsb when no OF controller is unavailable 2014-08-13 17:04:24 +02:00
Tomasz Buchert e8623fdc91 introducing OVSBridge 2014-08-13 16:55:00 +02:00
Gregory Gee 06dbd774a1 Update to MiniEdit 2.1.0.9
Includes some big fixes and new feature to run user defined command during
node start and stop.
2014-08-07 22:35:45 -04:00
Brian O'Connor a280501ff1 Merge branch 'master' into nat
Conflicts:
	mininet/net.py
	mininet/node.py
2014-08-07 13:40:14 -07:00
cody burkard 891a9e8bdf fixed syntax error 2014-08-06 17:52:40 -07:00
cody burkard 7ae39fffc2 stop using ONLAB OUI for generated mac addressses 2014-08-06 17:51:32 -07:00
lantz a56d9a6661 Merge pull request #344 from bentenshan/patch-1
fix Singleton.__call__ error
2014-08-04 16:18:38 -07:00
Brian O'Connor b0048c0aca Merge pull request #333 from mininet/devel/buildtopo
Clean up standard topologies to use build
2014-08-03 21:47:10 -07:00
lip.z 0983ed29bb fix Singleton.__call__ error
fix Singleton.__call__ error
2014-08-02 20:18:06 +08:00
cody burkard 88763cfbe1 removed more unnecessary ifconfigs 2014-08-01 13:22:02 -07:00
cody burkard 19dd7f70c1 switched back to node.cmd for OVS commands. this is faster.. 2014-08-01 12:18:50 -07:00
cody burkard 42cdda38bb added some documentation 2014-08-01 11:27:25 -07:00
cody burkard f0fd84770a Merge branch 'devel/startup' of github.com:cdburkard/mininet into devel/startup 2014-08-01 11:00:58 -07:00
cody burkard a2d0ea78be fixed issue with regex matching 2014-08-01 11:00:08 -07:00
cody burkard e9d034bd31 adding old changes 2014-08-01 11:00:07 -07:00
cody burkard a3d51b77e9 few small fixes to syntax errors 2014-08-01 11:00:07 -07:00
cody burkard 4b65110e4d removed comments and cleaned up code. 2014-08-01 11:00:07 -07:00
cody burkard eba13f0ca8 removed many of the commands being run to maximize startup performance 2014-08-01 11:00:07 -07:00
cody burkard c1934706bb testing link stuff 2014-08-01 11:00:07 -07:00
Brian O'Connor f67a7b64c8 Merge pull request #322 from mininet/devel/pty
Attach a pty to each node's bash process
2014-07-31 18:36:35 -07:00
Brian O'Connor 628e84068e Reverting the disable signals change 2014-07-31 18:27:57 -07:00
Brian O'Connor 78a32e93fd Merge branch 'master' into devel/pty 2014-07-31 18:23:19 -07:00
cody burkard 859bfea502 fixed issue with regex matching 2014-07-25 03:41:13 -07:00
cody burkard 2973798ca1 Merge branch 'devel/pty' of github.com:mininet/mininet into startup 2014-07-24 16:31:10 -07:00
cody burkard b9a15f071c adding old changes 2014-07-24 16:30:48 -07:00
cody burkard f11dbe81d2 few small fixes to syntax errors 2014-07-24 15:59:38 -07:00
cody burkard 6bc9d68485 removed comments and cleaned up code. 2014-07-22 23:00:43 -07:00
cody burkard 5cd6b553a5 removed many of the commands being run to maximize startup performance 2014-07-22 19:27:45 -07:00
cody burkard 5b13dc62ce Merge branch 'master' of git://github.com/mininet/mininet into devel/startup 2014-07-19 02:09:03 -07:00
cody burkard 4d381f0b58 testing link stuff 2014-07-19 02:05:37 -07:00
Gregory Gee 84ce84f501 Add parameter to set protocol list in OVSSwitch. Allows setting OpenFlow version.
s2 = net.addSwitch( 's2', protocols='OpenFlow13' )
2014-07-18 22:10:03 -04:00
Bob Lantz 5b0897701b Merge branch 'cdburkard-devel/defaultController' 2014-07-16 10:25:37 -07:00
Bob Lantz 5465246245 Merge branch 'devel/defaultController' of https://github.com/cdburkard/mininet into cdburkard-devel/defaultController
Conflicts:
	bin/mn
	mininet/net.py
2014-07-16 10:24:35 -07:00
Bob Lantz e183e69997 Check for Controller type using isinstance() 2014-07-16 09:57:48 -07:00
Cody Burkard 779ea5f0ad removed bookmark 2014-07-15 19:39:50 -07:00
Cody Burkard 00d1963484 revised comment on defaultController function 2014-07-15 18:21:56 -07:00
Cody Burkard 5ac3cde2bd restructured defaultController into a function 2014-07-15 15:48:18 -07:00
Bob Lantz 2a08dec648 Hack to avoid failing version check... ;-/ 2014-07-15 08:50:30 -07:00
Bob Lantz b7268856d7 Tolerate passing controller *objects* into Mininet() 2014-07-15 08:28:05 -07:00
Bob Lantz 1b2c7a3193 Clean up standard topologies to use build 2014-07-15 05:58:10 -07:00
Bob Lantz b5962e8ee9 Added TorusTopo, a 2D torus topology 2014-07-15 05:44:13 -07:00
Bob Lantz ece509d579 add connected() to LinuxBridge 2014-07-15 05:34:32 -07:00
Bob Lantz 2935000485 Add utopic/Ubuntu 14.10 2014-07-15 04:32:52 -07:00
Bob Lantz 708b184397 Don't remove items from a list we're iterating over 2014-07-15 01:29:09 -07:00
Brian O'Connor 9a11544d87 Merge pull request #332 from cdburkard/patches/fix_linear5
adding waitConnected to linear5 test
2014-07-14 16:12:43 -07:00
lantz 2451d757bd Merge pull request #318 from cdburkard/patches/hifi_fix
added support in iperf for different result formats.
2014-07-14 15:20:11 -07:00
Cody Burkard ea97dea902 adding waitConnected to linear5 test 2014-07-14 14:42:00 -07:00
Cody Burkard a19cc91537 set DefaultController as the mininet class default 2014-07-14 14:09:39 -07:00
Cody Burkard 796b281bf1 fixed command parameter 2014-07-14 13:09:41 -07:00
Cody Burkard 72fd120dc8 added default controller class 2014-07-11 19:04:20 -07:00
Bob Lantz 4794871a9a Change algorithm slightly and print progress 2014-07-10 13:40:21 -07:00
Bob Lantz 13d25b4109 Minor message changes 2014-07-10 12:44:49 -07:00
lantz 21b50c962e Merge pull request #325 from cdburkard/patches/userspace_connect
added waitConnected attribute to mininet class
2014-07-14 13:46:07 -07:00
Brian O'Connor 54b29af818 Merge pull request #327 from mininet/devel/nodelib
Devel/nodelib
2014-07-11 17:02:18 -07:00
Brian O'Connor 8f34fa4c88 Merge pull request #326 from cdburkard/patches/nets
Switched shutdown order to kill controller first
2014-07-11 17:01:43 -07:00
lantz 872e336462 Merge pull request #328 from mininet/devel/newtopo
Add build() method to simplify Topo() usage
2014-07-11 16:27:49 -07:00
Cody Burkard b7a112cbec Shutting down controller first 2014-07-10 11:24:58 -07:00
Cody Burkard 5a9c74be03 fixed last commit 2014-07-10 11:07:50 -07:00
Bob Lantz 38addf2e24 Add alias + switch: { 'ovs': OVSSwitch, 'lxbr': LinuxBridge } 2014-07-10 01:34:53 -07:00
Bob Lantz 3878c000fe Add nodelib.py, a library of new node types 2014-07-10 00:44:53 -07:00
Bob Lantz 1324ae6262 Add build() method to simplify Topo() usage 2014-07-09 21:37:47 -07:00
Cody Burkard 3a52ad2f53 fixed linearbandwidth and waitconnected 2014-07-09 19:24:22 -07:00
Cody Burkard c23c992f14 fixed waitConnected performance and moved waitConnected call to mn.start 2014-07-09 19:12:15 -07:00
Cody Burkard 73f477be9d added waitConnect to linearbandwidth example. 2014-07-09 19:12:15 -07:00
Cody Burkard 4797b42005 conforming to style, and fixing documentation 2014-07-09 19:12:15 -07:00
Cody Burkard 6845fd8339 added documentation for waitConnected timeout 2014-07-09 19:12:15 -07:00
Cody Burkard 8e2443ada4 improved waitConnected algorithm and set default wait time to wait forever 2014-07-09 19:12:15 -07:00
Cody Burkard 84ea8d7f90 added waitConnected attribute to mininet class 2014-07-09 19:12:15 -07:00
Cody Burkard 1aed2b8abd Merge remote-tracking branch 'upstream/master' 2014-07-09 19:07:29 -07:00
Brian O'Connor 191df1cb73 Adding listen socket to UserSwitch when there is no listenPort set 2014-07-09 17:47:25 -07:00
Cody Burkard b6be1e2810 Merge branch 'patches/cleanup' 2014-07-08 17:57:10 -07:00
Cody Burkard a1acfa89c2 set default iperf formatting to none 2014-07-08 17:23:35 -07:00
Cody Burkard 93ddd92662 Revert "fixed default iperf formatting behavior"
This reverts commit 0e733c7754.
2014-07-08 16:55:50 -07:00
Cody Burkard 3131c90344 rolled back to iperf format option, and changed 'cpu' variable to 'pct' 2014-07-08 16:53:45 -07:00
lantz 3b484491ce Merge pull request #315 from cdburkard/patches/fix_bindpy
Added support for mount namespaces in bind.py
2014-07-08 16:27:06 -07:00
Bob Lantz 3b24bd7abd Restore non-mnexec pid detection for background commands 2014-07-08 02:22:02 -07:00
Bob Lantz e9013d761f Fix pid regex to eat \r\n 2014-07-07 21:58:30 -07:00
Bob Lantz c49b216c1f Set default printPid back to True 2014-07-07 21:55:34 -07:00
Bob Lantz 16ddf6560a Fix findPid since pty uses \r\n as line ending 2014-07-07 21:51:07 -07:00
Cody Burkard 0e733c7754 fixed default iperf formatting behavior 2014-07-02 13:07:57 -07:00
Cody Burkard 9c3ecfe338 conforming to mininet style 2014-07-02 10:53:41 -07:00
Bob Lantz 771850b9cf Possibly faster check for sentinel. 2014-07-01 18:04:44 -07:00
Bob Lantz 355696f3dd Don't set self.waiting twice 2014-07-01 17:55:14 -07:00
Cody Burkard 342b743b13 set staticArp in testLinkDelay 2014-07-01 17:07:14 -07:00
Cody Burkard 40a4a25dd8 use a single mininet instance in bindpy 2014-07-01 14:51:07 -07:00
lantz 25979e715e Merge pull request #317 from cdburkard/patches/cleanup
added code to kill stale mininet processes
2014-07-01 13:32:58 -07:00
Bob Lantz 82e0e9f38f Avoid overhead of another process (env) in startShell() 2014-07-01 01:49:10 -07:00
Bob Lantz 549f1ebc8f Attach a pty to each node's bash process
This should enable node commands that are expecting a tty to
behave better.
2014-06-27 16:41:54 -07:00
Bob Lantz 00803bcd7f Whitespace changes in OVSSwitch. 2014-06-27 13:05:10 -07:00
Cody Burkard af2f67d98c added documentation for HostWithPrivateDirs 2014-06-26 09:29:06 -07:00
Cody Burkard 752c2d6e7c mountprivatedirs is no longer needed 2014-06-20 23:54:18 -07:00
Cody Burkard 3c3344e1f5 imported check_output 2014-06-20 23:31:45 -07:00
Brian O'Connor 68e2e45f7d Merge pull request #316 from cdburkard:patches/fix_remote_ip
fixed netParse bug that caused mininet crash when no ip prefix was specified
2014-06-19 16:28:09 -07:00
Cody Burkard 6a81b6dfb3 added persistence option to HostWithPrivateDirs. also attached mount namespaces when mnexec -a is specified 2014-06-19 15:08:26 -07:00
Cody Burkard 4e76439c79 added support in iperf for different result formats. also added upper bounds for hifi tests 2014-06-16 23:33:38 -07:00
Cody Burkard 0d39f11034 added code to kill stale mininet processes 2014-06-16 17:39:24 -07:00
Brian O'Connor 893cf61c21 Merge pull request #313 from cdburkard/master
ovs port numbering bug fix
2014-06-11 16:17:14 -07:00
Cody Burkard ebc1eae679 Merge branch 'patches/fix_bindpy' of https://github.com/cdburkard/mininet into patches/fix_bindpy 2014-06-11 03:26:45 -07:00
Cody Burkard 29e5bee34e fixed issue with AssertTrue and skip first test if using old OVS version 2014-06-10 22:15:49 -07:00
Cody Burkard de41192ea7 imported warn from mininet.log 2014-06-10 21:50:40 -07:00
Cody Burkard b3055067ac fixed netParse bug that caused mininet crash when no ip prefix was specified 2014-06-10 18:38:10 -07:00
Cody Burkard 9109233886 Added support for mount namespaces in bind.py. Also moved it to the node class as a host type. 2014-06-10 11:44:03 -07:00
Brian O'Connor e49c9d2600 build.py: making ovf generation more generic 2014-06-06 21:21:13 -07:00
Cody 87b6021428 restructured code and added a test for the numberedports.py example 2014-05-29 17:26:40 -07:00
Cody 50f5080912 corrected code 2014-05-29 11:52:56 -07:00
Cody 3641723193 explaining test 2014-05-29 11:11:12 -07:00
Brian O'Connor 8b215af818 slight refactoring of util/vm/build.py to make it more extensible 2014-05-28 22:22:20 -07:00
Cody 586a9bb631 adding example to test functionality of port numbering 2014-05-28 17:46:19 -07:00
lantz 00c3238e50 Merge pull request #310 from rlane/ivs-verbose
IVSSwitch: add an option to control the --verbose flag
2014-05-28 14:31:45 -07:00
lantz e07775c7c3 Merge pull request #309 from rlane/ivs-batch-shutdown
support batch shutdown for IVS
2014-05-28 14:31:34 -07:00
Cody 4579b303e6 conforming to mininet python style 2014-05-28 13:46:55 -07:00
Cody 32d3c2bc79 removing debugging messages 2014-05-28 12:56:24 -07:00
Cody ba43451bd6 rearranged code for elegance 2014-05-28 12:42:48 -07:00
Cody f1e42ba5fa adding ovs version detection to fix port numbering bug 2014-05-28 11:50:13 -07:00
Rich Lane 163a66c64c IVSSwitch: add an option to control the --verbose flag 2014-05-22 13:06:57 -07:00
Rich Lane 876e66e555 net: allow batch shutdown of multiple types of switches
Each switch class will be called to shutdown its own instances.
2014-05-22 12:36:07 -07:00
Rich Lane 93cd5583eb IVSSwitch: support batch shutdown
Not a single command like the OVS one, but it still greatly decreases the
shutdown time.

This does assume that stop() is called after batchShutdown(), which is true in
the current mininet code.
2014-05-22 12:22:41 -07:00
lantz 5797f5852e Merge pull request #303 from jhall11/pingall
Add a timeout parameter to the pingAll command
2014-05-07 13:31:44 -07:00
lantz 15d2d76972 Merge pull request #305 from ggee/ovsssl
OVS switch connect to controllers using protocols other than TCP like SSL.
2014-05-07 13:29:39 -07:00
Gregory Gee 5cb4a5424d Add ability for for OVS switch start connect to controllers using protocols other than TCP.
net.addController( 'c0', protocol='ssl' )

This now allows OVS to connect to a controller using SSL.  The default of protocol is 'tcp'
as it currently is.
2014-05-03 16:21:53 -04:00
Jon Hall 4d1a9cdc1d Add a timeout parameter to the pingAll command 2014-04-25 04:37:11 +00:00
Bob Lantz c3bf407adf Added Ubuntu 14.04. 2014-04-23 14:28:09 -07:00
lantz 14e14f1b87 Merge pull request #286 from lantz/devel/ovsbatch
Enable batch startup/shutdown of OVS

Not perfect, but it moves us forward at least.
2014-04-13 18:44:11 -07:00
lantz bffe045267 Merge pull request #290 from backb1/patch/netstatnumeric
Netstat: do not resolve addresses
2014-04-01 11:50:51 -07:00
lantz 92a28881b1 Update net.py 2014-04-01 11:46:52 -07:00
lantz ebac6784d4 Merge pull request #293 from backb1/patch/pingloss
Ping: packet loss should be a float
2014-04-01 11:45:06 -07:00
Adrian d9376439b1 Ping: packet loss should be a float 2014-03-26 13:37:32 +01:00
lantz d718bb72e9 Merge pull request #257 from ggee/miniedit21071
Uploading MiniEdit 2.1.0.7.1
2014-03-21 13:02:35 -07:00
lantz 40ea9172f9 Merge pull request #283 from ggee/ovs2install
OVS install Ubuntu packages
2014-03-21 13:00:48 -07:00
lantz 787f8234ce Merge pull request #289 from rlane/ivs-wait
IVSSwitch: wait for ivs to terminate before tearing down node
2014-03-20 18:33:07 -07:00
lantz cc20908bb3 Merge pull request #288 from rlane/history
persistent command history
2014-03-20 18:26:55 -07:00
Rich Lane a7eb557680 IVSSwitch: wait for ivs to terminate before tearing down node
This was a problem when running IVS in a container. IVS would begin the process
of closing controller connections on receiving SIGTERM, but often mininet would
have continued on and removed the control network interface from the container
before it could send the FIN. The controller wouldn't know the connection had
been closed until it timed out much later.
2014-03-18 11:04:14 -07:00
Bob Lantz 0fe73a6780 build=False is unnecessary if topo=None, which is the default 2014-03-16 05:20:43 -07:00
Rich Lane a905be2260 persistent command history
Saves readline history to ~/.mininet_history.
2014-03-15 10:46:07 -07:00
lantz 8f5f38c6a5 Merge pull request #246 from rlane/newns
(pending) mnexec: mount sysfs in each container
2014-03-14 17:30:32 -07:00
Bob Lantz d82900d3a8 Don't look through all interfaces if you don't need to. 2014-03-06 17:52:41 -08:00
Gregory Gee e62715870a Update to 2.1.0.8.1. Include a fix to work around Mininet version number
checking with non-numeric characters.
2014-02-28 22:23:27 -05:00
Bob Lantz 2e19ceb0aa Use a single ovs-vsctl command for speed/atomicity 2014-02-28 18:45:41 -08:00
Bob Lantz a0bc100289 Enable batch shutdown for OVS. 2014-02-28 18:45:41 -08:00
Bob Lantz 5e60ee266b assertTrue( a > b ) -> assertGreater( a, b ) for better messages 2014-02-28 18:41:41 -08:00
Bob Lantz 7c29c2ebf2 Fix IVS build 2014-02-28 14:56:08 -08:00
Gregory Gee 4b7b23cf20 Change the installation to a separate option as recommended with -V.
This argument expect a parameter which is the version number of OVS you wish to install.
    install.sh -V 2.0.0

    What is nice that I tested, is that you can keep running the above to change
    which OVS version you want to test with.  Also, if a new version of OVS
    is released, just run the above again specifying the new version number.

    The version number must match the version number in the tarball file name
    like openvswitch-2.0.0.tar.gz.  In this case, the version specified
    must be 2.0.0.
2014-02-25 23:15:03 -05:00
Bob Lantz 2dee3413cf Remove Ubuntu 10 and Debian Lenny and add Debian Wheezy support 2014-02-25 16:49:33 -08:00
Gregory Gee 59cbec3fc9 Update to 2.1.0.8 2014-02-23 18:30:04 -08:00
Bob Lantz 3e2eb71316 Fix default of in-band control for OVS.
fixes #279
2014-02-17 00:23:10 -08:00
Bob Lantz 06115a0456 Add support for batch shutdown of OVS switches.
This saves about 10 seconds for a 200 switch network.
2014-02-06 17:56:32 -08:00
Bob Lantz 9cf9b7b223 Clean things up slightly. 2014-02-06 17:50:09 -08:00
Bob Lantz 1fda4865c8 Try batch deleting OVS instances. 2014-02-06 15:51:24 -08:00
Bob Lantz f0e55e1096 Remove mn links with dots in them (e.g. foo_bar-baz1.2-eth0) 2014-02-06 15:33:11 -08:00
Bob Lantz 74c71bc8a4 Minor tweak of return value. 2014-02-03 17:55:25 -08:00
Bob Lantz 0b5609f587 Check (and canonicalize) dpid arguments to Switch()
This seems slightly ugly, but it has bitten many people.

Closes #268
2014-02-03 17:52:51 -08:00
moijes12 2fc5e46f1b Update test_switchdpidassignment.py 2014-01-30 23:41:46 +05:30
lantz ef6774325a Merge pull request #258 from ggee/MininetINSTALL
Add notes about specific release branches.
2014-01-29 17:05:24 -08:00
lantz 7450cfc627 Merge pull request #263 from adferguson/clean-fix
adjust regex for finding mininet's links during cleanup
2014-01-29 17:03:37 -08:00
Bob Lantz 29988c8b1d Canonicalize dpid by removing colons and padding with zeros
closes #268
2014-01-29 16:54:25 -08:00
lantz 34bb64eddd Merge pull request #249 from yeasy/master
Close the file when done with it.
2014-01-28 15:24:24 -08:00
lantz 873049c346 Merge pull request #252 from sieben/useless_parenthesis
fixup: useless_parenthesis
2014-01-28 15:22:53 -08:00
lantz a722a3a110 Update test_simpleperf.py
Add spaces.
2014-01-28 15:21:48 -08:00
lantz f2942a7f92 Merge pull request #253 from sieben/Simplify_chained_comparaison
OK...
2014-01-28 15:20:29 -08:00
lantz ae367d3645 Merge pull request #266 from adferguson/if_namesize
print error messages when making interfaces
2014-01-28 15:16:19 -08:00
lantz 6022e96b4d Merge pull request #269 from adferguson/userspace_unix
userspace switch can be reached on unix port by dpctl
2014-01-28 15:14:30 -08:00
Bob Lantz 2286ef4b36 Remove GRUB_TERMINAL=serial from /etc/default/grub
This is added because we install Ubuntu from a serial console.
Fixes #265
2014-01-24 15:44:49 -08:00
Andrew Ferguson 0dd96ebc57 userspace switch can be reached on unix port by dpctl 2014-01-24 16:59:42 -05:00
Bob 06b99c8ef2 Merge pull request #264 from adferguson/tc-no_opt-fix
don't crash when link is TCLink but without options
2014-01-24 12:43:50 -08:00
Bob b357a212dd Merge pull request #254 from sieben/unresolved_references
fixup: unresolved_references
2014-01-24 12:41:14 -08:00
Andrew Ferguson 2e704f996b print error messages when making interfaces
without this, thereis no indication in Mininet that creating an
interface has failed. for example, this may happen when the interface
name is too long (longer than IFNAMSIZ, which is 16 chars).
2014-01-23 16:39:27 -05:00
Andrew Ferguson 284547080c don't crash when link is TCLink but without options
caused by optimized return in link.py#275 in TCIntf.config()
2014-01-20 17:45:30 -05:00
Andrew Ferguson 07e3da08d0 adjust regex for finding mininet's links during cleanup
link names of the form "a-b-ethN" were previously interpreted
as "b-ethN". this change accepts link names with a dash, and
requires N to only contain digits.
2014-01-19 18:33:27 -05:00
Bob Lantz dfd79bde56 Add OperatingSystemSection to OVF template
should facilitate importing 64-bit image
2014-01-15 10:47:06 -08:00
Bob Lantz 317d6482e4 Fix typo/minor error. 2014-01-14 20:26:40 -08:00
Bob Lantz 5f51abd142 Allow -b to specify install or test branch 2014-01-14 20:08:22 -08:00
Bob Lantz b9288efc4a Allow specification of branch to install 2014-01-14 19:42:55 -08:00
Bob Lantz c90fb34d6d If specified, add Branch to build dir name 2014-01-13 23:35:15 -08:00
Bob Lantz 75abd94bf5 Add #streamOptimized to fix .ovf for VirtualBox 4.3.2
fixes #261
2014-01-10 18:07:08 -08:00
Bob Lantz 55e48112f8 Remove trailing spaces 2014-01-10 18:06:29 -08:00
Gregory Gee 4b65570ba5 Add notes about specific release branches. 2014-01-02 21:54:56 -05:00
Gregory Gee 9aefda7c1a Uploading MiniEdit 2.1.0.7.1
Many changes since master version.
- save/load topologies
- host, controller, switch and link properties
- link actions to set status up/down
2014-01-02 21:40:46 -05:00
Baohua Yang bb485009c3 Merge branch 'master' of github.com:yeasy/mininet 2013-12-21 21:42:31 +08:00
Baohua Yang 24fe68d925 Correct the comments of do_pingallfull() and do_iperfudp() 2013-12-21 21:36:24 +08:00
Baohua Yang 3780d9cda8 Close the file when done with it. 2013-12-21 21:36:22 +08:00
Rémy Léone e10703cd7b fixup: unresolved_references 2013-12-20 14:46:38 +01:00
Rémy Léone 824afb84c9 fixup: useless_parenthesis 2013-12-20 14:43:30 +01:00
Rémy Léone aee33863c8 fixup: Simplify_chained_comparaison 2013-12-20 14:41:22 +01:00
Baohua Yang 90c29d8f23 Merge branch 'master' of github.com:yeasy/mininet 2013-12-16 10:33:12 +08:00
Baohua Yang e686911210 Correct the comments of do_pingallfull() and do_iperfudp() 2013-12-16 10:31:54 +08:00
Baohua Yang 8bb830824b Close the file when done with it. 2013-12-16 10:31:51 +08:00
Bob a6a0cb4331 Merge pull request #250 from rlane/killpg
kill entire process group in Node.terminate
2013-12-14 12:36:32 -08:00
Rich Lane 2200d8d173 node: kill entire process group in terminate
mnexec already puts the shell into its own process group. Killing the entire
process group cleans up after any background processes the user left running.
2013-12-14 11:12:46 -08:00
backb1 c34a000e78 Do not resolve addresses 2013-12-14 16:11:33 +01:00
Brian O'Connor fb51cdaca3 adding output file to build.py 2013-12-12 18:38:20 -08:00
Brian O'Connor 50423936b2 Merge branch 'master' of github.com:mininet/mininet 2013-12-12 15:56:41 -08:00
Brian O'Connor 49994c8915 adding noneTest to Mininet vm build script 2013-12-12 15:38:45 -08:00
Bob Lantz 17dbc7e055 Minor codecheck fixes 2013-12-11 18:33:54 -08:00
Bob Lantz 312c386cda Fix regex to support Mininet 20.30.40+++ 2013-12-11 18:29:58 -08:00
Bob Lantz 96952b92f8 2.1.0 -> 2.1.0+ 2013-12-11 18:08:33 -08:00
Baohua Yang 3e2333e5ed Correct the comments of do_pingallfull() and do_iperfudp() 2013-12-11 15:19:24 +08:00
Baohua Yang fc7c919b43 Close the file when done with it. 2013-12-11 14:41:21 +08:00
Brian O'Connor c7e86f9374 fixing CLI host rewriting when host's default interface does not have an IP 2013-12-05 17:30:09 -08:00
Bob Lantz 5da9376222 Depend: add dnsmasq (needed), remove landscape-client (not) 2013-11-20 22:15:26 -08:00
Rich Lane 5461565945 mnexec: mount sysfs in each container
The sysfs filesystem is [tagged][1] with a set of namespaces when mounted, taken
from the mounting process. Among other things, this controls which network
devices will show up in /sys/class/net and /sys/class/net/bonding_masters.

Without this change, mininet will not mount sysfs in a node. Attempting to
configure a bond interface in a node will only affect the parent namespace.

This change mounts a new sysfs filesystem in each node. To prevent this mount
from affecting the parent namespace the mount namespace is also unshared.

[1]: https://www.kernel.org/doc/Documentation/filesystems/sysfs-tagging.txt
2013-11-18 17:05:09 -08:00
Bob bee06cf264 Merge pull request #245 from yeasy/master
Fix error wiki url.
2013-11-15 13:23:10 -08:00
Baohua Yang cd238fe567 Fix error wiki url. 2013-11-15 14:24:51 +08:00
moijes12 09b06509a8 Create test_switchdpidassignment.py
Regression tests to verify switch datapath ID assignment.
2013-11-07 09:49:36 -08:00
Bob Lantz e771239608 Only restart network-manager if we've changed config 2013-10-24 15:11:43 -07:00
Brian O'Connor e0af160213 small fixes for NAT 2013-10-23 13:48:50 -07:00
Bob e5380d646c Merge pull request #226 from rlane/ivs-lo
IVSSwitch: bring up lo interface
ok for symmetry - we can probably get rid of this later though
2013-10-15 15:22:21 -07:00
Bob 621c3eebf3 Merge pull request #218 from jpoliv/master
Fixes a couple of compiler warnings
2013-10-15 15:20:53 -07:00
Rich Lane 4a94f76ec3 IVSSwitch: bring up lo interface 2013-10-08 16:59:02 -07:00
Bob c0ddd5c5d8 Merge pull request #225 from fcappi/master
Update Oflops repository in install.sh
2013-10-08 12:42:19 -07:00
Fernando Cappi a6e55e3528 Update Oflops repository in install.sh 2013-10-05 22:49:15 -03:00
Brian O'Connor ffeb16eb66 fixing --nat option in mn 2013-10-03 16:29:05 -07:00
Brian O'Connor a802d8b19a more NAT cleanup of net and topo 2013-10-03 15:19:34 -07:00
Brian O'Connor 555d10dea7 adding internet / nat example 2013-10-03 15:15:40 -07:00
Brian O'Connor 3f2355a36a undoing gateway in net and removing addNAT helpers 2013-10-03 15:15:20 -07:00
Brian O'Connor bceb298edb Adding NAT class
Includes automatic NAT feature (mn --nat) and addNAT convenience method for topologies
fixes #111
2013-10-03 09:40:00 -07:00
Brian O'Connor 47b9466fad Adding NAT class
Includes automatic NAT feature (mn --nat) and addNAT convenience method for topologies
fixes #111
2013-10-03 09:39:40 -07:00
Jose Pedro Oliveira 8f80f875b5 Change cgroup() return type from int to void (avoids a gcc warning) 2013-09-28 01:42:05 +01:00
Jose Pedro Oliveira 2941bbae2d Defines _GNU_SOURCE (required by the unshare syscall) 2013-09-28 01:37:51 +01:00
Jose Pedro Oliveira 8842e450db Turns on gcc warnings (CFLAGS += -Wall -Wextra) 2013-09-28 01:36:02 +01:00
Jose Pedro Oliveira f5737aa3cc The header file limits.h was being included twice 2013-09-28 01:34:01 +01:00
Jose Pedro Oliveira b8fd3d2d8e Fixes compiler warning: control reaches end of non-void function 2013-09-19 15:26:26 +01:00
Jose Pedro Oliveira 387250cd83 Fixes compiler warning: implicit declaration of function 'isalnum' 2013-09-19 15:25:22 +01:00
Bob Lantz 433d83221a Fix typo 2013-09-19 04:12:04 -07:00
Bob Lantz 3151804cf8 Add option to set pexpect timeout 2013-09-19 02:02:03 -07:00
Bob Lantz f66e9af515 Update for 2.1.0 final packaging 2013-09-18 22:44:35 -07:00
Bob Lantz f92abd2ba5 Sync changelog (somewhat) with ubuntu packaging
Only differences are copyright and log message.
2013-09-18 22:41:17 -07:00
Bob Lantz 700c5bf5b5 Add date to ovf name 2013-09-18 21:39:09 -07:00
Bob Lantz 87c37bb182 Add jpoliv 2013-09-18 21:38:36 -07:00
Bob Lantz 9cc9a491a8 Avoid reverse DNS lookup 2013-09-18 20:53:54 -07:00
Bob Lantz 76a8a1637f Clean up sshd.py and its test so it works on VirtualBox 2013-09-18 20:48:22 -07:00
Bob Lantz 568f6424e5 Add --memory option for VM memory size (for large tests) 2013-09-18 18:49:21 -07:00
Bob f32a8f7ea0 Minor edits 2013-09-18 16:47:28 -07:00
Bob Lantz e0b50c8a70 Fix var name change 2013-09-18 00:04:20 -07:00
Bob Lantz 0294f5ec55 Add options to run commands before or after tests 2013-09-18 00:03:16 -07:00
Bob 53987e31aa Merge pull request #214 from zlim/mnexec-fix
mnexec: getopt bugfix
2013-09-18 13:06:58 -07:00
Bob Lantz f59858543c Fix walkthrough test path 2013-09-18 12:44:54 -07:00
Zi Shen Lim cae7be1a60 mnexec: getopt bugfix
getopt returns an 'int', so use change datatype of 'c' to match it.
Otherwise, 'c' may hold a value of 255 (0xff), and fail the comparison
with -1 (0xffffffff): while ((c = getopt(...)) != -1)

This bug was uncovered on Ubuntu 13.04 running on ARM, using
arm-linux-gnueabihf-gcc4.7.
2013-09-18 10:33:15 -07:00
Bob Lantz 4ccfe242e8 Remove extra expect (paste error) that broke bootAndRunTests() 2013-09-17 18:02:06 -07:00
Brian O'Connor 811963ad26 small additions to README 2013-09-17 15:51:46 -07:00
Brian O'Connor 41d932017b updated source install for Ubuntu in INSTALL 2013-09-17 15:51:46 -07:00
Bob Lantz 7a24407ecc Remove unneeded bc dependency
fixes #212
2013-09-17 17:31:21 -07:00
Brian O'Connor df68c211b5 Merge pull request #209 from jpoliv/master
Fedora 18+ installation notes
2013-09-17 16:38:24 -07:00
Bob Lantz 2ca1ea92ff Clarify log message 2013-09-17 15:56:09 -07:00
Bob Lantz 8f546d89b4 Backing out attempt to identify kernel binary format 2013-09-17 15:40:52 -07:00
Bob Lantz 6d3cb5bcd3 Add arch to vm name, and check kernel for boot arch 2013-09-17 14:50:41 -07:00
Bob Lantz ca5b0c56f0 setLogLevel('warning') to avoid test spam 2013-09-17 13:44:42 -07:00
Jose Pedro Oliveira 0d58b93a84 Fedora 18+ installation notes 2013-09-16 21:42:06 +01:00
Bob Lantz b7548e68a8 Add walkthrough test and log build exceptions 2013-09-16 11:22:26 -07:00
Bob Lantz 2f3e8c2bd3 Log failed test output. 2013-09-16 11:06:12 -07:00
Brian O'Connor fc2a8fd59a fixed git download for testRemoteController in test_walkthrough.py 2013-09-17 11:28:10 -07:00
Brian O'Connor 47b24beb6c Merge branch 'master' of github.com:mininet/mininet 2013-09-16 23:59:06 -07:00
Brian O'Connor 895ff6f452 adding runner to mininet/test, added test_walkthrough.py 2013-09-16 23:58:22 -07:00
Bob Lantz fce7f5c56b Add --zip option to archive VM. 2013-09-16 07:45:32 -07:00
Bob b5e8dd5edc Merge pull request #210 from rlane/ivs-opts
IVSSwitch: support opts constructor parameter
2013-09-16 14:22:18 -07:00
Rich Lane d4fabc0464 IVSSwitch: support opts constructor parameter
This parameter is already supported by the other switch classes.
2013-09-16 13:33:38 -07:00
Brian O'Connor 971d6aafd4 Merge pull request #208 from jpoliv/master
install.sh: improve support for the Fedora linux distribution
2013-09-13 18:32:29 -07:00
Jose Pedro Oliveira 0457824193 Fedora: update status messages 2013-09-14 02:22:07 +01:00
Jose Pedro Oliveira 40ad3a1bf9 Replaces a couple of 'sudo apt-get install -y' instances by '$install' 2013-09-14 02:21:24 +01:00
Jose Pedro Oliveira de2680152b Fedora: support the -w option (wireshark) 2013-09-14 02:19:39 +01:00
Jose Pedro Oliveira 541ba67daf Fedora: support the -v option (OVS) 2013-09-14 02:18:04 +01:00
Brian O'Connor 6576d894a3 Merge branch 'master' of github.com:mininet/mininet 2013-09-13 13:06:49 -07:00
Brian O'Connor 8e1dade106 removing assert from util.py 2013-09-13 13:06:21 -07:00
Bob 2ebdd028cf Merge pull request #194 from jpoliv/master
Make install.sh (-n) work in Fedora 19
2013-09-13 12:40:08 -07:00
Jose Pedro Oliveira b5a48f9f6c Merge branch 'master' of https://github.com/mininet/mininet
Conflicts:
	mininet/node.py -- revert our change; better solution upstream
	util/install.sh -- resolved the conflict (echo statement)
2013-09-13 04:05:47 +01:00
Bob d70ca981c9 Update README.md 2013-09-12 14:23:19 -07:00
Bob 4b719d7443 Minor cosmetic edits 2013-09-12 14:21:20 -07:00
Bob Lantz 5b9f6b2192 Added .md to README so that it displays nicely on github. 2013-09-12 14:16:58 -07:00
Bob Lantz 4e242e9211 Add -v so that we can see exampletest results 2013-09-12 14:14:55 -07:00
Bob 94f3c76039 Merge pull request #207 from mininet/devel/exampletest
Added tests for all non-X11 examples
2013-09-12 14:14:14 -07:00
Brian O'Connor 67a7c5601a Merge branch 'master' of github.com:mininet/mininet 2013-09-12 13:49:45 -07:00
Brian O'Connor 4ea0c0936d Updated mininet/util.py to support better resource setting semantics and protected with try block 2013-09-12 13:49:40 -07:00
Bob Lantz 7bd9a79b12 Add --test {test} and --branch {branch} options, and exampletest 2013-09-11 22:59:50 -07:00
Brian O'Connor bfb560045c add rm to sshd tests 2013-09-11 14:45:49 -07:00
Brian O'Connor c5da46f125 added -quick options to skip long tests 2013-09-11 14:45:49 -07:00
Brian O'Connor 10fdd01dc8 fixed runner.py and added -v and -quick options 2013-09-11 14:45:48 -07:00
Brian O'Connor 1e9e781c12 changed 1% to 2% in test_limit.py 2013-09-11 14:45:48 -07:00
Brian O'Connor 24b38126ec cleaned up and commented test_simpleperf.py 2013-09-11 14:45:48 -07:00
Brian O'Connor 3577a6989d cleaned up and commented test_tree1024.py and test_treeping64.py 2013-09-11 14:45:48 -07:00
Brian O'Connor 48c49c54e2 cleaned up and commented test_sshd.py 2013-09-11 14:45:48 -07:00
Brian O'Connor d4993c0ba4 cleaned up and commented test_scratchnet.py 2013-09-11 14:45:48 -07:00
Brian O'Connor 213b7c57ee cleaned up and commented test_popen.py 2013-09-11 14:45:48 -07:00
Brian O'Connor b9b1f2e7f0 cleaned up and commented test_nat.py; added check for connectivity before running test 2013-09-11 14:45:48 -07:00
Brian O'Connor cdd5210bb7 cleaned up and commented test_multitest.py 2013-09-11 14:45:48 -07:00
Brian O'Connor bc90a79581 cleaned up and commented test_multipoll.py 2013-09-11 14:45:47 -07:00
Brian O'Connor e6e1260bc2 cleaned up and commented test_multiping.py 2013-09-11 14:45:47 -07:00
Brian O'Connor 1d555e724b cleaned up and commented test_linearbandwidth.py 2013-09-11 14:45:47 -07:00
Brian O'Connor e6fe480a30 cleaned up and commented test_limit.py 2013-09-11 14:45:47 -07:00
Brian O'Connor 91a06063b4 cleaned up and commented test_hwintf.py 2013-09-11 14:45:47 -07:00
Brian O'Connor 49fc496c12 cleaned up and commented test_emptynet.py 2013-09-11 14:45:47 -07:00
Brian O'Connor 94abeeabb9 cleaned up and commented test_cpu.py 2013-09-11 14:45:47 -07:00
Brian O'Connor b7e506341f cleaned up and commented test_controlnet.py 2013-09-11 14:45:47 -07:00
Brian O'Connor fba3fd81fa cleaned up and commented test_controllers.py 2013-09-11 14:45:47 -07:00
Brian O'Connor e875c0de26 minor test cleanup 2013-09-11 14:45:47 -07:00
Brian O'Connor 43f058df6d cleaned up and commented test_bind.py; added one new test 2013-09-11 14:45:46 -07:00
Brian O'Connor 01c0ef0013 added comments to test_baresshd.py 2013-09-11 14:45:46 -07:00
Brian O'Connor a46fae0687 adding first draft of tests for all examples, they need comments and clean up, some could be made more rebust 2013-09-11 14:45:46 -07:00
Brian O'Connor 5a646a0d20 sshd.py: allow sshd args to be passed via commandline 2013-09-11 14:45:46 -07:00
Brian O'Connor 9a73dcad53 fixed print format in popenpoll 2013-09-11 14:45:46 -07:00
Brian O'Connor b605cf74d2 style in multitest 2013-09-11 14:45:46 -07:00
Brian O'Connor 220376b6e2 hwintf.py: allow intf to be specified in cmd line 2013-09-11 14:45:46 -07:00
Brian O'Connor cfb6bf95a3 adding commandline args to UserSwitch in controlnet, examples of partial 2013-09-11 14:45:46 -07:00
Brian O'Connor 3905843257 accept command line args in baresshd.py 2013-09-11 14:45:45 -07:00
Bob Lantz 501a164eba Added --test option to boot and test a VM 2013-09-11 12:00:17 -07:00
Bob Lantz 9e725cb28a Add 'mininet' prefix to output files 2013-09-11 12:00:17 -07:00
Bob Lantz e02cdc0c54 XML file cannot begin with a newline :( 2013-09-11 12:00:17 -07:00
Bob Lantz 0038720c01 Add generateOVF to finally create the OVF descriptor file! 2013-09-11 12:00:17 -07:00
Bob Lantz d4279559fa Add options; generate virtimage file (in progress) 2013-09-11 12:00:17 -07:00
Bob Lantz 1ea9d7d4de Update copyright for 2013 2013-09-11 12:00:17 -07:00
Bob Lantz f7abd084c6 Added socat, iperf, cgroup-bin to dependencies 2013-09-11 12:00:17 -07:00
Bob Lantz d82e0ef5c2 Add mtools to dependencies 2013-09-11 12:00:17 -07:00
Bob Lantz 3027856c7b Find wireshark dir using find (fix for 13.10) 2013-09-11 12:00:17 -07:00
Bob Lantz 9de7bd666d Minor additions and edits 2013-09-11 12:00:16 -07:00
Bob Lantz 92b51563b5 Remove extra ` 2013-09-11 12:00:16 -07:00
Brian O'Connor 389c7aa5af install.sh: making BUILD_DIR more robust 2013-09-11 12:00:16 -07:00
Brian O'Connor bda54a9aed updating INSTALL 2013-09-11 12:00:16 -07:00
Brian O'Connor 09b1239131 fixing comment 2013-09-11 12:00:16 -07:00
Bob Lantz 662f2447e3 Flush log file output to avoid slow buffering 2013-09-11 12:00:16 -07:00
Bob Lantz 20005f5bbc Add a space 2013-09-11 12:00:16 -07:00
Bob Lantz 803a1a5489 Write build log to file, and detect installation failure 2013-09-11 12:00:16 -07:00
Bob Lantz 20ba29590a Add 13.10 (won't work until final) 2013-09-11 12:00:16 -07:00
Bob Lantz 13554a3d83 Minor cleanup 2013-09-11 12:00:16 -07:00
Bob Lantz 9bfc7c7768 Satisfy pylint 2013-09-11 12:00:16 -07:00
Bob Lantz 045ef7b801 Add docstring to satisfy pylint 2013-09-11 12:00:15 -07:00
Bob Lantz e69355f78f One last code check fix: line too long 2013-09-11 12:00:15 -07:00
Bob Lantz 9d14c841d7 Pass code check 2013-09-11 12:00:15 -07:00
Bob Lantz f796f01f38 add spaces to satisfy pylint ;-p 2013-09-11 12:00:15 -07:00
Bob Lantz 350299786d code check fixes & add comment spaces 2013-09-11 12:00:15 -07:00
Bob Lantz 445c0959b5 Pass code check (except bogus Popen error) 2013-09-11 12:00:15 -07:00
Bob Lantz 0c5aae157a examples -> mininet/examples for code check 2013-09-11 12:00:15 -07:00
Brian O'Connor 2e7d0d4934 fixed indent issue with examples/controllers.py 2013-09-11 12:00:15 -07:00
Brian O'Connor e9a835ac55 print usage message for unknown command 2013-09-11 12:00:15 -07:00
Bob Lantz b55806017a Check for Connected in checkListening() 2013-09-11 12:00:15 -07:00
Bob Lantz b79ce2a549 Clarify actual testing in module comment 2013-09-11 12:00:14 -07:00
Bob Lantz a155795837 quetzal -> quantal 2013-09-11 12:00:14 -07:00
Brian O'Connor e935da461a added comments and cleaned up controlnet.py 2013-09-11 12:00:14 -07:00
Brian O'Connor 92bf2cf105 codecheck: removed unused variable in topo.py 2013-09-11 12:00:14 -07:00
Brian O'Connor 0840af5277 removing todos in net.py 2013-09-11 12:00:14 -07:00
Brian O'Connor 967614f64a adding examples/__init__.py 2013-09-11 12:00:14 -07:00
Brian O'Connor 891d807137 fixed multiping example 2013-09-11 12:00:14 -07:00
Brian O'Connor ecddbcf240 updated emptynet to use addLink 2013-09-11 12:00:14 -07:00
Brian O'Connor aacf7c4613 fixing controllers.py to use api 2013-09-11 12:00:14 -07:00
Brian O'Connor 3a35480c7a removing test from controlnet 2013-09-11 12:00:14 -07:00
Brian O'Connor 7c962d2f61 Fixed MininetFacade and moved main logic into run. First shot at "test" function 2013-09-11 12:00:13 -07:00
Brian O'Connor dc882d6905 clean up controlnet 2013-09-11 12:00:13 -07:00
Brian O'Connor 15146d900c changed CLI to MininetFacade; a great deal of logic also changed 2013-09-11 12:00:13 -07:00
Bob Lantz ad5a0e42d0 Explicitly create a qcow2 image 2013-09-11 12:00:13 -07:00
Bob Lantz a56e29704e Make sure that /bin/bash exists before attempting to chroot. 2013-09-11 12:00:13 -07:00
Bob Lantz f344290368 Change API for more efficient remount and unmount. 2013-09-11 12:00:13 -07:00
Bob Lantz 5ae8c936e7 Prototype implementation of bind mounts. 2013-09-11 12:00:13 -07:00
Bob Lantz 5413d2e5a3 Check for chroot dir and chroot if necessary. 2013-09-11 12:00:13 -07:00
Bob Lantz 226a1dc391 Minor edits 2013-09-11 12:00:13 -07:00
Bob Lantz ec810dd6db minor edits 2013-09-11 12:00:13 -07:00
Bob Lantz 5493212578 Add tests for OVS user switch (skipping hifi test for now)
test_hifi.py currently fails for OVS when datapath=user -
we should look at this and fix it.
2013-09-11 12:00:13 -07:00
Bob Lantz 45d365f98b Need a few more skipUnless() checks. 2013-09-11 12:00:12 -07:00
Bob Lantz 94324e3f46 Skip IVS and UserSwitch tests if they are not installed 2013-09-11 12:00:12 -07:00
Bob Lantz d2762938b7 Increase timeout (for lengthy hifi test) 2013-09-11 12:00:12 -07:00
Bob Lantz 765d126ee9 Delete leftover TAP interface from OVS with datapath=user
fixes #199
2013-09-11 12:00:12 -07:00
Bob Lantz 896c4cbccc Edits for 2.1.0 2013-09-11 12:00:12 -07:00
Bob Lantz 325074981c Initial text and version updates for 2.1.0 2013-09-11 12:00:12 -07:00
Bob Lantz b26f38a6aa Added CONTRIBUTORS file 2013-09-11 12:00:12 -07:00
Brian O'Connor d13505b6c6 updating setup to include examples 2013-08-26 15:29:05 -07:00
Bob Lantz 67f9d8f655 Remove qcow2 post conversion; drop unused etree dep 2013-08-26 11:46:25 -07:00
Bob Lantz c353e60913 correction: pexpect.timeout -> TIMEOUT 2013-08-25 18:06:22 -07:00
Bob Lantz 662fb712bc Detect failed iso download; begin virt-image support 2013-08-25 17:42:15 -07:00
Bob Lantz 28165f7b4e Check make test results 2013-08-25 16:27:43 -07:00
Bob Lantz dbcfda77d9 Update release URLS - should probably clean this up. 2013-08-25 15:51:56 -07:00
Bob Lantz 1dfa7776e1 Change to extract kernel and initrd 2013-08-25 15:25:04 -07:00
Bob Lantz 40a9c15345 Remove gigantic doxypy/texlive/fonts from install.sh -a
fixes #192
2013-08-25 13:55:50 -07:00
Bob Lantz 3dc3e066aa Update build directory name to include date. 2013-08-24 13:57:36 -07:00
Bob Lantz bbf808c347 Get rid of unused pexpect import. 2013-08-23 21:27:01 -07:00
Bob Lantz 4556e06fcf Fix erroneous tab hit before commit. 2013-08-23 21:25:07 -07:00
Bob Lantz f605a4e430 Works, more or less. 2013-08-23 20:33:25 -07:00
Bob Lantz fa1758b950 First draft of new world order (create build image from iso) 2013-08-23 17:26:46 -07:00
Bob Lantz 14903d6a05 Final gasp of cloud image version. 2013-08-22 18:40:10 -07:00
Jose Pedro Oliveira 5b08af2e8d Add a small notice about the Fedora's support. 2013-08-22 18:13:31 +01:00
Jose Pedro Oliveira 6cb05c3762 Make options -f and -b work in Fedora 19 2013-08-22 17:42:17 +01:00
Bob Lantz 94954177e5 Added support for creating a volume rather than a raw partition. 2013-08-21 21:18:11 -07:00
Jose Pedro Oliveira 3d89df13ef Handle Fedora's telnet output:
----------
*** c0 : ('echo A | telnet -e A 127.0.0.1 6633',)
telnet: connect to address 127.0.0.1: Connection refused
Telnet escape character is 'A'.
Trying 127.0.0.1...
Unable to contact the remote controller at 127.0.0.1:6633
----------
2013-08-22 00:57:14 +01:00
Jose Pedro Oliveira 15f2d240d6 Make install.sh support Fedora 19 (install.sh -n) 2013-08-22 00:47:30 +01:00
Bob Lantz 85dfac5c06 Many more improvements. 2013-08-20 13:31:15 -07:00
Bob Lantz 860bcc02c6 Minor changes and script evolution. 2013-08-20 13:31:15 -07:00
Bob Lantz 4daeeff0e3 Created first revision of VM build script. 2013-08-20 13:31:15 -07:00
Brian O'Connor 32de4c9e7c reverted iperf output and fixed regex 2013-08-16 11:16:28 -07:00
Brian O'Connor f0c123d4c0 fixing console.py graph parser 2013-08-15 19:06:31 -07:00
Brian O'Connor 8c22fe84c2 fixed iperf output parsing, changed to csv format
fixes #191
2013-08-15 18:54:07 -07:00
Brian O'Connor 9ff453a50b Changed iperf -sD to iperf -s &
fixes #190
2013-08-15 18:22:21 -07:00
Brian O'Connor 4e6b03d668 Merge pull request #188 from mininet/devel/fixlimits
Set sysctl limits when net starts
2013-08-14 17:30:43 -07:00
Brian O'Connor b635fd9edd Some cleanup and style fixes for fixlimits 2013-08-14 17:29:23 -07:00
Brian O'Connor a387952493 fixed host ip assignment and shutdown with xterms
fixes #189
2013-08-14 17:24:32 -07:00
Brian O'Connor 867a6d6731 Cleaned up sysctl and rlimit test and set
Use files instead of sysctl to set limits
2013-08-14 15:04:11 -07:00
Brian O'Connor b20c9470c7 add sysctl test and set
fixes #184
2013-08-12 16:22:19 -07:00
Brian O'Connor 7523c420bd Merge pull request #186 from mininet/devel/clifix
Replaced nodelist and nodemap in CLI with mn
2013-08-12 14:03:33 -07:00
Brian O'Connor 98cb33599f fixed comment in cli.py 2013-08-09 17:10:50 -07:00
Brian O'Connor 9281719d74 Made net compliant with dict semantics and added function comments
Fixed locals bug (now they are persisent across calls)
2013-08-09 17:07:39 -07:00
Brian O'Connor 8e04a9f844 Replaced nodelist and nodemap in CLI with mn
Updated Mininet to be more compliant with dict
Fixes #182
2013-08-09 12:20:13 -07:00
Brian O'Connor 6df4371df6 Removing test prints from user switch merge 2013-08-06 15:16:24 -07:00
Brian O'Connor be13072f0c Merge branch 'adf-userswitch-tclink' of github.com:adferguson/mininet into adferguson-adf-userswitch-tclink
Only sleep and reapply if slicing is enabled

Conflicts:
	mininet/node.py
2013-08-06 15:13:45 -07:00
Brian O'Connor 989df7454c Merge branch 'patches/examplesdoc' of github.com:ryancox/mininet into ryancox-patches/examplesdoc
Conflicts:
	examples/README
2013-08-05 18:13:37 -07:00
Brian O'Connor 7e87dbaa39 Fixed modprobe install. Checks to ensure that OVS_KMODS is set 2013-08-05 14:00:37 -07:00
Brian O'Connor 1e5cdfd805 Merge branch 'master' of github.com:mininet/mininet 2013-08-02 13:36:18 -07:00
Brian O'Connor bb0006b683 Merging MurphyMc LinearTopo pull request 2013-08-02 13:35:38 -07:00
Bob Lantz 786117dd49 Merge branch 'ivs' of https://github.com/rlane/mininet into rlane-ivs
Conflicts:
	util/install.sh

fixes #159
2013-07-31 18:20:18 -07:00
Brian O'Connor 43ba774e52 Merge pull request #181 from mininet/devel/ping
pingall now reports fraction received
2013-07-30 18:31:12 -07:00
Brian O'Connor f7439671bc pingall now reports fraction received
fixes #168
2013-07-30 18:28:38 -07:00
Brian O'Connor 48df51aa3b Merge branch 'notrace'
fixes #166
2013-07-30 18:15:56 -07:00
Brian O'Connor 4a77702473 Merge branch 'master' of github.com:mininet/mininet 2013-07-30 18:12:15 -07:00
Brian O'Connor 15c1a0e5e7 install.sh automatically detects wireshark version and installs correct version of of-dissector
fixes #180
2013-07-30 18:11:20 -07:00
Bob Lantz 9c4b734361 Fix indentation in LinearTopo() 2013-07-30 11:52:53 -07:00
Bob Lantz 5b48a7d92c Reimplemented and corrected Graph as MultiGraph
fixes #172
2013-07-30 11:51:32 -07:00
Brian O'Connor 4316be95c2 Prevent Mininet from crashing when display not set
fixes #173
2013-07-26 14:43:27 -07:00
Brian O'Connor 19bc1df15d fixed style error 2013-07-26 13:45:56 -07:00
Brian O'Connor bda2317d8b Catching exceptions thrown in mn 2013-07-25 19:27:06 -07:00
Brandon Heller 1f07530a54 install.sh: Fix break from version overrides missing, + annotate them
D'oh!  Next time test presence _and_ absense of an added env var.

OTOH, when people notice this quickly, it means they're using install.sh :-)
2013-07-24 06:01:30 +00:00
Brian O'Connor d5f5778492 Merge branch 'master' of github.com:mininet/mininet 2013-07-23 17:05:23 -07:00
Brian O'Connor 1ecc63dfec improved check for downed link in parsePingFull
fixes #176
2013-07-23 17:03:51 -07:00
Brian O'Connor 1e4e8b70d9 Merge pull request #174 from pantuza/master
Dynamic Network with Remote Controller example; Extended LinearTopo
2013-07-22 22:14:03 -07:00
Gustavo Pantuza Coelho Pinto e45cc16a90 Merge pull request #1 from bocon13/master
Simplified and refactored examples/dynamicnet.py
2013-07-21 12:53:37 -07:00
Brian O'Connor c26b4525aa Moving developer dependencies to separate function in install.sh
Developer dependencies are ~1GB
2013-07-19 16:17:16 -07:00
Brian O'Connor ea29d2b2cd Merge pull request #171 from vitalivanov/dev
Cleanup and cosmetic changes.
2013-07-19 16:07:15 -07:00
Brian O'Connor 5559a93d8a Merge pull request #170 from piyushs/cgroup-fix
Fix issue with mountCgroups not recognizing mounted cgroup
2013-07-19 16:04:48 -07:00
Brian O'Connor 921123155a Simplified and refactored examples/dynamicnet.py
Extended LinearTopo to support mulitple hosts per switch
2013-07-19 15:56:06 -07:00
Brandon Heller 2a1f2d59ee Merge pull request #175 from daviderickson/extensibility
Extensibility Improvements
2013-07-19 13:55:33 -07:00
David Erickson 3e70b01ec5 Enable OF 1.3 switch revision choice 2013-07-19 10:32:20 -07:00
David Erickson b55527739a Enable OF dissector revision choice 2013-07-19 10:29:53 -07:00
Gustavo Pantuza Coelho Pinto bf97d21c03 Added dynamicnet.py to README file of the examples 2013-07-18 18:42:10 -07:00
Gustavo Pantuza Coelho Pinto c554987912 Merge branch 'master' of github.com:pantuza/mininet 2013-07-18 18:34:21 -07:00
Gustavo Pantuza Coelho Pinto 6f09dedfad Dynamic network creation using a remote controller
The script builds a network topology based on command line
arguments and uses a remote controller
2013-07-18 18:32:08 -07:00
Rich Lane 0a54360211 IVSSwitch: support running IVS in a namespace
This change uses the `Node.cmd` method instead of `Popen`. The `cmd` method
sends the input to a shell which may be in another namespace (if --innamespace
is in use), while `Popen` would always run in the root namespace.
2013-07-18 17:50:52 -07:00
Rich Lane 5c24263779 clean: send SIGTERM before SIGKILL
IVS needs to be sent SIGTERM so it has a chance to clean up the kernel
datapath.
2013-07-18 13:50:20 -07:00
Vitaliy Ivanov 5b609ef9e2 Adding mininet doxygen installation dependencies.
Right now after installing mininet using util/install.sh there is a problem when try to generate doc:
	make doc
	doxygen doc/doxygen.cfg
	make: doxygen: Command not found
	make: *** [doc] Error 127
Adding doxygen, doxypy and texlive-fonts-recommended packages to fix the problem.
2013-07-15 14:20:16 +02:00
Vitaliy Ivanov 36bf8ac911 mnexec.c: substituting tabs with spaces. 2013-07-15 13:17:56 +03:00
Vitaliy Ivanov efe3877e3c Fixed mininet.org url in README.md.
s/http:\/\/openflow.org\/mininet/http:\/\/mininet.org/g
2013-07-15 13:17:19 +03:00
Piyush Srivastava 433ca2ecb6 Fix issue with mountCgroups not recognizing mounted cgroup
Changed mountCgroups to use the file /proc/mounts (instead of the
current case where it uses the less reliable
(http://www.mail-archive.com/lxc-devel@lists.sourceforge.net/msg00455.html)
/etc/mtab thorugh the mount program
2013-07-13 13:31:05 -07:00
Brian O'Connor fec98e2798 Added output line to ping that is closer to ping program output 2013-07-11 11:30:12 -07:00
Brian O'Connor c188bee3e3 Fixed divide by 0 error in ping command when no packets are sent
fixes #143
2013-07-11 11:17:46 -07:00
Rich Lane 0e2cc609df tests: run all tests with OVS, IVS, and userspace switches
Each switch gets its own class so that the test results are listed separately.
2013-07-10 11:19:25 -07:00
Brian O'Connor adf391fdec Fixed install.sh script to allow Mininet to be installed from any directory (not just ~/)
Fixes #94
2013-07-09 19:23:29 -07:00
Brian O'Connor 5d529edfb1 Removing unused import in mininet/link.py 2013-07-09 16:34:02 -07:00
Brian O'Connor 59eeeadbac Style changes in mininet/node.py and removing used import in mininet/link.py 2013-07-09 16:30:29 -07:00
Brian O'Connor 7265e2e88c Merge branch 'master' of github.com:mininet/mininet 2013-07-09 15:49:57 -07:00
Brian O'Connor 5c019d2aef CPULimitedHost cleanup() calls superclass method
fixes #161
2013-07-09 15:48:48 -07:00
Bob Lantz 679a3f1915 Don't stop data network controllers twice. 2013-07-09 14:34:37 -07:00
Rich Lane 60abb34497 clean: kill ivs processes 2013-07-09 08:36:36 -07:00
Rich Lane 94ff77f2f2 clean: don't wait forever for ovsdb
This could happen if OVS was installed but not running.
2013-07-09 08:34:33 -07:00
Bob Lantz e2eb95a29f Add $ to avoid h1 matching h10 2013-07-06 14:14:25 -07:00
Bob Lantz 10be691b86 Clean up intfs in root NS, and avoid deleting HW intfs
It appears that under certain conditions, such as when a
namespace exits, both ends of a veth pair may get dumped
into the root namespace. We therefore now remove an interface
both from its home namespace and from the root namespace.
2013-07-04 19:27:57 -07:00
Bob Lantz fcdb6d8a54 Remove unneeded line. 2013-07-04 00:45:08 -07:00
Bob Lantz 32502bbd1a Add controlnet.py example. 2013-07-04 00:41:30 -07:00
Rich Lane 71ffb0028e IVSSwitch: remove namespace warnings
IVS works fine using --innamespace.
2013-07-01 16:05:52 -07:00
Rich Lane 803c0a6e22 IVSSwitch: use ovs-ofctl for dpctl functionality 2013-06-29 18:11:15 -07:00
Rich Lane 8ee4aa6de4 install.sh: add support for IVS 2013-06-28 15:01:58 -07:00
Rich Lane 91261b2757 IVSSwitch: add support for dpctl
dpctl is not included with IVS. The user will need to obtain it from the
OpenFlow reference repository.
2013-06-27 17:56:46 -07:00
Rich Lane 812c91cc9e test_hifi: use SWITCH to pick the switch class 2013-06-27 14:50:59 -07:00
Rich Lane 27da832d6d add support for the IVS virtual switch
IVS is an open source virtual switch available for download at
https://github.com/floodlight/ivs. It uses the openvswitch
kernel module.
2013-06-27 14:50:59 -07:00
Bob Lantz aa554d985d Workaround: add default dpopts='--no-slicing' to UserSwitch
This disables slicing by default but fixes bandwidth limits.
Eventually we want to enable both to work together, but for now
this enables one or the other depending on the dpopts setting.
2013-06-26 06:21:59 -07:00
Bob Lantz 804c4bbfa6 Workaround: add dpopts to UserSwitch
Currently, slicing on the user switch breaks bandwidth limits.
We don't yet have a good way of using both of them at the same time.
I'm inclined to turn off slicing by default, but I have to think
about it and also see if any one is using it...
2013-06-26 06:14:43 -07:00
Bob Lantz 1a658054ab Ensure dpid is a valid hex string in OVSSwitch 2013-06-26 05:00:30 -07:00
Bob Lantz 33e39a2471 Fix some pylint messages. 2013-06-25 20:26:06 -07:00
Bob Lantz 538a856c2f Add Switch.connected() and OVSSwitch.controllerUUIDs() 2013-06-25 20:16:25 -07:00
Bob Lantz 877e7efb5f Minor comment change and text change. 2013-06-25 19:39:53 -07:00
Bob Lantz bdd43beaf3 Clean up (and fix) OVSSwitch fast reconnect 2013-06-25 19:31:27 -07:00
Bob Lantz 307d60a0c8 Replace /etc/hostname entirely; clarify sources.list edit 2013-06-25 16:35:26 -07:00
Bob Lantz 12758046e1 Fix setDefaultRoute to work with passed parameters. 2013-06-25 12:51:43 -07:00
Bob 9aaf87c19b Fix typo. 2013-06-25 01:06:00 -06:00
Bob 400bbbac11 Update archive for 13.04 2013-06-25 01:04:45 -06:00
Bob 226eae97cb Add script completion message 2013-06-24 14:34:53 -06:00
Brandon Heller e5d7b3801d topo: make new minimal Graph object a Graph, not a DiGraph
Fixes another Graph regression relative to NetworkX.

RipL broke because the NetworkX Graph object that was used previously
for topologies is an undirected graph:

>>> import networkx as nx
>>> g=nx.Graph()
>>> g.add_edge(0,1)
>>> g[1]
{0: {}}
>>> g[0]
{1: {}}

There is a separate DiGraph object in NetworkX for directed behavior.

The minimal replacement previously implemented DiGraph behavior.

>>> from mininet.topo import Graph
>>> g2=Graph()
>>> g2.add_edge(0,1)
>>> g2[0]
[1]
>>> g2[1]
[]

This commit restores undirected graph behavior.
2013-06-20 18:51:09 -07:00
Brandon Heller 4e1630e126 topo: add __getitem__ for Graph
Commit 65c35b65 'Remove networkx dependency' broke this line from RipL:

    nodes = [n for n in self.g[name] if self.layer(n) == layer]

To work around this, RipL code would have to be changed to something
like this:

    nodes = [n for n in self.g.data[name] if self.layer(n) == layer]

...which would use an internal variable, data.

It seems cleaner to add this one little feature from NetworkX Graph objects.
2013-06-20 16:27:17 -07:00
Brandon Heller 40b13c28b8 install.sh: Make OF1.3 Netbee location cmd-line configurable
If NBEEURL is defined when running install.sh, use that location.

Enables use of a local mirror for netbee download.

Thanks to David Erickson for the code.
2013-06-20 15:57:39 -07:00
Bob Lantz 2de621cda0 "file blocks" -> "disk blocks" 2013-06-19 17:27:33 -07:00
Bob Lantz 5c5a1eae8a Use dd to zero out disk space (hopefully faster) 2013-06-19 17:26:39 -07:00
Bob Lantz 8f113b48cc vm_cleanup: add apt-get autoremove, and zero disk blocks 2013-06-19 16:58:00 -07:00
Bob Lantz 949e0b3aff Separate VM finalization as install.sh -tc 2013-06-19 16:32:54 -07:00
Bob 448ac9dcd4 Merge pull request #150 from MurphyMc/ovs_fast_reconnect
node: Make OVS switches reconnect quickly
2013-06-19 12:22:28 -07:00
Bob Lantz dd21df3ce4 Don't flush ALL routes and enable OPTIONAL default route/gw
fixes #152 hopefully
2013-06-17 17:09:54 -07:00
Bob Lantz 3484389dcd Add NAT script to examples. 2013-06-12 14:57:13 -07:00
Bob ace0977930 Merge pull request #149 from MurphyMc/ovs_userspace_v2
node: Allow OVSSwitch to run in userspace mode
2013-06-06 18:35:39 -07:00
Murphy McCauley 3df07feb11 node: Make OVS switches reconnect quickly
Ordinarily, OVS switches back off when they can't reach their controllers.
Under the type of scenarios where Mininet is used, I think this is
probably just inconvenient.  This patch set controllers to attempt to
reconnect every second.
2013-06-06 16:28:13 -07:00
Murphy McCauley 153d598df3 node: Allow OVSSwitch to run in userspace mode
This adds a datapath parameter to OVSSwitch which allows one to tell OVS to
run in userspace mode rather than kernel mode.  From the commandline, this
is --switch=ovsk,datapath=user.

Note that this makes "ovsk" and the OVSKernelSwitch alias misnomers.  Since
the default behavior is still kernel mode, this is hopefully harmless.

This is the second version of this patch, which changes the argument name
and values according to Bob's suggestion.
2013-06-06 16:23:56 -07:00
Murphy McCauley a22e2618a6 topo: Add host count param to LinearTopo
Previously, LinearTopo took one parameter (k), which controlled the number
of switches; each of these got one host.  This adds a second parameter (j),
which controls the number of hosts per switch, defaulting to 1 (as before).

This is the second version of this patch, which attempts to make the
host name generation more straightforward.
2013-06-06 16:18:04 -07:00
Brandon Heller 3582facd34 install.sh: Use newer Netbee location for OF1.3 install
The previous version (12-05-16) does not compile on Ubuntu 12.10.

Also use a local variable to reduce duplication.
2013-06-04 23:53:04 -07:00
Bob Lantz 2a079911b5 Clarify controllers.py and add RemoteController 2013-06-03 17:10:12 -07:00
Bob Lantz 5fae96eb6e Change to only split once so that cargs='--foo=1 --bar=2' works.
fixes #144
2013-06-03 15:37:56 -07:00
Bob Lantz e3d07bc1a0 Add 'x' command to open an X11 tunnel (and run a client)
fixes #142
2013-05-28 22:10:27 -07:00
Bob f53866d0c0 Merge pull request #140 from fasaxc/patch-1
Fix method name mismatch for setDefaultRoute. 
This seems to be logically correct according to the intention of the code, but it may cause some trouble because routes will now be flushed by Mininet.configHosts().
2013-05-23 15:38:41 -07:00
Shaun Crampton e5754ae96f Fix method name mismatch for setDefaultRoute. 2013-05-23 14:31:27 -06:00
Bob Lantz 294bbad407 Display usage information if there are extra arguments
Fixes #130
2013-05-22 18:04:35 -07:00
Bob 83e43a42d9 Merge pull request #135 from adferguson/adf-vm-script-fix
tiny fix to vm script
2013-05-22 16:02:43 -07:00
Bob Lantz 2485d57f66 Edits to pass code check and make style consistent. 2013-05-22 15:40:12 -07:00
ryanc 65c35b6595 Remove networkx dependency
Conflicts:

	util/install.sh

closes #100
2013-05-22 15:24:22 -07:00
Bob Lantz 1ea5c91fcc Update host's IP address during name-IP substitution
fixes #139
2013-05-22 15:06:10 -07:00
Bob Lantz 76c5b9d021 Add ovs-controller to shutdown list 2013-05-22 15:03:48 -07:00
Bob Lantz 229f112ff3 Change OVSSwitch.dpctl() to call ovs-ofctl
This should fix the problem of dump-flows not showing the OpenFlow
flow table flows and only showing cached kernel flow table flows.

fixes #136
2013-04-29 14:04:46 -07:00
Andrew Ferguson fae4365983 actually, drop comment as per Bob Lantz 2013-04-26 13:11:39 -04:00
Andrew Ferguson e7f45ca90e tiny fix to vm script 2013-04-25 13:22:46 -04:00
Andrew Ferguson 3236d33b6a allow user switch to be used with TCIntf's 2013-04-21 15:47:37 -04:00
Ryan Cox 898efb69a3 Added markdown formatting to examples readme 2013-03-07 17:54:08 -08:00
107 changed files with 12134 additions and 1723 deletions
+19
View File
@@ -0,0 +1,19 @@
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,
please use the documentation at docs.mininet.org, the FAQ
at faq.mininet.org, and the mininet-discuss mailing list.
For bug reports, please fill in the following information in detail,
and also feel free to include additional information such as debug
output from mn -v debug, etc.
--- Cut Here ---
### Expected/Desired Behavior:
### Actual Behavior:
### Detailed Steps to Reproduce the Behavior:
### Additional Information:
+14 -8
View File
@@ -41,16 +41,21 @@ 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).
disable=W0704,C0103,W0231,E1102,W0511,W0142,R0902,R0903,R0904,R0913,R0914,R0801,I0011
disable=pointless-except, invalid-name, super-init-not-called, fixme, star-args,
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, wrong-import-order
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html
output-format=colorized
msg-template='{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}'
# Include message's id in outpu
# Include message's id in output
include-ids=yes
# Put messages in a separate file for each module / package specified on the
@@ -58,7 +63,7 @@ include-ids=yes
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells wether to display a full report or only the messages
# Tells whether to display a full report or only the messages
reports=no
# Python expression which should return a note less than 10 (10 is the highes
@@ -108,10 +113,10 @@ const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
function-rgx=[a-z_][a-z0-9]{2,30}$
# Regular expression which should only match correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$
method-rgx=[a-z_][a-z0-9]{2,30}$
# Regular expression which should only match correct instance attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
@@ -120,7 +125,7 @@ attr-rgx=[a-z_][a-z0-9_]{2,30}$
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
variable-rgx=[a-z_][a-z0-9]{2,30}$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
@@ -191,7 +196,7 @@ additional-builtins=
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
defining-attr-methods=__init__,__new__,setUp,build
# checks for sign of poor/misdesign:
@@ -264,7 +269,8 @@ int-import-graph=
max-line-length=80
# Maximum number of lines in a module
max-module-lines=1500
# XXX 1500 -> 4000 for miniedit.py
max-module-lines=4000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
+35
View File
@@ -0,0 +1,35 @@
language: python
sudo: required
matrix:
include:
- dist: trusty
python: 2.7
env: dist="14.04 LTS trusty"
- dist: trusty
python: 3.6
env: dist="14.04 LTS trusty"
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq vlan
- PYTHON=`which python` util/install.sh -n
install:
- bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi"
- pip install pexpect || pip3 install pexpect
- util/install.sh -nfvw
script:
- alias sudo="sudo env PATH=$PATH"
- export PYTHON=`which python`
- echo 'px import sys; print(sys.version_info)' | sudo $PYTHON bin/mn -v output
- sudo $PYTHON bin/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
+52
View File
@@ -0,0 +1,52 @@
Mininet Contributors
Mininet is an open source project and we gratefully acknowledge
the many contributions to the project! If you have contributed
code into the project and are not on this list, please let us know
or send a pull request.
Contributors include:
Mininet Core Team (and alumni)
Bob Lantz
Brandon Heller
Nikhil Handigol
Vimal Jeyakumar
Brian O'Connor
Cody Burkard
Additional Mininet Contributors
Tomasz Buchert
Gustavo Pantuza Coelho Pinto
Fernando Cappi
Ryan Cox
Shaun Crampton
David Erickson
Glen Gibb
Andrew Ferguson
Eder Leao Fernandes
Gregory Gee
Jon Hall
Roan Huang
Vitaly Ivanov
Babis Kaidos
Rich Lane
Rémy Léone
Zi Shen Lim
David Mahler
Murphy McCauley
José Pedro Oliveira
James Page
Angad Singh
Piyush Srivastava
Ed Swierk
Darshan Thaker
Andreas Wundsam
Isaku Yamahata
Baohua Yang
Thanks also to everyone who has submitted issues and pull
requests on github, and to our friendly mininet-discuss
mailing list!
+72 -16
View File
@@ -2,7 +2,7 @@
Mininet Installation/Configuration Notes
----------------------------------------
Mininet 2.0.0
Mininet 2.3.0d4
---
The supported installation methods for Mininet are 1) using a
@@ -15,7 +15,7 @@ like to contribute an installation script, we would welcome it!)
1. Easiest "installation" - use our pre-built VM image!
The easiest way to get Mininet running is to start with one of our
pre-built virtual machine images from <http://openflow.org/mininet>
pre-built virtual machine images from <http://mininet.org/>
Boot up the VM image, log in, and follow the instructions on the
Mininet web site.
@@ -42,21 +42,38 @@ like to contribute an installation script, we would welcome it!)
sudo rm /usr/local/bin/ovs*
sudo rm /usr/local/sbin/ovs*
3. Native installation from source on Ubuntu 11.10+
3. Native installation from source
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:
git clone git://github.com/mininet/mininet.git
If you are running Ubuntu, you may be able to use our handy
`install.sh` script, which is in `mininet/util`.
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
cd mininet
git tag
and then
git checkout <release tag>
where <release tag> is the release you want to check out.
If you are running Ubuntu, Debian, or Fedora, you may be able to use
our handy `install.sh` script, which is in `util/`.
*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`, or `noxcosre`.
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.
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!
@@ -64,7 +81,7 @@ like to contribute an installation script, we would welcome it!)
To install Mininet itself, the OpenFlow reference implementation, and
Open vSwitch, you may use:
mininet/util/install.sh -fnv
util/install.sh -fnv
This should be reasonably quick, and the following command should
work after the installation:
@@ -73,14 +90,55 @@ like to contribute an installation script, we would welcome it!)
To install ALL of the software which we use for OpenFlow tutorials,
including POX, the OpenFlow WireShark dissector, the `oftest`
framework, and other potentially useful software (and to add some
stuff to `/etc/sysctl.conf` which may or may not be useful) you may
use:
framework, and other potentially useful software, you may use:
mininet/util/install.sh -a
util/install.sh -a
This takes about 4 minutes on our test system.
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:
* install git
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
* install Mininet, the OpenFlow reference implementation, and
Open vSwitch
util/install.sh -fnv
* enable and start openvswitch
sudo systemctl enable openvswitch
sudo systemctl start openvswitch
* test the mininet installation
sudo mn --test pingall
4. Creating your own Mininet/OpenFlow tutorial VM
Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial
@@ -103,12 +161,10 @@ like to contribute an installation script, we would welcome it!)
* A Linux kernel compiled with network namespace support enabled
* An OpenFlow implementation (either the reference user or kernel
space implementations, or Open vSwitch.) Appropriate kernel
modules (e.g. tun and ofdatapath for the reference kernel
implementation) must be loaded.
* An compatible software switch such as Open vSwitch or
the Linux bridge.
* Python, `bash`, `ping`, `iperf`, etc.`
* Python, `bash`, `ping`, `iperf`, etc.
* Root privileges (required for network device access)
+2 -2
View File
@@ -1,6 +1,6 @@
Mininet 2.0.0 License
Mininet 2.3.0d4 License
Copyright (c) 2012 Open Networking Laboratory
Copyright (c) 2013-2018 Open Networking Laboratory
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
The Leland Stanford Junior University
+30 -15
View File
@@ -1,17 +1,22 @@
MININET = mininet/*.py
TEST = mininet/test/*.py
EXAMPLES = examples/*.py
EXAMPLES = mininet/examples/*.py
MN = bin/mn
PYTHON ?= python
PYMN = $(PYTHON) -B bin/mn
BIN = $(MN)
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
MNEXEC = mnexec
MANPAGES = mn.1 mnexec.1
P8IGN = E251,E201,E302,E202
BINDIR = /usr/bin
MANDIR = /usr/share/man/man1
P8IGN = E251,E201,E302,E202,E126,E127,E203,E226
PREFIX ?= /usr
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man/man1
DOCDIRS = doc/html doc/latex
PDF = doc/latex/refman.pdf
CFLAGS += -Wall -Wextra
all: codecheck test
clean:
@@ -22,7 +27,8 @@ codecheck: $(PYSRC)
util/versioncheck.py
pyflakes $(PYSRC)
pylint --rcfile=.pylint $(PYSRC)
pep8 --repeat --ignore=$(P8IGN) $(PYSRC)
# Exclude miniedit from pep8 checking for now
pep8 --repeat --ignore=$(P8IGN) `ls $(PYSRC) | grep -v miniedit.py`
errcheck: $(PYSRC)
-echo "Running check for errors only"
@@ -34,29 +40,38 @@ test: $(MININET) $(TEST)
mininet/test/test_nets.py
mininet/test/test_hifi.py
mnexec: mnexec.c $(MN) mininet/net.py
cc $(CFLAGS) $(LDFLAGS) -DVERSION=\"`PYTHONPATH=. $(MN) --version`\" $< -o $@
slowtest: $(MININET)
-echo "Running slower tests (walkthrough, examples)"
mininet/test/test_walkthrough.py -v
mininet/examples/test/runner.py -v
install: $(MNEXEC) $(MANPAGES)
install $(MNEXEC) $(BINDIR)
install $(MANPAGES) $(MANDIR)
python setup.py install
mnexec: mnexec.c $(MN) mininet/net.py
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
$(PYTHON) setup.py install
develop: $(MNEXEC) $(MANPAGES)
# Perhaps we should link these as well
# Perhaps we should link these as well
install $(MNEXEC) $(BINDIR)
install $(MANPAGES) $(MANDIR)
python setup.py develop
$(PYTHON) setup.py develop
man: $(MANPAGES)
mn.1: $(MN)
PYTHONPATH=. help2man -N -n "create a Mininet network." \
--no-discard-stderr $< -o $@
--no-discard-stderr "$(PYMN)" -o $@
mnexec.1: mnexec
help2man -N -n "execution utility for Mininet." \
-h "-h" -v "-v" --no-discard-stderr ./$< -o $@
-h "-h" -v "-v" --no-discard-stderr ./$< -o $@
.PHONY: doc
+34 -36
View File
@@ -1,10 +1,10 @@
Mininet: Rapid Prototyping for Software Defined Networks
========================================================
*The best way to emulate almost any network on your laptop!*
Version 2.0.0
Mininet 2.3.0d4
[![Build Status][1]](https://travis-ci.org/mininet/mininet)
### What is Mininet?
@@ -67,32 +67,27 @@ Mininet includes:
`mn -c`
### New features in 2.0.0
### New features in this release
Mininet 2.0.0 is a major upgrade and provides
a number of enhancements and new features, including:
This is primarily a performance improvement and bug fix release.
* "Mininet-HiFi" functionality:
- Batch startup has been implemented for Open vSwitch, improving
startup performance.
* Link bandwidth limits using `tc` (`TCIntf` and `TCLink` classes)
- OVS patch links have been implemented via OVSLink and --link ovs
* CPU isolation and bandwidth limits (`CPULimitedHost` class)
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.
* Support for Open vSwitch 1.4+ (including Ubuntu OVS packages)
- You can now easily install Mininet on a Raspberry Pi ;-)
* Debian packaging (and `apt-get install mininet` in Ubuntu 12.10)
* First-class Interface (`Intf`) and Link (`Link`) classes for easier
extensibility
* An upgraded Topology (`Topo`) class which supports node and link
customization
* Man pages for the `mn` and `mnexec` utilities.
[Since the API (most notably the topology) has changed, existing code
that runs in Mininet 1.0 will need to be changed to run with Mininet
2.0. This is the primary reason for the major version number change.]
- Additional information for this release and previous releases
may be found in the release notes on docs.mininet.org
### Installation
@@ -103,7 +98,7 @@ See `INSTALL` for installation instructions and details.
In addition to the API documentation (`make doc`), much useful
information, including a Mininet walkthrough and an introduction
to the Python API, is available on the
[Mininet Web Site](http://openflow.org/mininet).
[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.)
@@ -114,21 +109,24 @@ Mininet mailing list, `mininet-discuss` at:
<https://mailman.stanford.edu/mailman/listinfo/mininet-discuss>
### Contributing
### Join Us
Mininet is an open-source project and is currently hosted at
<https://github.com/mininet>. You are encouraged to download the code,
examine it, modify it, and submit bug reports, bug fixes, feature
requests, and enhancements!
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
the code, examine it, modify it, and submit bug reports, bug fixes,
feature requests, new features and other issues and pull requests.
Thanks to everyone who has contributed code to the Mininet project
(see CONTRIBUTORS for more info!) It is because of everyone's
hard work that Mininet continues to grow and improve.
### Enjoy Mininet
Best wishes, and we look forward to seeing what you can do with
Mininet to change the networking world!
### Credits
Bob Lantz
Mininet Core Team
The Mininet Team:
* Bob Lantz
* Brandon Heller
* Nikhil Handigol
* Vimal Jeyakumar
[1]: https://travis-ci.org/mininet/mininet.svg?branch=master
+268 -111
View File
@@ -21,83 +21,141 @@ if 'PYTHONPATH' in os.environ:
sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
from mininet.clean import cleanup
from mininet.cli import CLI
from mininet.log import lg, LEVELS, info
import mininet.cli
from mininet.log import lg, LEVELS, info, debug, warn, error, output
from mininet.net import Mininet, MininetWithControlNet, VERSION
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
NOX, RemoteController, UserSwitch, OVSKernelSwitch,
OVSLegacyKernelSwitch )
from mininet.link import Link, TCLink
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
from mininet.topolib import TreeTopo
from mininet.util import custom, customConstructor
Ryu, NOX, RemoteController, findController,
DefaultController, NullController,
UserSwitch, OVSSwitch, OVSBridge,
IVSSwitch )
from mininet.nodelib import LinuxBridge
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
from mininet.util import buildTopo
from functools import partial
# Experimental! cluster edition prototype
from mininet.examples.cluster import ( MininetCluster, RemoteHost,
RemoteOVSSwitch, RemoteLink,
SwitchBinPlacer, RandomPlacer,
ClusterCleanup )
from mininet.examples.clustercli import ClusterCLI
PLACEMENT = { 'block': SwitchBinPlacer, 'random': RandomPlacer }
# built in topologies, created only when run
TOPODEF = 'minimal'
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
TOPOS = { 'minimal': MinimalTopo,
'linear': LinearTopo,
'reversed': SingleSwitchReversedTopo,
'single': SingleSwitchTopo,
'tree': TreeTopo }
'tree': TreeTopo,
'torus': TorusTopo }
SWITCHDEF = 'ovsk'
SWITCHDEF = 'default'
SWITCHES = { 'user': UserSwitch,
'ovsk': OVSKernelSwitch,
'ovsl': OVSLegacyKernelSwitch }
'ovs': OVSSwitch,
'ovsbr' : OVSBridge,
# Keep ovsk for compatibility with 2.0
'ovsk': OVSSwitch,
'ivs': IVSSwitch,
'lxbr': LinuxBridge,
'default': OVSSwitch }
HOSTDEF = 'proc'
HOSTS = { 'proc': Host,
'rt': custom( CPULimitedHost, sched='rt' ),
'cfs': custom( CPULimitedHost, sched='cfs' ) }
'rt': specialClass( CPULimitedHost, defaults=dict( sched='rt' ) ),
'cfs': specialClass( CPULimitedHost, defaults=dict( sched='cfs' ) ) }
CONTROLLERDEF = 'ovsc'
CONTROLLERDEF = 'default'
CONTROLLERS = { 'ref': Controller,
'ovsc': OVSController,
'nox': NOX,
'remote': RemoteController,
'none': lambda name: None }
'ryu': Ryu,
'default': DefaultController, # Note: overridden below
'none': NullController }
LINKDEF = 'default'
LINKS = { 'default': Link,
'tc': TCLink }
LINKS = { 'default': Link, # Note: overridden below
'tc': TCLink,
'tcu': TCULink,
'ovs': OVSLink }
# TESTS dict can contain functions and/or Mininet() method names
# XXX: it would be nice if we could specify a default test, but
# this may be tricky
TESTS = { name: True
for name in ( 'pingall', 'pingpair', 'iperf', 'iperfudp' ) }
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()
def nullTest( _net ):
"Null 'test' (does nothing)"
pass
TESTS.update( all=allTest, none=nullTest, build=nullTest )
# Map to alternate spellings of Mininet() methods
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
'iperfudp': 'iperfUdp' }
def runTests( mn, options ):
"""Run tests
mn: Mininet object
option: list of test optinos """
# Split option into test name and parameters
for option in options:
# Multiple tests may be separated by '+' for now
for test in option.split( '+' ):
test, args, kwargs = splitArgs( test )
test = ALTSPELLING.get( test.lower(), test )
testfn = TESTS.get( test, test )
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 '
'%s ' % ( test, TESTS.keys() ) )
# optional tests to run
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
'none' ]
ALTSPELLING = { 'pingall': 'pingAll',
'pingpair': 'pingPair',
'iperfudp': 'iperfUdp',
'iperfUDP': 'iperfUdp' }
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
def addDictOption( opts, choicesDict, default, name, **kwargs ):
"""Convenience function to add choices dicts to OptionParser.
opts: OptionParser instance
choicesDict: dictionary of valid choices, must include default
default: default choice key
name: long option name
help: string"""
if default not in choicesDict:
raise Exception( 'Invalid default %s for choices dict: %s' %
( default, name ) )
if not helpStr:
helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
'[,param=value...]' )
opts.add_option( '--' + name,
type='string',
default = default,
help = helpStr )
kwargs: additional arguments to add_option"""
helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
'[,param=value...]' )
helpList = [ '%s=%s' % ( k, v.__name__ )
for k, v in choicesDict.items() ]
helpStr += ' ' + ( ' '.join( helpList ) )
params = dict( type='string', default=default, help=helpStr )
params.update( **kwargs )
opts.add_option( '--' + name, **params )
def version( *_args ):
"Print Mininet version and exit"
print "%s" % VERSION
output( "%s\n" % VERSION )
exit()
class MininetRunner( object ):
"Build, setup, and run Mininet."
@@ -111,9 +169,35 @@ class MininetRunner( object ):
self.setup()
self.begin()
def custom( self, _option, _opt_str, value, _parser ):
"""Parse custom file and add params.
option: option e.g. --custom
opt_str: option string e.g. --custom
value: the value the follows the option
parser: option parser instance"""
files = []
if os.path.isfile( value ):
# Accept any single file (including those with commas)
files.append( value )
else:
# Accept a comma-separated list of filenames
files += value.split(',')
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():
self.setCustom( name, val )
else:
raise Exception( 'could not find custom file: %s' % fileName )
def setCustom( self, name, value ):
"Set custom parameters for MininetRunner."
if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
if name in ( 'topos', 'switches', 'hosts', 'controllers', 'links'
'testnames', 'tests' ):
# Update dictionaries
param = name.upper()
globals()[ param ].update( value )
@@ -124,26 +208,23 @@ class MininetRunner( object ):
# Add or modify global variable or class
globals()[ name ] = value
def parseCustomFile( self, fileName ):
"Parse custom file and add params before parsing cmd-line options."
customs = {}
if os.path.isfile( fileName ):
execfile( fileName, customs, customs )
for name, val in customs.iteritems():
self.setCustom( name, val )
def setNat( self, _option, opt_str, value, parser ):
"Set NAT option(s)"
assert self # satisfy pylint
parser.values.nat = True
# first arg, first char != '-'
if parser.rargs and parser.rargs[ 0 ][ 0 ] != '-':
value = parser.rargs.pop( 0 )
_, args, kwargs = splitArgs( opt_str + ',' + value )
parser.values.nat_args = args
parser.values.nat_kwargs = kwargs
else:
raise Exception( 'could not find custom file: %s' % fileName )
parser.values.nat_args = []
parser.values.nat_kwargs = {}
def parseArgs( self ):
"""Parse command-line args and return options object.
returns: opts parse options dict"""
if '--custom' in sys.argv:
index = sys.argv.index( '--custom' )
if len( sys.argv ) > index + 1:
filename = sys.argv[ index + 1 ]
self.parseCustomFile( filename )
else:
raise Exception( 'Custom file name not found' )
desc = ( "The %prog utility creates Mininet network from the\n"
"command line. It can create parametrized topologies,\n"
@@ -155,18 +236,19 @@ class MininetRunner( object ):
opts = OptionParser( description=desc, usage=usage )
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
addDictOption( opts, CONTROLLERS, [], 'controller', action='append' )
addDictOption( opts, LINKS, LINKDEF, 'link' )
addDictOption( opts, TOPOS, TOPODEF, 'topo' )
opts.add_option( '--clean', '-c', action='store_true',
default=False, help='clean and exit' )
opts.add_option( '--custom', type='string', default=None,
help='read custom topo and node params from .py' +
'file' )
opts.add_option( '--test', type='choice', choices=TESTS,
default=TESTS[ 0 ],
help='|'.join( TESTS ) )
opts.add_option( '--custom', action='callback',
callback=self.custom,
type='string',
help='read custom classes or params from .py file(s)'
)
opts.add_option( '--test', default=[], action='append',
dest='test', help='|'.join( TESTS.keys() ) )
opts.add_option( '--xterms', '-x', action='store_true',
default=False, help='spawn xterms for each node' )
opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
@@ -176,11 +258,11 @@ 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=LEVELS.keys(), default = 'info',
choices=list( LEVELS.keys() ), default = 'info',
help = '|'.join( LEVELS.keys() ) )
opts.add_option( '--innamespace', action='store_true',
default=False, help='sw and ctrl in namespace?' )
opts.add_option( '--listenport', type='int', default=6634,
opts.add_option( '--listenport', type='int', default=6654,
help='base port for passive switch listening' )
opts.add_option( '--nolistenport', action='store_true',
default=False, help="don't use passive listening " +
@@ -192,79 +274,137 @@ class MininetRunner( object ):
opts.add_option( '--pin', action='store_true',
default=False, help="pin hosts to CPU cores "
"(requires --host cfs or --host rt)" )
opts.add_option( '--version', action='callback', callback=version )
opts.add_option( '--nat', action='callback', callback=self.setNat,
help="[option=val...] adds a NAT to the topology that"
" connects Mininet hosts to the physical network."
" Warning: This may route any traffic on the machine"
" that uses Mininet's"
" IP subnet into the Mininet network."
" If you need to change"
" 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( '--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',
metavar='block|random',
help=( 'node placement for --cluster '
'(experimental!) ' ) )
self.options, self.args = opts.parse_args()
# We don't accept extra arguments after the options
if self.args:
opts.print_help()
exit()
def setup( self ):
"Setup and validate environment."
# set logging verbosity
if LEVELS[self.options.verbosity] > LEVELS['output']:
print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
warn( '*** WARNING: selected verbosity level (%s) will hide CLI '
'output!\n'
'Please restart Mininet with -v [debug, info, output].'
'Please restart Mininet with -v [debug, info, output].\n'
% self.options.verbosity )
lg.setLogLevel( self.options.verbosity )
# Maybe we'll reorganize this someday...
# pylint: disable=too-many-branches,too-many-statements,global-statement
def begin( self ):
"Create and run mininet."
if self.options.clean:
global CLI
opts = self.options
if opts.cluster:
servers = opts.cluster.split( ',' )
for server in servers:
ClusterCleanup.add( server )
if opts.clean:
cleanup()
exit()
start = time.time()
topo = buildTopo( TOPOS, self.options.topo )
switch = customConstructor( SWITCHES, self.options.switch )
host = customConstructor( HOSTS, self.options.host )
controller = customConstructor( CONTROLLERS, self.options.controller )
link = customConstructor( LINKS, self.options.link )
if not opts.controller:
# Update default based on available controllers
CONTROLLERS[ 'default' ] = findController()
opts.controller = [ 'default' ]
if not CONTROLLERS[ 'default' ]:
opts.controller = [ 'none' ]
if opts.switch == 'default':
info( '*** No default OpenFlow controller found '
'for default switch!\n' )
info( '*** Falling back to OVS Bridge\n' )
opts.switch = 'ovsbr'
elif opts.switch not in ( 'ovsbr', 'lxbr' ):
raise Exception( "Could not find a default controller "
"for switch %s" %
opts.switch )
topo = buildTopo( TOPOS, opts.topo )
switch = customClass( SWITCHES, opts.switch )
host = customClass( HOSTS, opts.host )
controller = [ customClass( CONTROLLERS, c )
for c in opts.controller ]
if opts.switch == 'user' and opts.link == 'default':
debug( '*** Using TCULink with UserSwitch\n' )
# Use link configured correctly for UserSwitch
opts.link = 'tcu'
link = customClass( LINKS, opts.link )
if self.validate:
self.validate( self.options )
self.validate( opts )
if opts.nolistenport:
opts.listenport = None
# Handle innamespace, cluster options
if opts.innamespace and opts.cluster:
error( "Please specify --innamespace OR --cluster\n" )
exit()
Net = MininetWithControlNet if opts.innamespace else Mininet
if opts.cluster:
warn( '*** WARNING: Experimental cluster mode!\n'
'*** Using RemoteHost, RemoteOVSSwitch, RemoteLink\n' )
host, switch, link = RemoteHost, RemoteOVSSwitch, RemoteLink
Net = partial( MininetCluster, servers=servers,
placement=PLACEMENT[ opts.placement ] )
mininet.cli.CLI = ClusterCLI
inNamespace = self.options.innamespace
Net = MininetWithControlNet if inNamespace else Mininet
ipBase = self.options.ipbase
xterms = self.options.xterms
mac = self.options.mac
arp = self.options.arp
pin = self.options.pin
listenPort = None
if not self.options.nolistenport:
listenPort = self.options.listenport
mn = Net( topo=topo,
switch=switch, host=host, controller=controller,
link=link,
ipBase=ipBase,
inNamespace=inNamespace,
xterms=xterms, autoSetMacs=mac,
autoStaticArp=arp, autoPinCpus=pin,
listenPort=listenPort )
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,
listenPort=opts.listenport )
if self.options.pre:
CLI( mn, script=self.options.pre )
if opts.ensure_value( 'nat', False ):
mn.addNAT( *opts.nat_args, **opts.nat_kwargs ).configDefault()
test = self.options.test
test = ALTSPELLING.get( test, test )
# --custom files can set CLI or change mininet.cli.CLI
CLI = mininet.cli.CLI if CLI is None else CLI
if opts.pre:
CLI( mn, script=opts.pre )
mn.start()
if test == 'none':
pass
elif test == 'all':
mn.start()
mn.ping()
mn.iperf()
elif test == 'cli':
if opts.test:
runTests( mn, opts.test )
else:
CLI( mn )
elif test != 'build':
getattr( mn, test )()
if self.options.post:
CLI( mn, script=self.options.post )
if opts.post:
CLI( mn, script=opts.post )
mn.stop()
@@ -273,4 +413,21 @@ class MininetRunner( object ):
if __name__ == "__main__":
MininetRunner()
try:
MininetRunner()
except KeyboardInterrupt:
info( "\n\nKeyboard Interrupt. Shutting down and cleaning up...\n\n")
cleanup()
except Exception:
# Print exception
type_, val_, trace_ = sys.exc_info()
errorMsg = ( "-"*80 + "\n" +
"Caught exception. Cleaning up...\n\n" +
"%s: %s\n" % ( type_.__name__, val_ ) +
"-"*80 + "\n" )
error( errorMsg )
# Print stack trace to debug log
import traceback
stackTrace = traceback.format_exc()
debug( stackTrace + "\n" )
cleanup()
+20
View File
@@ -1,3 +1,23 @@
mininet (2.1.0-0ubuntu1) saucy; urgency=low
* Add 2.1.0 final packaging
-- Bob Lantz <rlantz@cs.stanford.edu> Wed, 18 Sep 2013 22:43:47 -0700
mininet (2.1.0~rc1-0ubuntu1) saucy; urgency=low
* New upstream release candidate:
- d/control: Drop dependency on python-networkx, add iperf, socat
and cgroup-bin to Depends.
-- James Page <james.page@ubuntu.com> Wed, 28 Aug 2013 10:10:20 +0100
mininet (2.0.0-0ubuntu1) raring; urgency=low
* New upstream release.
-- James Page <james.page@ubuntu.com> Wed, 19 Dec 2012 15:48:01 +0000
mininet (2.0.0~rc1-0ubuntu1) quantal; urgency=low
* New upstream release.
+5 -4
View File
@@ -9,20 +9,21 @@ Build-Depends:
help2man,
python-dev,
python-pkg-resources,
python-setuptools,
python-networkx
python-setuptools
Homepage: http://openflow.org/mininet
Package: mininet
Architecture: any
Depends:
openvswitch-switch,
python-networkx,
telnet,
socat,
iperf,
cgroup-bin,
${misc:Depends},
${python:Depends},
${shlibs:Depends}
Recommends: iperf, openvswitch-controller, socat
Recommends: openvswitch-controller
Description: Process-based network emulator
Mininet is a network emulator which uses lightweight
virtualization to create virtual networks for rapid
+1 -1
View File
@@ -3,7 +3,7 @@ Upstream-Name: mininet
Source: https://github.com/mininet/mininet
Files: *
Copyright: 2012 Open Networking Laboratory,
Copyright: 2012-2013 Open Networking Laboratory,
2009-2012 Bob Lantz,
2009-2012 The Board of Trustees of the Leland Stanford Junior
University
-109
View File
@@ -1,109 +0,0 @@
Mininet Examples
These examples are intended to help you get started using
Mininet's Python API.
---
baresshd.py:
This example uses Mininet's medium-level API to create an sshd
process running in a namespace. Doesn't use OpenFlow.
consoles.py:
This example creates a grid of console windows, one for each node,
and allows interaction with and monitoring of each console, including
graphical monitoring.
controllers.py:
This example creates a network with multiple controllers, by
using a custom Switch() subclass.
controllers2.py:
This example creates a network with multiple controllers by
creating an empty network, adding nodes to it, and manually
starting the switches.
cpu.py:
This example tests iperf bandwidth for varying CPU limits.
emptynet.py:
This example demonstrates creating an empty network (i.e. with no
topology object) and adding nodes to it.
hwintf.py:
This example shows how to add an interface (for example a real
hardware interface) to a network after the network is created.
limit.py:
This example shows how to use link and CPU limits.
linearbandwidth.py:
This example shows how to create a custom topology programatically
by subclassing Topo, and how to run a series of tests on it.
miniedit.py:
This example demonstrates creating a network via a graphical editor.
multiping.py:
This example demonstrates one method for
monitoring output from multiple hosts, using node.monitor().
multipoll.py:
This example demonstrates monitoring output files from multiple hosts.
multitest.py:
This example creates a network and runs multiple tests on it.
popen.py:
This example monitors a number of hosts using host.popen() and
pmonitor().
popenpoll.py:
This example demonstrates monitoring output from multiple hosts using
the node.popen() interface (which returns Popen objects) and pmonitor().
scratchnet.py, scratchnetuser.py:
These two examples demonstrate how to create a network by using the lowest-
level Mininet functions. Generally the higher-level API is easier to use,
but scratchnet shows what is going on behind the scenes.
simpleperf.py:
A simple example of configuring network and CPU bandwidth limits.
sshd.py:
This example shows how to run an sshd process in each host, allowing
you to log in via ssh. This requires connecting the Mininet data network
to an interface in the root namespace (generaly the control network
already lives in the root namespace, so it does not need to be explicitly
connected.)
treeping64.py:
This example creates a 64-host tree network, and attempts to check full
connectivity using ping, for different switch/datapath types.
tree1024.py:
This example attempts to create a 1024-host network, and then runs the
CLI on it. It may run into scalability limits, depending on available
memory and sysctl configuration (see INSTALL.)
+179
View File
@@ -0,0 +1,179 @@
Mininet Examples
========================================================
These examples are intended to help you get started using
Mininet's Python API.
========================================================
#### baresshd.py:
This example uses Mininet's medium-level API to create an sshd
process running in a namespace. Doesn't use OpenFlow.
#### bind.py:
This example shows how you can create private directories for each
node in a Mininet topology.
#### cluster.py:
This example contains all of the code for experimental cluster
edition. Remote classes and MininetCluster can be imported from
here to create a topology with nodes on remote machines.
#### clusterSanity.py:
This example runs cluster edition locally as a sanity check to test
basic functionality.
#### clustercli.py:
This example contains a CLI for experimental cluster edition.
#### clusterdemo.py:
This example is a basic demo of cluster edition on 3 servers with
a tree topology of depth 3 and fanout 3.
#### consoles.py:
This example creates a grid of console windows, one for each node,
and allows interaction with and monitoring of each console, including
graphical monitoring.
#### controllers.py:
This example creates a network with multiple controllers, by
using a custom `Switch()` subclass.
#### controllers2.py:
This example creates a network with multiple controllers by
creating an empty network, adding nodes to it, and manually
starting the switches.
#### controlnet.py:
This examples shows how you can model the control network as well
as the data network, by actually creating two Mininet objects.
#### cpu.py:
This example tests iperf bandwidth for varying CPU limits.
#### emptynet.py:
This example demonstrates creating an empty network (i.e. with no
topology object) and adding nodes to it.
#### hwintf.py:
This example shows how to add an interface (for example a real
hardware interface) to a network after the network is created.
#### intfoptions.py:
This example reconfigures a TCIntf during runtime with different
traffic control commands to test bandwidth, loss, and delay.
#### limit.py:
This example shows how to use link and CPU limits.
#### linearbandwidth.py:
This example shows how to create a custom topology programatically
by subclassing Topo, and how to run a series of tests on it.
#### linuxrouter.py:
This example shows how to create and configure a router in Mininet
that uses Linux IP forwarding.
#### miniedit.py:
This example demonstrates creating a network via a graphical editor.
#### mobility.py:
This example demonstrates detaching an interface from one switch and
attaching it another as a basic way to move a host around a network.
#### multiLink.py:
This example demonstrates the creation of multiple links between
nodes using a custom Topology class.
#### multiping.py:
This example demonstrates one method for
monitoring output from multiple hosts, using `node.monitor()`.
#### multipoll.py:
This example demonstrates monitoring output files from multiple hosts.
#### multitest.py:
This example creates a network and runs multiple tests on it.
#### nat.py:
This example shows how to connect a Mininet network to the Internet
using NAT. It also answers the eternal question "why can't I ping
`google.com`?"
#### natnet.py:
This example demonstrates how to create a network using a NAT node
to connect hosts to the internet.
#### numberedports.py:
This example verifies the mininet ofport numbers match up to the ovs port numbers.
It also verifies that the port numbers match up to the interface numbers
#### popen.py:
This example monitors a number of hosts using `host.popen()` and
`pmonitor()`.
#### popenpoll.py:
This example demonstrates monitoring output from multiple hosts using
the `node.popen()` interface (which returns `Popen` objects) and `pmonitor()`.
#### scratchnet.py, scratchnetuser.py:
These two examples demonstrate how to create a network by using the lowest-
level Mininet functions. Generally the higher-level API is easier to use,
but scratchnet shows what is going on behind the scenes.
#### simpleperf.py:
A simple example of configuring network and CPU bandwidth limits.
#### sshd.py:
This example shows how to run an `sshd` process in each host, allowing
you to log in via `ssh`. This requires connecting the Mininet data network
to an interface in the root namespace (generaly the control network
already lives in the root namespace, so it does not need to be explicitly
connected.)
#### tree1024.py:
This example attempts to create a 1024-host network, and then runs the
CLI on it. It may run into scalability limits, depending on available
memory and `sysctl` configuration (see `INSTALL`.)
#### treeping64.py:
This example creates a 64-host tree network, and attempts to check full
connectivity using `ping`, for different switch/datapath types.
#### vlanhost.py:
An example of how to subclass Host to use a VLAN on its primary interface.
+4
View File
@@ -0,0 +1,4 @@
"""
Mininet Examples
See README for details
"""
+23 -9
View File
@@ -2,31 +2,45 @@
"This example doesn't use OpenFlow, but attempts to run sshd in a namespace."
import sys
from mininet.node import Host
from mininet.util import ensureRoot
from mininet.util import ensureRoot, waitListening
from mininet.log import info, warn, output
ensureRoot()
timeout = 5
print "*** Creating nodes"
info( "*** Creating nodes\n" )
h1 = Host( 'h1' )
root = Host( 'root', inNamespace=False )
print "*** Creating links"
info( "*** Creating link\n" )
h1.linkTo( root )
print h1
info( h1 )
print "*** Configuring nodes"
info( "*** Configuring nodes\n" )
h1.setIP( '10.0.0.1', 8 )
root.setIP( '10.0.0.2', 8 )
print "*** Creating banner file"
info( "*** Creating banner file\n" )
f = open( '/tmp/%s.banner' % h1.name, 'w' )
f.write( 'Welcome to %s at %s\n' % ( h1.name, h1.IP() ) )
f.close()
print "*** Running sshd"
h1.cmd( '/usr/sbin/sshd -o "Banner /tmp/%s.banner"' % h1.name )
info( "*** Running sshd\n" )
cmd = '/usr/sbin/sshd -o UseDNS=no -u0 -o "Banner /tmp/%s.banner"' % h1.name
# add arguments from the command line
if len( sys.argv ) > 1:
cmd += ' ' + ' '.join( sys.argv[ 1: ] )
h1.cmd( cmd )
listening = waitListening( server=h1, port=22, timeout=timeout )
print "*** You may now ssh into", h1.name, "at", h1.IP()
if listening:
output( "*** You may now ssh into", h1.name, "at", h1.IP(), '\n' )
else:
warn( "*** Warning: after %s seconds, %s is not listening on port 22"
% ( timeout, h1.name ), '\n' )
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/python
"""
bind.py: Bind mount example
This creates hosts with private directories that the user specifies.
These hosts may have persistent directories that will be available
across multiple mininet session, or temporary directories that will
only last for one mininet session. To specify a persistent
directory, add a tuple to a list of private directories:
[ ( 'directory to be mounted on', 'directory to be mounted' ) ]
String expansion may be used to create a directory template for
each host. To do this, add a %(name)s in place of the host name
when creating your list of directories:
[ ( '/var/run', '/tmp/%(name)s/var/run' ) ]
If no persistent directory is specified, the directories will default
to temporary private directories. To do this, simply create a list of
directories to be made private. A tmpfs will then be mounted on them.
You may use both temporary and persistent directories at the same
time. In the following privateDirs string, each host will have a
persistent directory in the root filesystem at
"/tmp/(hostname)/var/run" mounted on "/var/run". Each host will also
have a temporary private directory mounted on "/var/log".
[ ( '/var/run', '/tmp/%(name)s/var/run' ), '/var/log' ]
This example has both persistent directories mounted on '/var/log'
and '/var/run'. It also has a temporary private directory mounted
on '/var/mn'
"""
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
def testHostWithPrivateDirs():
"Test bind mounts"
topo = SingleSwitchTopo( 10 )
privateDirs = [ ( '/var/log', '/tmp/%(name)s/var/log' ),
( '/var/run', '/tmp/%(name)s/var/run' ),
'/var/mn' ]
host = partial( Host,
privateDirs=privateDirs )
net = Mininet( topo=topo, host=host )
net.start()
directories = [ directory[ 0 ] if isinstance( directory, tuple )
else directory for directory in privateDirs ]
info( 'Private Directories:', directories, '\n' )
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
testHostWithPrivateDirs()
info( 'Done.\n')
+1001
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python
'''
A sanity check for cluster edition
'''
from mininet.examples.cluster import MininetCluster
from mininet.log import setLogLevel
from mininet.examples.clustercli import ClusterCLI as CLI
from mininet.topo import SingleSwitchTopo
def clusterSanity():
"Sanity check for cluster mode"
topo = SingleSwitchTopo()
net = MininetCluster( topo=topo )
net.start()
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
clusterSanity()
+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/python
"CLI for Mininet Cluster Edition prototype demo"
from mininet.cli import CLI
from mininet.log import output, error
# pylint: disable=global-statement
nx, graphviz_layout, plt = None, None, None # Will be imported on demand
class ClusterCLI( CLI ):
"CLI with additional commands for Cluster Edition demo"
@staticmethod
def colorsFor( seq ):
"Return a list of background colors for a sequence"
colors = [ 'red', 'lightgreen', 'cyan', 'yellow', 'orange',
'magenta', 'pink', 'grey', 'brown',
'white' ]
slen, clen = len( seq ), len( colors )
reps = max( 1, slen / clen )
colors = colors * reps
colors = colors[ 0 : slen ]
return colors
def do_plot( self, _line ):
"Plot topology colored by node placement"
# Import networkx if needed
global nx, plt, graphviz_layout
if not nx:
try:
# pylint: disable=import-error
import networkx
nx = networkx # satisfy pylint
from matplotlib import pyplot
plt = pyplot # satisfy pylint
import pygraphviz
assert pygraphviz # silence pyflakes
# Networkx moved this around
if hasattr( nx, 'graphviz_layout' ):
graphviz_layout = nx.graphviz_layout
else:
graphviz_layout = nx.drawing.nx_agraph.graphviz_layout
# pylint: enable=import-error
except ImportError:
error( 'plot requires networkx, matplotlib and pygraphviz - '
'please install them and try again\n' )
return
# Make a networkx Graph
g = nx.Graph()
mn = self.mn
servers = getattr( mn, 'servers', [ 'localhost' ] )
hosts, switches = mn.hosts, mn.switches
nodes = hosts + switches
g.add_nodes_from( nodes )
links = [ ( link.intf1.node, link.intf2.node )
for link in self.mn.links ]
g.add_edges_from( links )
# Pick some shapes and colors
# shapes = hlen * [ 's' ] + slen * [ 'o' ]
color = dict( zip( servers, self.colorsFor( servers ) ) )
# Plot it!
pos = graphviz_layout( g )
opts = { 'ax': None, 'font_weight': 'bold',
'width': 2, 'edge_color': 'darkblue' }
hcolors = [ color[ getattr( h, 'server', 'localhost' ) ]
for h in hosts ]
scolors = [ color[ getattr( s, 'server', 'localhost' ) ]
for s in switches ]
nx.draw_networkx( g, pos=pos, nodelist=hosts, node_size=800,
label='host', node_color=hcolors, node_shape='s',
**opts )
nx.draw_networkx( g, pos=pos, nodelist=switches, node_size=1000,
node_color=scolors, node_shape='o', **opts )
# Get rid of axes, add title, and show
fig = plt.gcf()
ax = plt.gca()
ax.get_xaxis().set_visible( False )
ax.get_yaxis().set_visible( False )
fig.canvas.set_window_title( 'Mininet')
plt.title( 'Node Placement', fontweight='bold' )
plt.show()
def do_status( self, _line ):
"Report on node shell status"
nodes = self.mn.hosts + self.mn.switches
for node in nodes:
node.shell.poll()
exited = [ node for node in nodes
if node.shell.returncode is not None ]
if exited:
for node in exited:
output( '%s has exited with code %d\n'
% ( node, node.shell.returncode ) )
else:
output( 'All nodes are still running.\n' )
def do_placement( self, _line ):
"Describe node placement"
mn = self.mn
nodes = mn.hosts + mn.switches + mn.controllers
for server in mn.servers:
names = [ n.name for n in nodes if hasattr( n, 'server' )
and n.server == server ]
output( '%s: %s\n' % ( server, ' '.join( names ) ) )
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/python
"clusterdemo.py: demo of Mininet Cluster Edition prototype"
from mininet.examples.cluster import ( MininetCluster, SwitchBinPlacer,
RemoteLink )
# ^ Could also use: RemoteSSHLink, RemoteGRELink
from mininet.topolib import TreeTopo
from mininet.log import setLogLevel
from mininet.examples.clustercli import ClusterCLI as CLI
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,
placement=SwitchBinPlacer )
net.start()
CLI( net )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
demo()
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/python
"clusterperf.py compare the maximum throughput between SSH and GRE tunnels"
from mininet.examples.cluster import RemoteSSHLink, RemoteGRELink, RemoteHost
from mininet.net import Mininet
from mininet.log import setLogLevel
def perf(Link):
"Test connectivity nand performance over Link"
net = Mininet( host=RemoteHost, link=Link )
h1 = net.addHost( 'h1')
h2 = net.addHost( 'h2', server='ubuntu2' )
net.addLink( h1, h2 )
net.start()
net.pingAll()
net.iperf()
net.stop()
if __name__ == '__main__':
setLogLevel('info')
perf( RemoteSSHLink )
perf( RemoteGRELink )
+13 -3
View File
@@ -315,11 +315,19 @@ class ConsoleApp( Frame ):
def updateGraph( self, _console, output ):
"Update our graph."
m = re.search( r'(\d+) Mbits/sec', output )
m = re.search( r'(\d+.?\d*) ([KMG]?bits)/sec', output )
if not m:
return
val, units = float( m.group( 1 ) ), m.group( 2 )
#convert to Gbps
if units[0] == 'M':
val *= 10 ** -3
elif units[0] == 'K':
val *= 10 ** -6
elif units[0] == 'b':
val *= 10 ** -9
self.updates += 1
self.bw += .001 * float( m.group( 1 ) )
self.bw += val
if self.updates >= self.hostCount:
self.graph.addBar( self.bw )
self.bw = 0
@@ -410,7 +418,9 @@ class ConsoleApp( Frame ):
count = len( consoles )
self.setOutputHook( self.updateGraph )
for console in consoles:
console.node.cmd( 'iperf -sD' )
# Sometimes iperf -sD doesn't return,
# so we run it in the background instead
console.node.cmd( 'iperf -s &' )
i = 0
for console in consoles:
i = ( i + 1 ) % count
+13 -5
View File
@@ -6,13 +6,20 @@ different controllers, by creating a custom Switch() subclass.
"""
from mininet.net import Mininet
from mininet.node import OVSSwitch, Controller
from mininet.node import OVSSwitch, Controller, RemoteController
from mininet.topolib import TreeTopo
from mininet.log import setLogLevel
from mininet.cli import CLI
c0 = Controller( 'c0' )
c1 = Controller( 'c1', ip='127.0.0.2' )
cmap = { 's1': c0, 's2': c1, 's3': c1 }
setLogLevel( 'info' )
# Two local and one "external" controller (which is actually c0)
# Ignore the warning message that the remote isn't (yet) running
c0 = Controller( 'c0', port=6633 )
c1 = Controller( 'c1', port=6634 )
c2 = RemoteController( 'c2', ip='127.0.0.1', port=6633 )
cmap = { 's1': c0, 's2': c1, 's3': c2 }
class MultiSwitch( OVSSwitch ):
"Custom Switch() subclass that connects to different controllers"
@@ -21,7 +28,8 @@ class MultiSwitch( OVSSwitch ):
topo = TreeTopo( depth=2, fanout=2 )
net = Mininet( topo=topo, switch=MultiSwitch, build=False )
net.controllers = [ c0, c1 ]
for c in [ c0, c1 ]:
net.addController(c)
net.build()
net.start()
CLI( net )
+13 -12
View File
@@ -11,49 +11,50 @@ Note that one could also create a custom switch class and pass it into
the Mininet() constructor.
"""
from mininet.net import Mininet
from mininet.node import Controller, OVSSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.log import setLogLevel, info
def multiControllerNet():
"Create a network from semi-scratch with multiple controllers."
net = Mininet( controller=Controller, switch=OVSSwitch, build=False )
net = Mininet( controller=Controller, switch=OVSSwitch )
print "*** Creating (reference) controllers"
info( "*** Creating (reference) controllers\n" )
c1 = net.addController( 'c1', port=6633 )
c2 = net.addController( 'c2', port=6634 )
print "*** Creating switches"
info( "*** Creating switches\n" )
s1 = net.addSwitch( 's1' )
s2 = net.addSwitch( 's2' )
print "*** Creating hosts"
hosts1 = [ net.addHost( 'h%d' % n ) for n in 3, 4 ]
hosts2 = [ net.addHost( 'h%d' % n ) for n in 5, 6 ]
info( "*** Creating hosts\n" )
hosts1 = [ net.addHost( 'h%d' % n ) for n in ( 3, 4 ) ]
hosts2 = [ net.addHost( 'h%d' % n ) for n in ( 5, 6 ) ]
print "*** Creating links"
info( "*** Creating links\n" )
for h in hosts1:
net.addLink( s1, h )
for h in hosts2:
net.addLink( s2, h )
net.addLink( s1, s2 )
print "*** Starting network"
info( "*** Starting network\n" )
net.build()
c1.start()
c2.start()
s1.start( [ c1 ] )
s2.start( [ c2 ] )
print "*** Testing network"
info( "*** Testing network\n" )
net.pingAll()
print "*** Running CLI"
info( "*** Running CLI\n" )
CLI( net )
print "*** Stopping network"
info( "*** Stopping network\n" )
net.stop()
if __name__ == '__main__':
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/python
"""
controlnet.py: Mininet with a custom control network
We create two Mininet() networks, a control network
and a data network, running four DataControllers on the
control network to control the data network.
Since we're using UserSwitch on the data network,
it should correctly fail over to a backup controller.
We also use a Mininet Facade to talk to both the
control and data networks from a single CLI.
"""
from functools import partial
from mininet.net import Mininet
from mininet.node import Controller, UserSwitch
from mininet.cli import CLI
from mininet.topo import Topo
from mininet.topolib import TreeTopo
from mininet.log import setLogLevel, info
# Some minor hacks
class DataController( Controller ):
"""Data Network Controller.
patched to avoid checkListening error and to delete intfs"""
def checkListening( self ):
"Ignore spurious error"
pass
def stop( self, *args, **kwargs ):
"Make sure intfs are deleted"
kwargs.update( deleteIntfs=True )
super( DataController, self ).stop( *args, **kwargs )
class MininetFacade( object ):
"""Mininet object facade that allows a single CLI to
talk to one or more networks"""
def __init__( self, net, *args, **kwargs ):
"""Create MininetFacade object.
net: Primary Mininet 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.nameToNet = kwargs
self.nameToNet['net'] = net
def __getattr__( self, name ):
"returns attribute from Primary Mininet object"
return getattr( self.net, name )
def __getitem__( self, key ):
"returns primary/named networks or node from any net"
#search kwargs for net named key
if key in self.nameToNet:
return self.nameToNet[ key ]
#search each net for node named key
for net in self.nets:
if key in net:
return net[ key ]
def __iter__( self ):
"Iterate through all nodes in all Mininet objects"
for net in self.nets:
for node in net:
yield node
def __len__( self ):
"returns aggregate number of nodes in all nets"
count = 0
for net in self.nets:
count += len(net)
return count
def __contains__( self, key ):
"returns True if node is a member of any net"
return key in self.keys()
def keys( self ):
"returns a list of all node names in all networks"
return list( self )
def values( self ):
"returns a list of all nodes in all networks"
return [ self[ key ] for key in self ]
def items( self ):
"returns (key,value) tuple list for every node in all networks"
return zip( self.keys(), self.values() )
# A real control network!
class ControlNetwork( Topo ):
"Control Network Topology"
def __init__( self, n, dataController=DataController, **kwargs ):
"""n: number of data network controller nodes
dataController: class for data network controllers"""
Topo.__init__( self, **kwargs )
# Connect everything to a single switch
cs0 = self.addSwitch( 'cs0' )
# Add hosts which will serve as data network controllers
for i in range( 0, n ):
c = self.addHost( 'c%s' % i, cls=dataController,
inNamespace=True )
self.addLink( c, cs0 )
# Connect switch to root namespace so that data network
# switches will be able to talk to us
root = self.addHost( 'root', inNamespace=False )
self.addLink( root, cs0 )
# Make it Happen!!
def run():
"Create control and data networks, and invoke the CLI"
info( '* Creating Control Network\n' )
ctopo = ControlNetwork( n=4, dataController=DataController )
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')
cnet.start()
info( '* Creating Data Network\n' )
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 )
info( '* Adding Controllers to Data Network\n' )
for host in cnet.hosts:
if isinstance(host, Controller):
net.addController( host )
info( '* Starting Data Network\n')
net.start()
mn = MininetFacade( net, cnet=cnet )
CLI( mn )
info( '* Stopping Data Network\n' )
net.stop()
info( '* Stopping Control Network\n' )
cnet.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
run()
+58 -32
View File
@@ -2,29 +2,40 @@
"""
cpu.py: test iperf bandwidth for varying cpu limits
Since we are limiting the hosts (only), we should expect the iperf
processes to be affected, as well as any system processing which is
billed to the hosts.
We reserve >50% of cycles for system processing; we assume that
this is enough for it not to affect results. Hosts are limited to
40% of total cycles, which we assume is enough to make them CPU
bound.
As CPU performance increases over time, we may have to reduce the
overall CPU allocation so that the host processing is still CPU bound.
This is perhaps an argument for specifying performance in a more
system-independent manner.
It would also be nice to have a better handle on limiting packet
processing cycles. It's not entirely clear to me how those are
billed to user or system processes if we are using OVS with a kernel
datapath. With a user datapath, they are easier to account for, but
overall performance is usually lower.
Although the iperf client uses more CPU and should be CPU bound (?),
we measure the received data at the server since the client transmit
rate includes buffering.
"""
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.topolib import TreeTopo
from mininet.util import custom
from mininet.log import setLogLevel, output
from mininet.util import custom, waitListening, decode
from mininet.log import setLogLevel, info
from mininet.clean import cleanup
from time import sleep
def waitListening(client, server, port):
"Wait until server is listening on port"
if not client.cmd('which telnet'):
raise Exception('Could not find telnet')
cmd = ('sh -c "echo A | telnet -e A %s %s"' %
(server.IP(), port))
while 'Connected' not in client.cmd(cmd):
output('waiting for', server,
'to listen on port', port, '\n')
sleep(.5)
def bwtest( cpuLimits, period_us=100000, seconds=5 ):
def bwtest( cpuLimits, period_us=100000, seconds=10 ):
"""Example/test of link and CPU bandwidth limits
cpu: cpu limit as fraction of overall CPU time"""
@@ -33,22 +44,36 @@ def bwtest( cpuLimits, period_us=100000, seconds=5 ):
results = {}
for sched in 'rt', 'cfs':
print '*** Testing with', sched, 'bandwidth limiting'
info( '*** Testing with', sched, 'bandwidth limiting\n' )
for cpu in cpuLimits:
# cpu is the cpu fraction for all hosts, so we divide
# it across two hosts
host = custom( CPULimitedHost, sched=sched,
period_us=period_us,
cpu=cpu )
net = Mininet( topo=topo, host=host )
cpu=.5*cpu )
try:
net = Mininet( topo=topo, host=host )
# pylint: disable=bare-except
except:
info( '*** Skipping scheduler %s and cleaning up\n' % sched )
cleanup()
break
net.start()
net.pingAll()
hosts = [ net.getNodeByName( h ) for h in topo.hosts() ]
client, server = hosts[ 0 ], hosts[ -1 ]
server.cmd( 'iperf -s -p 5001 &' )
info( '*** Starting iperf with %d%% of CPU allocated to hosts\n' %
( 100.0 * cpu ) )
# We measure at the server because it doesn't include
# the client's buffer fill rate
popen = server.popen( 'iperf -yc -s -p 5001' )
waitListening( client, server, 5001 )
result = client.cmd( 'iperf -yc -t %s -c %s' % (
seconds, server.IP() ) ).split( ',' )
# 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( ',' )
bps = float( result[ -1 ] )
server.cmdPrint( 'kill %iperf' )
popen.terminate()
net.stop()
updated = results.get( sched, [] )
updated += [ ( cpu, bps ) ]
@@ -60,22 +85,23 @@ def bwtest( cpuLimits, period_us=100000, seconds=5 ):
def dump( results ):
"Dump results"
fmt = '%s\t%s\t%s'
fmt = '%s\t%s\t%s\n'
print
print fmt % ( 'sched', 'cpu', 'client MB/s' )
print
info( '\n' )
info( fmt % ( 'sched', 'cpu', 'received bits/sec' ) )
for sched in sorted( results.keys() ):
entries = results[ sched ]
for cpu, bps in entries:
pct = '%.2f%%' % ( cpu * 100 )
mbps = bps / 1e6
print fmt % ( sched, pct, mbps )
pct = '%d%%' % ( cpu * 100 )
mbps = '%.2e' % bps
info( fmt % ( sched, pct, mbps ) )
if __name__ == '__main__':
setLogLevel( 'info' )
limits = [ .45, .4, .3, .2, .1 ]
# These are the limits for the hosts/iperfs - the
# rest is for system processes
limits = [ .5, .4, .3, .2, .1 ]
out = bwtest( limits )
dump( out )
+2 -2
View File
@@ -27,8 +27,8 @@ def emptyNet():
s3 = net.addSwitch( 's3' )
info( '*** Creating links\n' )
h1.linkTo( s3 )
h2.linkTo( s3 )
net.addLink( h1, s3 )
net.addLink( h2, s3 )
info( '*** Starting network\n')
net.start()
+8 -3
View File
@@ -6,6 +6,7 @@ hardware interface) to a network after the network is created.
"""
import re
import sys
from mininet.cli import CLI
from mininet.log import setLogLevel, info, error
@@ -16,10 +17,11 @@ from mininet.util import quietRun
def checkIntf( intf ):
"Make sure intf exists and is not configured."
if ( ' %s:' % intf ) not in quietRun( 'ip link show' ):
config = quietRun( 'ifconfig %s 2>/dev/null' % intf, shell=True )
if not config:
error( 'Error:', intf, 'does not exist!\n' )
exit( 1 )
ips = re.findall( r'\d+\.\d+\.\d+\.\d+', quietRun( 'ifconfig ' + intf ) )
ips = re.findall( r'\d+\.\d+\.\d+\.\d+', config )
if ips:
error( 'Error:', intf, 'has an IP address,'
'and is probably in use!\n' )
@@ -28,7 +30,10 @@ def checkIntf( intf ):
if __name__ == '__main__':
setLogLevel( 'info' )
intfName = 'eth1'
# try to get hw intf from the command line; by default, use eth1
intfName = sys.argv[ 1 ] if len( sys.argv ) > 1 else 'eth1'
info( '*** Connecting to hw intf: %s' % intfName )
info( '*** Checking', intfName, '\n' )
checkIntf( intfName )
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/python
'''
example of using various TCIntf options.
reconfigures a single interface using intf.config()
to use different traffic control commands to test
bandwidth, loss, and delay
'''
from mininet.net import Mininet
from mininet.log import setLogLevel, info
from mininet.link import TCLink
def intfOptions():
"run various traffic control commands on a single interface"
net = Mininet( autoStaticArp=True )
net.addController( 'c0' )
h1 = net.addHost( 'h1' )
h2 = net.addHost( 'h2' )
s1 = net.addSwitch( 's1' )
link1 = net.addLink( h1, s1, cls=TCLink )
net.addLink( h2, s1 )
net.start()
# flush out latency from reactive forwarding delay
net.pingAll()
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()
info( '\n*** Configuring one intf with loss of 50%\n' )
link1.intf1.config( loss=50 )
info( '\n' )
net.iperf( ( h1, h2 ), l4Type='UDP' )
info( '\n*** Configuring one intf with delay of 15ms\n' )
link1.intf1.config( delay='15ms' )
info( '\n*** Run a ping to confirm delay\n' )
net.pingPairFull()
info( '\n*** Done testing\n' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
intfOptions()
+13 -6
View File
@@ -8,15 +8,14 @@ from mininet.net import Mininet
from mininet.link import TCIntf
from mininet.node import CPULimitedHost
from mininet.topolib import TreeTopo
from mininet.util import custom
from mininet.log import setLogLevel
from mininet.util import custom, quietRun
from mininet.log import setLogLevel, info
def testLinkLimit( net, bw ):
"Run bandwidth limit test"
print '*** Testing network %.2f Mbps bandwidth limit' % bw
net.iperf( )
info( '*** Testing network %.2f Mbps bandwidth limit\n' % bw )
net.iperf()
def limit( bw=10, cpu=.1 ):
"""Example/test of link and CPU bandwidth limits
@@ -25,7 +24,15 @@ def limit( bw=10, cpu=.1 ):
intf = custom( TCIntf, bw=bw )
myTopo = TreeTopo( depth=1, fanout=2 )
for sched in 'rt', 'cfs':
print '*** Testing with', sched, 'bandwidth limiting'
info( '*** Testing with', sched, 'bandwidth limiting\n' )
if sched == 'rt':
release = quietRun( 'uname -r' ).strip('\r\n')
output = quietRun( 'grep CONFIG_RT_GROUP_SCHED /boot/config-%s'
% release )
if output == '# CONFIG_RT_GROUP_SCHED is not set\n':
info( '*** RT Scheduler is not enabled in your kernel. '
'Skipping this test\n' )
continue
host = custom( CPULimitedHost, sched=sched, cpu=cpu )
net = Mininet( topo=myTopo, intf=intf, host=host )
net.start()
+38 -22
View File
@@ -23,11 +23,14 @@ of switches, this example demonstrates:
"""
from mininet.net import Mininet
from mininet.node import UserSwitch, OVSKernelSwitch
from mininet.node import UserSwitch, OVSKernelSwitch, Controller
from mininet.topo import Topo
from mininet.log import lg
from mininet.util import irange
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
@@ -70,41 +73,54 @@ def linearBandwidthTest( lengths ):
switches = { 'reference user': UserSwitch,
'Open vSwitch kernel': OVSKernelSwitch }
# UserSwitch is horribly slow with recent kernels.
# We can reinstate it once its performance is fixed
del switches[ 'reference user' ]
topo = LinearTestTopo( hostCount )
# Select TCP Reno
output = quietRun( 'sysctl -w net.ipv4.tcp_congestion_control=reno' )
assert 'reno' in output
for datapath in switches.keys():
print "*** testing", datapath, "datapath"
info( "*** testing", datapath, "datapath\n" )
Switch = switches[ datapath ]
results[ datapath ] = []
net = Mininet( topo=topo, switch=Switch )
link = partial( TCLink, delay='2ms', bw=10 )
net = Mininet( topo=topo, switch=Switch,
controller=Controller, waitConnected=True,
link=link )
net.start()
print "*** testing basic connectivity"
info( "*** testing basic connectivity\n" )
for n in lengths:
net.ping( [ net.hosts[ 0 ], net.hosts[ n ] ] )
print "*** testing bandwidth"
info( "*** testing bandwidth\n" )
for n in lengths:
src, dst = net.hosts[ 0 ], net.hosts[ n ]
print "testing", src.name, "<->", dst.name,
bandwidth = net.iperf( [ src, dst ] )
print bandwidth
# Try to prime the pump to reduce PACKET_INs during test
# since the reference controller is reactive
src.cmd( 'telnet', dst.IP(), '5001' )
info( "testing", src.name, "<->", dst.name, '\n' )
# serverbw = received; _clientbw = buffered
serverbw, _clientbw = net.iperf( [ src, dst ], seconds=10 )
info( serverbw, '\n' )
flush()
results[ datapath ] += [ ( n, bandwidth ) ]
results[ datapath ] += [ ( n, serverbw ) ]
net.stop()
for datapath in switches.keys():
print
print "*** Linear network results for", datapath, "datapath:"
print
info( "\n*** Linear network results for", datapath, "datapath:\n" )
result = results[ datapath ]
print "SwitchCount\tiperf Results"
for switchCount, bandwidth in result:
print switchCount, '\t\t',
print bandwidth[ 0 ], 'server, ', bandwidth[ 1 ], 'client'
print
print
info( "SwitchCount\tiperf Results\n" )
for switchCount, serverbw in result:
info( switchCount, '\t\t' )
info( serverbw, '\n' )
info( '\n')
info( '\n' )
if __name__ == '__main__':
lg.setLogLevel( 'info' )
sizes = [ 1, 10, 20, 40, 60, 80, 100 ]
print "*** Running linearBandwidthTest", sizes
sizes = [ 1, 10, 20, 40, 60, 80 ]
info( "*** Running linearBandwidthTest", sizes, '\n' )
linearBandwidthTest( sizes )
+91
View File
@@ -0,0 +1,91 @@
#!/usr/bin/python
"""
linuxrouter.py: Example network with Linux IP router
This example converts a Node into a router using IP forwarding
already built into Linux.
The example topology creates a router and three IP subnets:
- 192.168.1.0/24 (r0-eth1, IP: 192.168.1.1)
- 172.16.0.0/12 (r0-eth2, IP: 172.16.0.1)
- 10.0.0.0/8 (r0-eth3, IP: 10.0.0.1)
Each subnet consists of a single host connected to
a single switch:
r0-eth1 - s1-eth1 - h1-eth0 (IP: 192.168.1.100)
r0-eth2 - s2-eth1 - h2-eth0 (IP: 172.16.0.100)
r0-eth3 - s3-eth1 - h3-eth0 (IP: 10.0.0.100)
The example relies on default routing entries that are
automatically created for each router interface, as well
as 'defaultRoute' parameters for the host interfaces.
Additional routes may be added to the router or hosts by
executing 'ip route' or 'route' commands on the router or hosts.
"""
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import Node
from mininet.log import setLogLevel, info
from mininet.cli import CLI
class LinuxRouter( Node ):
"A Node with IP forwarding enabled."
def config( self, **params ):
super( LinuxRouter, self).config( **params )
# Enable forwarding on the router
self.cmd( 'sysctl net.ipv4.ip_forward=1' )
def terminate( self ):
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
super( LinuxRouter, self ).terminate()
class NetworkTopo( Topo ):
"A LinuxRouter connecting three IP subnets"
def build( self, **_opts ):
defaultIP = '192.168.1.1/24' # IP address for r0-eth1
router = self.addNode( 'r0', cls=LinuxRouter, ip=defaultIP )
s1, s2, s3 = [ self.addSwitch( s ) for s in ( 's1', 's2', 's3' ) ]
self.addLink( s1, router, intfName2='r0-eth1',
params2={ 'ip' : defaultIP } ) # for clarity
self.addLink( s2, router, intfName2='r0-eth2',
params2={ 'ip' : '172.16.0.1/12' } )
self.addLink( s3, router, intfName2='r0-eth3',
params2={ 'ip' : '10.0.0.1/8' } )
h1 = self.addHost( 'h1', ip='192.168.1.100/24',
defaultRoute='via 192.168.1.1' )
h2 = self.addHost( 'h2', ip='172.16.0.100/12',
defaultRoute='via 172.16.0.1' )
h3 = self.addHost( 'h3', ip='10.0.0.100/8',
defaultRoute='via 10.0.0.1' )
for h, s in [ (h1, s1), (h2, s2), (h3, s3) ]:
self.addLink( h, s )
def run():
"Test linux router"
topo = NetworkTopo()
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()
+2981 -85
View File
File diff suppressed because it is too large Load Diff
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/python
"""
Simple example of Mobility with Mininet
(aka enough rope to hang yourself.)
We move a host from s1 to s2, s2 to s3, and then back to s1.
Gotchas:
The reference controller doesn't support mobility, so we need to
manually flush the switch flow tables!
Good luck!
to-do:
- think about wifi/hub behavior
- think about clearing last hop - why doesn't that work?
"""
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"
def delIntf( self, intf ):
"Remove (and detach) an interface"
port = self.ports[ intf ]
del self.ports[ intf ]
del self.intfs[ port ]
del self.nameToIntf[ intf.name ]
def addIntf( self, intf, rename=False, **kwargs ):
"Add (and reparent) an interface"
OVSSwitch.addIntf( self, intf, **kwargs )
intf.node = self
if rename:
self.renameIntf( intf )
def attach( self, intf ):
"Attach an interface and set its port"
port = self.ports[ intf ]
if port:
if self.isOldOVS():
self.cmd( 'ovs-vsctl add-port', self, intf )
else:
self.cmd( 'ovs-vsctl add-port', self, intf,
'-- set Interface', intf,
'ofport_request=%s' % port )
self.validatePort( intf )
def validatePort( self, intf ):
"Validate intf's OF port number"
ofport = int( self.cmd( 'ovs-vsctl get Interface', intf,
'ofport' ) )
if ofport != self.ports[ intf ]:
warn( 'WARNING: ofport for', intf, 'is actually', ofport,
'\n' )
def renameIntf( self, intf, newname='' ):
"Rename an interface (to its canonical name)"
intf.ifconfig( 'down' )
if not newname:
newname = '%s-eth%d' % ( self.name, self.ports[ intf ] )
intf.cmd( 'ip link set', intf, 'name', newname )
del self.nameToIntf[ intf.name ]
intf.name = newname
self.nameToIntf[ intf.name ] = intf
intf.ifconfig( 'up' )
def moveIntf( self, intf, switch, port=None, rename=True ):
"Move one of our interfaces to another switch"
self.detach( intf )
self.delIntf( intf )
switch.addIntf( intf, port=port, rename=rename )
switch.attach( intf )
def printConnections( switches ):
"Compactly print connected nodes to each switch"
for sw in switches:
output( '%s: ' % sw )
for intf in sw.intfList():
link = intf.link
if link:
intf1, intf2 = link.intf1, link.intf2
remote = intf1 if intf1.node != sw else intf2
output( '%s(%s) ' % ( remote.node, sw.ports[ intf ] ) )
output( '\n' )
def moveHost( host, oldSwitch, newSwitch, newPort=None ):
"Move a host from old switch to new switch"
hintf, sintf = host.connectionsTo( oldSwitch )[ 0 ]
oldSwitch.moveIntf( sintf, newSwitch, port=newPort )
return hintf, sintf
def mobilityTest():
"A simple test of mobility"
info( '* Simple mobility test\n' )
net = Mininet( topo=LinearTopo( 3 ), switch=MobilitySwitch )
info( '* Starting network:\n' )
net.start()
printConnections( net.switches )
info( '* Testing network\n' )
net.pingAll()
info( '* Identifying switch interface for h1\n' )
h1, old = net.get( 'h1', 's1' )
for s in 2, 3, 1:
new = net[ 's%d' % s ]
port = randint( 10, 20 )
info( '* Moving', h1, 'from', old, 'to', new, 'port', port, '\n' )
hintf, sintf = moveHost( h1, old, new, newPort=port )
info( '*', hintf, 'is now connected to', sintf, '\n' )
info( '* Clearing out old flows\n' )
for sw in net.switches:
sw.dpctl( 'del-flows' )
info( '* New network:\n' )
printConnections( net.switches )
info( '* Testing connectivity:\n' )
net.pingAll()
old = new
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
mobilityTest()
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/python
"""
This is a simple example that demonstrates multiple links
between nodes.
"""
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.net import Mininet
from mininet.topo import Topo
def runMultiLink():
"Create and run multiple link network"
topo = simpleMultiLinkTopo( n=2 )
net = Mininet( topo=topo )
net.start()
CLI( net )
net.stop()
class simpleMultiLinkTopo( Topo ):
"Simple topology with multiple links"
def __init__( self, n, **kwargs ):
Topo.__init__( self, **kwargs )
h1, h2 = self.addHost( 'h1' ), self.addHost( 'h2' )
s1 = self.addSwitch( 's1' )
for _ in range( n ):
self.addLink( s1, h1 )
self.addLink( s1, h2 )
if __name__ == '__main__':
setLogLevel( 'info' )
runMultiLink()
+8 -10
View File
@@ -8,10 +8,11 @@ multiple hosts and monitor their output interactively for a period=
of time.
"""
from mininet.net import Mininet
from mininet.node import Node
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel
from mininet.log import info, setLogLevel
from select import poll, POLLIN
from time import time
@@ -23,13 +24,8 @@ def chunks( l, n ):
def startpings( host, targetips ):
"Tell host to repeatedly ping targets"
targetips.append( '10.0.0.200' )
targetips = ' '.join( targetips )
# BL: Not sure why loopback intf isn't up!
host.cmd( 'ifconfig lo up' )
# Simple ping loop
cmd = ( 'while true; do '
' for ip in %s; do ' % targetips +
@@ -39,8 +35,8 @@ def startpings( host, targetips ):
' done; '
'done &' )
print ( '*** Host %s (%s) will be pinging ips: %s' %
( host.name, host.IP(), targetips ) )
info( '*** Host %s (%s) will be pinging ips: %s\n' %
( host.name, host.IP(), targetips ) )
host.cmd( cmd )
@@ -49,7 +45,7 @@ def multiping( netsize, chunksize, seconds):
# Create network and identify subnets
topo = SingleSwitchTopo( netsize )
net = Mininet( topo=topo )
net = Mininet( topo=topo, waitConnected=True )
net.start()
hosts = net.hosts
subnets = chunks( hosts, chunksize )
@@ -63,6 +59,8 @@ def multiping( netsize, chunksize, seconds):
# Start pings
for subnet in subnets:
ips = [ host.IP() for host in subnet ]
#adding bogus to generate packet loss
ips.append( '10.0.0.200' )
for host in subnet:
startpings( host, ips )
@@ -72,7 +70,7 @@ def multiping( netsize, chunksize, seconds):
readable = poller.poll(1000)
for fd, _mask in readable:
node = Node.outToNode[ fd ]
print '%s:' % node.name, node.monitor().strip()
info( '%s:' % node.name, node.monitor().strip(), '\n' )
# Stop pings
for host in hosts:
+9 -6
View File
@@ -5,19 +5,22 @@ Simple example of sending output to multiple files and
monitoring them
"""
from mininet.topo import SingleSwitchTopo
from mininet.net import Mininet
from mininet.log import setLogLevel
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.iteritems():
for h, outfile in outfiles.items():
tail = Popen( [ 'tail', '-f', outfile ],
stdout=PIPE, stderr=devnull )
fd = tail.stdout.fileno()
@@ -38,7 +41,7 @@ def monitorFiles( outfiles, seconds, timeoutms ):
host = fdToHost[ fd ]
# Wait for a line of output
line = f.readline().strip()
yield host, line
yield host, decode( line )
else:
# If we timed out, return nothing
yield None, ''
@@ -53,7 +56,7 @@ def monitorTest( N=3, seconds=3 ):
net = Mininet( topo )
net.start()
hosts = net.hosts
print "Starting test..."
info( "Starting test...\n" )
server = hosts[ 0 ]
outfiles, errfiles = {}, {}
for h in hosts:
@@ -67,10 +70,10 @@ def monitorTest( N=3, seconds=3 ):
'>', outfiles[ h ],
'2>', errfiles[ h ],
'&' )
print "Monitoring output for", seconds, "seconds"
info( "Monitoring output for", seconds, "seconds\n" )
for h, line in monitorFiles( outfiles, seconds, timeoutms=500 ):
if h:
print '%s: %s' % ( h.name, line )
info( '%s: %s\n' % ( h.name, line ) )
for h in hosts:
h.cmd('kill %ping')
net.stop()
+1 -1
View File
@@ -22,7 +22,7 @@ if __name__ == '__main__':
info( "*** Initializing Mininet and kernel modules\n" )
OVSKernelSwitch.setup()
info( "*** Creating network\n" )
network = Mininet( TreeTopo( depth=2, fanout=2 ), switch=OVSKernelSwitch)
network = Mininet( TreeTopo( depth=2, fanout=2 ), switch=OVSKernelSwitch )
info( "*** Starting network\n" )
network.start()
info( "*** Running ping test\n" )
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/python
"""
Example to create a Mininet topology and connect it to the internet via NAT
"""
from mininet.cli import CLI
from mininet.log import lg, info
from mininet.topolib import TreeNet
if __name__ == '__main__':
lg.setLogLevel( 'info')
net = TreeNet( depth=1, fanout=4 )
# Add NAT connectivity
net.addNAT().configDefault()
net.start()
info( "*** Hosts are running and should have internet connectivity\n" )
info( "*** Type 'exit' or control-D to shut down network\n" )
CLI( net )
# Shut down NAT
net.stop()
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/python
"""
natnet.py: Example network with NATs
h0
|
s0
|
----------------
| |
nat1 nat2
| |
s1 s2
| |
h1 h2
"""
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.nodelib import NAT
from mininet.log import setLogLevel
from mininet.cli import CLI
from mininet.util import irange
class InternetTopo(Topo):
"Single switch connected to n hosts."
def __init__(self, n=2, **opts):
Topo.__init__(self, **opts)
# set up inet switch
inetSwitch = self.addSwitch('s0')
# add inet host
inetHost = self.addHost('h0')
self.addLink(inetSwitch, inetHost)
# add local nets
for i in irange(1, n):
inetIntf = 'nat%d-eth0' % i
localIntf = 'nat%d-eth1' % i
localIP = '192.168.%d.1' % i
localSubnet = '192.168.%d.0/24' % i
natParams = { 'ip' : '%s/24' % localIP }
# add NAT to topology
nat = self.addNode('nat%d' % i, cls=NAT, subnet=localSubnet,
inetIntf=inetIntf, localIntf=localIntf)
switch = self.addSwitch('s%d' % i)
# connect NAT to inet and local switches
self.addLink(nat, inetSwitch, intfName1=inetIntf)
self.addLink(nat, switch, intfName1=localIntf, params1=natParams)
# add host and connect to local switch
host = self.addHost('h%d' % i,
ip='192.168.%d.100/24' % i,
defaultRoute='via %s' % localIP)
self.addLink(host, switch)
def run():
"Create network and run the CLI"
topo = InternetTopo()
net = Mininet(topo=topo)
net.start()
CLI(net)
net.stop()
if __name__ == '__main__':
setLogLevel('info')
run()
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/python
"""
Create a network with 5 hosts, numbered 1-4 and 9.
Validate that the port numbers match to the interface name,
and that the ovs ports match the mininet ports.
"""
from mininet.net import Mininet
from mininet.node import Controller
from mininet.log import setLogLevel, info, warn
def validatePort( switch, intf ):
"Validate intf's OF port number"
ofport = int( switch.cmd( 'ovs-vsctl get Interface', intf,
'ofport' ) )
if ofport != switch.ports[ intf ]:
warn( 'WARNING: ofport for', intf, 'is actually', ofport, '\n' )
return 0
else:
return 1
def testPortNumbering():
"""Test port numbering:
Create a network with 5 hosts (using Mininet's
mid-level API) and check that implicit and
explicit port numbering works as expected."""
net = Mininet( controller=Controller )
info( '*** Adding controller\n' )
net.addController( 'c0' )
info( '*** Adding hosts\n' )
h1 = net.addHost( 'h1', ip='10.0.0.1' )
h2 = net.addHost( 'h2', ip='10.0.0.2' )
h3 = net.addHost( 'h3', ip='10.0.0.3' )
h4 = net.addHost( 'h4', ip='10.0.0.4' )
h5 = net.addHost( 'h5', ip='10.0.0.5' )
info( '*** Adding switch\n' )
s1 = net.addSwitch( 's1' )
info( '*** Creating links\n' )
# host 1-4 connect to ports 1-4 on the switch
net.addLink( h1, s1 )
net.addLink( h2, s1 )
net.addLink( h3, s1 )
net.addLink( h4, s1 )
# specify a different port to connect host 5 to on the switch.
net.addLink( h5, s1, port1=1, port2= 9)
info( '*** Starting network\n' )
net.start()
# print the interfaces and their port numbers
info( '\n*** printing and validating the ports '
'running on each interface\n' )
for intfs in s1.intfList():
if not intfs.name == "lo":
info( intfs, ': ', s1.ports[intfs],
'\n' )
info( 'Validating that', intfs,
'is actually on port', s1.ports[intfs], '... ' )
if validatePort( s1, intfs ):
info( 'Validated.\n' )
info( '\n' )
# test the network with pingall
net.pingAll()
info( '\n' )
info( '*** Stopping network\n' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
testPortNumbering()
+3 -2
View File
@@ -5,10 +5,11 @@ This example monitors a number of hosts using host.popen() and
pmonitor()
"""
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel
from mininet.log import setLogLevel, info
from mininet.util import custom, pmonitor
def monitorhosts( hosts=5, sched='cfs' ):
@@ -27,7 +28,7 @@ def monitorhosts( hosts=5, sched='cfs' ):
# Monitor them and print output
for host, line in pmonitor( popens ):
if host:
print "<%s>: %s" % ( host.name, line.strip() )
info( "<%s>: %s" % ( host.name, line ) )
# Done
net.stop()
+6 -3
View File
@@ -5,6 +5,8 @@
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
@@ -14,20 +16,21 @@ def pmonitorTest( N=3, seconds=10 ):
net = Mininet( topo )
net.start()
hosts = net.hosts
print "Starting test..."
info( "Starting test...\n" )
server = hosts[ 0 ]
popens = {}
for h in hosts:
popens[ h ] = h.popen('ping', server.IP() )
print "Monitoring output for", seconds, "seconds"
info( "Monitoring output for", seconds, "seconds\n" )
endTime = time() + seconds
for h, line in pmonitor( popens, timeoutms=500 ):
if h:
print '%s: %s' % ( h.name, line ),
info( '<%s>: %s' % ( h.name, line ) )
if time() >= endTime:
for p in popens.values():
p.send_signal( SIGINT )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
pmonitorTest()
+2 -1
View File
@@ -8,6 +8,7 @@ but it exposes the configuration details and allows customization.
For most tasks, the higher-level API will be preferable.
"""
from mininet.net import Mininet
from mininet.node import Node
from mininet.link import Link
@@ -40,7 +41,7 @@ def scratchNet( cname='controller', cargs='-v ptcp:' ):
switch.cmd( 'ovs-vsctl del-br dp0' )
switch.cmd( 'ovs-vsctl add-br dp0' )
for intf in switch.intfs.values():
print switch.cmd( 'ovs-vsctl add-port dp0 %s' % intf )
switch.cmd( 'ovs-vsctl add-port dp0 %s\n' % intf )
# Note: controller and switch are in root namespace, and we
# can connect via loopback interface
+1 -1
View File
@@ -52,7 +52,7 @@ def scratchNetUser( cname='controller', cargs='ptcp:' ):
info( '*** Starting controller and user datapath\n' )
controller.cmd( cname + ' ' + cargs + '&' )
switch.cmd( 'ifconfig lo 127.0.0.1' )
intfs = [ str( i ) for i in sintf1, sintf2 ]
intfs = str( sintf1 ), str( sintf2 )
switch.cmd( 'ofdatapath -i ' + ','.join( intfs ) + ' ptcp: &' )
switch.cmd( 'ofprotocol tcp:' + controller.IP() + ' tcp:localhost &' )
+29 -18
View File
@@ -9,41 +9,52 @@ iperf will hang indefinitely if the TCP handshake fails
to complete.
"""
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.link import TCLink
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel
from mininet.log import setLogLevel, info
class SingleSwitchTopo(Topo):
from sys import argv
# It would be nice if we didn't have to do this:
# pylint: disable=arguments-differ
class SingleSwitchTopo( Topo ):
"Single switch connected to n hosts."
def __init__(self, n=2, **opts):
Topo.__init__(self, **opts)
def build( self, n=2, lossy=True ):
switch = self.addSwitch('s1')
for h in range(n):
# Each host gets 50%/n of system CPU
host = self.addHost('h%s' % (h + 1),
cpu=.5 / n)
# 10 Mbps, 5ms delay, 10% loss
self.addLink(host, switch,
bw=10, delay='5ms', loss=10, use_htb=True)
if lossy:
# 10 Mbps, 5ms delay, 10% packet loss
self.addLink(host, switch,
bw=10, delay='5ms', loss=10, use_htb=True)
else:
# 10 Mbps, 5ms delay, no packet loss
self.addLink(host, switch,
bw=10, delay='5ms', loss=0, use_htb=True)
def perfTest():
def perfTest( lossy=True ):
"Create network and run simple performance test"
topo = SingleSwitchTopo(n=4)
net = Mininet(topo=topo,
host=CPULimitedHost, link=TCLink)
topo = SingleSwitchTopo( n=4, lossy=lossy )
net = Mininet( topo=topo,
host=CPULimitedHost, link=TCLink,
autoStaticArp=True )
net.start()
print "Dumping host connections"
info( "Dumping host connections\n" )
dumpNodeConnections(net.hosts)
print "Testing network connectivity"
net.pingAll()
print "Testing bandwidth between h1 and h4"
info( "Testing bandwidth between h1 and h4\n" )
h1, h4 = net.getNodeByName('h1', 'h4')
net.iperf((h1, h4))
net.iperf( ( h1, h4 ), l4Type='UDP' )
net.stop()
if __name__ == '__main__':
setLogLevel('info')
perfTest()
setLogLevel( 'info' )
# Prevent test_simpleperf from failing due to packet loss
perfTest( lossy=( 'testmode' not in argv ) )
+33 -21
View File
@@ -16,50 +16,58 @@ demonstrates:
- running server processes (sshd in this case) on hosts
"""
import sys
from mininet.net import Mininet
from mininet.cli import CLI
from mininet.log import lg
from mininet.node import Node, OVSKernelSwitch
from mininet.log import lg, info
from mininet.node import Node
from mininet.topolib import TreeTopo
from mininet.link import Link
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, **kwargs )
def connectToRootNS( network, switch, ip, prefixLen, routes ):
def connectToRootNS( network, switch, ip, routes ):
"""Connect hosts to root namespace via switch. Starts network.
network: Mininet() network object
switch: switch to connect to root namespace
ip: IP address for root namespace node
prefixLen: IP address prefix length (e.g. 8, 16, 24)
routes: host networks to route to"""
# Create a node in root namespace and link to switch 0
root = Node( 'root', inNamespace=False )
intf = Link( root, switch ).intf1
root.setIP( ip, prefixLen, intf )
intf = network.addLink( root, switch ).intf1
root.setIP( ip, intf=intf )
# Start network that now includes link to root namespace
network.start()
# Add routes from root ns to hosts
for route in routes:
root.cmd( 'route add -net ' + route + ' dev ' + str( intf ) )
def sshd( network, cmd='/usr/sbin/sshd', opts='-D' ):
"Start a network, connect it to root ns, and run sshd on all hosts."
switch = network.switches[ 0 ] # switch to use
ip = '10.123.123.1' # our IP address on host network
routes = [ '10.0.0.0/8' ] # host networks to route to
connectToRootNS( network, switch, ip, 8, routes )
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.
ip: root-eth0 IP address in root namespace (10.123.123.1/32)
routes: Mininet host networks to route to (10.0/24)
switch: Mininet switch to connect to root namespace (s1)"""
if not switch:
switch = network[ 's1' ] # switch to use
if not routes:
routes = [ '10.0.0.0/24' ]
connectToRootNS( network, switch, ip, routes )
for host in network.hosts:
host.cmd( cmd + ' ' + opts + '&' )
print
print "*** Hosts are running sshd at the following addresses:"
print
info( "*** Waiting for ssh daemons to start\n" )
for server in network.hosts:
waitListening( server=server, port=22, timeout=5 )
info( "\n*** Hosts are running sshd at the following addresses:\n" )
for host in network.hosts:
print host.name, host.IP()
print
print "*** Type 'exit' or control-D to shut down network"
info( host.name, host.IP(), '\n' )
info( "\n*** Type 'exit' or control-D to shut down network\n" )
CLI( network )
for host in network.hosts:
host.cmd( 'kill %' + cmd )
@@ -67,5 +75,9 @@ def sshd( network, cmd='/usr/sbin/sshd', opts='-D' ):
if __name__ == '__main__':
lg.setLogLevel( 'info')
net = TreeNet( depth=1, fanout=4, switch=OVSKernelSwitch )
sshd( net )
net = TreeNet( depth=1, fanout=4 )
# get sshd args from the command line or use default args
# useDNS=no -u0 to avoid reverse DNS lookup timeout
argvopts = ' '.join( sys.argv[ 1: ] ) if len( sys.argv ) > 1 else (
'-D -o UseDNS=no -u0' )
sshd( net, opts=argvopts )
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env python
"""
Run all mininet.examples tests
-v : verbose output
-quick : skip tests that take more than ~30 seconds
"""
import unittest
import os
import sys
from mininet.util import ensureRoot
from mininet.clean import cleanup
class MininetTestResult( unittest.TextTestResult ):
def addFailure( self, test, err ):
super( MininetTestResult, self ).addFailure( test, err )
cleanup()
def addError( self,test, err ):
super( MininetTestResult, self ).addError( test, err )
cleanup()
class MininetTestRunner( unittest.TextTestRunner ):
def _makeResult( self ):
return MininetTestResult( self.stream, self.descriptions, self.verbosity )
def runTests( testDir, verbosity=1 ):
"discover and run all tests in testDir"
# ensure root and cleanup before starting tests
ensureRoot()
cleanup()
# discover all tests in testDir
testSuite = unittest.defaultTestLoader.discover( testDir )
# run tests
success = MininetTestRunner( verbosity=verbosity ).run( testSuite ).wasSuccessful()
sys.exit( 0 if success else 1 )
if __name__ == '__main__':
# get the directory containing example tests
testDir = os.path.dirname( os.path.realpath( __file__ ) )
verbosity = 2 if '-v' in sys.argv else 1
runTests( testDir, verbosity )
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python
"""
Tests for baresshd.py
"""
import unittest
from mininet.util import pexpect
from mininet.clean import cleanup, sh
from sys import stdout
class testBareSSHD( unittest.TestCase ):
opts = [ 'Welcome to h1', pexpect.EOF, pexpect.TIMEOUT ]
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' )
while True:
index = p.expect( self.opts )
if index == 0:
return True
else:
return False
def setUp( self ):
# verify that sshd is not running
self.assertFalse( self.connected() )
# create public key pair for testing
sh( 'rm -rf /tmp/ssh' )
sh( 'mkdir /tmp/ssh' )
sh( "ssh-keygen -t rsa -P '' -f /tmp/ssh/test_rsa" )
sh( 'cat /tmp/ssh/test_rsa.pub >> /tmp/ssh/authorized_keys' )
# run example with custom sshd args
cmd = ( 'python -m mininet.examples.baresshd '
'-o AuthorizedKeysFile=/tmp/ssh/authorized_keys '
'-o StrictModes=no' )
p = pexpect.spawn( cmd )
runOpts = [ 'You may now ssh into h1 at 10.0.0.1',
'after 5 seconds, h1 is not listening on port 22',
pexpect.EOF, pexpect.TIMEOUT ]
while True:
index = p.expect( runOpts )
if index == 0:
break
else:
self.tearDown()
self.fail( 'sshd failed to start in host h1' )
def testSSH( self ):
"Simple test to verify that we can ssh into h1"
result = False
# try to connect up to 3 times; sshd can take a while to start
result = self.connected()
self.assertTrue( result )
def tearDown( self ):
# kill the ssh process
sh( "ps aux | grep ssh |grep Banner| awk '{ print $2 }' | xargs kill" )
cleanup()
# remove public key pair
sh( 'rm -rf /tmp/ssh' )
if __name__ == '__main__':
unittest.main()
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env python
"""
Tests for bind.py
"""
import unittest
from mininet.util import pexpect
class testBind( unittest.TestCase ):
prompt = 'mininet>'
def setUp( self ):
self.net = pexpect.spawn( 'python -m mininet.examples.bind' )
self.net.expect( "Private Directories: \[([\w\s,'/]+)\]" )
self.directories = []
# parse directories from mn output
for d in self.net.match.group(1).split(', '):
self.directories.append( d.strip("'") )
self.net.expect( self.prompt )
self.assertTrue( len( self.directories ) > 0 )
def testCreateFile( self ):
"Create a file, a.txt, in the first private directory and verify"
fileName = 'a.txt'
directory = self.directories[ 0 ]
path = directory + '/' + fileName
self.net.sendline( 'h1 touch %s; ls %s' % ( path, directory ) )
index = self.net.expect( [ fileName, self.prompt ] )
self.assertTrue( index == 0 )
self.net.expect( self.prompt )
self.net.sendline( 'h1 rm %s' % path )
self.net.expect( self.prompt )
def testIsolation( self ):
"Create a file in two hosts and verify that contents are different"
fileName = 'b.txt'
directory = self.directories[ 0 ]
path = directory + '/' + fileName
contents = { 'h1' : '1', 'h2' : '2' }
# Verify file doesn't exist, then write private copy of file
for host in contents:
value = contents[ host ]
self.net.sendline( '%s cat %s' % ( host, path ) )
self.net.expect( 'No such file' )
self.net.expect( self.prompt )
self.net.sendline( '%s echo %s > %s' % ( host, value, path ) )
self.net.expect( self.prompt )
# Verify file contents
for host in contents:
value = contents[ host ]
self.net.sendline( '%s cat %s' % ( host, path ) )
self.net.expect( value )
self.net.expect( self.prompt )
self.net.sendline( '%s rm %s' % ( host, path ) )
self.net.expect( self.prompt )
# TODO: need more tests
def tearDown( self ):
self.net.sendline( 'exit' )
self.net.wait()
if __name__ == '__main__':
unittest.main()
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env python
'''
A simple sanity check test for cluster edition
'''
import unittest
from mininet.util import pexpect
class clusterSanityCheck( unittest.TestCase ):
prompt = 'mininet>'
def testClusterPingAll( self ):
p = pexpect.spawn( 'python -m mininet.examples.clusterSanity' )
p.expect( self.prompt )
p.sendline( 'pingall' )
p.expect ( '(\d+)% dropped' )
percent = int( p.match.group( 1 ) ) if p.match else -1
self.assertEqual( percent, 0 )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
if __name__ == '__main__':
unittest.main()
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env python
"""
Tests for controllers.py and controllers2.py
"""
import unittest
from mininet.util import pexpect
class testControllers( unittest.TestCase ):
prompt = 'mininet>'
def connectedTest( self, name, cmap ):
"Verify that switches are connected to the controller specified by cmap"
p = pexpect.spawn( 'python -m %s' % name )
p.expect( self.prompt )
# but first a simple ping test
p.sendline( 'pingall' )
p.expect ( '(\d+)% dropped' )
percent = int( p.match.group( 1 ) ) if p.match else -1
self.assertEqual( percent, 0 )
p.expect( self.prompt )
# verify connected controller
for switch in cmap:
p.sendline( 'sh ovs-vsctl get-controller %s' % switch )
p.expect( 'tcp:([\d.:]+)')
actual = p.match.group(1)
expected = cmap[ switch ]
self.assertEqual( actual, expected )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
def testControllers( self ):
c0 = '127.0.0.1:6633'
c1 = '127.0.0.1:6634'
cmap = { 's1': c0, 's2': c1, 's3': c0 }
self.connectedTest( 'mininet.examples.controllers', cmap )
def testControllers2( self ):
c0 = '127.0.0.1:6633'
c1 = '127.0.0.1:6634'
cmap = { 's1': c0, 's2': c1 }
self.connectedTest( 'mininet.examples.controllers2', cmap )
if __name__ == '__main__':
unittest.main()
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python
"""
Test for controlnet.py
"""
import unittest
from mininet.util import pexpect
class testControlNet( unittest.TestCase ):
prompt = 'mininet>'
def testPingall( self ):
"Simple pingall test that verifies 0% packet drop in data network"
p = pexpect.spawn( 'python -m mininet.examples.controlnet' )
p.expect( self.prompt )
p.sendline( 'pingall' )
p.expect ( '(\d+)% dropped' )
percent = int( p.match.group( 1 ) ) if p.match else -1
self.assertEqual( percent, 0 )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
def testFailover( self ):
"Kill controllers and verify that switch, s1, fails over properly"
count = 1
p = pexpect.spawn( 'python -m mininet.examples.controlnet' )
p.expect( self.prompt )
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 )
count += 1
for c in [ 'c0', 'c1' ]:
p.sendline( '%s ifconfig %s-eth0 down' % ( c, c) )
p.expect( self.prompt )
lp.expect( 'tcp:\d+\.\d+\.\d+\.(\d+):\d+: connected' )
ip = int( lp.match.group( 1 ) )
self.assertEqual( count, ip )
count += 1
p.sendline( 'exit' )
p.wait()
if __name__ == '__main__':
unittest.main()
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python
"""
Test for cpu.py
results format:
sched cpu received bits/sec
cfs 50% 8.14e+09
cfs 40% 6.48e+09
cfs 30% 4.56e+09
cfs 20% 2.84e+09
cfs 10% 1.29e+09
"""
import unittest
from mininet.util import pexpect
import sys
class testCPU( unittest.TestCase ):
prompt = 'mininet>'
@unittest.skipIf( '-quick' in sys.argv, 'long test' )
def testCPU( self ):
"Verify that CPU utilization is monotonically decreasing for each scheduler"
p = pexpect.spawn( 'python -m mininet.examples.cpu', timeout=300 )
# matches each line from results( shown above )
opts = [ '([a-z]+)\t([\d\.]+)%\t([\d\.e\+]+)',
pexpect.EOF ]
scheds = []
while True:
index = p.expect( opts )
if index == 0:
sched = p.match.group( 1 )
cpu = float( p.match.group( 2 ) )
bw = float( p.match.group( 3 ) )
if sched not in scheds:
scheds.append( sched )
else:
self.assertTrue( bw < previous_bw,
"%e should be less than %e\n" %
( bw, previous_bw ) )
previous_bw = bw
else:
break
self.assertTrue( len( scheds ) > 0 )
if __name__ == '__main__':
unittest.main()
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python
"""
Test for emptynet.py
"""
import unittest
from mininet.util import pexpect
class testEmptyNet( unittest.TestCase ):
prompt = 'mininet>'
def testEmptyNet( self ):
"Run simple CLI tests: pingall (verify 0% drop) and iperf (sanity)"
p = pexpect.spawn( 'python -m mininet.examples.emptynet' )
p.expect( self.prompt )
# pingall test
p.sendline( 'pingall' )
p.expect ( '(\d+)% dropped' )
percent = int( p.match.group( 1 ) ) if p.match else -1
self.assertEqual( percent, 0 )
p.expect( self.prompt )
# iperf test
p.sendline( 'iperf' )
p.expect( "Results: \['[\d.]+ .bits/sec', '[\d.]+ .bits/sec'\]" )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
if __name__ == '__main__':
unittest.main()
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python
"""
Test for hwintf.py
"""
import unittest
import re
from mininet.util import pexpect
from mininet.log import setLogLevel
from mininet.node import Node
from mininet.link import Link
class testHwintf( unittest.TestCase ):
prompt = 'mininet>'
def setUp( self ):
self.h3 = Node( 't0', ip='10.0.0.3/8' )
self.n0 = Node( 't1', inNamespace=False )
Link( self.h3, self.n0 )
self.h3.configDefault()
def testLocalPing( self ):
"Verify connectivity between virtual hosts using pingall"
p = pexpect.spawn( 'python -m mininet.examples.hwintf %s' % self.n0.intf() )
p.expect( self.prompt )
p.sendline( 'pingall' )
p.expect ( '(\d+)% dropped' )
percent = int( p.match.group( 1 ) ) if p.match else -1
self.assertEqual( percent, 0 )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
def testExternalPing( self ):
"Verify connnectivity between virtual host and virtual-physical 'external' host "
p = pexpect.spawn( 'python -m mininet.examples.hwintf %s' % self.n0.intf() )
p.expect( self.prompt )
# test ping external to internal
expectStr = '(\d+) packets transmitted, (\d+) received'
m = re.search( expectStr, self.h3.cmd( 'ping -v -c 1 10.0.0.1' ) )
tx = m.group( 1 )
rx = m.group( 2 )
self.assertEqual( tx, rx )
# test ping internal to external
p.sendline( 'h1 ping -c 1 10.0.0.3')
p.expect( expectStr )
tx = p.match.group( 1 )
rx = p.match.group( 2 )
self.assertEqual( tx, rx )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
def tearDown( self ):
self.h3.stop( deleteIntfs=True )
self.n0.stop( deleteIntfs=True )
if __name__ == '__main__':
setLogLevel( 'warning' )
unittest.main()
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python
"""
Test for intfOptions.py
"""
import unittest
from mininet.util import pexpect
import sys
class testIntfOptions( unittest.TestCase ):
def testIntfOptions( self ):
"verify that intf.config is correctly limiting traffic"
p = pexpect.spawn( 'python -m mininet.examples.intfoptions ' )
tolerance = .2 # plus or minus 20%
opts = [ "Results: \['([\d\.]+) .bits/sec",
"Results: \['10M', '([\d\.]+) .bits/sec",
"h(\d+)->h(\d+): (\d)/(\d),"
"rtt min/avg/max/mdev ([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms",
pexpect.EOF ]
while True:
index = p.expect( opts, timeout=600 )
if index == 0:
BW = 5
bw = float( p.match.group( 1 ) )
self.assertGreaterEqual( bw, BW * ( 1 - tolerance ) )
self.assertLessEqual( bw, BW * ( 1 + tolerance ) )
elif index == 1:
BW = 10
measuredBw = float( p.match.group( 1 ) )
loss = ( measuredBw / BW ) * 100
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 ) )
self.assertLessEqual( delay, 15 * ( 1 + tolerance ) )
else:
break
if __name__ == '__main__':
unittest.main()
+40
View File
@@ -0,0 +1,40 @@
#!/usr/bin/env python
"""
Test for limit.py
"""
import unittest
from mininet.util import pexpect
import sys
class testLimit( unittest.TestCase ):
@unittest.skipIf( '-quick' in sys.argv, 'long test' )
def testLimit( self ):
"Verify that CPU limits are within a 2% tolerance of limit for each scheduler"
p = pexpect.spawn( 'python -m mininet.examples.limit' )
opts = [ '\*\*\* Testing network ([\d\.]+) Mbps',
'\*\*\* Results: \[([\d\., ]+)\]',
pexpect.EOF ]
count = 0
bw = 0
tolerance = 2
while True:
index = p.expect( opts )
if index == 0:
bw = float( p.match.group( 1 ) )
count += 1
elif index == 1:
results = p.match.group( 1 )
for x in results.split( ',' ):
result = float( x )
self.assertTrue( result < bw + tolerance )
self.assertTrue( result > bw - tolerance )
else:
break
self.assertTrue( count > 0 )
if __name__ == '__main__':
unittest.main()
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env python
"""
Test for linearbandwidth.py
"""
import unittest
from mininet.util import pexpect
import sys
class testLinearBandwidth( unittest.TestCase ):
@unittest.skipIf( '-quick' in sys.argv, 'long test' )
def testLinearBandwidth( self ):
"Verify that bandwidth is monotonically decreasing as # of hops increases"
p = pexpect.spawn( 'python -m mininet.examples.linearbandwidth' )
count = 0
opts = [ '\*\*\* Linear network results',
'(\d+)\s+([\d\.]+) (.bits)',
pexpect.EOF ]
while True:
index = p.expect( opts, timeout=600 )
if index == 0:
count += 1
elif index == 1:
n = int( p.match.group( 1 ) )
bw = float( p.match.group( 2 ) )
unit = p.match.group( 3 )
if unit[ 0 ] == 'K':
bw *= 10 ** 3
elif unit[ 0 ] == 'M':
bw *= 10 ** 6
elif unit[ 0 ] == 'G':
bw *= 10 ** 9
# check that we have a previous result to compare to
if n != 1:
info = ( 'bw: %.2e bits/s across %d switches, '
'previous: %.2e bits/s across %d switches' %
( bw, n, previous_bw, previous_n ) )
self.assertTrue( bw < previous_bw, info )
previous_bw, previous_n = bw, n
else:
break
# verify that we received results from at least one switch
self.assertTrue( count > 0 )
if __name__ == '__main__':
unittest.main()
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python
"""
Test for linuxrouter.py
"""
import unittest
from mininet.util import pexpect
from mininet.util import quietRun
class testLinuxRouter( unittest.TestCase ):
prompt = 'mininet>'
def testPingall( self ):
"Test connectivity between hosts"
p = pexpect.spawn( 'python -m mininet.examples.linuxrouter' )
p.expect( self.prompt )
p.sendline( 'pingall' )
p.expect ( '(\d+)% dropped' )
percent = int( p.match.group( 1 ) ) if p.match else -1
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
self.assertEqual( percent, 0 )
def testRouterPing( self ):
"Test connectivity from h1 to router"
p = pexpect.spawn( 'python -m mininet.examples.linuxrouter' )
p.expect( self.prompt )
p.sendline( 'h1 ping -c 1 r0' )
p.expect ( '(\d+)% packet loss' )
percent = int( p.match.group( 1 ) ) if p.match else -1
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
self.assertEqual( percent, 0 )
def testTTL( self ):
"Verify that the TTL is decremented"
p = pexpect.spawn( 'python -m mininet.examples.linuxrouter' )
p.expect( self.prompt )
p.sendline( 'h1 ping -c 1 h2' )
p.expect ( 'ttl=(\d+)' )
ttl = int( p.match.group( 1 ) ) if p.match else -1
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
self.assertEqual( ttl, 63 ) # 64 - 1
if __name__ == '__main__':
unittest.main()
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env python
"""
Test for mobility.py
"""
import unittest
from subprocess import check_output
class testMobility( unittest.TestCase ):
def testMobility( self ):
"Run the example and verify its 4 ping results"
cmd = 'python -m mininet.examples.mobility 2>&1'
grep = ' | grep -c " 0% dropped" '
result = check_output( cmd + grep, shell=True )
assert int( result ) == 4
if __name__ == '__main__':
unittest.main()
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python
'''
Test for multiple links between nodes
validates mininet interfaces against systems interfaces
'''
import unittest
from mininet.util import pexpect
class testMultiLink( unittest.TestCase ):
prompt = 'mininet>'
def testMultiLink(self):
p = pexpect.spawn( 'python -m mininet.examples.multilink' )
p.expect( self.prompt )
p.sendline( 'intfs' )
p.expect( 's(\d): lo' )
intfsOutput = p.before
# parse interfaces from mininet intfs, and store them in a list
hostToIntfs = intfsOutput.split( '\r\n' )[ 1:3 ]
intfList = []
for hostToIntf in hostToIntfs:
intfList += [ intf for intf in
hostToIntf.split()[1].split(',') ]
# get interfaces from system by running ifconfig on every host
sysIntfList = []
opts = [ 'h(\d)-eth(\d)', self.prompt ]
p.expect( self.prompt )
p.sendline( 'h1 ifconfig' )
while True:
p.expect( opts )
if p.after == self.prompt:
break
sysIntfList.append( p.after )
p.sendline( 'h2 ifconfig' )
while True:
p.expect( opts )
if p.after == self.prompt:
break
sysIntfList.append( p.after )
failMsg = ( 'The systems interfaces and mininet interfaces\n'
'are not the same' )
self.assertEqual( sysIntfList, intfList, msg=failMsg )
p.sendline( 'exit' )
p.wait()
if __name__ == '__main__':
unittest.main()
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python
"""
Test for multiping.py
"""
import unittest
from mininet.util import pexpect
from collections import defaultdict
class testMultiPing( unittest.TestCase ):
def testMultiPing( self ):
"""Verify that each target is pinged at least once, and
that pings to 'real' targets are successful and unknown targets fail"""
p = pexpect.spawn( 'python -m mininet.examples.multiping' )
opts = [ "Host (h\d+) \(([\d.]+)\) will be pinging ips: ([\d\. ]+)",
"(h\d+): ([\d.]+) -> ([\d.]+) \d packets transmitted, (\d) received",
pexpect.EOF ]
pings = defaultdict( list )
while True:
index = p.expect( opts )
if index == 0:
name = p.match.group(1)
ip = p.match.group(2)
targets = p.match.group(3).split()
pings[ name ] += targets
elif index == 1:
name = p.match.group(1)
ip = p.match.group(2)
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 )
else:
self.assertEqual( received, 1, p.match.group(0) + '\n' +
target + ' received %d != 1 packets' % received )
try:
pings[ name ].remove( target )
except:
pass
else:
break
self.assertTrue( len( pings ) > 0, 'too few pings' )
for t in pings.values():
self.assertEqual( len( t ), 0, 'missed ping target(s): %s' % t )
if __name__ == '__main__':
unittest.main()
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env python
"""
Test for multipoll.py
"""
import unittest
from mininet.util import pexpect
class testMultiPoll( unittest.TestCase ):
def testMultiPoll( self ):
"Verify that we receive one ping per second per host"
p = pexpect.spawn( 'python -m mininet.examples.multipoll' )
opts = [ "\*\*\* (h\d) :" ,
"(h\d+): \d+ bytes from",
"Monitoring output for (\d+) seconds",
pexpect.EOF ]
pings, seconds = {}, -1
while True:
index = p.expect( opts )
if index == 0:
name = p.match.group( 1 )
pings[ name ] = 0
elif index == 1:
name = p.match.group( 1 )
pings[ name ] += 1
elif index == 2:
seconds = int( p.match.group( 1 ) )
else:
break
self.assertTrue( len( pings ) > 0 )
# make sure we have received at least one ping per second
for count in pings.values():
self.assertTrue( count >= seconds,
'%d pings < %d seconds' % ( count, seconds ) )
if __name__ == '__main__':
unittest.main()
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python
"""
Test for multitest.py
"""
import unittest
from mininet.util import pexpect
class testMultiTest( unittest.TestCase ):
prompt = 'mininet>'
def testMultiTest( self ):
"Verify pingall (0% dropped) and hX-eth0 interface for each host (ifconfig)"
p = pexpect.spawn( 'python -m mininet.examples.multitest' )
p.expect( '(\d+)% dropped' )
dropped = int( p.match.group( 1 ) )
self.assertEqual( dropped, 0 )
ifCount = 0
while True:
index = p.expect( [ 'h\d-eth0', self.prompt ] )
if index == 0:
ifCount += 1
elif index == 1:
p.sendline( 'exit' )
break
p.wait()
self.assertEqual( ifCount, 4 )
if __name__ == '__main__':
unittest.main()
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python
"""
Test for nat.py
"""
import unittest
from mininet.util import pexpect
from mininet.util import quietRun
destIP = '8.8.8.8' # Google DNS
class testNAT( unittest.TestCase ):
prompt = 'mininet>'
@unittest.skipIf( '0 received' in quietRun( 'ping -c 1 %s' % destIP ),
'Destination IP is not reachable' )
def testNAT( self ):
"Attempt to ping an IP on the Internet and verify 0% packet loss"
p = pexpect.spawn( 'python -m mininet.examples.nat' )
p.expect( self.prompt )
p.sendline( 'h1 ping -c 1 %s' % destIP )
p.expect ( '(\d+)% packet loss' )
percent = int( p.match.group( 1 ) ) if p.match else -1
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
self.assertEqual( percent, 0 )
if __name__ == '__main__':
unittest.main()
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python
"""
Test for natnet.py
"""
import unittest
from mininet.util import pexpect
from mininet.util import quietRun
class testNATNet( unittest.TestCase ):
prompt = 'mininet>'
def setUp( self ):
self.net = pexpect.spawn( 'python -m mininet.examples.natnet' )
self.net.expect( self.prompt )
def testPublicPing( self ):
"Attempt to ping the public server (h0) from h1 and h2"
self.net.sendline( 'h1 ping -c 1 h0' )
self.net.expect ( '(\d+)% packet loss' )
percent = int( self.net.match.group( 1 ) ) if self.net.match else -1
self.assertEqual( percent, 0 )
self.net.expect( self.prompt )
self.net.sendline( 'h2 ping -c 1 h0' )
self.net.expect ( '(\d+)% packet loss' )
percent = int( self.net.match.group( 1 ) ) if self.net.match else -1
self.assertEqual( percent, 0 )
self.net.expect( self.prompt )
def testPrivatePing( self ):
"Attempt to ping h1 and h2 from public server"
self.net.sendline( 'h0 ping -c 1 -t 1 h1' )
result = self.net.expect ( [ 'unreachable', 'loss' ] )
self.assertEqual( result, 0 )
self.net.expect( self.prompt )
self.net.sendline( 'h0 ping -c 1 -t 1 h2' )
result = self.net.expect ( [ 'unreachable', 'loss' ] )
self.assertEqual( result, 0 )
self.net.expect( self.prompt )
def testPrivateToPrivatePing( self ):
"Attempt to ping from NAT'ed host h1 to NAT'ed host h2"
self.net.sendline( 'h1 ping -c 1 -t 1 h2' )
result = self.net.expect ( [ '[Uu]nreachable', 'loss' ] )
self.assertEqual( result, 0 )
self.net.expect( self.prompt )
def tearDown( self ):
self.net.sendline( 'exit' )
self.net.wait()
if __name__ == '__main__':
unittest.main()
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python
"""
Test for numberedports.py
"""
import unittest
from mininet.util import pexpect
from collections import defaultdict
from mininet.node import OVSSwitch
class testNumberedports( unittest.TestCase ):
@unittest.skipIf( OVSSwitch.setup() or OVSSwitch.isOldOVS(), "old version of OVS" )
def testConsistency( self ):
"""verify consistency between mininet and ovs ports"""
p = pexpect.spawn( 'python -m mininet.examples.numberedports' )
opts = [ 'Validating that s1-eth\d is actually on port \d ... Validated.',
'Validating that s1-eth\d is actually on port \d ... WARNING',
pexpect.EOF ]
correct_ports = True
count = 0
while True:
index = p.expect( opts )
if index == 0:
count += 1
elif index == 1:
correct_ports = False
elif index == 2:
self.assertNotEqual( 0, count )
break
self.assertTrue( correct_ports )
def testNumbering( self ):
"""verify that all of the port numbers are printed correctly and consistent with their interface"""
p = pexpect.spawn( 'python -m mininet.examples.numberedports' )
opts = [ 's1-eth(\d+) : (\d+)',
pexpect.EOF ]
count_intfs = 0
while True:
index = p.expect( opts )
if index == 0:
count_intfs += 1
intfport = p.match.group( 1 )
ofport = p.match.group( 2 )
self.assertEqual( intfport, ofport )
elif index == 1:
break
self.assertNotEqual( 0, count_intfs )
if __name__ == '__main__':
unittest.main()
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python
"""
Test for popen.py and popenpoll.py
"""
import unittest
from mininet.util import pexpect
class testPopen( unittest.TestCase ):
def pingTest( self, name ):
"Verify that there are no dropped packets for each host"
p = pexpect.spawn( 'python -m %s' % name )
opts = [ "<(h\d+)>: PING ",
"<(h\d+)>: (\d+) packets transmitted, (\d+) received",
pexpect.EOF ]
pings = {}
while True:
index = p.expect( opts )
if index == 0:
name = p.match.group(1)
pings[ name ] = 0
elif index == 1:
name = p.match.group(1)
transmitted = p.match.group(2)
received = p.match.group(3)
# verify no dropped packets
self.assertEqual( received, transmitted )
pings[ name ] += 1
else:
break
self.assertTrue( len(pings) > 0 )
# verify that each host has gotten results
for count in pings.values():
self.assertEqual( count, 1 )
def testPopen( self ):
self.pingTest( 'mininet.examples.popen' )
def testPopenPoll( self ):
self.pingTest( 'mininet.examples.popenpoll' )
if __name__ == '__main__':
unittest.main()
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env python
"""
Test for scratchnet.py
"""
import unittest
from mininet.util import pexpect
class testScratchNet( unittest.TestCase ):
opts = [ "1 packets transmitted, 1 received, 0% packet loss", pexpect.EOF ]
def pingTest( self, name ):
"Verify that no ping packets were dropped"
p = pexpect.spawn( 'python -m %s' % name )
index = p.expect( self.opts, timeout=120 )
self.assertEqual( index, 0 )
def testPingKernel( self ):
self.pingTest( 'mininet.examples.scratchnet' )
def testPingUser( self ):
self.pingTest( 'mininet.examples.scratchnetuser' )
if __name__ == '__main__':
unittest.main()
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python
"""
Test for simpleperf.py
"""
import unittest
from mininet.util import pexpect
import sys
from mininet.log import setLogLevel
from mininet.examples.simpleperf import SingleSwitchTopo
class testSimplePerf( unittest.TestCase ):
@unittest.skipIf( '-quick' in sys.argv, 'long test' )
def testE2E( self ):
"Run the example and verify iperf results"
# 10 Mb/s, plus or minus 20% tolerance
BW = 10
TOLERANCE = .2
p = pexpect.spawn( 'python -m mininet.examples.simpleperf testmode' )
# check iperf results
p.expect( "Results: \['10M', '([\d\.]+) .bits/sec", timeout=480 )
measuredBw = float( p.match.group( 1 ) )
lowerBound = BW * ( 1 - TOLERANCE )
upperBound = BW + ( 1 + TOLERANCE )
self.assertGreaterEqual( measuredBw, lowerBound )
self.assertLessEqual( measuredBw, upperBound )
p.wait()
if __name__ == '__main__':
setLogLevel( 'warning' )
unittest.main()
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python
"""
Test for sshd.py
"""
import unittest
from mininet.util import pexpect
from mininet.clean import sh
class testSSHD( unittest.TestCase ):
opts = [ '\(yes/no\)\?', 'refused', 'Welcome|\$|#', pexpect.EOF, pexpect.TIMEOUT ]
def connected( self, ip ):
"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
p = pexpect.spawn( 'ssh -i /tmp/ssh/test_rsa %s' % ip, timeout=10 )
while True:
index = p.expect( self.opts )
if index == 0:
print( p.match.group(0) )
p.sendline( 'yes' )
elif index == 1:
return False
elif index == 2:
p.sendline( 'exit' )
p.wait()
return True
else:
return False
def setUp( self ):
# create public key pair for testing
sh( 'rm -rf /tmp/ssh' )
sh( 'mkdir /tmp/ssh' )
sh( "ssh-keygen -t rsa -P '' -f /tmp/ssh/test_rsa" )
sh( 'cat /tmp/ssh/test_rsa.pub >> /tmp/ssh/authorized_keys' )
cmd = ( 'python -m mininet.examples.sshd -D '
'-o AuthorizedKeysFile=/tmp/ssh/authorized_keys '
'-o StrictModes=no -o UseDNS=no -u0' )
# run example with custom sshd args
self.net = pexpect.spawn( cmd )
self.net.expect( 'mininet>' )
def testSSH( self ):
"Verify that we can ssh into all hosts (h1 to h4)"
for h in range( 1, 5 ):
self.assertTrue( self.connected( '10.0.0.%d' % h ) )
def tearDown( self ):
self.net.sendline( 'exit' )
self.net.wait()
# remove public key pair
sh( 'rm -rf /tmp/ssh' )
if __name__ == '__main__':
unittest.main()
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env python
"""
Test for tree1024.py
"""
import unittest
from mininet.util import pexpect
import sys
class testTree1024( unittest.TestCase ):
prompt = 'mininet>'
@unittest.skipIf( '-quick' in sys.argv, 'long test' )
def testTree1024( self ):
"Run the example and do a simple ping test from h1 to h1024"
p = pexpect.spawn( 'python -m mininet.examples.tree1024' )
p.expect( self.prompt, timeout=6000 ) # it takes awhile to set up
p.sendline( 'h1 ping -c 20 h1024' )
p.expect ( '(\d+)% packet loss' )
packetLossPercent = int( p.match.group( 1 ) ) if p.match else -1
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
# Tolerate slow startup on some systems - we should revisit this
# and determine the root cause.
self.assertLess( packetLossPercent, 60 )
if __name__ == '__main__':
unittest.main()
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env python
"""
Test for treeping64.py
"""
import unittest
from mininet.util import pexpect
import sys
class testTreePing64( unittest.TestCase ):
prompt = 'mininet>'
@unittest.skipIf( '-quick' in sys.argv, 'long test' )
def testTreePing64( self ):
"Run the example and verify ping results"
p = pexpect.spawn( 'python -m mininet.examples.treeping64' )
p.expect( 'Tree network ping results:', timeout=6000 )
count = 0
while True:
index = p.expect( [ '(\d+)% packet loss', pexpect.EOF ] )
if index == 0:
percent = int( p.match.group( 1 ) ) if p.match else -1
self.assertEqual( percent, 0 )
count += 1
else:
break
self.assertTrue( count > 0 )
if __name__ == '__main__':
unittest.main()
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python
"""
Test for vlanhost.py
"""
import unittest
from mininet.util import pexpect
import sys
from mininet.util import quietRun
class testVLANHost( unittest.TestCase ):
prompt = 'mininet>'
@unittest.skipIf( '-quick' in sys.argv, 'long test' )
def testVLANTopo( self ):
"Test connectivity (or lack thereof) between hosts in VLANTopo"
p = pexpect.spawn( 'python -m mininet.examples.vlanhost' )
p.expect( self.prompt )
p.sendline( 'pingall 1' ) #ping timeout=1
p.expect( '(\d+)% dropped', timeout=30 ) # there should be 24 failed pings
percent = int( p.match.group( 1 ) ) if p.match else -1
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
self.assertEqual( percent, 80 )
def testSpecificVLAN( self ):
"Test connectivity between hosts on a specific VLAN"
vlan = 1001
p = pexpect.spawn( 'python -m mininet.examples.vlanhost %d' % vlan )
p.expect( self.prompt )
p.sendline( 'h1 ping -c 1 h2' )
p.expect ( '(\d+)% packet loss' )
percent = int( p.match.group( 1 ) ) if p.match else -1
p.expect( self.prompt )
p.sendline( 'h1 ifconfig' )
i = p.expect( ['h1-eth0.%d' % vlan, pexpect.TIMEOUT ], timeout=2 )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
self.assertEqual( percent, 0 ) # no packet loss on ping
self.assertEqual( i, 0 ) # check vlan intf is present
if __name__ == '__main__':
unittest.main()
+2 -2
View File
@@ -9,10 +9,10 @@ and running sysctl -p. Check util/sysctl_addon.
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.node import OVSKernelSwitch
from mininet.node import OVSSwitch
from mininet.topolib import TreeNet
if __name__ == '__main__':
setLogLevel( 'info' )
network = TreeNet( depth=2, fanout=32, switch=OVSKernelSwitch )
network = TreeNet( depth=2, fanout=32, switch=OVSSwitch )
network.run( CLI, network )
+6 -6
View File
@@ -2,7 +2,8 @@
"Create a 64-node tree network, and test connectivity using ping."
from mininet.log import setLogLevel
from mininet.log import setLogLevel, info
from mininet.node import UserSwitch, OVSKernelSwitch # , KernelSwitch
from mininet.topolib import TreeNet
@@ -15,17 +16,16 @@ def treePing64():
'Open vSwitch kernel': OVSKernelSwitch }
for name in switches:
print "*** Testing", name, "datapath"
info( "*** Testing", name, "datapath\n" )
switch = switches[ name ]
network = TreeNet( depth=2, fanout=8, switch=switch )
result = network.run( network.pingAll )
results[ name ] = result
print
print "*** Tree network ping results:"
info( "\n*** Tree network ping results:\n" )
for name in switches:
print "%s: %d%% packet loss" % ( name, results[ name ] )
print
info( "%s: %d%% packet loss\n" % ( name, results[ name ] ) )
info( '\n' )
if __name__ == '__main__':
setLogLevel( 'info' )
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env python
"""
vlanhost.py: Host subclass that uses a VLAN tag for the default interface.
Dependencies:
This class depends on the "vlan" package
$ sudo apt-get install vlan
Usage (example uses VLAN ID=1000):
From the command line:
sudo mn --custom vlanhost.py --host vlan,vlan=1000
From a script (see exampleUsage function below):
from functools import partial
from vlanhost import VLANHost
....
host = partial( VLANHost, vlan=1000 )
net = Mininet( host=host, ... )
Directly running this script:
sudo python vlanhost.py 1000
"""
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"
def config( self, vlan=100, **params ):
"""Configure VLANHost according to (optional) parameters:
vlan: VLAN ID for default interface"""
r = super( VLANHost, self ).config( **params )
intf = self.defaultIntf()
# remove IP from default, "physical" interface
self.cmd( 'ifconfig %s inet 0' % intf )
# create VLAN interface
self.cmd( 'vconfig add %s %d' % ( intf, vlan ) )
# assign the host's IP to the VLAN interface
self.cmd( 'ifconfig %s.%d inet %s' % ( intf, vlan, params['ip'] ) )
# update the intf name and host's intf map
newName = '%s.%d' % ( intf, vlan )
# update the (Mininet) interface to refer to VLAN interface name
intf.name = newName
# add VLAN interface to host's name to intf map
self.nameToIntf[ newName ] = intf
return r
hosts = { 'vlan': VLANHost }
def exampleAllHosts( vlan ):
"""Simple example of how VLANHost can be used in a script"""
# This is where the magic happens...
host = partial( VLANHost, vlan=vlan )
# vlan (type: int): VLAN ID to be used by all hosts
# Start a basic network using our VLANHost
topo = SingleSwitchTopo( k=2 )
net = Mininet( host=host, topo=topo )
net.start()
CLI( net )
net.stop()
# pylint: disable=arguments-differ
class VLANStarTopo( Topo ):
"""Example topology that uses host in multiple VLANs
The topology has a single switch. There are k VLANs with
n hosts in each, all connected to the single switch. There
are also n hosts that are not in any VLAN, also connected to
the switch."""
def build( self, k=2, n=2, vlanBase=100 ):
s1 = self.addSwitch( 's1' )
for i in range( k ):
vlan = vlanBase + i
for j in range(n):
name = 'h%d-%d' % ( j+1, vlan )
h = self.addHost( name, cls=VLANHost, vlan=vlan )
self.addLink( h, s1 )
for j in range( n ):
h = self.addHost( 'h%d' % (j+1) )
self.addLink( h, s1 )
def exampleCustomTags():
"""Simple example that exercises VLANStarTopo"""
net = Mininet( topo=VLANStarTopo() )
net.start()
CLI( net )
net.stop()
if __name__ == '__main__':
import sys
from functools import partial
from mininet.net import Mininet
from mininet.cli import CLI
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel
setLogLevel( 'info' )
if not quietRun( 'which vconfig' ):
error( "Cannot find command 'vconfig'\nThe package",
"'vlan' is required in Ubuntu or Debian,",
"or 'vconfig' in Fedora\n" )
exit()
if len( sys.argv ) >= 2:
exampleAllHosts( vlan=int( sys.argv[ 1 ] ) )
else:
exampleCustomTags()
+100 -65
View File
@@ -10,83 +10,118 @@ It may also get rid of 'false positives', but hopefully
nothing irreplaceable!
"""
from subprocess import Popen, PIPE, STDOUT, check_output as co
from sys import stdout, exit
from time import sleep
from subprocess import ( Popen, PIPE, check_output as co,
CalledProcessError )
import time
from mininet.log import info, error
from mininet.log import info
from mininet.term import cleanUpScreens
from mininet.util import decode
def sh( cmd ):
"Run a command in the shell and return non-empty output lines"
"Print a command and send it to the shell"
info( cmd + '\n' )
output = ( Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE )
.communicate()[ 0 ]
.strip()
.split( '\n' ) )
return [ s for s in output if s ]
result = Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
return decode( result )
def cleanup():
"""Clean up junk which might be left over from old runs;
do fast stuff before slow dp and link removal!"""
info( "*** Removing excess "
"controllers/ofprotocols/ofdatapaths/pings/noxes\n" )
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
zombies += 'ovs-openflowd ovs-controller udpbwtest mnexec'
# Note: real zombie processes can't actually be killed, since they
# are already (un)dead. Then again,
# you can't connect to them either, so they're mostly harmless.
sh( 'killall -9 ' + zombies + ' 2> /dev/null' )
# And kill off sudo mnexec
sh( 'pkill -9 -f "sudo mnexec"')
info( "*** Removing junk from /tmp\n" )
sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' )
info( "*** Removing old X11 tunnels\n" )
cleanUpScreens()
info( "*** Removing excess kernel datapaths\n" )
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" )
for dp in dps:
sh( 'dpctl deldp ' + dp )
info( "*** Removing OVS datapaths\n" )
dps = sh("ovs-vsctl list-br")
for dp in dps:
sh( 'ovs-vsctl del-br ' + dp )
if co( 'ovs-vsctl list-br', shell=True ):
raise Excpetion( "Error: could not remove all OVS datapaths" )
info( "*** Removing all links of the pattern foo-ethX\n" )
links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" )
for link in links:
sh( "ip link del " + link )
if sh( "ip link show | egrep -o '(\w+-eth\w+)'" ):
raise Exception( "Error could not remove stale links")
info( "*** Killing stale mininet node processes\n" )
sh( 'pkill -9 -f mininet:' )
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 mininet:'.split() )
except:
pids = co( [ 'pgrep', '-f', pattern ] )
except CalledProcessError:
pids = ''
if pids:
sh( 'pkill -f 9 mininet:' )
sleep( .5 )
sh( 'pkill -9 -f %s' % pattern )
time.sleep( .5 )
else:
break
info( "*** Removing stale namespaces\n" )
nses = sh( "ip netns list" )
for ns in nses:
sh( "ip netns del " + ns )
if co( "ip netns list", shell=True ):
error( "Error: could not remove all namespaces - exiting\n" )
exit( 1 )
class Cleanup( object ):
"Wrapper for cleanup()"
info( "*** Cleanup complete.\n" )
callbacks = []
@classmethod
def cleanup( cls):
"""Clean up junk which might be left over from old runs;
do fast stuff before slow dp and link removal!"""
info( "*** Removing excess controllers/ofprotocols/ofdatapaths/"
"pings/noxes\n" )
zombies = ( 'controller ofprotocol ofdatapath ping nox_core'
'lt-nox_core ovs-openflowd ovs-controller'
'ovs-testcontroller udpbwtest mnexec ivs ryu-manager' )
# Note: real zombie processes can't actually be killed, since they
# are already (un)dead. Then again,
# you can't connect to them either, so they're mostly harmless.
# Send SIGTERM first to give processes a chance to shutdown cleanly.
sh( 'killall ' + zombies + ' 2> /dev/null' )
time.sleep( 1 )
sh( 'killall -9 ' + zombies + ' 2> /dev/null' )
# And kill off sudo mnexec
sh( 'pkill -9 -f "sudo mnexec"')
info( "*** Removing junk from /tmp\n" )
sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' )
info( "*** Removing old X11 tunnels\n" )
cleanUpScreens()
info( "*** Removing excess kernel datapaths\n" )
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'"
).splitlines()
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:
sh( "ovs-vsctl " + " -- ".join( "--if-exists del-br " + dp
for dp in dps if dp ) )
# And in case the above didn't work...
dps = sh( "ovs-vsctl --timeout=1 list-br" ).strip().splitlines()
for dp in dps:
sh( 'ovs-vsctl del-br ' + dp )
info( "*** Removing all links of the pattern foo-ethX\n" )
links = sh( "ip link show | "
"egrep -o '([-_.[:alnum:]]+-eth[[:digit:]]+)'"
).splitlines()
# Delete blocks of links
n = 1000 # chunk size
for i in range( 0, len( links ), n ):
cmd = ';'.join( 'ip link del %s' % link
for link in links[ i : i + n ] )
sh( '( %s ) 2> /dev/null' % cmd )
if 'tap9' in sh( 'ip link show' ):
info( "*** Removing tap9 - assuming it's from cluster edition\n" )
sh( 'ip link del tap9' )
info( "*** Killing stale mininet node processes\n" )
killprocs( 'mininet:' )
info( "*** Shutting down stale tunnels\n" )
killprocs( 'Tunnel=Ethernet' )
killprocs( '.ssh/mn')
sh( 'rm -f ~/.ssh/mn/*' )
# Call any additional cleanup code if necessary
for callback in cls.callbacks:
callback()
info( "*** Cleanup complete.\n" )
@classmethod
def addCleanupCallback( cls, callback ):
"Add cleanup callback"
if callback not in cls.callbacks:
cls.callbacks.append( callback )
cleanup = Cleanup.cleanup
addCleanupCallback = Cleanup.addCleanupCallback
+163 -63
View File
@@ -31,10 +31,13 @@ from os import isatty
from select import poll, POLLIN
import sys
import time
import os
import atexit
from mininet.log import info, output, error
from mininet.term import makeTerms
from mininet.util import quietRun, isShellBuiltin, dumpNodeConnections
from mininet.term import makeTerms, runX11
from mininet.util import ( quietRun, dumpNodeConnections,
dumpPorts )
class CLI( Cmd ):
"Simple command-line interface to talk to nodes."
@@ -42,14 +45,13 @@ class CLI( Cmd ):
prompt = 'mininet> '
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
script: script to run in batch mode"""
self.mn = mininet
self.nodelist = self.mn.controllers + self.mn.switches + self.mn.hosts
self.nodemap = {} # map names to Node objects
for node in self.nodelist:
self.nodemap[ node.name ] = node
# Local variable bindings for py command
self.locals = { 'net': mininet }
self.locals.update( self.nodemap )
# Attempt to handle input
self.stdin = stdin
self.inPoller = poll()
@@ -57,31 +59,66 @@ class CLI( Cmd ):
self.inputFile = script
Cmd.__init__( self )
info( '*** Starting CLI:\n' )
if self.inputFile:
self.do_source( self.inputFile )
return
self.initReadline()
self.run()
readlineInited = False
@classmethod
def initReadline( cls ):
"Set up history if readline is available"
# Only set up readline once to prevent multiplying the history file
if cls.readlineInited:
return
cls.readlineInited = True
try:
from readline import ( read_history_file, write_history_file,
set_history_length )
except ImportError:
pass
else:
history_path = os.path.expanduser( '~/.mininet_history' )
if os.path.isfile( history_path ):
read_history_file( history_path )
set_history_length( 1000 )
atexit.register( lambda: write_history_file( history_path ) )
def run( self ):
"Run our cmdloop(), catching KeyboardInterrupt"
while True:
try:
# Make sure no nodes are still waiting
for node in self.nodelist:
for node in self.mn.values():
while node.waiting:
info( 'stopping', node, '\n' )
node.sendInt()
node.monitor()
node.waitOutput()
if self.isatty():
quietRun( 'stty sane' )
quietRun( 'stty echo sane intr ^C' )
self.cmdloop()
break
except KeyboardInterrupt:
output( '\nInterrupt\n' )
# Output a message - unless it's also interrupted
# pylint: disable=broad-except
try:
output( '\nInterrupt\n' )
except Exception:
pass
# pylint: enable=broad-except
def emptyline( self ):
"Don't repeat last command when you hit return."
pass
# Disable pylint "Unused argument: 'arg's'" messages, as well as
# "method could be a function" warning, since each CLI function
# must have the same interface
# pylint: disable-msg=R0201
def getLocals( self ):
"Local variable bindings for py command"
self.locals.update( self.mn )
return self.locals
helpStr = (
'You may also send a command to a node using:\n'
@@ -110,57 +147,63 @@ class CLI( Cmd ):
def do_nodes( self, _line ):
"List all nodes."
nodes = ' '.join( [ node.name for node in sorted( self.nodelist ) ] )
nodes = ' '.join( sorted( self.mn ) )
output( 'available nodes are: \n%s\n' % nodes )
def do_ports( self, _line ):
"display ports and interfaces for each switch"
dumpPorts( self.mn.switches )
def do_net( self, _line ):
"List network connections."
dumpNodeConnections( self.nodelist )
dumpNodeConnections( self.mn.values() )
def do_sh( self, line ):
"Run an external shell command"
"""Run an external shell command
Usage: sh [cmd args]"""
assert self # satisfy pylint and allow override
call( line, shell=True )
# do_py() and do_px() need to catch any exception during eval()/exec()
# pylint: disable-msg=W0703
# pylint: disable=broad-except
def do_py( self, line ):
"""Evaluate a Python expression.
Node names may be used, e.g.: py h1.cmd('ls')"""
try:
result = eval( line, globals(), self.locals )
result = eval( line, globals(), self.getLocals() )
if not result:
return
elif isinstance( result, str ):
output( result + '\n' )
else:
output( repr( result ) + '\n' )
except Exception, e:
except Exception as e:
output( str( e ) + '\n' )
# We are in fact using the exec() pseudo-function
# pylint: disable-msg=W0122
# pylint: disable=exec-used
def do_px( self, line ):
"""Execute a Python statement.
Node names may be used, e.g.: px print h1.cmd('ls')"""
try:
exec( line, globals(), self.locals )
except Exception, e:
exec( line, globals(), self.getLocals() )
except Exception as e:
output( str( e ) + '\n' )
# pylint: enable-msg=W0703,W0122
# pylint: enable=broad-except,exec-used
def do_pingall( self, _line ):
def do_pingall( self, line ):
"Ping between all hosts."
self.mn.pingAll()
self.mn.pingAll( line )
def do_pingpair( self, _line ):
"Ping between first two hosts, useful for testing."
self.mn.pingPair()
def do_pingallfull( self, _line ):
"Ping between first two hosts, returns all ping results."
"Ping between all hosts, returns all ping results."
self.mn.pingAllFull()
def do_pingpairfull( self, _line ):
@@ -168,7 +211,8 @@ class CLI( Cmd ):
self.mn.pingPairFull()
def do_iperf( self, line ):
"Simple iperf TCP test between two (optionally specified) hosts."
"""Simple iperf TCP test between two (optionally specified) hosts.
Usage: iperf node1 node2"""
args = line.split()
if not args:
self.mn.iperf()
@@ -176,18 +220,19 @@ class CLI( Cmd ):
hosts = []
err = False
for arg in args:
if arg not in self.nodemap:
if arg not in self.mn:
err = True
error( "node '%s' not in network\n" % arg )
else:
hosts.append( self.nodemap[ arg ] )
hosts.append( self.mn[ arg ] )
if not err:
self.mn.iperf( hosts )
else:
error( 'invalid number of args: iperf src dst\n' )
def do_iperfudp( self, line ):
"Simple iperf TCP test between two (optionally specified) hosts."
"""Simple iperf UDP test between two (optionally specified) hosts.
Usage: iperfudp bw node1 node2"""
args = line.split()
if not args:
self.mn.iperf( l4Type='UDP' )
@@ -196,11 +241,11 @@ class CLI( Cmd ):
hosts = []
err = False
for arg in args[ 1:3 ]:
if arg not in self.nodemap:
if arg not in self.mn:
err = True
error( "node '%s' not in network\n" % arg )
else:
hosts.append( self.nodemap[ arg ] )
hosts.append( self.mn[ arg ] )
if not err:
self.mn.iperf( hosts, l4Type='UDP', udpBw=udpBw )
else:
@@ -209,17 +254,18 @@ class CLI( Cmd ):
def do_intfs( self, _line ):
"List interfaces."
for node in self.nodelist:
for node in self.mn.values():
output( '%s: %s\n' %
( node.name, ','.join( node.intfNames() ) ) )
def do_dump( self, _line ):
"Dump node info."
for node in self.nodelist:
for node in self.mn.values():
output( '%s\n' % repr( node ) )
def do_link( self, line ):
"Bring link(s) between two nodes up or down."
"""Bring link(s) between two nodes up or down.
Usage: link node1 node2 [up/down]"""
args = line.split()
if len(args) != 3:
error( 'invalid number of args: link end1 end2 [up down]\n' )
@@ -229,24 +275,39 @@ class CLI( Cmd ):
self.mn.configLinkStatus( *args )
def do_xterm( self, line, term='xterm' ):
"Spawn xterm(s) for the given node(s)."
"""Spawn xterm(s) for the given node(s).
Usage: xterm node1 node2 ..."""
args = line.split()
if not args:
error( 'usage: %s node1 node2 ...\n' % term )
else:
for arg in args:
if arg not in self.nodemap:
if arg not in self.mn:
error( "node '%s' not in network\n" % arg )
else:
node = self.nodemap[ arg ]
node = self.mn[ arg ]
self.mn.terms += makeTerms( [ node ], term = term )
def do_x( self, line ):
"""Create an X11 tunnel to the given node,
optionally starting a client.
Usage: x node [cmd args]"""
args = line.split()
if not args:
error( 'usage: x node [cmd args]...\n' )
else:
node = self.mn[ args[ 0 ] ]
cmd = args[ 1: ]
self.mn.terms += runX11( node, cmd )
def do_gterm( self, line ):
"Spawn gnome-terminal(s) for the given node(s)."
"""Spawn gnome-terminal(s) for the given node(s).
Usage: gterm node1 node2 ..."""
self.do_xterm( line, term='gterm' )
def do_exit( self, _line ):
"Exit"
assert self # satisfy pylint and allow override
return 'exited by user command'
def do_quit( self, line ):
@@ -263,7 +324,8 @@ class CLI( Cmd ):
return isatty( self.stdin.fileno() )
def do_noecho( self, line ):
"Run an interactive command with echoing turned off."
"""Run an interactive command with echoing turned off.
Usage: noecho [cmd args]"""
if self.isatty():
quietRun( 'stty -echo' )
self.default( line )
@@ -271,7 +333,8 @@ class CLI( Cmd ):
quietRun( 'stty echo' )
def do_source( self, line ):
"Read commands from an input file."
"""Read commands from an input file.
Usage: source <file>"""
args = line.split()
if len(args) != 1:
error( 'usage: source <file>\n' )
@@ -286,10 +349,12 @@ class CLI( Cmd ):
break
except IOError:
error( 'error reading file %s\n' % args[ 0 ] )
self.inputFile.close()
self.inputFile = None
def do_dpctl( self, line ):
"Run dpctl command on all switches."
"""Run dpctl (or ovs-ofctl) command on all switches.
Usage: dpctl command [arg1] [arg2] ..."""
args = line.split()
if len(args) < 1:
error( 'usage: dpctl command [arg1] [arg2] ...\n' )
@@ -305,37 +370,62 @@ class CLI( Cmd ):
elapsed = time.time() - start
self.stdout.write("*** Elapsed time: %0.6f secs\n" % elapsed)
def do_links( self, _line ):
"Report on links"
for link in self.mn.links:
output( link, link.status(), '\n' )
def do_switch( self, line ):
"Starts or stops a switch"
args = line.split()
if len(args) != 2:
error( 'invalid number of args: switch <switch name>'
'{start, stop}\n' )
return
sw = args[ 0 ]
command = args[ 1 ]
if sw not in self.mn or self.mn.get( sw ) not in self.mn.switches:
error( 'invalid switch: %s\n' % args[ 1 ] )
else:
sw = args[ 0 ]
command = args[ 1 ]
if command == 'start':
self.mn.get( sw ).start( self.mn.controllers )
elif command == 'stop':
self.mn.get( sw ).stop( deleteIntfs=False )
else:
error( 'invalid command: '
'switch <switch name> {start, stop}\n' )
def default( self, line ):
"""Called on an input line when the command prefix is not recognized.
Overridden to run shell commands when a node is the first CLI argument.
Past the first CLI argument, node names are automatically replaced with
corresponding IP addrs."""
Overridden to run shell commands when a node is the first
CLI argument. Past the first CLI argument, node names are
automatically replaced with corresponding IP addrs."""
first, args, line = self.parseline( line )
if not args:
return
if args and len(args) > 0 and args[ -1 ] == '\n':
args = args[ :-1 ]
rest = args.split( ' ' )
if first in self.nodemap:
node = self.nodemap[ first ]
if first in self.mn:
if not args:
error( '*** Please enter a command for node: %s <cmd>\n'
% first )
return
node = self.mn[ first ]
rest = args.split( ' ' )
# Substitute IP addresses for node names in command
rest = [ self.nodemap[ arg ].IP()
if arg in self.nodemap else arg
# If updateIP() returns None, then use node name
rest = [ self.mn[ arg ].defaultIntf().updateIP() or arg
if arg in self.mn else arg
for arg in rest ]
rest = ' '.join( rest )
# Run cmd on node:
builtin = isShellBuiltin( first )
node.sendCmd( rest, printPid=( not builtin ) )
node.sendCmd( rest )
self.waitForNode( node )
else:
error( '*** Unknown command: %s\n' % first )
# pylint: enable-msg=R0201
error( '*** Unknown command: %s\n' % line )
def waitForNode( self, node ):
"Wait for a node to finish, and print its output."
"Wait for a node to finish, and print its output."
# Pollers
nodePoller = poll()
nodePoller.register( node.stdout )
@@ -353,7 +443,7 @@ class CLI( Cmd ):
if False and self.inputFile:
key = self.inputFile.read( 1 )
if key is not '':
node.write(key)
node.write( key )
else:
self.inputFile = None
if isReadable( self.inPoller ):
@@ -365,8 +455,18 @@ class CLI( Cmd ):
if not node.waiting:
break
except KeyboardInterrupt:
# There is an at least one race condition here, since
# it's possible to interrupt ourselves after we've
# read data but before it has been printed.
node.sendInt()
def precmd( self, line ):
"allow for comments in the cli"
if '#' in line:
line = line.split( '#' )[ 0 ]
return line
# Helper functions
def isReadable( poller ):
+1
View File
@@ -0,0 +1 @@
../examples
+236 -75
View File
@@ -25,15 +25,15 @@ Link: basic link class for creating veth pairs
"""
from mininet.log import info, error, debug
from mininet.util import makeIntfPair, errFail, quietRun
from time import sleep
from mininet.util import makeIntfPair
import re
class Intf( object ):
"Basic interface object that can configure itself."
def __init__( self, name, node=None, port=None, link=None, **params ):
def __init__( self, name, node=None, port=None, link=None,
mac=None, **params ):
"""name: interface name (e.g. h1-eth0)
node: owning node (where this intf most likely lives)
link: parent link if we're part of a link
@@ -41,9 +41,21 @@ class Intf( object ):
self.node = node
self.name = name
self.link = link
self.mac, self.ip, self.prefixLen = None, None, None
self.mac = mac
self.ip, self.prefixLen = None, None
# if interface is lo, we know the ip is 127.0.0.1.
# This saves an ifconfig command per node
if self.name == 'lo':
self.ip = '127.0.0.1'
self.prefixLen = 8
# Add to node (and move ourselves if necessary )
node.addIntf( self, port=port )
if node:
moveIntfFn = params.pop( 'moveIntfFn', None )
if moveIntfFn:
node.addIntf( self, port=port, moveIntfFn=moveIntfFn )
else:
node.addIntf( self, port=port )
# Save params for future reference
self.params = params
self.config( **params )
@@ -64,6 +76,9 @@ class Intf( object ):
self.ip, self.prefixLen = ipstr.split( '/' )
return self.ifconfig( ipstr, 'up' )
else:
if prefixLen is None:
raise Exception( 'No prefix length set for IP address %s'
% ( ipstr, ) )
self.ip, self.prefixLen = ipstr, prefixLen
return self.ifconfig( '%s/%s' % ( ipstr, prefixLen ) )
@@ -80,7 +95,10 @@ class Intf( object ):
def updateIP( self ):
"Return updated IP address based on ifconfig"
ifconfig = self.ifconfig()
# use pexec instead of node.cmd so that we dont read
# backgrounded output from the cli.
ifconfig, _err, _exitCode = self.node.pexec(
'ifconfig %s' % self.name )
ips = self._ipMatchRegex.findall( ifconfig )
self.ip = ips[ 0 ] if ips else None
return self.ip
@@ -92,6 +110,19 @@ class Intf( object ):
self.mac = macs[ 0 ] if macs else None
return self.mac
# Instead of updating ip and mac separately,
# use one ifconfig call to do it simultaneously.
# This saves an ifconfig command, which improves performance.
def updateAddr( self ):
"Return IP address and MAC address based on ifconfig."
ifconfig = self.ifconfig()
ips = self._ipMatchRegex.findall( ifconfig )
macs = self._macMatchRegex.findall( ifconfig )
self.ip = ips[ 0 ] if ips else None
self.mac = macs[ 0 ] if macs else None
return self.ip, self.mac
def IP( self ):
"Return IP address"
return self.ip
@@ -103,13 +134,20 @@ class Intf( object ):
def isUp( self, setUp=False ):
"Return whether interface is up"
if setUp:
self.ifconfig( 'up' )
return "UP" in self.ifconfig()
cmdOutput = self.ifconfig( 'up' )
# no output indicates success
if cmdOutput:
error( "Error setting %s up: %s " % ( self.name, cmdOutput ) )
return False
else:
return True
else:
return "UP" in self.ifconfig()
def rename( self, newname ):
"Rename interface"
self.ifconfig( 'down' )
result = self.cmd( 'ip link set dev', self.name, 'name', newname )
result = self.cmd( 'ip link set', self.name, 'name', newname )
self.name = newname
self.ifconfig( 'up' )
return result
@@ -126,13 +164,13 @@ class Intf( object ):
method: config method name
param: arg=value (ignore if value=None)
value may also be list or dict"""
name, value = param.items()[ 0 ]
name, value = list( param.items() )[ 0 ]
f = getattr( self, method, None )
if not f or value is None:
return
if type( value ) is list:
if isinstance( value, list ):
result = f( *value )
elif type( value ) is dict:
elif isinstance( value, dict ):
result = f( **value )
else:
result = f( value )
@@ -155,15 +193,25 @@ class Intf( object ):
self.setParam( r, 'setIP', ip=ip )
self.setParam( r, 'isUp', up=up )
self.setParam( r, 'ifconfig', ifconfig=ifconfig )
self.updateIP()
self.updateMAC()
return r
def delete( self ):
"Delete interface"
self.cmd( 'ip link del ' + self.name )
# Does it help to sleep to let things run?
sleep( 0.001 )
# We used to do this, but it slows us down:
# if self.node.inNamespace:
# Link may have been dumped into root NS
# quietRun( 'ip link del ' + self.name )
self.node.delIntf( self )
self.link = None
def status( self ):
"Return intf status as a string"
links, _err, _result = self.node.pexec( 'ip link show' )
if self.name in links:
return "OK"
else:
return "MISSING"
def __repr__( self ):
return '<%s %s>' % ( self.__class__.__name__, self.name )
@@ -177,15 +225,19 @@ class TCIntf( Intf ):
Allows specification of bandwidth limits (various methods)
as well as delay, loss and max queue length"""
# The parameters we use seem to work reasonably up to 1 Gb/sec
# For higher data rates, we will probably need to change them.
bwParamMax = 1000
def bwCmds( self, bw=None, speedup=0, use_hfsc=False, use_tbf=False,
latency_ms=None, enable_ecn=False, enable_red=False ):
"Return tc commands to set bandwidth"
cmds, parent = [], ' root '
if bw and ( bw < 0 or bw > 1000 ):
error( 'Bandwidth', bw, 'is outside range 0..1000 Mbps\n' )
if bw and ( bw < 0 or bw > self.bwParamMax ):
error( 'Bandwidth limit', bw, 'is outside supported range 0..%d'
% self.bwParamMax, '- ignoring\n' )
elif bw is not None:
# BL: this seems a bit brittle...
if ( speedup > 0 and
@@ -201,7 +253,7 @@ class TCIntf( Intf ):
+ 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ]
elif use_tbf:
if latency_ms is None:
latency_ms = 15 * 8 / bw
latency_ms = 15.0 * 8 / bw
cmds += [ '%s qdisc add dev %s root handle 5: tbf ' +
'rate %fMbit burst 15000 latency %fms' %
( bw, latency_ms ) ]
@@ -233,18 +285,14 @@ class TCIntf( Intf ):
loss=None, max_queue_size=None ):
"Internal method: return tc commands for delay and loss"
cmds = []
if delay and delay < 0:
error( 'Negative delay', delay, '\n' )
elif jitter and jitter < 0:
error( 'Negative jitter', jitter, '\n' )
elif loss and ( loss < 0 or loss > 100 ):
if 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 %d ' % loss if loss is not None 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:
@@ -261,16 +309,40 @@ class TCIntf( Intf ):
return self.cmd( c )
def config( self, bw=None, delay=None, jitter=None, loss=None,
disable_gro=True, speedup=0, use_hfsc=False, use_tbf=False,
gro=False, txo=True, rxo=True,
speedup=0, use_hfsc=False, use_tbf=False,
latency_ms=None, enable_ecn=False, enable_red=False,
max_queue_size=None, **params ):
"Configure the port and set its properties."
"""Configure the port and set its properties.
bw: bandwidth in b/s (e.g. '10m')
delay: transmit delay (e.g. '1ms' )
jitter: jitter (e.g. '1ms')
loss: loss (e.g. '1%' )
gro: enable GRO (False)
txo: enable transmit checksum offload (True)
rxo: enable receive checksum offload (True)
speedup: experimental switch-side bw option
use_hfsc: use HFSC scheduling
use_tbf: use TBF scheduling
latency_ms: TBF latency parameter
enable_ecn: enable ECN (False)
enable_red: enable RED (False)
max_queue_size: queue limit parameter for netem"""
# Support old names for parameters
gro = not params.pop( 'disable_gro', not gro )
result = Intf.config( self, **params)
# Disable GRO
if disable_gro:
self.cmd( 'ethtool -K %s gro off' % self )
def on( isOn ):
"Helper method: bool -> 'on'/'off'"
return 'on' if isOn else 'off'
# Set offload parameters with ethool
self.cmd( 'ethtool -K', self,
'gro', on( gro ),
'tx', on( txo ),
'rx', on( rxo ) )
# Optimization: return if nothing else to configure
# Question: what happens if we want to reset things?
@@ -279,7 +351,11 @@ class TCIntf( Intf ):
return
# Clear existing configuration
cmds = [ '%s qdisc del dev %s root' ]
tcoutput = self.tc( '%s qdisc show dev %s' )
if "priomap" not in tcoutput and "noqueue" not in tcoutput:
cmds = [ '%s qdisc del dev %s root' ]
else:
cmds = []
# Bandwidth limits via various methods
bwcmds, parent = self.bwCmds( bw=bw, speedup=speedup,
@@ -290,16 +366,17 @@ class TCIntf( Intf ):
cmds += bwcmds
# Delay/jitter/loss/max_queue_size using netem
delaycmds, parent = self.delayCmds( delay=delay, jitter=jitter, loss=loss,
max_queue_size=max_queue_size,
parent=parent )
delaycmds, parent = self.delayCmds( delay=delay, jitter=jitter,
loss=loss,
max_queue_size=max_queue_size,
parent=parent )
cmds += delaycmds
# Ugly but functional: display configuration info
stuff = ( ( [ '%.2fMbit' % bw ] if bw is not None else [] ) +
( [ '%s delay' % delay ] if delay is not None else [] ) +
( [ '%s jitter' % jitter ] if jitter is not None else [] ) +
( ['%d%% loss' % loss ] if loss is not None else [] ) +
( ['%.5f%% loss' % loss ] if loss is not None else [] ) +
( [ 'ECN' ] if enable_ecn else [ 'RED' ]
if enable_red else [] ) )
info( '(' + ' '.join( stuff ) + ') ' )
@@ -307,6 +384,9 @@ class TCIntf( Intf ):
# Execute all the commands in our node
debug("at map stage w/cmds: %s\n" % cmds)
tcoutputs = [ self.tc(cmd) for cmd in cmds ]
for output in tcoutputs:
if output != '':
error( "*** Error: %s" % output )
debug( "cmds:", cmds, '\n' )
debug( "outputs:", tcoutputs, '\n' )
result[ 'tcoutputs'] = tcoutputs
@@ -320,10 +400,11 @@ class Link( object ):
"""A basic link is just a veth pair.
Other types of links could be tunnels, link emulators, etc.."""
# pylint: disable=too-many-branches
def __init__( self, node1, node2, port1=None, port2=None,
intfName1=None, intfName2=None,
intfName1=None, intfName2=None, addr1=None, addr2=None,
intf=Intf, cls1=None, cls2=None, params1=None,
params2=None ):
params2=None, fast=True ):
"""Create veth link to another node, making two new interfaces.
node1: first node
node2: second node
@@ -336,77 +417,157 @@ class Link( object ):
params1: parameters for interface 1
params2: parameters for interface 2"""
# This is a bit awkward; it seems that having everything in
# params would be more orthogonal, but being able to specify
# in-line arguments is more convenient!
if port1 is None:
port1 = node1.newPort()
if port2 is None:
port2 = node2.newPort()
# params is more orthogonal, but being able to specify
# in-line arguments is more convenient! So we support both.
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:
params2[ 'port' ] = port2
if 'port' not in params1:
params1[ 'port' ] = node1.newPort()
if 'port' not in params2:
params2[ 'port' ] = node2.newPort()
if not intfName1:
intfName1 = self.intfName( node1, port1 )
intfName1 = self.intfName( node1, params1[ 'port' ] )
if not intfName2:
intfName2 = self.intfName( node2, port2 )
intfName2 = self.intfName( node2, params2[ 'port' ] )
self.makeIntfPair( intfName1, intfName2, node1, node2 )
self.fast = fast
if fast:
params1.setdefault( 'moveIntfFn', self._ignore )
params2.setdefault( 'moveIntfFn', self._ignore )
self.makeIntfPair( intfName1, intfName2, addr1, addr2,
node1, node2, deleteIntfs=False )
else:
self.makeIntfPair( intfName1, intfName2, addr1, addr2 )
if not cls1:
cls1 = intf
if not cls2:
cls2 = intf
if not params1:
params1 = {}
if not params2:
params2 = {}
intf1 = cls1( name=intfName1, node=node1, port=port1,
link=self, **params1 )
intf2 = cls2( name=intfName2, node=node2, port=port2,
link=self, **params2 )
intf1 = cls1( name=intfName1, node=node1,
link=self, mac=addr1, **params1 )
intf2 = cls2( name=intfName2, node=node2,
link=self, mac=addr2, **params2 )
# All we are is dust in the wind, and our two interfaces
self.intf1, self.intf2 = intf1, intf2
# pylint: enable=too-many-branches
@classmethod
def intfName( cls, node, n ):
@staticmethod
def _ignore( *args, **kwargs ):
"Ignore any arguments"
pass
def intfName( self, node, n ):
"Construct a canonical interface name node-ethN for interface n."
# Leave this as an instance method for now
assert self
return node.name + '-eth' + repr( n )
@classmethod
def makeIntfPair( cls, intf1, intf2, node1=None, node2=None ):
def makeIntfPair( cls, intfname1, intfname2, addr1=None, addr2=None,
node1=None, node2=None, deleteIntfs=True ):
"""Create pair of interfaces
intf1: name of interface 1
intf2: name of interface 2
(override this class method [and possibly delete()]
intfname1: name for interface 1
intfname2: name for interface 2
addr1: MAC address for interface 1 (optional)
addr2: MAC address for interface 2 (optional)
node1: home node for interface 1 (optional)
node2: home node for interface 2 (optional)
(override this method [and possibly delete()]
to change link type)"""
# To be compatible with pid namespaces and chroot in the future
# we create links in the root namespace and then move
# the ends as needed.
# First, make sure there aren't stale links sitting around
quietRun( 'ip link delete %s type veth' % intf1 )
quietRun( 'ip link delete %s type veth' % intf2 )
cmd = 'ip link add %s type veth peer name %s' % ( intf1, intf2 )
if node2 and node2.inNamespace:
cmd += ' netns %s' % node2
errFail( cmd )
if node1 and node1.inNamespace:
errFail( 'ip link set dev %s netns %s' % ( intf1, node1 ) )
# Leave this as a class method for now
assert cls
return makeIntfPair( intfname1, intfname2, addr1, addr2, node1, node2,
deleteIntfs=deleteIntfs )
def delete( self ):
"Delete this link"
self.intf1.delete()
self.intf1 = None
self.intf2.delete()
self.intf2 = None
def stop( self ):
"Override to stop and clean up link as needed"
self.delete()
def status( self ):
"Return link status as a string"
return "(%s %s)" % ( self.intf1.status(), self.intf2.status() )
def __str__( self ):
return '%s<->%s' % ( self.intf1, self.intf2 )
class OVSIntf( Intf ):
"Patch interface on an OVSSwitch"
def ifconfig( self, *args ):
cmd = ' '.join( args )
if cmd == 'up':
# OVSIntf is always up
return
else:
raise Exception( 'OVSIntf cannot do ifconfig ' + cmd )
class OVSLink( Link ):
"""Link that makes patch links between OVSSwitches
Warning: in testing we have found that no more
than ~64 OVS patch links should be used in row."""
def __init__( self, node1, node2, **kwargs ):
"See Link.__init__() for options"
from mininet.node import OVSSwitch
self.isPatchLink = False
if ( isinstance( node1, OVSSwitch ) and
isinstance( node2, OVSSwitch ) ):
self.isPatchLink = True
kwargs.update( cls1=OVSIntf, cls2=OVSIntf )
Link.__init__( self, node1, node2, **kwargs )
def makeIntfPair( self, *args, **kwargs ):
"Usually delegated to OVSSwitch"
if self.isPatchLink:
return None, None
else:
return Link.makeIntfPair( *args, **kwargs )
class TCLink( Link ):
"Link with symmetric TC interfaces configured via opts"
def __init__( self, node1, node2, port1=None, port2=None,
intfName1=None, intfName2=None, **params ):
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)
params2=params )
class TCULink( TCLink ):
"""TCLink with default settings optimized for UserSwitch
(txo=rxo=0/False). Unfortunately with recent Linux kernels,
enabling TX and RX checksum offload on veth pairs doesn't work
well with UserSwitch: either it gets terrible performance or
TCP packets with bad checksums are generated, forwarded, and
*dropped* due to having bad checksums! OVS and LinuxBridge seem
to cope with this somehow, but it is likely to be an issue with
many software Ethernet bridges."""
def __init__( self, *args, **kwargs ):
kwargs.update( txo=False, rxo=False )
TCLink.__init__( self, *args, **kwargs )
+18 -19
View File
@@ -57,21 +57,19 @@ class StreamHandlerNoNewline( logging.StreamHandler ):
class Singleton( type ):
"""Singleton pattern from Wikipedia
See http://en.wikipedia.org/wiki/SingletonPattern#Python
See http://en.wikipedia.org/wiki/Singleton_Pattern
Intended to be used as a __metaclass_ param, as shown for the class
below.
below."""
Changed cls first args to mcs to satisfy pylint."""
def __init__( cls, name, bases, dict_ ):
super( Singleton, cls ).__init__( name, bases, dict_ )
cls.instance = None
def __init__( mcs, name, bases, dict_ ):
super( Singleton, mcs ).__init__( name, bases, dict_ )
mcs.instance = None
def __call__( mcs, *args, **kw ):
if mcs.instance is None:
mcs.instance = super( Singleton, mcs ).__call__( *args, **kw )
return mcs.instance
def __call__( cls, *args, **kw ):
if cls.instance is None:
cls.instance = super( Singleton, cls ).__call__( *args, **kw )
return cls.instance
class MininetLogger( Logger, object ):
@@ -126,8 +124,8 @@ class MininetLogger( Logger, object ):
self.setLevel( level )
self.handlers[ 0 ].setLevel( level )
# pylint: disable-msg=E0202
# "An attribute inherited from mininet.log hide this method"
# 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()
@@ -144,7 +142,7 @@ class MininetLogger( Logger, object ):
if self.isEnabledFor( OUTPUT ):
self._log( OUTPUT, msg, args, kwargs )
# pylint: enable-msg=E0202
# pylint: enable=method-hidden
lg = MininetLogger()
@@ -162,7 +160,7 @@ def makeListCompatible( fn ):
"Generated function. Closure-ish."
if len( args ) == 1:
return fn( *args )
args = ' '.join( [ str( arg ) for arg in args ] )
args = ' '.join( str( arg ) for arg in args )
return fn( args )
# Fix newfn's name and docstring
@@ -170,9 +168,10 @@ def makeListCompatible( fn ):
setattr( newfn, '__doc__', fn.__doc__ )
return newfn
info, output, warn, error, debug = (
lg.info, lg.output, lg.warn, lg.error, lg.debug ) = [
makeListCompatible( f ) for f in
lg.info, lg.output, lg.warn, lg.error, lg.debug ]
_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
setLogLevel = lg.setLogLevel
+3 -3
View File
@@ -1,6 +1,6 @@
"Module dependency utility functions for Mininet."
from mininet.util import quietRun
from mininet.util import quietRun, BaseString
from mininet.log import info, error, debug
from os import environ
@@ -28,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 type( subtract ) is str:
if isinstance( subtract, BaseString ):
subtract = [ subtract ]
if type( add ) is str:
if isinstance( add, BaseString ):
add = [ add ]
for mod in subtract:
if mod in lsmod():
+345 -123
View File
@@ -90,29 +90,35 @@ import os
import re
import select
import signal
import random
from time import sleep
from itertools import chain
from itertools import chain, groupby
from math import ceil
from mininet.cli import CLI
from mininet.log import info, error, debug, output
from mininet.node import Host, OVSKernelSwitch, Controller
from mininet.log import info, error, debug, output, warn
from mininet.node import ( Node, Host, OVSKernelSwitch, DefaultController,
Controller )
from mininet.nodelib import NAT
from mininet.link import Link, Intf
from mininet.util import quietRun, errFail, fixLimits, numCores, ensureRoot
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
macColonHex, ipStr, ipParse, netParse, ipAdd,
waitListening, BaseString )
from mininet.term import cleanUpScreens, makeTerms
# Mininet version: should be consistent with README and LICENSE
VERSION = "2.0.0"
VERSION = "2.3.0d4"
class Mininet( object ):
"Network emulation with hosts spawned in network namespaces."
def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
controller=Controller, link=Link, intf=Intf,
controller=DefaultController, link=Link, intf=Intf,
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
inNamespace=False,
autoSetMacs=False, autoStaticArp=False, autoPinCpus=False,
listenPort=None ):
listenPort=None, waitConnected=False ):
"""Create Mininet object.
topo: Topo (topology) object or None
switch: default Switch class
@@ -138,7 +144,9 @@ class Mininet( object ):
self.intf = intf
self.ipBase = ipBase
self.ipBaseNum, self.prefixLen = netParse( self.ipBase )
self.nextIP = 1 # start for address allocation
hostIP = ( 0xffffffff >> self.prefixLen ) & self.ipBaseNum
# Start for address allocation
self.nextIP = hostIP if hostIP > 0 else 1
self.inNamespace = inNamespace
self.xterms = xterms
self.cleanup = cleanup
@@ -148,12 +156,13 @@ class Mininet( object ):
self.numCores = numCores()
self.nextCore = 0 # next core for pinning hosts to CPUs
self.listenPort = listenPort
self.waitConn = waitConnected
self.hosts = []
self.switches = []
self.controllers = []
self.links = []
self.nameToNode = {} # name to Node (Host/Switch) objects
self.terms = [] # list of spawned xterm processes
@@ -164,6 +173,36 @@ class Mininet( object ):
if topo and build:
self.build()
def waitConnected( self, timeout=None, delay=.5 ):
"""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
remaining = list( self.switches )
while True:
for switch in tuple( remaining ):
if switch.connected():
info( '%s ' % switch )
remaining.remove( switch )
if not remaining:
info( '\n' )
return True
if timeout is not None and time > timeout:
break
sleep( delay )
time += delay
warn( 'Timed out after %d seconds\n' % time )
for switch in remaining:
if not switch.connected():
warn( 'Warning: %s is not connected to a controller\n'
% switch.name )
else:
remaining.remove( switch )
return not remaining
def addHost( self, name, cls=None, **params ):
"""Add host.
name: name of host to add
@@ -176,7 +215,7 @@ class Mininet( object ):
prefixLen=self.prefixLen ) +
'/%s' % self.prefixLen }
if self.autoSetMacs:
defaults[ 'mac'] = macColonHex( self.nextIP )
defaults[ 'mac' ] = macColonHex( self.nextIP )
if self.autoPinCpus:
defaults[ 'cores' ] = self.nextCore
self.nextCore = ( self.nextCore + 1 ) % self.numCores
@@ -189,6 +228,24 @@ class Mininet( object ):
self.nameToNode[ name ] = h
return h
def delNode( self, node, nodes=None):
"""Delete node
node: node to delete
nodes: optional list to delete from (e.g. self.hosts)"""
if nodes is None:
nodes = ( self.hosts if node in self.hosts else
( self.switches if node in self.switches else
( self.controllers if node in self.controllers else
[] ) ) )
node.stop( deleteIntfs=True )
node.terminate()
nodes.remove( node )
del self.nameToNode[ node.name ]
def delHost( self, host ):
"Delete a host"
self.delNode( host, nodes=self.hosts )
def addSwitch( self, name, cls=None, **params ):
"""Add switch.
name: name of switch to add
@@ -207,17 +264,61 @@ class Mininet( object ):
self.nameToNode[ name ] = sw
return sw
def delSwitch( self, switch ):
"Delete a switch"
self.delNode( switch, nodes=self.switches )
def addController( self, name='c0', controller=None, **params ):
"""Add controller.
controller: Controller class"""
# Get controller class
if not controller:
controller = self.controller
controller_new = controller( name, **params )
# Construct new controller if one is not given
if isinstance( name, Controller ):
controller_new = name
# Pylint thinks controller is a str()
# pylint: disable=maybe-no-member
name = controller_new.name
# pylint: enable=maybe-no-member
else:
controller_new = controller( name, **params )
# Add new controller to net
if controller_new: # allow controller-less setups
self.controllers.append( controller_new )
self.nameToNode[ name ] = controller_new
return controller_new
def delController( self, controller ):
"""Delete a controller
Warning - does not reconfigure switches, so they
may still attempt to connect to it!"""
self.delNode( controller )
def addNAT( self, name='nat0', connect=True, inNamespace=False,
**params):
"""Add a NAT to the Mininet network
name: name of NAT node
connect: switch to connect to | True (s1) | None
inNamespace: create in a network namespace
params: other NAT node params, notably:
ip: used as default gateway address"""
nat = self.addHost( name, cls=NAT, inNamespace=inNamespace,
subnet=self.ipBase, **params )
# find first switch and create link
if connect:
if not isinstance( connect, Node ):
# Use first switch if not specified
connect = self.switches[ 0 ]
# Connect the nat to the switch
self.addLink( nat, connect )
# Set the default route on hosts
natIP = nat.params[ 'ip' ].split('/')[ 0 ]
for host in self.hosts:
if host.inNamespace:
host.setDefaultRoute( 'via %s' % natIP )
return nat
# BL: We now have four ways to look up nodes
# This may (should?) be cleaned up in the future.
def getNodeByName( self, *args ):
@@ -231,39 +332,106 @@ class Mininet( object ):
return self.getNodeByName( *args )
# Even more convenient syntax for node lookup and iteration
def __getitem__( self, *args ):
"""net [ name ] operator: Return node(s) with given name(s)"""
return self.getNodeByName( *args )
def __getitem__( self, key ):
"net[ name ] operator: Return node with given name"
return self.nameToNode[ key ]
def __delitem__( self, key ):
"del net[ name ] operator - delete node with given name"
self.delNode( self.nameToNode[ key ] )
def __iter__( self ):
"return iterator over nodes"
return chain( self.hosts, self.switches, self.controllers )
"return iterator over node names"
for node in chain( self.hosts, self.switches, self.controllers ):
yield node.name
def __len__( self ):
"returns number of nodes in net"
return ( len( self.hosts ) + len( self.switches ) +
len( self.controllers ) )
def __contains__( self, item ):
"returns True if net contains named node"
return item in self.nameToNode
def keys( self ):
"return a list of all node names or net's keys"
return list( self )
def values( self ):
"return a list of all nodes or net's values"
return [ self[name] for name in self ]
def items( self ):
"return (key,value) tuple list for every node in net"
return zip( self.keys(), self.values() )
@staticmethod
def randMac():
"Return a random, non-multicast MAC address"
return macColonHex( random.randint(1, 2**48 - 1) & 0xfeffffffffff |
0x020000000000 )
def addLink( self, node1, node2, port1=None, port2=None,
cls=None, **params ):
""""Add a link from node1 to node2
node1: source node
node2: dest node
port1: source port
port2: dest port
node1: source node (or name)
node2: dest node (or name)
port1: source port (optional)
port2: dest port (optional)
cls: link class (optional)
params: additional link params (optional)
returns: link object"""
defaults = { 'port1': port1,
'port2': port2,
'intf': self.intf }
defaults.update( params )
if not cls:
cls = self.link
link = cls( node1, node2, **defaults )
# 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 ]
options = dict( params )
# Port is optional
if port1 is not None:
options.setdefault( 'port1', port1 )
if port2 is not None:
options.setdefault( 'port2', port2 )
if self.intf is not None:
options.setdefault( 'intf', self.intf )
# Set default MAC - this should probably be in Link
options.setdefault( 'addr1', self.randMac() )
options.setdefault( 'addr2', self.randMac() )
cls = self.link if cls is None else cls
link = cls( node1, node2, **options )
self.links.append( link )
return link
def delLink( self, link ):
"Remove a link from this network"
link.delete()
self.links.remove( link )
def linksBetween( self, node1, node2 ):
"Return Links between node1 and node2"
return [ link for link in self.links
if ( node1, node2 ) in (
( link.intf1.node, link.intf2.node ),
( link.intf2.node, link.intf1.node ) ) ]
def delLinkBetween( self, node1, node2, index=0, allLinks=False ):
"""Delete link(s) between node1 and node2
index: index of link to delete if multiple links (0)
allLinks: ignore index and delete all such links (False)
returns: deleted link(s)"""
links = self.linksBetween( node1, node2 )
if not allLinks:
links = [ links[ index ] ]
for link in links:
self.delLink( link )
return links
def configHosts( self ):
"Configure a set of hosts."
for host in self.hosts:
info( host.name + ' ' )
intf = host.defaultIntf()
if intf:
host.configDefault( defaultRoute=intf )
host.configDefault()
else:
# Don't configure nonexistent intf
host.configDefault( ip=None, mac=None )
@@ -273,7 +441,6 @@ class Mininet( object ):
# quietRun( 'renice +18 -p ' + repr( host.pid ) )
# This may not be the right place to do this, but
# it needs to be done somewhere.
host.cmd( 'ifconfig lo up' )
info( '\n' )
def buildFromTopo( self, topo=None ):
@@ -288,14 +455,18 @@ class Mininet( object ):
info( '*** Creating network\n' )
if not self.controllers:
if not self.controllers and self.controller:
# Add a default controller
info( '*** Adding controller\n' )
classes = self.controller
if type( classes ) is not list:
if not isinstance( classes, list ):
classes = [ classes ]
for i, cls in enumerate( classes ):
self.addController( 'c%d' % i, cls )
# Allow Controller objects because nobody understands partial()
if isinstance( cls, Controller ):
self.addController( cls )
else:
self.addController( 'c%d' % i, cls )
info( '*** Adding hosts:\n' )
for hostName in topo.hosts():
@@ -304,16 +475,19 @@ class Mininet( object ):
info( '\n*** Adding switches:\n' )
for switchName in topo.switches():
self.addSwitch( switchName, **topo.nodeInfo( switchName) )
# A bit ugly: add batch parameter if appropriate
params = topo.nodeInfo( switchName)
cls = params.get( 'cls', self.switch )
if hasattr( cls, 'batchStartup' ):
params.setdefault( 'batch', True )
self.addSwitch( switchName, **params )
info( switchName + ' ' )
info( '\n*** Adding links:\n' )
for srcName, dstName in topo.links(sort=True):
src, dst = self.nameToNode[ srcName ], self.nameToNode[ dstName ]
params = topo.linkInfo( srcName, dstName )
srcPort, dstPort = topo.port( srcName, dstName )
self.addLink( src, dst, srcPort, dstPort, **params )
info( '(%s, %s) ' % ( src.name, dst.name ) )
for srcName, dstName, params in topo.links(
sort=True, withInfo=True ):
self.addLink( **params )
info( '(%s, %s) ' % ( srcName, dstName ) )
info( '\n' )
@@ -326,7 +500,7 @@ class Mininet( object ):
"Build mininet."
if self.topo:
self.buildFromTopo( self.topo )
if ( self.inNamespace ):
if self.inNamespace:
self.configureControlNetwork()
info( '*** Configuring hosts\n' )
self.configHosts()
@@ -338,6 +512,9 @@ class Mininet( object ):
def startTerms( self ):
"Start a terminal for each node."
if 'DISPLAY' not in os.environ:
error( "Error starting terms: Cannot connect to display\n" )
return
info( "*** Running terms on %s\n" % os.environ[ 'DISPLAY' ] )
cleanUpScreens()
self.terms += makeTerms( self.controllers, 'controller' )
@@ -363,46 +540,59 @@ class Mininet( object ):
self.build()
info( '*** Starting controller\n' )
for controller in self.controllers:
info( controller.name + ' ')
controller.start()
info( '\n' )
info( '*** Starting %s switches\n' % len( self.switches ) )
for switch in self.switches:
info( switch.name + ' ')
switch.start( self.controllers )
started = {}
for swclass, switches in groupby(
sorted( self.switches,
key=lambda s: str( type( s ) ) ), 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()
def stop( self ):
"Stop the controller(s), switches and hosts"
if self.terms:
info( '*** Stopping %i terms\n' % len( self.terms ) )
self.stopXterms()
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
for controller in self.controllers:
info( controller.name + ' ' )
controller.stop()
info( '\n' )
info( '*** Stopping %i switches\n' % len( self.switches ) )
for switch in self.switches:
info( switch.name + ' ' )
switch.stop( deleteIntfs=False )
info( '\n' )
info( '*** Removing links\n' )
if self.terms:
info( '*** Stopping %i terms\n' % len( self.terms ) )
self.stopXterms()
info( '*** Stopping %i links\n' % len( self.links ) )
for link in self.links:
info( '.' )
link.delete()
info( '\n*** Terminating switches\n' )
link.stop()
info( '\n' )
info( '*** Stopping %i switches\n' % len( self.switches ) )
stopped = {}
for swclass, switches in groupby(
sorted( self.switches,
key=lambda s: str( type( s ) ) ), type ):
switches = tuple( switches )
if hasattr( swclass, 'batchShutdown' ):
success = swclass.batchShutdown( switches )
stopped.update( { s: s for s in success } )
for switch in self.switches:
info( '.' )
info( switch.name + ' ' )
if switch not in stopped:
switch.stop()
switch.terminate()
info( '\n' )
info( '*** Stopping %i hosts\n' % len( self.hosts ) )
for host in self.hosts:
info( host.name + ' ' )
host.terminate()
info( '\n' )
nses = quietRun( 'ip netns list').strip().split()
info( '*** Removing namespaces' )
for ns in nses:
errFail( 'ip netns del ' + ns )
info( '\n*** Done\n' )
def run( self, test, *args, **kwargs ):
@@ -422,13 +612,13 @@ class Mininet( object ):
if hosts is None:
hosts = self.hosts
poller = select.poll()
Node = hosts[ 0 ] # so we can call class method fdToNode
h1 = hosts[ 0 ] # so we can call class method fdToNode
for host in hosts:
poller.register( host.stdout )
while True:
ready = poller.poll( timeoutms )
for fd, event in ready:
host = Node.fdToNode( fd )
host = h1.fdToNode( fd )
if event & select.POLLIN:
line = host.readline()
if line is not None:
@@ -445,13 +635,13 @@ class Mininet( object ):
"Parse ping output and return packets sent, received."
# Check for downed link
if 'connect: Network is unreachable' in pingOutput:
return (1, 0)
r = r'(\d+) packets transmitted, (\d+) received'
return 1, 0
r = r'(\d+) packets transmitted, (\d+)( packets)? received'
m = re.search( r, pingOutput )
if m is None:
error( '*** Error: could not parse ping output: %s\n' %
pingOutput )
return (1, 0)
return 1, 0
sent, received = int( m.group( 1 ) ), int( m.group( 2 ) )
return sent, received
@@ -474,8 +664,12 @@ class Mininet( object ):
opts = ''
if timeout:
opts = '-W %s' % timeout
result = node.cmd( 'ping -c1 %s %s' % (opts, dest.IP()) )
sent, received = self._parsePing( result )
if dest.intfs:
result = node.cmd( 'ping -c1 %s %s' %
(opts, dest.IP()) )
sent, received = self._parsePing( result )
else:
sent, received = 0, 0
packets += sent
if received > sent:
error( '*** Error: received too many packets' )
@@ -485,27 +679,41 @@ class Mininet( object ):
lost += sent - received
output( ( '%s ' % dest.name ) if received else 'X ' )
output( '\n' )
ploss = 100 * lost / packets
output( "*** Results: %i%% dropped (%d/%d lost)\n" %
( ploss, lost, packets ) )
if packets > 0:
ploss = 100.0 * lost / packets
received = packets - lost
output( "*** Results: %i%% dropped (%d/%d received)\n" %
( ploss, received, packets ) )
else:
ploss = 0
output( "*** Warning: No packets sent\n" )
return ploss
@staticmethod
def _parsePingFull( pingOutput ):
"Parse ping output and return all data."
errorTuple = (1, 0, 0, 0, 0, 0)
# Check for downed link
if 'connect: Network is unreachable' in pingOutput:
return (1, 0)
r = r'(\d+) packets transmitted, (\d+) received'
r = r'[uU]nreachable'
m = re.search( r, pingOutput )
if m is not None:
return errorTuple
r = r'(\d+) packets transmitted, (\d+)( packets)? received'
m = re.search( r, pingOutput )
if m is None:
error( '*** Error: could not parse ping output: %s\n' %
pingOutput )
return (1, 0, 0, 0, 0, 0)
return errorTuple
sent, received = int( m.group( 1 ) ), int( m.group( 2 ) )
r = r'rtt min/avg/max/mdev = '
r += r'(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+) ms'
m = re.search( r, pingOutput )
if m is None:
if received == 0:
return errorTuple
error( '*** Error: could not parse ping output: %s\n' %
pingOutput )
return errorTuple
rttmin = float( m.group( 1 ) )
rttavg = float( m.group( 2 ) )
rttmax = float( m.group( 3 ) )
@@ -545,10 +753,10 @@ class Mininet( object ):
(rttmin, rttavg, rttmax, rttdev) )
return all_outputs
def pingAll( self ):
def pingAll( self, timeout=None ):
"""Ping between all hosts.
returns: ploss packet loss percentage"""
return self.ping()
return self.ping( timeout=timeout )
def pingPair( self ):
"""Ping between first two hosts, useful for testing.
@@ -583,41 +791,48 @@ class Mininet( object ):
# XXX This should be cleaned up
def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
def iperf( self, hosts=None, l4Type='TCP', udpBw='10M', fmt=None,
seconds=5, port=5001):
"""Run iperf between two hosts.
hosts: list of hosts; if None, uses opposite hosts
hosts: list of hosts; if None, uses first and last hosts
l4Type: string, one of [ TCP, UDP ]
returns: results two-element array of server and client speeds"""
if not quietRun( 'which telnet' ):
error( 'Cannot find telnet in $PATH - required for iperf test' )
return
if not hosts:
hosts = [ self.hosts[ 0 ], self.hosts[ -1 ] ]
else:
assert len( hosts ) == 2
udpBw: bandwidth target for UDP test
fmt: iperf format argument if any
seconds: iperf time to transmit
port: iperf port
returns: two-element array of [ server, client ] speeds
note: send() is buffered, so client rate can be much higher than
the actual transmission rate; on an unloaded system, server
rate should be much closer to the actual receive rate"""
hosts = hosts or [ self.hosts[ 0 ], self.hosts[ -1 ] ]
assert len( hosts ) == 2
client, server = hosts
output( '*** Iperf: testing ' + l4Type + ' bandwidth between ' )
output( "%s and %s\n" % ( client.name, server.name ) )
output( '*** Iperf: testing', l4Type, 'bandwidth between',
client, 'and', server, '\n' )
server.cmd( 'killall -9 iperf' )
iperfArgs = 'iperf '
iperfArgs = 'iperf -p %d ' % port
bwArgs = ''
if l4Type == 'UDP':
iperfArgs += '-u '
bwArgs = '-b ' + udpBw + ' '
elif l4Type != 'TCP':
raise Exception( 'Unexpected l4 type: %s' % l4Type )
server.sendCmd( iperfArgs + '-s', printPid=True )
servout = ''
while server.lastPid is None:
servout += server.monitor()
if fmt:
iperfArgs += '-f %s ' % fmt
server.sendCmd( iperfArgs + '-s' )
if l4Type == 'TCP':
while 'Connected' not in client.cmd(
'sh -c "echo A | telnet -e A %s 5001"' % server.IP()):
output('waiting for iperf to start up...')
sleep(.5)
cliout = client.cmd( iperfArgs + '-t 5 -c ' + server.IP() + ' ' +
bwArgs )
if not waitListening( client, server.IP(), port ):
raise Exception( 'Could not connect to iperf on port %d'
% port )
cliout = client.cmd( iperfArgs + '-t %d -c ' % seconds +
server.IP() + ' ' + bwArgs )
debug( 'Client output: %s\n' % cliout )
servout = ''
# We want the last *b/sec from the iperf server output
# for TCP, there are two of them because of waitListening
count = 2 if l4Type == 'TCP' else 1
while len( re.findall( '/sec', servout ) ) < count:
servout += server.monitor( timeoutms=5000 )
server.sendInt()
servout += server.waitOutput()
debug( 'Server output: %s\n' % servout )
@@ -630,36 +845,45 @@ class Mininet( object ):
def runCpuLimitTest( self, cpu, duration=5 ):
"""run CPU limit test with 'while true' processes.
cpu: desired CPU fraction of each host
duration: test duration in seconds
duration: test duration in seconds (integer)
returns a single list of measured CPU fractions as floats.
"""
pct = cpu * 100
info('*** Testing CPU %.0f%% bandwidth limit\n' % pct)
info( '*** Testing CPU %.0f%% bandwidth limit\n' % pct )
hosts = self.hosts
cores = int( quietRun( 'nproc' ) )
# number of processes to run a while loop on per host
num_procs = int( ceil( cores * cpu ) )
pids = {}
for h in hosts:
h.cmd( 'while true; do a=1; done &' )
pids = [h.cmd( 'echo $!' ).strip() for h in hosts]
pids_str = ",".join(["%s" % pid for pid in pids])
cmd = 'ps -p %s -o pid,%%cpu,args' % pids_str
# It's a shame that this is what pylint prefers
outputs = []
pids[ h ] = []
for _core in range( num_procs ):
h.cmd( 'while true; do a=1; done &' )
pids[ h ].append( h.cmd( 'echo $!' ).strip() )
outputs = {}
time = {}
# get the initial cpu time for each host
for host in hosts:
outputs[ host ] = []
with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' %
host, 'r' ) as f:
time[ host ] = float( f.read() )
for _ in range( duration ):
sleep( 1 )
outputs.append( quietRun( cmd ).strip() )
for h in hosts:
h.cmd( 'kill %1' )
for host in hosts:
with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' %
host, 'r' ) as f:
readTime = float( f.read() )
outputs[ host ].append( ( ( readTime - time[ host ] )
/ 1000000000 ) / cores * 100 )
time[ host ] = readTime
for h, pids in pids.items():
for pid in pids:
h.cmd( 'kill -9 %s' % pid )
cpu_fractions = []
for test_output in outputs:
# Split by line. Ignore first line, which looks like this:
# PID %CPU COMMAND\n
for line in test_output.split('\n')[1:]:
r = r'\d+\s*(\d+\.\d+)'
m = re.search( r, line )
if m is None:
error( '*** Error: could not extract CPU fraction: %s\n' %
line )
return None
cpu_fractions.append( float( m.group( 1 ) ) )
for _host, outputs in outputs.items():
for pct in outputs:
cpu_fractions.append( pct )
output( '*** Results: %s\n' % cpu_fractions )
return cpu_fractions
@@ -675,10 +899,8 @@ class Mininet( object ):
elif dst not in self.nameToNode:
error( 'dst not in network: %s\n' % dst )
else:
if type( src ) is str:
src = self.nameToNode[ src ]
if type( dst ) is str:
dst = self.nameToNode[ dst ]
src = self.nameToNode[ src ]
dst = self.nameToNode[ dst ]
connections = src.connectionsTo( dst )
if len( connections ) == 0:
error( 'src and dst not connected: %s %s\n' % ( src, dst) )
+721 -260
View File
File diff suppressed because it is too large Load Diff
+145
View File
@@ -0,0 +1,145 @@
"""
Node Library for Mininet
This contains additional Node types which you may find to be useful.
"""
from mininet.node import Node, Switch
from mininet.log import info, warn
from mininet.moduledeps import pathCheck
from mininet.util import quietRun
class LinuxBridge( Switch ):
"Linux Bridge (with optional spanning tree)"
nextPrio = 100 # next bridge priority for spanning tree
def __init__( self, name, stp=False, prio=None, **kwargs ):
"""stp: use spanning tree protocol? (default False)
prio: optional explicit bridge priority for STP"""
self.stp = stp
if prio:
self.prio = prio
else:
self.prio = LinuxBridge.nextPrio
LinuxBridge.nextPrio += 1
Switch.__init__( self, name, **kwargs )
def connected( self ):
"Are we forwarding yet?"
if self.stp:
return 'forwarding' in self.cmd( 'brctl showstp', self )
else:
return True
def start( self, _controllers ):
"Start Linux bridge"
self.cmd( 'ifconfig', self, 'down' )
self.cmd( 'brctl delbr', self )
self.cmd( 'brctl addbr', self )
if self.stp:
self.cmd( 'brctl setbridgeprio', self.prio )
self.cmd( 'brctl stp', self, 'on' )
for i in self.intfList():
if self.name in i.name:
self.cmd( 'brctl addif', self, i )
self.cmd( 'ifconfig', self, 'up' )
def stop( self, deleteIntfs=True ):
"""Stop Linux bridge
deleteIntfs: delete interfaces? (True)"""
self.cmd( 'ifconfig', self, 'down' )
self.cmd( 'brctl delbr', self )
super( LinuxBridge, self ).stop( deleteIntfs )
def dpctl( self, *args ):
"Run brctl command"
return self.cmd( 'brctl', *args )
@classmethod
def setup( cls ):
"Check dependencies and warn about firewalling"
pathCheck( 'brctl', moduleName='bridge-utils' )
# Disable Linux bridge firewalling so that traffic can flow!
for table in 'arp', 'ip', 'ip6':
cmd = 'sysctl net.bridge.bridge-nf-call-%stables' % table
out = quietRun( cmd ).strip()
if out.endswith( '1' ):
warn( 'Warning: Linux bridge may not work with', out, '\n' )
class NAT( Node ):
"NAT: Provides connectivity to external network"
def __init__( self, name, subnet='10.0/8',
localIntf=None, flush=False, **params):
"""Start NAT/forwarding between Mininet and external network
subnet: Mininet subnet (default 10.0/8)
flush: flush iptables before installing NAT rules"""
super( NAT, self ).__init__( name, **params )
self.subnet = subnet
self.localIntf = localIntf
self.flush = flush
self.forwardState = self.cmd( 'sysctl -n net.ipv4.ip_forward' ).strip()
def config( self, **params ):
"""Configure the NAT and iptables"""
super( NAT, self).config( **params )
if not self.localIntf:
self.localIntf = self.defaultIntf()
if self.flush:
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
self.cmd( 'iptables -F' )
self.cmd( 'iptables -t nat -F' )
# Create default entries for unmatched traffic
self.cmd( 'iptables -P INPUT ACCEPT' )
self.cmd( 'iptables -P OUTPUT ACCEPT' )
self.cmd( 'iptables -P FORWARD DROP' )
# Install NAT rules
self.cmd( 'iptables -I FORWARD',
'-i', self.localIntf, '-d', self.subnet, '-j DROP' )
self.cmd( 'iptables -A FORWARD',
'-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -A FORWARD',
'-o', self.localIntf, '-d', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -t nat -A POSTROUTING',
'-s', self.subnet, "'!'", '-d', self.subnet,
'-j MASQUERADE' )
# 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
self.cmd( 'iptables -D FORWARD',
'-i', self.localIntf, '-d', self.subnet, '-j DROP' )
self.cmd( 'iptables -D FORWARD',
'-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -D FORWARD',
'-o', self.localIntf, '-d', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -t nat -D POSTROUTING',
'-s', self.subnet, '\'!\'', '-d', self.subnet,
'-j MASQUERADE' )
# Put the forwarding state back to what it was
self.cmd( 'sysctl net.ipv4.ip_forward=%s' % self.forwardState )
super( NAT, self ).terminate()
+19 -5
View File
@@ -15,8 +15,11 @@ def tunnelX11( node, display=None):
"""Create an X11 tunnel from node:6000 to the root host
display: display on root host (optional)
returns: node $DISPLAY, Popen object for tunnel"""
if display is None:
if display is None and 'DISPLAY' in environ:
display = environ[ 'DISPLAY' ]
if display is None:
error( "Error: Cannot connect to display\n" )
return None, None
host, screen = display.split( ':' )
# Unix sockets should work
if not host or host == 'unix':
@@ -29,16 +32,16 @@ def tunnelX11( node, display=None):
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 ]
"EXEC:'mnexec -a 1 socat STDIO %s'" % connection ]
return 'localhost:' + screen, node.popen( cmd )
def makeTerm( node, title='Node', term='xterm', display=None ):
def makeTerm( node, title='Node', term='xterm', display=None, cmd='bash'):
"""Create an X11 tunnel to the node and start up a terminal.
node: Node object
title: base title
term: 'xterm' or 'gterm'
returns: two Popen objects, tunnel and terminal"""
title += ': ' + node.name
title = '"%s: %s"' % ( title, node.name )
if not node.inNamespace:
title += ' (root)'
cmds = {
@@ -49,9 +52,20 @@ def makeTerm( node, title='Node', term='xterm', display=None ):
error( 'invalid terminal type: %s' % term )
return
display, tunnel = tunnelX11( node, display )
term = node.popen( cmds[ term ] + [ display, '-e', 'env TERM=ansi bash'] )
if display is None:
return []
term = node.popen( cmds[ term ] +
[ display, '-e', 'env TERM=ansi %s' % cmd ] )
return [ tunnel, term ] if tunnel else [ term ]
def runX11( node, cmd ):
"Run an X11 client on a node"
_display, tunnel = tunnelX11( node )
if _display is None:
return []
popen = node.popen( cmd )
return [ tunnel, popen ]
def cleanUpScreens():
"Remove moldy socat X11 tunnels."
errRun( "pkill -9 -f mnexec.*socat" )
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env python
"""
Run all mininet core tests
-v : verbose output
-quick : skip tests that take more than ~30 seconds
"""
from unittest import defaultTestLoader, TextTestRunner
import os
import sys
from mininet.util import ensureRoot
from mininet.clean import cleanup
from mininet.log import setLogLevel
def runTests( testDir, verbosity=1 ):
"discover and run all tests in testDir"
# ensure root and cleanup before starting tests
ensureRoot()
cleanup()
# discover all tests in testDir
testSuite = defaultTestLoader.discover( testDir )
# run tests
success = ( TextTestRunner( verbosity=verbosity )
.run( testSuite ).wasSuccessful() )
sys.exit( 0 if success else 1 )
if __name__ == '__main__':
setLogLevel( 'warning' )
# get the directory containing example tests
thisdir = os.path.dirname( os.path.realpath( __file__ ) )
vlevel = 2 if '-v' in sys.argv else 1
runTests( testDir=thisdir, verbosity=vlevel )
+169 -28
View File
@@ -4,16 +4,18 @@
Test creation and pings for topologies with link and/or CPU options."""
import unittest
import sys
from functools import partial
from mininet.net import Mininet
from mininet.node import OVSKernelSwitch
from mininet.node import OVSSwitch, UserSwitch, IVSSwitch
from mininet.node import CPULimitedHost
from mininet.link import TCLink
from mininet.topo import Topo
from mininet.log import setLogLevel
from mininet.util import quietRun
from mininet.clean import cleanup
SWITCH = OVSKernelSwitch
# Number of hosts for each test
N = 2
@@ -31,24 +33,62 @@ class SingleSwitchOptionsTopo(Topo):
host = self.addHost('h%s' % (h + 1))
self.addLink(host, switch)
# Tell pylint not to complain about calls to other class
# pylint: disable=E1101
class testOptionsTopo( unittest.TestCase ):
"Verify ability to create networks with host and link options."
class testOptionsTopoCommon( object ):
"""Verify ability to create networks with host and link options
(common code)."""
def runOptionsTopoTest( self, n, hopts=None, lopts=None ):
switchClass = None # overridden in subclasses
@staticmethod
def tearDown():
"Clean up if necessary"
if sys.exc_info != ( None, None, None ):
cleanup()
def runOptionsTopoTest( self, n, msg, hopts=None, lopts=None ):
"Generic topology-with-options test runner."
mn = Mininet( topo=SingleSwitchOptionsTopo( n=n, hopts=hopts,
lopts=lopts ),
host=CPULimitedHost, link=TCLink )
host=CPULimitedHost, link=TCLink,
switch=self.switchClass, waitConnected=True )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
hoptsStr = ', '.join( '%s: %s' % ( opt, value )
for opt, value in hopts.items() )
loptsStr = ', '.join( '%s: %s' % ( opt, value )
for opt, value in lopts.items() )
msg += ( '%s%% of pings were dropped during mininet.ping().\n'
'Topo = SingleSwitchTopo, %s hosts\n'
'hopts = %s\n'
'lopts = %s\n'
'host = CPULimitedHost\n'
'link = TCLink\n'
'Switch = %s\n'
% ( dropped, n, hoptsStr, loptsStr, self.switchClass ) )
def assertWithinTolerance(self, measured, expected, tolerance_frac):
self.assertEqual( dropped, 0, msg=msg )
def assertWithinTolerance( self, measured, expected, tolerance_frac, msg ):
"""Check that a given value is within a tolerance of expected
tolerance_frac: less-than-1.0 value; 0.8 would yield 20% tolerance.
"""
self.assertTrue( float(measured) >= float(expected) * tolerance_frac )
self.assertTrue( float(measured) >= float(expected) * tolerance_frac )
upperBound = ( float( expected ) + ( 1 - tolerance_frac ) *
float( expected ) )
lowerBound = float( expected ) * tolerance_frac
info = ( 'measured value is out of bounds\n'
'expected value: %s\n'
'measured value: %s\n'
'failure tolerance: %s\n'
'upper bound: %s\n'
'lower bound: %s\n'
% ( expected, measured, tolerance_frac,
upperBound, lowerBound ) )
msg += info
self.assertGreaterEqual( float( measured ), lowerBound, msg=msg )
self.assertLessEqual( float( measured ), upperBound, msg=msg )
def testCPULimits( self ):
"Verify topology creation with CPU limits set for both schedulers."
@@ -58,46 +98,102 @@ class testOptionsTopo( unittest.TestCase ):
#self.runOptionsTopoTest( N, hopts=hopts )
mn = Mininet( SingleSwitchOptionsTopo( n=N, hopts=hopts ),
host=CPULimitedHost )
host=CPULimitedHost, switch=self.switchClass,
waitConnected=True )
mn.start()
results = mn.runCpuLimitTest( cpu=CPU_FRACTION )
mn.stop()
for cpu in results:
self.assertWithinTolerance( cpu, CPU_FRACTION, CPU_TOLERANCE )
hostUsage = '\n'.join( 'h%s: %s' %
( n + 1,
results[ (n - 1) * 5 : (n * 5) - 1 ] )
for n in range( N ) )
hoptsStr = ', '.join( '%s: %s' % ( opt, value )
for opt, value in hopts.items() )
msg = ( '\nTesting cpu limited to %d%% of cpu per host\n'
'cpu usage percent per host:\n%s\n'
'Topo = SingleSwitchTopo, %s hosts\n'
'hopts = %s\n'
'host = CPULimitedHost\n'
'Switch = %s\n'
% ( CPU_FRACTION * 100, hostUsage, N, hoptsStr,
self.switchClass ) )
for pct in results:
#divide cpu by 100 to convert from percentage to fraction
self.assertWithinTolerance( pct/100, CPU_FRACTION,
CPU_TOLERANCE, msg )
def testLinkBandwidth( self ):
"Verify that link bandwidths are accurate within a bound."
if self.switchClass is UserSwitch:
self.skipTest( 'UserSwitch has very poor performance -'
' skipping for now' )
BW = 5 # Mbps
BW_TOLERANCE = 0.8 # BW fraction below which test should fail
# Verify ability to create limited-link topo first;
lopts = { 'bw': BW, 'use_htb': True }
# Also verify correctness of limit limitng within a bound.
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
link=TCLink )
bw_strs = mn.run( mn.iperf )
for bw_str in bw_strs:
bw = float( bw_str.split(' ')[0] )
self.assertWithinTolerance( bw, BW, BW_TOLERANCE )
link=TCLink, switch=self.switchClass,
waitConnected=True )
bw_strs = mn.run( mn.iperf, fmt='m' )
loptsStr = ', '.join( '%s: %s' % ( opt, value )
for opt, value in lopts.items() )
msg = ( '\nTesting link bandwidth limited to %d Mbps per link\n'
'iperf results[ client, server ]: %s\n'
'Topo = SingleSwitchTopo, %s hosts\n'
'Link = TCLink\n'
'lopts = %s\n'
'host = default\n'
'switch = %s\n'
% ( BW, bw_strs, N, loptsStr, self.switchClass ) )
# On the client side, iperf doesn't wait for ACKs - it simply
# reports how long it took to fill up the TCP send buffer.
# As long as the kernel doesn't wait a long time before
# delivering bytes to the iperf server, its reported data rate
# should be close to the actual receive rate.
serverRate, _clientRate = bw_strs
bw = float( serverRate.split(' ')[0] )
self.assertWithinTolerance( bw, BW, BW_TOLERANCE, msg )
def testLinkDelay( self ):
"Verify that link delays are accurate within a bound."
DELAY_MS = 15
DELAY_TOLERANCE = 0.8 # Delay fraction below which test should fail
REPS = 3
lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True }
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
link=TCLink )
ping_delays = mn.run( mn.pingFull )
link=TCLink, switch=self.switchClass, autoStaticArp=True,
waitConnected=True )
mn.start()
for _ in range( REPS ):
ping_delays = mn.pingFull()
mn.stop()
test_outputs = ping_delays[0]
# Ignore unused variables below
# pylint: disable-msg=W0612
# pylint: disable=W0612
node, dest, ping_outputs = test_outputs
sent, received, rttmin, rttavg, rttmax, rttdev = ping_outputs
self.assertEqual( sent, received )
# pylint: enable-msg=W0612
pingFailMsg = 'sent %s pings, only received %s' % ( sent, received )
self.assertEqual( sent, received, msg=pingFailMsg )
# pylint: enable=W0612
loptsStr = ', '.join( '%s: %s' % ( opt, value )
for opt, value in lopts.items() )
msg = ( '\nTesting Link Delay of %s ms\n'
'ping results across 4 links:\n'
'(Sent, Received, rttmin, rttavg, rttmax, rttdev)\n'
'%s\n'
'Topo = SingleSwitchTopo, %s hosts\n'
'Link = TCLink\n'
'lopts = %s\n'
'host = default'
'switch = %s\n'
% ( DELAY_MS, ping_outputs, N, loptsStr, self.switchClass ) )
for rttval in [rttmin, rttavg, rttmax]:
# Multiply delay by 4 to cover there & back on two links
self.assertWithinTolerance( rttval, DELAY_MS * 4.0,
DELAY_TOLERANCE)
DELAY_TOLERANCE, msg )
def testLinkLoss( self ):
"Verify that we see packet drops with a high configured loss rate."
@@ -105,7 +201,9 @@ class testOptionsTopo( unittest.TestCase ):
REPS = 1
lopts = { 'loss': LOSS_PERCENT, 'use_htb': True }
mn = Mininet( topo=SingleSwitchOptionsTopo( n=N, lopts=lopts ),
host=CPULimitedHost, link=TCLink )
host=CPULimitedHost, link=TCLink,
switch=self.switchClass,
waitConnected=True )
# Drops are probabilistic, but the chance of no dropped packets is
# 1 in 100 million with 4 hops for a link w/99% loss.
dropped_total = 0
@@ -113,14 +211,57 @@ class testOptionsTopo( unittest.TestCase ):
for _ in range(REPS):
dropped_total += mn.ping(timeout='1')
mn.stop()
self.assertTrue(dropped_total > 0)
loptsStr = ', '.join( '%s: %s' % ( opt, value )
for opt, value in lopts.items() )
msg = ( '\nTesting packet loss with %d%% loss rate\n'
'number of dropped pings during mininet.ping(): %s\n'
'expected number of dropped packets: 1\n'
'Topo = SingleSwitchTopo, %s hosts\n'
'Link = TCLink\n'
'lopts = %s\n'
'host = default\n'
'switch = %s\n'
% ( LOSS_PERCENT, dropped_total, N, loptsStr,
self.switchClass ) )
self.assertGreater( dropped_total, 0, msg )
def testMostOptions( self ):
"Verify topology creation with most link options and CPU limits."
lopts = { 'bw': 10, 'delay': '5ms', 'use_htb': True }
hopts = { 'cpu': 0.5 / N }
self.runOptionsTopoTest( N, hopts=hopts, lopts=lopts )
msg = '\nTesting many cpu and link options\n'
self.runOptionsTopoTest( N, msg, hopts=hopts, lopts=lopts )
# pylint: enable=E1101
class testOptionsTopoOVSKernel( testOptionsTopoCommon, unittest.TestCase ):
"""Verify ability to create networks with host and link options
(OVS kernel switch)."""
longMessage = True
switchClass = OVSSwitch
@unittest.skip( 'Skipping OVS user switch test for now' )
class testOptionsTopoOVSUser( testOptionsTopoCommon, unittest.TestCase ):
"""Verify ability to create networks with host and link options
(OVS user switch)."""
longMessage = True
switchClass = partial( OVSSwitch, datapath='user' )
@unittest.skipUnless( quietRun( 'which ivs-ctl' ), 'IVS is not installed' )
class testOptionsTopoIVS( testOptionsTopoCommon, unittest.TestCase ):
"Verify ability to create networks with host and link options (IVS)."
longMessage = True
switchClass = IVSSwitch
@unittest.skipUnless( quietRun( 'which ofprotocol' ),
'Reference user switch is not installed' )
class testOptionsTopoUserspace( testOptionsTopoCommon, unittest.TestCase ):
"""Verify ability to create networks with host and link options
(UserSwitch)."""
longMessage = True
switchClass = UserSwitch
if __name__ == '__main__':
setLogLevel( 'warning' )
+81 -23
View File
@@ -4,45 +4,103 @@
Test creation and all-pairs ping for each included mininet topo type."""
import unittest
import sys
from functools import partial
from mininet.net import Mininet
from mininet.node import Host, Controller
from mininet.node import UserSwitch, OVSKernelSwitch
from mininet.node import UserSwitch, OVSSwitch, IVSSwitch
from mininet.topo import SingleSwitchTopo, LinearTopo
from mininet.log import setLogLevel
from mininet.util import quietRun
from mininet.clean import cleanup
SWITCHES = { 'user': UserSwitch,
'ovsk': OVSKernelSwitch,
}
# Tell pylint not to complain about calls to other class
# pylint: disable=E1101
class testSingleSwitchCommon( object ):
"Test ping with single switch topology (common code)."
class testSingleSwitch( unittest.TestCase ):
"For each datapath type, test ping with single switch topologies."
switchClass = None # overridden in subclasses
@staticmethod
def tearDown():
"Clean up if necessary"
if sys.exc_info != ( None, None, None ):
cleanup()
def testMinimal( self ):
"Ping test with both datapaths on minimal topology"
for switch in SWITCHES.values():
mn = Mininet( SingleSwitchTopo(), switch, Host, Controller )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
"Ping test on minimal topology"
mn = Mininet( SingleSwitchTopo(), self.switchClass, Host, Controller,
waitConnected=True )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
def testSingle5( self ):
"Ping test with both datapaths on 5-host single-switch topology"
for switch in SWITCHES.values():
mn = Mininet( SingleSwitchTopo( k=5 ), switch, Host, Controller )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
"Ping test on 5-host single-switch topology"
mn = Mininet( SingleSwitchTopo( k=5 ), self.switchClass, Host,
Controller, waitConnected=True )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
# pylint: enable=E1101
class testSingleSwitchOVSKernel( testSingleSwitchCommon, unittest.TestCase ):
"Test ping with single switch topology (OVS kernel switch)."
switchClass = OVSSwitch
class testSingleSwitchOVSUser( testSingleSwitchCommon, unittest.TestCase ):
"Test ping with single switch topology (OVS user switch)."
switchClass = partial( OVSSwitch, datapath='user' )
@unittest.skipUnless( quietRun( 'which ivs-ctl' ), 'IVS is not installed' )
class testSingleSwitchIVS( testSingleSwitchCommon, unittest.TestCase ):
"Test ping with single switch topology (IVS switch)."
switchClass = IVSSwitch
@unittest.skipUnless( quietRun( 'which ofprotocol' ),
'Reference user switch is not installed' )
class testSingleSwitchUserspace( testSingleSwitchCommon, unittest.TestCase ):
"Test ping with single switch topology (Userspace switch)."
switchClass = UserSwitch
class testLinear( unittest.TestCase ):
"For each datapath type, test all-pairs ping with LinearNet."
# Tell pylint not to complain about calls to other class
# pylint: disable=E1101
class testLinearCommon( object ):
"Test all-pairs ping with LinearNet (common code)."
switchClass = None # overridden in subclasses
def testLinear5( self ):
"Ping test with both datapaths on a 5-switch topology"
for switch in SWITCHES.values():
mn = Mininet( LinearTopo( k=5 ), switch, Host, Controller )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
"Ping test on a 5-switch topology"
mn = Mininet( LinearTopo( k=5 ), self.switchClass, Host,
Controller, waitConnected=True )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
# pylint: enable=E1101
class testLinearOVSKernel( testLinearCommon, unittest.TestCase ):
"Test all-pairs ping with LinearNet (OVS kernel switch)."
switchClass = OVSSwitch
class testLinearOVSUser( testLinearCommon, unittest.TestCase ):
"Test all-pairs ping with LinearNet (OVS user switch)."
switchClass = partial( OVSSwitch, datapath='user' )
@unittest.skipUnless( quietRun( 'which ivs-ctl' ), 'IVS is not installed' )
class testLinearIVS( testLinearCommon, unittest.TestCase ):
"Test all-pairs ping with LinearNet (IVS switch)."
switchClass = IVSSwitch
@unittest.skipUnless( quietRun( 'which ofprotocol' ),
'Reference user switch is not installed' )
class testLinearUserspace( testLinearCommon, unittest.TestCase ):
"Test all-pairs ping with LinearNet (Userspace switch)."
switchClass = UserSwitch
if __name__ == '__main__':
+101
View File
@@ -0,0 +1,101 @@
#!/usr/bin/env python
"""Package: mininet
Regression tests for switch dpid assignment."""
import unittest
import sys
from mininet.net import Mininet
from mininet.node import Host, Controller
from mininet.node import ( UserSwitch, OVSSwitch, IVSSwitch )
from mininet.topo import Topo
from mininet.log import setLogLevel
from mininet.util import quietRun
from mininet.clean import cleanup
class TestSwitchDpidAssignmentOVS( unittest.TestCase ):
"Verify Switch dpid assignment."
switchClass = OVSSwitch # overridden in subclasses
def tearDown( self ):
"Clean up if necessary"
# satisfy pylint
assert self
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' )
self.assertEqual( switch.defaultDpid(), switch.dpid )
net.stop()
def dpidFrom( self, num ):
"Compute default dpid from number"
fmt = ( '%0' + str( self.switchClass.dpidLen ) + 'x' )
return fmt % num
def testActualDpidAssignment( self ):
"""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 )
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 '
'default datapath ID - please either specify a dpid '
'or use a canonical switch name such as s23.'
in str( raises_cm.exception ) )
net.stop()
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()
class OVSUser( OVSSwitch):
"OVS User Switch convenience class"
def __init__( self, *args, **kwargs ):
kwargs.update( datapath='user' )
OVSSwitch.__init__( self, *args, **kwargs )
class testSwitchOVSUser( TestSwitchDpidAssignmentOVS ):
"Test dpid assignnment of OVS User Switch."
switchClass = OVSUser
@unittest.skipUnless( quietRun( 'which ivs-ctl' ),
'IVS switch is not installed' )
class testSwitchIVS( TestSwitchDpidAssignmentOVS ):
"Test dpid assignment of IVS switch."
switchClass = IVSSwitch
@unittest.skipUnless( quietRun( 'which ofprotocol' ),
'Reference user switch is not installed' )
class testSwitchUserspace( TestSwitchDpidAssignmentOVS ):
"Test dpid assignment of Userspace switch."
switchClass = UserSwitch
if __name__ == '__main__':
setLogLevel( 'warning' )
unittest.main()
cleanup()
+380
View File
@@ -0,0 +1,380 @@
#!/usr/bin/env python
"""
Tests for the Mininet Walkthrough
TODO: missing xterm test
"""
import unittest
import os
import re
from mininet.util import quietRun, pexpect
from distutils.version import StrictVersion
from time import sleep
def tsharkVersion():
"Return tshark version"
versionStr = quietRun( 'tshark -v' )
versionMatch = re.findall( r'TShark[^\d]*(\d+.\d+.\d+)', versionStr )
return versionMatch[ 0 ]
# pylint doesn't understand pexpect.match, unfortunately!
# pylint:disable=maybe-no-member
class testWalkthrough( unittest.TestCase ):
"Test Mininet walkthrough"
prompt = 'mininet>'
# PART 1
def testHelp( self ):
"Check the usage message"
p = pexpect.spawn( 'mn -h' )
index = p.expect( [ 'Usage: mn', pexpect.EOF ] )
self.assertEqual( index, 0 )
def testWireshark( self ):
"Use tshark to test the of dissector"
# Satisfy pylint
assert self
if StrictVersion( tsharkVersion() ) < StrictVersion( '1.12.0' ):
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'" ] )
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( pexpect.EOF )
def testBasic( self ):
"Test basic CLI commands (help, nodes, net, dump)"
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
# help command
p.sendline( 'help' )
index = p.expect( [ 'commands', self.prompt ] )
self.assertEqual( index, 0, 'No output for "help" command')
# nodes command
p.sendline( 'nodes' )
p.expect( r'([chs]\d ?){4}' )
nodes = p.match.group( 0 ).split()
self.assertEqual( len( nodes ), 4, 'No nodes in "nodes" command')
p.expect( self.prompt )
# net command
p.sendline( 'net' )
expected = [ x for x in nodes ]
while len( expected ) > 0:
index = p.expect( expected )
node = p.match.group( 0 )
expected.remove( node )
p.expect( '\n' )
self.assertEqual( len( expected ), 0, '"nodes" and "net" differ')
p.expect( self.prompt )
# dump command
p.sendline( 'dump' )
expected = [ r'<\w+ (%s)' % n for n in nodes ]
actual = []
for _ in nodes:
index = p.expect( expected )
node = p.match.group( 1 )
actual.append( node )
p.expect( '\n' )
self.assertEqual( actual.sort(), nodes.sort(),
'"nodes" and "dump" differ' )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
def testHostCommands( self ):
"Test ifconfig and ps on h1 and s1"
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]',
self.prompt ]
# h1 ifconfig
p.sendline( 'h1 ifconfig -a' )
ifcount = 0
while True:
index = p.expect( interfaces )
if index == 0 or index == 3:
ifcount += 1
elif index == 1:
self.fail( 's1 interface displayed in "h1 ifconfig"' )
elif index == 2:
self.fail( 'eth0 displayed in "h1 ifconfig"' )
else:
break
self.assertEqual( ifcount, 2, 'Missing interfaces on h1')
# s1 ifconfig
p.sendline( 's1 ifconfig -a' )
ifcount = 0
while True:
index = p.expect( interfaces )
if index == 0:
self.fail( 'h1 interface displayed in "s1 ifconfig"' )
elif index == 1 or index == 2 or index == 3:
ifcount += 1
else:
break
self.assertTrue( ifcount <= 3, 'Missing interfaces on s1')
# h1 ps
p.sendline( "h1 ps -a | egrep -v 'ps|grep'" )
p.expect( self.prompt )
h1Output = p.before
# s1 ps
p.sendline( "s1 ps -a | egrep -v 'ps|grep'" )
p.expect( self.prompt )
s1Output = p.before
# strip command from ps output and compute diffs
h1Output = h1Output.split( '\n' )[ 1: ]
s1Output = s1Output.split( '\n' )[ 1: ]
diffs = set( h1Output ).difference( set( s1Output ) )
# allow up to two diffs to account for daemons, etc.
self.assertTrue( len( diffs ) <= 2,
'h1 and s1 "ps" output differ too much: %s' % diffs )
p.sendline( 'exit' )
p.wait()
def testConnectivity( self ):
"Test ping and pingall"
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
p.sendline( 'h1 ping -c 1 h2' )
p.expect( '1 packets transmitted, 1 received' )
p.expect( self.prompt )
p.sendline( 'pingall' )
p.expect( '0% dropped' )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
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' )
p.expect( self.prompt )
p.sendline( 'h1 python -m %s 80 &' % httpserver )
# 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 couple of seconds to make
# it less likely to fail due to the race condition.
sleep( 2 )
p.expect( self.prompt )
p.sendline( ' h2 wget -O - h1' )
p.expect( '200 OK' )
p.expect( self.prompt )
p.sendline( 'h1 kill %python' )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
# PART 2
def testRegressionRun( self ):
"Test pingpair (0% drop) and iperf (bw > 0) regression tests"
# test pingpair
p = pexpect.spawn( 'mn --test pingpair' )
p.expect( '0% dropped' )
p.expect( pexpect.EOF )
# test iperf
p = pexpect.spawn( 'mn --test iperf' )
p.expect( r"Results: \['([\d\.]+) .bits/sec'," )
bw = float( p.match.group( 1 ) )
self.assertTrue( bw > 0 )
p.expect( pexpect.EOF )
def testTopoChange( self ):
"Test pingall on single,3 and linear,4 topos"
# testing single,3
p = pexpect.spawn( 'mn --test pingall --topo single,3' )
p.expect( r'(\d+)/(\d+) received')
received = int( p.match.group( 1 ) )
sent = int( p.match.group( 2 ) )
self.assertEqual( sent, 6, 'Wrong number of pings sent in single,3' )
self.assertEqual( sent, received, 'Dropped packets in single,3')
p.expect( pexpect.EOF )
# testing linear,4
p = pexpect.spawn( 'mn --test pingall --topo linear,4' )
p.expect( r'(\d+)/(\d+) received')
received = int( p.match.group( 1 ) )
sent = int( p.match.group( 2 ) )
self.assertEqual( sent, 12, 'Wrong number of pings sent in linear,4' )
self.assertEqual( sent, received, 'Dropped packets in linear,4')
p.expect( pexpect.EOF )
def testLinkChange( self ):
"Test TCLink bw and delay"
p = pexpect.spawn( 'mn --link tc,bw=10,delay=10ms' )
# test bw
p.expect( self.prompt )
p.sendline( 'iperf' )
p.expect( r"Results: \['([\d\.]+) Mbits/sec'," )
bw = float( p.match.group( 1 ) )
self.assertTrue( bw < 10.1, 'Bandwidth %.2f >= 10.1 Mb/s' % bw )
self.assertTrue( bw > 9.0, 'Bandwidth %.2f <= 9 Mb/s' % bw )
p.expect( self.prompt )
# test delay
p.sendline( 'h1 ping -c 4 h2' )
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' )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
def testVerbosity( self ):
"Test debug and output verbosity"
# test output
p = pexpect.spawn( 'mn -v output' )
p.expect( self.prompt )
self.assertEqual( len( p.before ), 0, 'Too much output for "output"' )
p.sendline( 'exit' )
p.wait()
# test debug
p = pexpect.spawn( 'mn -v debug --test none' )
p.expect( pexpect.EOF )
lines = p.before.split( '\n' )
self.assertTrue( len( lines ) > 70, "Debug output is too short" )
def testCustomTopo( self ):
"Start Mininet using a custom topo, then run pingall"
# Satisfy pylint
assert self
custom = os.path.dirname( os.path.realpath( __file__ ) )
custom = os.path.join( custom, '../../custom/topo-2sw-2host.py' )
custom = os.path.normpath( custom )
p = pexpect.spawn(
'mn --custom %s --topo mytopo --test pingall' % custom )
p.expect( '0% dropped' )
p.expect( pexpect.EOF )
def testStaticMAC( self ):
"Verify that MACs are set to easy to read numbers"
p = pexpect.spawn( 'mn --mac' )
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( self.prompt )
p.sendline( 'exit' )
p.expect( pexpect.EOF )
def testSwitches( self ):
"Run iperf test using user and ovsk switches"
switches = [ 'user', 'ovsk' ]
for sw in switches:
p = pexpect.spawn( 'mn --switch %s --test iperf' % sw )
p.expect( r"Results: \['([\d\.]+) .bits/sec'," )
bw = float( p.match.group( 1 ) )
self.assertTrue( bw > 0 )
p.expect( pexpect.EOF )
def testBenchmark( self ):
"Run benchmark and verify that it takes less than 2 seconds"
p = pexpect.spawn( 'mn --test none' )
p.expect( r'completed in ([\d\.]+) seconds' )
time = float( p.match.group( 1 ) )
self.assertTrue( time < 2, 'Benchmark takes more than 2 seconds' )
def testOwnNamespace( self ):
"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 ]
p.sendline( 's1 ifconfig -a' )
ifcount = 0
while True:
index = p.expect( interfaces )
if index == 1 or index == 3:
ifcount += 1
elif index == 0:
self.fail( 'h1 interface displayed in "s1 ifconfig"' )
elif index == 2:
self.fail( 'eth0 displayed in "s1 ifconfig"' )
else:
break
self.assertEqual( ifcount, 2, 'Missing interfaces on s1' )
# verify that all hosts a reachable
p.sendline( 'pingall' )
p.expect( r'(\d+)% dropped' )
dropped = int( p.match.group( 1 ) )
self.assertEqual( dropped, 0, 'pingall failed')
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
# PART 3
def testPythonInterpreter( self ):
"Test py and px by checking IP for h1 and adding h3"
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
# test host IP
p.sendline( 'py h1.IP()' )
p.expect( '10.0.0.1' )
p.expect( self.prompt )
# test adding host
p.sendline( "px net.addHost('h3')" )
p.expect( self.prompt )
p.sendline( "px net.addLink(s1, h3)" )
p.expect( self.prompt )
p.sendline( 'net' )
p.expect( 'h3' )
p.expect( self.prompt )
p.sendline( 'py h3.MAC()' )
p.expect( '([a-f0-9]{2}:?){6}' )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
def testLink( self ):
"Test link CLI command using ping"
p = pexpect.spawn( 'mn' )
p.expect( self.prompt )
p.sendline( 'link s1 h1 down' )
p.expect( self.prompt )
p.sendline( 'h1 ping -c 1 h2' )
p.expect( 'unreachable' )
p.expect( self.prompt )
p.sendline( 'link s1 h1 up' )
p.expect( self.prompt )
p.sendline( 'h1 ping -c 1 h2' )
p.expect( '0% packet loss' )
p.expect( self.prompt )
p.sendline( 'exit' )
p.wait()
@unittest.skipUnless( os.path.exists( '/tmp/pox' ) or
'1 received' in quietRun( 'ping -c 1 github.com' ),
'Github is not reachable; cannot download Pox' )
def testRemoteController( self ):
"Test Mininet using Pox controller"
# Satisfy pylint
assert self
if not os.path.exists( '/tmp/pox' ):
p = pexpect.spawn(
'git clone https://github.com/noxrepo/pox.git /tmp/pox' )
p.expect( pexpect.EOF )
pox = pexpect.spawn( '/tmp/pox/pox.py forwarding.l2_learning' )
net = pexpect.spawn(
'mn --controller=remote,ip=127.0.0.1,port=6633 --test pingall' )
net.expect( '0% dropped' )
net.expect( pexpect.EOF )
pox.sendintr()
pox.wait()
if __name__ == '__main__':
unittest.main()
+265 -141
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
'''@package topo
"""@package topo
Network topology creation.
@@ -9,222 +9,346 @@ This package includes code to represent network topologies.
A Topo object can be a topology database for NOX, can represent a physical
setup for testing, and can even be emulated with the Mininet package.
'''
"""
# BL: we may have to fix compatibility here.
# networkx is also a fairly heavyweight dependency
# from networkx.classes.graph import Graph
from networkx import Graph
from mininet.util import irange, natural, naturalSeq
class Topo(object):
class MultiGraph( object ):
"Utility class to track nodes and edges - replaces networkx.MultiGraph"
def __init__( self ):
self.node = {}
self.edge = {}
def add_node( self, node, attr_dict=None, **attrs):
"""Add node to graph
attr_dict: attribute dict (optional)
attrs: more attributes (optional)
warning: updates attr_dict with attrs"""
attr_dict = {} if attr_dict is None else attr_dict
attr_dict.update( attrs )
self.node[ node ] = attr_dict
def add_edge( self, src, dst, key=None, attr_dict=None, **attrs ):
"""Add edge to graph
key: optional key
attr_dict: optional attribute dict
attrs: more attributes
warning: udpates attr_dict with attrs"""
attr_dict = {} if attr_dict is None else attr_dict
attr_dict.update( attrs )
self.node.setdefault( src, {} )
self.node.setdefault( dst, {} )
self.edge.setdefault( src, {} )
self.edge.setdefault( dst, {} )
self.edge[ src ].setdefault( dst, {} )
entry = self.edge[ dst ][ src ] = self.edge[ src ][ dst ]
# If no key, pick next ordinal number
if key is None:
keys = [ k for k in entry.keys() if isinstance( k, int ) ]
key = max( [ 0 ] + keys ) + 1
entry[ key ] = attr_dict
return key
def nodes( self, data=False):
"""Return list of graph nodes
data: return list of ( node, attrs)"""
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():
if src > dst:
# Skip duplicate edges
continue
for k, attrs in entrykeys.items():
if data:
if keys:
yield( src, dst, k, attrs )
else:
yield( src, dst, attrs )
else:
if keys:
yield( src, dst, k )
else:
yield( src, dst )
def edges( self, data=False, keys=False ):
"Return list of graph edges"
return list( self.edges_iter( data=data, keys=keys ) )
def __getitem__( self, node ):
"Return link dict for given src node"
return self.edge[ node ]
def __len__( self ):
"Return the number of nodes"
return len( self.node )
def convertTo( self, cls, data=False, keys=False ):
"""Convert to a new object of networkx.MultiGraph-like class cls
data: include node and edge data
keys: include edge keys as well as edge data"""
g = cls()
g.add_nodes_from( self.nodes( data=data ) )
g.add_edges_from( self.edges( data=( data or keys ), keys=keys ) )
return g
class Topo( object ):
"Data center network representation for structured multi-trees."
def __init__(self, hopts=None, sopts=None, lopts=None):
"""Topo object:
def __init__( self, *args, **params ):
"""Topo object.
Optional named parameters:
hinfo: default host options
sopts: default switch options
lopts: default link options"""
self.g = Graph()
self.node_info = {}
self.link_info = {} # (src, dst) tuples hash to EdgeInfo objects
self.hopts = {} if hopts is None else hopts
self.sopts = {} if sopts is None else sopts
self.lopts = {} if lopts is None else lopts
self.ports = {} # ports[src][dst] is port on src that connects to dst
lopts: default link options
calls build()"""
self.g = MultiGraph()
self.hopts = params.pop( 'hopts', {} )
self.sopts = params.pop( 'sopts', {} )
self.lopts = params.pop( 'lopts', {} )
# ports[src][dst][sport] is port on dst that connects to src
self.ports = {}
self.build( *args, **params )
def addNode(self, name, **opts):
def build( self, *args, **params ):
"Override this method to build your topology."
pass
def addNode( self, name, **opts ):
"""Add Node to graph.
name: name
opts: node options
returns: node name"""
self.g.add_node(name)
self.node_info[name] = opts
self.g.add_node( name, **opts )
return name
def addHost(self, name, **opts):
def addHost( self, name, **opts ):
"""Convenience method: Add host to graph.
name: host name
opts: host options
returns: host name"""
if not opts and self.hopts:
opts = self.hopts
return self.addNode(name, **opts)
return self.addNode( name, **opts )
def addSwitch(self, name, **opts):
def addSwitch( self, name, **opts ):
"""Convenience method: Add switch to graph.
name: switch name
opts: switch options
returns: switch name"""
if not opts and self.sopts:
opts = self.sopts
result = self.addNode(name, isSwitch=True, **opts)
result = self.addNode( name, isSwitch=True, **opts )
return result
def addLink(self, node1, node2, port1=None, port2=None,
**opts):
def addLink( self, node1, node2, port1=None, port2=None,
key=None, **opts ):
"""node1, node2: nodes to link together
port1, port2: ports (optional)
opts: link options (optional)
returns: link info key"""
if not opts and self.lopts:
opts = self.lopts
self.addPort(node1, node2, port1, port2)
key = tuple(self.sorted([node1, node2]))
self.link_info[key] = opts
self.g.add_edge(*key)
port1, port2 = self.addPort( node1, node2, port1, port2 )
opts = dict( opts )
opts.update( node1=node1, node2=node2, port1=port1, port2=port2 )
self.g.add_edge(node1, node2, key, opts )
return key
def addPort(self, src, dst, sport=None, dport=None):
'''Generate port mapping for new edge.
@param src source switch name
@param dst destination switch name
'''
self.ports.setdefault(src, {})
self.ports.setdefault(dst, {})
# New port: number of outlinks + base
src_base = 1 if self.isSwitch(src) else 0
dst_base = 1 if self.isSwitch(dst) else 0
if sport is None:
sport = len(self.ports[src]) + src_base
if dport is None:
dport = len(self.ports[dst]) + dst_base
self.ports[src][dst] = sport
self.ports[dst][src] = dport
def nodes(self, sort=True):
def nodes( self, sort=True ):
"Return nodes in graph"
if sort:
return self.sorted( self.g.nodes() )
else:
return self.g.nodes()
def isSwitch(self, n):
'''Returns true if node is a switch.'''
info = self.node_info[n]
return info and info.get('isSwitch', False)
def isSwitch( self, n ):
"Returns true if node is a switch."
return self.g.node[ n ].get( 'isSwitch', False )
def switches(self, sort=True):
'''Return switches.
sort: sort switches alphabetically
@return dpids list of dpids
'''
return [n for n in self.nodes(sort) if self.isSwitch(n)]
def switches( self, sort=True ):
"""Return switches.
sort: sort switches alphabetically
returns: dpids list of dpids"""
return [ n for n in self.nodes( sort ) if self.isSwitch( n ) ]
def hosts(self, sort=True):
'''Return hosts.
sort: sort hosts alphabetically
@return dpids list of dpids
'''
return [n for n in self.nodes(sort) if not self.isSwitch(n)]
def hosts( self, sort=True ):
"""Return hosts.
sort: sort hosts alphabetically
returns: list of hosts"""
return [ n for n in self.nodes( sort ) if not self.isSwitch( n ) ]
def links(self, sort=True):
'''Return links.
sort: sort links alphabetically
@return links list of name pairs
'''
def iterLinks( self, withKeys=False, withInfo=False ):
"""Return links (iterator)
withKeys: return link keys
withInfo: return link info
returns: list of ( src, dst [,key, info ] )"""
for _src, _dst, key, info in self.g.edges_iter( data=True, keys=True ):
node1, node2 = info[ 'node1' ], info[ 'node2' ]
if withKeys:
if withInfo:
yield( node1, node2, key, info )
else:
yield( node1, node2, key )
else:
if withInfo:
yield( node1, node2, info )
else:
yield( node1, node2 )
def links( self, sort=False, withKeys=False, withInfo=False ):
"""Return links
sort: sort links alphabetically, preserving (src, dst) order
withKeys: return link keys
withInfo: return link info
returns: list of ( src, dst [,key, info ] )"""
links = list( self.iterLinks( withKeys, withInfo ) )
if not sort:
return self.g.edges()
else:
links = [tuple(self.sorted(e)) for e in self.g.edges()]
return sorted( links, key=naturalSeq )
return links
# Ignore info when sorting
tupleSize = 3 if withKeys else 2
return sorted( links, key=( lambda l: naturalSeq( l[ :tupleSize ] ) ) )
def port(self, src, dst):
'''Get port number.
# This legacy port management mechanism is clunky and will probably
# be removed at some point.
@param src source switch name
@param dst destination switch name
@return tuple (src_port, dst_port):
src_port: port on source switch leading to the destination switch
dst_port: port on destination switch leading to the source switch
'''
if src in self.ports and dst in self.ports[src]:
assert dst in self.ports and src in self.ports[dst]
return (self.ports[src][dst], self.ports[dst][src])
def addPort( self, src, dst, sport=None, dport=None ):
"""Generate port mapping for new edge.
src: source switch name
dst: destination switch name"""
# Initialize if necessary
ports = self.ports
ports.setdefault( src, {} )
ports.setdefault( dst, {} )
# New port: number of outlinks + base
if sport is None:
src_base = 1 if self.isSwitch( src ) else 0
sport = len( ports[ src ] ) + src_base
if dport is None:
dst_base = 1 if self.isSwitch( dst ) else 0
dport = len( ports[ dst ] ) + dst_base
ports[ src ][ sport ] = ( dst, dport )
ports[ dst ][ dport ] = ( src, sport )
return sport, dport
def linkInfo( self, src, dst ):
"Return link metadata"
src, dst = self.sorted([src, dst])
return self.link_info[(src, dst)]
def port( self, src, dst ):
"""Get port numbers.
src: source switch name
dst: destination switch name
sport: optional source port (otherwise use lowest src port)
returns: tuple (sport, dport), where
sport = port on source switch leading to the destination switch
dport = port on destination switch leading to the source switch
Note that you can also look up ports using linkInfo()"""
# A bit ugly and slow vs. single-link implementation ;-(
ports = [ ( sport, entry[ 1 ] )
for sport, entry in self.ports[ src ].items()
if entry[ 0 ] == dst ]
return ports if len( ports ) != 1 else ports[ 0 ]
def setlinkInfo( self, src, dst, info ):
"Set link metadata"
src, dst = self.sorted([src, dst])
self.link_info[(src, dst)] = info
def _linkEntry( self, src, dst, key=None ):
"Helper function: return link entry and key"
entry = self.g[ src ][ dst ]
if key is None:
key = min( entry )
return entry, key
def linkInfo( self, src, dst, key=None ):
"Return link metadata dict"
entry, key = self._linkEntry( src, dst, key )
return entry[ key ]
def setlinkInfo( self, src, dst, info, key=None ):
"Set link metadata dict"
entry, key = self._linkEntry( src, dst, key )
entry[ key ] = info
def nodeInfo( self, name ):
"Return metadata (dict) for node"
info = self.node_info[ name ]
return info if info is not None else {}
return self.g.node[ name ]
def setNodeInfo( self, name, info ):
"Set metadata (dict) for node"
self.node_info[ name ] = info
self.g.node[ name ] = info
def convertTo( self, cls, data=True, keys=True ):
"""Convert to a new object of networkx.MultiGraph-like class cls
data: include node and edge data (default True)
keys: include edge keys as well as edge data (default True)"""
return self.g.convertTo( cls, data=data, keys=keys )
@staticmethod
def sorted( items ):
"Items sorted in natural (i.e. alphabetical) order"
return sorted(items, key=natural)
return sorted( items, key=natural )
class SingleSwitchTopo(Topo):
'''Single switch connected to k hosts.'''
def __init__(self, k=2, **opts):
'''Init.
# Our idiom defines additional parameters in build(param...)
# pylint: disable=arguments-differ
@param k number of hosts
@param enable_all enables all nodes and switches?
'''
super(SingleSwitchTopo, self).__init__(**opts)
class SingleSwitchTopo( Topo ):
"Single switch connected to k hosts."
def build( self, k=2, **_opts ):
"k: number of hosts"
self.k = k
switch = self.addSwitch('s1')
for h in irange(1, k):
host = self.addHost('h%s' % h)
self.addLink(host, switch)
switch = self.addSwitch( 's1' )
for h in irange( 1, k ):
host = self.addHost( 'h%s' % h )
self.addLink( host, switch )
class SingleSwitchReversedTopo(Topo):
'''Single switch connected to k hosts, with reversed ports.
class SingleSwitchReversedTopo( Topo ):
"""Single switch connected to k hosts, with reversed ports.
The lowest-numbered host is connected to the highest-numbered port.
Useful to verify that Mininet properly handles custom port
numberings."""
The lowest-numbered host is connected to the highest-numbered port.
Useful to verify that Mininet properly handles custom port numberings.
'''
def __init__(self, k=2, **opts):
'''Init.
@param k number of hosts
@param enable_all enables all nodes and switches?
'''
super(SingleSwitchReversedTopo, self).__init__(**opts)
def build( self, k=2 ):
"k: number of hosts"
self.k = k
switch = self.addSwitch('s1')
for h in irange(1, k):
host = self.addHost('h%s' % h)
self.addLink(host, switch,
port1=0, port2=(k - h + 1))
switch = self.addSwitch( 's1' )
for h in irange( 1, k ):
host = self.addHost( 'h%s' % h )
self.addLink( host, switch,
port1=0, port2=( k - h + 1 ) )
class LinearTopo(Topo):
"Linear topology of k switches, with one host per switch."
def __init__(self, k=2, **opts):
"""Init.
k: number of switches (and hosts)
hconf: host configuration options
lconf: link configuration options"""
class MinimalTopo( SingleSwitchTopo ):
"Minimal topology with two hosts and one switch"
def build( self ):
return SingleSwitchTopo.build( self, k=2 )
super(LinearTopo, self).__init__(**opts)
class LinearTopo( Topo ):
"Linear topology of k switches, with n hosts per switch."
def build( self, k=2, n=1, **_opts):
"""k: number of switches
n: number of hosts per switch"""
self.k = k
self.n = n
if n == 1:
genHostName = lambda i, j: 'h%s' % i
else:
genHostName = lambda i, j: 'h%ss%d' % ( j, i )
lastSwitch = None
for i in irange(1, k):
host = self.addHost('h%s' % i)
switch = self.addSwitch('s%s' % i)
self.addLink( host, switch)
for i in irange( 1, k ):
# Add switch
switch = self.addSwitch( 's%s' % i )
# Add hosts to switch
for j in irange( 1, n ):
host = self.addHost( genHostName( i, j ) )
self.addLink( host, switch )
# Connect switch to previous
if lastSwitch:
self.addLink( switch, lastSwitch)
self.addLink( switch, lastSwitch )
lastSwitch = switch
# pylint: enable=arguments-differ
+48 -2
View File
@@ -3,11 +3,13 @@
from mininet.topo import Topo
from mininet.net import Mininet
# The build() method is expected to do this:
# pylint: disable=arguments-differ
class TreeTopo( Topo ):
"Topology for a tree network with a given depth and fanout."
def __init__( self, depth=1, fanout=2 ):
super( TreeTopo, self ).__init__()
def build( self, depth=1, fanout=2 ):
# Numbering: h1..N, s1..M
self.hostNum = 1
self.switchNum = 1
@@ -34,3 +36,47 @@ def TreeNet( depth=1, fanout=2, **kwargs ):
"Convenience function for creating tree networks."
topo = TreeTopo( depth, fanout )
return Mininet( topo, **kwargs )
class TorusTopo( Topo ):
"""2-D Torus 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 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"""
if x < 3 or y < 3:
raise Exception( 'Please use 3x3 or greater for compatibility '
'with 2.1' )
if n == 1:
genHostName = lambda loc, k: 'h%s' % ( loc )
else:
genHostName = lambda loc, k: 'h%sx%d' % ( loc, k )
hosts, switches, dpid = {}, {}, 0
# Create and wire interior
for i in range( 0, x ):
for j in range( 0, y ):
loc = '%dx%d' % ( i + 1, j + 1 )
# dpid cannot be zero for OVS
dpid = ( i + 1 ) * 256 + ( j + 1 )
switch = switches[ i, j ] = self.addSwitch(
's' + loc, dpid='%x' % dpid )
for k in range( 0, n ):
host = hosts[ i, j, k ] = self.addHost(
genHostName( loc, k + 1 ) )
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 )
# pylint: enable=arguments-differ
+279 -93
View File
@@ -1,15 +1,50 @@
"Utility functions for Mininet."
from mininet.log import output, info, error, warn
from mininet.log import output, info, error, warn, debug
from time import sleep
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
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
import sys
# 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
def decode( s ):
"Decode a byte string if needed for Python 3"
return s.decode( Encoding ) if Python3 else s
def encode( s ):
"Encode a byte string if needed for Python 3"
return s.encode( Encoding ) if Python3 else s
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
# Command execution support
@@ -24,7 +59,7 @@ def checkRun( cmd ):
return check_call( cmd.split( ' ' ) )
# pylint doesn't understand explicit type checking
# pylint: disable-msg=E1103
# pylint: disable=maybe-no-member
def oldQuietRun( *cmd ):
"""Run a command, routing stderr to stdout, and return the output.
@@ -55,18 +90,13 @@ 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
def errRun( *cmd, **kwargs ):
"""Run a command and return stdout, stderr and return code
cmd: string or list of command and args
stderr: STDOUT to merge stderr with stdout
shell: run command using shell
echo: monitor output to console"""
# Allow passing in a list or a string
if len( cmd ) == 1:
cmd = cmd[ 0 ]
if isinstance( cmd, str ):
cmd = cmd.split( ' ' )
cmd = [ str( arg ) for arg in cmd ]
# By default we separate stderr, don't run in a shell, and don't echo
stderr = kwargs.get( 'stderr', PIPE )
shell = kwargs.get( 'shell', False )
@@ -74,6 +104,15 @@ def errRun( *cmd, **kwargs ):
if echo:
# cmd goes to stderr, output goes to stdout
info( cmd, '\n' )
if len( cmd ) == 1:
cmd = cmd[ 0 ]
# Allow passing in a list or a string
if isinstance( cmd, str ) and not shell:
cmd = cmd.split( ' ' )
cmd = [ str( arg ) for arg in cmd ]
elif isinstance( cmd, list ) and shell:
cmd = " ".join( arg for arg in cmd )
debug( '*** errRun:', cmd, '\n' )
popen = Popen( cmd, stdout=PIPE, stderr=stderr, shell=shell )
# We use poll() because select() doesn't work with large fd numbers,
# and thus communicate() doesn't work either
@@ -88,21 +127,37 @@ def errRun( *cmd, **kwargs ):
errDone = False
while not outDone or not errDone:
readable = poller.poll()
for fd, _event in readable:
for fd, event in readable:
f = fdtofile[ fd ]
data = f.read( 1024 )
if echo:
output( data )
if f == popen.stdout:
out += data
if data == '':
if event & POLLIN:
data = f.read( 1024 )
if Python3:
data = data.decode( Encoding )
if echo:
output( data )
if f == popen.stdout:
out += data
if data == '':
outDone = True
elif f == popen.stderr:
err += data
if data == '':
errDone = True
else: # POLLHUP or something unexpected
if f == popen.stdout:
outDone = True
elif f == popen.stderr:
err += data
if data == '':
elif f == popen.stderr:
errDone = True
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
def errFail( *cmd, **kwargs ):
"Run a command using errRun and raise exception on nonzero exit"
@@ -116,8 +171,7 @@ def quietRun( cmd, **kwargs ):
"Run a command and return merged stdout and stderr"
return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ]
# pylint: enable-msg=E1103
# pylint: disable-msg=E1101
# pylint: enable=maybe-no-member
def isShellBuiltin( cmd ):
"Return True if cmd is a bash builtin."
@@ -130,8 +184,6 @@ def isShellBuiltin( cmd ):
isShellBuiltin.builtIns = None
# pylint: enable-msg=E1101
# Interface management
#
# Interfaces are managed as strings which are simply the
@@ -145,17 +197,41 @@ isShellBuiltin.builtIns = None
# live in the root namespace and thus do not have to be
# explicitly moved.
def makeIntfPair( intf1, intf2 ):
"""Make a veth pair connecting intf1 and intf2.
intf1: string, interface
intf2: string, interface
returns: success boolean"""
# Delete any old interfaces with the same names
quietRun( 'ip link del ' + intf1 )
quietRun( 'ip link del ' + intf2 )
def makeIntfPair( intf1, intf2, addr1=None, addr2=None, node1=None, node2=None,
deleteIntfs=True, runCmd=None ):
"""Make a veth pair connnecting new interfaces intf1 and intf2
intf1: name for interface 1
intf2: name for interface 2
addr1: MAC address for interface 1 (optional)
addr2: MAC address for interface 2 (optional)
node1: home node for interface 1 (optional)
node2: home node for interface 2 (optional)
deleteIntfs: delete intfs before creating them
runCmd: function to run shell commands (quietRun)
raises Exception on failure"""
if not runCmd:
runCmd = quietRun if not node1 else node1.cmd
runCmd2 = quietRun if not node2 else node2.cmd
if deleteIntfs:
# Delete any old interfaces with the same names
runCmd( 'ip link del ' + intf1 )
runCmd2( 'ip link del ' + intf2 )
# Create new pair
cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
return quietRun( cmd )
netns = 1 if not node2 else node2.pid
if addr1 is None and addr2 is None:
cmdOutput = runCmd( 'ip link add name %s '
'type veth peer name %s '
'netns %s' % ( intf1, intf2, netns ) )
else:
cmdOutput = runCmd( 'ip link add name %s '
'address %s '
'type veth peer name %s '
'address %s '
'netns %s' %
( intf1, addr1, intf2, addr2, netns ) )
if cmdOutput:
raise Exception( "Error creating interface pair (%s,%s): %s " %
( intf1, intf2, cmdOutput ) )
def retry( retries, delaySecs, fn, *args, **keywords ):
"""Try something several times before giving up.
@@ -171,35 +247,32 @@ def retry( retries, delaySecs, fn, *args, **keywords ):
error( "*** gave up after %i retries\n" % tries )
exit( 1 )
def moveIntfNoRetry( intf, dstNode, srcNode=None, printError=False ):
def moveIntfNoRetry( intf, dstNode, printError=False ):
"""Move interface to node, without retrying.
intf: string, interface
dstNode: destination Node
srcNode: source Node or None (default) for root ns
printError: if true, print error"""
intf = str( intf )
cmd = 'ip link set %s netns %s' % ( intf, dstNode.pid )
if srcNode:
srcNode.cmd( cmd )
else:
quietRun( cmd )
links = dstNode.cmd( 'ip link show' )
if not ( ' %s:' % intf ) in links:
cmdOutput = quietRun( cmd )
# If ip link set does not produce any output, then we can assume
# that the link has been moved successfully.
if cmdOutput:
if printError:
error( '*** Error: moveIntf: ' + intf +
' not successfully moved to ' + dstNode.name + '\n' )
' not successfully moved to ' + dstNode.name + ':\n',
cmdOutput )
return False
return True
def moveIntf( intf, dstNode, srcNode=None, printError=False,
retries=3, delaySecs=0.001 ):
def moveIntf( intf, dstNode, printError=True,
retries=3, delaySecs=0.001 ):
"""Move interface to node, retrying on failure.
intf: string, interface
dstNode: destination Node
srcNode: source Node or None (default) for root ns
printError: if true, print error"""
retry( retries, delaySecs, moveIntfNoRetry, intf, dstNode,
srcNode=srcNode, printError=printError )
printError=printError )
# Support for dumping network
@@ -227,6 +300,15 @@ def dumpNetConnections( net ):
nodes = net.controllers + net.switches + net.hosts
dumpNodeConnections( nodes )
def dumpPorts( switches ):
"dump interface to openflow port mappings for each switch"
for switch in switches:
output( '%s ' % switch.name )
for intf in switch.intfList():
port = switch.ports[ intf ]
output( '%s:%d ' % ( intf, port ) )
output( '\n' )
# IP and Mac address formatting and parsing
def _colonHex( val, bytecount ):
@@ -269,7 +351,7 @@ def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ):
ipBaseNum: option base IP address as int
returns IP address as string"""
imax = 0xffffffff >> prefixLen
assert i <= imax
assert i <= imax, 'Not enough IP addresses in the subnet'
mask = 0xffffffff ^ imax
ipnum = ( ipBaseNum & mask ) + i
return ipStr( ipnum )
@@ -277,6 +359,8 @@ def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ):
def ipParse( ip ):
"Parse an IP address and return an unsigned int."
args = [ int( arg ) for arg in ip.split( '.' ) ]
while len(args) < 4:
args.insert( len(args) - 1, 0 )
return ipNum( *args )
def netParse( ipstr ):
@@ -286,6 +370,10 @@ def netParse( ipstr ):
if '/' in ipstr:
ip, pf = ipstr.split( '/' )
prefixLen = int( pf )
#if no prefix is specified, set the prefix to 24
else:
ip = ipstr
prefixLen = 24
return ipParse( ip ), prefixLen
def checkInt( s ):
@@ -325,51 +413,99 @@ def pmonitor(popens, timeoutms=500, readline=True,
terminates: when all EOFs received"""
poller = poll()
fdToHost = {}
for host, popen in popens.iteritems():
for host, popen in popens.items():
fd = popen.stdout.fileno()
fdToHost[ fd ] = host
poller.register( fd, POLLIN )
if not readline:
# Use non-blocking reads
flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
poller.register( fd, POLLIN | POLLHUP )
flags = fcntl( fd, F_GETFL )
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
while popens:
fds = poller.poll( timeoutms )
if fds:
for fd, event in fds:
host = fdToHost[ fd ]
popen = popens[ host ]
if event & POLLIN:
if readline:
# Attempt to read a line of output
# This blocks until we receive a newline!
line = popen.stdout.readline()
else:
line = popen.stdout.read( readmax )
yield host, line
# Check for EOF
elif event & POLLHUP:
if event & POLLIN or event & POLLHUP:
while True:
try:
f = popen.stdout
line = decode( f.readline() if readline
else f.read( readmax ) )
except IOError:
line = ''
if line == '':
break
yield host, line
if event & POLLHUP:
poller.unregister( fd )
del popens[ host ]
else:
yield None, ''
# Other stuff we use
def sysctlTestAndSet( name, limit ):
"Helper function to set sysctl limits"
#convert non-directory names into directory names
if '/' not in name:
name = '/proc/sys/' + name.replace( '.', '/' )
#read limit
with open( name, 'r' ) as readFile:
oldLimit = readFile.readline()
if isinstance( limit, int ):
#compare integer limits before overriding
if int( oldLimit ) < limit:
with open( name, 'w' ) as writeFile:
writeFile.write( "%d" % limit )
else:
#overwrite non-integer limits
with open( name, 'w' ) as writeFile:
writeFile.write( limit )
def rlimitTestAndSet( name, limit ):
"Helper function to set rlimits"
soft, hard = getrlimit( name )
if soft < limit:
hardLimit = hard if limit < hard else limit
setrlimit( name, ( limit, hardLimit ) )
def fixLimits():
"Fix ridiculously small resource limits."
setrlimit( RLIMIT_NPROC, ( 8192, 8192 ) )
setrlimit( RLIMIT_NOFILE, ( 16384, 16384 ) )
debug( "*** Setting resource limits\n" )
try:
rlimitTestAndSet( RLIMIT_NPROC, 8192 )
rlimitTestAndSet( RLIMIT_NOFILE, 16384 )
#Increase open file limit
sysctlTestAndSet( 'fs.file-max', 10000 )
#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
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
sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 )
#Increase number of PTYs for nodes
sysctlTestAndSet( 'kernel.pty.max', 20000 )
# pylint: disable=broad-except
except Exception:
warn( "*** Error setting resource limits. "
"Mininet's performance may be affected.\n" )
# pylint: enable=broad-except
def mountCgroups():
"Make sure cgroups file system is mounted"
mounts = quietRun( 'mount' )
mounts = quietRun( 'grep cgroup /proc/mounts' )
cgdir = '/sys/fs/cgroup'
csdir = cgdir + '/cpuset'
if ('cgroup on %s' % cgdir not in mounts and
'cgroups on %s' % cgdir not in mounts):
if ('cgroup %s' % cgdir not in mounts and
'cgroups %s' % cgdir not in mounts):
raise Exception( "cgroups not mounted on " + cgdir )
if 'cpuset on %s' % csdir not in mounts:
if 'cpuset %s' % csdir not in mounts:
errRun( 'mkdir -p ' + csdir )
errRun( 'mount -t cgroup -ocpuset cpuset ' + csdir )
@@ -378,7 +514,7 @@ def natural( text ):
def num( s ):
"Convert text segment to int if necessary"
return int( s ) if s.isdigit() else s
return [ num( s ) for s in re.split( r'(\d+)', text ) ]
return [ num( s ) for s in re.split( r'(\d+)', str( text ) ) ]
def naturalSeq( t ):
"Natural sort key function for sequences"
@@ -423,35 +559,58 @@ def splitArgs( argstr ):
args = [ makeNumeric( s ) for s in params if '=' not in s ]
kwargs = {}
for s in [ p for p in params if '=' in p ]:
key, val = s.split( '=' )
key, val = s.split( '=', 1 )
kwargs[ key ] = makeNumeric( val )
return fn, args, kwargs
def customConstructor( constructors, argStr ):
"""Return custom constructor based on argStr
The args and key/val pairs in argsStr will be automatically applied
when the generated constructor is later used.
def customClass( classes, argStr ):
"""Return customized class based on argStr
The args and key/val pairs in argStr will be automatically applied
when the generated class is later used.
"""
cname, newargs, kwargs = splitArgs( argStr )
constructor = constructors.get( cname, None )
if not constructor:
cname, args, kwargs = splitArgs( argStr )
cls = classes.get( cname, None )
if not cls:
raise Exception( "error: %s is unknown - please specify one of %s" %
( cname, constructors.keys() ) )
( cname, classes.keys() ) )
if not args and not kwargs:
return cls
def customized( name, *args, **params ):
"Customized constructor, useful for Node, Link, and other classes"
params = params.copy()
params.update( kwargs )
if not newargs:
return constructor( name, *args, **params )
if args:
warn( 'warning: %s replacing %s with %s\n' % (
constructor, args, newargs ) )
return constructor( name, *newargs, **params )
return specialClass( cls, append=args, defaults=kwargs )
def specialClass( cls, prepend=None, append=None,
defaults=None, override=None ):
"""Like functools.partial, but it returns a class
prepend: arguments to prepend to argument list
append: arguments to append to argument list
defaults: default values for keyword arguments
override: keyword arguments to override"""
if prepend is None:
prepend = []
if append is None:
append = []
if defaults is None:
defaults = {}
if override is None:
override = {}
class CustomClass( cls ):
"Customized subclass with preset args/params"
def __init__( self, *args, **params ):
newparams = defaults.copy()
newparams.update( params )
newparams.update( override )
cls.__init__( self, *( list( prepend ) + list( args ) +
list( append ) ),
**newparams )
CustomClass.__name__ = '%s%s' % ( cls.__name__, defaults )
return CustomClass
customized.__name__ = 'customConstructor(%s)' % argStr
return customized
def buildTopo( topos, topoStr ):
"""Create topology from string with format (object, arg1, arg2,...).
@@ -468,6 +627,33 @@ def ensureRoot():
Probably we should only sudo when needed as per Big Switch's patch.
"""
if os.getuid() != 0:
print "*** Mininet must run as root."
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.
returns True if server is listening"""
runCmd = ( client.cmd if client else
partial( quietRun, shell=True ) )
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()
cmd = ( 'echo A | telnet -e A %s %s' % ( serverIP, port ) )
time = 0
result = runCmd( cmd )
while 'Connected' not in result:
if 'No route' in result:
rtable = runCmd( 'route' )
error( 'no route to %s:\n%s' % ( server, rtable ) )
return False
if timeout and time >= timeout:
error( 'could not connect to %s on port %d\n' % ( server, port ) )
return False
debug( 'waiting for', server, 'to listen on port', port, '\n' )
info( '.' )
sleep( .5 )
time += .5
result = runCmd( cmd )
return True
+53 -16
View File
@@ -5,7 +5,7 @@
*
* - closing all file descriptors except stdin/out/error
* - detaching from a controlling tty using setsid
* - running in a network namespace
* - running in network and mount namespaces
* - printing out the pid of a process so we can identify it later
* - attaching to a namespace and cgroup
* - setting RT scheduling
@@ -13,6 +13,7 @@
* Partially based on public domain setsid(1)
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <linux/sched.h>
#include <unistd.h>
@@ -20,23 +21,24 @@
#include <syscall.h>
#include <fcntl.h>
#include <stdlib.h>
#include <limits.h>
#include <sched.h>
#include <ctype.h>
#include <sys/mount.h>
#if !defined(VERSION)
#define VERSION "(devel)"
#endif
void usage(char *name)
void usage(char *name)
{
printf("Execution utility for Mininet\n\n"
"Usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n\n"
"Options:\n"
" -c: close all file descriptors except stdin/out/error\n"
" -d: detach from tty by calling setsid()\n"
" -n: run in new network namespace\n"
" -n: run in new network and mount namespaces\n"
" -p: print ^A + pid\n"
" -a pid: attach to pid's network namespace\n"
" -a pid: attach to pid's network and mount namespaces\n"
" -g group: add to cgroup\n"
" -r rtprio: run with SCHED_RR (usually requires -g)\n"
" -v: print version\n",
@@ -46,7 +48,7 @@ void usage(char *name)
int setns(int fd, int nstype)
{
return syscall(__NR_setns, fd, nstype);
return syscall(__NR_setns, fd, nstype);
}
/* Validate alphanumeric path foo1/bar2/baz */
@@ -62,7 +64,7 @@ void validate(char *path)
}
/* Add our pid to cgroup */
int cgroup(char *gname)
void cgroup(char *gname)
{
static char path[PATH_MAX];
static char *groups[] = {
@@ -92,11 +94,13 @@ int cgroup(char *gname)
int main(int argc, char *argv[])
{
char c;
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)
switch(c) {
@@ -112,20 +116,35 @@ int main(int argc, char *argv[])
case -1:
perror("fork");
return 1;
case 0: /* child */
case 0: /* child */
break;
default: /* parent */
default: /* parent */
return 0;
}
}
setsid();
break;
case 'n':
/* run in network namespace */
if (unshare(CLONE_NEWNET) == -1) {
/* run in network and mount namespaces */
if (unshare(CLONE_NEWNET|CLONE_NEWNS) == -1) {
perror("unshare");
return 1;
}
/* Mark our whole hierarchy recursively as private, so that our
* mounts do not propagate to other processes.
*/
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 */
@@ -133,9 +152,9 @@ int main(int argc, char *argv[])
fflush(stdout);
break;
case 'a':
/* Attach to pid's network namespace */
/* Attach to pid's network namespace and mount namespace */
pid = atoi(optarg);
sprintf(path, "/proc/%d/ns/net", pid );
sprintf(path, "/proc/%d/ns/net", pid);
nsid = open(path, O_RDONLY);
if (nsid < 0) {
perror(path);
@@ -145,6 +164,22 @@ int main(int argc, char *argv[])
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 */
@@ -166,7 +201,7 @@ int main(int argc, char *argv[])
exit(0);
default:
usage(argv[0]);
exit(1);
exit(1);
}
if (optind < argc) {
@@ -174,6 +209,8 @@ int main(int argc, char *argv[])
perror(argv[optind]);
return 1;
}
usage(argv[0]);
return 0;
}
+5 -6
View File
@@ -20,25 +20,24 @@ setup(
description='Process-based OpenFlow emulator',
author='Bob Lantz',
author_email='rlantz@cs.stanford.edu',
packages=find_packages(exclude='test'),
packages=[ 'mininet', 'mininet.examples' ],
long_description="""
Mininet is a network emulator which uses lightweight
virtualization to create virtual networks for rapid
prototyping of Software-Defined Network (SDN) designs
using OpenFlow. http://openflow.org/mininet
using OpenFlow. http://mininet.org
""",
classifiers=[
"License :: OSI Approved :: BSD License",
"Programming Language :: Python",
"Development Status :: 2 - Pre-Alpha",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Topic :: Internet",
"Topic :: System :: Emulators",
],
keywords='networking emulator protocol Internet OpenFlow SDN',
license='BSD',
install_requires=[
'setuptools',
'networkx'
'setuptools'
],
scripts=scripts,
)
+182
View File
@@ -0,0 +1,182 @@
#!/usr/bin/env bash
# Mininet ssh authentication script for cluster edition
# This script will create a single key pair, which is then
# propagated throughout the entire cluster.
# There are two options for setup; temporary setup
# persistent setup. If no options are specified, and the script
# is only given ip addresses or host names, it will default to
# the temporary setup. An ssh directory is then created in
# /tmp/mn/ssh on each node, and mounted with the keys over the
# user's ssh directory. This setup can easily be torn down by running
# clustersetup with the -c option.
# If the -p option is used, the setup will be persistent. In this
# case, the key pair will be be distributed directly to each node's
# ssh directory, but will be called cluster_key. An option to
# specify this key for use will be added to the config file in each
# user's ssh directory.
set -e
num_options=0
persistent=false
showHelp=false
clean=false
declare -a hosts=()
user=$(whoami)
SSHDIR=/tmp/mn/ssh
USERDIR=$HOME/.ssh
usage="./clustersetup.sh [ -p|h|c ] [ host1 ] [ host2 ] ...\n
Authenticate yourself and other cluster nodes to each other
via ssh for mininet cluster edition. By default, we use a
temporary ssh setup. An ssh directory is mounted over
$USERDIR on each machine in the cluster.
-h: display this help
-p: create a persistent ssh setup. This will add
new ssh keys and known_hosts to each nodes
$USERDIR directory
-c: method to clean up a temporary ssh setup.
Any hosts taken as arguments will be cleaned
"
persistentSetup() {
echo "***creating key pair"
ssh-keygen -t rsa -C "Cluster_Edition_Key" -f $USERDIR/cluster_key -N '' &> /dev/null
cat $USERDIR/cluster_key.pub >> $USERDIR/authorized_keys
echo "***configuring ssh"
echo "IdentityFile $USERDIR/cluster_key" >> $USERDIR/config
echo "IdentityFile $USERDIR/id_rsa" >> $USERDIR/config
for host in $hosts; do
echo "***copying public key to $host"
ssh-copy-id -i $USERDIR/cluster_key.pub $user@$host &> /dev/null
echo "***copying key pair to remote host"
scp $USERDIR/cluster_key $user@$host:$USERDIR
scp $USERDIR/cluster_key.pub $user@$host:$USERDIR
echo "***configuring remote host"
ssh -o ForwardAgent=yes $user@$host "
echo 'IdentityFile $USERDIR/cluster_key' >> $USERDIR/config
echo 'IdentityFile $USERDIR/id_rsa' >> $USERDIR/config"
done
for host in $hosts; do
echo "***copying known_hosts to $host"
scp $USERDIR/known_hosts $user@$host:$USERDIR/cluster_known_hosts
ssh $user@$host "
cat $USERDIR/cluster_known_hosts >> $USERDIR/known_hosts
rm $USERDIR/cluster_known_hosts"
done
}
tempSetup() {
echo "***creating temporary ssh directory"
mkdir -p $SSHDIR
echo "***creating key pair"
ssh-keygen -t rsa -C "Cluster_Edition_Key" -f $SSHDIR/id_rsa -N '' &> /dev/null
echo "***mounting temporary ssh directory"
sudo mount --bind $SSHDIR $USERDIR
cp $SSHDIR/id_rsa.pub $SSHDIR/authorized_keys
for host in $hosts; do
echo "***copying public key to $host"
ssh-copy-id $user@$host &> /dev/null
echo "***mounting remote temporary ssh directory for $host"
ssh -o ForwardAgent=yes $user@$host "
mkdir -p $SSHDIR
cp $USERDIR/authorized_keys $SSHDIR/authorized_keys
sudo mount --bind $SSHDIR $USERDIR"
echo "***copying key pair to $host"
scp $SSHDIR/{id_rsa,id_rsa.pub} $user@$host:$SSHDIR
done
for host in $hosts; do
echo "***copying known_hosts to $host"
scp $SSHDIR/known_hosts $user@$host:$SSHDIR
done
}
cleanup() {
for host in $hosts; do
echo "***cleaning up $host"
ssh $user@$host "sudo umount $USERDIR
sudo rm -rf $SSHDIR"
done
echo "**unmounting local directories"
sudo umount $USERDIR
echo "***removing temporary ssh directory"
sudo rm -rf $SSHDIR
echo "done!"
}
if [ $# -eq 0 ]; then
echo "ERROR: No Arguments"
echo "$usage"
exit
else
while getopts 'hpc' OPTION
do
((num_options+=1))
case $OPTION in
h) showHelp=true;;
p) persistent=true;;
c) clean=true;;
?) showHelp=true;;
esac
done
shift $(($OPTIND - 1))
fi
if [ "$num_options" -gt 1 ]; then
echo "ERROR: Too Many Options"
echo "$usage"
exit
fi
if $showHelp; then
echo "$usage"
exit
fi
for i in "$@"; do
output=$(getent ahostsv4 "$i")
if [ -z "$output" ]; then
echo '***WARNING: could not find hostname "$i"'
echo ""
else
hosts+="$i "
fi
done
if $clean; then
cleanup
exit
fi
echo "***authenticating to:"
for host in $hosts; do
echo "$host"
done
echo
if $persistent; then
echo '***Setting up persistent SSH configuration between all nodes'
persistentSetup
echo $'\n*** Sucessfully set up ssh throughout the cluster!'
else
echo '*** Setting up temporary SSH configuration between all nodes'
tempSetup
echo $'\n***Finished temporary setup. When you are done with your cluster'
echo $' session, tear down the SSH connections with'
echo $' ./clustersetup.sh -c '$hosts''
fi
echo

Some files were not shown because too many files have changed in this diff Show More