From 591a9617623c88c02cb7c9ecc1f18b83f75fd913 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Sun, 13 Dec 2020 12:04:21 -0800 Subject: [PATCH 01/51] Initial support for github actions CI builds --- .github/workflows/run-tests.yaml | 32 ++++++++++++++++++++++++++++++++ README.md | 5 ++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/run-tests.yaml diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml new file mode 100644 index 000000000..1d7be9786 --- /dev/null +++ b/.github/workflows/run-tests.yaml @@ -0,0 +1,32 @@ + +name: mininet tests + +on: [push, pull_request] + +jobs: + test: + name: Mininet-tests + runs-on: ubuntu-18.04 ubuntu 16.04 + steps: + - name: Checking out Mininet source + uses: actions/checkout@v2 + - name: Installing dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -qq vlan + PYTHON=`which python` util/install.sh -n + pip install pexpect || pip3 install pexpect + - name: Code Check + run: | + bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi" + - name: Install + run: | + util/install.sh -fvw + - name: Building and running tests + run: | + alias sudo="sudo env PATH=$PATH" + export PYTHON=`which python` + echo 'px import sys; print(sys.version_info)' | sudo $PYTHON bin/mn -v output + sudo $PYTHON bin/mn --test pingall + sudo $PYTHON mininet/test/runner.py -v -quick + sudo $PYTHON examples/test/runner.py -v -quick diff --git a/README.md b/README.md index e54fe3498..2b399b611 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ Mininet: Rapid Prototyping for Software Defined Networks Mininet 2.3.0d6 -[![Build Status][1]](https://travis-ci.org/mininet/mininet) +[![Build Status][2]](https://github.com/mininet/mininet/actions) +[![Travis Status][1]](https://travis-ci.org/mininet/mininet) + ### What is Mininet? @@ -130,3 +132,4 @@ Bob Lantz Mininet Core Team [1]: https://travis-ci.org/mininet/mininet.svg?branch=master +[2]: https://github.com/mininet/mininet/workflows/mininet%20tests/badge.svg From 362514935691818ded8138cefdc5334868b81e6d Mon Sep 17 00:00:00 2001 From: lantz Date: Sun, 13 Dec 2020 18:00:44 -0800 Subject: [PATCH 02/51] Update run-tests.yaml --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 1d7be9786..a885d34df 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -6,7 +6,7 @@ on: [push, pull_request] jobs: test: name: Mininet-tests - runs-on: ubuntu-18.04 ubuntu 16.04 + runs-on: ubuntu-18.04 ubuntu-16.04 steps: - name: Checking out Mininet source uses: actions/checkout@v2 From cab8970b0ab0d5af4bb5a1719237fd9715dd865e Mon Sep 17 00:00:00 2001 From: lantz Date: Sun, 13 Dec 2020 18:13:27 -0800 Subject: [PATCH 03/51] Update run-tests.yaml --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index a885d34df..cd8b1a65c 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -6,7 +6,7 @@ on: [push, pull_request] jobs: test: name: Mininet-tests - runs-on: ubuntu-18.04 ubuntu-16.04 + runs-on: ubuntu-18.04 steps: - name: Checking out Mininet source uses: actions/checkout@v2 From 537e8242fc8bccf871ae9b78a60425179daf053e Mon Sep 17 00:00:00 2001 From: "Jeff R. Allen" Date: Mon, 14 Dec 2020 04:00:20 +0100 Subject: [PATCH 04/51] Install correctly on Ubuntu 20.04 (#980) * Install correctly on Ubuntu 20.04 Main changes are to avoid pulling in python2 by mistake, and then to make sure to install only python3 packages. Also: Add net-tools which is needed to get ifconfig on newer Ubuntu releases. (admin note: there are still a couple of remaining 20.04 issues but this is helpful) --- util/install.sh | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/util/install.sh b/util/install.sh index 44ba2065a..7789b04b6 100755 --- a/util/install.sh +++ b/util/install.sh @@ -171,8 +171,15 @@ function mn_deps { ethtool help2man python-pyflakes python3-pylint \ python-pep8 ${PYPKG}-pexpect ${PYPKG}-tk else # Debian/Ubuntu + pf=pyflakes + # Starting around 20.04, installing pyflakes instead of pyflakes3 + # causes Python 2 to be installed, which is exactly NOT what we want. + if [ `expr $RELEASE '>=' 20.04` = "1" ]; then + pf=pyflakes3 + fi $install gcc make socat psmisc xterm ssh iperf telnet \ - ethtool help2man pyflakes pylint pep8 \ + ethtool help2man $pf pylint pep8 \ + net-tools \ ${PYPKG}-setuptools ${PYPKG}-pexpect ${PYPKG}-tk $install iproute2 || $install iproute $install cgroup-tools || $install cgroup-bin @@ -351,8 +358,8 @@ function ubuntuOvs { # Get build deps $install build-essential fakeroot debhelper autoconf automake libssl-dev \ - pkg-config bzip2 openssl python-all procps python-qt4 \ - python-zopeinterface python-twisted-conch dkms dh-python dh-autoreconf \ + pkg-config bzip2 openssl ${PYPKG}-all procps ${PYPKG}-qt4 \ + ${PYPKG}-zopeinterface ${PYPKG}-twisted-conch dkms dh-python dh-autoreconf \ uuid-runtime # Build OVS @@ -482,7 +489,7 @@ function ryu { # install Ryu dependencies" $install autoconf automake g++ libtool python make if [ "$DIST" = "Ubuntu" -o "$DIST" = "Debian" ]; then - $install gcc python-pip python-dev libffi-dev libssl-dev \ + $install gcc ${PYPKG}-pip ${PYPKG}-dev libffi-dev libssl-dev \ libxml2-dev libxslt1-dev zlib1g-dev fi @@ -505,17 +512,17 @@ function nox { echo "Installing NOX w/tutorial files..." # Install NOX deps: - $install autoconf automake g++ libtool python python-twisted \ + $install autoconf automake g++ libtool python ${PYPKG}-twisted \ swig libssl-dev make if [ "$DIST" = "Debian" ]; then $install libboost1.35-dev elif [ "$DIST" = "Ubuntu" ]; then - $install python-dev libboost-dev + $install ${PYPKG}-dev libboost-dev $install libboost-filesystem-dev $install libboost-test-dev fi # Install NOX optional deps: - $install libsqlite3-dev python-simplejson + $install libsqlite3-dev ${PYPKG}-simplejson # Fetch NOX destiny cd $BUILD_DIR/ @@ -553,12 +560,12 @@ function nox13 { echo "Installing NOX w/tutorial files..." # Install NOX deps: - $install autoconf automake g++ libtool python python-twisted \ + $install autoconf automake g++ libtool python ${PYPKG}-twisted \ swig libssl-dev make if [ "$DIST" = "Debian" ]; then $install libboost1.35-dev elif [ "$DIST" = "Ubuntu" ]; then - $install python-dev libboost-dev + $install ${PYPKG}-dev libboost-dev $install libboost-filesystem-dev $install libboost-test-dev fi @@ -594,7 +601,7 @@ function oftest { echo "Installing oftest..." # Install deps: - $install tcpdump python-scapy + $install tcpdump ${PYPKG}-scapy # Install oftest: cd $BUILD_DIR/ @@ -620,6 +627,7 @@ function cbench { sh boot.sh || true # possible error in autoreconf, so run twice sh boot.sh ./configure --with-openflow-src-dir=$BUILD_DIR/openflow + make liboflops_test.la make sudo make install || true # make install fails; force past this } From 336b01ae34f8a230dba7ad74323112980e7ec92e Mon Sep 17 00:00:00 2001 From: lantz Date: Sun, 13 Dec 2020 19:14:26 -0800 Subject: [PATCH 05/51] Add matrix build for ubuntu-16.04 and ubuntu-18.04 (#987) --- .github/workflows/run-tests.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index cd8b1a65c..619fbed33 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -6,7 +6,10 @@ on: [push, pull_request] jobs: test: name: Mininet-tests - runs-on: ubuntu-18.04 + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-18.04, ubuntu-16.04] steps: - name: Checking out Mininet source uses: actions/checkout@v2 From afdf9fd57129432d26b7b0dadcada955033eef48 Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 19 Dec 2020 18:06:52 -0800 Subject: [PATCH 06/51] Update for python 2.x and 3.x builds (#988) --- .github/workflows/run-tests.yaml | 55 ++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 619fbed33..2e59beefe 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -1,35 +1,58 @@ -name: mininet tests +name: mininet-tests on: [push, pull_request] jobs: test: - name: Mininet-tests + name: Mininet Tests runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-18.04, ubuntu-16.04] + python-version: [3.x, 2.x] steps: - - name: Checking out Mininet source + - name: Check out Mininet source uses: actions/checkout@v2 - - name: Installing dependencies + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install Mininet and base dependencies run: | sudo apt-get update -qq - sudo apt-get install -qq vlan - PYTHON=`which python` util/install.sh -n - pip install pexpect || pip3 install pexpect - - name: Code Check + # This seems too slow unfortunately: + # sudo apt-get upgrade -y -qq + PYTHON=`which python` util/install.sh -nv + - name: Run code check (skipping for now) run: | bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi" - - name: Install + - name: Sanity test + run: | + export sudo="sudo env PATH=$PATH" + # Verify major python-version number matches python and mininet + export PYVER=`echo ${{ matrix.python-version }} | cut -d . -f 1` + export CHKVER='px import platform; print(platform.python_version())' + python --version |& grep " $PYVER\." + echo $CHKVER | $sudo mn -v output | grep " $PYVER\." + # Newer OvS tries OpenFlow15 which crashes ovsc on ubuntu-20.04 + $sudo mn --switch ovs,protocols=OpenFlow13 --test pingall + - name: Install test dependencies run: | - util/install.sh -fvw - - name: Building and running tests + sudo apt-get install -qq vlan + pip install pexpect + util/install.sh -fw + - name: Run tests (quick) + run: | + export sudo="sudo env PATH=$PATH" + export PYTHON=`which python` + rm -f pexpect.out + $sudo $PYTHON mininet/test/runner.py -v -quick || \ + (cat pexpect.out && exit 1) + - name: Run examples tests (quick) run: | - alias sudo="sudo env PATH=$PATH" + export sudo="sudo env PATH=$PATH" export PYTHON=`which python` - echo 'px import sys; print(sys.version_info)' | sudo $PYTHON bin/mn -v output - sudo $PYTHON bin/mn --test pingall - sudo $PYTHON mininet/test/runner.py -v -quick - sudo $PYTHON examples/test/runner.py -v -quick + rm -f pexpect.out + $sudo $PYTHON examples/test/runner.py -v -quick || \ + (cat pexpect.out && exit 1) From b7c412073a5941b7474b4b20a9af39a414b17d3a Mon Sep 17 00:00:00 2001 From: lantz Date: Sun, 3 Jan 2021 20:00:33 -0800 Subject: [PATCH 07/51] CI matrix build + 20.04 fixes (#990) Ubuntu 20.04 fixes: - fixes sshd test - speeds up examples/{treeping64,tree1024}.py - debugging hacks/output for testLinkChange - removes cfs from examples/popen.py - improves nat in nodelib (netplan fixes?) - makes some tests executable - waits for switches to connect in tests to avoid race conditions -- adds mn -w option and wait CLI command Changes: - REMOVES default "-v" argument for Controller() and adds verbose(=False) option; avoiding logging makes it faster - CHANGES waitConnected to wait for 5 seconds as documented; we may wish to implement an argument to -w to set this timeout Issues? - There may still be an issue with the ovs-netplan-clean service causing the boot to hang ;-( --- .github/workflows/run-tests.yaml | 8 +++--- README.md | 2 +- bin/mn | 3 +++ examples/bind.py | 2 +- examples/cluster.py | 5 ++-- examples/clusterperf.py | 2 +- examples/controllers.py | 2 +- examples/controllers2.py | 3 ++- examples/controlnet.py | 6 +++-- examples/cpu.py | 2 +- examples/emptynet.py | 2 +- examples/hwintf.py | 2 +- examples/intfoptions.py | 2 +- examples/limit.py | 4 +-- examples/linearbandwidth.py | 10 ++++---- examples/linuxrouter.py | 3 ++- examples/mobility.py | 3 ++- examples/multilink.py | 2 +- examples/multipoll.py | 2 +- examples/multitest.py | 3 ++- examples/nat.py | 2 +- examples/natnet.py | 2 +- examples/numberedports.py | 2 +- examples/popen.py | 10 +++----- examples/popenpoll.py | 2 +- examples/sshd.py | 2 +- examples/test/test_clusterSanity.py | 2 ++ examples/test/test_linuxrouter.py | 0 examples/test/test_natnet.py | 0 examples/test/test_sshd.py | 4 +-- examples/test/test_vlanhost.py | 0 examples/tree1024.py | 7 ++++-- examples/treeping64.py | 23 +++++++++++++---- examples/vlanhost.py | 4 +-- mininet/cli.py | 4 +++ mininet/net.py | 2 +- mininet/node.py | 6 +++-- mininet/nodelib.py | 38 ++++++++++++++++++----------- mininet/test/test_walkthrough.py | 19 +++++++++------ 39 files changed, 119 insertions(+), 78 deletions(-) mode change 100644 => 100755 examples/test/test_linuxrouter.py mode change 100644 => 100755 examples/test/test_natnet.py mode change 100644 => 100755 examples/test/test_vlanhost.py diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 2e59beefe..5ada3229f 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-18.04, ubuntu-16.04] + os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04] python-version: [3.x, 2.x] steps: - name: Check out Mininet source @@ -47,12 +47,10 @@ jobs: export sudo="sudo env PATH=$PATH" export PYTHON=`which python` rm -f pexpect.out - $sudo $PYTHON mininet/test/runner.py -v -quick || \ - (cat pexpect.out && exit 1) + $sudo $PYTHON mininet/test/runner.py -v -quick - name: Run examples tests (quick) run: | export sudo="sudo env PATH=$PATH" export PYTHON=`which python` rm -f pexpect.out - $sudo $PYTHON examples/test/runner.py -v -quick || \ - (cat pexpect.out && exit 1) + $sudo $PYTHON examples/test/runner.py -v -quick diff --git a/README.md b/README.md index 2b399b611..28b16527b 100644 --- a/README.md +++ b/README.md @@ -132,4 +132,4 @@ Bob Lantz Mininet Core Team [1]: https://travis-ci.org/mininet/mininet.svg?branch=master -[2]: https://github.com/mininet/mininet/workflows/mininet%20tests/badge.svg +[2]: https://github.com/mininet/mininet/workflows/mininet-tests/badge.svg diff --git a/bin/mn b/bin/mn index ae55e4f3f..d7f1b2bcc 100755 --- a/bin/mn +++ b/bin/mn @@ -284,6 +284,8 @@ class MininetRunner( object ): " Mininet's IP subnet, see the --ipbase option." ) opts.add_option( '--version', action='callback', callback=version, help='prints the version and exits' ) + opts.add_option( '--wait', '-w', action='store_true', + default=False, help='wait for switches to connect' ) opts.add_option( '--cluster', type='string', default=None, metavar='server1,server2...', help=( 'run on multiple servers (experimental!)' ) ) @@ -385,6 +387,7 @@ class MininetRunner( object ): ipBase=opts.ipbase, inNamespace=opts.innamespace, xterms=opts.xterms, autoSetMacs=opts.mac, autoStaticArp=opts.arp, autoPinCpus=opts.pin, + waitConnected=opts.wait, listenPort=opts.listenport ) if opts.ensure_value( 'nat', False ): diff --git a/examples/bind.py b/examples/bind.py index 6a60e6350..e2a74d7eb 100755 --- a/examples/bind.py +++ b/examples/bind.py @@ -53,7 +53,7 @@ def testHostWithPrivateDirs(): '/var/mn' ] host = partial( Host, privateDirs=privateDirs ) - net = Mininet( topo=topo, host=host ) + net = Mininet( topo=topo, host=host, waitConnected=True ) net.start() directories = [ directory[ 0 ] if isinstance( directory, tuple ) else directory for directory in privateDirs ] diff --git a/examples/cluster.py b/examples/cluster.py index aa718da68..276b71af2 100755 --- a/examples/cluster.py +++ b/examples/cluster.py @@ -875,7 +875,7 @@ def buildFromTopo( self, *args, **kwargs ): def testNsTunnels( remote='ubuntu2', link=RemoteGRELink ): "Test tunnels between nodes in namespaces" - net = Mininet( host=RemoteHost, link=link ) + net = Mininet( host=RemoteHost, link=link, waitConnected=True ) h1 = net.addHost( 'h1') h2 = net.addHost( 'h2', server=remote ) net.addLink( h1, h2 ) @@ -891,7 +891,8 @@ def testNsTunnels( remote='ubuntu2', link=RemoteGRELink ): def testRemoteNet( remote='ubuntu2', link=RemoteGRELink ): "Test remote Node classes" info( '*** Remote Node Test\n' ) - net = Mininet( host=RemoteHost, switch=RemoteOVSSwitch, link=link ) + net = Mininet( host=RemoteHost, switch=RemoteOVSSwitch, link=link, + waitConnected=True ) c0 = net.addController( 'c0' ) # Make sure controller knows its non-loopback address Intf( 'eth0', node=c0 ).updateIP() diff --git a/examples/clusterperf.py b/examples/clusterperf.py index 46e483efe..2c9486ff1 100755 --- a/examples/clusterperf.py +++ b/examples/clusterperf.py @@ -8,7 +8,7 @@ def perf(Link): "Test connectivity nand performance over Link" - net = Mininet( host=RemoteHost, link=Link ) + net = Mininet( host=RemoteHost, link=Link, waitConnected=True ) h1 = net.addHost( 'h1') h2 = net.addHost( 'h2', server='ubuntu2' ) net.addLink( h1, h2 ) diff --git a/examples/controllers.py b/examples/controllers.py index 7ed52424e..952ced483 100755 --- a/examples/controllers.py +++ b/examples/controllers.py @@ -27,7 +27,7 @@ def start( self, controllers ): return OVSSwitch.start( self, [ cmap[ self.name ] ] ) topo = TreeTopo( depth=2, fanout=2 ) -net = Mininet( topo=topo, switch=MultiSwitch, build=False ) +net = Mininet( topo=topo, switch=MultiSwitch, build=False, waitConnected=True ) for c in [ c0, c1 ]: net.addController(c) net.build() diff --git a/examples/controllers2.py b/examples/controllers2.py index fc0626917..316979025 100755 --- a/examples/controllers2.py +++ b/examples/controllers2.py @@ -20,7 +20,8 @@ def multiControllerNet(): "Create a network from semi-scratch with multiple controllers." - net = Mininet( controller=Controller, switch=OVSSwitch ) + net = Mininet( controller=Controller, switch=OVSSwitch, + waitConnected=True ) info( "*** Creating (reference) controllers\n" ) c1 = net.addController( 'c1', port=6633 ) diff --git a/examples/controlnet.py b/examples/controlnet.py index 53fce35eb..257199b03 100755 --- a/examples/controlnet.py +++ b/examples/controlnet.py @@ -123,7 +123,8 @@ def run(): info( '* Creating Control Network\n' ) ctopo = ControlNetwork( n=4, dataController=DataController ) - cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', controller=None ) + cnet = Mininet( topo=ctopo, ipBase='192.168.123.0/24', + controller=None, waitConnected=True ) info( '* Adding Control Network Controller\n') cnet.addController( 'cc0', controller=Controller ) info( '* Starting Control Network\n') @@ -133,7 +134,8 @@ def run(): topo = TreeTopo( depth=2, fanout=2 ) # UserSwitch so we can easily test failover sw = partial( UserSwitch, opts='--inactivity-probe=1 --max-backoff=1' ) - net = Mininet( topo=topo, switch=sw, controller=None ) + net = Mininet( topo=topo, switch=sw, controller=None, + waitConnected=True ) info( '* Adding Controllers to Data Network\n' ) for host in cnet.hosts: if isinstance(host, Controller): diff --git a/examples/cpu.py b/examples/cpu.py index accb0ea74..3878cb9c1 100755 --- a/examples/cpu.py +++ b/examples/cpu.py @@ -52,7 +52,7 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ): period_us=period_us, cpu=.5*cpu ) try: - net = Mininet( topo=topo, host=host ) + net = Mininet( topo=topo, host=host, waitConnected=True ) # pylint: disable=bare-except except: info( '*** Skipping scheduler %s and cleaning up\n' % sched ) diff --git a/examples/emptynet.py b/examples/emptynet.py index afcf6a8ba..fa7da67e0 100755 --- a/examples/emptynet.py +++ b/examples/emptynet.py @@ -14,7 +14,7 @@ def emptyNet(): "Create an empty network and add nodes to it." - net = Mininet( controller=Controller ) + net = Mininet( controller=Controller, waitConnected=True ) info( '*** Adding controller\n' ) net.addController( 'c0' ) diff --git a/examples/hwintf.py b/examples/hwintf.py index bbcff3464..af90c9bf1 100755 --- a/examples/hwintf.py +++ b/examples/hwintf.py @@ -38,7 +38,7 @@ def checkIntf( intf ): checkIntf( intfName ) info( '*** Creating network\n' ) - net = Mininet( topo=TreeTopo( depth=1, fanout=2 ) ) + net = Mininet( topo=TreeTopo( depth=1, fanout=2 ), waitConnected=True ) switch = net.switches[ 0 ] info( '*** Adding hardware interface', intfName, 'to switch', diff --git a/examples/intfoptions.py b/examples/intfoptions.py index 41bd84cb8..183e73b71 100755 --- a/examples/intfoptions.py +++ b/examples/intfoptions.py @@ -13,7 +13,7 @@ def intfOptions(): "run various traffic control commands on a single interface" - net = Mininet( autoStaticArp=True ) + net = Mininet( autoStaticArp=True, waitConnected=True ) net.addController( 'c0' ) h1 = net.addHost( 'h1' ) h2 = net.addHost( 'h2' ) diff --git a/examples/limit.py b/examples/limit.py index 4db88acd8..903fd7363 100755 --- a/examples/limit.py +++ b/examples/limit.py @@ -34,7 +34,7 @@ def limit( bw=10, cpu=.1 ): 'Skipping this test\n' ) continue host = custom( CPULimitedHost, sched=sched, cpu=cpu ) - net = Mininet( topo=myTopo, intf=intf, host=host ) + net = Mininet( topo=myTopo, intf=intf, host=host, waitConnected=True ) net.start() testLinkLimit( net, bw=bw ) net.runCpuLimitTest( cpu=cpu ) @@ -43,7 +43,7 @@ def limit( bw=10, cpu=.1 ): def verySimpleLimit( bw=150 ): "Absurdly simple limiting test" intf = custom( TCIntf, bw=bw ) - net = Mininet( intf=intf ) + net = Mininet( intf=intf, waitConnected=True ) h1, h2 = net.addHost( 'h1' ), net.addHost( 'h2' ) net.addLink( h1, h2 ) net.start() diff --git a/examples/linearbandwidth.py b/examples/linearbandwidth.py index 3bb608cb5..1c06ecea4 100755 --- a/examples/linearbandwidth.py +++ b/examples/linearbandwidth.py @@ -83,10 +83,10 @@ def linearBandwidthTest( lengths ): info( "*** testing", datapath, "datapath\n" ) Switch = switches[ datapath ] results[ datapath ] = [] - link = partial( TCLink, delay='2ms', bw=10 ) + link = partial( TCLink, delay='30ms', bw=100 ) net = Mininet( topo=topo, switch=Switch, - controller=Controller, waitConnected=True, - link=link ) + controller=Controller, link=link, + waitConnected=True ) net.start() info( "*** testing basic connectivity\n" ) for n in lengths: @@ -99,7 +99,7 @@ def linearBandwidthTest( lengths ): src.cmd( 'telnet', dst.IP(), '5001' ) info( "testing", src.name, "<->", dst.name, '\n' ) # serverbw = received; _clientbw = buffered - serverbw, _clientbw = net.iperf( [ src, dst ], seconds=10 ) + serverbw, _clientbw = net.iperf( [ src, dst ], seconds=5 ) info( serverbw, '\n' ) flush() results[ datapath ] += [ ( n, serverbw ) ] @@ -117,6 +117,6 @@ def linearBandwidthTest( lengths ): if __name__ == '__main__': lg.setLogLevel( 'info' ) - sizes = [ 1, 10, 20, 40, 60, 80 ] + sizes = [ 1, 2, 3, 4 ] info( "*** Running linearBandwidthTest", sizes, '\n' ) linearBandwidthTest( sizes ) diff --git a/examples/linuxrouter.py b/examples/linuxrouter.py index a7e312b9f..37699f354 100755 --- a/examples/linuxrouter.py +++ b/examples/linuxrouter.py @@ -79,7 +79,8 @@ def build( self, **_opts ): def run(): "Test linux router" topo = NetworkTopo() - net = Mininet( topo=topo ) # controller is used by s1-s3 + net = Mininet( topo=topo, + waitConnected=True ) # controller is used by s1-s3 net.start() info( '*** Routing Table on Router:\n' ) info( net[ 'r0' ].cmd( 'route' ) ) diff --git a/examples/mobility.py b/examples/mobility.py index ba09089a7..d7347dae5 100755 --- a/examples/mobility.py +++ b/examples/mobility.py @@ -107,7 +107,8 @@ def moveHost( host, oldSwitch, newSwitch, newPort=None ): def mobilityTest(): "A simple test of mobility" info( '* Simple mobility test\n' ) - net = Mininet( topo=LinearTopo( 3 ), switch=MobilitySwitch ) + net = Mininet( topo=LinearTopo( 3 ), switch=MobilitySwitch, + waitConnected=True ) info( '* Starting network:\n' ) net.start() printConnections( net.switches ) diff --git a/examples/multilink.py b/examples/multilink.py index 6cde4dc23..b6b405146 100755 --- a/examples/multilink.py +++ b/examples/multilink.py @@ -13,7 +13,7 @@ def runMultiLink(): "Create and run multiple link network" topo = simpleMultiLinkTopo( n=2 ) - net = Mininet( topo=topo ) + net = Mininet( topo=topo, waitConnected=True ) net.start() CLI( net ) net.stop() diff --git a/examples/multipoll.py b/examples/multipoll.py index bb1c9d33f..e9998df36 100755 --- a/examples/multipoll.py +++ b/examples/multipoll.py @@ -53,7 +53,7 @@ def monitorFiles( outfiles, seconds, timeoutms ): def monitorTest( N=3, seconds=3 ): "Run pings and monitor multiple hosts" topo = SingleSwitchTopo( N ) - net = Mininet( topo ) + net = Mininet( topo, waitConnected=True ) net.start() hosts = net.hosts info( "Starting test...\n" ) diff --git a/examples/multitest.py b/examples/multitest.py index b50acb212..2d68cd4d9 100755 --- a/examples/multitest.py +++ b/examples/multitest.py @@ -22,7 +22,8 @@ def ifconfigTest( net ): info( "*** Initializing Mininet and kernel modules\n" ) OVSKernelSwitch.setup() info( "*** Creating network\n" ) - network = Mininet( TreeTopo( depth=2, fanout=2 ), switch=OVSKernelSwitch ) + network = Mininet( TreeTopo( depth=2, fanout=2), switch=OVSKernelSwitch, + waitConnected=True ) info( "*** Starting network\n" ) network.start() info( "*** Running ping test\n" ) diff --git a/examples/nat.py b/examples/nat.py index e6d55f77c..bb7e8c495 100755 --- a/examples/nat.py +++ b/examples/nat.py @@ -12,7 +12,7 @@ if __name__ == '__main__': lg.setLogLevel( 'info') - net = TreeNet( depth=1, fanout=4 ) + net = TreeNet( depth=1, fanout=4, waitConnected=True ) # Add NAT connectivity net.addNAT().configDefault() net.start() diff --git a/examples/natnet.py b/examples/natnet.py index 59ba6c7c8..bfbc6dfdf 100755 --- a/examples/natnet.py +++ b/examples/natnet.py @@ -57,7 +57,7 @@ def build(self, n=2, **_kwargs ): def run(): "Create network and run the CLI" topo = InternetTopo() - net = Mininet(topo=topo) + net = Mininet(topo=topo, waitConnected=True ) net.start() CLI(net) net.stop() diff --git a/examples/numberedports.py b/examples/numberedports.py index 3bd18d634..1fed0da4f 100755 --- a/examples/numberedports.py +++ b/examples/numberedports.py @@ -28,7 +28,7 @@ def testPortNumbering(): mid-level API) and check that implicit and explicit port numbering works as expected.""" - net = Mininet( controller=Controller ) + net = Mininet( controller=Controller, waitConnected=True ) info( '*** Adding controller\n' ) net.addController( 'c0' ) diff --git a/examples/popen.py b/examples/popen.py index b43fb1c4c..4de4d6179 100755 --- a/examples/popen.py +++ b/examples/popen.py @@ -5,19 +5,15 @@ pmonitor() """ - from mininet.net import Mininet -from mininet.node import CPULimitedHost from mininet.topo import SingleSwitchTopo from mininet.log import setLogLevel, info -from mininet.util import custom, pmonitor +from mininet.util import pmonitor -def monitorhosts( hosts=5, sched='cfs' ): +def monitorhosts( hosts=5 ): "Start a bunch of pings and monitor them using popen" mytopo = SingleSwitchTopo( hosts ) - cpu = .5 / hosts - myhost = custom( CPULimitedHost, cpu=cpu, sched=sched ) - net = Mininet( topo=mytopo, host=myhost ) + net = Mininet( topo=mytopo, waitConnected=True ) net.start() # Start a bunch of pings popens = {} diff --git a/examples/popenpoll.py b/examples/popenpoll.py index c153dcb52..75534c9a3 100755 --- a/examples/popenpoll.py +++ b/examples/popenpoll.py @@ -13,7 +13,7 @@ def pmonitorTest( N=3, seconds=10 ): "Run pings and monitor multiple hosts using pmonitor" topo = SingleSwitchTopo( N ) - net = Mininet( topo ) + net = Mininet( topo, waitConnected=True ) net.start() hosts = net.hosts info( "Starting test...\n" ) diff --git a/examples/sshd.py b/examples/sshd.py index 7e0f5172c..a5641ac77 100755 --- a/examples/sshd.py +++ b/examples/sshd.py @@ -29,7 +29,7 @@ def TreeNet( depth=1, fanout=2, **kwargs ): "Convenience function for creating tree networks." topo = TreeTopo( depth, fanout ) - return Mininet( topo, **kwargs ) + return Mininet( topo, waitConnected=True, **kwargs ) def connectToRootNS( network, switch, ip, routes ): """Connect hosts to root namespace via switch. Starts network. diff --git a/examples/test/test_clusterSanity.py b/examples/test/test_clusterSanity.py index 13e51e26b..e91c8851f 100755 --- a/examples/test/test_clusterSanity.py +++ b/examples/test/test_clusterSanity.py @@ -14,6 +14,8 @@ class clusterSanityCheck( unittest.TestCase ): def testClusterPingAll( self ): p = pexpect.spawn( 'python -m mininet.examples.clusterSanity' ) p.expect( self.prompt ) + p.sendline( 'py net.waitConnected()' ) + p.expect( self.prompt ) p.sendline( 'pingall' ) p.expect ( '(\d+)% dropped' ) percent = int( p.match.group( 1 ) ) if p.match else -1 diff --git a/examples/test/test_linuxrouter.py b/examples/test/test_linuxrouter.py old mode 100644 new mode 100755 diff --git a/examples/test/test_natnet.py b/examples/test/test_natnet.py old mode 100644 new mode 100755 diff --git a/examples/test/test_sshd.py b/examples/test/test_sshd.py index 193b1eaf1..e012a291e 100755 --- a/examples/test/test_sshd.py +++ b/examples/test/test_sshd.py @@ -16,7 +16,8 @@ def connected( self, ip ): "Log into ssh server, check banner, then exit" # Note: this test will fail if "Welcome" is not in the sshd banner # and '#'' or '$'' are not in the prompt - p = pexpect.spawn( 'ssh -i /tmp/ssh/test_rsa %s' % ip, timeout=10 ) + ssh = 'ssh -o StrictHostKeyChecking=no -i /tmp/ssh/test_rsa ' + ip + p = pexpect.spawn( ssh, timeout=5 ) while True: index = p.expect( self.opts ) if index == 0: @@ -57,4 +58,3 @@ def tearDown( self ): if __name__ == '__main__': unittest.main() - diff --git a/examples/test/test_vlanhost.py b/examples/test/test_vlanhost.py old mode 100644 new mode 100755 diff --git a/examples/tree1024.py b/examples/tree1024.py index d5c25c288..cfb23cff3 100755 --- a/examples/tree1024.py +++ b/examples/tree1024.py @@ -9,10 +9,13 @@ from mininet.cli import CLI from mininet.log import setLogLevel -from mininet.node import OVSSwitch +from mininet.node import OVSSwitch, Host from mininet.topolib import TreeNet +from mininet.examples.treeping64 import HostV4, QuietController if __name__ == '__main__': setLogLevel( 'info' ) - network = TreeNet( depth=2, fanout=32, switch=OVSSwitch ) + network = TreeNet( depth=2, fanout=32, host=HostV4, + switch=OVSSwitch, controller=QuietController, + waitConnected=True) network.run( CLI, network ) diff --git a/examples/treeping64.py b/examples/treeping64.py index bd54650a1..35beec88c 100755 --- a/examples/treeping64.py +++ b/examples/treeping64.py @@ -4,21 +4,34 @@ from mininet.log import setLogLevel, info -from mininet.node import UserSwitch, OVSKernelSwitch # , KernelSwitch +from mininet.node import UserSwitch, OVSKernelSwitch, Host, Controller from mininet.topolib import TreeNet + +class HostV4( Host ): + "Try to IPv6 and its awful neighbor discovery" + def __init__( self, *args, **kwargs ): + super( HostV4, self ).__init__( *args, **kwargs ) + cfgs = [ 'all.disable_ipv6=1', 'default.disable_ipv6=1', + 'default.autoconf=0', 'lo.autoconf=0' ] + for cfg in cfgs: + self.cmd( 'sysctl -w net.ipv6.conf.' + cfg ) + + + + def treePing64(): "Run ping test on 64-node tree networks." results = {} - switches = { # 'reference kernel': KernelSwitch, - 'reference user': UserSwitch, - 'Open vSwitch kernel': OVSKernelSwitch } + switches = { 'reference user': UserSwitch, + 'Open vSwitch kernel': OVSKernelSwitch } for name in switches: info( "*** Testing", name, "datapath\n" ) switch = switches[ name ] - network = TreeNet( depth=2, fanout=8, switch=switch ) + network = TreeNet( depth=2, fanout=8, switch=switch, + waitConnected=True ) result = network.run( network.pingAll ) results[ name ] = result diff --git a/examples/vlanhost.py b/examples/vlanhost.py index 3e4dd515a..ec68b9332 100755 --- a/examples/vlanhost.py +++ b/examples/vlanhost.py @@ -65,7 +65,7 @@ def exampleAllHosts( vlan ): # Start a basic network using our VLANHost topo = SingleSwitchTopo( k=2 ) - net = Mininet( host=host, topo=topo ) + net = Mininet( host=host, topo=topo, waitConnected=True ) net.start() CLI( net ) net.stop() @@ -96,7 +96,7 @@ def build( self, k=2, n=2, vlanBase=100 ): def exampleCustomTags(): """Simple example that exercises VLANStarTopo""" - net = Mininet( topo=VLANStarTopo() ) + net = Mininet( topo=VLANStarTopo(), waitConnected=True ) net.start() CLI( net ) net.stop() diff --git a/mininet/cli.py b/mininet/cli.py index 0802a95aa..be20ca8cd 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -399,6 +399,10 @@ def do_switch( self, line ): error( 'invalid command: ' 'switch {start, stop}\n' ) + def do_wait( self, line ): + "Wait until all switches have connected to a controller" + self.mn.waitConnected() + def default( self, line ): """Called on an input line when the command prefix is not recognized. Overridden to run shell commands when a node is the first diff --git a/mininet/net.py b/mininet/net.py index b23d84136..9b9437885 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -173,7 +173,7 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host, if topo and build: self.build() - def waitConnected( self, timeout=None, delay=.5 ): + def waitConnected( self, timeout=5, delay=.5 ): """wait for each switch to connect to a controller, up to 5 seconds timeout: time to wait, or None to wait indefinitely diff --git a/mininet/node.py b/mininet/node.py index 8617dee45..c3e12a7e5 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1382,10 +1382,12 @@ class Controller( Node ): OpenFlow controller.""" def __init__( self, name, inNamespace=False, command='controller', - cargs='-v ptcp:%d', cdir=None, ip="127.0.0.1", - port=6653, protocol='tcp', **params ): + cargs='ptcp:%d', cdir=None, ip="127.0.0.1", + port=6653, protocol='tcp', verbose=False, **params ): self.command = command self.cargs = cargs + if verbose: + cargs = '-v ' + cargs self.cdir = cdir # Accept 'ip:port' syntax as shorthand if ':' in ip: diff --git a/mininet/nodelib.py b/mininet/nodelib.py index 7d87dbd40..02fbf0048 100644 --- a/mininet/nodelib.py +++ b/mininet/nodelib.py @@ -84,13 +84,35 @@ def __init__( self, name, subnet='10.0/8', self.flush = flush self.forwardState = self.cmd( 'sysctl -n net.ipv4.ip_forward' ).strip() + def setManualConfig( self, intf ): + """Prevent network-manager/networkd from messing with our interface + by specifying manual configuration in /etc/network/interfaces""" + cfile = '/etc/network/interfaces' + line = '\niface %s inet manual\n' % intf + try: + with open( cfile ) as f: + config = f.read() + except IOError: + config = '' + if ( line ) not in config: + info( '*** Adding "' + line.strip() + '" to ' + cfile + '\n' ) + with open( cfile, 'a' ) as f: + f.write( line ) + # Probably need to restart network manager to be safe - + # hopefully this won't disconnect you + self.cmd( 'service network-manager restart || netplan apply' ) + def config( self, **params ): """Configure the NAT and iptables""" - super( NAT, self).config( **params ) if not self.localIntf: self.localIntf = self.defaultIntf() + self.setManualConfig( self.localIntf ) + + # Now we can configure manually without interference + super( NAT, self).config( **params ) + if self.flush: self.cmd( 'sysctl net.ipv4.ip_forward=0' ) self.cmd( 'iptables -F' ) @@ -114,19 +136,7 @@ def config( self, **params ): # Instruct the kernel to perform forwarding self.cmd( 'sysctl net.ipv4.ip_forward=1' ) - # Prevent network-manager from messing with our interface - # by specifying manual configuration in /etc/network/interfaces - intf = self.localIntf - cfile = '/etc/network/interfaces' - line = '\niface %s inet manual\n' % intf - config = open( cfile ).read() - if ( line ) not in config: - info( '*** Adding "' + line.strip() + '" to ' + cfile + '\n' ) - with open( cfile, 'a' ) as f: - f.write( line ) - # Probably need to restart network-manager to be safe - - # hopefully this won't disconnect you - self.cmd( 'service network-manager restart' ) + def terminate( self ): "Stop NAT/forwarding between Mininet and external network" diff --git a/mininet/test/test_walkthrough.py b/mininet/test/test_walkthrough.py index c322c1397..795f9564a 100755 --- a/mininet/test/test_walkthrough.py +++ b/mininet/test/test_walkthrough.py @@ -43,17 +43,18 @@ def testWireshark( self ): tshark = pexpect.spawn( 'tshark -i lo -R of' ) else: tshark = pexpect.spawn( 'tshark -i lo -Y openflow_v1' ) - tshark.expect( [ 'Capturing on lo', "Capturing on 'Loopback'" ] ) + tshark.expect( [ 'Capturing on lo', "Capturing on 'Loopback" ] ) mn = pexpect.spawn( 'mn --test pingall' ) mn.expect( '0% dropped' ) tshark.expect( [ '74 Hello', '74 of_hello', '74 Type: OFPT_HELLO' ] ) tshark.sendintr() mn.expect( pexpect.EOF ) + tshark.expect( 'aptured' ) # 'xx packets captured' tshark.expect( pexpect.EOF ) def testBasic( self ): "Test basic CLI commands (help, nodes, net, dump)" - p = pexpect.spawn( 'mn' ) + p = pexpect.spawn( 'mn -w' ) p.expect( self.prompt ) # help command p.sendline( 'help' ) @@ -92,7 +93,7 @@ def testBasic( self ): def testHostCommands( self ): "Test ifconfig and ps on h1 and s1" - p = pexpect.spawn( 'mn' ) + p = pexpect.spawn( 'mn -w' ) p.expect( self.prompt ) # Third pattern is a local interface beginning with 'eth' or 'en' interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]', @@ -144,7 +145,7 @@ def testHostCommands( self ): def testConnectivity( self ): "Test ping and pingall" - p = pexpect.spawn( 'mn' ) + p = pexpect.spawn( 'mn -w' ) p.expect( self.prompt ) p.sendline( 'h1 ping -c 1 h2' ) p.expect( '1 packets transmitted, 1 received' ) @@ -161,7 +162,7 @@ def testSimpleHTTP( self ): httpserver = 'SimpleHTTPServer' else: httpserver = 'http.server' - p = pexpect.spawn( 'mn' ) + p = pexpect.spawn( 'mn -w' ) p.expect( self.prompt ) p.sendline( 'h1 python -m %s 80 &' % httpserver ) # The walkthrough doesn't specify a delay here, and @@ -213,7 +214,9 @@ def testTopoChange( self ): def testLinkChange( self ): "Test TCLink bw and delay" - p = pexpect.spawn( 'mn --link tc,bw=10,delay=10ms' ) + p = pexpect.spawn( 'mn -w --link tc,bw=10,delay=10ms' ) + p.expect( self.prompt ) + p.sendline( 'h1 route && ping -c1 h2' ) # test bw p.expect( self.prompt ) p.sendline( 'iperf' ) @@ -319,7 +322,7 @@ def testOwnNamespace( self ): # PART 3 def testPythonInterpreter( self ): "Test py and px by checking IP for h1 and adding h3" - p = pexpect.spawn( 'mn' ) + p = pexpect.spawn( 'mn -w' ) p.expect( self.prompt ) # test host IP p.sendline( 'py h1.IP()' ) @@ -341,7 +344,7 @@ def testPythonInterpreter( self ): def testLink( self ): "Test link CLI command using ping" - p = pexpect.spawn( 'mn' ) + p = pexpect.spawn( 'mn -w' ) p.expect( self.prompt ) p.sendline( 'link s1 h1 down' ) p.expect( self.prompt ) From e02e338e3c7eda2f36442c3f147316ce455202d1 Mon Sep 17 00:00:00 2001 From: lantz Date: Sun, 3 Jan 2021 22:24:28 -0800 Subject: [PATCH 08/51] intfoptions and test adjustments (#992) * 2.3.0a1 * intfoptions and test_intfoptions tweaks also added cleanup() to test_walkthrough fixture --- INSTALL | 2 +- LICENSE | 4 ++-- README.md | 19 +++++-------------- examples/intfoptions.py | 6 +++--- examples/test/test_intfoptions.py | 2 +- mininet/net.py | 2 +- mininet/test/test_walkthrough.py | 6 ++++++ 7 files changed, 19 insertions(+), 22 deletions(-) diff --git a/INSTALL b/INSTALL index 960a4389a..23327c371 100644 --- a/INSTALL +++ b/INSTALL @@ -2,7 +2,7 @@ Mininet Installation/Configuration Notes ---------------------------------------- -Mininet 2.3.0d6 +Mininet 2.3.0a1 --- The supported installation methods for Mininet are 1) using a diff --git a/LICENSE b/LICENSE index 846f4fe95..73a2f67cb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ -Mininet 2.3.0d6 License +Mininet 2.3.0a1 License -Copyright (c) 2013-2019 Open Networking Laboratory +Copyright (c) 2013-2020 Open Networking Foundation Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of The Leland Stanford Junior University diff --git a/README.md b/README.md index 28b16527b..6e48ad063 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Mininet: Rapid Prototyping for Software Defined Networks ======================================================== *The best way to emulate almost any network on your laptop!* -Mininet 2.3.0d6 +Mininet 2.3.0a1 [![Build Status][2]](https://github.com/mininet/mininet/actions) [![Travis Status][1]](https://travis-ci.org/mininet/mininet) @@ -73,20 +73,11 @@ Mininet includes: This is primarily a performance improvement and bug fix release. -- Batch startup has been implemented for Open vSwitch, improving - startup performance. +- Python 3 support (Python 2 is still supported as well) -- OVS patch links have been implemented via OVSLink and --link ovs +- Support for Ubuntu 20.04 - 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 ;-) +- More reliable testing and CI via github actions - Additional information for this release and previous releases may be found in the release notes on docs.mininet.org @@ -129,7 +120,7 @@ Best wishes, and we look forward to seeing what you can do with Mininet to change the networking world! Bob Lantz -Mininet Core Team +on behalf of the Mininet Contributors [1]: https://travis-ci.org/mininet/mininet.svg?branch=master [2]: https://github.com/mininet/mininet/workflows/mininet-tests/badge.svg diff --git a/examples/intfoptions.py b/examples/intfoptions.py index 183e73b71..b1b864e20 100755 --- a/examples/intfoptions.py +++ b/examples/intfoptions.py @@ -25,10 +25,10 @@ def intfOptions(): # flush out latency from reactive forwarding delay net.pingAll() - info( '\n*** Configuring one intf with bandwidth of 5 Mb\n' ) - link1.intf1.config( bw=5 ) + info( '\n*** Configuring one intf with bandwidth of 10 Mb\n' ) + link1.intf1.config( bw=10 ) info( '\n*** Running iperf to test\n' ) - net.iperf() + net.iperf( seconds=10 ) info( '\n*** Configuring one intf with loss of 50%\n' ) link1.intf1.config( loss=50 ) diff --git a/examples/test/test_intfoptions.py b/examples/test/test_intfoptions.py index 2d724711e..35b45cdd4 100755 --- a/examples/test/test_intfoptions.py +++ b/examples/test/test_intfoptions.py @@ -22,7 +22,7 @@ def testIntfOptions( self ): while True: index = p.expect( opts, timeout=600 ) if index == 0: - BW = 5 + BW = 10 bw = float( p.match.group( 1 ) ) self.assertGreaterEqual( bw, BW * ( 1 - tolerance ) ) self.assertLessEqual( bw, BW * ( 1 + tolerance ) ) diff --git a/mininet/net.py b/mininet/net.py index 9b9437885..84bb7aee3 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -108,7 +108,7 @@ from mininet.term import cleanUpScreens, makeTerms # Mininet version: should be consistent with README and LICENSE -VERSION = "2.3.0d6" +VERSION = "2.3.0a1" class Mininet( object ): "Network emulation with hosts spawned in network namespaces." diff --git a/mininet/test/test_walkthrough.py b/mininet/test/test_walkthrough.py index 795f9564a..b3b83fb51 100755 --- a/mininet/test/test_walkthrough.py +++ b/mininet/test/test_walkthrough.py @@ -10,6 +10,7 @@ import os import re from mininet.util import quietRun, pexpect +from mininet.clean import cleanup from distutils.version import StrictVersion from time import sleep @@ -28,6 +29,11 @@ class testWalkthrough( unittest.TestCase ): prompt = 'mininet>' + + def setup( self ): + "Be paranoid and run cleanup() before each test" + cleanup() + # PART 1 def testHelp( self ): "Check the usage message" From 6def30458503bfc7b3b718bf7981cfc7d9ced5a8 Mon Sep 17 00:00:00 2001 From: lantz Date: Mon, 4 Jan 2021 13:53:30 -0800 Subject: [PATCH 09/51] Remove long tests from travis (#993) --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c9b987e9..1d184ce60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,8 +25,6 @@ script: - export PYTHON=`which python` - echo 'px import sys; print(sys.version_info)' | sudo $PYTHON bin/mn -v output - sudo $PYTHON bin/mn --test pingall -- sudo $PYTHON mininet/test/runner.py -v -quick -- sudo $PYTHON examples/test/runner.py -v -quick notifications: email: From ebdb3a510718288f5db14539d7261f10abb59c96 Mon Sep 17 00:00:00 2001 From: Giuseppe Di Lena Date: Mon, 4 Jan 2021 23:14:44 +0100 Subject: [PATCH 10/51] Fix a small typo error in clusterdemo.py (#945) --- examples/clusterdemo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/clusterdemo.py b/examples/clusterdemo.py index f551b70c0..3fd21b7d6 100755 --- a/examples/clusterdemo.py +++ b/examples/clusterdemo.py @@ -13,7 +13,7 @@ def demo(): "Simple Demo of Cluster Mode" servers = [ 'localhost', 'ubuntu2', 'ubuntu3' ] topo = TreeTopo( depth=3, fanout=3 ) - net = MininetCluster( topo=topo, servers=servers, Link=RemoteLink, + net = MininetCluster( topo=topo, servers=servers, link=RemoteLink, placement=SwitchBinPlacer ) net.start() CLI( net ) From dcc39a7b25ae14ec4c7a0ecf716f1046063f0230 Mon Sep 17 00:00:00 2001 From: lantz Date: Mon, 4 Jan 2021 18:25:35 -0800 Subject: [PATCH 11/51] Loosen test_intfoptions tolerance to 25% for CI (#998) Adjusting the tolerance for this test to compensate for apparent performance variation when running as part of github actions CI builds/tests. --- examples/test/test_intfoptions.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/test/test_intfoptions.py b/examples/test/test_intfoptions.py index 35b45cdd4..531925eec 100755 --- a/examples/test/test_intfoptions.py +++ b/examples/test/test_intfoptions.py @@ -13,7 +13,7 @@ class testIntfOptions( unittest.TestCase ): def testIntfOptions( self ): "verify that intf.config is correctly limiting traffic" p = pexpect.spawn( 'python -m mininet.examples.intfoptions ' ) - tolerance = .2 # plus or minus 20% + tolerance = .25 # plus or minus 25% for cloud CI tests opts = [ "Results: \['([\d\.]+) .bits/sec", "Results: \['10M', '([\d\.]+) .bits/sec", "h(\d+)->h(\d+): (\d)/(\d)," @@ -30,8 +30,10 @@ def testIntfOptions( self ): BW = 10 measuredBw = float( p.match.group( 1 ) ) loss = ( measuredBw / BW ) * 100 - self.assertGreaterEqual( loss, 50 * ( 1 - tolerance ) ) - self.assertLessEqual( loss, 50 * ( 1 + tolerance ) ) + self.assertGreaterEqual( loss, 50 * ( 1 - tolerance ), + 'loss of %d%% << 50%%' % loss ) + self.assertLessEqual( loss, 50 * ( 1 + tolerance ), + 'loss of %d%% >> 50%%' % loss ) elif index == 2: delay = float( p.match.group( 6 ) ) self.assertGreaterEqual( delay, 15 * ( 1 - tolerance ) ) From 942745e91f9ec0ee0f774d9b5584b02458f47573 Mon Sep 17 00:00:00 2001 From: lantz Date: Mon, 4 Jan 2021 18:35:42 -0800 Subject: [PATCH 12/51] Fix tree1024.py (#995) --- examples/tree1024.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/tree1024.py b/examples/tree1024.py index cfb23cff3..e19abae74 100755 --- a/examples/tree1024.py +++ b/examples/tree1024.py @@ -9,13 +9,12 @@ from mininet.cli import CLI from mininet.log import setLogLevel -from mininet.node import OVSSwitch, Host +from mininet.node import OVSSwitch from mininet.topolib import TreeNet -from mininet.examples.treeping64 import HostV4, QuietController +from mininet.examples.treeping64 import HostV4 if __name__ == '__main__': setLogLevel( 'info' ) network = TreeNet( depth=2, fanout=32, host=HostV4, - switch=OVSSwitch, controller=QuietController, - waitConnected=True) + switch=OVSSwitch, waitConnected=True) network.run( CLI, network ) From 26c7c700245d8fdc09f6a271d69734c9f679aaea Mon Sep 17 00:00:00 2001 From: lantz Date: Mon, 4 Jan 2021 18:51:54 -0800 Subject: [PATCH 13/51] use pip for make {install,develop} (#999) --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 935652089..752f69ce3 100644 --- a/Makefile +++ b/Makefile @@ -56,13 +56,13 @@ install-manpages: $(MANPAGES) install -D -t $(MANDIR) $(MANPAGES) install: install-mnexec install-manpages - $(PYTHON) setup.py install + $(PYTHON) -m pip install . develop: $(MNEXEC) $(MANPAGES) # Perhaps we should link these as well install $(MNEXEC) $(BINDIR) install $(MANPAGES) $(MANDIR) - $(PYTHON) setup.py develop + $(PYTHON) -m pip install -e . --no-binary man: $(MANPAGES) From 462929b3af6983ffccd2a4892d7f4c96b394cb81 Mon Sep 17 00:00:00 2001 From: lantz Date: Mon, 4 Jan 2021 19:12:43 -0800 Subject: [PATCH 14/51] Run full core test suite (#1000) also remove unneeded rm -f pexpect.out since we are not generating that at the moment --- .github/workflows/run-tests.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 5ada3229f..372e7164f 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -42,15 +42,13 @@ jobs: sudo apt-get install -qq vlan pip install pexpect util/install.sh -fw - - name: Run tests (quick) + - name: Run core tests run: | export sudo="sudo env PATH=$PATH" export PYTHON=`which python` - rm -f pexpect.out - $sudo $PYTHON mininet/test/runner.py -v -quick + $sudo $PYTHON mininet/test/runner.py -v - name: Run examples tests (quick) run: | export sudo="sudo env PATH=$PATH" export PYTHON=`which python` - rm -f pexpect.out $sudo $PYTHON examples/test/runner.py -v -quick From 0847991030edd7875b1e7a7db419d6713eb1fd26 Mon Sep 17 00:00:00 2001 From: lantz Date: Mon, 4 Jan 2021 22:14:10 -0800 Subject: [PATCH 15/51] Install pip for debian/ubuntu (#1001) --- util/install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/install.sh b/util/install.sh index 7789b04b6..9438545e8 100755 --- a/util/install.sh +++ b/util/install.sh @@ -180,7 +180,8 @@ function mn_deps { $install gcc make socat psmisc xterm ssh iperf telnet \ ethtool help2man $pf pylint pep8 \ net-tools \ - ${PYPKG}-setuptools ${PYPKG}-pexpect ${PYPKG}-tk + ${PYPKG}-pexpect ${PYPKG}-tk + $install ${PYPKG}-pip || $install ${PYPKG}-pip-whl $install iproute2 || $install iproute $install cgroup-tools || $install cgroup-bin fi From 77c473687e1acff1c7a1fddf71990ef84bf65dd0 Mon Sep 17 00:00:00 2001 From: lantz Date: Tue, 5 Jan 2021 17:01:35 -0800 Subject: [PATCH 16/51] Wait for exit to avoid leftover dp0 (#1002) In certain cases, dp0 and its interfaces were not being cleaned up, probably due to scratchnet.py being killed before it terminated. This in turn caused the natnet test to fail. --- examples/test/test_scratchnet.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/test/test_scratchnet.py b/examples/test/test_scratchnet.py index 3d44955fb..7facc0fa5 100755 --- a/examples/test/test_scratchnet.py +++ b/examples/test/test_scratchnet.py @@ -16,6 +16,7 @@ def pingTest( self, name ): p = pexpect.spawn( 'python -m %s' % name ) index = p.expect( self.opts, timeout=120 ) self.assertEqual( index, 0 ) + p.wait() def testPingKernel( self ): self.pingTest( 'mininet.examples.scratchnet' ) From 53975940de00fc79275e555a67f9d1bc13e7c4a1 Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 9 Jan 2021 18:53:50 -0800 Subject: [PATCH 17/51] Test fixes and debugging (#1005) test_controlnet: log to stdout for now test_walkthrough: wait for http server connection --- examples/test/test_controlnet.py | 8 +++++--- mininet/test/test_walkthrough.py | 12 +++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/test/test_controlnet.py b/examples/test/test_controlnet.py index ba22740b5..7e7ce9a6b 100755 --- a/examples/test/test_controlnet.py +++ b/examples/test/test_controlnet.py @@ -7,13 +7,15 @@ import unittest from mininet.util import pexpect +from sys import stdout + class testControlNet( unittest.TestCase ): prompt = 'mininet>' def testPingall( self ): "Simple pingall test that verifies 0% packet drop in data network" - p = pexpect.spawn( 'python -m mininet.examples.controlnet' ) + p = pexpect.spawn( 'python -m mininet.examples.controlnet', logfile=stdout) p.expect( self.prompt ) p.sendline( 'pingall' ) p.expect ( '(\d+)% dropped' ) @@ -26,9 +28,9 @@ def testPingall( self ): def testFailover( self ): "Kill controllers and verify that switch, s1, fails over properly" count = 1 - p = pexpect.spawn( 'python -m mininet.examples.controlnet' ) + p = pexpect.spawn( 'python -m mininet.examples.controlnet', logfile=stdout ) p.expect( self.prompt ) - lp = pexpect.spawn( 'tail -f /tmp/s1-ofp.log' ) + lp = pexpect.spawn( 'tail -f /tmp/s1-ofp.log', logfile=stdout ) lp.expect( 'tcp:\d+\.\d+\.\d+\.(\d+):\d+: connected' ) ip = int( lp.match.group( 1 ) ) self.assertEqual( count, ip ) diff --git a/mininet/test/test_walkthrough.py b/mininet/test/test_walkthrough.py index b3b83fb51..f418d2d3f 100755 --- a/mininet/test/test_walkthrough.py +++ b/mininet/test/test_walkthrough.py @@ -12,7 +12,7 @@ from mininet.util import quietRun, pexpect from mininet.clean import cleanup from distutils.version import StrictVersion -from time import sleep +from sys import stdout def tsharkVersion(): @@ -168,14 +168,16 @@ def testSimpleHTTP( self ): httpserver = 'SimpleHTTPServer' else: httpserver = 'http.server' - p = pexpect.spawn( 'mn -w' ) + p = pexpect.spawn( 'mn -w', logfile=stdout ) + p.expect( self.prompt ) + p.sendline( 'h1 python -m %s 80 >& /dev/null &' % httpserver ) p.expect( self.prompt ) - p.sendline( 'h1 python -m %s 80 &' % httpserver ) # The walkthrough doesn't specify a delay here, and # we also don't read the output (also a possible problem), - # but for now let's wait a couple of seconds to make + # but for now let's wait a number of seconds to make # it less likely to fail due to the race condition. - sleep( 2 ) + p.sendline( 'px from mininet.util import waitListening;' + 'waitListening(h1, port=80, timeout=30)' ) p.expect( self.prompt ) p.sendline( ' h2 wget -O - h1' ) p.expect( '200 OK' ) From d8c30910cb284956229099640abd252dc5a0527d Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 9 Jan 2021 21:15:27 -0800 Subject: [PATCH 18/51] ubuntu 14 code check fixes so travis can pass (#1006) --- examples/treeping64.py | 4 +--- mininet/cli.py | 2 +- mininet/nodelib.py | 2 -- mininet/test/test_walkthrough.py | 4 ++-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/treeping64.py b/examples/treeping64.py index 35beec88c..c72943cad 100755 --- a/examples/treeping64.py +++ b/examples/treeping64.py @@ -4,7 +4,7 @@ from mininet.log import setLogLevel, info -from mininet.node import UserSwitch, OVSKernelSwitch, Host, Controller +from mininet.node import UserSwitch, OVSKernelSwitch, Host from mininet.topolib import TreeNet @@ -18,8 +18,6 @@ def __init__( self, *args, **kwargs ): self.cmd( 'sysctl -w net.ipv6.conf.' + cfg ) - - def treePing64(): "Run ping test on 64-node tree networks." diff --git a/mininet/cli.py b/mininet/cli.py index be20ca8cd..5c644cacc 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -399,7 +399,7 @@ def do_switch( self, line ): error( 'invalid command: ' 'switch {start, stop}\n' ) - def do_wait( self, line ): + def do_wait( self, _line ): "Wait until all switches have connected to a controller" self.mn.waitConnected() diff --git a/mininet/nodelib.py b/mininet/nodelib.py index 02fbf0048..1d5106ebd 100644 --- a/mininet/nodelib.py +++ b/mininet/nodelib.py @@ -136,8 +136,6 @@ def config( self, **params ): # Instruct the kernel to perform forwarding self.cmd( 'sysctl net.ipv4.ip_forward=1' ) - - def terminate( self ): "Stop NAT/forwarding between Mininet and external network" # Remote NAT rules diff --git a/mininet/test/test_walkthrough.py b/mininet/test/test_walkthrough.py index f418d2d3f..2b26e1841 100755 --- a/mininet/test/test_walkthrough.py +++ b/mininet/test/test_walkthrough.py @@ -29,8 +29,8 @@ class testWalkthrough( unittest.TestCase ): prompt = 'mininet>' - - def setup( self ): + @staticmethod + def setup(): "Be paranoid and run cleanup() before each test" cleanup() From 9517f6c197c88060e73f877639f5434b87d76a25 Mon Sep 17 00:00:00 2001 From: lantz Date: Wed, 13 Jan 2021 19:36:18 -0800 Subject: [PATCH 19/51] Build script for 20.04 (#1004) Should be able to build 16.04, 18.04 and 20.04, as well as branch builds. --- util/install.sh | 48 +++++++++---- util/vm/build.py | 127 +++++++++++++++++++++++----------- util/vm/install-mininet-vm.sh | 17 ++--- 3 files changed, 123 insertions(+), 69 deletions(-) diff --git a/util/install.sh b/util/install.sh index 9438545e8..fd7856d39 100755 --- a/util/install.sh +++ b/util/install.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # Mininet install script for Ubuntu and Debian # Original author: Brandon Heller @@ -181,7 +181,13 @@ function mn_deps { ethtool help2man $pf pylint pep8 \ net-tools \ ${PYPKG}-pexpect ${PYPKG}-tk + # Install pip $install ${PYPKG}-pip || $install ${PYPKG}-pip-whl + if ! ${PYTHON} -m pip; then + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + sudo ${PYTHON} get-pip.py + rm get-pip.py + fi $install iproute2 || $install iproute $install cgroup-tools || $install cgroup-bin fi @@ -192,9 +198,9 @@ function mn_deps { popd } -# Install Mininet developer dependencies -function mn_dev { - echo "Installing Mininet developer dependencies" +# Install Mininet documentation dependencies +function mn_doc { + echo "Installing Mininet documentation dependencies" $install doxygen doxypy texlive-fonts-recommended if ! $install doxygen-latex; then echo "doxygen-latex not needed" @@ -437,6 +443,12 @@ function ovs { sudo update-rc.d $OVSC disable fi fi + # This service seems to hang on 20.04 + if systemctl list-units | \ + grep status netplan-ovs-cleanup.service>&/dev/null; then + echo 'TimeoutSec=10' | sudo EDITOR='tee -a' \ + sudo systemctl edit --full netplan-ovs-cleanup.service + fi } function remove_ovs { @@ -602,7 +614,8 @@ function oftest { echo "Installing oftest..." # Install deps: - $install tcpdump ${PYPKG}-scapy + $install tcpdump + $install ${PYPKG}-scapy || sudo $PYTHON -m pip install scapy # Install oftest: cd $BUILD_DIR/ @@ -660,9 +673,10 @@ net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee -a /etc/sysctl.conf > /dev/null fi # Since the above doesn't disable neighbor discovery, also do this: + # disable via boot line, and also restore eth0 naming for VM use if ! grep 'ipv6.disable' /etc/default/grub; then sudo sed -i -e \ - 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 /' \ + 's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 net.ifnames=0 /' \ /etc/default/grub sudo update-grub fi @@ -740,8 +754,8 @@ function all { echo "Installing all packages except for -eix (doxypy, ivs, nox-classic)..." kernel mn_deps - # Skip mn_dev (doxypy/texlive/fonts/etc.) because it's huge - # mn_dev + # Skip mn_doc (doxypy/texlive/fonts/etc.) because it's huge + # mn_doc of install_wireshark ovs @@ -772,8 +786,12 @@ function vm_clean { # Remove SSH keys and regenerate on boot echo 'Removing SSH keys from /etc/ssh/' sudo rm -f /etc/ssh/*key* + if [ ! -e /etc/rc.local ]; then + echo '#!/usr/bin/bash' | sudo tee /etc/rc.local + sudo chmod +x /etc/rc.local + fi if ! grep mininet /etc/rc.local >& /dev/null; then - sudo sed -i -e "s/exit 0//" /etc/rc.local + sudo sed -i -e "s/exit 0//" /etc/rc.local || true echo ' # mininet: regenerate ssh keys if we deleted them if ! stat -t /etc/ssh/*key* >/dev/null 2>&1; then @@ -781,15 +799,15 @@ if ! stat -t /etc/ssh/*key* >/dev/null 2>&1; then fi exit 0 ' | sudo tee -a /etc/rc.local > /dev/null + sudo chmod +x /etc/rc.local fi - # Remove Mininet files - #sudo rm -f /lib/modules/python2.5/site-packages/mininet* - #sudo rm -f /usr/bin/mnexec - # Clear optional dev script for SSH keychain load on boot rm -f ~/.bash_profile + # Remove leftover install script if any + rm -f install-mininet-vm.sh + # Clear git changes git config --global user.name "None" git config --global user.email "None" @@ -816,7 +834,7 @@ function usage { printf -- ' -b: install controller (B)enchmark (oflops)\n' >&2 printf -- ' -c: (C)lean up after kernel install\n' >&2 printf -- ' -d: (D)elete some sensitive files from a VM image\n' >&2 - printf -- ' -e: install Mininet d(E)veloper dependencies\n' >&2 + printf -- ' -e: install Mininet documentation/LaT(e)X dependencies\n' >&2 printf -- ' -f: install Open(F)low\n' >&2 printf -- ' -h: print this (H)elp message\n' >&2 printf -- ' -i: install (I)ndigo Virtual Switch\n' >&2 @@ -850,7 +868,7 @@ else b) cbench;; c) kernel_clean;; d) vm_clean;; - e) mn_dev;; + e) mn_doc;; f) case $OF_VERSION in 1.0) of;; 1.3) of13;; diff --git a/util/vm/build.py b/util/vm/build.py index a33fdd556..b3abc22f6 100755 --- a/util/vm/build.py +++ b/util/vm/build.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python2.7 """ build.py: build a Mininet VM @@ -31,6 +31,7 @@ from stat import ST_MODE, ST_SIZE from os.path import abspath from sys import exit, stdout, argv, modules +import sys import re from glob import glob from subprocess import check_output, call, Popen @@ -39,11 +40,13 @@ import argparse from distutils.spawn import find_executable import inspect +from traceback import print_exc + pexpect = None # For code check - imported dynamically # boot can be slooooow!!!! need to debug/optimize somehow -TIMEOUT=600 +TIMEOUT = 600 # Some configuration options # Possibly change this to use the parsed arguments instead! @@ -60,10 +63,23 @@ Prompt = '\$ ' # Shell prompt that pexpect will wait for + +# URLs for Ubunto .iso images + +def serverURL( version, arch ): + "Return .iso URL for Ubuntu version and arch" + server = 'http://cdimage.ubuntu.com/ubuntu/releases/%s/release/' + iso = 'ubuntu-%s-server-%s.iso' + return (server + iso ) % ( version, version, arch ) + +def legacyURL( version, arch ): + "Return .iso URL for Ubuntu version" + server = ( 'http://cdimage.ubuntu.com/ubuntu-legacy-server/' + 'releases/%s/release/' ) + iso = 'ubuntu-%s-legacy-server-%s.iso' + return (server + iso ) % ( version, version, arch ) + isoURLs = { - 'precise32server': - 'http://mirrors.kernel.org/ubuntu-releases/12.04/' - 'ubuntu-12.04.5-server-i386.iso', 'precise64server': 'http://mirrors.kernel.org/ubuntu-releases/12.04/' 'ubuntu-12.04.5-server-amd64.iso', @@ -73,18 +89,14 @@ 'trusty64server': 'http://mirrors.kernel.org/ubuntu-releases/14.04/' 'ubuntu-14.04.4-server-amd64.iso', - 'wily32server': - 'http://mirrors.kernel.org/ubuntu-releases/15.10/' - 'ubuntu-15.10-server-i386.iso', - 'wily64server': - 'http://mirrors.kernel.org/ubuntu-releases/15.10/' - 'ubuntu-15.10-server-amd64.iso', 'xenial32server': 'http://mirrors.kernel.org/ubuntu-releases/16.04/' - 'ubuntu-16.04.1-server-i386.iso', + 'ubuntu-16.04.6-server-i386.iso', 'xenial64server': 'http://mirrors.kernel.org/ubuntu-releases/16.04/' - 'ubuntu-16.04.1-server-amd64.iso', + 'ubuntu-16.04.7-server-amd64.iso', + 'bionic64server': serverURL( '18.04.5', 'amd64' ), + 'focal64server': legacyURL( '20.04.1', 'amd64' ), } @@ -122,7 +134,7 @@ def log( *args, **kwargs ): else: print( output, ) # Optionally mirror to LogFile - if type( LogFile ) is file: + if LogFile: if cr: output += '\n' LogFile.write( output ) @@ -131,7 +143,7 @@ def log( *args, **kwargs ): def run( cmd, **kwargs ): "Convenient interface to check_output" - log( '-', cmd ) + log( '+', cmd ) cmd = cmd.split() arg0 = cmd[ 0 ] if not find_executable( arg0 ): @@ -153,7 +165,7 @@ def depend(): log( '* Installing package dependencies' ) run( 'sudo apt-get -qy update' ) run( 'sudo apt-get -qy install' - ' kvm cloud-utils genisoimage qemu-kvm qemu-utils' + ' kvmtool cloud-utils genisoimage qemu-kvm qemu-utils' ' e2fsprogs curl' ' python-setuptools mtools zip' ) run( 'sudo easy_install pexpect' ) @@ -181,7 +193,7 @@ def findiso( flavor ): iso = path.join( VMImageDir, name ) if not path.exists( iso ) or ( stat( iso )[ ST_MODE ] & 0o777 != 0o444 ): log( '* Retrieving', url ) - run( 'curl -C - -o %s %s' % ( iso, url ) ) + run( 'curl -L -C - -o %s %s' % ( iso, url ) ) # Make sure the file header/type is something reasonable like # 'ISO' or 'x86 boot sector', and not random html or text result = run( 'file ' + iso ) @@ -201,10 +213,11 @@ def attachNBD( cow, flags='' ): # qemu-nbd requires an absolute path cow = abspath( cow ) log( '* Checking for unused /dev/nbdX device ' ) - for i in range ( 0, 63 ): - nbd = '/dev/nbd%d' % i + for i in range ( 1, 63 ): + entry = 'nbd%d' % i + nbd = '/dev/' + entry # Check whether someone's already messing with that device - if call( [ 'pgrep', '-f', nbd ] ) == 0: + if call( [ 'pgrep', '-f', entry ] ) == 0: continue srun( 'modprobe nbd max-part=64' ) srun( 'qemu-nbd %s -c %s %s' % ( flags, nbd, cow ) ) @@ -222,17 +235,26 @@ def extractKernel( image, flavor, imageDir=VMImageDir ): "Extract kernel and initrd from base image" kernel = path.join( imageDir, flavor + '-vmlinuz' ) initrd = path.join( imageDir, flavor + '-initrd' ) - if path.exists( kernel ) and ( stat( image )[ ST_MODE ] & 0o777 ) == 0o444: - # If kernel is there, then initrd should also be there - return kernel, initrd log( '* Extracting kernel to', kernel ) nbd = attachNBD( image, flags='-r' ) try: print( srun( 'partx ' + nbd ) ) except: log( 'Warning - partx failed with error' ) - # Assume kernel is in partition 1/boot/vmlinuz*generic for now + # Guess that kernel is in partition 1/boot/vmlinuz*generic + # ...but look for other Linux partitions just in case part = nbd + 'p1' + partitions = srun( 'fdisk -l ' + nbd ) + for line in partitions.split( '\n' ): + line = line.strip() + if line.endswith( 'Linux' ): + part = line.split()[ 0 ] + break + partnum = int( part.split( 'p' )[ -1 ] ) + if path.exists( kernel ) and ( stat( image )[ ST_MODE ] & 0o777 ) == 0o444: + # If kernel is there, then initrd should also be there + detachNBD( nbd ) + return kernel, initrd, partnum mnt = mkdtemp() srun( 'mount -o ro,noload %s %s' % ( part, mnt ) ) kernsrc = glob( '%s/boot/vmlinuz*generic' % mnt )[ 0 ] @@ -244,7 +266,7 @@ def extractKernel( image, flavor, imageDir=VMImageDir ): srun( 'umount ' + mnt ) run( 'rmdir ' + mnt ) detachNBD( nbd ) - return kernel, initrd + return kernel, initrd, partnum def findBaseImage( flavor, size='8G' ): @@ -267,9 +289,10 @@ def findBaseImage( flavor, size='8G' ): # Write-protect image, also signaling it is complete log( '* Write-protecting image', image) os.chmod( image, 0o444 ) - kernel, initrd = extractKernel( image, flavor ) - log( '* Using base image', image, 'and kernel', kernel ) - return image, kernel, initrd + kernel, initrd, partnum = extractKernel( image, flavor ) + log( '* Using base image', image, 'and kernel', kernel, + 'and partition #', partnum ) + return image, kernel, initrd, partnum # Kickstart and Preseed files for Ubuntu/Debian installer @@ -382,8 +405,20 @@ def installUbuntu( iso, image, logfilename='install.log', memory=1024 ): # Mount iso so we can use its kernel mnt = mkdtemp() srun( 'mount %s %s' % ( iso, mnt ) ) - kernel = path.join( mnt, 'install/vmlinuz' ) - initrd = path.join( mnt, 'install/initrd.gz' ) + for kdir in 'install', 'casper': + kernel = path.join( mnt, kdir, 'vmlinuz' ) + if not path.exists( kernel ): + kernel = '' + for initrd in 'initrd.gz', 'initrd': + initrd = path.join( mnt, kdir, initrd ) + if path.exists( initrd ): + break + else: + initrd = '' + if kernel and initrd: + break + if not kernel or not initrd: + raise Exception( 'unable to locate kernel and initrd in iso image' ) if NoKVM: accel = 'tcg' else: @@ -407,6 +442,7 @@ def installUbuntu( iso, image, logfilename='install.log', memory=1024 ): '-append', ' ks=floppy:/' + kickstart + ' preseed/file=floppy://' + preseed + + ' net.ifnames=0' + ' console=ttyS0' ] ubuntuStart = time() log( '* INSTALLING UBUNTU FROM', iso, 'ONTO', image ) @@ -423,6 +459,8 @@ def installUbuntu( iso, image, logfilename='install.log', memory=1024 ): logfile.close() elapsed = time() - ubuntuStart # Unmount iso and clean up + ### DEBUGGING + srun( 'ls -l ' + mnt ) srun( 'umount ' + mnt ) run( 'rmdir ' + mnt ) if vm.returncode != 0: @@ -432,7 +470,7 @@ def installUbuntu( iso, image, logfilename='install.log', memory=1024 ): log( '* Ubuntu installation completed in %.2f seconds' % elapsed ) -def boot( cow, kernel, initrd, logfile, memory=1024, cpuCores=1 ): +def boot( cow, kernel, initrd, logfile, memory=1024, cpuCores=1, partnum=1 ): """Boot qemu/kvm with a COW disk and local/user data store cow: COW disk path kernel: kernel path @@ -464,7 +502,9 @@ def close( self, force=False ): '-kernel', kernel, '-initrd', initrd, '-drive file=%s,if=virtio' % cow, - '-append "root=/dev/vda1 init=/sbin/init console=ttyS0" ' ] + '-append "root=/dev/vda%d init=/sbin/init' + ' net.ifnames=0 console=ttyS0" ' % partnum ] + log( cmd ) if Forward: cmd += sum( [ [ '-redir', f ] for f in Forward ], [] ) if cpuCores > 1: @@ -590,10 +630,12 @@ def checkOutBranch( vm, branch, prompt=Prompt ): # The branch will be rebased to its parent on origin. # This probably doesn't matter since we're running on a COW disk # anyway. - vm.sendline( 'cd ~/mininet; git fetch --all; git checkout ' - + branch + '; git pull --rebase origin ' + branch ) + vm.sendline( 'cd ~/mininet; git fetch origin ' + branch + + '; git checkout ' + branch + + '; git pull --rebase origin ' + branch ) vm.expect( prompt ) - vm.sendline( 'sudo -n make install' ) + # Use install.sh since we may need to identify python version? + vm.sendline( 'util/install.sh -n' ) def interact( vm, tests, pre='', post='', prompt=Prompt ): @@ -799,7 +841,7 @@ def build( flavor='raring32server', tests=None, pre='', post='', memory=1024 ): ovfdate = strftime( '%y%m%d', lstart ) dir = 'mn-%s-%s' % ( flavor, date ) if Branch: - dirname = 'mn-%s-%s-%s' % ( Branch, flavor, date ) + dir = 'mn-%s-%s-%s' % ( Branch, flavor, date ) try: os.mkdir( dir) except: @@ -810,7 +852,7 @@ def build( flavor='raring32server', tests=None, pre='', post='', memory=1024 ): LogFile = open( 'build.log', 'w' ) log( '* Logging to', abspath( LogFile.name ) ) log( '* Created working directory', dir ) - image, kernel, initrd = findBaseImage( flavor ) + image, kernel, initrd, partnum = findBaseImage( flavor ) basename = 'mininet-' + flavor volume = basename + '.qcow2' run( 'qemu-img create -f qcow2 -b %s %s' % ( image, volume ) ) @@ -820,7 +862,7 @@ def build( flavor='raring32server', tests=None, pre='', post='', memory=1024 ): else: logfile = open( flavor + '.log', 'w+' ) log( '* Logging results to', abspath( logfile.name ) ) - vm = boot( volume, kernel, initrd, logfile, memory=memory ) + vm = boot( volume, kernel, initrd, logfile, memory=memory, partnum=partnum ) version = interact( vm, tests=tests, pre=pre, post=post ) size = qcow2size( volume ) arch = archFor( flavor ) @@ -879,7 +921,7 @@ def runTests( vm, tests=None, pre='', post='', prompt=Prompt, uninstallNtpd=Fals def getMininetVersion( vm ): "Run mn to find Mininet version in VM" - vm.sendline( '~/mininet/bin/mn --version' ) + vm.sendline( '(cd ~/mininet; PYTHONPATH=. bin/mn --version)' ) # Eat command line echo, then read output line vm.readline() version = vm.readline().strip() @@ -904,7 +946,7 @@ def bootAndRun( image, prompt=Prompt, memory=1024, cpuCores=1, outputFile=None, log( '* Creating COW disk', cow ) run( 'qemu-img create -f qcow2 -b %s %s' % ( image, cow ) ) log( '* Extracting kernel and initrd' ) - kernel, initrd = extractKernel( image, flavor=basename, imageDir=tmpdir ) + kernel, initrd, part = extractKernel( image, flavor=basename, imageDir=tmpdir ) if LogToConsole: logfile = stdout else: @@ -912,7 +954,7 @@ def bootAndRun( image, prompt=Prompt, memory=1024, cpuCores=1, outputFile=None, suffix='.testlog', delete=False ) log( '* Logging VM output to', logfile.name ) vm = boot( cow=cow, kernel=kernel, initrd=initrd, logfile=logfile, - memory=memory, cpuCores=cpuCores ) + memory=memory, cpuCores=cpuCores, part=part ) login( vm ) log( '* Waiting for prompt after login' ) vm.expect( prompt ) @@ -951,7 +993,7 @@ def testDict(): def testString(): "Return string listing valid tests" tests = [ '%s <%s>' % ( name, func.__doc__ ) - for name, func in testDict().iteritems() ] + for name, func in testDict().items() ] return 'valid tests: %s' % ', '.join( tests ) @@ -1031,6 +1073,7 @@ def parseArgs(): memory=args.memory ) except Exception as e: log( '* BUILD FAILED with exception: ', e ) + print_exc( e ) exit( 1 ) for image in args.image: bootAndRun( image, runFunction=runTests, tests=args.test, pre=args.run, diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 11632ca22..38dc318a5 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -15,13 +15,7 @@ sudo sed -i -e 's/splash//' /etc/default/grub sudo sed -i -e 's/quiet/text/' /etc/default/grub sudo update-grub # Update from official archive -sudo apt-get update -# 12.10 and earlier -#sudo sed -i -e 's/us.archive.ubuntu.com/mirrors.kernel.org/' \ -# /etc/apt/sources.list -# 13.04 and later -#sudo sed -i -e 's/\/archive.ubuntu.com/\/mirrors.kernel.org/' \ -# /etc/apt/sources.list +sudo apt-get -qq update # Clean up vmware easy install junk if present if [ -e /etc/issue.backup ]; then sudo mv /etc/issue.backup /etc/issue @@ -34,11 +28,10 @@ sudo apt-get -y install git-core openssh-server git clone git://github.com/mininet/mininet # Optionally check out branch if [ "$1" != "" ]; then - pushd mininet - #git checkout -b $1 $1 - # TODO branch will in detached HEAD state if it is not master - git checkout $1 - popd + pushd mininet + git fetch origin $1 + git checkout $1 + popd fi # Install Mininet time mininet/util/install.sh From e4003290e02789ca0116c4c45a04d9f429f7ce22 Mon Sep 17 00:00:00 2001 From: lantz Date: Wed, 13 Jan 2021 23:24:06 -0800 Subject: [PATCH 20/51] Try to install python2 and python3 mininet (#1008) --- util/install.sh | 4 ++-- util/vm/build.py | 7 ++++++- util/vm/install-mininet-vm.sh | 12 +++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/util/install.sh b/util/install.sh index fd7856d39..8ea754c03 100755 --- a/util/install.sh +++ b/util/install.sh @@ -183,8 +183,8 @@ function mn_deps { ${PYPKG}-pexpect ${PYPKG}-tk # Install pip $install ${PYPKG}-pip || $install ${PYPKG}-pip-whl - if ! ${PYTHON} -m pip; then - curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + if ! ${PYTHON} -m pip -V; then + wget https://bootstrap.pypa.io/get-pip.py sudo ${PYTHON} get-pip.py rm get-pip.py fi diff --git a/util/vm/build.py b/util/vm/build.py index b3abc22f6..4fd02a7c7 100755 --- a/util/vm/build.py +++ b/util/vm/build.py @@ -638,7 +638,8 @@ def checkOutBranch( vm, branch, prompt=Prompt ): vm.sendline( 'util/install.sh -n' ) -def interact( vm, tests, pre='', post='', prompt=Prompt ): +def interact( vm, tests, pre='', post='', prompt=Prompt, + clean=True): "Interact with vm, which is a pexpect object" login( vm ) log( '* Waiting for login...' ) @@ -677,6 +678,10 @@ def interact( vm, tests, pre='', post='', prompt=Prompt ): vm.sendline( "sudo sed -i -e 's/^GRUB_TERMINAL=serial/#GRUB_TERMINAL=serial/' " "/etc/default/grub; sudo update-grub" ) vm.expect( prompt ) + if clean: + log( '* Cleaning vm' ) + vm.sendline( '~/mininet/util/install.sh -d' ) + vm.expect( prompt ) log( '* Shutting down' ) vm.sendline( 'sync; sudo shutdown -h now' ) log( '* Waiting for EOF/shutdown' ) diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 38dc318a5..2ea176e46 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -24,7 +24,7 @@ if [ -e /etc/rc.local.backup ]; then sudo mv /etc/rc.local.backup /etc/rc.local fi # Fetch Mininet -sudo apt-get -y install git-core openssh-server +sudo apt-get -y -qq install git-core openssh-server git clone git://github.com/mininet/mininet # Optionally check out branch if [ "$1" != "" ]; then @@ -33,8 +33,14 @@ if [ "$1" != "" ]; then git checkout $1 popd fi -# Install Mininet -time mininet/util/install.sh +# Install Mininet for Python2 and Python3 +APT="sudo apt-get -y -qq" +$APT install python3 +$APT install python-is-python3 || true +$APT install python2 || $APT install python +python --version +time PYTHON=python3 mininet/util/install.sh +time PYTHON=python2 mininet/util/install.sh -n # Finalize VM time mininet/util/install.sh -tcd # Ignoring this since NOX classic is deprecated From 77938e0a85ba6f6b13508fb4cda40d8ca22c0d76 Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 16 Jan 2021 19:21:00 -0800 Subject: [PATCH 21/51] Increase timeout for emulated build (#1009) --- util/vm/build.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/util/vm/build.py b/util/vm/build.py index 4fd02a7c7..de566ca9b 100755 --- a/util/vm/build.py +++ b/util/vm/build.py @@ -662,8 +662,11 @@ def interact( vm, tests, pre='', post='', prompt=Prompt, vm.expect ( 'password for mininet: ' ) vm.sendline( 'mininet' ) log( '* Waiting for script to complete... ' ) - # Gigantic timeout for now ;-( - vm.expect( 'Done preparing Mininet', timeout=3600 ) + # Long timeout since we may be on cloud CI + # 30min for kvm, 1.5hr for emulation + # TODO: detect installation errors + timeout = 5200 if NoKVM else 1800 + vm.expect( 'Done preparing Mininet', timeout=timeout ) log( '* Completed successfully' ) vm.expect( prompt ) version = getMininetVersion( vm ) From dad451bf8fc8f9d0527b4a10b875660ac30e8b8b Mon Sep 17 00:00:00 2001 From: lantz Date: Mon, 25 Jan 2021 14:00:53 -0800 Subject: [PATCH 22/51] Pass code check with pylint=2.4.4 (#1012) --- .github/workflows/code-check.yaml | 22 ++++ .github/workflows/run-tests.yaml | 3 - .pylint | 10 +- .travis.yml | 11 +- Makefile | 2 +- bin/mn | 16 ++- examples/bind.py | 5 +- examples/cluster.py | 66 ++++++----- examples/clusterSanity.py | 1 + examples/clustercli.py | 1 + examples/clusterdemo.py | 1 + examples/clusterperf.py | 1 + examples/consoles.py | 6 +- examples/controllers.py | 1 + examples/controllers2.py | 1 + examples/controlnet.py | 6 +- examples/cpu.py | 2 +- examples/emptynet.py | 1 + examples/hwintf.py | 4 + examples/intfoptions.py | 1 + examples/limit.py | 1 + examples/linearbandwidth.py | 13 ++- examples/linuxrouter.py | 3 + examples/miniedit.py | 127 +++++++++++----------- examples/mobility.py | 5 +- examples/multilink.py | 2 + examples/multiping.py | 6 +- examples/multipoll.py | 8 +- examples/multitest.py | 1 + examples/natnet.py | 2 + examples/numberedports.py | 1 + examples/popen.py | 1 + examples/popenpoll.py | 6 +- examples/scratchnet.py | 3 +- examples/scratchnetuser.py | 1 + examples/simpleperf.py | 3 +- examples/sshd.py | 2 + examples/treeping64.py | 1 + examples/vlanhost.py | 6 + mininet/cli.py | 13 ++- mininet/link.py | 19 +++- mininet/log.py | 8 +- mininet/moduledeps.py | 6 +- mininet/net.py | 2 + mininet/node.py | 48 +++++--- mininet/nodelib.py | 1 + mininet/term.py | 2 +- mininet/test/runner.py | 1 + mininet/test/test_hifi.py | 7 +- mininet/test/test_nets.py | 2 +- mininet/test/test_ptyleak.py | 1 + mininet/test/test_switchdpidassignment.py | 3 +- mininet/test/test_util.py | 1 + mininet/test/test_walkthrough.py | 16 +-- mininet/topo.py | 3 + mininet/util.py | 26 +++-- 56 files changed, 330 insertions(+), 182 deletions(-) create mode 100644 .github/workflows/code-check.yaml diff --git a/.github/workflows/code-check.yaml b/.github/workflows/code-check.yaml new file mode 100644 index 000000000..fd35ce432 --- /dev/null +++ b/.github/workflows/code-check.yaml @@ -0,0 +1,22 @@ + +name: code-check + +on: [push, pull_request] + +jobs: + code-check: + name: Mininet Code Check + runs-on: ubuntu-latest + steps: + - name: Set up Python 3.x + uses: actions/setup-python@v2 + with: + python-version: 3.x + - name: Check out Mininet source + uses: actions/checkout@v2 + - name: Install Mininet code check dependencies + run: | + PYTHON=`which python` util/install.sh -n + python -m pip install pylint==2.4.4 + - name: Run code check + run: make codecheck diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 372e7164f..bfa6b9342 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -24,9 +24,6 @@ jobs: # This seems too slow unfortunately: # sudo apt-get upgrade -y -qq PYTHON=`which python` util/install.sh -nv - - name: Run code check (skipping for now) - run: | - bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi" - name: Sanity test run: | export sudo="sudo env PATH=$PATH" diff --git a/.pylint b/.pylint index 22de3115f..a61fce162 100644 --- a/.pylint +++ b/.pylint @@ -41,10 +41,16 @@ load-plugins= # can either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). +# +# Note: we may want to re-enable some of these at some point, but many of them +# are just style issues rather than errors. +# disable=pointless-except, invalid-name, super-init-not-called, fixme, star-args, - too-many-instance-attributes, too-few-public-methods, too-many-arguments, + too-many-instance-attributes, too-few-public-methods, too-many-locals, too-many-public-methods, duplicate-code, bad-whitespace, - locally-disabled, locally-enabled + locally-disabled, locally-enabled, bad-continuation, + useless-object-inheritance, unnecessary-pass, no-else-return, + no-else-raise, no-else-continue, super-with-arguments # bad-continuation, wrong-import-order diff --git a/.travis.yml b/.travis.yml index 1d184ce60..cafb18c71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,20 +3,17 @@ sudo: required matrix: include: - - dist: trusty - python: 2.7 - env: dist="14.04 LTS trusty" - - dist: trusty + - dist: focal python: 3.6 - env: dist="14.04 LTS trusty" + env: dist="24.04 LTS focal" before_install: - sudo apt-get update -qq -- sudo apt-get install -qq vlan +- sudo apt-get install -qq vlan pyflakes - PYTHON=`which python` util/install.sh -n install: -- bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi" +- make codecheck - pip install pexpect || pip3 install pexpect - util/install.sh -nfvw diff --git a/Makefile b/Makefile index 752f69ce3..9e5901142 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ BIN = $(MN) PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN) MNEXEC = mnexec MANPAGES = mn.1 mnexec.1 -P8IGN = E251,E201,E302,E202,E126,E127,E203,E226 +P8IGN = E251,E201,E302,E202,E126,E127,E203,E226,E402,W504,W503,E731 PREFIX ?= /usr BINDIR ?= $(PREFIX)/bin MANDIR ?= $(PREFIX)/share/man/man1 diff --git a/bin/mn b/bin/mn index d7f1b2bcc..3c5a7ec40 100755 --- a/bin/mn +++ b/bin/mn @@ -11,15 +11,20 @@ Example to pull custom params (topo, switch, etc.) from a file: sudo mn --custom ~/mininet/custom/custom_example.py """ -from optparse import OptionParser import os import sys import time +from functools import partial +from optparse import OptionParser # pylint: disable=deprecated-module +from sys import exit # pylint: disable=redefined-builtin + # Fix setuptools' evil madness, and open up (more?) security holes if 'PYTHONPATH' in os.environ: sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path +# pylint: disable=wrong-import-position + from mininet.clean import cleanup import mininet.cli from mininet.log import lg, LEVELS, info, debug, warn, error, output @@ -34,10 +39,7 @@ from mininet.link import Link, TCLink, TCULink, OVSLink from mininet.topo import ( SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo, MinimalTopo ) from mininet.topolib import TreeTopo, TorusTopo -from mininet.util import customClass, specialClass, splitArgs -from mininet.util import buildTopo - -from functools import partial +from mininet.util import customClass, specialClass, splitArgs, buildTopo # Experimental! cluster edition prototype from mininet.examples.cluster import ( MininetCluster, RemoteHost, @@ -46,6 +48,7 @@ from mininet.examples.cluster import ( MininetCluster, RemoteHost, ClusterCleanup ) from mininet.examples.clustercli import ClusterCLI + PLACEMENT = { 'block': SwitchBinPlacer, 'random': RandomPlacer } # built in topologies, created only when run @@ -107,6 +110,7 @@ def nullTest( _net ): "Null 'test' (does nothing)" pass + TESTS.update( all=allTest, none=nullTest, build=nullTest ) # Map to alternate spellings of Mininet() methods @@ -425,7 +429,7 @@ if __name__ == "__main__": except KeyboardInterrupt: info( "\n\nKeyboard Interrupt. Shutting down and cleaning up...\n\n") cleanup() - except Exception: + except Exception: # pylint: disable=broad-except # Print exception type_, val_, trace_ = sys.exc_info() errorMsg = ( "-"*80 + "\n" + diff --git a/examples/bind.py b/examples/bind.py index e2a74d7eb..9a7272a31 100755 --- a/examples/bind.py +++ b/examples/bind.py @@ -34,14 +34,14 @@ on '/var/mn' """ +from functools import partial + from mininet.net import Mininet from mininet.node import Host from mininet.cli import CLI from mininet.topo import SingleSwitchTopo from mininet.log import setLogLevel, info -from functools import partial - # Sample usage @@ -61,6 +61,7 @@ def testHostWithPrivateDirs(): CLI( net ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) testHostWithPrivateDirs() diff --git a/examples/cluster.py b/examples/cluster.py index 276b71af2..78cfbc004 100755 --- a/examples/cluster.py +++ b/examples/cluster.py @@ -74,6 +74,15 @@ - hifi support (e.g. delay compensation) """ +from signal import signal, SIGINT, SIG_IGN +from subprocess import Popen, PIPE, STDOUT +import os +from random import randrange +import sys +import re +from itertools import groupby +from operator import attrgetter +from distutils.version import StrictVersion from mininet.node import Node, Host, OVSSwitch, Controller from mininet.link import Link, Intf @@ -85,15 +94,7 @@ from mininet.log import setLogLevel, debug, info, error from mininet.clean import addCleanupCallback -from signal import signal, SIGINT, SIG_IGN -from subprocess import Popen, PIPE, STDOUT -import os -from random import randrange -import sys -import re -from itertools import groupby -from operator import attrgetter -from distutils.version import StrictVersion +# pylint: disable=too-many-arguments def findUser(): @@ -261,7 +262,7 @@ def _popen( self, cmd, sudo=True, tt=True, **params): cmd: remote command to run (list) **params: parameters to Popen() returns: Popen() object""" - if type( cmd ) is str: + if isinstance( cmd, str): cmd = cmd.split() if self.isRemote: if sudo: @@ -289,6 +290,7 @@ def popen( self, *args, **kwargs ): def addIntf( self, *args, **kwargs ): "Override: use RemoteLink.moveIntf" # kwargs.update( moveIntfFn=RemoteLink.moveIntf ) + # pylint: disable=useless-super-delegation return super( RemoteMixin, self).addIntf( *args, **kwargs ) @@ -325,6 +327,7 @@ def isOldOVS( self ): StrictVersion( '1.10' ) ) @classmethod + # pylint: disable=arguments-differ def batchStartup( cls, switches, **_kwargs ): "Start up switches in per-server batches" key = attrgetter( 'server' ) @@ -336,6 +339,7 @@ def batchStartup( cls, switches, **_kwargs ): return switches @classmethod + # pylint: disable=arguments-differ def batchShutdown( cls, switches, **_kwargs ): "Stop switches in per-server batches" key = attrgetter( 'server' ) @@ -413,8 +417,9 @@ def makeTunnel( self, node1, node2, intfname1, intfname2, # And we can't ssh into this server remotely as 'localhost', # so try again swappping node1 and node2 if node2.server == 'localhost': - return self.makeTunnel( node2, node1, intfname2, intfname1, - addr2, addr1 ) + return self.makeTunnel( node1=node2, node2=node1, + intfname1=intfname2, intfname2=intfname1, + addr1=addr2, addr2=addr1 ) debug( '\n*** Make SSH tunnel ' + node1.server + ':' + intfname1 + ' == ' + node2.server + ':' + intfname2 ) # 1. Create tap interfaces @@ -526,8 +531,9 @@ def makeTunnel(self, node1, node2, intfname1, intfname2, # We should never try to create a tunnel to ourselves! assert node1.server != node2.server if node2.server == 'localhost': - return self.makeTunnel( node2, node1, intfname2, intfname1, - addr2, addr1 ) + return self.makeTunnel( node1=node2, node2=node1, + intfname1=intfname2, intfname2=intfname1, + addr1=addr2, addr2=addr1 ) IP1, IP2 = node1.serverIP, node2.serverIP # GRE tunnel needs to be set up with the IP of the local interface # that connects the remote node, NOT '127.0.0.1' of localhost @@ -555,6 +561,7 @@ def makeTunnel(self, node1, node2, intfname1, intfname2, node.rcmd('ip link set dev %s mtu 1450' % intfname) if not self.moveIntf(intfname, node): raise Exception('interface move failed on node %s' % node) + return None # May want to return something useful here # Some simple placement algorithms for MininetCluster @@ -589,10 +596,10 @@ def place( self, node ): class RandomPlacer( Placer ): "Random placement" - def place( self, nodename ): + def place( self, node ): """Random placement function - nodename: node name""" - assert nodename # please pylint + node: node""" + assert node # please pylint # This may be slow with lots of servers return self.servers[ randrange( 0, len( self.servers ) ) ] @@ -606,10 +613,10 @@ def __init__( self, *args, **kwargs ): Placer.__init__( self, *args, **kwargs ) self.next = 0 - def place( self, nodename ): + def place( self, node ): """Round-robin placement function - nodename: node name""" - assert nodename # please pylint + node: node""" + assert node # please pylint # This may be slow with lots of servers server = self.servers[ self.next ] self.next = ( self.next + 1 ) % len( self.servers ) @@ -647,7 +654,7 @@ def bin( nodes, servers ): tickets = sum( [ binsizes[ server ] * [ server ] for server in servers ], [] ) # And assign one ticket to each node - return { node: ticket for node, ticket in zip( nodes, tickets ) } + return dict( zip( nodes, tickets ) ) def calculatePlacement( self ): "Pre-calculate node placement" @@ -704,21 +711,21 @@ def __init__( self, *args, **kwargs ): self.cset = frozenset( self.controllers ) self.hind, self.sind, self.cind = 0, 0, 0 - def place( self, nodename ): + def place( self, node ): """Simple placement algorithm: place nodes into evenly sized bins""" # Place nodes into bins - if nodename in self.hset: + if node in self.hset: server = self.servdict[ self.hind / self.hbin ] self.hind += 1 - elif nodename in self.sset: + elif node in self.sset: server = self.servdict[ self.sind / self.sbin ] self.sind += 1 - elif nodename in self.cset: + elif node in self.cset: server = self.servdict[ self.cind / self.cbin ] self.cind += 1 else: - info( 'warning: unknown node', nodename ) + info( 'warning: unknown node', node ) server = self.servdict[ 0 ] return server @@ -764,6 +771,7 @@ def __init__( self, *args, **kwargs ): # Make sure control directory exists self.cdir = os.environ[ 'HOME' ] + '/.ssh/mn' errRun( [ 'mkdir', '-p', self.cdir ] ) + # pylint: disable=unexpected-keyword-arg Mininet.__init__( self, *args, **params ) def popen( self, cmd ): @@ -840,18 +848,19 @@ def placeNodes( self ): if cfile: config.setdefault( 'controlPath', cfile ) + # pylint: disable=arguments-differ,signature-differs def addController( self, *args, **kwargs ): "Patch to update IP address to global IP address" controller = Mininet.addController( self, *args, **kwargs ) loopback = '127.0.0.1' if ( not isinstance( controller, Controller ) or controller.IP() != loopback ): - return + return None # Find route to a different server IP address serverIPs = [ ip for ip in self.serverIP.values() if ip is not controller.IP() ] if not serverIPs: - return # no remote servers - loopback is fine + return None # no remote servers - loopback is fine remoteIP = serverIPs[ 0 ] # Route should contain 'dev ' route = controller.cmd( 'ip route get', remoteIP, @@ -865,6 +874,7 @@ def addController( self, *args, **kwargs ): debug( controller, 'IP address updated to', controller.IP() ) return controller + # pylint: disable=arguments-differ,signature-differs def buildFromTopo( self, *args, **kwargs ): "Start network" info( '*** Placing nodes\n' ) diff --git a/examples/clusterSanity.py b/examples/clusterSanity.py index 2e1af9161..71c2b5214 100755 --- a/examples/clusterSanity.py +++ b/examples/clusterSanity.py @@ -17,6 +17,7 @@ def clusterSanity(): CLI( net ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) clusterSanity() diff --git a/examples/clustercli.py b/examples/clustercli.py index 68dc686d7..75cd3178b 100644 --- a/examples/clustercli.py +++ b/examples/clustercli.py @@ -31,6 +31,7 @@ def do_plot( self, _line ): if not nx: try: # pylint: disable=import-error,no-member + # pylint: disable=import-outside-toplevel import networkx nx = networkx # satisfy pylint from matplotlib import pyplot diff --git a/examples/clusterdemo.py b/examples/clusterdemo.py index 3fd21b7d6..b117ba464 100755 --- a/examples/clusterdemo.py +++ b/examples/clusterdemo.py @@ -19,6 +19,7 @@ def demo(): CLI( net ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) demo() diff --git a/examples/clusterperf.py b/examples/clusterperf.py index 2c9486ff1..ffa48a80f 100755 --- a/examples/clusterperf.py +++ b/examples/clusterperf.py @@ -17,6 +17,7 @@ def perf(Link): net.iperf() net.stop() + if __name__ == '__main__': setLogLevel('info') perf( RemoteSSHLink ) diff --git a/examples/consoles.py b/examples/consoles.py index fd92378a8..6a8aca148 100755 --- a/examples/consoles.py +++ b/examples/consoles.py @@ -27,6 +27,7 @@ import re +# pylint: disable=import-error from Tkinter import Frame, Button, Label, Text, Scrollbar, Canvas, Wm, READABLE from mininet.log import setLogLevel @@ -34,6 +35,9 @@ from mininet.term import makeTerms, cleanUpScreens from mininet.util import quietRun +# pylint: disable=too-many-arguments + + class Console( Frame ): "A simple console on a host." @@ -319,7 +323,7 @@ def updateGraph( self, _console, output ): if not m: return val, units = float( m.group( 1 ) ), m.group( 2 ) - #convert to Gbps + # convert to Gbps if units[0] == 'M': val *= 10 ** -3 elif units[0] == 'K': diff --git a/examples/controllers.py b/examples/controllers.py index 952ced483..dad8e5f84 100755 --- a/examples/controllers.py +++ b/examples/controllers.py @@ -26,6 +26,7 @@ class MultiSwitch( OVSSwitch ): def start( self, controllers ): return OVSSwitch.start( self, [ cmap[ self.name ] ] ) + topo = TreeTopo( depth=2, fanout=2 ) net = Mininet( topo=topo, switch=MultiSwitch, build=False, waitConnected=True ) for c in [ c0, c1 ]: diff --git a/examples/controllers2.py b/examples/controllers2.py index 316979025..ceefc3201 100755 --- a/examples/controllers2.py +++ b/examples/controllers2.py @@ -58,6 +58,7 @@ def multiControllerNet(): info( "*** Stopping network\n" ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) # for CLI output multiControllerNet() diff --git a/examples/controlnet.py b/examples/controlnet.py index 257199b03..eb7aaa512 100755 --- a/examples/controlnet.py +++ b/examples/controlnet.py @@ -59,13 +59,14 @@ def __getattr__( self, name ): def __getitem__( self, key ): "returns primary/named networks or node from any net" - #search kwargs for net named key + # search kwargs for net named key if key in self.nameToNet: return self.nameToNet[ key ] - #search each net for node named key + # search each net for node named key for net in self.nets: if key in net: return net[ key ] + return None def __iter__( self ): "Iterate through all nodes in all Mininet objects" @@ -100,6 +101,7 @@ def items( self ): class ControlNetwork( Topo ): "Control Network Topology" + # pylint: disable=arguments-differ def build( self, n, dataController=DataController, **_kwargs ): """n: number of data network controller nodes dataController: class for data network controllers""" diff --git a/examples/cpu.py b/examples/cpu.py index 3878cb9c1..a5dddeda6 100755 --- a/examples/cpu.py +++ b/examples/cpu.py @@ -54,7 +54,7 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ): try: net = Mininet( topo=topo, host=host, waitConnected=True ) # pylint: disable=bare-except - except: + except: # noqa info( '*** Skipping scheduler %s and cleaning up\n' % sched ) cleanup() break diff --git a/examples/emptynet.py b/examples/emptynet.py index fa7da67e0..474886c50 100755 --- a/examples/emptynet.py +++ b/examples/emptynet.py @@ -39,6 +39,7 @@ def emptyNet(): info( '*** Stopping network' ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) emptyNet() diff --git a/examples/hwintf.py b/examples/hwintf.py index af90c9bf1..990beb0c0 100755 --- a/examples/hwintf.py +++ b/examples/hwintf.py @@ -8,6 +8,8 @@ import re import sys +from sys import exit # pylint: disable=redefined-builtin + from mininet.cli import CLI from mininet.log import setLogLevel, info, error from mininet.net import Mininet @@ -15,6 +17,7 @@ from mininet.topolib import TreeTopo from mininet.util import quietRun + def checkIntf( intf ): "Make sure intf exists and is not configured." config = quietRun( 'ifconfig %s 2>/dev/null' % intf, shell=True ) @@ -27,6 +30,7 @@ def checkIntf( intf ): 'and is probably in use!\n' ) exit( 1 ) + if __name__ == '__main__': setLogLevel( 'info' ) diff --git a/examples/intfoptions.py b/examples/intfoptions.py index b1b864e20..f7373ed35 100755 --- a/examples/intfoptions.py +++ b/examples/intfoptions.py @@ -43,6 +43,7 @@ def intfOptions(): info( '\n*** Done testing\n' ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) intfOptions() diff --git a/examples/limit.py b/examples/limit.py index 903fd7363..a75bb50ef 100755 --- a/examples/limit.py +++ b/examples/limit.py @@ -55,6 +55,7 @@ def verySimpleLimit( bw=150 ): h2.cmdPrint( 'tc -d class show dev', h2.defaultIntf() ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) limit() diff --git a/examples/linearbandwidth.py b/examples/linearbandwidth.py index 1c06ecea4..e66f36b31 100755 --- a/examples/linearbandwidth.py +++ b/examples/linearbandwidth.py @@ -24,20 +24,24 @@ """ +import sys + +from functools import partial + from mininet.net import Mininet from mininet.node import UserSwitch, OVSKernelSwitch, Controller from mininet.topo import Topo from mininet.log import lg, info from mininet.util import irange, quietRun from mininet.link import TCLink -from functools import partial -import sys flush = sys.stdout.flush + class LinearTestTopo( Topo ): "Topology for a string of N hosts and N-1 switches." + # pylint: disable=arguments-differ def build( self, N, **params ): # Create switches and hosts hosts = [ self.addHost( 'h%s' % h ) @@ -79,7 +83,7 @@ def linearBandwidthTest( lengths ): output = quietRun( 'sysctl -w net.ipv4.tcp_congestion_control=reno' ) assert 'reno' in output - for datapath in switches.keys(): + for datapath in switches: info( "*** testing", datapath, "datapath\n" ) Switch = switches[ datapath ] results[ datapath ] = [] @@ -105,7 +109,7 @@ def linearBandwidthTest( lengths ): results[ datapath ] += [ ( n, serverbw ) ] net.stop() - for datapath in switches.keys(): + for datapath in switches: info( "\n*** Linear network results for", datapath, "datapath:\n" ) result = results[ datapath ] info( "SwitchCount\tiperf Results\n" ) @@ -115,6 +119,7 @@ def linearBandwidthTest( lengths ): info( '\n') info( '\n' ) + if __name__ == '__main__': lg.setLogLevel( 'info' ) sizes = [ 1, 2, 3, 4 ] diff --git a/examples/linuxrouter.py b/examples/linuxrouter.py index 37699f354..861c31968 100755 --- a/examples/linuxrouter.py +++ b/examples/linuxrouter.py @@ -38,6 +38,7 @@ class LinuxRouter( Node ): "A Node with IP forwarding enabled." + # pylint: disable=arguments-differ def config( self, **params ): super( LinuxRouter, self).config( **params ) # Enable forwarding on the router @@ -51,6 +52,7 @@ def terminate( self ): class NetworkTopo( Topo ): "A LinuxRouter connecting three IP subnets" + # pylint: disable=arguments-differ def build( self, **_opts ): defaultIP = '192.168.1.1/24' # IP address for r0-eth1 @@ -87,6 +89,7 @@ def run(): CLI( net ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) run() diff --git a/examples/miniedit.py b/examples/miniedit.py index aed0f345e..a35584106 100755 --- a/examples/miniedit.py +++ b/examples/miniedit.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ MiniEdit: a simple network editor for Mininet @@ -13,16 +13,30 @@ OpenFlow icon from https://www.opennetworking.org/ """ -# Miniedit needs some work in order to pass pylint... -# pylint: disable=line-too-long,too-many-branches -# pylint: disable=too-many-statements,attribute-defined-outside-init -# pylint: disable=missing-docstring - -MINIEDIT_VERSION = '2.2.0.1' - +import json +import os +import re import sys + +from distutils.version import StrictVersion +from functools import partial from optparse import OptionParser from subprocess import call +from sys import exit # pylint: disable=redefined-builtin + +from mininet.log import info, debug, warn, setLogLevel +from mininet.net import Mininet, VERSION +from mininet.util import (netParse, ipAdd, quietRun, + buildTopo, custom, customClass ) +from mininet.term import makeTerm, cleanUpScreens +from mininet.node import (Controller, RemoteController, NOX, OVSController, + CPULimitedHost, Host, Node, + OVSSwitch, UserSwitch, IVSSwitch ) +from mininet.link import TCLink, Intf, Link +from mininet.cli import CLI +from mininet.moduledeps import moduleDeps +from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo +from mininet.topolib import TreeTopo # pylint: disable=import-error if sys.version_info[0] == 2: @@ -47,38 +61,24 @@ from tkinter import font as tkFont from tkinter import simpledialog as tkSimpleDialog from tkinter import filedialog as tkFileDialog +# someday: from ttk import * # pylint: enable=import-error -import re -import json -from distutils.version import StrictVersion -import os -from functools import partial -if 'PYTHONPATH' in os.environ: - sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path +# Miniedit still needs work in order to pass pylint... +# pylint: disable=line-too-long,too-many-branches +# pylint: disable=too-many-statements,attribute-defined-outside-init +# pylint: disable=missing-docstring,too-many-ancestors +# pylint: disable=too-many-nested-blocks,too-many-arguments -# someday: from ttk import * -from mininet.log import info, debug, warn, setLogLevel -from mininet.net import Mininet, VERSION -from mininet.util import netParse, ipAdd, quietRun -from mininet.util import buildTopo -from mininet.util import custom, customClass -from mininet.term import makeTerm, cleanUpScreens -from mininet.node import Controller, RemoteController, NOX, OVSController -from mininet.node import CPULimitedHost, Host, Node -from mininet.node import OVSSwitch, UserSwitch -from mininet.link import TCLink, Intf, Link -from mininet.cli import CLI -from mininet.moduledeps import moduleDeps -from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo -from mininet.topolib import TreeTopo +MINIEDIT_VERSION = '2.2.0.1' + +if 'PYTHONPATH' in os.environ: + sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path info( 'MiniEdit running against Mininet '+VERSION, '\n' ) MININET_VERSION = re.sub(r'[^\d\.]', '', VERSION) -if StrictVersion(MININET_VERSION) > StrictVersion('2.0'): - from mininet.node import IVSSwitch TOPODEF = 'none' TOPOS = { 'minimal': lambda: SingleSwitchTopo( k=2 ), @@ -138,6 +138,7 @@ class LegacyRouter( Node ): def __init__( self, name, inNamespace=True, **params ): Node.__init__( self, name, inNamespace, **params ) + # pylint: disable=arguments-differ def config( self, **_params ): if self.intfs: self.setParam( _params, 'setIP', ip='0.0.0.0' ) @@ -818,8 +819,8 @@ class VerticalScrolledTable(LabelFrame): * This frame only allows vertical scrolling """ - def __init__(self, parent, rows=2, columns=2, title=None, *args, **kw): - LabelFrame.__init__(self, parent, text=title, padx=5, pady=5, *args, **kw) + def __init__(self, parent, rows=2, columns=2, title=None, **kw): + LabelFrame.__init__(self, parent, text=title, padx=5, pady=5, **kw) # create a canvas object and a vertical scrollbar for scrolling it vscrollbar = Scrollbar(self, orient=VERTICAL) @@ -855,8 +856,6 @@ def _configure_canvas(_event): canvas.itemconfigure(interior_id, width=canvas.winfo_width()) canvas.bind('', _configure_canvas) - return - class TableFrame(Frame): def __init__(self, parent, rows=2, columns=2): @@ -888,7 +887,7 @@ def addRow( self, value=None, readonly=False ): label.grid(row=self.rows, column=column, sticky="wens", padx=1, pady=1) if value is not None: label.insert(0, value[column]) - if readonly == True: + if readonly: label.configure(state='readonly') current_row.append(label) self._widgets.append(current_row) @@ -1401,11 +1400,11 @@ def doStop( self ): def addNode( self, node, nodeNum, x, y, name=None): "Add a new node to our canvas." - if 'Switch' == node: + if node == 'Switch': self.switchCount += 1 - if 'Host' == node: + if node == 'Host': self.hostCount += 1 - if 'Controller' == node: + if node == 'Controller': self.controllerCount += 1 if name is None: name = self.nodePrefixes[ node ] + nodeNum @@ -1422,14 +1421,17 @@ def addNamedNode( self, node, name, x, y): def convertJsonUnicode(self, text): "Some part of Mininet don't like Unicode" + try: + unicode + except NameError: + return text if isinstance(text, dict): return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.items()} - elif isinstance(text, list): + if isinstance(text, list): return [self.convertJsonUnicode(element) for element in text] - elif isinstance(text, unicode): + if isinstance(text, unicode): # pylint: disable=undefined-variable return text.encode('utf-8') - else: - return text + return text def loadTopology( self ): "Load command." @@ -1440,7 +1442,7 @@ def loadTopology( self ): ('All Files','*'), ] f = tkFileDialog.askopenfile(filetypes=myFormats, mode='rb') - if f == None: + if f is None: return self.newTopology() loadedTopology = self.convertJsonUnicode(json.load(f)) @@ -1601,10 +1603,11 @@ def findWidgetByName( self, name ): for widget in self.widgetToItem: if name == widget[ 'text' ]: return widget + return None def newTopology( self ): "New command." - for widget in self.widgetToItem.keys(): + for widget in self.widgetToItem: self.deleteItem( self.widgetToItem[ widget ] ) self.hostCount = 0 self.switchCount = 0 @@ -1725,7 +1728,7 @@ def exportScript( self ): if controllerType == 'inband': inBandCtrl = True - if inBandCtrl == True: + if inBandCtrl: f.write("\n") f.write("class InbandController( RemoteController ):\n") f.write("\n") @@ -2122,7 +2125,7 @@ def newNode( self, node, event ): c = self.canvas x, y = c.canvasx( event.x ), c.canvasy( event.y ) name = self.nodePrefixes[ node ] - if 'Switch' == node: + if node == 'Switch': self.switchCount += 1 name = self.nodePrefixes[ node ] + str( self.switchCount ) self.switchOpts[name] = {} @@ -2130,14 +2133,14 @@ def newNode( self, node, event ): self.switchOpts[name]['hostname']=name self.switchOpts[name]['switchType']='default' self.switchOpts[name]['controllers']=[] - if 'LegacyRouter' == node: + if node == 'LegacyRouter': self.switchCount += 1 name = self.nodePrefixes[ node ] + str( self.switchCount ) self.switchOpts[name] = {} self.switchOpts[name]['nodeNum']=self.switchCount self.switchOpts[name]['hostname']=name self.switchOpts[name]['switchType']='legacyRouter' - if 'LegacySwitch' == node: + if node == 'LegacySwitch': self.switchCount += 1 name = self.nodePrefixes[ node ] + str( self.switchCount ) self.switchOpts[name] = {} @@ -2145,13 +2148,13 @@ def newNode( self, node, event ): self.switchOpts[name]['hostname']=name self.switchOpts[name]['switchType']='legacySwitch' self.switchOpts[name]['controllers']=[] - if 'Host' == node: + if node == 'Host': self.hostCount += 1 name = self.nodePrefixes[ node ] + str( self.hostCount ) self.hostOpts[name] = {'sched':'host'} self.hostOpts[name]['nodeNum']=self.hostCount self.hostOpts[name]['hostname']=name - if 'Controller' == node: + if node == 'Controller': name = self.nodePrefixes[ node ] + str( self.controllerCount ) ctrlr = { 'controllerType': 'ref', 'hostname': name, @@ -2169,15 +2172,15 @@ def newNode( self, node, event ): self.itemToWidget[ item ] = icon self.selectItem( item ) icon.links = {} - if 'Switch' == node: + if node == 'Switch': icon.bind('', self.do_switchPopup ) - if 'LegacyRouter' == node: + if node == 'LegacyRouter': icon.bind('', self.do_legacyRouterPopup ) - if 'LegacySwitch' == node: + if node == 'LegacySwitch': icon.bind('', self.do_legacySwitchPopup ) - if 'Host' == node: + if node == 'Host': icon.bind('', self.do_hostPopup ) - if 'Controller' == node: + if node == 'Controller': icon.bind('', self.do_controllerPopup ) def clickController( self, event ): @@ -2374,6 +2377,8 @@ def finishLink( self, event ): # For now, don't allow hosts to be directly linked stags = self.canvas.gettags( self.widgetToItem[ source ] ) dtags = self.canvas.gettags( target ) + # TODO: Make this less confusing + # pylint: disable=too-many-boolean-expressions if (('Host' in stags and 'Host' in dtags) or ('Controller' in dtags and 'LegacyRouter' in stags) or ('Controller' in stags and 'LegacyRouter' in dtags) or @@ -2657,7 +2662,7 @@ def addLink( self, source, dest, linktype='data', linkopts=None ): linkopts = {} source.links[ dest ] = self.link dest.links[ source ] = self.link - self.links[ self.link ] = {'type' :linktype, + self.links[ self.link ] = {'type':linktype, 'src':source, 'dest':dest, 'linkOpts':linkopts} @@ -3225,7 +3230,8 @@ def parseCustomFile( self, fileName ): "Parse custom file and add params before parsing cmd-line options." customs = {} if os.path.isfile( fileName ): - execfile( fileName, customs, customs ) + with open( fileName, 'r' ) as f: + exec( f.read() ) # pylint: disable=exec-used for name, val in customs.items(): self.setCustom( name, val ) else: @@ -3592,8 +3598,7 @@ def addDictOption( opts, choicesDict, default, name, helpStr=None ): if __name__ == '__main__': setLogLevel( 'info' ) app = MiniEdit() - ### import topology if specified ### app.parseArgs() + ### import topology if specified ### app.importTopo() - app.mainloop() diff --git a/examples/mobility.py b/examples/mobility.py index d7347dae5..05a8869a1 100755 --- a/examples/mobility.py +++ b/examples/mobility.py @@ -19,14 +19,13 @@ - think about clearing last hop - why doesn't that work? """ +from random import randint from mininet.net import Mininet from mininet.node import OVSSwitch from mininet.topo import LinearTopo from mininet.log import info, output, warn, setLogLevel -from random import randint - class MobilitySwitch( OVSSwitch ): "Switch that can reattach and rename interfaces" @@ -38,6 +37,7 @@ def delIntf( self, intf ): del self.intfs[ port ] del self.nameToIntf[ intf.name ] + # pylint: disable=arguments-differ def addIntf( self, intf, rename=False, **kwargs ): "Add (and reparent) an interface" OVSSwitch.addIntf( self, intf, **kwargs ) @@ -132,6 +132,7 @@ def mobilityTest(): old = new net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) mobilityTest() diff --git a/examples/multilink.py b/examples/multilink.py index b6b405146..e95730a86 100755 --- a/examples/multilink.py +++ b/examples/multilink.py @@ -21,6 +21,7 @@ def runMultiLink(): class simpleMultiLinkTopo( Topo ): "Simple topology with multiple links" + # pylint: disable=arguments-differ def build( self, n, **_kwargs ): h1, h2 = self.addHost( 'h1' ), self.addHost( 'h2' ) s1 = self.addSwitch( 's1' ) @@ -29,6 +30,7 @@ def build( self, n, **_kwargs ): self.addLink( s1, h1 ) self.addLink( s1, h2 ) + if __name__ == '__main__': setLogLevel( 'info' ) runMultiLink() diff --git a/examples/multiping.py b/examples/multiping.py index fedf46281..7d723a419 100755 --- a/examples/multiping.py +++ b/examples/multiping.py @@ -8,14 +8,14 @@ of time. """ +from select import poll, POLLIN +from time import time from mininet.net import Mininet from mininet.node import Node from mininet.topo import SingleSwitchTopo from mininet.log import info, setLogLevel -from select import poll, POLLIN -from time import time def chunks( l, n ): "Divide list l into chunks of size n - thanks Stackoverflow" @@ -59,7 +59,7 @@ def multiping( netsize, chunksize, seconds): # Start pings for subnet in subnets: ips = [ host.IP() for host in subnet ] - #adding bogus to generate packet loss + # adding bogus to generate packet loss ips.append( '10.0.0.200' ) for host in subnet: startpings( host, ips ) diff --git a/examples/multipoll.py b/examples/multipoll.py index e9998df36..13ceaa7fb 100755 --- a/examples/multipoll.py +++ b/examples/multipoll.py @@ -6,15 +6,15 @@ """ +from time import time +from select import poll, POLLIN +from subprocess import Popen, PIPE + from mininet.topo import SingleSwitchTopo from mininet.net import Mininet from mininet.log import info, setLogLevel from mininet.util import decode -from time import time -from select import poll, POLLIN -from subprocess import Popen, PIPE - def monitorFiles( outfiles, seconds, timeoutms ): "Monitor set of files and return [(host, line)...]" diff --git a/examples/multitest.py b/examples/multitest.py index 2d68cd4d9..b208ddf73 100755 --- a/examples/multitest.py +++ b/examples/multitest.py @@ -17,6 +17,7 @@ def ifconfigTest( net ): for host in hosts: info( host.cmd( 'ifconfig' ) ) + if __name__ == '__main__': lg.setLogLevel( 'info' ) info( "*** Initializing Mininet and kernel modules\n" ) diff --git a/examples/natnet.py b/examples/natnet.py index bfbc6dfdf..638a43791 100755 --- a/examples/natnet.py +++ b/examples/natnet.py @@ -27,6 +27,7 @@ class InternetTopo(Topo): "Single switch connected to n hosts." + # pylint: disable=arguments-differ def build(self, n=2, **_kwargs ): # set up inet switch inetSwitch = self.addSwitch('s0') @@ -62,6 +63,7 @@ def run(): CLI(net) net.stop() + if __name__ == '__main__': setLogLevel('info') run() diff --git a/examples/numberedports.py b/examples/numberedports.py index 1fed0da4f..0bd1d3e26 100755 --- a/examples/numberedports.py +++ b/examples/numberedports.py @@ -75,6 +75,7 @@ def testPortNumbering(): info( '*** Stopping network\n' ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) testPortNumbering() diff --git a/examples/popen.py b/examples/popen.py index 4de4d6179..94e7b4574 100755 --- a/examples/popen.py +++ b/examples/popen.py @@ -28,6 +28,7 @@ def monitorhosts( hosts=5 ): # Done net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) monitorhosts( hosts=5 ) diff --git a/examples/popenpoll.py b/examples/popenpoll.py index 75534c9a3..7f56ef0d4 100755 --- a/examples/popenpoll.py +++ b/examples/popenpoll.py @@ -2,13 +2,14 @@ "Monitor multiple hosts using popen()/pmonitor()" +from time import time +from signal import SIGINT + from mininet.net import Mininet from mininet.topo import SingleSwitchTopo from mininet.util import pmonitor from mininet.log import setLogLevel, info -from time import time -from signal import SIGINT def pmonitorTest( N=3, seconds=10 ): "Run pings and monitor multiple hosts using pmonitor" @@ -31,6 +32,7 @@ def pmonitorTest( N=3, seconds=10 ): p.send_signal( SIGINT ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) pmonitorTest() diff --git a/examples/scratchnet.py b/examples/scratchnet.py index cc1d19c5f..a8d536d06 100755 --- a/examples/scratchnet.py +++ b/examples/scratchnet.py @@ -8,6 +8,7 @@ For most tasks, the higher-level API will be preferable. """ +from time import sleep from mininet.net import Mininet from mininet.node import Node @@ -15,7 +16,6 @@ from mininet.log import setLogLevel, info from mininet.util import quietRun -from time import sleep def scratchNet( cname='controller', cargs='-v ptcp:' ): "Create network from scratch using Open vSwitch." @@ -62,6 +62,7 @@ def scratchNet( cname='controller', cargs='-v ptcp:' ): switch.deleteIntfs() info( '\n' ) + if __name__ == '__main__': setLogLevel( 'info' ) info( '*** Scratch network demo (kernel datapath)\n' ) diff --git a/examples/scratchnetuser.py b/examples/scratchnetuser.py index 690c712bb..2c50f9d7e 100755 --- a/examples/scratchnetuser.py +++ b/examples/scratchnetuser.py @@ -66,6 +66,7 @@ def scratchNetUser( cname='controller', cargs='ptcp:' ): switch.deleteIntfs() info( '\n' ) + if __name__ == '__main__': setLogLevel( 'info' ) info( '*** Scratch network demo (user datapath)\n' ) diff --git a/examples/simpleperf.py b/examples/simpleperf.py index 0124d790d..91e7e0155 100755 --- a/examples/simpleperf.py +++ b/examples/simpleperf.py @@ -9,6 +9,7 @@ to complete. """ +from sys import argv from mininet.topo import Topo from mininet.net import Mininet @@ -17,7 +18,6 @@ from mininet.util import dumpNodeConnections from mininet.log import setLogLevel, info -from sys import argv # It would be nice if we didn't have to do this: # pylint: disable=arguments-differ @@ -54,6 +54,7 @@ def perfTest( lossy=True ): net.iperf( ( h1, h4 ), l4Type='UDP' ) net.stop() + if __name__ == '__main__': setLogLevel( 'info' ) # Prevent test_simpleperf from failing due to packet loss diff --git a/examples/sshd.py b/examples/sshd.py index a5641ac77..ac62fb526 100755 --- a/examples/sshd.py +++ b/examples/sshd.py @@ -47,6 +47,7 @@ def connectToRootNS( network, switch, ip, routes ): for route in routes: root.cmd( 'route add -net ' + route + ' dev ' + str( intf ) ) +# pylint: disable=too-many-arguments def sshd( network, cmd='/usr/sbin/sshd', opts='-D', ip='10.123.123.1/32', routes=None, switch=None ): """Start a network, connect it to root ns, and run sshd on all hosts. @@ -73,6 +74,7 @@ def sshd( network, cmd='/usr/sbin/sshd', opts='-D', host.cmd( 'kill %' + cmd ) network.stop() + if __name__ == '__main__': lg.setLogLevel( 'info') net = TreeNet( depth=1, fanout=4 ) diff --git a/examples/treeping64.py b/examples/treeping64.py index c72943cad..1c044b105 100755 --- a/examples/treeping64.py +++ b/examples/treeping64.py @@ -38,6 +38,7 @@ def treePing64(): info( "%s: %d%% packet loss\n" % ( name, results[ name ] ) ) info( '\n' ) + if __name__ == '__main__': setLogLevel( 'info' ) treePing64() diff --git a/examples/vlanhost.py b/examples/vlanhost.py index ec68b9332..d15d2d660 100755 --- a/examples/vlanhost.py +++ b/examples/vlanhost.py @@ -24,14 +24,18 @@ """ +from sys import exit # pylint: disable=redefined-builtin + from mininet.node import Host from mininet.topo import Topo from mininet.util import quietRun from mininet.log import error + class VLANHost( Host ): "Host connected to VLAN interface" + # pylint: disable=arguments-differ def config( self, vlan=100, **params ): """Configure VLANHost according to (optional) parameters: vlan: VLAN ID for default interface""" @@ -54,6 +58,7 @@ def config( self, vlan=100, **params ): return r + hosts = { 'vlan': VLANHost } @@ -101,6 +106,7 @@ def exampleCustomTags(): CLI( net ) net.stop() + if __name__ == '__main__': import sys from functools import partial diff --git a/mininet/cli.py b/mininet/cli.py index 5c644cacc..82e2ac552 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -47,7 +47,7 @@ class CLI( Cmd ): prompt = 'mininet> ' def __init__( self, mininet, stdin=sys.stdin, script=None, - *args, **kwargs ): + **kwargs ): """Start and run interactive or batch mode CLI mininet: Mininet network object stdin: standard input for CLI @@ -59,7 +59,7 @@ def __init__( self, mininet, stdin=sys.stdin, script=None, self.inPoller = poll() self.inPoller.register( stdin ) self.inputFile = script - Cmd.__init__( self, *args, stdin=stdin, **kwargs ) + Cmd.__init__( self, stdin=stdin, **kwargs ) info( '*** Starting CLI:\n' ) if self.inputFile: @@ -79,6 +79,7 @@ def initReadline( cls ): return cls.readlineInited = True try: + # pylint: disable=import-outside-toplevel from readline import ( read_history_file, write_history_file, set_history_length ) except ImportError: @@ -141,7 +142,7 @@ def getLocals( self ): ' mininet> xterm h2\n\n' ) - def do_help( self, line ): + def do_help( self, line ): # pylint: disable=arguments-differ "Describe available CLI commands." Cmd.do_help( self, line ) if line == '': @@ -173,6 +174,7 @@ def do_py( self, line ): """Evaluate a Python expression. Node names may be used, e.g.: py h1.cmd('ls')""" try: + # pylint: disable=eval-used result = eval( line, globals(), self.getLocals() ) if not result: return @@ -467,10 +469,10 @@ def waitForNode( self, node ): node.sendInt() except select.error as e: # pylint: disable=unpacking-non-sequence + # pylint: disable=unbalanced-tuple-unpacking errno_, errmsg = e.args - # pylint: enable=unpacking-non-sequence if errno_ != errno.EINTR: - error( "select.error: %d, %s" % (errno_, errmsg) ) + error( "select.error: %s, %s" % (errno_, errmsg) ) node.sendInt() def precmd( self, line ): @@ -488,3 +490,4 @@ def isReadable( poller ): mask = fdmask[ 1 ] if mask & POLLIN: return True + return False diff --git a/mininet/link.py b/mininet/link.py index bf10dc717..56912f7d5 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -24,9 +24,14 @@ Link: basic link class for creating veth pairs """ +import re + from mininet.log import info, error, debug from mininet.util import makeIntfPair -import re + +# Make pylint happy: +# pylint: disable=too-many-arguments + class Intf( object ): @@ -170,7 +175,7 @@ def setParam( self, results, method, **param ): name, value = list( param.items() )[ 0 ] f = getattr( self, method, None ) if not f or value is None: - return + return None if isinstance( value, list ): result = f( *value ) elif isinstance( value, dict ): @@ -311,6 +316,7 @@ def tc( self, cmd, tc='tc' ): debug(" *** executing command: %s\n" % c) return self.cmd( c ) + # pylint: disable=arguments-differ def config( self, bw=None, delay=None, jitter=None, loss=None, gro=False, txo=True, rxo=True, speedup=0, use_hfsc=False, use_tbf=False, @@ -351,7 +357,7 @@ def on( isOn ): # Question: what happens if we want to reset things? if ( bw is None and not delay and not loss and max_queue_size is None ): - return + return None # Clear existing configuration tcoutput = self.tc( '%s qdisc show dev %s' ) @@ -533,7 +539,11 @@ class OVSLink( Link ): def __init__( self, node1, node2, **kwargs ): "See Link.__init__() for options" - from mininet.node import OVSSwitch + try: + OVSSwitch + except NameError: + # pylint: disable=import-outside-toplevel,cyclic-import + from mininet.node import OVSSwitch self.isPatchLink = False if ( isinstance( node1, OVSSwitch ) and isinstance( node2, OVSSwitch ) ): @@ -541,6 +551,7 @@ def __init__( self, node1, node2, **kwargs ): kwargs.update( cls1=OVSIntf, cls2=OVSIntf ) Link.__init__( self, node1, node2, **kwargs ) + # pylint: disable=arguments-differ, signature-differs def makeIntfPair( self, *args, **kwargs ): "Usually delegated to OVSSwitch" if self.isPatchLink: diff --git a/mininet/log.py b/mininet/log.py index a19970f28..48475e78c 100644 --- a/mininet/log.py +++ b/mininet/log.py @@ -20,7 +20,7 @@ # change this to logging.INFO to get printouts when running unit tests LOGLEVELDEFAULT = OUTPUT -#default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' +# default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' LOGMSGFORMAT = '%(message)s' @@ -51,7 +51,7 @@ def emit( self, record ): self.flush() except ( KeyboardInterrupt, SystemExit ): raise - except: + except: # noqa pylint: disable=bare-except self.handleError( record ) @@ -137,13 +137,14 @@ def output( self, msg, *args, **kwargs ): logger.warning("Houston, we have a %s", "cli output", exc_info=1) """ - if self.manager.disable >= OUTPUT: + if getattr( self.manager, 'disabled', 0 ) >= OUTPUT: return if self.isEnabledFor( OUTPUT ): self._log( OUTPUT, msg, args, kwargs ) # pylint: enable=method-hidden + lg = MininetLogger() # Make things a bit more convenient by adding aliases @@ -168,6 +169,7 @@ def newfn( *args ): setattr( newfn, '__doc__', fn.__doc__ ) return newfn + _loggers = lg.info, lg.output, lg.warn, lg.error, lg.debug _loggers = tuple( makeListCompatible( logger ) for logger in _loggers ) diff --git a/mininet/moduledeps.py b/mininet/moduledeps.py index fda2d7029..470465a26 100644 --- a/mininet/moduledeps.py +++ b/mininet/moduledeps.py @@ -1,8 +1,11 @@ "Module dependency utility functions for Mininet." +from os import environ +from sys import exit # pylint: disable=redefined-builtin + from mininet.util import quietRun, BaseString from mininet.log import info, error, debug -from os import environ + def lsmod(): "Return output of lsmod." @@ -18,6 +21,7 @@ def modprobe( mod ): mod: module string""" return quietRun( [ 'modprobe', mod ] ) + OF_KMOD = 'ofdatapath' OVS_KMOD = 'openvswitch_mod' # Renamed 'openvswitch' in OVS 1.7+/Linux 3.5+ TUN = 'tun' diff --git a/mininet/net.py b/mininet/net.py index 84bb7aee3..8bca10e32 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -92,6 +92,7 @@ import signal import random +from sys import exit # pylint: disable=redefined-builtin from time import sleep from itertools import chain, groupby from math import ceil @@ -113,6 +114,7 @@ class Mininet( object ): "Network emulation with hosts spawned in network namespaces." + # pylint: disable=too-many-arguments def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host, controller=DefaultController, link=Link, intf=Intf, build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8', diff --git a/mininet/node.py b/mininet/node.py index c3e12a7e5..817b39a53 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -57,7 +57,10 @@ import re import signal import select +from distutils.version import StrictVersion +from re import findall from subprocess import Popen, PIPE +from sys import exit # pylint: disable=redefined-builtin from time import sleep from mininet.log import info, error, warn, debug @@ -66,8 +69,10 @@ encode, getincrementaldecoder, Python3, which ) from mininet.moduledeps import moduleDeps, pathCheck, TUN from mininet.link import Link, Intf, TCIntf, OVSIntf -from re import findall -from distutils.version import StrictVersion + + +# pylint: disable=too-many-arguments + class Node( object ): """A virtual network node is simply a shell in a network namespace. @@ -94,9 +99,13 @@ def __init__( self, name, inNamespace=True, **params ): # 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 ? + # dict of port numbers to interfacse + self.intfs = {} + + # dict of interfaces to port numbers + # todo: replace with Port objects, eventually ? + self.ports = {} + self.nameToIntf = {} # dict of interface names to Intfs # Make pylint happy @@ -284,6 +293,7 @@ def waitReadable( self, timeoutms=None ): returns: result of poll()""" if len( self.readbuf ) == 0: return self.pollOut.poll( timeoutms ) + return None def sendCmd( self, *args, **kwargs ): """Send a command, followed by a command to echo a sentinel, @@ -377,6 +387,7 @@ def cmd( self, *args, **kwargs ): return self.waitOutput( verbose ) else: warn( '(%s exited - ignoring cmd%s)\n' % ( self, args ) ) + return None def cmdPrint( self, *args): """Call cmd and printing its output @@ -469,6 +480,7 @@ def defaultIntf( self ): else: warn( '*** defaultIntf: warning:', self.name, 'has no interfaces\n' ) + return None def intf( self, intf=None ): """Return our interface object with given string name, @@ -582,10 +594,10 @@ def setParam( self, results, method, **param ): value may also be list or dict""" name, value = list( param.items() )[ 0 ] if value is None: - return + return None f = getattr( self, method, None ) if not f: - return + return None if isinstance( value, list ): result = f( *value ) elif isinstance( value, dict ): @@ -653,11 +665,12 @@ def __str__( self ): @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 + clas = cls + while clas and not getattr( clas, 'isSetup', True ): + clas.setup() + clas.isSetup = True # Make pylint happy - cls = getattr( type( cls ), '__base__', None ) + clas = getattr( type( clas ), '__base__', None ) @classmethod def setup( cls ): @@ -838,6 +851,7 @@ def setCPUs( self, cores, mems=0 ): errFail( 'cgclassify -g cpuset:/%s %s' % ( self.name, self.pid ) ) + # pylint: disable=arguments-differ def config( self, cpu=-1, cores=None, **params ): """cpu: desired overall system CPU fraction cores: (real) core(s) this host can run on @@ -930,6 +944,7 @@ def sendCmd( self, *cmd, **kwargs ): else: error( '*** Error: %s has execed and cannot accept commands' % self.name ) + return None def connected( self ): "Is the switch connected to a controller? (override this method)" @@ -1115,6 +1130,7 @@ def vsctl( self, *args, **kwargs ): if self.batch: cmd = ' '.join( str( arg ).strip() for arg in args ) self.commands.append( cmd ) + return None else: return self.cmd( 'ovs-vsctl', *args, **kwargs ) @@ -1302,7 +1318,7 @@ def connected( self ): "Are we forwarding yet?" if self.stp: status = self.dpctl( 'show' ) - return 'STP_FORWARD' in status and not 'STP_LEARN' in status + return 'STP_FORWARD' in status and 'STP_LEARN' not in status else: return True @@ -1429,6 +1445,7 @@ def start( self ): ' 1>' + cout + ' 2>' + cout + ' &' ) self.execed = False + # pylint: disable=arguments-differ,signature-differs def stop( self, *args, **kwargs ): "Stop controller." self.cmd( 'kill %' + self.command ) @@ -1479,7 +1496,7 @@ def __init__( self, name, *noxArgs, **kwargs ): warn( 'warning: no NOX modules specified; ' 'running packetdump only\n' ) noxArgs = [ 'packetdump' ] - elif type( noxArgs ) not in ( list, tuple ): + elif not isinstance( noxArgs, ( list, tuple ) ): noxArgs = [ noxArgs ] if 'NOX_CORE_DIR' not in os.environ: @@ -1505,7 +1522,7 @@ def __init__( self, name, *ryuArgs, **kwargs ): warn( 'warning: no Ryu modules specified; ' 'running simple_switch only\n' ) ryuArgs = [ ryuCoreDir + 'simple_switch.py' ] - elif type( ryuArgs ) not in ( list, tuple ): + elif not isinstance( ryuArgs, ( list, tuple ) ): ryuArgs = [ ryuArgs ] Controller.__init__( self, name, @@ -1532,6 +1549,7 @@ def start( self ): "Overridden to do nothing." return + # pylint: disable=arguments-differ def stop( self ): "Overridden to do nothing." return @@ -1563,6 +1581,7 @@ def isListening( self, ip, port ): else: return True + DefaultControllers = ( Controller, OVSController ) def findController( controllers=DefaultControllers ): @@ -1570,6 +1589,7 @@ def findController( controllers=DefaultControllers ): for controller in controllers: if controller.isAvailable(): return controller + return None def DefaultController( name, controllers=DefaultControllers, **kwargs ): "Find a controller that is available and instantiate it" diff --git a/mininet/nodelib.py b/mininet/nodelib.py index 1d5106ebd..44ee6d027 100644 --- a/mininet/nodelib.py +++ b/mininet/nodelib.py @@ -102,6 +102,7 @@ def setManualConfig( self, intf ): # hopefully this won't disconnect you self.cmd( 'service network-manager restart || netplan apply' ) + # pylint: disable=arguments-differ def config( self, **params ): """Configure the NAT and iptables""" diff --git a/mininet/term.py b/mininet/term.py index 04d9871c4..769367db1 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -50,7 +50,7 @@ def makeTerm( node, title='Node', term='xterm', display=None, cmd='bash'): } if term not in cmds: error( 'invalid terminal type: %s' % term ) - return + return None display, tunnel = tunnelX11( node, display ) if display is None: return [] diff --git a/mininet/test/runner.py b/mininet/test/runner.py index 73dd9fb55..4540599d1 100755 --- a/mininet/test/runner.py +++ b/mininet/test/runner.py @@ -25,6 +25,7 @@ def runTests( testDir, verbosity=1 ): .run( testSuite ).wasSuccessful() ) sys.exit( 0 if success else 1 ) + if __name__ == '__main__': setLogLevel( 'warning' ) # get the directory containing example tests diff --git a/mininet/test/test_hifi.py b/mininet/test/test_hifi.py index 1a3a0acfe..ec742398b 100755 --- a/mininet/test/test_hifi.py +++ b/mininet/test/test_hifi.py @@ -45,7 +45,7 @@ class testOptionsTopoCommon( object ): @staticmethod def tearDown(): "Clean up if necessary" - if sys.exc_info != ( None, None, None ): + if sys.exc_info() != ( None, None, None ): cleanup() def runOptionsTopoTest( self, n, msg, hopts=None, lopts=None ): @@ -95,7 +95,7 @@ def testCPULimits( self ): CPU_FRACTION = 0.1 CPU_TOLERANCE = 0.8 # CPU fraction below which test should fail hopts = { 'cpu': CPU_FRACTION } - #self.runOptionsTopoTest( N, hopts=hopts ) + # self.runOptionsTopoTest( N, hopts=hopts ) mn = Mininet( SingleSwitchOptionsTopo( n=N, hopts=hopts ), host=CPULimitedHost, switch=self.switchClass, @@ -118,7 +118,7 @@ def testCPULimits( self ): % ( CPU_FRACTION * 100, hostUsage, N, hoptsStr, self.switchClass ) ) for pct in results: - #divide cpu by 100 to convert from percentage to fraction + # divide cpu by 100 to convert from percentage to fraction self.assertWithinTolerance( pct/100, CPU_FRACTION, CPU_TOLERANCE, msg ) @@ -263,6 +263,7 @@ class testOptionsTopoUserspace( testOptionsTopoCommon, unittest.TestCase ): longMessage = True switchClass = UserSwitch + if __name__ == '__main__': setLogLevel( 'warning' ) unittest.main() diff --git a/mininet/test/test_nets.py b/mininet/test/test_nets.py index e46855549..98048ec9f 100755 --- a/mininet/test/test_nets.py +++ b/mininet/test/test_nets.py @@ -26,7 +26,7 @@ class testSingleSwitchCommon( object ): @staticmethod def tearDown(): "Clean up if necessary" - if sys.exc_info != ( None, None, None ): + if sys.exc_info() != ( None, None, None ): cleanup() def testMinimal( self ): diff --git a/mininet/test/test_ptyleak.py b/mininet/test/test_ptyleak.py index 9d3aafbe6..813be764f 100755 --- a/mininet/test/test_ptyleak.py +++ b/mininet/test/test_ptyleak.py @@ -26,6 +26,7 @@ def testPtyLeak(): assert ( host.slave, host.master ) == oldptys net.stop() + if __name__ == '__main__': unittest.main() cleanup() diff --git a/mininet/test/test_switchdpidassignment.py b/mininet/test/test_switchdpidassignment.py index 62ef493e3..f3ea30978 100755 --- a/mininet/test/test_switchdpidassignment.py +++ b/mininet/test/test_switchdpidassignment.py @@ -24,7 +24,7 @@ def tearDown( self ): "Clean up if necessary" # satisfy pylint assert self - if sys.exc_info != ( None, None, None ): + if sys.exc_info() != ( None, None, None ): cleanup() def testDefaultDpid( self ): @@ -95,6 +95,7 @@ class testSwitchUserspace( TestSwitchDpidAssignmentOVS ): "Test dpid assignment of Userspace switch." switchClass = UserSwitch + if __name__ == '__main__': setLogLevel( 'warning' ) unittest.main() diff --git a/mininet/test/test_util.py b/mininet/test/test_util.py index 66a312832..5e480b71a 100755 --- a/mininet/test/test_util.py +++ b/mininet/test/test_util.py @@ -35,5 +35,6 @@ def testMultipleReads( self ): output = quietRun(testQuietRun.getEchoCmd( n ) ) self.assertEqual( n, len( output ) ) + if __name__ == "__main__": unittest.main() diff --git a/mininet/test/test_walkthrough.py b/mininet/test/test_walkthrough.py index 2b26e1841..7ed67fe2e 100755 --- a/mininet/test/test_walkthrough.py +++ b/mininet/test/test_walkthrough.py @@ -6,14 +6,16 @@ TODO: missing xterm test """ -import unittest import os import re -from mininet.util import quietRun, pexpect -from mininet.clean import cleanup +import unittest + from distutils.version import StrictVersion from sys import stdout +from mininet.util import quietRun, pexpect +from mininet.clean import cleanup + def tsharkVersion(): "Return tshark version" @@ -74,7 +76,7 @@ def testBasic( self ): p.expect( self.prompt ) # net command p.sendline( 'net' ) - expected = [ x for x in nodes ] + expected = list( nodes ) while len( expected ) > 0: index = p.expect( expected ) node = p.match.group( 0 ) @@ -110,7 +112,7 @@ def testHostCommands( self ): ifcount = 0 while True: index = p.expect( interfaces ) - if index == 0 or index == 3: + if index in (0, 3): ifcount += 1 elif index == 1: self.fail( 's1 interface displayed in "h1 ifconfig"' ) @@ -126,7 +128,7 @@ def testHostCommands( self ): index = p.expect( interfaces ) if index == 0: self.fail( 'h1 interface displayed in "s1 ifconfig"' ) - elif index == 1 or index == 2 or index == 3: + elif index in (1, 2, 3): ifcount += 1 else: break @@ -309,7 +311,7 @@ def testOwnNamespace( self ): ifcount = 0 while True: index = p.expect( interfaces ) - if index == 1 or index == 3: + if index in (1, 3): ifcount += 1 elif index == 0: self.fail( 'h1 interface displayed in "s1 ifconfig"' ) diff --git a/mininet/topo.py b/mininet/topo.py index d3cb67fc2..21f1dcfdf 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -13,6 +13,9 @@ from mininet.util import irange, natural, naturalSeq +# pylint: disable=too-many-arguments + + class MultiGraph( object ): "Utility class to track nodes and edges - replaces networkx.MultiGraph" diff --git a/mininet/util.py b/mininet/util.py index d72409649..36b5d24ea 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -1,19 +1,23 @@ "Utility functions for Mininet." +import codecs +import os +import re +import sys -from mininet.log import output, info, error, warn, debug - -from time import sleep +from fcntl import fcntl, F_GETFL, F_SETFL +from functools import partial +from os import O_NONBLOCK from resource import getrlimit, setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE from select import poll, POLLIN, POLLHUP from subprocess import call, check_call, Popen, PIPE, STDOUT -import re -from fcntl import fcntl, F_GETFL, F_SETFL -from os import O_NONBLOCK -import os -from functools import partial -import sys -import codecs +from sys import exit # pylint: disable=redefined-builtin +from time import sleep + +from mininet.log import output, info, error, warn, debug + +# pylint: disable=too-many-arguments + # Python 2/3 compatibility @@ -454,6 +458,7 @@ def pmonitor(popens, timeoutms=500, readline=True, poller.register( fd, POLLIN ) flags = fcntl( fd, F_GETFL ) fcntl( fd, F_SETFL, flags | O_NONBLOCK ) + # pylint: disable=too-many-nested-blocks while popens: fds = poller.poll( timeoutms ) if fds: @@ -665,7 +670,6 @@ def ensureRoot(): if os.getuid() != 0: error( '*** Mininet must run as root.\n' ) exit( 1 ) - return def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ): """Wait until server is listening on port. From f9d5ef34614f4c28c372d4243a9d7cf371930eb2 Mon Sep 17 00:00:00 2001 From: lantz Date: Mon, 25 Jan 2021 14:56:05 -0800 Subject: [PATCH 23/51] remove .travis.yml and travis badge from README.md (#1013) Thanks to travis.org for the CI support for many years. --- .travis.yml | 30 ------------------------------ README.md | 6 ++---- 2 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index cafb18c71..000000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: python -sudo: required - -matrix: - include: - - dist: focal - python: 3.6 - env: dist="24.04 LTS focal" - -before_install: -- sudo apt-get update -qq -- sudo apt-get install -qq vlan pyflakes -- PYTHON=`which python` util/install.sh -n - -install: -- make codecheck -- pip install pexpect || pip3 install pexpect -- util/install.sh -nfvw - -script: -- alias sudo="sudo env PATH=$PATH" -- export PYTHON=`which python` -- echo 'px import sys; print(sys.version_info)' | sudo $PYTHON bin/mn -v output -- sudo $PYTHON bin/mn --test pingall - -notifications: - email: - on_success: never - -# More details: https://docs.travis-ci.com/user/notifications diff --git a/README.md b/README.md index 6e48ad063..df86072ee 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ Mininet: Rapid Prototyping for Software Defined Networks Mininet 2.3.0a1 -[![Build Status][2]](https://github.com/mininet/mininet/actions) -[![Travis Status][1]](https://travis-ci.org/mininet/mininet) +[![Build Status][1]](https://github.com/mininet/mininet/actions) ### What is Mininet? @@ -122,5 +121,4 @@ Mininet to change the networking world! Bob Lantz on behalf of the Mininet Contributors -[1]: https://travis-ci.org/mininet/mininet.svg?branch=master -[2]: https://github.com/mininet/mininet/workflows/mininet-tests/badge.svg +[1]: https://github.com/mininet/mininet/workflows/mininet-tests/badge.svg From 12f4d5b8ae4ff5ab964ca0df7694566ced71884c Mon Sep 17 00:00:00 2001 From: lantz Date: Tue, 26 Jan 2021 00:18:54 -0800 Subject: [PATCH 24/51] Fetch older version of get-pip.py for python 2 (#1015) fixes #1014 --- util/install.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/install.sh b/util/install.sh index 8ea754c03..a6fd16630 100755 --- a/util/install.sh +++ b/util/install.sh @@ -184,7 +184,11 @@ function mn_deps { # Install pip $install ${PYPKG}-pip || $install ${PYPKG}-pip-whl if ! ${PYTHON} -m pip -V; then - wget https://bootstrap.pypa.io/get-pip.py + if [ $PYTHON_VERSION == 2 ]; then + wget https://bootstrap.pypa.io/2.6/get-pip.py + else + wget https://bootstrap.pypa.io/get-pip.py + fi sudo ${PYTHON} get-pip.py rm get-pip.py fi From 2255bc7da37aa935beb00709991a25b77443e569 Mon Sep 17 00:00:00 2001 From: lantz Date: Wed, 27 Jan 2021 18:27:22 -0800 Subject: [PATCH 25/51] Fix/clean up setLogLevel (#1016) Sometimes we got no output with python 3 on ubuntu 20 This simplifies setLogLevel slightly and should work on python 2 and python 3. --- mininet/log.py | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/mininet/log.py b/mininet/log.py index 48475e78c..a6cf311b7 100644 --- a/mininet/log.py +++ b/mininet/log.py @@ -4,6 +4,7 @@ from logging import Logger import types + # Create a new loglevel, 'CLI info', which enables a Mininet user to see only # the output of the commands they execute, plus any errors or warnings. This # level is in between info and warning. CLI info-level commands should not be @@ -105,30 +106,21 @@ def __init__( self ): formatter = logging.Formatter( LOGMSGFORMAT ) # add formatter to ch ch.setFormatter( formatter ) - # add ch to lg + # add ch to lg and initialize log level self.addHandler( ch ) - + self.ch = ch self.setLogLevel() def setLogLevel( self, levelname=None ): """Setup loglevel. Convenience function to support lowercase names. levelName: level name from LEVELS""" - level = LOGLEVELDEFAULT - if levelname is not None: - if levelname not in LEVELS: - raise Exception( 'unknown levelname seen in setLogLevel' ) - else: - level = LEVELS.get( levelname, level ) - + if levelname and levelname not in LEVELS: + raise Exception( 'setLogLevel: unknown levelname %s' % levelname ) + level = LEVELS.get( levelname, LOGLEVELDEFAULT ) self.setLevel( level ) - self.handlers[ 0 ].setLevel( level ) - - # pylint: disable=method-hidden - # "An attribute inherited from mininet.log hide this method" (sic) - # Not sure why this is occurring - this function definitely gets called. + self.ch.setLevel( level ) - # See /usr/lib/python2.5/logging/__init__.py; modified from warning() def output( self, msg, *args, **kwargs ): """Log 'msg % args' with severity 'OUTPUT'. @@ -142,8 +134,6 @@ def output( self, msg, *args, **kwargs ): if self.isEnabledFor( OUTPUT ): self._log( OUTPUT, msg, args, kwargs ) - # pylint: enable=method-hidden - lg = MininetLogger() From e07a29b4e647fe10aca7e24c122faf08a3c38a9c Mon Sep 17 00:00:00 2001 From: lantz Date: Thu, 28 Jan 2021 16:04:39 -0800 Subject: [PATCH 26/51] fix make develop: --no-binary :all: (#1017) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9e5901142..950c31705 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ develop: $(MNEXEC) $(MANPAGES) # Perhaps we should link these as well install $(MNEXEC) $(BINDIR) install $(MANPAGES) $(MANDIR) - $(PYTHON) -m pip install -e . --no-binary + $(PYTHON) -m pip install -e . --no-binary :all: man: $(MANPAGES) From 715db45b9dcd9bcf0ffc9bb4211808217276e664 Mon Sep 17 00:00:00 2001 From: lantz Date: Thu, 28 Jan 2021 18:48:45 -0800 Subject: [PATCH 27/51] more logging fixes (#1018) - call getLogger( "mininet" ) to set lg properly - support warning() as well as (deprecated) warn() - rearrange initialization slightly --- mininet/log.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/mininet/log.py b/mininet/log.py index a6cf311b7..881d22cfc 100644 --- a/mininet/log.py +++ b/mininet/log.py @@ -15,6 +15,7 @@ 'info': logging.INFO, 'output': OUTPUT, 'warning': logging.WARNING, + 'warn': logging.WARNING, 'error': logging.ERROR, 'critical': logging.CRITICAL } @@ -96,9 +97,9 @@ class MininetLogger( Logger, object ): __metaclass__ = Singleton - def __init__( self ): + def __init__( self, name="mininet" ): - Logger.__init__( self, "mininet" ) + Logger.__init__( self, name ) # create console handler ch = StreamHandlerNoNewline() @@ -116,6 +117,7 @@ def setLogLevel( self, levelname=None ): Convenience function to support lowercase names. levelName: level name from LEVELS""" if levelname and levelname not in LEVELS: + print(LEVELS) raise Exception( 'setLogLevel: unknown levelname %s' % levelname ) level = LEVELS.get( levelname, LOGLEVELDEFAULT ) self.setLevel( level ) @@ -135,8 +137,6 @@ def output( self, msg, *args, **kwargs ): self._log( OUTPUT, msg, args, kwargs ) -lg = MininetLogger() - # Make things a bit more convenient by adding aliases # (info, warn, error, debug) and allowing info( 'this', 'is', 'OK' ) # In the future we may wish to make things more efficient by only @@ -160,10 +160,13 @@ def newfn( *args ): return newfn -_loggers = lg.info, lg.output, lg.warn, lg.error, lg.debug -_loggers = tuple( makeListCompatible( logger ) - for logger in _loggers ) -lg.info, lg.output, lg.warn, lg.error, lg.debug = _loggers -info, output, warn, error, debug = _loggers +# Initialize logger and logging functions +logging.setLoggerClass( MininetLogger ) +lg = logging.getLogger( "mininet" ) +_loggers = lg.info, lg.output, lg.warning, lg.error, lg.debug +_loggers = tuple( makeListCompatible( logger ) for logger in _loggers ) +lg.info, lg.output, lg.warning, lg.error, lg.debug = _loggers +info, output, warning, error, debug = _loggers +warn = warning # alternate/old name setLogLevel = lg.setLogLevel From 96ac94a985fb38569ede4f0cf4401b304ec98c6f Mon Sep 17 00:00:00 2001 From: lantz Date: Fri, 29 Jan 2021 15:47:47 -0800 Subject: [PATCH 28/51] fix session typo thanks to Vintas Avinash closes #1011 --- examples/miniedit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/miniedit.py b/examples/miniedit.py index a35584106..24d1ad3ad 100755 --- a/examples/miniedit.py +++ b/examples/miniedit.py @@ -3016,7 +3016,7 @@ def postStartSetup( self ): ## NOTE: MAKE SURE THIS IS LAST THING CALLED # Start the CLI if enabled if self.appPrefs['startCLI'] == '1': - info( "\n\n NOTE: PLEASE REMEMBER TO EXIT THE CLI BEFORE YOU PRESS THE STOP BUTTON. Not exiting will prevent MiniEdit from quitting and will prevent you from starting the network again during this sessoin.\n\n") + info( "\n\n NOTE: PLEASE REMEMBER TO EXIT THE CLI BEFORE YOU PRESS THE STOP BUTTON. Not exiting will prevent MiniEdit from quitting and will prevent you from starting the network again during this session.\n\n") CLI(self.net) def start( self ): From b6ad3a1619c60d5d7773665c33d7d2b87dd7a104 Mon Sep 17 00:00:00 2001 From: lantz Date: Fri, 29 Jan 2021 16:15:39 -0800 Subject: [PATCH 29/51] Mininet 2.3.0b1 (#1019) Also tweak README.md, INSTALL, and CONTRIBUTORS --- CONTRIBUTORS | 31 ++++++++++++++++++++++++++++++- INSTALL | 13 +++++-------- LICENSE | 2 +- README.md | 9 +++++---- mininet/net.py | 2 +- 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9bdbb5192..ef20a775b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -18,34 +18,63 @@ Cody Burkard Additional Mininet Contributors +Joseph Beshay +M S Vishwanath Bhat +Muhammad Umair Bhatti +Arie Bregman Tomasz Buchert -Gustavo Pantuza Coelho Pinto Fernando Cappi +HW Chiu Ryan Cox Shaun Crampton +Jason Croft +Hantao Cui +Nirmoy Das +Lenoardo D'avila +Giuseppe Di Lena David Erickson +Juan Gascon Glen Gibb Andrew Ferguson Eder Leao Fernandes +Julian Filter +Ben Frankel +Tim Gates Gregory Gee Jon Hall Roan Huang Vitaly Ivanov +Theo Jepsen +Mathieu Jadin Babis Kaidos Rich Lane Rémy Léone +Xiaozhou Li Zi Shen Lim David Mahler +Felix Maurer Murphy McCauley +Alex Moijes +Felician Nemeth José Pedro Oliveira James Page +Gustavo Pantuza Coelho Pinto +Ramon Pujianto +Stempha Reiter +Damien Saucez +Shan Sikdar Angad Singh Piyush Srivastava Ed Swierk Darshan Thaker +Olivier Tl]ilmans +Niels van Adrichem +Brad Walker Andreas Wundsam +Vikas Yadav Isaku Yamahata Baohua Yang +Zhuo Thanks also to everyone who has submitted issues and pull requests on github, and to our friendly mininet-discuss diff --git a/INSTALL b/INSTALL index 23327c371..9d7ce7b58 100644 --- a/INSTALL +++ b/INSTALL @@ -2,7 +2,7 @@ Mininet Installation/Configuration Notes ---------------------------------------- -Mininet 2.3.0a1 +Mininet 2.3.0b1 --- The supported installation methods for Mininet are 1) using a @@ -32,19 +32,16 @@ like to contribute an installation script, we would welcome it!) 2. Next-easiest option: use our Ubuntu package! To install Mininet itself (i.e. `mn` and the Python API) on Ubuntu - 12.10+: + 16.04+: sudo apt-get install mininet - Note: if you are upgrading from an older version of Mininet, make - sure you remove the old OVS from `/usr/local`: - - sudo rm /usr/local/bin/ovs* - sudo rm /usr/local/sbin/ovs* + Note: this may install an older version of Mininet. If you would + like the latest version, consider a native install from source. 3. Native installation from source -3.1. Native installation from source on Ubuntu 12.04+ +3.1. Native installation from source on Ubuntu 16.04+ If you're reading this, you've probably already done so, but the command to download the Mininet source code is: diff --git a/LICENSE b/LICENSE index 73a2f67cb..b5d064b19 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Mininet 2.3.0a1 License +Mininet 2.3.0b1 License Copyright (c) 2013-2020 Open Networking Foundation Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of diff --git a/README.md b/README.md index df86072ee..7341c1b8e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Mininet: Rapid Prototyping for Software Defined Networks ======================================================== *The best way to emulate almost any network on your laptop!* -Mininet 2.3.0a1 +Mininet 2.3.0b1 [![Build Status][1]](https://github.com/mininet/mininet/actions) @@ -74,12 +74,12 @@ This is primarily a performance improvement and bug fix release. - Python 3 support (Python 2 is still supported as well) -- Support for Ubuntu 20.04 +- Support for Ubuntu 20.04 LTS - More reliable testing and CI via github actions - Additional information for this release and previous releases - may be found in the release notes on docs.mininet.org + may be found in the release notes on http://docs.mininet.org. ### Installation @@ -92,7 +92,8 @@ information, including a Mininet walkthrough and an introduction to the Python API, is available on the [Mininet Web Site](http://mininet.org). There is also a wiki which you are encouraged to read and to -contribute to, particularly the Frequently Asked Questions (FAQ.) +contribute to, particularly the Frequently Asked Questions +(FAQ) at http://faq.mininet.org. ### Support diff --git a/mininet/net.py b/mininet/net.py index 8bca10e32..4b61c669c 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -109,7 +109,7 @@ from mininet.term import cleanUpScreens, makeTerms # Mininet version: should be consistent with README and LICENSE -VERSION = "2.3.0a1" +VERSION = "2.3.0b1" class Mininet( object ): "Network emulation with hosts spawned in network namespaces." From dffddc338f28c00f2270e4bf3aed417fc10129df Mon Sep 17 00:00:00 2001 From: lantz Date: Fri, 29 Jan 2021 22:39:19 -0800 Subject: [PATCH 30/51] Install python3 mn last in install-mininet-vm.sh (#1021) This means that 'mn' will run be default in python3. For python2, run sudo python2 `which mn` Also: - change mn execution line to /usr/bin/python (install seems to change it to python2 or python3) - don't install python-is-python3 package --- bin/mn | 2 +- util/vm/install-mininet-vm.sh | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/bin/mn b/bin/mn index 3c5a7ec40..46667ab38 100755 --- a/bin/mn +++ b/bin/mn @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python """ Mininet runner diff --git a/util/vm/install-mininet-vm.sh b/util/vm/install-mininet-vm.sh index 2ea176e46..c1c8403b2 100755 --- a/util/vm/install-mininet-vm.sh +++ b/util/vm/install-mininet-vm.sh @@ -36,11 +36,10 @@ fi # Install Mininet for Python2 and Python3 APT="sudo apt-get -y -qq" $APT install python3 -$APT install python-is-python3 || true $APT install python2 || $APT install python -python --version -time PYTHON=python3 mininet/util/install.sh +python --version || $APT install python-is-python3 time PYTHON=python2 mininet/util/install.sh -n +time PYTHON=python3 mininet/util/install.sh # Finalize VM time mininet/util/install.sh -tcd # Ignoring this since NOX classic is deprecated From ec2d93d48260122d7cdb7d57ea58e38ac0fa6f5d Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 30 Jan 2021 15:41:20 -0800 Subject: [PATCH 31/51] 2.3.0b2 (#1022) + text file updates --- INSTALL | 82 ++++++++++++++++++++++++++++++++++++++------------ LICENSE | 2 +- README.md | 22 ++++++++++---- mininet/net.py | 2 +- 4 files changed, 80 insertions(+), 28 deletions(-) diff --git a/INSTALL b/INSTALL index 9d7ce7b58..1ba227582 100644 --- a/INSTALL +++ b/INSTALL @@ -2,7 +2,7 @@ Mininet Installation/Configuration Notes ---------------------------------------- -Mininet 2.3.0b1 +Mininet 2.3.0b2 --- The supported installation methods for Mininet are 1) using a @@ -36,12 +36,17 @@ like to contribute an installation script, we would welcome it!) sudo apt-get install mininet - Note: this may install an older version of Mininet. If you would - like the latest version, consider a native install from source. + Note: this may install an older version of Mininet which may not + support Python 3. If you would like the latest version of Mininet, + consider installing from source as described in the next section. 3. Native installation from source -3.1. Native installation from source on Ubuntu 16.04+ + If you are running Ubuntu, Debian, or Fedora, you may be able to use + our handy `install.sh` script, which is in `util/`. Please read the + following sections first. + +3.1. Obtaining the Mininet source code If you're reading this, you've probably already done so, but the command to download the Mininet source code is: @@ -49,8 +54,9 @@ like to contribute an installation script, we would welcome it!) git clone git://github.com/mininet/mininet.git Note that the above git command will check out the latest and greatest - Mininet (which we recommend!) If you want to run the last tagged/released - version of Mininet, you can look at the release tags using + Mininet (which we recommend!) If you want to run the last + tagged/released version of Mininet, you can look at the release tags + using cd mininet git tag @@ -61,21 +67,38 @@ like to contribute an installation script, we would welcome it!) where is the release you want to check out. - If you are running Ubuntu, Debian, or Fedora, you may be able to use - our handy `install.sh` script, which is in `util/`. - - *WARNING: USE AT YOUR OWN RISK!* +3.1.1 *CAUTION: USE AT YOUR OWN RISK!* - `install.sh` is a bit intrusive and may possibly damage your OS + `install.sh` can be a bit intrusive and may possibly damage your OS and/or home directory, by creating/modifying several directories such as `mininet`, `openflow`, `oftest`, `pox`, etc.. We recommend - trying it in a VM before trying it on a system you use from day to day. + trying it in a VM before trying it on a system you use from day to + day. Although we hope it won't do anything completely terrible, you may want to look at the script before you run it, and you should make sure your system and home directory are backed up just in case! - To install Mininet itself, the OpenFlow reference implementation, and + You can change the directory where the dependencies are installed + using the -s flag. + + util/install.sh -s ... + +3.1.2 Running `install.sh` + + Installing a "minimal" version of Mininet with Open vSwitch should + be reasonably non-perturbing since it should not create directories + for other tools: + + util/install.sh -nv + + Note this will not install a controller, so you will have to either + install your own controller, or use a switch such OVSBridge that does + not require a controller: + + sudo mn --switch ovsbr --test pingall + + To install Mininet itself, the OpenFlow reference controller, and Open vSwitch, you may use: util/install.sh -fnv @@ -85,6 +108,27 @@ like to contribute an installation script, we would welcome it!) sudo mn --test pingall +3.1.3 Python 3 and Python 2 support + + Mininet supports Python 3 and Python 2. By default, `install.sh` + will use whatever `python` is on your system. To specify a + specific version of Pythonm, you can set the PYTHON environment + variable: + + PYTHON=python3 util/install.sh -fnv + + You can install Mininet for both Python 3 and Python 2: + + PYTHON=python2 util/install.sh -fnv + PYTHON=python3 util/install.sh -n + + Whichever version was installed last will be the default for `mn`. + As long as Mininet is installed for the appropriate version of + Python, you can run it using that versinon of Python: + + python3 `which mn` + python2 `which mn` + To install ALL of the software which we use for OpenFlow tutorials, including POX, the OpenFlow WireShark dissector, the `oftest` framework, and other potentially useful software, you may use: @@ -93,13 +137,10 @@ like to contribute an installation script, we would welcome it!) This takes about 4 minutes on our test system. - You can change the directory where the dependencies are installed using - the -s flag. - - util/install.sh -s -a - 3.2. Native installation from source on Fedora 18+. + *This may be out of date.* + As root execute the following operations: * install git @@ -152,7 +193,8 @@ like to contribute an installation script, we would welcome it!) Although we don't support other Linux distributions directly, it should be possible to install and run Mininet with some degree of - manual effort. + manual effort. People have even gotten `mn --switch user` to run + in a ChromeOS container. In general, you must have: @@ -171,6 +213,6 @@ like to contribute an installation script, we would welcome it!) Good luck! -Mininet Team +Mininet Developers --- diff --git a/LICENSE b/LICENSE index b5d064b19..5aaad0c02 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Mininet 2.3.0b1 License +Mininet 2.3.0b2 License Copyright (c) 2013-2020 Open Networking Foundation Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of diff --git a/README.md b/README.md index 7341c1b8e..56a93406f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Mininet: Rapid Prototyping for Software Defined Networks ======================================================== *The best way to emulate almost any network on your laptop!* -Mininet 2.3.0b1 +Mininet 2.3.0b2 [![Build Status][1]](https://github.com/mininet/mininet/actions) @@ -68,17 +68,27 @@ Mininet includes: `mn -c` -### New features in this release +### Python 3 Support -This is primarily a performance improvement and bug fix release. +- Mininet 2.3.0b2 supports Python 3 and Python 2. -- Python 3 support (Python 2 is still supported as well) +- You can install both the Python 3 and Python 2 versions of +Mininet side by side, but the most recent installation will +determine which Python version is used by default by `mn`. -- Support for Ubuntu 20.04 LTS +- You can run `mn` directly with Python 2 or Python 3, + as long as the appropriate version of Mininet is installed, + e.g. + + $ sudo python2 `which mn` + +### Other Enhancements and Information + +- Support for Ubuntu 20.04 LTS (and 18.04 and 16.04) - More reliable testing and CI via github actions -- Additional information for this release and previous releases +- Additional information about this release and previous releases may be found in the release notes on http://docs.mininet.org. ### Installation diff --git a/mininet/net.py b/mininet/net.py index 4b61c669c..e8c7f4cdf 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -109,7 +109,7 @@ from mininet.term import cleanUpScreens, makeTerms # Mininet version: should be consistent with README and LICENSE -VERSION = "2.3.0b1" +VERSION = "2.3.0b2" class Mininet( object ): "Network emulation with hosts spawned in network namespaces." From 904796436dd632e4e93907d616f4928e610a0999 Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 30 Jan 2021 16:38:36 -0800 Subject: [PATCH 32/51] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 56a93406f..ffc1adabe 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Mininet includes: ### Python 3 Support -- Mininet 2.3.0b2 supports Python 3 and Python 2. +- Mininet 2.3.0b2 supports Python 3 and Python 2! - You can install both the Python 3 and Python 2 versions of Mininet side by side, but the most recent installation will @@ -82,6 +82,9 @@ determine which Python version is used by default by `mn`. $ sudo python2 `which mn` +- More information regarding Python 3 and Python 2 support + may be found in the release notes on http://docs.mininet.org. + ### Other Enhancements and Information - Support for Ubuntu 20.04 LTS (and 18.04 and 16.04) From 9b69c99f4e4116d4272dffc4b3acd3f20f1930d6 Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 30 Jan 2021 16:40:40 -0800 Subject: [PATCH 33/51] Update INSTALL --- INSTALL | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index 1ba227582..f6b077151 100644 --- a/INSTALL +++ b/INSTALL @@ -211,7 +211,10 @@ like to contribute an installation script, we would welcome it!) support other Linux distributions. -Good luck! +As always, please feel free to submit issues or pull requests for +installation-related features. + +Good luck, and have fun! Mininet Developers From a882d68a5f3bb3a07999afed49fa06ac8f92267d Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 30 Jan 2021 16:42:03 -0800 Subject: [PATCH 34/51] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ffc1adabe..4aafd4f8e 100644 --- a/README.md +++ b/README.md @@ -129,8 +129,8 @@ hard work that Mininet continues to grow and improve. ### Enjoy Mininet -Best wishes, and we look forward to seeing what you can do with -Mininet to change the networking world! +Have fun! We look forward to seeing what you will do with Mininet +to change the networking world. Bob Lantz on behalf of the Mininet Contributors From f0c726a42f3543e74779ab0c1bf57381f0c3399a Mon Sep 17 00:00:00 2001 From: lantz Date: Fri, 5 Feb 2021 07:42:50 -0800 Subject: [PATCH 35/51] Use /usr/bin/env python for virtualenv (#1025) This helps with virtualenv although it can open up another security hole if you end up using an unexpected python interpreter. Overall it seems to make sense to err on the side of usability but it's good to be aware of security. However, for the remaining utility scripts that require python 2, we explicitly note this with #!/usr/bin/python2. --- bin/mn | 2 +- examples/baresshd.py | 2 +- examples/bind.py | 2 +- examples/cluster.py | 2 +- examples/clustercli.py | 2 +- examples/clusterdemo.py | 2 +- examples/clusterperf.py | 2 +- examples/consoles.py | 2 +- examples/controllers.py | 2 +- examples/controllers2.py | 2 +- examples/controlnet.py | 2 +- examples/cpu.py | 2 +- examples/emptynet.py | 2 +- examples/hwintf.py | 2 +- examples/intfoptions.py | 2 +- examples/limit.py | 2 +- examples/linearbandwidth.py | 2 +- examples/linuxrouter.py | 2 +- examples/miniedit.py | 2 +- examples/mobility.py | 2 +- examples/multilink.py | 2 +- examples/multiping.py | 2 +- examples/multipoll.py | 2 +- examples/multitest.py | 2 +- examples/nat.py | 2 +- examples/natnet.py | 2 +- examples/numberedports.py | 2 +- examples/popen.py | 2 +- examples/popenpoll.py | 2 +- examples/scratchnet.py | 2 +- examples/scratchnetuser.py | 2 +- examples/simpleperf.py | 2 +- examples/sshd.py | 2 +- examples/tree1024.py | 2 +- examples/treeping64.py | 2 +- util/doxify.py | 6 +----- util/unpep8 | 30 +++++++++++++++--------------- util/versioncheck.py | 2 +- util/vm/build.py | 2 +- 39 files changed, 53 insertions(+), 57 deletions(-) diff --git a/bin/mn b/bin/mn index 46667ab38..3c5a7ec40 100755 --- a/bin/mn +++ b/bin/mn @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Mininet runner diff --git a/examples/baresshd.py b/examples/baresshd.py index 39b683a7e..c04db0e2b 100755 --- a/examples/baresshd.py +++ b/examples/baresshd.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python "This example doesn't use OpenFlow, but attempts to run sshd in a namespace." diff --git a/examples/bind.py b/examples/bind.py index 9a7272a31..d2ee46fff 100755 --- a/examples/bind.py +++ b/examples/bind.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ bind.py: Bind mount example diff --git a/examples/cluster.py b/examples/cluster.py index 78cfbc004..5ce44e736 100755 --- a/examples/cluster.py +++ b/examples/cluster.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ cluster.py: prototyping/experimentation for distributed Mininet, diff --git a/examples/clustercli.py b/examples/clustercli.py index 75cd3178b..34f0956e2 100644 --- a/examples/clustercli.py +++ b/examples/clustercli.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python "CLI for Mininet Cluster Edition prototype demo" diff --git a/examples/clusterdemo.py b/examples/clusterdemo.py index b117ba464..0e97cc384 100755 --- a/examples/clusterdemo.py +++ b/examples/clusterdemo.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python "clusterdemo.py: demo of Mininet Cluster Edition prototype" diff --git a/examples/clusterperf.py b/examples/clusterperf.py index ffa48a80f..f18f072dd 100755 --- a/examples/clusterperf.py +++ b/examples/clusterperf.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python "clusterperf.py compare the maximum throughput between SSH and GRE tunnels" diff --git a/examples/consoles.py b/examples/consoles.py index 6a8aca148..a9af8fb5f 100755 --- a/examples/consoles.py +++ b/examples/consoles.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ consoles.py: bring up a bunch of miniature consoles on a virtual network diff --git a/examples/controllers.py b/examples/controllers.py index dad8e5f84..4cd88669c 100755 --- a/examples/controllers.py +++ b/examples/controllers.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Create a network where different switches are connected to diff --git a/examples/controllers2.py b/examples/controllers2.py index ceefc3201..f20bf3c2e 100755 --- a/examples/controllers2.py +++ b/examples/controllers2.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ This example creates a multi-controller network from semi-scratch by diff --git a/examples/controlnet.py b/examples/controlnet.py index eb7aaa512..bba4f004c 100755 --- a/examples/controlnet.py +++ b/examples/controlnet.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ controlnet.py: Mininet with a custom control network diff --git a/examples/cpu.py b/examples/cpu.py index a5dddeda6..a9835178a 100755 --- a/examples/cpu.py +++ b/examples/cpu.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ cpu.py: test iperf bandwidth for varying cpu limits diff --git a/examples/emptynet.py b/examples/emptynet.py index 474886c50..877e07a23 100755 --- a/examples/emptynet.py +++ b/examples/emptynet.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ This example shows how to create an empty Mininet object diff --git a/examples/hwintf.py b/examples/hwintf.py index 990beb0c0..31b865674 100755 --- a/examples/hwintf.py +++ b/examples/hwintf.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ This example shows how to add an interface (for example a real diff --git a/examples/intfoptions.py b/examples/intfoptions.py index f7373ed35..3df590f35 100755 --- a/examples/intfoptions.py +++ b/examples/intfoptions.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python ''' example of using various TCIntf options. diff --git a/examples/limit.py b/examples/limit.py index a75bb50ef..5063acc38 100755 --- a/examples/limit.py +++ b/examples/limit.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ limit.py: example of using link and CPU limits diff --git a/examples/linearbandwidth.py b/examples/linearbandwidth.py index e66f36b31..6802e7e97 100755 --- a/examples/linearbandwidth.py +++ b/examples/linearbandwidth.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Test bandwidth (using iperf) on linear networks of varying size, diff --git a/examples/linuxrouter.py b/examples/linuxrouter.py index 861c31968..6f1afa1b1 100755 --- a/examples/linuxrouter.py +++ b/examples/linuxrouter.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ linuxrouter.py: Example network with Linux IP router diff --git a/examples/miniedit.py b/examples/miniedit.py index 24d1ad3ad..1263a7484 100755 --- a/examples/miniedit.py +++ b/examples/miniedit.py @@ -1704,7 +1704,7 @@ def exportScript( self ): # 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") diff --git a/examples/mobility.py b/examples/mobility.py index 05a8869a1..ea8f99ead 100755 --- a/examples/mobility.py +++ b/examples/mobility.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Simple example of Mobility with Mininet diff --git a/examples/multilink.py b/examples/multilink.py index e95730a86..6f7a5fbbf 100755 --- a/examples/multilink.py +++ b/examples/multilink.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ This is a simple example that demonstrates multiple links diff --git a/examples/multiping.py b/examples/multiping.py index 7d723a419..3700f9e3c 100755 --- a/examples/multiping.py +++ b/examples/multiping.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ multiping.py: monitor multiple sets of hosts using ping diff --git a/examples/multipoll.py b/examples/multipoll.py index 13ceaa7fb..fcf63ed7b 100755 --- a/examples/multipoll.py +++ b/examples/multipoll.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Simple example of sending output to multiple files and diff --git a/examples/multitest.py b/examples/multitest.py index b208ddf73..294a31318 100755 --- a/examples/multitest.py +++ b/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. diff --git a/examples/nat.py b/examples/nat.py index bb7e8c495..49506b19a 100755 --- a/examples/nat.py +++ b/examples/nat.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Example to create a Mininet topology and connect it to the internet via NAT diff --git a/examples/natnet.py b/examples/natnet.py index 638a43791..12a169894 100755 --- a/examples/natnet.py +++ b/examples/natnet.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ natnet.py: Example network with NATs diff --git a/examples/numberedports.py b/examples/numberedports.py index 0bd1d3e26..dd0259e87 100755 --- a/examples/numberedports.py +++ b/examples/numberedports.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Create a network with 5 hosts, numbered 1-4 and 9. diff --git a/examples/popen.py b/examples/popen.py index 94e7b4574..b7104081c 100755 --- a/examples/popen.py +++ b/examples/popen.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ This example monitors a number of hosts using host.popen() and diff --git a/examples/popenpoll.py b/examples/popenpoll.py index 7f56ef0d4..3b5312e26 100755 --- a/examples/popenpoll.py +++ b/examples/popenpoll.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python "Monitor multiple hosts using popen()/pmonitor()" diff --git a/examples/scratchnet.py b/examples/scratchnet.py index a8d536d06..ad43a9892 100755 --- a/examples/scratchnet.py +++ b/examples/scratchnet.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Build a simple network from scratch, using mininet primitives. diff --git a/examples/scratchnetuser.py b/examples/scratchnetuser.py index 2c50f9d7e..99f5bf029 100755 --- a/examples/scratchnetuser.py +++ b/examples/scratchnetuser.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Build a simple network from scratch, using mininet primitives. diff --git a/examples/simpleperf.py b/examples/simpleperf.py index 91e7e0155..b29d88aa1 100755 --- a/examples/simpleperf.py +++ b/examples/simpleperf.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Simple example of setting network and CPU parameters diff --git a/examples/sshd.py b/examples/sshd.py index ac62fb526..80fe0f814 100755 --- a/examples/sshd.py +++ b/examples/sshd.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Create a network and start sshd(8) on each host. diff --git a/examples/tree1024.py b/examples/tree1024.py index e19abae74..35a796c83 100755 --- a/examples/tree1024.py +++ b/examples/tree1024.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Create a 1024-host network, and run the CLI on it. diff --git a/examples/treeping64.py b/examples/treeping64.py index 1c044b105..3f8667957 100755 --- a/examples/treeping64.py +++ b/examples/treeping64.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python "Create a 64-node tree network, and test connectivity using ping." diff --git a/util/doxify.py b/util/doxify.py index c6a78ff54..7b9d4c1d4 100755 --- a/util/doxify.py +++ b/util/doxify.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python2 """ Convert simple documentation to epydoc/pydoctor-compatible markup @@ -83,7 +83,3 @@ def fixLines( lines, fid ): infile.close() os.close( outfid ) call( [ 'doxypy', outname ] ) - - - - diff --git a/util/unpep8 b/util/unpep8 index 17f5dd53a..c6dad6efe 100755 --- a/util/unpep8 +++ b/util/unpep8 @@ -1,7 +1,7 @@ -#!/usr/bin/python +#!/usr/bin/python2 """ -Translate from PEP8 Python style to Mininet (i.e. Arista-like) +Translate from PEP8 Python style to Mininet (i.e. Arista-like) Python style usage: unpep8 < old.py > new.py @@ -51,7 +51,7 @@ def fixUnderscoreTriplet( match ): def reinstateCapWords( text ): underscoreTriplet = re.compile( r'[A-Za-z0-9]_[A-Za-z0-9]' ) return underscoreTriplet.sub( fixUnderscoreTriplet, text ) - + def replaceTripleApostrophes( text ): "Replace triple apostrophes with triple quotes." return text.replace( "'''", '"""') @@ -60,7 +60,7 @@ def simplifyTripleQuotes( text ): "Fix single-line doc strings." r = re.compile( r'"""([^\"\n]+)"""' ) return r.sub( r'"\1"', text ) - + def insertExtraSpaces( text ): "Insert extra spaces inside of parentheses and brackets/curly braces." lparen = re.compile( r'\((?![\s\)])' ) @@ -76,9 +76,9 @@ def insertExtraSpaces( text ): lcurly = re.compile( r'\{(?![\s\}])' ) text = lcurly.sub( r'{ ', text ) rcurly = re.compile( r'([^\s\{])(?=\})' ) - text = rcurly.sub( r'\1 ', text) + text = rcurly.sub( r'\1 ', text) return text - + def fixDoxygen( text ): """Translate @param foo to foo:, @return bar to returns: bar, and @author me to author: me""" @@ -96,11 +96,11 @@ def removeCommentFirstBlankLine( text ): "Remove annoying blank lines after first line in comments." line = re.compile( r'("""[^\n]*\n)\s*\n', re.MULTILINE ) return line.sub( r'\1', text ) - + def fixArgs( match, kwarg = re.compile( r'(\w+) = ' ) ): "Replace foo = bar with foo=bar." return kwarg.sub( r'\1=', match.group() ) - + def fixKeywords( text ): "Change keyword argumentsfrom foo = bar to foo=bar." args = re.compile( r'\(([^\)]+)\)', re.MULTILINE ) @@ -115,7 +115,7 @@ def fixKeywords( text ): def lineIter( text ): "Simple iterator over lines in text." for line in text.splitlines(): yield line - + def stringIter( strList ): "Yield strings in strList." for s in strList: yield s @@ -134,7 +134,7 @@ def restoreRegex( regex, old, new ): # This is a cheap hack, and it may not work 100%, since # it doesn't handle multiline strings. # However, it should be mostly harmless... - + def restoreStrings( oldText, newText ): "Restore strings from oldText into newText, returning result." oldLines, newLines = lineIter( oldText ), lineIter( newText ) @@ -149,13 +149,13 @@ def restoreStrings( oldText, newText ): newLine = restoreRegex( tickStrings, oldLine, newLine ) result += newLine + '\n' return result - + # This might be slightly controversial, since it uses # three spaces to line up multiline comments. However, # I much prefer it. Limitations: if you have deeper # indents in comments, they will be eliminated. ;-( -def fixComment( match, +def fixComment( match, indentExp=re.compile( r'\n([ ]*)(?=[^/s])', re.MULTILINE ), trailingQuotes=re.compile( r'\s+"""' ) ): "Re-indent comment, and join trailing quotes." @@ -166,17 +166,17 @@ def fixComment( match, if len( originalIndent ) is not 0: indent += ' ' comment = indentExp.sub( indent, comment ) return originalIndent + trailingQuotes.sub( '"""', comment ) - + def fixCommentIndents( text ): "Fix multiline comment indentation." comments = re.compile( r'^([ ]*)("""[^"]*""")$', re.MULTILINE ) return comments.sub( fixComment, text ) - + def removeBogusLinefeeds( text ): "Remove extra linefeeds at the end of single-line comments." bogusLfs = re.compile( r'"([^"\n]*)\n"', re.MULTILINE ) return bogusLfs.sub( '"\1"', text) - + def convertFromPep8( program ): oldProgram = program # Program text transforms diff --git a/util/versioncheck.py b/util/versioncheck.py index 0a4af2ba1..a9d6cfc22 100755 --- a/util/versioncheck.py +++ b/util/versioncheck.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from subprocess import check_output as co from sys import exit, version_info diff --git a/util/vm/build.py b/util/vm/build.py index de566ca9b..a9f28602e 100755 --- a/util/vm/build.py +++ b/util/vm/build.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.7 +#!/usr/bin/python2 """ build.py: build a Mininet VM From 06dae1adc1221292b4e8cc412c744feb7916f5d5 Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 6 Feb 2021 15:55:40 -0800 Subject: [PATCH 36/51] fix bootAndRun() (#1024) * rc.local: /usr/bin/bash -> /bin/bash bash is (and should be) located in /bin this may have caused ubuntu 18.04 to not execute /etc/rc.local and regenerate ssh keys * fix bootAndRun() --- util/install.sh | 2 +- util/vm/build.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/util/install.sh b/util/install.sh index a6fd16630..7e8783ebf 100755 --- a/util/install.sh +++ b/util/install.sh @@ -791,7 +791,7 @@ function vm_clean { echo 'Removing SSH keys from /etc/ssh/' sudo rm -f /etc/ssh/*key* if [ ! -e /etc/rc.local ]; then - echo '#!/usr/bin/bash' | sudo tee /etc/rc.local + echo '#!/bin/bash' | sudo tee /etc/rc.local sudo chmod +x /etc/rc.local fi if ! grep mininet /etc/rc.local >& /dev/null; then diff --git a/util/vm/build.py b/util/vm/build.py index a9f28602e..b0e056a1f 100755 --- a/util/vm/build.py +++ b/util/vm/build.py @@ -954,7 +954,8 @@ def bootAndRun( image, prompt=Prompt, memory=1024, cpuCores=1, outputFile=None, log( '* Creating COW disk', cow ) run( 'qemu-img create -f qcow2 -b %s %s' % ( image, cow ) ) log( '* Extracting kernel and initrd' ) - kernel, initrd, part = extractKernel( image, flavor=basename, imageDir=tmpdir ) + kernel, initrd, partnum = extractKernel( + image, flavor=basename, imageDir=tmpdir ) if LogToConsole: logfile = stdout else: @@ -962,7 +963,7 @@ def bootAndRun( image, prompt=Prompt, memory=1024, cpuCores=1, outputFile=None, suffix='.testlog', delete=False ) log( '* Logging VM output to', logfile.name ) vm = boot( cow=cow, kernel=kernel, initrd=initrd, logfile=logfile, - memory=memory, cpuCores=cpuCores, part=part ) + memory=memory, cpuCores=cpuCores, partnum=partnum ) login( vm ) log( '* Waiting for prompt after login' ) vm.expect( prompt ) From c7de350a4e3311ce9d76a83114bbf567a09d6c4a Mon Sep 17 00:00:00 2001 From: lantz Date: Sat, 6 Feb 2021 19:42:15 -0800 Subject: [PATCH 37/51] update make doc for current doxygen/doxypy (#1027) --- doc/doxygen.cfg | 2756 +++++++++++++++++++++++++++++++++-------------- util/install.sh | 3 +- 2 files changed, 1933 insertions(+), 826 deletions(-) diff --git a/doc/doxygen.cfg b/doc/doxygen.cfg index a92bb155b..9384d4dc2 100644 --- a/doc/doxygen.cfg +++ b/doc/doxygen.cfg @@ -1,1417 +1,2523 @@ -# Doxyfile 1.5.6 +# Doxyfile 1.8.17 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project +# doxygen (www.doxygen.org) for a project. # -# All text after a hash (#) is considered a comment and will be ignored +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. # The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. PROJECT_NAME = "Mininet Python API Reference Manual" -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. -PROJECT_NUMBER = +PROJECT_BRIEF = -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. OUTPUT_DIRECTORY = doc -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. CREATE_SUBDIRS = NO -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, -# and Ukrainian. +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. +# The default value is: YES. REPEAT_BRIEF = YES -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief # description. +# The default value is: NO. ALWAYS_DETAILED_SEC = NO -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. +# The default value is: NO. INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. FULL_PATH_NAMES = YES -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. JAVADOC_AUTOBRIEF = NO -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. -QT_AUTOBRIEF = NO +JAVADOC_BANNER = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. -MULTILINE_CPP_IS_BRIEF = NO +QT_AUTOBRIEF = NO -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. -DETAILS_AT_TOP = NO +MULTILINE_CPP_IS_BRIEF = NO -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. SEPARATE_MEMBER_PAGES = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. +# The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. +# The default value is: NO. CPP_CLI_SUPPORT = NO -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. SIP_SUPPORT = NO -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. IDL_PROPERTY_SUPPORT = YES -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. +# The default value is: NO. DISTRIBUTE_GROUP_DOC = NO -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. SUBGROUPING = YES -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. TYPEDEF_HIDES_STRUCT = NO +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. EXTRACT_ALL = NO -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. EXTRACT_PRIVATE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. EXTRACT_LOCAL_METHODS = NO -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. EXTRACT_ANON_NSPACES = NO -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the # documentation. +# The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. HIDE_IN_BODY_DOCS = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. CASE_SENSE_NAMES = YES -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. HIDE_SCOPE_NAMES = NO -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. SHOW_INCLUDE_FILES = YES -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. SORT_MEMBER_DOCS = YES -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. SORT_BRIEF_DOCS = NO -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. SORT_GROUP_NAMES = NO -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. SORT_BY_SCOPE_NAME = NO -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. GENERATE_DEPRECATEDLIST= YES -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. +# The default value is: YES. SHOW_USED_FILES = YES -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. SHOW_FILES = YES -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. SHOW_NAMESPACES = YES -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. -FILE_VERSION_FILTER = +CITE_BIB_FILES = #--------------------------------------------------------------------------- -# configuration options related to warning and progress messages +# Configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. QUIET = NO -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. WARN_IF_UNDOCUMENTED = YES -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. WARN_IF_DOC_ERROR = YES -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. WARN_NO_PARAMDOC = NO -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- -# configuration options related to the input files +# Configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. INPUT = mininet -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. INPUT_ENCODING = UTF-8 -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f, *.for, *.tcl, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.py -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. RECURSIVE = NO -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. -EXCLUDE = +EXCLUDE = -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded # from the input. +# The default value is: NO. EXCLUDE_SYMLINKS = NO -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). -EXAMPLE_PATH = +EXAMPLE_PATH = -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. EXAMPLE_RECURSIVE = NO -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). -IMAGE_PATH = +IMAGE_PATH = -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. INPUT_FILTER = util/doxify.py -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. FILTER_SOURCE_FILES = YES +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + #--------------------------------------------------------------------------- -# configuration options related to source browsing +# Configuration options related to source browsing #--------------------------------------------------------------------------- -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. SOURCE_BROWSER = NO -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. STRIP_CODE_COMMENTS = YES -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. REFERENCED_BY_RELATION = NO -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. REFERENCES_RELATION = NO -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. REFERENCES_LINK_SOURCE = YES -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. VERBATIM_HEADERS = YES +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files +# were built. This is equivalent to specifying the "-p" option to a clang tool, +# such as clang-check. These options will then be passed to the parser. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index +# Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. ALPHABETICAL_INDEX = NO -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- -# configuration options related to the HTML output +# Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a # standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = +HTML_DYNAMIC_SECTIONS = NO -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. -HTML_ALIGN_MEMBERS = YES +GENERATE_DOCSET = NO -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. -GENERATE_HTMLHELP = NO +DOCSET_FEEDNAME = "Doxygen generated docs" -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. -GENERATE_DOCSET = NO +DOCSET_BUNDLE_ID = org.doxygen.Project -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_PUBLISHER_ID = org.doxygen.Publisher -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_NAME = Publisher -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +GENERATE_HTMLHELP = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be # written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to FRAME, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. Other possible values -# for this tag are: HIERARCHIES, which will generate the Groups, Directories, -# and Class Hiererachy pages using a tree view instead of an ordered list; -# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which -# disables this behavior completely. For backwards compatibility with previous -# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE -# respectively. +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NONE -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /