From 8b5f676563c47ee820a4e76a4ee164a90d1517ca Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 27 Nov 2018 20:20:59 -0500 Subject: [PATCH 001/384] tests: Exclude topotests from consideration When running make check, exclude the topotests directory from considertion. Signed-off-by: Donald Sharp --- tests/pytest.ini | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/pytest.ini diff --git a/tests/pytest.ini b/tests/pytest.ini new file mode 100644 index 0000000000..3c436ed5dd --- /dev/null +++ b/tests/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +norecursedirs = topotests From 59d80fffc2b50a488951b6a5d08607c7518a328b Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 17 Nov 2016 03:16:21 -0800 Subject: [PATCH 002/384] Initial commit with first OSPFv6 Topology Test --- tests/topotests/README.md | 33 ++ tests/topotests/ospf6-test1/ospf6-test1.py | 331 ++++++++++++++++++ tests/topotests/ospf6-test1/r1/ospf6d.conf | 27 ++ .../ospf6-test1/r1/show_ipv6_route.ref | 9 + tests/topotests/ospf6-test1/r1/zebra.conf | 17 + tests/topotests/ospf6-test1/r2/ospf6d.conf | 27 ++ .../ospf6-test1/r2/show_ipv6_route.ref | 10 + tests/topotests/ospf6-test1/r2/zebra.conf | 17 + tests/topotests/ospf6-test1/r3/ospf6d.conf | 31 ++ .../ospf6-test1/r3/show_ipv6_route.ref | 10 + tests/topotests/ospf6-test1/r3/zebra.conf | 20 ++ tests/topotests/ospf6-test1/r4/ospf6d.conf | 27 ++ .../ospf6-test1/r4/show_ipv6_route.ref | 9 + tests/topotests/ospf6-test1/r4/zebra.conf | 17 + 14 files changed, 585 insertions(+) create mode 100644 tests/topotests/README.md create mode 100755 tests/topotests/ospf6-test1/ospf6-test1.py create mode 100644 tests/topotests/ospf6-test1/r1/ospf6d.conf create mode 100644 tests/topotests/ospf6-test1/r1/show_ipv6_route.ref create mode 100644 tests/topotests/ospf6-test1/r1/zebra.conf create mode 100644 tests/topotests/ospf6-test1/r2/ospf6d.conf create mode 100644 tests/topotests/ospf6-test1/r2/show_ipv6_route.ref create mode 100644 tests/topotests/ospf6-test1/r2/zebra.conf create mode 100644 tests/topotests/ospf6-test1/r3/ospf6d.conf create mode 100644 tests/topotests/ospf6-test1/r3/show_ipv6_route.ref create mode 100644 tests/topotests/ospf6-test1/r3/zebra.conf create mode 100644 tests/topotests/ospf6-test1/r4/ospf6d.conf create mode 100644 tests/topotests/ospf6-test1/r4/show_ipv6_route.ref create mode 100644 tests/topotests/ospf6-test1/r4/zebra.conf diff --git a/tests/topotests/README.md b/tests/topotests/README.md new file mode 100644 index 0000000000..75807c1cee --- /dev/null +++ b/tests/topotests/README.md @@ -0,0 +1,33 @@ +# Quagga Topology Tests with Mininet + +## Installation of Mininet for running tests +Only tested with Ubuntu 16.04 + +Instructions are the same for all setups (ie ExaBGP is only used for BGP tests) + +### Installing Mininet Infrastructure: + +1. apt-get install mininet +2. apt-get install python-pip +3. apt-get install iproute +4. pip install ipaddr +5. pip install exabgp +6. useradd -d /var/run/exabgp/ -s /bin/false exabgp + +### Quagga Installation +Quagga needs to be installed separatly. It is assume to be configured like the standard Ubuntu Packages: + +- Binaries in /usr/lib/quagga +- Running under user quagga, group quagga +- vtygroup: quaggavty +- config directory: /etc/quagga + +No Quagga config needs to be done and no Quagga daemons should be run ahead +of the test. They are all started as part of the test + +## Executing Tests + +Go to test directory and execute python script. +Test will run all on it's own and return non-zero exit code if it fails. + +For the simulated topology, see the description in the python file diff --git a/tests/topotests/ospf6-test1/ospf6-test1.py b/tests/topotests/ospf6-test1/ospf6-test1.py new file mode 100755 index 0000000000..a60965847c --- /dev/null +++ b/tests/topotests/ospf6-test1/ospf6-test1.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python + +# +# ospf6-test1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2016 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +ospf6-test1.py: + + -----\ + SW1 - Stub Net 1 SW2 - Stub Net 2 \ + fc00:1:1:1::/64 fc00:2:2:2::/64 \ +\___________________/ \___________________/ | + | | | + | | | + | ::1 | ::2 | ++---------+---------+ +---------+---------+ | +| R1 | | R2 | | +| Quagga | | Quagga | | +| Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | | ++---------+---------+ +---------+---------+ | + | ::1 | ::2 \ + \______ ___________/ OSPFv3 + \ / Area 0.0.0.0 + \ / / + ~~~~~~~~~~~~~~~~~~ | + ~~ SW5 ~~ | + ~~ Switch ~~ | + ~~ fc00:A:A:A::/64 ~~ | + ~~~~~~~~~~~~~~~~~~ | + | /---- | + | ::3 | SW3 - Stub Net 3 | + +---------+---------+ /-+ fc00:3:3:3::/64 | + | R3 | / | / + | Quagga +--/ \---- / + | Rtr-ID: 10.0.0.3 | ::3 ___________/ + +---------+---------+ \ + | ::3 \ + | \ + ~~~~~~~~~~~~~~~~~~ | + ~~ SW6 ~~ | + ~~ Switch ~~ | + ~~ fc00:B:B:B::/64 ~~ \ + ~~~~~~~~~~~~~~~~~~ OSPFv3 + | Area 0.0.0.1 + | ::4 / + +---------+---------+ /---- | + | R4 | | SW4 - Stub Net 4 | + | Quagga +------+ fc00:4:4:4::/64 | + | Rtr-ID: 10.0.0.4 | ::4 | / + +-------------------+ \---- / + -----/ +""" + +import os +import re +import StringIO +import sys +import difflib + +from pprint import pprint + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI + +from functools import partial +from time import sleep + +def int2dpid(dpid): + "Converting Integer to DPID" + + try: + dpid = hex(dpid)[2:] + dpid = '0'*(16-len(dpid))+dpid + return dpid + except IndexError: + raise Exception('Unable to derive default datapath ID - ' + 'please either specify a dpid or use a ' + 'canonical switch name such as s23.') +class LinuxRouter(Node): + "A Node with IPv4/IPv6 forwarding enabled." + + def config(self, **params): + super(LinuxRouter, self).config(**params) + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + def terminate(self): + """ + Terminate generic LinuxRouter Mininet instance + """ + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(LinuxRouter, self).terminate() + +class QuaggaRouter(Node): + "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" + + def config(self, **params): + super(QuaggaRouter, self).config(**params) + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + self.cmd('chown quagga:quaggavty /etc/quagga') + self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, + 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} + def terminate(self): + # Delete Running Quagga Daemons + rundaemons = self.cmd('ls -1 /var/run/quagga/*.pid') + for d in StringIO.StringIO(rundaemons): + self.cmd('kill -7 `cat %s`' % d.rstrip()) + self.waitOutput() + # Disable forwarding + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(QuaggaRouter, self).terminate() + def removeIPs(self): + for interface in self.intfNames(): + self.cmd('ip address flush', interface) + def loadConf(self, daemon, source=None): + # print "Daemons before:", self.daemons + if daemon in self.daemons.keys(): + self.daemons[daemon] = 1 + if source is None: + self.cmd('touch /etc/quagga/%s.conf' % daemon) + self.waitOutput() + else: + self.cmd('cp %s /etc/quagga/%s.conf' % (source, daemon)) + self.waitOutput() + self.cmd('chmod 640 /etc/quagga/%s.conf' % daemon) + self.waitOutput() + self.cmd('chown quagga:quagga /etc/quagga/%s.conf' % daemon) + self.waitOutput() + else: + print("No daemon %s known" % daemon) + # print "Daemons after:", self.daemons + def startQuagga(self): + # Disable integrated-vtysh-config + self.cmd('echo "no service integrated-vtysh-config" > /etc/quagga/vtysh.conf') + with open("/etc/quagga/vtysh.conf", "w") as vtyshfile: + vtyshfile.write('no service integrated-vtysh-config') + self.cmd('chown quagga:quaggavty /etc/quagga/vtysh.conf') + # Remove IP addresses from OS first - we have them in zebra.conf + self.removeIPs() + # Start Zebra first + if self.daemons['zebra'] == 1: + self.cmd('/usr/lib/quagga/zebra -d') + self.waitOutput() + print('%s: zebra started' % self) + sleep(1) + # Fix Link-Local Addresses + # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this + self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') + # Now start all the other daemons + for daemon in self.daemons: + if (self.daemons[daemon] == 1) and (daemon != 'zebra'): + self.cmd('/usr/lib/quagga/%s -d' % daemon) + self.waitOutput() + print('%s: %s started' % (self, daemon)) + + +class LegacySwitch(OVSSwitch): + "A Legacy Switch without OpenFlow" + + def __init__(self, name, **params): + OVSSwitch.__init__(self, name, failMode='standalone', **params) + self.switchIP = None + +class NetworkTopo(Topo): + "A Quagga Topology with direct peering router and IXP connection" + + def build(self, **_opts): + + quaggaPrivateDirs = ['/etc/quagga', + '/var/run/quagga', + '/var/log'] + # + # Define Switches first + # + switch = {} + for i in range(1, 7): + switch[i] = self.addSwitch('SW%s' % i, dpid=int2dpid(i), + cls=LegacySwitch) + + # + # Define Quagga Routers + # + router = {} + for i in range(1, 5): + router[i] = self.addNode('r%s' % i, cls=QuaggaRouter, + privateDirs=quaggaPrivateDirs) + + # + # Wire up the switches and routers + # + # Stub nets + for i in range(1, 5): + self.addLink(switch[i], router[i], intfName2='r%s-stubnet' % i) + # Switch 5 + self.addLink(switch[5], router[1], intfName2='r1-sw5') + self.addLink(switch[5], router[2], intfName2='r2-sw5') + self.addLink(switch[5], router[3], intfName2='r3-sw5') + # Switch 6 + self.addLink(switch[6], router[3], intfName2='r3-sw6') + self.addLink(switch[6], router[4], intfName2='r4-sw6') + + +def run(): + "ospf6-test1 Topology" + + thisDir = os.path.dirname(os.path.realpath(__file__)) + topo = NetworkTopo() + + net = Mininet(controller=None, topo=topo) + net.start() + + # Starting Routers + for i in range(1, 5): + net['r%s' % i].loadConf('zebra', 'r%s/zebra.conf' % i) + net['r%s' % i].loadConf('ospf6d', 'r%s/ospf6d.conf' % i) + net['r%s' % i].startQuagga() + + print('') + + # + # Stop here for all manual checks + # + #CLI(net) + + # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State) + print("Waiting for OSPFv3 neighbors to establish (to Full)") + timeout = 60 + while timeout > 0: + print("Timeout in %s: " % timeout), + sys.stdout.flush() + # Look for any node not yet converged + for i in range(1, 5): + notConverged = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh" 2> /dev/null | grep ^[0-9] | grep -v Full') + if notConverged: + print('Waiting for r%s' %i), + sys.stdout.flush() + break + if notConverged: + sleep(2) + timeout -= 2 + print('\r \r'), + else: + print('\rDone ') + print(notConverged) + break + else: + # Bail out with error if a router fails to converge + sys.stderr.write("Router r%s failed to converge\n" % i) + ospfStatus = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh"') + sys.stderr.write("Status:\n%s" % ospfStatus) + net.stop() + sys.exit(1) + print("OSPFv3 converged.") + + print("\nwaiting 15s for routes to populate") + sleep(10) + + # Verify OSPFv3 Routing Table + print("\nVerifing OSPFv3 Routing Table") + failures = 0 + for i in range(1, 5): + refTableFile = 'r%s/show_ipv6_route.ref' % i + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ipv6 route" 2> /dev/null | grep "^O"').rstrip() + # Mask out Link-Local mac address portion. They are random... + actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual) + # Drop timers on end of line (older Quagga Versions) + actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff=difflib.unified_diff(actual, expected) + diff=''.join(diff) + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed Routing Table Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + # + # Stop here for manual checks after tests are executed + # + # CLI(net) + + # End - Shutdown network + net.stop() + + # Set non-zero exit status in case of failures + if failures > 0: + sys.stderr.write("Verification failed\n") + sys.exit(1) + else: + print("Verification Successful") + +if __name__ == '__main__': + setLogLevel('info') + run() diff --git a/tests/topotests/ospf6-test1/r1/ospf6d.conf b/tests/topotests/ospf6-test1/r1/ospf6d.conf new file mode 100644 index 0000000000..8fc431fc4a --- /dev/null +++ b/tests/topotests/ospf6-test1/r1/ospf6d.conf @@ -0,0 +1,27 @@ +hostname r1 +log file /tmp/r1-ospf6d.log +! +debug ospf6 message all +debug ospf6 lsa unknown +debug ospf6 zebra +debug ospf6 interface +debug ospf6 neighbor +debug ospf6 route table +debug ospf6 flooding +! +interface r1-stubnet + ipv6 ospf6 network broadcast +! +interface r1-sw5 + ipv6 ospf6 network broadcast +! +router ospf6 + router-id 10.0.0.1 + log-adjacency-changes detail + redistribute static + interface r1-stubnet area 0.0.0.0 + interface r1-sw5 area 0.0.0.0 +! +line vty + exec-timeout 0 0 +! diff --git a/tests/topotests/ospf6-test1/r1/show_ipv6_route.ref b/tests/topotests/ospf6-test1/r1/show_ipv6_route.ref new file mode 100644 index 0000000000..c961512bd9 --- /dev/null +++ b/tests/topotests/ospf6-test1/r1/show_ipv6_route.ref @@ -0,0 +1,9 @@ +O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet +O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 +O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 +O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 +O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5 +O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 +O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 +O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 +O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 diff --git a/tests/topotests/ospf6-test1/r1/zebra.conf b/tests/topotests/ospf6-test1/r1/zebra.conf new file mode 100644 index 0000000000..3de7882c5d --- /dev/null +++ b/tests/topotests/ospf6-test1/r1/zebra.conf @@ -0,0 +1,17 @@ +! +hostname r1 +log file /tmp/r1-zebra.log +! +interface r1-stubnet + ipv6 address fc00:1:1:1::1/64 +! +interface r1-sw5 + ipv6 address fc00:a:a:a::1/64 +! +interface lo +! +ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234 +! +! +line vty +! diff --git a/tests/topotests/ospf6-test1/r2/ospf6d.conf b/tests/topotests/ospf6-test1/r2/ospf6d.conf new file mode 100644 index 0000000000..e98ed29224 --- /dev/null +++ b/tests/topotests/ospf6-test1/r2/ospf6d.conf @@ -0,0 +1,27 @@ +hostname r2 +log file /tmp/r2-ospf6d.log +! +debug ospf6 message all +debug ospf6 lsa unknown +debug ospf6 zebra +debug ospf6 interface +debug ospf6 neighbor +debug ospf6 route table +debug ospf6 flooding +! +interface r2-stubnet + ipv6 ospf6 network broadcast +! +interface r2-sw5 + ipv6 ospf6 network broadcast +! +router ospf6 + router-id 10.0.0.2 + log-adjacency-changes detail + redistribute static + interface r2-stubnet area 0.0.0.0 + interface r2-sw5 area 0.0.0.0 +! +line vty + exec-timeout 0 0 +! diff --git a/tests/topotests/ospf6-test1/r2/show_ipv6_route.ref b/tests/topotests/ospf6-test1/r2/show_ipv6_route.ref new file mode 100644 index 0000000000..014eddbcb6 --- /dev/null +++ b/tests/topotests/ospf6-test1/r2/show_ipv6_route.ref @@ -0,0 +1,10 @@ +O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 +O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet +O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 +O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 +O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5 +O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 +O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 +O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 +O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 + diff --git a/tests/topotests/ospf6-test1/r2/zebra.conf b/tests/topotests/ospf6-test1/r2/zebra.conf new file mode 100644 index 0000000000..23bd2f73a8 --- /dev/null +++ b/tests/topotests/ospf6-test1/r2/zebra.conf @@ -0,0 +1,17 @@ +! +hostname r2 +log file /tmp/r2-zebra.log +! +interface r2-stubnet + ipv6 address fc00:2:2:2::2/64 +! +interface r2-sw5 + ipv6 address fc00:a:a:a::2/64 +! +interface lo +! +ipv6 route fc00:2222:2222:2222::/64 fc00:2:2:2::1234 +! +! +line vty +! diff --git a/tests/topotests/ospf6-test1/r3/ospf6d.conf b/tests/topotests/ospf6-test1/r3/ospf6d.conf new file mode 100644 index 0000000000..e9ce6a5303 --- /dev/null +++ b/tests/topotests/ospf6-test1/r3/ospf6d.conf @@ -0,0 +1,31 @@ +hostname r3 +log file /tmp/r3-ospf6d.log +! +debug ospf6 message all +debug ospf6 lsa unknown +debug ospf6 zebra +debug ospf6 interface +debug ospf6 neighbor +debug ospf6 route table +debug ospf6 flooding +! +interface r3-stubnet + ipv6 ospf6 network broadcast +! +interface r3-sw5 + ipv6 ospf6 network broadcast +! +interface r3-sw6 + ipv6 ospf6 network broadcast +! +router ospf6 + router-id 10.0.0.3 + log-adjacency-changes detail + redistribute static + interface r3-stubnet area 0.0.0.0 + interface r3-sw5 area 0.0.0.0 + interface r3-sw6 area 0.0.0.1 +! +line vty + exec-timeout 0 0 +! diff --git a/tests/topotests/ospf6-test1/r3/show_ipv6_route.ref b/tests/topotests/ospf6-test1/r3/show_ipv6_route.ref new file mode 100644 index 0000000000..1ac7cbd6b4 --- /dev/null +++ b/tests/topotests/ospf6-test1/r3/show_ipv6_route.ref @@ -0,0 +1,10 @@ +O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5 +O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5 +O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet +O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6 +O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5 +O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6 +O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5 +O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5 +O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6 + diff --git a/tests/topotests/ospf6-test1/r3/zebra.conf b/tests/topotests/ospf6-test1/r3/zebra.conf new file mode 100644 index 0000000000..d63489be94 --- /dev/null +++ b/tests/topotests/ospf6-test1/r3/zebra.conf @@ -0,0 +1,20 @@ +! +hostname r3 +log file /tmp/r3-zebra.log +! +interface r3-stubnet + ipv6 address fc00:3:3:3::3/64 +! +interface r3-sw5 + ipv6 address fc00:a:a:a::3/64 +! +interface r3-sw6 + ipv6 address fc00:b:b:b::3/64 +! +interface lo +! +ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234 +! +! +line vty +! diff --git a/tests/topotests/ospf6-test1/r4/ospf6d.conf b/tests/topotests/ospf6-test1/r4/ospf6d.conf new file mode 100644 index 0000000000..71f72a9c99 --- /dev/null +++ b/tests/topotests/ospf6-test1/r4/ospf6d.conf @@ -0,0 +1,27 @@ +hostname r4 +log file /tmp/r4-ospf6d.log +! +debug ospf6 message all +debug ospf6 lsa unknown +debug ospf6 zebra +debug ospf6 interface +debug ospf6 neighbor +debug ospf6 route table +debug ospf6 flooding +! +interface r4-stubnet + ipv6 ospf6 network broadcast +! +interface r4-sw6 + ipv6 ospf6 network broadcast +! +router ospf6 + router-id 10.0.0.4 + log-adjacency-changes detail + redistribute static + interface r4-stubnet area 0.0.0.1 + interface r4-sw6 area 0.0.0.1 +! +line vty + exec-timeout 0 0 +! diff --git a/tests/topotests/ospf6-test1/r4/show_ipv6_route.ref b/tests/topotests/ospf6-test1/r4/show_ipv6_route.ref new file mode 100644 index 0000000000..698dea6c7b --- /dev/null +++ b/tests/topotests/ospf6-test1/r4/show_ipv6_route.ref @@ -0,0 +1,9 @@ +O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 +O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 +O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 +O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet +O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 +O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6 +O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 +O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 +O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 diff --git a/tests/topotests/ospf6-test1/r4/zebra.conf b/tests/topotests/ospf6-test1/r4/zebra.conf new file mode 100644 index 0000000000..1434b08b3b --- /dev/null +++ b/tests/topotests/ospf6-test1/r4/zebra.conf @@ -0,0 +1,17 @@ +! +hostname r4 +log file /tmp/r4-zebra.log +! +interface r4-stubnet + ipv6 address fc00:4:4:4::4/64 +! +interface r4-sw6 + ipv6 address fc00:b:b:b::4/64 +! +interface lo +! +ipv6 route fc00:4444:4444:4444::/64 fc00:4:4:4::1234 +! +! +line vty +! From 8ab9a376691468ba5b68e3bf6dabf95a51a518b0 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 17 Nov 2016 16:10:38 -0800 Subject: [PATCH 003/384] Cleanup README and a reference to License --- tests/topotests/README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index 75807c1cee..f9c9079266 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -3,7 +3,8 @@ ## Installation of Mininet for running tests Only tested with Ubuntu 16.04 -Instructions are the same for all setups (ie ExaBGP is only used for BGP tests) +Instructions are the same for all setups (ie ExaBGP is only used for BGP +tests) ### Installing Mininet Infrastructure: @@ -15,7 +16,8 @@ Instructions are the same for all setups (ie ExaBGP is only used for BGP tests) 6. useradd -d /var/run/exabgp/ -s /bin/false exabgp ### Quagga Installation -Quagga needs to be installed separatly. It is assume to be configured like the standard Ubuntu Packages: +Quagga needs to be installed separatly. It is assume to be configured +like the standard Ubuntu Packages: - Binaries in /usr/lib/quagga - Running under user quagga, group quagga @@ -31,3 +33,12 @@ Go to test directory and execute python script. Test will run all on it's own and return non-zero exit code if it fails. For the simulated topology, see the description in the python file + +If you need to clear the mininet setup between tests (if it isn't cleanly +shutdown), then use the `mn -c` command to clean up the environment + +## License + +All the configs and scripts are licensed under a ISC-style license. See +Python scripts for details. + From d14615d8652700814a167598d6e43f2a2053753e Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 18 Nov 2016 23:42:49 -0800 Subject: [PATCH 004/384] ospf6-test1: Look for test config in directories relative to main script location --- tests/topotests/ospf6-test1/ospf6-test1.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/topotests/ospf6-test1/ospf6-test1.py b/tests/topotests/ospf6-test1/ospf6-test1.py index a60965847c..0d8594d527 100755 --- a/tests/topotests/ospf6-test1/ospf6-test1.py +++ b/tests/topotests/ospf6-test1/ospf6-test1.py @@ -202,7 +202,6 @@ class NetworkTopo(Topo): for i in range(1, 7): switch[i] = self.addSwitch('SW%s' % i, dpid=int2dpid(i), cls=LegacySwitch) - # # Define Quagga Routers # @@ -210,7 +209,6 @@ class NetworkTopo(Topo): for i in range(1, 5): router[i] = self.addNode('r%s' % i, cls=QuaggaRouter, privateDirs=quaggaPrivateDirs) - # # Wire up the switches and routers # @@ -237,8 +235,8 @@ def run(): # Starting Routers for i in range(1, 5): - net['r%s' % i].loadConf('zebra', 'r%s/zebra.conf' % i) - net['r%s' % i].loadConf('ospf6d', 'r%s/ospf6d.conf' % i) + net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i)) net['r%s' % i].startQuagga() print('') @@ -279,13 +277,13 @@ def run(): print("OSPFv3 converged.") print("\nwaiting 15s for routes to populate") - sleep(10) + sleep(15) # Verify OSPFv3 Routing Table print("\nVerifing OSPFv3 Routing Table") failures = 0 for i in range(1, 5): - refTableFile = 'r%s/show_ipv6_route.ref' % i + refTableFile = '%s/r%s/show_ipv6_route.ref' % (thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() From 52f17ef4aa72fe74be64c6e7eb61ac369a9c6149 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 19 Nov 2016 19:06:01 -0800 Subject: [PATCH 005/384] ospf6-test1: Renamed testscript to have test_ prefix for pytest discovery --- .../topotests/ospf6-test1/{ospf6-test1.py => test_ospf6_topo1.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/topotests/ospf6-test1/{ospf6-test1.py => test_ospf6_topo1.py} (100%) diff --git a/tests/topotests/ospf6-test1/ospf6-test1.py b/tests/topotests/ospf6-test1/test_ospf6_topo1.py similarity index 100% rename from tests/topotests/ospf6-test1/ospf6-test1.py rename to tests/topotests/ospf6-test1/test_ospf6_topo1.py From a92d8407ab5d97bb03a9eabfe21464a0a6bbd89c Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 19 Nov 2016 19:08:49 -0800 Subject: [PATCH 006/384] Renamed Test Directory: ospf6-test1 -> ospf6_topo1 --- tests/topotests/{ospf6-test1 => ospf6-topo1}/r1/ospf6d.conf | 0 .../topotests/{ospf6-test1 => ospf6-topo1}/r1/show_ipv6_route.ref | 0 tests/topotests/{ospf6-test1 => ospf6-topo1}/r1/zebra.conf | 0 tests/topotests/{ospf6-test1 => ospf6-topo1}/r2/ospf6d.conf | 0 .../topotests/{ospf6-test1 => ospf6-topo1}/r2/show_ipv6_route.ref | 0 tests/topotests/{ospf6-test1 => ospf6-topo1}/r2/zebra.conf | 0 tests/topotests/{ospf6-test1 => ospf6-topo1}/r3/ospf6d.conf | 0 .../topotests/{ospf6-test1 => ospf6-topo1}/r3/show_ipv6_route.ref | 0 tests/topotests/{ospf6-test1 => ospf6-topo1}/r3/zebra.conf | 0 tests/topotests/{ospf6-test1 => ospf6-topo1}/r4/ospf6d.conf | 0 .../topotests/{ospf6-test1 => ospf6-topo1}/r4/show_ipv6_route.ref | 0 tests/topotests/{ospf6-test1 => ospf6-topo1}/r4/zebra.conf | 0 tests/topotests/{ospf6-test1 => ospf6-topo1}/test_ospf6_topo1.py | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r1/ospf6d.conf (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r1/show_ipv6_route.ref (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r1/zebra.conf (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r2/ospf6d.conf (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r2/show_ipv6_route.ref (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r2/zebra.conf (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r3/ospf6d.conf (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r3/show_ipv6_route.ref (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r3/zebra.conf (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r4/ospf6d.conf (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r4/show_ipv6_route.ref (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/r4/zebra.conf (100%) rename tests/topotests/{ospf6-test1 => ospf6-topo1}/test_ospf6_topo1.py (100%) diff --git a/tests/topotests/ospf6-test1/r1/ospf6d.conf b/tests/topotests/ospf6-topo1/r1/ospf6d.conf similarity index 100% rename from tests/topotests/ospf6-test1/r1/ospf6d.conf rename to tests/topotests/ospf6-topo1/r1/ospf6d.conf diff --git a/tests/topotests/ospf6-test1/r1/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref similarity index 100% rename from tests/topotests/ospf6-test1/r1/show_ipv6_route.ref rename to tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref diff --git a/tests/topotests/ospf6-test1/r1/zebra.conf b/tests/topotests/ospf6-topo1/r1/zebra.conf similarity index 100% rename from tests/topotests/ospf6-test1/r1/zebra.conf rename to tests/topotests/ospf6-topo1/r1/zebra.conf diff --git a/tests/topotests/ospf6-test1/r2/ospf6d.conf b/tests/topotests/ospf6-topo1/r2/ospf6d.conf similarity index 100% rename from tests/topotests/ospf6-test1/r2/ospf6d.conf rename to tests/topotests/ospf6-topo1/r2/ospf6d.conf diff --git a/tests/topotests/ospf6-test1/r2/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref similarity index 100% rename from tests/topotests/ospf6-test1/r2/show_ipv6_route.ref rename to tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref diff --git a/tests/topotests/ospf6-test1/r2/zebra.conf b/tests/topotests/ospf6-topo1/r2/zebra.conf similarity index 100% rename from tests/topotests/ospf6-test1/r2/zebra.conf rename to tests/topotests/ospf6-topo1/r2/zebra.conf diff --git a/tests/topotests/ospf6-test1/r3/ospf6d.conf b/tests/topotests/ospf6-topo1/r3/ospf6d.conf similarity index 100% rename from tests/topotests/ospf6-test1/r3/ospf6d.conf rename to tests/topotests/ospf6-topo1/r3/ospf6d.conf diff --git a/tests/topotests/ospf6-test1/r3/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref similarity index 100% rename from tests/topotests/ospf6-test1/r3/show_ipv6_route.ref rename to tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref diff --git a/tests/topotests/ospf6-test1/r3/zebra.conf b/tests/topotests/ospf6-topo1/r3/zebra.conf similarity index 100% rename from tests/topotests/ospf6-test1/r3/zebra.conf rename to tests/topotests/ospf6-topo1/r3/zebra.conf diff --git a/tests/topotests/ospf6-test1/r4/ospf6d.conf b/tests/topotests/ospf6-topo1/r4/ospf6d.conf similarity index 100% rename from tests/topotests/ospf6-test1/r4/ospf6d.conf rename to tests/topotests/ospf6-topo1/r4/ospf6d.conf diff --git a/tests/topotests/ospf6-test1/r4/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref similarity index 100% rename from tests/topotests/ospf6-test1/r4/show_ipv6_route.ref rename to tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref diff --git a/tests/topotests/ospf6-test1/r4/zebra.conf b/tests/topotests/ospf6-topo1/r4/zebra.conf similarity index 100% rename from tests/topotests/ospf6-test1/r4/zebra.conf rename to tests/topotests/ospf6-topo1/r4/zebra.conf diff --git a/tests/topotests/ospf6-test1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py similarity index 100% rename from tests/topotests/ospf6-test1/test_ospf6_topo1.py rename to tests/topotests/ospf6-topo1/test_ospf6_topo1.py From b057efe120eae340a282d454c490fbdcc6f4de08 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 19 Nov 2016 19:10:05 -0800 Subject: [PATCH 007/384] test_ospf6_topo1: Restructure to run under pytest --- .../topotests/ospf6-topo1/test_ospf6_topo1.py | 108 ++++++++++++------ 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 0d8594d527..bae842d0e8 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -23,7 +23,7 @@ # """ -ospf6-test1.py: +test_ospf6_topo1.py: -----\ SW1 - Stub Net 1 SW2 - Stub Net 2 \ @@ -76,8 +76,6 @@ import StringIO import sys import difflib -from pprint import pprint - from mininet.topo import Topo from mininet.net import Mininet from mininet.node import Node, OVSSwitch, Host @@ -87,6 +85,8 @@ from mininet.cli import CLI from functools import partial from time import sleep +import pytest + def int2dpid(dpid): "Converting Integer to DPID" @@ -178,6 +178,11 @@ class QuaggaRouter(Node): self.cmd('/usr/lib/quagga/%s -d' % daemon) self.waitOutput() print('%s: %s started' % (self, daemon)) + def checkQuaggaRunning(self): + daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') + for daemon in self.daemons: + if (self.daemons[daemon] == 1): + assert daemon in daemonsRunning, "Daemon %s not running" % daemon class LegacySwitch(OVSSwitch): @@ -187,6 +192,12 @@ class LegacySwitch(OVSSwitch): OVSSwitch.__init__(self, name, failMode='standalone', **params) self.switchIP = None +##################################################### +## +## Network Topology Definition +## +##################################################### + class NetworkTopo(Topo): "A Quagga Topology with direct peering router and IXP connection" @@ -224,8 +235,17 @@ class NetworkTopo(Topo): self.addLink(switch[6], router[4], intfName2='r4-sw6') -def run(): - "ospf6-test1 Topology" +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + global topo, net + + print ("\n\n** Setup Topology: %s\n" % module.__name__) + print("******************************************\n") thisDir = os.path.dirname(os.path.realpath(__file__)) topo = NetworkTopo() @@ -233,21 +253,47 @@ def run(): net = Mininet(controller=None, topo=topo) net.start() + # For debugging after starting net, but before starting Quagga, uncomment the next line + # CLI(net) + # Starting Routers for i in range(1, 5): net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i)) net['r%s' % i].startQuagga() - print('') + # For debugging after starting Quagga daemons, uncomment the next line + # CLI(net) - # - # Stop here for all manual checks - # - #CLI(net) + +def teardown_module(module): + global net + + print ("\n\n** Shutdown Topology: %s\n" % module.__name__) + print("******************************************\n") + + # End - Shutdown network + net.stop() + + +def test_quagga_running(): + global net + + print ("\n\n** Check if Quagga is running on each Router node\n") + print("******************************************\n") + sleep(5) + + # Starting Routers + for i in range(1, 5): + net['r%s' % i].checkQuaggaRunning() + + +def test_ospf6_converged(): + global net # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State) - print("Waiting for OSPFv3 neighbors to establish (to Full)") + print("\n\n** Verify for OSPF6 daemons to converge\n") + print("******************************************\n") timeout = 60 while timeout > 0: print("Timeout in %s: " % timeout), @@ -269,18 +315,25 @@ def run(): break else: # Bail out with error if a router fails to converge - sys.stderr.write("Router r%s failed to converge\n" % i) ospfStatus = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh"') - sys.stderr.write("Status:\n%s" % ospfStatus) - net.stop() - sys.exit(1) + + assert False, "OSPFv6 did not converge:\n%s" % ospfStatus + print("OSPFv3 converged.") - print("\nwaiting 15s for routes to populate") - sleep(15) + if timeout < 60: + # Only wait if we actually went through a convergence + print("\nwaiting 15s for routes to populate") + sleep(15) + +def test_ospf6_routingTable(): + global net + + thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\nVerifing OSPFv3 Routing Table") + print("\n\n** Verifing OSPFv3 Routing Table\n") + print("******************************************\n") failures = 0 for i in range(1, 5): refTableFile = '%s/r%s/show_ipv6_route.ref' % (thisDir, i) @@ -303,27 +356,18 @@ def run(): diff=difflib.unified_diff(actual, expected) diff=''.join(diff) # Empty string if it matches, otherwise diff contains unified diff + if diff: sys.stderr.write('r%s failed Routing Table Check:\n%s\n' % (i, diff)) failures += 1 else: print("r%s ok" % i) - - # - # Stop here for manual checks after tests are executed - # - # CLI(net) - # End - Shutdown network - net.stop() + assert failures == 0, "Routing Table verification failed for router r%s:\n%s" % (i, diff) - # Set non-zero exit status in case of failures - if failures > 0: - sys.stderr.write("Verification failed\n") - sys.exit(1) - else: - print("Verification Successful") if __name__ == '__main__': + setLogLevel('info') - run() + retval = pytest.main(["-s"]) + sys.exit(retval) From a177e146bb71268912e11c00843fbef189f769c0 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 19 Nov 2016 23:59:42 -0800 Subject: [PATCH 008/384] Add .gitignore --- tests/topotests/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/topotests/.gitignore diff --git a/tests/topotests/.gitignore b/tests/topotests/.gitignore new file mode 100644 index 0000000000..b3c9e26dcc --- /dev/null +++ b/tests/topotests/.gitignore @@ -0,0 +1,2 @@ +.cache +__pycache__ From 806111c083dbd6d339be37a23e93025c820bb79b Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Mon, 21 Nov 2016 00:32:40 -0800 Subject: [PATCH 009/384] ospf6-topo1: Cleanup log messages --- tests/topotests/ospf6-topo1/test_ospf6_topo1.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index bae842d0e8..d32aefa8fe 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -244,7 +244,7 @@ class NetworkTopo(Topo): def setup_module(module): global topo, net - print ("\n\n** Setup Topology: %s\n" % module.__name__) + print ("\n\n** %s: Setup Topology" % module.__name__) print("******************************************\n") thisDir = os.path.dirname(os.path.realpath(__file__)) @@ -269,7 +269,7 @@ def setup_module(module): def teardown_module(module): global net - print ("\n\n** Shutdown Topology: %s\n" % module.__name__) + print ("\n\n** %s: Shutdown Topology" % module.__name__) print("******************************************\n") # End - Shutdown network @@ -279,7 +279,7 @@ def teardown_module(module): def test_quagga_running(): global net - print ("\n\n** Check if Quagga is running on each Router node\n") + print ("\n\n** Check if Quagga is running on each Router node") print("******************************************\n") sleep(5) @@ -292,7 +292,7 @@ def test_ospf6_converged(): global net # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State) - print("\n\n** Verify for OSPF6 daemons to converge\n") + print("\n\n** Verify for OSPF6 daemons to converge") print("******************************************\n") timeout = 60 while timeout > 0: @@ -332,7 +332,7 @@ def test_ospf6_routingTable(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing OSPFv3 Routing Table\n") + print("\n\n** Verifing OSPFv3 Routing Table") print("******************************************\n") failures = 0 for i in range(1, 5): From 50bd94cd20ffb64cce606aeeffd42020c3b30f8b Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Mon, 21 Nov 2016 00:42:06 -0800 Subject: [PATCH 010/384] ospf6-topo1: Less chatty timeout messages during convergence --- tests/topotests/ospf6-topo1/test_ospf6_topo1.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index d32aefa8fe..3e2d2229d5 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -302,15 +302,14 @@ def test_ospf6_converged(): for i in range(1, 5): notConverged = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh" 2> /dev/null | grep ^[0-9] | grep -v Full') if notConverged: - print('Waiting for r%s' %i), + print('Waiting for r%s' %i) sys.stdout.flush() break if notConverged: - sleep(2) - timeout -= 2 - print('\r \r'), + sleep(5) + timeout -= 5 else: - print('\rDone ') + print('Done') print(notConverged) break else: From 68a655673f2a158e01853fee25e56287dae3625f Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 24 Nov 2016 03:56:05 -0800 Subject: [PATCH 011/384] ospf6-topo1: Code cleanup --- .../topotests/ospf6-topo1/test_ospf6_topo1.py | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 3e2d2229d5..e7d0b1ab9f 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -1,23 +1,23 @@ #!/usr/bin/env python # -# ospf6-test1.py +# test_ospf6_topo1.py # Part of NetDEF Topology Tests # -# Copyright (c) 2016 by -# Network Device Education Foundation, Inc. ("NetDEF") +# Copyright (c) 2016 by +# Network Device Education Foundation, Inc. ("NetDEF") # -# Permission to use, copy, modify, and/or distribute this software -# for any purpose with or without fee is hereby granted, provided -# that the above copyright notice and this permission notice appear +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear # in all copies. # -# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE # OF THIS SOFTWARE. # @@ -72,9 +72,9 @@ test_ospf6_topo1.py: import os import re -import StringIO import sys import difflib +import StringIO from mininet.topo import Topo from mininet.net import Mininet @@ -98,6 +98,7 @@ def int2dpid(dpid): raise Exception('Unable to derive default datapath ID - ' 'please either specify a dpid or use a ' 'canonical switch name such as s23.') + class LinuxRouter(Node): "A Node with IPv4/IPv6 forwarding enabled." @@ -121,7 +122,7 @@ class QuaggaRouter(Node): super(QuaggaRouter, self).config(**params) # Enable forwarding on the router self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') self.cmd('chown quagga:quaggavty /etc/quagga') self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} @@ -244,9 +245,12 @@ class NetworkTopo(Topo): def setup_module(module): global topo, net - print ("\n\n** %s: Setup Topology" % module.__name__) + print("\n\n** %s: Setup Topology" % module.__name__) print("******************************************\n") + print("Cleanup old Mininet runs") + os.system('sudo mn -c > /dev/null 2>&1') + thisDir = os.path.dirname(os.path.realpath(__file__)) topo = NetworkTopo() @@ -269,7 +273,7 @@ def setup_module(module): def teardown_module(module): global net - print ("\n\n** %s: Shutdown Topology" % module.__name__) + print("\n\n** %s: Shutdown Topology" % module.__name__) print("******************************************\n") # End - Shutdown network @@ -279,7 +283,7 @@ def teardown_module(module): def test_quagga_running(): global net - print ("\n\n** Check if Quagga is running on each Router node") + print("\n\n** Check if Quagga is running on each Router node") print("******************************************\n") sleep(5) @@ -352,8 +356,7 @@ def test_ospf6_routingTable(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff=difflib.unified_diff(actual, expected) - diff=''.join(diff) + diff = ''.join(difflib.unified_diff(actual, expected)) # Empty string if it matches, otherwise diff contains unified diff if diff: From 586e15c4fbab6faa7de237312b5f682672661aca Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 24 Nov 2016 03:58:47 -0800 Subject: [PATCH 012/384] bgp_multiview_topo1: Add "bgp multiview" simple topology to test. Initial commit --- .../topotests/bgp_multiview_topo1/exabgp.env | 54 +++ .../bgp_multiview_topo1/peer1/exa-receive.py | 38 ++ .../bgp_multiview_topo1/peer1/exa-send.py | 28 ++ .../bgp_multiview_topo1/peer1/exabgp.cfg | 21 + .../bgp_multiview_topo1/peer2/exa-receive.py | 38 ++ .../bgp_multiview_topo1/peer2/exa-send.py | 28 ++ .../bgp_multiview_topo1/peer2/exabgp.cfg | 21 + .../bgp_multiview_topo1/peer3/exa-receive.py | 38 ++ .../bgp_multiview_topo1/peer3/exa-send.py | 28 ++ .../bgp_multiview_topo1/peer3/exabgp.cfg | 21 + .../bgp_multiview_topo1/peer4/exa-receive.py | 38 ++ .../bgp_multiview_topo1/peer4/exa-send.py | 28 ++ .../bgp_multiview_topo1/peer4/exabgp.cfg | 21 + .../bgp_multiview_topo1/peer5/exa-receive.py | 38 ++ .../bgp_multiview_topo1/peer5/exa-send.py | 28 ++ .../bgp_multiview_topo1/peer5/exabgp.cfg | 21 + .../bgp_multiview_topo1/peer6/exa-receive.py | 38 ++ .../bgp_multiview_topo1/peer6/exa-send.py | 28 ++ .../bgp_multiview_topo1/peer6/exabgp.cfg | 21 + .../bgp_multiview_topo1/peer7/exa-receive.py | 38 ++ .../bgp_multiview_topo1/peer7/exa-send.py | 28 ++ .../bgp_multiview_topo1/peer7/exabgp.cfg | 21 + .../bgp_multiview_topo1/peer8/exa-receive.py | 38 ++ .../bgp_multiview_topo1/peer8/exa-send.py | 28 ++ .../bgp_multiview_topo1/peer8/exabgp.cfg | 21 + .../bgp_multiview_topo1/r1/bgpd.conf | 49 +++ .../r1/show_ip_bgp_view_1.ref | 40 ++ .../r1/show_ip_bgp_view_2.ref | 29 ++ .../r1/show_ip_bgp_view_3.ref | 40 ++ .../bgp_multiview_topo1/r1/zebra.conf | 23 ++ .../test_bgp_multiview_topo1.py | 366 ++++++++++++++++++ 31 files changed, 1297 insertions(+) create mode 100644 tests/topotests/bgp_multiview_topo1/exabgp.env create mode 100755 tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py create mode 100755 tests/topotests/bgp_multiview_topo1/peer1/exa-send.py create mode 100644 tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg create mode 100755 tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py create mode 100755 tests/topotests/bgp_multiview_topo1/peer2/exa-send.py create mode 100644 tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg create mode 100755 tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py create mode 100755 tests/topotests/bgp_multiview_topo1/peer3/exa-send.py create mode 100644 tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg create mode 100755 tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py create mode 100755 tests/topotests/bgp_multiview_topo1/peer4/exa-send.py create mode 100644 tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg create mode 100755 tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py create mode 100755 tests/topotests/bgp_multiview_topo1/peer5/exa-send.py create mode 100644 tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg create mode 100755 tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py create mode 100755 tests/topotests/bgp_multiview_topo1/peer6/exa-send.py create mode 100644 tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg create mode 100755 tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py create mode 100755 tests/topotests/bgp_multiview_topo1/peer7/exa-send.py create mode 100644 tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg create mode 100755 tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py create mode 100755 tests/topotests/bgp_multiview_topo1/peer8/exa-send.py create mode 100644 tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg create mode 100644 tests/topotests/bgp_multiview_topo1/r1/bgpd.conf create mode 100644 tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref create mode 100644 tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref create mode 100644 tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref create mode 100644 tests/topotests/bgp_multiview_topo1/r1/zebra.conf create mode 100755 tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py diff --git a/tests/topotests/bgp_multiview_topo1/exabgp.env b/tests/topotests/bgp_multiview_topo1/exabgp.env new file mode 100644 index 0000000000..a328e04962 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/exabgp.env @@ -0,0 +1,54 @@ + +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' +##daemonize = false + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py new file mode 100755 index 0000000000..8e65f1ae9a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg new file mode 100644 index 0000000000..8991610e8a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "./exa-send.py 1 10"; + } + + process receive-routes { + run "./exa-receive.py 1"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.1; + local-address 172.16.1.1; + local-as 65001; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py new file mode 100755 index 0000000000..8e65f1ae9a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg new file mode 100644 index 0000000000..efddec5cc9 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "./exa-send.py 2 10"; + } + + process receive-routes { + run "./exa-receive.py 2"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.2; + local-address 172.16.1.2; + local-as 65002; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py new file mode 100755 index 0000000000..8e65f1ae9a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg new file mode 100644 index 0000000000..abffe32f81 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "./exa-send.py 3 10"; + } + + process receive-routes { + run "./exa-receive.py 3"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.3; + local-address 172.16.1.3; + local-as 65003; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py new file mode 100755 index 0000000000..8e65f1ae9a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg new file mode 100644 index 0000000000..27dfef902e --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "./exa-send.py 4 10"; + } + + process receive-routes { + run "./exa-receive.py 4"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.4; + local-address 172.16.1.4; + local-as 65004; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py new file mode 100755 index 0000000000..8e65f1ae9a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg new file mode 100644 index 0000000000..9326aed19f --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "./exa-send.py 5 10"; + } + + process receive-routes { + run "./exa-receive.py 5"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.5; + local-address 172.16.1.5; + local-as 65005; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py new file mode 100755 index 0000000000..8e65f1ae9a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg new file mode 100644 index 0000000000..f99976b65b --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "./exa-send.py 6 10"; + } + + process receive-routes { + run "./exa-receive.py 6"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.6; + local-address 172.16.1.6; + local-as 65006; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py new file mode 100755 index 0000000000..8e65f1ae9a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg new file mode 100644 index 0000000000..2dea4c9797 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "./exa-send.py 7 10"; + } + + process receive-routes { + run "./exa-receive.py 7"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.7; + local-address 172.16.1.7; + local-as 65007; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py new file mode 100755 index 0000000000..8e65f1ae9a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg new file mode 100644 index 0000000000..ae3c5eb44c --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "./exa-send.py 8 10"; + } + + process receive-routes { + run "./exa-receive.py 8"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.8; + local-address 172.16.1.8; + local-as 65008; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf new file mode 100644 index 0000000000..7cfcb6c9aa --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf @@ -0,0 +1,49 @@ +! +! Zebra configuration saved from vty +! 2015/12/24 21:46:33 +! +log file /tmp/r1-bgpd.log +! +!debug bgp events +!debug bgp keepalives +!debug bgp updates +!debug bgp fsm +!debug bgp filters +!debug bgp zebra +! +bgp multiple-instance +! +router bgp 100 view 1 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 route-map local1 + timers bgp 60 180 + neighbor 172.16.1.1 remote-as 65001 + neighbor 172.16.1.2 remote-as 65002 + neighbor 172.16.1.5 remote-as 65005 +! +router bgp 100 view 2 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 route-map local2 + timers bgp 60 180 + neighbor 172.16.1.3 remote-as 65003 + neighbor 172.16.1.4 remote-as 65004 +! +router bgp 100 view 3 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 + timers bgp 60 180 + neighbor 172.16.1.6 remote-as 65006 + neighbor 172.16.1.7 remote-as 65007 + neighbor 172.16.1.8 remote-as 65008 +! +route-map local1 permit 10 + set community 100:9999 additive + set metric 0 +! +route-map local2 permit 10 + set as-path prepend 100 100 100 100 100 + set community 100:1 additive + set metric 9999 +! +line vty +! diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref new file mode 100644 index 0000000000..0e8bf842fd --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref @@ -0,0 +1,40 @@ +BGP table version is 0, local router ID is 172.30.1.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.5 0 65005 i +* 172.16.1.2 0 65002 i +*> 172.16.1.1 0 65001 i +*> 10.101.0.0/24 172.16.1.1 100 0 65001 i +*> 10.101.1.0/24 172.16.1.1 100 0 65001 i +*> 10.101.2.0/24 172.16.1.1 100 0 65001 i +*> 10.101.3.0/24 172.16.1.1 100 0 65001 i +*> 10.101.4.0/24 172.16.1.1 100 0 65001 i +*> 10.101.5.0/24 172.16.1.1 100 0 65001 i +*> 10.101.6.0/24 172.16.1.1 100 0 65001 i +*> 10.101.7.0/24 172.16.1.1 100 0 65001 i +*> 10.101.8.0/24 172.16.1.1 100 0 65001 i +*> 10.101.9.0/24 172.16.1.1 100 0 65001 i +*> 10.102.0.0/24 172.16.1.2 100 0 65002 i +*> 10.102.1.0/24 172.16.1.2 100 0 65002 i +*> 10.102.2.0/24 172.16.1.2 100 0 65002 i +*> 10.102.3.0/24 172.16.1.2 100 0 65002 i +*> 10.102.4.0/24 172.16.1.2 100 0 65002 i +*> 10.102.5.0/24 172.16.1.2 100 0 65002 i +*> 10.102.6.0/24 172.16.1.2 100 0 65002 i +*> 10.102.7.0/24 172.16.1.2 100 0 65002 i +*> 10.102.8.0/24 172.16.1.2 100 0 65002 i +*> 10.102.9.0/24 172.16.1.2 100 0 65002 i +*> 10.105.0.0/24 172.16.1.5 100 0 65005 i +*> 10.105.1.0/24 172.16.1.5 100 0 65005 i +*> 10.105.2.0/24 172.16.1.5 100 0 65005 i +*> 10.105.3.0/24 172.16.1.5 100 0 65005 i +*> 10.105.4.0/24 172.16.1.5 100 0 65005 i +*> 10.105.5.0/24 172.16.1.5 100 0 65005 i +*> 10.105.6.0/24 172.16.1.5 100 0 65005 i +*> 10.105.7.0/24 172.16.1.5 100 0 65005 i +*> 10.105.8.0/24 172.16.1.5 100 0 65005 i +*> 10.105.9.0/24 172.16.1.5 100 0 65005 i +*> 172.20.0.0/28 0.0.0.0 0 32768 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref new file mode 100644 index 0000000000..cfdbaeb99d --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref @@ -0,0 +1,29 @@ +BGP table version is 0, local router ID is 172.30.1.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.4 0 65004 i +*> 172.16.1.3 0 65003 i +*> 10.103.0.0/24 172.16.1.3 100 0 65003 i +*> 10.103.1.0/24 172.16.1.3 100 0 65003 i +*> 10.103.2.0/24 172.16.1.3 100 0 65003 i +*> 10.103.3.0/24 172.16.1.3 100 0 65003 i +*> 10.103.4.0/24 172.16.1.3 100 0 65003 i +*> 10.103.5.0/24 172.16.1.3 100 0 65003 i +*> 10.103.6.0/24 172.16.1.3 100 0 65003 i +*> 10.103.7.0/24 172.16.1.3 100 0 65003 i +*> 10.103.8.0/24 172.16.1.3 100 0 65003 i +*> 10.103.9.0/24 172.16.1.3 100 0 65003 i +*> 10.104.0.0/24 172.16.1.4 100 0 65004 i +*> 10.104.1.0/24 172.16.1.4 100 0 65004 i +*> 10.104.2.0/24 172.16.1.4 100 0 65004 i +*> 10.104.3.0/24 172.16.1.4 100 0 65004 i +*> 10.104.4.0/24 172.16.1.4 100 0 65004 i +*> 10.104.5.0/24 172.16.1.4 100 0 65004 i +*> 10.104.6.0/24 172.16.1.4 100 0 65004 i +*> 10.104.7.0/24 172.16.1.4 100 0 65004 i +*> 10.104.8.0/24 172.16.1.4 100 0 65004 i +*> 10.104.9.0/24 172.16.1.4 100 0 65004 i +*> 172.20.0.0/28 0.0.0.0 9999 32768 100 100 100 100 100 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref new file mode 100644 index 0000000000..f0f471db8e --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref @@ -0,0 +1,40 @@ +BGP table version is 0, local router ID is 172.30.1.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.8 0 65008 i +* 172.16.1.7 0 65007 i +*> 172.16.1.6 0 65006 i +*> 10.106.0.0/24 172.16.1.6 100 0 65006 i +*> 10.106.1.0/24 172.16.1.6 100 0 65006 i +*> 10.106.2.0/24 172.16.1.6 100 0 65006 i +*> 10.106.3.0/24 172.16.1.6 100 0 65006 i +*> 10.106.4.0/24 172.16.1.6 100 0 65006 i +*> 10.106.5.0/24 172.16.1.6 100 0 65006 i +*> 10.106.6.0/24 172.16.1.6 100 0 65006 i +*> 10.106.7.0/24 172.16.1.6 100 0 65006 i +*> 10.106.8.0/24 172.16.1.6 100 0 65006 i +*> 10.106.9.0/24 172.16.1.6 100 0 65006 i +*> 10.107.0.0/24 172.16.1.7 100 0 65007 i +*> 10.107.1.0/24 172.16.1.7 100 0 65007 i +*> 10.107.2.0/24 172.16.1.7 100 0 65007 i +*> 10.107.3.0/24 172.16.1.7 100 0 65007 i +*> 10.107.4.0/24 172.16.1.7 100 0 65007 i +*> 10.107.5.0/24 172.16.1.7 100 0 65007 i +*> 10.107.6.0/24 172.16.1.7 100 0 65007 i +*> 10.107.7.0/24 172.16.1.7 100 0 65007 i +*> 10.107.8.0/24 172.16.1.7 100 0 65007 i +*> 10.107.9.0/24 172.16.1.7 100 0 65007 i +*> 10.108.0.0/24 172.16.1.8 100 0 65008 i +*> 10.108.1.0/24 172.16.1.8 100 0 65008 i +*> 10.108.2.0/24 172.16.1.8 100 0 65008 i +*> 10.108.3.0/24 172.16.1.8 100 0 65008 i +*> 10.108.4.0/24 172.16.1.8 100 0 65008 i +*> 10.108.5.0/24 172.16.1.8 100 0 65008 i +*> 10.108.6.0/24 172.16.1.8 100 0 65008 i +*> 10.108.7.0/24 172.16.1.8 100 0 65008 i +*> 10.108.8.0/24 172.16.1.8 100 0 65008 i +*> 10.108.9.0/24 172.16.1.8 100 0 65008 i +*> 172.20.0.0/28 0.0.0.0 0 32768 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/zebra.conf b/tests/topotests/bgp_multiview_topo1/r1/zebra.conf new file mode 100644 index 0000000000..6aebf56f03 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/zebra.conf @@ -0,0 +1,23 @@ +! +! Zebra configuration saved from vty +! 2015/12/24 16:48:27 +! +log file /tmp/r1-zebra.log +! +hostname r1 +! +interface r1-stub + description Stub Network + ip address 172.20.0.1/28 + no link-detect +! +interface r1-eth0 + description to PE router - vlan1 + ip address 172.16.1.254/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py new file mode 100755 index 0000000000..3af993dfad --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -0,0 +1,366 @@ +#!/usr/bin/env python + +# +# test_bgp_multiview_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2016 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bgp_multiview_topo1.py: Simple Quagga Route-Server Test + +See Topology Diagram bgp-routeserver-1.pdf +""" + +import os +import re +import sys +import difflib +import StringIO + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from functools import partial +from time import sleep + +import pytest + +def int2dpid(dpid): + "Converting Integer to DPID" + + try: + dpid = hex(dpid)[2:] + dpid = '0'*(16-len(dpid))+dpid + return dpid + except IndexError: + raise Exception('Unable to derive default datapath ID - ' + 'please either specify a dpid or use a ' + 'canonical switch name such as s23.') + +class LinuxRouter(Node): + "A Node with IPv4/IPv6 forwarding enabled." + + def config(self, **params): + super(LinuxRouter, self).config(**params) + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + def terminate(self): + """ + Terminate generic LinuxRouter Mininet instance + """ + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(LinuxRouter, self).terminate() + +class QuaggaRouter(Node): + "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" + + def config(self, **params): + super(QuaggaRouter, self).config(**params) + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + self.cmd('chown quagga:quaggavty /etc/quagga') + self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, + 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} + def terminate(self): + # Delete Running Quagga Daemons + rundaemons = self.cmd('ls -1 /var/run/quagga/*.pid') + for d in StringIO.StringIO(rundaemons): + self.cmd('kill -7 `cat %s`' % d.rstrip()) + self.waitOutput() + # Disable forwarding + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(QuaggaRouter, self).terminate() + def removeIPs(self): + for interface in self.intfNames(): + self.cmd('ip address flush', interface) + def loadConf(self, daemon, source=None): + # print "Daemons before:", self.daemons + if daemon in self.daemons.keys(): + self.daemons[daemon] = 1 + if source is None: + self.cmd('touch /etc/quagga/%s.conf' % daemon) + self.waitOutput() + else: + self.cmd('cp %s /etc/quagga/%s.conf' % (source, daemon)) + self.waitOutput() + self.cmd('chmod 640 /etc/quagga/%s.conf' % daemon) + self.waitOutput() + self.cmd('chown quagga:quagga /etc/quagga/%s.conf' % daemon) + self.waitOutput() + else: + print("No daemon %s known" % daemon) + # print "Daemons after:", self.daemons + def startQuagga(self): + # Disable integrated-vtysh-config + self.cmd('echo "no service integrated-vtysh-config" > /etc/quagga/vtysh.conf') + with open("/etc/quagga/vtysh.conf", "w") as vtyshfile: + vtyshfile.write('no service integrated-vtysh-config') + self.cmd('chown quagga:quaggavty /etc/quagga/vtysh.conf') + # Remove IP addresses from OS first - we have them in zebra.conf + self.removeIPs() + # Start Zebra first + if self.daemons['zebra'] == 1: + self.cmd('/usr/lib/quagga/zebra -d') + self.waitOutput() + print('%s: zebra started' % self) + sleep(1) + # Fix Link-Local Addresses + # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this + self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') + # Now start all the other daemons + for daemon in self.daemons: + if (self.daemons[daemon] == 1) and (daemon != 'zebra'): + self.cmd('/usr/lib/quagga/%s -d' % daemon) + self.waitOutput() + print('%s: %s started' % (self, daemon)) + def checkQuaggaRunning(self): + daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') + for daemon in self.daemons: + if (self.daemons[daemon] == 1): + assert daemon in daemonsRunning, "Daemon %s not running" % daemon + + +class LegacySwitch(OVSSwitch): + "A Legacy Switch without OpenFlow" + + def __init__(self, name, **params): + OVSSwitch.__init__(self, name, failMode='standalone', **params) + self.switchIP = None + + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "A LinuxRouter connecting three IP subnets" + + def build(self, **_opts): + + quaggaPrivateDirs = ['/etc/quagga', + '/var/run/quagga', + '/var/log', + '/var/run/ssh'] + exabgpPrivateDirs = ['/etc/exabgp', + '/var/run/exabgp', + '/var/log'] + + # Setup Routers + quagga = {} + for i in range(1, 2): + quagga[i] = self.addNode('r%s' % i, cls=QuaggaRouter, + privateDirs=quaggaPrivateDirs) + + # Setup Provider BGP peers + peer = {} + for i in range(1, 9): + peer[i] = self.addHost('peer%s' % i, ip='172.16.1.%s/24' % i, + defaultRoute='via 172.16.1.254', + privateDirs=exabgpPrivateDirs) + + # Setup Switches + switch = {} + # First switch is for a dummy interface (for local network) + switch[0] = self.addSwitch('sw0', cls=LegacySwitch) + self.addLink(switch[0], quagga[1], intfName2='r1-stub') + # Second switch is for connection to all peering routers + switch[1] = self.addSwitch('sw1', cls=LegacySwitch) + self.addLink(switch[1], quagga[1], intfName2='r1-eth0') + for j in range(1, 9): + self.addLink(switch[1], peer[j], intfName2='peer%s-eth0' % j) + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + global topo, net + + print("\n\n** %s: Setup Topology" % module.__name__) + print("******************************************\n") + + print("Cleanup old Mininet runs") + os.system('sudo mn -c > /dev/null 2>&1') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + topo = NetworkTopo() + + net = Mininet(controller=None, topo=topo) + net.start() + + # Starting Routers + for i in range(1, 2): + net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) + net['r%s' % i].loadConf('bgpd', '%s/r%s/bgpd.conf' % (thisDir, i)) + net['r%s' % i].startQuagga() + + # Starting PE Hosts and init ExaBGP on each of them + print('*** Starting BGP on all 8 Peers in 10s') + sleep(10) + for i in range(1, 9): + net['peer%s' % i].cmd('cp %s/exabgp.env /etc/exabgp/exabgp.env' % thisDir) + net['peer%s' % i].cmd('cp %s/peer%s/* /etc/exabgp/' % (thisDir, i)) + net['peer%s' % i].cmd('chmod 644 /etc/exabgp/*') + net['peer%s' % i].cmd('chmod 755 /etc/exabgp/*.py') + net['peer%s' % i].cmd('chown -R exabgp:exabgp /etc/exabgp') + net['peer%s' % i].cmd('exabgp -e /etc/exabgp/exabgp.env /etc/exabgp/exabgp.cfg') + print('peer%s' % i), + print('') + + # For debugging after starting Quagga daemons, uncomment the next line + # CLI(net) + +def teardown_module(module): + global net + + print("\n\n** %s: Shutdown Topology" % module.__name__) + print("******************************************\n") + + # Shutdown - clean up everything + print('*** Killing BGP on Peer routers') + # Killing ExaBGP + for i in range(1, 9): + net['peer%s' % i].cmd('kill `cat /var/run/exabgp/exabgp.pid`') + + # End - Shutdown network + net.stop() + +def test_quagga_running(): + global net + + print("\n\n** Check if Quagga is running on each Router node") + print("******************************************\n") + sleep(5) + + # Starting Routers + for i in range(1, 2): + net['r%s' % i].checkQuaggaRunning() + +def test_bgp_converge(): + "Check for BGP converged on all peers and BGP views" + + global net + + # Wait for BGP to converge (All Neighbors in either Full or TwoWay State) + print("\n\n** Verify for BGP to converge") + print("******************************************\n") + timeout = 60 + while timeout > 0: + print("Timeout in %s: " % timeout), + sys.stdout.flush() + # Look for any node not yet converged + for i in range(1, 2): + for view in range(1, 4): + notConverged = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s summary" 2> /dev/null | grep ^[0-9] | grep -v " 11$"' % view) + if notConverged: + print('Waiting for r%s, view %s' % (i, view)) + sys.stdout.flush() + break + if notConverged: + break + if notConverged: + sleep(5) + timeout -= 5 + else: + print('Done') + break + else: + # Bail out with error if a router fails to converge + bgpStatus = net['r%s' % i].cmd('show ip bgp view %s summary"') + + assert False, "BGP did not converge:\n%s" % bgpStatus + + print("BGP converged.") + + # if timeout < 60: + # # Only wait if we actually went through a convergence + # print("\nwaiting 15s for routes to populate") + # sleep(15) + + # For debugging after starting Quagga daemons, uncomment the next line + # CLI(net) + +def test_bgp_routingTable(): + global net + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing BGP Routing Tables") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + for view in range(1, 4): + refTableFile = '%s/r%s/show_ip_bgp_view_%s.ref' % (thisDir, i, view) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s" 2> /dev/null' % view).rstrip() + + # Fix inconsitent spaces between 0.99.24 and newer versions of Quagga... + actual = re.sub('0 0', '0 0', actual) + actual = re.sub(r'([0-9]) 32768', r'\1 32768', actual) + # Remove summary line (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + actual = actual.rstrip() + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.unified_diff(actual, expected)) + # Empty string if it matches, otherwise diff contains unified diff + + if diff: + sys.stderr.write('r%s failed Routing Table Check for view %s:\n%s\n' + % (i, view, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "Routing Table verification failed for router r%s, view %s:\n%s" % (i, view, diff) + + # For debugging after starting Quagga daemons, uncomment the next line + # CLI(net) + + +if __name__ == '__main__': + + setLogLevel('info') + retval = pytest.main(["-s"]) + sys.exit(retval) From 2cda38e488c04ec529a324b1b24088df1f5a73a4 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 25 Nov 2016 19:56:37 -0800 Subject: [PATCH 013/384] bgp_multiview_topo1: Skip remaining on fatal error and try to get more crash info of daemon is not running --- .../test_bgp_multiview_topo1.py | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 3af993dfad..e3654df841 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -33,6 +33,8 @@ import re import sys import difflib import StringIO +import glob +import subprocess from mininet.topo import Topo from mininet.net import Mininet @@ -46,6 +48,8 @@ from time import sleep import pytest +fatal_error = "" + def int2dpid(dpid): "Converting Integer to DPID" @@ -82,6 +86,11 @@ class QuaggaRouter(Node): # Enable forwarding on the router self.cmd('sysctl net.ipv4.ip_forward=1') self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + # Enable coredumps + self.cmd('sysctl kernel.core_uses_pid=1') + self.cmd('sysctl fs.suid_dumpable=2') + self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) + # Set ownership of config files self.cmd('chown quagga:quaggavty /etc/quagga') self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} @@ -121,6 +130,10 @@ class QuaggaRouter(Node): with open("/etc/quagga/vtysh.conf", "w") as vtyshfile: vtyshfile.write('no service integrated-vtysh-config') self.cmd('chown quagga:quaggavty /etc/quagga/vtysh.conf') + # Try to find relevant old logfiles in /tmp and delete them + map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) + # Remove old core files + map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) # Remove IP addresses from OS first - we have them in zebra.conf self.removeIPs() # Start Zebra first @@ -139,11 +152,27 @@ class QuaggaRouter(Node): self.waitOutput() print('%s: %s started' % (self, daemon)) def checkQuaggaRunning(self): + global fatal_error + daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') for daemon in self.daemons: - if (self.daemons[daemon] == 1): - assert daemon in daemonsRunning, "Daemon %s not running" % daemon + if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): + sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) + # Look for core file + corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) + if (len(corefiles) > 0): + backtrace = subprocess.check_output(["gdb /usr/lib/quagga/%s %s --batch -ex bt" % (daemon, corefiles[0])], shell=True) + sys.stderr.write("%s %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) + sys.stderr.write("%s\n" % backtrace) + else: + # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. + if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): + log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log" % (self.name, daemon)], shell=True) + sys.stderr.write("From quagga %s %s log file:\n" % (self.name, daemon)) + sys.stderr.write("%s\n" % log_tail) + fatal_error = "%s: Daemon %s not running" % (self.name, daemon) + assert False, "%s: Daemon %s not running" % (self.name, daemon) class LegacySwitch(OVSSwitch): "A Legacy Switch without OpenFlow" @@ -256,8 +285,13 @@ def teardown_module(module): net.stop() def test_quagga_running(): + global fatal_error global net + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + print("\n\n** Check if Quagga is running on each Router node") print("******************************************\n") sleep(5) @@ -269,8 +303,13 @@ def test_quagga_running(): def test_bgp_converge(): "Check for BGP converged on all peers and BGP views" + global fatal_error global net + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + # Wait for BGP to converge (All Neighbors in either Full or TwoWay State) print("\n\n** Verify for BGP to converge") print("******************************************\n") @@ -297,7 +336,6 @@ def test_bgp_converge(): else: # Bail out with error if a router fails to converge bgpStatus = net['r%s' % i].cmd('show ip bgp view %s summary"') - assert False, "BGP did not converge:\n%s" % bgpStatus print("BGP converged.") @@ -311,8 +349,13 @@ def test_bgp_converge(): # CLI(net) def test_bgp_routingTable(): + global fatal_error global net + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table @@ -362,5 +405,7 @@ def test_bgp_routingTable(): if __name__ == '__main__': setLogLevel('info') + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) retval = pytest.main(["-s"]) sys.exit(retval) From 6b1be61ad89d3e87ef53f875dadbabdf022b447d Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 25 Nov 2016 20:11:02 -0800 Subject: [PATCH 014/384] Update Documentation --- tests/topotests/README.md | 47 ++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index f9c9079266..0e34091cc7 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -12,8 +12,29 @@ tests) 2. apt-get install python-pip 3. apt-get install iproute 4. pip install ipaddr -5. pip install exabgp -6. useradd -d /var/run/exabgp/ -s /bin/false exabgp +5. pip install pytest +6. pip install exabgp +7. useradd -d /var/run/exabgp/ -s /bin/false exabgp + +### Enable Coredumps +Optional, will give better output + +1. apt-get install gdb +2. disable apport (which move core files) + + Set `enabled=0` in `/etc/default/apport` + +3. Update security limits + + Add/change `/etc/security/limits.conf` to + + # + * soft core unlimited + root soft core unlimited + * hard core unlimited + root hard core unlimited + +4. reboot (for options to take effect) ### Quagga Installation Quagga needs to be installed separatly. It is assume to be configured @@ -23,14 +44,31 @@ like the standard Ubuntu Packages: - Running under user quagga, group quagga - vtygroup: quaggavty - config directory: /etc/quagga +- For Quagga Packages, install the dbg package as well for coredump decoding No Quagga config needs to be done and no Quagga daemons should be run ahead of the test. They are all started as part of the test ## Executing Tests -Go to test directory and execute python script. -Test will run all on it's own and return non-zero exit code if it fails. +#### Execute all tests with output to console + + py.test -s -v --tb=no + +All test_* scripts in subdirectories are detected and executed (unless disabled in +`pytest.ini` file) + +`--tb=no` disables the python traceback which might be irrelevant unless the +test script itself is debugged + +#### Execute single test + + cd test_to_be_run + ./test_to_be_run.py + +For further options, refer to pytest documentation + +Test will set exit code which can be used with `git bisect` For the simulated topology, see the description in the python file @@ -41,4 +79,3 @@ shutdown), then use the `mn -c` command to clean up the environment All the configs and scripts are licensed under a ISC-style license. See Python scripts for details. - From 309c9764c512d39ca404e34dd106ee2d8a3d9a76 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 25 Nov 2016 20:19:10 -0800 Subject: [PATCH 015/384] example-test: Add simple example pytest for documentation (and exclude it from running in pytest.ini) --- tests/topotests/example-test/test_example.py | 60 ++++++++++++++++++++ tests/topotests/pytest.ini | 3 + 2 files changed, 63 insertions(+) create mode 100755 tests/topotests/example-test/test_example.py create mode 100644 tests/topotests/pytest.ini diff --git a/tests/topotests/example-test/test_example.py b/tests/topotests/example-test/test_example.py new file mode 100755 index 0000000000..8e37ad11d4 --- /dev/null +++ b/tests/topotests/example-test/test_example.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +import subprocess +import sys +import os +import time + +import pytest + +fatal_error = "" + +def setup_module(module): + print ("setup_module module:%s" % module.__name__) + +def teardown_module(module): + print ("teardown_module module:%s" % module.__name__) + +def setup_function(function): + print ("setup_function function:%s" % function.__name__) + +def teardown_function(function): + print ("teardown_function function:%s" % function.__name__) + +def test_numbers_compare(): + a = 12 + print ("Dummy Output") + assert( a == 12 ) + +def test_fail_example(): + assert True, "Some Text with explaination in case of failure" + +def test_ls_exits_zero(): + "Tests for ls command on invalid file" + + global fatal_error + + proc = subprocess.Popen( + ["ls", "/some/nonexistant/file"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + stdout, stderr = proc.communicate() + + if (proc.returncode != 0): + # Mark this as a fatal error which skips some other tests on failure + fatal_error = "test_fail_example failed" + assert proc.returncode == 0, "Return Code is non-Zero:\n%s" % stderr + +def test_skipped_on_fatalerror(): + global fatal_error + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + assert True, "Some Text with explaination in case of failure" + +if __name__ == '__main__': + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini new file mode 100644 index 0000000000..a744b34aae --- /dev/null +++ b/tests/topotests/pytest.ini @@ -0,0 +1,3 @@ +# Skip pytests example directory +[pytest] +norecursedirs = .git example-test From 64581658b1e352d93064a7940cb61fe792e17d05 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 26 Nov 2016 02:56:28 -0800 Subject: [PATCH 016/384] bgp_multiview_topo1: Rename received bgp route log with .log for easy clean between runs --- tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py | 2 +- tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py | 2 +- tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py | 2 +- tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py | 2 +- tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py | 2 +- tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py | 2 +- tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py | 2 +- tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py index 8e65f1ae9a..5334ea5369 100755 --- a/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py +++ b/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py @@ -13,7 +13,7 @@ peer = int(argv[1]) # When the parent dies we are seeing continual newlines, so we only access so many before stopping counter = 0 -routesavefile = open('/tmp/peer%s-received' % peer, 'w') +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') while True: try: diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py index 8e65f1ae9a..5334ea5369 100755 --- a/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py +++ b/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py @@ -13,7 +13,7 @@ peer = int(argv[1]) # When the parent dies we are seeing continual newlines, so we only access so many before stopping counter = 0 -routesavefile = open('/tmp/peer%s-received' % peer, 'w') +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') while True: try: diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py index 8e65f1ae9a..5334ea5369 100755 --- a/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py +++ b/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py @@ -13,7 +13,7 @@ peer = int(argv[1]) # When the parent dies we are seeing continual newlines, so we only access so many before stopping counter = 0 -routesavefile = open('/tmp/peer%s-received' % peer, 'w') +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') while True: try: diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py index 8e65f1ae9a..5334ea5369 100755 --- a/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py +++ b/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py @@ -13,7 +13,7 @@ peer = int(argv[1]) # When the parent dies we are seeing continual newlines, so we only access so many before stopping counter = 0 -routesavefile = open('/tmp/peer%s-received' % peer, 'w') +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') while True: try: diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py index 8e65f1ae9a..5334ea5369 100755 --- a/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py +++ b/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py @@ -13,7 +13,7 @@ peer = int(argv[1]) # When the parent dies we are seeing continual newlines, so we only access so many before stopping counter = 0 -routesavefile = open('/tmp/peer%s-received' % peer, 'w') +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') while True: try: diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py index 8e65f1ae9a..5334ea5369 100755 --- a/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py +++ b/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py @@ -13,7 +13,7 @@ peer = int(argv[1]) # When the parent dies we are seeing continual newlines, so we only access so many before stopping counter = 0 -routesavefile = open('/tmp/peer%s-received' % peer, 'w') +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') while True: try: diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py index 8e65f1ae9a..5334ea5369 100755 --- a/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py +++ b/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py @@ -13,7 +13,7 @@ peer = int(argv[1]) # When the parent dies we are seeing continual newlines, so we only access so many before stopping counter = 0 -routesavefile = open('/tmp/peer%s-received' % peer, 'w') +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') while True: try: diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py index 8e65f1ae9a..5334ea5369 100755 --- a/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py +++ b/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py @@ -13,7 +13,7 @@ peer = int(argv[1]) # When the parent dies we are seeing continual newlines, so we only access so many before stopping counter = 0 -routesavefile = open('/tmp/peer%s-received' % peer, 'w') +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') while True: try: From 5ead87b456baf3654273c6611b7abc22d01051ae Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 26 Nov 2016 02:57:03 -0800 Subject: [PATCH 017/384] bgp_multiview_topo1: Fix limit to create coredumps on quagga crashes --- .../bgp_multiview_topo1/test_bgp_multiview_topo1.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index e3654df841..db6d333538 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -90,6 +90,7 @@ class QuaggaRouter(Node): self.cmd('sysctl kernel.core_uses_pid=1') self.cmd('sysctl fs.suid_dumpable=2') self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) + self.cmd('ulimit -c unlimited') # Set ownership of config files self.cmd('chown quagga:quaggavty /etc/quagga') self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, @@ -161,14 +162,14 @@ class QuaggaRouter(Node): # Look for core file corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) if (len(corefiles) > 0): - backtrace = subprocess.check_output(["gdb /usr/lib/quagga/%s %s --batch -ex bt" % (daemon, corefiles[0])], shell=True) - sys.stderr.write("%s %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) + backtrace = subprocess.check_output(["gdb /usr/lib/quagga/%s %s --batch -ex bt 2> /dev/null" % (daemon, corefiles[0])], shell=True) + sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) sys.stderr.write("%s\n" % backtrace) else: # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): - log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log" % (self.name, daemon)], shell=True) - sys.stderr.write("From quagga %s %s log file:\n" % (self.name, daemon)) + log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) + sys.stderr.write("\nFrom quagga %s %s log file:\n" % (self.name, daemon)) sys.stderr.write("%s\n" % log_tail) fatal_error = "%s: Daemon %s not running" % (self.name, daemon) From 04df53ab5a242862266a59a6a40e8af6f1e0e5f2 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 26 Nov 2016 14:49:56 -0800 Subject: [PATCH 018/384] bgp_multiview_topo1: Added Network Diagram as comment --- .../test_bgp_multiview_topo1.py | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index db6d333538..3f8523e997 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -25,8 +25,42 @@ """ test_bgp_multiview_topo1.py: Simple Quagga Route-Server Test -See Topology Diagram bgp-routeserver-1.pdf -""" ++----------+ +----------+ +----------+ +----------+ +----------+ +| peer1 | | peer2 | | peer3 | | peer4 | | peer5 | +| AS 65001 | | AS 65002 | | AS 65003 | | AS 65004 | | AS 65005 | ++-----+----+ +-----+----+ +-----+----+ +-----+----+ +-----+----+ + | .1 | .2 | .3 | .4 | .5 + | ______/ / / _________/ + \ / ________________/ / / + | | / _________________________/ / +----------+ + | | | / __________________________/ ___| peer6 | + | | | | / ____________________________/.6 | AS 65006 | + | | | | | / _________________________ +----------+ + | | | | | | / __________________ \ +----------+ + | | | | | | | / \ \___| peer7 | + | | | | | | | | \ .7 | AS 65007 | + ~~~~~~~~~~~~~~~~~~~~~ \ +----------+ + ~~ SW1 ~~ \ +----------+ + ~~ Switch ~~ \_____| peer8 | + ~~ 172.16.1.0/24 ~~ .8 | AS 65008 | + ~~~~~~~~~~~~~~~~~~~~~ +----------+ + | + | .254 + +---------+---------+ + | Quagga R1 | + | BGP Multi-View | + | Peer 1-3 > View 1 | + | Peer 4-5 > View 2 | + | Peer 6-8 > View 3 | + +---------+---------+ + | .1 + | + ~~~~~~~~~~~~~ Stub Network is redistributed + ~~ SW0 ~~ into each BGP view with different + ~~ 172.20.0.1/28 ~~ attributes (using route-map) + ~~ Stub Switch ~~ + ~~~~~~~~~~~~~ +""" import os import re From a99a6a026ecd45d986274f4e3efca31183ebd182 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 26 Nov 2016 14:50:57 -0800 Subject: [PATCH 019/384] ospf6-topo1: Enable coredumps for Quagga Daemons and add logic to skip remaining test in case of fatal error --- .../topotests/ospf6-topo1/test_ospf6_topo1.py | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index e7d0b1ab9f..12bcbe332c 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -75,6 +75,8 @@ import re import sys import difflib import StringIO +import glob +import subprocess from mininet.topo import Topo from mininet.net import Mininet @@ -87,6 +89,8 @@ from time import sleep import pytest +fatal_error = "" + def int2dpid(dpid): "Converting Integer to DPID" @@ -123,6 +127,12 @@ class QuaggaRouter(Node): # Enable forwarding on the router self.cmd('sysctl net.ipv4.ip_forward=1') self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + # Enable coredumps + self.cmd('sysctl kernel.core_uses_pid=1') + self.cmd('sysctl fs.suid_dumpable=2') + self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) + self.cmd('ulimit -c unlimited') + # Set ownership of config files self.cmd('chown quagga:quaggavty /etc/quagga') self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} @@ -162,6 +172,10 @@ class QuaggaRouter(Node): with open("/etc/quagga/vtysh.conf", "w") as vtyshfile: vtyshfile.write('no service integrated-vtysh-config') self.cmd('chown quagga:quaggavty /etc/quagga/vtysh.conf') + # Try to find relevant old logfiles in /tmp and delete them + map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) + # Remove old core files + map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) # Remove IP addresses from OS first - we have them in zebra.conf self.removeIPs() # Start Zebra first @@ -180,10 +194,27 @@ class QuaggaRouter(Node): self.waitOutput() print('%s: %s started' % (self, daemon)) def checkQuaggaRunning(self): + global fatal_error + daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') for daemon in self.daemons: - if (self.daemons[daemon] == 1): - assert daemon in daemonsRunning, "Daemon %s not running" % daemon + if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): + sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) + # Look for core file + corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) + if (len(corefiles) > 0): + backtrace = subprocess.check_output(["gdb /usr/lib/quagga/%s %s --batch -ex bt 2> /dev/null" % (daemon, corefiles[0])], shell=True) + sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) + sys.stderr.write("%s\n" % backtrace) + else: + # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. + if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): + log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) + sys.stderr.write("\nFrom quagga %s %s log file:\n" % (self.name, daemon)) + sys.stderr.write("%s\n" % log_tail) + + fatal_error = "%s: Daemon %s not running" % (self.name, daemon) + assert False, "%s: Daemon %s not running" % (self.name, daemon) class LegacySwitch(OVSSwitch): @@ -281,8 +312,13 @@ def teardown_module(module): def test_quagga_running(): + global fatal_error global net + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + print("\n\n** Check if Quagga is running on each Router node") print("******************************************\n") sleep(5) @@ -293,8 +329,13 @@ def test_quagga_running(): def test_ospf6_converged(): + global fatal_error global net + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State) print("\n\n** Verify for OSPF6 daemons to converge") print("******************************************\n") @@ -319,7 +360,7 @@ def test_ospf6_converged(): else: # Bail out with error if a router fails to converge ospfStatus = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh"') - + fatal_error = "OSPFv6 did not converge" assert False, "OSPFv6 did not converge:\n%s" % ospfStatus print("OSPFv3 converged.") @@ -330,8 +371,13 @@ def test_ospf6_converged(): sleep(15) def test_ospf6_routingTable(): + global fatal_error global net + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table @@ -367,9 +413,14 @@ def test_ospf6_routingTable(): assert failures == 0, "Routing Table verification failed for router r%s:\n%s" % (i, diff) + # For debugging after starting Quagga daemons, uncomment the next line + # CLI(net) + if __name__ == '__main__': setLogLevel('info') + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) retval = pytest.main(["-s"]) sys.exit(retval) From 2bdcdbd1b8afbf1a0fedb9a14dc80ccc5f6dca9e Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 26 Nov 2016 17:30:22 -0800 Subject: [PATCH 020/384] ospf6-topo1: Add check for Linux Kernel Routing Table as well and change to better human readable context diff --- .../topotests/ospf6-topo1/r1/ip_6_address.ref | 13 +++ .../topotests/ospf6-topo1/r2/ip_6_address.ref | 13 +++ .../topotests/ospf6-topo1/r3/ip_6_address.ref | 14 +++ .../topotests/ospf6-topo1/r4/ip_6_address.ref | 13 +++ .../topotests/ospf6-topo1/test_ospf6_topo1.py | 99 +++++++++++++++++-- 5 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 tests/topotests/ospf6-topo1/r1/ip_6_address.ref create mode 100644 tests/topotests/ospf6-topo1/r2/ip_6_address.ref create mode 100644 tests/topotests/ospf6-topo1/r3/ip_6_address.ref create mode 100644 tests/topotests/ospf6-topo1/r4/ip_6_address.ref diff --git a/tests/topotests/ospf6-topo1/r1/ip_6_address.ref b/tests/topotests/ospf6-topo1/r1/ip_6_address.ref new file mode 100644 index 0000000000..2f7e246c15 --- /dev/null +++ b/tests/topotests/ospf6-topo1/r1/ip_6_address.ref @@ -0,0 +1,13 @@ +fc00:1:1:1::/64 dev r1-stubnet proto kernel metric 256 pref medium +fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium +fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium +fc00:a:a:a::/64 dev r1-sw5 proto kernel metric 256 pref medium +fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium +fc00:1111:1111:1111::/64 via fc00:1:1:1::1234 dev r1-stubnet proto zebra metric 20 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium +unreachable fe80::/64 dev lo proto kernel metric 256 error -101 pref medium +fe80::/64 dev r1-stubnet proto kernel metric 256 pref medium +fe80::/64 dev r1-sw5 proto kernel metric 256 pref medium diff --git a/tests/topotests/ospf6-topo1/r2/ip_6_address.ref b/tests/topotests/ospf6-topo1/r2/ip_6_address.ref new file mode 100644 index 0000000000..5dd539f038 --- /dev/null +++ b/tests/topotests/ospf6-topo1/r2/ip_6_address.ref @@ -0,0 +1,13 @@ +fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium +fc00:2:2:2::/64 dev r2-stubnet proto kernel metric 256 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium +fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium +fc00:a:a:a::/64 dev r2-sw5 proto kernel metric 256 pref medium +fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium +fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium +fc00:2222:2222:2222::/64 via fc00:2:2:2::1234 dev r2-stubnet proto zebra metric 20 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium +unreachable fe80::/64 dev lo proto kernel metric 256 error -101 pref medium +fe80::/64 dev r2-stubnet proto kernel metric 256 pref medium +fe80::/64 dev r2-sw5 proto kernel metric 256 pref medium diff --git a/tests/topotests/ospf6-topo1/r3/ip_6_address.ref b/tests/topotests/ospf6-topo1/r3/ip_6_address.ref new file mode 100644 index 0000000000..ce54ceced9 --- /dev/null +++ b/tests/topotests/ospf6-topo1/r3/ip_6_address.ref @@ -0,0 +1,14 @@ +fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto zebra metric 20 pref medium +fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto zebra metric 20 pref medium +fc00:3:3:3::/64 dev r3-stubnet proto kernel metric 256 pref medium +fc00:4:4:4::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto zebra metric 20 pref medium +fc00:a:a:a::/64 dev r3-sw5 proto kernel metric 256 pref medium +fc00:b:b:b::/64 dev r3-sw6 proto kernel metric 256 pref medium +fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto zebra metric 20 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto zebra metric 20 pref medium +fc00:3333:3333:3333::/64 via fc00:3:3:3::1234 dev r3-stubnet proto zebra metric 20 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto zebra metric 20 pref medium +unreachable fe80::/64 dev lo proto kernel metric 256 error -101 pref medium +fe80::/64 dev r3-stubnet proto kernel metric 256 pref medium +fe80::/64 dev r3-sw5 proto kernel metric 256 pref medium +fe80::/64 dev r3-sw6 proto kernel metric 256 pref medium diff --git a/tests/topotests/ospf6-topo1/r4/ip_6_address.ref b/tests/topotests/ospf6-topo1/r4/ip_6_address.ref new file mode 100644 index 0000000000..e7307f0088 --- /dev/null +++ b/tests/topotests/ospf6-topo1/r4/ip_6_address.ref @@ -0,0 +1,13 @@ +fc00:1:1:1::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium +fc00:2:2:2::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium +fc00:4:4:4::/64 dev r4-stubnet proto kernel metric 256 pref medium +fc00:a:a:a::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium +fc00:b:b:b::/64 dev r4-sw6 proto kernel metric 256 pref medium +fc00:1111:1111:1111::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium +fc00:4444:4444:4444::/64 via fc00:4:4:4::1234 dev r4-stubnet proto zebra metric 20 pref medium +unreachable fe80::/64 dev lo proto kernel metric 256 error -101 pref medium +fe80::/64 dev r4-stubnet proto kernel metric 256 pref medium +fe80::/64 dev r4-sw6 proto kernel metric 256 pref medium diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 12bcbe332c..09dc538baf 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -215,6 +215,30 @@ class QuaggaRouter(Node): fatal_error = "%s: Daemon %s not running" % (self.name, daemon) assert False, "%s: Daemon %s not running" % (self.name, daemon) + def get_ipv6_linklocal(self): + "Get LinkLocal Addresses from interfaces" + + linklocal = [] + + ifaces = self.cmd('ip -6 address') + # Fix newlines (make them all the same) + ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines() + interface="" + ll_per_if_count=0 + for line in ifaces: + m = re.search('[0-9]+: ([^:@]+)[@if0-9:]+ <', line) + if m: + interface = m.group(1) + ll_per_if_count = 0 + m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)[/0-9]* scope link', line) + if m: + local = m.group(1) + ll_per_if_count += 1 + if (ll_per_if_count > 1): + linklocal += [["%s-%s" % (interface, ll_per_if_count), local]] + else: + linklocal += [[interface, local]] + return linklocal class LegacySwitch(OVSSwitch): @@ -337,7 +361,7 @@ def test_ospf6_converged(): pytest.skip(fatal_error) # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State) - print("\n\n** Verify for OSPF6 daemons to converge") + print("\n\n** Verify OSPF6 daemons to converge") print("******************************************\n") timeout = 60 while timeout > 0: @@ -370,7 +394,7 @@ def test_ospf6_converged(): print("\nwaiting 15s for routes to populate") sleep(15) -def test_ospf6_routingTable(): +def test_ospfv3_routingTable(): global fatal_error global net @@ -402,16 +426,79 @@ def test_ospf6_routingTable(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.unified_diff(actual, expected)) - # Empty string if it matches, otherwise diff contains unified diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual OSPFv3 IPv6 routing table", + tofile="expected OSPFv3 IPv6 routing table")) + # Empty string if it matches, otherwise diff contains unified diff if diff: - sys.stderr.write('r%s failed Routing Table Check:\n%s\n' % (i, diff)) + sys.stderr.write('r%s failed OSPFv3 (IPv6) Routing Table Check:\n%s\n' % (i, diff)) failures += 1 else: print("r%s ok" % i) - assert failures == 0, "Routing Table verification failed for router r%s:\n%s" % (i, diff) + assert failures == 0, "OSPFv3 (IPv6) Routing Table verification failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting Quagga daemons, uncomment the next line + # CLI(net) + +def test_linux_ipv6_kernel_routingTable(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify Linux Kernel Routing Table + print("\n\n** Verifing Linux IPv6 Kernel Routing Table") + print("******************************************\n") + failures = 0 + + # Get a list of all current link-local addresses first as they change for + # each run and we need to translate them + linklocals = [] + for i in range(1, 5): + linklocals += net['r%s' % i].get_ipv6_linklocal() + + # Now compare the routing tables (after substituting link-local addresses) + for i in range(1, 5): + refTableFile = '%s/r%s/ip_6_address.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines())).splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('ip -6 route').rstrip() + # Mask out Link-Local mac addresses + for ll in linklocals: + actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0]) + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines())).splitlines(1) + + # Print Actual table + # print("Router r%s table" % i) + # for line in actual: + # print(line.rstrip()) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual IPv6 kernel routing table", + tofile="expected IPv6 kernel routing table")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff) # For debugging after starting Quagga daemons, uncomment the next line # CLI(net) From 3b6bac2adf98aca0a05a201df7e40e26648c6982 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 26 Nov 2016 17:36:07 -0800 Subject: [PATCH 021/384] bgp_multiview_topo1: Change from unified to context diff for better readability --- .../topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 3f8523e997..b0834336d7 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -421,7 +421,9 @@ def test_bgp_routingTable(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.unified_diff(actual, expected)) + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual BGP routing table", + tofile="expected BGP routing table")) # Empty string if it matches, otherwise diff contains unified diff if diff: From 024fc0b8bc537e2c962ef2620bd3d5b7bf7dea55 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 30 Nov 2016 19:50:29 -0800 Subject: [PATCH 022/384] README: Add example configure statement for building test quagga code --- tests/topotests/README.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index 0e34091cc7..69548f5577 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -1,7 +1,7 @@ # Quagga Topology Tests with Mininet ## Installation of Mininet for running tests -Only tested with Ubuntu 16.04 +Only tested with Ubuntu 16.04 (which uses Mininet 2.2.0) Instructions are the same for all setups (ie ExaBGP is only used for BGP tests) @@ -36,11 +36,12 @@ Optional, will give better output 4. reboot (for options to take effect) -### Quagga Installation +## Quagga Installation Quagga needs to be installed separatly. It is assume to be configured like the standard Ubuntu Packages: - Binaries in /usr/lib/quagga +- State Directory /var/run/quagga - Running under user quagga, group quagga - vtygroup: quaggavty - config directory: /etc/quagga @@ -49,6 +50,31 @@ like the standard Ubuntu Packages: No Quagga config needs to be done and no Quagga daemons should be run ahead of the test. They are all started as part of the test +#### Manual Quagga build + +If you prefer to manually build Quagga, then use the following suggested config: + + ./configure \ + --prefix=/usr \ + --localstatedir=/var/run/quagga \ + --sbindir=/usr/lib/quagga \ + --sysconfdir=/etc/quagga \ + --enable-vtysh \ + --enable-pimd \ + --enable-multipath=64 \ + --enable-user=quagga \ + --enable-group=quagga \ + --enable-vty-group=quaggavty \ + --with-pkg-extra-version=-my-manual-build + +And create Quagga User and Quaggavty group as follows: + + addgroup --system --gid 92 quagga + addgroup --system --gid 85 quaggavty + usermod -G quaggavty quagga + adduser --system --ingroup quagga --home /var/run/quagga/ \ + --gecos "Quagga routing suite" --shell /bin/false quagga + ## Executing Tests #### Execute all tests with output to console From d71f3675804dff4ef7a80a14f4d08abda45a9e52 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 30 Nov 2016 19:51:16 -0800 Subject: [PATCH 023/384] bgp_multiview_topo1: Add Markdown doc for test --- .../bgp_multiview_topo1/test_description.md | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 tests/topotests/bgp_multiview_topo1/test_description.md diff --git a/tests/topotests/bgp_multiview_topo1/test_description.md b/tests/topotests/bgp_multiview_topo1/test_description.md new file mode 100644 index 0000000000..79bbb36b6b --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/test_description.md @@ -0,0 +1,127 @@ +# Simple Quagga Route-Server Test + +## Topology + +----------+ +----------+ +----------+ +----------+ +----------+ + | peer1 | | peer2 | | peer3 | | peer4 | | peer5 | + | AS 65001 | | AS 65002 | | AS 65003 | | AS 65004 | | AS 65005 | + +-----+----+ +-----+----+ +-----+----+ +-----+----+ +-----+----+ + | .1 | .2 | .3 | .4 | .5 + | ______/ / / _________/ + \ / ________________/ / / + | | / _________________________/ / +----------+ + | | | / __________________________/ ___| peer6 | + | | | | / ____________________________/.6 | AS 65006 | + | | | | | / _________________________ +----------+ + | | | | | | / __________________ \ +----------+ + | | | | | | | / \ \___| peer7 | + | | | | | | | | \ .7 | AS 65007 | + ~~~~~~~~~~~~~~~~~~~~~ \ +----------+ + ~~ SW1 ~~ \ +----------+ + ~~ Switch ~~ \_____| peer8 | + ~~ 172.16.1.0/24 ~~ .8 | AS 65008 | + ~~~~~~~~~~~~~~~~~~~~~ +----------+ + | + | .254 + +---------+---------+ + | Quagga R1 | + | BGP Multi-View | + | Peer 1-3 > View 1 | + | Peer 4-5 > View 2 | + | Peer 6-8 > View 3 | + +---------+---------+ + | .1 + | + ~~~~~~~~~~~~~ Stub Network is redistributed + ~~ SW0 ~~ into each BGP view with different + ~~ 172.20.0.1/28 ~~ attributes (using route-map) + ~~ Stub Switch ~~ + ~~~~~~~~~~~~~ + +## Quagga Configuration + +Full config as used is in r1 subdirectory + +Simplified `R1` config: + + hostname r1 + ! + interface r1-stub + description Stub Network + ip address 172.20.0.1/28 + no link-detect + ! + interface r1-eth0 + description to PE router - vlan1 + ip address 172.16.1.254/24 + no link-detect + ! + bgp multiple-instance + ! + router bgp 100 view 1 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 route-map local1 + timers bgp 60 180 + neighbor 172.16.1.1 remote-as 65001 + neighbor 172.16.1.2 remote-as 65002 + neighbor 172.16.1.5 remote-as 65005 + ! + router bgp 100 view 2 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 route-map local2 + timers bgp 60 180 + neighbor 172.16.1.3 remote-as 65003 + neighbor 172.16.1.4 remote-as 65004 + ! + router bgp 100 view 3 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 + timers bgp 60 180 + neighbor 172.16.1.6 remote-as 65006 + neighbor 172.16.1.7 remote-as 65007 + neighbor 172.16.1.8 remote-as 65008 + ! + route-map local1 permit 10 + set community 100:9999 additive + set metric 0 + ! + route-map local2 permit 10 + set as-path prepend 100 100 100 100 100 + set community 100:1 additive + set metric 9999 + ! + +## Tests executed + +### Check if Quagga is running + +Test is executed by running + + vtysh -c "show log" | grep "Logging configuration for" + +on router `R1`. This should return the logging information for all daemons registered +to Zebra and the list of running daemons is compared to the daemons started for this +test (`zebra` and `bgpd`) + +### Verify for BGP to converge + +BGP is expected to converge on each view within 60s total time. Convergence is verified by executing + + vtysh -c "show ip bgp view 1 summary" + vtysh -c "show ip bgp view 2 summary" + vtysh -c "show ip bgp view 3 summary" + +and expecting 11 routes seen in the last column for each peer. (Each peer sends 11 routes) + +### Verifing BGP Routing Tables + +Routing table is verified by running + + vtysh -c "show ip bgp view 1" + vtysh -c "show ip bgp view 2" + vtysh -c "show ip bgp view 3" + +and comparing the result against the stored table in the r1/show_ip_bgp_view_NN.ref files +(with NN 1, 2, 3) (A few header and trailer lines are cut/adjusted ahead of the compare to +adjust for different output based on recent changes) + + From 6d9d0176e4b3c0bbde31ea6d8872b8e5d5165e82 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 30 Nov 2016 19:58:30 -0800 Subject: [PATCH 024/384] bgp_multiview_topo1: Rename test_description.md to README.md for automatic rendering in online git --- .../bgp_multiview_topo1/{test_description.md => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/topotests/bgp_multiview_topo1/{test_description.md => README.md} (100%) diff --git a/tests/topotests/bgp_multiview_topo1/test_description.md b/tests/topotests/bgp_multiview_topo1/README.md similarity index 100% rename from tests/topotests/bgp_multiview_topo1/test_description.md rename to tests/topotests/bgp_multiview_topo1/README.md From 615f6ba3207c9dcbf2d8f41659d2c093de9eb622 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 1 Dec 2016 02:23:38 -0800 Subject: [PATCH 025/384] ospf6-topo1: Add Markdown doc with testdescription --- tests/topotests/ospf6-topo1/README.md | 132 ++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 tests/topotests/ospf6-topo1/README.md diff --git a/tests/topotests/ospf6-topo1/README.md b/tests/topotests/ospf6-topo1/README.md new file mode 100644 index 0000000000..864c8e9ede --- /dev/null +++ b/tests/topotests/ospf6-topo1/README.md @@ -0,0 +1,132 @@ +# OSPFv3 (IPv6) Topology Test + +## Topology + -----\ + SW1 - Stub Net 1 SW2 - Stub Net 2 \ + fc00:1:1:1::/64 fc00:2:2:2::/64 \ + \___________________/ \___________________/ | + | | | + | | | + | ::1 | ::2 | + +---------+---------+ +---------+---------+ | + | R1 | | R2 | | + | Quagga | | Quagga | | + | Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | | + +---------+---------+ +---------+---------+ | + | ::1 | ::2 \ + \______ ___________/ OSPFv3 + \ / Area 0.0.0.0 + \ / / + ~~~~~~~~~~~~~~~~~~ | + ~~ SW5 ~~ | + ~~ Switch ~~ | + ~~ fc00:A:A:A::/64 ~~ | + ~~~~~~~~~~~~~~~~~~ | + | /---- | + | ::3 | SW3 - Stub Net 3 | + +---------+---------+ /-+ fc00:3:3:3::/64 | + | R3 | / | / + | Quagga +--/ \---- / + | Rtr-ID: 10.0.0.3 | ::3 ___________/ + +---------+---------+ \ + | ::3 \ + | \ + ~~~~~~~~~~~~~~~~~~ | + ~~ SW6 ~~ | + ~~ Switch ~~ | + ~~ fc00:B:B:B::/64 ~~ \ + ~~~~~~~~~~~~~~~~~~ OSPFv3 + | Area 0.0.0.1 + | ::4 / + +---------+---------+ /---- | + | R4 | | SW4 - Stub Net 4 | + | Quagga +------+ fc00:4:4:4::/64 | + | Rtr-ID: 10.0.0.4 | ::4 | / + +-------------------+ \---- / + -----/ + +## Quagga Configuration + +Full config as used is in r1 / r2 / r3 / r4 / r5 subdirectories + +Simplified `R1` config (R1 is similar) + + hostname r1 + ! + interface r1-stubnet + ipv6 address fc00:1:1:1::1/64 + ipv6 ospf6 network broadcast + ! + interface r1-sw5 + ipv6 address fc00:a:a:a::1/64 + ipv6 ospf6 network broadcast + ! + router ospf6 + router-id 10.0.0.1 + log-adjacency-changes detail + redistribute static + interface r1-stubnet area 0.0.0.0 + interface r1-sw5 area 0.0.0.0 + ! + ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234 + +Simplified `R3` config + + hostname r3 + ! + interface r3-stubnet + ipv6 address fc00:3:3:3::3/64 + ipv6 ospf6 network broadcast + ! + interface r3-sw5 + ipv6 address fc00:a:a:a::3/64 + ipv6 ospf6 network broadcast + ! + interface r3-sw6 + ipv6 address fc00:b:b:b::3/64 + ipv6 ospf6 network broadcast + ! + router ospf6 + router-id 10.0.0.3 + log-adjacency-changes detail + redistribute static + interface r3-stubnet area 0.0.0.0 + interface r3-sw5 area 0.0.0.0 + interface r3-sw6 area 0.0.0.1 + ! + ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234 + +## Tests executed + +### Check if Quagga is running + +Test is executed by running + + vtysh -c "show log" | grep "Logging configuration for" + +on each quagga router. This should return the logging information for all daemons registered +to Zebra and the list of running daemons is compared to the daemons started for this test (`zebra` and `ospf6d`) + +### Verify for OSPFv3 to converge + +OSPFv3 is expected to converge on each view within 60s total time. Convergence is verified by executing (on each node) + + vtysh -c "show ipv6 ospf neigh" + +and checking for "Full" neighbor status in the output. An additional 15 seconds after the full converge is waited for routes to populate before the following routing table checks are executed + +### Verifing OSPFv3 Routing Tables + +Routing table is verified by running + + vtysh -c "show ipv6 route" + +on each node and comparing the result to the stored example config (see `show_ipv6_route.ref` in r1 / r2 / r3 / r4 directories). Link-Local addresses are masked out before the compare. + +### Verifying Linux Kernel Routing Table + +Linux Kernel IPv6 Routing table is verified on each Quagga node with + + ip -6 route + +Tables are compared with reference routing table (see `ip_6_address.ref` in r1 / r2 / r3 / r4 directories). Link-Local addresses are translated after getting collected on each node with interface name to make them consistent From 593335d02de255130c48fa61eda805c525d6dc0f Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Tue, 20 Dec 2016 15:19:52 +0700 Subject: [PATCH 026/384] change in checkRunning: Check all daemons on all nodes before aborting with an assert --- .../test_bgp_multiview_topo1.py | 18 ++++++++++++------ .../topotests/ospf6-topo1/test_ospf6_topo1.py | 16 +++++++++++----- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index b0834336d7..e0ee850c3c 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -190,6 +190,7 @@ class QuaggaRouter(Node): global fatal_error daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') + failed = [] for daemon in self.daemons: if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) @@ -205,9 +206,8 @@ class QuaggaRouter(Node): log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) sys.stderr.write("\nFrom quagga %s %s log file:\n" % (self.name, daemon)) sys.stderr.write("%s\n" % log_tail) - - fatal_error = "%s: Daemon %s not running" % (self.name, daemon) - assert False, "%s: Daemon %s not running" % (self.name, daemon) + failed += [daemon] + return failed class LegacySwitch(OVSSwitch): "A Legacy Switch without OpenFlow" @@ -331,9 +331,15 @@ def test_quagga_running(): print("******************************************\n") sleep(5) - # Starting Routers - for i in range(1, 2): - net['r%s' % i].checkQuaggaRunning() + # CLI(net) + failedRunning = "" + for i in range(1, 5): + failedDaemon = net['r%s' % i].checkQuaggaRunning() + if failedDaemon: + failedRunning += " Daemons failed on r%s: %s\n" % (i, failedDaemon) + if failedRunning: + fatal_error = "Some Daemons failed to start or crashed" + assert False, "Daemons failed to start or crashed:\n%s" % failedRunning def test_bgp_converge(): "Check for BGP converged on all peers and BGP views" diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 09dc538baf..2a79380130 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -197,6 +197,7 @@ class QuaggaRouter(Node): global fatal_error daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') + failed = [] for daemon in self.daemons: if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) @@ -212,9 +213,8 @@ class QuaggaRouter(Node): log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) sys.stderr.write("\nFrom quagga %s %s log file:\n" % (self.name, daemon)) sys.stderr.write("%s\n" % log_tail) - - fatal_error = "%s: Daemon %s not running" % (self.name, daemon) - assert False, "%s: Daemon %s not running" % (self.name, daemon) + failed += [daemon] + return failed def get_ipv6_linklocal(self): "Get LinkLocal Addresses from interfaces" @@ -347,9 +347,15 @@ def test_quagga_running(): print("******************************************\n") sleep(5) - # Starting Routers + # CLI(net) + failedRunning = "" for i in range(1, 5): - net['r%s' % i].checkQuaggaRunning() + failedDaemon = net['r%s' % i].checkQuaggaRunning() + if failedDaemon: + failedRunning += " Daemons failed on r%s: %s\n" % (i, failedDaemon) + if failedRunning: + fatal_error = "Some Daemons failed to start or crashed" + assert False, "Daemons failed to start or crashed:\n%s" % failedRunning def test_ospf6_converged(): From b36d3e1c85b21321ef6e3bd56891e8c062a12a31 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sun, 15 Jan 2017 00:45:57 +0700 Subject: [PATCH 027/384] Add support for FRR in addition to Quagga --- .../test_bgp_multiview_topo1.py | 46 ++++++++++------ .../topotests/ospf6-topo1/test_ospf6_topo1.py | 53 +++++++++++-------- 2 files changed, 60 insertions(+), 39 deletions(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index e0ee850c3c..fbafd30cf5 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -117,6 +117,13 @@ class QuaggaRouter(Node): def config(self, **params): super(QuaggaRouter, self).config(**params) + # Check if Quagga or FRR is installed + if os.path.isfile('/usr/lib/frr/zebra'): + self.routertype = 'frr' + elif os.path.isfile('/usr/lib/quagga/zebra'): + self.routertype = 'quagga' + else: + raise Exception('No FRR or Quagga found in ususal location') # Enable forwarding on the router self.cmd('sysctl net.ipv4.ip_forward=1') self.cmd('sysctl net.ipv6.conf.all.forwarding=1') @@ -126,7 +133,7 @@ class QuaggaRouter(Node): self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) self.cmd('ulimit -c unlimited') # Set ownership of config files - self.cmd('chown quagga:quaggavty /etc/quagga') + self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} def terminate(self): @@ -147,24 +154,24 @@ class QuaggaRouter(Node): if daemon in self.daemons.keys(): self.daemons[daemon] = 1 if source is None: - self.cmd('touch /etc/quagga/%s.conf' % daemon) + self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) self.waitOutput() else: - self.cmd('cp %s /etc/quagga/%s.conf' % (source, daemon)) + self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) self.waitOutput() - self.cmd('chmod 640 /etc/quagga/%s.conf' % daemon) + self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) self.waitOutput() - self.cmd('chown quagga:quagga /etc/quagga/%s.conf' % daemon) + self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) self.waitOutput() else: print("No daemon %s known" % daemon) # print "Daemons after:", self.daemons def startQuagga(self): # Disable integrated-vtysh-config - self.cmd('echo "no service integrated-vtysh-config" > /etc/quagga/vtysh.conf') - with open("/etc/quagga/vtysh.conf", "w") as vtyshfile: + ### self.cmd('echo "no service integrated-vtysh-config" > /etc/%s/vtysh.conf' % self.routertype) + with open('/etc/%s/vtysh.conf' % self.routertype, "w") as vtyshfile: vtyshfile.write('no service integrated-vtysh-config') - self.cmd('chown quagga:quaggavty /etc/quagga/vtysh.conf') + self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) # Try to find relevant old logfiles in /tmp and delete them map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) # Remove old core files @@ -173,9 +180,9 @@ class QuaggaRouter(Node): self.removeIPs() # Start Zebra first if self.daemons['zebra'] == 1: - self.cmd('/usr/lib/quagga/zebra -d') + self.cmd('/usr/lib/%s/zebra -d' % self.routertype) self.waitOutput() - print('%s: zebra started' % self) + print('%s: %s zebra started' % (self, self.routertype)) sleep(1) # Fix Link-Local Addresses # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this @@ -183,9 +190,9 @@ class QuaggaRouter(Node): # Now start all the other daemons for daemon in self.daemons: if (self.daemons[daemon] == 1) and (daemon != 'zebra'): - self.cmd('/usr/lib/quagga/%s -d' % daemon) + self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) self.waitOutput() - print('%s: %s started' % (self, daemon)) + print('%s: %s %s started' % (self, self.routertype, daemon)) def checkQuaggaRunning(self): global fatal_error @@ -197,14 +204,14 @@ class QuaggaRouter(Node): # Look for core file corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) if (len(corefiles) > 0): - backtrace = subprocess.check_output(["gdb /usr/lib/quagga/%s %s --batch -ex bt 2> /dev/null" % (daemon, corefiles[0])], shell=True) + backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) sys.stderr.write("%s\n" % backtrace) else: # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) - sys.stderr.write("\nFrom quagga %s %s log file:\n" % (self.name, daemon)) + sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) sys.stderr.write("%s\n" % log_tail) failed += [daemon] return failed @@ -229,9 +236,10 @@ class NetworkTopo(Topo): def build(self, **_opts): quaggaPrivateDirs = ['/etc/quagga', + '/etc/frr', '/var/run/quagga', - '/var/log', - '/var/run/ssh'] + '/var/run/frr', + '/var/log'] exabgpPrivateDirs = ['/etc/exabgp', '/var/run/exabgp', '/var/log'] @@ -327,7 +335,7 @@ def test_quagga_running(): if (fatal_error != ""): pytest.skip(fatal_error) - print("\n\n** Check if Quagga is running on each Router node") + print("\n\n** Check if FRR/Quagga is running on each Router node") print("******************************************\n") sleep(5) @@ -379,6 +387,10 @@ def test_bgp_converge(): bgpStatus = net['r%s' % i].cmd('show ip bgp view %s summary"') assert False, "BGP did not converge:\n%s" % bgpStatus + # Wait for an extra 30s to announce all routes + print('Waiting 30s for routes to be announced'); + sleep(30) + print("BGP converged.") # if timeout < 60: diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 2a79380130..f669fdecdc 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -120,10 +120,17 @@ class LinuxRouter(Node): super(LinuxRouter, self).terminate() class QuaggaRouter(Node): - "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" + "A Node with IPv4/IPv6 forwarding enabled and FRR/Quagga as Routing Engine" def config(self, **params): super(QuaggaRouter, self).config(**params) + # Check if Quagga or FRR is installed + if os.path.isfile('/usr/lib/frr/zebra'): + self.routertype = 'frr' + elif os.path.isfile('/usr/lib/quagga/zebra'): + self.routertype = 'quagga' + else: + raise Exception('No FRR or Quagga found in ususal location') # Enable forwarding on the router self.cmd('sysctl net.ipv4.ip_forward=1') self.cmd('sysctl net.ipv6.conf.all.forwarding=1') @@ -133,12 +140,12 @@ class QuaggaRouter(Node): self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) self.cmd('ulimit -c unlimited') # Set ownership of config files - self.cmd('chown quagga:quaggavty /etc/quagga') + self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} def terminate(self): # Delete Running Quagga Daemons - rundaemons = self.cmd('ls -1 /var/run/quagga/*.pid') + rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) for d in StringIO.StringIO(rundaemons): self.cmd('kill -7 `cat %s`' % d.rstrip()) self.waitOutput() @@ -154,24 +161,24 @@ class QuaggaRouter(Node): if daemon in self.daemons.keys(): self.daemons[daemon] = 1 if source is None: - self.cmd('touch /etc/quagga/%s.conf' % daemon) + self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) self.waitOutput() else: - self.cmd('cp %s /etc/quagga/%s.conf' % (source, daemon)) + self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) self.waitOutput() - self.cmd('chmod 640 /etc/quagga/%s.conf' % daemon) + self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) self.waitOutput() - self.cmd('chown quagga:quagga /etc/quagga/%s.conf' % daemon) + self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) self.waitOutput() else: print("No daemon %s known" % daemon) # print "Daemons after:", self.daemons def startQuagga(self): # Disable integrated-vtysh-config - self.cmd('echo "no service integrated-vtysh-config" > /etc/quagga/vtysh.conf') - with open("/etc/quagga/vtysh.conf", "w") as vtyshfile: + ### self.cmd('echo "no service integrated-vtysh-config" > /etc/%s/vtysh.conf' % self.routertype) + with open('/etc/%s/vtysh.conf' % self.routertype, "w") as vtyshfile: vtyshfile.write('no service integrated-vtysh-config') - self.cmd('chown quagga:quaggavty /etc/quagga/vtysh.conf') + self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) # Try to find relevant old logfiles in /tmp and delete them map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) # Remove old core files @@ -180,9 +187,9 @@ class QuaggaRouter(Node): self.removeIPs() # Start Zebra first if self.daemons['zebra'] == 1: - self.cmd('/usr/lib/quagga/zebra -d') + self.cmd('/usr/lib/%s/zebra -d' % self.routertype) self.waitOutput() - print('%s: zebra started' % self) + print('%s: %s zebra started' % (self, self.routertype)) sleep(1) # Fix Link-Local Addresses # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this @@ -190,9 +197,9 @@ class QuaggaRouter(Node): # Now start all the other daemons for daemon in self.daemons: if (self.daemons[daemon] == 1) and (daemon != 'zebra'): - self.cmd('/usr/lib/quagga/%s -d' % daemon) + self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) self.waitOutput() - print('%s: %s started' % (self, daemon)) + print('%s: %s %s started' % (self, self.routertype, daemon)) def checkQuaggaRunning(self): global fatal_error @@ -204,14 +211,14 @@ class QuaggaRouter(Node): # Look for core file corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) if (len(corefiles) > 0): - backtrace = subprocess.check_output(["gdb /usr/lib/quagga/%s %s --batch -ex bt 2> /dev/null" % (daemon, corefiles[0])], shell=True) + backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) sys.stderr.write("%s\n" % backtrace) else: # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) - sys.stderr.write("\nFrom quagga %s %s log file:\n" % (self.name, daemon)) + sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) sys.stderr.write("%s\n" % log_tail) failed += [daemon] return failed @@ -260,7 +267,9 @@ class NetworkTopo(Topo): def build(self, **_opts): quaggaPrivateDirs = ['/etc/quagga', + '/etc/frr', '/var/run/quagga', + '/var/run/frr', '/var/log'] # # Define Switches first @@ -270,7 +279,7 @@ class NetworkTopo(Topo): switch[i] = self.addSwitch('SW%s' % i, dpid=int2dpid(i), cls=LegacySwitch) # - # Define Quagga Routers + # Define FRR/Quagga Routers # router = {} for i in range(1, 5): @@ -312,7 +321,7 @@ def setup_module(module): net = Mininet(controller=None, topo=topo) net.start() - # For debugging after starting net, but before starting Quagga, uncomment the next line + # For debugging after starting net, but before starting FRR/Quagga, uncomment the next line # CLI(net) # Starting Routers @@ -321,7 +330,7 @@ def setup_module(module): net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i)) net['r%s' % i].startQuagga() - # For debugging after starting Quagga daemons, uncomment the next line + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -343,7 +352,7 @@ def test_quagga_running(): if (fatal_error != ""): pytest.skip(fatal_error) - print("\n\n** Check if Quagga is running on each Router node") + print("\n\n** Check if FRR/Quagga is running on each Router node") print("******************************************\n") sleep(5) @@ -445,7 +454,7 @@ def test_ospfv3_routingTable(): assert failures == 0, "OSPFv3 (IPv6) Routing Table verification failed for router r%s:\n%s" % (i, diff) - # For debugging after starting Quagga daemons, uncomment the next line + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) def test_linux_ipv6_kernel_routingTable(): @@ -506,7 +515,7 @@ def test_linux_ipv6_kernel_routingTable(): assert failures == 0, "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff) - # For debugging after starting Quagga daemons, uncomment the next line + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) From e631b5186f4ce2fa38d78a7eeff7a0cd1b53bf93 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Mon, 16 Jan 2017 09:34:03 -0800 Subject: [PATCH 028/384] bgp_multiview_topo1: Fix bad check for running daemons Only one ruter running in the setup --- tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index fbafd30cf5..c3165a10a6 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -341,7 +341,7 @@ def test_quagga_running(): # CLI(net) failedRunning = "" - for i in range(1, 5): + for i in range(1, 2): failedDaemon = net['r%s' % i].checkQuaggaRunning() if failedDaemon: failedRunning += " Daemons failed on r%s: %s\n" % (i, failedDaemon) From f03e38f397f721d209c4493f38c6a3ebb5ddbd5e Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Mon, 16 Jan 2017 09:36:13 -0800 Subject: [PATCH 029/384] ldp-topo1: Add new LDP Topology Test --- tests/topotests/ldp-topo1/ldpd-test1.tar | Bin 0 -> 15360 bytes .../topotests/ldp-topo1/r1/ip_mpls_route.ref | 5 + tests/topotests/ldp-topo1/r1/ldpd.conf | 15 + tests/topotests/ldp-topo1/r1/ospfd.conf | 7 + .../ldp-topo1/r1/show_ipv4_route.ref | 7 + .../ldp-topo1/r1/show_mpls_ldp_binding.ref | 42 + .../ldp-topo1/r1/show_mpls_ldp_discovery.ref | 7 + .../ldp-topo1/r1/show_mpls_ldp_interface.ref | 2 + .../ldp-topo1/r1/show_mpls_ldp_neighbor.ref | 8 + .../ldp-topo1/r1/show_mpls_table.ref | 8 + tests/topotests/ldp-topo1/r1/zebra.conf | 17 + .../topotests/ldp-topo1/r2/how_mpls_table.ref | 7 + .../topotests/ldp-topo1/r2/ip_mpls_route.ref | 5 + tests/topotests/ldp-topo1/r2/ldpd.conf | 17 + tests/topotests/ldp-topo1/r2/ospfd.conf | 7 + .../ldp-topo1/r2/show_ipv4_route.ref | 7 + .../ldp-topo1/r2/show_mpls_ldp_binding.ref | 56 ++ .../ldp-topo1/r2/show_mpls_ldp_discovery.ref | 12 + .../ldp-topo1/r2/show_mpls_ldp_interface.ref | 3 + .../ldp-topo1/r2/show_mpls_ldp_neighbor.ref | 26 + .../ldp-topo1/r2/show_mpls_table.ref | 7 + tests/topotests/ldp-topo1/r2/zebra.conf | 27 + .../topotests/ldp-topo1/r3/how_mpls_table.ref | 10 + .../topotests/ldp-topo1/r3/ip_mpls_route.ref | 10 + tests/topotests/ldp-topo1/r3/ldpd.conf | 15 + tests/topotests/ldp-topo1/r3/ospfd.conf | 8 + .../ldp-topo1/r3/show_ipv4_route.ref | 7 + .../ldp-topo1/r3/show_mpls_ldp_binding.ref | 49 ++ .../ldp-topo1/r3/show_mpls_ldp_discovery.ref | 9 + .../ldp-topo1/r3/show_mpls_ldp_interface.ref | 2 + .../ldp-topo1/r3/show_mpls_ldp_neighbor.ref | 17 + .../ldp-topo1/r3/show_mpls_table.ref | 10 + tests/topotests/ldp-topo1/r3/zebra.conf | 22 + .../topotests/ldp-topo1/r4/how_mpls_table.ref | 9 + .../topotests/ldp-topo1/r4/ip_mpls_route.ref | 7 + tests/topotests/ldp-topo1/r4/ldpd.conf | 15 + tests/topotests/ldp-topo1/r4/ospfd.conf | 7 + .../ldp-topo1/r4/show_ipv4_route.ref | 7 + .../ldp-topo1/r4/show_mpls_ldp_binding.ref | 49 ++ .../ldp-topo1/r4/show_mpls_ldp_discovery.ref | 9 + .../ldp-topo1/r4/show_mpls_ldp_interface.ref | 2 + .../ldp-topo1/r4/show_mpls_ldp_neighbor.ref | 17 + .../ldp-topo1/r4/show_mpls_table.ref | 9 + tests/topotests/ldp-topo1/r4/zebra.conf | 17 + tests/topotests/ldp-topo1/test_ldp_topo1.py | 814 ++++++++++++++++++ 45 files changed, 1413 insertions(+) create mode 100644 tests/topotests/ldp-topo1/ldpd-test1.tar create mode 100644 tests/topotests/ldp-topo1/r1/ip_mpls_route.ref create mode 100644 tests/topotests/ldp-topo1/r1/ldpd.conf create mode 100644 tests/topotests/ldp-topo1/r1/ospfd.conf create mode 100644 tests/topotests/ldp-topo1/r1/show_ipv4_route.ref create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_table.ref create mode 100644 tests/topotests/ldp-topo1/r1/zebra.conf create mode 100644 tests/topotests/ldp-topo1/r2/how_mpls_table.ref create mode 100644 tests/topotests/ldp-topo1/r2/ip_mpls_route.ref create mode 100644 tests/topotests/ldp-topo1/r2/ldpd.conf create mode 100644 tests/topotests/ldp-topo1/r2/ospfd.conf create mode 100644 tests/topotests/ldp-topo1/r2/show_ipv4_route.ref create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_table.ref create mode 100644 tests/topotests/ldp-topo1/r2/zebra.conf create mode 100644 tests/topotests/ldp-topo1/r3/how_mpls_table.ref create mode 100644 tests/topotests/ldp-topo1/r3/ip_mpls_route.ref create mode 100644 tests/topotests/ldp-topo1/r3/ldpd.conf create mode 100644 tests/topotests/ldp-topo1/r3/ospfd.conf create mode 100644 tests/topotests/ldp-topo1/r3/show_ipv4_route.ref create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_table.ref create mode 100644 tests/topotests/ldp-topo1/r3/zebra.conf create mode 100644 tests/topotests/ldp-topo1/r4/how_mpls_table.ref create mode 100644 tests/topotests/ldp-topo1/r4/ip_mpls_route.ref create mode 100644 tests/topotests/ldp-topo1/r4/ldpd.conf create mode 100644 tests/topotests/ldp-topo1/r4/ospfd.conf create mode 100644 tests/topotests/ldp-topo1/r4/show_ipv4_route.ref create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_table.ref create mode 100644 tests/topotests/ldp-topo1/r4/zebra.conf create mode 100755 tests/topotests/ldp-topo1/test_ldp_topo1.py diff --git a/tests/topotests/ldp-topo1/ldpd-test1.tar b/tests/topotests/ldp-topo1/ldpd-test1.tar new file mode 100644 index 0000000000000000000000000000000000000000..897e67b67ab8bd136ba6ffc799f158241881837c GIT binary patch literal 15360 zcmeHN>z1N04E8rq5g$P94R{__>JDcSIHltr_vyDSPM6UUZxz`yp+6L2LQV2DX;P)x zs&1Q2zFgPUX7-ee5RwQ1GeT$@lm4fnn2RPHC?||?Mp#OKP{HG52IMKTITHHb>P(rb zDOqK@J|gyRFVVZdV*i}IpvO7suWxm$t86R5IYHE9ZTq`cInb!Af5N6HC9L$eSt(5y zou8QJ(L7T1yOzpvMbO3d}_5VHh3H~YK|4Yk-d1&MRl=lB!|4;CQV*C$d;bAEr|6%$+K8$1kXISq@ NMGc?^Py?^lz+YSuUrPW0 literal 0 HcmV?d00001 diff --git a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref new file mode 100644 index 0000000000..053b08c338 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref @@ -0,0 +1,5 @@ +xx as to xx via inet 10.0.1.2 dev r1-eth0 proto zebra +xx as to xx via inet 10.0.1.2 dev r1-eth0 proto zebra +xx via inet 10.0.1.2 dev r1-eth0 proto zebra +xx via inet 10.0.1.2 dev r1-eth0 proto zebra +xx via inet 10.0.1.2 dev r1-eth0 proto zebra diff --git a/tests/topotests/ldp-topo1/r1/ldpd.conf b/tests/topotests/ldp-topo1/r1/ldpd.conf new file mode 100644 index 0000000000..9f1d43d78f --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/ldpd.conf @@ -0,0 +1,15 @@ +hostname r1 +log file /tmp/r1-ldpd.log +! +mpls ldp + router-id 1.1.1.1 + ! + address-family ipv4 + discovery transport-address 1.1.1.1 + ! + interface r1-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-topo1/r1/ospfd.conf b/tests/topotests/ldp-topo1/r1/ospfd.conf new file mode 100644 index 0000000000..8d12ea4446 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/ospfd.conf @@ -0,0 +1,7 @@ +hostname r1 +log file /tmp/r1-ospfd.log +! +router ospf + router-id 1.1.1.1 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref new file mode 100644 index 0000000000..e72a20bac0 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref @@ -0,0 +1,7 @@ +O 1.1.1.1/32 [110/0] is directly connected, lo +O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0 +O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0 label xxx +O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0 label xxx +O 10.0.1.0/24 [110/10] is directly connected, r1-eth0 +O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0 +O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref new file mode 100644 index 0000000000..ff72a1c0b7 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref @@ -0,0 +1,42 @@ +1.1.1.1/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx +2.2.2.2/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null +3.3.3.3/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx +4.4.4.4/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx +10.0.1.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null +10.0.2.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null +10.0.3.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref new file mode 100644 index 0000000000..38522e162e --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref @@ -0,0 +1,7 @@ +Local LDP Identifier: 1.1.1.1:0 +Discovery Sources: + Interfaces: + r1-eth0: xmit/recv + LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 + Hold time: 15 sec + Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref new file mode 100644 index 0000000000..0fb15d2da7 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref @@ -0,0 +1,2 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r1-eth0 ACTIVE xx:xx:xx 5/15 1 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref new file mode 100644 index 0000000000..3df98bfae5 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref @@ -0,0 +1,8 @@ +Peer LDP Identifier: 2.2.2.2:0 + TCP connection: 1.1.1.1:xxx - 2.2.2.2:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref new file mode 100644 index 0000000000..912a082019 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref @@ -0,0 +1,8 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + XX LDP 10.0.1.2 3 + XX LDP 10.0.1.2 3 + XX LDP 10.0.1.2 3 + XX LDP 10.0.1.2 XX + XX LDP 10.0.1.2 XX diff --git a/tests/topotests/ldp-topo1/r1/zebra.conf b/tests/topotests/ldp-topo1/r1/zebra.conf new file mode 100644 index 0000000000..61fb7dc058 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/zebra.conf @@ -0,0 +1,17 @@ +log file /tmp/r1-zebra.log +! +hostname r1 +! +interface lo + ip address 1.1.1.1/32 +! +interface r1-eth0 + description to sw0 + ip address 10.0.1.1/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-topo1/r2/how_mpls_table.ref b/tests/topotests/ldp-topo1/r2/how_mpls_table.ref new file mode 100644 index 0000000000..67f9162bcd --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/how_mpls_table.ref @@ -0,0 +1,7 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + 16 LDP 10.0.2.3 3 + 16 LDP 10.0.3.3 3 + 17 LDP 10.0.1.1 3 + 18 LDP 10.0.2.4 3 diff --git a/tests/topotests/ldp-topo1/r2/ip_mpls_route.ref b/tests/topotests/ldp-topo1/r2/ip_mpls_route.ref new file mode 100644 index 0000000000..007ef6f0a5 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/ip_mpls_route.ref @@ -0,0 +1,5 @@ +xx proto zebra + nexthopvia inet 10.0.2.3 dev r2-eth1 weight 1 + nexthopvia inet 10.0.3.3 dev r2-eth2 weight 1 +xx via inet 10.0.1.1 dev r2-eth0 proto zebra +xx via inet 10.0.2.4 dev r2-eth1 proto zebra diff --git a/tests/topotests/ldp-topo1/r2/ldpd.conf b/tests/topotests/ldp-topo1/r2/ldpd.conf new file mode 100644 index 0000000000..cb56c4cf66 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/ldpd.conf @@ -0,0 +1,17 @@ +hostname r2 +log file /tmp/r2-ldpd.log +! +mpls ldp + router-id 2.2.2.2 + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + ! + interface r2-eth0 + ! + interface r2-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-topo1/r2/ospfd.conf b/tests/topotests/ldp-topo1/r2/ospfd.conf new file mode 100644 index 0000000000..c58914a7fa --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/ospfd.conf @@ -0,0 +1,7 @@ +hostname r2 +log file /tmp/r2-ospfd.log +! +router ospf + router-id 2.2.2.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref new file mode 100644 index 0000000000..eaec2f16b9 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref @@ -0,0 +1,7 @@ +O>* 1.1.1.1/32 [110/10] via 10.0.1.1, r2-eth0 +O 2.2.2.2/32 [110/0] is directly connected, lo +O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r2-eth1 +O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r2-eth1 +O 10.0.1.0/24 [110/10] is directly connected, r2-eth0 +O 10.0.2.0/24 [110/10] is directly connected, r2-eth1 +O 10.0.3.0/24 [110/10] is directly connected, r2-eth2 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref new file mode 100644 index 0000000000..54ee39080a --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref @@ -0,0 +1,56 @@ +1.1.1.1/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 imp-null + 3.3.3.3 xxx + 4.4.4.4 xxx +2.2.2.2/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 xxx + 4.4.4.4 xxx +3.3.3.3/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 imp-null + 4.4.4.4 xxx +4.4.4.4/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 xxx + 4.4.4.4 imp-null +10.0.1.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 imp-null + 3.3.3.3 xxx + 4.4.4.4 xxx +10.0.2.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 imp-null + 4.4.4.4 imp-null +10.0.3.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 imp-null + 4.4.4.4 xxx diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref new file mode 100644 index 0000000000..539bdc890b --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref @@ -0,0 +1,12 @@ +Local LDP Identifier: 2.2.2.2:0 +Discovery Sources: + Interfaces: + r2-eth1: xmit/recv + LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 + Hold time: 15 sec + LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 + Hold time: 15 sec + r2-eth0: xmit/recv + LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1 + Hold time: 15 sec + Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref new file mode 100644 index 0000000000..86e82b919e --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref @@ -0,0 +1,3 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r2-eth1 ACTIVE xx:xx:xx 5/15 2 +ipv4 r2-eth0 ACTIVE xx:xx:xx 5/15 1 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref new file mode 100644 index 0000000000..a70e2f48c6 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref @@ -0,0 +1,26 @@ +Peer LDP Identifier: 1.1.1.1:0 + TCP connection: 2.2.2.2:xxx - 1.1.1.1:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r2-eth0 + +Peer LDP Identifier: 3.3.3.3:0 + TCP connection: 2.2.2.2:xxx - 3.3.3.3:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r2-eth1 + +Peer LDP Identifier: 4.4.4.4:0 + TCP connection: 2.2.2.2:xxx - 4.4.4.4:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r2-eth1 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref new file mode 100644 index 0000000000..ba244e76ec --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref @@ -0,0 +1,7 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + XX LDP 10.0.1.1 3 + XX LDP 10.0.2.3 3 + XX LDP 10.0.2.4 3 + XX LDP 10.0.3.3 3 diff --git a/tests/topotests/ldp-topo1/r2/zebra.conf b/tests/topotests/ldp-topo1/r2/zebra.conf new file mode 100644 index 0000000000..b74ce318e4 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/zebra.conf @@ -0,0 +1,27 @@ +log file /tmp/r2-zebra.log +! +hostname r2 +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to sw0 + ip address 10.0.1.2/24 + no link-detect +! +interface r2-eth1 + description to sw1 + ip address 10.0.2.2/24 + no link-detect +! +interface r2-eth2 + description to sw2 + ip address 10.0.3.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-topo1/r3/how_mpls_table.ref b/tests/topotests/ldp-topo1/r3/how_mpls_table.ref new file mode 100644 index 0000000000..18f7df0ee4 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/how_mpls_table.ref @@ -0,0 +1,10 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + 16 LDP 10.0.2.2 3 + 16 LDP 10.0.3.2 3 + 17 LDP 10.0.2.2 3 + 17 LDP 10.0.3.2 3 + 18 LDP 10.0.2.2 17 + 18 LDP 10.0.3.2 17 + 19 LDP 10.0.2.4 3 diff --git a/tests/topotests/ldp-topo1/r3/ip_mpls_route.ref b/tests/topotests/ldp-topo1/r3/ip_mpls_route.ref new file mode 100644 index 0000000000..680fcf26fd --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/ip_mpls_route.ref @@ -0,0 +1,10 @@ +xx proto zebra + nexthopvia inet 10.0.2.2 dev r3-eth0 weight 1 + nexthopvia inet 10.0.3.2 dev r3-eth1 weight 1 +xx proto zebra + nexthopvia inet 10.0.2.2 dev r3-eth0 weight 1 + nexthopvia inet 10.0.3.2 dev r3-eth1 weight 1 +xx proto zebra + nexthopvia inet 10.0.2.2 dev r3-eth0 weight 1 + nexthopvia inet 10.0.3.2 dev r3-eth1 weight 1 +xx via inet 10.0.2.4 dev r3-eth0 proto zebra diff --git a/tests/topotests/ldp-topo1/r3/ldpd.conf b/tests/topotests/ldp-topo1/r3/ldpd.conf new file mode 100644 index 0000000000..a62a43f0c0 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/ldpd.conf @@ -0,0 +1,15 @@ +hostname r3 +log file /tmp/r3-ldpd.log +! +mpls ldp + router-id 3.3.3.3 + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + ! + interface r3-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-topo1/r3/ospfd.conf b/tests/topotests/ldp-topo1/r3/ospfd.conf new file mode 100644 index 0000000000..c784bd745a --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/ospfd.conf @@ -0,0 +1,8 @@ +hostname r3 +password 1 +log file /tmp/r3-ospfd.log +! +router ospf + router-id 3.3.3.3 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref new file mode 100644 index 0000000000..f6e6199310 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref @@ -0,0 +1,7 @@ +O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0 label xxx +O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0 +O 3.3.3.3/32 [110/0] is directly connected, lo +O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0 +O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r3-eth0 +O 10.0.2.0/24 [110/10] is directly connected, r3-eth0 +O 10.0.3.0/24 [110/10] is directly connected, r3-eth1 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref new file mode 100644 index 0000000000..e04d2b7e4a --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref @@ -0,0 +1,49 @@ +1.1.1.1/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 4.4.4.4 xxx +2.2.2.2/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 4.4.4.4 xxx +3.3.3.3/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 4.4.4.4 xxx +4.4.4.4/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 4.4.4.4 imp-null +10.0.1.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 4.4.4.4 xxx +10.0.2.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 4.4.4.4 imp-null +10.0.3.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 4.4.4.4 xxx diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref new file mode 100644 index 0000000000..5e299fff9c --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref @@ -0,0 +1,9 @@ +Local LDP Identifier: 3.3.3.3:0 +Discovery Sources: + Interfaces: + r3-eth0: xmit/recv + LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 + Hold time: 15 sec + LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 + Hold time: 15 sec + Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref new file mode 100644 index 0000000000..243811e3a9 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref @@ -0,0 +1,2 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r3-eth0 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref new file mode 100644 index 0000000000..ee1983ac29 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref @@ -0,0 +1,17 @@ +Peer LDP Identifier: 2.2.2.2:0 + TCP connection: 3.3.3.3:xxx - 2.2.2.2:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r3-eth0 + +Peer LDP Identifier: 4.4.4.4:0 + TCP connection: 3.3.3.3:xxx - 4.4.4.4:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r3-eth0 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref new file mode 100644 index 0000000000..9198969bd5 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref @@ -0,0 +1,10 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 XX + XX LDP 10.0.2.4 3 + XX LDP 10.0.3.2 3 + XX LDP 10.0.3.2 3 + XX LDP 10.0.3.2 XX diff --git a/tests/topotests/ldp-topo1/r3/zebra.conf b/tests/topotests/ldp-topo1/r3/zebra.conf new file mode 100644 index 0000000000..62d1f3a83a --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/zebra.conf @@ -0,0 +1,22 @@ +log file /tmp/r3-zebra.log +! +hostname r3 +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to sw1 + ip address 10.0.2.3/24 + no link-detect +! +interface r3-eth1 + description to sw2 + ip address 10.0.3.3/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-topo1/r4/how_mpls_table.ref b/tests/topotests/ldp-topo1/r4/how_mpls_table.ref new file mode 100644 index 0000000000..40efab8b5b --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/how_mpls_table.ref @@ -0,0 +1,9 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + 16 LDP 10.0.2.2 17 + 17 LDP 10.0.2.2 3 + 18 LDP 10.0.2.3 3 + 19 LDP 10.0.2.2 3 + 20 LDP 10.0.2.3 3 + 20 LDP 10.0.2.2 3 diff --git a/tests/topotests/ldp-topo1/r4/ip_mpls_route.ref b/tests/topotests/ldp-topo1/r4/ip_mpls_route.ref new file mode 100644 index 0000000000..7fdb057345 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/ip_mpls_route.ref @@ -0,0 +1,7 @@ +xx proto zebra + nexthopvia inet 10.0.2.2 dev r4-eth0 weight 1 + nexthopvia inet 10.0.2.3 dev r4-eth0 weight 1 +xx as to xx via inet 10.0.2.2 dev r4-eth0 proto zebra +xx via inet 10.0.2.2 dev r4-eth0 proto zebra +xx via inet 10.0.2.2 dev r4-eth0 proto zebra +xx via inet 10.0.2.3 dev r4-eth0 proto zebra diff --git a/tests/topotests/ldp-topo1/r4/ldpd.conf b/tests/topotests/ldp-topo1/r4/ldpd.conf new file mode 100644 index 0000000000..0391f4ee4d --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/ldpd.conf @@ -0,0 +1,15 @@ +hostname r4 +log file /tmp/r4-ldpd.log +! +mpls ldp + router-id 4.4.4.4 + ! + address-family ipv4 + discovery transport-address 4.4.4.4 + ! + interface r4-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/ldp-topo1/r4/ospfd.conf b/tests/topotests/ldp-topo1/r4/ospfd.conf new file mode 100644 index 0000000000..9f0784a9f2 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/ospfd.conf @@ -0,0 +1,7 @@ +hostname r4 +log file /tmp/r4-ospfd.log +! +router ospf + router-id 4.4.4.4 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref new file mode 100644 index 0000000000..bcef173a64 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref @@ -0,0 +1,7 @@ +O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0 label xxx +O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0 +O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0 +O 4.4.4.4/32 [110/0] is directly connected, lo +O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r4-eth0 +O 10.0.2.0/24 [110/10] is directly connected, r4-eth0 +O>* 10.0.3.0/24 [110/20] via 10.0.2.2, r4-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref new file mode 100644 index 0000000000..3d55805d7c --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref @@ -0,0 +1,49 @@ +1.1.1.1/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 3.3.3.3 xxx +2.2.2.2/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 xxx +3.3.3.3/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 3.3.3.3 imp-null +4.4.4.4/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 3.3.3.3 xxx +10.0.1.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 xxx +10.0.2.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 imp-null +10.0.3.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 imp-null diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref new file mode 100644 index 0000000000..4fbf536f81 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref @@ -0,0 +1,9 @@ +Local LDP Identifier: 4.4.4.4:0 +Discovery Sources: + Interfaces: + r4-eth0: xmit/recv + LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 + Hold time: 15 sec + LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 + Hold time: 15 sec + Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref new file mode 100644 index 0000000000..dd57656f15 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref @@ -0,0 +1,2 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r4-eth0 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref new file mode 100644 index 0000000000..fb0e7d7dfa --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref @@ -0,0 +1,17 @@ +Peer LDP Identifier: 2.2.2.2:0 + TCP connection: 4.4.4.4:xxx - 2.2.2.2:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r4-eth0 + +Peer LDP Identifier: 3.3.3.3:0 + TCP connection: 4.4.4.4:xxx - 3.3.3.3:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r4-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref new file mode 100644 index 0000000000..b8cf5a2702 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref @@ -0,0 +1,9 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 XX + XX LDP 10.0.2.3 3 + XX LDP 10.0.2.3 3 diff --git a/tests/topotests/ldp-topo1/r4/zebra.conf b/tests/topotests/ldp-topo1/r4/zebra.conf new file mode 100644 index 0000000000..ecec23ee58 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/zebra.conf @@ -0,0 +1,17 @@ +log file /tmp/r4-zebra.log +! +hostname r4 +! +interface lo + ip address 4.4.4.4/32 +! +interface r4-eth0 + description to sw1 + ip address 10.0.2.4/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py new file mode 100755 index 0000000000..81807fa214 --- /dev/null +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -0,0 +1,814 @@ +#!/usr/bin/env python + +# +# test_bgp_multiview_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2016 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_ldp_topo1.py: Simple FRR/Quagga LDP Test + + +---------+ + | r1 | + | 1.1.1.1 | + +----+----+ + | .1 r1-eth0 + | + ~~~~~~~~~~~~~ + ~~ sw0 ~~ + ~~ 10.0.1.0/24 ~~ + ~~~~~~~~~~~~~ + |10.0.1.0/24 + | + | .2 r2-eth0 + +----+----+ + | r2 | + | 2.2.2.2 | + +--+---+--+ + r2-eth2 .2 | | .2 r2-eth1 + ______/ \______ + / \ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ +~~ sw2 ~~ ~~ sw1 ~~ +~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ + | / | + \ _________/ | + \ / \ +r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0 + +----+--+---+ +----+----+ + | r3 | | r4 | + | 3.3.3.3 | | 4.4.4.4 | + +-----------+ +---------+ +""" + +import os +import re +import sys +import difflib +import StringIO +import glob +import subprocess +import platform + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from functools import partial +from time import sleep + +import pytest + +fatal_error = "" + +def int2dpid(dpid): + "Converting Integer to DPID" + + try: + dpid = hex(dpid)[2:] + dpid = '0'*(16-len(dpid))+dpid + return dpid + except IndexError: + raise Exception('Unable to derive default datapath ID - ' + 'please either specify a dpid or use a ' + 'canonical switch name such as s23.') + +class LinuxRouter(Node): + "A Node with IPv4/IPv6 forwarding enabled." + + def config(self, **params): + super(LinuxRouter, self).config(**params) + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + def terminate(self): + """ + Terminate generic LinuxRouter Mininet instance + """ + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(LinuxRouter, self).terminate() + +class QuaggaRouter(Node): + "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" + + def config(self, **params): + super(QuaggaRouter, self).config(**params) + # Check if Quagga or FRR is installed + if os.path.isfile('/usr/lib/frr/zebra'): + self.routertype = 'frr' + elif os.path.isfile('/usr/lib/quagga/zebra'): + self.routertype = 'quagga' + else: + raise Exception('No FRR or Quagga found in ususal location') + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + # Enable coredumps + self.cmd('sysctl kernel.core_uses_pid=1') + self.cmd('sysctl fs.suid_dumpable=2') + self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) + self.cmd('ulimit -c unlimited') + # Set ownership of config files + self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) + self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, + 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0, + 'ldpd': 0} + def terminate(self): + # Delete Running Quagga Daemons + rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) + for d in StringIO.StringIO(rundaemons): + self.cmd('kill -7 `cat %s`' % d.rstrip()) + self.waitOutput() + # Disable forwarding + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(QuaggaRouter, self).terminate() + def removeIPs(self): + for interface in self.intfNames(): + self.cmd('ip address flush', interface) + def loadConf(self, daemon, source=None): + # print "Daemons before:", self.daemons + if daemon in self.daemons.keys(): + self.daemons[daemon] = 1 + if source is None: + self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) + self.waitOutput() + else: + self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) + self.waitOutput() + self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) + self.waitOutput() + self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) + self.waitOutput() + else: + print("No daemon %s known" % daemon) + # print "Daemons after:", self.daemons + def startQuagga(self): + global fatal_error + + # Disable integrated-vtysh-config + with open('/etc/%s/vtysh.conf' % self.routertype, "w") as vtyshfile: + vtyshfile.write('no service integrated-vtysh-config') + self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) + # Try to find relevant old logfiles in /tmp and delete them + map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) + # Remove old core files + map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) + # Remove IP addresses from OS first - we have them in zebra.conf + self.removeIPs() + # If ldp is used, check for LDP to be compiled and Linux Kernel to be 4.5 or higher + # No error - but return message and skip all the tests + if self.daemons['ldpd'] == 1: + if not os.path.isfile('/usr/lib/%s/ldpd' % self.routertype): + fatal_error = "LDP Test, but no ldpd compiled or installed" + print("LDP Test, but no ldpd compiled or installed") + return + kernel_version = re.search(r'([0-9]+\.[0-9]+).*', platform.release()) + if kernel_version: + if float(kernel_version.group(1)) < 4.5: + fatal_error = "LDP Test need Linux Kernel 4.5 minimum" + print("LDP Test need Linux Kernel 4.5 minimum") + return + # Add mpls modules to kernel if we use LDP + if self.daemons['ldpd'] == 1: + self.cmd('/sbin/modprobe mpls-router') + self.cmd('/sbin/modprobe mpls-iptunnel') + self.cmd('echo 100000 > /proc/sys/net/mpls/platform_labels') + # Start Zebra first + if self.daemons['zebra'] == 1: + self.cmd('/usr/lib/%s/zebra -d' % self.routertype) + self.waitOutput() + print('%s: %s zebra started' % (self, self.routertype)) + sleep(1) + # Fix Link-Local Addresses + # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this + self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') + # Now start all the other daemons + for daemon in self.daemons: + if (self.daemons[daemon] == 1) and (daemon != 'zebra'): + self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) + self.waitOutput() + print('%s: %s %s started' % (self, self.routertype, daemon)) + def checkQuaggaRunning(self): + global fatal_error + + daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') + for daemon in self.daemons: + if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): + sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) + # Look for core file + corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) + if (len(corefiles) > 0): + backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) + sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) + sys.stderr.write("%s\n" % backtrace) + else: + # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. + if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): + log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) + sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) + sys.stderr.write("%s\n" % log_tail) + + fatal_error = "%s: Daemon %s not running" % (self.name, daemon) + assert False, "%s: Daemon %s not running" % (self.name, daemon) + +class LegacySwitch(OVSSwitch): + "A Legacy Switch without OpenFlow" + + def __init__(self, name, **params): + OVSSwitch.__init__(self, name, failMode='standalone', **params) + self.switchIP = None + + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "A LinuxRouter connecting three IP subnets" + + def build(self, **_opts): + + quaggaPrivateDirs = ['/etc/quagga', + '/etc/frr', + '/var/run/quagga', + '/var/run/frr', + '/var/log'] + exabgpPrivateDirs = ['/etc/exabgp', + '/var/run/exabgp', + '/var/log'] + + # Setup Routers + router = {} + for i in range(1, 5): + router[i] = self.addNode('r%s' % i, cls=QuaggaRouter, + privateDirs=quaggaPrivateDirs) + + # Setup Switches + switch = {} + # First switch + switch[0] = self.addSwitch('sw0', cls=LegacySwitch) + self.addLink(switch[0], router[1], intfName2='r1-eth0', addr1='80:AA:00:00:00:00', addr2='00:11:00:01:00:00') + self.addLink(switch[0], router[2], intfName2='r2-eth0', addr1='80:AA:00:00:00:01', addr2='00:11:00:02:00:00') + # Second switch + switch[1] = self.addSwitch('sw1', cls=LegacySwitch) + self.addLink(switch[1], router[2], intfName2='r2-eth1', addr1='80:AA:00:01:00:00', addr2='00:11:00:02:00:01') + self.addLink(switch[1], router[3], intfName2='r3-eth0', addr1='80:AA:00:01:00:01', addr2='00:11:00:03:00:00') + self.addLink(switch[1], router[4], intfName2='r4-eth0', addr1='80:AA:00:01:00:02', addr2='00:11:00:04:00:00') + # Third switch + switch[2] = self.addSwitch('sw2', cls=LegacySwitch) + self.addLink(switch[2], router[2], intfName2='r2-eth2', addr1='80:AA:00:02:00:00', addr2='00:11:00:02:00:02') + self.addLink(switch[2], router[3], intfName2='r3-eth1', addr1='80:AA:00:02:00:01', addr2='00:11:00:03:00:01') + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + global topo, net + + print("\n\n** %s: Setup Topology" % module.__name__) + print("******************************************\n") + + print("Cleanup old Mininet runs") + os.system('sudo mn -c > /dev/null 2>&1') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + topo = NetworkTopo() + + net = Mininet(controller=None, topo=topo) + net.start() + + # Starting Routers + for i in range(1, 5): + net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ospfd', '%s/r%s/ospfd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i)) + net['r%s' % i].startQuagga() + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + +def teardown_module(module): + global net + + print("\n\n** %s: Shutdown Topology" % module.__name__) + print("******************************************\n") + + # End - Shutdown network + net.stop() + + +def test_quagga_running(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check if FRR/Quagga is running on each Router node") + print("******************************************\n") + sleep(5) + + # Starting Routers + for i in range(1, 5): + net['r%s' % i].checkQuaggaRunning() + + +def test_mpls_interfaces(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing MPLS Interfaces") + print("******************************************\n") + failures = 0 + for i in range(1, 5): + refTableFile = '%s/r%s/show_mpls_ldp_interface.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp interface" 2> /dev/null').rstrip() + # Mask out Timer in Uptime + actual = re.sub(r" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual MPLS LDP interface status", + tofile="expected MPLS LDP interface status")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed MPLS LDP Interface status Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_mpls_ldp_neighbor_establish(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State) + print("\n\n** Verify MPLS LDP neighbors to establish") + print("******************************************\n") + timeout = 90 + while timeout > 0: + print("Timeout in %s: " % timeout), + sys.stdout.flush() + # Look for any node not yet converged + for i in range(1, 5): + established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null') + if not established: + print('Waiting for r%s' %i) + sys.stdout.flush() + break + if not established: + sleep(5) + timeout -= 5 + else: + print('Done') + break + else: + # Bail out with error if a router fails to converge + fatal_error = "MPLS LDP neighbors did not establish" + assert False, "MPLS LDP neighbors did not establish" % ospfStatus + + print("MPLS LDP neighbors established.") + + if timeout < 60: + # Only wait if we actually went through a convergence + print("\nwaiting 15s for LDP sessions to establish") + sleep(15) + + +def test_mpls_ldp_discovery(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing MPLS LDP discovery") + print("******************************************\n") + failures = 0 + for i in range(1, 5): + refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip() + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual MPLS LDP discovery output", + tofile="expected MPLS LDP discovery output")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed MPLS LDP discovery output Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "MPLS LDP Interface discovery output for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_mpls_ldp_neighbor(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing MPLS LDP neighbor") + print("******************************************\n") + failures = 0 + for i in range(1, 5): + refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip() + # Mask out Timer in Uptime + actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual) + # Mask out Port numbers in TCP connection + actual = re.sub(r"TCP connection: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+ - ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+", + r"TCP connection: \1:xxx - \2:xxx", actual) + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual MPLS LDP neighbor output", + tofile="expected MPLS LDP neighbor output")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed MPLS LDP neighbor output Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "MPLS LDP Interface neighbor output for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + #CLI(net) + + +def test_mpls_ldp_binding(): + global fatal_error + global net + + # Skip this test for now until proper sorting of the output + # is implemented + # pytest.skip("Skipping test_mpls_ldp_binding") + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing MPLS LDP binding") + print("******************************************\n") + failures = 0 + for i in range(1, 5): + refTableFile = '%s/r%s/show_mpls_ldp_binding.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp binding" 2> /dev/null').rstrip() + # Mask out label + actual = re.sub(r"label: [0-9]+", "label: xxx", actual) + actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual) + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Sort lines which start with "xx via inet " + pattern = r'^\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s+' + swapped = True + while swapped: + swapped = False + for j in range(1, len(actual)): + if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]): + if actual[j-1] > actual[j]: + temp = actual[j-1] + actual[j-1] = actual[j] + actual[j] = temp + swapped = True + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual MPLS LDP binding output", + tofile="expected MPLS LDP binding output")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed MPLS LDP binding output Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "MPLS LDP Interface binding output for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + #CLI(net) + + +def test_zebra_ipv4_routingTable(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing Zebra IPv4 Routing Table") + print("******************************************\n") + failures = 0 + for i in range(1, 5): + refTableFile = '%s/r%s/show_ipv4_route.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip route" 2> /dev/null | grep "^O"').rstrip() + # Drop timers on end of line (older Quagga Versions) + actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual) + # Mask out label + actual = re.sub(r" label [0-9]+", " label xxx", actual) + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual IPv4 zebra routing table", + tofile="expected IPv4 zera routing table")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed IPv4 Zebra Routing Table Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_mpls_table(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing MPLS table") + print("******************************************\n") + failures = 0 + for i in range(1, 5): + refTableFile = '%s/r%s/show_mpls_table.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show mpls table" 2> /dev/null').rstrip() + + # Fix inconsistent Label numbers at beginning of line + actual = re.sub(r"(\s+)[0-9]+(\s+LDP)", r"\1XX\2", actual) + # Fix inconsistent Label numbers at end of line + actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\s+)[0-9][0-9]", r"\1XX", actual) + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Sort lines which start with " XX LDP" + pattern = r'^\s+[0-9X]+\s+LDP' + swapped = True + while swapped: + swapped = False + for j in range(1, len(actual)): + if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]): + if actual[j-1] > actual[j]: + temp = actual[j-1] + actual[j-1] = actual[j] + actual[j] = temp + swapped = True + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual MPLS table output", + tofile="expected MPLS table output")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed MPLS table output Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "MPLS table output for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_linux_mpls_routes(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing Linux Kernel MPLS routes") + print("******************************************\n") + failures = 0 + for i in range(1, 5): + refTableFile = '%s/r%s/ip_mpls_route.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('ip -family mpls route 2> /dev/null').rstrip() + # Mask out label + actual = re.sub(r"[0-9][0-9] via inet ", "xx via inet ", actual) + actual = re.sub(r"[0-9][0-9] proto zebra", "xx proto zebra", actual) + actual = re.sub(r"[0-9][0-9] as to ", "xx as to ", actual) + actual = re.sub(r"proto zebra ", "proto zebra", actual) + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Sort lines which start with "xx via inet " + pattern = r'^xx via inet ' + swapped = True + while swapped: + swapped = False + for j in range(1, len(actual)): + if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]): + if actual[j-1] > actual[j]: + temp = actual[j-1] + actual[j-1] = actual[j] + actual[j] = temp + swapped = True + + # Sort lines which start with " nexthopvia" + pattern = r'^\snexthopvia ' + swapped = True + while swapped: + swapped = False + for j in range(1, len(actual)): + if re.search(pattern, actual[j]) and re.search(pattern, actual[j-1]): + if actual[j-1] > actual[j]: + temp = actual[j-1] + actual[j-1] = actual[j] + actual[j] = temp + swapped = True + + # Sort Sections of "xx proto zebra" (with all the indented lines below) + pattern = r'^xx via inet ' + # Join paragraphs first + j = 0 + temp = [actual[0].rstrip()] + for k in range(1, len(actual)): + if re.search(r'^\s', actual[k]): + # Continue line + temp[j] += '\n' + actual[k].rstrip() + else: + j += 1 + temp.append(actual[k].rstrip()) + # sort Array + temp.sort() + # Now write sort array back + actual = [] + for k in range(0, len(temp)): + actual.extend(temp[k].splitlines()) + # put \n back at line ends + actual = ('\n'.join(actual) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual Linux Kernel MPLS route", + tofile="expected Linux Kernel MPLS route")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed Linux Kernel MPLS route output Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "Linux Kernel MPLS route output for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +if __name__ == '__main__': + + setLogLevel('info') + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) + retval = pytest.main(["-s"]) + sys.exit(retval) From 594b1259f994f781c19afd98ae5cee034cf3805b Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Mon, 30 Jan 2017 13:50:48 -0800 Subject: [PATCH 030/384] Move common function and class to topotest library Signed-off-by: Martin Winter --- tests/topotests/.gitignore | 1 + .../test_bgp_multiview_topo1.py | 199 ++------------- tests/topotests/ldp-topo1/test_ldp_topo1.py | 211 ++-------------- tests/topotests/lib/__init__.py | 0 tests/topotests/lib/topotest.py | 232 ++++++++++++++++++ .../topotests/ospf6-topo1/test_ospf6_topo1.py | 230 +++-------------- 6 files changed, 323 insertions(+), 550 deletions(-) create mode 100644 tests/topotests/lib/__init__.py create mode 100644 tests/topotests/lib/topotest.py diff --git a/tests/topotests/.gitignore b/tests/topotests/.gitignore index b3c9e26dcc..9ab8c1f765 100644 --- a/tests/topotests/.gitignore +++ b/tests/topotests/.gitignore @@ -1,2 +1,3 @@ .cache __pycache__ +*.pyc diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index c3165a10a6..4836e2ba06 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -23,7 +23,7 @@ # """ -test_bgp_multiview_topo1.py: Simple Quagga Route-Server Test +test_bgp_multiview_topo1.py: Simple Quagga/FRR Route-Server Test +----------+ +----------+ +----------+ +----------+ +----------+ | peer1 | | peer2 | | peer3 | | peer4 | | peer5 | @@ -47,7 +47,7 @@ test_bgp_multiview_topo1.py: Simple Quagga Route-Server Test | | .254 +---------+---------+ - | Quagga R1 | + | FRR R1 | | BGP Multi-View | | Peer 1-3 > View 1 | | Peer 4-5 > View 2 | @@ -66,9 +66,8 @@ import os import re import sys import difflib -import StringIO -import glob -import subprocess +import pytest +from time import sleep from mininet.topo import Topo from mininet.net import Mininet @@ -78,151 +77,12 @@ from mininet.cli import CLI from mininet.link import Intf from functools import partial -from time import sleep -import pytest +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from lib import topotest fatal_error = "" -def int2dpid(dpid): - "Converting Integer to DPID" - - try: - dpid = hex(dpid)[2:] - dpid = '0'*(16-len(dpid))+dpid - return dpid - except IndexError: - raise Exception('Unable to derive default datapath ID - ' - 'please either specify a dpid or use a ' - 'canonical switch name such as s23.') - -class LinuxRouter(Node): - "A Node with IPv4/IPv6 forwarding enabled." - - def config(self, **params): - super(LinuxRouter, self).config(**params) - # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') - def terminate(self): - """ - Terminate generic LinuxRouter Mininet instance - """ - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') - super(LinuxRouter, self).terminate() - -class QuaggaRouter(Node): - "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" - - def config(self, **params): - super(QuaggaRouter, self).config(**params) - # Check if Quagga or FRR is installed - if os.path.isfile('/usr/lib/frr/zebra'): - self.routertype = 'frr' - elif os.path.isfile('/usr/lib/quagga/zebra'): - self.routertype = 'quagga' - else: - raise Exception('No FRR or Quagga found in ususal location') - # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') - # Enable coredumps - self.cmd('sysctl kernel.core_uses_pid=1') - self.cmd('sysctl fs.suid_dumpable=2') - self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) - self.cmd('ulimit -c unlimited') - # Set ownership of config files - self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) - self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, - 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} - def terminate(self): - # Delete Running Quagga Daemons - rundaemons = self.cmd('ls -1 /var/run/quagga/*.pid') - for d in StringIO.StringIO(rundaemons): - self.cmd('kill -7 `cat %s`' % d.rstrip()) - self.waitOutput() - # Disable forwarding - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') - super(QuaggaRouter, self).terminate() - def removeIPs(self): - for interface in self.intfNames(): - self.cmd('ip address flush', interface) - def loadConf(self, daemon, source=None): - # print "Daemons before:", self.daemons - if daemon in self.daemons.keys(): - self.daemons[daemon] = 1 - if source is None: - self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) - self.waitOutput() - else: - self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) - self.waitOutput() - self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) - self.waitOutput() - self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) - self.waitOutput() - else: - print("No daemon %s known" % daemon) - # print "Daemons after:", self.daemons - def startQuagga(self): - # Disable integrated-vtysh-config - ### self.cmd('echo "no service integrated-vtysh-config" > /etc/%s/vtysh.conf' % self.routertype) - with open('/etc/%s/vtysh.conf' % self.routertype, "w") as vtyshfile: - vtyshfile.write('no service integrated-vtysh-config') - self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) - # Try to find relevant old logfiles in /tmp and delete them - map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) - # Remove old core files - map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) - # Remove IP addresses from OS first - we have them in zebra.conf - self.removeIPs() - # Start Zebra first - if self.daemons['zebra'] == 1: - self.cmd('/usr/lib/%s/zebra -d' % self.routertype) - self.waitOutput() - print('%s: %s zebra started' % (self, self.routertype)) - sleep(1) - # Fix Link-Local Addresses - # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this - self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') - # Now start all the other daemons - for daemon in self.daemons: - if (self.daemons[daemon] == 1) and (daemon != 'zebra'): - self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) - self.waitOutput() - print('%s: %s %s started' % (self, self.routertype, daemon)) - def checkQuaggaRunning(self): - global fatal_error - - daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') - failed = [] - for daemon in self.daemons: - if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): - sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) - # Look for core file - corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) - if (len(corefiles) > 0): - backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) - sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) - sys.stderr.write("%s\n" % backtrace) - else: - # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. - if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): - log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) - sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) - sys.stderr.write("%s\n" % log_tail) - failed += [daemon] - return failed - -class LegacySwitch(OVSSwitch): - "A Legacy Switch without OpenFlow" - - def __init__(self, name, **params): - OVSSwitch.__init__(self, name, failMode='standalone', **params) - self.switchIP = None - ##################################################### ## @@ -231,24 +91,18 @@ class LegacySwitch(OVSSwitch): ##################################################### class NetworkTopo(Topo): - "A LinuxRouter connecting three IP subnets" + "BGP Multiview Topology 1" def build(self, **_opts): - quaggaPrivateDirs = ['/etc/quagga', - '/etc/frr', - '/var/run/quagga', - '/var/run/frr', - '/var/log'] exabgpPrivateDirs = ['/etc/exabgp', '/var/run/exabgp', '/var/log'] - + # Setup Routers - quagga = {} + router = {} for i in range(1, 2): - quagga[i] = self.addNode('r%s' % i, cls=QuaggaRouter, - privateDirs=quaggaPrivateDirs) + router[i] = topotest.addRouter(self, 'r%s' % i) # Setup Provider BGP peers peer = {} @@ -260,11 +114,11 @@ class NetworkTopo(Topo): # Setup Switches switch = {} # First switch is for a dummy interface (for local network) - switch[0] = self.addSwitch('sw0', cls=LegacySwitch) - self.addLink(switch[0], quagga[1], intfName2='r1-stub') + switch[0] = self.addSwitch('sw0', cls=topotest.LegacySwitch) + self.addLink(switch[0], router[1], intfName2='r1-stub') # Second switch is for connection to all peering routers - switch[1] = self.addSwitch('sw1', cls=LegacySwitch) - self.addLink(switch[1], quagga[1], intfName2='r1-eth0') + switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch) + self.addLink(switch[1], router[1], intfName2='r1-eth0') for j in range(1, 9): self.addLink(switch[1], peer[j], intfName2='peer%s-eth0' % j) @@ -294,7 +148,7 @@ def setup_module(module): for i in range(1, 2): net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) net['r%s' % i].loadConf('bgpd', '%s/r%s/bgpd.conf' % (thisDir, i)) - net['r%s' % i].startQuagga() + net['r%s' % i].startRouter() # Starting PE Hosts and init ExaBGP on each of them print('*** Starting BGP on all 8 Peers in 10s') @@ -309,7 +163,7 @@ def setup_module(module): print('peer%s' % i), print('') - # For debugging after starting Quagga daemons, uncomment the next line + # For debugging after starting Quagga/FRR daemons, uncomment the next line # CLI(net) def teardown_module(module): @@ -327,7 +181,7 @@ def teardown_module(module): # End - Shutdown network net.stop() -def test_quagga_running(): +def test_router_running(): global fatal_error global net @@ -339,15 +193,14 @@ def test_quagga_running(): print("******************************************\n") sleep(5) - # CLI(net) - failedRunning = "" + # Starting Routers for i in range(1, 2): - failedDaemon = net['r%s' % i].checkQuaggaRunning() - if failedDaemon: - failedRunning += " Daemons failed on r%s: %s\n" % (i, failedDaemon) - if failedRunning: - fatal_error = "Some Daemons failed to start or crashed" - assert False, "Daemons failed to start or crashed:\n%s" % failedRunning + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + def test_bgp_converge(): "Check for BGP converged on all peers and BGP views" @@ -398,7 +251,7 @@ def test_bgp_converge(): # print("\nwaiting 15s for routes to populate") # sleep(15) - # For debugging after starting Quagga daemons, uncomment the next line + # For debugging after starting Quagga/FRR daemons, uncomment the next line # CLI(net) def test_bgp_routingTable(): @@ -453,7 +306,7 @@ def test_bgp_routingTable(): assert failures == 0, "Routing Table verification failed for router r%s, view %s:\n%s" % (i, view, diff) - # For debugging after starting Quagga daemons, uncomment the next line + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 81807fa214..88b01d6dbb 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -63,10 +63,8 @@ import os import re import sys import difflib -import StringIO -import glob -import subprocess -import platform +import pytest +from time import sleep from mininet.topo import Topo from mininet.net import Mininet @@ -75,173 +73,11 @@ from mininet.log import setLogLevel, info from mininet.cli import CLI from mininet.link import Intf -from functools import partial -from time import sleep - -import pytest +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from lib import topotest fatal_error = "" -def int2dpid(dpid): - "Converting Integer to DPID" - - try: - dpid = hex(dpid)[2:] - dpid = '0'*(16-len(dpid))+dpid - return dpid - except IndexError: - raise Exception('Unable to derive default datapath ID - ' - 'please either specify a dpid or use a ' - 'canonical switch name such as s23.') - -class LinuxRouter(Node): - "A Node with IPv4/IPv6 forwarding enabled." - - def config(self, **params): - super(LinuxRouter, self).config(**params) - # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') - def terminate(self): - """ - Terminate generic LinuxRouter Mininet instance - """ - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') - super(LinuxRouter, self).terminate() - -class QuaggaRouter(Node): - "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" - - def config(self, **params): - super(QuaggaRouter, self).config(**params) - # Check if Quagga or FRR is installed - if os.path.isfile('/usr/lib/frr/zebra'): - self.routertype = 'frr' - elif os.path.isfile('/usr/lib/quagga/zebra'): - self.routertype = 'quagga' - else: - raise Exception('No FRR or Quagga found in ususal location') - # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') - # Enable coredumps - self.cmd('sysctl kernel.core_uses_pid=1') - self.cmd('sysctl fs.suid_dumpable=2') - self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) - self.cmd('ulimit -c unlimited') - # Set ownership of config files - self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) - self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, - 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0, - 'ldpd': 0} - def terminate(self): - # Delete Running Quagga Daemons - rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) - for d in StringIO.StringIO(rundaemons): - self.cmd('kill -7 `cat %s`' % d.rstrip()) - self.waitOutput() - # Disable forwarding - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') - super(QuaggaRouter, self).terminate() - def removeIPs(self): - for interface in self.intfNames(): - self.cmd('ip address flush', interface) - def loadConf(self, daemon, source=None): - # print "Daemons before:", self.daemons - if daemon in self.daemons.keys(): - self.daemons[daemon] = 1 - if source is None: - self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) - self.waitOutput() - else: - self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) - self.waitOutput() - self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) - self.waitOutput() - self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) - self.waitOutput() - else: - print("No daemon %s known" % daemon) - # print "Daemons after:", self.daemons - def startQuagga(self): - global fatal_error - - # Disable integrated-vtysh-config - with open('/etc/%s/vtysh.conf' % self.routertype, "w") as vtyshfile: - vtyshfile.write('no service integrated-vtysh-config') - self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) - # Try to find relevant old logfiles in /tmp and delete them - map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) - # Remove old core files - map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) - # Remove IP addresses from OS first - we have them in zebra.conf - self.removeIPs() - # If ldp is used, check for LDP to be compiled and Linux Kernel to be 4.5 or higher - # No error - but return message and skip all the tests - if self.daemons['ldpd'] == 1: - if not os.path.isfile('/usr/lib/%s/ldpd' % self.routertype): - fatal_error = "LDP Test, but no ldpd compiled or installed" - print("LDP Test, but no ldpd compiled or installed") - return - kernel_version = re.search(r'([0-9]+\.[0-9]+).*', platform.release()) - if kernel_version: - if float(kernel_version.group(1)) < 4.5: - fatal_error = "LDP Test need Linux Kernel 4.5 minimum" - print("LDP Test need Linux Kernel 4.5 minimum") - return - # Add mpls modules to kernel if we use LDP - if self.daemons['ldpd'] == 1: - self.cmd('/sbin/modprobe mpls-router') - self.cmd('/sbin/modprobe mpls-iptunnel') - self.cmd('echo 100000 > /proc/sys/net/mpls/platform_labels') - # Start Zebra first - if self.daemons['zebra'] == 1: - self.cmd('/usr/lib/%s/zebra -d' % self.routertype) - self.waitOutput() - print('%s: %s zebra started' % (self, self.routertype)) - sleep(1) - # Fix Link-Local Addresses - # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this - self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') - # Now start all the other daemons - for daemon in self.daemons: - if (self.daemons[daemon] == 1) and (daemon != 'zebra'): - self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) - self.waitOutput() - print('%s: %s %s started' % (self, self.routertype, daemon)) - def checkQuaggaRunning(self): - global fatal_error - - daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') - for daemon in self.daemons: - if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): - sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) - # Look for core file - corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) - if (len(corefiles) > 0): - backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) - sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) - sys.stderr.write("%s\n" % backtrace) - else: - # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. - if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): - log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) - sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) - sys.stderr.write("%s\n" % log_tail) - - fatal_error = "%s: Daemon %s not running" % (self.name, daemon) - assert False, "%s: Daemon %s not running" % (self.name, daemon) - -class LegacySwitch(OVSSwitch): - "A Legacy Switch without OpenFlow" - - def __init__(self, name, **params): - OVSSwitch.__init__(self, name, failMode='standalone', **params) - self.switchIP = None - - ##################################################### ## ## Network Topology Definition @@ -249,41 +85,32 @@ class LegacySwitch(OVSSwitch): ##################################################### class NetworkTopo(Topo): - "A LinuxRouter connecting three IP subnets" + "LDP Test Topology 1" def build(self, **_opts): - quaggaPrivateDirs = ['/etc/quagga', - '/etc/frr', - '/var/run/quagga', - '/var/run/frr', - '/var/log'] - exabgpPrivateDirs = ['/etc/exabgp', - '/var/run/exabgp', - '/var/log'] - # Setup Routers router = {} for i in range(1, 5): - router[i] = self.addNode('r%s' % i, cls=QuaggaRouter, - privateDirs=quaggaPrivateDirs) + router[i] = topotest.addRouter(self, 'r%s' % i) - # Setup Switches + # Setup Switches, add Interfaces and Connections switch = {} # First switch - switch[0] = self.addSwitch('sw0', cls=LegacySwitch) + switch[0] = self.addSwitch('sw0', cls=topotest.LegacySwitch) self.addLink(switch[0], router[1], intfName2='r1-eth0', addr1='80:AA:00:00:00:00', addr2='00:11:00:01:00:00') self.addLink(switch[0], router[2], intfName2='r2-eth0', addr1='80:AA:00:00:00:01', addr2='00:11:00:02:00:00') # Second switch - switch[1] = self.addSwitch('sw1', cls=LegacySwitch) + switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch) self.addLink(switch[1], router[2], intfName2='r2-eth1', addr1='80:AA:00:01:00:00', addr2='00:11:00:02:00:01') self.addLink(switch[1], router[3], intfName2='r3-eth0', addr1='80:AA:00:01:00:01', addr2='00:11:00:03:00:00') self.addLink(switch[1], router[4], intfName2='r4-eth0', addr1='80:AA:00:01:00:02', addr2='00:11:00:04:00:00') # Third switch - switch[2] = self.addSwitch('sw2', cls=LegacySwitch) + switch[2] = self.addSwitch('sw2', cls=topotest.LegacySwitch) self.addLink(switch[2], router[2], intfName2='r2-eth2', addr1='80:AA:00:02:00:00', addr2='00:11:00:02:00:02') self.addLink(switch[2], router[3], intfName2='r3-eth1', addr1='80:AA:00:02:00:01', addr2='00:11:00:03:00:01') + ##################################################### ## ## Tests starting @@ -292,6 +119,7 @@ class NetworkTopo(Topo): def setup_module(module): global topo, net + global fatal_error print("\n\n** %s: Setup Topology" % module.__name__) print("******************************************\n") @@ -310,7 +138,10 @@ def setup_module(module): net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) net['r%s' % i].loadConf('ospfd', '%s/r%s/ospfd.conf' % (thisDir, i)) net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i)) - net['r%s' % i].startQuagga() + fatal_error = net['r%s' % i].startRouter() + + if fatal_error != "": + break # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -325,7 +156,7 @@ def teardown_module(module): net.stop() -def test_quagga_running(): +def test_router_running(): global fatal_error global net @@ -339,8 +170,11 @@ def test_quagga_running(): # Starting Routers for i in range(1, 5): - net['r%s' % i].checkQuaggaRunning() + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) def test_mpls_interfaces(): global fatal_error @@ -383,6 +217,9 @@ def test_mpls_interfaces(): else: print("r%s ok" % i) + if failures>0: + fatal_error = "MPLS LDP Interface status failed" + assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff) # For debugging after starting FRR/Quagga daemons, uncomment the next line diff --git a/tests/topotests/lib/__init__.py b/tests/topotests/lib/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py new file mode 100644 index 0000000000..175edf4ab7 --- /dev/null +++ b/tests/topotests/lib/topotest.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python + +# +# topotest.py +# Library of helper functions for NetDEF Topology Tests +# +# Copyright (c) 2016 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import re +import sys +import glob +import StringIO +import subprocess +import platform + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from time import sleep + +def int2dpid(dpid): + "Converting Integer to DPID" + + try: + dpid = hex(dpid)[2:] + dpid = '0'*(16-len(dpid))+dpid + return dpid + except IndexError: + raise Exception('Unable to derive default datapath ID - ' + 'please either specify a dpid or use a ' + 'canonical switch name such as s23.') + +def addRouter(topo, name): + "Adding a FreeRangeRouter (or Quagga) to Topology" + + MyPrivateDirs = ['/etc/frr', + '/etc/quagga', + '/var/run/frr', + '/var/run/quagga', + '/var/log'] + return topo.addNode(name, cls=Router, privateDirs=MyPrivateDirs) + +class LinuxRouter(Node): + "A Node with IPv4/IPv6 forwarding enabled." + + def config(self, **params): + super(LinuxRouter, self).config(**params) + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + def terminate(self): + """ + Terminate generic LinuxRouter Mininet instance + """ + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(LinuxRouter, self).terminate() + +class Router(Node): + "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" + + def config(self, **params): + super(Router, self).config(**params) + + # Check if Quagga or FRR is installed + if os.path.isfile('/usr/lib/frr/zebra'): + self.routertype = 'frr' + elif os.path.isfile('/usr/lib/quagga/zebra'): + self.routertype = 'quagga' + else: + raise Exception('No FRR or Quagga found in ususal location') + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + # Enable coredumps + self.cmd('sysctl kernel.core_uses_pid=1') + self.cmd('sysctl fs.suid_dumpable=2') + self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) + self.cmd('ulimit -c unlimited') + # Set ownership of config files + self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) + self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, + 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0, + 'ldpd': 0} + def terminate(self): + # Delete Running Quagga or FRR Daemons + rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) + for d in StringIO.StringIO(rundaemons): + self.cmd('kill -7 `cat %s`' % d.rstrip()) + self.waitOutput() + # Disable forwarding + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(Router, self).terminate() + def removeIPs(self): + for interface in self.intfNames(): + self.cmd('ip address flush', interface) + def loadConf(self, daemon, source=None): + # print "Daemons before:", self.daemons + if daemon in self.daemons.keys(): + self.daemons[daemon] = 1 + if source is None: + self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) + self.waitOutput() + else: + self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) + self.waitOutput() + self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) + self.waitOutput() + self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) + self.waitOutput() + else: + print("No daemon %s known" % daemon) + # print "Daemons after:", self.daemons + def startRouter(self): + # Disable integrated-vtysh-config + with open('/etc/%s/vtysh.conf' % self.routertype, "w") as vtyshfile: + vtyshfile.write('no service integrated-vtysh-config') + self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) + # Try to find relevant old logfiles in /tmp and delete them + map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) + # Remove old core files + map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) + # Remove IP addresses from OS first - we have them in zebra.conf + self.removeIPs() + # If ldp is used, check for LDP to be compiled and Linux Kernel to be 4.5 or higher + # No error - but return message and skip all the tests + if self.daemons['ldpd'] == 1: + if not os.path.isfile('/usr/lib/%s/ldpd' % self.routertype): + print("LDP Test, but no ldpd compiled or installed") + return "LDP Test, but no ldpd compiled or installed" + kernel_version = re.search(r'([0-9]+\.[0-9]+).*', platform.release()) + if kernel_version: + if float(kernel_version.group(1)) < 4.5: + print("LDP Test need Linux Kernel 4.5 minimum") + return "LDP Test need Linux Kernel 4.5 minimum" + # Add mpls modules to kernel if we use LDP + if self.daemons['ldpd'] == 1: + self.cmd('/sbin/modprobe mpls-router') + self.cmd('/sbin/modprobe mpls-iptunnel') + self.cmd('echo 100000 > /proc/sys/net/mpls/platform_labels') + # Start Zebra first + if self.daemons['zebra'] == 1: + self.cmd('/usr/lib/%s/zebra -d' % self.routertype) + self.waitOutput() + print('%s: %s zebra started' % (self, self.routertype)) + sleep(1) + # Fix Link-Local Addresses + # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this + self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') + # Now start all the other daemons + for daemon in self.daemons: + if (self.daemons[daemon] == 1) and (daemon != 'zebra'): + self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) + self.waitOutput() + print('%s: %s %s started' % (self, self.routertype, daemon)) + return "" + def checkRouterRunning(self): + global fatal_error + + daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') + for daemon in self.daemons: + if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): + sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) + # Look for core file + corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) + if (len(corefiles) > 0): + backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) + sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) + sys.stderr.write("%s\n" % backtrace) + else: + # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. + if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): + log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) + sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) + sys.stderr.write("%s\n" % log_tail) + + return "%s: Daemon %s not running" % (self.name, daemon) + return "" + def get_ipv6_linklocal(self): + "Get LinkLocal Addresses from interfaces" + + linklocal = [] + + ifaces = self.cmd('ip -6 address') + # Fix newlines (make them all the same) + ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines() + interface="" + ll_per_if_count=0 + for line in ifaces: + m = re.search('[0-9]+: ([^:@]+)[@if0-9:]+ <', line) + if m: + interface = m.group(1) + ll_per_if_count = 0 + m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)[/0-9]* scope link', line) + if m: + local = m.group(1) + ll_per_if_count += 1 + if (ll_per_if_count > 1): + linklocal += [["%s-%s" % (interface, ll_per_if_count), local]] + else: + linklocal += [[interface, local]] + return linklocal + +class LegacySwitch(OVSSwitch): + "A Legacy Switch without OpenFlow" + + def __init__(self, name, **params): + OVSSwitch.__init__(self, name, failMode='standalone', **params) + self.switchIP = None + diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index f669fdecdc..7b3eeb9549 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -34,7 +34,7 @@ test_ospf6_topo1.py: | ::1 | ::2 | +---------+---------+ +---------+---------+ | | R1 | | R2 | | -| Quagga | | Quagga | | +| FreeRangeRouting | | FreeRangeRouting | | | Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | | +---------+---------+ +---------+---------+ | | ::1 | ::2 \ @@ -50,7 +50,7 @@ test_ospf6_topo1.py: | ::3 | SW3 - Stub Net 3 | +---------+---------+ /-+ fc00:3:3:3::/64 | | R3 | / | / - | Quagga +--/ \---- / + | FreeRangeRouting +--/ \---- / | Rtr-ID: 10.0.0.3 | ::3 ___________/ +---------+---------+ \ | ::3 \ @@ -64,196 +64,53 @@ test_ospf6_topo1.py: | ::4 / +---------+---------+ /---- | | R4 | | SW4 - Stub Net 4 | - | Quagga +------+ fc00:4:4:4::/64 | + | FreeRangeRouting +------+ fc00:4:4:4::/64 | | Rtr-ID: 10.0.0.4 | ::4 | / +-------------------+ \---- / -----/ """ +# import os +# import re +# import sys +# import difflib +# import StringIO +# import glob +# import subprocess + +# from mininet.topo import Topo +# from mininet.net import Mininet +# from mininet.node import Node, OVSSwitch, Host +# from mininet.log import setLogLevel, info +# from mininet.cli import CLI + +# from functools import partial +# from time import sleep + +# import pytest + import os import re import sys import difflib -import StringIO -import glob -import subprocess +import pytest +from time import sleep from mininet.topo import Topo from mininet.net import Mininet from mininet.node import Node, OVSSwitch, Host from mininet.log import setLogLevel, info from mininet.cli import CLI +from mininet.link import Intf from functools import partial -from time import sleep -import pytest +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from lib import topotest + fatal_error = "" -def int2dpid(dpid): - "Converting Integer to DPID" - - try: - dpid = hex(dpid)[2:] - dpid = '0'*(16-len(dpid))+dpid - return dpid - except IndexError: - raise Exception('Unable to derive default datapath ID - ' - 'please either specify a dpid or use a ' - 'canonical switch name such as s23.') - -class LinuxRouter(Node): - "A Node with IPv4/IPv6 forwarding enabled." - - def config(self, **params): - super(LinuxRouter, self).config(**params) - # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') - def terminate(self): - """ - Terminate generic LinuxRouter Mininet instance - """ - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') - super(LinuxRouter, self).terminate() - -class QuaggaRouter(Node): - "A Node with IPv4/IPv6 forwarding enabled and FRR/Quagga as Routing Engine" - - def config(self, **params): - super(QuaggaRouter, self).config(**params) - # Check if Quagga or FRR is installed - if os.path.isfile('/usr/lib/frr/zebra'): - self.routertype = 'frr' - elif os.path.isfile('/usr/lib/quagga/zebra'): - self.routertype = 'quagga' - else: - raise Exception('No FRR or Quagga found in ususal location') - # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') - # Enable coredumps - self.cmd('sysctl kernel.core_uses_pid=1') - self.cmd('sysctl fs.suid_dumpable=2') - self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) - self.cmd('ulimit -c unlimited') - # Set ownership of config files - self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) - self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, - 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0} - def terminate(self): - # Delete Running Quagga Daemons - rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) - for d in StringIO.StringIO(rundaemons): - self.cmd('kill -7 `cat %s`' % d.rstrip()) - self.waitOutput() - # Disable forwarding - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') - super(QuaggaRouter, self).terminate() - def removeIPs(self): - for interface in self.intfNames(): - self.cmd('ip address flush', interface) - def loadConf(self, daemon, source=None): - # print "Daemons before:", self.daemons - if daemon in self.daemons.keys(): - self.daemons[daemon] = 1 - if source is None: - self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) - self.waitOutput() - else: - self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) - self.waitOutput() - self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) - self.waitOutput() - self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) - self.waitOutput() - else: - print("No daemon %s known" % daemon) - # print "Daemons after:", self.daemons - def startQuagga(self): - # Disable integrated-vtysh-config - ### self.cmd('echo "no service integrated-vtysh-config" > /etc/%s/vtysh.conf' % self.routertype) - with open('/etc/%s/vtysh.conf' % self.routertype, "w") as vtyshfile: - vtyshfile.write('no service integrated-vtysh-config') - self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) - # Try to find relevant old logfiles in /tmp and delete them - map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) - # Remove old core files - map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) - # Remove IP addresses from OS first - we have them in zebra.conf - self.removeIPs() - # Start Zebra first - if self.daemons['zebra'] == 1: - self.cmd('/usr/lib/%s/zebra -d' % self.routertype) - self.waitOutput() - print('%s: %s zebra started' % (self, self.routertype)) - sleep(1) - # Fix Link-Local Addresses - # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this - self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') - # Now start all the other daemons - for daemon in self.daemons: - if (self.daemons[daemon] == 1) and (daemon != 'zebra'): - self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) - self.waitOutput() - print('%s: %s %s started' % (self, self.routertype, daemon)) - def checkQuaggaRunning(self): - global fatal_error - - daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') - failed = [] - for daemon in self.daemons: - if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): - sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) - # Look for core file - corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) - if (len(corefiles) > 0): - backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) - sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) - sys.stderr.write("%s\n" % backtrace) - else: - # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. - if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): - log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) - sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) - sys.stderr.write("%s\n" % log_tail) - failed += [daemon] - return failed - def get_ipv6_linklocal(self): - "Get LinkLocal Addresses from interfaces" - - linklocal = [] - - ifaces = self.cmd('ip -6 address') - # Fix newlines (make them all the same) - ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines() - interface="" - ll_per_if_count=0 - for line in ifaces: - m = re.search('[0-9]+: ([^:@]+)[@if0-9:]+ <', line) - if m: - interface = m.group(1) - ll_per_if_count = 0 - m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)[/0-9]* scope link', line) - if m: - local = m.group(1) - ll_per_if_count += 1 - if (ll_per_if_count > 1): - linklocal += [["%s-%s" % (interface, ll_per_if_count), local]] - else: - linklocal += [[interface, local]] - return linklocal - - -class LegacySwitch(OVSSwitch): - "A Legacy Switch without OpenFlow" - - def __init__(self, name, **params): - OVSSwitch.__init__(self, name, failMode='standalone', **params) - self.switchIP = None ##################################################### ## @@ -262,29 +119,24 @@ class LegacySwitch(OVSSwitch): ##################################################### class NetworkTopo(Topo): - "A Quagga Topology with direct peering router and IXP connection" + "OSPFv3 (IPv6) Test Topology 1" def build(self, **_opts): - - quaggaPrivateDirs = ['/etc/quagga', - '/etc/frr', - '/var/run/quagga', - '/var/run/frr', - '/var/log'] # # Define Switches first # switch = {} for i in range(1, 7): - switch[i] = self.addSwitch('SW%s' % i, dpid=int2dpid(i), - cls=LegacySwitch) + switch[i] = self.addSwitch('SW%s' % i, + dpid=topotest.int2dpid(i), + cls=topotest.LegacySwitch) # # Define FRR/Quagga Routers # router = {} for i in range(1, 5): - router[i] = self.addNode('r%s' % i, cls=QuaggaRouter, - privateDirs=quaggaPrivateDirs) + router[i] = topotest.addRouter(self, 'r%s' % i) + # # Wire up the switches and routers # @@ -328,7 +180,7 @@ def setup_module(module): for i in range(1, 5): net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i)) - net['r%s' % i].startQuagga() + net['r%s' % i].startRouter() # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -344,7 +196,7 @@ def teardown_module(module): net.stop() -def test_quagga_running(): +def test_router_running(): global fatal_error global net @@ -359,13 +211,11 @@ def test_quagga_running(): # CLI(net) failedRunning = "" for i in range(1, 5): - failedDaemon = net['r%s' % i].checkQuaggaRunning() - if failedDaemon: - failedRunning += " Daemons failed on r%s: %s\n" % (i, failedDaemon) - if failedRunning: - fatal_error = "Some Daemons failed to start or crashed" - assert False, "Daemons failed to start or crashed:\n%s" % failedRunning + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) def test_ospf6_converged(): global fatal_error From 99561211e1d7581e22eab450999e7cd04ed919e4 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 1 Feb 2017 07:50:13 -0800 Subject: [PATCH 031/384] Added optional output for memleaks at the end of test. Enable them by setting the environment variable TOPOTESTS_CHECK_STDERR to some value Signed-off-by: Martin Winter --- .../test_bgp_multiview_topo1.py | 24 ++++++++++++- tests/topotests/ldp-topo1/test_ldp_topo1.py | 27 +++++++++++++++ tests/topotests/lib/topotest.py | 34 +++++++++++++++---- .../topotests/ospf6-topo1/test_ospf6_topo1.py | 24 +++++++++++++ 4 files changed, 101 insertions(+), 8 deletions(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 4836e2ba06..9ada8422cc 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -264,7 +264,6 @@ def test_bgp_routingTable(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify OSPFv3 Routing Table print("\n\n** Verifing BGP Routing Tables") print("******************************************\n") failures = 0 @@ -309,6 +308,29 @@ def test_bgp_routingTable(): # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) +def test_shutdown_check_stderr(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + pytest.skip('Skipping test for Stderr output and memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifing unexpected STDERR output from daemons") + print("******************************************\n") + + net['r1'].stopRouter() + + log = net['r1'].getStdErr('bgpd') + print("\nBGPd StdErr Log:\n" + log) + log = net['r1'].getStdErr('zebra') + print("\nZebra StdErr Log:\n" + log) + if __name__ == '__main__': diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 88b01d6dbb..2db7cbe5f4 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -642,6 +642,33 @@ def test_linux_mpls_routes(): # CLI(net) +def test_shutdown_check_stderr(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + pytest.skip('Skipping test for Stderr output and memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifing unexpected STDERR output from daemons") + print("******************************************\n") + + for i in range(1, 5): + net['r%s' % i].stopRouter() + log = net['r%s' % i].getStdErr('ldpd') + print("\nRouter r%s LDPd StdErr Log:\n%s" % (i, log)) + log = net['r%s' % i].getStdErr('ospfd') + print("\nRouter r%s OSPFd StdErr Log:\n%s" % (i, log)) + log = net['r%s' % i].getStdErr('zebra') + print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log)) + + + if __name__ == '__main__': setLogLevel('info') diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 175edf4ab7..015705510a 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -105,14 +105,22 @@ class Router(Node): 'ldpd': 0} def terminate(self): # Delete Running Quagga or FRR Daemons - rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) - for d in StringIO.StringIO(rundaemons): - self.cmd('kill -7 `cat %s`' % d.rstrip()) - self.waitOutput() + self.stopRouter() + # rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) + # for d in StringIO.StringIO(rundaemons): + # self.cmd('kill -7 `cat %s`' % d.rstrip()) + # self.waitOutput() # Disable forwarding self.cmd('sysctl net.ipv4.ip_forward=0') self.cmd('sysctl net.ipv6.conf.all.forwarding=0') super(Router, self).terminate() + def stopRouter(self): + # Stop Running Quagga or FRR Daemons + rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) + if rundaemons is not None: + for d in StringIO.StringIO(rundaemons): + self.cmd('kill -7 `cat %s`' % d.rstrip()) + self.waitOutput() def removeIPs(self): for interface in self.intfNames(): self.cmd('ip address flush', interface) @@ -160,9 +168,15 @@ class Router(Node): self.cmd('/sbin/modprobe mpls-router') self.cmd('/sbin/modprobe mpls-iptunnel') self.cmd('echo 100000 > /proc/sys/net/mpls/platform_labels') + # Init done - now restarting daemons + self.restartRouter() + return "" + def restartRouter(self): + # Starts actuall daemons without init (ie restart) # Start Zebra first if self.daemons['zebra'] == 1: - self.cmd('/usr/lib/%s/zebra -d' % self.routertype) +# self.cmd('/usr/lib/%s/zebra -d' % self.routertype) + self.cmd('/usr/lib/%s/zebra > /tmp/%s-zebra.out 2> /tmp/%s-zebra.err &' % (self.routertype, self.name, self.name)) self.waitOutput() print('%s: %s zebra started' % (self, self.routertype)) sleep(1) @@ -172,10 +186,16 @@ class Router(Node): # Now start all the other daemons for daemon in self.daemons: if (self.daemons[daemon] == 1) and (daemon != 'zebra'): - self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) +# self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) + self.cmd('/usr/lib/%s/%s > /tmp/%s-%s.out 2> /tmp/%s-%s.err &' % (self.routertype, daemon, self.name, daemon, self.name, daemon)) self.waitOutput() print('%s: %s %s started' % (self, self.routertype, daemon)) - return "" + def getStdErr(self, daemon): + return self.getLog('err', daemon) + def getStdOut(self, daemon): + return self.getLog('out', daemon) + def getLog(self, log, daemon): + return self.cmd('cat /tmp/%s-%s.%s' % (self.name, daemon, log) ) def checkRouterRunning(self): global fatal_error diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 7b3eeb9549..6da2e89780 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -369,6 +369,30 @@ def test_linux_ipv6_kernel_routingTable(): # CLI(net) +def test_shutdown_check_stderr(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + pytest.skip('Skipping test for Stderr output and memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifing unexpected STDERR output from daemons") + print("******************************************\n") + + for i in range(1, 5): + net['r%s' % i].stopRouter() + log = net['r%s' % i].getStdErr('ospf6d') + print("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log)) + log = net['r%s' % i].getStdErr('zebra') + print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log)) + + if __name__ == '__main__': setLogLevel('info') From d98b7d6359392c79a135bbe00f1eb981403adeb6 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 1 Feb 2017 08:01:32 -0800 Subject: [PATCH 032/384] bgp_multiview_topo1: Mask out BGP Table version in comparison Signed-off-by: Martin Winter --- tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref | 2 +- tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref | 2 +- tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref | 2 +- tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref index 0e8bf842fd..6f1b1a1036 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref @@ -1,4 +1,4 @@ -BGP table version is 0, local router ID is 172.30.1.1 +BGP table version is XXX, local router ID is 172.30.1.1 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref index cfdbaeb99d..0230d25f53 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref @@ -1,4 +1,4 @@ -BGP table version is 0, local router ID is 172.30.1.1 +BGP table version is XXX, local router ID is 172.30.1.1 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref index f0f471db8e..b7e8c79d3c 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref @@ -1,4 +1,4 @@ -BGP table version is 0, local router ID is 172.30.1.1 +BGP table version is XXX, local router ID is 172.30.1.1 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 9ada8422cc..3e548d6ff5 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -286,6 +286,8 @@ def test_bgp_routingTable(): actual = re.sub(r'Total number.*', '', actual) actual = re.sub(r'Displayed.*', '', actual) actual = actual.rstrip() + # Fix table version (ignore it) + actual = re.sub(r'(BGP table version is )[0-9]+', r'\1XXX', actual) # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) From 33ae1f751e133afa1c8f1dfb2f1bd9852a1e4133 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 1 Feb 2017 08:07:53 -0800 Subject: [PATCH 033/384] Update Readme to reflect FreeRangeRouting name Signed-off-by: Martin Winter --- tests/topotests/README.md | 46 +++++++++---------- tests/topotests/bgp_multiview_topo1/README.md | 8 ++-- tests/topotests/ospf6-topo1/README.md | 14 +++--- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index 69548f5577..321a04bfa8 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -1,4 +1,4 @@ -# Quagga Topology Tests with Mininet +# FreeRangeRouting Topology Tests with Mininet ## Installation of Mininet for running tests Only tested with Ubuntu 16.04 (which uses Mininet 2.2.0) @@ -36,44 +36,44 @@ Optional, will give better output 4. reboot (for options to take effect) -## Quagga Installation +## FreeRangeRouting (FRR) Installation Quagga needs to be installed separatly. It is assume to be configured like the standard Ubuntu Packages: -- Binaries in /usr/lib/quagga -- State Directory /var/run/quagga -- Running under user quagga, group quagga -- vtygroup: quaggavty -- config directory: /etc/quagga -- For Quagga Packages, install the dbg package as well for coredump decoding +- Binaries in /usr/lib/frr +- State Directory /var/run/frr +- Running under user frr, group frr +- vtygroup: frrvty +- config directory: /etc/frr +- For FRR Packages, install the dbg package as well for coredump decoding -No Quagga config needs to be done and no Quagga daemons should be run ahead +No FRR config needs to be done and no FRR daemons should be run ahead of the test. They are all started as part of the test -#### Manual Quagga build +#### Manual FreeRangeRouting (FRR) build -If you prefer to manually build Quagga, then use the following suggested config: +If you prefer to manually build FRR, then use the following suggested config: ./configure \ --prefix=/usr \ - --localstatedir=/var/run/quagga \ - --sbindir=/usr/lib/quagga \ - --sysconfdir=/etc/quagga \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ --enable-vtysh \ --enable-pimd \ --enable-multipath=64 \ - --enable-user=quagga \ - --enable-group=quagga \ - --enable-vty-group=quaggavty \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ --with-pkg-extra-version=-my-manual-build -And create Quagga User and Quaggavty group as follows: +And create frr User and frrvty group as follows: - addgroup --system --gid 92 quagga - addgroup --system --gid 85 quaggavty - usermod -G quaggavty quagga - adduser --system --ingroup quagga --home /var/run/quagga/ \ - --gecos "Quagga routing suite" --shell /bin/false quagga + addgroup --system --gid 92 frr + addgroup --system --gid 85 frrvty + usermod -G frrvty frr + adduser --system --ingroup frr --home /var/run/frr/ \ + --gecos "FreeRangeRouting suite" --shell /bin/false frr ## Executing Tests diff --git a/tests/topotests/bgp_multiview_topo1/README.md b/tests/topotests/bgp_multiview_topo1/README.md index 79bbb36b6b..4ae6c1e699 100644 --- a/tests/topotests/bgp_multiview_topo1/README.md +++ b/tests/topotests/bgp_multiview_topo1/README.md @@ -1,4 +1,4 @@ -# Simple Quagga Route-Server Test +# Simple FreeRangeRouting Route-Server Test ## Topology +----------+ +----------+ +----------+ +----------+ +----------+ @@ -23,7 +23,7 @@ | | .254 +---------+---------+ - | Quagga R1 | + | FRR R1 | | BGP Multi-View | | Peer 1-3 > View 1 | | Peer 4-5 > View 2 | @@ -37,7 +37,7 @@ ~~ Stub Switch ~~ ~~~~~~~~~~~~~ -## Quagga Configuration +## FRR Configuration Full config as used is in r1 subdirectory @@ -92,7 +92,7 @@ Simplified `R1` config: ## Tests executed -### Check if Quagga is running +### Check if FRR is running Test is executed by running diff --git a/tests/topotests/ospf6-topo1/README.md b/tests/topotests/ospf6-topo1/README.md index 864c8e9ede..e638550f4d 100644 --- a/tests/topotests/ospf6-topo1/README.md +++ b/tests/topotests/ospf6-topo1/README.md @@ -10,7 +10,7 @@ | ::1 | ::2 | +---------+---------+ +---------+---------+ | | R1 | | R2 | | - | Quagga | | Quagga | | + | FreeRangeRouting | | FreeRangeRouting | | | Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | | +---------+---------+ +---------+---------+ | | ::1 | ::2 \ @@ -26,7 +26,7 @@ | ::3 | SW3 - Stub Net 3 | +---------+---------+ /-+ fc00:3:3:3::/64 | | R3 | / | / - | Quagga +--/ \---- / + | FreeRangeRouting +--/ \---- / | Rtr-ID: 10.0.0.3 | ::3 ___________/ +---------+---------+ \ | ::3 \ @@ -40,12 +40,12 @@ | ::4 / +---------+---------+ /---- | | R4 | | SW4 - Stub Net 4 | - | Quagga +------+ fc00:4:4:4::/64 | + | FreeRangeRouting +------+ fc00:4:4:4::/64 | | Rtr-ID: 10.0.0.4 | ::4 | / +-------------------+ \---- / -----/ -## Quagga Configuration +## FRR Configuration Full config as used is in r1 / r2 / r3 / r4 / r5 subdirectories @@ -98,13 +98,13 @@ Simplified `R3` config ## Tests executed -### Check if Quagga is running +### Check if FRR is running Test is executed by running vtysh -c "show log" | grep "Logging configuration for" -on each quagga router. This should return the logging information for all daemons registered +on each FRR router. This should return the logging information for all daemons registered to Zebra and the list of running daemons is compared to the daemons started for this test (`zebra` and `ospf6d`) ### Verify for OSPFv3 to converge @@ -125,7 +125,7 @@ on each node and comparing the result to the stored example config (see `show_ip ### Verifying Linux Kernel Routing Table -Linux Kernel IPv6 Routing table is verified on each Quagga node with +Linux Kernel IPv6 Routing table is verified on each FRR node with ip -6 route From 3a4f98d58769d3205005948761d90be92f00ffc2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 8 Feb 2017 19:12:43 -0500 Subject: [PATCH 034/384] Update Readme to have correct ordering for frr user We cannot usermod the frr user until after we create the user with adduser. Signed-off-by: Donald Sharp --- tests/topotests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index 321a04bfa8..6f61b61d65 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -71,9 +71,9 @@ And create frr User and frrvty group as follows: addgroup --system --gid 92 frr addgroup --system --gid 85 frrvty - usermod -G frrvty frr adduser --system --ingroup frr --home /var/run/frr/ \ --gecos "FreeRangeRouting suite" --shell /bin/false frr + usermod -G frrvty frr ## Executing Tests From 37c4800c4400e749bf3c194063d6740b535741b1 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 16 Feb 2017 23:53:48 +0700 Subject: [PATCH 035/384] ldp-topo1: Delete accidentally include tar file Signed-off-by: Martin Winter --- tests/topotests/ldp-topo1/ldpd-test1.tar | Bin 15360 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/topotests/ldp-topo1/ldpd-test1.tar diff --git a/tests/topotests/ldp-topo1/ldpd-test1.tar b/tests/topotests/ldp-topo1/ldpd-test1.tar deleted file mode 100644 index 897e67b67ab8bd136ba6ffc799f158241881837c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15360 zcmeHN>z1N04E8rq5g$P94R{__>JDcSIHltr_vyDSPM6UUZxz`yp+6L2LQV2DX;P)x zs&1Q2zFgPUX7-ee5RwQ1GeT$@lm4fnn2RPHC?||?Mp#OKP{HG52IMKTITHHb>P(rb zDOqK@J|gyRFVVZdV*i}IpvO7suWxm$t86R5IYHE9ZTq`cInb!Af5N6HC9L$eSt(5y zou8QJ(L7T1yOzpvMbO3d}_5VHh3H~YK|4Yk-d1&MRl=lB!|4;CQV*C$d;bAEr|6%$+K8$1kXISq@ NMGc?^Py?^lz+YSuUrPW0 From ff0d89dcfdf115b707c077eb38ba686db90c7079 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 16 Feb 2017 23:54:40 +0700 Subject: [PATCH 036/384] ldp-topo1: Fix ordering of reference output to check against Ordering of output is now done by LDP and should be consistent Signed-off-by: Martin Winter --- .../topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref | 10 +++++----- .../topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref | 2 +- .../topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref index 539bdc890b..b1bebd7c46 100644 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref @@ -1,12 +1,12 @@ Local LDP Identifier: 2.2.2.2:0 Discovery Sources: Interfaces: - r2-eth1: xmit/recv - LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 - Hold time: 15 sec - LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 - Hold time: 15 sec r2-eth0: xmit/recv LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1 Hold time: 15 sec + r2-eth1: xmit/recv + LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 + Hold time: 15 sec + LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 + Hold time: 15 sec Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref index 86e82b919e..f9fc98408c 100644 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref @@ -1,3 +1,3 @@ AF Interface State Uptime Hello Timers ac -ipv4 r2-eth1 ACTIVE xx:xx:xx 5/15 2 ipv4 r2-eth0 ACTIVE xx:xx:xx 5/15 1 +ipv4 r2-eth1 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref index 4fbf536f81..3ebddd606a 100644 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref @@ -2,8 +2,8 @@ Local LDP Identifier: 4.4.4.4:0 Discovery Sources: Interfaces: r4-eth0: xmit/recv - LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 - Hold time: 15 sec LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 Hold time: 15 sec + LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 + Hold time: 15 sec Targeted Hellos: From 1c909f424847f361504a52ab414929460022ce93 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 2 Mar 2017 14:36:30 +0700 Subject: [PATCH 037/384] Fix README incorrect reference to Quagga --- tests/topotests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index 6f61b61d65..7e82a3fa4e 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -37,7 +37,7 @@ Optional, will give better output 4. reboot (for options to take effect) ## FreeRangeRouting (FRR) Installation -Quagga needs to be installed separatly. It is assume to be configured +FRR needs to be installed separatly. It is assume to be configured like the standard Ubuntu Packages: - Binaries in /usr/lib/frr From 3eaafbd95d179853c5431ac40f13190158f088b5 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 23 Mar 2017 22:31:50 -0700 Subject: [PATCH 038/384] LDP-Topo1: Update test to accept new format of LDP output * Added test to check for version * Adopted all tests to verify against the correct version of output Signed-off-by: Martin Winter --- .../ldp-topo1/r1/ip_mpls_route.ref-1 | 5 + .../ldp-topo1/r1/show_ipv4_route.ref-1 | 7 ++ .../ldp-topo1/r1/show_mpls_ldp_binding.ref | 50 ++------ .../ldp-topo1/r1/show_mpls_ldp_binding.ref-1 | 42 +++++++ .../ldp-topo1/r1/show_mpls_ldp_discovery.ref | 9 +- .../r1/show_mpls_ldp_discovery.ref-1 | 7 ++ .../r1/show_mpls_ldp_interface.ref-1 | 2 + .../ldp-topo1/r1/show_mpls_ldp_neighbor.ref | 10 +- .../ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 | 8 ++ .../ldp-topo1/r1/show_mpls_table.ref-1 | 8 ++ .../topotests/ldp-topo1/r2/how_mpls_table.ref | 7 -- .../ldp-topo1/r2/ip_mpls_route.ref-1 | 5 + .../ldp-topo1/r2/show_ipv4_route.ref-1 | 7 ++ .../ldp-topo1/r2/show_mpls_ldp_binding.ref | 78 ++++--------- .../ldp-topo1/r2/show_mpls_ldp_binding.ref-1 | 56 +++++++++ .../ldp-topo1/r2/show_mpls_ldp_discovery.ref | 16 +-- .../r2/show_mpls_ldp_discovery.ref-1 | 12 ++ .../r2/show_mpls_ldp_interface.ref-1 | 3 + .../ldp-topo1/r2/show_mpls_ldp_neighbor.ref | 30 +---- .../ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 | 26 +++++ .../ldp-topo1/r2/show_mpls_table.ref-1 | 7 ++ .../ldp-topo1/r3/ip_mpls_route.ref-1 | 10 ++ .../ldp-topo1/r3/show_ipv4_route.ref-1 | 7 ++ .../ldp-topo1/r3/show_mpls_ldp_binding.ref | 64 +++-------- .../ldp-topo1/r3/show_mpls_ldp_binding.ref-1 | 49 ++++++++ .../ldp-topo1/r3/show_mpls_ldp_discovery.ref | 12 +- .../r3/show_mpls_ldp_discovery.ref-1 | 9 ++ .../r3/show_mpls_ldp_interface.ref-1 | 2 + .../ldp-topo1/r3/show_mpls_ldp_neighbor.ref | 20 +--- .../ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 | 17 +++ .../ldp-topo1/r3/show_mpls_table.ref-1 | 10 ++ .../ldp-topo1/r4/ip_mpls_route.ref-1 | 7 ++ .../ldp-topo1/r4/show_ipv4_route.ref-1 | 7 ++ .../ldp-topo1/r4/show_mpls_ldp_binding.ref | 64 +++-------- .../ldp-topo1/r4/show_mpls_ldp_binding.ref-1 | 49 ++++++++ .../ldp-topo1/r4/show_mpls_ldp_discovery.ref | 12 +- .../r4/show_mpls_ldp_discovery.ref-1 | 9 ++ .../r4/show_mpls_ldp_interface.ref-1 | 2 + .../ldp-topo1/r4/show_mpls_ldp_neighbor.ref | 20 +--- .../ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 | 17 +++ .../ldp-topo1/r4/show_mpls_table.ref-1 | 9 ++ tests/topotests/ldp-topo1/test_ldp_topo1.py | 107 +++++++++++++++--- 42 files changed, 573 insertions(+), 325 deletions(-) create mode 100644 tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 create mode 100644 tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 create mode 100644 tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 delete mode 100644 tests/topotests/ldp-topo1/r2/how_mpls_table.ref create mode 100644 tests/topotests/ldp-topo1/r2/ip_mpls_route.ref-1 create mode 100644 tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 create mode 100644 tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 create mode 100644 tests/topotests/ldp-topo1/r3/ip_mpls_route.ref-1 create mode 100644 tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 create mode 100644 tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 create mode 100644 tests/topotests/ldp-topo1/r4/ip_mpls_route.ref-1 create mode 100644 tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 create mode 100644 tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 diff --git a/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 new file mode 100644 index 0000000000..053b08c338 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/ip_mpls_route.ref-1 @@ -0,0 +1,5 @@ +xx as to xx via inet 10.0.1.2 dev r1-eth0 proto zebra +xx as to xx via inet 10.0.1.2 dev r1-eth0 proto zebra +xx via inet 10.0.1.2 dev r1-eth0 proto zebra +xx via inet 10.0.1.2 dev r1-eth0 proto zebra +xx via inet 10.0.1.2 dev r1-eth0 proto zebra diff --git a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 new file mode 100644 index 0000000000..e72a20bac0 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 @@ -0,0 +1,7 @@ +O 1.1.1.1/32 [110/0] is directly connected, lo +O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0 +O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0 label xxx +O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0 label xxx +O 10.0.1.0/24 [110/10] is directly connected, r1-eth0 +O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0 +O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref index ff72a1c0b7..32aa60c30d 100644 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref @@ -1,42 +1,8 @@ -1.1.1.1/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx -10.0.1.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -10.0.2.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null -10.0.3.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null +AF Destination Nexthop Local Label Remote Label In Use +ipv4 1.1.1.1/32 2.2.2.2 imp-null xxx no +ipv4 2.2.2.2/32 2.2.2.2 xxx imp-null yes +ipv4 3.3.3.3/32 2.2.2.2 xxx xxx yes +ipv4 4.4.4.4/32 2.2.2.2 xxx xxx yes +ipv4 10.0.1.0/24 2.2.2.2 imp-null imp-null no +ipv4 10.0.2.0/24 2.2.2.2 xxx imp-null yes +ipv4 10.0.3.0/24 2.2.2.2 xxx imp-null yes diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 new file mode 100644 index 0000000000..ff72a1c0b7 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_binding.ref-1 @@ -0,0 +1,42 @@ +1.1.1.1/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx +2.2.2.2/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null +3.3.3.3/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx +4.4.4.4/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx +10.0.1.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null +10.0.2.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null +10.0.3.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref index 38522e162e..373755ab87 100644 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref @@ -1,7 +1,2 @@ -Local LDP Identifier: 1.1.1.1:0 -Discovery Sources: - Interfaces: - r1-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - Targeted Hellos: +AF ID Type Source Holdtime +ipv4 2.2.2.2 Link r1-eth0 15 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 new file mode 100644 index 0000000000..38522e162e --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_discovery.ref-1 @@ -0,0 +1,7 @@ +Local LDP Identifier: 1.1.1.1:0 +Discovery Sources: + Interfaces: + r1-eth0: xmit/recv + LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 + Hold time: 15 sec + Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 new file mode 100644 index 0000000000..0fb15d2da7 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_interface.ref-1 @@ -0,0 +1,2 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r1-eth0 ACTIVE xx:xx:xx 5/15 1 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref index 3df98bfae5..29e264ff3c 100644 --- a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref @@ -1,8 +1,2 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 1.1.1.1:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r1-eth0 +AF ID State Remote Address Uptime +ipv4 2.2.2.2 OPERATIONAL 2.2.2.2 xx:xx:xx diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 new file mode 100644 index 0000000000..3df98bfae5 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_ldp_neighbor.ref-1 @@ -0,0 +1,8 @@ +Peer LDP Identifier: 2.2.2.2:0 + TCP connection: 1.1.1.1:xxx - 2.2.2.2:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 new file mode 100644 index 0000000000..912a082019 --- /dev/null +++ b/tests/topotests/ldp-topo1/r1/show_mpls_table.ref-1 @@ -0,0 +1,8 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + XX LDP 10.0.1.2 3 + XX LDP 10.0.1.2 3 + XX LDP 10.0.1.2 3 + XX LDP 10.0.1.2 XX + XX LDP 10.0.1.2 XX diff --git a/tests/topotests/ldp-topo1/r2/how_mpls_table.ref b/tests/topotests/ldp-topo1/r2/how_mpls_table.ref deleted file mode 100644 index 67f9162bcd..0000000000 --- a/tests/topotests/ldp-topo1/r2/how_mpls_table.ref +++ /dev/null @@ -1,7 +0,0 @@ - Inbound Outbound - Label Type Nexthop Label --------- ------- --------------- -------- - 16 LDP 10.0.2.3 3 - 16 LDP 10.0.3.3 3 - 17 LDP 10.0.1.1 3 - 18 LDP 10.0.2.4 3 diff --git a/tests/topotests/ldp-topo1/r2/ip_mpls_route.ref-1 b/tests/topotests/ldp-topo1/r2/ip_mpls_route.ref-1 new file mode 100644 index 0000000000..007ef6f0a5 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/ip_mpls_route.ref-1 @@ -0,0 +1,5 @@ +xx proto zebra + nexthopvia inet 10.0.2.3 dev r2-eth1 weight 1 + nexthopvia inet 10.0.3.3 dev r2-eth2 weight 1 +xx via inet 10.0.1.1 dev r2-eth0 proto zebra +xx via inet 10.0.2.4 dev r2-eth1 proto zebra diff --git a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 new file mode 100644 index 0000000000..eaec2f16b9 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref-1 @@ -0,0 +1,7 @@ +O>* 1.1.1.1/32 [110/10] via 10.0.1.1, r2-eth0 +O 2.2.2.2/32 [110/0] is directly connected, lo +O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r2-eth1 +O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r2-eth1 +O 10.0.1.0/24 [110/10] is directly connected, r2-eth0 +O 10.0.2.0/24 [110/10] is directly connected, r2-eth1 +O 10.0.3.0/24 [110/10] is directly connected, r2-eth2 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref index 54ee39080a..d7df72e854 100644 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref @@ -1,56 +1,22 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 imp-null - 3.3.3.3 xxx - 4.4.4.4 xxx -2.2.2.2/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 xxx - 4.4.4.4 xxx -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 xxx - 4.4.4.4 imp-null -10.0.1.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 imp-null - 3.3.3.3 xxx - 4.4.4.4 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 imp-null -10.0.3.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 1.1.1.1 xxx - 3.3.3.3 imp-null - 4.4.4.4 xxx +AF Destination Nexthop Local Label Remote Label In Use +ipv4 1.1.1.1/32 1.1.1.1 xxx imp-null yes +ipv4 1.1.1.1/32 3.3.3.3 xxx xxx no +ipv4 1.1.1.1/32 4.4.4.4 xxx xxx no +ipv4 2.2.2.2/32 1.1.1.1 imp-null xxx no +ipv4 2.2.2.2/32 3.3.3.3 imp-null xxx no +ipv4 2.2.2.2/32 4.4.4.4 imp-null xxx no +ipv4 3.3.3.3/32 1.1.1.1 xxx xxx no +ipv4 3.3.3.3/32 3.3.3.3 xxx imp-null yes +ipv4 3.3.3.3/32 4.4.4.4 xxx xxx no +ipv4 4.4.4.4/32 1.1.1.1 xxx xxx no +ipv4 4.4.4.4/32 3.3.3.3 xxx xxx no +ipv4 4.4.4.4/32 4.4.4.4 xxx imp-null yes +ipv4 10.0.1.0/24 1.1.1.1 imp-null imp-null no +ipv4 10.0.1.0/24 3.3.3.3 imp-null xxx no +ipv4 10.0.1.0/24 4.4.4.4 imp-null xxx no +ipv4 10.0.2.0/24 1.1.1.1 imp-null xxx no +ipv4 10.0.2.0/24 3.3.3.3 imp-null imp-null no +ipv4 10.0.2.0/24 4.4.4.4 imp-null imp-null no +ipv4 10.0.3.0/24 1.1.1.1 imp-null xxx no +ipv4 10.0.3.0/24 3.3.3.3 imp-null imp-null no +ipv4 10.0.3.0/24 4.4.4.4 imp-null xxx no diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 new file mode 100644 index 0000000000..54ee39080a --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_binding.ref-1 @@ -0,0 +1,56 @@ +1.1.1.1/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 imp-null + 3.3.3.3 xxx + 4.4.4.4 xxx +2.2.2.2/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 xxx + 4.4.4.4 xxx +3.3.3.3/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 imp-null + 4.4.4.4 xxx +4.4.4.4/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 xxx + 4.4.4.4 imp-null +10.0.1.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 imp-null + 3.3.3.3 xxx + 4.4.4.4 xxx +10.0.2.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 imp-null + 4.4.4.4 imp-null +10.0.3.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 xxx + 3.3.3.3 imp-null + 4.4.4.4 xxx diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref index b1bebd7c46..6405b5e388 100644 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref @@ -1,12 +1,4 @@ -Local LDP Identifier: 2.2.2.2:0 -Discovery Sources: - Interfaces: - r2-eth0: xmit/recv - LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1 - Hold time: 15 sec - r2-eth1: xmit/recv - LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 - Hold time: 15 sec - LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 - Hold time: 15 sec - Targeted Hellos: +AF ID Type Source Holdtime +ipv4 1.1.1.1 Link r2-eth0 15 +ipv4 3.3.3.3 Link r2-eth1 15 +ipv4 4.4.4.4 Link r2-eth1 15 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 new file mode 100644 index 0000000000..b1bebd7c46 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_discovery.ref-1 @@ -0,0 +1,12 @@ +Local LDP Identifier: 2.2.2.2:0 +Discovery Sources: + Interfaces: + r2-eth0: xmit/recv + LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1 + Hold time: 15 sec + r2-eth1: xmit/recv + LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 + Hold time: 15 sec + LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 + Hold time: 15 sec + Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 new file mode 100644 index 0000000000..f9fc98408c --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_interface.ref-1 @@ -0,0 +1,3 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r2-eth0 ACTIVE xx:xx:xx 5/15 1 +ipv4 r2-eth1 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref index a70e2f48c6..1172cbfc2b 100644 --- a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref @@ -1,26 +1,4 @@ -Peer LDP Identifier: 1.1.1.1:0 - TCP connection: 2.2.2.2:xxx - 1.1.1.1:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth0 - -Peer LDP Identifier: 3.3.3.3:0 - TCP connection: 2.2.2.2:xxx - 3.3.3.3:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth1 - -Peer LDP Identifier: 4.4.4.4:0 - TCP connection: 2.2.2.2:xxx - 4.4.4.4:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r2-eth1 +AF ID State Remote Address Uptime +ipv4 1.1.1.1 OPERATIONAL 1.1.1.1 xx:xx:xx +ipv4 3.3.3.3 OPERATIONAL 3.3.3.3 xx:xx:xx +ipv4 4.4.4.4 OPERATIONAL 4.4.4.4 xx:xx:xx diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 new file mode 100644 index 0000000000..a70e2f48c6 --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_ldp_neighbor.ref-1 @@ -0,0 +1,26 @@ +Peer LDP Identifier: 1.1.1.1:0 + TCP connection: 2.2.2.2:xxx - 1.1.1.1:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r2-eth0 + +Peer LDP Identifier: 3.3.3.3:0 + TCP connection: 2.2.2.2:xxx - 3.3.3.3:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r2-eth1 + +Peer LDP Identifier: 4.4.4.4:0 + TCP connection: 2.2.2.2:xxx - 4.4.4.4:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r2-eth1 diff --git a/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 new file mode 100644 index 0000000000..ba244e76ec --- /dev/null +++ b/tests/topotests/ldp-topo1/r2/show_mpls_table.ref-1 @@ -0,0 +1,7 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + XX LDP 10.0.1.1 3 + XX LDP 10.0.2.3 3 + XX LDP 10.0.2.4 3 + XX LDP 10.0.3.3 3 diff --git a/tests/topotests/ldp-topo1/r3/ip_mpls_route.ref-1 b/tests/topotests/ldp-topo1/r3/ip_mpls_route.ref-1 new file mode 100644 index 0000000000..680fcf26fd --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/ip_mpls_route.ref-1 @@ -0,0 +1,10 @@ +xx proto zebra + nexthopvia inet 10.0.2.2 dev r3-eth0 weight 1 + nexthopvia inet 10.0.3.2 dev r3-eth1 weight 1 +xx proto zebra + nexthopvia inet 10.0.2.2 dev r3-eth0 weight 1 + nexthopvia inet 10.0.3.2 dev r3-eth1 weight 1 +xx proto zebra + nexthopvia inet 10.0.2.2 dev r3-eth0 weight 1 + nexthopvia inet 10.0.3.2 dev r3-eth1 weight 1 +xx via inet 10.0.2.4 dev r3-eth0 proto zebra diff --git a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 new file mode 100644 index 0000000000..f6e6199310 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 @@ -0,0 +1,7 @@ +O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0 label xxx +O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0 +O 3.3.3.3/32 [110/0] is directly connected, lo +O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0 +O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r3-eth0 +O 10.0.2.0/24 [110/10] is directly connected, r3-eth0 +O 10.0.3.0/24 [110/10] is directly connected, r3-eth1 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref index e04d2b7e4a..058a245f59 100644 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref @@ -1,49 +1,15 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx -3.3.3.3/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 xxx -4.4.4.4/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 4.4.4.4 imp-null -10.0.1.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 imp-null -10.0.3.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 4.4.4.4 xxx +AF Destination Nexthop Local Label Remote Label In Use +ipv4 1.1.1.1/32 2.2.2.2 xxx xxx yes +ipv4 1.1.1.1/32 4.4.4.4 xxx xxx no +ipv4 2.2.2.2/32 2.2.2.2 xxx imp-null yes +ipv4 2.2.2.2/32 4.4.4.4 xxx xxx no +ipv4 3.3.3.3/32 2.2.2.2 imp-null xxx no +ipv4 3.3.3.3/32 4.4.4.4 imp-null xxx no +ipv4 4.4.4.4/32 2.2.2.2 xxx xxx no +ipv4 4.4.4.4/32 4.4.4.4 xxx imp-null yes +ipv4 10.0.1.0/24 2.2.2.2 xxx imp-null yes +ipv4 10.0.1.0/24 4.4.4.4 xxx xxx no +ipv4 10.0.2.0/24 2.2.2.2 imp-null imp-null no +ipv4 10.0.2.0/24 4.4.4.4 imp-null imp-null no +ipv4 10.0.3.0/24 2.2.2.2 imp-null imp-null no +ipv4 10.0.3.0/24 4.4.4.4 imp-null xxx no diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 new file mode 100644 index 0000000000..e04d2b7e4a --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_binding.ref-1 @@ -0,0 +1,49 @@ +1.1.1.1/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 4.4.4.4 xxx +2.2.2.2/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 4.4.4.4 xxx +3.3.3.3/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 4.4.4.4 xxx +4.4.4.4/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 4.4.4.4 imp-null +10.0.1.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 4.4.4.4 xxx +10.0.2.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 4.4.4.4 imp-null +10.0.3.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 4.4.4.4 xxx diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref index 5e299fff9c..e3dbf06c2e 100644 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref @@ -1,9 +1,3 @@ -Local LDP Identifier: 3.3.3.3:0 -Discovery Sources: - Interfaces: - r3-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 - Hold time: 15 sec - Targeted Hellos: +AF ID Type Source Holdtime +ipv4 2.2.2.2 Link r3-eth0 15 +ipv4 4.4.4.4 Link r3-eth0 15 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 new file mode 100644 index 0000000000..5e299fff9c --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_discovery.ref-1 @@ -0,0 +1,9 @@ +Local LDP Identifier: 3.3.3.3:0 +Discovery Sources: + Interfaces: + r3-eth0: xmit/recv + LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 + Hold time: 15 sec + LDP Id: 4.4.4.4:0, Transport address: 4.4.4.4 + Hold time: 15 sec + Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 new file mode 100644 index 0000000000..243811e3a9 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_interface.ref-1 @@ -0,0 +1,2 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r3-eth0 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref index ee1983ac29..769f78277b 100644 --- a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref @@ -1,17 +1,3 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 3.3.3.3:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r3-eth0 - -Peer LDP Identifier: 4.4.4.4:0 - TCP connection: 3.3.3.3:xxx - 4.4.4.4:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r3-eth0 +AF ID State Remote Address Uptime +ipv4 2.2.2.2 OPERATIONAL 2.2.2.2 xx:xx:xx +ipv4 4.4.4.4 OPERATIONAL 4.4.4.4 xx:xx:xx diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 new file mode 100644 index 0000000000..ee1983ac29 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_ldp_neighbor.ref-1 @@ -0,0 +1,17 @@ +Peer LDP Identifier: 2.2.2.2:0 + TCP connection: 3.3.3.3:xxx - 2.2.2.2:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r3-eth0 + +Peer LDP Identifier: 4.4.4.4:0 + TCP connection: 3.3.3.3:xxx - 4.4.4.4:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r3-eth0 diff --git a/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 new file mode 100644 index 0000000000..9198969bd5 --- /dev/null +++ b/tests/topotests/ldp-topo1/r3/show_mpls_table.ref-1 @@ -0,0 +1,10 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 XX + XX LDP 10.0.2.4 3 + XX LDP 10.0.3.2 3 + XX LDP 10.0.3.2 3 + XX LDP 10.0.3.2 XX diff --git a/tests/topotests/ldp-topo1/r4/ip_mpls_route.ref-1 b/tests/topotests/ldp-topo1/r4/ip_mpls_route.ref-1 new file mode 100644 index 0000000000..7fdb057345 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/ip_mpls_route.ref-1 @@ -0,0 +1,7 @@ +xx proto zebra + nexthopvia inet 10.0.2.2 dev r4-eth0 weight 1 + nexthopvia inet 10.0.2.3 dev r4-eth0 weight 1 +xx as to xx via inet 10.0.2.2 dev r4-eth0 proto zebra +xx via inet 10.0.2.2 dev r4-eth0 proto zebra +xx via inet 10.0.2.2 dev r4-eth0 proto zebra +xx via inet 10.0.2.3 dev r4-eth0 proto zebra diff --git a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 new file mode 100644 index 0000000000..bcef173a64 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 @@ -0,0 +1,7 @@ +O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0 label xxx +O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0 +O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0 +O 4.4.4.4/32 [110/0] is directly connected, lo +O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r4-eth0 +O 10.0.2.0/24 [110/10] is directly connected, r4-eth0 +O>* 10.0.3.0/24 [110/20] via 10.0.2.2, r4-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref index 3d55805d7c..1e9dfa3d16 100644 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref @@ -1,49 +1,15 @@ -1.1.1.1/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 xxx -2.2.2.2/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 xxx -3.3.3.3/32 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 imp-null -4.4.4.4/32 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 xxx - 3.3.3.3 xxx -10.0.1.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 xxx -10.0.2.0/24 - Local binding: label: imp-null - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 imp-null -10.0.3.0/24 - Local binding: label: xxx - Remote bindings: - Peer Label - ----------------- --------- - 2.2.2.2 imp-null - 3.3.3.3 imp-null +AF Destination Nexthop Local Label Remote Label In Use +ipv4 1.1.1.1/32 2.2.2.2 xxx xxx yes +ipv4 1.1.1.1/32 3.3.3.3 xxx xxx no +ipv4 2.2.2.2/32 2.2.2.2 xxx imp-null yes +ipv4 2.2.2.2/32 3.3.3.3 xxx xxx no +ipv4 3.3.3.3/32 2.2.2.2 xxx xxx no +ipv4 3.3.3.3/32 3.3.3.3 xxx imp-null yes +ipv4 4.4.4.4/32 2.2.2.2 imp-null xxx no +ipv4 4.4.4.4/32 3.3.3.3 imp-null xxx no +ipv4 10.0.1.0/24 2.2.2.2 xxx imp-null yes +ipv4 10.0.1.0/24 3.3.3.3 xxx xxx no +ipv4 10.0.2.0/24 2.2.2.2 imp-null imp-null no +ipv4 10.0.2.0/24 3.3.3.3 imp-null imp-null no +ipv4 10.0.3.0/24 2.2.2.2 xxx imp-null yes +ipv4 10.0.3.0/24 3.3.3.3 xxx imp-null yes diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 new file mode 100644 index 0000000000..3d55805d7c --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_binding.ref-1 @@ -0,0 +1,49 @@ +1.1.1.1/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 3.3.3.3 xxx +2.2.2.2/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 xxx +3.3.3.3/32 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 3.3.3.3 imp-null +4.4.4.4/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 xxx + 3.3.3.3 xxx +10.0.1.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 xxx +10.0.2.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 imp-null +10.0.3.0/24 + Local binding: label: xxx + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 imp-null diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref index 3ebddd606a..a7026570db 100644 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref @@ -1,9 +1,3 @@ -Local LDP Identifier: 4.4.4.4:0 -Discovery Sources: - Interfaces: - r4-eth0: xmit/recv - LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 - Hold time: 15 sec - LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 - Hold time: 15 sec - Targeted Hellos: +AF ID Type Source Holdtime +ipv4 2.2.2.2 Link r4-eth0 15 +ipv4 3.3.3.3 Link r4-eth0 15 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 new file mode 100644 index 0000000000..3ebddd606a --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_discovery.ref-1 @@ -0,0 +1,9 @@ +Local LDP Identifier: 4.4.4.4:0 +Discovery Sources: + Interfaces: + r4-eth0: xmit/recv + LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 + Hold time: 15 sec + LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 + Hold time: 15 sec + Targeted Hellos: diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 new file mode 100644 index 0000000000..dd57656f15 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_interface.ref-1 @@ -0,0 +1,2 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r4-eth0 ACTIVE xx:xx:xx 5/15 2 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref index fb0e7d7dfa..7c60522f9b 100644 --- a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref @@ -1,17 +1,3 @@ -Peer LDP Identifier: 2.2.2.2:0 - TCP connection: 4.4.4.4:xxx - 2.2.2.2:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r4-eth0 - -Peer LDP Identifier: 3.3.3.3:0 - TCP connection: 4.4.4.4:xxx - 3.3.3.3:xxx - Session Holdtime: 180 sec - State: OPERATIONAL; Downstream-Unsolicited - Up time: xx:xx:xx - LDP Discovery Sources: - IPv4: - Interface: r4-eth0 +AF ID State Remote Address Uptime +ipv4 2.2.2.2 OPERATIONAL 2.2.2.2 xx:xx:xx +ipv4 3.3.3.3 OPERATIONAL 3.3.3.3 xx:xx:xx diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 new file mode 100644 index 0000000000..fb0e7d7dfa --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_ldp_neighbor.ref-1 @@ -0,0 +1,17 @@ +Peer LDP Identifier: 2.2.2.2:0 + TCP connection: 4.4.4.4:xxx - 2.2.2.2:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r4-eth0 + +Peer LDP Identifier: 3.3.3.3:0 + TCP connection: 4.4.4.4:xxx - 3.3.3.3:xxx + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: xx:xx:xx + LDP Discovery Sources: + IPv4: + Interface: r4-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 new file mode 100644 index 0000000000..b8cf5a2702 --- /dev/null +++ b/tests/topotests/ldp-topo1/r4/show_mpls_table.ref-1 @@ -0,0 +1,9 @@ + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 3 + XX LDP 10.0.2.2 XX + XX LDP 10.0.2.3 3 + XX LDP 10.0.2.3 3 diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 2db7cbe5f4..956e62addf 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -78,6 +78,12 @@ from lib import topotest fatal_error = "" +# Expected version of CLI Output - Appendix to filename +# empty string = current, latest output (default) +# "-1" ... "-NNN" previous versions (incrementing with each version) +cli_version = "" + + ##################################################### ## ## Network Topology Definition @@ -159,6 +165,7 @@ def teardown_module(module): def test_router_running(): global fatal_error global net + global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -173,12 +180,35 @@ def test_router_running(): fatal_error = net['r%s' % i].checkRouterRunning() assert fatal_error == "", fatal_error + # Detect CLI Version + # At this time, there are only 2 possible outputs, so simple check + output = net['r1'].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip() + + # Check if old or new format of CLI Output. Default is to current format + # + # Old (v1) output looks like this: + # Local LDP Identifier: 1.1.1.1:0 + # Discovery Sources: + # Interfaces: + # r1-eth0: xmit/recv + # LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 + # Hold time: 15 sec + # Targeted Hellos: + # + # Current (v0) output looks like this: + # AF ID Type Source Holdtime + # ipv4 2.2.2.2 Link r1-eth0 15 + pattern = re.compile("^Local LDP Identifier.*") + if pattern.match(output): + cli_version = "-1" + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) def test_mpls_interfaces(): global fatal_error global net + global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -191,7 +221,7 @@ def test_mpls_interfaces(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_interface.ref' % (thisDir, i) + refTableFile = '%s/r%s/show_mpls_ldp_interface.ref%s' % (thisDir, i, cli_version) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -229,6 +259,7 @@ def test_mpls_interfaces(): def test_mpls_ldp_neighbor_establish(): global fatal_error global net + global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -243,7 +274,23 @@ def test_mpls_ldp_neighbor_establish(): sys.stdout.flush() # Look for any node not yet converged for i in range(1, 5): - established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null') + established = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip() + if cli_version != "-1": + # On current version, we need to make sure they all turn to OPERATIONAL on all lines + # + lines = ('\n'.join(established.splitlines()) + '\n').splitlines(1) + # Check all lines to be either table header (starting with ^AF or show OPERATIONAL) + header = r'^AF.*' + operational = r'^ip.*OPERATIONAL.*' + found_operational = 0 + for j in range(1, len(lines)): + if (not re.search(header, lines[j])) and (not re.search(operational, lines[j])): + established = "" # Empty string shows NOT established + if re.search(operational, lines[j]): + found_operational += 1 + if found_operational < 1: + # Need at least one operational neighbor + established = "" # Empty string shows NOT established if not established: print('Waiting for r%s' %i) sys.stdout.flush() @@ -270,6 +317,7 @@ def test_mpls_ldp_neighbor_establish(): def test_mpls_ldp_discovery(): global fatal_error global net + global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -282,8 +330,11 @@ def test_mpls_ldp_discovery(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref' % (thisDir, i) + refTableFile = '%s/r%s/show_mpls_ldp_discovery.ref%s' % (thisDir, i, cli_version) if os.path.isfile(refTableFile): + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp discovery" 2> /dev/null').rstrip() + # Read expected result from file expected = open(refTableFile).read().rstrip() # Fix newlines (make them all the same) @@ -316,6 +367,7 @@ def test_mpls_ldp_discovery(): def test_mpls_ldp_neighbor(): global fatal_error global net + global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -328,7 +380,7 @@ def test_mpls_ldp_neighbor(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref' % (thisDir, i) + refTableFile = '%s/r%s/show_mpls_ldp_neighbor.ref%s' % (thisDir, i, cli_version) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -337,11 +389,19 @@ def test_mpls_ldp_neighbor(): # Actual output from router actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp neighbor" 2> /dev/null').rstrip() - # Mask out Timer in Uptime - actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual) - # Mask out Port numbers in TCP connection - actual = re.sub(r"TCP connection: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+ - ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+", - r"TCP connection: \1:xxx - \2:xxx", actual) + + # Mask out changing parts in output + if cli_version == "-1": + # Mask out Timer in Uptime + actual = re.sub(r"Up time: [0-9][0-9]:[0-9][0-9]:[0-9][0-9]", "Up time: xx:xx:xx", actual) + # Mask out Port numbers in TCP connection + actual = re.sub(r"TCP connection: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+ - ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]):[0-9]+", + r"TCP connection: \1:xxx - \2:xxx", actual) + else: + # Current Version + # + # Mask out Timer in Uptime + actual = re.sub(r"(ipv4 [0-9\.]+ +OPERATIONAL [0-9\.]+ +)[0-9][0-9]:[0-9][0-9]:[0-9][0-9]", r"\1xx:xx:xx", actual) # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -367,6 +427,7 @@ def test_mpls_ldp_neighbor(): def test_mpls_ldp_binding(): global fatal_error global net + global cli_version # Skip this test for now until proper sorting of the output # is implemented @@ -383,7 +444,7 @@ def test_mpls_ldp_binding(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_ldp_binding.ref' % (thisDir, i) + refTableFile = '%s/r%s/show_mpls_ldp_binding.ref%s' % (thisDir, i, cli_version) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -392,10 +453,19 @@ def test_mpls_ldp_binding(): # Actual output from router actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp binding" 2> /dev/null').rstrip() - # Mask out label - actual = re.sub(r"label: [0-9]+", "label: xxx", actual) - actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual) - + + # Mask out changing parts in output + if cli_version == "-1": + # Mask out label + actual = re.sub(r"label: [0-9]+", "label: xxx", actual) + actual = re.sub(r"(\s+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ ]+)[0-9]+", r"\1xxx", actual) + else: + # Current Version + # + # Mask out label + actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) + actual = re.sub(r"(ipv4 [0-9\./]+ +[0-9\.]+ +[a-z\-]+ +)[0-9][0-9] (.*)", r"\1xxx\2", actual) + # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -433,6 +503,7 @@ def test_mpls_ldp_binding(): def test_zebra_ipv4_routingTable(): global fatal_error global net + global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -445,7 +516,7 @@ def test_zebra_ipv4_routingTable(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_ipv4_route.ref' % (thisDir, i) + refTableFile = '%s/r%s/show_ipv4_route.ref%s' % (thisDir, i, cli_version) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -483,6 +554,7 @@ def test_zebra_ipv4_routingTable(): def test_mpls_table(): global fatal_error global net + global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -495,7 +567,7 @@ def test_mpls_table(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/show_mpls_table.ref' % (thisDir, i) + refTableFile = '%s/r%s/show_mpls_table.ref%s' % (thisDir, i, cli_version) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -547,6 +619,7 @@ def test_mpls_table(): def test_linux_mpls_routes(): global fatal_error global net + global cli_version # Skip if previous fatal error condition is raised if (fatal_error != ""): @@ -559,7 +632,7 @@ def test_linux_mpls_routes(): print("******************************************\n") failures = 0 for i in range(1, 5): - refTableFile = '%s/r%s/ip_mpls_route.ref' % (thisDir, i) + refTableFile = '%s/r%s/ip_mpls_route.ref%s' % (thisDir, i, cli_version) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() From 5b7a4ad33a8d7adab667d069fb744dc038ca0ef4 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 6 Apr 2017 00:34:43 -0700 Subject: [PATCH 039/384] bgp_multiview_topo1: Fix case of tests hanging if convergence is not successful. - Part of a command was missing which caused a hang in cases when BGP didn't converge Signed-off-by: Martin Winter --- tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 3e548d6ff5..6fef5d2284 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -237,7 +237,7 @@ def test_bgp_converge(): break else: # Bail out with error if a router fails to converge - bgpStatus = net['r%s' % i].cmd('show ip bgp view %s summary"') + bgpStatus = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s summary"' % view) assert False, "BGP did not converge:\n%s" % bgpStatus # Wait for an extra 30s to announce all routes From a93477ec425fb1949c1335fc454d15a45eb61dc8 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 6 Apr 2017 17:38:48 -0700 Subject: [PATCH 040/384] topotest library: Fix creation of /etc/XXX/vtysh.conf - Needs to be created in local filesystem of each router Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 015705510a..bd797bfafc 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -143,8 +143,7 @@ class Router(Node): # print "Daemons after:", self.daemons def startRouter(self): # Disable integrated-vtysh-config - with open('/etc/%s/vtysh.conf' % self.routertype, "w") as vtyshfile: - vtyshfile.write('no service integrated-vtysh-config') + self.cmd('echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf' % self.routertype) self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) # Try to find relevant old logfiles in /tmp and delete them map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) From 9f3e0f6493cb3718e3c6b43ce11b08e8182f2fea Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 7 Apr 2017 16:40:47 -0700 Subject: [PATCH 041/384] ripng_topo1: Adding new test for RIPng Topology Signed-off-by: Martin Winter --- .../topotests/ripng-topo1/r1/ripng_status.ref | 16 + tests/topotests/ripng-topo1/r1/ripngd.conf | 12 + .../ripng-topo1/r1/show_ipv6_ripng.ref | 14 + .../ripng-topo1/r1/show_ipv6_route.ref | 3 + tests/topotests/ripng-topo1/r1/zebra.conf | 19 + .../topotests/ripng-topo1/r2/ripng_status.ref | 20 + tests/topotests/ripng-topo1/r2/ripngd.conf | 12 + .../ripng-topo1/r2/show_ipv6_ripng.ref | 14 + .../ripng-topo1/r2/show_ipv6_route.ref | 2 + tests/topotests/ripng-topo1/r2/zebra.conf | 21 + .../topotests/ripng-topo1/r3/ripng_status.ref | 16 + tests/topotests/ripng-topo1/r3/ripngd.conf | 14 + .../ripng-topo1/r3/show_ipv6_ripng.ref | 14 + .../ripng-topo1/r3/show_ipv6_route.ref | 1 + tests/topotests/ripng-topo1/r3/zebra.conf | 22 ++ .../ripng-topo1/test_ripng_topo1.dot | 59 +++ .../ripng-topo1/test_ripng_topo1.pdf | Bin 0 -> 18639 bytes .../topotests/ripng-topo1/test_ripng_topo1.py | 362 ++++++++++++++++++ 18 files changed, 621 insertions(+) create mode 100644 tests/topotests/ripng-topo1/r1/ripng_status.ref create mode 100644 tests/topotests/ripng-topo1/r1/ripngd.conf create mode 100644 tests/topotests/ripng-topo1/r1/show_ipv6_ripng.ref create mode 100644 tests/topotests/ripng-topo1/r1/show_ipv6_route.ref create mode 100644 tests/topotests/ripng-topo1/r1/zebra.conf create mode 100644 tests/topotests/ripng-topo1/r2/ripng_status.ref create mode 100644 tests/topotests/ripng-topo1/r2/ripngd.conf create mode 100644 tests/topotests/ripng-topo1/r2/show_ipv6_ripng.ref create mode 100644 tests/topotests/ripng-topo1/r2/show_ipv6_route.ref create mode 100644 tests/topotests/ripng-topo1/r2/zebra.conf create mode 100644 tests/topotests/ripng-topo1/r3/ripng_status.ref create mode 100644 tests/topotests/ripng-topo1/r3/ripngd.conf create mode 100644 tests/topotests/ripng-topo1/r3/show_ipv6_ripng.ref create mode 100644 tests/topotests/ripng-topo1/r3/show_ipv6_route.ref create mode 100644 tests/topotests/ripng-topo1/r3/zebra.conf create mode 100644 tests/topotests/ripng-topo1/test_ripng_topo1.dot create mode 100644 tests/topotests/ripng-topo1/test_ripng_topo1.pdf create mode 100755 tests/topotests/ripng-topo1/test_ripng_topo1.py diff --git a/tests/topotests/ripng-topo1/r1/ripng_status.ref b/tests/topotests/ripng-topo1/r1/ripng_status.ref new file mode 100644 index 0000000000..48816c1a9b --- /dev/null +++ b/tests/topotests/ripng-topo1/r1/ripng_status.ref @@ -0,0 +1,16 @@ +Routing Protocol is "RIPng" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: + Default version control: send version 1, receive version 1 + Interface Send Recv + r1-eth1 1 1 + Routing for Networks: + fc00:5::/64 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update + fe80::XXXX:XXXX:XXXX:XXXX + 0 0 120 XX:XX:XX diff --git a/tests/topotests/ripng-topo1/r1/ripngd.conf b/tests/topotests/ripng-topo1/r1/ripngd.conf new file mode 100644 index 0000000000..64a6f84e3b --- /dev/null +++ b/tests/topotests/ripng-topo1/r1/ripngd.conf @@ -0,0 +1,12 @@ +log file /tmp/r1-ripngd.log +! +debug ripng events +debug ripng packet +debug ripng zebra +! +router ripng + network fc00:5::/64 +! +line vty +! + diff --git a/tests/topotests/ripng-topo1/r1/show_ipv6_ripng.ref b/tests/topotests/ripng-topo1/r1/show_ipv6_ripng.ref new file mode 100644 index 0000000000..18d026a8fd --- /dev/null +++ b/tests/topotests/ripng-topo1/r1/show_ipv6_ripng.ref @@ -0,0 +1,14 @@ +Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Sub-codes: + (n) - normal, (s) - static, (d) - default, (r) - redistribute, + (i) - interface, (a/S) - aggregated/Suppressed + + Network Next Hop Via Metric Tag Time +C(i) fc00:5::/64 + :: self 1 0 +R(n) fc00:6::/62 + fe80::XXXX:XXXX:XXXX:XXXX r1-eth1 2 0 XX:XX +R(n) fc00:7::/64 + fe80::XXXX:XXXX:XXXX:XXXX r1-eth1 3 0 XX:XX +R(n) fc00:7:1111::/64 + fe80::XXXX:XXXX:XXXX:XXXX r1-eth1 3 0 XX:XX diff --git a/tests/topotests/ripng-topo1/r1/show_ipv6_route.ref b/tests/topotests/ripng-topo1/r1/show_ipv6_route.ref new file mode 100644 index 0000000000..7e5fc3f0f5 --- /dev/null +++ b/tests/topotests/ripng-topo1/r1/show_ipv6_route.ref @@ -0,0 +1,3 @@ +R>* fc00:6::/62 [120/2] via fe80::XXXX:XXXX:XXXX:XXXX, r1-eth1 +R>* fc00:7::/64 [120/3] via fe80::XXXX:XXXX:XXXX:XXXX, r1-eth1 +R>* fc00:7:1111::/64 [120/3] via fe80::XXXX:XXXX:XXXX:XXXX, r1-eth1 diff --git a/tests/topotests/ripng-topo1/r1/zebra.conf b/tests/topotests/ripng-topo1/r1/zebra.conf new file mode 100644 index 0000000000..f315e90ea0 --- /dev/null +++ b/tests/topotests/ripng-topo1/r1/zebra.conf @@ -0,0 +1,19 @@ +log file /tmp/r1-zebra.log +! +hostname r1 +! +interface r1-eth0 + ipv6 address fc00:0:0:1::1/64 +! +interface r1-eth1 + description to sw2 - RIPng interface + ipv6 address fc00:5::1/64 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/tests/topotests/ripng-topo1/r2/ripng_status.ref b/tests/topotests/ripng-topo1/r2/ripng_status.ref new file mode 100644 index 0000000000..fddcf63e5b --- /dev/null +++ b/tests/topotests/ripng-topo1/r2/ripng_status.ref @@ -0,0 +1,20 @@ +Routing Protocol is "RIPng" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: + Default version control: send version 1, receive version 1 + Interface Send Recv + r2-eth0 1 1 + r2-eth1 1 1 + Routing for Networks: + fc00:5::/64 + fc00:6::/62 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update + fe80::XXXX:XXXX:XXXX:XXXX + 0 0 120 XX:XX:XX + fe80::XXXX:XXXX:XXXX:XXXX + 0 0 120 XX:XX:XX diff --git a/tests/topotests/ripng-topo1/r2/ripngd.conf b/tests/topotests/ripng-topo1/r2/ripngd.conf new file mode 100644 index 0000000000..919a64fae8 --- /dev/null +++ b/tests/topotests/ripng-topo1/r2/ripngd.conf @@ -0,0 +1,12 @@ +log file /tmp/r2-ripngd.log +! +debug ripng events +debug ripng packet +debug ripng zebra +! +router ripng + network fc00:5::/64 + network fc00:6::/62 +! +line vty +! diff --git a/tests/topotests/ripng-topo1/r2/show_ipv6_ripng.ref b/tests/topotests/ripng-topo1/r2/show_ipv6_ripng.ref new file mode 100644 index 0000000000..765efd07a2 --- /dev/null +++ b/tests/topotests/ripng-topo1/r2/show_ipv6_ripng.ref @@ -0,0 +1,14 @@ +Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Sub-codes: + (n) - normal, (s) - static, (d) - default, (r) - redistribute, + (i) - interface, (a/S) - aggregated/Suppressed + + Network Next Hop Via Metric Tag Time +C(i) fc00:5::/64 + :: self 1 0 +C(i) fc00:6::/62 + :: self 1 0 +R(n) fc00:7::/64 + fe80::XXXX:XXXX:XXXX:XXXX r2-eth1 2 0 XX:XX +R(n) fc00:7:1111::/64 + fe80::XXXX:XXXX:XXXX:XXXX r2-eth1 2 0 XX:XX diff --git a/tests/topotests/ripng-topo1/r2/show_ipv6_route.ref b/tests/topotests/ripng-topo1/r2/show_ipv6_route.ref new file mode 100644 index 0000000000..688e77e7ed --- /dev/null +++ b/tests/topotests/ripng-topo1/r2/show_ipv6_route.ref @@ -0,0 +1,2 @@ +R>* fc00:7::/64 [120/2] via fe80::XXXX:XXXX:XXXX:XXXX, r2-eth1 +R>* fc00:7:1111::/64 [120/2] via fe80::XXXX:XXXX:XXXX:XXXX, r2-eth1 diff --git a/tests/topotests/ripng-topo1/r2/zebra.conf b/tests/topotests/ripng-topo1/r2/zebra.conf new file mode 100644 index 0000000000..cb3ff37fbc --- /dev/null +++ b/tests/topotests/ripng-topo1/r2/zebra.conf @@ -0,0 +1,21 @@ +log file /tmp/r2-zebra.log +! +hostname r2 +! +interface r2-eth0 + description to sw2 - RIPng interface + ipv6 address fc00:5::2/64 + no link-detect +! +interface r2-eth1 + description to sw3 - RIPng interface + ipv6 address fc00:6::2/62 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/tests/topotests/ripng-topo1/r3/ripng_status.ref b/tests/topotests/ripng-topo1/r3/ripng_status.ref new file mode 100644 index 0000000000..1a8dabbf5f --- /dev/null +++ b/tests/topotests/ripng-topo1/r3/ripng_status.ref @@ -0,0 +1,16 @@ +Routing Protocol is "RIPng" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: connected static + Default version control: send version 1, receive version 1 + Interface Send Recv + r3-eth1 1 1 + Routing for Networks: + fc00:6::/62 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update + fe80::XXXX:XXXX:XXXX:XXXX + 0 0 120 XX:XX:XX diff --git a/tests/topotests/ripng-topo1/r3/ripngd.conf b/tests/topotests/ripng-topo1/r3/ripngd.conf new file mode 100644 index 0000000000..ad49464fae --- /dev/null +++ b/tests/topotests/ripng-topo1/r3/ripngd.conf @@ -0,0 +1,14 @@ +log file /tmp/r3-ripngd.log +! +debug ripng events +debug ripng packet +debug ripng zebra +! +router ripng + network fc00:6::/62 + redistribute connected + redistribute static +! +line vty +! + diff --git a/tests/topotests/ripng-topo1/r3/show_ipv6_ripng.ref b/tests/topotests/ripng-topo1/r3/show_ipv6_ripng.ref new file mode 100644 index 0000000000..81e76b97a6 --- /dev/null +++ b/tests/topotests/ripng-topo1/r3/show_ipv6_ripng.ref @@ -0,0 +1,14 @@ +Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Sub-codes: + (n) - normal, (s) - static, (d) - default, (r) - redistribute, + (i) - interface, (a/S) - aggregated/Suppressed + + Network Next Hop Via Metric Tag Time +R(n) fc00:5::/64 + fe80::XXXX:XXXX:XXXX:XXXX r3-eth1 2 0 XX:XX +C(i) fc00:6::/62 + :: self 1 0 +C(r) fc00:7::/64 + :: self 1 0 +S(r) fc00:7:1111::/64 + :: self 1 0 diff --git a/tests/topotests/ripng-topo1/r3/show_ipv6_route.ref b/tests/topotests/ripng-topo1/r3/show_ipv6_route.ref new file mode 100644 index 0000000000..8e46e39921 --- /dev/null +++ b/tests/topotests/ripng-topo1/r3/show_ipv6_route.ref @@ -0,0 +1 @@ +R>* fc00:5::/64 [120/2] via fe80::XXXX:XXXX:XXXX:XXXX, r3-eth1 diff --git a/tests/topotests/ripng-topo1/r3/zebra.conf b/tests/topotests/ripng-topo1/r3/zebra.conf new file mode 100644 index 0000000000..cedb6ca48a --- /dev/null +++ b/tests/topotests/ripng-topo1/r3/zebra.conf @@ -0,0 +1,22 @@ +log file /tmp/r3-zebra.log +! +hostname r3 +! +interface r3-eth0 + description to sw2 - Stub interface + ipv6 address fc00:7::1/64 + no link-detect +! +interface r3-eth1 + description to sw3 - RIPng interface + ipv6 address fc00:6::2/62 + no link-detect +! +ipv6 route fc00:7:1111::/64 fc00:7::10 +! +ip forwarding +ipv6 forwarding +! +! +line vty +! diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.dot b/tests/topotests/ripng-topo1/test_ripng_topo1.dot new file mode 100644 index 0000000000..f5d32a02a1 --- /dev/null +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.dot @@ -0,0 +1,59 @@ +## GraphViz file for test_all_protocol_topo1 +## +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph test_ripng_topo1 { + + // title + labelloc="t"; + label="Test Topologoy RIPng Topo1"; + + ###################### + # Routers + ###################### + + # Main FRR Router with all protocols + R1 [shape=doubleoctagon, label="R1 FRR\nMain Router", fillcolor="#f08080", style=filled]; + + # RIPng Routers + R2 [shape=doubleoctagon, label="R2 FRR\nRIPng Router", fillcolor="#fcb314", style=filled]; + R3 [shape=doubleoctagon, label="R3 FRR\nRIPng Router", fillcolor="#fcb314", style=filled]; + + ###################### + # Network Lists + ###################### + + SW1_R1_stub [label="SW1\nfc00:0:0:1::/64", fillcolor="#d0e0d0", style=filled]; + + # RIPng Networks + SW2_R1_R2 [label="SW2\nRIPng\nfc00:5:0:0::/64", fillcolor="#d0e0d0", style=filled]; + SW3_R2_R3 [label="SW3\nRIPng\nfc00:6:0:0::/62", fillcolor="#d0e0d0", style=filled]; + SW4_R3 [label="SW4\nfc00::7/128", fillcolor="#d0e0d0", style=filled]; + Net_R3_remote [label="Static Net\nfc00:7:1111::/64"]; + + ###################### + # Network Connections + ###################### + R1 -- SW1_R1_stub [label = "eth0\n.1\n::1"]; + + # RIPng Network + R1 -- SW2_R1_R2 [label = "eth2\n::1"]; + SW2_R1_R2 -- R2 [label = "eth0\n::2"]; + R2 -- SW3_R2_R3 [label = "eth1\n::1"]; + SW3_R2_R3 -- R3 [label = "eth1\n::2"]; + R3 -- SW4_R3 [label = "eth0\n::1"]; + SW4_R3 -- Net_R3_remote [label = ":10"]; + +} diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.pdf b/tests/topotests/ripng-topo1/test_ripng_topo1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f998c4697d7d9e0a8b759e24466664047efbf2a0 GIT binary patch literal 18639 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 literal 0 HcmV?d00001 diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py new file mode 100755 index 0000000000..f40a241333 --- /dev/null +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -0,0 +1,362 @@ +#!/usr/bin/env python + +# +# test_ripng_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_ripng_topo1.py: Test of RIPng Topology + +""" + +import os +import re +import sys +import difflib +import pytest +import unicodedata +from time import sleep + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from functools import partial + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from lib import topotest + +fatal_error = "" + + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "RIPng Topology 1" + + def build(self, **_opts): + + # Setup Routers + router = {} + # + # Setup Main Router + router[1] = topotest.addRouter(self, 'r1') + # + # Setup RIPng Routers + for i in range(2, 4): + router[i] = topotest.addRouter(self, 'r%s' % i) + + # Setup Switches + switch = {} + # + # On main router + # First switch is for a dummy interface (for local network) + switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch) + self.addLink(switch[1], router[1], intfName2='r1-eth0') + # + # Switches for RIPng + # switch 2 switch is for connection to RIP router + switch[2] = self.addSwitch('sw2', cls=topotest.LegacySwitch) + self.addLink(switch[2], router[1], intfName2='r1-eth1') + self.addLink(switch[2], router[2], intfName2='r2-eth0') + # switch 3 is between RIP routers + switch[3] = self.addSwitch('sw3', cls=topotest.LegacySwitch) + self.addLink(switch[3], router[2], intfName2='r2-eth1') + self.addLink(switch[3], router[3], intfName2='r3-eth1') + # switch 4 is stub on remote RIP router + switch[4] = self.addSwitch('sw4', cls=topotest.LegacySwitch) + self.addLink(switch[4], router[3], intfName2='r3-eth0') + + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + global topo, net + + print("\n\n** %s: Setup Topology" % module.__name__) + print("******************************************\n") + + print("Cleanup old Mininet runs") + os.system('sudo mn -c > /dev/null 2>&1') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + topo = NetworkTopo() + + net = Mininet(controller=None, topo=topo) + net.start() + + # Starting Routers + # + for i in range(1, 4): + net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ripngd', '%s/r%s/ripngd.conf' % (thisDir, i)) + net['r%s' % i].startRouter() + + # For debugging after starting Quagga/FRR daemons, uncomment the next line + # CLI(net) + + +def teardown_module(module): + global net + + print("\n\n** %s: Shutdown Topology" % module.__name__) + print("******************************************\n") + + # End - Shutdown network + net.stop() + + +def test_router_running(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check if FRR/Quagga is running on each Router node") + print("******************************************\n") + sleep(5) + + # Starting Routers + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_converge_protocols(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Waiting for protocols convergence") + print("******************************************\n") + + # Not really implemented yet - just sleep 60 secs for now + sleep(60) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + #CLI(net) + + +def test_ripng_status(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing RIPng status") + print("******************************************\n") + failures = 0 + for i in range(1, 4): + refTableFile = '%s/r%s/ripng_status.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null').rstrip() + # Mask out Link-Local mac address portion. They are random... + actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual) + # Drop time in next due + actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual IPv6 RIPng status", + tofile="expected IPv6 RIPng status")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed IPv6 RIPng status check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_ripng_routes(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIPng Status + print("\n\n** Verifing RIPng routes") + print("******************************************\n") + failures = 0 + for i in range(1, 4): + refTableFile = '%s/r%s/show_ipv6_ripng.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ipv6 ripng" 2> /dev/null').rstrip() + # Drop Time + actual = re.sub(r" [0-9][0-9]:[0-5][0-9]", " XX:XX", actual) + # Mask out Link-Local mac address portion. They are random... + actual = re.sub(r" fe80::[0-9a-f: ]+", " fe80::XXXX:XXXX:XXXX:XXXX ", actual) + # Remove trailing spaces on all lines + actual = '\n'.join([line.rstrip() for line in actual.splitlines()]) + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual SHOW IPv6 RIPng", + tofile="expected SHOW IPv6 RIPng")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW IPv6 RIPng check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW IPv6 RIPng failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_zebra_ipv6_routingTable(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing Zebra IPv6 Routing Table") + print("******************************************\n") + failures = 0 + for i in range(1, 4): + refTableFile = '%s/r%s/show_ipv6_route.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ipv6 route" 2> /dev/null | grep "^R"').rstrip() + # Mask out Link-Local mac address portion. They are random... + actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual) + # Drop timers on end of line (older Quagga Versions) + actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual Zebra IPv6 routing table", + tofile="expected Zebra IPv6 routing table")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed Zebra IPv6 Routing Table Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "Zebra IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_shutdown_check_stderr(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + pytest.skip('Skipping test for Stderr output and memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifing unexpected STDERR output from daemons") + print("******************************************\n") + + net['r1'].stopRouter() + + log = net['r1'].getStdErr('ripngd') + print("\nRIPngd StdErr Log:\n" + log) + log = net['r1'].getStdErr('zebra') + print("\nZebra StdErr Log:\n" + log) + + +if __name__ == '__main__': + + setLogLevel('info') + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) + retval = pytest.main(["-s"]) + sys.exit(retval) From d6df723b103f222c6c967b571d20aa062e7cdd93 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 7 Apr 2017 17:22:03 -0700 Subject: [PATCH 042/384] rip_topo1: Adding new test for RIPv2 Topology Signed-off-by: Martin Winter --- tests/topotests/rip-topo1/r1/rip_status.ref | 16 + tests/topotests/rip-topo1/r1/ripd.conf | 9 + tests/topotests/rip-topo1/r1/show_ip_rip.ref | 10 + .../topotests/rip-topo1/r1/show_ip_route.ref | 3 + tests/topotests/rip-topo1/r1/zebra.conf | 19 + tests/topotests/rip-topo1/r2/rip_status.ref | 18 + tests/topotests/rip-topo1/r2/ripd.conf | 11 + tests/topotests/rip-topo1/r2/show_ip_rip.ref | 10 + .../topotests/rip-topo1/r2/show_ip_route.ref | 2 + tests/topotests/rip-topo1/r2/zebra.conf | 21 ++ tests/topotests/rip-topo1/r3/rip_status.ref | 16 + tests/topotests/rip-topo1/r3/ripd.conf | 12 + tests/topotests/rip-topo1/r3/show_ip_rip.ref | 10 + .../topotests/rip-topo1/r3/show_ip_route.ref | 1 + tests/topotests/rip-topo1/r3/zebra.conf | 22 ++ tests/topotests/rip-topo1/test_rip_topo1.dot | 61 +++ tests/topotests/rip-topo1/test_rip_topo1.pdf | Bin 0 -> 18433 bytes tests/topotests/rip-topo1/test_rip_topo1.py | 352 ++++++++++++++++++ 18 files changed, 593 insertions(+) create mode 100644 tests/topotests/rip-topo1/r1/rip_status.ref create mode 100644 tests/topotests/rip-topo1/r1/ripd.conf create mode 100644 tests/topotests/rip-topo1/r1/show_ip_rip.ref create mode 100644 tests/topotests/rip-topo1/r1/show_ip_route.ref create mode 100644 tests/topotests/rip-topo1/r1/zebra.conf create mode 100644 tests/topotests/rip-topo1/r2/rip_status.ref create mode 100644 tests/topotests/rip-topo1/r2/ripd.conf create mode 100644 tests/topotests/rip-topo1/r2/show_ip_rip.ref create mode 100644 tests/topotests/rip-topo1/r2/show_ip_route.ref create mode 100644 tests/topotests/rip-topo1/r2/zebra.conf create mode 100644 tests/topotests/rip-topo1/r3/rip_status.ref create mode 100644 tests/topotests/rip-topo1/r3/ripd.conf create mode 100644 tests/topotests/rip-topo1/r3/show_ip_rip.ref create mode 100644 tests/topotests/rip-topo1/r3/show_ip_route.ref create mode 100644 tests/topotests/rip-topo1/r3/zebra.conf create mode 100644 tests/topotests/rip-topo1/test_rip_topo1.dot create mode 100644 tests/topotests/rip-topo1/test_rip_topo1.pdf create mode 100755 tests/topotests/rip-topo1/test_rip_topo1.py diff --git a/tests/topotests/rip-topo1/r1/rip_status.ref b/tests/topotests/rip-topo1/r1/rip_status.ref new file mode 100644 index 0000000000..30c840e508 --- /dev/null +++ b/tests/topotests/rip-topo1/r1/rip_status.ref @@ -0,0 +1,16 @@ +Routing Protocol is "rip" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: + Default version control: send version 2, receive version 2 + Interface Send Recv Key-chain + r1-eth1 2 2 + Routing for Networks: + 193.1.1.0/26 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update + 193.1.1.2 0 0 120 XX:XX:XX + Distance: (default is 120) diff --git a/tests/topotests/rip-topo1/r1/ripd.conf b/tests/topotests/rip-topo1/r1/ripd.conf new file mode 100644 index 0000000000..7448f58634 --- /dev/null +++ b/tests/topotests/rip-topo1/r1/ripd.conf @@ -0,0 +1,9 @@ +log file /tmp/r1-ripd.log +! +router rip + version 2 + network 193.1.1.0/26 +! +line vty +! + diff --git a/tests/topotests/rip-topo1/r1/show_ip_rip.ref b/tests/topotests/rip-topo1/r1/show_ip_rip.ref new file mode 100644 index 0000000000..561560f230 --- /dev/null +++ b/tests/topotests/rip-topo1/r1/show_ip_rip.ref @@ -0,0 +1,10 @@ +Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Sub-codes: + (n) - normal, (s) - static, (d) - default, (r) - redistribute, + (i) - interface + + Network Next Hop Metric From Tag Time +R(n) 192.168.2.0/24 193.1.1.2 3 193.1.1.2 0 XX:XX +R(n) 192.168.3.0/24 193.1.1.2 3 193.1.1.2 0 XX:XX +C(i) 193.1.1.0/26 0.0.0.0 1 self 0 +R(n) 193.1.2.0/24 193.1.1.2 2 193.1.1.2 0 XX:XX diff --git a/tests/topotests/rip-topo1/r1/show_ip_route.ref b/tests/topotests/rip-topo1/r1/show_ip_route.ref new file mode 100644 index 0000000000..62d71f0ab6 --- /dev/null +++ b/tests/topotests/rip-topo1/r1/show_ip_route.ref @@ -0,0 +1,3 @@ +R>* 192.168.2.0/24 [120/3] via 193.1.1.2, r1-eth1 +R>* 192.168.3.0/24 [120/3] via 193.1.1.2, r1-eth1 +R>* 193.1.2.0/24 [120/2] via 193.1.1.2, r1-eth1 diff --git a/tests/topotests/rip-topo1/r1/zebra.conf b/tests/topotests/rip-topo1/r1/zebra.conf new file mode 100644 index 0000000000..4dc46c2c8b --- /dev/null +++ b/tests/topotests/rip-topo1/r1/zebra.conf @@ -0,0 +1,19 @@ +log file /tmp/r1-zebra.log +! +hostname r1 +! +interface r1-eth0 + ip address 192.168.1.1/24 +! +interface r1-eth1 + description to sw2 - RIPv2 interface + ip address 193.1.1.1/26 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/tests/topotests/rip-topo1/r2/rip_status.ref b/tests/topotests/rip-topo1/r2/rip_status.ref new file mode 100644 index 0000000000..b539d321d5 --- /dev/null +++ b/tests/topotests/rip-topo1/r2/rip_status.ref @@ -0,0 +1,18 @@ +Routing Protocol is "rip" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: + Default version control: send version 2, receive version 2 + Interface Send Recv Key-chain + r2-eth0 2 2 + r2-eth1 2 2 + Routing for Networks: + 193.1.1.0/26 + 193.1.2.0/24 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update + 193.1.2.2 0 0 120 XX:XX:XX + Distance: (default is 120) diff --git a/tests/topotests/rip-topo1/r2/ripd.conf b/tests/topotests/rip-topo1/r2/ripd.conf new file mode 100644 index 0000000000..d4e3065cfe --- /dev/null +++ b/tests/topotests/rip-topo1/r2/ripd.conf @@ -0,0 +1,11 @@ +log file /tmp/r2-ripd.log +! +! +router rip + version 2 + network 193.1.1.0/26 + network 193.1.2.0/24 +! +line vty +! + diff --git a/tests/topotests/rip-topo1/r2/show_ip_rip.ref b/tests/topotests/rip-topo1/r2/show_ip_rip.ref new file mode 100644 index 0000000000..58ab052160 --- /dev/null +++ b/tests/topotests/rip-topo1/r2/show_ip_rip.ref @@ -0,0 +1,10 @@ +Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Sub-codes: + (n) - normal, (s) - static, (d) - default, (r) - redistribute, + (i) - interface + + Network Next Hop Metric From Tag Time +R(n) 192.168.2.0/24 193.1.2.2 2 193.1.2.2 0 XX:XX +R(n) 192.168.3.0/24 193.1.2.2 2 193.1.2.2 0 XX:XX +C(i) 193.1.1.0/26 0.0.0.0 1 self 0 +C(i) 193.1.2.0/24 0.0.0.0 1 self 0 diff --git a/tests/topotests/rip-topo1/r2/show_ip_route.ref b/tests/topotests/rip-topo1/r2/show_ip_route.ref new file mode 100644 index 0000000000..4b34939aa5 --- /dev/null +++ b/tests/topotests/rip-topo1/r2/show_ip_route.ref @@ -0,0 +1,2 @@ +R>* 192.168.2.0/24 [120/2] via 193.1.2.2, r2-eth1 +R>* 192.168.3.0/24 [120/2] via 193.1.2.2, r2-eth1 diff --git a/tests/topotests/rip-topo1/r2/zebra.conf b/tests/topotests/rip-topo1/r2/zebra.conf new file mode 100644 index 0000000000..74f7bfec06 --- /dev/null +++ b/tests/topotests/rip-topo1/r2/zebra.conf @@ -0,0 +1,21 @@ +log file /tmp/r2-zebra.log +! +hostname r2 +! +interface r2-eth0 + description to sw2 - RIPv2 interface + ip address 193.1.1.2/26 + no link-detect +! +interface r2-eth1 + description to sw3 - RIPv1 interface + ip address 193.1.2.1/24 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/tests/topotests/rip-topo1/r3/rip_status.ref b/tests/topotests/rip-topo1/r3/rip_status.ref new file mode 100644 index 0000000000..0e3a4be944 --- /dev/null +++ b/tests/topotests/rip-topo1/r3/rip_status.ref @@ -0,0 +1,16 @@ +Routing Protocol is "rip" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: connected static + Default version control: send version 2, receive version 2 + Interface Send Recv Key-chain + r3-eth1 2 2 + Routing for Networks: + 193.1.2.0/24 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update + 193.1.2.1 0 0 120 XX:XX:XX + Distance: (default is 120) diff --git a/tests/topotests/rip-topo1/r3/ripd.conf b/tests/topotests/rip-topo1/r3/ripd.conf new file mode 100644 index 0000000000..e9918c975f --- /dev/null +++ b/tests/topotests/rip-topo1/r3/ripd.conf @@ -0,0 +1,12 @@ +log file /tmp/r3-ripd.log +! +! +router rip + version 2 + redistribute connected + redistribute static + network 193.1.2.0/24 +! +line vty +! + diff --git a/tests/topotests/rip-topo1/r3/show_ip_rip.ref b/tests/topotests/rip-topo1/r3/show_ip_rip.ref new file mode 100644 index 0000000000..cf672712a8 --- /dev/null +++ b/tests/topotests/rip-topo1/r3/show_ip_rip.ref @@ -0,0 +1,10 @@ +Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Sub-codes: + (n) - normal, (s) - static, (d) - default, (r) - redistribute, + (i) - interface + + Network Next Hop Metric From Tag Time +S(r) 192.168.2.0/24 192.168.3.10 1 self 0 +C(r) 192.168.3.0/24 0.0.0.0 1 self 0 +R(n) 193.1.1.0/26 193.1.2.1 2 193.1.2.1 0 XX:XX +C(i) 193.1.2.0/24 0.0.0.0 1 self 0 diff --git a/tests/topotests/rip-topo1/r3/show_ip_route.ref b/tests/topotests/rip-topo1/r3/show_ip_route.ref new file mode 100644 index 0000000000..835e1229c8 --- /dev/null +++ b/tests/topotests/rip-topo1/r3/show_ip_route.ref @@ -0,0 +1 @@ +R>* 193.1.1.0/26 [120/2] via 193.1.2.1, r3-eth1 diff --git a/tests/topotests/rip-topo1/r3/zebra.conf b/tests/topotests/rip-topo1/r3/zebra.conf new file mode 100644 index 0000000000..1c79b36b3e --- /dev/null +++ b/tests/topotests/rip-topo1/r3/zebra.conf @@ -0,0 +1,22 @@ +log file /tmp/r3-zebra.log +! +hostname r3 +! +interface r3-eth0 + description to sw4 - Stub interface + ip address 192.168.3.1/24 + no link-detect +! +interface r3-eth1 + description to sw3 - RIPv2 interface + ip address 193.1.2.2/24 + no link-detect +! +ip route 192.168.2.0/24 192.168.3.10 +! +ip forwarding +ipv6 forwarding +! +! +line vty +! diff --git a/tests/topotests/rip-topo1/test_rip_topo1.dot b/tests/topotests/rip-topo1/test_rip_topo1.dot new file mode 100644 index 0000000000..f052b697ea --- /dev/null +++ b/tests/topotests/rip-topo1/test_rip_topo1.dot @@ -0,0 +1,61 @@ +## GraphViz file for test_rip_topo1 +## +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph test_rip_topo1 { + overlap=false; + constraint=false; + + // title + labelloc="t"; + label="Test Topologoy RIP Topo1"; + + ###################### + # Routers + ###################### + + # Main FRR Router with all protocols + R1 [shape=doubleoctagon, label="R1 FRR\nMain Router", fillcolor="#f08080", style=filled]; + + # RIP Routers + R2 [shape=doubleoctagon, label="R2 FRR\nRIP Router", fillcolor="#19e3d9", style=filled]; + R3 [shape=doubleoctagon, label="R3 FRR\nRIP Router", fillcolor="#19e3d9", style=filled]; + + ###################### + # Network Lists + ###################### + + SW1_R1_stub [label="SW1\n192.168.1.0/24", fillcolor="#d0e0d0", style=filled]; + + # RIP Networks + SW2_R1_R2 [label="SW2\nRIPv2\n193.1.1.0/26", fillcolor="#d0e0d0", style=filled]; + SW3_R2_R3 [label="SW3\nRIPv1\n193.1.2.0/24", fillcolor="#d0e0d0", style=filled]; + SW4_R3 [label="SW4\n192.168.3.0/24", fillcolor="#d0e0d0", style=filled]; + Net_R3_remote [label="Static Net\n192.168.2.0/24"]; + + ###################### + # Network Connections + ###################### + R1 -- SW1_R1_stub [label = "eth0\n.1\n::1"]; + + # RIP Network + R1 -- SW2_R1_R2 [label = "eth1\n.1"]; + SW2_R1_R2 -- R2 [label = "eth0\n.2"]; + R2 -- SW3_R2_R3 [label = "eth1\n.1"]; + SW3_R2_R3 -- R3 [label = "eth1\n.2"]; + R3 -- SW4_R3 [label = "eth0\n.1"]; + SW4_R3 -- Net_R3_remote [label = ".10"]; + +} diff --git a/tests/topotests/rip-topo1/test_rip_topo1.pdf b/tests/topotests/rip-topo1/test_rip_topo1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c201ac1f0796c880e9a46f403b207388a5314b3f GIT binary patch literal 18433 zcmafa1CS+6w{6?g(>6}qwr$(C?e1yYp0@32+nTm9ZQJJS`M>{}br$!+fRzz_^GfF59HXbHp34WN@Yu{Cox2e5pZ z6ajRi7S_%tj$f^{fwPIQiIJVL34oUu#>v^y#J~o|9k@|lCKiVUq4QO3-r>=2_omrN z8VpHXz}T%22LX~9L@=o~2%PwXr>4!Ox!o&eWfX}-VQ67}KeqhwB$;p4>P37?cY_J{ za#Y&)B9{L8E^!q5+3Ss;4u0SVt7k;8qci8+HYg7l&QEpRAH|o)C-yR<(+hG-#tlUk zuU0RHFV|))(<~0Nb=~fduj{WbM;EE>zDEbAm(|IUoYM>8YR~CEa{Jlt_JPMtJwttK z=oPNVDInfpLZp~Io{MVJEZpeqPA_crvR82r3!~*y82fV?vw5ctodhzH@;zgT#5qZZ z9s(C|6!RXHE1OvBv2ENn0|s}sy9d1@t0sYc-~TAvXKpZVoI1fZHQyOV%+pe9t7B`a zn2tIRcE^3{@PMdP?xFY2z-{RS8$P2WbZn+R^~Ne(|5n9Z{^~PB^-X3}806p}om&t06n$#g^T%{fg;THBD{u z>+~{=W(R5X*fvph&VHYh1S11}paQEElY~fD6@S=zp10SdZk!OC#H}L;=onPB=R$yK z_u3%%vlosu`9yDm>{vx!GaV?!FU$=Up;8%Ylf@|rlNG@vfYgS}q((K*k++f}T+`x_ zk$T~{cb?)uw8|B<2u%XZ@@H%fX4_s;ylBuj(-&szq&RLvp|CJTMnkJMsot+<78?m7 zAL=nhY$7WkP& zRt^_7enG#(?EOM*jWWqVkP#zSpjjdlG_E9kdx@-Z+#Qgz7J7%7CuSkVPR7hx8>t&P zG^kTSgsS`u>NxhC4|MKqH9Jj@ z0+mF8cTpF2wlr$OsO!$Pu}}RAGXQ(TD+)wJy-C}|3b}E* znNBO2!cqS10}q7+4eYpMxQ`?Sa zsx;b0H+Yq@R)!E7uWtpnVxeRrE9AE(iF9S27QPps9TW;i;9t(jhP?^FtY!Lb(i!5b zV6ae?V|x8&sJ%Ht(a!mfnx$r*P*l1>o*$8Ji_=}L+6Cs=nT)#tSOz)!-vm2z4M!DvVRlLv zp3d5uWI3OMgNT)v00=~7^0fUp8OH0sAD|jNc zi?6u7n&u}oy{j6qa_1&Q%QK53&QDFq);UH1bt}Y}*2hyYu4UeEeVXzm(gDGc3koo* z63@O8sN5-u+Wg?@3kG2r`bAOovH1&)J4B`S;k@zlY(U93;apQL7VpStQ2pfGkn~vF z9+anC9#NVkRyi6x>C8VJ77?sK%?~WhT6(7UGmBNm=))z9RF@TGKT*$@jj(wjr1F$f z0>X7ACYoh4WT$k*gA(dSy|luov6PFCb_aYIb0Q5)MS$zRLCua<+mc}v*Qbcu%cz%x z*{?5TwYnk`qVRNFw-fduTdJfG`M|zlrFbXhtwn&Xt?TE4P(}s5rDuno34VJ-w`NHf z3qOf$#sXlvX}w>Xc{`x%@!XPCCYui1~r}4Q?*F zTuJ(Vc4!X8X@WhzE5j5Pel(rv7*jUu3=yVi;?p70|*V{h#LrX5Qyi72T-(W)Ue3>?lC#=juk726;OQi z54}&=3AVLi7!zCLe}miC)n82f3xt1L1~z8azrBC28UGtzDtp+Q0O;fm%>H$DG_iFC zF#Us_iY88WE{;YfP5{<_3_^Cc&R_jbfWLVA1+FqC#uf&GcJ2Tz`Y!_$8xw$og+mAC z3t#^o=kI&}!DV?zJ0m3%XMomMFkw*uowA9$Ge8GGCuC=B=cr_FU}OUL3*SOc3;?!& zx##8mg6*$}|1v8pGXU8Cn!mjN1@M0d;P`I={tf&Le{=atPWEdUbOL|T-}Vdo0d&G9 zt`Vc_{oEW1d+N5gNvdd zQm7g$_W+B95*mr1zy<~wEMh5&*QSzzVsBzq>;?9@EAyURAk@(fRy|Bv6@5MD~kIilv0d z$Kl{pr;Ohp5k7Z&I4mYc`>8W?deEy{ng`WjbVa(7q)#dSjiwU ze`Hyqn7il!`2=&ww@5&a*zo`f5rGoh@_B;zoN6I3z>IWtm{-NuIK?u0ejL8w!)iy^ zZc7UgDjht)#Tq-3-lC63+E@s4-?WWMGw5;Zvho> zg@BqbP#%X?_&rT<5dm8h%0oy%o*e~rP$)bOA%XvSnzR&yGO#>PNS^18$Qi2*N+<9o z7jhcF4Dk-^6NLB^WX|B*GEkG>N-Y--lvv-`masc&CM0^#pKZw&G+y}TKJ;zuD!{t+n98Buj8>}z4cICWxRL;|aL!a|TTk@PtDLhROP@py+lP>9exgP#~^Lzugv z8d2MZss@XOlJpBdjee?1qaU!EA~5+s2NW4D)D^3fRr0w)vm$0h(+sHU$Led$}Xu;5Cv}LIVYyQ3z)$VuN|81M}+P#Bv1LZQ{d#}@#p*KMnj4zHa z-exTRP&Zi|v?iEUz;}Wa0I@Z(G6ELVA=G;iVjr`Df2o`^VF-f9fVLq;UCgpThXf9( zY$A$82r;@MF-2N~zp{iSp$;hzX(vJAD5tTQBZdaQu3R;74nU9Odjg+)5;-Y~oFtBj z;EF7VWGlZ1zlTtf;R~fa!E_6 zZmD{-Ib?bSzLFosZ!I7Sz5KmO{spzFd7|45eLTSuBI)_bhGB;3hT(>RJ1m0=BpnI< z3C&1yW&Fprvm`|XSb}p!9!C%c2FcgQ`%B`Cle-{CIctOmP@PH zEubu9mD`ld&C^?cVV&iQ| z;d%v6l~HNEx>;yPpErnC;a2GvnzRfkk10*>Ctw}D24kwi) z9%4V~D(sKu+*G$%Y7URqw3@N)8o^G5R`ce!>|_|QEWyo0>EzO3IaT^+tGy~=^H zgH=Kw!4!gtf~i9C!ZJc5fxCe9_X78}2jJ7q>Je+tqk#y%3AqMyL$ko?puRX^&{8v3 zlAd|AsJQ=dcLSp_6cH90XcvzinH>>}j7F0}a}ymE8x&a(lM(R}NfnVwRj1ad-xH0} zi~pYpf#e<~={R)~9P94w*HmT+F&$ zKSJJmSuU*LtAZD+wg0rry6N<`ZQpmD#@YaE#87Wm&Fe1@ zh6Gy$6}CHRCbi(L2dz=9&(}@st1SPd66(&}8;< zq^;Y`SI<}YT>LtIN-S8cXt*!dWr1sciLI0^iM1~}VW@7`Vc70{>t4tUx#C!!si5@< zjGchvdT00v|1uknd&MKdr~H`gJ?EimS~Eg3Z*grgys41Y!b{p~^Vn}L3wIKihA-pO z`!4DsExrD?nbcJLBx+^`M~>T%8^NLA>&S5QP);>x-nNFl*{tf?>Wwk~)EeFER>!hG zov&{ysTF3`96DS+Sw5ZTA@9+Pc!UAzm(MySzSi*LaS7Hr{6-%f9RKjeD}co4*^K?dFrg$WdmO^HsesJS~}) zb>5xjF6mFzhndBOvkHdo{Wn zjz2z=dy-4eiRN?jhJL$oC$%v>*nAASef^)b`(HHlUtF7&f$=|d^)IpgYy0BB5<)_P z22Li%fWH)05uo#*NB(l}|4`=tqUKKjFS7lYKf8Q!WCj48l!dX=7rXw;?Z5o}H&! zqm#3cxq%~qiScVU&*0xT42)kxRI@O4HviWkS?FQ@^8Ek(U}T{OFtV`&Sm^2h$M+x0 zf7!pD`+s<1VfiaxzH|-K-a=$@J}BrE8D-WSpPM{^Z*WK=KsYPGxJ}$ z^xx0_$?I>9fBpW`{>S>a{Z~{NrmuMaeH?%7e|!J0;{H!9_qQDXHR=BpLDs z|Eru|A^w*3Z}6|pS`$V9!$0!#zgFYF4F6e<|517WmZ1OKG5{D@*y-87y!?N*dpo_L z-BlJ^k2Jm5y>dKq2+Xn%6PZZK$dEBzMF9pO{2*XR5NT24z`|f!@d8!KushQ*s%3^W zWYQ2~**o$@Rp%;JWttV{oszcaG}C`1WjDGXpv_-BHr=`(J1?`cIuAM@G(SIUeAhIZ zP2UX*1^*yK4+Q&kR>a-SO$DEw^?kTx3ud_i23o4M8VhUW)fNB)7ut^R#iuYX{h~qn z!>P0vI?AO5RB@?v!6AaUsRDTFtIhC3@i`Z8#IH4at@aI@2>vgHT^rE_mtvO!>rO&; zn}#FXYOerde-)~w>csL=R`};~6)UvZnBgp_QC&hGJy%(D3EFr1LV^aY(P>^{F%+aN ztU!cE%qSCt5UH2Z?lm{-uBHQ|#cRd);YO#zx5jqfkpr*lwSq1^feo^5&g?zLq)^iP zvFB{>*q0A0o>`~3AP5BsYlL8>Xku-PS*)<5@n^@(Flk;uj9CpneM+gGWGm z&TZ-CO=+{|{M7EB8I+?gUCFxAwEQ1#5p5O`Z9gK~JR@E(xgkVyGtiDTyk;}!LPW*PP+H4%LmyB zC_wbbH06;4^+ekVPAGOkmlSyu$x6Lr#}wyZEw2{1@C8`k&$QhF#h{W?xX|*Yb9}E# z7Bd@nVjFQVb)Hn5A5Y{!7CXK0zt}0b)@#9bW{*l>hnfIRif?--Cz{y7o-h$J3({xz z!a?Ii!X0=jmys&D=KcK`%=K>tw}h01g}QUah^M+ukR?v`77_Q^W2Y@C#!2_ z`XQ;NnQq;2Z5!{-+MZk22WF#M(?;ykm*~kCVoHxK_!8%ieA;9#_#@)C=NSYhUIo+c zvz@TT8W}hPOtEcC#v|BC7pU~RH}36T1k9Usmg}SL!Csyxn2+=GSdV*s8AEJROfgbC zG&ZL-`E9+&w&EP?jV|5xu@)g&I4)}O!?A5+Fm!Y>l7FbmGPYuRAATlY>|m1E;&&iL zLc0wk+43&+s@QALP6W3A4tFv$^*$I~?rygcw4$$T3YoMvdVl zFw3ZWj(hAw#3RVZmH0IS-HpBAH!V(Tn&(eXomHwPHWTi|qj@Ik>|QyXURO)p4&b@k z9g7O-cg`%QOiH{CT(kRp`*IqXbNX@;Dq&A_-%3&}6x*9yE5>HCGw6$)5PVmEStD?! z+#d+fK2tF74d`M_XJ=4M1m;iAd&5isFvo?G3&_(T#hbLTnkwk2!Rvc!O%vh`4izM^ zQt~II`hN(7d^?M3V*V~n;7?$Ubeb@P4431qbOyq2^?>#hvs`6yj%?YJ+*pE(q3nz)AuKIwnN)% zHZO<+@u_#I$G}3bm~Iaso@K@Yr!4^ohuayBolG=7z}>QqTea0S_%QhL$3%!j6!8SXhOG|>kpEj8e8Bg>TpRr%Z(N^92&9?6^9#%_}LT8-9b>}0{ z&B0yhma%s%@MiOa`K$ApFw|4P& zIZN@y?DF|?q0L!2LCsE~xzWx=6Xj7)`Wwmpd;@3 zo1x6iU5q~Cce(0%KeD(3W{sZDBUBEtlxNZmNXh4Q25m!q$riFJ*ffMZBlVxX%2s8D zU5~jCc+AJ~1aH4KeG?Mp{pD=Tkq%9z4nMX2t=$9p9r_*o^a}QA0daWbIv&xz8DAw| zwCq#hPRJR7N7^+&H~5qrt8ea_dQ~npx>QV3tSjJJ(=R=2bw=Ag|NA-^*GjCes9n!J zq`MVZ>Mnc-j9q{Gb%ipKjXt~U?1-CwGIviqTJ>n{M`P_Qk2zh>6~i5|HeH@C=*U=I zj%99>0=fk*4WrV^M|>5Lm}oZsGpc@&2$r8Omp1Y=X9ME7aJxRATS4NH$Q|w0i4=1b z2em#^~dd|v?qNih+FrlsTLJKGniz@Lz5k1L$6VjuD!ZzBouokVs~Z|G;)AU;G; zKWqFdkTw)zi}R05VQE0rYvPV}d7Z(&Nab z*`bI)Ct+`37P-oQ?{!J%l$W)FS-jZ1G=FXKbThG<;?}1<>y2w1;5cPJ%N;OM)mk(KW>M6SlpDYQ z5;GodL0wB+<8VgNe`8vnWAlZbA+^N6|L)Ahf;PEg1-R8M83HD4+A?}V^qVg@5@5$S z$&KuWOrpp~YC*C0fz(%rLr3b*)9<;w^<1MZ>9?)d94{s;5U4?Jz-p8%i@VK?GBKA= z+@bkc#FL|)Pc#zzaM(pEytoVw*|1~2+vA>|f0;6J#Jka^bAF!_M-(CVS8*LJ8(^bm|G$~;Li?(CCTUj&vI`I?BJI^5|)xVvALE||B?si<6K+hreOPf zelo?hed$kf*rENL;Aa5N4ckFO-OTW)Q%_Ui9Ow3W_!DE?8HaPbWxVgqc_5+Yw2)+{ z6PJ^-om$KZ!R7Rzqp7dcr1vgaN==2D6pfpA0h1WGmKXY^?L;_FGw8HLW9Yo+rJp8O z{4WkmFEulGyU@XS5pgTJvwXmE0M8f?M{D;?xAWr-o*zg0qQ^YxDlv3|kP>ICrbvad z#DJWJE#5A8Zl)wNF_t**kX37I+~;w7@WW;%Y3u$06TaXE?>Uw>y+^YzH#O6t26^Ye zcdIJm(H+SKF9Q<4?>}@fTwAHh>`qo_ltFnNt>v%0T=hWeONaTKw{x^S#k7nCwvh<4 zz_OOe2_c6Y_;K|M2LC|DdrKYy4Q-whzH9(2U9&+bgr;&*F@zBX;m6XqElP!Vr{&Lr z6&=>*U@B}$+;7hw&hWa;n@bkzQ4l7((^}>ybnfYm3N`C9lb??Xud!Wct;&S?ve$G+X3d;{d?CL3LcEK#KriLCB zz!OuAazislU0@~KmySF*okKYe!g<8{GvDgbmhtdTwwuk(^U?Oz){zwEULfkDQ2@sV zL)aLKAX%Wp28J6pZPSYE+mD(}*s&AK5Va!zj_Q1L>g`XaAgP)v?CkL#ODPhl)OWrB z`v+f;?VC@;Agb!ByBvTvv{f|#q59<$a{I)N|ECYC2gR0*eYcnj0faRc&l-Ne4y+sc znrVyH_C;Vj+7S2eN)gi&`Wr`C9qdbQv1~Z^XXt1_wkPU%Qb2P`x&kqsI3qwSQu2RQn`G>6kAVPL**p31G}4S zg3G~Oact*6PT_qZFM%2PcS^FEq(JW2+w#J4k|YajAq}yWbWwUCM_T;%Qj~U-MLjZ2 z1R1$SC6r=w`V&MMin?fUOZ}Xo!I4OO>?eYbKF;Hgt1|EuZN0#I6%{U0QX{RPRH<3^ z!1t$Uk!OabI;qbYx?WK}M&a+ZJh@qI)9d+{B~P#mWTG!7cknM@GbH3=s%6K}9cO-# z3pn&;Wmzu*5qt*{_acK6dQ|(GF1|l zL&1-^dFdm_l2^#iYg*f?;_`0UI7N2Cx6{#X=Kb6r({h_!;YI>WuG_2G98P~b zbHw%os;dG!1`7?NH zd3D)RMg^%ZR$BnwpdpC`7&a5?aTKXjJeyW%ecP|NO|sozy>N{{a#}3ju1Xmsh8cK0 zR4Uf!RG*f81BOG}3CUB%zDcw$F!1uU49f&zKLT~Y$SmbE5#|G(E+IO``RVc>Ea%vE@)MmI`rZjVa zAES|Fzp-sO7fxoQ)9Qhpty)fLTJyi&3vn*PEFM?fsT2~wX+Loc!?5Pk^mGOyJ^@M~ zsK-z#Nh*r!)vH0~89|7{a@9%^EvxfgUBF}OjZZV9V3!Pzq2!mfG<6M%I~$)MsJUt# z)x;>#sNQd@hkf4_K3LyGrwWn&{HF3{-p#nmANIZK$&X;Uk&Es0`6PN~yUj?{DSzt* zl>oJF6a5f;tRL%TU8h=%YM$ICr`3lMZl$cw(wd|>WOK-P9Ll3ucLwwvOnU`{~+1=P9x?Z$t#}_f(*oe z^08OdM*uWk*k)yOX$R~F-LICXBBF0n|ArF-KyYcLP}0n%ft4~3t@@-w0RoT;9*vwP z{_N)>JGoren0fD7C6tGR=-%|{k1}4w<#1c_;j@62J1x5y>(1(~^~hs;s%M$1(q?c$ zFScHIWqqtl!^#;u=X+lM)~S@JG816}nKR`}-?f}VN}ms6?l833SRRO}P5+%&Jh+JpsKUDDHp`VgsX`>AH1d>$YN??F!K??Yl(jyYn84^XS zw72x^vO&ENPuHi%Jo$NFgO9~KafWGIVAtt5_wa_?V$|O7u^2yfe7F)_8w*$^dO0+A zNJ*s{7wEOk?3j%?uX2@CcHghO1S*2R5H_`j7;@pJZgKk+S`8`FEncS%d9T++C;!n0AyZgOSgH= z5%xs1r!GzwD#dF8YrI#F7y7_tYVcKlnb$JubknW;{3@RcQoZ_Uu#=y;wECgO^XXQX%JB? zp2xSZ{|)NU=o)-UVF@0A2V@5d5LGsfRAraFq0$vMxXN_`U198zdqhB_B~IRpl-=Pz z0MV6>C<(9gL z&s3Whq;Hd}k6Y9Jfmzc9htm$Eme(mkt>~o5`AEhcVow3Y;53E9?~)X`s#NOKO6dxt zVy8f#K%-Ef(A^&fIX*SJwO7t}_eUJt+RBN0RcMhcJ9!KflvM(-6j!~Yw=C*Rx<=dI z2h=0e*TbFF#R}a7TbTs)GsDme**Jjig@PX1X@q)8xA;Lq*+3&}1VL)4x6Zoc>!jsF zfifLIlw`+D>nP!Fv=H~})k*moVYCE4fL3l``WCk^5X4Qbfw*Awp`!3)L7Y|MBEY15 zLM&gp0^--}jCzX~_}Jg~)4QtZ?r{~VZCcBGo>hA{n@Xu&pBD0zl+VF3c2Y(%esXZy zKl;w(z4f|19_p>Ub*9)W3>ea3wm)4mStpB>cfak~NH-|J@NnLkbwvI^nheA=5rI@0 zcWN`NpM_EUqh6_iR$n<}S=Y7K`Rk^<1rMo9bu5fA5C%30p4KHAiC?0PAzTc@k0I|NB>(%?Xa?ErFjD2pC>08k`z+jl;H-6D7|M%PzGw#yJ8UVY&#ZJ|}~j+SN%Mm6G*D<&}zk;m*_!9kh_28G>a|r{}Jrg0!(G zIg+ce76t2j_7DNqh;*DCllftk`Aj0#{$UxhU_{K)Th6tt&Fg5W zTVaf3eY9>JezFqs5=Tj{(3S(iuzlbLP`_4_&RMX{pAXUvn9N^T3P9Cm!x#j=m6|a4 zLs|u!KxUKAr9uXs~+8$dJLLzELHbnX5g_TCqqz75NNiB2qZ4iX2VAY0*wby9=S z0=I;41CVK?fF-MC@CU9%U?uS<$sFK6$2fx%yhpOH761bk#|eM&aS2cI>7G|@ncr!nkgCl5aLAE>DGN*`879|r)$yW$QEwiI6_W=cTAS;!XUbp`95IbbLJU&;=b1Yuo3x#-GzHRNn2$vPW$XLm!v^Z%Lp`%RfK&OEyRr>oP+13@iXU-P0c=YEiNF05FA&WVff`Cy>077U=Ocs)F~MZ zQ+$qfHG3cWeD1d#?PBP~*No_$LA|I$`Yt~=B+fRKoejqOZ8c&O{ji~zr?!{uom)(6uOM=!fPZQK@&-Td8F&Y0m2)(x3v$~+ zh=JMwc5uDS^0k#jO$4C#<3Z5w1iMpy#LPEBBmX{&Yfst?#Ui{<@&q&**hcbP&ZdEp z#xW9NOv(>rv<(Cc2Ax}kK!t(WXpFL_*WZ@348;g9$YJlwpytQkX!{X+ne9AQY5zmZ z*QH;w+%WgEUoEF6v@g-}mh3i#r6*gjNEe!M2kax%QQ2R~Q2cPSaJh1=YOU%;X)6)1H0egc8IYvd z3+_hYTIL4kTjNeOlKkCJR@uxBtz9xDS)K%PSAxsJ;g2nvS$Z{-LUAC05OJw0eH535 zL2jC{B5le_eV}_aSDM?J;j)^c>|8*-$!sxyX*VqM`$!8!+xt-hQ?lkuFT(k=QY>52 zIse)6)26D_CCV!pPt?B$j;;Y6E%1Y31r8Vct^&x1M}e}O_pZwa6(e#Crk->L)J(1m z%u5}6qrgKW@(ZIg`jN0%o)^&{eS({PZ%{TS29`o0t{;si35+$z89?1Cxvny)V#`*y zUuv1}6eBG$eZR3k9ZQc(q?1ib>hgV$qB*|X*^O;x{=9E}?w*CHl+H)v{qAZ1*wAjP z*;-1&Qd7e`*Z$$J*96w_3{A(^QtRYsqO$(GsGgGz&)ZFVEh2W#OrXR62gnb0Q-sMR z%(Fet6|06U&VX3?c_9p5r}WtEND?+zrKIYKYS}0EtM9~bAxqM(zpbYUFb_PkG)=|( z+;A*W?Sh>gk}QVWyTdbKTt}-(NILEL$azp*b%Y+0UQbP zxw-^F;8`Q8C~nX87L*4|Vi8yvIKa=1cuWjU1VWfDEXa%H)y)ZDMl6F}s_4#kw zI@)@>THA(85wB~Z)zBcZnS!Udm#_zkZTTztBX-W1oEcssZd7l|JISl$IJtmq__vzO zxJ?&QPCj&}8P8mhAFs%q-k{@+%7RI;w7M<%6M^GL%nI7^Y3%ZH3KLO+wq!Oie&@wPMr^qa-gU`kECxv2A<-> z&Bkb+hD-^MPy9DQ)>R~`^ZmPn!qmXf&_o|;W-w}c2Pr%mo3b_|4h zSV%39%X^TqV6Hh2m$yT^Mm8CQ@AaMuc%wf3h`5#!IJB58A@S#FU)V>e5Lxt--PaHE zY6MZxZIcx!Ki?x>EAZ5~tG%V)E8kq6vCG(IFGn|}a;RDX_>xv;*VhS#_5C)^1yQPz zjk{8b`zj<3RUo5L9Sq2O2`>ARUDc{9JuJ$>;3nmH>eMSJGN||z#SxGc#FXjO243|w z@fK*?O!@xBq6msY=%L}Me~*KBn>;~K4;J?Tu7hwQ+-LUTr| zzHqlqJaHmhQROPmiQnKrFnwYqA>UhBMZ zG|&?H`V+V(-wOtPp+KSI60CRIF@OjzEX;&$K$*UuzGO>f4IvcP353iJ_0_Nf8uSQe zMA!AV7VgbB_t*QV>Q(=jO0l1zx5>LSpJGnLLfr5BSUQ|xo zwJ_uPQ~>&)T^haHezHpqP8N;x((=u_=|DZh6)T6A5gO!9m1AR0D@xD%8Lw_@c()_g zrVZEU%^%>1kl~9&L^-`n1fjhtPJX9PZibJHKUyt|K3?)C)<{1@7tq#K-_dqc@~P6t zG+iKlaW@ON`a8;fBcGK&;!|o!Y`I{6@+WBvjPa8PUK&!5@HDNyCC zxkb+ztmh9b12`!5r9%j7)d3H4Ij!LTjjpdM@6}GT<=uH;jRUS-Hx#p+pG#vrFNFg4 z&;+YRQyBtJkT?l!0ta1?+)DrvLGp0|@*d;KA}ykue+}}+ynI>k%j5+PDB%`F=|)W+ zb^~jp+WmuT>|y?;!1wLCzWXT_{fFl6%$AU(*XSyk&r^|6PNz%1;liR@-R}I9gZ|sj zjYXs+=dch;HTR}?H&la(ADyXbpPIZ~MCUH{Fw6QzOT}?*mI;w{aL4GP@{T#GPR>@E`1yONjn);L+;0oH=$vCjw}m1Ws-^bl!ep)md*-vuy60T zPj7mIjZEo&1x8N+qWz1J`^rxr+4tQRc_nD=6=RDX0KKgTbJWRsP(DxB*C&3dTa0Ag z!x*r3G)$f2Z?~TX?Z#`-bc*M>R!9EVz95@7MKcmJ^M-xCY(}jsrp4ABagHSvzMY_5 zq#u$vy9KB5MCZ`UC%Ck+e5#k?9&f*$#!-TWTFFjg2lIbq#H0kzMadV6Y_}28W;wQ_ z0Q>%iQDAfar3^K!xP=RJmXsn60afcdUCv)b7y{YiMSO)^7bzMj%Rja*Zg?t4Z~QAr z8kio7TEJ-;+!X?WW18(cIHnCcECGB~m522dXb02K%v%VY>PZat+lvLJSLop5P?&bMxc1B~TmPH#i&Jkyx zZ$AQAew(kQQ;gW1eqegfXoO@VwO2NUvs&gH#6g5D zo})^xrzJISj6s~@>c+-WbM8X3m*e8a;u{N>4cFYDsMg4k2Ec;~Ibn9PYMQ}YwMv&Q z6_D@#?!ng>TE?v{D*1iCZ5&Zdpv%lCpG}fPg-}%(Qc5gLM6d_z%B(;eY!x)-$^_o` zO^muJj08-26|G6Mn{@3$;a4Y2h^MxtBU0zpA1L$|7hqv__9jUa3?er3{KtviqgInd zQ)V??z4gpX3_Y4j9Hmn#bgi57C!SDlF7(Mt8exSWDrH&(-Dbrl#N69O-iDcBxbPz9 zE>GcU6+{PTR~fsKBajJmOMZ|roltW{iLN(M`mO+ zbqX~M=~2B+iAvtN!_>8)v23Cw;1tPfu*zuMN&_HG+JdsXNJ;t=Z}m7P_aKUyy2uAN z5*Qap3aXQZCin*?Kxhaq5AYL`-w`~$;UVS!kl@Yw={(tP0~kPP*&~nypY)cmDso3@ zIi>m?qUQt7q^8T2)g9Gdj*i=5wNU(e39tBQDD?5Wy+)Aw_XF#P!b&C|&P2}pzFhV| z5lc|WUcwuepPd-vQPi>uE#2cq{RTQWjyJP6uQ$awRe*I1jW|BcRtnI=wP50EJO{cs zD~BZCl@>SWF@InMieRJ!0prGau9#X{`_pdL`1>H>^-EDNg+ zFjfvj7VuMef%3QKo3?-k)=3oJTIs@ahg?b}K>$W3=nMJ!zfusi5&<#nOWm@bwi?bB?Zf+K4e9mf=vyx9bYZdIBITkdXnyaK28e5s|#Rm zayAZo;ot$vdsLK;)CFbKM@CgqD@!d;DPyBxD|0Oepe4H|y@tk(f3cdmxLRGS^_qoTAe=?NJy{U%?T_e1A8cbP@{E~4p^|E3eKY$L7X7R7=35at z?$9=)J)*Ef z_W|R5tmREBYZ+DOyzK}X!CS8^hi{hLwYA~lATiaAOGxEi=H+NbeI zNz8LJ1$4FmN~Z@NDBTVkA`|)}kWU#`K~~d^T@S!InXE=2p#$ zR27=ygBeEEJZ9DC^{G-ibQ$>O7bHsKOsi_e3v|u9VQV~3mdN8<);JE0%VC1 z2hs$C^hl5s`XFXtkP^lH-x8@E5PXF7KFCyy9>K{&;2C(&zP7#hAt~dWSpYzWs}cg( zJ3ck!L8pGOD*RU6^dFd-HWyX#o8dX(^Md?&r2UF?n zqh?s4pVFV^?pjXHf_+$!bQ0s^0^gb<56h$qnr7m7Gpgpu(N8Y}!;4lhjtKQk2p>aUCnp+B&`!#6ec;pQMr8lu0`zn2{Qu#Ac-b*%xo>O8S4K8bL|N>COdo6EDh}s$`v%& zNdtGA(btf!_P%Xd#bFMvEg(jl_&@vK*#2T(+xh=S5jnn>+3y-H_Ajt%+ka?%^>N8V zR+ewej6=QKF0=JUy6?UI^y29g?!6AdeS19iGn!0g%6^devF&EqnZ}vYntjJ^KRNqt z+Yg`LmwxyiJ@@0^kCi|2AI~Z*lT>-vu;7w){2)M{rZy5x&% z$*DvKqxcOs7kU=ITwR;FQ!v*!DS2hJ^nx}C*7qgz1>+dicSLeE^UnX7exjkf_Xu0% z!!wc=Nh*gDCfrGnXXcpECBiMudLi`NBK7%R47)kmWq$;$R9zWR|4)ba|M!>2+A>0B z*H_-!w{GUna8O{r>A?d#sieTDAZ8)BNexdX{Njs`>1mxXOQb z#kI4QB?XQY?(}t(&G#-`$@Isg%S~+Y(V&O%!jDoGKm2|9(Dmi6A6Vy0n&|F+Qr~e% z)315XiH1C8LGBRV|K(S>rj^eAvfq62!~cQH4*ox0;xVmE{m=X}F_}e4dlOfxD3{&& zv956QGM~P)5!bd?R~|9AXIDP^|&nH=*DktPr7KXrO1QXQ~ibnpjj)r2yPn4c??(QG(C| z+jOFlUX)mnQI=VyV5Dbkre}aq0o(4O;bLWE09^5JVqjrlU}S7$9%W#l4nzo*P*;OC zYKLT&0QUiaoebP<4cy(GQko1rX$9;=pnx;*fED1D58pdJ`MGe6G-v>DqFypM!-EqDCPmhFv0~GeultQh^Efm1j%nDMTx*28Aae@ zb%HaifbnLjpdXZ<58Q49+EN6JRnNS%eBji?9;N2AARzV3GzW1VeKROH(dYRabvEE&x;#+?)Ua literal 0 HcmV?d00001 diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py new file mode 100755 index 0000000000..7f39dffca1 --- /dev/null +++ b/tests/topotests/rip-topo1/test_rip_topo1.py @@ -0,0 +1,352 @@ +#!/usr/bin/env python + +# +# test_rip_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_rip_topo1.py: Testing RIPv2 + +""" + +import os +import re +import sys +import difflib +import pytest +from time import sleep + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from functools import partial + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from lib import topotest + +fatal_error = "" + + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "RIP Topology 1" + + def build(self, **_opts): + + # Setup Routers + router = {} + # + # Setup Main Router + router[1] = topotest.addRouter(self, 'r1') + # + # Setup RIP Routers + for i in range(2, 4): + router[i] = topotest.addRouter(self, 'r%s' % i) + # + # Setup Switches + switch = {} + # + # On main router + # First switch is for a dummy interface (for local network) + switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch) + self.addLink(switch[1], router[1], intfName2='r1-eth0') + # + # Switches for RIP + # switch 2 switch is for connection to RIP router + switch[2] = self.addSwitch('sw2', cls=topotest.LegacySwitch) + self.addLink(switch[2], router[1], intfName2='r1-eth1') + self.addLink(switch[2], router[2], intfName2='r2-eth0') + # switch 3 is between RIP routers + switch[3] = self.addSwitch('sw3', cls=topotest.LegacySwitch) + self.addLink(switch[3], router[2], intfName2='r2-eth1') + self.addLink(switch[3], router[3], intfName2='r3-eth1') + # switch 4 is stub on remote RIP router + switch[4] = self.addSwitch('sw4', cls=topotest.LegacySwitch) + self.addLink(switch[4], router[3], intfName2='r3-eth0') + + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + global topo, net + + print("\n\n** %s: Setup Topology" % module.__name__) + print("******************************************\n") + + print("Cleanup old Mininet runs") + os.system('sudo mn -c > /dev/null 2>&1') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + topo = NetworkTopo() + + net = Mininet(controller=None, topo=topo) + net.start() + + # Starting Routers + # + for i in range(1, 4): + net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ripd', '%s/r%s/ripd.conf' % (thisDir, i)) + net['r%s' % i].startRouter() + + # For debugging after starting Quagga/FRR daemons, uncomment the next line + # CLI(net) + + +def teardown_module(module): + global net + + print("\n\n** %s: Shutdown Topology" % module.__name__) + print("******************************************\n") + + # End - Shutdown network + net.stop() + + +def test_router_running(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check if FRR/Quagga is running on each Router node") + print("******************************************\n") + sleep(5) + + # Starting Routers + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_converge_protocols(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Waiting for protocols convergence") + print("******************************************\n") + + # Not really implemented yet - just sleep 60 secs for now + sleep(60) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_rip_status(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing RIP status") + print("******************************************\n") + failures = 0 + for i in range(1, 4): + refTableFile = '%s/r%s/rip_status.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip rip status" 2> /dev/null').rstrip() + # Drop time in next due + actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual IP RIP status", + tofile="expected IP RIP status")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed IP RIP status check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_rip_routes(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing RIP routes") + print("******************************************\n") + failures = 0 + for i in range(1, 4): + refTableFile = '%s/r%s/show_ip_rip.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip rip" 2> /dev/null').rstrip() + # Drop Time + actual = re.sub(r"[0-9][0-9]:[0-5][0-9]", "XX:XX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual SHOW IP RIP", + tofile="expected SHOW IP RIP")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW IP RIP check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW IP RIP failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_zebra_ipv4_routingTable(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing Zebra IPv4 Routing Table") + print("******************************************\n") + failures = 0 + for i in range(1, 4): + refTableFile = '%s/r%s/show_ip_route.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip route" 2> /dev/null | grep "^R"').rstrip() + # Drop timers on end of line (older Quagga Versions) + actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual Zebra IPv4 routing table", + tofile="expected Zebra IPv4 routing table")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed Zebra IPv4 Routing Table Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "Zebra IPv4 Routing Table verification failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_shutdown_check_stderr(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + pytest.skip('Skipping test for Stderr output and memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifing unexpected STDERR output from daemons") + print("******************************************\n") + + net['r1'].stopRouter() + + log = net['r1'].getStdErr('ripd') + print("\nRIPd StdErr Log:\n" + log) + log = net['r1'].getStdErr('zebra') + print("\nZebra StdErr Log:\n" + log) + + +if __name__ == '__main__': + + setLogLevel('info') + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) + retval = pytest.main(["-s"]) + sys.exit(retval) From 598d845766cbda09b25ea8b23415a8bc07392168 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 8 Apr 2017 03:39:47 -0700 Subject: [PATCH 043/384] Update FreeRangeRouting -> FRRouting name Signed-off-by: Martin Winter --- tests/topotests/README.md | 8 ++++---- tests/topotests/ospf6-topo1/README.md | 6 +++--- tests/topotests/ospf6-topo1/test_ospf6_topo1.py | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index 7e82a3fa4e..ce494d49eb 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -1,4 +1,4 @@ -# FreeRangeRouting Topology Tests with Mininet +# FRRouting Topology Tests with Mininet ## Installation of Mininet for running tests Only tested with Ubuntu 16.04 (which uses Mininet 2.2.0) @@ -36,7 +36,7 @@ Optional, will give better output 4. reboot (for options to take effect) -## FreeRangeRouting (FRR) Installation +## FRRouting (FRR) Installation FRR needs to be installed separatly. It is assume to be configured like the standard Ubuntu Packages: @@ -50,7 +50,7 @@ like the standard Ubuntu Packages: No FRR config needs to be done and no FRR daemons should be run ahead of the test. They are all started as part of the test -#### Manual FreeRangeRouting (FRR) build +#### Manual FRRouting (FRR) build If you prefer to manually build FRR, then use the following suggested config: @@ -72,7 +72,7 @@ And create frr User and frrvty group as follows: addgroup --system --gid 92 frr addgroup --system --gid 85 frrvty adduser --system --ingroup frr --home /var/run/frr/ \ - --gecos "FreeRangeRouting suite" --shell /bin/false frr + --gecos "FRRouting suite" --shell /bin/false frr usermod -G frrvty frr ## Executing Tests diff --git a/tests/topotests/ospf6-topo1/README.md b/tests/topotests/ospf6-topo1/README.md index e638550f4d..2369ab22f7 100644 --- a/tests/topotests/ospf6-topo1/README.md +++ b/tests/topotests/ospf6-topo1/README.md @@ -10,7 +10,7 @@ | ::1 | ::2 | +---------+---------+ +---------+---------+ | | R1 | | R2 | | - | FreeRangeRouting | | FreeRangeRouting | | + | FRRouting | | FRRouting | | | Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | | +---------+---------+ +---------+---------+ | | ::1 | ::2 \ @@ -26,7 +26,7 @@ | ::3 | SW3 - Stub Net 3 | +---------+---------+ /-+ fc00:3:3:3::/64 | | R3 | / | / - | FreeRangeRouting +--/ \---- / + | FRRouting +--/ \---- / | Rtr-ID: 10.0.0.3 | ::3 ___________/ +---------+---------+ \ | ::3 \ @@ -40,7 +40,7 @@ | ::4 / +---------+---------+ /---- | | R4 | | SW4 - Stub Net 4 | - | FreeRangeRouting +------+ fc00:4:4:4::/64 | + | FRRouting +------+ fc00:4:4:4::/64 | | Rtr-ID: 10.0.0.4 | ::4 | / +-------------------+ \---- / -----/ diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 6da2e89780..963e49e719 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -34,7 +34,7 @@ test_ospf6_topo1.py: | ::1 | ::2 | +---------+---------+ +---------+---------+ | | R1 | | R2 | | -| FreeRangeRouting | | FreeRangeRouting | | +| FRRouting | | FRRouting | | | Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | | +---------+---------+ +---------+---------+ | | ::1 | ::2 \ @@ -50,7 +50,7 @@ test_ospf6_topo1.py: | ::3 | SW3 - Stub Net 3 | +---------+---------+ /-+ fc00:3:3:3::/64 | | R3 | / | / - | FreeRangeRouting +--/ \---- / + | FRRouting +--/ \---- / | Rtr-ID: 10.0.0.3 | ::3 ___________/ +---------+---------+ \ | ::3 \ @@ -64,7 +64,7 @@ test_ospf6_topo1.py: | ::4 / +---------+---------+ /---- | | R4 | | SW4 - Stub Net 4 | - | FreeRangeRouting +------+ fc00:4:4:4::/64 | + | FRRouting +------+ fc00:4:4:4::/64 | | Rtr-ID: 10.0.0.4 | ::4 | / +-------------------+ \---- / -----/ From 80eeefb7da6ad100213baa7bd5fac024cae8148a Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 8 Apr 2017 03:40:51 -0700 Subject: [PATCH 044/384] lib: Add function to check for daemon available (i.e. LDPd) and function to return typ (quagga or frr) Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index bd797bfafc..221910b13f 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -52,7 +52,7 @@ def int2dpid(dpid): 'canonical switch name such as s23.') def addRouter(topo, name): - "Adding a FreeRangeRouter (or Quagga) to Topology" + "Adding a FRRouter (or Quagga) to Topology" MyPrivateDirs = ['/etc/frr', '/etc/quagga', @@ -241,6 +241,24 @@ class Router(Node): else: linklocal += [[interface, local]] return linklocal + def daemon_available(self, daemon): + "Check if specified daemon is installed (and for ldp if kernel supports MPLS)" + + if not os.path.isfile('/usr/lib/%s/%s' % (self.routertype, daemon)): + return False + if (daemon == 'ldpd'): + kernel_version = re.search(r'([0-9]+\.[0-9]+).*', platform.release()) + if kernel_version: + if float(kernel_version.group(1)) < 4.5: + return False + else: + return False + return True + def get_routertype(self): + "Return the type of Router (frr or quagga)" + + return self.routertype + class LegacySwitch(OVSSwitch): "A Legacy Switch without OpenFlow" From 4501fbcaa8850d050a3f674f39e16eb59cf36aff Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 8 Apr 2017 03:49:43 -0700 Subject: [PATCH 045/384] all-protocol-startup: Add test suite which runs all protocols at once and verifies startup and spurious errors of each Signed-off-by: Martin Winter --- .../all-protocol-startup/r1/bgpd.conf | 47 ++ .../all-protocol-startup/r1/isisd.conf | 21 + .../all-protocol-startup/r1/ldpd.conf | 25 + .../all-protocol-startup/r1/ospf6d.conf | 16 + .../all-protocol-startup/r1/ospfd.conf | 13 + .../all-protocol-startup/r1/rip_status.ref | 15 + .../all-protocol-startup/r1/ripd.conf | 12 + .../all-protocol-startup/r1/ripng_status.ref | 14 + .../all-protocol-startup/r1/ripngd.conf | 11 + .../all-protocol-startup/r1/show_bgp_ipv4.ref | 7 + .../all-protocol-startup/r1/show_bgp_ipv6.ref | 7 + .../r1/show_bgp_ipv6_summary.ref | 21 + .../r1/show_ip_bgp_summary.ref | 15 + .../r1/show_ip_ospf_interface.ref | 22 + .../r1/show_ipv6_ospf6_interface | 0 .../r1/show_ipv6_ospf6_interface.ref | 46 + .../r1/show_isis_interface_detail.ref | 28 + .../r1/show_mpls_ldp_interface.ref | 3 + .../all-protocol-startup/r1/zebra.conf | 72 ++ .../test_all_protocol_startup.dot | 61 ++ .../test_all_protocol_startup.pdf | Bin 0 -> 21760 bytes .../test_all_protocol_startup.py | 785 ++++++++++++++++++ 22 files changed, 1241 insertions(+) create mode 100644 tests/topotests/all-protocol-startup/r1/bgpd.conf create mode 100644 tests/topotests/all-protocol-startup/r1/isisd.conf create mode 100644 tests/topotests/all-protocol-startup/r1/ldpd.conf create mode 100644 tests/topotests/all-protocol-startup/r1/ospf6d.conf create mode 100644 tests/topotests/all-protocol-startup/r1/ospfd.conf create mode 100644 tests/topotests/all-protocol-startup/r1/rip_status.ref create mode 100644 tests/topotests/all-protocol-startup/r1/ripd.conf create mode 100644 tests/topotests/all-protocol-startup/r1/ripng_status.ref create mode 100644 tests/topotests/all-protocol-startup/r1/ripngd.conf create mode 100644 tests/topotests/all-protocol-startup/r1/show_bgp_ipv4.ref create mode 100644 tests/topotests/all-protocol-startup/r1/show_bgp_ipv6.ref create mode 100644 tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref create mode 100644 tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref create mode 100644 tests/topotests/all-protocol-startup/r1/show_ip_ospf_interface.ref create mode 100644 tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface create mode 100644 tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface.ref create mode 100644 tests/topotests/all-protocol-startup/r1/show_isis_interface_detail.ref create mode 100644 tests/topotests/all-protocol-startup/r1/show_mpls_ldp_interface.ref create mode 100644 tests/topotests/all-protocol-startup/r1/zebra.conf create mode 100644 tests/topotests/all-protocol-startup/test_all_protocol_startup.dot create mode 100644 tests/topotests/all-protocol-startup/test_all_protocol_startup.pdf create mode 100755 tests/topotests/all-protocol-startup/test_all_protocol_startup.py diff --git a/tests/topotests/all-protocol-startup/r1/bgpd.conf b/tests/topotests/all-protocol-startup/r1/bgpd.conf new file mode 100644 index 0000000000..9ef8695896 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/bgpd.conf @@ -0,0 +1,47 @@ +log file /tmp/r1-bgpd.log +! +! +router bgp 100 + bgp router-id 192.168.0.1 + bgp log-neighbor-changes + neighbor 192.168.7.10 remote-as 100 + neighbor 192.168.7.20 remote-as 200 + neighbor fc00:0:0:8::1000 remote-as 100 + neighbor fc00:0:0:8::2000 remote-as 200 + ! + address-family ipv4 unicast + network 192.168.0.0/24 + neighbor 192.168.7.10 route-map bgp-map in + neighbor 192.168.7.10 filter-list bgp-filter-v4 out + neighbor 192.168.7.20 route-map bgp-map in + neighbor 192.168.7.20 filter-list bgp-filter-v4 out + exit-address-family + ! + address-family ipv6 unicast + network fc00::/64 + neighbor fc00:0:0:8::1000 activate + neighbor fc00:0:0:8::1000 route-map bgp-map in + neighbor fc00:0:0:8::1000 filter-list bgp-filter-v6 out + neighbor fc00:0:0:8::2000 activate + neighbor fc00:0:0:8::2000 route-map bgp-map in + neighbor fc00:0:0:8::2000 filter-list bgp-filter-v6 out + exit-address-family +! +! +ip prefix-list bgp-filter-v4 description dummy-test-prefix-list +ip prefix-list bgp-filter-v4 seq 5 permit 192.168.0.0/24 +! +ipv6 prefix-list bgp-filter-v4 seq 5 permit fc00::/64 +ipv6 prefix-list bgp-filter-v6 description dummy-test-prefix-list-v6 +! +route-map bgp-map permit 10 + set community 100:100 additive + set local-preference 100 +! +route-map bgp-map permit 20 + set metric 10 + set local-preference 200 +! +line vty +! + diff --git a/tests/topotests/all-protocol-startup/r1/isisd.conf b/tests/topotests/all-protocol-startup/r1/isisd.conf new file mode 100644 index 0000000000..b63bc3f8d3 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/isisd.conf @@ -0,0 +1,21 @@ +log file /tmp/r1-isisd.log +! +debug isis events +! +! +interface r1-eth5 + ip router isis test + isis circuit-type level-1 +! +interface r1-eth6 + ipv6 router isis test + isis circuit-type level-2-only +! +! +router isis test + net 00.0001.00b0.64bc.43a0.00 + metric-style wide + log-adjacency-changes +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/ldpd.conf b/tests/topotests/all-protocol-startup/r1/ldpd.conf new file mode 100644 index 0000000000..b69007181e --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ldpd.conf @@ -0,0 +1,25 @@ +log file /tmp/r1-ldpd.log +! +debug mpls ldp event +debug mpls ldp zebra +! +! +mpls ldp + router-id 192.168.0.1 + ! + address-family ipv4 + discovery transport-address 192.168.9.1 + ! + interface r1-eth9 + ! + ! + address-family ipv6 + discovery transport-address fc00:0:0:9::1 + ! + interface r1-eth9 + ! + ! +! +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/ospf6d.conf b/tests/topotests/all-protocol-startup/r1/ospf6d.conf new file mode 100644 index 0000000000..1a14eaac77 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ospf6d.conf @@ -0,0 +1,16 @@ +log file /tmp/r1-ospf6d.log +! +debug ospf6 lsa unknown +debug ospf6 zebra +debug ospf6 interface +debug ospf6 neighbor +! +interface r1-eth4 +! +router ospf6 + router-id 192.168.0.1 + log-adjacency-changes + interface r1-eth4 area 0.0.0.0 +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/ospfd.conf b/tests/topotests/all-protocol-startup/r1/ospfd.conf new file mode 100644 index 0000000000..1a901b9643 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ospfd.conf @@ -0,0 +1,13 @@ +log file /tmp/r1-ospfd.log +! +debug ospf event +debug ospf zebra +! +router ospf + ospf router-id 192.168.0.1 + log-adjacency-changes + network 192.168.0.0/24 area 0.0.0.0 + network 192.168.3.0/24 area 0.0.0.0 +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/rip_status.ref b/tests/topotests/all-protocol-startup/r1/rip_status.ref new file mode 100644 index 0000000000..4a5255fe13 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/rip_status.ref @@ -0,0 +1,15 @@ +Routing Protocol is "rip" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: + Default version control: send version 2, receive version 2 + Interface Send Recv Key-chain + r1-eth1 2 2 + Routing for Networks: + 192.168.1.0/26 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update + Distance: (default is 120) diff --git a/tests/topotests/all-protocol-startup/r1/ripd.conf b/tests/topotests/all-protocol-startup/r1/ripd.conf new file mode 100644 index 0000000000..899bfda984 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ripd.conf @@ -0,0 +1,12 @@ +log file /tmp/r1-ripd.log +! +debug rip events +debug rip zebra +! +router rip + version 2 + network 192.168.1.0/26 +! +line vty +! + diff --git a/tests/topotests/all-protocol-startup/r1/ripng_status.ref b/tests/topotests/all-protocol-startup/r1/ripng_status.ref new file mode 100644 index 0000000000..5d67c1467a --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ripng_status.ref @@ -0,0 +1,14 @@ +Routing Protocol is "RIPng" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: + Default version control: send version 1, receive version 1 + Interface Send Recv + r1-eth2 1 1 + Routing for Networks: + fc00:0:0:2::/64 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update diff --git a/tests/topotests/all-protocol-startup/r1/ripngd.conf b/tests/topotests/all-protocol-startup/r1/ripngd.conf new file mode 100644 index 0000000000..9b1f556277 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ripngd.conf @@ -0,0 +1,11 @@ +log file /tmp/r1-ripngd.log +! +debug ripng events +debug ripng zebra +! +router ripng + network fc00:0:0:2::/64 +! +line vty +! + diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4.ref new file mode 100644 index 0000000000..3be6cd3d7b --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4.ref @@ -0,0 +1,7 @@ +BGP table version is 1, local router ID is 192.168.0.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> 192.168.0.0 0.0.0.0 0 32768 i diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6.ref new file mode 100644 index 0000000000..fffee63c6b --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6.ref @@ -0,0 +1,7 @@ +BGP table version is 1, local router ID is 192.168.0.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> fc00::/64 :: 0 32768 i diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref new file mode 100644 index 0000000000..2b1aff16cb --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref @@ -0,0 +1,21 @@ + +IPv6 Unicast Summary: +BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP table version 1 +RIB entries 1, using XXXX bytes of memory +Peers 4, using XXXX KiB of memory + +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd +fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active +fc00:0:0:8::2000 4 200 0 0 0 0 0 never Active + +Total number of neighbors 2 + +IPv6 Multicast Summary: +No IPv6 Multicast neighbor is configured + +IPv6 VPN Summary: +No IPv6 VPN neighbor is configured + +IPv6 Encap Summary: +No IPv6 Encap neighbor is configured diff --git a/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref b/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref new file mode 100644 index 0000000000..9ec43848cf --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref @@ -0,0 +1,15 @@ +BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP table version 1 +RIB entries 1, using XXXX bytes of memory +Peers 4, using XXXX KiB of memory + +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/ +PfxRcd +192.168.7.10 4 100 0 0 0 0 0 never +Active +192.168.7.20 4 200 0 0 0 0 0 never +Active +fc00:0:0:8::1000 4 100 0 0 0 0 0 never +Active +fc00:0:0:8::2000 4 200 0 0 0 0 0 never +Active diff --git a/tests/topotests/all-protocol-startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all-protocol-startup/r1/show_ip_ospf_interface.ref new file mode 100644 index 0000000000..d134fb1c69 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_ip_ospf_interface.ref @@ -0,0 +1,22 @@ +r1-eth0 is up + ifindex 2, MTU 1500 bytes, BW XX Mbit + Internet Address 192.168.0.1/24, Broadcast 192.168.0.255, Area 0.0.0.0 + MTU mismatch detection:enabled + Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 + Transmit Delay is 1 sec, State DR, Priority 1 + No backup designated router on this network + Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters + Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5 + Hello due in XX.XXXs + Neighbor Count is 0, Adjacent neighbor count is 0 +r1-eth3 is up + ifindex 5, MTU 1500 bytes, BW XX Mbit + Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0 + MTU mismatch detection:enabled + Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 + Transmit Delay is 1 sec, State DR, Priority 1 + No backup designated router on this network + Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters + Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5 + Hello due in XX.XXXs + Neighbor Count is 0, Adjacent neighbor count is 0 diff --git a/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface b/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface.ref b/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface.ref new file mode 100644 index 0000000000..6fbf40bbb8 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface.ref @@ -0,0 +1,46 @@ +lo is up, type LOOPBACK + Interface ID: 1 + OSPF not enabled on this interface +r1-eth0 is up, type BROADCAST + Interface ID: 2 + OSPF not enabled on this interface +r1-eth1 is up, type BROADCAST + Interface ID: 3 + OSPF not enabled on this interface +r1-eth2 is up, type BROADCAST + Interface ID: 4 + OSPF not enabled on this interface +r1-eth3 is up, type BROADCAST + Interface ID: 5 + OSPF not enabled on this interface +r1-eth4 is up, type BROADCAST + Interface ID: 6 + Internet Address: + inet : 192.168.4.1/26 + inet6: fc00:0:0:4::1/64 + inet6: fe80::XXXX:XXXX:XXXX:XXXX/64 + Instance ID 0, Interface MTU 1500 (autodetect: 1500) + MTU mismatch detection: enabled + Area ID 0.0.0.0, Cost 10 + State DR, Transmit Delay 1 sec, Priority 1 + Timer intervals configured: + Hello 10, Dead 40, Retransmit 5 + DR: 192.168.0.1 BDR: 0.0.0.0 + Number of I/F scoped LSAs is 1 + 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off] + 0 Pending LSAs for LSAck in Time 00:00:00 [thread off] +r1-eth5 is up, type BROADCAST + Interface ID: 7 + OSPF not enabled on this interface +r1-eth6 is up, type BROADCAST + Interface ID: 8 + OSPF not enabled on this interface +r1-eth7 is up, type BROADCAST + Interface ID: 9 + OSPF not enabled on this interface +r1-eth8 is up, type BROADCAST + Interface ID: 10 + OSPF not enabled on this interface +r1-eth9 is up, type BROADCAST + Interface ID: 11 + OSPF not enabled on this interface diff --git a/tests/topotests/all-protocol-startup/r1/show_isis_interface_detail.ref b/tests/topotests/all-protocol-startup/r1/show_isis_interface_detail.ref new file mode 100644 index 0000000000..ebf7ab50cd --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_isis_interface_detail.ref @@ -0,0 +1,28 @@ +Area test: + Interface: r1-eth5, State: Up, Active, Circuit Id: 0x1 + Type: lan, Level: L1, SNPA: XXXX.XXXX.XXXX + Level-1 Information: + Metric: 10, Active neighbors: 0 + Hello interval: 3, Holddown count: 10 (pad) + CNSP interval: 10, PSNP interval: 2 + LAN Priority: 64, is not DIS + IP Prefix(es): + 192.168.5.1/26 + IPv6 Link-Locals: + fe80::XXXX:XXXX:XXXX:XXXX/64 + IPv6 Prefixes: + fc00:0:0:5::1/64 + + Interface: r1-eth6, State: Up, Active, Circuit Id: 0x1 + Type: lan, Level: L2, SNPA: XXXX.XXXX.XXXX + Level-2 Information: + Metric: 10, Active neighbors: 0 + Hello interval: 3, Holddown count: 10 (pad) + CNSP interval: 10, PSNP interval: 2 + LAN Priority: 64, is not DIS + IP Prefix(es): + 192.168.6.1/26 + IPv6 Link-Locals: + fe80::XXXX:XXXX:XXXX:XXXX/64 + IPv6 Prefixes: + fc00:0:0:6::1/64 diff --git a/tests/topotests/all-protocol-startup/r1/show_mpls_ldp_interface.ref b/tests/topotests/all-protocol-startup/r1/show_mpls_ldp_interface.ref new file mode 100644 index 0000000000..c6bb01c34b --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_mpls_ldp_interface.ref @@ -0,0 +1,3 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r1-eth9 ACTIVE xx:xx:xx 5/15 0 +ipv6 r1-eth9 ACTIVE xx:xx:xx 5/15 0 diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf new file mode 100644 index 0000000000..afb28e0768 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/zebra.conf @@ -0,0 +1,72 @@ +log file /tmp/r1-zebra.log +! +hostname r1 +! +interface r1-eth0 + description to sw0 - no routing protocol + ip address 192.168.0.1/24 + ipv6 address fc00:0:0:0::1/64 +! +interface r1-eth1 + description to sw1 - RIP interface + ip address 192.168.1.1/26 + ipv6 address fc00:0:0:1::1/64 + no link-detect +! +interface r1-eth2 + description to sw2 - RIPng interface + ip address 192.168.2.1/26 + ipv6 address fc00:0:0:2::1/64 + no link-detect +! +interface r1-eth3 + description to sw3 - OSPFv2 interface + ip address 192.168.3.1/26 + ipv6 address fc00:0:0:3::1/64 + no link-detect +! +interface r1-eth4 + description to sw4 - OSPFv3 interface + ip address 192.168.4.1/26 + ipv6 address fc00:0:0:4::1/64 + no link-detect +! +interface r1-eth5 + description to sw5 - ISIS IPv4 interface + ip address 192.168.5.1/26 + ipv6 address fc00:0:0:5::1/64 + no link-detect +! +interface r1-eth6 + description to sw6 - ISIS IPv6 interface + ip address 192.168.6.1/26 + ipv6 address fc00:0:0:6::1/64 + no link-detect +! +interface r1-eth7 + description to sw7 - BGP IPv4 interface + ip address 192.168.7.1/26 + ipv6 address fc00:0:0:7::1/64 + no link-detect +! +interface r1-eth8 + description to sw8 - BGP IPv6 interface + ip address 192.168.8.1/26 + ipv6 address fc00:0:0:8::1/64 + no link-detect +! +interface r1-eth9 + description to sw9 - LDP interface + ip address 192.168.9.1/26 + ipv6 address fc00:0:0:9::1/64 + + no link-detect +! +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.dot b/tests/topotests/all-protocol-startup/test_all_protocol_startup.dot new file mode 100644 index 0000000000..f39f8f87b8 --- /dev/null +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.dot @@ -0,0 +1,61 @@ +## GraphViz file for test_all_protocol_startup +## +## Color coding: +######################### +## Main FRR: #f08080 red +## No protocol: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #33ff99 light green +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +## LDP IPv4 #fedbe2 light pink +##### Colors (see http://www.color-hex.com/) + +graph test_all_protocol_startup { + + // title + labelloc="t"; + label="Test Topologoy All Protocols Startup"; + + ###################### + # Routers + ###################### + + # Main FRR Router with all protocols + R1 [shape=doubleoctagon, label="R1 FRR\nMain Router", fillcolor="#f08080", style=filled]; + + ###################### + # Network Lists + ###################### + + SW0_STUB [label="SW0 (no protocol)\n192.168.1.0/24\nfc00:0:0:0::/64", fillcolor="#d0e0d0", style=filled]; + + SW1_RIP [label="SW1 RIP\n192.168.1.0/24\nfc00:0:0:1::/64", fillcolor="#19e3d9", style=filled]; + SW2_RIPNG [label="SW2 RIPng\n192.168.2.0/24\nfc00:0:0:2::/64", fillcolor="#fcb314", style=filled]; + SW3_OSPF [label="SW3 OSPFv2\n192.168.3.0/24\nfc00:0:0:3::/64", fillcolor="#32b835", style=filled]; + SW4_OSPFV3 [label="SW4 OSPFv3\n192.168.4.0/24\nfc00:0:0:4::/64", fillcolor="#19e3d9", style=filled]; + SW5_ISIS_V4 [label="SW5 ISIS IPv4\n192.168.5.0/24\nfc00:0:0:5::/64", fillcolor="#33ff99", style=filled]; + SW6_ISIS_V6 [label="SW6 ISIS IPv6\n192.168.6.0/24\nfc00:0:0:6::/64", fillcolor="#9a81ec", style=filled]; + SW7_BGP_V4 [label="SW7 BGP IPv4\n192.168.7.0/24\nfc00:0:0:7::/64", fillcolor="#eee3d3", style=filled]; + SW8_BGP_V6 [label="SW8 BGP IPv6\n192.168.8.0/24\nfc00:0:0:8::/64", fillcolor="#fdff00", style=filled]; + SW9_LDP [label="SW9 LDP\n192.168.9.0/24\nfc00:0:0:9::/64", fillcolor="#fedbe2", style=filled]; + + ###################### + # Network Connections + ###################### + R1 -- SW0_STUB [label = "eth0\n.1\n::1"]; + R1 -- SW1_RIP [label = "eth1\n.1\n::1"]; + R1 -- SW2_RIPNG [label = "eth2\n.1\n::1"]; + R1 -- SW3_OSPF [label = "eth3\n.1\n::1"]; + R1 -- SW4_OSPFV3 [label = "eth4\n.1\n::1"]; + R1 -- SW5_ISIS_V4 [label = "eth5\n.1\n::1"]; + R1 -- SW6_ISIS_V6 [label = "eth6\n.1\n::1"]; + R1 -- SW7_BGP_V4 [label = "eth7\n.1\n::1"]; + R1 -- SW8_BGP_V6 [label = "eth8\n.1\n::1"]; + R1 -- SW9_LDP [label = "eth9\n.1\n::1"]; + +} diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.pdf b/tests/topotests/all-protocol-startup/test_all_protocol_startup.pdf new file mode 100644 index 0000000000000000000000000000000000000000..23f69bcddf813e0f60f7a8f93cb384212bc3bba4 GIT binary patch literal 21760 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 literal 0 HcmV?d00001 diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py new file mode 100755 index 0000000000..ea70d4f53d --- /dev/null +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -0,0 +1,785 @@ +#!/usr/bin/env python + +# +# test_all_protocol_startup.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_all_protocol_startup.py: Test of all protocols at same time + +""" + +import os +import re +import sys +import difflib +import pytest +from time import sleep + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from functools import partial + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from lib import topotest + +fatal_error = "" + + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "All Protocol Startup Test" + + def build(self, **_opts): + + # Setup Routers + router = {} + # + # Setup Main Router + router[1] = topotest.addRouter(self, 'r1') + # + + # Setup Switches + switch = {} + # + for i in range(0, 10): + switch[i] = self.addSwitch('sw%s' % i, cls=topotest.LegacySwitch) + self.addLink(switch[i], router[1], intfName2='r1-eth%s' % i ) + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + global topo, net + global fatal_error + + print("\n\n** %s: Setup Topology" % module.__name__) + print("******************************************\n") + + print("Cleanup old Mininet runs") + os.system('sudo mn -c > /dev/null 2>&1') + os.system('sudo rm /tmp/r* > /dev/null 2>&1') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + topo = NetworkTopo() + + net = Mininet(controller=None, topo=topo) + net.start() + + if net['r1'].get_routertype() != 'frr': + fatal_error = "Test is only implemented for FRR" + sys.stderr.write('\n\nTest is only implemented for FRR - Skipping\n\n') + pytest.skip(fatal_error) + + # Starting Routers + # + # Main router + for i in range(1, 2): + net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ripd', '%s/r%s/ripd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ripngd', '%s/r%s/ripngd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ospfd', '%s/r%s/ospfd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i)) + net['r%s' % i].loadConf('isisd', '%s/r%s/isisd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('bgpd', '%s/r%s/bgpd.conf' % (thisDir, i)) + if net['r%s' % i].daemon_available('ldpd'): + # Only test LDPd if it's installed and Kernel >= 4.5 + net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i)) + net['r%s' % i].startRouter() + + # For debugging after starting Quagga/FRR daemons, uncomment the next line + # CLI(net) + + +def teardown_module(module): + global net + + print("\n\n** %s: Shutdown Topology" % module.__name__) + print("******************************************\n") + + # End - Shutdown network + net.stop() + + +def test_router_running(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check if FRR/Quagga is running on each Router node") + print("******************************************\n") + sleep(5) + + # Starting Routers + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_error_messages_vtysh(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check for error messages on VTYSH") + print("******************************************\n") + + failures = 0 + for i in range(1, 2): + # + # First checking Standard Output + # + + # VTYSH output from router + vtystdout = net['r%s' % i].cmd('vtysh -c "show version" 2> /dev/null').rstrip() + + # Fix newlines (make them all the same) + vtystdout = ('\n'.join(vtystdout.splitlines()) + '\n').rstrip() + # Drop everything starting with "FRRouting X.xx" message + vtystdout = re.sub(r"FRRouting [0-9]+.*", "", vtystdout, flags=re.DOTALL) + + if (vtystdout != ''): + sys.stderr.write('\nr%s created some spurious VTYSH start StdOut messages:\n%s\n' % (i, vtystdout)) + failures += 1 + else: + print("r%s StdOut ok" % i) + + # + # Second checking Standard Error + # + + # VTYSH StdErr output from router + vtystderr = net['r%s' % i].cmd('vtysh -c "show version" > /dev/null').rstrip() + + # Fix newlines (make them all the same) + vtystderr = ('\n'.join(vtystderr.splitlines()) + '\n').rstrip() + # # Drop everything starting with "FRRouting X.xx" message + # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL) + + if (vtystderr != ''): + sys.stderr.write('\nr%s created some spurious VTYSH start StdErr messages:\n<%s>\n' % (i, vtystderr)) + failures += 1 + else: + print("r%s StdErr ok" % i) + + assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_error_messages_daemons(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check for error messages in daemons") + print("******************************************\n") + + error_logs = "" + + for i in range(1, 2): + log = net['r%s' % i].getStdErr('ripd') + if log: + error_logs += "r%s RIPd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('ripngd') + if log: + error_logs += "r%s RIPngd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('ospfd') + if log: + error_logs += "r%s OSPFd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('ospf6d') + if log: + error_logs += "r%s OSPF6d StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('isisd') + # ISIS shows debugging enabled status on StdErr + # Remove these messages + log = re.sub(r"^IS-IS .* debugging is on.*", "", log).rstrip() + if log: + error_logs += "r%s ISISd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('bgpd') + if log: + error_logs += "r%s BGPd StdErr Output:\n" % i + error_logs += log + if (net['r%s' % i].daemon_available('ldpd')): + log = net['r%s' % i].getStdErr('ldpd') + if log: + error_logs += "r%s LDPd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('zebra') + if log: + error_logs += "r%s Zebra StdErr Output:\n" + error_logs += log + + if error_logs: + sys.stderr.write('Failed check for StdErr Output on daemons:\n%s\n' % error_logs) + + assert error_logs == "", "Daemons report errors to StdErr" + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_converge_protocols(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Waiting for protocols convergence") + print("******************************************\n") + + # Not really implemented yet - just sleep 60 secs for now + sleep(60) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + ## CLI(net) + + +def test_rip_status(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing RIP status") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/rip_status.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip rip status" 2> /dev/null').rstrip() + # Drop time in next due + actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual IP RIP status", + tofile="expected IP RIP status")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed IP RIP status check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_ripng_status(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing RIPng status") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/ripng_status.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null').rstrip() + # Mask out Link-Local mac address portion. They are random... + actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual) + # Drop time in next due + actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual IPv6 RIPng status", + tofile="expected IPv6 RIPng status")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed IPv6 RIPng status check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_ospfv2_interfaces(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing OSPFv2 interfaces") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_ip_ospf_interface.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip ospf interface" 2> /dev/null').rstrip() + # Mask out Bandwidth portion. They may change.. + actual = re.sub(r"BW [0-9]+ Mbit", "BW XX Mbit", actual) + # Drop time in next due + actual = re.sub(r"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual SHOW IP OSPF INTERFACE", + tofile="expected SHOW IP OSPF INTERFACE")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW IP OSPF INTERFACE check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_isis_interfaces(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing ISIS interfaces") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_isis_interface_detail.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show isis interface detail" 2> /dev/null').rstrip() + # Mask out Link-Local mac address portion. They are random... + actual = re.sub(r"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual) + # Mask out SNPA mac address portion. They are random... + actual = re.sub(r"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual SHOW ISIS INTERFACE DETAIL", + tofile="expected SHOW ISIS OSPF6 INTERFACE DETAIL")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_summary(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing BGP Summary") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_bgp_summary.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show bgp summary" 2> /dev/null').rstrip() + # Mask out "using XXiXX bytes" portion. They are random... + actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual) + # Mask out "using XiXXX KiB" portion. They are random... + actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual SHOW BGP SUMMARY", + tofile="expected SHOW BGP SUMMARY")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW BGP SUMMARY check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW SHOW BGP SUMMARY failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_ipv6_summary(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing BGP IPv6 Summary") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_bgp_ipv6_summary.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null').rstrip() + # Mask out "using XXiXX bytes" portion. They are random... + actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual) + # Mask out "using XiXXX KiB" portion. They are random... + actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual SHOW BGP IPv6 SUMMARY", + tofile="expected SHOW BGP IPv6 SUMMARY")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_ipv4(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing BGP IPv4") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_bgp_ipv4.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip() + # Remove summary line (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + actual = actual.rstrip() + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual SHOW BGP IPv4", + tofile="expected SHOW BGP IPv4")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW BGP IPv4 check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_ipv6(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify RIP Status + print("\n\n** Verifing BGP IPv6") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_bgp_ipv6.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip() + # Remove summary line (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + actual = actual.rstrip() + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual SHOW BGP IPv6", + tofile="expected SHOW BGP IPv6")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW BGP IPv6 check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + + +def test_mpls_interfaces(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + # Skip if no LDP installed or old kernel + if (net['r1'].daemon_available('ldpd') == False): + pytest.skip("No MPLS or kernel < 4.5") + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + # Verify OSPFv3 Routing Table + print("\n\n** Verifing MPLS Interfaces") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_mpls_ldp_interface.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp interface" 2> /dev/null').rstrip() + # Mask out Timer in Uptime + actual = re.sub(r" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = ''.join(difflib.context_diff(actual, expected, + fromfile="actual MPLS LDP interface status", + tofile="expected MPLS LDP interface status")) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed MPLS LDP Interface status Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + if failures>0: + fatal_error = "MPLS LDP Interface status failed" + + assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_shutdown_check_stderr(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Verifing unexpected STDERR output from daemons") + print("******************************************\n") + + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + print("SKIPPED (Disabled) - TOPOTESTS_CHECK_STDERR undefined\n") + pytest.skip('Skipping test for Stderr output and memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + net['r1'].stopRouter() + + log = net['r1'].getStdErr('ripd') + print("\nRIPd StdErr Log:\n" + log) + log = net['r1'].getStdErr('ripngd') + print("\nRIPngd StdErr Log:\n" + log) + log = net['r1'].getStdErr('ospfd') + print("\nOSPFd StdErr Log:\n" + log) + log = net['r1'].getStdErr('ospf6d') + print("\nOSPF6d StdErr Log:\n" + log) + log = net['r1'].getStdErr('isisd') + print("\nISISd StdErr Log:\n" + log) + log = net['r1'].getStdErr('bgpd') + print("\nBGPd StdErr Log:\n" + log) + if (net['r1'].daemon_available('ldpd')): + log = net['r1'].getStdErr('ldpd') + print("\nLDPd StdErr Log:\n" + log) + log = net['r1'].getStdErr('zebra') + print("\nZebra StdErr Log:\n" + log) + + +if __name__ == '__main__': + + setLogLevel('info') + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) + retval = pytest.main(["-s"]) + sys.exit(retval) From e341b1927d7ae99e477ea28c7d460f70cb3f4297 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 8 Apr 2017 14:52:41 -0700 Subject: [PATCH 046/384] ripng-topo1: Fix duplicate IP (Thanks Renato!) and documentation typos --- tests/topotests/ripng-topo1/r2/zebra.conf | 2 +- .../ripng-topo1/test_ripng_topo1.dot | 12 ++++++------ .../ripng-topo1/test_ripng_topo1.pdf | Bin 18639 -> 18609 bytes 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/topotests/ripng-topo1/r2/zebra.conf b/tests/topotests/ripng-topo1/r2/zebra.conf index cb3ff37fbc..0e90c2810e 100644 --- a/tests/topotests/ripng-topo1/r2/zebra.conf +++ b/tests/topotests/ripng-topo1/r2/zebra.conf @@ -9,7 +9,7 @@ interface r2-eth0 ! interface r2-eth1 description to sw3 - RIPng interface - ipv6 address fc00:6::2/62 + ipv6 address fc00:6::1/62 no link-detect ! ip forwarding diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.dot b/tests/topotests/ripng-topo1/test_ripng_topo1.dot index f5d32a02a1..7d66a2a306 100644 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.dot +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.dot @@ -46,14 +46,14 @@ graph test_ripng_topo1 { ###################### # Network Connections ###################### - R1 -- SW1_R1_stub [label = "eth0\n.1\n::1"]; + R1 -- SW1_R1_stub [label = "r1-eth0\n::1"]; # RIPng Network - R1 -- SW2_R1_R2 [label = "eth2\n::1"]; - SW2_R1_R2 -- R2 [label = "eth0\n::2"]; - R2 -- SW3_R2_R3 [label = "eth1\n::1"]; - SW3_R2_R3 -- R3 [label = "eth1\n::2"]; - R3 -- SW4_R3 [label = "eth0\n::1"]; + R1 -- SW2_R1_R2 [label = "r1-eth1\n::1"]; + SW2_R1_R2 -- R2 [label = "r2-eth0\n::2"]; + R2 -- SW3_R2_R3 [label = "r2-eth1\n::1"]; + SW3_R2_R3 -- R3 [label = "r3-eth1\n::2"]; + R3 -- SW4_R3 [label = "r3-eth0\n::1"]; SW4_R3 -- Net_R3_remote [label = ":10"]; } diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.pdf b/tests/topotests/ripng-topo1/test_ripng_topo1.pdf index f998c4697d7d9e0a8b759e24466664047efbf2a0..cb1adde239c7c324e1b17b0544e28b6f4db8fa7a 100644 GIT binary patch delta 14407 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 delta 14492 zcmaib18m?=yKZgUcDJ^xctF74D4{ zE-VU)Q{8e2vZflo#HSy<)MekA@98feH4+gnKU>HO7%u--owT0mbH48^!wj0+WT3LGvBT5@K%*I`QKgA>wf_SDb0svvEre~7K^wwvys>(6nK!hMdVFd1&@(yrDOj#j z(5)P3%gNa*TnjrGf8fo|^20D{wwBv_A*@0M)jPgnoW(Qg+jX*E2Lx0tqrVjD8N$h& zNNnApv}DJ)#0K7Fv=CN&YoV3Q`jdHDHNK9}<9J9sfL!eR^VJq1R{uPgEP=Llk@M$t z4%0hghbsbXI$hNgjxvpClV3kn$WYBr20W6jEP6=n?2k7;8cm%ckhIXW0J24DX0%~G zrrHwu5J->#dLOVblKO?}Y3ijg=_AfQ&)WXYf=y;j zC}S0R0R0ep5C(}UF(|2dI7>EnT)3}l9C4Bwt|_MaTfjJ?W(ZUlhvGUDyrw*!upFKt zdGo4QsUyh@*cBT%eEUX z2WSIfkWKhoYV7i{s^Ppwwh7iiYTX;YQq2&gus9QgE||*;fyrTciH_Ia7BuvUWn7$) zK~E<6HsiuiWqp{1FTM#KSW>#qi~N&%ldPOz0f#EFjy&HzzLVsvl;FNMprpOhPObIm zkCvtO;d$Yd?81y&Ijh&*kU(?^VUU-_8^GuuRN|#MjXsHDgaGDZ)mUwp9~~7vjoP?2 z=;BIkreX;0L~)%J0^0)zRjBI=-&4}LOV)eObvvKAiPj1;x(v9XS-&e-Ws zXLX5bSjx=8jR1$lh5^qjW3fw4BssbHx=Cc_N7pA23W~IZrzYpZ6DVw-%$9hOOh(aV zd17>f87Q0PR^<)C&95Sj13J%vB(hHpxW{Mx-)rP4pZkKlMFE&qK~j8rfN^h<_1!1E zPJ#|b_)mINr8OSVJ$YYv#Tz69R^;59TqOQiq7>a?>g^+`mSy*OZq8R;OA~$PtgfdO zP(;6kik@2Hu8h$o@q};Dm*QW`CiKIKAeSqBsm>Rdmeq$v&rLd)@lLk7qz5YsrIFFg zdRZ>R?jZcsF*fZD%C94Lz<`2unMQ+@%>v|U>- z31?<+>f-8bW@PuTo`bP990v(A$-guUH#_}I>8t{5=u%#MOjrU z;T}Bzf|-Psquvt(7xcftG|Xi%cJ4SvvV=q|6rf9{{zt*=QQU%d=SVw)PF)O;D^^po+!(<3*e_fIw5Yk>0Moq5KsLKrqn|t{O81R?) zr_C#$E3f&pwf6S21s=Cgm$C+<&7nf6s3uap9}yZ4)grgkGtjfAgW&ky&R92$K{(Tg zHb9l8+F1D=Ol^Bri}T%KVaE+`(Ae#G@*@-N;q3RY@)Qvf+L&?@BnF+v-7{r<0B-NC zO1IOaVk_0}{a)=uBgTig6ZzM++DCbE@*39=2~wq2r>_|8HZ#OcI>&i(bmQZ|+sFGBW4T0!}#Z0mY4#4%SBuZSAX&V>CI?vw7txHvK`fYc_>Ds&3GDQFfr7&+HxAj?Q6)H zoX+tqW0@T%mO~Kk9Cn=&4@XYCHNM*k_g;Ktg>kx1OpDi-fN^RE8j}z9M?cpi6{zly z4b!vwJ&l1DkfG4dkHfl|yg-D5@4bysh9UL56Fv~s? zS1q65f;++?!bpBRciqT-Fy}lab0f*jBoHOkt8zVI!h02A)3{~fM4cUgMaopg?L5zZ zb@z;VAcp6iL9j()<&%!=lm6tL4y=2pR|-zvJ)5%=mQ^Q;eX}aI*~+T2`bW~MN^`1y zLB)u%loU~_$lmG7vSG}>GZ(co7U70j#j|*LqR0iD5s&RYQEXF88cVb#Pin36AmVmYu%WmqKJwbQa_o5W8=G zMtOKfy@Iw1qbPskI)&Ua;F7=14&drwe~WwyzE9dJM!yA*X%vv@3LqN9^^W;-E122U z@5S7?{-#)<>qA1{?eJyGvxXhox4*S{o&Hct%6}a8Q!m+DGI&BBM)Q$_ZH^k-HpuOT-RjPhl?HY z$G;$_uX~z1tSs-zfl>m0nlucu-xvt6xI7F2u77A7&S{MM4L)I&Dv1uwsIj7 zK6;YtLa?s~eO*nrz@rQHATh2Eoq77mO-r4VX>lO>}#F~U||&fPJ|Jf--K?-`Flq| zl_Nai31nP-e9}E7y>ORdrXouG&nj+Waz5L6`2n=#(}Lo&n^tG-R>iVFMDG9iRSSs%vVfU`?-Tmy zH$gzjrDi);0OOp;aKbo4tuqr!6IxLd4MgIT0vMhCz7bRfzfLelmi9gP*8+?3c^lxk zasiZ2$})+|6W@D&{#xA1kS4;D_7P+S0fAStM74t9S(G*q&y^@VMXruREZ3(KT2~OC zkf|6!?pL0%e8QQ%%h~M$c9L`*;bcM@gezVDr5%b!BUftcpsUT`YzboHaZ7U60=h&= zyA!wugi2A3Jp8=BJolWhnC`un@igGur+~1_?BofOD>YrNMh&(>ME5jI!MKD*F3(IL z=Jm!Ub2`@y@k~xFQMaD~p<5IYAz`osv=W1L-1(K*wj^?X=!n!zxnq_{zXw*f4D@N4 z(xm0#Ny>~qv}%GPbsIvqW^h$t+(xjzM0Njz&a*Xw#y(>QltaJQb-60Mohi5b8E}F) zBSUnu39`(7^5uDQs^5TY`Ap*pR+Tc-4Sono@F%_0Zh=QzL1qHM-O%;?WOw#h5&&iE zBV(B9Mz0#R1aHH;6m2)+Z!XwB`F_thv6wRhb5s*nITKp&4E_!oOe269+We8IFL#xP z%of%f^WtY``V)(oHXFCo*me8l94PogEGPzX2r@dd*(nQlV9&#~#5xm^@mr!d`)t7{ zln6Y5nE7jWPxJ~Bl}q;6!)@aTpB-A=E7VhbZS}4Zo-aNIza6Qtu`y;DptB9~6 zBYGC|9?Vnd1LT9o1-d;*Z`?PAP}RHll8%v)kroM~nqH7^jmPu&Bt}9(6mWQ-!DlT- zpApBoL}14^zjk(wl06p)O34*c$Tx8$4AmD1%>G`S=g=*7?03uvMhKCH#F;A&wY+uS%*oul5dJU^{eG7%sI?==L0fd zQBKVGsWxd}gPG=ACR5B`gSv*_Is4sfT`)MmXBi7SDc(>t$9n~MArpe)ec=qu7+ zpKES{^zsfi;t}{R4_qb9<4L`JT>DjTHdRb&^!Ri=iVpYG30(TvjY0^Lf<7dULNG%s zihbAD6|Vfy5hl!4pUdyufoW>Qz7UZTBP6uHGEhzxENJhXJbikiK!@CD<8CSO3t)iM zds*2(;L&XAXKUYGA02R>xqx)7_x#~FIw^*xy&$Rlk>ZAZ0(@qJElPIfF)?Wd+CiRk zc;60#Sqg_S+dRbvm z4r2Y)*`XTg|kky5a7= zd{urAy-FMdfM4+gP3H%G5cCIcL5-{VN`8hFbtg<1XP>yeOgMItrw zd?Fe8S`xe7La}zq0bvkh(v2k$W$8m2U*EAB89-N51dc*gwfdGpJO7g09j))LvpJ0t z8H76E%5tM8o0Mp_6;mVjr!968^sR1w1}yA%BpcQe?|ZYp4537i5Hi;t(X-4U&&yck-$7iZWL?k4%LsaCK!cY2hy zL?LAh48U>4@5r~9Cc2%{+7tnH53&WO1jMPNUq~ZAYlZRXaYX;X8YPi-*zxkiE6rR{ zK#Bk}$eU+YfeL1Ron7hrH9=p~7*!n$4j!!Vot25Sx({DreXU=x!R23)7*(wc^A1Wa zSg*QbG`de;F?|o)xy)~Lw<cc@DqGPz)@${KBOJ|FV04J?q>gl zr)eP)snD^6x<@GHt*?7D!A}-qa_pb9+aUOVW>lOW%=L+b$3&KWVG0Z?H_(jMkQ1M%oG z(BQ{Bpx=7t_Dk+EPq6sP*n0wmFQ!vLsi-B|#S!`$3l!EO310Q7#9<~ZJ%IDizMBvl z!yZ|uHc*f^=D6VzcoTW*Sr1Kx(AB>Mz;dUD)HV?nUW==P9yJ_@B5=h?NGGRB%_oW} zI-;}G-SuIAMyEC1-j*KUsz}_b48p(A?nx1G97^8q@xairYIPbA2d_^fA^5!fY`VJ| z4msJ@r7-C^`Iw!)hWDdZqanjxWlfScY2p^`uB-(}*730#tsj%Zbh83x< z^ny{>DD1Ny496h(5(^sTcuKr4KDl-bT57Z@XjZ}h=+sTYme_K|J5r~@8h4OIy(Iot% z>TZW*L=F+464&2A1ZGS>3i_kRflq%u!cz>&M=cQ!$})J>w9yn1;@vS35JHJM8B9O> z)_6zh@fq-OyMwtIu>PSWcG5 z0qk>_vt2n@O*&lyY0Z3j-HwjZ9FuBLn!$#X&{b;WN_D>detInj6dNgwcA{!MNzg~4 z!x71RdDe052xQ9vZ>e9gW=qkcgq-$4ccUFA4%r1S)l8&Ry_T0Z6p}-h zfn3yY6pfIj;y5euEdnI?BWaOCeQn#Xx-T5O{O8ZY@p1aEmbY3i zz@P)RdyA{Ful9BCs^Xcqnfv2~ zPe5!78t|LkK&d=>X3XdfHjISXt&vhkE2}(wY#vGMOOg&mV)mXkX zDWyBK>GnQb{%Y~(Y>#7{*t_d_cYswgWF`zuhIqCb>`J9(?<%%KV?K3}2FE|217`mL zDk@|M?@tjfWnTl>`vAV-rRqLk46T)VsXCHT3`K4rAR6)#mX}JZ`;n+XN{d8eImniX zR$8}PWqAhtsX4uVAKAj%;n!A-# z&=zj~{(ZcUYunrKfTI4VDVopz;JG^n@vt7>0gpY=N9NX;{dd@V7h2B*^ka_%-1l%N zdK|sF+6cA3KXdqgW7|O?kVr%p^&WIz^4*=|1i96brng zRj6AOr(nyi0OMOU3D)hLMw1U8kqHtD!UQVl zRtd`(TCbJUj6zG_S#J-Hh$hJIwdcd%V-G@f*`03^5#hy_X9Dj*Oebi?tfVeZGRwWA zI_3(gs@^Zt5w|j92?}<=hgYipvN(K4_#m-1{~9`&*NPca29K}f4fNp8sIAj%)8AaY zfM3&ey#{zp(5yZ!w*mA5X5v!K3A>!m<-imYH6`r_7(TbKRbP87rj7_LK~(sb-nUt} zS(uT5kz^H46!{!F0Dw1ljL362)mxSPm!5adsNGvCVtd zv3=vKGHWKl7jnv|Wa04{0>2VeTe>;v)S8}rrG~&eC}}1e+uh_K1#iJZ-}PA#yO+91ilRIOsL9F0?q!n`vyfbv?gL z{Mjb(y?*&zV+j5G{BT43J{-C66Kwre{c=O^qu{iiI3GVjMV(=z)@UgJdYC@rm2-pp ze*XdA%jI%esNU_W)MR^oZ5tw^!qmst<37fN>jPq<0P~OnTW!eY6<{qNLn`T4EmBLW ztyr?J?>^{md8Kb*`R0pA4~rvKs6W;x;)8CwwURx;E?p}A_A#lIy{@eCt~u&Y6kXJeo|?&;+_ZLhhH^0 z;QV5#uv!yw&|Vyq48Pi3I}OLSDYB=N;FP14w#k49xHHQLSc7XIeN<@1n19X^Wfgvl zn@>$VjYF{hkOvRK3o(zR@-L2r+A_t>$N4b>X2!0Ka|OGC!C5?NX{5VXZ1wBMNT79^ zsOEh}APcxb@+%Pip+hCNCdxpvJ0iwSh;_y}+gxd0GH)QG)oUxwZ{!&GPA`%Wtu z=!(-x!tk{a!y}?dtLvV$h^ety%B$<5tI^_1=ZCCRs!S=Y)Rq{4!sWqlAEN@>6d&SJ zrZ(e*(J)6Yk*jOM-I*Y2%73#M;O`l8j)S&|AStT0z*Ov8 zZit;_`xfI_g9sw4(=30|f^^k?wVQIIcdo6y6xHFO*FVCuJR%kB;5LiDbk8p?Q?7#< z$MiJ@g9>!HEeH|`;l5^+CY5v9ihGxfKqoLfdDNG*A%WO?IK*)`C#)>7-- zaSYhFB=EC{tXlcB2piG8^5MeY(2vo+Gsg}j*;@C(Te%bh44<1rrM(g0tQ;jd?5lo-@MG!_5Y0GJhQr5ef!{c*78U#XaO2d~zPAX78 zP666u#01wV%WtOle3dMYs(j?5xuiS4@vNqDZvP}^ZFn#m7pj0XmRbfaPhn-@9=lRs zQaBT9K(4O{sT*Pnmvm) zW<0MAmX_Va|FG;h z2lo`oKo*C-imr8lWuoo=d*e_v6s%vKE9&ySwr zSMvRRbZk0~go9v-jId0BF0knpz5}$N9gDP}n>t6NQpaXZKwA&7;)y; z^gu9kBANTkf>~-950dB04@-S=RMP*BD%dgPgEPf;p$u2S$NJoPEL}gAh**a@%g|8a z2m~kYeC76~;BCzF=&;m*9=|JJ7>`>*mrM_QRE@*eDmq({aA>Pj3!`YC+5miJSZ(t=IO4 z_LEcB4v7xIt!JbYKhifIlobYV;mY=U#m9a~cSN5T@+6NlBp&vLv0yFH;0|S!vCPTR zQA(*zZJ_8gp2pT|lhgJ4rveG(wS0t%?h}Xi-0iKTnMtl3@+>N!!?&}}Z5>r@e9S@B zUU0v0VmW7mgScfOGlF_7{Jt?OVZ#MC;&sWc2Jf?olmb%BdLz|O?x>m+ zU%mR~0koLx4=AMVjqHUrX+U!JM zr~2pTTmavaeKWg($rMU@I-wTl$7EUa)7jy*_0QXlK7$iccdAto$;`j&YP%^g z`ZZ;&>)kh7InAN(gTN@$c5{oDww>PonVCy_weR&NEG(a(bPm)5)GOk9_5{jEBId=r z#Gp+>0&gU;$^tk}v^B$kBrUju~p$dz8MOO$nZ3RWJy29x!a$w2!bE8$}3L1);yxwfgqu04 zN|AK<+q6!$6k{${rciaYOt%V+Zx+PC@hqoaGIN(W`83m57SlBZDwAVsO;cVvh!9ql zhy9`-qf(pw^Gs2#)}>bk~XF3l+ry#v^qcscqo5zjCURrn*mb~dv& zYS=xNVBi6fB8GpzCXSHty&6n@;pmQ_2h%P)6o-{hX2#5p=^L<8K@w6r7#@{dV8$Sz zPGVT2KRPGH&XwrIE(u-0j#S1BY39+;8>d|Ac+u%=(O8`ZC+Ae`fjUJ?0za+pb?X5{ zwU6ECFE?&!9fvb{UC~sWr4PGH(1_%)f9J=J093~f)_bI*#cPyv*to|fP#zXq62&UO z73?Yc&NufZiJtR4#+f-BZ{D6!J{h7fP0g_Rqj-Bmn=%C9UZq7RH5v3ie;tg&41VXs zNaXd1xy^1HPK+rfTI8pHSM?D1@I3O_{h08=vWml{H7ob<@l_{vUG!8{3p2+5giqeMuI{py*@lV6*DYeXH9=~pa>7Q7 zA~rSo#p4NbiFVk&C>SwH+*-hJg2lLu62g85KhWhZo`GFTIMQm-jV_2fHDDYvFSd5MI0&X&t?G(zcOu}+ z`6sQaO5<|2C!|sPJ{xzL)j{;_H7u_o${jFs~x&)TiUkJ7J19_AEkbZMO1sbFhN59hWV5VL@r1W{C3sM zPbJr}>KQ9k2uOZKUp~Dm2Du;L_M(Gj} zm6r)*%mR3>``+Fc&%3?`2*=I;oawpAWe~SqDQMnk2MBifgm*J0j2(PC0yK!b?iB21 z89x>Yx%8f&40@tr-z~4NyrHOdk^C7X-AjBK9vF``N;L4R*bT<*j;fU$W*s1V3nx)cSQMiuyz~vLym{aapLe zz}~G#!}h4fIaJfxc9JMkLsvKyV?*sd2d10qiPoTW-vAGP-yL}b#a22oESS+3BPF;c z#fUAu)jaRdkV7y0fSc`)oz1XZvfP$mt z-rQN53|$*_Ky-l1e!~b-4{oWPvRo9}U4R}gw6XXJ)j_y7&MjAKA2F1b5I&2x?W<2y z1)SF^Z%l>?4Ve+;<;|dDg(*(^hZQ3t1V5-nO@Woxa<<^M4s|ku$xH`C%2*K!4)_XH zcAZbZAi`1IP6F;aAPp}*hjRg3!?dy7(2mn_H|0Ov43ArU7QG$G_UIig*^v8>%5SCs zHYGe-wiqe^I@%%95E?9Z>4<42CQ_ZTifkIiH zfVIECZv*MI_upD}`IIKBHavz#-yE}zYl``NJjLA;{UNe_ZGxW1{rq7RII^Jdop(OA zK>L)eekm9Ok&VL0XnHU!b>b5J8j3M1iPw_vr6JX%+uXKDzQK3-lshR8s3;2Gs6ayG za_glKz_gunMs19fKSy1b`EQ3V%C15zpuR=ep1D%B-Jgn~!?R83Nj#uK6@IpYKbk-F zMXNFlrEF?>@0|1|tWIIMjp5lCcnM}+8MM>b5@_}S*k5FoIh%0l@cmZQ4C@qXDzjd% zoS$`B*-A&1)!I)1H6!Qqw40}1SAhHQfTGtrccaKvRIpcaDu0?B{8xRmaUTbha#l}u zje{HjcFf3j(qd}Wywj~!Yv`s)3(Zv2iA%R~5RkBKAiWP31h93*7K|R=K#phVS{W!l z5U~Mzr^=U6(BtF#BB9yp;%t$YOL>+BY2$x7iOgtHoBIFK@aoe_jL+{t`mdHC{% z8uj$|ObqmZH7CpZf-%jk9R2gy$rQgVwE|MJLY9nzBiU5LaR%xI7leC|`b;;xK?)%Y zR%Y9$-gyC$!ZAfzqIGMKjI+(mc3!2H#_=1td=xAz&40TM9eSao!Y-byw9V#vcr2^h z^GLDYP`e*pBajPbH`?lt+F&D%-R3Ydaax7@aq3)pUfuV$BP4nMeLr2B0~LCPmgFfB z>!bt>S*02Sw#-e=T4Mzp?$w(!hkNs^Zu9T$FQcnL%%dkI#|2UXWeGFHE0s%=0{v|O zIzL+KpFQFax;<8c=RSB?`8|zd@0Vr|9cxJSAg|>3P@AosGf$uOYBi?{@g(&aKHeDm ziygfUq@ILX)i?8Va8;Av<=) z%+{;tJw>S$FB4(*-x!bx)jf95o9C*O`%FGN=?L*lC9VxTvoUmBtz#z zQa{C{Ca>W(gY@cJMvY}Z>Q;6JvrYy&mB1y3?H7K@V{8mP#yoqh5A%pl*}Ut}TkH80 zwj*<%leCM#JfR{0q1d5(MnyShlVwoka#=7RvgqM;P}+g>(&4s#mnvl&n#$jFN6R)rqdHwGTk3$qK*~89CIyy}ij@vW()Yj*<(LKlwmF|Py z^(EV`<40yUYECSst~Wa1!iHyS=t*Pp>oRWdH0SFYRyU2BpJL?I2IaA~?j&(Rg+cZ0 zY5fX`7*2>l09}CiFv*CMmsVB?t?!bQU}sQ0ivCTXX7Q}-o!Rp4)XX0$h1nLgctDju zI{B9SWr*bXpk&ZVtx0*j$$u)~qc;;eRSHlZATuhM6GQ@RA;v?$kDNiTWHHZB z%0UplS0hP*h&Kcq8^R5)z#NI9Fe}joU>FH1JO54EkghRPnbR0JHe8C~Nj~_Fnj9=M z0r~n*0;ra7#2yT0oenpVzvZ~f-3&smI;xwoe=}96wUs&S2=>zd*son{QQfR-E7_iT zEl&^|KBf-u8`%fKn||MqjviuMKJ9Ue)YcDbybYc%hb!1jHV&f8sCd^jxWfn^i1a`^ zHOQoUj|JL*t>6!flkw^eTD}oiDZV1QY3R_q5HQ%q*C~JJW*tQ9@b+|= zJvpW?+E2mySsS^nN`+%5ePcKsAEMgPWMbE~!d#pbAVw85oE(LuB9sTc8zxR!MA?ms zTN@m1bH)ygFN||!sAVj+FN|^LIH`5O8pBQ_>|P1No*tk)%CrfmO_~8J&Ta2VOp)0O zB1^JoV;@k6%C|En*R8c%wuSyC^=4(#S>Ru@EN8g{gx)TcW8zK?aJtq&oH&MF0bed( zX@MJI37m$Rzbm-Is^>I9pv$Bp7r$fK&q_H7$vS{OipEH>-#Bo;V$$hvf<8j2krd+i z_Z^crh`K3s!!u(l{L1iz z>%R#h;r~=&dW5otxQFR$(_mt8yfIe9v24#>!_%C^6$XcY%mInVW7Vty5LdyZzlj#EW$J5Kj}rs~V(fOMLN{=yyR zhk4xAEtQ=yvG8M6a?AD;Renj@Z9o?4%rL%Khqwwj2P&~SStNC%~3vPQ9 zlgW$t%^IG(tJ+il#pUwk{NxE)Jyc$}(NVWm_y9@%P~~he0|7`4 zoUmRtwqKw&mtd?oGbs1GZk}jRa%-rjEm5KwDM26M@Ft7a_oDk z2(9jel*Q~EIxwh(2!|P;z@YaKVIU}p?115xgMy==t8Zn-M=i}Efmeuf)cgR4V??nc zsR}~NGbL8U;lk;USWoYdd*|QKW&tXT%6exfmF*h!;E(0g@M>gxfInBnt4mlpnGMuE z_=!dzHr}6^F0sEOCZQ*DiyffbrEuTnF%YL~}__yNG zM^ID2+D-lV%`;{8TW?J7cRLz2TDP<%HHBk?ZW>L>6T~?JXFK8}gat0z?^_@!w{A5r zS|OA+FipNaQVJEOxwQe8@lH)of;rEQ%C_v@9z2;m_bF>jWsiPmqG@bhi@dmp(hxFS z`~2Wiz%eOKKv19G4Nf!c0t3g43+E<@XVg<4Qk4A4$|==xfl_5axaq97D1;sZFh!H$yQt*TkjFE$LP249ta7xXE{zDo~Vx+HqRFWj?9 zLc(te>$Iiwy?Oa*P+=ElCNfI_5gO0S3p+70=P4n|-iE=Dg#Lvip63@*UlUU6QiIhK z1tAkVUu8c74x8%LvVeZJ zWuv~Z!5J6Jrt;YwUBDjJr&MdV3G%o+lzob!mVd|CdDvJJjwPr7_Wu}SW#;^+(*J)h z!OqRY_3s$R|H5Ns;bi@H9y>SJf4IcK%<}(i0RPQT4tAb@Li?YFIk;H=-9Z*EZkGQA zV`KZbx&QDux&H&>VP*dB81z5pSh#pN640cC47p9X|MAQCpJ0tRjLnQpj7>PXc}z^% vc+7dsxy;yD1mXDqzZ4QZ5 Date: Mon, 10 Apr 2017 21:07:02 -0700 Subject: [PATCH 047/384] all-protocol-startup: Add option to skip currently broken checks and relax BGP check Signed-off-by: Martin Winter --- .../r1/show_bgp_ipv6_summary.ref | 13 --- .../r1/show_ip_bgp_summary.ref | 15 ++-- .../test_all_protocol_startup.py | 81 +++++++++++++++---- 3 files changed, 71 insertions(+), 38 deletions(-) diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref index 2b1aff16cb..6777cd9fc3 100644 --- a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref @@ -1,5 +1,3 @@ - -IPv6 Unicast Summary: BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 BGP table version 1 RIB entries 1, using XXXX bytes of memory @@ -8,14 +6,3 @@ Peers 4, using XXXX KiB of memory Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active fc00:0:0:8::2000 4 200 0 0 0 0 0 never Active - -Total number of neighbors 2 - -IPv6 Multicast Summary: -No IPv6 Multicast neighbor is configured - -IPv6 VPN Summary: -No IPv6 VPN neighbor is configured - -IPv6 Encap Summary: -No IPv6 Encap neighbor is configured diff --git a/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref b/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref index 9ec43848cf..4f0ac1c910 100644 --- a/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref +++ b/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref @@ -3,13 +3,8 @@ BGP table version 1 RIB entries 1, using XXXX bytes of memory Peers 4, using XXXX KiB of memory -Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/ -PfxRcd -192.168.7.10 4 100 0 0 0 0 0 never -Active -192.168.7.20 4 200 0 0 0 0 0 never -Active -fc00:0:0:8::1000 4 100 0 0 0 0 0 never -Active -fc00:0:0:8::2000 4 200 0 0 0 0 0 never -Active +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd +192.168.7.10 4 100 0 0 0 0 0 never Active +192.168.7.20 4 200 0 0 0 0 0 never Active +fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active +fc00:0:0:8::2000 4 200 0 0 0 0 0 never Active diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index ea70d4f53d..b8baba38df 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -263,6 +263,12 @@ def test_error_messages_daemons(): if error_logs: sys.stderr.write('Failed check for StdErr Output on daemons:\n%s\n' % error_logs) + # Ignoring the issue if told to ignore (ie not yet fixed) + if (error_logs != ""): + if (os.environ.get('BAMBOO_TOPOTESTS_ISSUE_349') == "IGNORE"): + sys.stderr.write('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n') + pytest.skip('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349') + assert error_logs == "", "Daemons report errors to StdErr" # For debugging after starting FRR/Quagga daemons, uncomment the next line @@ -299,7 +305,6 @@ def test_rip_status(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify RIP Status print("\n\n** Verifing RIP status") print("******************************************\n") failures = 0 @@ -348,7 +353,6 @@ def test_ripng_status(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify RIP Status print("\n\n** Verifing RIPng status") print("******************************************\n") failures = 0 @@ -399,7 +403,6 @@ def test_ospfv2_interfaces(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify RIP Status print("\n\n** Verifing OSPFv2 interfaces") print("******************************************\n") failures = 0 @@ -432,6 +435,12 @@ def test_ospfv2_interfaces(): else: print("r%s ok" % i) + # Ignoring the issue if told to ignore (ie not yet fixed) + if (failures != 0): + if (os.environ.get('BAMBOO_TOPOTESTS_ISSUE_348') == "IGNORE"): + sys.stderr.write('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n') + pytest.skip('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348') + assert failures == 0, "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff) # For debugging after starting FRR/Quagga daemons, uncomment the next line @@ -448,7 +457,6 @@ def test_isis_interfaces(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify RIP Status print("\n\n** Verifing ISIS interfaces") print("******************************************\n") failures = 0 @@ -497,12 +505,11 @@ def test_bgp_summary(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify RIP Status print("\n\n** Verifing BGP Summary") print("******************************************\n") failures = 0 for i in range(1, 2): - refTableFile = '%s/r%s/show_bgp_summary.ref' % (thisDir, i) + refTableFile = '%s/r%s/show_ip_bgp_summary.ref' % (thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -510,27 +517,51 @@ def test_bgp_summary(): expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) # Actual output from router - actual = net['r%s' % i].cmd('vtysh -c "show bgp summary" 2> /dev/null').rstrip() + actual = net['r%s' % i].cmd('vtysh -c "show ip bgp summary" 2> /dev/null').rstrip() # Mask out "using XXiXX bytes" portion. They are random... actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual) # Mask out "using XiXXX KiB" portion. They are random... actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual) + # + # Remove extra summaries which exist with newer versions + # + # Remove summary lines (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + # Remove IPv4 Unicast Summary (Title only) + actual = re.sub(r'IPv4 Unicast Summary:', '', actual) + # Remove IPv4 Multicast Summary (all of it) + actual = re.sub(r'IPv4 Multicast Summary:', '', actual) + actual = re.sub(r'No IPv4 Multicast neighbor is configured', '', actual) + # Remove IPv4 VPN Summary (all of it) + actual = re.sub(r'IPv4 VPN Summary:', '', actual) + actual = re.sub(r'No IPv4 VPN neighbor is configured', '', actual) + # Remove IPv4 Encap Summary (all of it) + actual = re.sub(r'IPv4 Encap Summary:', '', actual) + actual = re.sub(r'No IPv4 Encap neighbor is configured', '', actual) + # Remove Unknown Summary (all of it) + actual = re.sub(r'Unknown Summary:', '', actual) + actual = re.sub(r'No Unknown neighbor is configured', '', actual) + # Strip empty lines + actual = actual.lstrip() + actual = actual.rstrip() + # # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW BGP SUMMARY", - tofile="expected SHOW BGP SUMMARY")) + fromfile="actual SHOW IP BGP SUMMARY", + tofile="expected SHOW IP BGP SUMMARY")) # Empty string if it matches, otherwise diff contains unified diff if diff: - sys.stderr.write('r%s failed SHOW BGP SUMMARY check:\n%s\n' % (i, diff)) + sys.stderr.write('r%s failed SHOW IP BGP SUMMARY check:\n%s\n' % (i, diff)) failures += 1 else: print("r%s ok" % i) - assert failures == 0, "SHOW SHOW BGP SUMMARY failed for router r%s:\n%s" % (i, diff) + assert failures == 0, "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (i, diff) # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -546,7 +577,6 @@ def test_bgp_ipv6_summary(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify RIP Status print("\n\n** Verifing BGP IPv6 Summary") print("******************************************\n") failures = 0 @@ -564,6 +594,30 @@ def test_bgp_ipv6_summary(): actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual) # Mask out "using XiXXX KiB" portion. They are random... actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual) + # + # Remove extra summaries which exist with newer versions + # + # Remove summary lines (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + # Remove IPv4 Unicast Summary (Title only) + actual = re.sub(r'IPv6 Unicast Summary:', '', actual) + # Remove IPv4 Multicast Summary (all of it) + actual = re.sub(r'IPv6 Multicast Summary:', '', actual) + actual = re.sub(r'No IPv6 Multicast neighbor is configured', '', actual) + # Remove IPv4 VPN Summary (all of it) + actual = re.sub(r'IPv6 VPN Summary:', '', actual) + actual = re.sub(r'No IPv6 VPN neighbor is configured', '', actual) + # Remove IPv4 Encap Summary (all of it) + actual = re.sub(r'IPv6 Encap Summary:', '', actual) + actual = re.sub(r'No IPv6 Encap neighbor is configured', '', actual) + # Remove Unknown Summary (all of it) + actual = re.sub(r'Unknown Summary:', '', actual) + actual = re.sub(r'No Unknown neighbor is configured', '', actual) + # Strip empty lines + actual = actual.lstrip() + actual = actual.rstrip() + # # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) @@ -595,7 +649,6 @@ def test_bgp_ipv4(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify RIP Status print("\n\n** Verifing BGP IPv4") print("******************************************\n") failures = 0 @@ -644,7 +697,6 @@ def test_bgp_ipv6(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify RIP Status print("\n\n** Verifing BGP IPv6") print("******************************************\n") failures = 0 @@ -698,7 +750,6 @@ def test_mpls_interfaces(): thisDir = os.path.dirname(os.path.realpath(__file__)) - # Verify OSPFv3 Routing Table print("\n\n** Verifing MPLS Interfaces") print("******************************************\n") failures = 0 From 1026c19adbefe06d9e6ea041ba4d23a92763f2de Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Mon, 10 Apr 2017 21:58:54 -0700 Subject: [PATCH 048/384] all-protocol-startup: Fix pref commit - bamboo prefix is lower case Signed-off-by: Martin Winter --- .../all-protocol-startup/test_all_protocol_startup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index b8baba38df..ad0e6d2032 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -265,7 +265,7 @@ def test_error_messages_daemons(): # Ignoring the issue if told to ignore (ie not yet fixed) if (error_logs != ""): - if (os.environ.get('BAMBOO_TOPOTESTS_ISSUE_349') == "IGNORE"): + if (os.environ.get('bamboo_TOPOTESTS_ISSUE_349') == "IGNORE"): sys.stderr.write('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n') pytest.skip('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349') @@ -437,7 +437,7 @@ def test_ospfv2_interfaces(): # Ignoring the issue if told to ignore (ie not yet fixed) if (failures != 0): - if (os.environ.get('BAMBOO_TOPOTESTS_ISSUE_348') == "IGNORE"): + if (os.environ.get('bamboo_TOPOTESTS_ISSUE_348') == "IGNORE"): sys.stderr.write('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n') pytest.skip('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348') From 798fb5934d6f45b7ce69d18e4579b3f15012a3ad Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Mon, 24 Apr 2017 16:12:55 -0700 Subject: [PATCH 049/384] all-protocol-startup: Fix bad assert in case of failed vtysh output test Signed-off-by: Martin Winter --- .../all-protocol-startup/test_all_protocol_startup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index ad0e6d2032..ca6cac4b61 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -181,10 +181,11 @@ def test_error_messages_vtysh(): if (vtystdout != ''): sys.stderr.write('\nr%s created some spurious VTYSH start StdOut messages:\n%s\n' % (i, vtystdout)) - failures += 1 else: print("r%s StdOut ok" % i) + assert vtystdout == '', "Vtysh StdOut Output check failed for router r%s:\n%s" % (i, vtystdout) + # # Second checking Standard Error # @@ -199,11 +200,10 @@ def test_error_messages_vtysh(): if (vtystderr != ''): sys.stderr.write('\nr%s created some spurious VTYSH start StdErr messages:\n<%s>\n' % (i, vtystderr)) - failures += 1 else: print("r%s StdErr ok" % i) - assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) + assert vtystderr == '', "Vtysh StdErr Output check failed for router r%s:\n%s" % (i, vtystderr) # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) From f6c44df78f5350a711254c449425d8912ee99a45 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 26 Apr 2017 05:30:50 -0700 Subject: [PATCH 050/384] ospf6-topo1: Update to ignore the proto type in linux kernel table Signed-off-by: Martin Winter --- .../topotests/ospf6-topo1/r1/ip_6_address.ref | 26 ++++++++--------- .../topotests/ospf6-topo1/r2/ip_6_address.ref | 26 ++++++++--------- .../topotests/ospf6-topo1/r3/ip_6_address.ref | 28 +++++++++---------- .../topotests/ospf6-topo1/r4/ip_6_address.ref | 26 ++++++++--------- .../topotests/ospf6-topo1/test_ospf6_topo1.py | 2 ++ 5 files changed, 55 insertions(+), 53 deletions(-) diff --git a/tests/topotests/ospf6-topo1/r1/ip_6_address.ref b/tests/topotests/ospf6-topo1/r1/ip_6_address.ref index 2f7e246c15..e0600a5ba1 100644 --- a/tests/topotests/ospf6-topo1/r1/ip_6_address.ref +++ b/tests/topotests/ospf6-topo1/r1/ip_6_address.ref @@ -1,13 +1,13 @@ -fc00:1:1:1::/64 dev r1-stubnet proto kernel metric 256 pref medium -fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium -fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium -fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium -fc00:a:a:a::/64 dev r1-sw5 proto kernel metric 256 pref medium -fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium -fc00:1111:1111:1111::/64 via fc00:1:1:1::1234 dev r1-stubnet proto zebra metric 20 pref medium -fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium -fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium -fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto zebra metric 20 pref medium -unreachable fe80::/64 dev lo proto kernel metric 256 error -101 pref medium -fe80::/64 dev r1-stubnet proto kernel metric 256 pref medium -fe80::/64 dev r1-sw5 proto kernel metric 256 pref medium +fc00:1:1:1::/64 dev r1-stubnet proto XXXX metric 256 pref medium +fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r1-sw5 proto XXXX metric 256 pref medium +fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:1111:1111:1111::/64 via fc00:1:1:1::1234 dev r1-stubnet proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +unreachable fe80::/64 dev lo proto XXXX metric 256 error -101 pref medium +fe80::/64 dev r1-stubnet proto XXXX metric 256 pref medium +fe80::/64 dev r1-sw5 proto XXXX metric 256 pref medium diff --git a/tests/topotests/ospf6-topo1/r2/ip_6_address.ref b/tests/topotests/ospf6-topo1/r2/ip_6_address.ref index 5dd539f038..24bc071d12 100644 --- a/tests/topotests/ospf6-topo1/r2/ip_6_address.ref +++ b/tests/topotests/ospf6-topo1/r2/ip_6_address.ref @@ -1,13 +1,13 @@ -fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium -fc00:2:2:2::/64 dev r2-stubnet proto kernel metric 256 pref medium -fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium -fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium -fc00:a:a:a::/64 dev r2-sw5 proto kernel metric 256 pref medium -fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium -fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium -fc00:2222:2222:2222::/64 via fc00:2:2:2::1234 dev r2-stubnet proto zebra metric 20 pref medium -fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium -fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto zebra metric 20 pref medium -unreachable fe80::/64 dev lo proto kernel metric 256 error -101 pref medium -fe80::/64 dev r2-stubnet proto kernel metric 256 pref medium -fe80::/64 dev r2-sw5 proto kernel metric 256 pref medium +fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 dev r2-stubnet proto XXXX metric 256 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r2-sw5 proto XXXX metric 256 pref medium +fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 via fc00:2:2:2::1234 dev r2-stubnet proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +unreachable fe80::/64 dev lo proto XXXX metric 256 error -101 pref medium +fe80::/64 dev r2-stubnet proto XXXX metric 256 pref medium +fe80::/64 dev r2-sw5 proto XXXX metric 256 pref medium diff --git a/tests/topotests/ospf6-topo1/r3/ip_6_address.ref b/tests/topotests/ospf6-topo1/r3/ip_6_address.ref index ce54ceced9..eda7c4fc9b 100644 --- a/tests/topotests/ospf6-topo1/r3/ip_6_address.ref +++ b/tests/topotests/ospf6-topo1/r3/ip_6_address.ref @@ -1,14 +1,14 @@ -fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto zebra metric 20 pref medium -fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto zebra metric 20 pref medium -fc00:3:3:3::/64 dev r3-stubnet proto kernel metric 256 pref medium -fc00:4:4:4::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto zebra metric 20 pref medium -fc00:a:a:a::/64 dev r3-sw5 proto kernel metric 256 pref medium -fc00:b:b:b::/64 dev r3-sw6 proto kernel metric 256 pref medium -fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto zebra metric 20 pref medium -fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto zebra metric 20 pref medium -fc00:3333:3333:3333::/64 via fc00:3:3:3::1234 dev r3-stubnet proto zebra metric 20 pref medium -fc00:4444:4444:4444::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto zebra metric 20 pref medium -unreachable fe80::/64 dev lo proto kernel metric 256 error -101 pref medium -fe80::/64 dev r3-stubnet proto kernel metric 256 pref medium -fe80::/64 dev r3-sw5 proto kernel metric 256 pref medium -fe80::/64 dev r3-sw6 proto kernel metric 256 pref medium +fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 dev r3-stubnet proto XXXX metric 256 pref medium +fc00:4:4:4::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r3-sw5 proto XXXX metric 256 pref medium +fc00:b:b:b::/64 dev r3-sw6 proto XXXX metric 256 pref medium +fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 via fc00:3:3:3::1234 dev r3-stubnet proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium +unreachable fe80::/64 dev lo proto XXXX metric 256 error -101 pref medium +fe80::/64 dev r3-stubnet proto XXXX metric 256 pref medium +fe80::/64 dev r3-sw5 proto XXXX metric 256 pref medium +fe80::/64 dev r3-sw6 proto XXXX metric 256 pref medium diff --git a/tests/topotests/ospf6-topo1/r4/ip_6_address.ref b/tests/topotests/ospf6-topo1/r4/ip_6_address.ref index e7307f0088..a9c597756d 100644 --- a/tests/topotests/ospf6-topo1/r4/ip_6_address.ref +++ b/tests/topotests/ospf6-topo1/r4/ip_6_address.ref @@ -1,13 +1,13 @@ -fc00:1:1:1::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium -fc00:2:2:2::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium -fc00:3:3:3::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium -fc00:4:4:4::/64 dev r4-stubnet proto kernel metric 256 pref medium -fc00:a:a:a::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium -fc00:b:b:b::/64 dev r4-sw6 proto kernel metric 256 pref medium -fc00:1111:1111:1111::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium -fc00:2222:2222:2222::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium -fc00:3333:3333:3333::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto zebra metric 20 pref medium -fc00:4444:4444:4444::/64 via fc00:4:4:4::1234 dev r4-stubnet proto zebra metric 20 pref medium -unreachable fe80::/64 dev lo proto kernel metric 256 error -101 pref medium -fe80::/64 dev r4-stubnet proto kernel metric 256 pref medium -fe80::/64 dev r4-sw6 proto kernel metric 256 pref medium +fc00:1:1:1::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 dev r4-stubnet proto XXXX metric 256 pref medium +fc00:a:a:a::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 dev r4-sw6 proto XXXX metric 256 pref medium +fc00:1111:1111:1111::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 via fc00:4:4:4::1234 dev r4-stubnet proto XXXX metric 20 pref medium +unreachable fe80::/64 dev lo proto XXXX metric 256 error -101 pref medium +fe80::/64 dev r4-stubnet proto XXXX metric 256 pref medium +fe80::/64 dev r4-sw6 proto XXXX metric 256 pref medium diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 963e49e719..10256bc4a6 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -342,6 +342,8 @@ def test_linux_ipv6_kernel_routingTable(): # Mask out Link-Local mac addresses for ll in linklocals: actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0]) + # Mask out protocol name or number + actual = re.sub(r" proto [0-9a-z]+ ", " proto XXXX ", actual) # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines())).splitlines(1) From dd4eca4d974c290c48a14bb2dad4d67f0883279b Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 26 Apr 2017 08:51:50 -0400 Subject: [PATCH 051/384] lib: Fix kernel version parsing When we have a kernel sub version > 10 the float conversion of the kernel version causes 4.10 to be less than 4.5 Get the kernel version in groups on . and do comparison that way Signed-off-by: Donald Sharp --- tests/topotests/lib/topotest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 221910b13f..a8b3784b0f 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -157,9 +157,10 @@ class Router(Node): if not os.path.isfile('/usr/lib/%s/ldpd' % self.routertype): print("LDP Test, but no ldpd compiled or installed") return "LDP Test, but no ldpd compiled or installed" - kernel_version = re.search(r'([0-9]+\.[0-9]+).*', platform.release()) + kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) + if kernel_version: - if float(kernel_version.group(1)) < 4.5: + if float(kernel_version.group(1)) < 4 and float(kernel.version.group(2)) < 5: print("LDP Test need Linux Kernel 4.5 minimum") return "LDP Test need Linux Kernel 4.5 minimum" # Add mpls modules to kernel if we use LDP From 8b2e59e94317d1834f6da66665a8de5378381256 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 26 Apr 2017 12:15:39 -0400 Subject: [PATCH 052/384] Fix tests to handle new output The show commands for bgp now have a bit more data associated with labeled unicast routes. Signed-off-by: Donald Sharp --- .../all-protocol-startup/test_all_protocol_startup.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index ca6cac4b61..4ec1bf2df7 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -542,6 +542,10 @@ def test_bgp_summary(): # Remove Unknown Summary (all of it) actual = re.sub(r'Unknown Summary:', '', actual) actual = re.sub(r'No Unknown neighbor is configured', '', actual) + + actual = re.sub(r'IPv4 labeled-unicast Summary:', '', actual) + actual = re.sub(r'No IPv4 labeled-unicast neighbor is configured', '', actual) + # Strip empty lines actual = actual.lstrip() actual = actual.rstrip() @@ -614,6 +618,11 @@ def test_bgp_ipv6_summary(): # Remove Unknown Summary (all of it) actual = re.sub(r'Unknown Summary:', '', actual) actual = re.sub(r'No Unknown neighbor is configured', '', actual) + + # Remove Labeled Unicast Summary (all of it) + actual = re.sub(r'IPv6 labeled-unicast Summary:', '', actual) + actual = re.sub(r'No IPv6 labeled-unicast neighbor is configured', '', actual) + # Strip empty lines actual = actual.lstrip() actual = actual.rstrip() From b2764f904e352f05566c422fb0e661f9ec10b7ba Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 26 Apr 2017 12:18:58 -0400 Subject: [PATCH 053/384] Spell Verifying correctly Signed-off-by: Donald Sharp --- .../test_all_protocol_startup.py | 20 +++++++++---------- tests/topotests/bgp_multiview_topo1/README.md | 2 +- .../test_bgp_multiview_topo1.py | 4 ++-- tests/topotests/ldp-topo1/test_ldp_topo1.py | 16 +++++++-------- tests/topotests/ospf6-topo1/README.md | 2 +- .../topotests/ospf6-topo1/test_ospf6_topo1.py | 6 +++--- .../topotests/ripng-topo1/test_ripng_topo1.py | 8 ++++---- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index 4ec1bf2df7..8c2bbcae30 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -305,7 +305,7 @@ def test_rip_status(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing RIP status") + print("\n\n** Verifying RIP status") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -353,7 +353,7 @@ def test_ripng_status(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing RIPng status") + print("\n\n** Verifying RIPng status") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -403,7 +403,7 @@ def test_ospfv2_interfaces(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing OSPFv2 interfaces") + print("\n\n** Verifying OSPFv2 interfaces") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -457,7 +457,7 @@ def test_isis_interfaces(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing ISIS interfaces") + print("\n\n** Verifying ISIS interfaces") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -505,7 +505,7 @@ def test_bgp_summary(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing BGP Summary") + print("\n\n** Verifying BGP Summary") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -581,7 +581,7 @@ def test_bgp_ipv6_summary(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing BGP IPv6 Summary") + print("\n\n** Verifying BGP IPv6 Summary") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -658,7 +658,7 @@ def test_bgp_ipv4(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing BGP IPv4") + print("\n\n** Verifying BGP IPv4") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -706,7 +706,7 @@ def test_bgp_ipv6(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing BGP IPv6") + print("\n\n** Verifying BGP IPv6") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -759,7 +759,7 @@ def test_mpls_interfaces(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing MPLS Interfaces") + print("\n\n** Verifying MPLS Interfaces") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -806,7 +806,7 @@ def test_shutdown_check_stderr(): if (fatal_error != ""): pytest.skip(fatal_error) - print("\n\n** Verifing unexpected STDERR output from daemons") + print("\n\n** Verifying unexpected STDERR output from daemons") print("******************************************\n") if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: diff --git a/tests/topotests/bgp_multiview_topo1/README.md b/tests/topotests/bgp_multiview_topo1/README.md index 4ae6c1e699..b9982d4900 100644 --- a/tests/topotests/bgp_multiview_topo1/README.md +++ b/tests/topotests/bgp_multiview_topo1/README.md @@ -112,7 +112,7 @@ BGP is expected to converge on each view within 60s total time. Convergence is v and expecting 11 routes seen in the last column for each peer. (Each peer sends 11 routes) -### Verifing BGP Routing Tables +### Verifying BGP Routing Tables Routing table is verified by running diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 6fef5d2284..ccfd63b983 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -264,7 +264,7 @@ def test_bgp_routingTable(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing BGP Routing Tables") + print("\n\n** Verifying BGP Routing Tables") print("******************************************\n") failures = 0 for i in range(1, 2): @@ -323,7 +323,7 @@ def test_shutdown_check_stderr(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing unexpected STDERR output from daemons") + print("\n\n** Verifying unexpected STDERR output from daemons") print("******************************************\n") net['r1'].stopRouter() diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 956e62addf..667f07a655 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -217,7 +217,7 @@ def test_mpls_interfaces(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing MPLS Interfaces") + print("\n\n** Verifying MPLS Interfaces") print("******************************************\n") failures = 0 for i in range(1, 5): @@ -326,7 +326,7 @@ def test_mpls_ldp_discovery(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing MPLS LDP discovery") + print("\n\n** Verifying MPLS LDP discovery") print("******************************************\n") failures = 0 for i in range(1, 5): @@ -376,7 +376,7 @@ def test_mpls_ldp_neighbor(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing MPLS LDP neighbor") + print("\n\n** Verifying MPLS LDP neighbor") print("******************************************\n") failures = 0 for i in range(1, 5): @@ -440,7 +440,7 @@ def test_mpls_ldp_binding(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing MPLS LDP binding") + print("\n\n** Verifying MPLS LDP binding") print("******************************************\n") failures = 0 for i in range(1, 5): @@ -512,7 +512,7 @@ def test_zebra_ipv4_routingTable(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing Zebra IPv4 Routing Table") + print("\n\n** Verifying Zebra IPv4 Routing Table") print("******************************************\n") failures = 0 for i in range(1, 5): @@ -563,7 +563,7 @@ def test_mpls_table(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing MPLS table") + print("\n\n** Verifying MPLS table") print("******************************************\n") failures = 0 for i in range(1, 5): @@ -628,7 +628,7 @@ def test_linux_mpls_routes(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing Linux Kernel MPLS routes") + print("\n\n** Verifying Linux Kernel MPLS routes") print("******************************************\n") failures = 0 for i in range(1, 5): @@ -728,7 +728,7 @@ def test_shutdown_check_stderr(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing unexpected STDERR output from daemons") + print("\n\n** Verifying unexpected STDERR output from daemons") print("******************************************\n") for i in range(1, 5): diff --git a/tests/topotests/ospf6-topo1/README.md b/tests/topotests/ospf6-topo1/README.md index 2369ab22f7..28f68e8fa5 100644 --- a/tests/topotests/ospf6-topo1/README.md +++ b/tests/topotests/ospf6-topo1/README.md @@ -115,7 +115,7 @@ OSPFv3 is expected to converge on each view within 60s total time. Convergence i and checking for "Full" neighbor status in the output. An additional 15 seconds after the full converge is waited for routes to populate before the following routing table checks are executed -### Verifing OSPFv3 Routing Tables +### Verifying OSPFv3 Routing Tables Routing table is verified by running diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 10256bc4a6..6be7f6fad1 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -270,7 +270,7 @@ def test_ospfv3_routingTable(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing OSPFv3 Routing Table") + print("\n\n** Verifying OSPFv3 Routing Table") print("******************************************\n") failures = 0 for i in range(1, 5): @@ -318,7 +318,7 @@ def test_linux_ipv6_kernel_routingTable(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify Linux Kernel Routing Table - print("\n\n** Verifing Linux IPv6 Kernel Routing Table") + print("\n\n** Verifying Linux IPv6 Kernel Routing Table") print("******************************************\n") failures = 0 @@ -384,7 +384,7 @@ def test_shutdown_check_stderr(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing unexpected STDERR output from daemons") + print("\n\n** Verifying unexpected STDERR output from daemons") print("******************************************\n") for i in range(1, 5): diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py index f40a241333..2493108221 100755 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -188,7 +188,7 @@ def test_ripng_status(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify RIP Status - print("\n\n** Verifing RIPng status") + print("\n\n** Verifying RIPng status") print("******************************************\n") failures = 0 for i in range(1, 4): @@ -239,7 +239,7 @@ def test_ripng_routes(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify RIPng Status - print("\n\n** Verifing RIPng routes") + print("\n\n** Verifying RIPng routes") print("******************************************\n") failures = 0 for i in range(1, 4): @@ -291,7 +291,7 @@ def test_zebra_ipv6_routingTable(): thisDir = os.path.dirname(os.path.realpath(__file__)) # Verify OSPFv3 Routing Table - print("\n\n** Verifing Zebra IPv6 Routing Table") + print("\n\n** Verifying Zebra IPv6 Routing Table") print("******************************************\n") failures = 0 for i in range(1, 4): @@ -342,7 +342,7 @@ def test_shutdown_check_stderr(): thisDir = os.path.dirname(os.path.realpath(__file__)) - print("\n\n** Verifing unexpected STDERR output from daemons") + print("\n\n** Verifying unexpected STDERR output from daemons") print("******************************************\n") net['r1'].stopRouter() From dd43120e8ee38250f0c49c8b334bf52d8705862c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 26 Apr 2017 14:44:56 -0400 Subject: [PATCH 054/384] Actually fix version comparison Signed-off-by: Donald Sharp --- tests/topotests/lib/topotest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index a8b3784b0f..2fed37f86e 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -160,7 +160,8 @@ class Router(Node): kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) if kernel_version: - if float(kernel_version.group(1)) < 4 and float(kernel.version.group(2)) < 5: + if float(kernel_version.group(1)) < 4 or + (float(kernel_version.group(1)) == 4 and float(kernel.version.group(2)) < 5): print("LDP Test need Linux Kernel 4.5 minimum") return "LDP Test need Linux Kernel 4.5 minimum" # Add mpls modules to kernel if we use LDP From c63b6f86f07516f95cacc8fd07b31b67b777a6b9 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 26 Apr 2017 13:22:34 -0700 Subject: [PATCH 055/384] lib: Fix version check in previous kernel compare Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 2fed37f86e..9fe7c2c617 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -160,8 +160,8 @@ class Router(Node): kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) if kernel_version: - if float(kernel_version.group(1)) < 4 or - (float(kernel_version.group(1)) == 4 and float(kernel.version.group(2)) < 5): + if (float(kernel_version.group(1)) < 4 or + (float(kernel_version.group(1)) == 4 and float(kernel.version.group(2)) < 5)): print("LDP Test need Linux Kernel 4.5 minimum") return "LDP Test need Linux Kernel 4.5 minimum" # Add mpls modules to kernel if we use LDP @@ -249,9 +249,10 @@ class Router(Node): if not os.path.isfile('/usr/lib/%s/%s' % (self.routertype, daemon)): return False if (daemon == 'ldpd'): - kernel_version = re.search(r'([0-9]+\.[0-9]+).*', platform.release()) + kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) if kernel_version: - if float(kernel_version.group(1)) < 4.5: + if (float(kernel_version.group(1)) < 4 or + (float(kernel_version.group(1)) == 4 and float(kernel.version.group(2)) < 5)): return False else: return False From e9125d92862f681970c958e7ba9473f2857235cc Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 26 Apr 2017 13:35:48 -0700 Subject: [PATCH 056/384] lib: Fix another typo on kernel compare Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 9fe7c2c617..7a6ffb69f6 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -161,7 +161,7 @@ class Router(Node): if kernel_version: if (float(kernel_version.group(1)) < 4 or - (float(kernel_version.group(1)) == 4 and float(kernel.version.group(2)) < 5)): + (float(kernel_version.group(1)) == 4 and float(kernel_version.group(2)) < 5)): print("LDP Test need Linux Kernel 4.5 minimum") return "LDP Test need Linux Kernel 4.5 minimum" # Add mpls modules to kernel if we use LDP @@ -252,7 +252,7 @@ class Router(Node): kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) if kernel_version: if (float(kernel_version.group(1)) < 4 or - (float(kernel_version.group(1)) == 4 and float(kernel.version.group(2)) < 5)): + (float(kernel_version.group(1)) == 4 and float(kernel_version.group(2)) < 5)): return False else: return False From 50c40bdebb8c989e3cfec93554721029cda0c90f Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 26 Apr 2017 19:54:25 -0700 Subject: [PATCH 057/384] Fix memory leak detection and reporting which accidentally was dropped a month ago Signed-off-by: Martin Winter --- tests/topotests/README.md | 36 +++++++++++- .../test_all_protocol_startup.py | 25 ++++++++- .../test_bgp_multiview_topo1.py | 22 +++++++- tests/topotests/ldp-topo1/test_ldp_topo1.py | 21 ++++++- tests/topotests/lib/topotest.py | 56 ++++++++++++++++++- .../topotests/ospf6-topo1/test_ospf6_topo1.py | 22 +++++++- .../topotests/ripng-topo1/test_ripng_topo1.py | 21 ++++++- 7 files changed, 193 insertions(+), 10 deletions(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index ce494d49eb..ee099ea34a 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -81,8 +81,8 @@ And create frr User and frrvty group as follows: py.test -s -v --tb=no -All test_* scripts in subdirectories are detected and executed (unless disabled in -`pytest.ini` file) +All test_* scripts in subdirectories are detected and executed (unless +disabled in `pytest.ini` file) `--tb=no` disables the python traceback which might be irrelevant unless the test script itself is debugged @@ -101,6 +101,38 @@ For the simulated topology, see the description in the python file If you need to clear the mininet setup between tests (if it isn't cleanly shutdown), then use the `mn -c` command to clean up the environment +#### (Optional) StdErr log from daemos after exit + +To enable the reporting of any messages seen on StdErr after the +daemons exit, the following env variable can be set. + + export TOPOTESTS_CHECK_STDERR=Yes + +(The value doesn't matter at this time. The check is if the env variable +exists or not) +There is no pass/fail on this reporting. The Output will be reported to +the console + + export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" + +This will enable the check and output to console and the writing of +the information to files with the given prefix (followed by testname), +ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a +memory leak. + +#### (Optional) Collect Memory Leak Information + +FreeRangeRouting processes have the capabilities to report remaining memory +allocations upon exit. To enable the reporting of the memory, define an +enviroment variable `TOPOTESTS_CHECK_MEMLEAK` with the file prefix, ie + + export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" + +This will enable the check and output to console and the writing of +the information to files with the given prefix (followed by testname), +ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a +memory leak. + ## License All the configs and scripts are licensed under a ISC-style license. See diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index 8c2bbcae30..c02db441d9 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -810,11 +810,13 @@ def test_shutdown_check_stderr(): print("******************************************\n") if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: - print("SKIPPED (Disabled) - TOPOTESTS_CHECK_STDERR undefined\n") - pytest.skip('Skipping test for Stderr output and memory leaks') + print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") + pytest.skip('Skipping test for Stderr output') thisDir = os.path.dirname(os.path.realpath(__file__)) + print("thisDir=" + thisDir) + net['r1'].stopRouter() log = net['r1'].getStdErr('ripd') @@ -836,6 +838,25 @@ def test_shutdown_check_stderr(): print("\nZebra StdErr Log:\n" + log) +def test_shutdown_check_memleak(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: + print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") + pytest.skip('Skipping test for memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + for i in range(1, 2): + net['r%s' % i].stopRouter() + net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__)) + + if __name__ == '__main__': setLogLevel('info') diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index ccfd63b983..8c33156aaa 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -310,6 +310,7 @@ def test_bgp_routingTable(): # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) + def test_shutdown_check_stderr(): global fatal_error global net @@ -319,7 +320,8 @@ def test_shutdown_check_stderr(): pytest.skip(fatal_error) if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: - pytest.skip('Skipping test for Stderr output and memory leaks') + print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") + pytest.skip('Skipping test for Stderr output') thisDir = os.path.dirname(os.path.realpath(__file__)) @@ -334,6 +336,24 @@ def test_shutdown_check_stderr(): print("\nZebra StdErr Log:\n" + log) +def test_shutdown_check_memleak(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: + print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") + pytest.skip('Skipping test for memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + net['r1'].stopRouter() + net['r1'].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__)) + + if __name__ == '__main__': setLogLevel('info') diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 667f07a655..9d650e5cee 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -724,7 +724,8 @@ def test_shutdown_check_stderr(): pytest.skip(fatal_error) if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: - pytest.skip('Skipping test for Stderr output and memory leaks') + print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") + pytest.skip('Skipping test for Stderr output') thisDir = os.path.dirname(os.path.realpath(__file__)) @@ -741,6 +742,24 @@ def test_shutdown_check_stderr(): print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log)) +def test_shutdown_check_memleak(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: + print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") + pytest.skip('Skipping test for memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + for i in range(1, 5): + net['r%s' % i].stopRouter() + net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__)) + if __name__ == '__main__': diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 7a6ffb69f6..950500ab82 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -23,6 +23,7 @@ # import os +import errno import re import sys import glob @@ -51,6 +52,27 @@ def int2dpid(dpid): 'please either specify a dpid or use a ' 'canonical switch name such as s23.') +def pid_exists(pid): + "Check whether pid exists in the current process table." + + if pid <= 0: + return False + try: + os.kill(pid, 0) + except OSError as err: + if err.errno == errno.ESRCH: + # ESRCH == No such process + return False + elif err.errno == errno.EPERM: + # EPERM clearly means there's a process to deny access to + return True + else: + # According to "man 2 kill" possible error values are + # (EINVAL, EPERM, ESRCH) + raise + else: + return True + def addRouter(topo, name): "Adding a FRRouter (or Quagga) to Topology" @@ -119,8 +141,10 @@ class Router(Node): rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) if rundaemons is not None: for d in StringIO.StringIO(rundaemons): - self.cmd('kill -7 `cat %s`' % d.rstrip()) - self.waitOutput() + daemonpid = self.cmd('cat %s' % d.rstrip()).rstrip() + if pid_exists(int(daemonpid)): + self.cmd('kill -7 %s' % daemonpid) + self.waitOutput() def removeIPs(self): for interface in self.intfNames(): self.cmd('ip address flush', interface) @@ -261,6 +285,34 @@ class Router(Node): "Return the type of Router (frr or quagga)" return self.routertype + def report_memory_leaks(self, filename_prefix, testscript): + "Report Memory Leaks to file prefixed with given string" + + leakfound = False + filename = filename_prefix + re.sub(r"\.py", "", testscript) + ".txt" + for daemon in self.daemons: + if (self.daemons[daemon] == 1): + log = self.getStdErr(daemon) + if "memstats" in log: + # Found memory leak + print("\nRouter %s %s StdErr Log:\n%s" % (self.name, daemon, log)) + if not leakfound: + leakfound = True + # Check if file already exists + fileexists = os.path.isfile(filename) + leakfile = open(filename, "a") + if not fileexists: + # New file - add header + leakfile.write("# Memory Leak Detection for topotest %s\n\n" % testscript) + leakfile.write("## Router %s\n" % self.name) + leakfile.write("### Process %s\n" % daemon) + log = re.sub("core_handler: ", "", log) + log = re.sub(r"(showing active allocations in memory group [a-zA-Z0-9]+)", r"\n#### \1\n", log) + log = re.sub("memstats: ", " ", log) + leakfile.write(log) + leakfile.write("\n") + if leakfound: + leakfile.close() class LegacySwitch(OVSSwitch): diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 6be7f6fad1..82f4d1c083 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -380,7 +380,8 @@ def test_shutdown_check_stderr(): pytest.skip(fatal_error) if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: - pytest.skip('Skipping test for Stderr output and memory leaks') + print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") + pytest.skip('Skipping test for Stderr output') thisDir = os.path.dirname(os.path.realpath(__file__)) @@ -395,6 +396,25 @@ def test_shutdown_check_stderr(): print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log)) +def test_shutdown_check_memleak(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: + print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") + pytest.skip('Skipping test for memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + for i in range(1, 5): + net['r%s' % i].stopRouter() + net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__)) + + if __name__ == '__main__': setLogLevel('info') diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py index 2493108221..ed72a01bd0 100755 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -338,7 +338,8 @@ def test_shutdown_check_stderr(): pytest.skip(fatal_error) if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: - pytest.skip('Skipping test for Stderr output and memory leaks') + print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") + pytest.skip('Skipping test for Stderr output') thisDir = os.path.dirname(os.path.realpath(__file__)) @@ -353,6 +354,24 @@ def test_shutdown_check_stderr(): print("\nZebra StdErr Log:\n" + log) +def test_shutdown_check_memleak(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: + print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") + pytest.skip('Skipping test for memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + net['r1'].stopRouter() + net['r1'].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__)) + + if __name__ == '__main__': setLogLevel('info') From faf94e5a3abd0e3772e13a1823647c1021e30469 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Wed, 10 May 2017 09:41:53 -0700 Subject: [PATCH 058/384] ldp-topo1: Adjust to accept new format in "show ip route" as introduced with PR 495 (extra comma) Signed-off-by: Martin Winter --- tests/topotests/ldp-topo1/r1/show_ipv4_route.ref | 4 ++-- tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 | 4 ++-- tests/topotests/ldp-topo1/r3/show_ipv4_route.ref | 2 +- tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 | 2 +- tests/topotests/ldp-topo1/r4/show_ipv4_route.ref | 2 +- tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 | 2 +- tests/topotests/ldp-topo1/test_ldp_topo1.py | 2 ++ 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref index e72a20bac0..ff99ff9866 100644 --- a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref +++ b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref @@ -1,7 +1,7 @@ O 1.1.1.1/32 [110/0] is directly connected, lo O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0 -O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0 label xxx -O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0 label xxx +O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0, label xxx +O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0, label xxx O 10.0.1.0/24 [110/10] is directly connected, r1-eth0 O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0 O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0 diff --git a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 index e72a20bac0..ff99ff9866 100644 --- a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 +++ b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref-1 @@ -1,7 +1,7 @@ O 1.1.1.1/32 [110/0] is directly connected, lo O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0 -O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0 label xxx -O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0 label xxx +O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0, label xxx +O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0, label xxx O 10.0.1.0/24 [110/10] is directly connected, r1-eth0 O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0 O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0 diff --git a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref index f6e6199310..c8a29400b2 100644 --- a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref +++ b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref @@ -1,4 +1,4 @@ -O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0 label xxx +O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0, label xxx O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0 O 3.3.3.3/32 [110/0] is directly connected, lo O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0 diff --git a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 index f6e6199310..c8a29400b2 100644 --- a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 +++ b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref-1 @@ -1,4 +1,4 @@ -O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0 label xxx +O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0, label xxx O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0 O 3.3.3.3/32 [110/0] is directly connected, lo O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0 diff --git a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref index bcef173a64..df2a2b585f 100644 --- a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref +++ b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref @@ -1,4 +1,4 @@ -O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0 label xxx +O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0, label xxx O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0 O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0 O 4.4.4.4/32 [110/0] is directly connected, lo diff --git a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 index bcef173a64..df2a2b585f 100644 --- a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 +++ b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref-1 @@ -1,4 +1,4 @@ -O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0 label xxx +O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0, label xxx O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0 O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0 O 4.4.4.4/32 [110/0] is directly connected, lo diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 9d650e5cee..77857ad925 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -529,6 +529,8 @@ def test_zebra_ipv4_routingTable(): actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual) # Mask out label actual = re.sub(r" label [0-9]+", " label xxx", actual) + # Add missing comma before label (for old version) + actual = re.sub(r"([0-9]) label xxx", r"\1, label xxx", actual) # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) From 3a1f8275dbdb871398910c3eb1160f6e97b9bdfa Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 18 May 2017 18:51:07 -0700 Subject: [PATCH 059/384] Add support for collecting AddressSanitizer output. See README.md for details Signed-off-by: Martin Winter --- tests/topotests/README.md | 39 ++++ tests/topotests/topotest.py | 343 ++++++++++++++++++++++++++++++++++++ 2 files changed, 382 insertions(+) create mode 100644 tests/topotests/topotest.py diff --git a/tests/topotests/README.md b/tests/topotests/README.md index ee099ea34a..b25910d2e0 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -133,6 +133,45 @@ the information to files with the given prefix (followed by testname), ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory leak. +#### (Optional) Run topotests with GCC AddressSanitizer enabled + +Topotests can be run with the GCC AddressSanitizer. It requires GCC 4.8 or +newer. (Ubuntu 16.04 as suggested here is fine with GCC 5 as default) +For more information on AddressSanitizer, see +https://github.com/google/sanitizers/wiki/AddressSanitizer + +The checks are done automatically in the library call of `checkRouterRunning` +(ie at beginning of tests when there is a check for all daemons running). +No changes or extra configuration for topotests is required beside compiling +the suite with AddressSanitizer enabled. + +If a daemon crashed, then the errorlog is checked for AddressSanitizer +output. If found, then this is added with context (calling test) to +`/tmp/AddressSanitizer.txt` in markdown compatible format. + +Compiling for GCC AddressSanitizer requires to use gcc as a linker as well +(instead of ld). Here is a suggest way to compile frr with AddressSanitizer +for `stable/3.0` branch: + + git clone https://github.com/FRRouting/frr.git + cd frr + git checkout stable/3.0 + ./bootstrap.sh + export CC=gcc + export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer" + export LD=gcc + export LDFLAGS="-g -fsanitize=address -ldl" + ./configure --enable-shared=no \ + --prefix=/usr/lib/frr --sysconfdir=/etc/frr \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \ + --enable-exampledir=/usr/lib/frr/examples \ + --with-moduledir=/usr/lib/frr/modules \ + --enable-multipath=0 --enable-rtadv \ + --enable-tcp-zebra --enable-fpm --enable-pimd + make + sudo make install + ## License All the configs and scripts are licensed under a ISC-style license. See diff --git a/tests/topotests/topotest.py b/tests/topotests/topotest.py new file mode 100644 index 0000000000..ca0599771e --- /dev/null +++ b/tests/topotests/topotest.py @@ -0,0 +1,343 @@ +#!/usr/bin/env python + +# +# topotest.py +# Library of helper functions for NetDEF Topology Tests +# +# Copyright (c) 2016 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import errno +import re +import sys +import glob +import StringIO +import subprocess +import platform + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from time import sleep + +def int2dpid(dpid): + "Converting Integer to DPID" + + try: + dpid = hex(dpid)[2:] + dpid = '0'*(16-len(dpid))+dpid + return dpid + except IndexError: + raise Exception('Unable to derive default datapath ID - ' + 'please either specify a dpid or use a ' + 'canonical switch name such as s23.') + +def pid_exists(pid): + "Check whether pid exists in the current process table." + + if pid <= 0: + return False + try: + os.kill(pid, 0) + except OSError as err: + if err.errno == errno.ESRCH: + # ESRCH == No such process + return False + elif err.errno == errno.EPERM: + # EPERM clearly means there's a process to deny access to + return True + else: + # According to "man 2 kill" possible error values are + # (EINVAL, EPERM, ESRCH) + raise + else: + return True + +def addRouter(topo, name): + "Adding a FRRouter (or Quagga) to Topology" + + MyPrivateDirs = ['/etc/frr', + '/etc/quagga', + '/var/run/frr', + '/var/run/quagga', + '/var/log'] + return topo.addNode(name, cls=Router, privateDirs=MyPrivateDirs) + +class LinuxRouter(Node): + "A Node with IPv4/IPv6 forwarding enabled." + + def config(self, **params): + super(LinuxRouter, self).config(**params) + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + def terminate(self): + """ + Terminate generic LinuxRouter Mininet instance + """ + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(LinuxRouter, self).terminate() + +class Router(Node): + "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" + + def config(self, **params): + super(Router, self).config(**params) + + # Check if Quagga or FRR is installed + if os.path.isfile('/usr/lib/frr/zebra'): + self.routertype = 'frr' + elif os.path.isfile('/usr/lib/quagga/zebra'): + self.routertype = 'quagga' + else: + raise Exception('No FRR or Quagga found in ususal location') + # Enable forwarding on the router + self.cmd('sysctl net.ipv4.ip_forward=1') + self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + # Enable coredumps + self.cmd('sysctl kernel.core_uses_pid=1') + self.cmd('sysctl fs.suid_dumpable=2') + self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) + self.cmd('ulimit -c unlimited') + # Set ownership of config files + self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) + self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, + 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0, + 'ldpd': 0} + def terminate(self): + # Delete Running Quagga or FRR Daemons + self.stopRouter() + # rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) + # for d in StringIO.StringIO(rundaemons): + # self.cmd('kill -7 `cat %s`' % d.rstrip()) + # self.waitOutput() + # Disable forwarding + self.cmd('sysctl net.ipv4.ip_forward=0') + self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + super(Router, self).terminate() + def stopRouter(self): + # Stop Running Quagga or FRR Daemons + rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) + if rundaemons is not None: + for d in StringIO.StringIO(rundaemons): + daemonpid = self.cmd('cat %s' % d.rstrip()).rstrip() + if pid_exists(int(daemonpid)): + self.cmd('kill -7 %s' % daemonpid) + self.waitOutput() + def removeIPs(self): + for interface in self.intfNames(): + self.cmd('ip address flush', interface) + def loadConf(self, daemon, source=None): + # print "Daemons before:", self.daemons + if daemon in self.daemons.keys(): + self.daemons[daemon] = 1 + if source is None: + self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) + self.waitOutput() + else: + self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) + self.waitOutput() + self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) + self.waitOutput() + self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) + self.waitOutput() + else: + print("No daemon %s known" % daemon) + # print "Daemons after:", self.daemons + def startRouter(self): + # Disable integrated-vtysh-config + self.cmd('echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf' % self.routertype) + self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) + # Try to find relevant old logfiles in /tmp and delete them + map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) + # Remove old core files + map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) + # Remove IP addresses from OS first - we have them in zebra.conf + self.removeIPs() + # If ldp is used, check for LDP to be compiled and Linux Kernel to be 4.5 or higher + # No error - but return message and skip all the tests + if self.daemons['ldpd'] == 1: + if not os.path.isfile('/usr/lib/%s/ldpd' % self.routertype): + print("LDP Test, but no ldpd compiled or installed") + return "LDP Test, but no ldpd compiled or installed" + kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) + + if kernel_version: + if (float(kernel_version.group(1)) < 4 or + (float(kernel_version.group(1)) == 4 and float(kernel_version.group(2)) < 5)): + print("LDP Test need Linux Kernel 4.5 minimum") + return "LDP Test need Linux Kernel 4.5 minimum" + # Add mpls modules to kernel if we use LDP + if self.daemons['ldpd'] == 1: + self.cmd('/sbin/modprobe mpls-router') + self.cmd('/sbin/modprobe mpls-iptunnel') + self.cmd('echo 100000 > /proc/sys/net/mpls/platform_labels') + # Init done - now restarting daemons + self.restartRouter() + return "" + def restartRouter(self): + # Starts actuall daemons without init (ie restart) + # Start Zebra first + if self.daemons['zebra'] == 1: +# self.cmd('/usr/lib/%s/zebra -d' % self.routertype) + self.cmd('/usr/lib/%s/zebra > /tmp/%s-zebra.out 2> /tmp/%s-zebra.err &' % (self.routertype, self.name, self.name)) + self.waitOutput() + print('%s: %s zebra started' % (self, self.routertype)) + sleep(1) + # Fix Link-Local Addresses + # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this + self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') + # Now start all the other daemons + for daemon in self.daemons: + if (self.daemons[daemon] == 1) and (daemon != 'zebra'): +# self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) + self.cmd('/usr/lib/%s/%s > /tmp/%s-%s.out 2> /tmp/%s-%s.err &' % (self.routertype, daemon, self.name, daemon, self.name, daemon)) + self.waitOutput() + print('%s: %s %s started' % (self, self.routertype, daemon)) + def getStdErr(self, daemon): + return self.getLog('err', daemon) + def getStdOut(self, daemon): + return self.getLog('out', daemon) + def getLog(self, log, daemon): + return self.cmd('cat /tmp/%s-%s.%s' % (self.name, daemon, log) ) + def checkRouterRunning(self): + "Check if router daemons are running and collect crashinfo they don't run" + + global fatal_error + + daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') + for daemon in self.daemons: + if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): + sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) + # Look for core file + corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) + if (len(corefiles) > 0): + backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) + sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) + sys.stderr.write("%s\n" % backtrace) + else: + # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. + if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): + log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) + sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) + sys.stderr.write("%s\n" % log_tail) + # + # Look for AddressSanitizer Errors and append to /tmp/AddressSanitzer.txt if found + # only tested for GCC version 5.4 (as provided by Ubuntu 16.04) + # + errlog = self.getStdErr(daemon) + addressSantizerError = re.search('(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ', errlog) + if addressSantizerError: + # Sanitizer Error found in log + pidMark = addressSantizerError.group(1) + addressSantizerLog = re.search('%s(.*)%s' % (pidMark, pidMark), errlog, re.DOTALL) + if addressSantizerLog: + callingTest = os.path.basename(sys._current_frames().values()[0].f_back.f_globals['__file__']) + callingProc = sys._getframe(1).f_code.co_name + with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile: + addrSanFile.write("## Error: %s\n\n" % addressSantizerError.group(2)) + addrSanFile.write("### AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n" % (callingTest, callingProc, self.name)) + addrSanFile.write(' '+ '\n '.join(addressSantizerLog.group(1).splitlines()) + '\n') + addrSanFile.write("\n---------------\n") + return "%s: Daemon %s not running" % (self.name, daemon) + return "" + def get_ipv6_linklocal(self): + "Get LinkLocal Addresses from interfaces" + + linklocal = [] + + ifaces = self.cmd('ip -6 address') + # Fix newlines (make them all the same) + ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines() + interface="" + ll_per_if_count=0 + for line in ifaces: + m = re.search('[0-9]+: ([^:@]+)[@if0-9:]+ <', line) + if m: + interface = m.group(1) + ll_per_if_count = 0 + m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)[/0-9]* scope link', line) + if m: + local = m.group(1) + ll_per_if_count += 1 + if (ll_per_if_count > 1): + linklocal += [["%s-%s" % (interface, ll_per_if_count), local]] + else: + linklocal += [[interface, local]] + return linklocal + def daemon_available(self, daemon): + "Check if specified daemon is installed (and for ldp if kernel supports MPLS)" + + if not os.path.isfile('/usr/lib/%s/%s' % (self.routertype, daemon)): + return False + if (daemon == 'ldpd'): + kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) + if kernel_version: + if (float(kernel_version.group(1)) < 4 or + (float(kernel_version.group(1)) == 4 and float(kernel_version.group(2)) < 5)): + return False + else: + return False + return True + def get_routertype(self): + "Return the type of Router (frr or quagga)" + + return self.routertype + def report_memory_leaks(self, filename_prefix, testscript): + "Report Memory Leaks to file prefixed with given string" + + leakfound = False + filename = filename_prefix + re.sub(r"\.py", "", testscript) + ".txt" + for daemon in self.daemons: + if (self.daemons[daemon] == 1): + log = self.getStdErr(daemon) + if "memstats" in log: + # Found memory leak + print("\nRouter %s %s StdErr Log:\n%s" % (self.name, daemon, log)) + if not leakfound: + leakfound = True + # Check if file already exists + fileexists = os.path.isfile(filename) + leakfile = open(filename, "a") + if not fileexists: + # New file - add header + leakfile.write("# Memory Leak Detection for topotest %s\n\n" % testscript) + leakfile.write("## Router %s\n" % self.name) + leakfile.write("### Process %s\n" % daemon) + log = re.sub("core_handler: ", "", log) + log = re.sub(r"(showing active allocations in memory group [a-zA-Z0-9]+)", r"\n#### \1\n", log) + log = re.sub("memstats: ", " ", log) + leakfile.write(log) + leakfile.write("\n") + if leakfound: + leakfile.close() + + +class LegacySwitch(OVSSwitch): + "A Legacy Switch without OpenFlow" + + def __init__(self, name, **params): + OVSSwitch.__init__(self, name, failMode='standalone', **params) + self.switchIP = None + From 09bd98fbb775031d924d7bc7a1dd88f889bc8a99 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Thu, 18 May 2017 20:24:54 -0700 Subject: [PATCH 060/384] Doc: Update manual sample build instruction with symlink for vtysh and reference to user creation Signed-off-by: Martin Winter --- tests/topotests/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/topotests/README.md b/tests/topotests/README.md index b25910d2e0..58601f40ca 100644 --- a/tests/topotests/README.md +++ b/tests/topotests/README.md @@ -88,10 +88,10 @@ disabled in `pytest.ini` file) test script itself is debugged #### Execute single test - + cd test_to_be_run ./test_to_be_run.py - + For further options, refer to pytest documentation Test will set exit code which can be used with `git bisect` @@ -171,6 +171,10 @@ for `stable/3.0` branch: --enable-tcp-zebra --enable-fpm --enable-pimd make sudo make install + # Create symlink for vtysh, so topotest finds it in /usr/lib/frr + sudo ln -s /usr/lib/frr/vtysh /usr/bin/ + +and create `frr` user and `frrvty` group as shown above ## License From 597cabb74de6d5a287d68afb31c1f77f0781dcd1 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 19 May 2017 02:16:42 -0700 Subject: [PATCH 061/384] lib: Move updated topotest.py lib with AddressSanitizer to correct directory (fix mistake from 2 commits ago) Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 21 +- tests/topotests/topotest.py | 343 -------------------------------- 2 files changed, 20 insertions(+), 344 deletions(-) delete mode 100644 tests/topotests/topotest.py diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 950500ab82..ca0599771e 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -222,6 +222,8 @@ class Router(Node): def getLog(self, log, daemon): return self.cmd('cat /tmp/%s-%s.%s' % (self.name, daemon, log) ) def checkRouterRunning(self): + "Check if router daemons are running and collect crashinfo they don't run" + global fatal_error daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') @@ -240,7 +242,24 @@ class Router(Node): log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) sys.stderr.write("%s\n" % log_tail) - + # + # Look for AddressSanitizer Errors and append to /tmp/AddressSanitzer.txt if found + # only tested for GCC version 5.4 (as provided by Ubuntu 16.04) + # + errlog = self.getStdErr(daemon) + addressSantizerError = re.search('(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ', errlog) + if addressSantizerError: + # Sanitizer Error found in log + pidMark = addressSantizerError.group(1) + addressSantizerLog = re.search('%s(.*)%s' % (pidMark, pidMark), errlog, re.DOTALL) + if addressSantizerLog: + callingTest = os.path.basename(sys._current_frames().values()[0].f_back.f_globals['__file__']) + callingProc = sys._getframe(1).f_code.co_name + with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile: + addrSanFile.write("## Error: %s\n\n" % addressSantizerError.group(2)) + addrSanFile.write("### AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n" % (callingTest, callingProc, self.name)) + addrSanFile.write(' '+ '\n '.join(addressSantizerLog.group(1).splitlines()) + '\n') + addrSanFile.write("\n---------------\n") return "%s: Daemon %s not running" % (self.name, daemon) return "" def get_ipv6_linklocal(self): diff --git a/tests/topotests/topotest.py b/tests/topotests/topotest.py deleted file mode 100644 index ca0599771e..0000000000 --- a/tests/topotests/topotest.py +++ /dev/null @@ -1,343 +0,0 @@ -#!/usr/bin/env python - -# -# topotest.py -# Library of helper functions for NetDEF Topology Tests -# -# Copyright (c) 2016 by -# Network Device Education Foundation, Inc. ("NetDEF") -# -# Permission to use, copy, modify, and/or distribute this software -# for any purpose with or without fee is hereby granted, provided -# that the above copyright notice and this permission notice appear -# in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# - -import os -import errno -import re -import sys -import glob -import StringIO -import subprocess -import platform - -from mininet.topo import Topo -from mininet.net import Mininet -from mininet.node import Node, OVSSwitch, Host -from mininet.log import setLogLevel, info -from mininet.cli import CLI -from mininet.link import Intf - -from time import sleep - -def int2dpid(dpid): - "Converting Integer to DPID" - - try: - dpid = hex(dpid)[2:] - dpid = '0'*(16-len(dpid))+dpid - return dpid - except IndexError: - raise Exception('Unable to derive default datapath ID - ' - 'please either specify a dpid or use a ' - 'canonical switch name such as s23.') - -def pid_exists(pid): - "Check whether pid exists in the current process table." - - if pid <= 0: - return False - try: - os.kill(pid, 0) - except OSError as err: - if err.errno == errno.ESRCH: - # ESRCH == No such process - return False - elif err.errno == errno.EPERM: - # EPERM clearly means there's a process to deny access to - return True - else: - # According to "man 2 kill" possible error values are - # (EINVAL, EPERM, ESRCH) - raise - else: - return True - -def addRouter(topo, name): - "Adding a FRRouter (or Quagga) to Topology" - - MyPrivateDirs = ['/etc/frr', - '/etc/quagga', - '/var/run/frr', - '/var/run/quagga', - '/var/log'] - return topo.addNode(name, cls=Router, privateDirs=MyPrivateDirs) - -class LinuxRouter(Node): - "A Node with IPv4/IPv6 forwarding enabled." - - def config(self, **params): - super(LinuxRouter, self).config(**params) - # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') - def terminate(self): - """ - Terminate generic LinuxRouter Mininet instance - """ - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') - super(LinuxRouter, self).terminate() - -class Router(Node): - "A Node with IPv4/IPv6 forwarding enabled and Quagga as Routing Engine" - - def config(self, **params): - super(Router, self).config(**params) - - # Check if Quagga or FRR is installed - if os.path.isfile('/usr/lib/frr/zebra'): - self.routertype = 'frr' - elif os.path.isfile('/usr/lib/quagga/zebra'): - self.routertype = 'quagga' - else: - raise Exception('No FRR or Quagga found in ususal location') - # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') - # Enable coredumps - self.cmd('sysctl kernel.core_uses_pid=1') - self.cmd('sysctl fs.suid_dumpable=2') - self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) - self.cmd('ulimit -c unlimited') - # Set ownership of config files - self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) - self.daemons = {'zebra': 0, 'ripd': 0, 'ripngd': 0, 'ospfd': 0, - 'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0, - 'ldpd': 0} - def terminate(self): - # Delete Running Quagga or FRR Daemons - self.stopRouter() - # rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) - # for d in StringIO.StringIO(rundaemons): - # self.cmd('kill -7 `cat %s`' % d.rstrip()) - # self.waitOutput() - # Disable forwarding - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') - super(Router, self).terminate() - def stopRouter(self): - # Stop Running Quagga or FRR Daemons - rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype) - if rundaemons is not None: - for d in StringIO.StringIO(rundaemons): - daemonpid = self.cmd('cat %s' % d.rstrip()).rstrip() - if pid_exists(int(daemonpid)): - self.cmd('kill -7 %s' % daemonpid) - self.waitOutput() - def removeIPs(self): - for interface in self.intfNames(): - self.cmd('ip address flush', interface) - def loadConf(self, daemon, source=None): - # print "Daemons before:", self.daemons - if daemon in self.daemons.keys(): - self.daemons[daemon] = 1 - if source is None: - self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon)) - self.waitOutput() - else: - self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon)) - self.waitOutput() - self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon)) - self.waitOutput() - self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon)) - self.waitOutput() - else: - print("No daemon %s known" % daemon) - # print "Daemons after:", self.daemons - def startRouter(self): - # Disable integrated-vtysh-config - self.cmd('echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf' % self.routertype) - self.cmd('chown %s:%svty /etc/%s/vtysh.conf' % (self.routertype, self.routertype, self.routertype)) - # Try to find relevant old logfiles in /tmp and delete them - map(os.remove, glob.glob("/tmp/*%s*.log" % self.name)) - # Remove old core files - map(os.remove, glob.glob("/tmp/%s*.dmp" % self.name)) - # Remove IP addresses from OS first - we have them in zebra.conf - self.removeIPs() - # If ldp is used, check for LDP to be compiled and Linux Kernel to be 4.5 or higher - # No error - but return message and skip all the tests - if self.daemons['ldpd'] == 1: - if not os.path.isfile('/usr/lib/%s/ldpd' % self.routertype): - print("LDP Test, but no ldpd compiled or installed") - return "LDP Test, but no ldpd compiled or installed" - kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) - - if kernel_version: - if (float(kernel_version.group(1)) < 4 or - (float(kernel_version.group(1)) == 4 and float(kernel_version.group(2)) < 5)): - print("LDP Test need Linux Kernel 4.5 minimum") - return "LDP Test need Linux Kernel 4.5 minimum" - # Add mpls modules to kernel if we use LDP - if self.daemons['ldpd'] == 1: - self.cmd('/sbin/modprobe mpls-router') - self.cmd('/sbin/modprobe mpls-iptunnel') - self.cmd('echo 100000 > /proc/sys/net/mpls/platform_labels') - # Init done - now restarting daemons - self.restartRouter() - return "" - def restartRouter(self): - # Starts actuall daemons without init (ie restart) - # Start Zebra first - if self.daemons['zebra'] == 1: -# self.cmd('/usr/lib/%s/zebra -d' % self.routertype) - self.cmd('/usr/lib/%s/zebra > /tmp/%s-zebra.out 2> /tmp/%s-zebra.err &' % (self.routertype, self.name, self.name)) - self.waitOutput() - print('%s: %s zebra started' % (self, self.routertype)) - sleep(1) - # Fix Link-Local Addresses - # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local addresses on start. Fix this - self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done') - # Now start all the other daemons - for daemon in self.daemons: - if (self.daemons[daemon] == 1) and (daemon != 'zebra'): -# self.cmd('/usr/lib/%s/%s -d' % (self.routertype, daemon)) - self.cmd('/usr/lib/%s/%s > /tmp/%s-%s.out 2> /tmp/%s-%s.err &' % (self.routertype, daemon, self.name, daemon, self.name, daemon)) - self.waitOutput() - print('%s: %s %s started' % (self, self.routertype, daemon)) - def getStdErr(self, daemon): - return self.getLog('err', daemon) - def getStdOut(self, daemon): - return self.getLog('out', daemon) - def getLog(self, log, daemon): - return self.cmd('cat /tmp/%s-%s.%s' % (self.name, daemon, log) ) - def checkRouterRunning(self): - "Check if router daemons are running and collect crashinfo they don't run" - - global fatal_error - - daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') - for daemon in self.daemons: - if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): - sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) - # Look for core file - corefiles = glob.glob("/tmp/%s_%s_core*.dmp" % (self.name, daemon)) - if (len(corefiles) > 0): - backtrace = subprocess.check_output(["gdb /usr/lib/%s/%s %s --batch -ex bt 2> /dev/null" % (self.routertype, daemon, corefiles[0])], shell=True) - sys.stderr.write("\n%s: %s crashed. Core file found - Backtrace follows:\n" % (self.name, daemon)) - sys.stderr.write("%s\n" % backtrace) - else: - # No core found - If we find matching logfile in /tmp, then print last 20 lines from it. - if os.path.isfile("/tmp/%s-%s.log" % (self.name, daemon)): - log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) - sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) - sys.stderr.write("%s\n" % log_tail) - # - # Look for AddressSanitizer Errors and append to /tmp/AddressSanitzer.txt if found - # only tested for GCC version 5.4 (as provided by Ubuntu 16.04) - # - errlog = self.getStdErr(daemon) - addressSantizerError = re.search('(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ', errlog) - if addressSantizerError: - # Sanitizer Error found in log - pidMark = addressSantizerError.group(1) - addressSantizerLog = re.search('%s(.*)%s' % (pidMark, pidMark), errlog, re.DOTALL) - if addressSantizerLog: - callingTest = os.path.basename(sys._current_frames().values()[0].f_back.f_globals['__file__']) - callingProc = sys._getframe(1).f_code.co_name - with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile: - addrSanFile.write("## Error: %s\n\n" % addressSantizerError.group(2)) - addrSanFile.write("### AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n" % (callingTest, callingProc, self.name)) - addrSanFile.write(' '+ '\n '.join(addressSantizerLog.group(1).splitlines()) + '\n') - addrSanFile.write("\n---------------\n") - return "%s: Daemon %s not running" % (self.name, daemon) - return "" - def get_ipv6_linklocal(self): - "Get LinkLocal Addresses from interfaces" - - linklocal = [] - - ifaces = self.cmd('ip -6 address') - # Fix newlines (make them all the same) - ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines() - interface="" - ll_per_if_count=0 - for line in ifaces: - m = re.search('[0-9]+: ([^:@]+)[@if0-9:]+ <', line) - if m: - interface = m.group(1) - ll_per_if_count = 0 - m = re.search('inet6 (fe80::[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)[/0-9]* scope link', line) - if m: - local = m.group(1) - ll_per_if_count += 1 - if (ll_per_if_count > 1): - linklocal += [["%s-%s" % (interface, ll_per_if_count), local]] - else: - linklocal += [[interface, local]] - return linklocal - def daemon_available(self, daemon): - "Check if specified daemon is installed (and for ldp if kernel supports MPLS)" - - if not os.path.isfile('/usr/lib/%s/%s' % (self.routertype, daemon)): - return False - if (daemon == 'ldpd'): - kernel_version = re.search(r'([0-9]+)\.([0-9]+).*', platform.release()) - if kernel_version: - if (float(kernel_version.group(1)) < 4 or - (float(kernel_version.group(1)) == 4 and float(kernel_version.group(2)) < 5)): - return False - else: - return False - return True - def get_routertype(self): - "Return the type of Router (frr or quagga)" - - return self.routertype - def report_memory_leaks(self, filename_prefix, testscript): - "Report Memory Leaks to file prefixed with given string" - - leakfound = False - filename = filename_prefix + re.sub(r"\.py", "", testscript) + ".txt" - for daemon in self.daemons: - if (self.daemons[daemon] == 1): - log = self.getStdErr(daemon) - if "memstats" in log: - # Found memory leak - print("\nRouter %s %s StdErr Log:\n%s" % (self.name, daemon, log)) - if not leakfound: - leakfound = True - # Check if file already exists - fileexists = os.path.isfile(filename) - leakfile = open(filename, "a") - if not fileexists: - # New file - add header - leakfile.write("# Memory Leak Detection for topotest %s\n\n" % testscript) - leakfile.write("## Router %s\n" % self.name) - leakfile.write("### Process %s\n" % daemon) - log = re.sub("core_handler: ", "", log) - log = re.sub(r"(showing active allocations in memory group [a-zA-Z0-9]+)", r"\n#### \1\n", log) - log = re.sub("memstats: ", " ", log) - leakfile.write(log) - leakfile.write("\n") - if leakfound: - leakfile.close() - - -class LegacySwitch(OVSSwitch): - "A Legacy Switch without OpenFlow" - - def __init__(self, name, **params): - OVSSwitch.__init__(self, name, failMode='standalone', **params) - self.switchIP = None - From 84379e8e7fda8d41b050e643742a8a43c5ae1fc0 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 19 May 2017 20:30:40 -0700 Subject: [PATCH 062/384] lib: Add different failure comment on processes killed by AddressSanitizer Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index ca0599771e..6c7d393e5b 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -260,6 +260,8 @@ class Router(Node): addrSanFile.write("### AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n" % (callingTest, callingProc, self.name)) addrSanFile.write(' '+ '\n '.join(addressSantizerLog.group(1).splitlines()) + '\n') addrSanFile.write("\n---------------\n") + return "%s: Daemon %s not running - killed by AddressSanitizer" % (self.name, daemon) + return "%s: Daemon %s not running" % (self.name, daemon) return "" def get_ipv6_linklocal(self): From 7e7fc73b49d9ea90bdb3f5821592f832056f336f Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 19 May 2017 20:41:20 -0700 Subject: [PATCH 063/384] (all tests): Add extra check to make sure daemons are still running after each essential stage. If daemon crashed at a later stage (not startup), then the test scripts didn't properly detect it and report unpredictable errors. This will properly log the daemon crashes Signed-off-by: Martin Winter --- .../test_all_protocol_startup.py | 55 +++++++++++++++++++ .../test_bgp_multiview_topo1.py | 10 ++++ tests/topotests/ldp-topo1/test_ldp_topo1.py | 40 ++++++++++++++ .../topotests/ospf6-topo1/test_ospf6_topo1.py | 13 ++++- .../topotests/ripng-topo1/test_ripng_topo1.py | 20 +++++++ 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index c02db441d9..6e2f12ac5d 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -205,6 +205,11 @@ def test_error_messages_vtysh(): assert vtystderr == '', "Vtysh StdErr Output check failed for router r%s:\n%s" % (i, vtystderr) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -291,6 +296,11 @@ def test_converge_protocols(): # Not really implemented yet - just sleep 60 secs for now sleep(60) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line ## CLI(net) @@ -339,6 +349,11 @@ def test_rip_status(): assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -389,6 +404,11 @@ def test_ripng_status(): assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -443,6 +463,11 @@ def test_ospfv2_interfaces(): assert failures == 0, "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -491,6 +516,11 @@ def test_isis_interfaces(): assert failures == 0, "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -567,6 +597,11 @@ def test_bgp_summary(): assert failures == 0, "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -644,6 +679,11 @@ def test_bgp_ipv6_summary(): assert failures == 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -692,6 +732,11 @@ def test_bgp_ipv4(): assert failures == 0, "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -740,6 +785,11 @@ def test_bgp_ipv6(): assert failures == 0, "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -794,6 +844,11 @@ def test_mpls_interfaces(): assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 8c33156aaa..d7c350f5e5 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -251,6 +251,11 @@ def test_bgp_converge(): # print("\nwaiting 15s for routes to populate") # sleep(15) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting Quagga/FRR daemons, uncomment the next line # CLI(net) @@ -307,6 +312,11 @@ def test_bgp_routingTable(): assert failures == 0, "Routing Table verification failed for router r%s, view %s:\n%s" % (i, view, diff) + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 77857ad925..af2bae1853 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -252,6 +252,11 @@ def test_mpls_interfaces(): assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -313,6 +318,11 @@ def test_mpls_ldp_neighbor_establish(): print("\nwaiting 15s for LDP sessions to establish") sleep(15) + # Make sure that all daemons are running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + def test_mpls_ldp_discovery(): global fatal_error @@ -360,6 +370,11 @@ def test_mpls_ldp_discovery(): assert failures == 0, "MPLS LDP Interface discovery output for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -420,6 +435,11 @@ def test_mpls_ldp_neighbor(): assert failures == 0, "MPLS LDP Interface neighbor output for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line #CLI(net) @@ -496,6 +516,11 @@ def test_mpls_ldp_binding(): assert failures == 0, "MPLS LDP Interface binding output for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line #CLI(net) @@ -549,6 +574,11 @@ def test_zebra_ipv4_routingTable(): assert failures == 0, "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -614,6 +644,11 @@ def test_mpls_table(): assert failures == 0, "MPLS table output for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -713,6 +748,11 @@ def test_linux_mpls_routes(): assert failures == 0, "Linux Kernel MPLS route output for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 82f4d1c083..90489e4bec 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -208,8 +208,7 @@ def test_router_running(): print("******************************************\n") sleep(5) - # CLI(net) - failedRunning = "" + # Make sure that all daemons are running for i in range(1, 5): fatal_error = net['r%s' % i].checkRouterRunning() assert fatal_error == "", fatal_error @@ -259,6 +258,11 @@ def test_ospf6_converged(): print("\nwaiting 15s for routes to populate") sleep(15) + # Make sure that all daemons are still running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + def test_ospfv3_routingTable(): global fatal_error global net @@ -304,6 +308,11 @@ def test_ospfv3_routingTable(): assert failures == 0, "OSPFv3 (IPv6) Routing Table verification failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are still running + for i in range(1, 5): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py index ed72a01bd0..e790808e3b 100755 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -173,6 +173,11 @@ def test_converge_protocols(): # Not really implemented yet - just sleep 60 secs for now sleep(60) + # Make sure that all daemons are running + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line #CLI(net) @@ -224,6 +229,11 @@ def test_ripng_status(): assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -276,6 +286,11 @@ def test_ripng_routes(): assert failures == 0, "SHOW IPv6 RIPng failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -325,6 +340,11 @@ def test_zebra_ipv6_routingTable(): assert failures == 0, "Zebra IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are running + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) From 28aa9ae65827feb300ce3fd651ea275a4c09e0d7 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Fri, 19 May 2017 21:07:25 -0700 Subject: [PATCH 064/384] rip-topo1: Add check to make sure daemons are still running between essential tests Signed-off-by: Martin Winter --- tests/topotests/rip-topo1/test_rip_topo1.py | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py index 7f39dffca1..60b43ee42e 100755 --- a/tests/topotests/rip-topo1/test_rip_topo1.py +++ b/tests/topotests/rip-topo1/test_rip_topo1.py @@ -147,7 +147,7 @@ def test_router_running(): print("******************************************\n") sleep(5) - # Starting Routers + # Make sure that all daemons are running for i in range(1, 4): fatal_error = net['r%s' % i].checkRouterRunning() assert fatal_error == "", fatal_error @@ -172,6 +172,11 @@ def test_converge_protocols(): # Not really implemented yet - just sleep 60 secs for now sleep(60) + # Make sure that all daemons are still running + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -221,6 +226,11 @@ def test_rip_status(): assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are still running + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -268,6 +278,11 @@ def test_rip_routes(): assert failures == 0, "SHOW IP RIP failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are still running + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) @@ -315,6 +330,11 @@ def test_zebra_ipv4_routingTable(): assert failures == 0, "Zebra IPv4 Routing Table verification failed for router r%s:\n%s" % (i, diff) + # Make sure that all daemons are still running + for i in range(1, 4): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + # For debugging after starting FRR/Quagga daemons, uncomment the next line # CLI(net) From 311dba33323aa96ddff10c1cea8b79b64857e8af Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 20 May 2017 00:15:52 -0700 Subject: [PATCH 065/384] lib: Send Output error from AddressSanitizer to StdErr Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 6c7d393e5b..b3654333dc 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -249,6 +249,7 @@ class Router(Node): errlog = self.getStdErr(daemon) addressSantizerError = re.search('(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ', errlog) if addressSantizerError: + sys.stderr.write("%s: Daemon %s triggered an exception by AddressSanitizer\n" % (self.name, daemon)) # Sanitizer Error found in log pidMark = addressSantizerError.group(1) addressSantizerLog = re.search('%s(.*)%s' % (pidMark, pidMark), errlog, re.DOTALL) @@ -256,6 +257,7 @@ class Router(Node): callingTest = os.path.basename(sys._current_frames().values()[0].f_back.f_globals['__file__']) callingProc = sys._getframe(1).f_code.co_name with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile: + sys.stderr.write('\n'.join(addressSantizerLog.group(1).splitlines()) + '\n') addrSanFile.write("## Error: %s\n\n" % addressSantizerError.group(2)) addrSanFile.write("### AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n" % (callingTest, callingProc, self.name)) addrSanFile.write(' '+ '\n '.join(addressSantizerLog.group(1).splitlines()) + '\n') From 4942f298470d1839bc371235d6af27a3f77bcd9c Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Sat, 20 May 2017 02:24:11 -0700 Subject: [PATCH 066/384] lib: Move AddressSanitizer check to separate procedure and add check for errors in vtysh itself as part of checkRouterRunning Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 46 +++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index b3654333dc..b3cff8ca7d 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -73,6 +73,27 @@ def pid_exists(pid): else: return True +def checkAddressSanitizerError(output, router, component): + "Checks for AddressSanitizer in output. If found, then logs it and returns true, false otherwise" + + addressSantizerError = re.search('(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ', output) + if addressSantizerError: + sys.stderr.write("%s: %s triggered an exception by AddressSanitizer\n" % (router, component)) + # Sanitizer Error found in log + pidMark = addressSantizerError.group(1) + addressSantizerLog = re.search('%s(.*)%s' % (pidMark, pidMark), output, re.DOTALL) + if addressSantizerLog: + callingTest = os.path.basename(sys._current_frames().values()[0].f_back.f_back.f_globals['__file__']) + callingProc = sys._getframe(2).f_code.co_name + with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile: + sys.stderr.write('\n'.join(addressSantizerLog.group(1).splitlines()) + '\n') + addrSanFile.write("## Error: %s\n\n" % addressSantizerError.group(2)) + addrSanFile.write("### AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n" % (callingTest, callingProc, router)) + addrSanFile.write(' '+ '\n '.join(addressSantizerLog.group(1).splitlines()) + '\n') + addrSanFile.write("\n---------------\n") + return True + return False + def addRouter(topo, name): "Adding a FRRouter (or Quagga) to Topology" @@ -227,6 +248,10 @@ class Router(Node): global fatal_error daemonsRunning = self.cmd('vtysh -c "show log" | grep "Logging configuration for"') + # Look for AddressSanitizer Errors in vtysh output and append to /tmp/AddressSanitzer.txt if found + if checkAddressSanitizerError(daemonsRunning, self.name, "vtysh"): + return "%s: vtysh killed by AddressSanitizer" % (self.name) + for daemon in self.daemons: if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) @@ -242,26 +267,9 @@ class Router(Node): log_tail = subprocess.check_output(["tail -n20 /tmp/%s-%s.log 2> /dev/null" % (self.name, daemon)], shell=True) sys.stderr.write("\nFrom %s %s %s log file:\n" % (self.routertype, self.name, daemon)) sys.stderr.write("%s\n" % log_tail) - # + # Look for AddressSanitizer Errors and append to /tmp/AddressSanitzer.txt if found - # only tested for GCC version 5.4 (as provided by Ubuntu 16.04) - # - errlog = self.getStdErr(daemon) - addressSantizerError = re.search('(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ', errlog) - if addressSantizerError: - sys.stderr.write("%s: Daemon %s triggered an exception by AddressSanitizer\n" % (self.name, daemon)) - # Sanitizer Error found in log - pidMark = addressSantizerError.group(1) - addressSantizerLog = re.search('%s(.*)%s' % (pidMark, pidMark), errlog, re.DOTALL) - if addressSantizerLog: - callingTest = os.path.basename(sys._current_frames().values()[0].f_back.f_globals['__file__']) - callingProc = sys._getframe(1).f_code.co_name - with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile: - sys.stderr.write('\n'.join(addressSantizerLog.group(1).splitlines()) + '\n') - addrSanFile.write("## Error: %s\n\n" % addressSantizerError.group(2)) - addrSanFile.write("### AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n" % (callingTest, callingProc, self.name)) - addrSanFile.write(' '+ '\n '.join(addressSantizerLog.group(1).splitlines()) + '\n') - addrSanFile.write("\n---------------\n") + if checkAddressSanitizerError(self.getStdErr(daemon), self.name, daemon): return "%s: Daemon %s not running - killed by AddressSanitizer" % (self.name, daemon) return "%s: Daemon %s not running" % (self.name, daemon) From 17070436a3701489c3c33bbe3bbefb0a63afbd0d Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Tue, 30 May 2017 19:39:21 -0700 Subject: [PATCH 067/384] lib: cleanup diff text output formatting issue and move to library Signed-off-by: Martin Winter --- .../test_all_protocol_startup.py | 55 +++++++++---------- .../test_bgp_multiview_topo1.py | 8 +-- tests/topotests/ldp-topo1/test_ldp_topo1.py | 43 +++++++-------- tests/topotests/lib/topotest.py | 10 ++++ .../topotests/ospf6-topo1/test_ospf6_topo1.py | 32 ++--------- tests/topotests/rip-topo1/test_rip_topo1.py | 19 +++---- .../topotests/ripng-topo1/test_ripng_topo1.py | 19 +++---- 7 files changed, 85 insertions(+), 101 deletions(-) diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index 6e2f12ac5d..bbec24a0b4 100755 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -30,7 +30,6 @@ test_all_protocol_startup.py: Test of all protocols at same time import os import re import sys -import difflib import pytest from time import sleep @@ -336,9 +335,9 @@ def test_rip_status(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual IP RIP status", - tofile="expected IP RIP status")) + diff = topotest.get_textdiff(actual, expected, + title1="actual IP RIP status", + title2="expected IP RIP status") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -391,9 +390,9 @@ def test_ripng_status(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual IPv6 RIPng status", - tofile="expected IPv6 RIPng status")) + diff = topotest.get_textdiff(actual, expected, + title1="actual IPv6 RIPng status", + title2="expected IPv6 RIPng status") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -444,9 +443,9 @@ def test_ospfv2_interfaces(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW IP OSPF INTERFACE", - tofile="expected SHOW IP OSPF INTERFACE")) + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW IP OSPF INTERFACE", + title2="expected SHOW IP OSPF INTERFACE") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -503,9 +502,9 @@ def test_isis_interfaces(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW ISIS INTERFACE DETAIL", - tofile="expected SHOW ISIS OSPF6 INTERFACE DETAIL")) + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW ISIS INTERFACE DETAIL", + title2="expected SHOW ISIS OSPF6 INTERFACE DETAIL") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -584,9 +583,9 @@ def test_bgp_summary(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW IP BGP SUMMARY", - tofile="expected SHOW IP BGP SUMMARY")) + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW IP BGP SUMMARY", + title2="expected SHOW IP BGP SUMMARY") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -666,9 +665,9 @@ def test_bgp_ipv6_summary(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW BGP IPv6 SUMMARY", - tofile="expected SHOW BGP IPv6 SUMMARY")) + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW BGP IPv6 SUMMARY", + title2="expected SHOW BGP IPv6 SUMMARY") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -719,9 +718,9 @@ def test_bgp_ipv4(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW BGP IPv4", - tofile="expected SHOW BGP IPv4")) + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW BGP IPv4", + title2="expected SHOW BGP IPv4") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -772,9 +771,9 @@ def test_bgp_ipv6(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW BGP IPv6", - tofile="expected SHOW BGP IPv6")) + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW BGP IPv6", + title2="expected SHOW BGP IPv6") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -828,9 +827,9 @@ def test_mpls_interfaces(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual MPLS LDP interface status", - tofile="expected MPLS LDP interface status")) + diff = topotest.get_textdiff(actual, expected, + title1="actual MPLS LDP interface status", + title2="expected MPLS LDP interface status") # Empty string if it matches, otherwise diff contains unified diff if diff: diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index d7c350f5e5..d850787fa4 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -65,7 +65,6 @@ test_bgp_multiview_topo1.py: Simple Quagga/FRR Route-Server Test import os import re import sys -import difflib import pytest from time import sleep @@ -298,10 +297,9 @@ def test_bgp_routingTable(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual BGP routing table", - tofile="expected BGP routing table")) - # Empty string if it matches, otherwise diff contains unified diff + diff = topotest.get_textdiff(actual, expected, + title1="actual BGP routing table", + title2="expected BGP routing table") if diff: sys.stderr.write('r%s failed Routing Table Check for view %s:\n%s\n' diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index af2bae1853..82ee80fc24 100755 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -62,7 +62,6 @@ r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0 import os import re import sys -import difflib import pytest from time import sleep @@ -236,9 +235,9 @@ def test_mpls_interfaces(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual MPLS LDP interface status", - tofile="expected MPLS LDP interface status")) + diff = topotest.get_textdiff(actual, expected, + title1="actual MPLS LDP interface status", + title2="expected MPLS LDP interface status") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -357,9 +356,9 @@ def test_mpls_ldp_discovery(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual MPLS LDP discovery output", - tofile="expected MPLS LDP discovery output")) + diff = topotest.get_textdiff(actual, expected, + title1="actual MPLS LDP discovery output", + title2="expected MPLS LDP discovery output") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -422,9 +421,9 @@ def test_mpls_ldp_neighbor(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual MPLS LDP neighbor output", - tofile="expected MPLS LDP neighbor output")) + diff = topotest.get_textdiff(actual, expected, + title1="actual MPLS LDP neighbor output", + title2="expected MPLS LDP neighbor output") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -503,9 +502,9 @@ def test_mpls_ldp_binding(): swapped = True # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual MPLS LDP binding output", - tofile="expected MPLS LDP binding output")) + diff = topotest.get_textdiff(actual, expected, + title1="actual MPLS LDP binding output", + title2="expected MPLS LDP binding output") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -561,9 +560,9 @@ def test_zebra_ipv4_routingTable(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual IPv4 zebra routing table", - tofile="expected IPv4 zera routing table")) + diff = topotest.get_textdiff(actual, expected, + title1="actual IPv4 zebra routing table", + title2="expected IPv4 zebra routing table") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -631,9 +630,9 @@ def test_mpls_table(): swapped = True # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual MPLS table output", - tofile="expected MPLS table output")) + diff = topotest.get_textdiff(actual, expected, + title1="actual MPLS table output", + title2="expected MPLS table output") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -735,9 +734,9 @@ def test_linux_mpls_routes(): actual = ('\n'.join(actual) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual Linux Kernel MPLS route", - tofile="expected Linux Kernel MPLS route")) + diff = topotest.get_textdiff(actual, expected, + title1="actual Linux Kernel MPLS route", + title2="expected Linux Kernel MPLS route") # Empty string if it matches, otherwise diff contains unified diff if diff: diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index b3cff8ca7d..6572bc3390 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -30,6 +30,7 @@ import glob import StringIO import subprocess import platform +import difflib from mininet.topo import Topo from mininet.net import Mininet @@ -73,6 +74,15 @@ def pid_exists(pid): else: return True +def get_textdiff(text1, text2, title1="", title2=""): + "Returns empty string if same or formatted diff" + + diff = '\n'.join(difflib.context_diff(text1, text2, + fromfile=title1, tofile=title2)) + # Clean up line endings + diff = os.linesep.join([s for s in diff.splitlines() if s]) + return diff + def checkAddressSanitizerError(output, router, component): "Checks for AddressSanitizer in output. If found, then logs it and returns true, false otherwise" diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 90489e4bec..8c2b80382d 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -70,29 +70,9 @@ test_ospf6_topo1.py: -----/ """ -# import os -# import re -# import sys -# import difflib -# import StringIO -# import glob -# import subprocess - -# from mininet.topo import Topo -# from mininet.net import Mininet -# from mininet.node import Node, OVSSwitch, Host -# from mininet.log import setLogLevel, info -# from mininet.cli import CLI - -# from functools import partial -# from time import sleep - -# import pytest - import os import re import sys -import difflib import pytest from time import sleep @@ -295,9 +275,9 @@ def test_ospfv3_routingTable(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual OSPFv3 IPv6 routing table", - tofile="expected OSPFv3 IPv6 routing table")) + diff = topotest.get_textdiff(actual, expected, + title1="actual OSPFv3 IPv6 routing table", + title2="expected OSPFv3 IPv6 routing table") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -363,9 +343,9 @@ def test_linux_ipv6_kernel_routingTable(): # print(line.rstrip()) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual IPv6 kernel routing table", - tofile="expected IPv6 kernel routing table")) + diff = topotest.get_textdiff(actual, expected, + title1="actual OSPFv3 IPv6 routing table", + title2="expected OSPFv3 IPv6 routing table") # Empty string if it matches, otherwise diff contains unified diff if diff: diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py index 60b43ee42e..44be48c702 100755 --- a/tests/topotests/rip-topo1/test_rip_topo1.py +++ b/tests/topotests/rip-topo1/test_rip_topo1.py @@ -30,7 +30,6 @@ test_rip_topo1.py: Testing RIPv2 import os import re import sys -import difflib import pytest from time import sleep @@ -213,9 +212,9 @@ def test_rip_status(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual IP RIP status", - tofile="expected IP RIP status")) + diff = topotest.get_textdiff(actual, expected, + title1="actual IP RIP status", + title2="expected IP RIP status") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -265,9 +264,9 @@ def test_rip_routes(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW IP RIP", - tofile="expected SHOW IP RIP")) + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW IP RIP", + title2="expected SHOW IP RIP") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -317,9 +316,9 @@ def test_zebra_ipv4_routingTable(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual Zebra IPv4 routing table", - tofile="expected Zebra IPv4 routing table")) + diff = topotest.get_textdiff(actual, expected, + title1="actual Zebra IPv4 routing table", + title2="expected Zebra IPv4 routing table") # Empty string if it matches, otherwise diff contains unified diff if diff: diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py index e790808e3b..518f4e13e6 100755 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -30,7 +30,6 @@ test_ripng_topo1.py: Test of RIPng Topology import os import re import sys -import difflib import pytest import unicodedata from time import sleep @@ -216,9 +215,9 @@ def test_ripng_status(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual IPv6 RIPng status", - tofile="expected IPv6 RIPng status")) + diff = topotest.get_textdiff(actual, expected, + title1="actual IPv6 RIPng status", + title2="expected IPv6 RIPng status") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -273,9 +272,9 @@ def test_ripng_routes(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual SHOW IPv6 RIPng", - tofile="expected SHOW IPv6 RIPng")) + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW IPv6 RIPng", + title2="expected SHOW IPv6 RIPng") # Empty string if it matches, otherwise diff contains unified diff if diff: @@ -327,9 +326,9 @@ def test_zebra_ipv6_routingTable(): actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) # Generate Diff - diff = ''.join(difflib.context_diff(actual, expected, - fromfile="actual Zebra IPv6 routing table", - tofile="expected Zebra IPv6 routing table")) + diff = topotest.get_textdiff(actual, expected, + title1="actual Zebra IPv6 routing table", + title2="expected Zebra IPv6 routing table") # Empty string if it matches, otherwise diff contains unified diff if diff: From 9e05a644e9b4b5b041c1d63d9d081231920a3311 Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Tue, 30 May 2017 20:01:55 -0700 Subject: [PATCH 068/384] ospf6_topo1: Remove ff00:/8 routes from Linux Table compare Some Ubuntu VM setups show ff00:/8 kernel routes, not a FRR issue Signed-off-by: Martin Winter --- tests/topotests/ospf6-topo1/test_ospf6_topo1.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 8c2b80382d..f72a8082e3 100755 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -333,6 +333,12 @@ def test_linux_ipv6_kernel_routingTable(): actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0]) # Mask out protocol name or number actual = re.sub(r" proto [0-9a-z]+ ", " proto XXXX ", actual) + # Remove ff00::/8 routes (seen on some kernels - not from FRR) + actual = re.sub(r'ff00::/8.*', '', actual) + + # Strip empty lines + actual = actual.lstrip() + actual = actual.rstrip() # Fix newlines (make them all the same) actual = ('\n'.join(actual.splitlines())).splitlines(1) From c8cff3ced1afd20a041bc36a185540dab72cc56d Mon Sep 17 00:00:00 2001 From: Martin Winter Date: Tue, 30 May 2017 20:24:20 -0700 Subject: [PATCH 069/384] lib: Fix stopRouter not to fail for case if daemon was never started Fixes the issue for topotest to fail ot end of skipped LDP test on a system without MPLS support Signed-off-by: Martin Winter --- tests/topotests/lib/topotest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 6572bc3390..b5505d559c 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -173,7 +173,7 @@ class Router(Node): if rundaemons is not None: for d in StringIO.StringIO(rundaemons): daemonpid = self.cmd('cat %s' % d.rstrip()).rstrip() - if pid_exists(int(daemonpid)): + if (daemonpid.isdigit() and pid_exists(int(daemonpid))): self.cmd('kill -7 %s' % daemonpid) self.waitOutput() def removeIPs(self): From 0e5ae9cc1d84de32ba8ff7175ce3982bf872609a Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 15 Jun 2017 10:41:20 -0300 Subject: [PATCH 070/384] ldp-topo1: add some debug commands to facilitate troubleshooting Signed-off-by: Renato Westphal --- tests/topotests/ldp-topo1/r1/ldpd.conf | 8 ++++++++ tests/topotests/ldp-topo1/r2/ldpd.conf | 8 ++++++++ tests/topotests/ldp-topo1/r3/ldpd.conf | 8 ++++++++ tests/topotests/ldp-topo1/r4/ldpd.conf | 8 ++++++++ 4 files changed, 32 insertions(+) diff --git a/tests/topotests/ldp-topo1/r1/ldpd.conf b/tests/topotests/ldp-topo1/r1/ldpd.conf index 9f1d43d78f..428b674106 100644 --- a/tests/topotests/ldp-topo1/r1/ldpd.conf +++ b/tests/topotests/ldp-topo1/r1/ldpd.conf @@ -1,6 +1,14 @@ hostname r1 log file /tmp/r1-ldpd.log ! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! mpls ldp router-id 1.1.1.1 ! diff --git a/tests/topotests/ldp-topo1/r2/ldpd.conf b/tests/topotests/ldp-topo1/r2/ldpd.conf index cb56c4cf66..9bba8d8387 100644 --- a/tests/topotests/ldp-topo1/r2/ldpd.conf +++ b/tests/topotests/ldp-topo1/r2/ldpd.conf @@ -1,6 +1,14 @@ hostname r2 log file /tmp/r2-ldpd.log ! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! mpls ldp router-id 2.2.2.2 ! diff --git a/tests/topotests/ldp-topo1/r3/ldpd.conf b/tests/topotests/ldp-topo1/r3/ldpd.conf index a62a43f0c0..53ccf9ed17 100644 --- a/tests/topotests/ldp-topo1/r3/ldpd.conf +++ b/tests/topotests/ldp-topo1/r3/ldpd.conf @@ -1,6 +1,14 @@ hostname r3 log file /tmp/r3-ldpd.log ! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! mpls ldp router-id 3.3.3.3 ! diff --git a/tests/topotests/ldp-topo1/r4/ldpd.conf b/tests/topotests/ldp-topo1/r4/ldpd.conf index 0391f4ee4d..7bfdf7f3a8 100644 --- a/tests/topotests/ldp-topo1/r4/ldpd.conf +++ b/tests/topotests/ldp-topo1/r4/ldpd.conf @@ -1,6 +1,14 @@ hostname r4 log file /tmp/r4-ldpd.log ! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! mpls ldp router-id 4.4.4.4 ! From fa05076643d39dacc7c7c5cd3ba28ed7b1fad4cb Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 15 Jun 2017 10:47:15 -0300 Subject: [PATCH 071/384] ldp-topo1: sync with PR#710 in FRR Now zebra is adding the ldpd implicit-null labels to the RIB as well. We don't want to hide them in the "show ip route" commands because knowing that a route is associated with an implicit-null label is an useful piece of information, specially when troubleshooting L2/L3 VPNs. Note: preserve the original output for cli version 1 (stable/2.0). Signed-off-by: Renato Westphal --- tests/topotests/ldp-topo1/r1/show_ipv4_route.ref | 6 +++--- tests/topotests/ldp-topo1/r2/show_ipv4_route.ref | 6 +++--- tests/topotests/ldp-topo1/r3/show_ipv4_route.ref | 6 +++--- tests/topotests/ldp-topo1/r4/show_ipv4_route.ref | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref index ff99ff9866..aadf03aa49 100644 --- a/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref +++ b/tests/topotests/ldp-topo1/r1/show_ipv4_route.ref @@ -1,7 +1,7 @@ O 1.1.1.1/32 [110/0] is directly connected, lo -O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0 +O>* 2.2.2.2/32 [110/10] via 10.0.1.2, r1-eth0, label xxx O>* 3.3.3.3/32 [110/20] via 10.0.1.2, r1-eth0, label xxx O>* 4.4.4.4/32 [110/20] via 10.0.1.2, r1-eth0, label xxx O 10.0.1.0/24 [110/10] is directly connected, r1-eth0 -O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0 -O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0 +O>* 10.0.2.0/24 [110/20] via 10.0.1.2, r1-eth0, label xxx +O>* 10.0.3.0/24 [110/20] via 10.0.1.2, r1-eth0, label xxx diff --git a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref index eaec2f16b9..db997018ea 100644 --- a/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref +++ b/tests/topotests/ldp-topo1/r2/show_ipv4_route.ref @@ -1,7 +1,7 @@ -O>* 1.1.1.1/32 [110/10] via 10.0.1.1, r2-eth0 +O>* 1.1.1.1/32 [110/10] via 10.0.1.1, r2-eth0, label xxx O 2.2.2.2/32 [110/0] is directly connected, lo -O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r2-eth1 -O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r2-eth1 +O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r2-eth1, label xxx +O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r2-eth1, label xxx O 10.0.1.0/24 [110/10] is directly connected, r2-eth0 O 10.0.2.0/24 [110/10] is directly connected, r2-eth1 O 10.0.3.0/24 [110/10] is directly connected, r2-eth2 diff --git a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref index c8a29400b2..e5989a975f 100644 --- a/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref +++ b/tests/topotests/ldp-topo1/r3/show_ipv4_route.ref @@ -1,7 +1,7 @@ O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r3-eth0, label xxx -O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0 +O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r3-eth0, label xxx O 3.3.3.3/32 [110/0] is directly connected, lo -O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0 -O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r3-eth0 +O>* 4.4.4.4/32 [110/10] via 10.0.2.4, r3-eth0, label xxx +O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r3-eth0, label xxx O 10.0.2.0/24 [110/10] is directly connected, r3-eth0 O 10.0.3.0/24 [110/10] is directly connected, r3-eth1 diff --git a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref index df2a2b585f..5ffaf78504 100644 --- a/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref +++ b/tests/topotests/ldp-topo1/r4/show_ipv4_route.ref @@ -1,7 +1,7 @@ O>* 1.1.1.1/32 [110/20] via 10.0.2.2, r4-eth0, label xxx -O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0 -O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0 +O>* 2.2.2.2/32 [110/10] via 10.0.2.2, r4-eth0, label xxx +O>* 3.3.3.3/32 [110/10] via 10.0.2.3, r4-eth0, label xxx O 4.4.4.4/32 [110/0] is directly connected, lo -O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r4-eth0 +O>* 10.0.1.0/24 [110/20] via 10.0.2.2, r4-eth0, label xxx O 10.0.2.0/24 [110/10] is directly connected, r4-eth0 -O>* 10.0.3.0/24 [110/20] via 10.0.2.2, r4-eth0 +O>* 10.0.3.0/24 [110/20] via 10.0.2.2, r4-eth0, label xxx From 797e8dcf5c946968c8253a0819206e431f61f6d3 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 14 Jun 2017 10:30:10 -0300 Subject: [PATCH 072/384] lib: assert sysctl values Implemented two functions to help setting sysctl values: * set_sysctl: set a sysctl and return an auditable return value * assert_sysctl: uses the previous function to assert that the sysctl was set --- tests/topotests/lib/topotest.py | 43 ++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index b5505d559c..e24c7ca5b5 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -114,20 +114,40 @@ def addRouter(topo, name): '/var/log'] return topo.addNode(name, cls=Router, privateDirs=MyPrivateDirs) +def set_sysctl(node, sysctl, value): + "Set a sysctl value and return None on success or an error string" + valuestr = '{}'.format(value) + command = "sysctl {0}={1}".format(sysctl, valuestr) + cmdret = node.cmd(command) + + matches = re.search(r'([^ ]+) = ([^\s]+)', cmdret) + if matches is None: + return cmdret + if matches.group(1) != sysctl: + return cmdret + if matches.group(2) != valuestr: + return cmdret + + return None + +def assert_sysctl(node, sysctl, value): + "Set and assert that the sysctl is set with the specified value." + assert set_sysctl(node, sysctl, value) is None + class LinuxRouter(Node): "A Node with IPv4/IPv6 forwarding enabled." def config(self, **params): super(LinuxRouter, self).config(**params) # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + assert_sysctl(self, 'net.ipv4.ip_forward', 1) + assert_sysctl(self, 'net.ipv6.conf.all.forwarding', 1) def terminate(self): """ Terminate generic LinuxRouter Mininet instance """ - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + set_sysctl(self, 'net.ipv4.ip_forward', 0) + set_sysctl(self, 'net.ipv6.conf.all.forwarding', 0) super(LinuxRouter, self).terminate() class Router(Node): @@ -144,12 +164,13 @@ class Router(Node): else: raise Exception('No FRR or Quagga found in ususal location') # Enable forwarding on the router - self.cmd('sysctl net.ipv4.ip_forward=1') - self.cmd('sysctl net.ipv6.conf.all.forwarding=1') + assert_sysctl(self, 'net.ipv4.ip_forward', 1) + assert_sysctl(self, 'net.ipv6.conf.all.forwarding', 1) # Enable coredumps - self.cmd('sysctl kernel.core_uses_pid=1') - self.cmd('sysctl fs.suid_dumpable=2') - self.cmd("sysctl kernel.core_pattern=/tmp/%s_%%e_core-sig_%%s-pid_%%p.dmp" % self.name) + assert_sysctl(self, 'kernel.core_uses_pid', 1) + assert_sysctl(self, 'fs.suid_dumpable', 2) + corefile = '/tmp/{0}_%e_core-sig_%s-pid_%p.dmp'.format(self.name) + assert_sysctl(self, 'kernel.core_pattern', corefile) self.cmd('ulimit -c unlimited') # Set ownership of config files self.cmd('chown %s:%svty /etc/%s' % (self.routertype, self.routertype, self.routertype)) @@ -164,8 +185,8 @@ class Router(Node): # self.cmd('kill -7 `cat %s`' % d.rstrip()) # self.waitOutput() # Disable forwarding - self.cmd('sysctl net.ipv4.ip_forward=0') - self.cmd('sysctl net.ipv6.conf.all.forwarding=0') + set_sysctl(self, 'net.ipv4.ip_forward', 0) + set_sysctl(self, 'net.ipv6.conf.all.forwarding', 0) super(Router, self).terminate() def stopRouter(self): # Stop Running Quagga or FRR Daemons From 1fca63c1e43243f3b4c27c193b74cb965e59bbe4 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Thu, 15 Jun 2017 00:25:54 -0300 Subject: [PATCH 073/384] topogen: first code import Topogen (Topology Generator) is a helper that wraps around Topotest to simplify some of the boilerplate code. This abstraction will help the development of new tests and new APIs without breaking the existing ones. It also makes the relation of objects clearer, since we no longer touch the Mininet API directly, which in turn also makes us less vulnerable to external API changes. --- tests/topotests/conftest.py | 26 ++ tests/topotests/example-test/test_template.py | 107 +++++ tests/topotests/lib/topogen.py | 380 ++++++++++++++++++ tests/topotests/lib/topotest.py | 36 ++ 4 files changed, 549 insertions(+) create mode 100644 tests/topotests/conftest.py create mode 100644 tests/topotests/example-test/test_template.py create mode 100644 tests/topotests/lib/topogen.py diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py new file mode 100644 index 0000000000..e042a3d13a --- /dev/null +++ b/tests/topotests/conftest.py @@ -0,0 +1,26 @@ +""" +Topotest conftest.py file. +""" + +from lib.topogen import get_topogen +import pytest + +def pytest_addoption(parser): + """ + Add topology-only option to the topology tester. This option makes pytest + only run the setup_module() to setup the topology without running any tests. + """ + parser.addoption('--topology-only', action='store_true', + help='Only set up this topology, don\'t run tests') + +def pytest_runtest_call(): + """ + This function must be run after setup_module(), it does standarized post + setup routines. It is only being used for the 'topology-only' option. + """ + # pylint: disable=E1101 + # Trust me, 'config' exists. + if pytest.config.getoption('--topology-only'): + # Allow user to play with the setup. + get_topogen().mininet_cli() + pytest.exit('the topology executed successfully') diff --git a/tests/topotests/example-test/test_template.py b/tests/topotests/example-test/test_template.py new file mode 100644 index 0000000000..53a4f444cc --- /dev/null +++ b/tests/topotests/example-test/test_template.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +# +#