Compare commits

...

214 Commits

Author SHA1 Message Date
Bob Lantz 02bf34aa96 Remove setup/isOldOVS which have been merged into OVSSwitch 2014-09-22 12:27:49 -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
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
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
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
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
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
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
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
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
38 changed files with 4255 additions and 651 deletions
+8 -1
View File
@@ -2,7 +2,7 @@
Mininet Installation/Configuration Notes
----------------------------------------
Mininet 2.1.0
Mininet 2.1.0+
---
The supported installation methods for Mininet are 1) using a
@@ -51,6 +51,13 @@ like to contribute an installation script, we would welcome it!)
git clone git://github.com/mininet/mininet.git
Note that the above git command will check out the latest and greatest
Mininet (which we recommend!) If you want to run the last tagged/released
version of Mininet, use:
git clone git://github.com/mininet/mininet
git checkout -b 2.1.0 2.1.0
If you are running Ubuntu, you may be able to use our handy
`install.sh` script, which is in `mininet/util`.
+1 -1
View File
@@ -1,4 +1,4 @@
Mininet 2.1.0 License
Mininet 2.1.0+ License
Copyright (c) 2013 Open Networking Laboratory
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
+4 -4
View File
@@ -3,7 +3,7 @@ Mininet: Rapid Prototyping for Software Defined Networks
*The best way to emulate almost any network on your laptop!*
Version 2.1.0
Version 2.1.0+
### What is Mininet?
@@ -66,9 +66,9 @@ Mininet includes:
`mn -c`
### New features in 2.1.0
### New features in 2.1.0+
Mininet 2.1.0 provides a number of bug fixes as well as
Mininet 2.1.0+ provides a number of bug fixes as well as
several new features, including:
* Convenient access to `Mininet()` as a dict of nodes
@@ -127,7 +127,7 @@ Mininet to change the networking world!
### Credits
The Mininet 2.1.0 Team:
The Mininet 2.1.0+ Team:
* Bob Lantz
* Brian O'Connor
+22 -6
View File
@@ -25,11 +25,13 @@ from mininet.cli import CLI
from mininet.log import lg, LEVELS, info, debug, error
from mininet.net import Mininet, MininetWithControlNet, VERSION
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
NOX, RemoteController, UserSwitch, OVSKernelSwitch,
NOX, RemoteController, DefaultController,
UserSwitch, OVSSwitch,
OVSLegacyKernelSwitch, IVSSwitch )
from mininet.nodelib import LinuxBridge
from mininet.link import Link, TCLink
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
from mininet.topolib import TreeTopo
from mininet.topolib import TreeTopo, TorusTopo
from mininet.util import custom, customConstructor
from mininet.util import buildTopo
@@ -40,24 +42,29 @@ TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
'linear': LinearTopo,
'reversed': SingleSwitchReversedTopo,
'single': SingleSwitchTopo,
'tree': TreeTopo }
'tree': TreeTopo,
'torus': TorusTopo }
SWITCHDEF = 'ovsk'
SWITCHES = { 'user': UserSwitch,
'ovsk': OVSKernelSwitch,
'ovs': OVSSwitch,
# Keep ovsk for compatibility with 2.0
'ovsk': OVSSwitch,
'ovsl': OVSLegacyKernelSwitch,
'ivs': IVSSwitch }
'ivs': IVSSwitch,
'lxbr': LinuxBridge }
HOSTDEF = 'proc'
HOSTS = { 'proc': Host,
'rt': custom( CPULimitedHost, sched='rt' ),
'cfs': custom( CPULimitedHost, sched='cfs' ) }
CONTROLLERDEF = 'ovsc'
CONTROLLERDEF = 'default'
CONTROLLERS = { 'ref': Controller,
'ovsc': OVSController,
'nox': NOX,
'remote': RemoteController,
'default': DefaultController,
'none': lambda name: None }
LINKDEF = 'default'
@@ -193,6 +200,9 @@ 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( '--nat', action='store_true',
default=False, help="adds a NAT to the topology "
"that connects Mininet to the physical network" )
opts.add_option( '--version', action='callback', callback=version )
self.options, self.args = opts.parse_args()
@@ -250,6 +260,10 @@ class MininetRunner( object ):
autoStaticArp=arp, autoPinCpus=pin,
listenPort=listenPort )
if self.options.nat:
nat = mn.addNAT()
nat.configDefault()
if self.options.pre:
CLI( mn, script=self.options.pre )
@@ -261,12 +275,14 @@ class MininetRunner( object ):
if test == 'none':
pass
elif test == 'all':
mn.waitConnected()
mn.start()
mn.ping()
mn.iperf()
elif test == 'cli':
CLI( mn )
elif test != 'build':
mn.waitConnected()
getattr( mn, test )()
if self.options.post:
+12 -2
View File
@@ -13,7 +13,7 @@ process running in a namespace. Doesn't use OpenFlow.
#### consoles.py:
This example creates a grid of console windows, one for each node,
This example creates a grid of console windows, one for each node,
and allows interaction with and monitoring of each console, including
graphical monitoring.
@@ -60,9 +60,14 @@ by subclassing Topo, and how to run a series of tests on it.
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.
#### multiping.py:
This example demonstrates one method for
This example demonstrates one method for
monitoring output from multiple hosts, using `node.monitor()`.
#### multipoll.py:
@@ -117,3 +122,8 @@ memory and `sysctl` configuration (see `INSTALL`.)
This example creates a 64-host tree network, and attempts to check full
connectivity using `ping`, for different switch/datapath types.
#### 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
+42 -167
View File
@@ -1,197 +1,72 @@
#!/usr/bin/python
"""
bind.py: Bind mount prototype
bind.py: Bind mount example
This creates hosts with private directories as desired.
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.node import Host, HostWithPrivateDirs
from mininet.cli import CLI
from mininet.util import errFail, quietRun, errRun
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel, info, debug
from os.path import realpath
from functools import partial
# Utility functions for unmounting a tree
MNRUNDIR = realpath( '/var/run/mn' )
def mountPoints():
"Return list of mounted file systems"
mtab, _err, _ret = errFail( 'cat /proc/mounts' )
lines = mtab.split( '\n' )
mounts = []
for line in lines:
if not line:
continue
fields = line.split( ' ')
mount = fields[ 1 ]
mounts.append( mount )
return mounts
def unmountAll( rootdir=MNRUNDIR ):
"Unmount all mounts under a directory tree"
rootdir = realpath( rootdir )
# Find all mounts below rootdir
# This is subtle because /foo is not
# a parent of /foot
dirslash = rootdir + '/'
mounts = [ m for m in mountPoints()
if m == dir or m.find( dirslash ) == 0 ]
# Unmount them from bottom to top
mounts.sort( reverse=True )
for mount in mounts:
debug( 'Unmounting', mount, '\n' )
_out, err, code = errRun( 'umount', mount )
if code != 0:
info( '*** Warning: failed to umount', mount, '\n' )
info( err )
class HostWithPrivateDirs( Host ):
"Host with private directories"
mnRunDir = MNRUNDIR
def __init__(self, name, *args, **kwargs ):
"""privateDirs: list of private directories
remounts: dirs to remount
unmount: unmount dirs in cleanup? (True)
Note: if unmount is False, you must call unmountAll()
manually."""
self.privateDirs = kwargs.pop( 'privateDirs', [] )
self.remounts = kwargs.pop( 'remounts', [] )
self.unmount = kwargs.pop( 'unmount', True )
Host.__init__( self, name, *args, **kwargs )
self.rundir = '%s/%s' % ( self.mnRunDir, name )
self.root, self.private = None, None # set in createBindMounts
if self.privateDirs:
self.privateDirs = [ realpath( d ) for d in self.privateDirs ]
self.createBindMounts()
# These should run in the namespace before we chroot,
# in order to put the right entries in /etc/mtab
# Eventually this will allow a local pid space
# Now we chroot and cd to wherever we were before.
pwd = self.cmd( 'pwd' ).strip()
self.sendCmd( 'exec chroot', self.root, 'bash -ms mininet:'
+ self.name )
self.waiting = False
self.cmd( 'cd', pwd )
# In order for many utilities to work,
# we need to remount /proc and /sys
self.cmd( 'mount /proc' )
self.cmd( 'mount /sys' )
def mountPrivateDirs( self ):
"Create and bind mount private dirs"
for dir_ in self.privateDirs:
privateDir = self.private + dir_
errFail( 'mkdir -p ' + privateDir )
mountPoint = self.root + dir_
errFail( 'mount -B %s %s' %
( privateDir, mountPoint) )
def mountDirs( self, dirs ):
"Mount a list of directories"
for dir_ in dirs:
mountpoint = self.root + dir_
errFail( 'mount -B %s %s' %
( dir_, mountpoint ) )
@classmethod
def findRemounts( cls, fstypes=None ):
"""Identify mount points in /proc/mounts to remount
fstypes: file system types to match"""
if fstypes is None:
fstypes = [ 'nfs' ]
dirs = quietRun( 'cat /proc/mounts' ).strip().split( '\n' )
remounts = []
for dir_ in dirs:
line = dir_.split()
mountpoint, fstype = line[ 1 ], line[ 2 ]
# Don't re-remount directories!!!
if mountpoint.find( cls.mnRunDir ) == 0:
continue
if fstype in fstypes:
remounts.append( mountpoint )
return remounts
def createBindMounts( self ):
"""Create a chroot directory structure,
with self.privateDirs as private dirs"""
errFail( 'mkdir -p '+ self.rundir )
unmountAll( self.rundir )
# Create /root and /private directories
self.root = self.rundir + '/root'
self.private = self.rundir + '/private'
errFail( 'mkdir -p ' + self.root )
errFail( 'mkdir -p ' + self.private )
# Recursively mount / in private doort
# note we'll remount /sys and /proc later
errFail( 'mount -B / ' + self.root )
self.mountDirs( self.remounts )
self.mountPrivateDirs()
def unmountBindMounts( self ):
"Unmount all of our bind mounts"
unmountAll( self.rundir )
def popen( self, *args, **kwargs ):
"Popen with chroot support"
chroot = kwargs.pop( 'chroot', True )
mncmd = kwargs.get( 'mncmd',
[ 'mnexec', '-a', str( self.pid ) ] )
if chroot:
mncmd = [ 'chroot', self.root ] + mncmd
kwargs[ 'mncmd' ] = mncmd
return Host.popen( self, *args, **kwargs )
def cleanup( self ):
"""Clean up, then unmount bind mounts
unmount: actually unmount bind mounts?"""
# Wait for process to actually terminate
self.shell.wait()
Host.cleanup( self )
if self.unmount:
self.unmountBindMounts()
errFail( 'rmdir ' + self.root )
# Convenience aliases
findRemounts = HostWithPrivateDirs.findRemounts
# Sample usage
def testHostWithPrivateDirs():
"Test bind mounts"
topo = SingleSwitchTopo( 10 )
remounts = findRemounts( fstypes=[ 'nfs' ] )
privateDirs = [ '/var/log', '/var/run' ]
host = partial( HostWithPrivateDirs, remounts=remounts,
privateDirs=privateDirs, unmount=False )
privateDirs = [ ( '/var/log', '/tmp/%(name)s/var/log' ),
( '/var/run', '/tmp/%(name)s/var/run' ),
'/var/mn' ]
host = partial( HostWithPrivateDirs,
privateDirs=privateDirs )
net = Mininet( topo=topo, host=host )
net.start()
info( 'Private Directories:', privateDirs, '\n' )
directories = []
for directory in privateDirs:
directories.append( directory[ 0 ]
if isinstance( directory, tuple )
else directory )
info( 'Private Directories:', directories, '\n' )
CLI( net )
net.stop()
# We do this all at once to save a bit of time
info( 'Unmounting host bind mounts...\n' )
unmountAll()
if __name__ == '__main__':
unmountAll()
setLogLevel( 'info' )
testHostWithPrivateDirs()
info( 'Done.\n')
+1 -1
View File
@@ -19,7 +19,7 @@ from mininet.log import setLogLevel
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"
c1 = net.addController( 'c1', port=6633 )
+2 -2
View File
@@ -24,7 +24,7 @@ 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
@@ -76,7 +76,7 @@ def linearBandwidthTest( lengths ):
print "*** testing", datapath, "datapath"
Switch = switches[ datapath ]
results[ datapath ] = []
net = Mininet( topo=topo, switch=Switch )
net = Mininet( topo=topo, switch=Switch, controller=Controller, waitConnected=True )
net.start()
print "*** testing basic connectivity"
for n in lengths:
+2960 -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.util import quietRun
from mininet.log import output, warn
from random import randint
from re import findall
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"
print '* Simple mobility test'
net = Mininet( topo=LinearTopo( 3 ), switch=MobilitySwitch )
print '* Starting network:'
net.start()
printConnections( net.switches )
print '* Testing network'
net.pingAll()
print '* Identifying switch interface for h1'
h1, old = net.get( 'h1', 's1' )
for s in 2, 3, 1:
new = net[ 's%d' % s ]
port = randint( 10, 20 )
print '* Moving', h1, 'from', old, 'to', new, 'port', port
hintf, sintf = moveHost( h1, old, new, newPort=port )
print '*', hintf, 'is now connected to', sintf
print '* Clearing out old flows'
for sw in net.switches:
sw.dpctl( 'del-flows' )
print '* New network:'
printConnections( net.switches )
print '* Testing connectivity:'
net.pingAll()
old = new
net.stop()
if __name__ == '__main__':
mobilityTest()
+4 -4
View File
@@ -59,13 +59,13 @@ def fixNetworkManager( root, intf ):
cfile = '/etc/network/interfaces'
line = '\niface %s inet manual\n' % intf
config = open( cfile ).read()
if ( line ) not in config:
if line not in config:
print '*** Adding', line.strip(), 'to', cfile
with open( cfile, 'a' ) as f:
f.write( line )
# Probably need to restart network-manager to be safe -
# hopefully this won't disconnect you
root.cmd( 'service network-manager restart' )
# Probably need to restart network-manager to be safe -
# hopefully this won't disconnect you
root.cmd( 'service network-manager restart' )
def connectToInternet( network, switch='s1', rootip='10.254', subnet='10.0/8'):
"""Connect the network to the internet
+70
View File
@@ -0,0 +1,70 @@
#!/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, h=1, **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()
+76
View File
@@ -0,0 +1,76 @@
#!/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
from mininet.node import Node
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 net():
"Create a network with 5 hosts."
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 )
net.addLink( h5, s1, port1 = 1, port2 = 9 ) # specify a different port to connect host 5 to on the switch.
root = Node( 'root', inNamespace=False )
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' )
print '\n'
# test the network with pingall
net.pingAll()
print '\n'
info( '*** Stopping network' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
net()
+1 -1
View File
@@ -55,7 +55,7 @@ def sshd( network, cmd='/usr/sbin/sshd', opts='-D',
if not switch:
switch = network[ 's1' ] # switch to use
if not routes:
routes = [ '10.0.0.0/24' ]
routes = [ '10.0.0.0/24' ]
connectToRootNS( network, switch, ip, routes )
for host in network.hosts:
host.cmd( cmd + ' ' + opts + '&' )
+5 -3
View File
@@ -5,12 +5,14 @@ Test for hwintf.py
"""
import unittest
import pexpect
import re
import pexpect
from mininet.log import setLogLevel
from mininet.net import Mininet
from mininet.node import Node
from mininet.link import Link, Intf
from mininet.link import Link
class testHwintf( unittest.TestCase ):
+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()
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python
"""
Test for natnet.py
"""
import unittest
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
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()
+2 -2
View File
@@ -24,7 +24,7 @@ class testSimplePerf( unittest.TestCase ):
# check ping results
p.expect( "Results: (\d+)% dropped", timeout=120 )
loss = int( p.match.group( 1 ) )
self.assertTrue( loss > 0 and loss < 100 )
self.assertTrue( 0 < loss < 100 )
# check iperf results
p.expect( "Results: \['([\d\.]+) .bits/sec", timeout=480 )
bw = float( p.match.group( 1 ) )
@@ -46,7 +46,7 @@ class testSimplePerf( unittest.TestCase ):
m = re.search( expectStr, output )
loss = int( m.group( 3 ) )
net.stop()
self.assertTrue( loss > 0 and loss < 100 )
self.assertTrue( 0 < loss < 100 )
if __name__ == '__main__':
setLogLevel( 'warning' )
-1
View File
@@ -6,7 +6,6 @@ Test for sshd.py
import unittest
import pexpect
from time import sleep
from mininet.clean import sh
class testSSHD( unittest.TestCase ):
+27 -8
View File
@@ -10,7 +10,7 @@ It may also get rid of 'false positives', but hopefully
nothing irreplaceable!
"""
from subprocess import Popen, PIPE
from subprocess import Popen, PIPE, check_output as co
import time
from mininet.log import info
@@ -47,21 +47,40 @@ def cleanup():
cleanUpScreens()
info( "*** Removing excess kernel datapaths\n" )
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" ).split( '\n' )
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" ).splitlines()
for dp in dps:
if dp != '':
if dp:
sh( 'dpctl deldp ' + dp )
info( "*** Removing OVS datapaths" )
dps = sh("ovs-vsctl --timeout=1 list-br").split( '\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:
if dp:
sh( 'ovs-vsctl del-br ' + dp )
sh( 'ovs-vsctl del-br ' + dp )
info( "*** Removing all links of the pattern foo-ethX\n" )
links = sh( r"ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' )
links = sh( "ip link show | "
"egrep -o '([-_.[:alnum:]]+-eth[[:digit:]]+)'" ).splitlines()
for link in links:
if link != '':
if link:
sh( "ip link del " + link )
info( "*** Killing stale mininet node processes\n" )
sh( 'pkill -9 -f mininet:' )
# Make sure they are gone
while True:
try:
pids = co( 'pgrep -f mininet:'.split() )
except:
pids = ''
if pids:
sh( 'pkill -f 9 mininet:' )
sleep( .5 )
else:
break
info( "*** Cleanup complete.\n" )
+29 -10
View File
@@ -31,6 +31,8 @@ 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, runX11
@@ -52,6 +54,18 @@ class CLI( Cmd ):
self.inputFile = script
Cmd.__init__( self )
info( '*** Starting CLI:\n' )
# Set up history if readline is available
try:
import readline
except ImportError:
pass
else:
history_path = os.path.expanduser('~/.mininet_history')
if os.path.isfile(history_path):
readline.read_history_file(history_path)
atexit.register(lambda: readline.write_history_file(history_path))
if self.inputFile:
self.do_source( self.inputFile )
return
@@ -63,7 +77,7 @@ class CLI( Cmd ):
node.sendInt()
node.monitor()
if self.isatty():
quietRun( 'stty sane' )
quietRun( 'stty echo sane intr "^C"' )
self.cmdloop()
break
except KeyboardInterrupt:
@@ -151,16 +165,16 @@ class CLI( Cmd ):
# pylint: enable-msg=W0703,W0122
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 ):
@@ -187,7 +201,7 @@ class CLI( Cmd ):
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."
args = line.split()
if not args:
self.mn.iperf( l4Type='UDP' )
@@ -297,6 +311,7 @@ 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 ):
@@ -331,13 +346,13 @@ class CLI( Cmd ):
node = self.mn[ first ]
rest = args.split( ' ' )
# Substitute IP addresses for node names in command
rest = [ self.mn[ arg ].defaultIntf().updateIP()
# 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' % line )
@@ -345,7 +360,7 @@ class CLI( Cmd ):
# pylint: enable-msg=R0201
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 )
@@ -363,7 +378,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 ):
@@ -375,8 +390,12 @@ 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()
# Helper functions
def isReadable( poller ):
+8 -1
View File
@@ -279,7 +279,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:
cmds = [ '%s qdisc del dev %s root' ]
else:
cmds = []
# Bandwidth limits via various methods
bwcmds, parent = self.bwCmds( bw=bw, speedup=speedup,
@@ -307,6 +311,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
+2 -2
View File
@@ -57,7 +57,7 @@ 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."""
@@ -69,7 +69,7 @@ class Singleton( type ):
def __call__( cls, *args, **kw ):
if cls.instance is None:
cls.instance = super( Singleton, cls ).__call__( *args, **kw )
return cls.instance
return cls.instance
class MininetLogger( Logger, object ):
+82 -23
View File
@@ -90,29 +90,31 @@ import os
import re
import select
import signal
import copy
from time import sleep
from itertools import chain
from itertools import chain, groupby
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 Host, OVSKernelSwitch, DefaultController, Controller
from mininet.nodelib import NAT
from mininet.link import Link, Intf
from mininet.util import quietRun, fixLimits, numCores, ensureRoot
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
from mininet.term import cleanUpScreens, makeTerms
# Mininet version: should be consistent with README and LICENSE
VERSION = "2.1.0"
VERSION = "2.1.0+"
class Mininet( object ):
"Network emulation with hosts spawned in network namespaces."
def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
controller=Controller, link=Link, intf=Intf,
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
@@ -148,6 +150,7 @@ 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 = []
@@ -163,6 +166,37 @@ 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 time > timeout and timeout is not None:
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
@@ -175,7 +209,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
@@ -213,7 +247,7 @@ class Mininet( object ):
if not controller:
controller = self.controller
# Construct new controller if one is not given
if isinstance(name, Controller):
if isinstance( name, Controller ):
controller_new = name
# Pylint thinks controller is a str()
# pylint: disable=E1103
@@ -222,11 +256,25 @@ class Mininet( object ):
else:
controller_new = controller( name, **params )
# Add new controller to net
if controller_new: # allow controller-less setups
if controller_new: # allow controller-less setups
self.controllers.append( controller_new )
self.nameToNode[ name ] = controller_new
return controller_new
def addNAT( self, name='nat0', connect=True, inNamespace=False, **params ):
nat = self.addHost( name, cls=NAT, inNamespace=inNamespace,
subnet=self.ipBase, **params )
# find first switch and create link
if connect:
# connect the nat to the first switch
self.addLink( nat, self.switches[ 0 ] )
# 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 ):
@@ -324,7 +372,11 @@ class Mininet( object ):
if type( classes ) is not list:
classes = [ classes ]
for i, cls in enumerate( classes ):
self.addController( 'c%d' % i, cls )
# Allow Controller objects because nobody understands currying
if isinstance( cls, Controller ):
self.addController( cls )
else:
self.addController( 'c%d' % i, cls )
info( '*** Adding hosts:\n' )
for hostName in topo.hosts():
@@ -355,7 +407,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()
@@ -401,13 +453,23 @@ class Mininet( object ):
info( switch.name + ' ')
switch.start( self.controllers )
info( '\n' )
if self.waitConn:
self.waitConnected()
def stop( self ):
"Stop the controller(s), switches and hosts"
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
for controller in self.controllers:
info( controller.name + ' ' )
controller.stop()
info( '\n' )
if self.terms:
info( '*** Stopping %i terms\n' % len( self.terms ) )
self.stopXterms()
info( '*** Stopping %i switches\n' % len( self.switches ) )
for swclass, switches in groupby( sorted( self.switches, key=type ), type ):
if hasattr( swclass, 'batchShutdown' ):
swclass.batchShutdown( switches )
for switch in self.switches:
info( switch.name + ' ' )
switch.stop()
@@ -416,11 +478,6 @@ class Mininet( object ):
for host in self.hosts:
info( host.name + ' ' )
host.terminate()
info( '\n' )
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
for controller in self.controllers:
info( controller.name + ' ' )
controller.stop()
info( '\n*** Done\n' )
def run( self, test, *args, **kwargs ):
@@ -463,13 +520,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)
return 1, 0
r = r'(\d+) packets transmitted, (\d+) received'
m = re.search( r, pingOutput )
if m is None:
error( '*** Error: could not parse ping output: %s\n' %
pingOutput )
return (1, 0)
return 1, 0
sent, received = int( m.group( 1 ) ), int( m.group( 2 ) )
return sent, received
@@ -504,7 +561,7 @@ class Mininet( object ):
output( ( '%s ' % dest.name ) if received else 'X ' )
output( '\n' )
if packets > 0:
ploss = 100 * lost / packets
ploss = 100.0 * lost / packets
received = packets - lost
output( "*** Results: %i%% dropped (%d/%d received)\n" %
( ploss, received, packets ) )
@@ -575,10 +632,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.
@@ -613,7 +670,7 @@ 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', format=None ):
"""Run iperf between two hosts.
hosts: list of hosts; if None, uses opposite hosts
l4Type: string, one of [ TCP, UDP ]
@@ -636,6 +693,8 @@ class Mininet( object ):
bwArgs = '-b ' + udpBw + ' '
elif l4Type != 'TCP':
raise Exception( 'Unexpected l4 type: %s' % l4Type )
if format:
iperfArgs += '-f %s ' %format
server.sendCmd( iperfArgs + '-s', printPid=True )
servout = ''
while server.lastPid is None:
@@ -643,7 +702,7 @@ class Mininet( object ):
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...')
info( 'Waiting for iperf to start up...' )
sleep(.5)
cliout = client.cmd( iperfArgs + '-t 5 -c ' + server.IP() + ' ' +
bwArgs )
+183 -64
View File
@@ -16,6 +16,11 @@ Host: a virtual host. By default, a host is simply a shell; commands
CPULimitedHost: a virtual host whose CPU bandwidth is limited by
RT or CFS bandwidth limiting.
HostWithPrivateDirs: a virtual host that has user-specified private
directories. These may be temporary directories stored as a tmpfs,
or persistent directories that are mounted from another directory in
the root filesystem.
Switch: superclass for switch nodes.
UserSwitch: a switch using the user-space switch from the OpenFlow
@@ -45,6 +50,7 @@ Future enhancements:
"""
import os
import pty
import re
import signal
import select
@@ -57,6 +63,8 @@ from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
numCores, retry, mountCgroups )
from mininet.moduledeps import moduleDeps, pathCheck, OVS_KMOD, OF_KMOD, TUN
from mininet.link import Link, Intf, TCIntf
from re import findall
from distutils.version import StrictVersion
class Node( object ):
"""A virtual network node is simply a shell in a network namespace.
@@ -116,16 +124,22 @@ class Node( object ):
return
# mnexec: (c)lose descriptors, (d)etach from tty,
# (p)rint pid, and run in (n)amespace
opts = '-cdp'
opts = '-cd'
if self.inNamespace:
opts += 'n'
# bash -m: enable job control
# bash -m: enable job control, i: force interactive
# -s: pass $* to shell, and make process easy to find in ps
cmd = [ 'mnexec', opts, 'bash', '-ms', 'mininet:' + self.name ]
self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
close_fds=True )
self.stdin = self.shell.stdin
self.stdout = self.shell.stdout
# prompt is set to sentinel chr( 127 )
os.environ[ 'PS1' ] = chr( 127 )
cmd = [ 'mnexec', opts, 'bash', '--norc', '-mis', 'mininet:' + self.name ]
# Spawn a shell subprocess in a pseudo-tty, to disable buffering
# in the subprocess and insulate it from signals (e.g. SIGINT)
# received by the parent
master, slave = pty.openpty()
self.shell = Popen( cmd, stdin=slave, stdout=slave, stderr=slave,
close_fds=False )
self.stdin = os.fdopen( master )
self.stdout = self.stdin
self.pid = self.shell.pid
self.pollOut = select.poll()
self.pollOut.register( self.stdout )
@@ -138,7 +152,14 @@ class Node( object ):
self.lastCmd = None
self.lastPid = None
self.readbuf = ''
# Wait for prompt
while True:
data = self.read( 1024 )
if data[ -1 ] == chr( 127 ):
break
self.pollOut.poll()
self.waiting = False
self.cmd( 'stty -echo' )
def cleanup( self ):
"Help python collect its garbage."
@@ -184,7 +205,7 @@ class Node( object ):
def terminate( self ):
"Send kill signal to Node and clean up after it."
if self.shell:
os.kill( self.pid, signal.SIGKILL )
os.killpg( self.pid, signal.SIGHUP )
self.cleanup()
def stop( self ):
@@ -217,36 +238,32 @@ class Node( object ):
# Replace empty commands with something harmless
cmd = 'echo -n'
self.lastCmd = cmd
printPid = printPid and not isShellBuiltin( cmd )
if len( cmd ) > 0 and cmd[ -1 ] == '&':
# print ^A{pid}\n{sentinel}
cmd += ' printf "\\001%d\n\\177" $! \n'
else:
# print sentinel
cmd += '; printf "\\177"'
if printPid and not isShellBuiltin( cmd ):
if printPid and not isShellBuiltin( cmd ):
if len( cmd ) > 0 and cmd[ -1 ] == '&':
# print ^A{pid}\n so monitor() can set lastPid
cmd += ' printf "\\001%d\n" $! \n'
else:
cmd = 'mnexec -p ' + cmd
self.write( cmd + '\n' )
self.lastPid = None
self.waiting = True
def sendInt( self, sig=signal.SIGINT ):
def sendInt( self, intr=chr( 3 ) ):
"Interrupt running command."
if self.lastPid:
try:
os.kill( self.lastPid, sig )
except OSError:
pass
self.write( intr )
def monitor( self, timeoutms=None ):
def monitor( self, timeoutms=None, findPid=True ):
"""Monitor and return the output of a command.
Set self.waiting to False if command has completed.
timeoutms: timeout in ms or None to wait indefinitely."""
self.waitReadable( timeoutms )
data = self.read( 1024 )
# Look for PID
marker = chr( 1 ) + r'\d+\n'
if chr( 1 ) in data:
marker = chr( 1 ) + r'\d+\r\n'
if findPid and chr( 1 ) in data:
# Marker can be read in chunks; continue until all of it is read
while not re.findall( marker, data ):
data += self.read( 1024 )
markers = re.findall( marker, data )
if markers:
self.lastPid = int( markers[ 0 ][ 1: ] )
@@ -723,6 +740,33 @@ class CPULimitedHost( Host ):
mountCgroups()
cls.inited = True
class HostWithPrivateDirs( Host ):
"Host with private directories"
def __init__( self, name, *args, **kwargs ):
"privateDirs: list of private directory strings or tuples"
self.name = name
self.privateDirs = kwargs.pop( 'privateDirs', [] )
Host.__init__( self, name, *args, **kwargs )
self.mountPrivateDirs()
def mountPrivateDirs( self ):
"mount private directories"
for directory in self.privateDirs:
if isinstance( directory, tuple ):
# mount given private directory
privateDir = directory[ 1 ] % self.__dict__
mountPoint = directory[ 0 ]
self.cmd( 'mkdir -p %s' % privateDir )
self.cmd( 'mkdir -p %s' % mountPoint )
self.cmd( 'mount --bind %s %s' %
( privateDir, mountPoint ) )
else:
# mount temporary filesystem on directory
self.cmd( 'mkdir -p %s' % directory )
self.cmd( 'mount -n -t tmpfs tmpfs %s' % directory )
# Some important things to note:
#
@@ -752,27 +796,32 @@ class Switch( Node ):
dpidLen = 16 # digits in dpid passed to switch
def __init__( self, name, dpid=None, opts='', listenPort=None, **params):
"""dpid: dpid for switch (or None to derive from name, e.g. s1 -> 1)
"""dpid: dpid hex string (or None to derive from name, e.g. s1 -> 1)
opts: additional switch options
listenPort: port to listen on for dpctl connections"""
Node.__init__( self, name, **params )
self.dpid = dpid if dpid else self.defaultDpid()
self.dpid = self.defaultDpid( dpid )
self.opts = opts
self.listenPort = listenPort
if not self.inNamespace:
self.controlIntf = Intf( 'lo', self, port=0 )
def defaultDpid( self ):
"Derive dpid from switch name, s1 -> 1"
try:
dpid = int( re.findall( r'\d+', self.name )[ 0 ] )
dpid = hex( dpid )[ 2: ]
dpid = '0' * ( self.dpidLen - len( dpid ) ) + dpid
return dpid
except IndexError:
raise Exception( 'Unable to derive default datapath ID - '
'please either specify a dpid or use a '
'canonical switch name such as s23.' )
def defaultDpid( self, dpid=None ):
"Return correctly formatted dpid from dpid or switch name (s1 -> 1)"
if dpid:
# Remove any colons and make sure it's a good hex number
dpid = dpid.translate( None, ':' )
assert len( dpid ) <= self.dpidLen and int( dpid, 16 ) >= 0
else:
# Use hex of the first number in the switch name
nums = re.findall( r'\d+', self.name )
if nums:
dpid = hex( int( nums[ 0 ] ) )[ 2: ]
else:
raise Exception( 'Unable to derive default datapath ID - '
'please either specify a dpid or use a '
'canonical switch name such as s23.' )
return '0' * ( self.dpidLen - len( dpid ) ) + dpid
def defaultIntf( self ):
"Return control interface"
@@ -817,6 +866,8 @@ class UserSwitch( Switch ):
'(openflow.org)' )
if self.listenPort:
self.opts += ' --listen=ptcp:%i ' % self.listenPort
else:
self.opts += ' --listen=punix:/tmp/%s.listen' % self.name
self.dpopts = dpopts
@classmethod
@@ -827,10 +878,13 @@ class UserSwitch( Switch ):
def dpctl( self, *args ):
"Run dpctl command"
listenAddr = None
if not self.listenPort:
return "can't run dpctl without passive listening port"
listenAddr = 'unix:/tmp/%s.listen' % self.name
else:
listenAddr = 'tcp:127.0.0.1:%i' % self.listenPort
return self.cmd( 'dpctl ' + ' '.join( args ) +
' tcp:127.0.0.1:%i' % self.listenPort )
' ' + listenAddr )
def connected( self ):
"Is the switch connected to a controller?"
@@ -847,10 +901,13 @@ class UserSwitch( Switch ):
minspeed = ifspeed * 0.001
res = intf.config( **intf.params )
parent = res['parent']
if res is None: # link may not have TC parameters
return
# Re-add qdisc, root, and default classes user switch created, but
# with new parent, as setup by Mininet's TCIntf
parent = res['parent']
intf.tc( "%s qdisc add dev %s " + parent +
" handle 1: htb default 0xfffe" )
intf.tc( "%s class add dev %s classid 1:0xffff parent 1: htb rate "
@@ -945,14 +1002,18 @@ class OVSLegacyKernelSwitch( Switch ):
class OVSSwitch( Switch ):
"Open vSwitch switch. Depends on ovs-vsctl."
def __init__( self, name, failMode='secure', datapath='kernel', **params ):
def __init__( self, name, failMode='secure', datapath='kernel',
inband=False, protocols=None, **params ):
"""Init.
name: name for switch
failMode: controller loss behavior (secure|open)
datapath: userspace or kernel mode (kernel|user)"""
datapath: userspace or kernel mode (kernel|user)
inband: use in-band control (False)"""
Switch.__init__( self, name, **params )
self.failMode = failMode
self.datapath = datapath
self.inband = inband
self.protocols = protocols
@classmethod
def setup( cls ):
@@ -973,6 +1034,20 @@ class OVSSwitch( Switch ):
'You may wish to try '
'"service openvswitch-switch start".\n' )
exit( 1 )
info = quietRun( 'ovs-vsctl --version' )
cls.OVSVersion = findall( '\d+\.\d+', info )[ 0 ]
@classmethod
def isOldOVS( cls ):
return ( StrictVersion( cls.OVSVersion ) <
StrictVersion( '1.10' ) )
@classmethod
def batchShutdown( cls, switches ):
"Call ovs-vsctl del-br on all OVSSwitches in a list"
quietRun( 'ovs-vsctl ' +
' -- '.join( '--if-exists del-br %s' % s
for s in switches ) )
def dpctl( self, *args ):
"Run ovs-ofctl command"
@@ -1023,30 +1098,53 @@ class OVSSwitch( Switch ):
self.cmd( 'ifconfig lo up' )
# Annoyingly, --if-exists option seems not to work
self.cmd( 'ovs-vsctl del-br', self )
self.cmd( 'ovs-vsctl add-br', self )
if self.datapath == 'user':
self.cmd( 'ovs-vsctl set bridge', self,'datapath_type=netdev' )
int( self.dpid, 16 ) # DPID must be a hex string
self.cmd( 'ovs-vsctl -- set Bridge', self,
'other_config:datapath-id=' + self.dpid )
self.cmd( 'ovs-vsctl set-fail-mode', self, self.failMode )
for intf in self.intfList():
if not intf.IP():
self.attach( intf )
# Add controllers
clist = ' '.join( [ 'tcp:%s:%d' % ( c.IP(), c.port )
for c in controllers ] )
# Interfaces and controllers
intfs = ' '.join( '-- add-port %s %s ' % ( self, intf ) +
'-- set Interface %s ' % intf +
'ofport_request=%s ' % self.ports[ intf ]
for intf in self.intfList() if not intf.IP() )
clist = ' '.join( '%s:%s:%d' % ( c.protocol, c.IP(), c.port )
for c in controllers )
if self.listenPort:
clist += ' ptcp:%s' % self.listenPort
self.cmd( 'ovs-vsctl set-controller', self, clist )
# Construct big ovs-vsctl command for new versions of OVS
if not self.isOldOVS():
cmd = ( 'ovs-vsctl add-br %s ' % self +
'-- set Bridge %s ' % self +
'other_config:datapath-id=%s ' % self.dpid +
'-- set-fail-mode %s %s ' % ( self, self.failMode ) +
intfs +
'-- set-controller %s %s ' % ( self, clist ) )
# Construct ovs-vsctl commands for old versions of OVS
else:
self.cmd( 'ovs-vsctl add-br', self )
for intf in self.intfList():
if not intf.IP():
self.cmd( 'ovs-vsctl add-port', self, intf )
cmd = ( 'ovs-vsctl set Bridge %s ' % self +
'other_config:datapath-id=%s ' % self.dpid +
'-- set-fail-mode %s %s ' % ( self, self.failMode ) +
'-- set-controller %s %s ' % ( self, clist ) )
if not self.inband:
cmd += ( '-- set bridge %s '
'other-config:disable-in-band=true ' % self )
if self.datapath == 'user':
cmd += '-- set bridge %s datapath_type=netdev ' % self
if self.protocols:
cmd += '-- set bridge %s protocols=%s' % ( self, self.protocols )
# Reconnect quickly to controllers (1s vs. 15s max_backoff)
for uuid in self.controllerUUIDs():
if uuid.count( '-' ) != 4:
# Doesn't look like a UUID
continue
uuid = uuid.strip()
self.cmd( 'ovs-vsctl set Controller', uuid,
'max_backoff=1000' )
cmd += '-- set Controller %smax_backoff=1000 ' % uuid
# Do it!!
self.cmd( cmd )
for intf in self.intfList():
self.TCReapply( intf )
def stop( self ):
"Terminate OVS switch."
@@ -1061,8 +1159,9 @@ OVSKernelSwitch = OVSSwitch
class IVSSwitch(Switch):
"""IVS virtual switch"""
def __init__( self, name, **kwargs ):
def __init__( self, name, verbose=True, **kwargs ):
Switch.__init__( self, name, **kwargs )
self.verbose = verbose
@classmethod
def setup( cls ):
@@ -1077,12 +1176,19 @@ class IVSSwitch(Switch):
'not be loaded. Try modprobe openvswitch.\n' )
exit( 1 )
@classmethod
def batchShutdown( cls, switches ):
"Kill each IVS switch, to be waited on later in stop()"
for switch in switches:
switch.cmd( 'kill %ivs' )
def start( self, controllers ):
"Start up a new IVS switch"
args = ['ivs']
args.extend( ['--name', self.name] )
args.extend( ['--dpid', self.dpid] )
args.extend( ['--verbose'] )
if self.verbose:
args.extend( ['--verbose'] )
for intf in self.intfs.values():
if not intf.IP():
args.extend( ['-i', intf.name] )
@@ -1100,6 +1206,7 @@ class IVSSwitch(Switch):
def stop( self ):
"Terminate IVS switch."
self.cmd( 'kill %ivs' )
self.cmd( 'wait' )
self.deleteIntfs()
def attach( self, intf ):
@@ -1124,12 +1231,13 @@ class Controller( Node ):
def __init__( self, name, inNamespace=False, command='controller',
cargs='-v ptcp:%d', cdir=None, ip="127.0.0.1",
port=6633, **params ):
port=6633, protocol='tcp', **params ):
self.command = command
self.cargs = cargs
self.cdir = cdir
self.ip = ip
self.port = port
self.protocol = protocol
Node.__init__( self, name, inNamespace=inNamespace,
ip=ip, **params )
self.cmd( 'ifconfig lo up' ) # Shouldn't be necessary
@@ -1146,7 +1254,7 @@ class Controller( Node ):
listening = self.cmd( "echo A | telnet -e A %s %d" %
( self.ip, self.port ) )
if 'Connected' in listening:
servers = self.cmd( 'netstat -atp' ).split( '\n' )
servers = self.cmd( 'netstat -natp' ).split( '\n' )
pstr = ':%d ' % self.port
clist = servers[ 0:1 ] + [ s for s in servers if pstr in s ]
raise Exception( "Please shut down the controller which is"
@@ -1182,13 +1290,19 @@ class Controller( Node ):
return '<%s %s: %s:%s pid=%s> ' % (
self.__class__.__name__, self.name,
self.IP(), self.port, self.pid )
@classmethod
def isAvailable( self ):
return quietRun( 'which controller' )
class OVSController( Controller ):
"Open vSwitch controller"
def __init__( self, name, command='ovs-controller', **kwargs ):
if quietRun( 'which test-controller' ):
command = 'test-controller'
Controller.__init__( self, name, command=command, **kwargs )
@classmethod
def isAvailable( self ):
return quietRun( 'which ovs-controller' ) or quietRun( 'which test-controller' )
class NOX( Controller ):
"Controller to run a NOX application."
@@ -1244,3 +1358,8 @@ class RemoteController( Controller ):
warn( "Unable to contact the remote controller"
" at %s:%d\n" % ( self.ip, self.port ) )
def DefaultController( name, order=[ Controller, OVSController ], **kwargs ):
"find any controller that is available and run it"
for controller in order:
if controller.isAvailable():
return controller( name, **kwargs )
+115
View File
@@ -0,0 +1,115 @@
"""
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 setLogLevel, info
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 ):
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 ):
self.cmd( 'ifconfig', self, 'down' )
self.cmd( 'brctl delbr', self )
class NAT( Node ):
"""NAT: Provides connectivity to external network"""
def __init__( self, name, inetIntf='eth0', subnet='10.0/8', localIntf=None, **params):
super( NAT, self ).__init__( name, **params )
"""Start NAT/forwarding between Mininet and external network
inetIntf: interface for internet access
subnet: Mininet subnet (default 10.0/8)="""
self.inetIntf = inetIntf
self.subnet = subnet
self.localIntf = localIntf
def config( self, **params ):
super( NAT, self).config( **params )
"""Configure the NAT and iptables"""
if not self.localIntf:
self.localIntf = self.defaultIntf()
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
# Flush any currently active rules
# TODO: is this safe?
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' )
# Configure NAT
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 -i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' )
self.cmd( 'iptables -t nat -A POSTROUTING -o ', self.inetIntf, '-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 )
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"""
# Flush any currently active rules
# TODO: is this safe?
self.cmd( 'iptables -F' )
self.cmd( 'iptables -t nat -F' )
# Instruct the kernel to stop forwarding
self.cmd( 'sysctl net.ipv4.ip_forward=0' )
super( NAT, self ).terminate()
+14 -9
View File
@@ -53,8 +53,11 @@ class testOptionsTopoCommon( object ):
"""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 )
self.assertGreaterEqual( float(measured),
float(expected) * tolerance_frac )
self.assertLessEqual( float( measured ),
float(expected) + (1-tolerance_frac)
* float( expected ) )
def testCPULimits( self ):
"Verify topology creation with CPU limits set for both schedulers."
@@ -68,19 +71,20 @@ class testOptionsTopoCommon( object ):
mn.start()
results = mn.runCpuLimitTest( cpu=CPU_FRACTION )
mn.stop()
for cpu in results:
self.assertWithinTolerance( cpu, CPU_FRACTION, CPU_TOLERANCE )
for pct in results:
#divide cpu by 100 to convert from percentage to fraction
self.assertWithinTolerance( pct/100, CPU_FRACTION, CPU_TOLERANCE )
def testLinkBandwidth( self ):
"Verify that link bandwidths are accurate within a bound."
BW = 5 # Mbps
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, switch=self.switchClass )
bw_strs = mn.run( mn.iperf )
bw_strs = mn.run( mn.iperf, format='m' )
for bw_str in bw_strs:
bw = float( bw_str.split(' ')[0] )
self.assertWithinTolerance( bw, BW, BW_TOLERANCE )
@@ -91,7 +95,7 @@ class testOptionsTopoCommon( object ):
DELAY_TOLERANCE = 0.8 # Delay fraction below which test should fail
lopts = { 'delay': '%sms' % DELAY_MS, 'use_htb': True }
mn = Mininet( SingleSwitchOptionsTopo( n=N, lopts=lopts ),
link=TCLink, switch=self.switchClass )
link=TCLink, switch=self.switchClass, autoStaticArp=True )
ping_delays = mn.run( mn.pingFull )
test_outputs = ping_delays[0]
# Ignore unused variables below
@@ -102,9 +106,10 @@ class testOptionsTopoCommon( object ):
# pylint: enable-msg=W0612
for rttval in [rttmin, rttavg, rttmax]:
# Multiply delay by 4 to cover there & back on two links
self.assertWithinTolerance( rttval, DELAY_MS * 4.0,
self.assertWithinTolerance( rttval, DELAY_MS * 4.0,
DELAY_TOLERANCE)
def testLinkLoss( self ):
"Verify that we see packet drops with a high configured loss rate."
LOSS_PERCENT = 99
@@ -120,7 +125,7 @@ class testOptionsTopoCommon( object ):
for _ in range(REPS):
dropped_total += mn.ping(timeout='1')
mn.stop()
self.assertTrue(dropped_total > 0)
self.assertGreater( dropped_total, 0 )
def testMostOptions( self ):
"Verify topology creation with most link options and CPU limits."
+1 -1
View File
@@ -66,7 +66,7 @@ class testLinearCommon( object ):
def testLinear5( self ):
"Ping test on a 5-switch topology"
mn = Mininet( LinearTopo( k=5 ), self.switchClass, Host, Controller )
mn = Mininet( LinearTopo( k=5 ), self.switchClass, Host, Controller, waitConnected=True )
dropped = mn.run( mn.ping )
self.assertEqual( dropped, 0 )
-1
View File
@@ -9,7 +9,6 @@ TODO: missing xterm test
import unittest
import pexpect
import os
from time import sleep
from mininet.util import quietRun
class testWalkthrough( unittest.TestCase ):
+44 -57
View File
@@ -48,18 +48,25 @@ class MultiGraph( object ):
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"""
lopts: default link options
calls build()"""
self.g = MultiGraph()
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.hopts = params.pop( 'hopts', {} )
self.sopts = params.pop( 'sopts', {} )
self.lopts = params.pop( 'lopts', {} )
self.ports = {} # ports[src][dst] is port on src that connects to dst
self.build( *args, **params )
def build( self, *args, **params ):
"Override this method to build your topology."
pass
def addNode(self, name, **opts):
"""Add Node to graph.
@@ -168,7 +175,7 @@ class Topo(object):
'''
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])
return self.ports[src][dst], self.ports[dst][src]
def linkInfo( self, src, dst ):
"Return link metadata"
@@ -194,76 +201,56 @@ class Topo(object):
"Items sorted in natural (i.e. alphabetical) order"
return sorted(items, key=natural)
class SingleSwitchTopo(Topo):
'''Single switch connected to k hosts.'''
def __init__(self, k=2, **opts):
'''Init.
@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):
class LinearTopo( Topo ):
"Linear topology of k switches, with n hosts per switch."
def __init__(self, k=2, n=1, **opts):
"""Init.
k: number of switches
n: number of hosts per switch
hconf: host configuration options
lconf: link configuration options"""
super(LinearTopo, self).__init__(**opts)
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)
genHostName = lambda i, j: 'h%ss%d' % ( j, i )
lastSwitch = None
for i in irange(1, k):
for i in irange( 1, k ):
# Add switch
switch = self.addSwitch('s%s' % i)
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)
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
+35 -2
View File
@@ -6,8 +6,7 @@ from mininet.net import Mininet
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 +33,37 @@ 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 ):
if x < 3 or y < 3:
raise Exception( 'Please use 3x3 or greater for compatibility '
'with 2.1' )
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='%016x' % dpid )
host = hosts[ i, j ] = self.addHost( 'h' + loc )
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 )
+14 -4
View File
@@ -155,7 +155,12 @@ def makeIntfPair( intf1, intf2 ):
quietRun( 'ip link del ' + intf2 )
# Create new pair
cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
return quietRun( cmd )
cmdOutput = quietRun( cmd )
if cmdOutput == '':
return True
else:
error( "Error creating interface pair: %s " % cmdOutput )
return False
def retry( retries, delaySecs, fn, *args, **keywords ):
"""Try something several times before giving up.
@@ -183,8 +188,7 @@ def moveIntfNoRetry( intf, dstNode, srcNode=None, printError=False ):
srcNode.cmd( cmd )
else:
quietRun( cmd )
links = dstNode.cmd( 'ip link show' )
if not ( ' %s:' % intf ) in links:
if ( ' %s:' % intf ) not in dstNode.cmd( 'ip link show', intf ):
if printError:
error( '*** Error: moveIntf: ' + intf +
' not successfully moved to ' + dstNode.name + '\n' )
@@ -269,7 +273,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 +281,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.append( 0 )
return ipNum( *args )
def netParse( ipstr ):
@@ -286,6 +292,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 ):
+24 -7
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
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <sched.h>
#include <ctype.h>
#include <sys/mount.h>
#if !defined(VERSION)
#define VERSION "(devel)"
@@ -35,9 +36,9 @@ void usage(char *name)
"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",
@@ -122,11 +123,16 @@ int main(int argc, char *argv[])
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;
}
/* 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 */
@@ -134,9 +140,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);
@@ -146,6 +152,17 @@ 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 into pid's root file system */
sprintf(path, "/proc/%d/root", pid);
if (chroot(path) < 0) {
perror(path);
return 1;
}
}
break;
case 'g':
/* Attach to cgroup */
+85 -136
View File
@@ -63,22 +63,11 @@ echo "Detected Linux distribution: $DIST $RELEASE $CODENAME $ARCH"
# Kernel params
if [ "$DIST" = "Ubuntu" ]; then
if [ "$RELEASE" = "10.04" ]; then
KERNEL_NAME='3.0.0-15-generic'
else
KERNEL_NAME=`uname -r`
fi
KERNEL_HEADERS=linux-headers-${KERNEL_NAME}
elif [ "$DIST" = "Debian" ] && [ "$ARCH" = "i386" ] && [ "$CODENAME" = "lenny" ]; then
KERNEL_NAME=2.6.33.1-mininet
KERNEL_HEADERS=linux-headers-${KERNEL_NAME}_${KERNEL_NAME}-10.00.Custom_i386.deb
KERNEL_IMAGE=linux-image-${KERNEL_NAME}_${KERNEL_NAME}-10.00.Custom_i386.deb
elif [ "$DIST" = "Fedora" ]; then
KERNEL_NAME=`uname -r`
KERNEL_HEADERS=kernel-headers-${KERNEL_NAME}
else
echo "Install.sh currently only supports Ubuntu, Debian Lenny i386 and Fedora."
KERNEL_NAME=`uname -r`
KERNEL_HEADERS=kernel-headers-${KERNEL_NAME}
if ! echo $DIST | egrep 'Ubuntu|Debian|Fedora'; then
echo "Install.sh currently only supports Ubuntu, Debian and Fedora."
exit 1
fi
@@ -96,8 +85,6 @@ OVS_BUILDSUFFIX=-ignore # was -2
OVS_PACKAGE_NAME=ovs-$OVS_RELEASE-core-$DIST_LC-$RELEASE-$ARCH$OVS_BUILDSUFFIX.tar
OVS_TAG=v$OVS_RELEASE
IVS_TAG=v0.3
# Command-line versions overrides that simplify custom VM creation
# To use, pass in the vars on the cmd line before install.sh, e.g.
# WS_DISSECTOR_REV=pre-ws-1.10.0 install.sh -w
@@ -108,31 +95,7 @@ OF13_SWITCH_REV=${OF13_SWITCH_REV:-""}
function kernel {
echo "Install Mininet-compatible kernel if necessary"
sudo apt-get update
if [ "$DIST" = "Ubuntu" ] && [ "$RELEASE" = "10.04" ]; then
$install linux-image-$KERNEL_NAME
elif [ "$DIST" = "Debian" ]; then
# The easy approach: download pre-built linux-image and linux-headers packages:
wget -c $KERNEL_LOC/$KERNEL_HEADERS
wget -c $KERNEL_LOC/$KERNEL_IMAGE
# Install custom linux headers and image:
$pkginst $KERNEL_IMAGE $KERNEL_HEADERS
# The next two steps are to work around a bug in newer versions of
# kernel-package, which fails to add initrd images with the latest kernels.
# See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=525032
# Generate initrd image if the .deb didn't install it:
if ! test -e /boot/initrd.img-${KERNEL_NAME}; then
sudo update-initramfs -c -k ${KERNEL_NAME}
fi
# Ensure /boot/grub/menu.lst boots with initrd image:
sudo update-grub
# The default should be the new kernel. Otherwise, you may need to modify
# /boot/grub/menu.lst to set the default to the entry corresponding to the
# kernel you just installed.
fi
$install linux-image-$KERNEL_NAME
}
function kernel_clean {
@@ -176,10 +139,9 @@ function mn_dev {
# -user switch
# The instructions below are an abbreviated version from
# http://www.openflowswitch.org/wk/index.php/Debian_Install
# ... modified to use Debian Lenny rather than unstable.
function of {
echo "Installing OpenFlow reference implementation..."
cd $BUILD_DIR/
cd $BUILD_DIR
$install autoconf automake libtool make gcc
if [ "$DIST" = "Fedora" ]; then
$install git pkgconfig glibc-devel
@@ -300,111 +262,95 @@ function wireshark {
}
# Install Open vSwitch specific version Ubuntu package
function ubuntuOvs {
echo "Creating and Installing Open vSwitch packages..."
OVS_SRC=$BUILD_DIR/openvswitch
OVS_TARBALL_LOC=http://openvswitch.org/releases
if [ "$DIST" = "Ubuntu" ] && [ `expr $RELEASE '>=' 12.04` = 1 ]; then
rm -rf $OVS_SRC
mkdir -p $OVS_SRC
cd $OVS_SRC
if wget $OVS_TARBALL_LOC/openvswitch-$OVS_RELEASE.tar.gz 2> /dev/null; then
tar xzf openvswitch-$OVS_RELEASE.tar.gz
else
echo "Failed to find OVS at $OVS_TARBALL_LOC/openvswitch-$OVS_RELEASE.tar.gz"
cd $BUILD_DIR
return
fi
# Remove any old packages
$remove openvswitch-common openvswitch-datapath-dkms openvswitch-controller \
openvswitch-pki openvswitch-switch
# Get build deps
$install build-essential fakeroot debhelper autoconf automake libssl-dev \
pkg-config bzip2 openssl python-all procps python-qt4 \
python-zopeinterface python-twisted-conch dkms
# Build OVS
cd $BUILD_DIR/openvswitch/openvswitch-$OVS_RELEASE
DEB_BUILD_OPTIONS='parallel=2 nocheck' fakeroot debian/rules binary
cd ..
$pkginst openvswitch-common_$OVS_RELEASE*.deb openvswitch-datapath-dkms_$OVS_RELEASE*.deb \
openvswitch-pki_$OVS_RELEASE*.deb openvswitch-switch_$OVS_RELEASE*.deb
if $pkginst openvswitch-controller_$OVS_RELEASE*.deb; then
echo "Ignoring error installing openvswitch-controller"
fi
modinfo openvswitch
sudo ovs-vsctl show
# Switch can run on its own, but
# Mininet should control the controller
# This appears to only be an issue on Ubuntu/Debian
if sudo service openvswitch-controller stop; then
echo "Stopped running controller"
fi
if [ -e /etc/init.d/openvswitch-controller ]; then
sudo update-rc.d openvswitch-controller disable
fi
else
echo "Failed to install Open vSwitch. OS must be Ubuntu >= 12.04"
cd $BUILD_DIR
return
fi
}
# Install Open vSwitch
# Instructions derived from OVS INSTALL, INSTALL.OpenFlow and README files.
function ovs {
echo "Installing Open vSwitch..."
if [ "$DIST" = "Fedora" ]; then
# Just install Fedora's openvswitch RPMS
if [ "$DIST" == "Fedora" ]; then
$install openvswitch openvswitch-controller
return
fi
OVS_SRC=$BUILD_DIR/openvswitch
OVS_BUILD=$OVS_SRC/build-$KERNEL_NAME
OVS_KMODS=($OVS_BUILD/datapath/linux/{openvswitch_mod.ko,brcompat_mod.ko})
# Required for module build/dkms install
$install $KERNEL_HEADERS
ovspresent=0
# First see if we have packages
# XXX wget -c seems to fail from github/amazon s3
cd /tmp
if wget $OVS_PACKAGE_LOC/$OVS_PACKAGE_NAME 2> /dev/null; then
$install patch dkms fakeroot python-argparse
tar xf $OVS_PACKAGE_NAME
orig=`tar tf $OVS_PACKAGE_NAME`
# Now install packages in reasonable dependency order
order='dkms common pki openvswitch-switch brcompat controller'
pkgs=""
for p in $order; do
pkg=`echo "$orig" | grep $p`
# Annoyingly, things seem to be missing without this flag
$pkginst --force-confmiss $pkg
done
ovspresent=1
# Manually installing openvswitch-datapath may be necessary
# for manually built kernel .debs using Debian's defective kernel
# packaging, which doesn't yield usable headers.
if ! dpkg --get-selections | grep openvswitch-datapath; then
# If you've already installed a datapath, assume you
# know what you're doing and don't need dkms datapath.
# Otherwise, install it.
$install openvswitch-datapath-dkms
fi
# Otherwise try distribution's OVS packages
if [ "$DIST" = "Ubuntu" ] && [ `expr $RELEASE '>=' 11.10` = 1 ]; then
if ! dpkg --get-selections | grep openvswitch-datapath; then
# If you've already installed a datapath, assume you
# know what you're doing and don't need dkms datapath.
# Otherwise, install it.
$install openvswitch-datapath-dkms
fi
if $install openvswitch-switch openvswitch-controller; then
echo "Ignoring error installing openvswitch-controller"
fi
ovspresent=1
fi
$install openvswitch-switch openvswitch-controller
# Switch can run on its own, but
# Mininet should control the controller
# This appears to only be an issue on Ubuntu/Debian
if sudo service openvswitch-controller stop; then
echo "Stopped running controller"
fi
if [ -e /etc/init.d/openvswitch-controller ]; then
if sudo service openvswitch-controller stop; then
echo "Stopped running controller"
fi
sudo update-rc.d openvswitch-controller disable
fi
if [ $ovspresent = 1 ]; then
echo "Done (hopefully) installing packages"
cd $BUILD_DIR
return
fi
# Otherwise attempt to install from source
$install pkg-config gcc make python-dev libssl-dev libtool
if [ "$DIST" = "Debian" ]; then
if [ "$CODENAME" = "lenny" ]; then
$install git-core
# Install Autoconf 2.63+ backport from Debian Backports repo:
# Instructions from http://backports.org/dokuwiki/doku.php?id=instructions
sudo su -c "echo 'deb http://www.backports.org/debian lenny-backports main contrib non-free' >> /etc/apt/sources.list"
sudo apt-get update
sudo apt-get -y --force-yes install debian-backports-keyring
sudo apt-get -y --force-yes -t lenny-backports install autoconf
fi
else
$install git
fi
# Install OVS from release
cd $BUILD_DIR/
git clone git://openvswitch.org/openvswitch $OVS_SRC
cd $OVS_SRC
git checkout $OVS_TAG
./boot.sh
BUILDDIR=/lib/modules/${KERNEL_NAME}/build
if [ ! -e $BUILDDIR ]; then
echo "Creating build sdirectory $BUILDDIR"
sudo mkdir -p $BUILDDIR
fi
opts="--with-linux=$BUILDDIR"
mkdir -p $OVS_BUILD
cd $OVS_BUILD
../configure $opts
make
sudo make install
modprobe
}
function remove_ovs {
@@ -438,7 +384,7 @@ function ivs {
# Install IVS from source
cd $BUILD_DIR
git clone git://github.com/floodlight/ivs $IVS_SRC -b $IVS_TAG --recursive
git clone git://github.com/floodlight/ivs $IVS_SRC --recursive
cd $IVS_SRC
make
sudo make install
@@ -706,7 +652,7 @@ function vm_clean {
}
function usage {
printf '\nUsage: %s [-abcdfhikmnprtvwx03]\n\n' $(basename $0) >&2
printf '\nUsage: %s [-abcdfhikmnprtvVwx03]\n\n' $(basename $0) >&2
printf 'This install script attempts to install useful packages\n' >&2
printf 'for Mininet. It should (hopefully) work on Ubuntu 11.10+\n' >&2
@@ -731,6 +677,7 @@ function usage {
printf -- ' -s <dir>: place dependency (S)ource/build trees in <dir>\n' >&2
printf -- ' -t: complete o(T)her Mininet VM setup tasks\n' >&2
printf -- ' -v: install Open (V)switch\n' >&2
printf -- ' -V <version>: install a particular version of Open (V)switch on Ubuntu\n' >&2
printf -- ' -w: install OpenFlow (W)ireshark dissector\n' >&2
printf -- ' -x: install NO(X) Classic OpenFlow controller\n' >&2
printf -- ' -0: (default) -0[fx] installs OpenFlow 1.0 versions\n' >&2
@@ -744,7 +691,7 @@ if [ $# -eq 0 ]
then
all
else
while getopts 'abcdefhikmnprs:tvwx03' OPTION
while getopts 'abcdefhikmnprs:tvV:wx03' OPTION
do
case $OPTION in
a) all;;
@@ -769,6 +716,8 @@ else
echo "Dependency installation directory: $BUILD_DIR";;
t) vm_other;;
v) ovs;;
V) OVS_RELEASE=$OPTARG;
ubuntuOvs;;
w) wireshark;;
x) case $OF_VERSION in
1.0) nox;;
+1 -1
View File
@@ -8,7 +8,7 @@ version = 'Mininet ' + co( 'PYTHONPATH=. bin/mn --version', shell=True )
version = version.strip()
# Find all Mininet path references
lines = co( "grep -or 'Mininet \w\.\w\.\w\w*' *", shell=True )
lines = co( "grep -or 'Mininet \w\+\.\w\+\.\w\+[+]*' *", shell=True )
error = False
+106 -41
View File
@@ -61,10 +61,10 @@ Prompt = '\$ ' # Shell prompt that pexpect will wait for
isoURLs = {
'precise32server':
'http://mirrors.kernel.org/ubuntu-releases/12.04/'
'ubuntu-12.04.3-server-i386.iso',
'ubuntu-12.04.5-server-i386.iso',
'precise64server':
'http://mirrors.kernel.org/ubuntu-releases/12.04/'
'ubuntu-12.04.3-server-amd64.iso',
'ubuntu-12.04.5-server-amd64.iso',
'quantal32server':
'http://mirrors.kernel.org/ubuntu-releases/12.10/'
'ubuntu-12.10-server-i386.iso',
@@ -83,6 +83,18 @@ isoURLs = {
'saucy64server':
'http://mirrors.kernel.org/ubuntu-releases/13.10/'
'ubuntu-13.10-server-amd64.iso',
'trusty32server':
'http://mirrors.kernel.org/ubuntu-releases/14.04/'
'ubuntu-14.04-server-i386.iso',
'trusty64server':
'http://mirrors.kernel.org/ubuntu-releases/14.04/'
'ubuntu-14.04-server-amd64.iso',
'utopic32server':
'http://mirrors.kernel.org/ubuntu-releases/14.10/'
'ubuntu-14.10-server-i386.iso',
'utopic64server':
'http://mirrors.kernel.org/ubuntu-releases/14.10/'
'ubuntu-14.10-server-amd64.iso',
}
@@ -91,6 +103,18 @@ def OSVersion( flavor ):
urlbase = path.basename( isoURLs.get( flavor, 'unknown' ) )
return path.splitext( urlbase )[ 0 ]
def OVFOSNameID( flavor ):
"Return OVF-specified ( OS Name, ID ) for flavor"
version = OSVersion( flavor )
arch = archFor( flavor )
if 'ubuntu' in version:
map = { 'i386': ( 'Ubuntu', 93 ),
'x86_64': ( 'Ubuntu 64-bit', 94 ) }
else:
map = { 'i386': ( 'Linux', 36 ),
'x86_64': ( 'Linux 64-bit', 101 ) }
osname, osid = map[ arch ]
return osname, osid
LogStartTime = time()
LogFile = None
@@ -140,8 +164,7 @@ def depend():
run( 'sudo apt-get -y update' )
run( 'sudo apt-get install -y'
' kvm cloud-utils genisoimage qemu-kvm qemu-utils'
' e2fsprogs '
' landscape-client'
' e2fsprogs dnsmasq curl'
' python-setuptools mtools zip' )
run( 'sudo easy_install pexpect' )
@@ -215,7 +238,7 @@ def extractKernel( image, flavor, imageDir=VMImageDir ):
# Assume kernel is in partition 1/boot/vmlinuz*generic for now
part = nbd + 'p1'
mnt = mkdtemp()
srun( 'mount -o ro %s %s' % ( part, mnt ) )
srun( 'mount -o ro,noload %s %s' % ( part, mnt ) )
kernsrc = glob( '%s/boot/vmlinuz*generic' % mnt )[ 0 ]
initrdsrc = glob( '%s/boot/initrd*generic' % mnt )[ 0 ]
srun( 'cp %s %s' % ( initrdsrc, initrd ) )
@@ -440,16 +463,16 @@ def boot( cow, kernel, initrd, logfile, memory=1024 ):
return vm
def login( vm ):
def login( vm, user='mininet', password='mininet' ):
"Log in to vm (pexpect object)"
log( '* Waiting for login prompt' )
vm.expect( 'login: ' )
log( '* Logging in' )
vm.sendline( 'mininet' )
vm.sendline( user )
log( '* Waiting for password prompt' )
vm.expect( 'Password: ' )
log( '* Sending password' )
vm.sendline( 'mininet' )
vm.sendline( password )
log( '* Waiting for login...' )
@@ -485,6 +508,10 @@ def coreTest( vm, prompt=Prompt ):
log( '* Test', test, 'output:' )
log( vm.before )
def noneTest( vm ):
"This test does nothing"
vm.sendline( 'echo' )
def examplesquickTest( vm, prompt=Prompt ):
"Quick test of mininet examples"
vm.sendline( 'sudo apt-get install python-pexpect' )
@@ -507,8 +534,13 @@ def walkthroughTest( vm, prompt=Prompt ):
def checkOutBranch( vm, branch, prompt=Prompt ):
vm.sendline( 'cd ~/mininet; git fetch; git pull --rebase; git checkout '
+ branch )
# This is a bit subtle; it will check out an existing branch (e.g. master)
# if it exists; otherwise it will create a detached branch.
# The branch will be rebased to its parent on origin.
# This probably doesn't matter since we're running on a COW disk
# anyway.
vm.sendline( 'cd ~/mininet; git fetch --all; git checkout '
+ branch + '; git pull --rebase origin ' + branch )
vm.expect( prompt )
vm.sendline( 'sudo make install' )
@@ -523,12 +555,16 @@ def interact( vm, tests, pre='', post='', prompt=Prompt ):
log( '* Waiting for output' )
vm.expect( prompt )
log( '* Fetching Mininet VM install script' )
branch = Branch if Branch else 'master'
vm.sendline( 'wget '
'https://raw.github.com/mininet/mininet/master/util/vm/'
'install-mininet-vm.sh' )
'https://raw.github.com/mininet/mininet/%s/util/vm/'
'install-mininet-vm.sh' % branch )
vm.expect( prompt )
log( '* Running VM install script' )
vm.sendline( 'bash install-mininet-vm.sh' )
installcmd = 'bash install-mininet-vm.sh'
if Branch:
installcmd += ' ' + Branch
vm.sendline( installcmd )
vm.expect ( 'password for mininet: ' )
vm.sendline( 'mininet' )
log( '* Waiting for script to complete... ' )
@@ -541,6 +577,13 @@ def interact( vm, tests, pre='', post='', prompt=Prompt ):
log( '* Mininet version: ', version )
log( '* Testing Mininet' )
runTests( vm, tests=tests, pre=pre, post=post )
# Ubuntu adds this because we install via a serial console,
# but we want the VM to boot via the VM console. Otherwise
# we get the message 'error: terminal "serial" not found'
log( '* Disabling serial console' )
vm.sendline( "sudo sed -i -e 's/^GRUB_TERMINAL=serial/#GRUB_TERMINAL=serial/' "
"/etc/default/grub; sudo update-grub" )
vm.expect( prompt )
log( '* Shutting down' )
vm.sendline( 'sync; sudo shutdown -h now' )
log( '* Waiting for EOF/shutdown' )
@@ -577,13 +620,13 @@ OVFTemplate = """<?xml version="1.0"?>
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<References>
<File ovf:href="%s" ovf:id="file1" ovf:size="%d"/>
<File ovf:href="%(diskname)s" ovf:id="file1" ovf:size="%(filesize)d"/>
</References>
<DiskSection>
<Info>Virtual disk information</Info>
<Disk ovf:capacity="%d" ovf:capacityAllocationUnits="byte"
ovf:diskId="vmdisk1" ovf:fileRef="file1"
ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html"/>
<Disk ovf:capacity="%(disksize)d" ovf:capacityAllocationUnits="byte"
ovf:diskId="vmdisk1" ovf:fileRef="file1"
ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"/>
</DiskSection>
<NetworkSection>
<Info>The list of logical networks</Info>
@@ -591,26 +634,30 @@ OVFTemplate = """<?xml version="1.0"?>
<Description>The nat network</Description>
</Network>
</NetworkSection>
<VirtualSystem ovf:id="Mininet-VM">
<Info>A Mininet Virtual Machine (%s)</Info>
<Name>mininet-vm</Name>
<VirtualSystem ovf:id="%(vmname)s">
<Info>%(vminfo)s (%(name)s)</Info>
<Name>%(vmname)s</Name>
<OperatingSystemSection ovf:id="%(osid)d">
<Info>The kind of installed guest operating system</Info>
<Description>%(osname)s</Description>
</OperatingSystemSection>
<VirtualHardwareSection>
<Info>Virtual hardware requirements</Info>
<Item>
<rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
<rasd:Description>Number of Virtual CPUs</rasd:Description>
<rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
<rasd:ElementName>%(cpus)s virtual CPU(s)</rasd:ElementName>
<rasd:InstanceID>1</rasd:InstanceID>
<rasd:ResourceType>3</rasd:ResourceType>
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
<rasd:VirtualQuantity>%(cpus)s</rasd:VirtualQuantity>
</Item>
<Item>
<rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
<rasd:Description>Memory Size</rasd:Description>
<rasd:ElementName>%dMB of memory</rasd:ElementName>
<rasd:ElementName>%(mem)dMB of memory</rasd:ElementName>
<rasd:InstanceID>2</rasd:InstanceID>
<rasd:ResourceType>4</rasd:ResourceType>
<rasd:VirtualQuantity>%d</rasd:VirtualQuantity>
<rasd:VirtualQuantity>%(mem)d</rasd:VirtualQuantity>
</Item>
<Item>
<rasd:Address>0</rasd:Address>
@@ -653,16 +700,24 @@ OVFTemplate = """<?xml version="1.0"?>
"""
def generateOVF( name, diskname, disksize, mem=1024 ):
def generateOVF( name, osname, osid, diskname, disksize, mem=1024, cpus=1,
vmname='Mininet-VM', vminfo='A Mininet Virtual Machine' ):
"""Generate (and return) OVF file "name.ovf"
name: root name of OVF file to generate
osname: OS name for OVF (Ubuntu | Ubuntu 64-bit)
osid: OS ID for OVF (93 | 94 )
diskname: name of disk file
disksize: size of virtual disk in bytes
mem: VM memory size in MB"""
mem: VM memory size in MB
cpus: # of virtual CPUs
vmname: Name for VM (default name when importing)
vmimfo: Brief description of VM for OVF"""
ovf = name + '.ovf'
filesize = stat( diskname )[ ST_SIZE ]
# OVFTemplate uses the memory size twice in a row
xmltext = OVFTemplate % ( diskname, filesize, disksize, name, mem, mem )
params = dict( osname=osname, osid=osid, diskname=diskname,
filesize=filesize, disksize=disksize, name=name,
mem=mem, cpus=cpus, vmname=vmname, vminfo=vminfo )
xmltext = OVFTemplate % params
with open( ovf, 'w+' ) as f:
f.write( xmltext )
return ovf
@@ -689,6 +744,8 @@ def build( flavor='raring32server', tests=None, pre='', post='', memory=1024 ):
date = strftime( '%y%m%d-%H-%M-%S', lstart)
ovfdate = strftime( '%y%m%d', lstart )
dir = 'mn-%s-%s' % ( flavor, date )
if Branch:
dir = 'mn-%s-%s-%s' % ( Branch, flavor, date )
try:
os.mkdir( dir )
except:
@@ -710,13 +767,16 @@ def build( flavor='raring32server', tests=None, pre='', post='', memory=1024 ):
vm = boot( volume, kernel, initrd, logfile, memory=memory )
version = interact( vm, tests=tests, pre=pre, post=post )
size = qcow2size( volume )
vmdk = convert( volume, basename='mininet-vm-' + archFor( flavor ) )
arch = archFor( flavor )
vmdk = convert( volume, basename='mininet-vm-' + arch )
if not SaveQCOW2:
log( '* Removing qcow2 volume', volume )
os.remove( volume )
log( '* Converted VM image stored as', abspath( vmdk ) )
ovfname = 'mininet-%s-%s-%s' % ( version, ovfdate, OSVersion( flavor ) )
ovf = generateOVF( diskname=vmdk, disksize=size, name=ovfname )
osname, osid = OVFOSNameID( flavor )
ovf = generateOVF( name=ovfname, osname=osname, osid=osid,
diskname=vmdk, disksize=size )
log( '* Generated OVF descriptor file', ovf )
if Zip:
log( '* Generating .zip file' )
@@ -731,6 +791,9 @@ def build( flavor='raring32server', tests=None, pre='', post='', memory=1024 ):
def runTests( vm, tests=None, pre='', post='', prompt=Prompt ):
"Run tests (list) in vm (pexpect object)"
if Branch:
checkOutBranch( vm, branch=Branch )
vm.expect( prompt )
if not tests:
tests = []
if pre:
@@ -761,8 +824,8 @@ def getMininetVersion( vm ):
return version
def bootAndRunTests( image, tests=None, pre='', post='', prompt=Prompt,
memory=1024 ):
def bootAndRun( image, prompt=Prompt, memory=1024, outputFile=None,
runFunction=None, **runArgs ):
"""Boot and test VM
tests: list of tests to run
pre: command line to run in VM before tests
@@ -790,15 +853,16 @@ def bootAndRunTests( image, tests=None, pre='', post='', prompt=Prompt,
login( vm )
log( '* Waiting for prompt after login' )
vm.expect( prompt )
if Branch:
checkOutBranch( vm, branch=Branch )
vm.expect( prompt )
runTests( vm, tests=tests, pre=pre, post=post )
# runTests eats its last prompt, but maybe it shouldn't...
# runFunction should begin with sendline and should eat its last prompt
if runFunction:
runFunction( vm, **runArgs )
log( '* Shutting down' )
vm.sendline( 'sudo shutdown -h now ' )
log( '* Waiting for shutdown' )
vm.wait()
if outputFile:
log( '* Saving temporary image to %s' % outputFile )
convert( cow, outputFile )
log( '* Removing temporary dir', tmpdir )
srun( 'rm -rf ' + tmpdir )
elapsed = time() - bootTestStart
@@ -859,12 +923,13 @@ def parseArgs():
parser.add_argument( '-p', '--post', metavar='cmd', default='',
help='specify a command line to run after tests' )
parser.add_argument( '-b', '--branch', metavar='branch',
help='For an existing VM image, check out and install'
' this branch before testing' )
help='branch to install and/or check out and test' )
parser.add_argument( 'flavor', nargs='*',
help='VM flavor(s) to build (e.g. raring32server)' )
parser.add_argument( '-z', '--zip', action='store_true',
help='archive .ovf and .vmdk into .zip file' )
parser.add_argument( '-o', '--out',
help='output file for test image (vmdk)' )
args = parser.parse_args()
if args.depend:
depend()
@@ -896,8 +961,8 @@ def parseArgs():
log( '* BUILD FAILED with exception: ', e )
exit( 1 )
for image in args.image:
bootAndRunTests( image, tests=args.test, pre=args.run,
post=args.post, memory=args.memory)
bootAndRun( image, runFunction=runTests, tests=args.test, pre=args.run,
post=args.post, memory=args.memory, outputFile=args.out )
if not ( args.depend or args.list or args.clean or args.flavor
or args.image ):
parser.print_help()
+10 -4
View File
@@ -3,6 +3,8 @@
# This script is intended to install Mininet into
# a brand-new Ubuntu virtual machine,
# to create a fully usable "tutorial" VM.
#
# optional argument: Mininet branch to install
set -e
echo `whoami` ALL=NOPASSWD: ALL | sudo tee -a /etc/sudoers > /dev/null
sudo sed -i -e 's/Default/#Default/' /etc/sudoers
@@ -25,11 +27,16 @@ fi
if [ -e /etc/rc.local.backup ]; then
sudo mv /etc/rc.local.backup /etc/rc.local
fi
# Install Mininet
# Fetch Mininet
sudo apt-get -y install git-core openssh-server
git clone git://github.com/mininet/mininet
cd mininet
cd
# Optionally check out branch
if [ "$1" != "" ]; then
pushd mininet
git checkout -b $1 $1
popd
fi
# Install Mininet
time mininet/util/install.sh
# Finalize VM
time mininet/util/install.sh -tc
@@ -38,4 +45,3 @@ time mininet/util/install.sh -tc
# echo "export NOX_CORE_DIR=~/noxcore/build/src/" >> .bashrc
#fi
echo "Done preparing Mininet VM."