Hi,
I've been talking with the maintainer of the project and was told that I can
use my fork of the repo as the upstream for this port. I wasn't sure about
what to do with the version, so I'm tentatively calling it 2.2.2, since
that is the latest release.
I've also uploaded a tarball, and removed the patches that are in the tree.
The manpages also broke again, as help2man was looking for a file in WRKBUILD
- the tweak for that is also included here.
Makefile/distinfo/PLIST diffs are at the top, and the rest are all deletions.
OK?
Thanks,
Ayaka
Index: Makefile
===================================================================
RCS file: /cvs/ports/net/mininet/Makefile,v
retrieving revision 1.9
diff -u -p -u -r1.9 Makefile
--- Makefile 9 May 2018 14:56:19 -0000 1.9
+++ Makefile 16 Aug 2018 05:27:51 -0000
@@ -2,11 +2,9 @@
COMMENT = emulator for rapid prototyping of software defined networks
-DISTNAME = mininet-0.0.20170813
-REVISION = 6
-GH_ACCOUNT = mininet
-GH_PROJECT = mininet
-GH_COMMIT = 87e26ef931ee6063332ceba77db472140f832d3a
+V= 2.2.2
+DISTNAME = mininet-$V
+EXTRACT_SUFX= .tar.gz
CATEGORIES = net
@@ -19,6 +17,8 @@ PERMIT_PACKAGE_CDROM = Yes
WANTLIB = c
+MASTER_SITES= https://github.com/akoshibe/mininet/releases/download/v$V/
+
MODULES = lang/python
MODPY_SETUPTOOLS = Yes
BUILD_DEPENDS = devel/help2man
@@ -28,9 +28,10 @@ RUN_DEPENDS = net/socat \
SEPARATE_BUILD = Yes
do-build:
- ${CC} ${CFLAGS} ${WRKSRC}/mnexec.c -o ${WRKBUILD}/mnexec
+ ${CC} ${CFLAGS} ${WRKSRC}/mnexec.c ${WRKSRC}/mnexec_bsd.c \
+ -o ${WRKBUILD}/mnexec
help2man -N -n "create a Mininet network." --no-discard-stderr \
- "PYTHONPATH=${WRKBUILD} ${MODPY_BIN} -B ${WRKSRC}/bin/mn" \
+ "PYTHONPATH=${WRKSRC} ${MODPY_BIN} -B ${WRKSRC}/bin/mn" \
-o ${WRKBUILD}/mn.1
help2man -N -n "execution utility for Mininet." -h "-h" -v "-v" \
--no-discard-stderr ${WRKBUILD}/mnexec -o ${WRKBUILD}/mnexec.1
Index: distinfo
===================================================================
RCS file: /cvs/ports/net/mininet/distinfo,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 distinfo
--- distinfo 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ distinfo 16 Aug 2018 05:27:51 -0000
@@ -1,2 +1,2 @@
-SHA256 (mininet-0.0.20170813-87e26ef9.tar.gz) = /YDr4x0oZz6aBDSFAT7buk7hcqwRPrCYu0eIGF21yS4=
-SIZE (mininet-0.0.20170813-87e26ef9.tar.gz) = 226371
+SHA256 (mininet-2.2.2.tar.gz) = wvkGrX/GjypDtAifPtTcL+ADJ6SZQgerNE69DFIVNlY=
+SIZE (mininet-2.2.2.tar.gz) = 248145
Index: pkg/PLIST
===================================================================
RCS file: /cvs/ports/net/mininet/pkg/PLIST,v
retrieving revision 1.5
diff -u -p -u -r1.5 PLIST
--- pkg/PLIST 17 Apr 2018 19:39:33 -0000 1.5
+++ pkg/PLIST 16 Aug 2018 05:27:51 -0000
@@ -2,12 +2,12 @@
bin/mn
@bin bin/mnexec
lib/python${MODPY_VERSION}/site-packages/mininet/
-lib/python${MODPY_VERSION}/site-packages/mininet-2.3.0d1-py${MODPY_VERSION}.egg-info/
-lib/python${MODPY_VERSION}/site-packages/mininet-2.3.0d1-py${MODPY_VERSION}.egg-info/PKG-INFO
-lib/python${MODPY_VERSION}/site-packages/mininet-2.3.0d1-py${MODPY_VERSION}.egg-info/SOURCES.txt
-lib/python${MODPY_VERSION}/site-packages/mininet-2.3.0d1-py${MODPY_VERSION}.egg-info/dependency_links.txt
-lib/python${MODPY_VERSION}/site-packages/mininet-2.3.0d1-py${MODPY_VERSION}.egg-info/requires.txt
-lib/python${MODPY_VERSION}/site-packages/mininet-2.3.0d1-py${MODPY_VERSION}.egg-info/top_level.txt
+lib/python${MODPY_VERSION}/site-packages/mininet-2.2.2-py${MODPY_VERSION}.egg-info/
+lib/python${MODPY_VERSION}/site-packages/mininet-2.2.2-py${MODPY_VERSION}.egg-info/PKG-INFO
+lib/python${MODPY_VERSION}/site-packages/mininet-2.2.2-py${MODPY_VERSION}.egg-info/SOURCES.txt
+lib/python${MODPY_VERSION}/site-packages/mininet-2.2.2-py${MODPY_VERSION}.egg-info/dependency_links.txt
+lib/python${MODPY_VERSION}/site-packages/mininet-2.2.2-py${MODPY_VERSION}.egg-info/requires.txt
+lib/python${MODPY_VERSION}/site-packages/mininet-2.2.2-py${MODPY_VERSION}.egg-info/top_level.txt
lib/python${MODPY_VERSION}/site-packages/mininet/__init__.py
lib/python${MODPY_VERSION}/site-packages/mininet/__init__.pyc
lib/python${MODPY_VERSION}/site-packages/mininet/baseintf.py
@@ -42,8 +42,12 @@ lib/python${MODPY_VERSION}/site-packages
lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/__init__.pyc
lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/intf.py
lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/intf.pyc
+lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/mnopts.py
+lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/mnopts.pyc
lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/node.py
lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/node.pyc
+lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/nodelib.py
+lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/nodelib.pyc
lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/util.py
lib/python${MODPY_VERSION}/site-packages/mininet/openbsd/util.pyc
lib/python${MODPY_VERSION}/site-packages/mininet/term.py
Index: patches/patch-README_md
===================================================================
RCS file: patches/patch-README_md
diff -N patches/patch-README_md
--- patches/patch-README_md 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,128 +0,0 @@
-$OpenBSD: patch-README_md,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-
-Index: README.md
---- README.md.orig
-+++ README.md
-@@ -1,11 +1,15 @@
- Mininet: Rapid Prototyping for Software Defined Networks
- ========================================================
--*The best way to emulate almost any network on your laptop!*
-
--Mininet 2.3.0d1
-+Fork of Mininet 2.3.0d1
-
--[![Build Status][1]](https://travis-ci.org/mininet/mininet)
-+This is a heavily refactored version of Mininet that also supports
-+FreeBSD and OpenBSD, and attempts to make it easier to add support for
-+non-Linux systems. As such, the native install instructions are
-+slightly different. This is also a heavy work-in-progress so things
-+may be broken or unsupported.
-
-+
- ### What is Mininet?
-
- Mininet emulates a complete network of hosts, links, and switches
-@@ -19,20 +23,7 @@ especially those using OpenFlow and SDN. OpenFlow-bas
- controllers prototyped in Mininet can usually be transferred to
- hardware with minimal changes for full line-rate execution.
-
--### How does it work?
-
--Mininet creates virtual networks using process-based virtualization
--and network namespaces - features that are available in recent Linux
--kernels. In Mininet, hosts are emulated as `bash` processes running in
--a network namespace, so any code that would normally run on a Linux
--server (like a web server or client program) should run just fine
--within a Mininet "Host". The Mininet "Host" will have its own private
--network interface and can only see its own processes. Switches in
--Mininet are software-based switches like Open vSwitch or the OpenFlow
--reference switch. Links are virtual ethernet pairs, which live in the
--Linux kernel and connect our emulated switches to emulated hosts
--(processes).
--
- ### Features
-
- Mininet includes:
-@@ -67,32 +58,21 @@ Mininet includes:
-
- `mn -c`
-
--### New features in this release
-+ (Note: this is a fairly blunt command that may remove non-Mininet
-+ related things)
-
--This is primarily a performance improvement and bug fix release.
-
--- Batch startup has been implemented for Open vSwitch, improving
-- startup performance.
-+Note, different platform ports support varying subsets of the base
-+(Linux) version described below. Refer to the documentation/notes for
-+each platform for the specifics.
-
--- OVS patch links have been implemented via OVSLink and --link ovs
-
-- Warning! These links have *serious limitations* compared to
-- virtual Ethernet pairs: they are not attached to real Linux
-- interfaces so you cannot use tcpdump or wireshark with them;
-- they also cannot be used in long chains - we don't recommend more
-- than 64 OVSLinks, for example --linear,64. However, they can offer
-- significantly better performance than veth pairs, for certain
-- configurations.
--
--- You can now easily install Mininet on a Raspberry Pi ;-)
--
--- Additional information for this release and previous releases
-- may be found in the release notes on docs.mininet.org
--
- ### Installation
-
--See `INSTALL` for installation instructions and details.
-+The installation instructions and other details are found in the
-+`INSTALL.*` files.
-
-+
- ### Documentation
-
- In addition to the API documentation (`make doc`), much useful
-@@ -102,31 +82,19 @@ to the Python API, is available on the
- There is also a wiki which you are encouraged to read and to
- contribute to, particularly the Frequently Asked Questions (FAQ.)
-
--### Support
-+Details about FreeBSD support are available on the
-+[FreeBSD wiki Mininet page](https://wiki.freebsd.org/Mininet).
-
--Mininet is community-supported. We encourage you to join the
--Mininet mailing list, `mininet-discuss` at:
-+The details and status of OpenBSD support are found in
-+`INSTALL.OpenBSD`.
-
--<https://mailman.stanford.edu/mailman/listinfo/mininet-discuss>
-
--### Join Us
-+### Support
-
--Thanks again to all of the Mininet contributors!
-+This fork of Mininet is an experiment that isn't supported by the
-+Mininet community; However, Mininet-related questions pertaining to
-+the features of the original Mininet can be directed to
-+`mininet-discuss`:
-
--Mininet is an open source project and is currently hosted
--at <https://github.com/mininet>. You are encouraged to download
--the code, examine it, modify it, and submit bug reports, bug fixes,
--feature requests, new features and other issues and pull requests.
--Thanks to everyone who has contributed code to the Mininet project
--(see CONTRIBUTORS for more info!) It is because of everyone's
--hard work that Mininet continues to grow and improve.
-+<https://mailman.stanford.edu/mailman/listinfo/mininet-discuss>
-
--### Enjoy Mininet
--
--Best wishes, and we look forward to seeing what you can do with
--Mininet to change the networking world!
--
--Bob Lantz
--Mininet Core Team
--
--[1]: https://travis-ci.org/mininet/mininet.svg?branch=master
Index: patches/patch-bin_mn
===================================================================
RCS file: patches/patch-bin_mn
diff -N patches/patch-bin_mn
--- patches/patch-bin_mn 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,67 +0,0 @@
-$OpenBSD: patch-bin_mn,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-Choose node types that are applicable given an OS.
-Index: bin/mn
---- bin/mn.orig
-+++ bin/mn
-@@ -26,10 +26,10 @@ from mininet.log import lg, LEVELS, info, debug, warn,
- from mininet.net import Mininet, MininetWithControlNet, VERSION
- from mininet.node import ( Host, CPULimitedHost, Controller, OVSController,
- Ryu, NOX, RemoteController, findController,
-- DefaultController, NullController,
-+ DefaultController, NullController, Switchd,
- UserSwitch, OVSSwitch, OVSBridge,
-- IVSSwitch )
--from mininet.nodelib import LinuxBridge
-+ IVSSwitch, IfSwitch, DefaultSwitch )
-+from mininet.nodelib import ClassicBridge
- from mininet.link import Link, TCLink, TCULink, OVSLink
- from mininet.topo import ( SingleSwitchTopo, LinearTopo,
- SingleSwitchReversedTopo, MinimalTopo )
-@@ -64,8 +64,9 @@ SWITCHES = { 'user': UserSwitch,
- # Keep ovsk for compatibility with 2.0
- 'ovsk': OVSSwitch,
- 'ivs': IVSSwitch,
-- 'lxbr': LinuxBridge,
-- 'default': OVSSwitch }
-+ 'ifsw': IfSwitch,
-+ 'sysbr': ClassicBridge,
-+ 'default': DefaultSwitch }
-
- HOSTDEF = 'proc'
- HOSTS = { 'proc': Host,
-@@ -78,6 +79,7 @@ CONTROLLERS = { 'ref': Controller,
- 'nox': NOX,
- 'remote': RemoteController,
- 'ryu': Ryu,
-+ 'swd': Switchd,
- 'default': DefaultController, # Note: overridden below
- 'none': NullController }
-
-@@ -314,8 +316,6 @@ class MininetRunner( object ):
- def begin( self ):
- "Create and run mininet."
-
-- global CLI
--
- opts = self.options
-
- if opts.cluster:
-@@ -340,7 +340,7 @@ class MininetRunner( object ):
- 'for default switch!\n' )
- info( '*** Falling back to OVS Bridge\n' )
- opts.switch = 'ovsbr'
-- elif opts.switch not in ( 'ovsbr', 'lxbr' ):
-+ elif opts.switch not in ( 'ovsbr', 'sysbr' ):
- raise Exception( "Could not find a default controller "
- "for switch %s" %
- opts.switch )
-@@ -387,8 +387,7 @@ class MininetRunner( object ):
- if opts.ensure_value( 'nat', False ):
- mn.addNAT( *opts.nat_args, **opts.nat_kwargs ).configDefault()
-
-- # --custom files can set CLI or change mininet.cli.CLI
-- globals().setdefault( 'CLI', mininet.cli.CLI )
-+ CLI = mininet.cli.CLI
-
- if opts.pre:
- CLI( mn, script=opts.pre )
Index: patches/patch-examples_linearbandwidth_py
===================================================================
RCS file: patches/patch-examples_linearbandwidth_py
diff -N patches/patch-examples_linearbandwidth_py
--- patches/patch-examples_linearbandwidth_py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,29 +0,0 @@
-$OpenBSD: patch-examples_linearbandwidth_py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-KernelSwitch is either OVS or if_switch
-Index: examples/linearbandwidth.py
---- examples/linearbandwidth.py.orig
-+++ examples/linearbandwidth.py
-@@ -1,4 +1,4 @@
--#!/usr/bin/python
-+#!/usr/bin/env python
-
- """
- Test bandwidth (using iperf) on linear networks of varying size,
-@@ -25,7 +25,7 @@ of switches, this example demonstrates:
-
-
- from mininet.net import Mininet
--from mininet.node import UserSwitch, OVSKernelSwitch, Controller
-+from mininet.node import UserSwitch, KernelSwitch, Controller
- from mininet.topo import Topo
- from mininet.log import lg, info
- from mininet.util import irange, quietRun
-@@ -71,7 +71,7 @@ def linearBandwidthTest( lengths ):
- hostCount = switchCount + 1
-
- switches = { 'reference user': UserSwitch,
-- 'Open vSwitch kernel': OVSKernelSwitch }
-+ 'Open vSwitch kernel': KernelSwitch }
-
- # UserSwitch is horribly slow with recent kernels.
- # We can reinstate it once its performance is fixed
Index: patches/patch-examples_miniedit_py
===================================================================
RCS file: patches/patch-examples_miniedit_py
diff -N patches/patch-examples_miniedit_py
--- patches/patch-examples_miniedit_py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,53 +0,0 @@
-$OpenBSD: patch-examples_miniedit_py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-KernelSwitch - OVS or if_switch
-Index: examples/miniedit.py
---- examples/miniedit.py.orig
-+++ examples/miniedit.py
-@@ -1,4 +1,4 @@
--#!/usr/bin/python
-+#!/usr/bin/env python
-
- """
- MiniEdit: a simple network editor for Mininet
-@@ -1686,12 +1686,12 @@ class MiniEdit( Frame ):
- # debug( "Now saving under %s\n" % fileName )
- f = open(fileName, 'wb')
-
-- f.write("#!/usr/bin/python\n")
-+ f.write("#!/usr/bin/env python\n")
- f.write("\n")
- f.write("from mininet.net import Mininet\n")
- f.write("from mininet.node import Controller, RemoteController, OVSController\n")
- f.write("from mininet.node import CPULimitedHost, Host, Node\n")
-- f.write("from mininet.node import OVSKernelSwitch, UserSwitch\n")
-+ f.write("from mininet.node import KernelSwitch, UserSwitch\n")
- if StrictVersion(MININET_VERSION) > StrictVersion('2.0'):
- f.write("from mininet.node import IVSSwitch\n")
- f.write("from mininet.cli import CLI\n")
-@@ -1769,7 +1769,7 @@ class MiniEdit( Frame ):
- f.write(" "+name+" = net.addHost('"+name+"', cls=Node, ip='0.0.0.0')\n")
- f.write(" "+name+".cmd('sysctl -w net.ipv4.ip_forward=1')\n")
- if 'LegacySwitch' in tags:
-- f.write(" "+name+" = net.addSwitch('"+name+"', cls=OVSKernelSwitch, failMode='standalone')\n")
-+ f.write(" "+name+" = net.addSwitch('"+name+"', cls=KernelSwitch, failMode='standalone')\n")
- if 'Switch' in tags:
- opts = self.switchOpts[name]
- nodeNum = opts['nodeNum']
-@@ -1782,7 +1782,7 @@ class MiniEdit( Frame ):
- elif self.appPrefs['switchType'] == 'userns':
- f.write(", cls=UserSwitch, inNamespace=True")
- else:
-- f.write(", cls=OVSKernelSwitch")
-+ f.write(", cls=KernelSwitch")
- elif opts['switchType'] == 'ivs':
- f.write(", cls=IVSSwitch")
- elif opts['switchType'] == 'user':
-@@ -1790,7 +1790,7 @@ class MiniEdit( Frame ):
- elif opts['switchType'] == 'userns':
- f.write(", cls=UserSwitch, inNamespace=True")
- else:
-- f.write(", cls=OVSKernelSwitch")
-+ f.write(", cls=KernelSwitch")
- if 'dpctl' in opts:
- f.write(", listenPort="+opts['dpctl'])
- if 'dpid' in opts:
Index: patches/patch-examples_multitest_py
===================================================================
RCS file: patches/patch-examples_multitest_py
diff -N patches/patch-examples_multitest_py
--- patches/patch-examples_multitest_py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,32 +0,0 @@
-$OpenBSD: patch-examples_multitest_py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-KernelSwitch - OVS or if_switch
-Index: examples/multitest.py
---- examples/multitest.py.orig
-+++ examples/multitest.py
-@@ -1,4 +1,4 @@
--#!/usr/bin/python
-+#!/usr/bin/env python
-
- """
- This example shows how to create a network and run multiple tests.
-@@ -8,7 +8,7 @@ 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.node import KernelSwitch
- from mininet.topolib import TreeTopo
-
- def ifconfigTest( net ):
-@@ -20,9 +20,9 @@ def ifconfigTest( net ):
- if __name__ == '__main__':
- lg.setLogLevel( 'info' )
- info( "*** Initializing Mininet and kernel modules\n" )
-- OVSKernelSwitch.setup()
-+ KernelSwitch.setup()
- info( "*** Creating network\n" )
-- network = Mininet( TreeTopo( depth=2, fanout=2 ), switch=OVSKernelSwitch )
-+ network = Mininet( TreeTopo( depth=2, fanout=2 ), switch=KernelSwitch )
- info( "*** Starting network\n" )
- network.start()
- info( "*** Running ping test\n" )
Index: patches/patch-examples_treeping64_py
===================================================================
RCS file: patches/patch-examples_treeping64_py
diff -N patches/patch-examples_treeping64_py
--- patches/patch-examples_treeping64_py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,27 +0,0 @@
-$OpenBSD: patch-examples_treeping64_py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-
-Index: examples/treeping64.py
---- examples/treeping64.py.orig
-+++ examples/treeping64.py
-@@ -1,10 +1,10 @@
--#!/usr/bin/python
-+#!/usr/bin/env python
-
- "Create a 64-node tree network, and test connectivity using ping."
-
-
- from mininet.log import setLogLevel, info
--from mininet.node import UserSwitch, OVSKernelSwitch # , KernelSwitch
-+from mininet.node import UserSwitch, KernelSwitch # , KernelSwitch
- from mininet.topolib import TreeNet
-
- def treePing64():
-@@ -13,7 +13,7 @@ def treePing64():
- results = {}
- switches = { # 'reference kernel': KernelSwitch,
- 'reference user': UserSwitch,
-- 'Open vSwitch kernel': OVSKernelSwitch }
-+ 'kernel': KernelSwitch }
-
- for name in switches:
- info( "*** Testing", name, "datapath\n" )
Index: patches/patch-mininet_baseintf_py
===================================================================
RCS file: patches/patch-mininet_baseintf_py
diff -N patches/patch-mininet_baseintf_py
--- patches/patch-mininet_baseintf_py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,185 +0,0 @@
-$OpenBSD: patch-mininet_baseintf_py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-OS-agnostic parts of link.py's Intf class.
-Index: mininet/baseintf.py
---- mininet/baseintf.py.orig
-+++ mininet/baseintf.py
-@@ -0,0 +1,179 @@
-+"""
-+The base network interface object that Links and Nodes understand, and other
-+interface objects are based upon.
-+"""
-+
-+from mininet.log import error
-+import re
-+
-+class BaseIntf( object ):
-+ """Basic interface object that can configure itself."""
-+
-+ def __init__( self, name, node, port=None, link=None,
-+ mac=None, **params ):
-+ """name: interface name (e.g. h1-eth0)
-+ node: owning node (where this intf most likely lives)
-+ link: parent link if we're part of a link
-+ other arguments are passed to config()"""
-+ self.node = node
-+ self.name = name
-+ self.link = link
-+ self.mac = mac
-+ self.ip, self.prefixLen = None, None
-+
-+ # if interface is lo/lo0, we know the ip is 127.0.0.1.
-+ # This saves an ifconfig command per node
-+ if self.name == 'lo' or self.name == 'lo0':
-+ self.ip = '127.0.0.1'
-+ self.prefixLen = 8
-+ # Add to node (and move ourselves if necessary )
-+ moveIntfFn = params.pop( 'moveIntfFn', None )
-+ if moveIntfFn:
-+ node.addIntf( self, port=port, moveIntfFn=moveIntfFn )
-+ else:
-+ node.addIntf( self, port=port )
-+ # Save params for future reference
-+ self.params = params
-+ self.config( **params )
-+
-+ 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:
-+ if prefixLen is None:
-+ raise Exception( 'No prefix length set for IP address %s'
-+ % ( ipstr, ) )
-+ self.ip, self.prefixLen = ipstr, prefixLen
-+ return self.ifconfig( '%s/%s' % ( ipstr, prefixLen ) )
-+
-+ def setMAC( self, macstr ):
-+ """Set the MAC address for an interface.
-+ macstr: MAC address as string"""
-+ pass
-+
-+ _ipMatchRegex = re.compile( r'\d+\.\d+\.\d+\.\d+' )
-+ _macMatchRegex = re.compile( r'..:..:..:..:..:..' )
-+
-+ def updateIP( self ):
-+ "Return updated IP address based on ifconfig"
-+ # use pexec instead of node.cmd so that we dont read
-+ # backgrounded output from the cli.
-+ ifconfig, _err, _exitCode = self.node.pexec(
-+ 'ifconfig %s' % self.name )
-+ ips = self._ipMatchRegex.findall( ifconfig )
-+ self.ip = ips[ 0 ] if ips else None
-+ return self.ip
-+
-+ 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
-+
-+ # Instead of updating ip and mac separately,
-+ # use one ifconfig call to do it simultaneously.
-+ # This saves an ifconfig command, which improves performance.
-+
-+ def updateAddr( self ):
-+ "Return IP address and MAC address based on ifconfig."
-+ ifconfig = self.ifconfig()
-+ ips = self._ipMatchRegex.findall( ifconfig )
-+ macs = self._macMatchRegex.findall( ifconfig )
-+ self.ip = ips[ 0 ] if ips else None
-+ self.mac = macs[ 0 ] if macs else None
-+ return self.ip, self.mac
-+
-+ def IP( self ):
-+ "Return IP address"
-+ return self.ip
-+
-+ def MAC( self ):
-+ "Return MAC address"
-+ return self.mac
-+
-+ def isUp( self, setUp=False ):
-+ "Return whether interface is up"
-+ if setUp:
-+ cmdOutput = self.ifconfig( 'up' )
-+ # no output indicates success
-+ if cmdOutput:
-+ error( "Error setting %s up: %s " % ( self.name, cmdOutput ) )
-+ return False
-+ else:
-+ return True
-+ else:
-+ return "UP" in self.ifconfig()
-+
-+ def rename( self, newname ):
-+ """Rename interface"""
-+ pass
-+
-+ # 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 isinstance( value, list ):
-+ result = f( *value )
-+ elif isinstance( value, 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 )
-+ return r
-+
-+ def delete( self ):
-+ "Delete interface"
-+ pass
-+
-+ def status( self ):
-+ "Return intf status as a string"
-+ pass
-+
-+ def __repr__( self ):
-+ return '<%s %s>' % ( self.__class__.__name__, self.name )
-+
-+ def __str__( self ):
-+ return self.name
Index: patches/patch-mininet_basenode_py
===================================================================
RCS file: patches/patch-mininet_basenode_py
diff -N patches/patch-mininet_basenode_py
--- patches/patch-mininet_basenode_py 7 Dec 2017 06:33:40 -0000 1.3
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,546 +0,0 @@
-$OpenBSD: patch-mininet_basenode_py,v 1.3 2017/12/07 06:33:40 akoshibe Exp $
-OS-agnostic parts of node.py.
-Turn on PID tracking by default since it's used to reliably stop
-processes.
-Index: mininet/basenode.py
---- mininet/basenode.py.orig
-+++ mininet/basenode.py
-@@ -0,0 +1,538 @@
-+"""
-+The base node object that other network nodes are based upon. A node implements
-+the lightweight virtualization needed to implement hosts and switches.
-+"""
-+import os
-+import pty
-+import re
-+import select
-+from subprocess import Popen, PIPE
-+
-+plat = os.uname()[ 0 ]
-+if plat == 'FreeBSD':
-+ from mininet.freebsd.util import LO, moveIntf
-+elif plat == 'Linux':
-+ from mininet.linux.util import LO, moveIntf
-+else:
-+ from mininet.openbsd.util import LO, moveIntf
-+
-+from mininet.log import info, error, warn, debug
-+from mininet.util import quietRun
-+from mininet.moduledeps import pathCheck
-+from mininet.link import Link
-+from re import findall
-+
-+
-+class BaseNode( object ):
-+ """A virtual network node is simply a shell in a network namespace.
-+ We communicate with it using pipes."""
-+
-+ portBase = 0 # Nodes always start with eth0/port0, even in OF 1.0
-+
-+ def __init__( self, name, inNamespace=True, **params ):
-+ """name: name of node
-+ inNamespace: in network namespace?
-+ privateDirs: list of private directory strings or tuples
-+ params: Node parameters (see config() for details)"""
-+
-+ # Make sure class actually works
-+ self.checkSetup()
-+
-+ self.name = params.get( 'name', name )
-+ self.privateDirs = params.get( 'privateDirs', [] )
-+ self.inNamespace = params.get( 'inNamespace', inNamespace )
-+
-+ # Stash configuration parameters for future reference
-+ self.params = params
-+
-+ self.intfs = {} # dict of port numbers to interfaces
-+ self.ports = {} # dict of interfaces to port numbers
-+ # replace with Port objects, eventually ?
-+ self.nameToIntf = {} # dict of interface names to Intfs
-+
-+ # Make pylint happy
-+ ( self.shell, self.execed, self.pid, self.stdin, self.stdout,
-+ self.lastPid, self.lastCmd, self.pollOut ) = (
-+ None, None, None, None, None, None, None, None )
-+ self.waiting = False
-+ self.readbuf = ''
-+
-+ # Start command interpreter shell
-+ self.startShell()
-+ self.mountPrivateDirs()
-+
-+ # File descriptor to node mapping support
-+ # Class variables and methods
-+
-+ inToNode = {} # mapping of input fds to nodes
-+ outToNode = {} # mapping of output fds to nodes
-+
-+ @classmethod
-+ def fdToNode( cls, fd ):
-+ """Return node corresponding to given file descriptor.
-+ fd: file descriptor
-+ returns: node"""
-+ node = cls.outToNode.get( fd )
-+ return node or cls.inToNode.get( fd )
-+
-+ def getShell( self, master, slave, mnopts=None ):
-+ # OS-specific virtualization method - overriden in system nodes
-+ pass
-+
-+ def isShellBuiltin( self, cmd ):
-+ # Shell-specific check - overridden in system nodes
-+ pass
-+
-+ # Command support via shell process in namespace
-+ def startShell( self, mnopts=None ):
-+ "Start a shell process for running commands"
-+ if self.shell:
-+ error( "%s: shell is already running\n" % self.name )
-+ return
-+
-+ # Spawn a shell subprocess in a pseudo-tty, to disable buffering
-+ # in the subprocess and insulate it from signals (e.g. SIGINT)
-+ # received by the parent
-+ master, slave = pty.openpty()
-+ self.shell = self.getShell( master, slave, mnopts )
-+ self.stdin = os.fdopen( master, 'rw' )
-+ self.stdout = self.stdin
-+ self.pid = self.shell.pid
-+ self.pollOut = select.poll()
-+ self.pollOut.register( self.stdout )
-+ # Maintain mapping between file descriptors and nodes
-+ # This is useful for monitoring multiple nodes
-+ # using select.poll()
-+ self.outToNode[ self.stdout.fileno() ] = self
-+ self.inToNode[ self.stdin.fileno() ] = self
-+ self.execed = False
-+ self.lastCmd = None
-+ self.lastPid = None
-+ self.readbuf = ''
-+ # Wait for prompt
-+ while True:
-+ data = self.read( 1024 )
-+ if data[ -1 ] == chr( 127 ):
-+ break
-+ self.pollOut.poll()
-+ self.waiting = False
-+ # +m: disable job control notification
-+ self.cmd( 'unset HISTFILE; stty -echo; set +m' )
-+
-+ def mountPrivateDirs( self ):
-+ "mount private directories - overridden"
-+ pass
-+
-+ def unmountPrivateDirs( self ):
-+ "mount private directories - overridden"
-+ pass
-+
-+ def _popen( self, cmd, **params ):
-+ """Internal method: spawn and return a process
-+ cmd: command to run (list)
-+ params: parameters to Popen()"""
-+ # Leave this is as an instance method for now
-+ assert self
-+ return Popen( cmd, **params )
-+
-+ def cleanup( self ):
-+ "Help python collect its garbage."
-+ self.shell = None
-+
-+ # Subshell I/O, commands and control
-+
-+ def read( self, maxbytes=1024 ):
-+ """Buffered read from node, potentially blocking.
-+ maxbytes: maximum number of bytes to return"""
-+ count = len( self.readbuf )
-+ if count < maxbytes:
-+ data = os.read( self.stdout.fileno(), maxbytes - count )
-+ self.readbuf += data
-+ if maxbytes >= len( self.readbuf ):
-+ result = self.readbuf
-+ self.readbuf = ''
-+ else:
-+ result = self.readbuf[ :maxbytes ]
-+ self.readbuf = self.readbuf[ maxbytes: ]
-+ return result
-+
-+ def readline( self ):
-+ """Buffered readline from node, potentially blocking.
-+ returns: line (minus newline) or None"""
-+ self.readbuf += self.read( 1024 )
-+ if '\n' not in self.readbuf:
-+ return None
-+ pos = self.readbuf.find( '\n' )
-+ line = self.readbuf[ 0: pos ]
-+ self.readbuf = self.readbuf[ pos + 1: ]
-+ return line
-+
-+ # overridden in some platforms
-+ def write( self, data ):
-+ """Write data to node.
-+ data: string"""
-+ os.write( self.stdin.fileno(), data )
-+
-+ def terminate( self ):
-+ "Send kill signal to Node and clean up after it."
-+ pass
-+
-+ def stop( self, deleteIntfs=False ):
-+ """Stop node.
-+ deleteIntfs: delete interfaces? (False)"""
-+ if deleteIntfs:
-+ self.deleteIntfs()
-+ self.terminate()
-+
-+ def waitReadable( self, timeoutms=None ):
-+ """Wait until node's output is readable.
-+ timeoutms: timeout in ms or None to wait indefinitely.
-+ returns: result of poll()"""
-+ if len( self.readbuf ) == 0:
-+ return self.pollOut.poll( timeoutms )
-+
-+ def sendCmd( self, *args, **kwargs ):
-+ """Send a command, followed by a command to echo a sentinel,
-+ and return without waiting for the command to complete.
-+ args: command and arguments, or string
-+ printPid: print command's PID? (False)"""
-+ assert self.shell and not self.waiting
-+ printPid = kwargs.get( 'printPid', True )
-+ # Allow sendCmd( [ list ] )
-+ if len( args ) == 1 and isinstance( args[ 0 ], list ):
-+ cmd = args[ 0 ]
-+ # Allow sendCmd( cmd, arg1, arg2... )
-+ elif len( args ) > 0:
-+ cmd = args
-+ # Convert to string
-+ if not isinstance( cmd, str ):
-+ cmd = ' '.join( [ str( c ) for c in cmd ] )
-+ if not re.search( r'\w', cmd ):
-+ # Replace empty commands with something harmless
-+ cmd = 'echo -n'
-+ self.lastCmd = cmd
-+ # if a builtin command is backgrounded, it still yields a PID
-+ if len( cmd ) > 0 and cmd[ -1 ] == '&':
-+ # print ^A{pid}\n so monitor() can set lastPid
-+ cmd += ' printf "\\001%d\\012" $! '
-+ elif printPid and not self.isShellBuiltin( cmd ):
-+ cmd = 'mnexec -p ' + cmd
-+ self.write( cmd + '\n' )
-+ self.lastPid = None
-+ self.waiting = True
-+
-+ def monitor( self, timeoutms=None, findPid=True ):
-+ """Monitor and return the output of a command.
-+ Set self.waiting to False if command has completed.
-+ timeoutms: timeout in ms or None to wait indefinitely
-+ findPid: look for PID from mnexec -p"""
-+ ready = self.waitReadable( timeoutms )
-+ if not ready:
-+ return ''
-+ data = self.read( 1024 )
-+ pidre = r'\[\d+\] \d+\r\n'
-+ # Look for PID
-+ marker = chr( 1 ) + r'\d+\r\n'
-+ if findPid and chr( 1 ) in data:
-+ # suppress the job and PID of a backgrounded command
-+ if re.findall( pidre, data ):
-+ data = re.sub( pidre, '', data )
-+ # Marker can be read in chunks; continue until all of it is read
-+ while not re.findall( marker, data ):
-+ data += self.read( 1024 )
-+ markers = re.findall( marker, data )
-+ if markers:
-+ self.lastPid = int( markers[ 0 ][ 1: ] )
-+ data = re.sub( marker, '', data )
-+ # Look for sentinel/EOF
-+ if len( data ) > 0 and data[ -1 ] == chr( 127 ):
-+ self.waiting = False
-+ data = data[ :-1 ]
-+ elif chr( 127 ) in data:
-+ self.waiting = False
-+ data = data.replace( chr( 127 ), '' )
-+ return data
-+
-+ def waitOutput( self, verbose=False, findPid=True ):
-+ """Wait for a command to complete.
-+ Completion is signaled by a sentinel character, ASCII(127)
-+ appearing in the output stream. Wait for the sentinel and return
-+ the output, including trailing newline.
-+ verbose: print output interactively"""
-+ log = info if verbose else debug
-+ output = ''
-+ while self.waiting:
-+ data = self.monitor( findPid=findPid )
-+ output += data
-+ log( data )
-+ return output
-+
-+ def cmd( self, *args, **kwargs ):
-+ """Send a command, wait for output, and return it.
-+ cmd: string"""
-+ verbose = kwargs.get( 'verbose', False )
-+ log = info if verbose else debug
-+ log( '*** %s : %s\n' % ( self.name, args ) )
-+ if self.shell:
-+ self.sendCmd( *args, **kwargs )
-+ return self.waitOutput( verbose )
-+ else:
-+ warn( '(%s exited - ignoring cmd%s)\n' % ( self, args ) )
-+
-+ def cmdPrint( self, *args):
-+ """Call cmd and printing its output
-+ cmd: string"""
-+ return self.cmd( *args, **{ 'verbose': True } )
-+
-+ def popen( self, *args, **kwargs ):
-+ """Return a Popen() object in our namespace
-+ args: Popen() args, single list, or string
-+ kwargs: Popen() keyword args"""
-+ pass
-+
-+ def pexec( self, *args, **kwargs ):
-+ """Execute a command using popen
-+ returns: out, err, exitcode"""
-+ popen = self.popen( *args, stdin=PIPE, stdout=PIPE, stderr=PIPE,
-+ **kwargs )
-+ # Warning: this can fail with large numbers of fds!
-+ out, err = popen.communicate()
-+ exitcode = popen.wait()
-+ return out, err, exitcode
-+
-+ # Interface management, configuration, and routing
-+
-+ # BL notes: This might be a bit redundant or over-complicated.
-+ # However, it does allow a bit of specialization, including
-+ # changing the canonical interface names. It's also tricky since
-+ # the real interfaces are created as veth pairs, so we can't
-+ # make a single interface at a time.
-+
-+ def newPort( self ):
-+ "Return the next port number to allocate."
-+ if len( self.ports ) > 0:
-+ return max( self.ports.values() ) + 1
-+ return self.portBase
-+
-+ def addIntf( self, intf, port=None, moveIntfFn=moveIntf ):
-+ """Add an interface.
-+ intf: interface
-+ port: port number (optional, typically OpenFlow port number)
-+ moveIntfFn: function to move interface (optional)"""
-+ if port is None:
-+ port = self.newPort()
-+ self.intfs[ port ] = intf
-+ self.ports[ intf ] = port
-+ self.nameToIntf[ intf.name ] = intf
-+ debug( '\n' )
-+ debug( 'added intf %s (%d) to node %s\n' % (
-+ intf, port, self.name ) )
-+ if self.inNamespace:
-+ debug( 'moving', intf, 'into namespace for', self.name, '\n' )
-+ moveIntfFn( intf.name, self )
-+
-+ def delIntf( self, intf ):
-+ """Remove interface from Node's known interfaces
-+ Note: to fully delete interface, call intf.delete() instead"""
-+ port = self.ports.get( intf )
-+ if port is not None:
-+ del self.intfs[ port ]
-+ del self.ports[ intf ]
-+ del self.nameToIntf[ intf.name ]
-+
-+ def defaultIntf( self ):
-+ "Return interface for lowest port"
-+ ports = self.intfs.keys()
-+ if ports:
-+ return self.intfs[ min( ports ) ]
-+ else:
-+ warn( '*** defaultIntf: warning:', self.name,
-+ 'has no interfaces\n' )
-+
-+ def intf( self, intf=None ):
-+ """Return our interface object with given string name,
-+ default intf if name is falsy (None, empty string, etc).
-+ or the input intf arg.
-+
-+ Having this fcn return its arg for Intf objects makes it
-+ easier to construct functions with flexible input args for
-+ interfaces (those that accept both string names and Intf objects).
-+ """
-+ if not intf:
-+ return self.defaultIntf()
-+ elif isinstance( intf, basestring ):
-+ return self.nameToIntf[ intf ]
-+ else:
-+ return intf
-+
-+ def connectionsTo( self, node):
-+ "Return [ intf1, intf2... ] for all intfs that connect self to node."
-+ # We could optimize this if it is important
-+ connections = []
-+ for intf in self.intfList():
-+ link = intf.link
-+ if link:
-+ node1, node2 = link.intf1.node, link.intf2.node
-+ if node1 == self and node2 == node:
-+ connections += [ ( intf, link.intf2 ) ]
-+ elif node1 == node and node2 == self:
-+ connections += [ ( intf, link.intf1 ) ]
-+ return connections
-+
-+ def deleteIntfs( self, checkName=True ):
-+ """Delete all of our interfaces.
-+ checkName: only delete interfaces that contain our name"""
-+ # In theory the interfaces should go away after we shut down.
-+ # However, this takes time, so we're better off removing them
-+ # explicitly so that we won't get errors if we run before they
-+ # have been removed by the kernel. Unfortunately this is very slow,
-+ # at least with Linux kernels before 2.6.33
-+ for intf in self.intfs.values():
-+ # Protect against deleting hardware interfaces
-+ if ( self.name in intf.name ) or ( not checkName ):
-+ intf.delete()
-+ info( '.' )
-+
-+ # Routing support
-+
-+ def setARP( self, ip, mac ):
-+ """Add an ARP entry.
-+ ip: IP address as string
-+ mac: MAC address as string"""
-+ result = self.cmd( 'arp', '-s', ip, mac )
-+ return result
-+
-+ def setHostRoute( self, ip, intf ):
-+ """Add route to host.
-+ ip: IP address as dotted decimal
-+ intf: string, interface name"""
-+ pass
-+
-+ def setDefaultRoute( self, intf=None ):
-+ """Set the default route to go through intf.
-+ intf: Intf or {dev <intfname> via <gw-ip> ...}"""
-+ pass
-+
-+ # Convenience and configuration methods
-+
-+ def setMAC( self, mac, intf=None ):
-+ """Set the MAC address for an interface.
-+ intf: intf or intf name
-+ mac: MAC address as string"""
-+ return self.intf( intf ).setMAC( mac )
-+
-+ def setIP( self, ip, prefixLen=8, intf=None, **kwargs ):
-+ """Set the IP address for an interface.
-+ intf: intf or intf name
-+ ip: IP address as a string
-+ prefixLen: prefix length, e.g. 8 for /8 or 16M addrs
-+ kwargs: any additional arguments for intf.setIP"""
-+ return self.intf( intf ).setIP( ip, prefixLen, **kwargs )
-+
-+ def IP( self, intf=None ):
-+ "Return IP address of a node or specific interface."
-+ return self.intf( intf ).IP()
-+
-+ def MAC( self, intf=None ):
-+ "Return MAC address of a node or specific interface."
-+ return self.intf( intf ).MAC()
-+
-+ def intfIsUp( self, intf=None ):
-+ "Check if an interface is up."
-+ return self.intf( intf ).isUp()
-+
-+ # 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 ]
-+ if value is None:
-+ return
-+ f = getattr( self, method, None )
-+ if not f:
-+ return
-+ if isinstance( value, list ):
-+ result = f( *value )
-+ elif isinstance( value, dict ):
-+ result = f( **value )
-+ else:
-+ result = f( value )
-+ results[ name ] = result
-+ return result
-+
-+ def config( self, mac=None, ip=None,
-+ defaultRoute=None, lo='up', **_params ):
-+ """Configure Node according to (optional) parameters:
-+ mac: MAC address for default interface
-+ ip: IP address for default interface
-+ 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, 'setDefaultRoute', defaultRoute=defaultRoute )
-+ # This should be examined
-+ self.cmd( 'ifconfig %s %s' % ( LO, lo ) )
-+ return r
-+
-+ def configDefault( self, **moreParams ):
-+ "Configure with default parameters"
-+ self.params.update( moreParams )
-+ self.config( **self.params )
-+
-+ # This is here for backward compatibility
-+ def linkTo( self, node, link=Link ):
-+ """(Deprecated) Link to another node
-+ replace with Link( node1, node2)"""
-+ return link( self, node )
-+
-+ # Other methods
-+
-+ def intfList( self ):
-+ "List of our interfaces sorted by port number"
-+ return [ self.intfs[ p ] for p in sorted( self.intfs.iterkeys() ) ]
-+
-+ def intfNames( self ):
-+ "The names of our interfaces sorted by port number"
-+ return [ str( i ) for i in self.intfList() ]
-+
-+ def __repr__( self ):
-+ "More informative string representation"
-+ intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() )
-+ for i in self.intfList() ] ) )
-+ return '<%s %s: %s pid=%s> ' % (
-+ self.__class__.__name__, self.name, intfs, self.pid )
-+
-+ def __str__( self ):
-+ "Abbreviated string representation"
-+ return self.name
-+
-+ # Automatic class setup support
-+
-+ isSetup = False
-+
-+ @classmethod
-+ def checkSetup( cls ):
-+ "Make sure our class and superclasses are set up"
-+ while cls and not getattr( cls, 'isSetup', True ):
-+ cls.setup()
-+ cls.isSetup = True
-+ # Make pylint happy
-+ cls = getattr( type( cls ), '__base__', None )
-+
-+ @classmethod
-+ def setup( cls ):
-+ "Make sure our class dependencies are available"
-+ pathCheck( 'mnexec', 'ifconfig', moduleName='Mininet')
Index: patches/patch-mininet_clean_py
===================================================================
RCS file: patches/patch-mininet_clean_py
diff -N patches/patch-mininet_clean_py
--- patches/patch-mininet_clean_py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,189 +0,0 @@
-$OpenBSD: patch-mininet_clean_py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-
-Index: mininet/clean.py
---- mininet/clean.py.orig
-+++ mininet/clean.py
-@@ -9,7 +9,7 @@ code), this script may be used to get rid of unwanted
- It may also get rid of 'false positives', but hopefully
- nothing irreplaceable!
- """
--
-+from os import uname
- from subprocess import ( Popen, PIPE, check_output as co,
- CalledProcessError )
- import time
-@@ -17,27 +17,114 @@ import time
- 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 killprocs( pattern ):
-+def _coPids( pattern ):
-+ try:
-+ return co( [ 'pgrep', '-f', pattern ] )
-+ except CalledProcessError:
-+ return ''
-+
-+def _popenPids( pattern ):
-+ try:
-+ p1 = Popen( [ 'ps' ], stdout=PIPE )
-+ pids = co( [ 'awk', '/%s/{print $1}' % pattern ], stdin=p1.stdout )
-+ p1.stdout.close()
-+ return pids
-+ except CalledProcessError:
-+ return ''
-+
-+def killprocs( pidsFunc, pattern ):
- "Reliably terminate processes matching a pattern (including args)"
- sh( 'pkill -9 -f %s' % pattern )
- # Make sure they are gone
- while True:
-- try:
-- pids = co( [ 'pgrep', '-f', pattern ] )
-- except CalledProcessError:
-- pids = ''
-+ pids = pidsFunc( pattern )
- if pids:
- sh( 'pkill -9 -f %s' % pattern )
- time.sleep( .5 )
- else:
- break
-
-+def killnodes( pidsFunc, pattern='[m]ininet' ):
-+ "kill processes representing nodes"
-+ killprocs( pidsFunc, pattern )
-+ nodes = sh( 'jls name' ).split('\n')
-+ for node in nodes:
-+ if 'mininet:' in node:
-+ sh( 'jail -r %s 2>/dev/null' % node )
-+
-+def _iplinkClean( listCmd=None ):
-+ """ link cleanup using 'ip link' """
-+ links = sh( "ip link show | "
-+ "egrep -o '([-_.[:alnum:]]+-eth[[:digit:]]+)'"
-+ ).splitlines()
-+ # Delete blocks of links
-+ n = 1000 # chunk size
-+ for i in range( 0, len( links ), n ):
-+ cmd = ';'.join( 'ip link del %s' % link
-+ for link in links[ i : i + n ] )
-+ sh( '( %s ) 2> /dev/null' % cmd )
-+
-+ if 'tap9' in sh( 'ip link show' ):
-+ info( "*** Removing tap9 - assuming it's from cluster edition\n" )
-+ sh( 'ip link del tap9' )
-+
-+def _ifClean( listCmd ):
-+ links = sh( listCmd ).splitlines()
-+ # Delete blocks of links
-+ n = 1000 # chunk size
-+ for i in range( 0, len( links ), n ):
-+ cmd = ';'.join( 'ifconfig %s destroy' % link
-+ for link in links[ i : i + n ] )
-+ sh( '( %s ) 2> /dev/null' % cmd )
-+
-+def _ifcfgClean( listCmd ):
-+ """ link cleanup with 'ifconfig'"""
-+ _ifClean( listCmd )
-+ if 'tap9' in sh( 'ifconfig' ):
-+ info( "*** Removing tap9 - assuming it's from cluster edition\n" )
-+ sh( 'ifconfig tap9 destroy' )
-+
-+def _ifcfgCleanLo( listCmd ):
-+ """ link cleanup with 'ifconfig' that assumes formattable listCmd
-+ that takes an interface unit name (see args for OpenBSD)"""
-+ _ifClean( listCmd % 'switch' )
-+ _ifcfgClean( listCmd % 'pair' )
-+
-+ los = sh( listCmd % 'lo' ).splitlines()
-+ n = 256 # chunk size - can only have 256 max, per rdomain(4)
-+ for i in range( 1, len( los ), n ):
-+ cmd = ';'.join( 'ifconfig %s rdomain 0 destroy' % lo
-+ for lo in los[ i : i + n ] )
-+ sh( '( %s ) 2> /dev/null' % cmd )
-+
-+
-+platform = uname()[ 0 ]
-+if platform == 'FreeBSD':
-+ cleanLinks = _ifcfgClean
-+ args = "ifconfig -l | egrep -o '([-_.[:alnum:]]+-eth[[:digit:]]+)'"
-+ pidsFunc = _popenPids
-+ cleanNodes = killnodes
-+ zkill_cmd = ( 'killall -9 ping mnexec ryu-manager' )
-+elif platform == 'Linux':
-+ cleanLinks, args = _iplinkClean, None
-+ pidsFunc = _coPids
-+ cleanNodes = killprocs
-+ zkill_cmd = ( 'killall -9 controller ofprotocol ofdatapath ping nox_core'
-+ 'lt-nox_core ovs-openflowd ovs-controller'
-+ 'ovs-testcontroller udpbwtest mnexec ivs ryu-manager' )
-+else: # OpenBSD
-+ cleanLinks = _ifcfgCleanLo
-+ args = "ifconfig %s | sed -n 's|\(^[a-z]\{1,\}[0-9]\{1,\}\):.*|\\1| p'"
-+ pidsFunc = _coPids
-+ cleanNodes = killprocs
-+ zkill_cmd = ( 'pkill -9 ping mnexec switchd' )
-+
-+
- class Cleanup( object ):
- "Wrapper for cleanup()"
-
-@@ -50,19 +137,16 @@ class Cleanup( object ):
-
- info( "*** Removing excess controllers/ofprotocols/ofdatapaths/"
- "pings/noxes\n" )
-- zombies = ( 'controller ofprotocol ofdatapath ping nox_core'
-- 'lt-nox_core ovs-openflowd ovs-controller'
-- 'ovs-testcontroller udpbwtest mnexec ivs ryu-manager' )
- # Note: real zombie processes can't actually be killed, since they
- # are already (un)dead. Then again,
- # you can't connect to them either, so they're mostly harmless.
- # Send SIGTERM first to give processes a chance to shutdown cleanly.
-- sh( 'killall ' + zombies + ' 2> /dev/null' )
-+ sh( zkill_cmd + ' 2> /dev/null' )
- time.sleep( 1 )
-- sh( 'killall -9 ' + zombies + ' 2> /dev/null' )
-+ sh( zkill_cmd + ' 2> /dev/null' )
-
- # And kill off sudo mnexec
-- sh( 'pkill -9 -f "sudo mnexec"')
-+ sh( 'pkill -9 -f "mnexec"')
-
- info( "*** Removing junk from /tmp\n" )
- sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' )
-@@ -88,26 +172,14 @@ class Cleanup( object ):
- sh( 'ovs-vsctl del-br ' + dp )
-
- info( "*** Removing all links of the pattern foo-ethX\n" )
-- links = sh( "ip link show | "
-- "egrep -o '([-_.[:alnum:]]+-eth[[:digit:]]+)'"
-- ).splitlines()
-- # Delete blocks of links
-- n = 1000 # chunk size
-- for i in range( 0, len( links ), n ):
-- cmd = ';'.join( 'ip link del %s' % link
-- for link in links[ i : i + n ] )
-- sh( '( %s ) 2> /dev/null' % cmd )
-+ cleanLinks( args )
-
-- if 'tap9' in sh( 'ip link show' ):
-- info( "*** Removing tap9 - assuming it's from cluster edition\n" )
-- sh( 'ip link del tap9' )
--
- info( "*** Killing stale mininet node processes\n" )
-- killprocs( 'mininet:' )
-+ cleanNodes( pidsFunc, '[m]ininet:' )
-
- info( "*** Shutting down stale tunnels\n" )
-- killprocs( 'Tunnel=Ethernet' )
-- killprocs( '.ssh/mn')
-+ killprocs( pidsFunc, '[T]unnel=Ethernet' )
-+ killprocs( pidsFunc, '.ssh\/mn' )
- sh( 'rm -f ~/.ssh/mn/*' )
-
- # Call any additional cleanup code if necessary
Index: patches/patch-mininet_cli_py
===================================================================
RCS file: patches/patch-mininet_cli_py
diff -N patches/patch-mininet_cli_py
--- patches/patch-mininet_cli_py 10 Apr 2018 07:55:10 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,31 +0,0 @@
-$OpenBSD: patch-mininet_cli_py,v 1.2 2018/04/10 07:55:10 akoshibe Exp $
-split() automatically splits on whitespace.
-Index: mininet/cli.py
---- mininet/cli.py.orig
-+++ mininet/cli.py
-@@ -356,12 +356,11 @@ class CLI( Cmd ):
- """Run dpctl (or ovs-ofctl) command on all switches.
- Usage: dpctl command [arg1] [arg2] ..."""
- args = line.split()
-- if len(args) < 1:
-- error( 'usage: dpctl command [arg1] [arg2] ...\n' )
-- return
- for sw in self.mn.switches:
-- output( '*** ' + sw.name + ' ' + ('-' * 72) + '\n' )
-- output( sw.dpctl( *args ) )
-+ res = sw.dpctl( *args )
-+ if res:
-+ output( '*** ' + sw.name + ' ' + ('-' * 72) + '\n' )
-+ output( res )
-
- def do_time( self, line ):
- "Measure time taken for any command in Mininet."
-@@ -411,7 +410,7 @@ class CLI( Cmd ):
- % first )
- return
- node = self.mn[ first ]
-- rest = args.split( ' ' )
-+ rest = args.split()
- # Substitute IP addresses for node names in command
- # If updateIP() returns None, then use node name
- rest = [ self.mn[ arg ].defaultIntf().updateIP() or arg
Index: patches/patch-mininet_link_py
===================================================================
RCS file: patches/patch-mininet_link_py
diff -N patches/patch-mininet_link_py
--- patches/patch-mininet_link_py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,257 +0,0 @@
-$OpenBSD: patch-mininet_link_py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-virtual ethernet and related things (Intf) moved to OS-specific dirs.
-Index: mininet/link.py
---- mininet/link.py.orig
-+++ mininet/link.py
-@@ -23,203 +23,21 @@ TCIntf: interface with bandwidth limiting and delay vi
-
- Link: basic link class for creating veth pairs
- """
-+from os import uname
-
-+plat = uname()[ 0 ]
-+if plat == 'FreeBSD':
-+ from mininet.freebsd.intf import Intf
-+ from mininet.freebsd.util import makeIntfPair
-+elif plat == 'Linux':
-+ from mininet.linux.intf import Intf
-+ from mininet.linux.util import makeIntfPair
-+else:
-+ from mininet.openbsd.intf import Intf
-+ from mininet.openbsd.util import makeIntfPair
-+
- from mininet.log import info, error, debug
--from mininet.util import makeIntfPair
--import re
-
--class Intf( object ):
--
-- "Basic interface object that can configure itself."
--
-- def __init__( self, name, node=None, port=None, link=None,
-- mac=None, **params ):
-- """name: interface name (e.g. h1-eth0)
-- node: owning node (where this intf most likely lives)
-- link: parent link if we're part of a link
-- other arguments are passed to config()"""
-- self.node = node
-- self.name = name
-- self.link = link
-- self.mac = mac
-- self.ip, self.prefixLen = None, None
--
-- # if interface is lo, we know the ip is 127.0.0.1.
-- # This saves an ifconfig command per node
-- if self.name == 'lo':
-- self.ip = '127.0.0.1'
-- self.prefixLen = 8
-- # Add to node (and move ourselves if necessary )
-- if node:
-- moveIntfFn = params.pop( 'moveIntfFn', None )
-- if moveIntfFn:
-- node.addIntf( self, port=port, moveIntfFn=moveIntfFn )
-- else:
-- node.addIntf( self, port=port )
-- # Save params for future reference
-- self.params = params
-- self.config( **params )
--
-- 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:
-- if prefixLen is None:
-- raise Exception( 'No prefix length set for IP address %s'
-- % ( ipstr, ) )
-- self.ip, self.prefixLen = ipstr, prefixLen
-- return self.ifconfig( '%s/%s' % ( ipstr, prefixLen ) )
--
-- 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"
-- # use pexec instead of node.cmd so that we dont read
-- # backgrounded output from the cli.
-- ifconfig, _err, _exitCode = self.node.pexec(
-- 'ifconfig %s' % self.name )
-- ips = self._ipMatchRegex.findall( ifconfig )
-- self.ip = ips[ 0 ] if ips else None
-- return self.ip
--
-- 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
--
-- # Instead of updating ip and mac separately,
-- # use one ifconfig call to do it simultaneously.
-- # This saves an ifconfig command, which improves performance.
--
-- def updateAddr( self ):
-- "Return IP address and MAC address based on ifconfig."
-- ifconfig = self.ifconfig()
-- ips = self._ipMatchRegex.findall( ifconfig )
-- macs = self._macMatchRegex.findall( ifconfig )
-- self.ip = ips[ 0 ] if ips else None
-- self.mac = macs[ 0 ] if macs else None
-- return self.ip, self.mac
--
-- def IP( self ):
-- "Return IP address"
-- return self.ip
--
-- def MAC( self ):
-- "Return MAC address"
-- return self.mac
--
-- def isUp( self, setUp=False ):
-- "Return whether interface is up"
-- if setUp:
-- cmdOutput = self.ifconfig( 'up' )
-- # no output indicates success
-- if cmdOutput:
-- error( "Error setting %s up: %s " % ( self.name, cmdOutput ) )
-- return False
-- else:
-- return True
-- else:
-- return "UP" in self.ifconfig()
--
-- def rename( self, newname ):
-- "Rename interface"
-- self.ifconfig( 'down' )
-- result = self.cmd( 'ip link set', 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 isinstance( value, list ):
-- result = f( *value )
-- elif isinstance( value, 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 )
-- return r
--
-- def delete( self ):
-- "Delete interface"
-- self.cmd( 'ip link del ' + self.name )
-- # We used to do this, but it slows us down:
-- # if self.node.inNamespace:
-- # Link may have been dumped into root NS
-- # quietRun( 'ip link del ' + self.name )
-- self.node.delIntf( self )
-- self.link = None
--
-- def status( self ):
-- "Return intf status as a string"
-- links, _err, _result = self.node.pexec( 'ip link show' )
-- if self.name in links:
-- return "OK"
-- else:
-- return "MISSING"
--
-- def __repr__( self ):
-- return '<%s %s>' % ( self.__class__.__name__, self.name )
--
-- def __str__( self ):
-- return self.name
--
--
- class TCIntf( Intf ):
- """Interface customized by tc (traffic control) utility
- Allows specification of bandwidth limits (various methods)
-@@ -253,7 +71,7 @@ class TCIntf( Intf ):
- + 'rate %fMbit ul rate %fMbit' % ( bw, bw ) ]
- elif use_tbf:
- if latency_ms is None:
-- latency_ms = 15.0 * 8 / bw
-+ latency_ms = 15 * 8 / bw
- cmds += [ '%s qdisc add dev %s root handle 5: tbf ' +
- 'rate %fMbit burst 15000 latency %fms' %
- ( bw, latency_ms ) ]
-@@ -401,7 +219,7 @@ class TCIntf( Intf ):
-
- class Link( object ):
-
-- """A basic link is just a veth pair.
-+ """A basic link is just a virtual ethernet pair.
- Other types of links could be tunnels, link emulators, etc.."""
-
- # pylint: disable=too-many-branches
-@@ -447,10 +265,14 @@ class Link( object ):
- if fast:
- params1.setdefault( 'moveIntfFn', self._ignore )
- params2.setdefault( 'moveIntfFn', self._ignore )
-- self.makeIntfPair( intfName1, intfName2, addr1, addr2,
-- node1, node2, deleteIntfs=False )
-+ p1, p2 = self.makeIntfPair( intfName1, intfName2, addr1,
-+ addr2, node1, node2,
-+ deleteIntfs=False )
- else:
-- self.makeIntfPair( intfName1, intfName2, addr1, addr2 )
-+ p1, p2 = self.makeIntfPair( intfName1, intfName2, addr1, addr2 )
-+ # Original names of interfaces, if any, and new name are different
-+ # This is useful in cases where interface renaming isn't supported.
-+ params1[ 'orgName' ], params2[ 'orgName' ] = p1, p2
-
- if not cls1:
- cls1 = intf
Index: patches/patch-mininet_moduledeps_py
===================================================================
RCS file: patches/patch-mininet_moduledeps_py
diff -N patches/patch-mininet_moduledeps_py
--- patches/patch-mininet_moduledeps_py 2 Sep 2017 23:10:52 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,27 +0,0 @@
-$OpenBSD: patch-mininet_moduledeps_py,v 1.2 2017/09/02 23:10:52 akoshibe Exp $
-Pull out mod* commands to mininet/linux, map kld* to mod* to avoid
-more changes
-Index: mininet/moduledeps.py
---- mininet/moduledeps.py.orig
-+++ mininet/moduledeps.py
-@@ -4,19 +4,7 @@ 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 ] )
-+from mininet.openbsd.util import ( lsmod, rmmod, modprobe )
-
- OF_KMOD = 'ofdatapath'
- OVS_KMOD = 'openvswitch_mod' # Renamed 'openvswitch' in OVS 1.7+/Linux 3.5+
Index: patches/patch-mininet_net_py
===================================================================
RCS file: patches/patch-mininet_net_py
diff -N patches/patch-mininet_net_py
--- patches/patch-mininet_net_py 10 Apr 2018 07:55:10 -0000 1.3
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,138 +0,0 @@
-$OpenBSD: patch-mininet_net_py,v 1.3 2018/04/10 07:55:10 akoshibe Exp $
-
-Index: mininet/net.py
---- mininet/net.py.orig
-+++ mininet/net.py
-@@ -96,15 +96,29 @@ from time import sleep
- from itertools import chain, groupby
- from math import ceil
-
-+plat = os.uname()[ 0 ]
-+if plat == 'FreeBSD':
-+ from mininet.freebsd.node import Node
-+ from mininet.freebsd.intf import Intf
-+ from mininet.freebsd.util import fixLimits, numCores
-+elif plat == 'Linux':
-+ from mininet.linux.node import Node
-+ from mininet.linux.intf import Intf
-+ from mininet.linux.util import fixLimits, numCores
-+else:
-+ from mininet.openbsd.node import Node
-+ from mininet.openbsd.intf import Intf
-+ from mininet.openbsd.util import fixLimits, numCores, waitListening
-+
- from mininet.cli import CLI
- from mininet.log import info, error, debug, output, warn
--from mininet.node import ( Node, Host, OVSKernelSwitch, DefaultController,
-- Controller )
-+from mininet.node import ( Host, KernelSwitch, DefaultController,
-+ Controller, RctlHost )
- from mininet.nodelib import NAT
--from mininet.link import Link, Intf
--from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
-- macColonHex, ipStr, ipParse, netParse, ipAdd,
-- waitListening )
-+from mininet.link import Link
-+from mininet.util import ( quietRun, ensureRoot,
-+ macColonHex, ipStr, ipParse, netParse, ipAdd
-+ )
- from mininet.term import cleanUpScreens, makeTerms
-
- # Mininet version: should be consistent with README and LICENSE
-@@ -113,7 +127,7 @@ VERSION = "2.3.0d1"
- class Mininet( object ):
- "Network emulation with hosts spawned in network namespaces."
-
-- def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
-+ def __init__( self, topo=None, switch=KernelSwitch, host=Host,
- controller=DefaultController, link=Link, intf=Intf,
- build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
- inNamespace=False,
-@@ -807,7 +821,7 @@ class Mininet( object ):
- client, server = hosts
- output( '*** Iperf: testing', l4Type, 'bandwidth between',
- client, 'and', server, '\n' )
-- server.cmd( 'killall -9 iperf' )
-+ server.cmd( 'pkill -9 iperf' )
- iperfArgs = 'iperf -p %d ' % port
- bwArgs = ''
- if l4Type == 'UDP':
-@@ -817,9 +831,9 @@ class Mininet( object ):
- raise Exception( 'Unexpected l4 type: %s' % l4Type )
- if fmt:
- iperfArgs += '-f %s ' % fmt
-- server.sendCmd( iperfArgs + '-s' )
-+ server.cmd( iperfArgs + '-s &' )
- if l4Type == 'TCP':
-- if not waitListening( client, server.IP(), port ):
-+ if not waitListening( client, server, port ):
- raise Exception( 'Could not connect to iperf on port %d'
- % port )
- cliout = client.cmd( iperfArgs + '-t %d -c ' % seconds +
-@@ -827,8 +841,8 @@ class Mininet( object ):
- debug( 'Client output: %s\n' % cliout )
- servout = ''
- # We want the last *b/sec from the iperf server output
-- # for TCP, there are two of them because of waitListening
-- count = 2 if l4Type == 'TCP' else 1
-+ # for TCP, there are two fo them because of waitListening
-+ count = 1
- while len( re.findall( '/sec', servout ) ) < count:
- servout += server.monitor( timeoutms=5000 )
- server.sendInt()
-@@ -849,7 +863,7 @@ class Mininet( object ):
- pct = cpu * 100
- info( '*** Testing CPU %.0f%% bandwidth limit\n' % pct )
- hosts = self.hosts
-- cores = int( quietRun( 'nproc' ) )
-+ cores = numCores()
- # number of processes to run a while loop on per host
- num_procs = int( ceil( cores * cpu ) )
- pids = {}
-@@ -863,17 +877,26 @@ class Mininet( object ):
- # get the initial cpu time for each host
- for host in hosts:
- outputs[ host ] = []
-- with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' %
-- host, 'r' ) as f:
-- time[ host ] = float( f.read() )
-+ if isinstance( host, RctlHost ):
-+ time[ host ] = host.getCPUTime( pids[ host ] )
-+ else:
-+ with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' %
-+ host, 'r' ) as f:
-+ time[ host ] = float( f.read() )
- for _ in range( duration ):
- sleep( 1 )
- for host in hosts:
-- with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' %
-- host, 'r' ) as f:
-- readTime = float( f.read() )
-- outputs[ host ].append( ( ( readTime - time[ host ] )
-- / 1000000000 ) / cores * 100 )
-+ if isinstance( host, RctlHost ):
-+ readTime = host.getCPUTime( pids[ host ] )
-+ # is procstat output per-core?
-+ outputs[ host ].append( ( readTime - time[ host ] )
-+ / cores * 100 )
-+ else:
-+ with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' %
-+ host, 'r' ) as f:
-+ readTime = float( f.read() )
-+ outputs[ host ].append( ( ( readTime - time[ host ] )
-+ / 1000000000 ) / cores * 100 )
- time[ host ] = readTime
- for h, pids in pids.items():
- for pid in pids:
-@@ -893,9 +916,9 @@ class Mininet( object ):
- dst: node name
- status: string {up, down}"""
- if src not in self.nameToNode:
-- error( 'src not in network: %s\n' % src )
-+ error( 'src node not in network: %s\n' % src )
- elif dst not in self.nameToNode:
-- error( 'dst not in network: %s\n' % dst )
-+ error( 'dst node not in network: %s\n' % dst )
- else:
- src = self.nameToNode[ src ]
- dst = self.nameToNode[ dst ]
Index: patches/patch-mininet_node_py
===================================================================
RCS file: patches/patch-mininet_node_py
diff -N patches/patch-mininet_node_py
--- patches/patch-mininet_node_py 10 Apr 2018 07:55:10 -0000 1.5
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,992 +0,0 @@
-$OpenBSD: patch-mininet_node_py,v 1.5 2018/04/10 07:55:10 akoshibe Exp $
-Original Node functions are now in BaseNode, subclassed by OS-
-specific Node objects.
-Index: mininet/node.py
---- mininet/node.py.orig
-+++ mininet/node.py
-@@ -53,602 +53,44 @@ Future enhancements:
- """
-
- import os
--import pty
- import re
--import signal
--import select
--from subprocess import Popen, PIPE
-+from subprocess import Popen
- from time import sleep
-
-+plat = os.uname()[ 0 ]
-+if plat == 'FreeBSD':
-+ from mininet.freebsd.node import Node
-+ from mininet.freebsd.intf import Intf
-+ from mininet.freebsd.util import ( LO, DP_MODE, numCores, moveIntf )
-+ OVS_RCSTR = ( 'service ovsdb-server (one)start\n'
-+ 'service ovs-vswitchd (one)start\n' )
-+elif plat == 'Linux':
-+ from mininet.linux.node import Node
-+ from mininet.linux.intf import Intf
-+ from mininet.linux.util import ( LO, DP_MODE, numCores, moveIntf,
-+ mountCgroups )
-+ OVS_RCSTR = 'service openvswitch-switch start\n'
-+else:
-+ from mininet.openbsd.node import Node
-+ from mininet.openbsd.intf import Intf
-+ from mininet.openbsd.util import ( LO, DP_MODE, numCores, moveIntf )
-+
-+
- from mininet.log import info, error, warn, debug
--from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
-- numCores, retry, mountCgroups )
-+from mininet.util import ( quietRun, errRun, errFail, retry )
- from mininet.moduledeps import moduleDeps, pathCheck, TUN
--from mininet.link import Link, Intf, TCIntf, OVSIntf
-+from mininet.link import Link, TCIntf, OVSIntf
- from re import findall
- from distutils.version import StrictVersion
-
--class Node( object ):
-- """A virtual network node is simply a shell in a network namespace.
-- We communicate with it using pipes."""
-
-- portBase = 0 # Nodes always start with eth0/port0, even in OF 1.0
--
-- def __init__( self, name, inNamespace=True, **params ):
-- """name: name of node
-- inNamespace: in network namespace?
-- privateDirs: list of private directory strings or tuples
-- params: Node parameters (see config() for details)"""
--
-- # Make sure class actually works
-- self.checkSetup()
--
-- self.name = params.get( 'name', name )
-- self.privateDirs = params.get( 'privateDirs', [] )
-- self.inNamespace = params.get( 'inNamespace', inNamespace )
--
-- # Stash configuration parameters for future reference
-- self.params = params
--
-- self.intfs = {} # dict of port numbers to interfaces
-- self.ports = {} # dict of interfaces to port numbers
-- # replace with Port objects, eventually ?
-- self.nameToIntf = {} # dict of interface names to Intfs
--
-- # Make pylint happy
-- ( self.shell, self.execed, self.pid, self.stdin, self.stdout,
-- self.lastPid, self.lastCmd, self.pollOut ) = (
-- None, None, None, None, None, None, None, None )
-- self.waiting = False
-- self.readbuf = ''
--
-- # Start command interpreter shell
-- self.startShell()
-- self.mountPrivateDirs()
--
-- # File descriptor to node mapping support
-- # Class variables and methods
--
-- inToNode = {} # mapping of input fds to nodes
-- outToNode = {} # mapping of output fds to nodes
--
-- @classmethod
-- def fdToNode( cls, fd ):
-- """Return node corresponding to given file descriptor.
-- fd: file descriptor
-- returns: node"""
-- node = cls.outToNode.get( fd )
-- return node or cls.inToNode.get( fd )
--
-- # Command support via shell process in namespace
-- def startShell( self, mnopts=None ):
-- "Start a shell process for running commands"
-- if self.shell:
-- error( "%s: shell is already running\n" % self.name )
-- return
-- # mnexec: (c)lose descriptors, (d)etach from tty,
-- # (p)rint pid, and run in (n)amespace
-- opts = '-cd' if mnopts is None else mnopts
-- if self.inNamespace:
-- opts += 'n'
-- # bash -i: force interactive
-- # -s: pass $* to shell, and make process easy to find in ps
-- # prompt is set to sentinel chr( 127 )
-- cmd = [ 'mnexec', opts, 'env', 'PS1=' + chr( 127 ),
-- 'bash', '--norc', '-is', 'mininet:' + self.name ]
-- # Spawn a shell subprocess in a pseudo-tty, to disable buffering
-- # in the subprocess and insulate it from signals (e.g. SIGINT)
-- # received by the parent
-- master, slave = pty.openpty()
-- self.shell = self._popen( cmd, stdin=slave, stdout=slave, stderr=slave,
-- close_fds=False )
-- self.stdin = os.fdopen( master, 'rw' )
-- self.stdout = self.stdin
-- self.pid = self.shell.pid
-- self.pollOut = select.poll()
-- self.pollOut.register( self.stdout )
-- # Maintain mapping between file descriptors and nodes
-- # This is useful for monitoring multiple nodes
-- # using select.poll()
-- self.outToNode[ self.stdout.fileno() ] = self
-- self.inToNode[ self.stdin.fileno() ] = self
-- self.execed = False
-- self.lastCmd = None
-- self.lastPid = None
-- self.readbuf = ''
-- # Wait for prompt
-- while True:
-- data = self.read( 1024 )
-- if data[ -1 ] == chr( 127 ):
-- break
-- self.pollOut.poll()
-- self.waiting = False
-- # +m: disable job control notification
-- self.cmd( 'unset HISTFILE; stty -echo; set +m' )
--
-- def mountPrivateDirs( self ):
-- "mount private directories"
-- # Avoid expanding a string into a list of chars
-- assert not isinstance( self.privateDirs, basestring )
-- for directory in self.privateDirs:
-- if isinstance( directory, tuple ):
-- # mount given private directory
-- privateDir = directory[ 1 ] % self.__dict__
-- mountPoint = directory[ 0 ]
-- self.cmd( 'mkdir -p %s' % privateDir )
-- self.cmd( 'mkdir -p %s' % mountPoint )
-- self.cmd( 'mount --bind %s %s' %
-- ( privateDir, mountPoint ) )
-- else:
-- # mount temporary filesystem on directory
-- self.cmd( 'mkdir -p %s' % directory )
-- self.cmd( 'mount -n -t tmpfs tmpfs %s' % directory )
--
-- def unmountPrivateDirs( self ):
-- "mount private directories"
-- for directory in self.privateDirs:
-- if isinstance( directory, tuple ):
-- self.cmd( 'umount ', directory[ 0 ] )
-- else:
-- self.cmd( 'umount ', directory )
--
-- def _popen( self, cmd, **params ):
-- """Internal method: spawn and return a process
-- cmd: command to run (list)
-- params: parameters to Popen()"""
-- # Leave this is as an instance method for now
-- assert self
-- return Popen( cmd, **params )
--
-- def cleanup( self ):
-- "Help python collect its garbage."
-- # We used to do this, but it slows us down:
-- # Intfs may end up in root NS
-- # for intfName in self.intfNames():
-- # if self.name in intfName:
-- # quietRun( 'ip link del ' + intfName )
-- self.shell = None
--
-- # Subshell I/O, commands and control
--
-- def read( self, maxbytes=1024 ):
-- """Buffered read from node, potentially blocking.
-- maxbytes: maximum number of bytes to return"""
-- count = len( self.readbuf )
-- if count < maxbytes:
-- data = os.read( self.stdout.fileno(), maxbytes - count )
-- self.readbuf += data
-- if maxbytes >= len( self.readbuf ):
-- result = self.readbuf
-- self.readbuf = ''
-- else:
-- result = self.readbuf[ :maxbytes ]
-- self.readbuf = self.readbuf[ maxbytes: ]
-- return result
--
-- def readline( self ):
-- """Buffered readline from node, potentially blocking.
-- returns: line (minus newline) or None"""
-- self.readbuf += self.read( 1024 )
-- if '\n' not in self.readbuf:
-- return None
-- pos = self.readbuf.find( '\n' )
-- line = self.readbuf[ 0: pos ]
-- self.readbuf = self.readbuf[ pos + 1: ]
-- return line
--
-- def write( self, data ):
-- """Write data to node.
-- data: string"""
-- os.write( self.stdin.fileno(), data )
--
-- def terminate( self ):
-- "Send kill signal to Node and clean up after it."
-- self.unmountPrivateDirs()
-- if self.shell:
-- if self.shell.poll() is None:
-- os.killpg( self.shell.pid, signal.SIGHUP )
-- self.cleanup()
--
-- def stop( self, deleteIntfs=False ):
-- """Stop node.
-- deleteIntfs: delete interfaces? (False)"""
-- if deleteIntfs:
-- self.deleteIntfs()
-- self.terminate()
--
-- def waitReadable( self, timeoutms=None ):
-- """Wait until node's output is readable.
-- timeoutms: timeout in ms or None to wait indefinitely.
-- returns: result of poll()"""
-- if len( self.readbuf ) == 0:
-- return self.pollOut.poll( timeoutms )
--
-- def sendCmd( self, *args, **kwargs ):
-- """Send a command, followed by a command to echo a sentinel,
-- and return without waiting for the command to complete.
-- args: command and arguments, or string
-- printPid: print command's PID? (False)"""
-- assert self.shell and not self.waiting
-- printPid = kwargs.get( 'printPid', False )
-- # Allow sendCmd( [ list ] )
-- if len( args ) == 1 and isinstance( args[ 0 ], list ):
-- cmd = args[ 0 ]
-- # Allow sendCmd( cmd, arg1, arg2... )
-- elif len( args ) > 0:
-- cmd = args
-- # Convert to string
-- if not isinstance( cmd, str ):
-- cmd = ' '.join( [ str( c ) for c in cmd ] )
-- if not re.search( r'\w', cmd ):
-- # Replace empty commands with something harmless
-- cmd = 'echo -n'
-- self.lastCmd = cmd
-- # if a builtin command is backgrounded, it still yields a PID
-- if len( cmd ) > 0 and cmd[ -1 ] == '&':
-- # print ^A{pid}\n so monitor() can set lastPid
-- cmd += ' printf "\\001%d\\012" $! '
-- elif printPid and not isShellBuiltin( cmd ):
-- cmd = 'mnexec -p ' + cmd
-- self.write( cmd + '\n' )
-- self.lastPid = None
-- self.waiting = True
--
-- def sendInt( self, intr=chr( 3 ) ):
-- "Interrupt running command."
-- debug( 'sendInt: writing chr(%d)\n' % ord( intr ) )
-- self.write( intr )
--
-- def monitor( self, timeoutms=None, findPid=True ):
-- """Monitor and return the output of a command.
-- Set self.waiting to False if command has completed.
-- timeoutms: timeout in ms or None to wait indefinitely
-- findPid: look for PID from mnexec -p"""
-- ready = self.waitReadable( timeoutms )
-- if not ready:
-- return ''
-- data = self.read( 1024 )
-- pidre = r'\[\d+\] \d+\r\n'
-- # Look for PID
-- marker = chr( 1 ) + r'\d+\r\n'
-- if findPid and chr( 1 ) in data:
-- # suppress the job and PID of a backgrounded command
-- if re.findall( pidre, data ):
-- data = re.sub( pidre, '', data )
-- # Marker can be read in chunks; continue until all of it is read
-- while not re.findall( marker, data ):
-- data += self.read( 1024 )
-- markers = re.findall( marker, data )
-- if markers:
-- self.lastPid = int( markers[ 0 ][ 1: ] )
-- data = re.sub( marker, '', data )
-- # Look for sentinel/EOF
-- if len( data ) > 0 and data[ -1 ] == chr( 127 ):
-- self.waiting = False
-- data = data[ :-1 ]
-- elif chr( 127 ) in data:
-- self.waiting = False
-- data = data.replace( chr( 127 ), '' )
-- return data
--
-- def waitOutput( self, verbose=False, findPid=True ):
-- """Wait for a command to complete.
-- Completion is signaled by a sentinel character, ASCII(127)
-- appearing in the output stream. Wait for the sentinel and return
-- the output, including trailing newline.
-- verbose: print output interactively"""
-- log = info if verbose else debug
-- output = ''
-- while self.waiting:
-- data = self.monitor( findPid=findPid )
-- output += data
-- log( data )
-- return output
--
-- def cmd( self, *args, **kwargs ):
-- """Send a command, wait for output, and return it.
-- cmd: string"""
-- verbose = kwargs.get( 'verbose', False )
-- log = info if verbose else debug
-- log( '*** %s : %s\n' % ( self.name, args ) )
-- if self.shell:
-- self.sendCmd( *args, **kwargs )
-- return self.waitOutput( verbose )
-- else:
-- warn( '(%s exited - ignoring cmd%s)\n' % ( self, args ) )
--
-- def cmdPrint( self, *args):
-- """Call cmd and printing its output
-- cmd: string"""
-- return self.cmd( *args, **{ 'verbose': True } )
--
-- def popen( self, *args, **kwargs ):
-- """Return a Popen() object in our namespace
-- args: Popen() args, single list, or string
-- kwargs: Popen() keyword args"""
-- defaults = { 'stdout': PIPE, 'stderr': PIPE,
-- 'mncmd':
-- [ 'mnexec', '-da', str( self.pid ) ] }
-- defaults.update( kwargs )
-- if len( args ) == 1:
-- if isinstance( args[ 0 ], list ):
-- # popen([cmd, arg1, arg2...])
-- cmd = args[ 0 ]
-- elif isinstance( args[ 0 ], basestring ):
-- # popen("cmd arg1 arg2...")
-- cmd = args[ 0 ].split()
-- else:
-- raise Exception( 'popen() requires a string or list' )
-- elif len( args ) > 0:
-- # popen( cmd, arg1, arg2... )
-- cmd = list( args )
-- # Attach to our namespace using mnexec -a
-- cmd = defaults.pop( 'mncmd' ) + cmd
-- # Shell requires a string, not a list!
-- if defaults.get( 'shell', False ):
-- cmd = ' '.join( cmd )
-- popen = self._popen( cmd, **defaults )
-- return popen
--
-- def pexec( self, *args, **kwargs ):
-- """Execute a command using popen
-- returns: out, err, exitcode"""
-- popen = self.popen( *args, stdin=PIPE, stdout=PIPE, stderr=PIPE,
-- **kwargs )
-- # Warning: this can fail with large numbers of fds!
-- out, err = popen.communicate()
-- exitcode = popen.wait()
-- return out, err, exitcode
--
-- # Interface management, configuration, and routing
--
-- # BL notes: This might be a bit redundant or over-complicated.
-- # However, it does allow a bit of specialization, including
-- # changing the canonical interface names. It's also tricky since
-- # the real interfaces are created as veth pairs, so we can't
-- # make a single interface at a time.
--
-- def newPort( self ):
-- "Return the next port number to allocate."
-- if len( self.ports ) > 0:
-- return max( self.ports.values() ) + 1
-- return self.portBase
--
-- def addIntf( self, intf, port=None, moveIntfFn=moveIntf ):
-- """Add an interface.
-- intf: interface
-- port: port number (optional, typically OpenFlow port number)
-- moveIntfFn: function to move interface (optional)"""
-- if port is None:
-- port = self.newPort()
-- self.intfs[ port ] = intf
-- self.ports[ intf ] = port
-- self.nameToIntf[ intf.name ] = intf
-- debug( '\n' )
-- debug( 'added intf %s (%d) to node %s\n' % (
-- intf, port, self.name ) )
-- if self.inNamespace:
-- debug( 'moving', intf, 'into namespace for', self.name, '\n' )
-- moveIntfFn( intf.name, self )
--
-- def delIntf( self, intf ):
-- """Remove interface from Node's known interfaces
-- Note: to fully delete interface, call intf.delete() instead"""
-- port = self.ports.get( intf )
-- if port is not None:
-- del self.intfs[ port ]
-- del self.ports[ intf ]
-- del self.nameToIntf[ intf.name ]
--
-- def defaultIntf( self ):
-- "Return interface for lowest port"
-- ports = self.intfs.keys()
-- if ports:
-- return self.intfs[ min( ports ) ]
-- else:
-- warn( '*** defaultIntf: warning:', self.name,
-- 'has no interfaces\n' )
--
-- def intf( self, intf=None ):
-- """Return our interface object with given string name,
-- default intf if name is falsy (None, empty string, etc).
-- or the input intf arg.
--
-- Having this fcn return its arg for Intf objects makes it
-- easier to construct functions with flexible input args for
-- interfaces (those that accept both string names and Intf objects).
-- """
-- if not intf:
-- return self.defaultIntf()
-- elif isinstance( intf, basestring):
-- return self.nameToIntf[ intf ]
-- else:
-- return intf
--
-- def connectionsTo( self, node):
-- "Return [ intf1, intf2... ] for all intfs that connect self to node."
-- # We could optimize this if it is important
-- connections = []
-- for intf in self.intfList():
-- link = intf.link
-- if link:
-- node1, node2 = link.intf1.node, link.intf2.node
-- if node1 == self and node2 == node:
-- connections += [ ( intf, link.intf2 ) ]
-- elif node1 == node and node2 == self:
-- connections += [ ( intf, link.intf1 ) ]
-- return connections
--
-- def deleteIntfs( self, checkName=True ):
-- """Delete all of our interfaces.
-- checkName: only delete interfaces that contain our name"""
-- # In theory the interfaces should go away after we shut down.
-- # However, this takes time, so we're better off removing them
-- # explicitly so that we won't get errors if we run before they
-- # have been removed by the kernel. Unfortunately this is very slow,
-- # at least with Linux kernels before 2.6.33
-- for intf in self.intfs.values():
-- # Protect against deleting hardware interfaces
-- if ( self.name in intf.name ) or ( not checkName ):
-- intf.delete()
-- info( '.' )
--
-- # Routing support
--
-- def setARP( self, ip, mac ):
-- """Add an ARP entry.
-- ip: IP address as string
-- mac: MAC address as string"""
-- result = self.cmd( 'arp', '-s', ip, mac )
-- return result
--
-- def setHostRoute( self, ip, intf ):
-- """Add route to host.
-- ip: IP address as dotted decimal
-- intf: string, interface name"""
-- return self.cmd( 'route add -host', ip, 'dev', intf )
--
-- def setDefaultRoute( self, intf=None ):
-- """Set the default route to go through intf.
-- intf: Intf or {dev <intfname> via <gw-ip> ...}"""
-- # Note setParam won't call us if intf is none
-- if isinstance( intf, basestring ) and ' ' in intf:
-- params = intf
-- else:
-- params = 'dev %s' % intf
-- # Do this in one line in case we're messing with the root namespace
-- self.cmd( 'ip route del default; ip route add default', params )
--
-- # Convenience and configuration methods
--
-- def setMAC( self, mac, intf=None ):
-- """Set the MAC address for an interface.
-- intf: intf or intf name
-- mac: MAC address as string"""
-- return self.intf( intf ).setMAC( mac )
--
-- def setIP( self, ip, prefixLen=8, intf=None, **kwargs ):
-- """Set the IP address for an interface.
-- intf: intf or intf name
-- ip: IP address as a string
-- prefixLen: prefix length, e.g. 8 for /8 or 16M addrs
-- kwargs: any additional arguments for intf.setIP"""
-- return self.intf( intf ).setIP( ip, prefixLen, **kwargs )
--
-- def IP( self, intf=None ):
-- "Return IP address of a node or specific interface."
-- return self.intf( intf ).IP()
--
-- def MAC( self, intf=None ):
-- "Return MAC address of a node or specific interface."
-- return self.intf( intf ).MAC()
--
-- def intfIsUp( self, intf=None ):
-- "Check if an interface is up."
-- return self.intf( intf ).isUp()
--
-- # 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 ]
-- if value is None:
-- return
-- f = getattr( self, method, None )
-- if not f:
-- return
-- if isinstance( value, list ):
-- result = f( *value )
-- elif isinstance( value, dict ):
-- result = f( **value )
-- else:
-- result = f( value )
-- results[ name ] = result
-- return result
--
-- def config( self, mac=None, ip=None,
-- defaultRoute=None, lo='up', **_params ):
-- """Configure Node according to (optional) parameters:
-- mac: MAC address for default interface
-- ip: IP address for default interface
-- 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, 'setDefaultRoute', defaultRoute=defaultRoute )
-- # This should be examined
-- self.cmd( 'ifconfig lo ' + lo )
-- return r
--
-- def configDefault( self, **moreParams ):
-- "Configure with default parameters"
-- self.params.update( moreParams )
-- self.config( **self.params )
--
-- # This is here for backward compatibility
-- def linkTo( self, node, link=Link ):
-- """(Deprecated) Link to another node
-- replace with Link( node1, node2)"""
-- return link( self, node )
--
-- # Other methods
--
-- def intfList( self ):
-- "List of our interfaces sorted by port number"
-- return [ self.intfs[ p ] for p in sorted( self.intfs.iterkeys() ) ]
--
-- def intfNames( self ):
-- "The names of our interfaces sorted by port number"
-- return [ str( i ) for i in self.intfList() ]
--
-- def __repr__( self ):
-- "More informative string representation"
-- intfs = ( ','.join( [ '%s:%s' % ( i.name, i.IP() )
-- for i in self.intfList() ] ) )
-- return '<%s %s: %s pid=%s> ' % (
-- self.__class__.__name__, self.name, intfs, self.pid )
--
-- def __str__( self ):
-- "Abbreviated string representation"
-- return self.name
--
-- # Automatic class setup support
--
-- isSetup = False
--
-- @classmethod
-- def checkSetup( cls ):
-- "Make sure our class and superclasses are set up"
-- while cls and not getattr( cls, 'isSetup', True ):
-- cls.setup()
-- cls.isSetup = True
-- # Make pylint happy
-- cls = getattr( type( cls ), '__base__', None )
--
-- @classmethod
-- def setup( cls ):
-- "Make sure our class dependencies are available"
-- pathCheck( 'mnexec', 'ifconfig', moduleName='Mininet')
--
- class Host( Node ):
- "A host is simply a Node"
- pass
-
--class CPULimitedHost( Host ):
-
-+class CgroupHost( Host ):
-+
- "CPU limited host"
-
- def __init__( self, name, sched='cfs', **kwargs ):
-@@ -702,8 +144,8 @@ class CPULimitedHost( Host ):
- args: Popen() args, single list, or string
- kwargs: Popen() keyword args"""
- # Tell mnexec to execute command in our cgroup
-- mncmd = kwargs.pop( 'mncmd', [ 'mnexec', '-g', self.name,
-- '-da', str( self.pid ) ] )
-+ mncmd = [ 'mnexec', '-g', self.name,
-+ '-da', str( self.pid ) ]
- # if our cgroup is not given any cpu time,
- # we cannot assign the RR Scheduler.
- if self.sched == 'rt':
-@@ -739,7 +181,7 @@ class CPULimitedHost( Host ):
- quietRun( 'chrt -p %s %s' % ( self.rtprio, self.pid ) )
- result = quietRun( 'chrt -p %s' % self.pid )
- firstline = result.split( '\n' )[ 0 ]
-- lastword = firstline.split( ' ' )[ -1 ]
-+ lastword = firstline.split()[ -1 ]
- if lastword != 'SCHED_RR':
- error( '*** error: could not assign SCHED_RR to %s\n' % self.name )
- return lastword
-@@ -837,6 +279,105 @@ class CPULimitedHost( Host ):
- cls.inited = True
-
-
-+class RctlHost( Host ):
-+ """
-+ A CPU-limited host that uses a combination of `rctl(8)` and `cpuset(1)`
-+ is used to constrain the host resources. Here, a host is considered to be
-+ the jail.
-+ """
-+
-+ def __init__( self, name, **kwargs ):
-+ Host.__init__( self, name, **kwargs )
-+ self.period_us = kwargs.get( 'period_us', 100000 )
-+ self.pcpu = -1
-+
-+ def setCPUFrac( self, cpu, sched=None, numc=None ):
-+ """Set overall CPU fraction for this host
-+ cpu: CPU bandwidth limit (nonzero float)
-+ sched: Scheduler (ignored but exists for compatibility)
-+ numc: Number of cores"""
-+ if cpu == -1:
-+ return
-+ if cpu < 0:
-+ error( '*** error: fraction must be a positive value' )
-+ return
-+ self.pcpu = cpu
-+ cct = numCores() if numc is None else numc
-+ cmd = 'rctl -a jail:%s:pcpu:deny=%d' % ( self.jid, ( cpu * 100 * cct ) )
-+ quietRun( cmd )
-+
-+ def setCPUs( self, cores, mems=0 ):
-+ """Specify cores that host will run on."""
-+ # do we want to scale back/up pcpu?
-+ # extract valid cores to a list: mask: 0, 1 -> [0,1]
-+ avail = quietRun( 'cpuset -g' ).split()
-+ if avail[2] == "mask:":
-+ valid = map( ( lambda x : int( x.split( ',' )[0] ) ), avail[ 3: ] )
-+
-+ if isinstance( cores, list ):
-+ for c in cores:
-+ if c not in valid:
-+ error( '*** error: cannot assign target to core %d' % c )
-+ return
-+ args = ','.join( [ str( c ) for c in cores ] )
-+ cct = len( cores )
-+ else:
-+ if cores not in valid:
-+ error( '*** error: cannot assign target to core %d' % c )
-+ return
-+ else:
-+ args = str( cores )
-+ cct = 1
-+
-+ cmd = 'cpuset -l %s -j %s' % ( args, self.jid )
-+ quietRun( cmd )
-+
-+ #update the resourcelimit to scale
-+ self.setCPUFrac( self.pcpu, numc=cct )
-+
-+ def rulesDel( self ):
-+ """Remove `rctl` rules associated with this host"""
-+ _out, _err, exitcode = errRun( 'rctl -r jail:%s' % self.jid )
-+ return exitcode
-+
-+ def cleanup( self ):
-+ "Clean up Node, then clean up our resource allocation rules"
-+ super( ResourceLimitedHost, self ).cleanup()
-+ # no need/means to remove cpuset rules - they die with host
-+ retry( retries=3, delaySecs=.1, fn=self.rulesDel )
-+
-+ def config( self, cpu=-1, cores=None, **params ):
-+ """cpu: desired overall system CPU fraction
-+ cores: (real) core(s) this host can run on
-+ params: parameters for Node.config()"""
-+ r = Node.config( self, **params )
-+ # Was considering cpu={'cpu': cpu , 'sched': sched}, but
-+ # that seems redundant
-+ self.setParam( r, 'setCPUFrac', cpu=cpu )
-+ self.setParam( r, 'setCPUs', cores=cores )
-+ return r
-+
-+ def getCPUTime( self, pid ):
-+ """Get CPU time of a process identified by pid. We do this via
-+ procstat(1). It is janky, but 10.x procstat doesn't do libxo
-+ output."""
-+ res = quietRun( 'procstat -rh %s' % pid ).split('\n')
-+ c = 0;
-+ time = 0.0
-+ for line in res:
-+ if 'time' in line:
-+ # the microsecond portion of user/kernel time
-+ time += float(line.split(':')[-1])
-+ c+=1
-+ # got the two lines we need.
-+ if c == 2:
-+ break
-+ return time
-+
-+
-+CPULimitedHost = RctlHost if os.uname()[ 0 ] == 'FreeBSD' else CgroupHost
-+
-+
- # Some important things to note:
- #
- # The "IP" address which setIP() assigns to the switch is not
-@@ -873,7 +414,7 @@ class Switch( Node ):
- self.opts = opts
- self.listenPort = listenPort
- if not self.inNamespace:
-- self.controlIntf = Intf( 'lo', self, port=0 )
-+ self.controlIntf = Intf( LO, self, port=0 )
-
- def defaultDpid( self, dpid=None ):
- "Return correctly formatted dpid from dpid or switch name (s1 -> 1)"
-@@ -1033,7 +574,7 @@ class UserSwitch( Switch ):
- class OVSSwitch( Switch ):
- "Open vSwitch switch. Depends on ovs-vsctl."
-
-- def __init__( self, name, failMode='secure', datapath='kernel',
-+ def __init__( self, name, failMode='secure', datapath=DP_MODE,
- inband=False, protocols=None,
- reconnectms=1000, stp=False, batch=False, **params ):
- """name: name for switch
-@@ -1072,8 +613,8 @@ class OVSSwitch( Switch ):
- 'Make sure that Open vSwitch is installed, '
- 'that ovsdb-server is running, and that\n'
- '"ovs-vsctl show" works correctly.\n'
-- 'You may wish to try '
-- '"service openvswitch-switch start".\n' )
-+ 'You may wish to try the following:\n\n'
-+ + OVS_RCSTR + '\n' )
- exit( 1 )
- version = quietRun( 'ovs-vsctl --version' )
- cls.OVSVersion = findall( r'\d+\.\d+', version )[ 0 ]
-@@ -1153,7 +694,7 @@ class OVSSwitch( Switch ):
- opts = ( ' other_config:datapath-id=%s' % self.dpid +
- ' fail_mode=%s' % self.failMode )
- if not self.inband:
-- opts += ' other-config:disable-in-band=true'
-+ opts += ' other_config:disable-in-band=true'
- if self.datapath == 'user':
- opts += ' datapath_type=netdev'
- if self.protocols and not self.isOldOVS():
-@@ -1239,7 +780,7 @@ class OVSSwitch( Switch ):
- deleteIntfs: delete interfaces? (True)"""
- self.cmd( 'ovs-vsctl del-br', self )
- if self.datapath == 'user':
-- self.cmd( 'ip link del', self )
-+ self.cmd( deleteCmd( self ) )
- super( OVSSwitch, self ).stop( deleteIntfs )
-
- @classmethod
-@@ -1259,9 +800,84 @@ class OVSSwitch( Switch ):
- return switches
-
-
--OVSKernelSwitch = OVSSwitch
-+class IfSwitch( Switch ):
-+ """
-+ OpenBSD switch(4) device switch. Supported on OpenBSD 6.1+.
-+ TODOs : addlocal, dpid, maxflow, maxgroups, portno
-+ """
-
-+ unitNo = 0 # number following device name, e.g. 0 in bridge0
-+ local = None # local switchd instance for remote connection
-
-+ def __init__( self, name, **kwargs ):
-+ self.bname = 'switch%d' % IfSwitch.unitNo
-+ self.cdev = '/dev/' + self.bname # character device name
-+ self.newcdev = False # created a new device?
-+ IfSwitch.unitNo += 1
-+ Switch.__init__( self, name, **kwargs )
-+
-+ def connected( self ):
-+ "Are we forwarding yet?"
-+ return self.bname in self.cmd( 'ifconfig switch' )
-+
-+ def start( self, controllers ):
-+ "Start bridge. Retain the bridge's name to save on ifconfig calls"
-+ rdarg = 'rdomain %d' % self.rdid if self.inNamespace else ''
-+ dparg = 'datapath 0x%s' % self.dpid
-+ quietRun( 'ifconfig %s create %s %s description "%s" up' %
-+ ( self.bname, dparg, rdarg, self.name ) )
-+ addcmd, stpcmd = '', ''
-+ for i in self.intfList():
-+ if i.realname and 'pair' in i.realname:
-+ name = i.realname
-+ addcmd += ' add ' + name
-+ quietRun( 'ifconfig %s %s up' % ( name, rdarg ) )
-+ quietRun( 'ifconfig ' + self.bname + addcmd )
-+
-+ # Connect to controller using switchctl(8) using /dev/switch*
-+ if not os.path.exists( self.cdev ):
-+ # try to make character device, check and try to connect again
-+ self.cmd( 'cd /dev/ && ./MAKEDEV ' + self.bname )
-+ self.newcdev = True
-+
-+ if os.path.exists( self.cdev ):
-+ args = 'switchctl connect ' + self.cdev
-+ ctl = controllers[ 0 ] if controllers else None
-+ if ctl and isinstance( ctl, RemoteController ):
-+ args += ' forward-to %s:%d' % ( ctl.IP(), ctl.port )
-+ # start local Switchd instance and have it forward
-+ if not IfSwitch.local:
-+ IfSwitch.local = Switchd( 'lc0', port=6633 )
-+ IfSwitch.local.start()
-+ quietRun( args )
-+ else:
-+ error( "Can't connect to controller: %s doesn't exist" %
-+ self.cdev )
-+ exit( 1 )
-+
-+ def stop( self, deleteIntfs=True ):
-+ """Stop bridge
-+ deleteIntfs: delete interfaces? (True)"""
-+ quietRun( 'ifconfig %s destroy' % self.bname )
-+ # hack: the last switch destroys the local controller
-+ if IfSwitch.local:
-+ IfSwitch.local.stop()
-+ IfSwitch.local = None
-+ if self.newcdev:
-+ quietRun( 'rm ' + self.cdev )
-+ super( IfSwitch, self ).stop( deleteIntfs )
-+
-+ def dpctl( self, *args ):
-+ "Run brctl command"
-+ # actually switchctl
-+ # choose the first switch to run switchctl(8) from
-+ if self.bname == 'switch0':
-+ return self.cmd( 'switchctl', *args )
-+
-+
-+KernelSwitch = IfSwitch # OpenBSD
-+
-+
- class OVSBridge( OVSSwitch ):
- "OVSBridge is an OVSSwitch in standalone/bridge mode"
-
-@@ -1386,8 +1002,8 @@ class Controller( Node ):
- listening = self.cmd( "echo A | telnet -e A %s %d" %
- ( self.ip, self.port ) )
- if 'Connected' in listening:
-- servers = self.cmd( 'netstat -natp' ).split( '\n' )
-- pstr = ':%d ' % self.port
-+ servers = self.cmd( 'netstat -nlp tcp' ).split( '\n' )
-+ pstr = '.%d ' % self.port
- clist = servers[ 0:1 ] + [ s for s in servers if pstr in s ]
- raise Exception( "Please shut down the controller which is"
- " running on port %d:\n" % self.port +
-@@ -1405,7 +1021,10 @@ class Controller( Node ):
- self.execed = False
-
- def stop( self, *args, **kwargs ):
-- "Stop controller."
-+ """
-+ Stop controller. Find processes associated with the command, and kill
-+ them.
-+ """
- self.cmd( 'kill %' + self.command )
- self.cmd( 'wait %' + self.command )
- super( Controller, self ).stop( *args, **kwargs )
-@@ -1470,12 +1089,19 @@ class NOX( Controller ):
-
- class Ryu( Controller ):
- "Controller to run Ryu application"
-+
- def __init__( self, name, *ryuArgs, **kwargs ):
- """Init.
- name: name to give controller.
- ryuArgs: arguments and modules to pass to Ryu"""
-- homeDir = quietRun( 'printenv HOME' ).strip( '\r\n' )
-- ryuCoreDir = '%s/ryu/ryu/app/' % homeDir
-+
-+ if os.uname()[ 0 ] == 'FreeBSD':
-+ import site
-+ homeDir = site.getsitepackages()[ 0 ]
-+ else:
-+ homeDir = quietRun( 'printenv HOME' ).strip( '\r\n' ) + '/ryu'
-+
-+ ryuCoreDir = '%s/ryu/app/' % homeDir
- if not ryuArgs:
- warn( 'warning: no Ryu modules specified; '
- 'running simple_switch only\n' )
-@@ -1538,7 +1164,53 @@ class RemoteController( Controller ):
- else:
- return True
-
--DefaultControllers = ( Controller, OVSController )
-+
-+class Switchd( Controller ):
-+ """
-+ switchd(4): OpenBSD SDN sflow controller.
-+ """
-+ def __init__( self, name, ip='127.0.0.1', port=6653,
-+ conf='/etc/switchd.mininet.conf', **kwargs):
-+ cmd = '-f ' + conf
-+ cmd += ' -D ctl_ip=%s -D port=%s' % ( ip, port )
-+
-+ # optional parameters (defaults)
-+ tout = kwargs.get('timeout') # MAC address timeout, seconds (240)
-+ vflgs = kwargs.get('vflags') # verbosity, e.g. '-vv'
-+ csize = kwargs.get('cache') # MAC address cache size (4096)
-+
-+ cmd += ' -t %s' % tout if tout else ''
-+ cmd += ' ' + vflgs if vflgs else ''
-+ cmd += ' -t %s' % tout if tout else ''
-+
-+ Controller.__init__( self, name, ip=ip, port=port, command='switchd',
-+ cargs=cmd, **kwargs )
-+
-+ def start( self ):
-+ """Start <controller> <args> on controller."""
-+ pathCheck( self.command )
-+ if self.cdir is not None:
-+ self.cmd( 'cd ' + self.cdir )
-+ self.cmd( self.command + ' ' + self.cargs )
-+ self.ctlpid = quietRun( 'pgrep -n switchd' )
-+ self.execed = False
-+
-+ def stop( self, *args, **kwargs ):
-+ self.cmd( 'kill ' + self.ctlpid )
-+ super( Node, self ).stop()
-+
-+
-+# TODO: push these uname-ey things elsewhere
-+if plat == 'Linux':
-+ DefaultControllers = ( Controller, OVSController )
-+ DefaultSwitch = OVSSwitch
-+elif plat == 'FreeBSD':
-+ DefaultControllers = ( Ryu, )
-+ DefaultSwitch = OVSSwitch
-+else: # OpenBSD
-+ DefaultControllers = ( Switchd, )
-+ DefaultSwitch = IfSwitch
-+
-
- def findController( controllers=DefaultControllers ):
- "Return first available controller from list, if any"
Index: patches/patch-mininet_nodelib_py
===================================================================
RCS file: patches/patch-mininet_nodelib_py
diff -N patches/patch-mininet_nodelib_py
--- patches/patch-mininet_nodelib_py 10 Apr 2018 07:55:10 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,243 +0,0 @@
-$OpenBSD: patch-mininet_nodelib_py,v 1.2 2018/04/10 07:55:10 akoshibe Exp $
-
-Index: mininet/nodelib.py
---- mininet/nodelib.py.orig
-+++ mininet/nodelib.py
-@@ -3,10 +3,11 @@ Node Library for Mininet
-
- This contains additional Node types which you may find to be useful.
- """
-+from os import uname
-
- from mininet.node import Node, Switch
- from mininet.log import info, warn
--from mininet.moduledeps import pathCheck
-+from mininet.moduledeps import lsmod, rmmod, modprobe, pathCheck
- from mininet.util import quietRun
-
-
-@@ -69,7 +70,119 @@ class LinuxBridge( Switch ):
- warn( 'Warning: Linux bridge may not work with', out, '\n' )
-
-
--class NAT( Node ):
-+class IfBridge( Switch ):
-+ "FreeBSD if_bridge(4) Node (with optional spanning tree)."
-+
-+ nextPrio = 100 # next bridge priority for spanning tree
-+
-+ def __init__( self, name, stp=False, prio=None, **kwargs ):
-+ """stp: use spanning tree protocol? (default False)
-+ prio: optional explicit bridge priority for STP"""
-+ self.stp = stp
-+ if prio:
-+ self.prio = prio
-+ else:
-+ self.prio = IfBridge.nextPrio
-+ IfBridge.nextPrio += 1
-+ Switch.__init__( self, name, **kwargs )
-+
-+ def connected( self ):
-+ "Are we forwarding yet?"
-+ if self.stp:
-+ return 'UP' in self.cmd( 'ifconfig', self.bname )
-+ else:
-+ return True
-+
-+ def start( self, _controllers ):
-+ "Start bridge. Retain the bridge's name to save on ifconfig calls"
-+ res = quietRun( 'ifconfig bridge create' )[:-1]
-+ self.bname = res
-+ quietRun( 'ifconfig %s vnet %s' % ( res, self ) )
-+ addcmd, stpcmd = '', ''
-+ for i in self.intfList():
-+ if self.name in i.name or 'epair' in i.name:
-+ addcmd += ' addm ' + i.name
-+ if self.stp:
-+ # STP settings are per-port. perhaps enable that as an option.
-+ stpcmd += ' stp ' + i.name
-+ self.cmd( 'ifconfig', i.name, 'up' )
-+ self.cmd( 'ifconfig', res, addcmd )
-+ if self.stp:
-+ # ifconfig 'stp' and 'priority' latter default 32768
-+ self.cmd( 'ifconfig', res, 'priority', self.prio )
-+ self.cmd( 'ifconfig', res, stpcmd )
-+ self.cmd( 'ifconfig', res, 'up' )
-+
-+ def stop( self, deleteIntfs=True ):
-+ """Stop bridge
-+ deleteIntfs: delete interfaces? (True)"""
-+ self.cmd( 'ifconfig %s destroy' % self.bname )
-+ super( IfBridge, self ).stop( deleteIntfs )
-+
-+ def dpctl( self, *args ):
-+ "Run brctl command"
-+ # actually ifconfig
-+ return self.cmd( 'ifconfig', self.bname, *args )
-+
-+ @classmethod
-+ def setup( cls ):
-+ "Check dependencies"
-+ if 'if_bridge' not in lsmod():
-+ modprobe( 'if_bridge' )
-+
-+
-+class Bridge4( Switch ):
-+ "OpenBSD bridge(4) Node (with optional spanning tree)."
-+
-+ unitNo = 0 # number following device name, e.g. 0 in bridge0
-+
-+ def __init__( self, name, stp=False, prio=None, **kwargs ):
-+ """stp: use spanning tree protocol? (default False)
-+ prio: optional explicit bridge priority for STP"""
-+ self.stp = stp
-+ if prio:
-+ self.prio = prio # else automatically calculate, '-ifcost iface'
-+ Switch.__init__( self, name, **kwargs )
-+
-+ def connected( self ):
-+ "Are we forwarding yet?"
-+ if self.stp:
-+ return 'UP' in self.cmd( 'ifconfig', self.bname )
-+ else:
-+ return True
-+
-+ def start( self, _controllers ):
-+ "Start bridge. Retain the bridge's name to save on ifconfig calls"
-+ self.bname = 'bridge%d' % Bridge4.unitNo
-+ Bridge4.unitNo += 1
-+
-+ rdarg = 'rdomain %d' % self.rdid if self.inNamespace else ''
-+ quietRun( 'ifconfig %s create %s up' % ( self.bname, rdarg ) )
-+ addcmd, stpcmd = '', ''
-+ for i in self.intfList():
-+ if i.realname and 'pair' in i.realname:
-+ name = i.realname
-+ addcmd += ' add ' + name
-+ if self.stp:
-+ stpcmd += ' stp ' + name
-+ if self.prio:
-+ stpcmd += ' ifpriority %s %d ' % ( name, self.prio )
-+ quietRun( 'ifconfig %s %s up' % ( name, rdarg ) )
-+ quietRun( 'ifconfig ' + self.bname + addcmd )
-+
-+ def stop( self, deleteIntfs=True ):
-+ """Stop bridge
-+ deleteIntfs: delete interfaces? (True)"""
-+ quietRun( 'ifconfig %s destroy' % self.bname )
-+ super( Bridge4, self ).stop( deleteIntfs )
-+
-+ def dpctl( self, *args ):
-+ "Run brctl command"
-+ # actually ifconfig
-+ return self.cmd( 'ifconfig', self.bname, *args )
-+
-+
-+class IptablesNAT( Node ):
- "NAT: Provides connectivity to external network"
-
- def __init__( self, name, subnet='10.0/8',
-@@ -143,3 +256,103 @@ class NAT( Node ):
- # Put the forwarding state back to what it was
- self.cmd( 'sysctl net.ipv4.ip_forward=%s' % self.forwardState )
- super( NAT, self ).terminate()
-+
-+
-+class IpfwNAT( Node ):
-+ """NAT: Provides connectivity to external network using ipfw. NOTE: This
-+ *will* mangle IPFW rules that are already present on the host!"""
-+
-+ nextId = 100 # unique NAT instance number
-+ ruleBase = 10 # rule number to start from
-+
-+ def __init__( self, name, subnet='10.0/8',
-+ localIntf=None, flush=False,
-+ natid=None, rulenr=None, **params):
-+ """Start NAT/forwarding between Mininet and external network
-+ subnet: Mininet subnet (default 10.0/8)
-+ flush: flush existing rules before installing NAT rules"""
-+ super( NAT, self ).__init__( name, **params )
-+
-+ self.subnet = subnet
-+ self.localIntf = localIntf
-+ self.flush = flush
-+ if natid:
-+ self.natId = str( natid )
-+ else:
-+ self.natId = str( NAT.nextId )
-+ NAT.nextId += 1
-+ if rulenr:
-+ self.ruleNr = str( rulenr )
-+ else:
-+ self.ruleNr = str( NAT.ruleBase )
-+ NAT.ruleBase += 10 # rule numbers 10 apart for each for readability
-+ self.forwardState = self.cmd( 'sysctl -n net.inet.ip.forwarding' ).strip()
-+
-+ def ipfw( self, *args ):
-+ """ invoke ipfw, -q for quiet """
-+ return self.cmd( 'ipfw -q', *args )
-+
-+ def config( self, **params ):
-+ """Configure the NAT and iptables"""
-+ super( NAT, self).config( **params )
-+
-+ if not self.localIntf:
-+ self.localIntf = self.defaultIntf()
-+
-+ if self.flush:
-+ self.cmd( 'sysctl net.inet.ip.forwarding=0' )
-+ self.ipfw( 'flush' )
-+
-+ # Install NAT rules
-+ self.ipfw( 'nat', self.natId, 'config if', self.localIntf, 'reset' )
-+ self.ipfw( 'add', self.ruleNr, 'nat', self.natId,
-+ 'all from', self.subnet, 'to any out' )
-+ self.ipfw( 'add', self.ruleNr, 'nat', self.natId,
-+ 'all from any to any in' )
-+
-+ # Instruct the kernel to perform forwarding
-+ self.cmd( 'sysctl net.inet.ip.forwarding=1' )
-+
-+ def terminate( self ):
-+ "Stop NAT/forwarding between Mininet and external network"
-+ # Remove NAT rules
-+ self.ipfw( 'delete', self.ruleNr )
-+ self.ipfw( 'delete 32000' )
-+
-+ # Put the forwarding state back to what it was
-+ self.cmd( 'sysctl net.inet.ip.forwarding=%s' % self.forwardState )
-+ super( NAT, self ).terminate()
-+
-+ @classmethod
-+ def setup( cls ):
-+ """ check for dependencies, then configure and load them """
-+ klds = lsmod()
-+ kenv = quietRun( 'kenv net.inet.ip.fw.default_to_accept' ).strip()
-+ deny = True if kenv == '0' else False
-+ # if the default rule is deny all, change to allow all so hosts can
-+ # still pass traffic. Also reload ipfw so that it is reconfigured
-+ if deny:
-+ quietRun( 'kenv net.inet.ip.fw.default_to_accept=1' )
-+ if deny and 'ipfw.ko' in klds:
-+ rmmod( 'ipfw' )
-+ modprobe( 'ipfw' )
-+ if 'ipfw_nat.ko' not in klds:
-+ modprobe( 'ipfw_nat' )
-+
-+
-+class PfNAT( Node ):
-+ """
-+ A pf-based NAT node. (to-do)
-+ """
-+ pass
-+
-+plat = uname()[ 0 ]
-+if plat == 'FreeBSD':
-+ NAT = IpfwNAT
-+ ClassicBridge = IfBridge
-+elif plat == 'OpenBSD':
-+ NAT = PfNAT #todo
-+ ClassicBridge = Bridge4
-+else:
-+ NAT = IptablesNAT
-+ ClassicBridge = LinuxBridge
Index: patches/patch-mininet_openbsd___init___py
===================================================================
RCS file: patches/patch-mininet_openbsd___init___py
diff -N patches/patch-mininet_openbsd___init___py
--- patches/patch-mininet_openbsd___init___py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,7 +0,0 @@
-$OpenBSD: patch-mininet_openbsd___init___py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-
-Index: mininet/openbsd/__init__.py
---- mininet/openbsd/__init__.py.orig
-+++ mininet/openbsd/__init__.py
-@@ -0,0 +1 @@
-+"Docstring to silence pylint; ignores --ignore option for __init__.py"
Index: patches/patch-mininet_openbsd_intf_py
===================================================================
RCS file: patches/patch-mininet_openbsd_intf_py
diff -N patches/patch-mininet_openbsd_intf_py
--- patches/patch-mininet_openbsd_intf_py 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,91 +0,0 @@
-$OpenBSD: patch-mininet_openbsd_intf_py,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-
-Index: mininet/openbsd/intf.py
---- mininet/openbsd/intf.py.orig
-+++ mininet/openbsd/intf.py
-@@ -0,0 +1,85 @@
-+"""
-+A interface object that relies on ifconfig(8) to manipulate network
-+interfaces and devices.
-+"""
-+from mininet.baseintf import BaseIntf
-+
-+class Intf( BaseIntf ):
-+ """Interface objects that use 'ifconfig' to configure the underlying
-+ interface that it represents"""
-+
-+ index=0 # pair(4) index
-+
-+ def __init__( self, name, node=None, port=None, link=None,
-+ mac=None, **params ):
-+ self.realname = params.get( 'orgName' )
-+ BaseIntf.__init__( self, name, node=node, port=port, link=link,
-+ mac=mac, **params )
-+ self.ifconfig( 'description', '"%s"' % name )
-+
-+ def ifconfig( self, *args ):
-+ "Configure ourselves using ifconfig"
-+ name = self.realname if self.realname else self.name
-+ o, err, ext = self.node.pexec( 'ifconfig', name, *args )
-+ if not err:
-+ return o
-+ return err
-+
-+
-+ def setMAC( self, macstr ):
-+ self.mac = macstr
-+ return self.ifconfig( 'lladdr', macstr )
-+
-+ def rename( self, newname ):
-+ """
-+ Rename interface. We retain the real name of the interface as
-+ self.realname since interfaces can't be renamed. Instead we
-+ add a description to the device.
-+ """
-+ if self.name in self.node.portNames:
-+ del self.node.portNames[ self.name ]
-+ self.node.portNames[ newname ] = self.realname
-+ self.name = newname
-+ self.ifconfig( 'description', '"%s"' % newname )
-+ return newname
-+
-+ def delete( self ):
-+ "Delete interface"
-+ self.ifconfig( 'destroy' )
-+ if self.name in self.node.portNames:
-+ del self.node.portNames[ self.name ]
-+ self.node.delIntf( self )
-+ self.link = None
-+
-+ def status( self ):
-+ "Return intf status as a string"
-+ links, _err, _result = self.node.pexec( 'ifconfig pair' )
-+ if self.realname + ':' in links:
-+ return "OK"
-+ else:
-+ return "MISSING"
-+
-+ def realName( self ):
-+ """
-+ Pretend that the interface name has changed, but retain
-+ the real name so we can actually configure the interface
-+ """
-+ return self.realname
-+
-+ def updateIP( self ):
-+ """
-+ Return updated IP address based on ifconfig.
-+ """
-+ # use pexec instead of node.cmd so that we dont read
-+ # backgrounded output from the cli.
-+ ifconfig, _err, _exitCode = self.node.pexec(
-+ 'ifconfig %s' % self.realname )
-+ ips = self._ipMatchRegex.findall( ifconfig )
-+ self.ip = ips[ 0 ] if ips else None
-+ return self.ip
-+
-+ @classmethod
-+ def next( cls ):
-+ idx = Intf.index
-+ Intf.index += 1
-+ return idx
Index: patches/patch-mininet_openbsd_node_py
===================================================================
RCS file: patches/patch-mininet_openbsd_node_py
diff -N patches/patch-mininet_openbsd_node_py
--- patches/patch-mininet_openbsd_node_py 7 Dec 2017 06:33:40 -0000 1.3
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,167 +0,0 @@
-$OpenBSD: patch-mininet_openbsd_node_py,v 1.3 2017/12/07 06:33:40 akoshibe Exp $
-
-Index: mininet/openbsd/node.py
---- mininet/openbsd/node.py.orig
-+++ mininet/openbsd/node.py
-@@ -0,0 +1,161 @@
-+"""
-+Node: rdomain(4) based node. This is somewhat more similar to Linux's network
-+namespace moreso than a jail since it creates a separate network address space
-+only.
-+
-+Mininet 'hosts' are created by running shells within rdomains. Links are made of
-+pair(4)s patched together.
-+
-+This is a collection of helpers that call the right commands to manipulate these
-+components.
-+"""
-+import signal
-+import re
-+from os import killpg
-+
-+from subprocess import PIPE, Popen
-+from mininet.basenode import BaseNode
-+from mininet.log import debug, info, warn
-+from mininet.util import quietRun
-+
-+from mininet.openbsd.util import moveIntf
-+from mininet.openbsd.intf import Intf
-+
-+class Node( BaseNode ):
-+ """A virtual network node that manipulates and tracks rdomains. Because of
-+ the property of rdomains, an OpenBSD node will always come with at least
-+ one pair interface if inNamespace=True."""
-+
-+ index=1 # rdomain ID, can only go to 255
-+ builtins='. : [ alias bg break builtin cd command continue echo eval exec' \
-+ ' exit export false fc fg getopts jobs kill let print pwd read' \
-+ ' readonly return set shift suspend test times trap true typeset' \
-+ ' ulimit umask unalias unset wait whence'
-+
-+ def __init__( self, name, inNamespace=True, **params ):
-+ BaseNode.__init__( self, name, inNamespace, **params )
-+ # No renaming, supply map of assigned interface names to real names
-+ self.portNames = {}
-+
-+ def getShell( self, master, slave, mnopts=None ):
-+ """
-+ Starts a shell used by the node to run commands. If inNamespace=True,
-+ a pair interface is created, assigned to an rdomain, and a shell is
-+ exec'd in the rdomain.
-+ """
-+ execcmd = [ 'mnexec' ]
-+ opts = '-cd' if mnopts is None else mnopts
-+
-+ if self.inNamespace:
-+ # create the pair tied to an rdomain
-+ self.pair, self.rdid = 'pair%d' % Intf.next(), Node.index
-+ Node.index += 1
-+ if Node.index == 256:
-+ error( 'Exceeded supported number of hosts (255)' )
-+ exit( 1 )
-+ rcmd = [ 'ifconfig', self.pair, 'create', 'description',
-+ '"%s"' % self.name, 'rdomain', '%d' % self.rdid ]
-+ Popen( rcmd, stdout=PIPE )
-+ execcmd = [ 'route', '-T%d' % self.rdid, 'exec' ] + execcmd
-+ else:
-+ self.pair = None
-+ self.rdid = None
-+
-+ # -s: pass $* to shell, and make process easy to find in ps. The prompt
-+ # is set to sentinel chr( 127 ).
-+ cmd = execcmd + [ opts, 'env', 'PS1=' + chr( 127 ), '/bin/ksh',
-+ '-is', 'mininet:' + self.name ]
-+ return Popen( cmd, stdin=slave, stdout=slave, stderr=slave,
-+ close_fds=False )
-+
-+ def isShellBuiltin( self, cmd ):
-+ "Return True if cmd is a builtin."
-+ space = cmd.find( ' ' )
-+ if space > 0:
-+ cmd = cmd[ :space]
-+ return cmd in Node.builtins
-+
-+ def mountPrivateDirs( self ):
-+ "mount private directories"
-+ # **Not applicable until further notice**
-+ pass
-+
-+ def unmountPrivateDirs( self ):
-+ "mount private directories - overridden"
-+ # **Not applicable until further notice**
-+ pass
-+
-+ def terminate( self ):
-+ """ Cleanup when node is killed. """
-+ #self.unmountPrivateDirs()
-+ if self.rdid:
-+ lo = 'lo%s' % self.rdid
-+ Popen( [ 'ifconfig', self.pair, 'destroy' ] )
-+ # cleanup loopbacks that are left
-+ Popen( [ 'ifconfig', lo, 'rdomain', '0', 'destroy' ] )
-+ if self.shell:
-+ if self.shell.poll() is None:
-+ killpg( self.shell.pid, signal.SIGHUP )
-+ self.cleanup()
-+
-+ def popen( self, *args, **kwargs ):
-+ """Return a Popen() object in our namespace
-+ args: Popen() args, single list, or string
-+ kwargs: Popen() keyword args"""
-+ defaults = { 'stdout': PIPE, 'stderr': PIPE,
-+ 'mncmd':
-+ [ 'route', '-T%d' % self.rdid, 'exec' ] if self.rdid else
-+ [ 'mnexec', '-d' ] }
-+ defaults.update( kwargs )
-+ if len( args ) == 1:
-+ if isinstance( args[ 0 ], list ):
-+ # popen([cmd, arg1, arg2...])
-+ cmd = args[ 0 ]
-+ elif isinstance( args[ 0 ], basestring ):
-+ # popen("cmd arg1 arg2...")
-+ cmd = args[ 0 ].split()
-+ else:
-+ raise Exception( 'popen() requires a string or list' )
-+ elif len( args ) > 0:
-+ # popen( cmd, arg1, arg2... )
-+ cmd = list( args )
-+ # Attach to our namespace using mnexec -a
-+ cmd = defaults.pop( 'mncmd' ) + cmd
-+ # Shell requires a string, not a list!
-+ if defaults.get( 'shell', False ):
-+ cmd = ' '.join( cmd )
-+ popen = self._popen( cmd, **defaults )
-+ return popen
-+
-+ def sendInt( self, intr=chr( 3 ) ):
-+ "Interrupt running command."
-+ quietRun( 'kill -2 %s' % self.lastPid )
-+
-+ def setHostRoute( self, ip, intf ):
-+ """Add route to host.
-+ ip: IP address as dotted decimal
-+ intf: string, interface name
-+ intfs: interface map of names to Intf"""
-+ # add stronger checks for interface lookup
-+ cmd = 'route -T%s add -host %s %s'
-+ quietRun( cmd % ( self.rdid, ip, self.intfs( intf ).IP() ) )
-+
-+ def setDefaultRoute( self, intf=None ):
-+ """Set the default route to go through intf.
-+ intf: Intf or {dev <intfname> via <gw-ip> ...}"""
-+ # Note setParam won't call us if intf is none
-+ if isinstance( intf, basestring ):
-+ argv = intf.split(' ')
-+ if 'via' not in argv[ 0 ]:
-+ warn( '%s: setDefaultRoute takes a port name but we got: %s\n' %
-+ ( self.name, intf ) )
-+ return
-+ params = argv[ -1 ]
-+ else:
-+ params = intf.IP()
-+ quietRun( 'route -T%d change default %s' % ( self.rdid, params ) )
-+
-+
-+ def addIntf( self, intf, port=None, moveIntfFn=moveIntf ):
-+ self.portNames[ intf.name ] = intf.realname
-+ super( Node, self ).addIntf( intf, port, moveIntfFn )
Index: patches/patch-mininet_openbsd_util_py
===================================================================
RCS file: patches/patch-mininet_openbsd_util_py
diff -N patches/patch-mininet_openbsd_util_py
--- patches/patch-mininet_openbsd_util_py 10 Apr 2018 07:55:10 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,207 +0,0 @@
-$OpenBSD: patch-mininet_openbsd_util_py,v 1.2 2018/04/10 07:55:10 akoshibe Exp $
-
-Index: mininet/openbsd/util.py
---- mininet/openbsd/util.py.orig
-+++ mininet/openbsd/util.py
-@@ -0,0 +1,201 @@
-+"""
-+OS-specific utility functions for OpenBSD, counterpart to util.py.
-+"""
-+
-+from resource import getrlimit, setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
-+
-+from mininet.log import output, error, warn, debug
-+from mininet.util import ( quietRun, retry )
-+
-+from mininet.openbsd.intf import Intf
-+
-+LO='lo0' # loopback name.
-+DP_MODE=None # no OVS (unless manually built?)
-+
-+# Interface management
-+#
-+# Interfaces are managed as strings which are simply the
-+# interface names, of the form 'nodeN-ethM'.
-+#
-+# To connect nodes, we create virtual ethernet pairs (epairs), and then place
-+# them in the pair of nodes that we want to communicate. We then update the
-+# node's list of interfaces and connectivity map.
-+#
-+
-+def makeIntfPair( intf1, intf2, addr1=None, addr2=None, node1=None, node2=None,
-+ deleteIntfs=True, runCmd=None ):
-+ """Make two patched pair(4)s connnecting new interfaces intf1 and intf2
-+ intf1: name for interface 1
-+ intf2: name for interface 2
-+ addr1: MAC address for interface 1 (optional)
-+ addr2: MAC address for interface 2 (optional)
-+ node1: home node for interface 1 (optional)
-+ node2: home node for interface 2 (optional)
-+ deleteIntfs: delete intfs before creating them
-+ runCmd: function to run shell commands (quietRun) - ignored.
-+ raises Exception on failure"""
-+ if deleteIntfs:
-+ # Delete any old interfaces with the same names - want intf-node map?
-+ quietRun( deleteCmd( intf1, node1 ) )
-+ quietRun( deleteCmd( intf2, node2 ) )
-+
-+ # If there are nodes, and they are not 'in namespaces', create pairs for
-+ # them and patch it to a node's.
-+ pair1 = 'pair%d' % Intf.next()
-+ pair2 = 'pair%d' % Intf.next()
-+ cmd1 = 'ifconfig ' + pair1 + ' create'
-+ cmd2 = 'ifconfig ' + pair2 + ' create'
-+ if node1 and node1.rdid:
-+ cmd1 += ' rdomain %d' % node1.rdid
-+ if node2 and node2.rdid:
-+ cmd2 += ' rdomain %d' % node2.rdid
-+ if addr1:
-+ cmd1 += ' lladdr ' + addr1
-+ if addr2:
-+ cmd2 += ' lladdr ' + addr2
-+
-+ # make one end, then patch the other onto it to form a link
-+ quietRun( cmd1 + ' up' )
-+ quietRun( cmd2 + ' patch ' + pair1 + ' up' )
-+
-+ return pair1, pair2
-+
-+
-+def deleteCmd( intf, node=None ):
-+ """Command to destroy an interface. If only intf is specified, assume that
-+ it's in the host and is the true name of the intf."""
-+ if 'pair' not in intf and node:
-+ ifobj = node.nameToIntf.get( intf )
-+ intf = ifobj.realName() if ifobj else intf
-+ return 'ifconfig ' + intf + ' destroy'
-+
-+def moveIntfNoRetry( intf, dstNode, printError=False ):
-+ """Move interface to node from host/root space, without retrying.
-+ intf: string, interface
-+ dstNode: destination Node
-+ printError: if true, print error"""
-+ intf = str( intf )
-+ # get the real name of this intf
-+ if 'pair' not in intf:
-+ intf = dstNode.portNames[ intf ]
-+ cmd = 'ifconfig %s rdomain %s up' % ( intf, dstNode.rdid )
-+ cmdOutput = quietRun( cmd )
-+ # If command does not produce any output, then we can assume
-+ # that the interface has been moved successfully.
-+ if cmdOutput:
-+ if printError:
-+ error( '*** Error: moveIntf: ' + intf +
-+ ' not successfully moved to ' + dstNode.name + ':\n',
-+ cmdOutput )
-+ return False
-+ return True
-+
-+# duplicated in other platforms
-+def moveIntf( intf, dstNode, printError=True,
-+ retries=3, delaySecs=0.001 ):
-+ """Move interface to node, retrying on failure.
-+ intf: string, interface
-+ dstNode: destination Node
-+ printError: if true, print error"""
-+ retry( retries, delaySecs, moveIntfNoRetry, intf, dstNode,
-+ printError=printError )
-+
-+# Other stuff we use
-+def sysctlTestAndSet( name, limit ):
-+ "Helper function to set sysctl limits"
-+ oldLimit = quietRun( 'sysctl -n ' + name )
-+ if 'sysctl' in oldLimit:
-+ error( 'Could not set value: %s' % out )
-+ return
-+ if isinstance( limit, int ):
-+ #compare integer limits before overriding
-+ if int( oldLimit ) < limit:
-+ quietRun( 'sysctl %s=%s' % name, limit )
-+ else:
-+ #overwrite non-integer limits
-+ quietRun( 'sysctl %s=%s' % name, limit )
-+
-+def rlimitTestAndSet( name, limit ):
-+ "Helper function to set rlimits"
-+ soft, hard = getrlimit( name )
-+ if soft < limit:
-+ hardLimit = hard if limit < hard else limit
-+ setrlimit( name, ( limit, hardLimit ) )
-+
-+def fixLimits():
-+ "Fix ridiculously small resource limits."
-+ # see what needs to be/should be tuned here
-+ pass
-+ #debug( "*** Setting resource limits\n" )
-+ #try:
-+ #rlimitTestAndSet( RLIMIT_NPROC, 8192 )
-+ #rlimitTestAndSet( RLIMIT_NOFILE, 16384 )
-+ #Increase open file limit
-+ #sysctlTestAndSet( 'kern.maxfiles', 10000 )
-+ #Increase network buffer space
-+ #sysctlTestAndSet( 'net.core.wmem_max', 16777216 )
-+ #sysctlTestAndSet( 'net.core.rmem_max', 16777216 )
-+ #sysctlTestAndSet( 'net.ipv4.tcp_rmem', '10240 87380 16777216' )
-+ #sysctlTestAndSet( 'net.ipv4.tcp_wmem', '10240 87380 16777216' )
-+ #sysctlTestAndSet( 'net.core.netdev_max_backlog', 5000 )
-+ #Increase arp cache size
-+ #sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh1', 4096 )
-+ #sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh2', 8192 )
-+ #sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh3', 16384 )
-+ #Increase routing table size
-+ #sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 )
-+ #Increase number of PTYs for nodes
-+ #sysctlTestAndSet( 'kernel.pty.max', 20000 )
-+ # pylint: disable=broad-except
-+ #except Exception:
-+ #warn( "*** Error setting resource limits. "
-+ # "Mininet's performance may be affected.\n" )
-+ # pylint: enable=broad-except
-+
-+def numCores():
-+ "Returns number of CPU cores based on /proc/cpuinfo"
-+ if hasattr( numCores, 'ncores' ):
-+ return numCores.ncores
-+ try:
-+ numCores.ncores = int( quietRun('sysctl -n hw.ncpu') )
-+ except ValueError:
-+ return 0
-+ return numCores.ncores
-+
-+# Kernel module manipulation
-+# we don't have any.
-+
-+def lsmod():
-+ """Return list of currently loaded kernel modules."""
-+ pass
-+
-+def rmmod( mod ):
-+ """Attempt to unload a specified module.
-+ mod: module string"""
-+ pass
-+
-+def modprobe( mod ):
-+ """Attempt to load a specified module.
-+ mod: module string"""
-+ pass
-+
-+def waitListening( client, server, port=80, timeout=None ):
-+ """Wait until server is listening on port.
-+ returns True if server is listening"""
-+ # pylint: disable=maybe-no-member
-+ serverIP = server.IP().replace('.', '\.')
-+ rdid = 0 if not server.rdid else server.rdid
-+ cmd = ( 'netstat -nlp tcp -T %d | grep -e %s\.%s -e \*\.%s' \
-+ % ( server.rdid, serverIP, port, port ) )
-+ time = 0
-+ result = server.cmd( cmd )
-+ while 'LISTEN' not in result:
-+ if timeout and time >= timeout:
-+ error( 'could not connect to %s on port %d\n' % ( server, port ) )
-+ return False
-+ debug( 'waiting for', server, 'to listen on port', port, '\n' )
-+ info( '.' )
-+ sleep( .5 )
-+ time += .5
-+ result = server.cmd( cmd )
-+ return True
Index: patches/patch-mininet_util_py
===================================================================
RCS file: patches/patch-mininet_util_py
diff -N patches/patch-mininet_util_py
--- patches/patch-mininet_util_py 7 Dec 2017 06:33:40 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,242 +0,0 @@
-$OpenBSD: patch-mininet_util_py,v 1.2 2017/12/07 06:33:40 akoshibe Exp $
-Remove methods that do OS-specific things to their own platform dirs.
-Index: mininet/util.py
---- mininet/util.py.orig
-+++ mininet/util.py
-@@ -1,10 +1,9 @@
- "Utility functions for Mininet."
-
-
--from mininet.log import output, info, error, warn, debug
-+from mininet.log import output, info, error, debug
-
- from time import sleep
--from resource import getrlimit, setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
- from select import poll, POLLIN, POLLHUP
- from subprocess import call, check_call, Popen, PIPE, STDOUT
- import re
-@@ -18,12 +17,12 @@ from functools import partial
- def run( cmd ):
- """Simple interface to subprocess.call()
- cmd: list of command params"""
-- return call( cmd.split( ' ' ) )
-+ return call( cmd.split() )
-
- def checkRun( cmd ):
- """Simple interface to subprocess.check_call()
- cmd: list of command params"""
-- return check_call( cmd.split( ' ' ) )
-+ return check_call( cmd.split() )
-
- # pylint doesn't understand explicit type checking
- # pylint: disable=maybe-no-member
-@@ -34,7 +33,7 @@ def oldQuietRun( *cmd ):
- if len( cmd ) == 1:
- cmd = cmd[ 0 ]
- if isinstance( cmd, str ):
-- cmd = cmd.split( ' ' )
-+ cmd = cmd.split()
- popen = Popen( cmd, stdout=PIPE, stderr=STDOUT )
- # We can't use Popen.communicate() because it uses
- # select(), which can't handle
-@@ -75,7 +74,7 @@ def errRun( *cmd, **kwargs ):
- cmd = cmd[ 0 ]
- # Allow passing in a list or a string
- if isinstance( cmd, str ) and not shell:
-- cmd = cmd.split( ' ' )
-+ cmd = cmd.split()
- cmd = [ str( arg ) for arg in cmd ]
- elif isinstance( cmd, list ) and shell:
- cmd = " ".join( arg for arg in cmd )
-@@ -134,66 +133,6 @@ def quietRun( cmd, **kwargs ):
-
- # pylint: enable=maybe-no-member
-
--def isShellBuiltin( cmd ):
-- "Return True if cmd is a bash builtin."
-- if isShellBuiltin.builtIns is None:
-- isShellBuiltin.builtIns = quietRun( 'bash -c enable' )
-- space = cmd.find( ' ' )
-- if space > 0:
-- cmd = cmd[ :space]
-- return cmd in isShellBuiltin.builtIns
--
--isShellBuiltin.builtIns = None
--
--# Interface management
--#
--# Interfaces are managed as strings which are simply the
--# interface names, of the form 'nodeN-ethM'.
--#
--# To connect nodes, we create a pair of veth interfaces, and then place them
--# in the pair of nodes that we want to communicate. We then update the node's
--# list of interfaces and connectivity map.
--#
--# For the kernel datapath, switch interfaces
--# live in the root namespace and thus do not have to be
--# explicitly moved.
--
--def makeIntfPair( intf1, intf2, addr1=None, addr2=None, node1=None, node2=None,
-- deleteIntfs=True, runCmd=None ):
-- """Make a veth pair connnecting new interfaces intf1 and intf2
-- intf1: name for interface 1
-- intf2: name for interface 2
-- addr1: MAC address for interface 1 (optional)
-- addr2: MAC address for interface 2 (optional)
-- node1: home node for interface 1 (optional)
-- node2: home node for interface 2 (optional)
-- deleteIntfs: delete intfs before creating them
-- runCmd: function to run shell commands (quietRun)
-- raises Exception on failure"""
-- if not runCmd:
-- runCmd = quietRun if not node1 else node1.cmd
-- runCmd2 = quietRun if not node2 else node2.cmd
-- if deleteIntfs:
-- # Delete any old interfaces with the same names
-- runCmd( 'ip link del ' + intf1 )
-- runCmd2( 'ip link del ' + intf2 )
-- # Create new pair
-- netns = 1 if not node2 else node2.pid
-- if addr1 is None and addr2 is None:
-- cmdOutput = runCmd( 'ip link add name %s '
-- 'type veth peer name %s '
-- 'netns %s' % ( intf1, intf2, netns ) )
-- else:
-- cmdOutput = runCmd( 'ip link add name %s '
-- 'address %s '
-- 'type veth peer name %s '
-- 'address %s '
-- 'netns %s' %
-- ( intf1, addr1, intf2, addr2, netns ) )
-- if cmdOutput:
-- raise Exception( "Error creating interface pair (%s,%s): %s " %
-- ( intf1, intf2, cmdOutput ) )
--
- def retry( retries, delaySecs, fn, *args, **keywords ):
- """Try something several times before giving up.
- n: number of times to retry
-@@ -208,33 +147,6 @@ def retry( retries, delaySecs, fn, *args, **keywords )
- error( "*** gave up after %i retries\n" % tries )
- exit( 1 )
-
--def moveIntfNoRetry( intf, dstNode, printError=False ):
-- """Move interface to node, without retrying.
-- intf: string, interface
-- dstNode: destination Node
-- printError: if true, print error"""
-- intf = str( intf )
-- cmd = 'ip link set %s netns %s' % ( intf, dstNode.pid )
-- cmdOutput = quietRun( cmd )
-- # If ip link set does not produce any output, then we can assume
-- # that the link has been moved successfully.
-- if cmdOutput:
-- if printError:
-- error( '*** Error: moveIntf: ' + intf +
-- ' not successfully moved to ' + dstNode.name + ':\n',
-- cmdOutput )
-- return False
-- return True
--
--def moveIntf( intf, dstNode, printError=True,
-- retries=3, delaySecs=0.001 ):
-- """Move interface to node, retrying on failure.
-- intf: string, interface
-- dstNode: destination Node
-- printError: if true, print error"""
-- retry( retries, delaySecs, moveIntfNoRetry, intf, dstNode,
-- printError=printError )
--
- # Support for dumping network
-
- def dumpNodeConnections( nodes ):
-@@ -403,73 +315,6 @@ def pmonitor(popens, timeoutms=500, readline=True,
- else:
- yield None, ''
-
--# Other stuff we use
--def sysctlTestAndSet( name, limit ):
-- "Helper function to set sysctl limits"
-- #convert non-directory names into directory names
-- if '/' not in name:
-- name = '/proc/sys/' + name.replace( '.', '/' )
-- #read limit
-- with open( name, 'r' ) as readFile:
-- oldLimit = readFile.readline()
-- if isinstance( limit, int ):
-- #compare integer limits before overriding
-- if int( oldLimit ) < limit:
-- with open( name, 'w' ) as writeFile:
-- writeFile.write( "%d" % limit )
-- else:
-- #overwrite non-integer limits
-- with open( name, 'w' ) as writeFile:
-- writeFile.write( limit )
--
--def rlimitTestAndSet( name, limit ):
-- "Helper function to set rlimits"
-- soft, hard = getrlimit( name )
-- if soft < limit:
-- hardLimit = hard if limit < hard else limit
-- setrlimit( name, ( limit, hardLimit ) )
--
--def fixLimits():
-- "Fix ridiculously small resource limits."
-- debug( "*** Setting resource limits\n" )
-- try:
-- rlimitTestAndSet( RLIMIT_NPROC, 8192 )
-- rlimitTestAndSet( RLIMIT_NOFILE, 16384 )
-- #Increase open file limit
-- sysctlTestAndSet( 'fs.file-max', 10000 )
-- #Increase network buffer space
-- sysctlTestAndSet( 'net.core.wmem_max', 16777216 )
-- sysctlTestAndSet( 'net.core.rmem_max', 16777216 )
-- sysctlTestAndSet( 'net.ipv4.tcp_rmem', '10240 87380 16777216' )
-- sysctlTestAndSet( 'net.ipv4.tcp_wmem', '10240 87380 16777216' )
-- sysctlTestAndSet( 'net.core.netdev_max_backlog', 5000 )
-- #Increase arp cache size
-- sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh1', 4096 )
-- sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh2', 8192 )
-- sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh3', 16384 )
-- #Increase routing table size
-- sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 )
-- #Increase number of PTYs for nodes
-- sysctlTestAndSet( 'kernel.pty.max', 20000 )
-- # pylint: disable=broad-except
-- except Exception:
-- warn( "*** Error setting resource limits. "
-- "Mininet's performance may be affected.\n" )
-- # pylint: enable=broad-except
--
--
--def mountCgroups():
-- "Make sure cgroups file system is mounted"
-- mounts = quietRun( 'cat /proc/mounts' )
-- cgdir = '/sys/fs/cgroup'
-- csdir = cgdir + '/cpuset'
-- if ('cgroup %s' % cgdir not in mounts and
-- 'cgroups %s' % cgdir not in mounts):
-- raise Exception( "cgroups not mounted on " + cgdir )
-- if 'cpuset %s' % csdir not in mounts:
-- errRun( 'mkdir -p ' + csdir )
-- errRun( 'mount -t cgroup -ocpuset cpuset ' + csdir )
--
- def natural( text ):
- "To sort sanely/alphabetically: sorted( l, key=natural )"
- def num( s ):
-@@ -480,16 +325,6 @@ def natural( text ):
- def naturalSeq( t ):
- "Natural sort key function for sequences"
- return [ natural( x ) for x in t ]
--
--def numCores():
-- "Returns number of CPU cores based on /proc/cpuinfo"
-- if hasattr( numCores, 'ncores' ):
-- return numCores.ncores
-- try:
-- numCores.ncores = int( quietRun('grep -c processor /proc/cpuinfo') )
-- except ValueError:
-- return 0
-- return numCores.ncores
-
- def irange(start, end):
- """Inclusive range from start to end (vs. Python insanity.)
Index: patches/patch-mnexec_c
===================================================================
RCS file: patches/patch-mnexec_c
diff -N patches/patch-mnexec_c
--- patches/patch-mnexec_c 21 Aug 2017 18:47:12 -0000 1.1.1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,126 +0,0 @@
-$OpenBSD: patch-mnexec_c,v 1.1.1.1 2017/08/21 18:47:12 akoshibe Exp $
-
-Index: mnexec.c
---- mnexec.c.orig
-+++ mnexec.c
-@@ -13,18 +13,27 @@
- * Partially based on public domain setsid(1)
- */
-
-+#ifdef __linux__
- #define _GNU_SOURCE
--#include <stdio.h>
-+
- #include <linux/sched.h>
--#include <unistd.h>
- #include <limits.h>
- #include <syscall.h>
- #include <fcntl.h>
--#include <stdlib.h>
- #include <sched.h>
- #include <ctype.h>
- #include <sys/mount.h>
-
-+#else /* the BSDs */
-+
-+#include <sys/types.h>
-+
-+
No comments:
Post a Comment