Compare commits

..
638 Commits
Author SHA1 Message Date
Bob Lantz 0f832c9226 Propagate prefix length to host IP configuration. 2012-06-25 14:14:09 -07:00
Nikhil Handigol 107785ddf1 RED bug fix in another place 2012-06-05 12:18:26 -07:00
Nikhil Handigol 6bb5e12347 RED bug fix: change avg. packet size 2012-06-05 12:16:32 -07:00
Brandon Heller 928c0761a0 Move code from mn into mininet/util to enable reuse
Any code in mn is not usable by other Python code.

Hence, move this code into util, so other scripts can use it.
2012-05-30 00:08:01 -07:00
Brandon Heller 30b4b4e7f9 Rename and document customNode
Now customConstructor, because it general to both links and nodes.
2012-05-29 23:57:52 -07:00
Brandon Heller f509ae282d cli: add time command 2012-05-25 16:34:05 -07:00
Bob Lantz 6c947bca07 More indent errors - curse you emacs. 2012-05-23 21:12:24 -07:00
Bob Lantz e4514a4ecb Still more indentation errors. ;-p 2012-05-23 21:09:14 -07:00
Bob Lantz 8c778bb081 Fix indentation errors. 2012-05-23 21:06:15 -07:00
Bob Lantz f1bf3c60e0 Added popenpoll.py example of using popen()/pmonitor() 2012-05-23 20:56:35 -07:00
Bob Lantz 06f7408cf2 Fix popen to allow popen( cmd, arg1, arg2, arg3 ) 2012-05-23 20:04:36 -07:00
Bob Lantz e1ca7196c7 configHosts(): don't try to configure nonexistent interfaces. 2012-05-23 13:37:02 -07:00
Bob Lantz 8f310286f8 Add setLinkInfo() which seems to be missing. 2012-05-21 23:09:11 -07:00
Nikhil Handigol b97c0392a9 make install for sch_htb.ko 2012-05-17 19:59:55 +00:00
Nikhil Handigol 9c6620d85d modified HTB to fix the perfect synchronization bug 2012-05-17 17:13:30 +00:00
Nikhil Handigol ae2ede7994 bug fix: link config 2012-05-17 17:05:37 +00:00
Bob Lantz b91008345f Fix pexec('echo foo', shell=True) 2012-05-16 23:59:12 -07:00
Bob Lantz 2f8dfe5810 Ignore error installing OVS controller, and disable its startup script. 2012-05-14 17:29:24 -07:00
Bob Lantz 79dcdc0491 Add libconfig-dev dependency for oflops. 2012-05-14 16:58:36 -07:00
Bob Lantz b0fb398833 Patch/hacks to enable NOX destiny/classic to compile on Ubuntu 12.04 2012-05-14 16:03:48 -07:00
Bob Lantz 6e64deec08 Fix typo. 2012-05-13 15:29:08 -07:00
Bob Lantz b97c1dbd56 Set dpid on OVSSwitch. 2012-05-13 15:11:41 -07:00
Bob Lantz d75e39ac61 Change wireshark install to reflect new repository location. 2012-05-13 14:43:25 -07:00
Bob Lantz e8d60e0fcf Pass code check. 2012-05-10 22:37:49 -07:00
Bob Lantz 0d94548a09 Fix default dpid which should be 12 digits for reference user switch. 2012-05-10 22:36:20 -07:00
Bob Lantz 4c3ff8f184 Remove accidentally added debugging line. 2012-05-10 22:23:31 -07:00
Bob Lantz 0e8cca0869 Remove unnecessary and broken --ip option. 2012-05-10 16:54:03 -07:00
Bob Lantz 0eba655d2d Fix RemoteController which was still using defaultIP rather than ip. 2012-05-10 16:52:40 -07:00
Bob Lantz cece39e439 Fix poller to only check if stdin and node are readable.
Thanks to James Zeng for pointing this out!
2012-05-10 16:32:55 -07:00
Bob Lantz cfd381134f Fix errRun to not exit until all of stdout and stderr have been read. 2012-05-09 22:59:30 -07:00
Bob Lantz 55cf19c4de Improve error handling for defaultDpid()
I think it's worth considering how we want to specify dpids for
switches. One way would be to have Mininet (optionally) pick them
automatically. Another way, which I have currently implemented, is
to intuit them from the name, for example s1 -> 1. The latter is
slightly inefficient, but is convenient because it ensures that
there is a logical mapping between switch names and dpids, which
is very helpful for debugging an OpenFlow system!

Probably we should just clarify that the easiest way to set a dpid
is to include it in the switch name, but you can also pass it in
as a custom parameter to the constructor.
2012-04-25 14:21:39 -07:00
Bob Lantz 50cebe6753 Add pmonitor() to make it easy to monitor popen objects. 2012-04-13 17:42:37 -07:00
Bob Lantz 237a3c54cf Begin test/example for popen(). 2012-04-13 15:50:45 -07:00
Bob Lantz 5ca91f9ced White space edits for code check. 2012-04-13 15:50:45 -07:00
Bob Lantz df600200a7 CPULimiteHost.popen(): set cgroup and (optionally) RT priority 2012-04-13 15:50:45 -07:00
Bob Lantz 089e8130e4 Add popen() to regular hosts (cpu limited in progress) 2012-04-13 15:50:45 -07:00
Bob Lantz e78e8fb56a Add support for attaching to network namespace using setns(2) 2012-04-13 15:50:45 -07:00
Bob Lantz 669e420cc4 Add default value mems=0 for memory placement. 2012-04-13 07:38:35 +00:00
Bob Lantz 5507550c53 Fix wireshark dissector install on 11.10 2012-04-11 13:20:18 -07:00
Bob Lantz 7cb340b7c9 Pass code check. 2012-04-10 00:12:37 +00:00
Bob Lantz 92b601aba9 Allow fail-mode to be set.
Probably we should have a generic mechanism to specify OVS options.
2012-04-10 00:12:03 +00:00
Bob Lantz 350fdbfe50 Allow modules (node.py) to be 1500 lines. Maybe reduce this someday. 2012-04-10 00:02:56 +00:00
Bob Lantz 548580d817 Allow lists of nodes to be passed to getNodeByName
....which should perhaps be renamed!!!
2012-04-09 23:54:17 +00:00
Bob Lantz 149a1f5639 Apparently errRun isn't as flexible as I thought... 2012-04-08 20:49:21 -07:00
Bob Lantz 197b083fbc Add static cpu (and memory) assignment. 2012-04-08 20:49:12 -07:00
Bob Lantz a7648e78fb Add mountCgroups() and tweak/correct fixLimits() 2012-04-08 20:49:04 -07:00
Bob Lantz 50202e1246 Off by one... I dislike range() 2012-04-05 21:38:02 -07:00
Bob Lantz a4338de38c Fix error message. 2012-04-05 20:57:29 -07:00
Bob Lantz d08d101eba Added simpleperf.py to examples. 2012-04-03 18:49:39 -07:00
Bob Lantz 32f7847bca Change doxypy.py to doxypy. 2012-04-03 17:50:59 -07:00
Bob Lantz 1bb990357f Added multipoll and multiping examples. 2012-04-03 17:32:55 -07:00
Bob Lantz a9c28885f3 Bring up loopback interface when configuring hosts. 2012-04-03 17:22:28 -07:00
Bob Lantz d776bd3a4f Add handle 10: to netem for hifi compat, reconfiguration. 2012-04-02 16:39:37 -07:00
Bob Lantz 5d6fda932d Add openvswitch-datapath-dkms if no datapath installed. 2012-03-31 21:30:16 -07:00
Bob Lantz c1a6ae2b48 Remove blank line. 2012-03-31 21:29:56 -07:00
Bob Lantz 78606a35c9 Removed unused param in add_link. 2012-03-31 21:29:27 -07:00
Bob Lantz 1dd3de0d04 Remove unused burst. 2012-03-31 21:29:09 -07:00
Bob Lantz ece14ff4b5 Check out CS244 branch for class. 2012-03-31 20:48:12 -07:00
Bob Lantz e5653fb63b Change back to match mininet-hifi, except for max_queue_len=1000. 2012-03-27 00:31:37 -07:00
Bob Lantz 3f61ea7104 Restore deleted deleteIntfs in OVSSwitch.stop() 2012-03-25 22:10:04 -07:00
Bob Lantz 2ec866d2c5 TCLink: pass correct parameters to superclass. 2012-03-25 20:18:35 -07:00
Bob Lantz 26c61734da Add cgroup and ethtool dependencies for mininet (w/hifi integration.) 2012-03-25 15:41:02 -07:00
Bob Lantz e1246c3741 Simplify port specification.
For the moment, I've removed the ability to specify
a dict of options without using **. This is a slightly
unfortunate trade-off since it simplifies implementation
at the expense of making the API slightly less convenient
(if somewhat more consistent.)
2012-03-25 15:39:18 -07:00
Bob Lantz 2d924f8a65 Add Mininet object to locals as 'net' 2012-03-25 15:38:32 -07:00
Bob Lantz 00d9b78035 Reinstate more complicated test. 2012-03-23 18:41:25 -07:00
Bob Lantz 612b21cbe7 Pass code check. 2012-03-23 18:38:49 -07:00
Bob Lantz 8139695d46 Use 's%s' for bw speedup; change burst to fix tbf and htb performance. 2012-03-23 18:37:32 -07:00
Bob Lantz e8146dd130 Change to allow addLink() without specifying ports. 2012-03-23 18:36:13 -07:00
Bob Lantz 44af37bc2b Change default period to 100 ms, which seems to help cfs at least...
rt is still somewhat broken.
2012-03-23 18:18:48 -07:00
Bob Lantz beb05a71c8 Move dumpNetConnections to util() because it's useful! 2012-03-23 18:17:49 -07:00
Bob Lantz 74ea006d92 Increase the quota and cpu fraction to get max cfs performance. 2012-03-23 18:17:08 -07:00
Bob Lantz 335ba99b60 Add --switch ovsl for legacy OVS. 2012-03-23 13:33:31 -07:00
Bob Lantz 8dcefd5ff9 Fix OVS legacy switch. 2012-03-23 13:33:12 -07:00
Bob Lantz 28833d864c Retry deleting cgroup for the moment because it seems flaky.
Ultimately we may wish to create a mininet/ cgroup and do a recursive
delete at the end.
2012-03-22 19:08:45 -07:00
Bob Lantz a5af91d0d3 Have errFail report cmd and stderr as well as exit code. 2012-03-22 19:08:09 -07:00
Bob Lantz 4deb735425 Simple cpu limiting example. 2012-03-22 14:44:20 -07:00
Bob Lantz f89d9a4d6b Fix typo inadvertently saved in editor. 2012-03-22 14:43:52 -07:00
Bob Lantz d1b29d58df Fix printing pid for background tasks. 2012-03-22 14:43:27 -07:00
Bob Lantz ba8d4f9bd6 Add verySimpleLimit() for debugging. 2012-03-21 23:31:20 -07:00
Bob Lantz 0b7c277ec2 Save parameters for future reference (e.g. OVS/tc workaround.) 2012-03-21 23:07:40 -07:00
Bob Lantz 1aec55d960 Workaround: reapply tc config after OVS destroys it. 2012-03-21 22:39:46 -07:00
Bob Lantz 595427842c Make CPULimitedHost method sig friendlier, and make 'cfs' default sched. 2012-03-21 17:28:00 -07:00
Bob Lantz 41245f5087 Add getNodeByName for hifi compatibility. 2012-03-21 17:27:40 -07:00
Bob Lantz b684ff7844 Fix convenience configuration methods. 2012-03-20 16:23:17 -07:00
Bob Lantz ea7c326017 Ignore emacs autosaves. 2012-03-20 15:50:44 -07:00
Bob Lantz f85c1cefb4 Use upstream OVS packages. 2012-03-20 15:49:39 -07:00
Bob Lantz 9005ce3255 Whitespace fixes. 2012-03-20 15:48:06 -07:00
Bob Lantz efc991547e Add warning in defaultIntf() if host has no interfaces.
Possibly this should be in intf() instead, as intf() is assumed
to always succeed.
2012-03-20 15:46:54 -07:00
Bob Lantz 8bebd37759 Fix is_switch() to always succeed + whitespace edits. 2012-03-20 15:45:46 -07:00
Bob Lantz e52d0ee1de Fix to work with new Topo class. 2012-03-20 15:44:50 -07:00
Bob Lantz ff56881946 Add TCLink for simplified tc-limited link creation. 2012-03-20 15:43:43 -07:00
Bob Lantz 5a8bb48951 Attempt at revised/simplified topo class:
- keys are strings
- metadata is simply a dict
- buildFromTopo greatly simplified
2012-03-20 00:17:30 -07:00
Bob Lantz 318ae55e35 Allow sendCmd( [ cmd, arg1, ... ] ) 2012-03-20 00:10:11 -07:00
Bob Lantz bf9c6ab7b4 Clarify comments and finally remove ControllerParams definition. 2012-03-12 00:29:55 -07:00
Bob Lantz 14c1926081 Use port 0 for control interface on switches. 2012-03-12 00:20:48 -07:00
Bob Lantz d7e5dfc5b6 Minor tweaks: specify port, new repr() 2012-03-12 00:20:26 -07:00
Bob Lantz 8856d284c0 Fix CLI commands. 2012-03-11 19:44:04 -07:00
Bob Lantz 14ff3ad3d0 Fix codecheck and MininetWithControlNet. 2012-03-10 20:44:34 -08:00
Bob Lantz 1d814c606d disabled-msg -> disabled for current pylint 2012-03-09 19:27:04 -08:00
Bob Lantz 82f483f559 Add support for specifying host IP range with --ipbase. 2012-03-09 17:44:47 -08:00
Bob Lantz a49c85a610 Fix examples to work with new API (and vice-versa.) 2012-03-09 16:06:23 -08:00
Bob Lantz 8e3699eca6 Move init() into Mininet() and remove calls (since called automatically.)
Note: we should probably rename it "setup()" to avoid confusion.
2012-03-09 14:10:20 -08:00
Bob Lantz e3c074b881 Remove deprecated ControllerParams (for now.) 2012-03-09 13:53:13 -08:00
Bob Lantz 9addfc13ce Add OVSController to complete out-of-box Ubuntu experience. 2012-03-08 23:48:07 -08:00
Bob Lantz d27a3c52b9 Allow various subsets of (delay, bw, loss) and clean up status output. 2012-03-08 22:08:40 -08:00
Bob Lantz 2db4268ba8 Fix NOX controller so that mn --controller nox,pyswitch,... works. 2012-03-08 22:07:19 -08:00
Bob Lantz 0dbfd3a636 Add CPULimitedHost to file comment. 2012-03-08 13:48:46 -08:00
Bob Lantz a908fafad7 Change default to vanilla Intf. Also edit comments. 2012-03-08 13:48:25 -08:00
Bob Lantz 8688ca9249 Remove debugging message. 2012-03-08 13:40:03 -08:00
Bob Lantz 8a622c3a9a Reorganize CPULimitedHost and add cgroup cleanup. 2012-03-08 13:39:28 -08:00
Bob Lantz bf5becc7d5 Get rid of SWITCH_PORT_BASE since it's 1 for OF >= 1.0. 2012-03-08 13:38:46 -08:00
Bob Lantz 216a4b7c9d Support for CFS bandwidth limiting.
Also trying to fix NOX cmdline opt, but broken at the moment.
2012-03-08 00:05:45 -08:00
Bob Lantz cbe20c7587 Remove unused imports. 2012-03-08 00:05:25 -08:00
Bob Lantz edf46e9570 Slightly cleaned up setParam to match node.py. 2012-03-07 23:38:08 -08:00
Bob Lantz b1f90976a3 Remove default classes since Mininet() really handles them. 2012-03-07 00:03:38 -08:00
Bob Lantz 4ac1148e9f Example/test of link and CPU bandwidth limits. 2012-03-06 23:52:26 -08:00
Bob Lantz 84a91a14a4 New configuration scheme and support for CPU limits (RT). 2012-03-06 23:52:00 -08:00
Bob Lantz 94c02695fd Clarify precedence of default classes. 2012-03-06 23:50:46 -08:00
Bob Lantz d8c88bedf3 Add custom() function for customizing constructors. 2012-03-06 23:49:51 -08:00
Bob Lantz 7d557fd759 Remove deprecated reference kernel switch. 2012-03-06 23:48:26 -08:00
Bob Lantz 551a3666eb Tweak errRun; add errFail and numCores. 2012-03-05 15:01:08 -08:00
Bob Lantz 542fb6167e Ignore build, dist and emacs autosaves. 2012-03-02 20:36:57 -08:00
Bob Lantz ee222055f1 Use install(1) to install mnexec so that setup.py develop works. 2012-03-02 20:34:56 -08:00
Bob Lantz 03dd914edc Tease out intfList() from intfNames(). 2012-03-02 20:34:37 -08:00
Bob Lantz a6bcad8f48 Intf and Link classes. Latter support bandwidth limits using tc. 2012-03-02 15:45:21 -08:00
Bob Lantz 6f446f6e55 Make pylint happy. 2012-03-02 15:45:10 -08:00
Bob Lantz 134a75ef38 Fix pylint complaint and add natural sort key function. 2012-03-02 15:43:07 -08:00
Bob Lantz e6d8e974ce Added errcheck target which only checks for errors. 2012-03-02 15:39:05 -08:00
Bob Lantz 176856bc9b Added setting NOX_CORE_DIR in .bashrc - this should not be necessary. 2012-02-14 16:35:12 -08:00
Bob Lantz 7a106d9b0d Script for installing mininet + tutorial into new VM. 2012-02-14 15:25:22 -08:00
Bob Lantz de5d31184f Ugh, typo. 2012-02-13 20:34:59 -08:00
Bob Lantz 65d46518c0 Don't crash if we can't uninstall kernel. 2012-02-13 20:33:59 -08:00
Bob Lantz 7a0ee56c80 openvswitch-switch needs python-argparse 2012-02-13 18:52:07 -08:00
Bob Lantz 1c0b54e52a Update OVS build suffix. 2012-02-13 18:47:22 -08:00
Bob Lantz 148a3f5735 Still dealing with install directory issues... 2012-02-13 18:30:49 -08:00
Bob Lantz 8996208084 dkms needs kernel headers. 2012-02-13 18:19:24 -08:00
Bob Lantz 7eb869af85 Force config files to be installed even if removed/edited. ;-/ 2012-02-13 17:27:32 -08:00
Bob Lantz 2b26161000 More OVS install fixes. 2012-02-13 17:13:53 -08:00
Bob Lantz e5b54a3143 Only install module manually if we built OVS from source. 2012-02-13 11:35:17 -08:00
Bob Lantz a24705d784 More controller-stopping madness. 2012-02-13 11:31:53 -08:00
Bob Lantz 9d275262e2 sudo cp for wireshark plugin 2012-02-13 11:26:11 -08:00
Bob Lantz 8183cb6262 Handle libwireshark0/libwireshark1 2012-02-13 11:23:39 -08:00
Bob Lantz 46cffb3bcf Fixed arch detection - should be i686 rather than just 686 2012-02-13 11:10:11 -08:00
Bob Lantz 738ae1f3fa Make sure bc is installed. 2012-02-13 11:05:00 -08:00
Bob Lantz fb25ee0200 Disable automatic openvswitch-controller startup. 2012-02-13 01:36:02 -08:00
Bob Lantz 2a4cbe2f57 Fix OVS 1.4.0 switch and controller package build/remove/install. 2012-02-13 01:29:01 -08:00
Bob Lantz 0e3cb791b5 Add gross depends for ovsdbmonitor. 2012-02-10 23:43:30 -08:00
Bob Lantz ae5ac257dd Build tar archive of relevant OVS packages in correct order. 2012-02-10 22:25:01 -08:00
Bob Lantz 3cd2e1a6aa Add $install + various cleanup. 2012-02-10 16:16:16 -08:00
Bob Lantz 08773f8fe9 Script to build .deb packages for Open vSwitch. 2012-02-10 14:59:39 -08:00
Bob Lantz 8a7d42db0b Update OVS switch to use ovs-vsctl rather than deprecated ovs-openflowd. 2012-02-10 14:59:39 -08:00
Bob Lantz daa576c47a Add errRun to run a command with stderr, stdout, return code and monitoring. 2012-02-10 14:59:39 -08:00
Brandon Heller b80f4aeb85 install.sh: Copy Wireshark dissector to global plugin dir 2012-02-10 14:59:39 -08:00
Bob Lantz 60b5864e1d Change to not fail if OS not detected, and to print detected OS. 2012-02-10 14:57:32 -08:00
Bob Lantz 8d1444a914 Fix for 10.04 whose default kernel doesn't have CONFIG_NET_NS enabled. 2012-02-08 17:23:52 -08:00
Bob Lantz 7e79d1351c Changes (OVS 1.2.2, NOX destiny) for installation on Ubuntu 11.10 oneiric. 2012-02-03 22:25:30 -08:00
Bob Lantz c120e37897 Try to make format mostly consistent. No tabs for the moment, although
we could switch to smart tabs (i.e. tab for indent, space for align.)
2012-02-01 15:29:53 -08:00
Bob d990eb0717 Mininet Pre-Beta -> Mininet 1.0.0; (c) 2009-2011 2011-10-13 21:03:25 -07:00
Bob Lantz d2f9aea273 Minor text updates in preparation for ONS release. 2011-10-13 16:51:37 -07:00
Bob Lantz 0bfd19fe83 Have install.sh apply controller patch for > 16 switches 2011-06-29 21:14:48 -07:00
Bob Lantz 5cc808286a Revert inadvertent print in node.py 2011-06-29 19:36:44 -07:00
Bob Lantz 2668484163 Avoid printing out grep results. 2011-06-29 19:31:45 -07:00
Bob Lantz 7596de5903 Upgrade networkx on Ubuntu 10.04 LTS to avoid deprecation warning. 2011-06-29 19:25:28 -07:00
Bob Lantz 5675f2a142 Workaround in oflops build for possible autoreconf bug. 2011-06-29 17:32:00 -07:00
Bob Lantz c2e1451997 Add option to install cbench aka oflops 2011-06-29 17:16:20 -07:00
Bob Lantz 4e13f615aa Git clone oflops from openflow.org rather than www.openflow.org 2011-06-29 17:04:49 -07:00
Bob Lantz 37e1eafdbb Switch to Open vSwitch 1.1.1 for stability. 2011-06-28 16:50:14 -07:00
Bob Lantz 2b03a115d2 Changed make clean to delete mnexec; added codecheck and test messages. 2011-04-01 11:56:31 -07:00
Bob Lantz 85cc906f14 Fixed typo. 2011-03-15 00:39:50 -07:00
Bob Lantz d00fa51f4c Removed line that caused install.sh to fail with undefined variable.
Still should check to make sure Debian install works.
2011-02-02 23:47:05 -08:00
Bob Lantz 518c75b548 Fixed nox_pysw not to fail on startup, but --port still doesn't work. 2011-01-18 21:23:24 -08:00
Bob Lantz ad2fda2522 Attempt to make iperf test more robust. 2011-01-06 21:00:22 -08:00
Bob Lantz 1dcc047624 Changed to make 'output' the default log level. 2011-01-04 17:12:34 -08:00
Bob Lantz 1ee6fad705 Preliminary fixes for merge conflicts. 2010-11-17 17:17:21 -08:00
Bob Lantz 219f9de778 Pre-1.0rc0 changes to text files. 2010-10-27 21:29:05 -07:00
Bob Lantz 54d320ce9f Pass code check. 2010-10-27 21:21:54 -07:00
Bob Lantz 996098081e Not sure why, but there's an extra blank line ;-/ 2010-10-27 21:21:54 -07:00
Bob Lantz 8a130deae5 Support for generating documentation with doxygen/doxypy (such as it is.) 2010-10-27 21:21:53 -07:00
Bob Lantz 1d67218d1f Modified to add eth1. 2010-10-25 21:54:14 -07:00
Bob Lantz 76521ef1d4 Added example of adding hw interface to mininet. 2010-10-25 21:53:29 -07:00
Bob Lantz 7e643d36c0 Removed udpbwgraph - not ready for prime time. 2010-10-25 21:53:10 -07:00
Bob Lantz 11782ae0de Commented out kernel ref, moved to Open vSwitch. 2010-10-25 21:52:14 -07:00
Bob Lantz 24baea734f Changed networkx import line; we may have to deal with version issues here. 2010-10-17 17:36:48 -07:00
Bob Lantz 87737a7064 One more merge fix. 2010-10-17 17:25:16 -07:00
Bob Lantz 4876b43fe9 Merge branch 'of1.0' into testing
Conflicts:

	bin/mn
	mininet/cli.py
	mininet/moduledeps.py
	mininet/node.py
	mininet/topo.py
	util/install.sh
2010-10-17 17:23:23 -07:00
Bob Lantz 57fd19efaa Rename Controller.controller to .command 2010-09-01 20:52:29 -07:00
Bob Lantz e30f2c99c2 Rename Controller.controller to .command 2010-09-01 20:51:40 -07:00
Bob Lantz 55ca2d0c96 Pass code check. 2010-09-01 20:51:27 -07:00
Bob Lantz 74a56e2bae Pass code check. 2010-09-01 20:50:42 -07:00
Bob Lantz 444f9d8d76 Pass code check. 2010-09-01 20:50:28 -07:00
Bob Lantz 300efb2b80 Added simple example of using API just to create a namespace. 2010-09-01 19:54:10 -07:00
Bob Lantz e0e69bbeec Added new example of multiple controllers. 2010-09-01 19:53:09 -07:00
Bob Lantz 276bdaf0d3 Added more dependencies for some installs and for Debian. 2010-09-01 19:52:30 -07:00
Bob Lantz cde0c25bfe Fix for new networkx. 2010-09-01 19:51:54 -07:00
Bob Lantz 73a098a499 Use __dict__.update to update an object's fields. 2010-09-01 19:51:09 -07:00
Bob Lantz eaf5888ae0 Added controller class arg to addController(). 2010-09-01 19:50:30 -07:00
Bob Lantz 2a75022403 Fixed args for nox. 2010-09-01 19:50:00 -07:00
Bob Lantz fe769afa22 Added port to controller args; changed NOX to new arg format. 2010-09-01 19:46:48 -07:00
Bob Lantz 5c24e18639 Disable (broken) scripting for interactive commands. 2010-08-20 08:48:10 -07:00
Bob Lantz cc960215fc Added --prefixlen option - this may help with router tutorial. 2010-08-19 20:53:40 -07:00
Bob Lantz ec226c9b83 Better order - kernel first, then mininet, then everything else. 2010-08-19 16:49:06 -07:00
Bob Lantz ee7ee4065c Get the options right... 2010-08-19 16:48:02 -07:00
Bob Lantz 40beaabc14 More edits for pre-beta. 2010-08-19 16:45:11 -07:00
Bob Lantz e900a16caf Don't try to modprobe tun if it's built-in (e.g. Ubuntu.) 2010-08-19 14:42:33 -07:00
Bob Lantz 05c2d669a9 Add make to mininet deps. 2010-08-18 23:39:07 -07:00
Bob Lantz cc16d2ce29 Attempt to fix OS detection for Debian. 2010-08-18 23:33:48 -07:00
Brandon Heller 4800435d1a vm: Don't exit if some files aren't there 2010-08-18 04:43:51 -07:00
Bob Lantz f9654e5654 Better error messages when switch setup() fails. 2010-08-18 10:58:24 -07:00
Bob Lantz a77e7a029e Update for openflow.org URLs. 2010-08-18 10:23:14 -07:00
Bob Lantz bd507eecfa Oops, get rid of debug print. 2010-08-18 10:07:57 -07:00
Bob Lantz 9802686b32 Switches use high default intf; disable slicing for user switch. ;-(
This should fix --switch user --innamespace.
2010-08-18 10:04:42 -07:00
Brandon Heller 4d1c17e17e Move kernel downloads to OpenFlow web page 2010-08-18 02:30:18 -07:00
Brandon Heller 9da63d4e85 Add dpctl command, which runs on all switches 2010-08-18 02:08:35 -07:00
Brandon Heller 0a9358c9fc Add option to turn off passive listening port 2010-08-18 02:08:34 -07:00
Brandon Heller b480b6ef77 Add newline 2010-08-18 02:08:34 -07:00
Brandon Heller ccca871ae6 Add passive listening port 2010-08-18 02:08:34 -07:00
Bob Lantz 2d48b4633c More installation edits. 2010-08-17 23:11:10 -07:00
Bob Lantz f6149e4d18 More edits. 2010-08-17 23:01:12 -07:00
Bob Lantz 6555c9294b Added more hopefully useful information.
We may want to start cutting things at some point - it looks more
complicated than it really is!
2010-08-17 22:54:44 -07:00
Bob Lantz 4c85d6d3ec Quotes are better. 2010-08-17 22:36:40 -07:00
Bob Lantz 8e5892e2fd Make it easier to see what the error was on failed module load. 2010-08-17 22:35:24 -07:00
Bob Lantz 59d326295f Fixed module installation error, for real. 2010-08-17 22:32:22 -07:00
Bob Lantz dd2a2442c4 Hack: run depmod twice so it works (hopefully) on Ubuntu. 2010-08-17 20:40:53 -07:00
Bob Lantz 7268f6943c Add gcc to mininet dependencies. 2010-08-17 19:33:24 -07:00
Bob Lantz a0ca68b6b8 Install mininet along with its dependencies. 2010-08-17 17:41:01 -07:00
Bob Lantz cf9c968756 Change to not try to install kernel on ubuntu. 2010-08-17 17:31:02 -07:00
Bob Lantz 25f64a39a0 Changed to not install kernel on ubuntu. 2010-08-17 17:04:57 -07:00
Bob Lantz 57a0bb2f95 Removed unneeded lenny function. 2010-08-17 16:49:45 -07:00
Bob Lantz 01eea3503b Updated other install and help message. 2010-08-17 16:36:42 -07:00
Bob Lantz 85b69adbf8 Version that hopefully will work on Ubuntu with an ext3 root FS. 2010-08-17 16:07:07 -07:00
Bob Lantz 52c700ff0c Updated for 1.0 and to reflect install.sh. 2010-08-17 16:06:34 -07:00
Bob Lantz 5d4d630580 Getting close to Ubuntu install. 2010-08-17 03:04:30 -07:00
Bob Lantz 455194a3b8 Delete spaces around =. 2010-08-17 03:04:12 -07:00
Bob Lantz 0533e1cc1e Remove hard-wired /home/mininet directory. 2010-08-17 00:30:25 -07:00
Bob Lantz b13a2c17c5 Removed test for reference kernel implementation, for now at least. ;-( 2010-08-17 00:02:33 -07:00
Bob Lantz 2f40c85691 Added additional sanity checks for when OF/OVS isn't installed. 2010-08-17 00:02:33 -07:00
Bob Lantz ab312967fe Added pathCheck for additional sanity when OF/OVS isn't installed. 2010-08-17 00:02:32 -07:00
Bob Lantz 2c07d62b3c Remove blank lines to pass code check. 2010-08-17 00:02:31 -07:00
Bob Lantz e3a1fbb047 Added support for pre- and post-test CLI scripts. 2010-08-17 00:02:31 -07:00
Bob Lantz 9de7873bc8 Change to automatically update IP and MAC addresses. 2010-08-17 00:02:31 -07:00
Bob Lantz b7097daad4 Pass make codecheck. 2010-08-17 00:02:30 -07:00
Bob Lantz 52082ff3f9 mininet.node.SWITCH_PORT_BASE specifies first switch port number.
This should be mostly cosmetic, but it causes switches to number
their ports consistently with OpenFlow 1.0, which starts at 1.
For older versions of OpenFlow, SWITCH_PORT_BASE may be set to zero.
2010-08-17 00:02:30 -07:00
Bob Lantz b78c938201 Changed license to OpenFlow license. 2010-08-17 00:02:30 -07:00
Bob Lantz dde9c91dcf Added error message if we can't read script file. 2010-08-17 00:02:30 -07:00
Bob Lantz 9d0dbe488a Added "source" command and restored echo after noecho command.
Interactive commands should "work", sort of.
2010-08-17 00:02:29 -07:00
Bob Lantz 6d2416ecbe Removed test for reference kernel implementation, for now at least. ;-( 2010-08-16 23:02:04 -07:00
Bob Lantz f00101716b Added additional sanity checks for when OF/OVS isn't installed. 2010-08-16 23:01:31 -07:00
Bob Lantz b47cdfea26 Added pathCheck for additional sanity when OF/OVS isn't installed. 2010-08-16 23:01:06 -07:00
Bob Lantz f95aebb4f9 Remove blank lines to pass code check. 2010-08-16 23:00:43 -07:00
Bob Lantz d869d82027 Added support for pre- and post-test CLI scripts. 2010-08-16 20:21:08 -07:00
Bob Lantz 54d026f656 Change to automatically update IP and MAC addresses. 2010-08-16 19:36:00 -07:00
Bob Lantz 68c89df8a1 Pass make codecheck. 2010-08-16 19:35:49 -07:00
Bob Lantz dd159b4a73 mininet.node.SWITCH_PORT_BASE specifies first switch port number.
This should be mostly cosmetic, but it causes switches to number
their ports consistently with OpenFlow 1.0, which starts at 1.
For older versions of OpenFlow, SWITCH_PORT_BASE may be set to zero.
2010-08-16 14:49:02 -07:00
Brandon Heller 299925c22f Add more param choices for iperf udp on CLI 2010-08-16 12:04:24 -07:00
Brandon Heller 7d83d46270 Remove print statement left in 2010-08-16 12:04:24 -07:00
Brandon Heller 2fffa0bb6f Change port base from 0 to 1
OpenFlow versions > v0.9 require this.

Only tested w/FatTree topo - it's almost a guarantee that this breaks
every other topology.
2010-08-16 12:04:24 -07:00
Brandon Heller 0a6e54231e Set default switch type to OVS 2010-08-16 12:04:24 -07:00
Brandon Heller 6b2a3b187b Small OVS API change 2010-08-16 12:04:24 -07:00
Brandon Heller e282b6e29f Fix --mac breakage
The OVS interface for this moved to ovs-openflowd.

This functionality was never there for the user-space switch.  Now it's
in.
2010-08-16 12:04:23 -07:00
Brandon Heller 7abca147c4 vm: Remove SSH keychain load-on-boot script 2010-08-16 12:04:23 -07:00
Brandon Heller 71ba12c539 vm: Forgot to run boot.sh 2010-08-16 12:04:23 -07:00
Brandon Heller b97415eed4 vm: Use OVS git release
OVS1.0.1 does not work with veth pairs.
2010-08-16 12:04:23 -07:00
Brandon Heller 9f8c25515f Add missing dep for cbench 2010-08-16 12:04:23 -07:00
Brandon Heller 011b02f886 Update VM install for 1.0
Remove all OpenFlow Ref kmod stuff.
2010-08-16 12:04:23 -07:00
Bob Lantz fa8693480a Changed license to OpenFlow license. 2010-08-16 11:49:44 -07:00
Brandon Heller fc75a1b185 Add ability to specify hosts for iperf test 2010-08-16 11:41:25 -07:00
Bob Lantz 6e9074f89e Added error message if we can't read script file. 2010-08-10 18:57:00 -07:00
Bob Lantz 6aff964ea0 Added "source" command and restored echo after noecho command.
Interactive commands should "work", sort of.
2010-08-10 18:47:15 -07:00
Brandon Heller 57aae3e103 Add more param choices for iperf udp on CLI 2010-08-10 04:28:18 -07:00
Brandon Heller 60a39a7241 Add ability to specify hosts for iperf test 2010-08-10 02:16:36 -07:00
Brandon Heller 1a52deeea6 Remove print statement left in 2010-08-10 02:05:20 -07:00
Brandon Heller 956546acc7 Change port base from 0 to 1
OpenFlow versions > v0.9 require this.

Only tested w/FatTree topo - it's almost a guarantee that this breaks
every other topology.
2010-08-09 23:22:40 -07:00
Brandon Heller e9d4482e42 Set default switch type to OVS 2010-08-06 10:39:39 -07:00
Brandon Heller d26abda426 Small OVS API change 2010-08-06 10:38:15 -07:00
Brandon Heller 81d27b3c56 Fix --mac breakage
The OVS interface for this moved to ovs-openflowd.

This functionality was never there for the user-space switch.  Now it's
in.
2010-08-06 10:34:17 -07:00
Brandon Heller 72ddde869c vm: Remove SSH keychain load-on-boot script 2010-08-06 01:15:40 -07:00
Brandon Heller cd19cf520f vm: Forgot to run boot.sh 2010-08-06 00:44:29 -07:00
Brandon Heller a434c3d1b6 vm: Use OVS git release
OVS1.0.1 does not work with veth pairs.
2010-08-06 00:36:39 -07:00
Brandon Heller 6aa7f3493b Add missing dep for cbench 2010-08-05 16:56:50 -07:00
Brandon Heller 32b122bf42 Update VM install for 1.0
Remove all OpenFlow Ref kmod stuff.
2010-08-04 21:56:04 -07:00
Bob Lantz 272d496dfe Darned trailing whitespace. 2010-06-16 12:24:45 -07:00
Bob Lantz a6661f0ac1 Consistently use tcp:%s:%d for controller IP address format.
(In user, kernel and ovsk switch classes.)
2010-06-16 12:21:43 -07:00
Bob Lantz 68f5925ed6 Changed port to int type (was string, which caused %d not to work in node.py.) 2010-06-16 12:15:29 -07:00
Brandon Heller 3b48e82990 Add rough tutorial VM changes 2010-05-20 16:23:08 -07:00
Bob Lantz c26875cb55 Fixed minor breakage due to code cleanup. 2010-05-07 01:15:41 -07:00
Bob Lantz e3f6ecca97 Pass codecheck. 2010-05-06 17:48:15 -07:00
Bob Lantz 82b7207295 Pass pylint. 2010-05-06 16:24:15 -07:00
Bob Lantz 259d713315 Pass pyflakes. 2010-05-04 19:11:12 -07:00
Bob Lantz c79882b766 Fixed typo. 2010-05-04 17:32:46 -07:00
Bob Lantz fa20913b56 Added space to one line. 2010-04-29 16:18:25 -07:00
Bob Lantz 271013e0dc Minor cleanup. 2010-04-27 15:13:25 -07:00
Bob Lantz 6c5cc2bfee Fix malformed patch format.
For some reason, the leading spaces were missing.
2010-04-23 15:08:30 -07:00
Bob Lantz 83e7ea2a0d Correction: blacklist.conf -> blacklist
On debian, the module blacklist is blacklist, not
blacklist.conf.
2010-04-23 15:06:42 -07:00
Bob Lantz 6ef2973fe2 Use switches rather than switches.keys().
Minor cosmetic change, really.
2010-04-22 17:16:53 -07:00
Bob Lantz e55cbef182 Removed debugging printing.
Note now that we can pass options into switches; for example,
we could enable stp with Switch( 's1', opts='--stp' ).
2010-04-22 17:12:22 -07:00
Bob Lantz 3758da2ec8 Minor comment change. 2010-04-22 17:08:39 -07:00
Bob Lantz 121eb4496b Changed to support new cmd() interface.
It seems that it is more convenient to be able to call

cmd( 'foo', 'bar', 1)

for example. However, this may make it slightly less
efficient, so we will see how it works.
2010-04-22 17:06:34 -07:00
Bob Lantz 8bc0037938 Fixed link check and updated quietRun interface.
Link check wasn't quite right - e.g. 'eth1' could be found in
'eth10' previously.

Updated quietRun to allow passing in args directly rather than
as a list.
2010-04-22 17:05:27 -07:00
Bob Lantz 54dfb2434a Changed to use new cmd interface.
I'm still not 100% sure on this.
2010-04-22 17:04:48 -07:00
Bob Lantz b145865407 Added comment advising use of high-level API. 2010-04-22 17:04:17 -07:00
Bob Lantz 83332c1a42 Handle interfaces (e.g. real interfaces) without remote Node. 2010-04-22 17:03:26 -07:00
Bob Lantz d2ff558da7 Correctly handle xterm creation with new makeTerm interface. 2010-04-22 17:02:41 -07:00
Bob Lantz 34954fe671 Minor comment change. 2010-04-22 17:02:19 -07:00
Bob Lantz ab1fb093d1 Added output hook and graph. 2010-04-22 17:01:54 -07:00
Bob Lantz 2a554ae33c Changed 'args' to 'line' and fixed iperfudp. 2010-04-12 18:56:50 -07:00
Bob Lantz caf024bc98 Made help string a class var. 2010-04-12 18:52:00 -07:00
Bob Lantz e555f83c97 Replaced stdout.write() with output() 2010-04-12 18:45:43 -07:00
Bob Lantz c16679863b Updated comments to reflect interactive command support.
It may be fragile, but it does sort of work.
2010-04-12 18:37:33 -07:00
Bob Lantz f800e5124d Tweaks for better interactive command handling. 2010-04-12 18:34:52 -07:00
Bob Lantz f24e70a435 Added timeout option for monitor().
This allows monitor() to be used for polling. Of course, you
probably want to use poll() first anyway, but it's nice not
to have to block if there's no output.
2010-04-12 18:33:20 -07:00
Bob Lantz 3482b4467c Changed to not print control chars we don't handle. 2010-04-12 18:32:32 -07:00
Bob Lantz e7ba6b9ebb Add title to consoles. 2010-04-11 01:43:35 -07:00
Bob Lantz bbe5f8a389 Minor comment changes. 2010-04-11 01:42:58 -07:00
Bob Lantz fce4d59dc1 Added ability to show switches and controllers. 2010-04-11 01:12:23 -07:00
Bob Lantz f583900da9 Added default title of 'Node'. 2010-04-11 01:12:11 -07:00
Bob Lantz 68f97b74ad Added explicit xterm and gterm commands.
This is not as generic as having a single 'term' command, but
it's a lot more convenient to use.
2010-04-10 23:54:05 -07:00
Bob Lantz 9ab2cba870 Fixed gterm support; quote and join -e argument. 2010-04-10 23:53:00 -07:00
Bob Lantz 99c035d9ca Changed to automatically call build() if necessary. 2010-04-10 23:52:15 -07:00
Bob Lantz 6c82d1bae7 Added blurbs for new demos. 2010-04-10 23:51:57 -07:00
Bob Lantz 03e5965236 Changed to use info() and not call build() unnecessarily. 2010-04-10 23:51:34 -07:00
Bob Lantz c3a583c813 Changed comment on iperf. 2010-04-10 22:40:12 -07:00
Bob Lantz e123afea97 Changed to let iperf run indefinitely. Simplifies things. 2010-04-10 22:38:20 -07:00
Bob Lantz 7ad4829203 Added iperf command. 2010-04-10 22:27:55 -07:00
Bob Lantz a650b8e657 Fixed catch: typo. 2010-04-10 22:04:55 -07:00
Bob Lantz a4db2c2fca Removed unnecessary init() calls. 2010-04-10 21:35:58 -07:00
Bob Lantz 4720f559c3 Fixed to import TreeNet and to skip unnecessary init(). 2010-04-10 21:35:35 -07:00
Bob Lantz 56278434a8 Changed to use library TreeNet() and remove unnecessary init(). 2010-04-10 21:35:02 -07:00
Bob Lantz 4a67fc9a4a Changed screen(1) names from hN to mininet.hN.
This should make it easier for people who use screen for other purposes
to identify which sessions were created by mininet.
2010-04-10 21:31:34 -07:00
Bob Lantz 257a2f636b Added ovs-openflowd to list of zombies.
We may still need additional code to clean up after ovs.
2010-04-10 21:30:35 -07:00
Bob Lantz c6e7eaf07c Changed to not die immediately if we send in an empty command.
There might still be some issues with this however...
2010-04-10 21:29:34 -07:00
Bob Lantz cd7457480b Re-added TreeNet convenience function. 2010-04-10 21:29:11 -07:00
Bob Lantz 5fb3d5426c Restored numbering of tree nodes. 2010-04-10 21:15:15 -07:00
Bob Lantz 724f1144ac Changed messages slightly.
For a network, we create "links" rather than "edges" on a graph.

"Edges" is a bit confusing because the links may not be edge links on
the network!

Also, since you're not necessarily running a "test", I changed it to
just say that we're "Done."
2010-04-10 21:10:25 -07:00
Bob Lantz 8e4d818a60 Made the scroll bars narrower to fit ping output on my 15" screen. 2010-04-10 21:01:44 -07:00
Bob Lantz d0e53ca863 Added semi-interactive command line support.
Now you can type commands into each mini-console!
2010-04-10 20:52:45 -07:00
Bob Lantz f89015971f Added default prefix for window titles if none is specified. 2010-04-10 20:52:02 -07:00
Bob Lantz 388f54e148 Fixed regex typo. 2010-04-10 20:25:16 -07:00
Bob Lantz ff6145c015 Change import to reflect renamed mininet.term module. 2010-04-10 20:24:31 -07:00
Bob Lantz 3e6b3dd273 Added an example of how to make an empty Mininet and add things to it. 2010-04-10 19:29:04 -07:00
Bob Lantz c58bb42f57 Added updbwgraph, a demo of how to graphically monitor node output. 2010-04-10 19:28:18 -07:00
Bob Lantz afe0ce81a5 Added simple console tool demo.
The console tool spawns and monitors a bunch of nodes.
2010-04-10 19:26:54 -07:00
Bob Lantz e10abba08d Added a simple graphical network editor demo. 2010-04-10 19:26:20 -07:00
Bob Lantz b5672f1565 Cleaning up read/monitor/interrupt.
Now you don't need to specify a default read count.

Now, by default, we print the pid out in sendCmd() which allows us
to snarf it later and set lastPid correctly.

Now, we wrap os.kill() in a try block, so that if the process is
already gone we don't get an exception.
2010-04-10 19:24:47 -07:00
Bob Lantz de901ef058 Modified to allow execed nodes to work, if we ever reinstate them. 2010-04-10 19:24:11 -07:00
Bob Lantz b1affce867 Removed TreeNet() convenience function (moved to topolib.) 2010-04-10 19:23:45 -07:00
Bob Lantz 8bbd368576 Moved TreeNet() convenience function here. 2010-04-10 19:23:23 -07:00
Bob Lantz ce67093a62 Minor format tweaks. 2010-04-09 01:46:51 -07:00
Brandon Heller 15b482e375 Support gnome terminals too
Caution: code is incomplete - can't set a default type from the CLI
and in some places the phrase xterm should be replaced by terminal.
2010-04-05 02:27:00 -07:00
Brandon Heller e540ab5726 Use quit rather than kill when cleaning up screens
Kill seems to get ignored, while quit kills the detached sessions.
2010-04-05 02:07:23 -07:00
Brandon Heller ce9cd5bee5 Add command to spawn an xterm 2010-04-05 01:06:30 -07:00
Bob Lantz b14b1ee441 Remove unneeded '-' in '-n', which was causing error message. 2010-03-30 16:09:43 -07:00
Bob Lantz 06b8210ea1 Changed TreeTopo() to number hosts from h1 to hN. 2010-03-30 15:06:43 -07:00
Bob Lantz f2dee12d93 Added LICENSE.
We may wish to change this just to "mininet is copyrighted by its
authors" or something...
2010-03-26 19:05:22 -07:00
Bob Lantz 5eac2a8403 Changed help message to be a bit clearer. 2010-03-26 18:47:41 -07:00
Bob Lantz 5791f32a2d Fix --controller=remote 2010-03-26 18:41:09 -07:00
Bob Lantz ffd089ea1c Changed git clone command. 2010-03-26 17:50:37 -07:00
Bob Lantz 8eae25501c Changed installation notes to reflect VM image install. 2010-03-26 17:45:44 -07:00
Bob Lantz 9a17de9166 Minor changes for alpha.
Added alpha releas comments, inc. do not distribute yet.

Added install notes for install.sh.
2010-03-26 15:48:25 -07:00
Brandon Heller 74cd084315 Clean up a few more things 2010-03-23 00:51:45 -07:00
Bob Lantz a0c97d110c Added patches for openflow reference version.
These may not be needed if they are pushed upstream.
2010-03-26 14:05:48 -07:00
Bob Lantz 8125370d8e Minor tweaks for alpha. 2010-03-26 14:04:04 -07:00
Bob Lantz add0ee6059 Added sudo for aptitude install. 2010-03-26 13:50:13 -07:00
Bob Lantz e21aa14fac Minor comment edits. 2010-03-26 12:33:47 -07:00
Bob Lantz 3f02f15e47 Added kbuild script for 2.6.33.1 2010-03-26 12:28:55 -07:00
Brandon Heller 1e4f337584 Fix path for cleaning 2010-03-23 01:18:48 -07:00
Brandon Heller f5191b855f Revert "Add ability to pause and resume any node"
This reverts commit 07aad11081.

When the semantics are clear, functionality like this will get added back to
Mininet.

Conflicts:

	mininet/node.py
2010-03-23 01:15:51 -07:00
Brandon Heller f32a546855 Fix NOX breakage
Controllers are no longer namespace-able, and all calls need one fewer
arg.

Also use more sensible temporary variable name.
2010-03-23 00:48:35 -07:00
Brandon Heller e4370f7ee7 Run depmod for specified kernel 2010-03-22 23:56:58 -07:00
Brandon Heller c9ae0ab003 Generate initrd if missing
Works around bug in newer version of kernel-package.
2010-03-23 01:45:59 -07:00
Brandon Heller fc48e6ee7c Add VM build option for 2.6.33 OVS/OF 2010-03-22 23:17:22 -07:00
Brandon Heller 9a7717ed9d Get past NOX build error w/newer autoconf 2010-03-22 22:44:31 -07:00
Brandon Heller c532689266 Clone NOX into ~/ and fix typo 2010-03-22 22:28:13 -07:00
Brandon Heller d82b6183d6 Get past verification error 2010-03-22 22:14:57 -07:00
Brandon Heller a9aebba7f7 Restore 2.6.29 as default image 2010-03-22 22:14:10 -07:00
Brandon Heller 9098528a16 Fix CLI breakage with new test interface 2010-03-24 07:24:26 -07:00
Brandon Heller 55c335849a Add OVS patch for 2.6.33+
Thanks to Ben Pfaff who wrote the patch
2010-03-24 05:20:12 -07:00
Brandon Heller 4779fa84f9 Add bash_profile for VM build 2010-03-24 05:20:12 -07:00
Brandon Heller 0b1832ddc2 Consolidate install script and add cmd-line options
Now, the majority the install can be done with one line, but the other
to each part of the install is still available.

Also fix a few bugs and add Wireshark coloring rules.
2010-03-24 05:19:52 -07:00
Bob Lantz e91b2815fa Moved waitForNode. Maybe candidate for util.py or static method... 2010-03-24 17:21:57 -07:00
Bob Lantz c2cc1aacf6 Attempt to handle interrupts in the middle of CLI commands. 2010-03-24 17:17:24 -07:00
Bob Lantz 41badb9686 Pass code check. 2010-03-24 17:08:25 -07:00
Bob Lantz 45e82d0952 Restored treeping64 and tre1024 examples and updated README. 2010-03-24 17:04:11 -07:00
Bob Lantz d93c6ef6ce Change to use setLogLevel() 2010-03-24 17:03:57 -07:00
Bob Lantz fe414722ac Change to use setLogLevel() 2010-03-24 17:03:49 -07:00
Bob Lantz 8423875b37 Change to use new interface to mn.run() 2010-03-24 17:03:27 -07:00
Bob Lantz 47acf53974 Change to use printf rather than echo. 2010-03-24 17:02:44 -07:00
Bob Lantz 67516aa44f Change run() to allow running external functions. 2010-03-24 16:58:44 -07:00
Bob Lantz 6e4e79afc3 Add setLogLevel as an export. 2010-03-24 16:58:27 -07:00
Bob Lantz 22f807fc6f Reinstated multitest example and updated examples/README. 2010-03-24 15:20:22 -07:00
Bob Lantz b2ef87ae51 Changes to pass code check.
We should check NOXController and RemoteController to make sure that
they are not broken, but I cannot do this at the moment.
2010-03-24 15:02:28 -07:00
Bob Lantz 0774c8bbce Added two spaces before in-line # comments. 2010-03-24 14:42:42 -07:00
Bob Lantz cf6f67045b Added two spaces before in-line # comments. 2010-03-24 14:41:40 -07:00
Bob Lantz 353411422e Minor formatting changes. 2010-03-24 13:42:46 -07:00
Bob Lantz c70aab0a38 Changed mininet.link() to mininet.configLinkStatus(src,dst,status)
Also rearranged parameters in link command to

mininet> link s1 h2 up

To resemble ifconfig a bit more.
2010-03-23 15:25:12 -07:00
Bob Lantz fb2f652319 Changed mininet.link() to support multiple links.
It should also probably be renamed to something like:
configLinks(src, dst, status).
2010-03-23 15:05:55 -07:00
Bob Lantz 178a3d8410 Minor tweaks. 2010-03-22 19:34:47 -07:00
Bob Lantz c8fbd4465c Updated installation notes and added patch for controller.c. 2010-03-22 17:50:02 -07:00
Bob Lantz f2eaeac78c Added patch for 2.6.33.x kernel. 2010-03-22 16:24:22 -07:00
Bob Lantz 6ab417ccd7 Added setup for kernel switch. 2010-03-22 16:24:04 -07:00
Bob Lantz 3e624fb237 Added openvswitch kernel switch. 2010-03-17 23:43:03 -07:00
Bob Lantz 8abc3472e3 Pass code check. 2010-03-16 14:59:46 -07:00
Bob Lantz ec7b211c41 Buffered output. Added net.monitor() and node.readline()
Moved monitor() and readline() into net.py and node.py respectively,
which will hopefully be useful for monitoring large sets of hosts,
as is done in udpbwtest.py.

Changed iperf to use interactive command infrastructure (such as it
is), which may make it more reliable. Hopefully it's a bit clearer
as well, although it is slightly more complicated.
2010-03-16 14:59:45 -07:00
Bob Lantz 6ab1f1ff23 Run in non-verbose mode, and print network sizes. 2010-03-16 14:59:45 -07:00
Bob Lantz 736038f8ef Added README for examples. 2010-03-16 14:59:45 -07:00
Bob Lantz e4c82e526e Change Node.monitor() to just return output.
It seems easier to rely on node.waiting for the moment.
2010-03-16 14:59:45 -07:00
Brandon Heller a3d899123d Comment clarification 2010-03-14 03:57:25 -07:00
Brandon Heller b055728fd5 Automatically load kernel module dependencies
Before this commit, you'd have to manually insert the kernel module for
OVS or OF kernel modules, and you couldn't run one regression test with
all 3.

Now, these are kmod insert/remove is handled automatically.
2010-03-14 03:53:16 -07:00
Brandon Heller a165881049 Ignore pyc files 2010-03-14 03:53:16 -07:00
Brandon Heller e01292c167 Fix minor typo 2010-03-14 03:53:16 -07:00
Brandon Heller 956bf4f2d0 Fix param typo 2010-03-14 03:53:15 -07:00
Bob Lantz e100d1d9d0 Change ofprotocold -> ovs-openflowd in OVSKernelSwitch. 2010-03-15 19:27:55 -07:00
Bob Lantz ad824e4e84 Pass codecheck. 2010-03-15 19:24:54 -07:00
Brandon Heller 3fac5a43d7 Handle ping output for paused hosts 2010-03-13 21:44:11 -08:00
Brandon Heller 07aad11081 Add ability to pause and resume any node 2010-03-13 21:35:52 -08:00
Brandon Heller 28cd95c374 Fix link command parsing bug 2010-03-13 21:32:11 -08:00
Brandon Heller af380c8912 Show PIDs in dump() 2010-03-13 16:36:34 -08:00
Brandon Heller 8d3c2859e4 Add port status change command 2010-03-13 06:30:53 -08:00
Brandon Heller e7c787b343 Fix sending commands to switches 2010-03-13 06:02:40 -08:00
Bob Lantz cae423e543 For now, make install. 2010-03-14 19:32:10 -07:00
Bob Lantz 7f9eb9e540 Changed remaining refs to netns to refer to mnexec. 2010-03-14 19:28:19 -07:00
Bob Lantz 3465c9ea64 Updated to reflect changes and include 2.6.33 patch. 2010-03-14 19:19:10 -07:00
Bob Lantz ed097b3b9c Working a bit on text files. Removed netns. 2010-03-14 15:18:17 -07:00
Bob Lantz bca38c997e Minor config notes changes. 2010-03-14 00:18:24 -08:00
Bob Lantz 0e2a7240c3 Reinstate mnexec in install. 2010-03-14 00:11:36 -08:00
Bob Lantz 51a1482407 Removed unused variable. 2010-03-14 00:03:54 -08:00
Bob Lantz 0e3fef2fb3 Merge branch 'master' of yuba.stanford.edu:mininet
Conflicts:
	mininet/node.py
2010-03-13 18:28:48 -08:00
Bob Lantz bcacfc0510 Support for control-C. Finally.
I've changed the way things work a bit:

1. netns is replaced by mnexec, a general-purpose mininet helper.

2. For interactive commands, we now use mnexec -p, which prints out
   the pid, so we can kill it when someone hits control-C!

3. We close file descriptors for subshells. This might save memory,
   but who knows.

4. We detach our subshells from the tty using mnexec -s; thus
   control-C should not terminate everything.

5. Given 4, mn -c is now necessary if you kill mininet.
2010-03-13 18:23:07 -08:00
Bob Lantz c4ae423238 Support for control-C. Finally.
I've changed the way things work a bit:

1. netns is replaced by mnexec, a general-purpose mininet helper.

2. For interactive commands, we now use mnexec -p, which prints out
   the pid, so we can kill it when someone hits control-C!

3. We close file descriptors for subshells. This might save memory,
   but who knows.

4. We detach our subshells from the tty using mnexec -s; thus
   control-C should not terminate everything.

5. Given 4, mn -c is now necessary if you kill mininet.
2010-03-13 18:19:23 -08:00
Bob Lantz d4b53ea73d Removing setsid for the moment - breaks shutdown.
Close to solving this set of problems.
2010-03-13 16:37:13 -08:00
Bob Lantz e953444fa5 Corrected list checkin sendCmd. 2010-03-13 13:59:03 -08:00
Bob Lantz 74993b6536 Changes to note neither ^C nor interactive commands work atm. 2010-03-12 16:40:58 -08:00
Bob Lantz 7b323bd4f4 Removed executability since mn -c is easier! 2010-03-12 16:38:26 -08:00
Bob Lantz 7cbde77496 Added blank line. 2010-03-12 16:24:28 -08:00
Bob Lantz 08ed5bb68a Made executable. 2010-03-12 16:22:40 -08:00
Bob Lantz 9e7aee2061 Merge branch 'master' of yuba.stanford.edu:mininet
Conflicts:
	setup.py
2010-03-12 16:21:52 -08:00
Bob Lantz 740d7ce39a Added newline at EOF. 2010-03-12 16:17:32 -08:00
Bob Lantz 4065511abb Detach shells from tty; monitoring changes.
Call netns using setsid to detach from the tty; this is
intended to fix the problem of control-C killing your network.

sendInt() doesn't actually work - hopefully we can fix this in the
future, but it's tricky since we want to detach the many shells from
our tty, but then optionally send tty interrupts to them! Ideally we
would either know the pid of the subprocess or be able to send a signal
to bash to get it to interrupt its subprocess.

waitOutput() now uses monitor. We also handle sentinels
coming in the middle of output (but default at end should
still work well.)
2010-03-12 16:16:28 -08:00
Bob Lantz 2ad03eea40 Minor cleanup; got rid of backslash. 2010-03-12 16:16:27 -08:00
Bob Lantz 406f5da19d Change to mention 2.6.33 kernel. 2010-03-12 16:13:09 -08:00
Bob Lantz 5947e017fd Minor changes and corrections. 2010-03-12 16:13:09 -08:00
Brandon Heller 44c63c2abd Fix OVS breakage 2010-03-12 16:13:09 -08:00
Brandon Heller 77529ce550 Ignore binary and egg data 2010-03-12 16:13:08 -08:00
Brandon Heller c30e500731 Update install instructions 2010-03-12 16:13:08 -08:00
Brandon Heller b403cc7f96 Colorize git output by default in VM 2010-03-12 16:13:08 -08:00
Brandon Heller 3b1174eff6 Update install scripts
Don't build NOX and OVS as root.  Also don't nuke kernel src.  Install
newer autoconf needed for OVS install from Deb backports, not src.
2010-03-12 16:13:08 -08:00
Bob Lantz c46c1ae6ef Merge branch 'master' of yuba.stanford.edu:mininet 2010-03-11 17:23:29 -08:00
Bob Lantz 9dbe572abe Detach shells from tty; monitoring changes.
Call netns using setsid to detach from the tty; this is
intended to fix the problem of control-C killing your network.

sendInt() doesn't actually work - hopefully we can fix this in the
future, but it's tricky since we want to detach the many shells from
our tty, but then optionally send tty interrupts to them! Ideally we
would either know the pid of the subprocess or be able to send a signal
to bash to get it to interrupt its subprocess.

waitOutput() now uses monitor. We also handle sentinels
coming in the middle of output (but default at end should
still work well.)
2010-03-11 17:16:27 -08:00
Bob Lantz 9f32a08b28 Minor cleanup; got rid of backslash. 2010-03-11 16:54:30 -08:00
Bob Lantz 47abe6d950 Change to mention 2.6.33 kernel. 2010-03-11 16:53:58 -08:00
Bob Lantz 3a7d2a133e Minor changes and corrections. 2010-03-11 16:53:29 -08:00
Brandon Heller b0a7a2579a Fix OVS breakage 2010-03-10 15:44:00 -08:00
Brandon Heller 4e57ddbce1 Ignore binary and egg data 2010-03-09 22:45:54 -08:00
Brandon Heller 8f30aa0017 Update install instructions 2010-03-09 22:37:29 -08:00
Brandon Heller f7f2f977d5 Colorize git output by default in VM 2010-03-09 22:16:30 -08:00
Brandon Heller 188964c911 Update install scripts
Don't build NOX and OVS as root.  Also don't nuke kernel src.  Install
newer autoconf needed for OVS install from Deb backports, not src.
2010-03-09 22:16:30 -08:00
Bob Lantz e3a2ef011f Fixed docstrings for switch arg: name. 2010-03-09 21:52:36 -08:00
Bob Lantz d44a5843d3 Reinstantiated inNamespace and routed control network.
We need to figure out how to specify the IP addresses for the
routed control network. For now I'm going back to 192.168.12x.y

Also changed controller params to use IP strings rather than
numbers. However, we still need to clarify what ControllerParams
is actually for.
2010-03-09 21:48:14 -08:00
Bob Lantz 47dbca2921 Made iperf verbose and fixed node command output. 2010-03-09 21:47:32 -08:00
Bob Lantz 1a9d2eac29 Fixed createLink args and cleaned up slightly. 2010-03-09 21:47:02 -08:00
Bob Lantz 73a323f2a2 Made compatible with rearranged args for createLink. 2010-03-09 21:46:32 -08:00
Bob Lantz 315cbf9e79 Use IP address strings rather than hex number. 2010-03-09 21:45:32 -08:00
Bob Lantz 7ecd095c45 Allow *args and **kwargs. 2010-03-09 21:44:45 -08:00
Bob Lantz 7ba9e05542 Fixed errors due to renaming buffer to buf. 2010-03-08 15:36:09 -08:00
Bob Lantz 80be564274 Removed underscores for public Node methods. Minor cleanup & comments. 2010-03-08 15:32:41 -08:00
Bob Lantz 2626693241 Changed to report repeated pep8 issues. 2010-03-08 15:31:23 -08:00
Bob Lantz a16fae676f Tweaks to separate command and options. 2010-03-05 17:19:02 -08:00
Bob Lantz 91b9e374a0 Revived sshd.py example. 2010-03-05 17:13:44 -08:00
Bob Lantz be96355468 Added some additional explanatory comments. 2010-03-05 17:01:37 -08:00
Bob Lantz b924c5b562 Fixed printing in CLI.net() 2010-03-05 17:00:44 -08:00
Bob Lantz 73360ab95c Moved TreeTopo to mininet.topolib. 2010-03-05 15:15:40 -08:00
Bob Lantz 5156b3894c Renamed LinearTestTopo() and added full ping test. 2010-03-05 15:15:05 -08:00
Bob Lantz 11a6d400c5 Added mininet.topolib to store useful topologies. 2010-03-05 15:07:00 -08:00
Bob Lantz fd21c46f64 Restored udpbwtest.py 2010-03-05 14:49:17 -08:00
Bob Lantz c80e18cd46 Worked once on user, kernel for 1-20 switches. 2010-03-05 14:12:54 -08:00
Bob Lantz 1bda2d21ad Changed to use Node.MAC(). 2010-03-05 14:12:31 -08:00
Bob Lantz 6f45478f18 Removed spaces. 2010-03-05 13:59:52 -08:00
Bob Lantz 75d72d960b Restored accidentally deleted kill %ofpd lines. Added Node.MAC() 2010-03-05 13:58:20 -08:00
Brandon Heller cdeaca8682 Rename cliinfo debug level to output 2010-03-05 04:11:29 -08:00
Brandon Heller dfc08a869e Add none test to measure MN creation/teardown time 2010-03-05 04:08:58 -08:00
Brandon Heller c8641d7d15 Fix remote controller param 2010-03-05 01:13:22 -08:00
Brandon Heller 7ae73e677f Fix pylint warnings 2010-03-04 22:36:34 -08:00
Brandon Heller f259e2fa1c Don't try to codecheck non-existent mnclean 2010-03-04 22:26:29 -08:00
Brandon Heller 509a852f18 Add TreeTopo to cmd line 2010-03-04 21:52:41 -08:00
Brandon Heller 3eb5abe6a7 Make cleanup a param of mn, not a separate script
Also switch from print to info statements, to enable a non-verbose
clean.  Instead of 'mnclean', now run 'mn -c'.
2010-03-04 21:47:50 -08:00
Brandon Heller 4e69ae83dd Slightly reduce cliinfo verbosity 2010-03-04 21:34:01 -08:00
Brandon Heller bb941950d5 Add flexible topology input parsing
Now you can pass a topology name followed by params.  For example, to
create a switch with 3 hosts:

  sudo mn --topo single,3
2010-03-04 21:29:32 -08:00
Brandon Heller 1a40cd0477 Add new loglevel to display CLI output only
Also print warning if user chooses a loglevel that will hide CLI output.
2010-03-04 18:58:37 -08:00
Bob Lantz c246e2d55e Renamed topo_2sw_2host.py -> topo-2sw-2host.py
Still could be better though.... and we need more topology
examples.
2010-03-04 16:56:11 -08:00
Bob Lantz 95f6e7b728 linearbandwidth.py now works for kernel switch. 2010-03-04 16:55:38 -08:00
Bob Lantz 47e26cce19 Fixed to be compatible with new setIP(). 2010-03-04 16:55:21 -08:00
Bob Lantz 086ef80e8e Changed setIP to accept numeric prefix len. Added Node.deleteIntfs(). 2010-03-04 16:53:39 -08:00
Bob Lantz 48a8d297d1 Removed blank line. 2010-03-04 16:52:29 -08:00
Bob Lantz ddfbfc734c Added convenience mode to allow info( 'a', 1, 'b' )
Later we may wish to optimize this so that the arg lists are
not created if the logging level is too low.
2010-03-04 16:51:10 -08:00
Bob Lantz dc630c540a Restored scratchnet and scratchnetuser demos.
Also changed the str format for nodes to use str() rather
than repr() so we don't end up with extraneous quotes.
2010-03-03 14:37:14 -08:00
Bob Lantz efc9a01cf1 Moved link creation into Node.addIntf() and fixed util:CreateLink().
Also tweaked cmd/cmdPrint to make them more beautiful and functional,
and a few other minor changes, such as using a new idiom for verbose.

These changes support reinstating the examples.
2010-03-03 13:52:50 -08:00
Bob Lantz 04fa18dc61 Changed cmdPrint to cmd. 2010-03-03 13:51:58 -08:00
Bob Lantz a681f9b645 Added debug() convenience function. 2010-03-03 13:50:25 -08:00
Bob Lantz 54977c79cd Changed to be executable. 2010-03-03 13:49:58 -08:00
Bob Lantz 1fdcd6768c Added py command to evaluate Python expressions, e.g. h1.cmd('ls') 2010-03-03 13:46:44 -08:00
Bob Lantz 137ec3054d Removed trailing spaces. 2010-03-01 15:38:02 -08:00
Bob Lantz 63214ea2af Merge branch 'customtopos' into bl-dev 2010-03-01 15:34:40 -08:00
Bob Lantz e0cfcdd505 Tweaks to pass code check. 2010-03-01 15:21:29 -08:00
Bob Lantz 2235f21698 Minor cleanup of mn/net and fixes for CLI.
All commands should work now.
2010-02-27 23:40:05 -08:00
Bob Lantz c3a4440025 Changed custom feature so that params aren't added to globals.
There is probably a better way of doing this, but currently
parseCustomFile can modify globals (e.g. TOPOS) as well as
instance variables (self.validate) and classes (e.g. MyTopo),
which are also in the global name space.

Inconveniently enough, lambdas don't seem to be full closures
in Python; if they were, this trickiness would be unnecessary.

Even so, using execfile() seems like it might be a bit dubious...
2010-02-27 23:19:57 -08:00
Bob Lantz 5468377680 Removed blank line at EOF. 2010-02-27 13:55:12 -08:00
Bob Lantz dba3b59929 Changed to dump bad iperf output. 2010-02-27 13:54:38 -08:00
Bob Lantz 78073e1b6f Fixed to be compatible with modified Mininet() class. 2010-02-27 13:54:10 -08:00
Bob Lantz d40b0a9973 Merge branch 'customtopos' into bl-dev 2010-02-26 18:54:32 -08:00
Bob Lantz 235415cf49 Ran unpep8 on test_nets.py. 2010-02-26 17:25:38 -08:00
Bob Lantz 019bff8282 Made it possible to create a Mininet() without using a Topo object.
This increases flexibility by allowing a topology to be manually created
in Python, or specified using another format, without having to create
a Topo object first.

However, Topos are useful, and are still the default topology object!
2010-02-26 17:16:07 -08:00
Brandon Heller 28ab4a33d6 Add env var to install script 2010-02-18 12:10:36 -08:00
Brandon Heller 4f4f1dd2fa Fix KeyError for missing NOX env var 2010-02-18 11:44:08 -08:00
Brandon Heller 8ff7ee4297 Remove NOX_INSTALL file
NOX Install is covered in the wiki and in util/deb/install_nox.sh.
2010-02-18 11:37:50 -08:00
Brandon Heller 4e94bac0ae Update custom topo instructions 2010-02-18 11:36:56 -08:00
Brandon Heller fe29f64dd3 More specific topo example filename 2010-02-18 10:49:23 -08:00
Brandon Heller 2b083dd191 Add gitk to installed VM tools 2010-02-18 06:02:00 -08:00
Brandon Heller 777c90236e Add VM install scripts 2010-02-18 00:09:12 -08:00
Brandon Heller 8d8ac76e85 Move sysctl script to util 2010-02-17 22:47:03 -08:00
Bob Lantz 3e021c2579 Merge branch 'master' of yuba.stanford.edu:mininet 2010-02-16 16:04:31 -08:00
Bob Lantz 31b43002e7 Added a bit to comments, and removed trailing spaces. 2010-02-16 14:42:58 -08:00
Bob Lantz 64c451e01f Minor bug fixes and tweaks.
Shell now works (although we should use quietRun instead to avoid
file descriptor problem!)

exit/quit/EOF now all exit.

Renamed pingall and pingpair to make them easier to type - I think
commands should not require use of the shift key in general, although
ping-all and ping-pair might be OK.
2010-02-09 22:40:51 -08:00
Bob Lantz e34cd9a6cf Added warn to complement info, error. 2010-02-09 22:37:22 -08:00
Brandon Heller f52edfc545 Move sysctl params to separate file
Simplifies installation step
2010-01-31 06:58:02 -08:00
Brandon Heller befa1310df Revamp custom topology input
Defining custom topologies, switch types, controllers, and hosts is now
much easier.  Plus, all Ripcord-specific stuff has been moved out.
2010-01-30 02:46:08 -08:00
Brandon Heller 3774f234f0 Update license and add networkx dependency 2010-01-29 18:49:08 -08:00
Brandon Heller 114dcd5653 Improve CLI line editing capabilities
Convert CLI to use Python Cmd object, which provides line editing.
2010-01-29 14:42:53 -08:00
Brandon Heller 83097ff942 Fix errors from style changes 2010-01-29 13:29:12 -08:00
Bob Lantz 6d72a3cb0c Minor cleanup; clarified fdToNode (still need to test however.) 2010-02-08 15:51:43 -08:00
Bob Lantz d5886525cc Changed to use info() and error() logging aliases. 2010-02-08 15:51:25 -08:00
Bob Lantz f8952d56e1 Added info() and error() as aliases for lg.info() and lg.error() 2010-02-08 15:49:32 -08:00
Bob Lantz bd1e997f15 Remove backslash. 2010-02-08 15:43:23 -08:00
Bob Lantz 8895862acf Munged mn and mnclean into mininet style. 2010-02-08 15:42:31 -08:00
Bob Lantz 7c371cf32a Comment tweaks. 2010-02-05 17:29:15 -08:00
Bob Lantz e85f8bdf29 Removed hash-bang in module files which aren't executed directly,
with the exception of topo.py, which I haven't touched.
2010-02-05 17:22:18 -08:00
Bob Lantz 7d4b7b7f47 Comment tweaks and additions. 2010-02-05 17:18:08 -08:00
Bob Lantz 496b5f9ed0 Moved CLI into its own file. Also, MininetCLI is now just 'CLI'. 2010-02-05 17:01:03 -08:00
Bob Lantz 281f6e59db Minor changes to get 'make test' to pass.
- some namespace conflicts due to unpep8
- fixed infinite recursion caused by removing redundant makeIntfPair
2010-02-05 16:42:01 -08:00
Bob Lantz 80a8fa62d5 First crack at restoring mininet python style, assisted by handy
'unpep8' script, which does most of the work.

- topo.py is still in pep8
- not all examples work, but this is due to other issues
2010-02-05 02:33:34 -08:00
Bob Lantz bebe9dbed2 First crack at restoring Mininet style (via handy 'unpep8' script, which
does most of the work.)

topo.py is still in pep8, however
2010-02-04 23:35:07 -08:00
Bob Lantz 46fa564a8a Changed to ignore W0511, which fails on TODO, FIXME, etc..
We may wish to re-enable this later.
2010-02-04 23:13:33 -08:00
Bob Lantz 0df8b19568 Renamed logging_mod.py -> log.py
Updated other files accordingly.
2010-02-03 15:38:29 -08:00
Bob Lantz ac9554d6dc Renamed mn_run.py -> mn, mn_clean.py -> mnclean; updated Makefle
It's possible that mn_clean is a bit easier to read; mnclean may be easier
to type, however.

Added variables to Makefile so that source files are listed in a single
location.
2010-02-03 15:29:07 -08:00
Bob Lantz 799242c617 Fixed undefined variable 'custom' in setup(). 2010-02-03 15:06:41 -08:00
Brandon Heller 8f99421e02 Fix setuptools installation
The packages argument was incorrectly specified, leading to an install
process that would appear to have succeeded, but would not actually copy
code.

The error likely occurred due to copying setup.py from another project
where the source files were located in a different position relative to
setup.py.
2010-01-27 22:45:05 -08:00
Brandon Heller 8e8081c408 Add VL2 reduced topology 2010-01-25 15:27:50 -08:00
Brandon Heller 3031d31efe Add ability to read custom Mininets 2010-01-11 16:40:25 -08:00
Brandon Heller 1b6a9c3a20 Add missing pylint settings file 2010-01-09 21:12:17 -08:00
Brandon Heller f7c2df2513 Support OpenVSwitch in kernel-mode 2010-01-09 21:11:25 -08:00
Brandon Heller 723d068c51 Add static code checking for style and errors
This required a change to logging, which now uses a singleton pattern.

For all future checkins, 'make codecheck' should pass.
2010-01-09 17:59:43 -08:00
Brandon Heller ca58c896dd Restore user-space switch option
Switches and controller in root namespace only, for now.
2010-01-07 00:54:27 -08:00
Brandon Heller d856c81896 Support out-of-order link addition
Sort interface names before passing to dpctl for kernel switch, so that
links for multipath topologies can be added in any order.
2010-01-06 21:23:33 -08:00
Brandon Heller 6d2cd77b5a Add reversed version of the SingleSwitch topology
Possibly useful for adding custom port mappings.
2010-01-06 08:53:01 -08:00
Brandon Heller 80b3dbbd48 CLI: add node dump-all-data command 2010-01-06 08:52:38 -08:00
Brandon Heller 74ef761529 CLI: add interface dump command 2010-01-06 08:40:07 -08:00
Brandon Heller ee00736307 Add default ip and port for remote controller 2010-01-06 07:22:45 -08:00
David Erickson 60d9ead65a Added a RemoteController object
Now you can run a controller on a remote PC that is
not on the same pc as Mininet.
2010-01-01 03:26:58 -08:00
Brandon Heller 540379957b Add MAC auto set for switches
Also use indexing for DPIDs to avoid zeroed MAC
2010-01-01 03:16:57 -08:00
Brandon Heller 376bcba442 Add options for auto MAC and ARP setup.
Auto MAC setup sets each host MAC equal to its DPID, which simplifies
debugging.

Auto ARP setup removes the need for broadcast support for ARP, which
enables a smaller NOX controller.
2010-01-03 09:16:14 -08:00
Brandon Heller 433a7cc88c Make Ripcord-specific topologies optional
If ripcord.dctopo imports properly, then include its topologies in the
list of available ones.  Also replace topo.py with new generic
topologies and update paths.
2010-01-03 03:53:23 -08:00
Brandon Heller c98514ae44 Support more topologies 2010-01-03 02:44:08 -08:00
Brandon Heller ac65ea3ff3 Increase createLink retry count
Was seeing occasional errors with tests run back-to-back.
2010-01-03 02:43:30 -08:00
Brandon Heller fcf6a16f3d Remove accidentally-added iperf verbosity 2010-01-02 11:20:41 -08:00
Brandon Heller 0cd489a78b Add iperf UDP test 2010-01-02 10:58:28 -08:00
Brandon Heller 8a034f4f6c Add xterm support 2010-01-02 10:58:28 -08:00
Brandon Heller 1bb4412ff3 Separate kernel and user switches into separate objects 2010-01-02 10:58:28 -08:00
Brandon Heller 16c57ddb33 Enable controller-less setups 2010-01-02 10:58:28 -08:00
Brandon Heller 4804237fa7 Add more NOX options 2010-01-02 10:58:28 -08:00
Brandon Heller eeb9cb3c2b Restore iperf test
Also simplify test running.
2010-01-02 10:58:25 -08:00
Brandon Heller 83086439cc Remove/merge obsolete examples 2010-01-02 10:55:46 -08:00
Brandon Heller 8f20b95d56 Auto-install run and clean scripts
Also remove usused imports and outdated doc text.
2010-01-02 02:43:51 -08:00
Brandon Heller a6b473227f Add mn_run.py, a script to run Mininets.
Simplifies launching a Mininet or running tests on one.
2010-01-02 02:42:08 -08:00
Brandon Heller 8b5062a3a1 Move TreeNet to new Mininet API
Also remove all non-object-oriented legacy Mininet code and update
tests.

User-space compatibility is untested, but most of the code for it is
still in.
2009-12-26 14:25:48 -08:00
Brandon Heller e3621eb057 Move fixLimits function to util 2009-12-26 07:40:57 -08:00
Brandon Heller 89bf31030b Move Node functions into their own file
Nodes include Switch, Host, and Controller; move these to a separate
file.

This file still could use some attention to hide private functions.
Node seems like a primary class to extend, for adding stuff like Open
vSwitch, so it could benefit from a simpler interface.
2009-12-20 14:19:32 -08:00
Brandon Heller 4d2d52c3db Remove unused function 2009-12-20 09:46:16 -08:00
Brandon Heller 220890a0c9 Move utility functions out of mininet.py
Having a file with the same name as its package creates hard-to-diagnose
import error, so rename mininet.py to net.py.  This commit moves utility
functions, generally those dealing with network namespaces and interface
management, into their own file.

Also fix a few minor formatting bugs and clean up logging code (which
had issues when multiple files would import mininet.logging_mod).
2009-12-20 09:32:43 -08:00
Brandon Heller bc547080b8 Rewrite Ripcord test and most of mininet
Make much of the Mininet code object-oriented around the new Mininet
object, and create a generic way to build a Mininet.

Previously, each network topology was created by Mininet API calls,
which seems much less approachable for new users than passing in a
topology object along with controller, switch, and host classes.

The modified code is all in ripcordtest.py, but will need to replace the
main mininet.py code eventually.

Kernel-space support only, for now.
2009-12-20 04:03:23 -08:00
Brandon Heller 75810224ed Remove verbose command printouts 2009-12-20 03:54:37 -08:00
Brandon Heller 8e63d3cb72 Add missing newline printouts 2009-12-19 19:21:47 -08:00
Brandon Heller fabbac885f Document retry function 2009-12-19 19:21:18 -08:00
Brandon Heller 2e52801de5 Fix IP printing exception 2009-12-19 19:20:53 -08:00
Brandon Heller b426d24e45 Minor documentation 2009-12-19 19:05:09 -08:00
Brandon Heller b6423f8c4d Fix module resolution
Forgot to add __init__.py
2009-12-18 20:36:48 -08:00
Brandon Heller 15f37cc292 Add LinearNet test case 2009-12-18 20:36:48 -08:00
Brandon Heller 7b804ffbae More flexible logging support
Use customized StreamHandler from Python logging module to print
only messages for the specified loglevel to the console.
2009-12-18 20:36:36 -08:00
Brandon Heller 1095628b8a Clean up display
Don't print retry errors by default.
2009-12-18 15:51:30 -08:00
Brandon Heller 7c1d7c9f90 Don't attempt to kill processes twice
Was causing OSErrors because the process to kill no longer existed.
2009-12-18 15:42:13 -08:00
Brandon Heller 345bf7cc29 Reduce interface move delay and make configurable
Much faster now; from 1 s delay to 100 us.
2009-12-18 15:39:14 -08:00
Brandon Heller ff43615ab1 Add example unit tests and Makefile target 2009-12-18 12:15:04 -08:00
Brandon Heller fd99d67c33 Add make clean to remove dist files created by setuptools 2009-12-18 12:12:51 -08:00
Brandon Heller 51270ce4a2 Use setuptools to install python files
Now, to reference mininet files, use 'import mininet.mininet'.

PYTHONPATH mods are no longer required for installation.
2009-12-18 12:12:37 -08:00
Brandon Heller cd27f9db57 Start controller with verbose by default 2009-12-18 12:11:25 -08:00
Brandon Heller ede34b6a4d Add missing function import 2009-12-18 12:10:35 -08:00
Bob Lantz 40580731cd Added simple all-to-all UDP bandwidth test. 2009-12-17 16:31:42 -08:00
Bob Lantz 9bb15c76e9 Added missing value (60) in list. ;-) 2009-12-17 16:31:14 -08:00
Bob Lantz b7640209a8 Changed to use class vars and method to track nodes.
Useful for monitoring the output of a set of nodes.
2009-12-17 16:30:40 -08:00
Bob Lantz 1417fe7283 Changed cleanup to do fast things first. 2009-12-17 16:29:55 -08:00
Bob Lantz 7df36e476e Changed linearbandwidth.py to be much (!) smarter - it now *reuses* the network! Amazing. 2009-12-15 22:40:12 -08:00
Bob Lantz f939eb5625 Changes to mininet.py:
- invoke ofdatapath with --fail=closed (no controller = no connectivity!)
- stop hosts before switches before the controller
	- this seems slightly more sensible
	- it's the reverse of the startup order
- fix retry() so it kind of works (it's actually helpful I think!)
2009-12-15 22:38:17 -08:00
Bob Lantz 0b4ae53a7e We don't need to print the links. 2009-12-15 22:37:56 -08:00
Bob Lantz e04f092232 Bah, wasn't using correct command to remove datapaths! Fixed. 2009-12-15 21:01:19 -08:00
Bob Lantz 05cce994c3 Haha, retry is definitely not right. Time to take a break I think. 2009-12-15 19:59:48 -08:00
Bob Lantz 0a9ea29fd2 Fixed problem for empty lists in cleanup.
Added retry() function for createLink to see if it helps (probably won't.)
Random edits to docs.
2009-12-15 19:53:22 -08:00
Bob Lantz 696a619d0e Minor tweaks and corrections.
Added commentary on control network to mininet.py.
Hopefully fixed linearbandwidth.py for real.
2009-12-15 18:50:44 -08:00
Bob Lantz ea420ee29f First crack at converting cleanup to Python. 2009-12-15 18:49:46 -08:00
Bob Lantz 2708cadd40 Fixed LinearNet to pass correct parametersto GridNet.__init__() 2009-12-15 17:31:36 -08:00
Bob Lantz 657333199b Fixed treeping1024.py to import Cli, so it should work now. 2009-12-15 17:22:56 -08:00
Bob Lantz 6a30c394b1 Changed to include linux/sched.c for compiling on debian-stable. 2009-12-15 17:14:30 -08:00
Bob Lantz 93519c04f9 Fixed control network/user datapath networks. 2009-12-15 06:13:52 -08:00
Bob Lantz 9dbb68df9e Fixed iperf test.
Not sure if I want nox_core -v in nox.py - it's useful for debugging.
ripcordtest.py (and grid.py) still depend on routing, which I haven't been
able to test yet.
2009-12-14 22:37:19 -08:00
Bob Lantz 77131e8f24 OK, now we run 'routing' for the nox configurations with loops.
Unfortunately, I can't test this at the moment since nox seems not to
be able to find the routing module.

Added/renamed examples: grid.py, tree1024.py

Added -v flag to nox arguments, so we have some chance of figuring
out why nox is dying, as it generally is.
2009-12-14 22:13:53 -08:00
Bob Lantz c53fa3ba32 Second crack at a ripcordtest.py that actually works.
ripcord.py was a name conflict - ugh!
This one creates a network successfully, but ping doesn't work with
nox out of the box at least.
2009-12-14 21:35:08 -08:00
Bob Lantz 0b084dd51a Added ripcord.py, which attempts to make a FatTree using ripcord and
instantiate a mininet Network based on its topology.

Also minor cleanup of nox.py and GridNet class in mininet.py.
2009-12-14 21:01:45 -08:00
Bob Lantz 2f53491343 First crack at allowing Controller to be customized.
Network may now be used with custom controllers.
An example of doing this is in nox.py, which instantiates at TreeNet
using a custom Controller, NoxController, that runs nox_core rather
than the reference controller.
2009-12-14 20:14:44 -08:00
Bob Lantz 845dedca32 One more change to revert the broken exec behavior. 2009-12-14 19:21:17 -08:00
Brandon Heller 0608b5939b Add notes on installing NOX on Deb testing. 2009-12-12 04:47:13 -08:00
Brandon Heller ea7c8795f5 Ensure netns is in the path. 2009-12-12 02:54:52 -08:00
Bob Lantz ac75d7cff4 Inadvertently added verbosity into Node.setIP(); removed. 2009-12-14 13:46:36 -08:00
Bob Lantz fb7658c8ca Since execing controller/ofprotocol was broken, reverting to just running in background.
This should eliminate ofprotocol bogons living on past the end of a test.
2009-12-14 13:38:10 -08:00
Bob Lantz 98332cb616 Tweaks to documentation files and sshd and xterms examples.
Added scratchnetuser.
2009-12-14 13:22:03 -08:00
Bob Lantz 433503cf8a Added "from scratch" examples, to show how to create a network using
low-level primitives.

The "nox.py" example attempts to use nox as a controller rather than
controller(8).

More edits for INSTALL and README, and refinements for sshd and xterm
examples.
2009-12-14 12:43:42 -08:00
Bob Lantz 55dd936829 Cleanup of doc files.
Fixed xterm.py (and cleanup) to clean up screen sessions.
Cleaned up sshd.py (though interface is still in flux.)
Added 1024-node network example (treenet1024.py).
Added example showing multiple tests on a single network (multitest.py).
Renamed examples to make them easier to type!
2009-12-11 09:21:36 -08:00
Bob Lantz 08cef003f7 Changed cleanup to vaporize zombie screen sessions.
Other minor cleanup.
2009-12-11 06:17:42 -08:00
Bob Lantz f4d9e05d05 Fixed treePing64.
Minor tweaks to other files.
2009-12-11 04:25:31 -08:00
Bob Lantz 2a0cad3c85 Renamed and tweaked treePing64. 2009-12-11 04:01:56 -08:00
Bob Lantz b3dd44d41b Fixed bigTreePing64.
More edits for INSTALL and README files.
Batteries still not included (for the moment.) ;-)
2009-12-11 03:58:54 -08:00
Bob Lantz 3da2b1482c Place 'root namespace' in xterm title to make it clearer that
the node is running in the root namespace.
2009-12-11 03:33:38 -08:00
Bob Lantz d8ef79dff7 Tweaks for install and readme files. 2009-12-11 03:31:45 -08:00
Bob Lantz af8f0b61b6 Added INSTALL file incorporating Brandon's suggestions.
More tweaks for examples, which are still in progress.
2009-12-11 03:22:09 -08:00
Bob Lantz 42ba5d92c3 Added sshd example, which starts up sshd on each host, allowing host access via ssh.
(It also adds a route from the root namespace to the data network via
the first OpenFlow switch, so when you ssh in you go through OpenFlow!)

Modified Network() to optionally decouple starting the network, running
tests, and stopping the network. This allows multiple tests to be run
(or additional modifications to be made to the network before actually
starting the switches and controller.)

Still tweaking xterms - it sort of works but the screen sessions are not
cleaned up, which leads to nasty garbage.
2009-12-11 02:34:21 -08:00
Bob Lantz 748e35d50f Working on examples.
Added new example to create xterms.
Other minor changes.
2009-12-10 23:39:06 -08:00
Bob Lantz 4ccc7ee941 Added examples, which may or may not work yet. 2009-12-10 01:47:00 -08:00
Bob Lantz 95d9a374b2 Added README.
Modified cleanup to use dpctl to remove kernel datapaths.
2009-12-10 00:21:26 -08:00
Bob Lantz 994c68f648 Modified test infrastructure to return results.
Ping and iperf tests now return something possibly useful.
2009-12-09 23:24:27 -08:00
Bob Lantz 9011e0d22c Fixed user datapath support. 2009-12-09 22:13:46 -08:00
Bob Lantz 6bd22292b6 Added checks for tun and ofdatapath kernel modules. 2009-12-09 21:59:18 -08:00
Bob Lantz eddef947a4 Organized routines into classes:
Node -> { Host, Switch, Controller }
Network -> { TreeNet, GridNet -> LinearNet }

Modified cleanup to clean up kernel datapaths.
2009-12-09 21:13:17 -08:00
Bob Lantz 98d4f1891c Initial commit - first development version of Mininet 2009-12-08 18:08:03 -08:00
153 changed files with 10407 additions and 8787 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
Dockerfile
-44
View File
@@ -1,44 +0,0 @@
name: Publish Docker image
on:
push:
branches:
- master
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Login to ${{ env.REGISTRY }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
pull: true
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+6 -19
View File
@@ -1,21 +1,8 @@
# Python
build
dist
Mini_NDN.egg-info
mnexec
*.pyc
*~
\#*\#
mininet.egg-info
build/*
dist/*
# Docs
docs/html
docs/latex
docs/_build
# Misc
.DS_Store
dl
*.apconf
# Vagrant
.vagrant
venv/
.vscode
+297
View File
@@ -0,0 +1,297 @@
# lint Python modules using external checkers.
#
# This is the main checker controlling the other ones and the reports
# generation. It is itself both a raw checker and an astng checker in order
# to:
# * handle message activation / deactivation at the module level
# * handle some basic but necessary stats'data (number of classes, methods...)
#
[MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Profiled execution.
profile=no
# Add <file or directory> to the black list. It should be a base name, not a
# path. You may set this option multiple times.
ignore=CVS
# Pickle collected data for later comparisons.
persistent=yes
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
[MESSAGES CONTROL]
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once).
disable=W0704,C0103,W0231,E1102,W0511,W0142,R0902,R0903,R0904,R0913,R0914,R0801,I0011
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html
output-format=colorized
# Include message's id in outpu
include-ids=yes
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells wether to display a full report or only the messages
reports=no
# Python expression which should return a note less than 10 (10 is the highes
# note). You have access to the variables errors warning, statement which
# respectivly contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation repor
# (R0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Add a comment according to your evaluation note. This is used by the global
# evaluation report (R0004).
comment=no
# Enable the report(s) with the given id(s).
#enable-report=
# Disable the report(s) with the given id(s).
#disable-report=
# checks for :
# * doc strings
# * modules / classes / functions / methods / arguments / variables name
# * number of arguments, local variables, branchs, returns and statements in
# functions, methods
# * required module attributes
# * dangerous default values as arguments
# * redefinition of function / method / class
# * uses of the global statemen
#
[BASIC]
# Required attributes for module, separated by a comma
required-attributes=
# Regular expression which should only match functions or classes name which do
# not require a docstring
no-docstring-rgx=__.*__
# Regular expression which should only match correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression which should only match correct module level names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression which should only match correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct instance attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,inpu
# try to find bugs in the code using type inference
#
[TYPECHECK]
# Tells wether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamicaly set).
ignored-classes=SQLObjec
# When zope mode is activated, add a predefined set of Zope acquired attributes
# to generated-members.
zope=no
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed.
generated-members=REQUEST,acl_users,aq_paren
# checks for
# * unused variables / imports
# * undefined variables
# * redefinition of variable from builtins or from an outer scope
# * use of variable before assigmen
#
[VARIABLES]
# Tells wether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching names used for dummy variables (i.e. not used).
dummy-variables-rgx=_|dummy
# List of additional names supposed to be defined in builtins. Remember tha
# you should avoid to define new builtins when possible.
additional-builtins=
# checks for :
# * methods without self as first argumen
# * overridden methods signature
# * access only to existant members via self
# * attributes not defined in the __init__ method
# * supported interfaces implementation
# * unreachable code
#
[CLASSES]
# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# checks for sign of poor/misdesign:
# * number of methods, attributes, local variables...
# * size, complexity of functions, methods
#
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branchs=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# checks for
# * external modules dependencies
# * relative / wildcard imports
# * cyclic imports
# * uses of deprecated modules
#
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report R0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report R0402 mus
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report R0402 mus
# not be disabled)
int-import-graph=
# checks for :
# * unauthorized constructions
# * strict indentation
# * line length
# * use of <> instead of !=
#
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=80
# Maximum number of lines in a module
max-module-lines=1500
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# checks for:
# * warning notes in the code like FIXME, XXX
# * PEP 263: source code with non ascii character but no encoding declaration
#
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
# checks for similarities and duplicated code. This computation may be
# memory / CPU intensive, so you should disable it if you experiments some
# problems.
#
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
-38
View File
@@ -1,38 +0,0 @@
Mini-NDN Authors
=================
The following lists maintainers, primary developers, and all much-appreciated contributors to Mini-NDN in alphabetic order.
The specific contributions of individual authors can be obtained from the git history of the [official Mini-NDN repository](https://github.com/named-data/mini-ndn).
If you would like to become a contributor to the official repository, please follow the recommendations in https://github.com/named-data/.github/blob/master/CONTRIBUTING.md.
* Alexander Afanasyev <https://users.cs.fiu.edu/~afanasyev>
* Muktadir R. Chowdhury <https://github.com/alvyC>
* Damian Coomes <https://github.com/dmcoomes>
* ***(Maintainer)*** Saurab Dulal <https://dulalsaurab.github.io>
* Laqin Fan <https://github.com/laqinfan>
* ***(Former Maintainer)*** Ashlesh Gawande <https://www.linkedin.com/in/agawande>
* Nicholas Gordon <https://github.com/gorgonical>
* Giovanni Grieco <https://github.com/GiovanniGrieco>
* ***(Maintainer)*** Alexander Lane <https://github.com/awlane>
* Vince Lehman <http://vslehman.com>
* Philipp Moll <https://github.com/phylib>
* Eric Newberry <https://ericnewberry.com>
* Junxiao Shi <https://cs.arizona.edu/~shijunxiao>
* Jeff Thompson <https://remap.ucla.edu/jeff-thompson>
* Yucheng Zhang <https://peterskycloud.wixsite.com/yzportfolio>
* Italo Valcy S Brito <https://github.com/italovalcy>
Technical Advisors
-------------------
* Lan Wang <http://www.cs.memphis.edu/~lanwang>
* Beichuan Zhang <http://cs.arizona.edu/~bzhang>
The Mini-CCNx team
-------------------
* Carlos Cabral <https://github.com/carlosmscabral>
* Caio de Moraes Elias <https://github.com/ocaio>
* Christian Esteve Rothenberg <http://www.dca.fee.unicamp.br/~chesteve>
-674
View File
@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-37
View File
@@ -1,37 +0,0 @@
# Setup container with Ubuntu 22.04 image
FROM ubuntu:22.04
# Set the working directory to /
WORKDIR /
# expose ports for openvswitch-switch
EXPOSE 6633 6653 6640
# Update container image
RUN apt-get update -y && \
apt-get install --no-install-recommends -y \
lsb-release sudo \
zip unzip wget git ca-certificates \
curl iproute2 iputils-ping net-tools \
python3 python3-pip \
tcpdump vim x11-xserver-utils xterm && \
update-ca-certificates && \
rm -rf /var/lib/apt/lists/* && \
alias python=python3
COPY . /mini-ndn
RUN cd mini-ndn && \
pip3 install -r requirements.txt && \
./install.sh -y --source && \
cd dl/mininet && make install && cd ../.. && \
cd dl/mininet-wifi && make install && cd ../.. && \
rm -rf dl && rm -rf /var/lib/apt/lists/* && cd /
COPY docker/ENTRYPOINT.sh /
RUN chmod +x ENTRYPOINT.sh
# Change the working directory to /mini-ndn
WORKDIR /mini-ndn
ENTRYPOINT ["/ENTRYPOINT.sh"]
+273
View File
@@ -0,0 +1,273 @@
Mininet Installation/Configuration Notes
Mininet 1.0.0
---
The supported installation methods for Mininet are 1) using
a pre-built VM image, and 2) native installation on Ubuntu or Debian.
(Other distributions may be supported in the future - if you would
like to contribute an installation script, we would welcome it!)
1. Easiest "install" - use our pre-built VM image!
The easiest way to get Mininet running is to start with one of our pre-built
virtual machine images from http://openflow.org/mininet
Boot up the VM image, log in, and follow the instructions on the wiki page.
An additional advantage of using the VM image is that it doesn't mess with
your native OS installation or damage it in any way.
2. Native installation (experimental!) for Ubuntu 10.04 LTS
If you are running Ubuntu 10.04 LTS (or possibly Debian 5), you may be
able to use our handy install.sh script, which is in mininet/util.
WARNING: USE AT YOUR OWN RISK!
install.sh is a bit intrusive and may possibly damage your OS and/or
home directory, by creating/modifying several directories such as
mininet, openflow, openvswitch and noxcore. Although we hope it won't
do anything completely terrible, you may want to look at the script
before you run it, and you should make sure your system and home
directory are backed up just in case!
To install ALL of the software which we use for OpenFlow tutorials,
you may use
$ mininet/util/install.sh
This takes about 20-30 minutes.
Alternately, you can install just the pieces you need.
We recommend the following steps, in order:
[a) On Debian 5, first install a Mininet-compatible kernel:
$ mininet/util/install.sh -k
Reboot and run 'uname -r' to make sure you're running the new kernel.]
b) Install mininet and its dependencies:
$ mininet/util/install.sh -n
c) Install OpenFlow 1.0 and associated useful software
$ mininet/util/install.sh -f
d) Install Open vSwitch and its kernel module
$ mininet/util/install.sh -vm
e) If you wish to install the version of NOX we use in the tutorial:
$ mininet/util/install.sh -x
Note: NOX development is progressing over time, so after you complete
the tutorial you may wish to install the latest and greatest NOX from
noxrepo.org.
Good luck! Some additional installation notes are provided below, for
the brave and/or Linux-savvy, or those who are trying to understand what
is installed and why.
p.s. Note that only one instance of Mininet is currently supported on a single
machine - that's one reason we recommend using a VM to run it.
---
Mininet Manual Installation Notes
These installation notes assume you understand how to do things like
compile kernels, apply patches, configure networks, write code, etc.. If
this is unfamiliar territory, or if you run into trouble, we recommend
using one of our pre-built virtual machine images (see above.)
If you wish to try to create a VM to run Mininet, you may also wish
to look at the Wiki page:
http://openflow.org/foswiki/bin/view/OpenFlow/MininetVMCreationNotes
0. Obtaining Mininet
If you're reading this, you've already done it, but the command to
download mininet is:
git clone git://openflow.org/mininet.git
1. Core Mininet installation
The core Mininet installation requires gcc, make, python,
and setuptools. On Ubuntu and Debian you may install them with:
# aptitude install gcc make python setuptools
To install Mininet itself, with root privileges:
# cd mininet
# make install
This places the mininet package in /usr/lib/python-*/site-packages/,
so that 'import mininet' will work, and installs the primary mn
script (mn) as well as its helper utility (mnexec.)
On Ubuntu and Debian, Mininet's dependencies and core files may also be
installed using mininet/util/install.sh -n
2. Installation script for Ubuntu/Debian Lenny
If you are running Ubuntu 10.04 or Debian Lenny, you may be able to use the
util/install.sh script to install a compatible Linux kernel as well as
other software including the OpenFlow reference implementation, the Open
vSwitch switch implementation, and the NOX OpenFlow controller.
Many different installation options are possible by passing different
options to install.sh; install.sh -h lists them all.
Assuming the mininet source tree is installed in ~/mininet, the steps to run
install.sh to install EVERYTHING we use for OpenFlow tutorials are:
% cd
% time ~/mininet/util/install.sh # installs tons of stuff
% sudo reboot # to load new kernel
% ~/mininet/util/install.sh -c # to clean out unneeded kernel stuff
This installs a lot of useful software, but it will take a while (30
minutes or more, depending on your network connection, computer, etc..)
Probably the minimal semi-useful configuration would be to install
Mininet itself, kernel support if necessary, and either the
reference OpenFlow switch or Open vSwitch. This could be installed
as follows:
% sudo ~/mininet/util/install.sh -knvm
Respectively, this installs kernel support, core mininet dependencies,
Open vSwitch, and the Open vSwitch kernel module. If a new kernel was
installed, then a reboot may be required.
If install.sh cannot be used for some reason (e.g. you're on Fedora
or some other Linux - please don't say CentOS) or if you don't want to
install all of these components (they're useful!), the kernel and
OpenFlow software requirements are described in steps [3] and [4],
which follow.
If you successfully used install.sh, congratulations! You're basically
done. Proceed to step [6] for additional advice.
3. Linux Kernel requirements
Mininet requires a kernel built with network namespace support enabled,
i.e. with CONFIG_NET_NS=Y, such as the kernel shipped with
Ubuntu 10.04 LTS, currently 2.6.32. On Ubuntu 10.04, you should not need
to install or build a custom kernel, although 2.6.33+ is faster at
tearing down virtual ethernet pairs.
For Ubuntu and Debian, we provide a 2.6.33 kernel package which you may be
able to install using "util/install.sh -k". Note our kernel package
requires an ext2 or ext3 root file system, so it won't work if you have
a default Ubuntu install, which uses ext4.
If your kernel wasn't compiled with CONFIG_NET_NS=Y, you will need to
build and install a kernel that does! >= 2.6.33 works better, but may
be harder to get working, depending on your Linux distribution.
A script for building Debian packages for 2.6.33.1 is provided in
mininet/util/kbuild. You may wish to read it, as it applies patches
to enable 2.6.33.1 to build under debian-stable, and to enable the
tun driver to work correctly with Mininet.
Earlier kernels (e.g. 2.6.29) work with CONFIG_NET_NS enabled and no
additional patches, but are much slower at removing veth interfaces,
resulting in much slower switch shutdown.
For scalable configurations, you might need to increase some of your
kernel limits. Sample params are in util/sysctl_addon, which can be
appended to /etc/sysctl.conf (and modified as necessary for your
desired configuration):
sudo su -c "cat sysctl_addon >> /etc/sysctl.conf"
To save the config change, run:
sudo sysctl -p
4. OpenFlow software and configuration requirements
Mininet requires either the reference OpenFlow switch implementation
(from openflowswitch.org) or Open vSwitch (openvswitch.org) to be
installed. "make test" requires the reference user space
implementations as well as Open vSwitch. Note the reference kernel
implementation is not currently included in OpenFlow 1.0.
On Ubuntu and Debian, the install.sh script may be used with the '-f'
option to install the OpenFlow reference implementation, the '-v' option
to build Open vSwitch, and the '-m' option to install the Open vSwitch
kernel module into /lib/modules (note: you must build Open vSwitch first!)
Mininet will automatically load and remove kernel module dependencies
for supported switch types, using modprobe and rmmod - but these
modules must be in a location where modprobe can find them (e.g.
something like /lib/modules/`uname -r`/kernel/drivers/net/)
The reference OpenFlow controller (controller(8)) only supports 16
switches by default! If you wish to run a network with more than 16
switches, please recompile controller(8) with larger limits, or use a
different controller such as nox. A patch to controller(8) is included
as util/openflow-patches/controller.patch.
5. Other software dependencies
On Ubuntu and Debian, other Mininet dependencies may be installed using
the '-n' option of the install.sh script.
To run the iperf test, you need to install iperf:
sudo aptitude/yum install iperf
We assume you already have ping installed. ;-)
To use xterm or sshd with Mininet, you need the following:
sudo aptitude/yum install sshd xterm screen
Some examples may have additional requirements - consult the specific
example file for details.
The install.sh script has an '-x' option to install the version of
NOX from the OpenFlow tutorial.
6. Other notes and recommendations
If you did not install certain useful packages and you wish to later,
it may be possible to install them using install.sh.
Mininet should be run either on a machine with
no other important processes, or on a virtual machine (recommended!)
Multiple concurrent Mininet instances are not supported!
Good luck!
---
Historical information on OpenFlow 0.8.9 and the reference kernel module:
The kernel reference implementation has been deprecated, but it may
be possible to get it work with Mininet.
To switch to the most recent OpenFlow 0.8.9 release branch (the most
recent one with full NOX support and kernel datapath support) in your
OpenFlow git tree:
git checkout -b release/0.8.9 remotes/origin/release/0.8.9
A patch to enable datapath.c to compile with recent kernels
is included in util/openflow-patches/datapath.patch.
In OpenFlow 1.0, switch port numbering starts at 1 (for better or for worse.)
To run with previous versions of OpenFlow, it may be necessary
to change SWITCH_PORT_BASE from 1 to 0 in node.py.
+29
View File
@@ -0,0 +1,29 @@
Mininet 1.0.0 License
Copyright (c) 2009-2011 Bob Lantz and Brandon Heller
We are making Mininet available for public use and benefit with the
expectation that others will use, modify and enhance the Software and
contribute those enhancements back to the community. However, since we
would like to make the Software available for broadest use, with as few
restrictions as possible permission is hereby granted, free of charge, to
any person obtaining a copy of this Software to deal in the Software
under the copyrights without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The name and trademarks of copyright holder(s) may NOT be used in
advertising or publicity pertaining to the Software or any derivatives
without specific, written prior permission.
+39
View File
@@ -0,0 +1,39 @@
MININET = mininet/*.py
TEST = mininet/test/*.py
EXAMPLES = examples/*.py
BIN = bin/mn
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
MNEXEC = mnexec
P8IGN = E251,E201,E302,E202
all: codecheck test
clean:
rm -rf build dist *.egg-info *.pyc $(MNEXEC)
codecheck: $(PYSRC)
-echo "Running code check"
pyflakes $(PYSRC)
pylint --rcfile=.pylint $(PYSRC)
pep8 --repeat --ignore=$(P8IGN) $(PYSRC)
errcheck: $(PYSRC)
-echo "Running check for errors only"
pyflakes $(PYSRC)
pylint -E --rcfile=.pylint $(PYSRC)
test: $(MININET) $(TEST)
-echo "Running tests"
mininet/test/test_nets.py
install: $(MNEXEC)
install $(MNEXEC) /usr/local/bin/
python setup.py install
develop: $(MNEXEC)
install $(MNEXEC) /usr/local/bin/
python setup.py develop
doc:
doxygen doxygen.cfg
+86
View File
@@ -0,0 +1,86 @@
Mininet: A Simple Virtual Testbed for OpenFlow/SDN
or
How to Squeeze a 1024-node OpenFlow Network onto your Laptop
Mininet 1.0.0
---
Welcome to Mininet!
Mininet creates OpenFlow test networks by using process-based
virtualization and network namespaces.
Simulated hosts (as well as switches and controllers with the user
datapath) are created as processes in separate network namespaces. This
allows a complete OpenFlow network to be simulated on top of a single
Linux kernel.
Mininet may be invoked directly from the command line, and also provides a
handy Python API for creating networks of varying sizes and topologies.
Mininet is currently in *limited alpha release*. We encourage you to
experiment with it and hope that you will provide us with feedback on
features, documentation, and how you're using it. We plan to make it
available publicly via a GPL or BSD license (probably in April), but please
don't distribute the code or URLs yet! The feedback you provide will help
us improve Mininet for general release.
In order to run Mininet, you must have:
* A Linux 2.6.26 or greater kernel compiled with network namespace support
enabled (see INSTALL for additional information.)
* An OpenFlow implementation (either the reference user or kernel
space implementations, or Open vSwitch.) Appropriate kernel modules
(e.g. tun and ofdatapath for the reference kernel implementation) must
be loaded.
* Python, bash, ping, iperf, etc.
* Root privileges (required for network device access)
Currently Mininet includes:
- A simple node infrastructure (Host, Switch, Controller classes) for
creating virtual OpenFlow networks
- A simple network infrastructure (Mininet class) supporting parametrized
topologies (Topo subclasses.) For example, a tree network may be created
with the command
# mn --topo tree,depth=2,fanout=3
- Basic tests, including connectivity (ping) and bandwidth (iperf)
- A command-line interface (CLI class) which provides useful
diagnostic commands, as well as the ability to send a command to a
node. For example,
mininet> h11 ifconfig -a
tells host h11 to run the command 'ifconfig -a'
- A 'cleanup' command to get rid of junk (interfaces, processes, files in
/tmp, etc.) which might be left around by Mininet or Linux. Try this if
things stop working!
# mn -c
- Examples (in the examples/ directory) to help you get started.
Batteries are not included (yet!)
However, some preliminary installation notes are included in the INSTALL
file.
Additionally, much useful information, including a Mininet tutorial,
is available on the Mininet wiki:
http://openflow.org/mininet
Enjoy, and good luck!
---
Bob Lantz
rlantz@cs.stanford.edu
-32
View File
@@ -1,32 +0,0 @@
Mini-NDN
========
If you are new to the NDN community of software generally, read the
[Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md).
### What is Mini-NDN?
Mini-NDN is a lightweight networking emulation tool that enables testing, experimentation, and
research on the NDN platform based on [Mininet](https://github.com/mininet/mininet).
Mini-NDN uses the NDN libraries, NFD, NLSR, and tools released by the
[NDN project](http://named-data.net/codebase/platform/) to emulate an NDN network on a single system.
Mini-NDN is open and free software licensed under the GPL 3.0 license. Mini-NDN is free to all
users and developers. For more information about licensing details and limitations,
please refer to [COPYING.md](COPYING.md).
The first release of Mini-NDN is developed by members of the NSF-sponsored NDN project team.
Mini-NDN is open to contribution from the public.
For more details, please refer to [AUTHORS.rst](AUTHORS.rst).
Bug reports and feedback are highly appreciated and can be made through our
[Redmine site](http://redmine.named-data.net/projects/mini-ndn) and the
[mini-ndn mailing list](http://www.lists.cs.ucla.edu/mailman/listinfo/mini-ndn).
### Documentation
Please refer to http://minindn.memphis.edu/ or [docs/index.rst](docs/index.rst) for installation, usage, and other documentation.
The documentation can be built using:
./docs/build.sh
and is available under `docs/_build/html`.
Executable
+258
View File
@@ -0,0 +1,258 @@
#!/usr/bin/env python
"""
Mininet runner
author: Brandon Heller (brandonh@stanford.edu)
To see options:
sudo mn -h
Example to pull custom params (topo, switch, etc.) from a file:
sudo mn --custom ~/mininet/custom/custom_example.py
"""
from optparse import OptionParser
import os.path
import sys
import time
from mininet.clean import cleanup
from mininet.cli import CLI
from mininet.log import lg, LEVELS, info, warn
from mininet.net import Mininet, MininetWithControlNet
from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
NOX, RemoteController, UserSwitch, OVSKernelSwitch,
OVSLegacyKernelSwitch )
from mininet.link import Link, TCLink
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
from mininet.topolib import TreeTopo
from mininet.util import makeNumeric, custom, customConstructor, splitArgs
from mininet.util import buildTopo
# built in topologies, created only when run
TOPODEF = 'minimal'
TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ),
'linear': LinearTopo,
'reversed': SingleSwitchReversedTopo,
'single': SingleSwitchTopo,
'tree': TreeTopo }
SWITCHDEF = 'ovsk'
SWITCHES = { 'user': UserSwitch,
'ovsk': OVSKernelSwitch,
'ovsl': OVSLegacyKernelSwitch }
HOSTDEF = 'proc'
HOSTS = { 'proc': Host,
'rt': custom( CPULimitedHost, sched='rt' ),
'cfs': custom( CPULimitedHost, sched='cfs' ) }
CONTROLLERDEF = 'ref'
CONTROLLERS = { 'ref': Controller,
'ovsc': OVSController,
'nox': NOX,
'remote': RemoteController,
'none': lambda name: None }
LINKDEF = 'default'
LINKS = { 'default': Link,
'tc': TCLink }
# optional tests to run
TESTS = [ 'cli', 'build', 'pingall', 'pingpair', 'iperf', 'all', 'iperfudp',
'none' ]
ALTSPELLING = { 'pingall': 'pingAll', 'pingpair': 'pingPair',
'iperfudp': 'iperfUdp', 'iperfUDP': 'iperfUdp', 'prefixlen': 'prefixLen' }
def addDictOption( opts, choicesDict, default, name, helpStr=None ):
"""Convenience function to add choices dicts to OptionParser.
opts: OptionParser instance
choicesDict: dictionary of valid choices, must include default
default: default choice key
name: long option name
help: string"""
if default not in choicesDict:
raise Exception( 'Invalid default %s for choices dict: %s' %
( default, name ) )
if not helpStr:
helpStr = ( '|'.join( sorted( choicesDict.keys() ) ) +
'[,param=value...]' )
opts.add_option( '--' + name,
type='string',
default = default,
help = helpStr )
class MininetRunner( object ):
"Build, setup, and run Mininet."
def __init__( self ):
"Init."
self.options = None
self.args = None # May be used someday for more CLI scripts
self.validate = None
self.parseArgs()
self.setup()
self.begin()
def setCustom( self, name, value ):
"Set custom parameters for MininetRunner."
if name in ( 'topos', 'switches', 'hosts', 'controllers' ):
# Update dictionaries
param = name.upper()
globals()[ param ].update( value )
elif name == 'validate':
# Add custom validate function
self.validate = value
else:
# Add or modify global variable or class
globals()[ name ] = value
def parseCustomFile( self, fileName ):
"Parse custom file and add params before parsing cmd-line options."
customs = {}
if os.path.isfile( fileName ):
execfile( fileName, customs, customs )
for name, val in customs.iteritems():
self.setCustom( name, val )
else:
raise Exception( 'could not find custom file: %s' % fileName )
def parseArgs( self ):
"""Parse command-line args and return options object.
returns: opts parse options dict"""
if '--custom' in sys.argv:
index = sys.argv.index( '--custom' )
if len( sys.argv ) > index + 1:
filename = sys.argv[ index + 1 ]
self.parseCustomFile( filename )
else:
raise Exception( 'Custom file name not found' )
opts = OptionParser()
addDictOption( opts, SWITCHES, SWITCHDEF, 'switch' )
addDictOption( opts, HOSTS, HOSTDEF, 'host' )
addDictOption( opts, CONTROLLERS, CONTROLLERDEF, 'controller' )
addDictOption( opts, LINKS, LINKDEF, 'link' )
addDictOption( opts, TOPOS, TOPODEF, 'topo' )
opts.add_option( '--clean', '-c', action='store_true',
default=False, help='clean and exit' )
opts.add_option( '--custom', type='string', default=None,
help='read custom topo and node params from .py file' )
opts.add_option( '--test', type='choice', choices=TESTS,
default=TESTS[ 0 ],
help='|'.join( TESTS ) )
opts.add_option( '--xterms', '-x', action='store_true',
default=False, help='spawn xterms for each node' )
opts.add_option( '--ipbase', '-i', type='string', default='10.0.0.0/8',
help='base IP address for hosts' )
opts.add_option( '--mac', action='store_true',
default=False, help='automatically set host MACs' )
opts.add_option( '--arp', action='store_true',
default=False, help='set all-pairs ARP entries' )
opts.add_option( '--verbosity', '-v', type='choice',
choices=LEVELS.keys(), default = 'info',
help = '|'.join( LEVELS.keys() ) )
opts.add_option( '--innamespace', action='store_true',
default=False, help='sw and ctrl in namespace?' )
opts.add_option( '--listenport', type='int', default=6635,
help='base port for passive switch listening' )
opts.add_option( '--nolistenport', action='store_true',
default=False, help="don't use passive listening port")
opts.add_option( '--pre', type='string', default=None,
help='CLI script to run before tests' )
opts.add_option( '--post', type='string', default=None,
help='CLI script to run after tests' )
opts.add_option( '--prefixlen', type='int', default=8,
help='prefix length (e.g. /8) for automatic '
'network configuration' )
opts.add_option( '--pin', action='store_true',
default=False, help="pin hosts to CPU cores "
"(requires --host cfs or --host rt)" )
self.options, self.args = opts.parse_args()
def setup( self ):
"Setup and validate environment."
# set logging verbosity
if LEVELS[self.options.verbosity] > LEVELS['output']:
print ( '*** WARNING: selected verbosity level (%s) will hide CLI '
'output!\n'
'Please restart Mininet with -v [debug, info, output].'
% self.options.verbosity )
lg.setLogLevel( self.options.verbosity )
def begin( self ):
"Create and run mininet."
if self.options.clean:
cleanup()
exit()
start = time.time()
topo = buildTopo( TOPOS, self.options.topo )
switch = customConstructor( SWITCHES, self.options.switch )
host = customConstructor( HOSTS, self.options.host )
controller = customConstructor( CONTROLLERS, self.options.controller )
link = customConstructor( LINKS, self.options.link )
if self.validate:
self.validate( self.options )
inNamespace = self.options.innamespace
Net = MininetWithControlNet if inNamespace else Mininet
ipBase = self.options.ipbase
xterms = self.options.xterms
mac = self.options.mac
arp = self.options.arp
pin = self.options.pin
listenPort = None
if not self.options.nolistenport:
listenPort = self.options.listenport
mn = Net( topo=topo,
switch=switch, host=host, controller=controller,
link=link,
ipBase=ipBase,
inNamespace=inNamespace,
xterms=xterms, autoSetMacs=mac,
autoStaticArp=arp, autoPinCpus=pin,
listenPort=listenPort )
if self.options.pre:
CLI( mn, script=self.options.pre )
test = self.options.test
test = ALTSPELLING.get( test, test )
mn.start()
if test == 'none':
pass
elif test == 'all':
mn.start()
mn.ping()
mn.iperf()
elif test == 'cli':
CLI( mn )
elif test != 'build':
getattr( mn, test )()
if self.options.post:
CLI( mn, script=self.options.post )
mn.stop()
elapsed = float( time.time() - start )
info( 'completed in %0.3f seconds\n' % elapsed )
if __name__ == "__main__":
MininetRunner()
+6
View File
@@ -0,0 +1,6 @@
This directory should hold configuration files for custom mininets.
See custom_example.py, which loads the default minimal topology. The advantage of defining a mininet in a separate file is that you then use the --custom option in mn to run the CLI or specific tests with it.
To start up a mininet with the provided custom topology, do:
sudo mn --custom custom_example.py --topo mytopo
+45
View File
@@ -0,0 +1,45 @@
"""Custom topology example
author: Brandon Heller (brandonh@stanford.edu)
Two directly connected switches plus a host for each switch:
host --- switch --- switch --- host
Adding the 'topos' dict with a key/value pair to generate our newly defined
topology enables one to pass in '--topo=mytopo' from the command line.
"""
from mininet.topo import Topo, Node
class MyTopo( Topo ):
"Simple topology example."
def __init__( self, enable_all = True ):
"Create custom topo."
# Add default members to class.
super( MyTopo, self ).__init__()
# Set Node IDs for hosts and switches
leftHost = 1
leftSwitch = 2
rightSwitch = 3
rightHost = 4
# Add nodes
self.add_node( leftSwitch, Node( is_switch=True ) )
self.add_node( rightSwitch, Node( is_switch=True ) )
self.add_node( leftHost, Node( is_switch=False ) )
self.add_node( rightHost, Node( is_switch=False ) )
# Add edges
self.add_edge( leftHost, leftSwitch )
self.add_edge( leftSwitch, rightSwitch )
self.add_edge( rightSwitch, rightHost )
# Consider all switches and hosts 'on'
self.enable_all()
topos = { 'mytopo': ( lambda: MyTopo() ) }
-11
View File
@@ -1,11 +0,0 @@
#!/usr/bin/env bash
# set python3 alias, but needs permanent fix in image directly
alias python=python3
service openvswitch-switch start
ovs-vsctl set-manager ptcp:6640
bash
service openvswitch-switch stop
-35
View File
@@ -1,35 +0,0 @@
[comments]: The original author of Mini-NDN docker is Md Ashiqur Rahman (marahman@email.arizona.edu)
## Running Mini-NDN inside Docker
You can use the nightly build from GitHub package registry
```bash
docker run -m 4g --cpus=4 -it --privileged \
-v /lib/modules:/lib/modules \
ghcr.io/named-data/mini-ndn:master bash
```
## Building your own image
The Dockerfile can be used directly to `build` an image from scratch.
* Build with `Dockerfile`:
* Clone the repository and type.
```bash
docker build -t minindn .
```
* You can then access the container through shell with,
```bash
docker run -m 4g --cpus=4 -it --privileged \
-v /lib/modules:/lib/modules \
minindn bin/bash
```
### Notes:
* Memory (-m), CPU (--cpus) are recommended by Mini-NDN.
* `--privileged` is mandatory for underlying [Mininet](http://mininet.org/) to utilize virtual switch
* Root directory on `run` is `/mini-ndn` containing the installation and examples.
* GUI may not work for now due to docker and xterm setup issues and is independent from Mini-NDN.
If you intend to run the GUI, pass `-e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix` to the `docker run` command.
-20
View File
@@ -1,20 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-1
View File
@@ -1 +0,0 @@
.. include:: ../AUTHORS.rst
-36
View File
@@ -1,36 +0,0 @@
#!/bin/bash
# -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
set -eo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
PIP='python3 -m pip'
for PIPPKG in sphinx sphinx_rtd_theme; do
if ! $PIP show $PIPPKG >/dev/null; then
sudo $PIP install $PIPPKG
fi
done
make clean html
-61
View File
@@ -1,61 +0,0 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from datetime import datetime
from minindn import __version__
# -- Project information -----------------------------------------------------
project = 'Mini-NDN'
copyright = '2015-{}, Mini-NDN. This research is partially supported by NSF.'.format(datetime.now().year)
author = 'Mini-NDN'
# The full version, including alpha/beta/rc tags
release = __version__
version = __version__
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Need to specify the line below if custom conf.py
# https://github.com/readthedocs/readthedocs.org/issues/2569
# https://stackoverflow.com/questions/56336234/build-fail-sphinx-error-contents-rst-not-found
master_doc = 'index'
-274
View File
@@ -1,274 +0,0 @@
Experiment
==========
Configuration
-------------
Mini-NDN uses a configuration file describing the topology and its parameters to setup a network.
The [nodes] section:
At the bare minimum, the node section describes the nodes present in the
topology.
::
[nodes]
a: key1=value1 key2=value2
b: key1=value1
Any key and value passed here is accessible in Mini-NDN as:
::
ndn = Minindn(...)
value = ndn.net.hosts[0].params['params'].get('key1', "defaultValue")
One can specify log levels for each node's NFD and NLSR using this key-value system:
::
[nodes]
a: nfd-log-level=DEBUG nlsr-log-level=DEBUG
b: nfd-log-level=INFO
To specify a log level for certain modules of NFD, the following line can be added to `nfd.py`:
::
node.cmd('infoedit -f {} -s log.Forwarder -v {}'.format(self.confFile, 'INFO'))
This will turn on FORWARDER logging to INFO for all nodes.
.. Todo: Add switch section
The [links] section:
The links section describes the links in the topology.
::
e.g.)
[links]
a:b delay=10ms
This would create a link between a and b. 'b:a' would also result in the
same. The following parameters can be configured for a node:
- delay : Delay parameter is a required parameter which defines the
delay of the link (1-1000ms)
- bw : Bandwidth of a link (<1-1000> Mbps)
- loss : Percentage of packet loss (<1-100>)
Example configuration file
::
[nodes]
a:
b:
[links]
a:b delay=10ms bw=100
See ``ndn_utils/topologies`` for more sample files
Sample
------
Sample experiment may written as follows:
.. code:: python
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.appmanager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.helpers.routing_helper import IPRoutingHelper
if __name__ == '__main__':
setLogLevel('info')
Minindn.cleanUp()
Minindn.verifyDependencies()
# Can pass a custom parser, custom topology, or any Mininet params here
ndn = Minindn()
ndn.start()
# IP reachability if needed
# IPRoutingHelper.calcAllRoutes(ndn.net)
# info("IP routes configured, start ping\n")
# ndn.net.pingAll()
# Start apps with AppManager which registers a clean up function with ndn
info('Starting NFD on nodes\n')
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
info('Starting NLSR on nodes\n')
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr)
# or can not start NLSRs with some delay in between:
# nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr)
# for host in ndn.net.hosts:
# nlsrs.startOnNode(host)
# time.sleep(30)
MiniNDNCLI(ndn.net)
# Calls the clean up functions registered via AppManager
ndn.stop()
Users may look at how the NFD and NLSR applications are written as a sub class of Application
in the ``minindn/apps`` folder. Or users may choose to directly run their application on nodes
such as ndnpingserver is run in ``minindn/helpers/experiment.py``.
**Note:** A certain log-level can be set-up for all the NFD or NLSR nodes at once by passing it as an argument during the startup.
``nfds = AppManager(self.ndn, self.ndn.net.hosts, Nfd, logLevel='DEBUG')`` (same for NLSR)
Execution
---------
To run Mini-NDN with the default topology,
``ndn_utils/topologies/default-topology.conf``, type:
::
sudo python examples/minindn.py
To run Mini-NDN with a topology file, provide the filename as the first
argument:
::
sudo python examples/minindn.py my-topology.conf
After Mini-NDN is installed, users can run examples from anywhere with python directly as follows:
::
sudo python /path/to/myexample.py
The user no longer needs to create an experiment in the old Mini-NDN way, then install it to the system before executing it via the minindn binary. The new examples can be separate from the Mini-NDN folder if the core is not being modified.
CLI Interface
_____________
During set up, the list of nodes in the network will be listed as they
are initialized:
::
*** Adding hosts:
a b c d
After set up, the command-line interface (CLI) will display a prompt.
::
mini-ndn>
To interact with a node, first type the node's name and then the command
to be executed:
::
mini-ndn> a echo "Hello, world!"
Hello, world!
To see the status of the forwarder on the node:
::
mini-ndn> a nfdc status report
To see the status of routing on the node:
::
mini-ndn> a nlsrc status
To exit Mini-NDN, type ``quit`` in the CLI or use ``ctrl + D``:
::
mini-ndn> quit
``Ctrl + C`` is used to quit an application run in the foreground of the command line.
For a more in depth explanation of the CLI, please see the `Mininet
Walkthrough <http://mininet.org/walkthrough/>`__.
To run NDN commands from the outside the command line user can also open a new terminal
and export the HOME folder of a node ``export HOME=/tmp/minindn/a && cd ~``
Working Directory Structure
---------------------------
Currently Mini-NDN uses /tmp/minindn as the working directory if not
specified otherwise by using the option --work-dir.
Each node is given a HOME directory under /tmp/minindn/<node-name> where
<node-name> is the name of the node specified in the [nodes] section of
the conf file.
NFD
___
- NFD conf file is stored at ``/tmp/minindn/<node-name>/nfd.conf``
- NFD log file is stored at ``/tmp/minindn/<node-name>/log/nfd.log``
- ``.ndn`` folder is stored at ``/tmp/minindn/<node-name>/.ndn``
NLSR
____
- NLSR conf file is stored at ``/tmp/minindn/<node-name>/nlsr.conf``
- NLSR log file is stored at ``/tmp/minindn/<node-name>/log/nlsr.log``
When security is enabled, NLSR security certificates are stored in:
``/tmp/minindn/<node-name>/security`` Note that no NLSR publishes the root
certificate, Mini-NDN installs root.cert in security folder for each
NLSR.
While a host's NLSR neighbors are by default populated by adjacent nodes in wired scenarios,
for those running NLSR on wifi stations it is required that you specify "neighbor" faces
manually. The framework for this is provided either via a dictionary object or through
additional sections in topology files, and may also be used for wired experiments.
See an example of a topo of this sort in ``mini-ndn/topologies/wifi/nlsr_wifi_example.conf``.
NLSR faces to be created can be manually specified from topology files in a ``[faces]``
section, with the format ``nodeA:nodeB [cost=X]``. You should then call the ``setupFaces()``
method of an initialized Mini-NDN object to get a dictionary based on this parse in the format
``faceA:[(faceB, cost), (faceC, cost),...]``, which can finally be passed to the NLSR
helper via the faceDict parameter. An example experiment using this methodology is located
at ``mini-ndn/examples/wifi/nlsr_wifi.py``. Note that the aforementioned dict can also be
created manually in the previously established format.
Routing Options
----------------
Link State Routing (NLSR)
_________________________
By default, Mini-NDN uses `NLSR <https://github.com/named-data/NLSR>`__ for route management i.e route computation, route installation and so on. Additionally, the command line utility ``nlsrc`` can be used to advertise and withdraw prefixes and route status.
NDN Routing Helper
____________________
Computes link-state or hyperbolic route/s from a given minindn topology and installs them in the FIB. The major benefit of the routing helper is to eliminate the overhead of NLSR when using larger topology. See ``examples/static_routing_experiment.py`` on how to use the helper class.
**IMPORTANT:** NLSR and NDN Routing Helper are mutually exclusive, meaning you can only use one at a time, not both.
**Note:** The current version of ``ndn_routing_helper`` is still in the experimental phase. It doesn't support node or link failure and runtime prefix advertisement/withdrawal. If you find any bug please report `here <https://redmine.named-data.net/projects/mini-ndn>`__ or contact the :doc:`authors <authors>`.
IP Routing Helper
____________________
The routing helper allows to run IP-based evaluations with Mini-NDN. It configures static IP routes to all nodes, which means that all nodes can reach all other nodes in the network
reachable, even when relaying is required. Please see ``examples/ip_rounting_experiment.py`` for a simple example.
-48
View File
@@ -1,48 +0,0 @@
FAQ
=========
* ``How does Mini-NDN work?``
Mini-NDN's principles of operation most heavily rely on the underlying Mininet code it relies on.
Mininet uses a combination of limited containerization via network namespaces (which give processes
isolated interfaces and routing tables) and emulated ethernet connections via veth connections.
In practical terms, Mini-NDN ensures that processes running on distinct nodes will run seperately
and without interfering with each other.
* ``How does Mini-NDN apply link loss/delay/etc.?``
Mini-NDN relies on Mininet's code, which in turn uses the Linux tc utility on a stations' virtualized
interfaces to apply configurations known as qdiscs to these links. Note that these will only be applied
on egress packets from a station where it's applied.
For more information on qdiscs and tc, view the information `here <http://wiki.linuxwall.info/doku.php/en%3aressources%3adossiers%3anetworking%3atraffic_control>`_.
* ``Why use Mini-NDN rather than a simulator such as ndnSIM?``
Mini-NDN is easier and faster to use because, rather than serving as a mathematical model of a network,
it is instead running real NDN code on a real Linux kernel. This also means it's quite useful for testing code changes, as it can more accurately test the interaction of software componenents.
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Criteria | Mini-NDN | ndnSIM |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Based On | Mininet | ns-3 |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Language | Python | C++ |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Library/Forwarder/Applications | Use system binaries (free to use any compatible versions) | Integrated (fixed release version) |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Application language | C++ (ndn-cxx), CCL (ndn-cpp, PyNDN, ndn-js, jNDN) | C++ (ndn-cxx) |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Simulation size | Medium - Large (cluster edition in development) | Large (can be parallelized using MPI) |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Simulation time | Real time | Quick (depending on size/memory) |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Porting real applications | Drop in | Changes required |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Interactivity | Can interact directly with NFD, NLSR or Apps | Can show stats while running |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Logs | May need to manually setup to collect | Available with tracer |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Post processing scripts | Not available, users need to write their own | Available to use to process the logs |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
| Other | Not yet supported (Wifi in development) | WiFi, LTE, etc available from ns-3 |
+--------------------------------+-----------------------------------------------------------+-----------------------------------------+
-10
View File
@@ -1,10 +0,0 @@
Past NDN Hackathon projects
===========================
- 1st NDN Hackathon: `NFD integration test <http://ndncomm.github.io/mini-ndn/>`_.
- 2st NDN Hackathon: `Mini-NDN metrics <https://github.com/2nd-ndn-hackathon/mini-ndn-metrics>`_.
- 3rd NDN Hackathon: `Mini-NDN cluster <https://github.com/3rd-ndn-hackathon/mini-NDN-cluster>`_.
- 4th NDN Hackathon: `Mini-NDN wifi <https://github.com/4th-ndn-hackathon/Mini-NDN-Wi-Fi>`_.
- 7th NDN Hackathon: `Mini-NDN documentation <https://github.com/7th-ndn-hackathon/mini-ndn-documentation>`_.
- 11th NDN Hackathon: `Mini-NDN improvements <https://11th-ndn-hackathon.named-data.net/hacks.html#8-mini-ndn-improvements>`_.
- 12th NDN Hackathon: `Mini-NDN improvements and Refactoring <https://12th-ndn-hackathon.named-data.net/hacks.html#7-mini-ndn-improvements>`_.
-128
View File
@@ -1,128 +0,0 @@
Howtos
======
Connect Mini-NDN nodes to an outside network
---------------------------------------------
Mini-NDN nodes can be connected to an outside network indirectly by
running NFD on the local machine:
::
(Mini-NDN node) ------ (NFD running on the host machine where Mini-NDN is running) ------- (External Network)
Add a node in root namespace
____________________________
For this simple example, we can use a single node topology with node 'a'
If we want node 'a' to connect to the host machine, we need to add a
"root" node which has a link with node "a."
Then the following code can be used:
.. code:: python
topo = Topo()
root = topo.addHost('root', inNamespace=False)
a = topo.addHost('a')
topo.addLink(root, a, delay='10ms')
ndn = Minindn(topo=topo)
...
Configuration
_____________
Run Mini-NDN with the above code and issue ifconfig on the local
machine to confirm the addition of the interface. You should be able to
locate "root-eth0":
::
root-eth0 Link encap:Ethernet HWaddr 3e:eb:77:d2:6f:1f
inet addr:1.0.0.9 Bcast:1.0.0.11 Mask:255.255.255.252
inet6 addr: fe80::3ceb:77ff:fed2:6f1f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:34 errors:0 dropped:0 overruns:0 frame:0
TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2667 (2.6 KB) TX bytes:2797 (2.7 KB)
To make the IP address associated with this interface persistent, add
the following line to /etc/network/interfaces and reboot your machine:
::
iface root-eth0 inet manual
Check connection
________________
After rebooting, run Mini-NDN and issue the following command:
::
mini-ndn>net
a a-eth0:b-eth0 a-eth1:c-eth0 a-eth2:root-eth0
Node "a" is connected to "root-eth0". Now issue "ifconfig a-eth2" on
node "a":
::
mini-ndn>a ifconfig a-eth2
a-eth2 Link encap:Ethernet HWaddr fa:76:d4:86:d3:ba
inet addr:1.0.0.10 Bcast:1.0.0.11 Mask:255.255.255.252
As learned from the previous step, the IP address of root-eth0 is
1.0.0.9.
::
mini-ndn>a ping 1.0.0.9
PING 1.0.0.9 (1.0.0.9) 56(84) bytes of data.
64 bytes from 1.0.0.9: icmp_seq=1 ttl=64 time=0.137 ms
64 bytes from 1.0.0.9: icmp_seq=2 ttl=64 time=0.123 ms
The host machine will also be able to ping node "a":
::
VirtualBox:~$ ping 1.0.0.10
PING 1.0.0.10 (1.0.0.10) 56(84) bytes of data.
64 bytes from 1.0.0.10: icmp_seq=1 ttl=64 time=0.086 ms
Run NFD on local machine and register route
___________________________________________
Start NFD on the local machine by using:
::
sudo nfd
The "nfd-start" script cannot be used, since the script allows only one
instance of NFD at a time. The NFD processes running on the Mini-NDN
nodes will prevent the "nfd-start" script from working.
Now, using "nfdc register", we can register a route from node "a" in
Mini-NDN to the NFD process on the host machine and from the host
machine to an external machine.
Also, if the local machine has a public IP, Mini-NDN nodes can be
reached via external machines.
Generate NDN testbed topology
___________________________________________
Run the following install.sh command
::
python3 util/testbed_topo_generator.py
This will place a "testbed.conf" file in the topologies subdirectory,
where it can be referenced as desired. To update the topology, simply
rerun this command.
-30
View File
@@ -1,30 +0,0 @@
.. Mini-NDN documentation master file, created by
sphinx-quickstart on Mon Sep 23 11:15:54 2019.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Mini-NDN: A Mininet-based NDN emulator
======================================
.. toctree::
:maxdepth: 2
:caption: Contents
introduction
install
experiment
howtos
release-notes
faq
hackathon
videos
Helpful Links
-------------
* `NDN Website <http://named-data.net/>`_
* `NDN Contributor's Guide <https://github.com/named-data/NFD/blob/master/CONTRIBUTING.md>`_
* `Mininet Documentation <http://mininet.org/>`_
* `Mini-NDN redmine <https://redmine.named-data.net/projects/mini-ndn>`_
* `Mailing list <http://www.lists.cs.ucla.edu/mailman/listinfo/mini-ndn>`_
* :doc:`Mini-NDN Team <authors>`
-184
View File
@@ -1,184 +0,0 @@
Install
=======
Prerequisites
-------------
Mini-NDN is tested on the following Linux distributions:
- Ubuntu 20.04 (recommended)
- Ubuntu 22.04
- Debian 11 (WiFi scenario does not work)
- Fedora 33 (WiFi scenario does not work)
You must have sudo privileges to install and run Mini-NDN.
Using Vagrantfile
-----------------
With Vagrant installed, simply do ``vagrant up`` which will bring up an Ubuntu 18.04 virtual machine
and install Mini-NDN and all its dependencies on it. Please make sure to tweak the CPU core count
(default 4 cores) and RAM (default 4GB) according to your needs before doing vagrant up. Mini-NDN
can be found in /home/vagrant/mini-ndn which is a symlink to /vagrant if Vagrantfile was used from within mini-ndn cloned on the host. Otherwise it is an actual clone of mini-ndn.
Using install.sh
----------------
Mini-NDN has the following dependencies:
- `NDN Forwarding Daemon (NFD) <https://named-data.net/doc/NFD/>`_
- `Named Data Link State Routing (NLSR) <https://named-data.net/doc/NLSR/>`_
- `NDN Essential Tools (ndn-tools) <https://github.com/named-data/ndn-tools>`_
- `NDN Traffic Generator <https://github.com/named-data/ndn-traffic-generator>`_
- `infoedit <https://github.com/NDN-Routing/infoedit>`_
- `Mininet <http://mininet.org/>`_
- `Mininet-WiFi <https://mininet-wifi.github.io/>`_ (optional)
To install Mini-NDN and its dependencies, clone this repository and run:
::
./install.sh
The script accepts various command line flags.
Some notable flags are:
- ``-y`` skips interactive confirmation before installation.
- ``--ppa`` prefers installing NDN software from `named-data PPA <https://launchpad.net/~named-data/+archive/ubuntu/ppa>`_.
This shortens installation time by downloading binary packages, but is only available on Ubuntu.
- ``--source`` prefers installing NDN software from source code.
IMPORTANT: For now, Mininet-WiFi only works with ``--source`` installation because the current NFD release (0.7.1) doesn't
incorporate `issue 5155 <https://redmine.named-data.net/issues/5155>`, a required patch for WiFi module to work properly.
With the next NFD release, Mininet-WiFi will work with both ``source`` and ``ppa``. Alternatively, you can
checkout (at your own risk) a third-party source "`Use NFD nightly with Mini-NDN <https://yoursunny.com/t/2021/NFD-nightly-minindn/>`", which provides
NFD-nightly version and contains all the necessary patches.
- ``--dummy-keychain`` patches ndn-cxx to use an in-memory dummy KeyChain, which reduces CPU overhead
and allows you to scale up Mini-NDN experiments. Large Mini-NDN experiments would run significantly
faster after applying this patch. However, your experiments cannot use any NDN security related
features (signatures, verifier, access control, etc).
- ``--no-wifi`` skips Mininet-WiFi dependency.
Currently Mininet-WiFi only works on Ubuntu, so that you must specify this option when installing on other distros.
You can see all command line flags by running:
::
./install.sh -h
The script uses ``setup.py develop`` to point the system install of Python packages to the codebase
directory. Therefore, you can modify ``mininet``, ``mininet-wifi``, and ``mini-ndn``, and the
changes will be reflected immediately.
If NDN software is installed from source code (not PPA), the code is downloaded to ``dl`` directory
under your ``mini-ndn`` clone. If you modify the source code, you need to manually recompile and
reinstall the software (``./waf && sudo ./waf install``).
Installing Dependencies
-----------------------
This section outlines how to install dependnecies manually.
If you used ``install.sh``, you do not need to perform these steps.
Mininet
_______
Mini-NDN is based on Mininet. To install Mininet:
::
git clone --depth 1 https://github.com/mininet/mininet.git
After Mininet source is on your system, run the following command to
install Mininet core dependencies and Open vSwitch:
::
./util/install.sh -nv
To check if Mininet is working correctly, run this test:
::
sudo mn --test pingall
This will print out a series of statements that show the test setup and
the results of the test. Look for ``Results:`` two-thirds of the way
down where it will indicate the percentage of dropped packets. Your
results should show "0% dropped (2/2 received)".
NOTE: Mini-NDN, while providing a high level of emulation of hosts,
requires programs to be installed onto your computer. It will not work
if they are not installed. If you do not want NDN software installed
onto your computer, you can use a virtual machine, which can be quite
simply set up with the provided Vagrantfile.
NDN dependencies
________________
Each node in Mini-NDN will run the official implementation of NDN
installed on your system. The following dependencies are needed:
Mini-NDN uses NFD, NLSR, and ndn-tools.
- To install NFD: https://named-data.net/doc/NFD/current/INSTALL.html
- To install NLSR: https://named-data.net/doc/NLSR/current/INSTALL.html
- To install ndn-tools: https://github.com/named-data/ndn-tools
.. warning::
Please do not try to install NDN software from both the source (GitHub) and PPA (apt).
It will not work in most cases! If you used ./install.sh -a in the past but now want
to use apt, please run ``sudo ./waf uninstall`` in all the NDN projects before proceeding
with apt. Similarly, remove from apt if switching to source.
Please see the :ref:`scaling-note <scaling-note>` to learn about disabling
security for better scalability.
Note that all three of these can be installed from the Named Data PPA.
Instructions for setting it up can be found in the NFD installation
instructions. Note that PPA and installs from source **cannot** be
mixed. You must completely remove PPA installs from the system if switching
to source and vice-versa.
For PPA installs, if you are using a custom nfd.conf file in an experiment, you should
place it in /usr/local/etc/ndn/ rather than /etc/ndn/. This is to avoid
a bug from the default configuration file for the PPA, which is
incompatible with Mini-NDN.
Infoedit
________
Infoedit is used to edit configuration files for NFD and NLSR.
To install infoedit:
::
git clone --depth 1 https://github.com/NDN-Routing/infoedit
cd infoedit
make
sudo make install
Verification
------------
You can execute the following example to bring up the Mini-NDN command line
with NFD and NLSR running on each node:
::
sudo python examples/mnndn.py
You can use these steps to run the sample pingall experiment:
1. Issue the command: ``sudo python examples/nlsr/pingall.py``
2. When the ``mini-ndn>`` CLI prompt appears, the experiment has
finished. On the Mini-NDN CLI, issue the command ``exit`` to exit the
experiment.
3. Issue the command:
``grep -c content /tmp/minindn/*/ping-data/*.txt``. Each file should
report a count of 50.
4. Issue the command:
``grep -c timeout /tmp/minindn/*/ping-data/*.txt``. Each file should
report a count of 0.
-40
View File
@@ -1,40 +0,0 @@
Introduction
=================
If you are new to the NDN community of software generally, read the
`Contributor's Guide <https://github.com/named-data/NFD/blob/master/CONTRIBUTING.md>`_.
What is Mini-NDN?
-----------------
Mini-NDN is a lightweight networking emulation tool that enables testing, experimentation, and
research on the NDN platform. It was initially based on `Mini-CCNx <https://github.com/chesteve/mn-ccnx>`_ which was a fork of `Mininet <https://github.com/mininet/mininet>`_. Mini-NDN uses the NDN libraries, NFD, NLSR, and tools released by the `NDN project <http://named-data.net/codebase/platform/>`_ to emulate an NDN network on a single system.
The first release of Mini-NDN is developed by members of the NSF-sponsored NDN project team.
Mini-NDN is open to contribution from the public.
.. image:: minindnnet.svg
License
_______
Mini-NDN is open and free software licensed under the GPL 3.0 license. Mini-NDN is free to all
users and developers. For more information about licensing details and limitations,
please refer to COPYING.md.
Feedback/Mailing List
_____________________
Bug reports and feedback are highly appreciated and can be made through our
`Redmine site <http://redmine.named-data.net/projects/mini-ndn>`_ and the
`mini-ndn mailing list <http://www.lists.cs.ucla.edu/mailman/listinfo/mini-ndn>`_.
Video
_____
.. raw:: html
<div id="video-container" class="col-md-6 ">
<p>Mini-NDN (content maybe outdated)</p>
<iframe width="600" height="345" src="https://www.youtube.com/embed/UxHPqaUwefg" frameborder="0" allowfullscreen=""></iframe>
</div>
-126
View File
@@ -1,126 +0,0 @@
<svg width="692" height="380" xmlns="http://www.w3.org/2000/svg">
<metadata id="metadata7">image/svg+xml</metadata>
<g>
<title>background</title>
<rect fill="none" id="canvas_background" height="382" width="694" y="-1" x="-1"/>
</g>
<g>
<title>Layer 1</title>
<g stroke="null" id="g3790">
<rect stroke="#000000" fill="#ffffff" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" id="rect2985" width="680.84682" height="350.443392" x="4.962804" y="5.773119" rx="0.324652"/>
<path stroke="#000000" fill="none" stroke-miterlimit="4" d="m4,175.828501l681.727736,1.357954" id="path3770"/>
</g>
<rect stroke="#000000" fill="#e3dedb" stroke-width="0.99538" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-dashoffset="0" rx="2.988095" y="176.111777" x="5.140841" height="180.524655" width="680.312936" id="rect3813"/>
<rect stroke="#000000" fill="#ffffff" stroke-width="1.602133" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-dasharray="4.80639973, 4.80639973" stroke-dashoffset="0" ry="8.582684" rx="7.476771" y="44.78072" x="55.492192" height="195.219243" width="148.366914" id="rect3764"/>
<rect stroke="#000000" fill="#ffffff" stroke-width="1.638042" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-dasharray="4.9141253, 4.9141253" stroke-dashoffset="0" id="rect3772" width="155.115252" height="195.190135" x="270.220868" y="46.153231" rx="7.816845" ry="8.581405"/>
<rect stroke="#000000" fill="#ffffff" stroke-width="1.602133" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-dasharray="4.80639973, 4.80639973" stroke-dashoffset="0" ry="8.582684" rx="7.476771" y="45.459696" x="489.86568" height="195.219243" width="148.366914" id="rect3774"/>
<text transform="matrix(1.0192718802397343,0,0,0.9115536073383187,-2.8313337784806336,-12.183034089773187) " font-size="16.005802px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3776" y="392.709737" x="551.171304" xml:space="preserve">
<tspan stroke="null" font-weight="normal" y="398.194877" x="552.152396" id="tspan3778">Kernel Space</tspan>
</text>
<text transform="matrix(1.0524848569125234,0,0,0.8827879284304422,-52.30106698198968,-77.5201889102731) " font-size="14.180006px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="601.466013" y="108.524983" id="text3782">
<tspan stroke="null" font-weight="normal" id="tspan3784" x="602.416145" y="114.188857">User Space</tspan>
</text>
<path stroke="#000000" fill="none" stroke-width="1px" id="path3796" d="m488.56554,176.773764c1.782236,0.480113 1.527628,0.360085 1.527628,0.360085"/>
<rect stroke="#000000" fill="#ffffff" stroke-width="0.649807" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-dashoffset="0" rx="0.838801" y="202.851471" x="84.255138" height="26.434283" width="94.537572" id="rect3815"/>
<rect stroke="#000000" fill="#ffffff" stroke-width="0.792138" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-dashoffset="0" id="rect3817" width="131.339764" height="28.275376" x="282.077514" y="201.912133" rx="1.165334"/>
<path stroke="#000000" fill="none" stroke-width="0.865499px" id="path3823" d="m347.74739,201.086282l0,28.351986"/>
<text transform="matrix(0.7776670647796514,0,0,1.19475416519067,-52.30106724263901,-77.52018902784596) " font-size="12.623897px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="434.634023" y="248.956571" id="text3835">
<tspan stroke="null" font-size="15.579311px" font-weight="bold" font-family="Monospace" x="435.91992" y="253.141532" id="tspan3837">n2-eth0</tspan>
</text>
<text transform="matrix(0.9031157255303414,0,0,1.0287949657006918,-2.8313337284492768,-13.069358400177762) " font-size="13.163442px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="110.835751" y="225.210496" id="text3863">
<tspan stroke="null" font-size="16.245171px" font-weight="bold" font-family="Monospace" x="111.943029" y="230.070551" id="tspan3865">n1-eth0</tspan>
</text>
<path stroke="#000000" fill="none" stroke-width="0.992521px" id="path3887" d="m131.263954,229.882774l0,67.221296l176.555867,-0.960307l1.337531,-65.300682"/>
<rect stroke="#000000" fill="#ffffff" stroke-width="0.676601" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="4" stroke-dashoffset="0" id="rect3891" width="95.679394" height="28.317195" x="515.346399" y="202.85306" rx="0.848932"/>
<path stroke="#000000" fill="none" stroke-width="0.992521px" d="m383.833251,230.842992l0,67.221296l176.555867,-0.960307l1.337531,-65.300682" id="path3897"/>
<text transform="matrix(0.9778213687833123,0,0,0.9501950205038839,-52.301066914088324,-76.5370021990862) " font-size="16.459864px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="164.136782" y="409.888383" id="text3907">
<tspan stroke="null" id="tspan3915" x="165.159464" y="415.15046">isolated point to point link</tspan>
</text>
<text transform="matrix(0.9778213687833123,0,0,0.9501950205038839,-52.301066914088324,-76.5370021990862) " font-size="16.459864px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3919" y="409.573373" x="429.378262" xml:space="preserve">
<tspan stroke="null" y="414.83545" x="430.400944" id="tspan3921">isolated point to point link</tspan>
</text>
<text transform="matrix(0.9778213687833123,0,0,0.9501950205038839,-52.301066914088324,-76.5370021990862) " font-size="16.459864px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3923" y="428.078233" x="194.615642" xml:space="preserve">
<tspan stroke="null" font-weight="bold" y="433.34031" x="195.638324" id="tspan3925">(eg: 1Mbps, 10ms)</tspan>
</text>
<text transform="matrix(0.9778213687833123,0,0,0.9501950205038839,-52.301066914088324,-76.5370021990862) " font-size="16.459864px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3927" y="409.888383" x="164.136782" xml:space="preserve">
<tspan stroke="null" y="415.15046" x="165.159464" id="tspan3929">Isolated point to point link</tspan>
</text>
<text transform="matrix(0.9778213687833123,0,0,0.9501950205038839,-52.301066914088324,-76.5370021990862) " font-size="16.459864px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="429.378262" y="409.573373" id="text3931">
<tspan stroke="null" id="tspan3933" x="430.400944" y="414.83545">Isolated point to point link</tspan>
</text>
<text transform="matrix(0.877827228897152,0,0,1.0584326041598764,-53.30106731891522,-78.4233265445007) " font-size="13.706223px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3935" y="282.545218" x="661.482605" xml:space="preserve">
<tspan stroke="null" font-size="16.915024px" font-weight="bold" font-family="Monospace" id="tspan3937" y="287.269185" x="662.621781">n3-eth0</tspan>
</text>
<text transform="matrix(0.7776670647796514,0,0,1.19475416519067,-52.30106724263901,-77.52018902784596) " font-size="12.623897px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3939" y="248.297391" x="520.751053" xml:space="preserve">
<tspan stroke="null" font-size="15.579311px" font-weight="bold" font-family="Monospace" id="tspan3941" y="252.482352" x="522.03695">n2-eth1</tspan>
</text>
<text transform="matrix(0.8745385143393076,0,0,1.0624128521471832,-2.8313338199928846,-14.069358364146652) " font-size="16.205975px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3943" y="80.648481" x="141.655977" xml:space="preserve">
<tspan stroke="null" font-size="20px" font-weight="bold" font-family="Monospace" id="tspan3945" y="85.354749" x="142.799437">n1</tspan>
</text>
<text transform="matrix(0.8745385143393076,0,0,1.0624128521471832,-2.8313338199928846,-14.069358364146652) " font-size="16.205975px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="385.430517" y="78.840861" id="text3955">
<tspan stroke="null" font-size="20px" font-weight="bold" font-family="Monospace" x="386.573977" y="83.547129" id="tspan3957">n2</tspan>
</text>
<text transform="matrix(0.8745385143393076,0,0,1.0624128521471832,-2.8313338199928846,-14.069358364146652) " font-size="16.205975px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3959" y="79.181231" x="632.310457" xml:space="preserve">
<tspan stroke="null" font-size="20px" font-weight="bold" font-family="Monospace" id="tspan3961" y="83.887499" x="633.453917">n3</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="125.371536" y="171.060971" id="text3967">
<tspan stroke="null" font-weight="normal" id="tspan3969" x="126.421253" y="176.187525">(NDN Container)</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3979" y="170.076461" x="352.011746" xml:space="preserve">
<tspan stroke="null" font-weight="normal" y="175.203015" x="353.061463" id="tspan3981">(NDN Container)</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="580.077396" y="169.091931" id="text3983">
<tspan stroke="null" font-weight="normal" id="tspan3985" x="581.127113" y="174.218485">(NDN Container)</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3987" y="193.704961" x="123.946116" xml:space="preserve">
<tspan stroke="null" font-weight="bold" y="198.831515" x="124.995833" id="tspan3989">NFD</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="140.791686" y="208.664491" id="text3991">
<tspan stroke="null" font-weight="normal" id="tspan3993" x="141.841403" y="213.791045">n1.sock</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="123.946116" y="225.286191" id="text3995">
<tspan stroke="null" font-weight="bold" id="tspan3997" x="124.995833" y="230.412745">NLSR</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text3999" y="240.245731" x="138.385176" xml:space="preserve">
<tspan stroke="null" font-weight="normal" y="245.372285" x="139.434893" id="tspan4001">%C1.Router/n1</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="352.011746" y="191.735901" id="text4003">
<tspan stroke="null" font-weight="bold" id="tspan4005" x="353.061463" y="196.862455">NFD</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text4007" y="206.695431" x="366.450896" xml:space="preserve">
<tspan stroke="null" font-weight="normal" y="211.821985" x="367.500613" id="tspan4009">n2.sock</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text4011" y="223.317141" x="352.011746" xml:space="preserve">
<tspan stroke="null" font-weight="bold" y="228.443695" x="353.061463" id="tspan4013">NLSR</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="366.450896" y="238.276671" id="text4015">
<tspan stroke="null" font-weight="normal" id="tspan4017" x="367.500613" y="243.403225">%C1.Router/n2</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text4019" y="190.751371" x="582.928226" xml:space="preserve">
<tspan stroke="null" font-weight="bold" y="195.877925" x="583.977943" id="tspan4021">NFD</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="599.773686" y="205.710911" id="text4023">
<tspan stroke="null" font-weight="normal" id="tspan4025" x="600.823403" y="210.837465">n3.sock</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="582.928226" y="222.332611" id="text4027">
<tspan stroke="null" font-weight="bold" id="tspan4029" x="583.977943" y="227.459165">NLSR</tspan>
</text>
<text transform="matrix(0.9526376792163275,0,0,0.9753141035001042,-53.30106707952308,-77.42332645354041) " font-size="14.959435px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text4031" y="237.292141" x="597.367186" xml:space="preserve">
<tspan stroke="null" font-weight="normal" y="242.418695" x="598.416903" id="tspan4033">%C1.Router/n3</tspan>
</text>
<text transform="matrix(0.9778213687833123,0,0,0.9501950205038839,-52.301066914088324,-76.5370021990862) " font-size="16.459864px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text4035" y="102.475413" x="322.701992" xml:space="preserve">
<tspan stroke="null" y="107.73749" x="323.724674" id="tspan4037">Isolated NDN nodes</tspan>
</text>
<text transform="matrix(0.935021961689298,0,0,0.9936889310882339,-2.9798247609055646,-12.086171479984756) " font-size="11.279781px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="75.549398" y="206.131281" id="text4039">
<tspan stroke="null" id="tspan4041" x="76.618892" y="211.163037">Private network space</tspan>
</text>
<text transform="matrix(0.935021961689298,0,0,0.9936889310882339,-2.9798247609055646,-12.086171479984756) " font-size="11.279781px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" id="text4043" y="206.946991" x="308.474828" xml:space="preserve">
<tspan stroke="null" y="211.978747" x="309.544322" id="tspan4045">Private network space</tspan>
</text>
<text transform="matrix(0.935021961689298,0,0,0.9936889310882339,-2.9798247609055646,-12.086171479984756) " font-size="11.279781px" font-style="normal" font-weight="normal" fill="#000000" font-family="Sans" xml:space="preserve" x="540.174348" y="206.131281" id="text4047">
<tspan stroke="null" id="tspan4049" x="541.243842" y="211.163037">Private network space</tspan>
</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica,Arial,sans-serif" font-size="15px" id="svg_1" y="377" x="203.5" stroke-width="null" stroke="null" fill="#333">Figure: Relationship between Minindn and Mininet</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

-286
View File
@@ -1,286 +0,0 @@
Release Notes
=============
Mini-NDN version 0.6.0 (Major changes since version 0.5.0)
----------------------------------------------------------
**Breaking Changes**:
- Rewrite install script (`issue: 4630 <https://redmine.named-data.net/issues/4630>`__)
- Set dependency versions: PPA, git repository & commit
- Separate download and build+install steps
- Don't reinstall package if it's already installed
- More details `here <https://github.com/named-data/mini-ndn/blob/master/docs/install.rst>`__
- `Note: <https://redmine.named-data.net/issues/5161>`__ We have dropped support for python 2, the latest Mini-NDN requires at least python 3.0
**New features**:
- Update Mini-NDN codebase with Mini-NDN-Wifi code (`issue: 4858 <https://redmine.named-data.net/issues/4858>`__)
- Provide pre-built Mini-NDN Vagrant box and Docker container
- Added several new examples:
- consumer/producer
- ndnping
- traffic generator
- catchunks/putchunks
- Allow for creation of net object without topology (`issue: 5162 <https://redmine.named-data.net/issues/5162>`__)
**Improvements and Bug Fixes**:
- Support running NDN applications on mixed topologies (`issue: 5160 <https://redmine.named-data.net/issues/5160>`__)
- Support route addition using face-id in `Nfdc` helper (`issue: 5130 <https://redmine.named-data.net/issues/5130>`__)
- Add wrapper for `ndnpingserver` and fix passing the Mininet host object as a prefix on ndnpingclient
- Show status of route calculation in `NdnRoutingHelper`
- Incorporate changes of `NDNPing` Class (wrapper of pingserver and pingclient) in the examples
- Support simple topology files with no additional parameters
Mini-NDN version 0.5.0 (Major changes since version 0.4.0)
----------------------------------------------------------
**Breaking Changes**:
- `Mini-NDN re-design <https://redmine.named-data.net/issues/5062>`__: simple and robust design with better quality, control, and more consistency with Mininet
**New features**:
- Add a script to generate up-to-date NDN testbed topologies for Mini-NDN
- Add Mini-NDN utility application for PCAP logging
- Add NDN routing helper to compute centralized LS and HR routes
- Add routing helper to allow IP communication in experiments
- Add startup experiments for NLSR and current testbed topology
- Move the NDNPing wrapper method to a helper class
- Create a helper class to provide a wrapper around ``nfdc``
**Improvements and Bug Fixes**:
- Change workDir and resultDir to be class attribute
- Quiet apt install for Vagrant
- Fix route computation bug in ``ndn_routing_helper``
- Fix overwriting of existing prefixes in ``ndn_routing_helper``
- Move log files to resultDir after evaluation finishes
- Check for duplicate HR coordinates in the topology file
- Check PSync integration and add a tests case for it
- Bug fixes in nfdc and experiments
- Added functionality to check Mini-NDN dependencies
- Parser fix to avoid an infinite loop
- Allow use of NFD and NLSR PPA with Mini-NDN
- Remove arbitrary arguments in favor of parsing arguments from experiment files
- Auto-complete command-line arguments
- Add option to set CS size
- Adjust to use ndn-cxx logging
Mini-NDN version 0.4.0 (changes since version 0.3.0)
----------------------------------------------------
Release date: January 10, 2018
**New features**:
- Use SIGQUIT to quit Mini-NDN, SIGINT to kill programs
- Use Infoedit to edit NFD and NLSR configuration files
- Use nlsr.conf installed in the system
- Provide a Vagrantfile to setup Mini-NDN and NDN
- Provide option to disable NLSR
- Provide an option to run NLSR in dry-run mode
- Add option to specify whether to use TCP or UDP face in nlsr.conf
- Add option to specify arbitrary arguments to use in experiments
- Include a single option to install Mini-NDN and all the dependencies
**Bug fixes**:
- Fix "key does not exist error" after NLSR starts
- Update install.sh to call ldconfig after installing ChronoSync
- Add hyperbolic coordinates to default topology
**Misc changes**:
- Add an experiment to test nlsrc
- Create faces in NFD for each neighbor in NLSR
- Update to latest ndn-cxx
- Use /tmp/minindn folder as default work dir instead of /tmp
Mini-NDN version 0.3.0 (changes since version 0.2.0)
----------------------------------------------------
Release date: March 3, 2017
**New features**:
- Mini-NDN cluster edition
- New experiments for making NLSR testing easier
**Bug fixes**:
- Set site name correctly
- Install missing certificates in NLSR security config
- Fix quitting of NLSR due to key not found error
**Misc changes**:
- Removed nlsr.conf file, generate it within the code
- Use argparse instead of deprecated optparse
- Update security config section for NLSR
- Change mininet prompt to mini-ndn
- Set network name at one place
- Update install.sh script to install openssl
- Update install.sh script to install cryptopp from package instead of
compiling from source
- Update install.sh to clean build folder every time to get rid of
removed files such as old experiments
- Fix old code - use net.hosts instead of storing hosts in a variable
- Use nfdc instead of deprecated nfd-status
Mini-NDN version 0.2.0 (changes since version 0.1.1)
----------------------------------------------------
Release date: August 18, 2016
**New features**:
- Automatic security configuration for NLSR
- Use /usr/local/etc/ndn/nfd.conf as default config file for NFD
- Class to monitor /proc/$PID/stat file for PID
- Mini-NDN exits gracefully on SIGINT and non-convergence
- Faster Mini-NDN install script - does not do apt-get update everytime
- NLSR is launched with explicit config file for easier process
identification
- Add and update more documentation
**Bug fixes**:
- NFD is killed correctly on exit
- Best route strategy is set correctly
Mini-NDN version 0.1.1 (changes since version 0.1.0)
----------------------------------------------------
Release date: November 4, 2015
**New features**:
- Use nfd.conf.sample from currently installed NFD
- Add working directory option to allow execution environment outside
of /tmp
- Add results directory option to store experiment results after
completion
- Add support for switches in GUI and configuration file
- Add failNode and recoverNode methods to Experiment class
- Add most connected node (MCN) failure experiment
- Add option to specify percentage of nodes pinged
**Code changes**:
- Refactor program options into container class
- Remove unused "FIB Entries" option from NDN host options
**Bug fixes**:
- Abort start up if experiment name is invalid
- Restart pings after recovery in failure experiment
Mini-NDN version 0.1.0 (initial release)
----------------------------------------
Release date: July 15, 2015
Mini-NDN is a lightweight networking emulation tool that enables
testing, experimentation, and research on the NDN platform. Based on
Mininet, Mini-NDN uses the NDN libraries, NFD, NLSR, and tools released
by the `NDN project <http://named-data.net/codebase/platform/>`__ to
emulate an NDN network on a single system.
**Included features**:
- Run a complete NDN network on a single system
- Automatic configuration of NLSR to provide a routable NDN network
- Supports user created NDN applications
- Create a topology using the included Mini-NDN Edit GUI application
- Allows individual configuration of NFD and NLSR parameters for each
node
- Provides an experiment management framework for easy creation of
custom networking experiments
- Uses a simple topology file format to define hosts, links, and
configuration values
- Configure network link parameters including bandwidth, delay, and
loss rate
- Includes a pre-configured topology file to replicate the NDN testbed
-18
View File
@@ -1,18 +0,0 @@
Video Tutorials
===============
Maybe outdated since version 0.5.0.
.. raw:: html
<div id="video-container" class="col-md-6 ">
<p>Mini-NDN Demo at ACM, 2017</p>
<iframe width="400" height="230" src="https://www.youtube.com/embed/xYRPHZe18o0" frameborder="0" allowfullscreen=""></iframe>
</div>
.. raw:: html
<div id="video-container" class="col-md-6 "">
<p>Mini-NDN Overview </p>
<iframe width="400" height="230" src="https://www.youtube.com/embed/Da7t8yBWzv0" frameborder="0" allowfullscreen="">
</div>
+3 -3
View File
@@ -25,7 +25,7 @@ DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
PROJECT_NAME = "Mininet Python API Reference Manual"
PROJECT_NAME = Mininet
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
@@ -114,7 +114,7 @@ FULL_PATH_NAMES = YES
# If left blank the directory from which doxygen is run is used as the
# path to strip.
STRIP_FROM_PATH =
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
@@ -919,7 +919,7 @@ COMPACT_LATEX = NO
# by the printer. Possible values are: a4, a4wide, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = letter
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
+84
View File
@@ -0,0 +1,84 @@
Mininet Examples
These examples are intended to help you get started using
Mininet's Python API.
---
baresshd.py:
This example uses Mininet's medium-level API to create an sshd
process running in a namespace. Doesn't use OpenFlow.
consoles.py:
This example creates a grid of console windows, one for each node,
and allows interaction with and monitoring of each console, including
graphical monitoring.
controllers.py:
This example creates a network and adds multiple controllers to it.
emptynet.py:
This example demonstrates creating an empty network (i.e. with no
topology object) and adding nodes to it.
linearbandwidth.py:
This example shows how to create a custom topology programatically
by subclassing Topo, and how to run a series of tests on it.
miniedit.py:
This example demonstrates creating a network via a graphical editor.
multiping.py:
This example demonstrates one method for
monitoring output from multiple hosts, using node.monitor().
multipoll.py:
This example demonstrates monitoring output files from multiple hosts.
multitest.py:
This example creates a network and runs multiple tests on it.
popenpoll.py:
This example demonstrates monitoring output from multiple hosts using
the node.popen() interface (which returns Popen objects) and pmonitor().
scratchnet.py, scratchnetuser.py:
These two examples demonstrate how to create a network by using the lowest-
level Mininet functions. Generally the higher-level API is easier to use,
but scratchnet shows what is going on behind the scenes.
simpleperf.py:
A simple example of configuring network and CPU bandwidth limits.
sshd.py:
This example shows how to run an sshd process in each host, allowing
you to log in via ssh. This requires connecting the Mininet data network
to an interface in the root namespace (generaly the control network
already lives in the root namespace, so it does not need to be explicitly
connected.)
treeping64.py:
This example creates a 64-host tree network, and attempts to check full
connectivity using ping, for different switch/datapath types.
tree1024.py:
This example attempts to create a 1024-host network, and then runs the
CLI on it. It may run into scalability limits, depending on available
memory and sysctl configuration (see INSTALL.)
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/python
"This example doesn't use OpenFlow, but attempts to run sshd in a namespace."
from mininet.node import Host
print "*** Creating nodes"
h1 = Host( 'h1' )
root = Host( 'root', inNamespace=False )
print "*** Creating links"
h1.linkTo( root )
print h1
print "*** Configuring nodes"
h1.setIP( '10.0.0.1', 8 )
root.setIP( '10.0.0.2', 8 )
print "*** Creating banner file"
f = open( '/tmp/%s.banner' % h1.name, 'w' )
f.write( 'Welcome to %s at %s\n' % ( h1.name, h1.IP() ) )
f.close()
print "*** Running sshd"
h1.cmd( '/usr/sbin/sshd -o "Banner /tmp/%s.banner"' % h1.name )
print "*** You may now ssh into", h1.name, "at", h1.IP()
-95
View File
@@ -1,95 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
"""
This example demonstrates the functionality of the ndncatchunks and ndnputchunks. There are
programs to transfer a file as Data segments in NDN.
https://github.com/named-data/ndn-tools/tree/master/tools/chunks.
"""
from time import sleep
import subprocess
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
def sendFile(node, prefix, file):
"""
Publish a file using ndnputchunks
:parma mininet.node.Host node: mininet node object
:param string prefix: prefix to publish the chunks of the file
:param string file: file to publish
"""
info ("File published:", file)
cmd = 'ndnputchunks {}/{} < {} > putchunks.log 2>&1 &'.format(prefix, "fname", file)
node.cmd(cmd)
# Sleep for appropriate time based on the file size
sleep(5)
def receiveFile(node, prefix, filename):
"""
Fetch a file using ndncatchunks
:parma mininet.node.Host node: mininet node object
:param string prefix: producer's prefix under which the file the published
:param string file: name given to the file that will be received
"""
info ("Fething file: ", filename)
cmd = 'ndncatchunks {}/{} > {} 2> catchunks.log &'.format(prefix, "fname", filename)
node.cmd(cmd)
if __name__ == '__main__':
setLogLevel('info')
# Create a test file to publish
testFile = "/tmp/test-chunks"
cmd = 'echo "demonstrate file transfer using catchunks and putchunks" > {}'.format(testFile)
subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).communicate()
Minindn.cleanUp()
Minindn.verifyDependencies()
ndn = Minindn()
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr)
sleep(70)
# Default topology is used in this experiment "/topologies/default-topology.conf"
# lets make node "a" as a producer node, and node "c" as a conumer node
producer = ndn.net['a']
producerPrefix = "/test-producer" # prefix under which the file will be published
consumer = ndn.net['c']
# Advertise the producer prefix to the network
producer.cmd('nlsrc advertise {}'.format(producerPrefix))
sleep (5) # sleep for routing convergence.
sendFile(producer, producerPrefix, testFile)
receiveFile(consumer, producerPrefix, "test-chunks")
MiniNDNCLI(ndn.net)
ndn.stop()
+459
View File
@@ -0,0 +1,459 @@
#!/usr/bin/python
"""
consoles.py: bring up a bunch of miniature consoles on a virtual network
This demo shows how to monitor a set of nodes by using
Node's monitor() and Tkinter's createfilehandler().
We monitor nodes in a couple of ways:
- First, each individual node is monitored, and its output is added
to its console window
- Second, each time a console window gets iperf output, it is parsed
and accumulated. Once we have output for all consoles, a bar is
added to the bandwidth graph.
The consoles also support limited interaction:
- Pressing "return" in a console will send a command to it
- Pressing the console's title button will open up an xterm
Bob Lantz, April 2010
"""
import re
from Tkinter import Frame, Button, Label, Text, Scrollbar, Canvas, Wm, READABLE
from mininet.log import setLogLevel
from mininet.topolib import TreeNet
from mininet.term import makeTerms, cleanUpScreens
from mininet.util import quietRun
class Console( Frame ):
"A simple console on a host."
def __init__( self, parent, net, node, height=10, width=32, title='Node' ):
Frame.__init__( self, parent )
self.net = net
self.node = node
self.prompt = node.name + '# '
self.height, self.width, self.title = height, width, title
# Initialize widget styles
self.buttonStyle = { 'font': 'Monaco 7' }
self.textStyle = {
'font': 'Monaco 7',
'bg': 'black',
'fg': 'green',
'width': self.width,
'height': self.height,
'relief': 'sunken',
'insertbackground': 'green',
'highlightcolor': 'green',
'selectforeground': 'black',
'selectbackground': 'green'
}
# Set up widgets
self.text = self.makeWidgets( )
self.bindEvents()
self.sendCmd( 'export TERM=dumb' )
self.outputHook = None
def makeWidgets( self ):
"Make a label, a text area, and a scroll bar."
def newTerm( net=self.net, node=self.node, title=self.title ):
"Pop up a new terminal window for a node."
net.terms += makeTerms( [ node ], title )
label = Button( self, text=self.node.name, command=newTerm,
**self.buttonStyle )
label.pack( side='top', fill='x' )
text = Text( self, wrap='word', **self.textStyle )
ybar = Scrollbar( self, orient='vertical', width=7,
command=text.yview )
text.configure( yscrollcommand=ybar.set )
text.pack( side='left', expand=True, fill='both' )
ybar.pack( side='right', fill='y' )
return text
def bindEvents( self ):
"Bind keyboard and file events."
# The text widget handles regular key presses, but we
# use special handlers for the following:
self.text.bind( '<Return>', self.handleReturn )
self.text.bind( '<Control-c>', self.handleInt )
self.text.bind( '<KeyPress>', self.handleKey )
# This is not well-documented, but it is the correct
# way to trigger a file event handler from Tk's
# event loop!
self.tk.createfilehandler( self.node.stdout, READABLE,
self.handleReadable )
# We're not a terminal (yet?), so we ignore the following
# control characters other than [\b\n\r]
ignoreChars = re.compile( r'[\x00-\x07\x09\x0b\x0c\x0e-\x1f]+' )
def append( self, text ):
"Append something to our text frame."
text = self.ignoreChars.sub( '', text )
self.text.insert( 'end', text )
self.text.mark_set( 'insert', 'end' )
self.text.see( 'insert' )
outputHook = lambda x, y: True # make pylint happier
if self.outputHook:
outputHook = self.outputHook
outputHook( self, text )
def handleKey( self, event ):
"If it's an interactive command, send it to the node."
char = event.char
if self.node.waiting:
self.node.write( char )
def handleReturn( self, event ):
"Handle a carriage return."
cmd = self.text.get( 'insert linestart', 'insert lineend' )
# Send it immediately, if "interactive" command
if self.node.waiting:
self.node.write( event.char )
return
# Otherwise send the whole line to the shell
pos = cmd.find( self.prompt )
if pos >= 0:
cmd = cmd[ pos + len( self.prompt ): ]
self.sendCmd( cmd )
# Callback ignores event
def handleInt( self, _event=None ):
"Handle control-c."
self.node.sendInt()
def sendCmd( self, cmd ):
"Send a command to our node."
if not self.node.waiting:
self.node.sendCmd( cmd )
def handleReadable( self, _fds, timeoutms=None ):
"Handle file readable event."
data = self.node.monitor( timeoutms )
self.append( data )
if not self.node.waiting:
# Print prompt
self.append( self.prompt )
def waiting( self ):
"Are we waiting for output?"
return self.node.waiting
def waitOutput( self ):
"Wait for any remaining output."
while self.node.waiting:
# A bit of a trade-off here...
self.handleReadable( self, timeoutms=1000)
self.update()
def clear( self ):
"Clear all of our text."
self.text.delete( '1.0', 'end' )
class Graph( Frame ):
"Graph that we can add bars to over time."
def __init__( self, parent=None,
bg = 'white',
gheight=200, gwidth=500,
barwidth=10,
ymax=3.5,):
Frame.__init__( self, parent )
self.bg = bg
self.gheight = gheight
self.gwidth = gwidth
self.barwidth = barwidth
self.ymax = float( ymax )
self.xpos = 0
# Create everything
self.title, self.scale, self.graph = self.createWidgets()
self.updateScrollRegions()
self.yview( 'moveto', '1.0' )
def createScale( self ):
"Create a and return a new canvas with scale markers."
height = float( self.gheight )
width = 25
ymax = self.ymax
scale = Canvas( self, width=width, height=height,
background=self.bg )
opts = { 'fill': 'red' }
# Draw scale line
scale.create_line( width - 1, height, width - 1, 0, **opts )
# Draw ticks and numbers
for y in range( 0, int( ymax + 1 ) ):
ypos = height * (1 - float( y ) / ymax )
scale.create_line( width, ypos, width - 10, ypos, **opts )
scale.create_text( 10, ypos, text=str( y ), **opts )
return scale
def updateScrollRegions( self ):
"Update graph and scale scroll regions."
ofs = 20
height = self.gheight + ofs
self.graph.configure( scrollregion=( 0, -ofs,
self.xpos * self.barwidth, height ) )
self.scale.configure( scrollregion=( 0, -ofs, 0, height ) )
def yview( self, *args ):
"Scroll both scale and graph."
self.graph.yview( *args )
self.scale.yview( *args )
def createWidgets( self ):
"Create initial widget set."
# Objects
title = Label( self, text='Bandwidth (Gb/s)', bg=self.bg )
width = self.gwidth
height = self.gheight
scale = self.createScale()
graph = Canvas( self, width=width, height=height, background=self.bg)
xbar = Scrollbar( self, orient='horizontal', command=graph.xview )
ybar = Scrollbar( self, orient='vertical', command=self.yview )
graph.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set,
scrollregion=(0, 0, width, height ) )
scale.configure( yscrollcommand=ybar.set )
# Layout
title.grid( row=0, columnspan=3, sticky='new')
scale.grid( row=1, column=0, sticky='nsew' )
graph.grid( row=1, column=1, sticky='nsew' )
ybar.grid( row=1, column=2, sticky='ns' )
xbar.grid( row=2, column=0, columnspan=2, sticky='ew' )
self.rowconfigure( 1, weight=1 )
self.columnconfigure( 1, weight=1 )
return title, scale, graph
def addBar( self, yval ):
"Add a new bar to our graph."
percent = yval / self.ymax
c = self.graph
x0 = self.xpos * self.barwidth
x1 = x0 + self.barwidth
y0 = self.gheight
y1 = ( 1 - percent ) * self.gheight
c.create_rectangle( x0 , y0, x1, y1, fill='green' )
self.xpos += 1
self.updateScrollRegions()
self.graph.xview( 'moveto', '1.0' )
def clear( self ):
"Clear graph contents."
self.graph.delete( 'all' )
self.xpos = 0
def test( self ):
"Add a bar for testing purposes."
ms = 1000
if self.xpos < 10:
self.addBar( self.xpos / 10 * self.ymax )
self.after( ms, self.test )
def setTitle( self, text ):
"Set graph title"
self.title.configure( text=text, font='Helvetica 9 bold' )
class ConsoleApp( Frame ):
"Simple Tk consoles for Mininet."
menuStyle = { 'font': 'Geneva 7 bold' }
def __init__( self, net, parent=None, width=4 ):
Frame.__init__( self, parent )
self.top = self.winfo_toplevel()
self.top.title( 'Mininet' )
self.net = net
self.menubar = self.createMenuBar()
cframe = self.cframe = Frame( self )
self.consoles = {} # consoles themselves
titles = {
'hosts': 'Host',
'switches': 'Switch',
'controllers': 'Controller'
}
for name in titles:
nodes = getattr( net, name )
frame, consoles = self.createConsoles(
cframe, nodes, width, titles[ name ] )
self.consoles[ name ] = Object( frame=frame, consoles=consoles )
self.selected = None
self.select( 'hosts' )
self.cframe.pack( expand=True, fill='both' )
cleanUpScreens()
# Close window gracefully
Wm.wm_protocol( self.top, name='WM_DELETE_WINDOW', func=self.quit )
# Initialize graph
graph = Graph( cframe )
self.consoles[ 'graph' ] = Object( frame=graph, consoles=[ graph ] )
self.graph = graph
self.graphVisible = False
self.updates = 0
self.hostCount = len( self.consoles[ 'hosts' ].consoles )
self.bw = 0
self.pack( expand=True, fill='both' )
def updateGraph( self, _console, output ):
"Update our graph."
m = re.search( r'(\d+) Mbits/sec', output )
if not m:
return
self.updates += 1
self.bw += .001 * float( m.group( 1 ) )
if self.updates >= self.hostCount:
self.graph.addBar( self.bw )
self.bw = 0
self.updates = 0
def setOutputHook( self, fn=None, consoles=None ):
"Register fn as output hook [on specific consoles.]"
if consoles is None:
consoles = self.consoles[ 'hosts' ].consoles
for console in consoles:
console.outputHook = fn
def createConsoles( self, parent, nodes, width, title ):
"Create a grid of consoles in a frame."
f = Frame( parent )
# Create consoles
consoles = []
index = 0
for node in nodes:
console = Console( f, self.net, node, title=title )
consoles.append( console )
row = index / width
column = index % width
console.grid( row=row, column=column, sticky='nsew' )
index += 1
f.rowconfigure( row, weight=1 )
f.columnconfigure( column, weight=1 )
return f, consoles
def select( self, groupName ):
"Select a group of consoles to display."
if self.selected is not None:
self.selected.frame.pack_forget()
self.selected = self.consoles[ groupName ]
self.selected.frame.pack( expand=True, fill='both' )
def createMenuBar( self ):
"Create and return a menu (really button) bar."
f = Frame( self )
buttons = [
( 'Hosts', lambda: self.select( 'hosts' ) ),
( 'Switches', lambda: self.select( 'switches' ) ),
( 'Controllers', lambda: self.select( 'controllers' ) ),
( 'Graph', lambda: self.select( 'graph' ) ),
( 'Ping', self.ping ),
( 'Iperf', self.iperf ),
( 'Interrupt', self.stop ),
( 'Clear', self.clear ),
( 'Quit', self.quit )
]
for name, cmd in buttons:
b = Button( f, text=name, command=cmd, **self.menuStyle )
b.pack( side='left' )
f.pack( padx=4, pady=4, fill='x' )
return f
def clear( self ):
"Clear selection."
for console in self.selected.consoles:
console.clear()
def waiting( self, consoles=None ):
"Are any of our hosts waiting for output?"
if consoles is None:
consoles = self.consoles[ 'hosts' ].consoles
for console in consoles:
if console.waiting():
return True
return False
def ping( self ):
"Tell each host to ping the next one."
consoles = self.consoles[ 'hosts' ].consoles
if self.waiting( consoles ):
return
count = len( consoles )
i = 0
for console in consoles:
i = ( i + 1 ) % count
ip = consoles[ i ].node.IP()
console.sendCmd( 'ping ' + ip )
def iperf( self ):
"Tell each host to iperf to the next one."
consoles = self.consoles[ 'hosts' ].consoles
if self.waiting( consoles ):
return
count = len( consoles )
self.setOutputHook( self.updateGraph )
for console in consoles:
console.node.cmd( 'iperf -sD' )
i = 0
for console in consoles:
i = ( i + 1 ) % count
ip = consoles[ i ].node.IP()
console.sendCmd( 'iperf -t 99999 -i 1 -c ' + ip )
def stop( self, wait=True ):
"Interrupt all hosts."
consoles = self.consoles[ 'hosts' ].consoles
for console in consoles:
console.handleInt()
if wait:
for console in consoles:
console.waitOutput()
self.setOutputHook( None )
# Shut down any iperfs that might still be running
quietRun( 'killall -9 iperf' )
def quit( self ):
"Stop everything and quit."
self.stop( wait=False)
Frame.quit( self )
# Make it easier to construct and assign objects
def assign( obj, **kwargs ):
"Set a bunch of fields in an object."
obj.__dict__.update( kwargs )
class Object( object ):
"Generic object you can stuff junk into."
def __init__( self, **kwargs ):
assign( self, **kwargs )
if __name__ == '__main__':
setLogLevel( 'info' )
network = TreeNet( depth=2, fanout=4 )
network.start()
app = ConsoleApp( network, width=4 )
app.mainloop()
network.stop()
-70
View File
@@ -1,70 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from time import sleep
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
"""
This example demonstrates a basic consumer-producer using Mini-NDN. It uses ndnpeek and ndnpoke as
a consumer and a producer respectively. If you want to build your own consumer/producer program, you
can take help from here: https://github.com/named-data/ndn-cxx/tree/master/examples and
here: https://github.com/dulalsaurab/multicast-supression-ndn/tree/main/ndn-src/consumer-producer
"""
if __name__ == '__main__':
setLogLevel('info')
Minindn.cleanUp()
Minindn.verifyDependencies()
ndn = Minindn()
ndn.start()
info('Starting nfd and nlsr on nodes')
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr)
sleep(90)
# Default topology is used in this experiment "/topologies/default-topology.conf"
# lets make node "a" as a producer node, and node "c" as a consumer node
producer = ndn.net['a']
consumer = ndn.net['c']
# start producer
producerPrefix = "/example"
producer.cmd('nlsrc advertise {}'.format(producerPrefix))
sleep(5) # sleep for routing convergence
# Make sure that basic consumer/producer example are compiled and installed in the system
info('Starting consumer and producer application')
producer.cmd("echo 'HELLO WORLD' | ndnpoke {} &> producer.log &".format(producerPrefix))
consumer.cmd("ndnpeek -p {} &> consumer.log &".format(producerPrefix))
MiniNDNCLI(ndn.net)
ndn.stop()
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/python
"""
This example creates a multi-controller network from
semi-scratch; note a topo object could also be used and
would be passed into the Mininet() constructor.
"""
from mininet.net import Mininet
from mininet.node import Controller, OVSKernelSwitch
from mininet.cli import CLI
from mininet.log import setLogLevel
Switch = OVSKernelSwitch
def addHost( net, N ):
"Create host hN and add to net."
name = 'h%d' % N
ip = '10.0.0.%d' % N
return net.addHost( name, ip=ip )
def multiControllerNet():
"Create a network with multiple controllers."
net = Mininet( controller=Controller, switch=Switch)
print "*** Creating controllers"
c1 = net.addController( 'c1', port=6633 )
c2 = net.addController( 'c2', port=6634 )
print "*** Creating switches"
s1 = net.addSwitch( 's1' )
s2 = net.addSwitch( 's2' )
print "*** Creating hosts"
hosts1 = [ addHost( net, n ) for n in 3, 4 ]
hosts2 = [ addHost( net, n ) for n in 5, 6 ]
print "*** Creating links"
for h in hosts1:
s1.linkTo( h )
for h in hosts2:
s2.linkTo( h )
s1.linkTo( s2 )
print "*** Starting network"
net.build()
c1.start()
c2.start()
s1.start( [ c1 ] )
s2.start( [ c2 ] )
print "*** Testing network"
net.pingAll()
print "*** Running CLI"
CLI( net )
print "*** Stopping network"
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' ) # for CLI output
multiControllerNet()
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/python
"""
cpu.py: test iperf bandwidth for varying cpu limtis
"""
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.topolib import TreeTopo
from mininet.util import custom
from mininet.log import setLogLevel, output
from time import sleep
def waitListening(client, server, port):
"Wait until server is listening on port"
if not client.cmd('which telnet'):
raise Exception('Could not find telnet')
cmd = ('sh -c "echo A | telnet -e A %s %s"' %
(server.IP(), port))
while 'Connected' not in client.cmd(cmd):
output('waiting for', server,
'to listen on port', port, '\n')
sleep(.5)
def bwtest( cpuLimits, period_us=100000, seconds=5 ):
"""Example/test of link and CPU bandwidth limits
cpu: cpu limit as fraction of overall CPU time"""
topo = TreeTopo( depth=1, fanout=2 )
results = {}
for sched in 'rt', 'cfs':
print '*** Testing with', sched, 'bandwidth limiting'
for cpu in cpuLimits:
host = custom( CPULimitedHost, sched=sched,
period_us=period_us,
cpu=cpu )
net = Mininet( topo=topo, host=host )
net.start()
net.pingAll()
hosts = [ net.getNodeByName( h ) for h in topo.hosts() ]
client, server = hosts[ 0 ], hosts[ -1 ]
server.cmd( 'iperf -s -p 5001 &' )
waitListening( client, server, 5001 )
result = client.cmd( 'iperf -yc -t %s -c %s' % (
seconds, server.IP() ) ).split( ',' )
bps = float( result[ -1 ] )
server.cmdPrint( 'kill %iperf' )
net.stop()
updated = results.get( sched, [] )
updated += [ ( cpu, bps ) ]
results[ sched ] = updated
return results
def dump( results ):
"Dump results"
fmt = '%s\t%s\t%s'
print
print fmt % ( 'sched', 'cpu', 'client MB/s' )
print
for sched in sorted( results.keys() ):
entries = results[ sched ]
for cpu, bps in entries:
pct = '%.2f%%' % ( cpu * 100 )
mbps = bps / 1e6
print fmt % ( sched, pct, mbps )
if __name__ == '__main__':
setLogLevel( 'info' )
limits = [ .45, .4, .3, .2, .1 ]
out = bwtest( limits )
dump( out )
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/python
"""
This example shows how to create an empty Mininet object
(without a topology object) and add nodes to it manually.
"""
from mininet.net import Mininet
from mininet.node import Controller
from mininet.cli import CLI
from mininet.log import setLogLevel, info
def emptyNet():
"Create an empty network and add nodes to it."
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' )
info( '*** Adding switch\n' )
s3 = net.addSwitch( 's3' )
info( '*** Creating links\n' )
h1.linkTo( s3 )
h2.linkTo( s3 )
info( '*** Starting network\n')
net.start()
info( '*** Running CLI\n' )
CLI( net )
info( '*** Stopping network' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
emptyNet()
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/python
"""
This example shows how to add an interface (for example a real
hardware interface) to a network after the network is created.
"""
import re
from mininet.cli import CLI
from mininet.log import setLogLevel, info, error
from mininet.net import Mininet
from mininet.topolib import TreeTopo
from mininet.util import quietRun
def checkIntf( intf ):
"Make sure intf exists and is not configured."
if ( ' %s:' % intf ) not in quietRun( 'ip link show' ):
error( 'Error:', intf, 'does not exist!\n' )
exit( 1 )
ips = re.findall( r'\d+\.\d+\.\d+\.\d+', quietRun( 'ifconfig ' + intf ) )
if ips:
error( 'Error:', intf, 'has an IP address,'
'and is probably in use!\n' )
exit( 1 )
if __name__ == '__main__':
setLogLevel( 'info' )
newIntf = 'eth1'
info( '*** Checking', newIntf, '\n' )
checkIntf( newIntf )
info( '*** Creating network\n' )
net = Mininet( topo=TreeTopo( depth=1, fanout=2 ) )
switch = net.switches[ 0 ]
info( '*** Adding', newIntf, 'to switch', switch.name, '\n' )
switch.addIntf( newIntf )
net.start()
CLI( net )
net.stop()
-62
View File
@@ -1,62 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.helpers.ip_routing_helper import IPRoutingHelper
"""
This scenario demonstrates the functionality of the IPRoutingHelper. First, the routing helper
calculates and configures routes between all nodes and then calls the `pingAll` command to
demonstrate that all nodes are reachable.
Successful experiments end with: `*** Results: 0% dropped`
To demonstrate the IPRoutingHelper in more complex scenarios, consider starting the experiment with
the Geant-Topology (topologies/geant.conf).
"""
if __name__ == '__main__':
setLogLevel('info')
Minindn.cleanUp()
Minindn.verifyDependencies()
ndn = Minindn()
ndn.start()
info('Starting NFD on nodes\n')
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
info('Starting NLSR on nodes\n')
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr)
# Calculate all routes for IP routing
IPRoutingHelper.calcAllRoutes(ndn.net)
info("IP routes configured, start ping\n")
ndn.net.pingAll()
ndn.stop()
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/python
"""
limit.py: example of using link and CPU limits
"""
from mininet.net import Mininet
from mininet.link import TCIntf
from mininet.node import CPULimitedHost
from mininet.topolib import TreeTopo
from mininet.util import custom, quietRun
from mininet.log import setLogLevel
from time import sleep
def testLinkLimit( net, bw ):
"Run bandwidth limit test"
print '*** Testing network %.2f Mbps bandwidth limit' % bw
net.iperf( )
def testCpuLimit( net, cpu ):
"run CPU limit test"
pct = cpu * 100
print '*** Testing CPU %.0f%% bandwidth limit' % pct
h1, h2 = net.hosts
h1.cmd( 'while true; do a=1; done &' )
h2.cmd( 'while true; do a=1; done &' )
pid1 = h1.cmd( 'echo $!' ).strip()
pid2 = h2.cmd( 'echo $!' ).strip()
cmd = 'ps -p %s,%s -o pid,%%cpu,args' % ( pid1, pid2 )
# It's a shame that this is what pylint prefers
for _ in range( 5 ):
sleep( 1 )
print quietRun( cmd ).strip()
h1.cmd( 'kill %1')
h2.cmd( 'kill %1')
def limit( bw=10, cpu=.4 ):
"""Example/test of link and CPU bandwidth limits
bw: interface bandwidth limit in Mbps
cpu: cpu limit as fraction of overall CPU time"""
intf = custom( TCIntf, bw=bw )
myTopo = TreeTopo( depth=1, fanout=2 )
for sched in 'rt', 'cfs':
print '*** Testing with', sched, 'bandwidth limiting'
host = custom( CPULimitedHost, sched=sched, cpu=cpu )
net = Mininet( topo=myTopo, intf=intf, host=host )
net.start()
testLinkLimit( net, bw=bw )
testCpuLimit( net, cpu=cpu )
net.stop()
def verySimpleLimit( bw=150 ):
"Absurdly simple limiting test"
intf = custom( TCIntf, bw=bw )
net = Mininet( intf=intf )
h1, h2 = net.addHost( 'h1' ), net.addHost( 'h2' )
net.addLink( h1, h2 )
net.start()
net.pingAll()
net.iperf()
h1.cmdPrint( 'tc -s qdisc ls dev', h1.defaultIntf() )
h2.cmdPrint( 'tc -d class show dev', h2.defaultIntf() )
h1.cmdPrint( 'tc -s qdisc ls dev', h1.defaultIntf() )
h2.cmdPrint( 'tc -d class show dev', h2.defaultIntf() )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
limit()
+110
View File
@@ -0,0 +1,110 @@
#!/usr/bin/python
"""
Test bandwidth (using iperf) on linear networks of varying size,
using both kernel and user datapaths.
We construct a network of N hosts and N-1 switches, connected as follows:
h1 <-> s1 <-> s2 .. sN-1
| | |
h2 h3 hN
WARNING: by default, the reference controller only supports 16
switches, so this test WILL NOT WORK unless you have recompiled
your controller to support 100 switches (or more.)
In addition to testing the bandwidth across varying numbers
of switches, this example demonstrates:
- creating a custom topology, LinearTestTopo
- using the ping() and iperf() tests from Mininet()
- testing both the kernel and user switches
"""
from mininet.net import Mininet
from mininet.node import UserSwitch, OVSKernelSwitch
from mininet.topo import Topo
from mininet.log import lg
from mininet.util import irange
import sys
flush = sys.stdout.flush
class LinearTestTopo( Topo ):
"Topology for a string of N hosts and N-1 switches."
def __init__( self, N, **params ):
# Initialize topology
Topo.__init__( self, **params )
# Create switches and hosts
hosts = [ self.add_host( 'h%s' % h )
for h in irange( 1, N ) ]
switches = [ self.add_switch( 's%s' % s )
for s in irange( 1, N - 1 ) ]
# Wire up switches
last = None
for switch in switches:
if last:
self.add_link( last, switch )
last = switch
# Wire up hosts
self.add_link( hosts[ 0 ], switches[ 0 ] )
for host, switch in zip( hosts[ 1: ], switches ):
self.add_link( host, switch )
def linearBandwidthTest( lengths ):
"Check bandwidth at various lengths along a switch chain."
results = {}
switchCount = max( lengths )
hostCount = switchCount + 1
switches = { 'reference user': UserSwitch,
'Open vSwitch kernel': OVSKernelSwitch }
topo = LinearTestTopo( hostCount )
for datapath in switches.keys():
print "*** testing", datapath, "datapath"
Switch = switches[ datapath ]
results[ datapath ] = []
net = Mininet( topo=topo, switch=Switch )
net.start()
print "*** testing basic connectivity"
for n in lengths:
net.ping( [ net.hosts[ 0 ], net.hosts[ n ] ] )
print "*** testing bandwidth"
for n in lengths:
src, dst = net.hosts[ 0 ], net.hosts[ n ]
print "testing", src.name, "<->", dst.name,
bandwidth = net.iperf( [ src, dst ] )
print bandwidth
flush()
results[ datapath ] += [ ( n, bandwidth ) ]
net.stop()
for datapath in switches.keys():
print
print "*** Linear network results for", datapath, "datapath:"
print
result = results[ datapath ]
print "SwitchCount\tiperf Results"
for switchCount, bandwidth in result:
print switchCount, '\t\t',
print bandwidth[ 0 ], 'server, ', bandwidth[ 1 ], 'client'
print
print
if __name__ == '__main__':
lg.setLogLevel( 'info' )
sizes = [ 1, 10, 20, 40, 60, 80, 100 ]
print "*** Running linearBandwidthTest", sizes
linearBandwidthTest( sizes )
+703
View File
@@ -0,0 +1,703 @@
#!/usr/bin/python
"""
MiniEdit: a simple network editor for Mininet
This is a simple demonstration of how one might build a
GUI application using Mininet as the network model.
Development version - not entirely functional!
Bob Lantz, April 2010
"""
from Tkinter import Frame, Button, Label, Scrollbar, Canvas
from Tkinter import Menu, BitmapImage, PhotoImage, Wm, Toplevel
# someday: from ttk import *
from mininet.log import setLogLevel
from mininet.net import Mininet
from mininet.util import ipStr
from mininet.term import makeTerm, cleanUpScreens
class MiniEdit( Frame ):
"A simple network editor for Mininet."
def __init__( self, parent=None, cheight=200, cwidth=500 ):
Frame.__init__( self, parent )
self.action = None
self.appName = 'MiniEdit'
# Style
self.font = ( 'Geneva', 9 )
self.smallFont = ( 'Geneva', 7 )
self.bg = 'white'
# Title
self.top = self.winfo_toplevel()
self.top.title( self.appName )
# Menu bar
self.createMenubar()
# Editing canvas
self.cheight, self.cwidth = cheight, cwidth
self.cframe, self.canvas = self.createCanvas()
# Toolbar
self.images = miniEditImages()
self.buttons = {}
self.active = None
self.tools = ( 'Select', 'Host', 'Switch', 'Link' )
self.customColors = { 'Switch': 'darkGreen', 'Host': 'blue' }
self.toolbar = self.createToolbar()
# Layout
self.toolbar.grid( column=0, row=0, sticky='nsew')
self.cframe.grid( column=1, row=0 )
self.columnconfigure( 1, weight=1 )
self.rowconfigure( 0, weight=1 )
self.pack( expand=True, fill='both' )
# About box
self.aboutBox = None
# Initialize node data
self.nodeBindings = self.createNodeBindings()
self.nodePrefixes = { 'Switch': 's', 'Host': 'h' }
self.widgetToItem = {}
self.itemToWidget = {}
# Initialize link tool
self.link = self.linkWidget = None
# Selection support
self.selection = None
# Keyboard bindings
self.bind( '<Control-q>', lambda event: self.quit() )
self.bind( '<KeyPress-Delete>', self.deleteSelection )
self.bind( '<KeyPress-BackSpace>', self.deleteSelection )
self.focus()
# Event handling initalization
self.linkx = self.linky = self.linkItem = None
self.lastSelection = None
# Model initialization
self.links = {}
self.nodeCount = 0
self.net = None
# Close window gracefully
Wm.wm_protocol( self.top, name='WM_DELETE_WINDOW', func=self.quit )
def quit( self ):
"Stop our network, if any, then quit."
self.stop()
Frame.quit( self )
def createMenubar( self ):
"Create our menu bar."
font = self.font
mbar = Menu( self.top, font=font )
self.top.configure( menu=mbar )
# Application menu
appMenu = Menu( mbar, tearoff=False )
mbar.add_cascade( label=self.appName, font=font, menu=appMenu )
appMenu.add_command( label='About MiniEdit', command=self.about,
font=font)
appMenu.add_separator()
appMenu.add_command( label='Quit', command=self.quit, font=font )
#fileMenu = Menu( mbar, tearoff=False )
#mbar.add_cascade( label="File", font=font, menu=fileMenu )
#fileMenu.add_command( label="Load...", font=font )
#fileMenu.add_separator()
#fileMenu.add_command( label="Save", font=font )
#fileMenu.add_separator()
#fileMenu.add_command( label="Print", font=font )
editMenu = Menu( mbar, tearoff=False )
mbar.add_cascade( label="Edit", font=font, menu=editMenu )
editMenu.add_command( label="Cut", font=font,
command=lambda: self.deleteSelection( None ) )
runMenu = Menu( mbar, tearoff=False )
mbar.add_cascade( label="Run", font=font, menu=runMenu )
runMenu.add_command( label="Run", font=font, command=self.doRun )
runMenu.add_command( label="Stop", font=font, command=self.doStop )
runMenu.add_separator()
runMenu.add_command( label='Xterm', font=font, command=self.xterm )
# Canvas
def createCanvas( self ):
"Create and return our scrolling canvas frame."
f = Frame( self )
canvas = Canvas( f, width=self.cwidth, height=self.cheight,
bg=self.bg )
# Scroll bars
xbar = Scrollbar( f, orient='horizontal', command=canvas.xview )
ybar = Scrollbar( f, orient='vertical', command=canvas.yview )
canvas.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set )
# Resize box
resize = Label( f, bg='white' )
# Layout
canvas.grid( row=0, column=1, sticky='nsew')
ybar.grid( row=0, column=2, sticky='ns')
xbar.grid( row=1, column=1, sticky='ew' )
resize.grid( row=1, column=2, sticky='nsew' )
# Resize behavior
f.rowconfigure( 0, weight=1 )
f.columnconfigure( 1, weight=1 )
f.grid( row=0, column=0, sticky='nsew' )
f.bind( '<Configure>', lambda event: self.updateScrollRegion() )
# Mouse bindings
canvas.bind( '<ButtonPress-1>', self.clickCanvas )
canvas.bind( '<B1-Motion>', self.dragCanvas )
canvas.bind( '<ButtonRelease-1>', self.releaseCanvas )
return f, canvas
def updateScrollRegion( self ):
"Update canvas scroll region to hold everything."
bbox = self.canvas.bbox( 'all' )
if bbox is not None:
self.canvas.configure( scrollregion=( 0, 0, bbox[ 2 ],
bbox[ 3 ] ) )
def canvasx( self, x_root ):
"Convert root x coordinate to canvas coordinate."
c = self.canvas
return c.canvasx( x_root ) - c.winfo_rootx()
def canvasy( self, y_root ):
"Convert root y coordinate to canvas coordinate."
c = self.canvas
return c.canvasy( y_root ) - c.winfo_rooty()
# Toolbar
def activate( self, toolName ):
"Activate a tool and press its button."
# Adjust button appearance
if self.active:
self.buttons[ self.active ].configure( relief='raised' )
self.buttons[ toolName ].configure( relief='sunken' )
# Activate dynamic bindings
self.active = toolName
def createToolbar( self ):
"Create and return our toolbar frame."
toolbar = Frame( self )
# Tools
for tool in self.tools:
cmd = ( lambda t=tool: self.activate( t ) )
b = Button( toolbar, text=tool, font=self.smallFont, command=cmd)
if tool in self.images:
b.config( height=35, image=self.images[ tool ] )
# b.config( compound='top' )
b.pack( fill='x' )
self.buttons[ tool ] = b
self.activate( self.tools[ 0 ] )
# Spacer
Label( toolbar, text='' ).pack()
# Commands
for cmd, color in [ ( 'Stop', 'darkRed' ), ( 'Run', 'darkGreen' ) ]:
doCmd = getattr( self, 'do' + cmd )
b = Button( toolbar, text=cmd, font=self.smallFont,
fg=color, command=doCmd )
b.pack( fill='x', side='bottom' )
return toolbar
def doRun( self ):
"Run command."
self.activate( 'Select' )
for tool in self.tools:
self.buttons[ tool ].config( state='disabled' )
self.start()
def doStop( self ):
"Stop command."
self.stop()
for tool in self.tools:
self.buttons[ tool ].config( state='normal' )
# Generic canvas handler
#
# We could have used bindtags, as in nodeIcon, but
# the dynamic approach used here
# may actually require less code. In any case, it's an
# interesting introspection-based alternative to bindtags.
def canvasHandle( self, eventName, event ):
"Generic canvas event handler"
if self.active is None:
return
toolName = self.active
handler = getattr( self, eventName + toolName, None )
if handler is not None:
handler( event )
def clickCanvas( self, event ):
"Canvas click handler."
self.canvasHandle( 'click', event )
def dragCanvas( self, event ):
"Canvas drag handler."
self.canvasHandle( 'drag', event )
def releaseCanvas( self, event ):
"Canvas mouse up handler."
self.canvasHandle( 'release', event )
# Currently the only items we can select directly are
# links. Nodes are handled by bindings in the node icon.
def findItem( self, x, y ):
"Find items at a location in our canvas."
items = self.canvas.find_overlapping( x, y, x, y )
if len( items ) == 0:
return None
else:
return items[ 0 ]
# Canvas bindings for Select, Host, Switch and Link tools
def clickSelect( self, event ):
"Select an item."
self.selectItem( self.findItem( event.x, event.y ) )
def deleteItem( self, item ):
"Delete an item."
# Don't delete while network is running
if self.buttons[ 'Select' ][ 'state' ] == 'disabled' :
return
# Delete from model
if item in self.links:
self.deleteLink( item )
if item in self.itemToWidget:
self.deleteNode( item )
# Delete from view
self.canvas.delete( item )
def deleteSelection( self, _event ):
"Delete the selected item."
if self.selection is not None:
self.deleteItem( self.selection )
self.selectItem( None )
def nodeIcon( self, node, name ):
"Create a new node icon."
icon = Button( self.canvas, image=self.images[ node ],
text=name, compound='top' )
# Unfortunately bindtags wants a tuple
bindtags = [ str( self.nodeBindings ) ]
bindtags += list( icon.bindtags() )
icon.bindtags( tuple( bindtags ) )
return icon
def newNode( self, node, event ):
"Add a new node to our canvas."
c = self.canvas
x, y = c.canvasx( event.x ), c.canvasy( event.y )
self.nodeCount += 1
name = self.nodePrefixes[ node ] + str( self.nodeCount )
icon = self.nodeIcon( node, name )
item = self.canvas.create_window( x, y, anchor='c',
window=icon, tags=node )
self.widgetToItem[ icon ] = item
self.itemToWidget[ item ] = icon
self.selectItem( item )
icon.links = {}
def clickHost( self, event ):
"Add a new host to our canvas."
self.newNode( 'Host', event )
def clickSwitch( self, event ):
"Add a new switch to our canvas."
self.newNode( 'Switch', event )
def dragLink( self, event ):
"Drag a link's endpoint to another node."
if self.link is None:
return
# Since drag starts in widget, we use root coords
x = self.canvasx( event.x_root )
y = self.canvasy( event.y_root )
c = self.canvas
c.coords( self.link, self.linkx, self.linky, x, y )
def releaseLink( self, _event ):
"Give up on the current link."
if self.link is not None:
self.canvas.delete( self.link )
self.linkWidget = self.linkItem = self.link = None
# Generic node handlers
def createNodeBindings( self ):
"Create a set of bindings for nodes."
bindings = {
'<ButtonPress-1>': self.clickNode,
'<B1-Motion>': self.dragNode,
'<ButtonRelease-1>': self.releaseNode,
'<Enter>': self.enterNode,
'<Leave>': self.leaveNode,
'<Double-ButtonPress-1>': self.xterm
}
l = Label() # lightweight-ish owner for bindings
for event, binding in bindings.items():
l.bind( event, binding )
return l
def selectItem( self, item ):
"Select an item and remember old selection."
self.lastSelection = self.selection
self.selection = item
def enterNode( self, event ):
"Select node on entry."
self.selectNode( event )
def leaveNode( self, _event ):
"Restore old selection on exit."
self.selectItem( self.lastSelection )
def clickNode( self, event ):
"Node click handler."
if self.active is 'Link':
self.startLink( event )
else:
self.selectNode( event )
return 'break'
def dragNode( self, event ):
"Node drag handler."
if self.active is 'Link':
self.dragLink( event )
else:
self.dragNodeAround( event )
def releaseNode( self, event ):
"Node release handler."
if self.active is 'Link':
self.finishLink( event )
# Specific node handlers
def selectNode( self, event ):
"Select the node that was clicked on."
item = self.widgetToItem.get( event.widget, None )
self.selectItem( item )
def dragNodeAround( self, event ):
"Drag a node around on the canvas."
c = self.canvas
# Convert global to local coordinates;
# Necessary since x, y are widget-relative
x = self.canvasx( event.x_root )
y = self.canvasy( event.y_root )
w = event.widget
# Adjust node position
item = self.widgetToItem[ w ]
c.coords( item, x, y )
# Adjust link positions
for dest in w.links:
link = w.links[ dest ]
item = self.widgetToItem[ dest ]
x1, y1 = c.coords( item )
c.coords( link, x, y, x1, y1 )
def startLink( self, event ):
"Start a new link."
if event.widget not in self.widgetToItem:
# Didn't click on a node
return
w = event.widget
item = self.widgetToItem[ w ]
x, y = self.canvas.coords( item )
self.link = self.canvas.create_line( x, y, x, y, width=4,
fill='blue', tag='link' )
self.linkx, self.linky = x, y
self.linkWidget = w
self.linkItem = item
# Link bindings
# Selection still needs a bit of work overall
# Callbacks ignore event
def select( _event, link=self.link ):
"Select item on mouse entry."
self.selectItem( link )
def highlight( _event, link=self.link ):
"Highlight item on mouse entry."
# self.selectItem( link )
self.canvas.itemconfig( link, fill='green' )
def unhighlight( _event, link=self.link ):
"Unhighlight item on mouse exit."
self.canvas.itemconfig( link, fill='blue' )
# self.selectItem( None )
self.canvas.tag_bind( self.link, '<Enter>', highlight )
self.canvas.tag_bind( self.link, '<Leave>', unhighlight )
self.canvas.tag_bind( self.link, '<ButtonPress-1>', select )
def finishLink( self, event ):
"Finish creating a link"
if self.link is None:
return
source = self.linkWidget
c = self.canvas
# Since we dragged from the widget, use root coords
x, y = self.canvasx( event.x_root ), self.canvasy( event.y_root )
target = self.findItem( x, y )
dest = self.itemToWidget.get( target, None )
if ( source is None or dest is None or source == dest
or dest in source.links or source in dest.links ):
self.releaseLink( event )
return
# For now, don't allow hosts to be directly linked
stags = self.canvas.gettags( self.widgetToItem[ source ] )
dtags = self.canvas.gettags( target )
if 'Host' in stags and 'Host' in dtags:
self.releaseLink( event )
return
x, y = c.coords( target )
c.coords( self.link, self.linkx, self.linky, x, y )
self.addLink( source, dest )
# We're done
self.link = self.linkWidget = None
# Menu handlers
def about( self ):
"Display about box."
about = self.aboutBox
if about is None:
bg = 'white'
about = Toplevel( bg='white' )
about.title( 'About' )
info = self.appName + ': a simple network editor for MiniNet'
warning = 'Development version - not entirely functional!'
author = 'Bob Lantz <rlantz@cs>, April 2010'
line1 = Label( about, text=info, font='Helvetica 10 bold', bg=bg )
line2 = Label( about, text=warning, font='Helvetica 9', bg=bg )
line3 = Label( about, text=author, font='Helvetica 9', bg=bg )
line1.pack( padx=20, pady=10 )
line2.pack(pady=10 )
line3.pack(pady=10 )
hide = ( lambda about=about: about.withdraw() )
self.aboutBox = about
# Hide on close rather than destroying window
Wm.wm_protocol( about, name='WM_DELETE_WINDOW', func=hide )
# Show (existing) window
about.deiconify()
def createToolImages( self ):
"Create toolbar (and icon) images."
# Model interface
#
# Ultimately we will either want to use a topo or
# mininet object here, probably.
def addLink( self, source, dest ):
"Add link to model."
source.links[ dest ] = self.link
dest.links[ source ] = self.link
self.links[ self.link ] = ( source, dest )
def deleteLink( self, link ):
"Delete link from model."
pair = self.links.get( link, None )
if pair is not None:
source, dest = pair
del source.links[ dest ]
del dest.links[ source ]
if link is not None:
del self.links[ link ]
def deleteNode( self, item ):
"Delete node (and its links) from model."
widget = self.itemToWidget[ item ]
for link in widget.links.values():
# Delete from view and model
self.deleteItem( link )
del self.itemToWidget[ item ]
del self.widgetToItem[ widget ]
def build( self ):
"Build network based on our topology."
net = Mininet( topo=None )
# Make controller
net.addController( 'c0' )
# Make nodes
for widget in self.widgetToItem:
name = widget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
nodeNum = int( name[ 1: ] )
if 'Switch' in tags:
net.addSwitch( name )
elif 'Host' in tags:
net.addHost( name, ip=ipStr( nodeNum ) )
else:
raise Exception( "Cannot create mystery node: " + name )
# Make links
for link in self.links.values():
( src, dst ) = link
srcName, dstName = src[ 'text' ], dst[ 'text' ]
src, dst = net.nameToNode[ srcName ], net.nameToNode[ dstName ]
src.linkTo( dst )
# Build network (we have to do this separately at the moment )
net.build()
return net
def start( self ):
"Start network."
if self.net is None:
self.net = self.build()
self.net.start()
def stop( self ):
"Stop network."
if self.net is not None:
self.net.stop()
cleanUpScreens()
self.net = None
def xterm( self, _=None ):
"Make an xterm when a button is pressed."
if ( self.selection is None or
self.net is None or
self.selection not in self.itemToWidget ):
return
name = self.itemToWidget[ self.selection ][ 'text' ]
if name not in self.net.nameToNode:
return
term = makeTerm( self.net.nameToNode[ name ], 'Host' )
self.net.terms.append( term )
def miniEditImages():
"Create and return images for MiniEdit."
# Image data. Git will be unhappy. However, the alternative
# is to keep track of separate binary files, which is also
# unappealing.
return {
'Select': BitmapImage(
file='/usr/include/X11/bitmaps/left_ptr' ),
'Host': PhotoImage( data=r"""
R0lGODlhIAAYAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
M/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zM
AMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz
/8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswAM8wAAJn//5n/
zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZzJmZ
mZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkz
ZpkzM5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/
M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZ
AGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA
/2YAzGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPM
zDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZMzOZADNm/zNmzDNm
mTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMAzDMAmTMA
ZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBm
AAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0A
ALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAA
RAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3d1VVVURERCIiIhEREQAA
ACH5BAEAAAAALAAAAAAgABgAAAiNAAH8G0iwoMGDCAcKTMiw4UBw
BPXVm0ixosWLFvVBHFjPoUeC9Tb+6/jRY0iQ/8iVbHiS40CVKxG2
HEkQZsyCM0mmvGkw50uePUV2tEnOZkyfQA8iTYpTKNOgKJ+C3AhO
p9SWVaVOfWj1KdauTL9q5UgVbFKsEjGqXVtP40NwcBnCjXtw7tx/
C8cSBBAQADs=
""" ),
'Switch': PhotoImage( data=r"""
R0lGODlhIAAYAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
M/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zM
AMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz
/8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswAM8wAAJn//5n/
zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZzJmZ
mZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkz
ZpkzM5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/
M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZ
AGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA
/2YAzGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPM
zDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZMzOZADNm/zNmzDNm
mTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMAzDMAmTMA
ZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBm
AAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0A
ALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAA
RAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3d1VVVURERCIiIhEREQAA
ACH5BAEAAAAALAAAAAAgABgAAAhwAAEIHEiwoMGDCBMqXMiwocOH
ECNKnEixosWB3zJq3Mixo0eNAL7xG0mypMmTKPl9Cznyn8uWL/m5
/AeTpsyYI1eKlBnO5r+eLYHy9Ck0J8ubPmPOrMmUpM6UUKMa/Ui1
6saLWLNq3cq1q9evYB0GBAA7
""" ),
'Link': PhotoImage( data=r"""
R0lGODlhFgAWAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
M/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zM
AMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz
/8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswAM8wAAJn//5n/
zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZzJmZ
mZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkz
ZpkzM5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/
M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZ
AGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA
/2YAzGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPM
zDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZMzOZADNm/zNmzDNm
mTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMAzDMAmTMA
ZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBm
AAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0A
ALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAA
RAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3d1VVVURERCIiIhEREQAA
ACH5BAEAAAAALAAAAAAWABYAAAhIAAEIHEiwoEGBrhIeXEgwoUKG
Cx0+hGhQoiuKBy1irChxY0GNHgeCDAlgZEiTHlFuVImRJUWXEGEy
lBmxI8mSNknm1Dnx5sCAADs=
""" )
}
if __name__ == '__main__':
setLogLevel( 'info' )
app = MiniEdit()
app.mainloop()
-49
View File
@@ -1,49 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
if __name__ == '__main__':
setLogLevel('info')
Minindn.cleanUp()
Minindn.verifyDependencies()
ndn = Minindn()
ndn.start()
info('Starting NFD on nodes\n')
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
info('Starting NLSR on nodes\n')
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr)
MiniNDNCLI(ndn.net)
ndn.stop()
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/python
"""
multiping.py: monitor multiple sets of hosts using ping
This demonstrates how one may send a simple shell script to
multiple hosts and monitor their output interactively for a period=
of time.
"""
from mininet.net import Mininet
from mininet.node import Node
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel
from select import poll, POLLIN
from time import time
def chunks( l, n ):
"Divide list l into chunks of size n - thanks Stackoverflow"
return [ l[ i : i + n ] for i in range( 0, len( l ), n ) ]
def startpings( host, targetips ):
"Tell host to repeatedly ping targets"
targetips.append( '10.0.0.200' )
targetips = ' '.join( targetips )
# BL: Not sure why loopback intf isn't up!
host.cmd( 'ifconfig lo up' )
# Simple ping loop
cmd = ( 'while true; do '
' for ip in %s; do ' % targetips +
' echo -n %s "->" $ip ' % host.IP() +
' `ping -c1 -w 1 $ip | grep packets` ;'
' sleep 1;'
' done; '
'done &' )
print ( '*** Host %s (%s) will be pinging ips: %s' %
( host.name, host.IP(), targetips ) )
host.cmd( cmd )
def multiping( netsize, chunksize, seconds):
"Ping subsets of size chunksize in net of size netsize"
# Create network and identify subnets
topo = SingleSwitchTopo( netsize )
net = Mininet( topo=topo )
net.start()
hosts = net.hosts
subnets = chunks( hosts, chunksize )
# Create polling object
fds = [ host.stdout.fileno() for host in hosts ]
poller = poll()
for fd in fds:
poller.register( fd, POLLIN )
# Start pings
for subnet in subnets:
ips = [ host.IP() for host in subnet ]
for host in subnet:
startpings( host, ips )
# Monitor output
endTime = time() + seconds
while time() < endTime:
readable = poller.poll(1000)
for fd, _mask in readable:
node = Node.outToNode[ fd ]
print '%s:' % node.name, node.monitor().strip()
# Stop pings
for host in hosts:
host.cmd( 'kill %while' )
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
multiping( netsize=20, chunksize=4, seconds=10 )
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/python
"""
Simple example of sending output to multiple files and
monitoring them
"""
from mininet.topo import SingleSwitchTopo
from mininet.net import Mininet
from mininet.log import setLogLevel
from time import time
from select import poll, POLLIN
from subprocess import Popen, PIPE
def monitorFiles( outfiles, seconds, timeoutms ):
"Monitor set of files and return [(host, line)...]"
devnull = open( '/dev/null', 'w' )
tails, fdToFile, fdToHost = {}, {}, {}
for h, outfile in outfiles.iteritems():
tail = Popen( [ 'tail', '-f', outfile ],
stdout=PIPE, stderr=devnull )
fd = tail.stdout.fileno()
tails[ h ] = tail
fdToFile[ fd ] = tail.stdout
fdToHost[ fd ] = h
# Prepare to poll output files
readable = poll()
for t in tails.values():
readable.register( t.stdout.fileno(), POLLIN )
# Run until a set number of seconds have elapsed
endTime = time() + seconds
while time() < endTime:
fdlist = readable.poll(timeoutms)
if fdlist:
for fd, _flags in fdlist:
f = fdToFile[ fd ]
host = fdToHost[ fd ]
# Wait for a line of output
line = f.readline().strip()
yield host, line
else:
# If we timed out, return nothing
yield None, ''
for t in tails.values():
t.terminate()
devnull.close() # Not really necessary
def monitorTest( N=3, seconds=3 ):
"Run pings and monitor multiple hosts"
topo = SingleSwitchTopo( N )
net = Mininet( topo )
net.start()
hosts = net.hosts
print "Starting test..."
server = hosts[ 0 ]
outfiles, errfiles = {}, {}
for h in hosts:
# Create and/or erase output files
outfiles[ h ] = '/tmp/%s.out' % h.name
errfiles[ h ] = '/tmp/%s.err' % h.name
h.cmd( 'echo >', outfiles[ h ] )
h.cmd( 'echo >', errfiles[ h ] )
# Start pings
h.cmdPrint('ping', server.IP(),
'>', outfiles[ h ],
'2>', errfiles[ h ],
'&' )
print "Monitoring output for", seconds, "seconds"
for h, line in monitorFiles( outfiles, seconds, timeoutms=500 ):
if h:
print '%s: %s' % ( h.name, line )
for h in hosts:
h.cmd('kill %ping')
net.stop()
if __name__ == '__main__':
setLogLevel('info')
monitorTest()
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/python
"""
This example shows how to create a network and run multiple tests.
For a more complicated test example, see udpbwtest.py.
"""
from mininet.cli import CLI
from mininet.log import lg, info
from mininet.net import Mininet
from mininet.node import OVSKernelSwitch
from mininet.topolib import TreeTopo
def ifconfigTest( net ):
"Run ifconfig on all hosts in net."
hosts = net.hosts
for host in hosts:
info( host.cmd( 'ifconfig' ) )
if __name__ == '__main__':
lg.setLogLevel( 'info' )
info( "*** Initializing Mininet and kernel modules\n" )
OVSKernelSwitch.setup()
info( "*** Creating network\n" )
network = Mininet( TreeTopo( depth=2, fanout=2 ), switch=OVSKernelSwitch)
info( "*** Starting network\n" )
network.start()
info( "*** Running ping test\n" )
network.pingAll()
info( "*** Running ifconfig test\n" )
ifconfigTest( network )
info( "*** Starting CLI (type 'exit' to exit)\n" )
CLI( network )
info( "*** Stopping network\n" )
network.stop()
-79
View File
@@ -1,79 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
import sys
from mininet.log import setLogLevel, info
from mininet.topo import Topo
from minindn.minindn import Minindn
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from nlsr_common import getParser
if __name__ == '__main__':
setLogLevel('info')
topo = Topo()
h1 = topo.addHost('h1')
h2 = topo.addHost('h2')
topo.addLink(h1, h2, delay='10ms')
ndn = Minindn(parser=getParser(), topo=topo)
args = ndn.args
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, [], Nlsr)
host1 = ndn.net.hosts[0]
nlsrs.startOnNode(host1, security=args.security, faceType=args.faceType,
nFaces=args.faces, routingType=args.routingType)
expectedTotalCount = 500
for i in range(0, expectedTotalCount):
host1.cmd('nlsrc advertise /long/name/to/exceed/max/packet/size/host1/{}'.format(i))
time.sleep(60)
host2 = ndn.net.hosts[1]
nlsrs.startOnNode(host2, security=args.security, faceType=args.faceType,
nFaces=args.faces, routingType=args.routingType)
time.sleep(60)
advertiseCount = int(host2.cmd('nfdc fib | grep host1 | wc -l'))
info(advertiseCount)
if advertiseCount == expectedTotalCount:
info('\nSuccessfully advertised {} prefixes\n'.format(expectedTotalCount))
else:
info('\nAdvertising {} prefixes failed. Exiting...\n'.format(expectedTotalCount))
ndn.stop()
sys.exit(1)
ndn.stop()
-64
View File
@@ -1,64 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.helpers.experiment import Experiment
from nlsr_common import getParser
if __name__ == '__main__':
setLogLevel('info')
ndn = Minindn(parser=getParser())
args = ndn.args
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, [], Nlsr)
i = 1
info('Starting NLSR on nodes\n')
for host in ndn.net.hosts:
nlsrs.startOnNode(host, security=args.security, sync=args.sync, faceType=args.faceType,
nFaces=args.faces, routingType=args.routingType)
# Wait 1/2 minute between starting NLSRs
# Wait 1 hour before starting last NLSR
if i == len(ndn.net.hosts) - 1:
info('Sleeping 1 hour before starting last NLSR\n')
time.sleep(3600)
else:
time.sleep(30)
i += 1
Experiment.checkConvergence(ndn, ndn.net.hosts, args.ctime, quit=True)
ndn.stop()
-90
View File
@@ -1,90 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.helpers.experiment import Experiment
from minindn.helpers.nfdc import Nfdc
from minindn.helpers.ndnping import NDNPing
from nlsr_common import getParser
def mcnFailure(ndn, nfds, nlsrs, args):
Experiment.checkConvergence(ndn, ndn.net.hosts, args.ctime, quit=True)
if args.nPings != 0:
Experiment.setupPing(ndn.net.hosts, Nfdc.STRATEGY_BEST_ROUTE)
pingedDict = Experiment.startPctPings(ndn.net, args.nPings, args.pctTraffic)
PING_COLLECTION_TIME_BEFORE_FAILURE = 60
PING_COLLECTION_TIME_AFTER_RECOVERY = 120
time.sleep(PING_COLLECTION_TIME_BEFORE_FAILURE)
mcn = max(ndn.net.hosts, key=lambda host: len(host.intfNames()))
info('Bringing down node {}\n'.format(mcn.name))
nlsrs[mcn.name].stop()
nfds[mcn.name].stop()
time.sleep(args.ctime)
info('Bringing up node {}\n'.format(mcn.name))
nfds[mcn.name].start()
nlsrs[mcn.name].start()
# Restart pings
if args.nPings != 0:
Experiment.setupPing([mcn], Nfdc.STRATEGY_BEST_ROUTE)
for nodeToPing in pingedDict[mcn]:
NDNPing.ping(mcn, nodeToPing, nPings=PING_COLLECTION_TIME_AFTER_RECOVERY)
time.sleep(PING_COLLECTION_TIME_AFTER_RECOVERY)
Experiment.checkConvergence(ndn, ndn.net.hosts, args.ctime, quit=True)
if __name__ == '__main__':
setLogLevel('info')
ndn = Minindn(parser=getParser())
args = ndn.args
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr, sync=args.sync,
security=args.security, faceType=args.faceType,
nFaces=args.faces, routingType=args.routingType)
mcnFailure(ndn, nfds, nlsrs, args)
if args.isCliEnabled:
MiniNDNCLI(ndn.net)
ndn.stop()
-109
View File
@@ -1,109 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.helpers.experiment import Experiment
from minindn.helpers.nfdc import Nfdc
from minindn.helpers.ndnping import NDNPing
from nlsr_common import getParser
def multipleFailure(ndn, nfds, nlsrs, args):
Experiment.checkConvergence(ndn, ndn.net.hosts, args.ctime, quit=True)
Experiment.setupPing(ndn.net.hosts, Nfdc.STRATEGY_BEST_ROUTE)
PING_COLLECTION_TIME_BEFORE_FAILURE = 60
FAILURE_INTERVAL = 60
RECOVERY_INTERVAL = 60
# Number of pings required to make it through the full experiment
nInitialPings = (PING_COLLECTION_TIME_BEFORE_FAILURE +
len(ndn.net.hosts) * (FAILURE_INTERVAL + RECOVERY_INTERVAL))
print('Scheduling with {} initial pings'.format(nInitialPings))
pingedDict = Experiment.startPctPings(ndn.net, nInitialPings, args.pctTraffic)
time.sleep(PING_COLLECTION_TIME_BEFORE_FAILURE)
nNodesRemainingToFail = len(ndn.net.hosts)
for host in ndn.net.hosts:
# Fail the node
info('Bringing down node {}\n'.format(host.name))
nlsrs[host.name].stop()
nfds[host.name].stop()
# Stay in failure state for FAILURE_INTERVAL seconds
time.sleep(FAILURE_INTERVAL)
# Bring the node back up
start_time = time.time()
info('Bringing up node {}\n'.format(host.name))
nfds[host.name].start()
nlsrs[host.name].start()
Experiment.setupPing([host], Nfdc.STRATEGY_BEST_ROUTE)
recovery_time = int(time.time() - start_time)
# Number of pings required to reach the end of the test
nNodesRemainingToFail -= 1
nPings = ((RECOVERY_INTERVAL - recovery_time) +
nNodesRemainingToFail * (FAILURE_INTERVAL + RECOVERY_INTERVAL))
info('Scheduling with {} remaining pings\n'.format(nPings))
# Restart pings
for nodeToPing in pingedDict[host]:
NDNPing.ping(host, nodeToPing, nPings=nPings)
time.sleep(RECOVERY_INTERVAL - recovery_time)
Experiment.checkConvergence(ndn, ndn.net.hosts, args.ctime, quit=True)
if __name__ == '__main__':
setLogLevel('info')
ndn = Minindn(parser=getParser())
args = ndn.args
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr, sync=args.sync,
security=args.security, faceType=args.faceType,
nFaces=args.faces, routingType=args.routingType)
multipleFailure(ndn, nfds, nlsrs, args)
if args.isCliEnabled:
MiniNDNCLI(ndn.net)
ndn.stop()
-57
View File
@@ -1,57 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import argparse
def getParser():
parser = argparse.ArgumentParser()
parser.add_argument('--ctime', type=int, default=60,
help='Specify convergence time for the topology (Default: 60 seconds)')
parser.add_argument('--faces', type=int, default=3,
help='Specify number of max faces per prefix for NLSR 0-60')
parser.add_argument('--routing', dest='routingType', default='link-state',
choices=['link-state', 'hr', 'dry'],
help='''Choose routing type, dry = link-state is used
but hr is calculated for comparision.''')
parser.add_argument('--sync', dest='sync', default='psync',
choices=['chronosync', 'psync'],
help='choose the sync protocol to be used by NLSR.')
parser.add_argument('--security', action='store_true', dest='security',
help='Enables NLSR security')
parser.add_argument('--face-type', dest='faceType', default='udp', choices=['udp', 'tcp'])
parser.add_argument('--no-cli', action='store_false', dest='isCliEnabled',
help='Run experiments and exit without showing the command line interface')
parser.add_argument('--pct-traffic', dest='pctTraffic', type=float, default=1.0,
help='Specify the percentage of nodes each node should ping')
parser.add_argument('--nPings', type=int, default=300,
help='Number of pings to perform between each node in the experiment')
return parser
-63
View File
@@ -1,63 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
from mininet.log import setLogLevel
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.helpers.experiment import Experiment
from minindn.helpers.nfdc import Nfdc
from nlsr_common import getParser
if __name__ == '__main__':
setLogLevel('info')
ndn = Minindn(parser=getParser())
args = ndn.args
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr, sync=args.sync,
security=args.security, faceType=args.faceType,
nFaces=args.faces, routingType=args.routingType,
logLevel='ndn.*=TRACE:nlsr.*=TRACE')
Experiment.checkConvergence(ndn, ndn.net.hosts, args.ctime, quit=False)
if args.nPings != 0:
Experiment.setupPing(ndn.net.hosts, Nfdc.STRATEGY_BEST_ROUTE)
Experiment.startPctPings(ndn.net, args.nPings, args.pctTraffic)
time.sleep(args.nPings + 10)
if args.isCliEnabled:
MiniNDNCLI(ndn.net)
ndn.stop()
-85
View File
@@ -1,85 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
import sys
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.helpers.experiment import Experiment
from nlsr_common import getParser
if __name__ == '__main__':
setLogLevel('info')
ndn = Minindn(parser=getParser())
args = ndn.args
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr, sync=args.sync,
security=args.security, faceType=args.faceType,
nFaces=args.faces, routingType=args.routingType)
Experiment.checkConvergence(ndn, ndn.net.hosts, args.ctime, quit=True)
firstNode = ndn.net.hosts[0]
if args.security:
firstNode.cmd('ndnsec-set-default /ndn/{}-site/%C1.Operator/op'.format(firstNode.name))
info('Testing advertise\n')
firstNode.cmd('nlsrc advertise /testPrefix')
time.sleep(30)
for host in ndn.net.hosts:
if host.name != firstNode.name:
if (int(host.cmd('nfdc fib | grep testPrefix | wc -l')) != 1 or
int(host.cmd('nlsrc status | grep testPrefix | wc -l')) != 1):
info('Advertise test failed\n')
ndn.stop()
sys.exit(1)
info('Testing withdraw\n')
firstNode.cmd('nlsrc withdraw /testPrefix')
time.sleep(30)
for host in ndn.net.hosts:
if host.name != firstNode.name:
if (int(host.cmd('nfdc fib | grep testPrefix | wc -l')) != 0 or
int(host.cmd('nlsrc status | grep testPrefix | wc -l')) != 0):
info('Withdraw test failed\n')
ndn.stop()
sys.exit(1)
if args.isCliEnabled:
MiniNDNCLI(ndn.net)
ndn.stop()
-53
View File
@@ -1,53 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.apps.app_manager import AppManager
from minindn.util import MiniNDNCLI
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.apps.tshark import Tshark
if __name__ == '__main__':
setLogLevel('info')
Minindn.cleanUp()
Minindn.verifyDependencies()
ndn = Minindn()
ndn.start()
info('Starting tshark logging on nodes\n')
tshark = AppManager(ndn, ndn.net.hosts, Tshark, logFolder="./log/", singleLogFile=False)
info('Starting NFD on nodes\n')
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
info('Starting NLSR on nodes\n')
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr)
MiniNDNCLI(ndn.net)
ndn.stop()
-121
View File
@@ -1,121 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from subprocess import PIPE
from mininet.log import setLogLevel, info
from mininet.topo import Topo
from minindn.minindn import Minindn
from minindn.apps.app_manager import AppManager
from minindn.util import MiniNDNCLI, getPopen
from minindn.apps.nfd import Nfd
from minindn.helpers.nfdc import Nfdc
PREFIX = "/example"
def printOutput(output):
_out = output.decode("utf-8").split("\n")
for _line in _out:
info(_line + "\n")
def run():
Minindn.cleanUp()
Minindn.verifyDependencies()
# Topology can be created/modified using Mininet topo object
topo = Topo()
info("Setup\n")
# add hosts
a = topo.addHost('a')
b = topo.addHost('b')
c = topo.addHost('c')
# add links
topo.addLink(a, b, delay='10ms', bw=2.5) # bw = bandwidth
topo.addLink(b, c, delay='10ms', bw=2.5)
info(topo.links(withInfo=True))
ndn = Minindn(topo=topo)
ndn.start()
# configure and start nfd on each node
info("Configuring NFD111\n")
AppManager(ndn, ndn.net.hosts, Nfd, logLevel="DEBUG")
"""
There are multiple ways of setting up routes in Mini-NDN
refer: https://minindn.memphis.edu/experiment.html#routing-options
It can also be set manually as follows. The important bit to note here
is the use of the Nfdc command
"""
for link in topo.links(withInfo=True):
node1, node2, node_info = link
host1 = ndn.net[node1]
host2 = ndn.net[node2]
interface = host2.connectionsTo(host1)[0][0]
interface_ip = interface.IP()
bandwidth = interface.params.get("bw", 100) * 1000000
info(f"Setting up route from {node1} to {node2} with bandwidth {bandwidth}\n")
Nfdc.createFace(host1, interface_ip, bandwidth=bandwidth)
Nfdc.registerRoute(host1, PREFIX, interface_ip, cost=0)
# links = {"a":["b"], "b":["c"]}
# for first in links:
# for second in links[first]:
# host1 = ndn.net[first]
# host2 = ndn.net[second]
# interface = host2.connectionsTo(host1)[0][0]
# interface_ip = interface.IP()
# Nfdc.createFace(host1, interface_ip)
# Nfdc.registerRoute(host1, PREFIX, interface_ip, cost=0)
# Start ping server
info("Starting pings...\n")
pingserver_log = open("{}/c/ndnpingserver.log".format(ndn.workDir), "w")
getPopen(ndn.net["c"], "ndnpingserver {}".format(PREFIX), stdout=pingserver_log,\
stderr=pingserver_log)
# start ping client
ping1 = getPopen(ndn.net["a"], "ndnping {} -c 5".format(PREFIX), stdout=PIPE, stderr=PIPE)
ping1.wait()
printOutput(ping1.stdout.read())
interface = ndn.net["b"].connectionsTo(ndn.net["a"])[0][0]
info("Failing link\n") # failing link by setting link loss to 100%
interface.config(delay="10ms", bw=10, loss=100)
info ("\n starting ping2 client \n")
ping2 = getPopen(ndn.net["a"], "ndnping {} -c 5".format(PREFIX), stdout=PIPE, stderr=PIPE)
ping2.wait()
printOutput(ping2.stdout.read())
interface.config(delay="10ms", bw=10, loss=0) # bringing back the link
info("\nExperiment Completed!\n")
MiniNDNCLI(ndn.net)
ndn.stop()
if __name__ == '__main__':
setLogLevel("info")
run()
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/python
"""
This example monitors a number of hosts using host.popen() and
pmonitor()
"""
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.topo import SingleSwitchTopo
from mininet.log import setLogLevel
from mininet.util import custom, pmonitor
def monitorhosts( hosts=5, sched='cfs' ):
"Start a bunch of pings and monitor them using popen"
mytopo = SingleSwitchTopo( hosts )
cpu = .5 / hosts
myhost = custom( CPULimitedHost, cpu=cpu, sched=sched )
net = Mininet( topo=mytopo, host=myhost )
net.start()
# Start a bunch of pings
popens = {}
last = net.hosts[ -1 ]
for host in net.hosts:
popens[ host ] = host.popen( "ping -c5 %s" % last.IP() )
last = host
# Monitor them and print output
for host, line in pmonitor( popens ):
if host:
print "<%s>: %s" % ( host.name, line.strip() )
# Done
net.stop()
if __name__ == '__main__':
setLogLevel( 'info' )
monitorhosts( hosts=5 )
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/python
"Monitor multiple hosts using popen()/pmonitor()"
from mininet.net import Mininet
from mininet.topo import SingleSwitchTopo
from mininet.util import pmonitor
from time import time
from signal import SIGINT
def pmonitorTest( N=3, seconds=10 ):
"Run pings and monitor multiple hosts using pmonitor"
topo = SingleSwitchTopo( N )
net = Mininet( topo )
net.start()
hosts = net.hosts
print "Starting test..."
server = hosts[ 0 ]
popens = {}
for h in hosts:
popens[ h ] = h.popen('ping', server.IP() )
print "Monitoring output for", seconds, "seconds"
endTime = time() + seconds
for h, line in pmonitor( popens, timeoutms=500 ):
if h:
print '%s: %s' % ( h.name, line ),
if time() >= endTime:
for p in popens.values():
p.send_signal( SIGINT )
net.stop()
if __name__ == '__main__':
pmonitorTest()
-81
View File
@@ -1,81 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
import sys
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.helpers.nfdc import Nfdc
def registerRouteToAllNeighbors(ndn, host, syncPrefix):
for node in ndn.net.hosts:
for neighbor in node.connectionsTo(host):
ip = node.IP(neighbor[0])
faceID = Nfdc.createFace(host, ip)
Nfdc.registerRoute(host, syncPrefix, faceID)
if __name__ == '__main__':
setLogLevel('info')
ndn = Minindn()
args = ndn.args
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
syncPrefix = "/sync"
numUserPrefixesPerNode = 2
maxUpdatesPerUserPrefixPerNode = 3
for host in ndn.net.hosts:
Nfdc.setStrategy(host, syncPrefix, Nfdc.STRATEGY_MULTICAST)
registerRouteToAllNeighbors(ndn, host, syncPrefix)
info('Starting psync-full-sync on all the nodes\n')
for host in ndn.net.hosts:
host.cmd('export NDN_LOG=examples.FullSyncApp=INFO')
host.cmd('psync-full-sync {} {} {} {} &> psync.logs &'
.format(syncPrefix, host.name, numUserPrefixesPerNode,
maxUpdatesPerUserPrefixPerNode))
info('Sleeping 5 minutes for convergence\n')
# Estimated time for 4 node default topology
time.sleep(300)
totalUpdates = int(host.cmd('grep -r Update {}/*/psync.logs | wc -l'
.format(ndn.workDir)))
expectedUpdates = (maxUpdatesPerUserPrefixPerNode *
len(ndn.net.hosts) * (len(ndn.net.hosts) - 1) * numUserPrefixesPerNode)
if totalUpdates == expectedUpdates:
info('PSync full sync has successfully converged.\n')
else:
info('PSync full sync convergence was not successful. Exiting...\n')
ndn.stop()
sys.exit(1)
-67
View File
@@ -1,67 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
import sys
from mininet.log import setLogLevel, info
from mininet.topo import Topo
from minindn.minindn import Minindn
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
if __name__ == '__main__':
setLogLevel('info')
topo = Topo()
topo.addHost('h1')
ndn = Minindn(topo=topo)
args = ndn.args
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
host1 = ndn.net.hosts[0]
host1.cmd('export NDN_LOG=examples.PartialSyncProducerApp=INFO')
host1.cmd('psync-producer /sync /{} 10 1 &> producer.log &'.format(host1.name))
time.sleep(1)
host1.cmd('export NDN_LOG=examples.PartialSyncConsumerApp=INFO:$NDN_LOG')
host1.cmd('psync-consumer /sync 5 &> consumer.log &')
info('Sleeping 90 seconds for convergence\n')
time.sleep(90)
consumerSubs = int(host1.cmd('cat consumer.log | grep -c Subscribing'))
consumerUpdates = int(host1.cmd('cat consumer.log | grep -c Update'))
producerPublish = int(host1.cmd('cat producer.log | grep -c Publish'))
if consumerSubs == 5 and consumerUpdates == 5 and producerPublish == 10:
info('PSync partial sync has successfully converged.\n')
else:
info('PSync partial sync convergence was not successful. Exiting...\n')
ndn.stop()
sys.exit(1)
-111
View File
@@ -1,111 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from subprocess import PIPE
from mininet.log import setLogLevel, info
from mininet.topo import Topo
from minindn.minindn import Minindn
from minindn.apps.app_manager import AppManager
from minindn.util import MiniNDNCLI, getPopen
from minindn.apps.nfd import Nfd
from minindn.helpers.nfdc import Nfdc
PREFIX = "/A"
def printOutput(output):
_out = output.decode("utf-8").split("\n")
for _line in _out:
info(_line + "\n")
def run():
Minindn.cleanUp()
Minindn.verifyDependencies()
# Topology can be created/modified using Mininet topo object
topo = Topo()
info("Setup\n")
# add hosts
a = topo.addHost('a')
b = topo.addHost('b')
# add links
topo.addLink(a, b, delay='10ms', bw=10) # bw = bandwidth
info(topo.links(withInfo=True))
ndn = Minindn(topo=topo)
ndn.start()
# configure and start nfd on each node
info("Configuring NFD\n")
AppManager(ndn, ndn.net.hosts, Nfd, logLevel="INFO")
"""
There are multiple ways of setting up routes in Mini-NDN
refer: https://minindn.memphis.edu/experiment.html#routing-options
It can also be set manually as follows. The important bit to note here
is the use of the Nfdc command
"""
for link in topo.links(withInfo=True):
node1, node2, node_info = link
host1 = ndn.net[node1]
host2 = ndn.net[node2]
interface = host2.connectionsTo(host1)[0][0]
interface_ip = interface.IP()
bandwidth = interface.params.get("bw", 100) * 1000000
info(f"Setting up route from {node1} to {node2} with bandwidth {bandwidth}\n")
Nfdc.createFace(host1, interface_ip, bandwidth=bandwidth)
Nfdc.registerRoute(host1, PREFIX, interface_ip, cost=0)
# Start cc server
info("Starting cc...\n")
qsccp_server_log = open(f"{ndn.workDir}/qsccp-demo/qsccp-server.log", "w")
getPopen(ndn.net["b"], "cc-producer --prefix {}".format(PREFIX), stdout=qsccp_server_log,\
stderr=qsccp_server_log)
# start cc client
qsccp_client_log = open(f"{ndn.workDir}/qsccp-demo/qsccp-client.log", "w")
ping1 = getPopen(ndn.net["a"], "qsccp-client --prefix {} --timingStop 10000".format(PREFIX), stdout=qsccp_client_log, stderr=qsccp_client_log)
ping1.wait()
# printOutput(ping1.stdout.read())
# interface = ndn.net["b"].connectionsTo(ndn.net["a"])[0][0]
# info("Failing link\n") # failing link by setting link loss to 100%
# interface.config(delay="10ms", bw=10, loss=100)
# info ("\n starting ping2 client \n")
# ping2 = getPopen(ndn.net["a"], "ndnping {} -c 5".format(PREFIX), stdout=PIPE, stderr=PIPE)
# ping2.wait()
# printOutput(ping2.stdout.read())
# interface.config(delay="10ms", bw=10, loss=0) # bringing back the link
info("\nExperiment Completed!\n")
MiniNDNCLI(ndn.net)
ndn.stop()
if __name__ == '__main__':
setLogLevel("info")
run()
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/python
"""
Build a simple network from scratch, using mininet primitives.
This is more complicated than using the higher-level classes,
but it exposes the configuration details and allows customization.
For most tasks, the higher-level API will be preferable.
"""
from mininet.net import Mininet
from mininet.node import Node
from mininet.link import Link
from mininet.log import setLogLevel, info
from mininet.util import quietRun
from time import sleep
def scratchNet( cname='controller', cargs='-v ptcp:' ):
"Create network from scratch using Open vSwitch."
info( "*** Creating nodes\n" )
controller = Node( 'c0', inNamespace=False )
switch = Node( 's0', inNamespace=False )
h0 = Node( 'h0' )
h1 = Node( 'h1' )
info( "*** Creating links\n" )
Link( h0, switch )
Link( h1, switch )
info( "*** Configuring hosts\n" )
h0.setIP( '192.168.123.1/24' )
h1.setIP( '192.168.123.2/24' )
info( str( h0 ) + '\n' )
info( str( h1 ) + '\n' )
info( "*** Starting network using Open vSwitch\n" )
controller.cmd( cname + ' ' + cargs + '&' )
switch.cmd( 'ovs-vsctl del-br dp0' )
switch.cmd( 'ovs-vsctl add-br dp0' )
for intf in switch.intfs.values():
print switch.cmd( 'ovs-vsctl add-port dp0 %s' % intf )
# Note: controller and switch are in root namespace, and we
# can connect via loopback interface
switch.cmd( 'ovs-vsctl set-controller dp0 tcp:127.0.0.1:6633' )
info( '*** Waiting for switch to connect to controller' )
while 'is_connected' not in quietRun( 'ovs-vsctl show' ):
sleep( 1 )
info( '.' )
info( '\n' )
info( "*** Running test\n" )
h0.cmdPrint( 'ping -c1 ' + h1.IP() )
info( "*** Stopping network\n" )
controller.cmd( 'kill %' + cname )
switch.cmd( 'ovs-vsctl del-br dp0' )
switch.deleteIntfs()
info( '\n' )
if __name__ == '__main__':
setLogLevel( 'info' )
info( '*** Scratch network demo (kernel datapath)\n' )
Mininet.init()
scratchNet()
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/python
"""
Build a simple network from scratch, using mininet primitives.
This is more complicated than using the higher-level classes,
but it exposes the configuration details and allows customization.
For most tasks, the higher-level API will be preferable.
This version uses the user datapath and an explicit control network.
"""
from mininet.net import Mininet
from mininet.node import Node
from mininet.link import Link
from mininet.log import setLogLevel, info
def linkIntfs( node1, node2 ):
"Create link from node1 to node2 and return intfs"
link = Link( node1, node2 )
return link.intf1, link.intf2
def scratchNetUser( cname='controller', cargs='ptcp:' ):
"Create network from scratch using user switch."
# It's not strictly necessary for the controller and switches
# to be in separate namespaces. For performance, they probably
# should be in the root namespace. However, it's interesting to
# see how they could work even if they are in separate namespaces.
info( '*** Creating Network\n' )
controller = Node( 'c0' )
switch = Node( 's0')
h0 = Node( 'h0' )
h1 = Node( 'h1' )
cintf, sintf = linkIntfs( controller, switch )
h0intf, sintf1 = linkIntfs( h0, switch )
h1intf, sintf2 = linkIntfs( h1, switch )
info( '*** Configuring control network\n' )
controller.setIP( '10.0.123.1/24', cintf )
switch.setIP( '10.0.123.2/24', sintf)
info( '*** Configuring hosts\n' )
h0.setIP( '192.168.123.1/24', h0intf )
h1.setIP( '192.168.123.2/24', h1intf )
info( '*** Network state:\n' )
for node in controller, switch, h0, h1:
info( str( node ) + '\n' )
info( '*** Starting controller and user datapath\n' )
controller.cmd( cname + ' ' + cargs + '&' )
switch.cmd( 'ifconfig lo 127.0.0.1' )
intfs = [ str( i ) for i in sintf1, sintf2 ]
switch.cmd( 'ofdatapath -i ' + ','.join( intfs ) + ' ptcp: &' )
switch.cmd( 'ofprotocol tcp:' + controller.IP() + ' tcp:localhost &' )
info( '*** Running test\n' )
h0.cmdPrint( 'ping -c1 ' + h1.IP() )
info( '*** Stopping network\n' )
controller.cmd( 'kill %' + cname )
switch.cmd( 'kill %ofdatapath' )
switch.cmd( 'kill %ofprotocol' )
switch.deleteIntfs()
info( '\n' )
if __name__ == '__main__':
setLogLevel( 'info' )
info( '*** Scratch network demo (user datapath)\n' )
Mininet.init()
scratchNetUser()
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/python
"""
Simple example of setting network and CPU parameters
"""
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.link import TCLink
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel
class SingleSwitchTopo(Topo):
"Single switch connected to n hosts."
def __init__(self, n=2, **opts):
Topo.__init__(self, **opts)
switch = self.add_switch('s1')
for h in range(n):
# Each host gets 50%/n of system CPU
host = self.add_host('h%s' % (h + 1),
cpu=.5 / n)
# 10 Mbps, 5ms delay, 10% loss
self.add_link(host, switch,
bw=10, delay='5ms', loss=10, use_htb=True)
def perfTest():
"Create network and run simple performance test"
topo = SingleSwitchTopo(n=4)
net = Mininet(topo=topo,
host=CPULimitedHost, link=TCLink)
net.start()
print "Dumping host connections"
dumpNodeConnections(net.hosts)
print "Testing network connectivity"
net.pingAll()
print "Testing bandwidth between h1 and h4"
h1, h4 = net.getNodeByName('h1', 'h4')
net.iperf((h1, h4))
net.stop()
if __name__ == '__main__':
setLogLevel('info')
perfTest()
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/python
"""
Create a network and start sshd(8) on each host.
While something like rshd(8) would be lighter and faster,
(and perfectly adequate on an in-machine network)
the advantage of running sshd is that scripts can work
unchanged on mininet and hardware.
In addition to providing ssh access to hosts, this example
demonstrates:
- creating a convenience function to construct networks
- connecting the host network to the root namespace
- running server processes (sshd in this case) on hosts
"""
from mininet.net import Mininet
from mininet.cli import CLI
from mininet.log import lg
from mininet.node import Node, OVSKernelSwitch
from mininet.topolib import TreeTopo
from mininet.link import Link
def TreeNet( depth=1, fanout=2, **kwargs ):
"Convenience function for creating tree networks."
topo = TreeTopo( depth, fanout )
return Mininet( topo, **kwargs )
def connectToRootNS( network, switch, ip, prefixLen, routes ):
"""Connect hosts to root namespace via switch. Starts network.
network: Mininet() network object
switch: switch to connect to root namespace
ip: IP address for root namespace node
prefixLen: IP address prefix length (e.g. 8, 16, 24)
routes: host networks to route to"""
# Create a node in root namespace and link to switch 0
root = Node( 'root', inNamespace=False )
intf = Link( root, switch ).intf1
root.setIP( ip, prefixLen, intf )
# Start network that now includes link to root namespace
network.start()
# Add routes from root ns to hosts
for route in routes:
root.cmd( 'route add -net ' + route + ' dev ' + str( intf ) )
def sshd( network, cmd='/usr/sbin/sshd', opts='-D' ):
"Start a network, connect it to root ns, and run sshd on all hosts."
switch = network.switches[ 0 ] # switch to use
ip = '10.123.123.1' # our IP address on host network
routes = [ '10.0.0.0/8' ] # host networks to route to
connectToRootNS( network, switch, ip, 8, routes )
for host in network.hosts:
host.cmd( cmd + ' ' + opts + '&' )
print
print "*** Hosts are running sshd at the following addresses:"
print
for host in network.hosts:
print host.name, host.IP()
print
print "*** Type 'exit' or control-D to shut down network"
CLI( network )
for host in network.hosts:
host.cmd( 'kill %' + cmd )
network.stop()
if __name__ == '__main__':
lg.setLogLevel( 'info')
net = TreeNet( depth=1, fanout=4, switch=OVSKernelSwitch )
sshd( net )
-100
View File
@@ -1,100 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import argparse
import sys
from mininet.log import setLogLevel, info
from mininet.topo import Topo
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.helpers.ndn_routing_helper import NdnRoutingHelper
if __name__ == '__main__':
setLogLevel('info')
Minindn.cleanUp()
Minindn.verifyDependencies()
parser = argparse.ArgumentParser()
parser.add_argument('--face-type', dest='faceType', default='udp', choices=['udp', 'tcp'])
parser.add_argument('--routing', dest='routingType', default='link-state',
choices=['link-state', 'hr', 'dry'],
help='''Choose routing type, dry = link-state is used
but hr is calculated for comparision.''')
'''
Experiment run with default topology, test cases won't work with other topologies
# With calculateNPossibleRoutes,
10 # routing = hr, N = All, from A, 3 routes needs to added to NFD.
a +++++++ b # a - b -- cost 10
+ + # a - c -- cost 10
10 + + 10 # a - d -- cost 20
+ + # Same goes for B being a source.
c d #
'''
topo = Topo()
a = topo.addHost('a')
b = topo.addHost('b')
c = topo.addHost('c')
d = topo.addHost('d')
topo.addLink(a, b, delay='10ms')
topo.addLink(a, c, delay='10ms')
topo.addLink(b, d, delay='10ms')
ndn = Minindn(parser=parser, topo=topo)
ndn.start()
info('Starting NFD on nodes\n')
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
info('Adding static routes to NFD\n')
grh = NdnRoutingHelper(ndn.net, ndn.args.faceType, ndn.args.routingType)
# For all host, pass ndn.net.hosts or a list, [ndn.net['a'], ..] or [ndn.net.hosts[0],.]
grh.addOrigin([ndn.net['a']], ["/abc"])
grh.calculateNPossibleRoutes()
'''
prefix "/abc" is advertise from node A, it should be reachable from all other nodes.
'''
routesFromA = ndn.net['a'].cmd("nfdc route | grep -v '/localhost/nfd'")
if '/ndn/b-site/b' not in routesFromA or \
'/ndn/c-site/c' not in routesFromA or \
'/ndn/d-site/d' not in routesFromA:
info("Route addition failed\n")
routesToPrefix = ndn.net['b'].cmd("nfdc fib | grep '/abc'")
if '/abc' not in routesToPrefix:
info("Missing route to advertised prefix, Route addition failed\n")
ndn.net.stop()
sys.exit(1)
info('Route addition to NFD completed\n')
MiniNDNCLI(ndn.net)
ndn.stop()
-105
View File
@@ -1,105 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
"""
This example demonstrates the functionality of the Traffic generator. It consists of a traffic
server and client. The server will listen for interest on the prefix specified in the server
configuration file. The client will send a designated number of interests to the server and
get the data back.
More details on traffic generator here: https://github.com/named-data/ndn-traffic-generator
"""
from time import sleep
from mininet.log import setLogLevel, info
from minindn.minindn import Minindn
from minindn.util import MiniNDNCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.util import copyExistentFile
from examples.nlsr.nlsr_common import getParser
def trafficServer(node, serverConfFile):
"""
Start traffic server
:parma mininet.node.Host node: mininet node object
:param string serverConfFile: server configuration file
"""
info ("Starting traffic server \n")
# c = 10, i.e maximum number of Interests to respond
cmd = 'ndn-traffic-server -c {} {} &> traffic-server.log &'.format(10, serverConfFile)
node.cmd(cmd)
sleep(10)
# The server configuration file uses /example prefix to advertise its service
# thus, server needs to advertise this prefix for the client to reach it
serverPrefix = "/example"
server.cmd('nlsrc advertise {}'.format(serverPrefix))
sleep(5) # sleep for routing convergence
def trafficClient(node, clientConfFile):
"""
Start traffic client
:parma mininet.node.Host node: The expiration period in milliseconds, or None if not specified.
:param string clientConfFile: client configuration file
"""
info ("Starting ndn traffic client \n")
# c = 10, total number of Interests to be generated each at 200ms interval
cmd = 'ndn-traffic-client -c {} -i {} {} &> traffic-client.log &'.format(10, 200, clientConfFile)
node.cmd(cmd)
if __name__ == '__main__':
setLogLevel('info')
# Traffic generator configuration files. For this example, we are using default conf files.
# More details on configuration files here: https://github.com/named-data/ndn-traffic-generator
possibleServerConfPath = ["/etc/ndn/ndn-traffic-server.conf.sample", "/usr/local/etc/ndn/ndn-traffic-server.conf.sample"]
possibleClientConfPath = ["/etc/ndn/ndn-traffic-client.conf.sample", "/usr/local/etc/ndn/ndn-traffic-client.conf.sample"]
Minindn.cleanUp()
Minindn.verifyDependencies()
ndn = Minindn(parser=getParser())
ndn.start()
nfds = AppManager(ndn, ndn.net.hosts, Nfd)
nlsrs = AppManager(ndn, ndn.net.hosts, Nlsr)
sleep(90)
# Default topology is used in this experiment "/topologies/default-topology.conf"
# lets make node "a" as a traffic-server node, and node "c" as a traffic-client node
server = ndn.net['a']
client = ndn.net['c']
serverConf = '{}/{}/server-conf'.format(ndn.workDir, server.name)
clientConf = '{}/{}/client-conf'.format(ndn.workDir, client.name)
copyExistentFile(server, possibleServerConfPath, serverConf)
copyExistentFile(server, possibleClientConfPath, clientConf)
trafficServer(server, serverConf)
trafficClient(client, clientConf)
# default location for the results: /tmp/minindn/
MiniNDNCLI(ndn.net)
ndn.stop()
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/python
"""
Create a 1024-host network, and run the CLI on it.
If this fails because of kernel limits, you may have
to adjust them, e.g. by adding entries to /etc/sysctl.conf
and running sysctl -p. Check util/sysctl_addon.
"""
from mininet.cli import CLI
from mininet.log import setLogLevel
from mininet.node import OVSKernelSwitch
from mininet.topolib import TreeNet
if __name__ == '__main__':
setLogLevel( 'info' )
network = TreeNet( depth=2, fanout=32, switch=OVSKernelSwitch )
network.run( CLI, network )
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/python
"Create a 64-node tree network, and test connectivity using ping."
from mininet.log import setLogLevel
from mininet.node import UserSwitch, OVSKernelSwitch # , KernelSwitch
from mininet.topolib import TreeNet
def treePing64():
"Run ping test on 64-node tree networks."
results = {}
switches = { # 'reference kernel': KernelSwitch,
'reference user': UserSwitch,
'Open vSwitch kernel': OVSKernelSwitch }
for name in switches:
print "*** Testing", name, "datapath"
switch = switches[ name ]
network = TreeNet( depth=2, fanout=8, switch=switch )
result = network.run( network.pingAll )
results[ name ] = result
print
print "*** Tree network ping results:"
for name in switches:
print "%s: %d%% packet loss" % ( name, results[ name ] )
print
if __name__ == '__main__':
setLogLevel( 'info' )
treePing64()
-44
View File
@@ -1,44 +0,0 @@
import time
from mininet.log import setLogLevel, info
from minindn.wifi.minindnwifi import MinindnWifi
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.apps.nlsr import Nlsr
from minindn.helpers.experiment import Experiment
setLogLevel('info')
# Setup code
sync = Nlsr.SYNC_PSYNC
ndn = MinindnWifi()
args = ndn.args
ndn.start()
info('Starting NFD on nodes\n')
nfds = AppManager(ndn, ndn.net.stations, Nfd, logLevel='INFO')
face_dict = ndn.setupFaces()
if not face_dict:
print("Hint: Are you sure you're running with a topology with a faces section? \
Try topologies/wifi/nlsr_wifi_example.conf")
info('Starting NLSR on nodes\n')
nlsrs = AppManager(ndn, [], Nlsr)
print(face_dict)
for host in ndn.net.stations:
nlsrs.startOnNode(host, sync=sync, logLevel='INFO', faceDict=face_dict)
time.sleep(0.1)
Experiment.checkConvergence(ndn, ndn.net.stations, 60, False)
# Uncomment for CLI access
from minindn.util import MiniNDNWifiCLI
MiniNDNWifiCLI(ndn.net)
ndn.stop()
-84
View File
@@ -1,84 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from mininet.log import setLogLevel, info
from minindn.wifi.minindnwifi import MinindnWifi
from minindn.util import MiniNDNWifiCLI
from minindn.apps.app_manager import AppManager
from minindn.apps.nfd import Nfd
from minindn.helpers.nfdc import Nfdc
from minindn.helpers.ndnping import NDNPing
from time import sleep
# This experiment uses the singleap topology and is intended to be a basic
# test case where we see if two nodes can send interests to each other.
def runExperiment():
setLogLevel('info')
info("Starting network")
ndnwifi = MinindnWifi()
a = ndnwifi.net["sta1"]
b = ndnwifi.net["sta2"]
# Test for model-based mobility
if ndnwifi.args.modelMob:
ndnwifi.startMobilityModel(model='GaussMarkov')
#Test for replay based mobility
if ndnwifi.args.mobility:
info("Running with mobility...")
p1, p2, p3, p4 = dict(), dict(), dict(), dict()
p1 = {'position': '40.0,30.0,0.0'}
p2 = {'position': '40.0,40.0,0.0'}
p3 = {'position': '31.0,10.0,0.0'}
p4 = {'position': '200.0,200.0,0.0'}
ndnwifi.net.mobility(a, 'start', time=1, **p1)
ndnwifi.net.mobility(b, 'start', time=2, **p2)
ndnwifi.net.mobility(a, 'stop', time=12, **p3)
ndnwifi.net.mobility(b, 'stop', time=22, **p4)
ndnwifi.net.stopMobility(time=23)
ndnwifi.startMobility(time=0, mob_rep=1, reverse=False)
ndnwifi.start()
info("Starting NFD")
sleep(2)
AppManager(ndnwifi, ndnwifi.net.stations, Nfd)
info("Starting pingserver...")
NDNPing.startPingServer(b, "/example")
faceID = Nfdc.createFace(a, b.IP())
Nfdc.registerRoute(a, "/example", faceID)
info("Starting ping...")
NDNPing.ping(a, "/example", nPings=10)
sleep(10)
# Start the CLI
MiniNDNWifiCLI(ndnwifi.net)
ndnwifi.net.stop()
ndnwifi.cleanUp()
if __name__ == '__main__':
try:
runExperiment()
except Exception as e:
MinindnWifi.handleException()
-186
View File
@@ -1,186 +0,0 @@
#!/bin/bash
# -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
set -eo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
# These commands are generally installed on most systems. If not, user must install manually.
# 'sudo' is not directly used by this script, but Mininet install.sh uses it, so we check that also.
NEEDED_BINARIES=(
awk
git
sudo
)
MISSING_BINARIES=()
SUDO=
if [[ $(id -u) -eq 0 ]]; then
if [[ -n $SUDO_USER ]] && [[ -z $SKIPSUDOCHECK ]]; then
cat <<EOT
Do not run this script through sudo
Instead, run this script as a regular user; the script will call sudo when needed
To bypass this check, set the environment variable SKIPSUDOCHECK=1
EOT
exit 1
fi
else
SUDO=sudo
fi
for B in "${NEEDED_BINARIES[@]}"; do
if ! command -v "$B" >/dev/null; then
MISSING_BINARIES+=("$B")
fi
done
if [[ ${#MISSING_BINARIES[@]} -gt 0 ]] ; then
echo "Missing commands (${MISSING_BINARIES[*]}) to start this script. To install, run:"
echo " $SUDO apt install --no-install-recommends ca-certificates curl git mawk sudo"
echo " $SUDO yum install ca-certificates curl git mawk sudo"
exit 1
fi
CODEROOT="$(pwd)/dl"
NJOBS=$(nproc)
MEM_JOBS=$(awk '$1=="MemAvailable:" { print int($2/(1536*1024)); exit }' /proc/meminfo)
if [[ $MEM_JOBS -lt 1 ]]; then
NJOBS=1
echo 'Insufficient available RAM, build may fail'
elif [[ $MEM_JOBS -lt $NJOBS ]]; then
NJOBS=$MEM_JOBS
fi
PREFER_FROM=ppa
PPA_PKGS=()
ARGS=$(getopt -o 'hy' -l 'help,dir:,jobs:,no-wifi,ppa,source,cxx:,dummy-keychain,nfd:,psync:,nlsr:,tools:,traffic:,infoedit:,mininet:,mnwifi:,dl-only,ignore-existing' -- "$@")
eval set -- "$ARGS"
while true; do
case $1 in
-h|--help) HELP=1; shift;;
-y) CONFIRM=1; shift;;
--dir) CODEROOT=$2; shift 2;;
--jobs) NJOBS=$((0+$2)); shift 2;;
--no-wifi) NO_WIFI=1; shift;;
--ppa) PREFER_FROM=ppa; shift;;
--source) PREFER_FROM=source; shift;;
--cxx) CXX_VERSION=$2; NO_PPA=1; shift 2;;
--dummy-keychain) CXX_DUMMY_KEYCHAIN=1; NO_PPA=1; shift;;
--nfd) NFD_VERSION=$2; NO_PPA=1; shift 2;;
--psync) PSYNC_VERSION=$2; NO_PPA=1; shift 2;;
--nlsr) NLSR_VERSION=$2; NO_PPA=1; shift 2;;
--tools) TOOLS_VERSION=$2; NO_PPA=1; shift 2;;
--traffic) TRAFFIC_VERSION=$2; NO_PPA=1; shift 2;;
--infoedit) INFOEDIT_VERSION=$2; shift 2;;
--mininet) MININET_VERSION=$2; shift 2;;
--mnwifi) MNWIFI_VERSION=$2; shift 2;;
--dl-only) DL_ONLY=1; shift;;
--ignore-existing) IGNORE_EXISTING=1; shift;;
--) shift; break;;
*) exit 1;;
esac
done
if [[ $NJOBS -le 0 ]]; then
cat <<EOT
--jobs must be a positive integer.
Run ./install.sh -h to see help message.
EOT
exit 1
fi
if [[ $HELP -eq 1 ]]; then
cat <<EOT
./install.sh [OPTION]...
General options:
-h Display help and exit.
-y Skip confirmation.
--dir=${CODEROOT}
Set where to download and compile the code.
--jobs=${NJOBS}
Set number of parallel jobs.
--no-wifi
Do not install Mininet-WiFi.
Install preference options:
--ppa
Install available packages from named-data PPA.
This is the default on Ubuntu, unless a source code version option is used.
--source
Install all packages from source code.
Source code version options:
--cxx=[VERSION]
Set ndn-cxx version.
--dummy-keychain
Patch ndn-cxx to use dummy KeyChain.
This disables signing and verifications, which allows experiments to run faster.
Use this option only if your scenario does not require signature verification.
--nfd=[VERSION]
Set NFD version.
--psync=[VERSION]
Set PSync version.
--nlsr=[VERSION]
Set NLSR version.
--tools=[VERSION]
Set NDN Essential Tools version.
--traffic=[VERSION]
Set NDN Traffic Generator version.
--infoedit=[VERSION]
Set infoedit version.
--mininet=[VERSION]
Set Mininet version.
--mnwifi=[VERSION]
Set Mininet-WiFi version.
Acceptable version syntaxes:
* git commit/tag/branch, example: --nfd=NFD-0.7.1
* git repository (e.g. fork) and commit/tag/branch, example:
--nfd=https://github.com/named-data/NFD.git@NFD-0.7.1
* change,patchset on named-data Gerrit, example: --nfd=6236,8
Misc options:
--dl-only
Download the source code only.
You may modify the code in ${CODEROOT} and then rerun this script to install them.
--ignore-existing
Ignore already installed binaries and libraries, and attempt to reinstall.
This is useful if you have modified source code checkout and want to install again.
EOT
exit 0
fi
trap 'set +e; trap - ERR; echo "Error!"; exit 1;' ERR
PKGDEPDIR="$(pwd)/util/pkgdep"
if [[ -e /etc/os-release ]]; then
source /etc/os-release
fi
for id in ${ID,,} ${ID_LIKE,,}; do
if [[ -e $PKGDEPDIR/$id.sh ]]; then
source "$PKGDEPDIR/$id.sh"
source "$PKGDEPDIR/common.sh"
exit 0
fi
done
echo "Unsupported platform ${ID}, aborting"
exit 1
-1
View File
@@ -1 +0,0 @@
__version__ = '0.5.0'
View File
Whitespace-only changes.
-56
View File
@@ -1,56 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from mininet.node import Node
class AppManager(object):
def __init__(self, minindn, hosts, cls, **appParams):
self.cls = cls
self.apps = []
for host in hosts:
# Don't run NDN apps on switches
if isinstance(host, Node):
self.startOnNode(host, **appParams)
minindn.cleanups.append(self.cleanup)
def startOnNode(self, host, **appParams):
app = self.cls(host, **appParams)
app.start()
self.apps.append(app)
def cleanup(self):
for app in self.apps:
app.stop()
def __getitem__(self, nodeName):
for app in self.apps:
if app.node.name == nodeName:
return app
return None
def __iter__(self):
return self.apps.__iter__()
def __next__(self):
return self.apps.__next__()
-50
View File
@@ -1,50 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from minindn.util import getPopen
class Application(object):
def __init__(self, node):
self.node = node
self.process = None
self.logfile = None
self.homeDir = self.node.params['params']['homeDir']
# Make directory for log file
self.logDir = '{}/log'.format(self.homeDir)
self.node.cmd('mkdir -p {}'.format(self.logDir))
def start(self, command, logfile, envDict=None):
if self.process is None:
self.logfile = open('{}/{}'.format(self.logDir, logfile), 'w')
if isinstance(command, str):
command = command.split()
self.process = getPopen(self.node, command, envDict,
stdout=self.logfile, stderr=self.logfile)
def stop(self):
if self.process is not None:
self.process.kill()
self.process = None
if self.logfile is not None:
self.logfile.close()
-75
View File
@@ -1,75 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2019, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from minindn.apps.application import Application
from minindn.util import copyExistentFile
from minindn.minindn import Minindn
class Nfd(Application):
def __init__(self, node, logLevel='NONE', csSize=65536,
csPolicy='lru', csUnsolicitedPolicy='drop-all'):
Application.__init__(self, node)
self.logLevel = node.params['params'].get('nfd-log-level', logLevel)
self.confFile = '{}/nfd.conf'.format(self.homeDir)
self.logFile = 'nfd.log'
self.sockFile = '/run/{}.sock'.format(node.name)
self.ndnFolder = '{}/.ndn'.format(self.homeDir)
self.clientConf = '{}/client.conf'.format(self.ndnFolder)
# Copy nfd.conf file from /usr/local/etc/ndn or /etc/ndn to the node's home directory
# Use nfd.conf as default configuration for NFD, else use the sample
possibleConfPaths = ['/usr/local/etc/ndn/nfd.conf.sample', '/usr/local/etc/ndn/nfd.conf',
'/etc/ndn/nfd.conf.sample', '/etc/ndn/nfd.conf']
copyExistentFile(node, possibleConfPaths, self.confFile)
# Set log level
node.cmd('infoedit -f {} -s log.default_level -v {}'.format(self.confFile, self.logLevel))
# Open the conf file and change socket file name
node.cmd('infoedit -f {} -s face_system.unix.path -v {}'.format(self.confFile, self.sockFile))
# Set CS parameters
node.cmd('infoedit -f {} -s tables.cs_max_packets -v {}'.format(self.confFile, csSize))
node.cmd('infoedit -f {} -s tables.cs_policy -v {}'.format(self.confFile, csPolicy))
node.cmd('infoedit -f {} -s tables.cs_unsolicited_policy -v {}'.format(self.confFile, csUnsolicitedPolicy))
# Make NDN folder
node.cmd('mkdir -p {}'.format(self.ndnFolder))
# Copy client configuration to host
possibleClientConfPaths = ['/usr/local/etc/ndn/client.conf.sample', '/etc/ndn/client.conf.sample']
copyExistentFile(node, possibleClientConfPaths, self.clientConf)
# Change the unix socket
node.cmd('sudo sed -i "s|;transport|transport|g" {}'.format(self.clientConf))
node.cmd('sudo sed -i "s|nfd.sock|{}.sock|g" {}'.format(node.name, self.clientConf))
if not Minindn.ndnSecurityDisabled:
# Generate key and install cert for /localhost/operator to be used by NFD
node.cmd('ndnsec-key-gen /localhost/operator | ndnsec-cert-install -')
def start(self):
Application.start(self, 'nfd --config {}'.format(self.confFile), logfile=self.logFile)
Minindn.sleep(0.5)
-286
View File
@@ -1,286 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import shutil
import os, sys
from mininet.clean import sh
from mininet.examples.cluster import RemoteMixin
from mininet.log import warn
from mininet.node import Switch
from minindn.apps.application import Application
from minindn.util import scp, copyExistentFile
from minindn.helpers.nfdc import Nfdc
from minindn.minindn import Minindn
class Nlsr(Application):
ROUTING_LINK_STATE = 'link-state'
ROUTING_HYPERBOLIC = 'hr'
ROUTING_DRY_RUN = 'dry'
SYNC_PSYNC = 'psync'
def __init__(self, node, logLevel='NONE', security=False, sync=SYNC_PSYNC,
faceType='udp', nFaces=3, routingType=ROUTING_LINK_STATE, faceDict=None):
Application.__init__(self, node)
try:
from mn_wifi.node import Node_wifi
if isinstance(node, Node_wifi) and faceDict == None:
warn("Wifi nodes need to have faces configured manually. Please see \
documentation on provided helper methods.\r\n")
sys.exit(1)
except ImportError:
pass
self.network = '/ndn/'
self.node = node
self.parameters = self.node.params['params']
if self.parameters.get('nlsr-log-level', None) != None:
logLevel = self.parameters.get('nlsr-log-level')
if logLevel in ['NONE', 'WARN', 'INFO', 'DEBUG', 'TRACE']:
self.envDict = {'NDN_LOG': 'nlsr.*={}'.format(logLevel)}
else:
self.envDict = {'NDN_LOG': logLevel}
self.logFile = 'nlsr.log'
self.routerName = '/{}C1.Router/cs/{}'.format('%', node.name)
self.confFile = '{}/nlsr.conf'.format(self.homeDir)
self.security = security
self.sync = sync
self.faceType = faceType
self.infocmd = 'infoedit -f nlsr.conf'
# Expected format- node : tuple (node name, IP, cost)
self.faceDict = faceDict
self.parameters = self.node.params['params']
self.nFaces = nFaces
if routingType == Nlsr.ROUTING_HYPERBOLIC:
self.hyperbolicState = 'on'
elif routingType == Nlsr.ROUTING_DRY_RUN:
self.hyperbolicState = 'dry-run'
else:
self.hyperbolicState = 'off'
self.hyperRadius = self.parameters.get('radius', 0.0)
self.hyperAngle = self.parameters.get('angle', 0.0)
if ((self.hyperbolicState == 'on' or self.hyperbolicState == 'dry-run') and
(self.hyperRadius == 0.0 or self.hyperAngle == 0.0)):
warn('Hyperbolic coordinates in topology file are either missing or misconfigured.')
warn('Check that each node has one radius value and one or two angle value(s).')
sys.exit(1)
self.neighborIPs = []
possibleConfPaths = ['/usr/local/etc/ndn/nlsr.conf.sample', '/etc/ndn/nlsr.conf.sample']
copyExistentFile(node, possibleConfPaths, '{}/nlsr.conf'.format(self.homeDir))
self.createConfigFile()
if security and not Minindn.ndnSecurityDisabled:
self.createKeysAndCertificates()
def start(self):
self.createFaces()
Application.start(self, 'nlsr -f {}'.format(self.confFile), self.logFile, self.envDict)
Minindn.sleep(1)
def createFaces(self):
for ip in self.neighborIPs:
Nfdc.createFace(self.node, ip, self.faceType, isPermanent=True)
@staticmethod
def createKey(host, name, outputFile):
host.cmd('ndnsec-key-gen {} > {}'.format(name, outputFile))
@staticmethod
def createCertificate(host, signer, keyFile, outputFile):
host.cmd('ndnsec-cert-gen -s {} -r {} > {}'.format(signer, keyFile, outputFile))
def createKeysAndCertificates(self):
securityDir = '{}/security'.format(Minindn.workDir)
if not os.path.exists(securityDir):
os.mkdir(securityDir)
rootName = self.network
rootCertFile = '{}/root.cert'.format(securityDir)
if not os.path.isfile(rootCertFile):
# Create root certificate
sh('ndnsec-key-gen {}'.format(rootName)) # Installs a self-signed cert into the system
sh('ndnsec-cert-dump -i {} > {}'.format(rootName, rootCertFile))
# Create necessary certificates for each site
nodeSecurityFolder = '{}/security'.format(self.homeDir)
self.node.cmd('mkdir -p {}'.format(nodeSecurityFolder))
# Create temp folders for remote nodes on this machine (localhost) to store site.key file
# from RemoteNodes
if not os.path.exists(nodeSecurityFolder) and \
isinstance(self.node, RemoteMixin) and self.node.isRemote:
os.makedirs(nodeSecurityFolder)
shutil.copyfile('{}/root.cert'.format(securityDir),
'{}/root.cert'.format(nodeSecurityFolder))
# Create site certificate
siteName = '{}{}-site'.format(self.network, self.node.name)
siteKeyFile = '{}/site.keys'.format(nodeSecurityFolder)
siteCertFile = '{}/site.cert'.format(nodeSecurityFolder)
Nlsr.createKey(self.node, siteName, siteKeyFile)
# Copy siteKeyFile from remote for ndnsec-cert-gen
if isinstance(self.node, RemoteMixin) and self.node.isRemote:
login = 'mininet@{}'.format(self.node.server)
src = '{}:{}'.format(login, siteKeyFile)
dst = siteKeyFile
scp(src, dst)
# Root key is in root namespace, must sign site key and then install on host
sh('ndnsec-cert-gen -s {} -r {} > {}'.format(rootName, siteKeyFile, siteCertFile))
# Copy root.cert and site.cert from localhost to remote host
if isinstance(self.node, RemoteMixin) and self.node.isRemote:
login = 'mininet@{}'.format(self.node.server)
src = '{}/site.cert'.format(nodeSecurityFolder)
src2 = '{}/root.cert'.format(nodeSecurityFolder)
dst = '{}:/tmp/'.format(login)
scp(src, src2, dst)
self.node.cmd('mv /tmp/*.cert {}'.format(nodeSecurityFolder))
self.node.cmd('ndnsec-cert-install -f {}'.format(siteCertFile))
# Create and install operator certificate
opName = '{}/%C1.Operator/op'.format(siteName)
opKeyFile = '{}/op.keys'.format(nodeSecurityFolder)
opCertFile = '{}/op.cert'.format(nodeSecurityFolder)
Nlsr.createKey(self.node, opName, opKeyFile)
Nlsr.createCertificate(self.node, siteName, opKeyFile, opCertFile)
self.node.cmd('ndnsec-cert-install -f {}'.format(opCertFile))
# Create and install router certificate
routerName = '{}/%C1.Router/cs/{}'.format(siteName, self.node.name)
routerKeyFile = '{}/router.keys'.format(nodeSecurityFolder)
routerCertFile = '{}/router.cert'.format(nodeSecurityFolder)
Nlsr.createKey(self.node, routerName, routerKeyFile)
Nlsr.createCertificate(self.node, opName, routerKeyFile, routerCertFile)
self.node.cmd('ndnsec-cert-install -f {}'.format(routerCertFile))
def createConfigFile(self):
self.__editGeneralSection()
if self.faceDict:
self.__editNeighborsSectionManual()
else:
self.__editNeighborsSection()
self.__editHyperbolicSection()
self.__editFibSection()
self.__editAdvertisingSection()
self.__editSecuritySection()
def __editGeneralSection(self):
self.node.cmd('{} -s general.network -v {}'.format(self.infocmd, self.network))
self.node.cmd('{} -s general.site -v /{}-site'.format(self.infocmd, self.node.name))
self.node.cmd('{} -s general.router -v /%C1.Router/cs/{}'.format(self.infocmd, self.node.name))
self.node.cmd('{} -s general.state-dir -v {}/log'.format(self.infocmd, self.homeDir))
self.node.cmd('{} -s general.sync-protocol -v {}'.format(self.infocmd, self.sync))
def __editNeighborsSection(self):
self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
for intf in self.node.intfList():
link = intf.link
if not link:
continue
node1, node2 = link.intf1.node, link.intf2.node
# Todo: add some switch support
if isinstance(node1, Switch) or isinstance(node2, Switch):
continue
if node1 == self.node:
other = node2
ip = other.IP(str(link.intf2))
else:
other = node1
ip = other.IP(str(link.intf1))
linkCost = intf.params.get('delay', '10ms').replace('ms', '')
self.neighborIPs.append(ip)
self.node.cmd('{} -a neighbors.neighbor \
<<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
.format(self.infocmd, self.network, other.name, other.name,
self.faceType, ip, linkCost))
def __editNeighborsSectionManual(self):
self.node.cmd('{} -d neighbors.neighbor'.format(self.infocmd))
if self.node not in self.faceDict:
return
for link in self.faceDict[self.node]:
nodeName = link[0]
nodeIP = link[1]
linkCost = link[2]
self.node.cmd('{} -a neighbors.neighbor \
<<<\'name {}{}-site/%C1.Router/cs/{} face-uri {}://{}\n link-cost {}\''
.format(self.infocmd, self.network, nodeName, nodeName,
self.faceType, nodeIP, linkCost))
def __editHyperbolicSection(self):
self.node.cmd('{} -s hyperbolic.state -v {}'.format(self.infocmd, self.hyperbolicState))
self.node.cmd('{} -s hyperbolic.radius -v {}'.format(self.infocmd, self.hyperRadius))
self.node.cmd('{} -s hyperbolic.angle -v {}'.format(self.infocmd, self.hyperAngle))
def __editFibSection(self):
self.node.cmd('{} -s fib.max-faces-per-prefix -v {}'.format(self.infocmd, self.nFaces))
def __editAdvertisingSection(self):
self.node.cmd('{} -d advertising.prefix'.format(self.infocmd))
self.node.cmd('{} -s advertising.prefix -v {}{}-site/{}'
.format(self.infocmd, self.network, self.node.name, self.node.name))
def __editSecuritySection(self):
self.node.cmd('{} -d security.cert-to-publish'.format(self.infocmd))
if not self.security:
self.node.cmd('{} -s security.validator.trust-anchor.type -v any'.format(self.infocmd))
self.node.cmd('{} -d security.validator.trust-anchor.file-name'.format(self.infocmd))
self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.type -v any'.format(self.infocmd))
self.node.cmd('{} -d security.prefix-update-validator.trust-anchor.file-name'.format(self.infocmd))
else:
self.node.cmd('{} -s security.validator.trust-anchor.file-name -v security/root.cert'.format(self.infocmd))
self.node.cmd('{} -s security.prefix-update-validator.trust-anchor.file-name -v security/site.cert'.format(self.infocmd))
self.node.cmd('{} -p security.cert-to-publish -v security/site.cert'.format(self.infocmd))
self.node.cmd('{} -p security.cert-to-publish -v security/op.cert'.format(self.infocmd))
self.node.cmd('{} -p security.cert-to-publish -v security/router.cert'.format(self.infocmd))
-60
View File
@@ -1,60 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from minindn.apps.application import Application
from mininet.log import debug
class Tshark(Application):
"""
Logging utility to dump network traffic of a node to a PCAP file.
The app is based on the command line tool tshark and requires tshark to be installed on the system.
"""
def __init__(self, node, logFolder="./", singleLogFile=False):
"""
:param logFolder Folder, where PCAP files are stored.
:param singleLogFile Single PCAP file per node, or individual PCAP for each interface
"""
Application.__init__(self, node)
self.logFolder = logFolder
self.singleLogFile = singleLogFile
# Create logfile folder in case it does not exist
node.cmd('mkdir -p {}'.format(self.logFolder))
def start(self):
# Start capturing traffic with Tshark.
debug("[{0}] Starting tshark logging\n".format(self.node.name))
if self.singleLogFile:
interfaces = ["-i " + intf for intf in self.node.intfNames()]
ndnDumpOutputFile = "{}/{}-interfaces.pcap".format(self.logFolder, self.node.name)
self.node.cmd("tshark {} -w {} -q &".format(" ".join(interfaces), ndnDumpOutputFile))
else:
for intf in self.node.intfNames():
ndnDumpOutputFile = "{}/{}.pcap".format(self.logFolder, intf)
self.node.cmd("tshark -i {} -w {} -q &".format(intf, ndnDumpOutputFile))
View File
Whitespace-only changes.
-132
View File
@@ -1,132 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
import sys
from itertools import cycle
from mininet.log import info
from minindn.helpers.nfdc import Nfdc
from minindn.helpers.ndnping import NDNPing
from minindn.util import getSafeName
class Experiment(object):
@staticmethod
def checkConvergence(ndn, hosts, convergenceTime, quit=False, returnConvergenceInfo=False):
# Wait for convergence time period
info('Waiting {} seconds for convergence...\n'.format(convergenceTime))
time.sleep(convergenceTime)
info('...done\n')
didNlsrConverge = True
convergeInfo = {}
for host in hosts:
convergeInfo[host.name] = {}
statusRouter = host.cmd('nfdc fib list | grep site/%C1.Router/cs/')
statusPrefix = host.cmd('nfdc fib list | grep ndn | grep site | grep -v Router')
for node in hosts:
# Node has its own router name in the fib list, but not name prefix
routerPrefix = ('/ndn/{}-site/%C1.Router/cs/{}'.format(node.name, node.name))
namePrefix = ('/ndn/{}-site/{}'.format(node.name, node.name))
statusRouterCheck = routerPrefix not in statusRouter
statusPrefixCheck = host.name != node.name and namePrefix not in statusPrefix
if statusRouterCheck or statusPrefixCheck:
didNlsrConverge = False
host.cmd('echo {} > convergence-result &'.format(False))
if returnConvergenceInfo:
convergeInfo[host.name][node.name] = []
if statusRouterCheck:
convergeInfo[host.name][node.name].append(routerPrefix)
if statusPrefixCheck:
convergeInfo[host.name][node.name].append(namePrefix)
else:
host.cmd('echo {} > convergence-result &'.format(True))
if didNlsrConverge:
if quit:
info('NLSR has converged successfully. Exiting...\n')
ndn.stop()
sys.exit(0)
else:
info('NLSR has converged successfully.\n')
else:
if quit:
info('NLSR has not converged. Exiting...\n')
ndn.stop()
sys.exit(1)
else:
info('NLSR has not converged.\n')
if returnConvergenceInfo:
return didNlsrConverge, convergeInfo
else:
return didNlsrConverge
@staticmethod
def setupPing(hosts, strategy):
for host in hosts:
host.cmd('mkdir -p ping-data')
Nfdc.setStrategy(host, '/ndn/', strategy)
prefix = getSafeName('/ndn/{}-site/{}'.format(host.name, host.name))
NDNPing.startPingServer(host, prefix)
@staticmethod
def startPctPings(net, nPings, pctTraffic=1.0):
nNodesToPing = int(round(len(net.hosts) * pctTraffic))
info('Each node will ping {} node(s)\n'.format(nNodesToPing))
# Temporarily store all the nodes being pinged by a particular node
nodesPingedList = []
pingedDict = {}
for host in net.hosts:
# Create a circular list
pool = cycle(net.hosts)
# Move iterator to current node
next(x for x in pool if host.name == x.name)
# Track number of nodes to ping scheduled for this node
nNodesScheduled = 0
while nNodesScheduled < nNodesToPing:
other = next(pool)
# Do not ping self
if host.name != other.name:
destPrefix = getSafeName('/ndn/{}-site/{}'.format(other.name, other.name))
NDNPing.ping(host, destPrefix, other.name, nPings)
nodesPingedList.append(other)
# Always increment because in 100% case a node should not ping itself
nNodesScheduled = nNodesScheduled + 1
pingedDict[host] = nodesPingedList
nodesPingedList = []
return pingedDict
-203
View File
@@ -1,203 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from igraph import Graph
from mininet.log import info, debug
class LinkInfo(object):
"""
This class is used to encapsule link information (IP and interface names).
"""
def __init__(self, start_intf_name, start_ip, end_intf_name, end_ip):
self.start_intf_name = start_intf_name
self.start_intf_ip = start_ip
self.end_intf_name = end_intf_name
self.end_ip = end_ip
class IPRoutingHelper(object):
"""The routing helper allows to run IP-based evaluations with Mini-NDN. It configures static IP
routes to all nodes, which means that all nodes can reach all other nodes in the network
reachable, even when relaying is required.
Usage from Experiment folder: `IPRoutingHelper.calcAllRoutes(self.net)`
"""
@staticmethod
def findLinkInformation(links, first_node, second_node):
""" This method returns link information of a link connecting two nodes.
:param links: All links in the emulation topology
:param first_node: Current node which is looked at
:param second_node: Target node (neighbour of first_node)
:return: Link information as LinkInfo object, or returns null None if the
nodes are not directly connected
"""
for link in links:
if link.intf1.node.name == first_node and link.intf2.node.name == second_node:
return LinkInfo(link.intf1.name, link.intf1.ip, link.intf2.name, link.intf2.ip)
elif link.intf2.node.name == first_node and link.intf1.node.name == second_node:
return LinkInfo(link.intf2.name, link.intf2.ip, link.intf1.name, link.intf1.ip)
return None
@staticmethod
def calculateAllSubPaths(path):
""" This method returns all subpaths in forward and reverse order of a given path
:param path: Given path for which subpaths are calculated
:return: List of all subpaths
"""
paths = []
# Append original path and reversed path
paths.append(path)
reversed = path[:]
reversed.reverse()
paths.append(reversed)
# Iterate over all possible lengths for subpaths
for subpath_length in range(2, len(path)):
# Get all subpaths of length subpath_lenght of the given path
for start_index in range(0, len(path) - subpath_length + 1):
subpath = path[start_index: start_index + subpath_length]
paths.append(subpath)
subpath = subpath[:]
subpath.reverse()
paths.append(subpath)
return paths
@staticmethod
def replaceExistingSubpaths(path, existing_paths):
subpaths = []
for subpath_length in range(3, len(path)):
for start_index in range(0, len(path) - subpath_length + 1):
subpaths.append(path[start_index: start_index + subpath_length])
subpaths.reverse()
for subpath in subpaths:
if len(subpath) == len(path):
continue
if (subpath[0], subpath[-1]) in existing_paths:
existing = existing_paths[(subpath[0], subpath[-1])]
path = path[:path.index(existing[0])] + existing[:] + path[
path.index(existing[-1]) + 1:]
break
return path
@staticmethod
def calcAllRoutes(net):
""" Configures IP routes between all nodes in the emulation topology. This is done in three
steps:
1) IP forwarding is enabled on all nodes
2) The igraph lib is used to calculate all shortest paths between the nodes
3) Route add commands are used to actually configure the ip routes
:param net:
"""
mini_nodes = net.hosts
mini_links = net.links
# Enabling IP forwaring on all nodes
info('Configure IP forwarding on all nodes\n')
for node in mini_nodes:
node.cmd('sysctl -w net.ipv4.ip_forward=1')
# Create the network graph to calculate all shortest paths between nodes
node_names = [node.name for node in mini_nodes]
links = []
for link in mini_links:
links.append((link.intf1.node.name, link.intf2.node.name))
links.append((link.intf2.node.name, link.intf1.node.name))
networkGraph = Graph()
networkGraph = networkGraph.as_directed()
for node in node_names:
networkGraph.add_vertex(node)
for (a, b) in links:
networkGraph.add_edges([(a, b), (b, a)])
existing_paths = {} # Variable existing_paths stores all paths that are installed
shortest_paths = [] # List of calculated shorted paths betweeen all nodes
# Calculate shortest paths between all nodes using libigraph
for from_node in node_names:
for to_node in node_names:
if from_node != to_node:
if (from_node, to_node) in existing_paths \
or (to_node, from_node) in existing_paths:
continue
paths = networkGraph.get_all_shortest_paths(from_node, to_node)
if len(paths) == 0:
continue
paths.sort(key=lambda x: str(x))
paths.sort(key=lambda x: len(x))
shortest_path = paths[0] # Shortest path with node indizes as nodes
# Translate node indizes to node names
shortest_path_nodenames = [networkGraph.vs['name'][node]
for node in shortest_path]
shortest_paths.append(shortest_path_nodenames)
# Iterate over shortest paths and store subpaths that need to be installed on the nodes.
# Also, it is made sure that all paths and reverse paths are the same
shortest_paths.sort(key=lambda x: len(x), reverse=True)
for path in shortest_paths:
# Replace already existing subpaths of the path to make sure that no two paths between
# two nodes exist
path = IPRoutingHelper.replaceExistingSubpaths(path, existing_paths)
# Mark all subpaths of path to install on nodes, unless they already exist
subpaths = IPRoutingHelper.calculateAllSubPaths(path)
for subpath in subpaths:
if (subpath[0], subpath[-1]) not in existing_paths:
existing_paths[(subpath[0], subpath[-1])] = subpath
# Iterate over all paths and configure the routes using the 'route add'
info('Configure routes on all nodes\n')
for path in existing_paths.values():
start_node = path[0]
end_node = path[-1]
mini_start = net.get(start_node)
mini_end = net.get(end_node)
link_info = IPRoutingHelper.findLinkInformation(mini_links, path[0], path[1])
start_intf = link_info.start_intf_name
# Configure the route for every IP address of the destination
for intf in mini_end.intfs:
addr = mini_end.intfs[intf].ip
if len(path) == 2:
# For direct connection, configure exit interface
debug('[{}] route add -host {} dev {}\n'.format(start_node, addr, start_intf))
mini_start.cmd('route add -host {} dev {}'.format(addr, start_intf))
elif len(path) > 2:
# For longer paths, configure next hop as gateway
gateway_ip = link_info.end_ip
debug('[{}] route add -host {} dev {} gw {}\n'
.format(start_node, addr, start_intf, gateway_ip))
mini_start.cmd('route add -host {} dev {} gw {}'
.format(addr, start_intf, gateway_ip))
-394
View File
@@ -1,394 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
# IMPORTANT! This feature is in highly experimental phase and may go several changes
# in future
'''
This module will compute link state, hyperbolic and geohyperbolic
routes and their costs from the given Mini-NDN topology
'''
import sys
import heapq
from math import sin, cos, sinh, cosh, acos, acosh
import json
import operator
from collections import defaultdict
from joblib import Parallel, delayed
from mininet.log import info, debug, error, warn
from minindn.helpers.nfdc import Nfdc as nfdc
UNKNOWN_DISTANCE = -1
HYPERBOLIC_COST_ADJUSTMENT_FACTOR = 1000
def dijkstra(graph, start, end, ignoredNode=None):
"""
Compute shortest path and cost from a given source to a destination
using Dijkstra algorithm
:param Graph graph: given network topology/graph
:param Start start: source node in a given network graph/topology
:end End end: destination node in a given network graph/topology
:param Node ignoredNode: node to ignore computing shortest path from
"""
queue = [(0, start, [])]
seen = set()
while True:
(cost, v, path) = heapq.heappop(queue)
if v not in seen:
path = path + [v]
seen.add(v)
if v == end:
debug("Distance from {} to {} is {}".format(start, end, cost))
return cost, path
for (_next, c) in graph[v].items():
if _next != ignoredNode: # Ignore path going via ignoreNode
heapq.heappush(queue, (cost + c, _next, path))
if not queue: # return if no path exist from source - destination except via ignoreNode
debug("Distance from {} to {} is {}".format(start, end, cost))
return cost, None
def calculateAngularDistance(angleVectorI, angleVectorJ):
"""
For hyperbolic/geohyperbolic routing algorithm, this function computes angular distance between
two nodes. A node can have two or more than two angular coordinates.
:param AngleVectorI angleVectorI: list of angular coordinate of a give node I
:param AngleVectorJ angleVectorJ: list of angular coordinate of a give node J
ref: https://en.wikipedia.org/wiki/N-sphere#Spherical_coordinates
"""
innerProduct = 0.0
if len(angleVectorI) != len(angleVectorJ):
error("Angle vector sizes do not match")
return UNKNOWN_DISTANCE
# Calculate x0 of the vectors
x0i = cos(angleVectorI[0])
x0j = cos(angleVectorJ[0])
# Calculate xn of the vectors
xni = sin(angleVectorI[len(angleVectorI) - 1])
xnj = sin(angleVectorJ[len(angleVectorJ) - 1])
# Do the aggregation of the (n-1) coordinates (if there is more than one angle)
# i.e contraction of all (n-1)-dimensional angular coordinates to one variable
for k in range(0, len(angleVectorI)-1):
xni *= sin(angleVectorI[k])
xnj *= sin(angleVectorJ[k])
innerProduct += (x0i * x0j) + (xni * xnj)
if len(angleVectorI) > 1:
for m in range(1, len(angleVectorI)):
# Calculate euclidean coordinates given the angles and assuming R_sphere = 1
xmi = cos(angleVectorI[m])
xmj = cos(angleVectorJ[m])
for l in range(0, m):
xmi *= sin(angleVectorI[l])
xmj *= sin(angleVectorJ[l])
innerProduct += xmi * xmj
# ArcCos of the inner product gives the angular distance
# between two points on a d-dimensional sphere
angularDist = acos(innerProduct)
debug("Angular distance from {} to {} is {}".format(angleVectorI, angleVectorJ, angularDist))
return angularDist
def getHyperbolicDistance(sourceNode, destNode):
"""
Return hyperbolic or geohyperbolic distance between two nodes. The distance is computed
on the basis of following algorithm/mathematics
ref: https://en.wikipedia.org/wiki/Hyperbolic_geometry
"""
r1 = [key for key in sourceNode][0]
r2 = [key for key in destNode][0]
zeta = 1.0
dtheta = calculateAngularDistance(sourceNode[r1], destNode[r2])
hyperbolicDistance = (1./zeta) * acosh(cosh(zeta * r1) * cosh(zeta * r2) -\
sinh(zeta * r1) * sinh(zeta * r2) * cos(dtheta))
debug("Distance from {} to {} is {}".format(sourceNode, destNode, hyperbolicDistance))
return hyperbolicDistance
class _CalculateRoutes(object):
"""
Creates a route calculation object, which is used to compute routes from a node to
every other nodes in a given topology topology using hyperbolic or geohyperbolic
routing algorithm
:param NetObject netObj: Mininet net object
:param RoutingType routingType: (optional) Routing algorithm, link-state or hr etc
"""
def __init__(self, netObj, routingType):
self.adjacenctMatrix = defaultdict(dict)
self.nodeDict = defaultdict(dict)
self.routingType = routingType
self.isHrConfigValid = True
for host in netObj.hosts:
if 'radius' in host.params['params']:
radius = float(host.params['params']['radius'])
else:
self.isHrConfigValid = False
radius = 0.0
if 'angle' in host.params['params']:
angles = [float(x) for x in host.params['params']['angle'].split(',')]
else:
self.isHrConfigValid = False
angles = [0.0]
self.nodeDict[host.name][radius] = angles
for link in netObj.topo.links(withInfo=True):
linkDelay = int(link[2]['delay'].replace("ms", ""))
self.adjacenctMatrix[link[0]][link[1]] = linkDelay
self.adjacenctMatrix[link[1]][link[0]] = linkDelay
def getNestedDictionary(self):
return defaultdict(self.getNestedDictionary)
def getRoutes(self, nFaces):
resultMatrix = self.getNestedDictionary()
routes = defaultdict(list)
if self.routingType == "link-state":
if nFaces == 1:
resultMatrix = self.computeDijkastra() # only best routes.
else:
resultMatrix = self.computeDijkastraAll() # all possible routes
elif self.routingType == "hr":
if self.isHrConfigValid == True:
# Note: For hyperbolic, only way to find the best routes is by
# computing all possible routes and getting the best one.
resultMatrix = self.computeHyperbolic()
else:
warn('Hyperbolic coordinates in topology file are either missing or misconfigured.\n')
warn('Check that each node has one radius value and one or two angle value(s).\n')
return None
for node in resultMatrix:
for destinationNode in resultMatrix[node]:
# Sort node - destination via neighbor based on their cost
tempDict = resultMatrix[node][destinationNode]
shortedTempDict = sorted(tempDict.items(), key=operator.itemgetter(1))
# nFaces option gets n-best faces based on shortest distance, default is all
if nFaces == 0:
for item in shortedTempDict:
viaNeighbor = item[0]
cost = item[1]
routes[node].append([destinationNode, str(cost), viaNeighbor])
else:
for index, item in enumerate(shortedTempDict):
if index >= nFaces:
break
viaNeighbor = item[0]
cost = item[1]
routes[node].append([destinationNode, str(cost), viaNeighbor])
debug("-routes----", routes)
return routes
def getNodeNames(self):
return [k for k in self.nodeDict]
def computeHyperbolic(self):
paths = self.getNestedDictionary()
nodeNames = self.getNodeNames()
for node in self.nodeDict:
neighbors = [k for k in self.adjacenctMatrix[node]]
for viaNeighbor in neighbors:
others = [x for x in nodeNames if x not in [viaNeighbor, node]]
paths[node][viaNeighbor][viaNeighbor] = 0
# Compute distance from neighbors to no-neighbors
for destinationNode in others:
hyperbolicDistance = getHyperbolicDistance(self.nodeDict[viaNeighbor],
self.nodeDict[destinationNode])
hyperbolicCost = int(HYPERBOLIC_COST_ADJUSTMENT_FACTOR \
* round(hyperbolicDistance, 6))
paths[node][destinationNode][viaNeighbor] = hyperbolicCost
debug("Shortest Distance Matrix: {}".format(json.dumps(paths)))
return paths
def computeDijkastra(self):
"""
Dijkstra computation: Compute all the shortest paths from nodes to the destinations.
And fills the distance matrix with the corresponding source to destination cost
"""
distanceMatrix = self.getNestedDictionary()
nodeNames = self.getNodeNames()
for node in nodeNames:
others = [x for x in nodeNames if x not in [node]]
for destinationNode in others:
cost, path = dijkstra(self.adjacenctMatrix, node, destinationNode)
viaNeighbor = path[1]
distanceMatrix[node][destinationNode][viaNeighbor] = cost
debug("Shortest Distance Matrix: {}".format(json.dumps(distanceMatrix)))
return distanceMatrix
def computeDijkastraAll(self):
"""
Multi-path Dijkastra computation: Compute all the shortest paths from nodes to the
destinations via all of its neighbors individually. And fills the distanceMatrixViaNeighbor
with a corresponding source to its destination cost
Important: distanceMatrixViaNeighbor represents the shortest distance from a source to a
destination via specific neighbors
"""
distanceMatrixViaNeighbor = self.getNestedDictionary()
nodeNames = self.getNodeNames()
for node in nodeNames:
neighbors = [k for k in self.adjacenctMatrix[node]]
for viaNeighbor in neighbors:
directCost = self.adjacenctMatrix[node][viaNeighbor]
distanceMatrixViaNeighbor[node][viaNeighbor][viaNeighbor] = directCost
others = [x for x in nodeNames if x not in [viaNeighbor, node]]
for destinationNode in others:
nodeNeighborCost = self.adjacenctMatrix[node][viaNeighbor]
# path variable is not used for now
cost, path = dijkstra(self.adjacenctMatrix, viaNeighbor, destinationNode, node)
if cost != 0 and path != None:
totalCost = cost + nodeNeighborCost
distanceMatrixViaNeighbor[node][destinationNode][viaNeighbor] = totalCost
debug("Shortest Distance Matrix: {}".format(json.dumps(distanceMatrixViaNeighbor)))
return distanceMatrixViaNeighbor
class NdnRoutingHelper(object):
"""
This module is a helper class which helps to create face and register routes
to NFD from a given node to all of its neighbors.
:param NetObject netObject: Mininet net object
:param FaceType faceType: UDP, Ethernet etc.
:param Routing routingType: (optional) Routing algorithm, link-state or hr etc
"""
def __init__(self, netObject, faceType=nfdc.PROTOCOL_UDP, routingType="link-state", permanentFaces=False):
self.net = netObject
self.faceType = faceType
self.routingType = routingType
self.permanentFaces = permanentFaces
self.routes = []
self.namePrefixes = {host_name.name: [] for host_name in self.net.hosts}
self.routeObject = _CalculateRoutes(self.net, self.routingType)
def globalRoutingHelperHandler(self):
info('Creating faces and adding routes to FIB\n')
res = Parallel(n_jobs=-1, require='sharedmem',
prefer="threads", verbose=1)(delayed(self.addNodeRoutes)(host) for host in self.net.hosts)
info('Processed all the routes to NFD\n')
def addNodeRoutes(self, node):
"""
Create faces to neighbors and add all routes for one node
:param Node node: Node from net object
"""
neighborIPs = self.getNeighbor(node)
neighborFaces = self.createFaces(node, neighborIPs)
self.routeAdd(node, neighborFaces)
def addOrigin(self, nodes, prefix):
"""
Add prefix/s as origin on node/s
:param Prefix prefix: Prefix that is originated by node/s (as producer) for this prefix
:param Nodes nodes: List of nodes from net object
"""
for node in nodes:
if not node.name in self.namePrefixes:
self.namePrefixes[node.name] = []
self.namePrefixes[node.name] += prefix
def calculateNPossibleRoutes(self, nFaces=0):
"""
By default, calculates all possible routes i.e. routes via all the faces of a node.
pass nFaces if want to compute routes via n number of faces. e.g. 2. For larger topology
the computation might take huge amount of time.
:param int nFaces: (optional) number of faces to consider while computing routes. Default
i.e. nFaces = 0 will compute all possible routes
"""
self.routes = self.routeObject.getRoutes(nFaces)
if self.routes is not None:
info('Route computation completed\n')
self.globalRoutingHelperHandler()
else:
warn('Route computation failed\n')
self.net.stop()
sys.exit(1)
def calculateRoutes(self):
# Calculate shortest path for every node
self.calculateNPossibleRoutes(nFaces=1)
def createFaces(self, node, neighborIPs):
neighborFaces = {}
for k, ip in neighborIPs.items():
faceID = nfdc.createFace(node, ip, self.faceType, self.permanentFaces)
if not isinstance(faceID, str): raise ValueError(faceID)
neighborFaces[k] = faceID
return neighborFaces
def routeAdd(self, node, neighborFaces):
"""
Add route from a node to its neighbors for each prefix/s advertised by destination node
:param Node node: source node (Mininet net.host)
:param IP neighborIPs: IP addresses of neighbors
"""
neighbors = self.routes[node.name]
for route in neighbors:
destination = route[0]
cost = int(route[1])
nextHop = route[2]
defaultPrefix = "/ndn/{}-site/{}".format(destination, destination)
prefixes = [defaultPrefix] + self.namePrefixes[destination]
for prefix in prefixes:
# Register routes to all the available destination name prefix/s
nfdc.registerRoute(node, prefix, neighborFaces[nextHop], cost=cost)
@staticmethod
def getNeighbor(node):
# Nodes to IP mapping
neighborIPs = defaultdict()
for intf in node.intfList():
link = intf.link
if link:
node1, node2 = link.intf1.node, link.intf2.node
if node1 == node:
other = node2
ip = other.IP(str(link.intf2))
else:
other = node1
ip = other.IP(str(link.intf1))
# Used later to create faces
neighborIPs[other.name] = ip
return neighborIPs
-73
View File
@@ -1,73 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
# Todo: convert to app
class NDNPing(object):
@staticmethod
def ping(source, prefix, pingDataFile="output-client", nPings=1, interval=None, timeout=None,
starting_seq_num=None, identifier=None, allow_stale_data=False, print_timestamp=True,
sleepTime=0.2):
print('Scheduling ping(s) from {} for {}'.format(source.name, prefix))
# Use '&' to run in background and perform parallel pings
source.cmd("mkdir -p ping-data")
source.cmd('ndnping{1}{2}{3}{4}{5}{6}{7} {0} >> ping-data/{8}.txt &'
.format(
prefix,
' -c {}'.format(nPings),
' -i {}'.format(interval) if interval else '',
' -o {}'.format(timeout) if timeout else '',
' -n {}'.format(starting_seq_num) if starting_seq_num else '',
' -p {}'.format(identifier) if identifier else '',
' -a' if allow_stale_data else '',
' -t' if print_timestamp else '',
pingDataFile
))
time.sleep(sleepTime)
@staticmethod
def startPingServer(source, prefix, pingDataFile="output-server", freshness=None, satisfy=None,
size=None, timestamp=False, quiet=False):
"""
Start a pingserver
:param string preifx: prefix to start pingserver on
:param int freshness: FreshnessPeriod of the ping response, in milliseconds
:param int satisfy: maximum number of pings to satisfy
:param int size: size of response payload
:param boolean timestamp: prepend a timestamp to each log message
:param boolean quite: do not print a log message each time a ping packet is received
"""
print('Staring ping server on prefix {}'.format(prefix))
source.cmd("mkdir -p ping-data")
cmd = 'ndnpingserver {1}{2}{3}{4}{5} {0}>> ping-data/{6}.txt &'.format(
prefix,
'-f {}'.format(freshness) if freshness else '',
'-p {}'.format(satisfy) if satisfy else '',
'-s {}'.format(size) if size else '',
'{}'.format('-t') if timestamp else '',
'{}'.format('-q') if quiet else '',
pingDataFile
)
source.cmd(cmd)
-131
View File
@@ -1,131 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
from mininet.log import debug, warn
from minindn.minindn import Minindn
# If needed (e.g. to speed up the process), use a smaller (or larger value)
# based on your machines resource (CPU, memory)
SLEEP_TIME = 0.0015
class Nfdc(object):
STRATEGY_ASF = 'asf'
STRATEGY_BEST_ROUTE = 'best-route'
STRATEGY_MULTICAST = 'multicast'
STRATEGY_NCC = 'ncc'
PROTOCOL_UDP = 'udp'
PROTOCOL_TCP = 'tcp'
PROTOCOL_ETHER = 'ether'
@staticmethod
def registerRoute(node, namePrefix, remoteNode, protocol=PROTOCOL_UDP, origin=255,
cost=0, inheritFlag=True, captureFlag=False, expirationInMillis=None):
cmd = ""
if remoteNode.isdigit() and not protocol == "fd":
cmd = ('nfdc route add {} {} origin {} cost {} {}{}{}').format(
namePrefix,
remoteNode,
origin,
cost,
'no-inherit ' if not inheritFlag else '',
'capture ' if captureFlag else '',
'expires {}'.format(expirationInMillis) if expirationInMillis else ''
)
else:
cmd = ('nfdc route add {} {}://{} origin {} cost {} {}{}{}').format(
namePrefix,
protocol,
remoteNode,
origin,
cost,
'no-inherit ' if not inheritFlag else '',
'capture ' if captureFlag else '',
'expires {}'.format(expirationInMillis) if expirationInMillis else ''
)
debug(node.cmd(cmd))
Minindn.sleep(SLEEP_TIME)
@staticmethod
def unregisterRoute(node, namePrefix, remoteNode, origin=255):
cmd = ""
if remoteNode.isdigit() and not protocol == "fd":
cmd = 'nfdc route remove {} {} {}'.format(namePrefix, remoteNode, origin)
else:
cmd = 'nfdc route remove {} {} {}'.format(namePrefix, remoteNode, origin)
debug(node.cmd(cmd))
Minindn.sleep(SLEEP_TIME)
@staticmethod
def createFace(node, remoteNodeAddress, protocol='udp', isPermanent=False, allowExisting=True, bandwidth=100000000):
'''Create face in node's NFD instance. Returns FaceID of created face or -1 if failed.'''
cmd = ('nfdc face create {}://{} bandwidth {} persistency {}'.format(
protocol,
remoteNodeAddress,
int(bandwidth),
'permanent' if isPermanent else 'persistent'
))
output = node.cmd(cmd)
debug(output)
Minindn.sleep(SLEEP_TIME)
if "face-created" in output or (allowExisting and "face-exists" in output):
faceID = output.split(" ")[1][3:]
return faceID
warn("["+ node.name + "] Face register failed: " + output)
return -1
@staticmethod
def destroyFace(node, remoteNode, protocol='udp'):
if remoteNode.isdigit() and not protocol == "fd":
debug(node.cmd('nfdc face destroy {}'.format(protocol, remoteNode)))
else:
debug(node.cmd('nfdc face destroy {}://{}'.format(protocol, remoteNode)))
Minindn.sleep(SLEEP_TIME)
@staticmethod
def setStrategy(node, namePrefix, strategy):
cmd = 'nfdc strategy set {} ndn:/localhost/nfd/strategy/{}'.format(namePrefix, strategy)
out = node.cmd(cmd)
if out.find('error') != -1:
warn("[" + node.name + "] Error on strategy set out: " + out)
Minindn.sleep(SLEEP_TIME)
@staticmethod
def unsetStrategy(node, namePrefix):
debug(node.cmd("nfdc strategy unset {}".format(namePrefix)))
Minindn.sleep(SLEEP_TIME)
@staticmethod
def getFaceId(node, remoteNodeAddress, localEndpoint=None, protocol="udp", portNum="6363"):
'''Returns the faceId for a remote node based on FaceURI, or -1 if a face is not found'''
#Should this be cached or is the hit not worth it?
local = ""
if localEndpoint:
local = " local {}".format(localEndpoint)
output = node.cmd("nfdc face list remote {}://{}:{}{}".format(protocol, remoteNodeAddress, portNum, local))
debug(output)
Minindn.sleep(SLEEP_TIME)
# This is fragile but we don't have that many better options
if "faceid=" not in output:
return -1
faceId = output.split(" ")[0][7:]
return faceId
-52
View File
@@ -1,52 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import time
from threading import Timer
class ProcessMonitor(object):
def __init__(self, processId, processName, outputDir, interval=1):
self._processId = processId.strip()
self._processName = processName
self._statFile = '/proc/{}/stat'.format(self._processId)
self._logFile = '{}/{}-{}-stat.txt'.format(outputDir, self._processName, self._processId)
self._interval = interval
def _recordStats(self):
try:
with open(self._statFile, 'r') as stat:
currentTime = int(time.time())
with open(self._logFile, 'a') as log:
for line in stat:
log.write('{} {}'.format(currentTime, line))
except IOError as e:
print('I/O error({0}): {1}'.format(e.errno, e.strerror))
print('No process with PID={}'.format(self._processId))
return
self.start() # Reschedule event
def start(self):
self._timer = Timer(self._interval, self._recordStats)
self._timer.start()
-376
View File
@@ -1,376 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import argparse
import sys
import time
import os
import configparser
from subprocess import call, Popen, PIPE
import shutil
import glob
from traceback import format_exc
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.link import TCLink
from mininet.node import Switch
from mininet.util import ipStr, ipParse
from mininet.log import info, debug, error
class Minindn(object):
"""
This class provides the following features to the user:
1) Wrapper around Mininet object with option to pass topology directly
1.1) Users can pass custom argument parser to extend the default on here
2) Parses the topology file given via command line if user does not pass a topology object
3) Provides way to stop Mini-NDN via stop
3.1) Applications register their clean up function with this class
4) Sets IPs on neighbors for connectivity required in a switch-less topology
5) Some other utility functions
"""
ndnSecurityDisabled = False
workDir = '/tmp/minindn'
resultDir = None
def __init__(self, parser=argparse.ArgumentParser(), topo=None, topoFile=None, noTopo=False,
link=TCLink, workDir=None, **mininetParams):
"""
Create MiniNDN object
:param parser: Parent parser of Mini-NDN parser
:param topo: Mininet topo object (optional)
:param topoFile: Mininet topology file location (optional)
:param noTopo: Allows specification of topology after network object is
initialized (optional)
:param link: Allows specification of default Mininet link type for connections between
nodes (optional)
:param mininetParams: Any params to pass to Mininet
"""
self.parser = Minindn.parseArgs(parser)
self.args = self.parser.parse_args()
if not workDir:
Minindn.workDir = os.path.abspath(self.args.workDir)
else:
Minindn.workDir = os.path.abspath(workDir)
Minindn.resultDir = self.args.resultDir
if not topoFile:
# Args has default topology if none specified
self.topoFile = self.args.topoFile
else:
self.topoFile = topoFile
self.faces_to_create = {}
if topo is None and not noTopo:
try:
info('Using topology file {}\n'.format(self.topoFile))
self.topo, self.faces_to_create = self.processTopo(self.topoFile)
except configparser.NoSectionError as e:
info('Error reading config file: {}\n'.format(e))
sys.exit(1)
else:
self.topo = topo
if not noTopo:
self.net = Mininet(topo=self.topo, link=link, **mininetParams)
else:
self.net = Mininet(link=link, **mininetParams)
self.initParams(self.net.hosts)
self.cleanups = []
if not self.net.switches:
self.ethernetPairConnectivity()
try:
process = Popen(['ndnsec-get-default', '-k'], stdout=PIPE, stderr=PIPE)
output, error = process.communicate()
if process.returncode == 0:
Minindn.ndnSecurityDisabled = '/dummy/KEY/-%9C%28r%B8%AA%3B%60' in output.decode("utf-8")
info('Dummy key chain patch is installed in ndn-cxx. Security will be disabled.\n')
else:
debug(error)
except:
pass
@staticmethod
def parseArgs(parent):
parser = argparse.ArgumentParser(prog='minindn', parents=[parent], add_help=False)
# nargs='?' required here since optional argument
parser.add_argument('topoFile', nargs='?', default='/usr/local/etc/mini-ndn/default-topology.conf',
help='If no template_file is given, topologies/default-topology.conf \
will be used.')
parser.add_argument('--work-dir', action='store', dest='workDir', default='/tmp/minindn',
help='Specify the working directory; default is /tmp/minindn')
parser.add_argument('--result-dir', action='store', dest='resultDir', default=None,
help='Specify the full path destination folder where experiment \
results will be moved')
return parser
def ethernetPairConnectivity(self):
ndnNetBase = '10.0.0.0'
interfaces = []
for host in self.net.hosts:
for intf in host.intfList():
link = intf.link
node1, node2 = link.intf1.node, link.intf2.node
if isinstance(node1, Switch) or isinstance(node2, Switch):
continue
if link.intf1 not in interfaces and link.intf2 not in interfaces:
interfaces.append(link.intf1)
interfaces.append(link.intf2)
node1.setIP(ipStr(ipParse(ndnNetBase) + 1) + '/30', intf=link.intf1)
node2.setIP(ipStr(ipParse(ndnNetBase) + 2) + '/30', intf=link.intf2)
ndnNetBase = ipStr(ipParse(ndnNetBase) + 4)
@staticmethod
def processTopo(topoFile):
config = configparser.ConfigParser(delimiters=' ', allow_no_value=True)
config.read(topoFile)
topo = Topo()
items = config.items('nodes')
coordinates = []
for item in items:
name = item[0].split(':')[0]
params = {}
if item[1]:
if all (x in item[1] for x in ['radius', 'angle']) and item[1] in coordinates:
error("FATAL: Duplicate Coordinate, \'{}\' used by multiple nodes\n" \
.format(item[1]))
sys.exit(1)
coordinates.append(item[1])
for param in item[1].split(' '):
if param == '_':
continue
params[param.split('=')[0]] = param.split('=')[1]
topo.addHost(name, params=params)
try:
items = config.items('switches')
for item in items:
name = item[0].split(':')[0]
topo.addSwitch(name)
except configparser.NoSectionError:
# Switches are optional
pass
items = config.items('links')
for item in items:
link = item[0].split(':')
params = {}
for param in item[1].split(' '):
key = param.split('=')[0]
value = param.split('=')[1]
if key in ['jitter', 'max_queue_size']:
value = int(value)
if key == 'loss' or key == 'bw':
value = float(value)
params[key] = value
topo.addLink(link[0], link[1], **params)
faces = {}
try:
items = config.items('faces')
debug("Faces")
for item in items:
face_a, face_b = item[0].split(':')
debug(item)
cost = -1
for param in item[1].split(' '):
if param.split("=")[0] == 'cost':
cost = param.split("=")[1]
face_info = (face_b, int(cost))
if face_a not in faces:
faces[face_a] = [face_info]
else:
faces[face_a].append(face_info)
except configparser.NoSectionError:
debug("Faces section is optional")
pass
return (topo, faces)
return topo
def start(self):
self.net.start()
time.sleep(3)
def stop(self):
for cleanup in self.cleanups:
cleanup()
self.net.stop()
if Minindn.resultDir is not None:
info("Moving results to \'{}\'\n".format(Minindn.resultDir))
os.system("mkdir -p {}".format(Minindn.resultDir))
for file in glob.glob('{}/*'.format(Minindn.workDir)):
shutil.move(file, Minindn.resultDir)
@staticmethod
def cleanUp():
devnull = open(os.devnull, 'w')
call('nfd-stop', stdout=devnull, stderr=devnull)
call('mn --clean'.split(), stdout=devnull, stderr=devnull)
@staticmethod
def verifyDependencies():
"""Prevent MiniNDN from running without necessary dependencies"""
dependencies = ['nfd', 'nlsr', 'infoedit', 'ndnping', 'ndnpingserver']
devnull = open(os.devnull, 'w')
# Checks that each program is in the system path
for program in dependencies:
if call(['which', program], stdout=devnull):
error('{} is missing from the system path! Exiting...\n'.format(program))
sys.exit(1)
devnull.close()
@staticmethod
def sleep(seconds):
# sleep is not required if ndn-cxx is using in-memory keychain
if not Minindn.ndnSecurityDisabled:
time.sleep(seconds)
@staticmethod
def handleException():
"""Utility method to perform cleanup steps and exit after catching exception"""
Minindn.cleanUp()
info(format_exc())
exit(1)
def getInterfaceDelay(self, node, interface):
tc_output = node.cmd("tc qdisc show dev {}".format(interface))
for line in tc_output.splitlines():
if "qdisc netem 10:" in line:
split_line = line.split(" ")
for index in range(0, len(split_line)):
if split_line[index] == "delay":
return float(split_line[index + 1][:-2])
return 0.0
def initParams(self, nodes):
"""Initialize Mini-NDN parameters for array of nodes"""
for host in nodes:
if 'params' not in host.params:
host.params['params'] = {}
host.params['params']['workDir'] = Minindn.workDir
homeDir = '{}/{}'.format(Minindn.workDir, host.name)
host.params['params']['homeDir'] = homeDir
host.cmd('mkdir -p {}'.format(homeDir))
host.cmd('export HOME={} && cd ~'.format(homeDir))
def nfdcBatchProcessing(self, station, faces):
print("???")
# Input format: [IP, protocol, isPermanent]
batch_file = open("{}/{}/nfdc.batch".format(Minindn.workDir, station.name), "w")
lines = []
for face in faces:
ip = face[0]
protocol = face[1]
if face[2]:
face_type = "permanent"
else:
face_type = "persistent"
nfdc_command = "face create {}://{} {}\n".format(protocol, ip, face_type)
lines.append(nfdc_command)
batch_file.writelines(lines)
batch_file.close()
debug(station.cmd("nfdc -f {}/{}/nfdc.batch".format(Minindn.workDir, station.name)))
def setupFaces(self, faces_to_create=None):
""" Method to create unicast faces between connected nodes;
Returns dict- {node: (other node name, other node IP, other node's delay as int)}.
This is intended to pass to the NLSR helper via the faceDict param """
if not faces_to_create:
faces_to_create = self.faces_to_create
# (nodeName, IP, delay as int)
# list of tuples
created_faces = dict()
batch_faces = dict()
for nodeAname in faces_to_create.keys():
if not nodeAname in batch_faces.keys():
batch_faces[nodeAname] = []
for nodeBname, faceCost in faces_to_create[nodeAname]:
if not nodeBname in batch_faces.keys():
batch_faces[nodeBname] = []
nodeA = self.net[nodeAname]
nodeB = self.net[nodeBname]
if nodeA.connectionsTo(nodeB):
best_interface = None
delay = None
for interface in nodeA.connectionsTo(nodeB):
interface_delay = self.getInterfaceDelay(nodeA, interface[0])
if not delay or int(interface_delay) < delay:
best_interface = interface
faceAIP = best_interface[0].IP()
faceBIP = best_interface[1].IP()
# Node delay will be symmetrical for connected nodes
nodeDelay = int(self.getInterfaceDelay(nodeA, best_interface[0]))
#nodeBDelay = int(self.getInterfaceDelay(nodeB, best_interface[1]))
else:
# If no direct wired connections exist (ie when using a switch),
# assume the default interface
faceAIP = nodeA.IP()
faceBIP = nodeB.IP()
nodeADelay = int(self.getInterfaceDelay(nodeA, nodeA.defaultIntf()))
nodeBDelay = int(self.getInterfaceDelay(nodeB, nodeB.defaultIntf()))
nodeDelay = nodeADelay + nodeBDelay
if not faceCost == -1:
nodeALink = (nodeA.name, faceAIP, faceCost)
nodeBLink = (nodeB.name, faceBIP, faceCost)
else:
nodeALink = (nodeA.name, faceAIP, nodeDelay)
nodeBLink = (nodeB.name, faceBIP, nodeDelay)
# Importing this before initialization causes issues
batch_faces[nodeAname].append([faceBIP, "udp", True])
batch_faces[nodeBname].append([faceAIP, "udp", True])
if nodeA not in created_faces:
created_faces[nodeA] = [nodeBLink]
else:
created_faces[nodeA].append(nodeBLink)
if nodeB not in created_faces:
created_faces[nodeB] = [nodeALink]
else:
created_faces[nodeB].append(nodeALink)
for station_name in batch_faces.keys():
print("========= {} =========".format(station_name))
self.nfdcBatchProcessing(self.net[station_name], batch_faces[station_name])
return created_faces
-103
View File
@@ -1,103 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2020, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import sys
from os.path import isfile
from subprocess import call
from six.moves.urllib.parse import quote
from mininet.cli import CLI
sshbase = ['ssh', '-q', '-t', '-i/home/mininet/.ssh/id_rsa']
scpbase = ['scp', '-i', '/home/mininet/.ssh/id_rsa']
devnull = open('/dev/null', 'w')
def getSafeName(namePrefix):
"""
Check if the prefix/string is safe to use with ndn commands or not.
return safe prefix.
:param namePrefix: name of the prefix
"""
# remove redundant "/"es, multiple "/"es are an invalid representation for empty name component
# https://named-data.net/doc/NDN-packet-spec/current/changelog.html#version-0-3
namePrefix= "/" + ("/".join(filter(None, namePrefix.split("/"))))
return quote(namePrefix, safe='/')
def ssh(login, cmd):
rcmd = sshbase + [login, cmd]
call(rcmd, stdout=devnull, stderr=devnull)
def scp(*args):
tmp = []
for arg in args:
tmp.append(arg)
rcmd = scpbase + tmp
call(rcmd, stdout=devnull, stderr=devnull)
def copyExistentFile(node, fileList, destination):
for f in fileList:
if isfile(f):
node.cmd('cp {} {}'.format(f, destination))
break
if not isfile(destination):
fileName = destination.split('/')[-1]
raise IOError('{} not found in expected directory.'.format(fileName))
def popenGetEnv(node, envDict=None):
env = {}
homeDir = node.params['params']['homeDir']
printenv = node.popen('printenv'.split(), cwd=homeDir).communicate()[0].decode('utf-8')
for var in printenv.split('\n'):
if var == '':
break
p = var.split('=')
env[p[0]] = p[1]
env['HOME'] = homeDir
if envDict is not None:
for key, value in envDict.items():
env[key] = str(value)
return env
def getPopen(host, cmd, envDict=None, **params):
return host.popen(cmd, cwd=host.params['params']['homeDir'],
env=popenGetEnv(host, envDict), **params)
class MiniNDNCLI(CLI):
prompt = 'mini-ndn> '
def __init__(self, mininet, stdin=sys.stdin, script=None):
CLI.__init__(self, mininet, stdin, script)
try:
from mn_wifi.cli import CLI as CLI_wifi
class MiniNDNWifiCLI(CLI_wifi):
prompt = 'mini-ndn-wifi> '
def __init__(self, mininet, stdin=sys.stdin, script=None):
CLI_wifi.__init__(self, mininet, stdin, script)
except ImportError:
class MiniNDNWifiCLI:
def __init__(self):
raise ImportError('Mininet-WiFi is not installed')
View File
Whitespace-only changes.
-307
View File
@@ -1,307 +0,0 @@
# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
#
# Copyright (C) 2015-2021, The University of Memphis,
# Arizona Board of Regents,
# Regents of the University of California.
#
# This file is part of Mini-NDN.
# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
#
# Mini-NDN is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Mini-NDN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mini-NDN, e.g., in COPYING.md file.
# If not, see <http://www.gnu.org/licenses/>.
import os
import argparse
import sys
import configparser
from subprocess import Popen, PIPE
from mininet.log import info, debug
from mn_wifi.topo import Topo as Topo_WiFi
from mn_wifi.net import Mininet_wifi
from mn_wifi.link import WirelessLink
from minindn.minindn import Minindn
from minindn.helpers.nfdc import Nfdc
class MinindnWifi(Minindn):
""" Class for handling default args, Mininet-wifi object and home directories """
def __init__(self, parser=argparse.ArgumentParser(), topo=None, topoFile=None, noTopo=False,
link=WirelessLink, workDir=None, **mininetParams):
"""
Create Mini-NDN-Wifi object
parser: Parent parser of Mini-NDN-Wifi parser (use to specify experiment arguments)
topo: Mininet topo object (optional)
topoFile: topology file location (optional)
noTopo: Allows specification of topology after network object is initialized (optional)
link: Allows specification of default Mininet/Mininet-Wifi link type for
connections between nodes (optional)mininetParams: Any params to pass to Mininet-WiFi
"""
self.parser = self.parseArgs(parser)
self.args = self.parser.parse_args()
if not workDir:
Minindn.workDir = os.path.abspath(self.args.workDir)
else:
Minindn.workDir = os.path.abspath(workDir)
Minindn.resultDir = self.args.resultDir
self.topoFile = None
if not topoFile:
# Args has default topology if none specified
self.topoFile = self.args.topoFile
else:
self.topoFile = topoFile
self.faces_to_create = {}
if topo is None and not noTopo:
try:
info('Using topology file {}\n'.format(self.topoFile))
self.topo, self.faces_to_create = self.processTopo(self.topoFile)
except configparser.NoSectionError as e:
info('Error reading config file: {}\n'.format(e))
sys.exit(1)
else:
self.topo = topo
if not noTopo:
self.net = Mininet_wifi(topo=self.topo, ifb=self.args.ifb, link=link, **mininetParams)
else:
self.net = Mininet_wifi(ifb=self.args.ifb, link=link, **mininetParams)
# Prevents crashes running mixed topos
nodes = self.net.stations + self.net.hosts + self.net.cars
self.initParams(nodes)
try:
process = Popen(['ndnsec-get-default', '-k'], stdout=PIPE, stderr=PIPE)
output, error = process.communicate()
if process.returncode == 0:
Minindn.ndnSecurityDisabled = '/dummy/KEY/-%9C%28r%B8%AA%3B%60' in output.decode("utf-8")
info('Dummy key chain patch is installed in ndn-cxx. Security will be disabled.\n')
else:
debug(error)
except:
pass
self.cleanups = []
@staticmethod
def parseArgs(parent):
parser = argparse.ArgumentParser(prog='minindn-wifi', parents=[parent], add_help=False)
# nargs='?' required here since optional argument
parser.add_argument('topoFile', nargs='?', default='/usr/local/etc/mini-ndn/singleap-topology.conf',
help='If no template_file is given, topologies/wifi/singleap-topology.conf will be used.')
parser.add_argument('--work-dir', action='store', dest='workDir', default='/tmp/minindn',
help='Specify the working directory; default is /tmp/minindn')
parser.add_argument('--result-dir', action='store', dest='resultDir', default=None,
help='Specify the full path destination folder where experiment results will be moved')
parser.add_argument('--mobility',action='store_true',dest='mobility',default=False,
help='Enable custom mobility for topology (defined in topology file)')
parser.add_argument('--model-mob',action='store_true',dest='modelMob',default=False,
help='Enable model mobility for topology (defined in topology file)')
parser.add_argument('--ifb',action='store_true',dest='ifb',default=False,
help='Simulate delay on receiver-side by use of virtual IFB devices (see docs)')
return parser
@staticmethod
def processTopo(topoFile):
config = configparser.ConfigParser(delimiters=' ')
config.read(topoFile)
topo = Topo_WiFi()
items = config.items('stations')
debug("Stations")
for item in items:
debug(item[0].split(':'))
name = item[0].split(':')[0]
params = {}
for param in item[1].split(' '):
if param == "_":
continue
key = param.split('=')[0]
value = param.split('=')[1]
if key in ['range']:
value = int(value)
params[key] = value
topo.addStation(name, **params)
try:
debug("Switches")
items = config.items('switches')
for item in items:
debug(item[0].split(':'))
name = item[0].split(':')[0]
topo.addSwitch(name)
except configparser.NoSectionError:
debug("Switches are optional")
pass
try:
debug("APs")
items = config.items('accessPoints')
for item in items:
debug(item[0].split(':'))
name = item[0].split(':')[0]
ap_params = {}
for param in item[1].split(' '):
if param == "_":
continue
key = param.split('=')[0]
value = param.split('=')[1]
if key in ['range']:
value = int(value)
ap_params[key] = value
topo.addAccessPoint(name, **ap_params)
except configparser.NoSectionError:
debug("APs are optional")
pass
items = config.items('links')
debug("Links")
for item in items:
link = item[0].split(':')
debug(link)
params = {}
for param in item[1].split(' '):
if param == "_":
continue
key = param.split('=')[0]
value = param.split('=')[1]
if key in ['bw', 'jitter', 'max_queue_size']:
value = int(value)
if key == 'loss':
value = float(value)
params[key] = value
topo.addLink(link[0], link[1], **params)
faces = {}
try:
items = config.items('faces')
debug("Faces")
for item in items:
face_a, face_b = item[0].split(':')
debug(item)
cost = -1
for param in item[1].split(' '):
if param.split("=")[0] == 'cost':
cost = param.split("=")[1]
face_info = (face_b, int(cost))
if face_a not in faces:
faces[face_a] = [face_info]
else:
faces[face_a].append(face_info)
except configparser.NoSectionError:
debug("Faces section is optional")
pass
return (topo, faces)
def startMobility(self, max_x=1000, max_y=1000, **kwargs):
""" Method to run a basic mobility setup on your net"""
self.net.plotGraph(max_x=max_x, max_y=max_y)
self.net.startMobility(**kwargs)
def startMobilityModel(self, max_x=1000, max_y=1000, **kwargs):
""" Method to run a mobility model on your net until exited"""
self.net.plotGraph(max_x=max_x, max_y=max_y)
self.net.setMobilityModel(**kwargs)
def getWifiInterfaceDelay(self, node, interface=None):
"""Method to return the configured tc delay of a wifi node's interface as a float"""
if not interface:
wifi_interface = "{}-wlan0".format(node.name)
else:
wifi_interface = interface
tc_output = node.cmd("tc qdisc show dev {}".format(wifi_interface))
for line in tc_output.splitlines():
if "qdisc netem 10:" in line:
split_line = line.split(" ")
for index in range(0, len(split_line)):
if split_line[index] == "delay":
return float(split_line[index + 1][:-2])
return 0.0
def setupFaces(self, faces_to_create=None):
"""
Method to create unicast faces between nodes connected by an AP based on name or faces
between connected nodes; Returns dict- {node: (other node name, other node IP, other
node's delay as int)}. This is intended to pass to the NLSR helper via the faceDict param
"""
if not faces_to_create:
faces_to_create = self.faces_to_create
# (nodeName, IP, delay as int)
# list of tuples
created_faces = dict()
batch_faces = dict()
for nodeAname in faces_to_create.keys():
if not nodeAname in batch_faces.keys():
batch_faces[nodeAname] = []
for nodeBname, faceCost in faces_to_create[nodeAname]:
if not nodeBname in batch_faces.keys():
batch_faces[nodeBname] = []
nodeA = self.net[nodeAname]
nodeB = self.net[nodeBname]
if nodeA.connectionsTo(nodeB):
best_interface = None
delay = None
for interface in nodeA.connectionsTo(nodeB):
interface_delay = self.getInterfaceDelay(nodeA, interface[0])
if not delay or int(interface_delay) < delay:
best_interface = interface
faceAIP = best_interface[0].IP()
faceBIP = best_interface[1].IP()
# Node delay should be symmetrical
nodeDelay = int(self.getInterfaceDelay(nodeA, best_interface[0]))
else:
# Default IP will be the primary wireless interface, unclear if multiple wireless
# interfaces should be handled
faceAIP = nodeA.IP()
faceBIP = nodeB.IP()
nodeADelay = self.getWifiInterfaceDelay(nodeA)
nodeBDelay = self.getWifiInterfaceDelay(nodeB)
nodeDelay = nodeADelay + nodeBDelay
if not faceCost == -1:
nodeALink = (nodeA.name, faceAIP, faceCost)
nodeBLink = (nodeB.name, faceBIP, faceCost)
else:
nodeALink = (nodeA.name, faceAIP, nodeDelay)
nodeBLink = (nodeB.name, faceBIP, nodeDelay)
batch_faces[nodeAname].append([faceBIP, "udp", True])
batch_faces[nodeBname].append([faceAIP, "udp", True])
if nodeA not in created_faces:
created_faces[nodeA] = [nodeBLink]
else:
created_faces[nodeA].append(nodeBLink)
if nodeB not in created_faces:
created_faces[nodeB] = [nodeALink]
else:
created_faces[nodeB].append(nodeALink)
for station_name in batch_faces.keys():
self.nfdcBatchProcessing(self.net[station_name], batch_faces[station_name])
return created_faces
+1
View File
@@ -0,0 +1 @@
"Docstring to silence pylint; ignores --ignore option for __init__.py"
+60
View File
@@ -0,0 +1,60 @@
"""
Mininet Cleanup
author: Bob Lantz (rlantz@cs.stanford.edu)
Unfortunately, Mininet and OpenFlow (and the Linux kernel)
don't always clean up properly after themselves. Until they do
(or until cleanup functionality is integrated into the Python
code), this script may be used to get rid of unwanted garbage.
It may also get rid of 'false positives', but hopefully
nothing irreplaceable!
"""
from subprocess import Popen, PIPE
from mininet.log import info
from mininet.term import cleanUpScreens
def sh( cmd ):
"Print a command and send it to the shell"
info( cmd + '\n' )
return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
def cleanup():
"""Clean up junk which might be left over from old runs;
do fast stuff before slow dp and link removal!"""
info("*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
"\n")
zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
zombies += 'ovs-openflowd udpbwtest'
# Note: real zombie processes can't actually be killed, since they
# are already (un)dead. Then again,
# you can't connect to them either, so they're mostly harmless.
sh( 'killall -9 ' + zombies + ' 2> /dev/null' )
info( "*** Removing junk from /tmp\n" )
sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' )
info( "*** Removing old screen sessions\n" )
cleanUpScreens()
info( "*** Removing excess kernel datapaths\n" )
dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" ).split( '\n' )
for dp in dps:
if dp != '':
sh( 'dpctl deldp ' + dp )
info( "*** Removing OVS datapaths" )
dps = sh("ovs-vsctl list-br").split( '\n' )
for dp in dps:
if dp:
sh( 'ovs-vsctl del-br ' + dp )
info( "*** Removing all links of the pattern foo-ethX\n" )
links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' )
for link in links:
if link != '':
sh( "ip link del " + link )
info( "*** Cleanup complete.\n" )
+358
View File
@@ -0,0 +1,358 @@
"""
A simple command-line interface for Mininet.
The Mininet CLI provides a simple control console which
makes it easy to talk to nodes. For example, the command
mininet> h27 ifconfig
runs 'ifconfig' on host h27.
Having a single console rather than, for example, an xterm for each
node is particularly convenient for networks of any reasonable
size.
The CLI automatically substitutes IP addresses for node names,
so commands like
mininet> h2 ping h3
should work correctly and allow host h2 to ping host h3
Several useful commands are provided, including the ability to
list all nodes ('nodes'), to print out the network topology
('net') and to check connectivity ('pingall', 'pingpair')
and bandwidth ('iperf'.)
"""
from subprocess import call
from cmd import Cmd
from os import isatty
from select import poll, POLLIN
import sys
import time
from mininet.log import info, output, error
from mininet.term import makeTerms
from mininet.util import quietRun, isShellBuiltin, dumpNodeConnections
class CLI( Cmd ):
"Simple command-line interface to talk to nodes."
prompt = 'mininet> '
def __init__( self, mininet, stdin=sys.stdin, script=None ):
self.mn = mininet
self.nodelist = self.mn.controllers + self.mn.switches + self.mn.hosts
self.nodemap = {} # map names to Node objects
for node in self.nodelist:
self.nodemap[ node.name ] = node
# Local variable bindings for py command
self.locals = { 'net': mininet }
self.locals.update( self.nodemap )
# Attempt to handle input
self.stdin = stdin
self.inPoller = poll()
self.inPoller.register( stdin )
self.inputFile = script
Cmd.__init__( self )
info( '*** Starting CLI:\n' )
if self.inputFile:
self.do_source( self.inputFile )
return
while True:
try:
# Make sure no nodes are still waiting
for node in self.nodelist:
while node.waiting:
node.sendInt()
node.monitor()
if self.isatty():
quietRun( 'stty sane' )
self.cmdloop()
break
except KeyboardInterrupt:
output( '\nInterrupt\n' )
def emptyline( self ):
"Don't repeat last command when you hit return."
pass
# Disable pylint "Unused argument: 'arg's'" messages, as well as
# "method could be a function" warning, since each CLI function
# must have the same interface
# pylint: disable-msg=R0201
helpStr = (
'You may also send a command to a node using:\n'
' <node> command {args}\n'
'For example:\n'
' mininet> h1 ifconfig\n'
'\n'
'The interpreter automatically substitutes IP addresses\n'
'for node names when a node is the first arg, so commands\n'
'like\n'
' mininet> h2 ping h3\n'
'should work.\n'
'\n'
'Some character-oriented interactive commands require\n'
'noecho:\n'
' mininet> noecho h2 vi foo.py\n'
'However, starting up an xterm/gterm is generally better:\n'
' mininet> xterm h2\n\n'
)
def do_help( self, line ):
"Describe available CLI commands."
Cmd.do_help( self, line )
if line is '':
output( self.helpStr )
def do_nodes( self, _line ):
"List all nodes."
nodes = ' '.join( [ node.name for node in sorted( self.nodelist ) ] )
output( 'available nodes are: \n%s\n' % nodes )
def do_net( self, _line ):
"List network connections."
dumpNodeConnections( self.nodelist )
def do_sh( self, line ):
"Run an external shell command"
call( line, shell=True )
# do_py() needs to catch any exception during eval()
# pylint: disable-msg=W0703
def do_py( self, line ):
"""Evaluate a Python expression.
Node names may be used, e.g.: h1.cmd('ls')"""
try:
result = eval( line, globals(), self.locals )
if not result:
return
elif isinstance( result, str ):
output( result + '\n' )
else:
output( repr( result ) + '\n' )
except Exception, e:
output( str( e ) + '\n' )
# pylint: enable-msg=W0703
def do_pingall( self, _line ):
"Ping between all hosts."
self.mn.pingAll()
def do_pingpair( self, _line ):
"Ping between first two hosts, useful for testing."
self.mn.pingPair()
def do_iperf( self, line ):
"Simple iperf TCP test between two (optionally specified) hosts."
args = line.split()
if not args:
self.mn.iperf()
elif len(args) == 2:
hosts = []
err = False
for arg in args:
if arg not in self.nodemap:
err = True
error( "node '%s' not in network\n" % arg )
else:
hosts.append( self.nodemap[ arg ] )
if not err:
self.mn.iperf( hosts )
else:
error( 'invalid number of args: iperf src dst\n' )
def do_iperfudp( self, line ):
"Simple iperf TCP test between two (optionally specified) hosts."
args = line.split()
if not args:
self.mn.iperf( l4Type='UDP' )
elif len(args) == 3:
udpBw = args[ 0 ]
hosts = []
err = False
for arg in args[ 1:3 ]:
if arg not in self.nodemap:
err = True
error( "node '%s' not in network\n" % arg )
else:
hosts.append( self.nodemap[ arg ] )
if not err:
self.mn.iperf( hosts, l4Type='UDP', udpBw=udpBw )
else:
error( 'invalid number of args: iperfudp bw src dst\n' +
'bw examples: 10M\n' )
def do_intfs( self, _line ):
"List interfaces."
for node in self.nodelist:
output( '%s: %s\n' %
( node.name, ','.join( node.intfNames() ) ) )
def do_dump( self, _line ):
"Dump node info."
for node in self.nodelist:
output( '%s\n' % repr( node ) )
def do_link( self, line ):
"Bring link(s) between two nodes up or down."
args = line.split()
if len(args) != 3:
error( 'invalid number of args: link end1 end2 [up down]\n' )
elif args[ 2 ] not in [ 'up', 'down' ]:
error( 'invalid type: link end1 end2 [up down]\n' )
else:
self.mn.configLinkStatus( *args )
def do_xterm( self, line, term='xterm' ):
"Spawn xterm(s) for the given node(s)."
args = line.split()
if not args:
error( 'usage: %s node1 node2 ...\n' % term )
else:
for arg in args:
if arg not in self.nodemap:
error( "node '%s' not in network\n" % arg )
else:
node = self.nodemap[ arg ]
self.mn.terms += makeTerms( [ node ], term = term )
def do_gterm( self, line ):
"Spawn gnome-terminal(s) for the given node(s)."
self.do_xterm( line, term='gterm' )
def do_exit( self, _line ):
"Exit"
return 'exited by user command'
def do_quit( self, line ):
"Exit"
return self.do_exit( line )
def do_EOF( self, line ):
"Exit"
output( '\n' )
return self.do_exit( line )
def isatty( self ):
"Is our standard input a tty?"
return isatty( self.stdin.fileno() )
def do_noecho( self, line ):
"Run an interactive command with echoing turned off."
if self.isatty():
quietRun( 'stty -echo' )
self.default( line )
if self.isatty():
quietRun( 'stty echo' )
def do_source( self, line ):
"Read commands from an input file."
args = line.split()
if len(args) != 1:
error( 'usage: source <file>\n' )
return
try:
self.inputFile = open( args[ 0 ] )
while True:
line = self.inputFile.readline()
if len( line ) > 0:
self.onecmd( line )
else:
break
except IOError:
error( 'error reading file %s\n' % args[ 0 ] )
self.inputFile = None
def do_dpctl( self, line ):
"Run dpctl command on all switches."
args = line.split()
if len(args) < 1:
error( 'usage: dpctl command [arg1] [arg2] ...\n' )
return
for sw in self.mn.switches:
output( '*** ' + sw.name + ' ' + ('-' * 72) + '\n' )
output( sw.dpctl( *args ) )
def do_time( self, line ):
"Measure time taken for any command in Mininet."
start = time.time()
self.onecmd(line)
elapsed = time.time() - start
self.stdout.write("*** Elapsed time: %0.6f secs\n" % elapsed)
def default( self, line ):
"""Called on an input line when the command prefix is not recognized.
Overridden to run shell commands when a node is the first CLI argument.
Past the first CLI argument, node names are automatically replaced with
corresponding IP addrs."""
first, args, line = self.parseline( line )
if not args:
return
if args and len(args) > 0 and args[ -1 ] == '\n':
args = args[ :-1 ]
rest = args.split( ' ' )
if first in self.nodemap:
node = self.nodemap[ first ]
# Substitute IP addresses for node names in command
rest = [ self.nodemap[ arg ].IP()
if arg in self.nodemap else arg
for arg in rest ]
rest = ' '.join( rest )
# Run cmd on node:
builtin = isShellBuiltin( first )
node.sendCmd( rest, printPid=( not builtin ) )
self.waitForNode( node )
else:
error( '*** Unknown command: %s\n' % first )
# pylint: enable-msg=R0201
def waitForNode( self, node ):
"Wait for a node to finish, and print its output."
# Pollers
nodePoller = poll()
nodePoller.register( node.stdout )
bothPoller = poll()
bothPoller.register( self.stdin, POLLIN )
bothPoller.register( node.stdout, POLLIN )
if self.isatty():
# Buffer by character, so that interactive
# commands sort of work
quietRun( 'stty -icanon min 1' )
while True:
try:
bothPoller.poll()
# XXX BL: this doesn't quite do what we want.
if False and self.inputFile:
key = self.inputFile.read( 1 )
if key is not '':
node.write(key)
else:
self.inputFile = None
if isReadable( self.inPoller ):
key = self.stdin.read( 1 )
node.write( key )
if isReadable( nodePoller ):
data = node.monitor()
output( data )
if not node.waiting:
break
except KeyboardInterrupt:
node.sendInt()
# Helper functions
def isReadable( poller ):
"Check whether a Poll object has a readable fd."
for fdmask in poller.poll( 0 ):
mask = fdmask[ 1 ]
if mask & POLLIN:
return True
+390
View File
@@ -0,0 +1,390 @@
"""
link.py: interface and link abstractions for mininet
It seems useful to bundle functionality for interfaces into a single
class.
Also it seems useful to enable the possibility of multiple flavors of
links, including:
- simple veth pairs
- tunneled links
- patchable links (which can be disconnected and reconnected via a patchbay)
- link simulators (e.g. wireless)
Basic division of labor:
Nodes: know how to execute commands
Intfs: know how to configure themselves
Links: know how to connect nodes together
Intf: basic interface object that can configure itself
TCIntf: interface with bandwidth limiting and delay via tc
Link: basic link class for creating veth pairs
"""
from mininet.log import info, error, debug
from mininet.util import makeIntfPair
from time import sleep
import re
class Intf( object ):
"Basic interface object that can configure itself."
def __init__( self, name, node=None, port=None, link=None, **params ):
"""name: interface name (e.g. h1-eth0)
node: owning node (where this intf most likely lives)
link: parent link if we're part of a link
other arguments are passed to config()"""
self.node = node
self.name = name
self.link = link
self.mac, self.ip, self.prefixLen = None, None, None
# Add to node (and move ourselves if necessary )
node.addIntf( self, port=port )
# Save params for future reference
self.params = params
self.config( **params )
def cmd( self, *args, **kwargs ):
"Run a command in our owning node"
return self.node.cmd( *args, **kwargs )
def ifconfig( self, *args ):
"Configure ourselves using ifconfig"
return self.cmd( 'ifconfig', self.name, *args )
def setIP( self, ipstr, prefixLen=None ):
"""Set our IP address"""
# This is a sign that we should perhaps rethink our prefix
# mechanism and/or the way we specify IP addresses
if '/' in ipstr:
self.ip, self.prefixLen = ipstr.split( '/' )
return self.ifconfig( ipstr, 'up' )
else:
self.ip, self.prefixLen = ipstr, prefixLen
return self.ifconfig( '%s/%s' % ( ipstr, prefixLen ) )
def setMAC( self, macstr ):
"""Set the MAC address for an interface.
macstr: MAC address as string"""
self.mac = macstr
return ( self.ifconfig( 'down' ) +
self.ifconfig( 'hw', 'ether', macstr ) +
self.ifconfig( 'up' ) )
_ipMatchRegex = re.compile( r'\d+\.\d+\.\d+\.\d+' )
_macMatchRegex = re.compile( r'..:..:..:..:..:..' )
def updateIP( self ):
"Return updated IP address based on ifconfig"
ifconfig = self.ifconfig()
ips = self._ipMatchRegex.findall( ifconfig )
self.ip = ips[ 0 ] if ips else None
return self.ip
def updateMAC( self ):
"Return updated MAC address based on ifconfig"
ifconfig = self.ifconfig()
macs = self._macMatchRegex.findall( ifconfig )
self.mac = macs[ 0 ] if macs else None
return self.mac
def IP( self ):
"Return IP address"
return self.ip
def MAC( self ):
"Return MAC address"
return self.mac
def isUp( self, setUp=False ):
"Return whether interface is up"
if setUp:
self.ifconfig( 'up' )
return "UP" in self.ifconfig()
def rename( self, newname ):
"Rename interface"
self.ifconfig( 'down' )
result = self.cmd( 'ip link set', self.name, 'name', newname )
self.name = newname
self.ifconfig( 'up' )
return result
# The reason why we configure things in this way is so
# That the parameters can be listed and documented in
# the config method.
# Dealing with subclasses and superclasses is slightly
# annoying, but at least the information is there!
def setParam( self, results, method, **param ):
"""Internal method: configure a *single* parameter
results: dict of results to update
method: config method name
param: arg=value (ignore if value=None)
value may also be list or dict"""
name, value = param.items()[ 0 ]
f = getattr( self, method, None )
if not f or value is None:
return
if type( value ) is list:
result = f( *value )
elif type( value ) is dict:
result = f( **value )
else:
result = f( value )
results[ name ] = result
return result
def config( self, mac=None, ip=None, ifconfig=None,
up=True, **_params ):
"""Configure Node according to (optional) parameters:
mac: MAC address
ip: IP address
ifconfig: arbitrary interface configuration
Subclasses should override this method and call
the parent class's config(**params)"""
# If we were overriding this method, we would call
# the superclass config method here as follows:
# r = Parent.config( **params )
r = {}
self.setParam( r, 'setMAC', mac=mac )
self.setParam( r, 'setIP', ip=ip )
self.setParam( r, 'isUp', up=up )
self.setParam( r, 'ifconfig', ifconfig=ifconfig )
self.updateIP()
self.updateMAC()
return r
def delete( self ):
"Delete interface"
self.cmd( 'ip link del ' + self.name )
# Does it help to sleep to let things run?
sleep( 0.001 )
def __repr__( self ):
return '<%s %s>' % ( self.__class__.__name__, self.name )
def __str__( self ):
return self.name
class TCIntf( Intf ):
"""Interface customized by tc (traffic control) utility
Allows specification of bandwidth limits (various methods)
as well as delay, loss and max queue length"""
def bwCmds( self, bw=None, speedup=0, use_hfsc=False, use_tbf=False,
enable_ecn=False, enable_red=False ):
"Return tc commands to set bandwidth"
cmds, parent = [], ' root '
if bw and ( bw < 0 or bw > 1000 ):
error( 'Bandwidth', bw, 'is outside range 0..1000 Mbps\n' )
elif bw is not None:
# BL: this seems a bit brittle...
if ( speedup > 0 and
self.node.name[0:1] == 's' ):
bw = speedup
# This may not be correct - we should look more closely
# at the semantics of burst (and cburst) to make sure we
# are specifying the correct sizes. For now I have used
# the same settings we had in the mininet-hifi code.
if use_hfsc:
cmds += [ '%s qdisc add dev %s root handle 1:0 hfsc default 1',
'%s class add dev %s parent 1:0 classid 1:1 hfsc sc '
+ 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ]
elif use_tbf:
latency_us = 10 * 1500 * 8 / bw
cmds += ['%s qdisc add dev %s root handle 1: tbf ' +
'rate %fMbit burst 15000 latency %fus' %
( bw, latency_us ) ]
else:
cmds += [ '%s qdisc add dev %s root handle 1:0 htb default 1',
'%s class add dev %s parent 1:0 classid 1:1 htb ' +
'rate %fMbit burst 15k' % bw ]
parent = ' parent 1:1 '
# ECN or RED
if enable_ecn:
cmds += [ '%s qdisc add dev %s' + parent +
'handle 10: red limit 1000000 ' +
'min 30000 max 35000 avpkt 1500 ' +
'burst 20 ' +
'bandwidth %fmbit probability 1 ecn' % bw ]
parent = ' parent 10: '
elif enable_red:
cmds += [ '%s qdisc add dev %s' + parent +
'handle 10: red limit 1000000 ' +
'min 30000 max 35000 avpkt 1500 ' +
'burst 20 ' +
'bandwidth %fmbit probability 1' % bw ]
parent = ' parent 10: '
return cmds, parent
@staticmethod
def delayCmds( parent, delay=None, loss=None,
max_queue_size=None ):
"Internal method: return tc commands for delay and loss"
cmds = []
if delay and delay < 0:
error( 'Negative delay', delay, '\n' )
elif loss and ( loss < 0 or loss > 100 ):
error( 'Bad loss percentage', loss, '%%\n' )
else:
# Delay/loss/max queue size
netemargs = '%s%s%s' % (
'delay %s ' % delay if delay is not None else '',
'loss %d ' % loss if loss is not None else '',
'limit %d' % max_queue_size if max_queue_size is not None
else '' )
if netemargs:
cmds = [ '%s qdisc add dev %s ' + parent +
' handle 10: netem ' +
netemargs ]
return cmds
def tc( self, cmd, tc='tc' ):
"Execute tc command for our interface"
c = cmd % (tc, self) # Add in tc command and our name
debug(" *** executing command: %s\n" % c)
return self.cmd( c )
def config( self, bw=None, delay=None, loss=None, disable_gro=True,
speedup=0, use_hfsc=False, use_tbf=False, enable_ecn=False,
enable_red=False, max_queue_size=None, **params ):
"Configure the port and set its properties."
result = Intf.config( self, **params)
# Disable GRO
if disable_gro:
self.cmd( 'ethtool -K %s gro off' % self )
# Optimization: return if nothing else to configure
# Question: what happens if we want to reset things?
if ( bw is None and not delay and not loss
and max_queue_size is None ):
return
# Clear existing configuration
cmds = [ '%s qdisc del dev %s root' ]
# Bandwidth limits via various methods
bwcmds, parent = self.bwCmds( bw=bw, speedup=speedup,
use_hfsc=use_hfsc, use_tbf=use_tbf,
enable_ecn=enable_ecn,
enable_red=enable_red )
cmds += bwcmds
# Delay/loss/max_queue_size using netem
cmds += self.delayCmds( delay=delay, loss=loss,
max_queue_size=max_queue_size,
parent=parent )
# Ugly but functional: display configuration info
stuff = ( ( [ '%.2fMbit' % bw ] if bw is not None else [] ) +
( [ '%s delay' % delay ] if delay is not None else [] ) +
( ['%d%% loss' % loss ] if loss is not None else [] ) +
( [ 'ECN' ] if enable_ecn else [ 'RED' ]
if enable_red else [] ) )
info( '(' + ' '.join( stuff ) + ') ' )
# Execute all the commands in our node
debug("at map stage w/cmds: %s\n" % cmds)
tcoutputs = [ self.tc(cmd) for cmd in cmds ]
debug( "cmds:", cmds, '\n' )
debug( "outputs:", tcoutputs, '\n' )
result[ 'tcoutputs'] = tcoutputs
return result
class Link( object ):
"""A basic link is just a veth pair.
Other types of links could be tunnels, link emulators, etc.."""
def __init__( self, node1, node2, port1=None, port2=None,
intfName1=None, intfName2=None,
intf=Intf, cls1=None, cls2=None, params1=None,
params2=None ):
"""Create veth link to another node, making two new interfaces.
node1: first node
node2: second node
port1: node1 port number (optional)
port2: node2 port number (optional)
intf: default interface class/constructor
cls1, cls2: optional interface-specific constructors
intfName1: node1 interface name (optional)
intfName2: node2 interface name (optional)
params1: parameters for interface 1
params2: parameters for interface 2"""
# This is a bit awkward; it seems that having everything in
# params would be more orthogonal, but being able to specify
# in-line arguments is more convenient!
if port1 is None:
port1 = node1.newPort()
if port2 is None:
port2 = node2.newPort()
if not intfName1:
intfName1 = self.intfName( node1, port1 )
if not intfName2:
intfName2 = self.intfName( node2, port2 )
self.makeIntfPair( intfName1, intfName2 )
if not cls1:
cls1 = intf
if not cls2:
cls2 = intf
if not params1:
params1 = {}
if not params2:
params2 = {}
intf1 = cls1( name=intfName1, node=node1, port=port1,
link=self, **params1 )
intf2 = cls2( name=intfName2, node=node2, port=port2,
link=self, **params2 )
# All we are is dust in the wind, and our two interfaces
self.intf1, self.intf2 = intf1, intf2
@classmethod
def intfName( cls, node, n ):
"Construct a canonical interface name node-ethN for interface n."
return node.name + '-eth' + repr( n )
@classmethod
def makeIntfPair( cls, intf1, intf2 ):
"""Create pair of interfaces
intf1: name of interface 1
intf2: name of interface 2
(override this class method [and possibly delete()]
to change link type)"""
makeIntfPair( intf1, intf2 )
def delete( self ):
"Delete this link"
self.intf1.delete()
self.intf2.delete()
def __str__( self ):
return '%s<->%s' % ( self.intf1, self.intf2 )
class TCLink( Link ):
"Link with symmetric TC interfaces configured via opts"
def __init__( self, node1, node2, port1=None, port2=None,
intfName1=None, intfName2=None, **params ):
Link.__init__( self, node1, node2, port1=port1, port2=port2,
intfName1=intfName1, intfName2=intfName2,
cls1=TCIntf,
cls2=TCIntf,
params1=params,
params2=params)
+178
View File
@@ -0,0 +1,178 @@
"Logging functions for Mininet."
import logging
from logging import Logger
import types
# Create a new loglevel, 'CLI info', which enables a Mininet user to see only
# the output of the commands they execute, plus any errors or warnings. This
# level is in between info and warning. CLI info-level commands should not be
# printed during regression tests.
OUTPUT = 25
LEVELS = { 'debug': logging.DEBUG,
'info': logging.INFO,
'output': OUTPUT,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL }
# change this to logging.INFO to get printouts when running unit tests
LOGLEVELDEFAULT = OUTPUT
#default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
LOGMSGFORMAT = '%(message)s'
# Modified from python2.5/__init__.py
class StreamHandlerNoNewline( logging.StreamHandler ):
"""StreamHandler that doesn't print newlines by default.
Since StreamHandler automatically adds newlines, define a mod to more
easily support interactive mode when we want it, or errors-only logging
for running unit tests."""
def emit( self, record ):
"""Emit a record.
If a formatter is specified, it is used to format the record.
The record is then written to the stream with a trailing newline
[ N.B. this may be removed depending on feedback ]. If exception
information is present, it is formatted using
traceback.printException and appended to the stream."""
try:
msg = self.format( record )
fs = '%s' # was '%s\n'
if not hasattr( types, 'UnicodeType' ): # if no unicode support...
self.stream.write( fs % msg )
else:
try:
self.stream.write( fs % msg )
except UnicodeError:
self.stream.write( fs % msg.encode( 'UTF-8' ) )
self.flush()
except ( KeyboardInterrupt, SystemExit ):
raise
except:
self.handleError( record )
class Singleton( type ):
"""Singleton pattern from Wikipedia
See http://en.wikipedia.org/wiki/SingletonPattern#Python
Intended to be used as a __metaclass_ param, as shown for the class
below.
Changed cls first args to mcs to satisfy pylint."""
def __init__( mcs, name, bases, dict_ ):
super( Singleton, mcs ).__init__( name, bases, dict_ )
mcs.instance = None
def __call__( mcs, *args, **kw ):
if mcs.instance is None:
mcs.instance = super( Singleton, mcs ).__call__( *args, **kw )
return mcs.instance
class MininetLogger( Logger, object ):
"""Mininet-specific logger
Enable each mininet .py file to with one import:
from mininet.log import [lg, info, error]
...get a default logger that doesn't require one newline per logging
call.
Inherit from object to ensure that we have at least one new-style base
class, and can then use the __metaclass__ directive, to prevent this
error:
TypeError: Error when calling the metaclass bases
a new-style class can't have only classic bases
If Python2.5/logging/__init__.py defined Filterer as a new-style class,
via Filterer( object ): rather than Filterer, we wouldn't need this.
Use singleton pattern to ensure only one logger is ever created."""
__metaclass__ = Singleton
def __init__( self ):
Logger.__init__( self, "mininet" )
# create console handler
ch = StreamHandlerNoNewline()
# create formatter
formatter = logging.Formatter( LOGMSGFORMAT )
# add formatter to ch
ch.setFormatter( formatter )
# add ch to lg
self.addHandler( ch )
self.setLogLevel()
def setLogLevel( self, levelname=None ):
"""Setup loglevel.
Convenience function to support lowercase names.
levelName: level name from LEVELS"""
level = LOGLEVELDEFAULT
if levelname != None:
if levelname not in LEVELS:
raise Exception( 'unknown levelname seen in setLogLevel' )
else:
level = LEVELS.get( levelname, level )
self.setLevel( level )
self.handlers[ 0 ].setLevel( level )
# pylint: disable-msg=E0202
# "An attribute inherited from mininet.log hide this method"
# Not sure why this is occurring - this function definitely gets called.
# See /usr/lib/python2.5/logging/__init__.py; modified from warning()
def output( self, msg, *args, **kwargs ):
"""Log 'msg % args' with severity 'OUTPUT'.
To pass exception information, use the keyword argument exc_info
with a true value, e.g.
logger.warning("Houston, we have a %s", "cli output", exc_info=1)
"""
if self.manager.disable >= OUTPUT:
return
if self.isEnabledFor( OUTPUT ):
self._log( OUTPUT, msg, args, kwargs )
# pylint: enable-msg=E0202
lg = MininetLogger()
# Make things a bit more convenient by adding aliases
# (info, warn, error, debug) and allowing info( 'this', 'is', 'OK' )
# In the future we may wish to make things more efficient by only
# doing the join (and calling the function) unless the logging level
# is high enough.
def makeListCompatible( fn ):
"""Return a new function allowing fn( 'a 1 b' ) to be called as
newfn( 'a', 1, 'b' )"""
def newfn( *args ):
"Generated function. Closure-ish."
if len( args ) == 1:
return fn( *args )
args = ' '.join( [ str( arg ) for arg in args ] )
return fn( args )
# Fix newfn's name and docstring
setattr( newfn, '__name__', fn.__name__ )
setattr( newfn, '__doc__', fn.__doc__ )
return newfn
info, output, warn, error, debug = (
lg.info, lg.output, lg.warn, lg.error, lg.debug ) = [
makeListCompatible( f ) for f in
lg.info, lg.output, lg.warn, lg.error, lg.debug ]
setLogLevel = lg.setLogLevel
+68
View File
@@ -0,0 +1,68 @@
"Module dependency utility functions for Mininet."
from mininet.util import quietRun
from mininet.log import info, error, debug
from os import environ
def lsmod():
"Return output of lsmod."
return quietRun( 'lsmod' )
def rmmod( mod ):
"""Return output of lsmod.
mod: module string"""
return quietRun( [ 'rmmod', mod ] )
def modprobe( mod ):
"""Return output of modprobe
mod: module string"""
return quietRun( [ 'modprobe', mod ] )
OF_KMOD = 'ofdatapath'
OVS_KMOD = 'openvswitch_mod'
TUN = 'tun'
def moduleDeps( subtract=None, add=None ):
"""Handle module dependencies.
subtract: string or list of module names to remove, if already loaded
add: string or list of module names to add, if not already loaded"""
subtract = subtract if subtract is not None else []
add = add if add is not None else []
if type( subtract ) is str:
subtract = [ subtract ]
if type( add ) is str:
add = [ add ]
for mod in subtract:
if mod in lsmod():
info( '*** Removing ' + mod + '\n' )
rmmodOutput = rmmod( mod )
if rmmodOutput:
error( 'Error removing ' + mod + ': "%s">\n' % rmmodOutput )
exit( 1 )
if mod in lsmod():
error( 'Failed to remove ' + mod + '; still there!\n' )
exit( 1 )
for mod in add:
if mod not in lsmod():
info( '*** Loading ' + mod + '\n' )
modprobeOutput = modprobe( mod )
if modprobeOutput:
error( 'Error inserting ' + mod +
' - is it installed and available via modprobe?\n' +
'Error was: "%s"\n' % modprobeOutput )
if mod not in lsmod():
error( 'Failed to insert ' + mod + ' - quitting.\n' )
exit( 1 )
else:
debug( '*** ' + mod + ' already loaded\n' )
def pathCheck( *args, **kwargs ):
"Make sure each program in *args can be found in $PATH."
moduleName = kwargs.get( 'moduleName', 'it' )
for arg in args:
if not quietRun( 'which ' + arg ):
error( 'Cannot find required executable %s.\n' % arg +
'Please make sure that %s is installed ' % moduleName +
'and available in your $PATH:\n(%s)\n' % environ[ 'PATH' ] )
exit( 1 )
Executable
+645
View File
@@ -0,0 +1,645 @@
"""
Mininet: A simple networking testbed for OpenFlow/SDN!
author: Bob Lantz (rlantz@cs.stanford.edu)
author: Brandon Heller (brandonh@stanford.edu)
Mininet creates scalable OpenFlow test networks by using
process-based virtualization and network namespaces.
Simulated hosts are created as processes in separate network
namespaces. This allows a complete OpenFlow network to be simulated on
top of a single Linux kernel.
Each host has:
A virtual console (pipes to a shell)
A virtual interfaces (half of a veth pair)
A parent shell (and possibly some child processes) in a namespace
Hosts have a network interface which is configured via ifconfig/ip
link/etc.
This version supports both the kernel and user space datapaths
from the OpenFlow reference implementation (openflowswitch.org)
as well as OpenVSwitch (openvswitch.org.)
In kernel datapath mode, the controller and switches are simply
processes in the root namespace.
Kernel OpenFlow datapaths are instantiated using dpctl(8), and are
attached to the one side of a veth pair; the other side resides in the
host namespace. In this mode, switch processes can simply connect to the
controller via the loopback interface.
In user datapath mode, the controller and switches can be full-service
nodes that live in their own network namespaces and have management
interfaces and IP addresses on a control network (e.g. 192.168.123.1,
currently routed although it could be bridged.)
In addition to a management interface, user mode switches also have
several switch interfaces, halves of veth pairs whose other halves
reside in the host nodes that the switches are connected to.
Consistent, straightforward naming is important in order to easily
identify hosts, switches and controllers, both from the CLI and
from program code. Interfaces are named to make it easy to identify
which interfaces belong to which node.
The basic naming scheme is as follows:
Host nodes are named h1-hN
Switch nodes are named s1-sN
Controller nodes are named c0-cN
Interfaces are named {nodename}-eth0 .. {nodename}-ethN
Note: If the network topology is created using mininet.topo, then
node numbers are unique among hosts and switches (e.g. we have
h1..hN and SN..SN+M) and also correspond to their default IP addresses
of 10.x.y.z/8 where x.y.z is the base-256 representation of N for
hN. This mapping allows easy determination of a node's IP
address from its name, e.g. h1 -> 10.0.0.1, h257 -> 10.0.1.1.
Note also that 10.0.0.1 can often be written as 10.1 for short, e.g.
"ping 10.1" is equivalent to "ping 10.0.0.1".
Currently we wrap the entire network in a 'mininet' object, which
constructs a simulated network based on a network topology created
using a topology object (e.g. LinearTopo) from mininet.topo or
mininet.topolib, and a Controller which the switches will connect
to. Several configuration options are provided for functions such as
automatically setting MAC addresses, populating the ARP table, or
even running a set of terminals to allow direct interaction with nodes.
After the network is created, it can be started using start(), and a
variety of useful tasks maybe performed, including basic connectivity
and bandwidth tests and running the mininet CLI.
Once the network is up and running, test code can easily get access
to host and switch objects which can then be used for arbitrary
experiments, typically involving running a series of commands on the
hosts.
After all desired tests or activities have been completed, the stop()
method may be called to shut down the network.
"""
import os
import re
import select
import signal
from time import sleep
from mininet.cli import CLI
from mininet.log import info, error, debug, output
from mininet.node import Host, OVSKernelSwitch, Controller
from mininet.link import Link, Intf
from mininet.util import quietRun, fixLimits, numCores
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
from mininet.term import cleanUpScreens, makeTerms
class Mininet( object ):
"Network emulation with hosts spawned in network namespaces."
def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
controller=Controller, link=Link, intf=Intf,
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
inNamespace=False,
autoSetMacs=False, autoStaticArp=False, autoPinCpus=False,
listenPort=None ):
"""Create Mininet object.
topo: Topo (topology) object or None
switch: default Switch class
host: default Host class/constructor
controller: default Controller class/constructor
link: default Link class/constructor
intf: default Intf class/constructor
ipBase: base IP address for hosts,
build: build now from topo?
xterms: if build now, spawn xterms?
cleanup: if build now, cleanup before creating?
inNamespace: spawn switches and controller in net namespaces?
autoSetMacs: set MAC addrs automatically like IP addresses?
autoStaticArp: set all-pairs static MAC addrs?
autoPinCpus: pin hosts to (real) cores (requires CPULimitedHost)?
listenPort: base listening port to open; will be incremented for
each additional switch in the net if inNamespace=False"""
self.topo = topo
self.switch = switch
self.host = host
self.controller = controller
self.link = link
self.intf = intf
self.ipBase = ipBase
self.ipBaseNum, self.prefixLen = netParse( self.ipBase )
self.nextIP = 1 # start for address allocation
self.inNamespace = inNamespace
self.xterms = xterms
self.cleanup = cleanup
self.autoSetMacs = autoSetMacs
self.autoStaticArp = autoStaticArp
self.autoPinCpus = autoPinCpus
self.numCores = numCores()
self.nextCore = 0 # next core for pinning hosts to CPUs
self.listenPort = listenPort
self.hosts = []
self.switches = []
self.controllers = []
self.nameToNode = {} # name to Node (Host/Switch) objects
self.terms = [] # list of spawned xterm processes
Mininet.init() # Initialize Mininet if necessary
self.built = False
if topo and build:
self.build()
def addHost( self, name, cls=None, **params ):
"""Add host.
name: name of host to add
cls: custom host class/constructor (optional)
params: parameters for host
returns: added host"""
# Default IP and MAC addresses
defaults = { 'ip': ipAdd( self.nextIP,
ipBaseNum=self.ipBaseNum,
prefixLen=self.prefixLen ) +
'/%s' % self.prefixLen }
if self.autoSetMacs:
defaults[ 'mac'] = macColonHex( self.nextIP )
if self.autoPinCpus:
defaults[ 'cores' ] = self.nextCore
self.nextCore = ( self.nextCore + 1 ) % self.numCores
self.nextIP += 1
defaults.update( params )
if not cls:
cls = self.host
h = cls( name, **defaults )
self.hosts.append( h )
self.nameToNode[ name ] = h
return h
def addSwitch( self, name, cls=None, **params ):
"""Add switch.
name: name of switch to add
cls: custom switch class/constructor (optional)
returns: added switch
side effect: increments listenPort ivar ."""
defaults = { 'listenPort': self.listenPort,
'inNamespace': self.inNamespace }
defaults.update( params )
if not cls:
cls = self.switch
sw = cls( name, **defaults )
if not self.inNamespace and self.listenPort:
self.listenPort += 1
self.switches.append( sw )
self.nameToNode[ name ] = sw
return sw
def addController( self, name='c0', controller=None, **params ):
"""Add controller.
controller: Controller class"""
if not controller:
controller = self.controller
controller_new = controller( name, **params )
if controller_new: # allow controller-less setups
self.controllers.append( controller_new )
self.nameToNode[ name ] = controller_new
return controller_new
# BL: is this better than just using nameToNode[] ?
# Should it have a better name?
def getNodeByName( self, *args ):
"Return node(s) with given name(s)"
if len( args ) == 1:
return self.nameToNode[ args[ 0 ] ]
return [ self.nameToNode[ n ] for n in args ]
def get( self, *args ):
"Convenience alias for getNodeByName"
return self.getNodeByName( *args )
def addLink( self, node1, node2, port1=None, port2=None,
cls=None, **params ):
""""Add a link from node1 to node2
node1: source node
node2: dest node
port1: source port
port2: dest port
returns: link object"""
defaults = { 'port1': port1,
'port2': port2,
'intf': self.intf }
defaults.update( params )
if not cls:
cls = self.link
return cls( node1, node2, **defaults )
def configHosts( self ):
"Configure a set of hosts."
for host in self.hosts:
info( host.name + ' ' )
intf = host.defaultIntf()
if intf:
host.configDefault( defaultRoute=intf )
else:
# Don't configure nonexistent intf
host.configDefault( ip=None, mac=None )
# You're low priority, dude!
# BL: do we want to do this here or not?
# May not make sense if we have CPU lmiting...
# quietRun( 'renice +18 -p ' + repr( host.pid ) )
# This may not be the right place to do this, but
# it needs to be done somewhere.
host.cmd( 'ifconfig lo up' )
info( '\n' )
def buildFromTopo( self, topo=None ):
"""Build mininet from a topology object
At the end of this function, everything should be connected
and up."""
# Possibly we should clean up here and/or validate
# the topo
if self.cleanup:
pass
info( '*** Creating network\n' )
if not self.controllers:
# Add a default controller
info( '*** Adding controller\n' )
self.addController( 'c0' )
info( '*** Adding hosts:\n' )
for hostName in topo.hosts():
self.addHost( hostName, **topo.nodeInfo( hostName ) )
info( hostName + ' ' )
info( '\n*** Adding switches:\n' )
for switchName in topo.switches():
self.addSwitch( switchName, **topo.nodeInfo( switchName) )
info( switchName + ' ' )
info( '\n*** Adding links:\n' )
for srcName, dstName in topo.links(sort=True):
src, dst = self.nameToNode[ srcName ], self.nameToNode[ dstName ]
params = topo.linkInfo( srcName, dstName )
srcPort, dstPort = topo.port( srcName, dstName )
self.addLink( src, dst, srcPort, dstPort, **params )
info( '(%s, %s) ' % ( src.name, dst.name ) )
info( '\n' )
def configureControlNetwork( self ):
"Control net config hook: override in subclass"
raise Exception( 'configureControlNetwork: '
'should be overriden in subclass', self )
def build( self ):
"Build mininet."
if self.topo:
self.buildFromTopo( self.topo )
if ( self.inNamespace ):
self.configureControlNetwork()
info( '*** Configuring hosts\n' )
self.configHosts()
if self.xterms:
self.startTerms()
if self.autoStaticArp:
self.staticArp()
self.built = True
def startTerms( self ):
"Start a terminal for each node."
info( "*** Running terms on %s\n" % os.environ[ 'DISPLAY' ] )
cleanUpScreens()
self.terms += makeTerms( self.controllers, 'controller' )
self.terms += makeTerms( self.switches, 'switch' )
self.terms += makeTerms( self.hosts, 'host' )
def stopXterms( self ):
"Kill each xterm."
for term in self.terms:
os.kill( term.pid, signal.SIGKILL )
cleanUpScreens()
def staticArp( self ):
"Add all-pairs ARP entries to remove the need to handle broadcast."
for src in self.hosts:
for dst in self.hosts:
if src != dst:
src.setARP( ip=dst.IP(), mac=dst.MAC() )
def start( self ):
"Start controller and switches."
if not self.built:
self.build()
info( '*** Starting controller\n' )
for controller in self.controllers:
controller.start()
info( '*** Starting %s switches\n' % len( self.switches ) )
for switch in self.switches:
info( switch.name + ' ')
switch.start( self.controllers )
info( '\n' )
def stop( self ):
"Stop the controller(s), switches and hosts"
if self.terms:
info( '*** Stopping %i terms\n' % len( self.terms ) )
self.stopXterms()
info( '*** Stopping %i hosts\n' % len( self.hosts ) )
for host in self.hosts:
info( host.name + ' ' )
host.terminate()
info( '\n' )
info( '*** Stopping %i switches\n' % len( self.switches ) )
for switch in self.switches:
info( switch.name + ' ' )
switch.stop()
info( '\n' )
info( '*** Stopping %i controllers\n' % len( self.controllers ) )
for controller in self.controllers:
info( controller.name + ' ' )
controller.stop()
info( '\n*** Done\n' )
def run( self, test, *args, **kwargs ):
"Perform a complete start/test/stop cycle."
self.start()
info( '*** Running test\n' )
result = test( *args, **kwargs )
self.stop()
return result
def monitor( self, hosts=None, timeoutms=-1 ):
"""Monitor a set of hosts (or all hosts by default),
and return their output, a line at a time.
hosts: (optional) set of hosts to monitor
timeoutms: (optional) timeout value in ms
returns: iterator which returns host, line"""
if hosts is None:
hosts = self.hosts
poller = select.poll()
Node = hosts[ 0 ] # so we can call class method fdToNode
for host in hosts:
poller.register( host.stdout )
while True:
ready = poller.poll( timeoutms )
for fd, event in ready:
host = Node.fdToNode( fd )
if event & select.POLLIN:
line = host.readline()
if line is not None:
yield host, line
# Return if non-blocking
if not ready and timeoutms >= 0:
yield None, None
# XXX These test methods should be moved out of this class.
# Probably we should create a tests.py for them
@staticmethod
def _parsePing( pingOutput ):
"Parse ping output and return packets sent, received."
# Check for downed link
if 'connect: Network is unreachable' in pingOutput:
return (1, 0)
r = r'(\d+) packets transmitted, (\d+) received'
m = re.search( r, pingOutput )
if m == None:
error( '*** Error: could not parse ping output: %s\n' %
pingOutput )
return (1, 0)
sent, received = int( m.group( 1 ) ), int( m.group( 2 ) )
return sent, received
def ping( self, hosts=None ):
"""Ping between all specified hosts.
hosts: list of hosts
returns: ploss packet loss percentage"""
# should we check if running?
packets = 0
lost = 0
ploss = None
if not hosts:
hosts = self.hosts
output( '*** Ping: testing ping reachability\n' )
for node in hosts:
output( '%s -> ' % node.name )
for dest in hosts:
if node != dest:
result = node.cmd( 'ping -c1 ' + dest.IP() )
sent, received = self._parsePing( result )
packets += sent
if received > sent:
error( '*** Error: received too many packets' )
error( '%s' % result )
node.cmdPrint( 'route' )
exit( 1 )
lost += sent - received
output( ( '%s ' % dest.name ) if received else 'X ' )
output( '\n' )
ploss = 100 * lost / packets
output( "*** Results: %i%% dropped (%d/%d lost)\n" %
( ploss, lost, packets ) )
return ploss
def pingAll( self ):
"""Ping between all hosts.
returns: ploss packet loss percentage"""
return self.ping()
def pingPair( self ):
"""Ping between first two hosts, useful for testing.
returns: ploss packet loss percentage"""
hosts = [ self.hosts[ 0 ], self.hosts[ 1 ] ]
return self.ping( hosts=hosts )
@staticmethod
def _parseIperf( iperfOutput ):
"""Parse iperf output and return bandwidth.
iperfOutput: string
returns: result string"""
r = r'([\d\.]+ \w+/sec)'
m = re.findall( r, iperfOutput )
if m:
return m[-1]
else:
# was: raise Exception(...)
error( 'could not parse iperf output: ' + iperfOutput )
return ''
# XXX This should be cleaned up
def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
"""Run iperf between two hosts.
hosts: list of hosts; if None, uses opposite hosts
l4Type: string, one of [ TCP, UDP ]
returns: results two-element array of server and client speeds"""
if not quietRun( 'which telnet' ):
error( 'Cannot find telnet in $PATH - required for iperf test' )
return
if not hosts:
hosts = [ self.hosts[ 0 ], self.hosts[ -1 ] ]
else:
assert len( hosts ) == 2
client, server = hosts
output( '*** Iperf: testing ' + l4Type + ' bandwidth between ' )
output( "%s and %s\n" % ( client.name, server.name ) )
server.cmd( 'killall -9 iperf' )
iperfArgs = 'iperf '
bwArgs = ''
if l4Type == 'UDP':
iperfArgs += '-u '
bwArgs = '-b ' + udpBw + ' '
elif l4Type != 'TCP':
raise Exception( 'Unexpected l4 type: %s' % l4Type )
server.sendCmd( iperfArgs + '-s', printPid=True )
servout = ''
while server.lastPid is None:
servout += server.monitor()
if l4Type == 'TCP':
while 'Connected' not in client.cmd(
'sh -c "echo A | telnet -e A %s 5001"' % server.IP()):
output('waiting for iperf to start up...')
sleep(.5)
cliout = client.cmd( iperfArgs + '-t 5 -c ' + server.IP() + ' ' +
bwArgs )
debug( 'Client output: %s\n' % cliout )
server.sendInt()
servout += server.waitOutput()
debug( 'Server output: %s\n' % servout )
result = [ self._parseIperf( servout ), self._parseIperf( cliout ) ]
if l4Type == 'UDP':
result.insert( 0, udpBw )
output( '*** Results: %s\n' % result )
return result
# BL: I think this can be rewritten now that we have
# a real link class.
def configLinkStatus( self, src, dst, status ):
"""Change status of src <-> dst links.
src: node name
dst: node name
status: string {up, down}"""
if src not in self.nameToNode:
error( 'src not in network: %s\n' % src )
elif dst not in self.nameToNode:
error( 'dst not in network: %s\n' % dst )
else:
if type( src ) is str:
src = self.nameToNode[ src ]
if type( dst ) is str:
dst = self.nameToNode[ dst ]
connections = src.connectionsTo( dst )
if len( connections ) == 0:
error( 'src and dst not connected: %s %s\n' % ( src, dst) )
for srcIntf, dstIntf in connections:
result = srcIntf.ifconfig( status )
if result:
error( 'link src status change failed: %s\n' % result )
result = dstIntf.ifconfig( status )
if result:
error( 'link dst status change failed: %s\n' % result )
def interact( self ):
"Start network and run our simple CLI."
self.start()
result = CLI( self )
self.stop()
return result
inited = False
@classmethod
def init( cls ):
"Initialize Mininet"
if cls.inited:
return
if os.getuid() != 0:
# Note: this script must be run as root
# Probably we should only sudo when we need
# to as per Big Switch's patch
print "*** Mininet must run as root."
exit( 1 )
fixLimits()
cls.inited = True
class MininetWithControlNet( Mininet ):
"""Control network support:
Create an explicit control network. Currently this is only
used/usable with the user datapath.
Notes:
1. If the controller and switches are in the same (e.g. root)
namespace, they can just use the loopback connection.
2. If we can get unix domain sockets to work, we can use them
instead of an explicit control network.
3. Instead of routing, we could bridge or use 'in-band' control.
4. Even if we dispense with this in general, it could still be
useful for people who wish to simulate a separate control
network (since real networks may need one!)
5. Basically nobody ever used this code, so it has been moved
into its own class.
6. Ultimately we may wish to extend this to allow us to create a
control network which every node's control interface is
attached to."""
def configureControlNetwork( self ):
"Configure control network."
self.configureRoutedControlNetwork()
# We still need to figure out the right way to pass
# in the control network location.
def configureRoutedControlNetwork( self, ip='192.168.123.1',
prefixLen=16 ):
"""Configure a routed control network on controller and switches.
For use with the user datapath only right now."""
controller = self.controllers[ 0 ]
info( controller.name + ' <->' )
cip = ip
snum = ipParse( ip )
for switch in self.switches:
info( ' ' + switch.name )
link = self.link( switch, controller, port1=0 )
sintf, cintf = link.intf1, link.intf2
switch.controlIntf = sintf
snum += 1
while snum & 0xff in [ 0, 255 ]:
snum += 1
sip = ipStr( snum )
cintf.setIP( cip, prefixLen )
sintf.setIP( sip, prefixLen )
controller.setHostRoute( sip, cintf )
switch.setHostRoute( cip, sintf )
info( '\n' )
info( '*** Testing control network\n' )
while not cintf.isUp():
info( '*** Waiting for', cintf, 'to come up\n' )
sleep( 1 )
for switch in self.switches:
while not sintf.isUp():
info( '*** Waiting for', sintf, 'to come up\n' )
sleep( 1 )
if self.ping( hosts=[ switch, controller ] ) != 0:
error( '*** Error: control network test failed\n' )
exit( 1 )
info( '\n' )
+1060
View File
File diff suppressed because it is too large. Load diff
Loaded 100 of 153 files, more files were not shown because too many files have changed in this diff. Show more