diff --git a/rip-topo1-vrf/r1/rip_status.ref b/rip-topo1-vrf/r1/rip_status.ref new file mode 100644 index 0000000..30c840e --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r1/ripd.conf b/rip-topo1-vrf/r1/ripd.conf new file mode 100644 index 0000000..2bde254 --- /dev/null +++ b/rip-topo1-vrf/r1/ripd.conf @@ -0,0 +1,10 @@ +log file ripd.log +! +router rip vrf r1-cust1 + version 2 + network 193.1.1.0/26 +! +line vty +! + + diff --git a/rip-topo1-vrf/r1/show_ip_rip.ref b/rip-topo1-vrf/r1/show_ip_rip.ref new file mode 100644 index 0000000..561560f --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r1/show_ip_route.ref b/rip-topo1-vrf/r1/show_ip_route.ref new file mode 100644 index 0000000..62d71f0 --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r1/zebra.conf b/rip-topo1-vrf/r1/zebra.conf new file mode 100644 index 0000000..303c313 --- /dev/null +++ b/rip-topo1-vrf/r1/zebra.conf @@ -0,0 +1,19 @@ +log file zebra.log +! +hostname r1 +! +interface r1-eth0 vrf r1-cust1 + ip address 192.168.1.1/24 +! +interface r1-eth1 vrf r1-cust1 + description to sw2 - RIPv2 interface + ip address 193.1.1.1/26 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/rip-topo1-vrf/r1/zebra.conf~ b/rip-topo1-vrf/r1/zebra.conf~ new file mode 100644 index 0000000..6429a0e --- /dev/null +++ b/rip-topo1-vrf/r1/zebra.conf~ @@ -0,0 +1,20 @@ +log file zebra.log +! +hostname r1 +password zebra +! +interface r1-eth0 vrf r1-cust1 + ip address 192.168.1.1/24 +! +interface r1-eth1 vrf r1-cust1 + description to sw2 - RIPv2 interface + ip address 193.1.1.1/26 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/rip-topo1-vrf/r2/rip_status.ref b/rip-topo1-vrf/r2/rip_status.ref new file mode 100644 index 0000000..b539d32 --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r2/ripd.conf b/rip-topo1-vrf/r2/ripd.conf new file mode 100644 index 0000000..47add3b --- /dev/null +++ b/rip-topo1-vrf/r2/ripd.conf @@ -0,0 +1,13 @@ +log file ripd.log +! +! +router rip vrf r2-cust1 + version 2 + network 193.1.1.0/26 + network 193.1.2.0/24 +! +line vty +! + + + diff --git a/rip-topo1-vrf/r2/show_ip_rip.ref b/rip-topo1-vrf/r2/show_ip_rip.ref new file mode 100644 index 0000000..58ab052 --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r2/show_ip_route.ref b/rip-topo1-vrf/r2/show_ip_route.ref new file mode 100644 index 0000000..4b34939 --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r2/zebra.conf b/rip-topo1-vrf/r2/zebra.conf new file mode 100644 index 0000000..529a661 --- /dev/null +++ b/rip-topo1-vrf/r2/zebra.conf @@ -0,0 +1,21 @@ +log file zebra.log +! +hostname r2 +! +interface r2-eth0 vrf r2-cust1 + description to sw2 - RIPv2 interface + ip address 193.1.1.2/26 + no link-detect +! +interface r2-eth1 vrf r2-cust1 + description to sw3 - RIPv1 interface + ip address 193.1.2.1/24 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/rip-topo1-vrf/r3/rip_status.ref b/rip-topo1-vrf/r3/rip_status.ref new file mode 100644 index 0000000..0e3a4be --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r3/ripd.conf b/rip-topo1-vrf/r3/ripd.conf new file mode 100644 index 0000000..f966783 --- /dev/null +++ b/rip-topo1-vrf/r3/ripd.conf @@ -0,0 +1,13 @@ +log file ripd.log +! +! +router rip vrf r3-cust1 + version 2 + redistribute connected + redistribute static + network 193.1.2.0/24 +! +line vty +! + + diff --git a/rip-topo1-vrf/r3/show_ip_rip.ref b/rip-topo1-vrf/r3/show_ip_rip.ref new file mode 100644 index 0000000..cf67271 --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r3/show_ip_route.ref b/rip-topo1-vrf/r3/show_ip_route.ref new file mode 100644 index 0000000..835e122 --- /dev/null +++ b/rip-topo1-vrf/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/rip-topo1-vrf/r3/zebra.conf b/rip-topo1-vrf/r3/zebra.conf new file mode 100644 index 0000000..a7dd33c --- /dev/null +++ b/rip-topo1-vrf/r3/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname r3 +! +interface r3-eth0 vrf r3-cust1 + description to sw4 - Stub interface + ip address 192.168.3.1/24 + no link-detect +! +interface r3-eth1 vrf r3-cust1 + 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 vrf r3-cust1 +! +ip forwarding +ipv6 forwarding +! +! +line vty +! diff --git a/rip-topo1-vrf/test_rip_topo1_vrf.dot b/rip-topo1-vrf/test_rip_topo1_vrf.dot new file mode 100644 index 0000000..2b1524b --- /dev/null +++ b/rip-topo1-vrf/test_rip_topo1_vrf.dot @@ -0,0 +1,60 @@ +## GraphViz file for test_rip_topo1_vrf +## +## 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_vrf { + 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/rip-topo1-vrf/test_rip_topo1_vrf.pdf b/rip-topo1-vrf/test_rip_topo1_vrf.pdf new file mode 100644 index 0000000..c201ac1 Binary files /dev/null and b/rip-topo1-vrf/test_rip_topo1_vrf.pdf differ diff --git a/rip-topo1-vrf/test_rip_topo1_vrf.py b/rip-topo1-vrf/test_rip_topo1_vrf.py new file mode 100755 index 0000000..3f7e63c --- /dev/null +++ b/rip-topo1-vrf/test_rip_topo1_vrf.py @@ -0,0 +1,365 @@ +#!/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_vrf.py: Testing RIPv2 under VRF NETNS + +""" + +import os +import re +import sys +import pytest +import getopt +from time import sleep + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +CustomizeVrfWithNetns = True + + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class RIPVRFNETNSTopo1(Topo): + "RIP VRF NETNS Topology 1" + + def build(self, **_opts): + tgen = get_topogen(self) + + # Setup RIP Routers + for i in range(1, 4): + tgen.add_router('r%s' % i) + + # Setup Switches + # + # On main router + # Switches for RIP + # First switch is for a dummy interface (for local network) + switch1 = tgen.add_switch('s1') + switch1.add_link(tgen.gears['r1'], nodeif='r1-eth0') + + # switch 2 switch is for connection to RIP router + switch2 = tgen.add_switch('s2') + switch2.add_link(tgen.gears['r1'], nodeif='r1-eth1') + switch2.add_link(tgen.gears['r2'], nodeif='r2-eth0') + + # switch 3 is between RIP routers + switch3 = tgen.add_switch('s3') + switch3.add_link(tgen.gears['r2'], nodeif='r2-eth1') + switch3.add_link(tgen.gears['r3'], nodeif='r3-eth1') + + # switch 4 is stub on remote RIP router + switch4 = tgen.add_switch('s4') + switch4.add_link(tgen.gears['r3'], nodeif='r3-eth0') + + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + tgen = Topogen(RIPVRFNETNSTopo1, module.__name__) + tgen.start_topology() + + # Get r1 reference + router = tgen.gears['r1'] + + # check for zebra capability + if CustomizeVrfWithNetns == True: + if router.check_capability( + TopoRouter.RD_ZEBRA, + '--vrfwnetns' + ) == False: + return pytest.skip('Skipping RIP VRF NETNS Test. VRF NETNS backend not available on FRR') + if os.system('ip netns list') != 0: + return pytest.skip('Skipping RIP VRF NETNS Test. NETNS not available on System') + # retrieve VRF backend kind + if CustomizeVrfWithNetns == True: + logger.info('Testing with VRF Namespace support') + + print("Testing with VRF Namespace support\n") + + cmds = ['if [ -e /var/run/netns/r{0}-cust1 ] ; then ip netns del r{0}-cust1 ; fi', + 'ip netns add r{0}-cust1', + 'ip link set dev r{0}-eth0 netns r{0}-cust1', + 'ip netns exec r{0}-cust1 ifconfig r{0}-eth0 up', + 'ip netns exec r{0}-cust1 ifconfig lo 127.0.0.1 up', + 'ip link set dev r{0}-eth1 netns r{0}-cust1', + 'ip netns exec r{0}-cust1 ifconfig r{0}-eth1 up'] + + # create VRF rx-cust1 and link rx-eth0 to rx-cust1 + for i in range(1, 4): + for cmd in cmds: + tgen.gears['r%s' % i].run(cmd.format(i)) + + # Starting Routers + # + for i in range(1, 4): + router = tgen.gears['r%s' % i] + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format('r%s' % i)), + '--vrfwnetns' + ) + router.load_config( + TopoRouter.RD_RIP, + os.path.join(CWD, '{}/ripd.conf'.format('r%s' % i)) + ) + router.start() + + # For debugging after starting Quagga/FRR daemons, uncomment the next line + # tgen.mininet_cli() + + +def teardown_module(module): + tgen = get_topogen() + + print("\n\n** %s: Shutdown Topology" % module.__name__) + print("******************************************\n") + + cmds = ['ip netns exec r{0}-cust1 ip link set r{0}-eth0 netns 1', + 'ip netns exec r{0}-cust1 ip link set r{0}-eth1 netns 1', + 'ip netns delete r{0}-cust1'] + + for i in range(1, 4): + for cmd in cmds: + tgen.gears['r%s' % i].run(cmd.format(i)) + + tgen.stop_topology() + +def test_converge_protocols(): + "Test for RIP topology convergence" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + print("\n\n** Waiting for protocols convergence") + print("******************************************\n") + + # Not really implemented yet - just sleep 60 secs for now + # tgen.mininet_cli() + sleep(60) + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # tgen.mininet_cli() + + +def test_rip_status(): + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + 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 = tgen.gears['r%s' % i].run('vtysh -c "show ip rip vrf r{0}-cust1 status" 2> /dev/null'.format(i)).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 = 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: + 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) + + # Make sure that all daemons are still running + for i in range(1, 4): + fatal_error = tgen.gears['r%s' % i].check_router_running() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # tgen.mininet_cli() + + +def test_rip_routes(): + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + 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 = tgen.gears['r%s' % i].run('vtysh -c "show ip rip vrf r{0}-cust1" 2> /dev/null'.format(i)).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 = 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: + 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) + + # Make sure that all daemons are still running + for i in range(1, 4): + fatal_error = tgen.gears['r%s' % i].check_router_running() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # tgen.mininet_cli() + + +def test_zebra_ipv4_routingTable(): + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + 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 = tgen.gears['r%s' % i].run('vtysh -c "show ip route vrf r{0}-cust1" 2> /dev/null | grep "^R"'.format(i)).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 = 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: + 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) + + # Make sure that all daemons are still running + for i in range(1, 4): + fatal_error = tgen.gears['r%s' % i].check_router_running() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # tgen.mininet_cli() + + +def test_shutdown_check_stderr(): + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + 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") + + tgen.gears['r1'].stop() + + +if __name__ == '__main__': + + args = ["-s"] + sys.argv[1:] + ret = pytest.main(args) + + sys.exit(ret) +