From 6024e0b5dee842f6d34af12b7ca1a171b947cf60 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Mon, 19 Jun 2017 16:18:25 -0300 Subject: [PATCH] ospf: added convergence test for IPv4 Added a convergence test for OSPF (IPv4) using the new topology builder Topogen. --- tests/topotests/ospf-topo1/__init__.py | 0 tests/topotests/ospf-topo1/r1/ospfd.conf | 10 ++ tests/topotests/ospf-topo1/r1/ospfroute.txt | 23 +++ tests/topotests/ospf-topo1/r1/zebra.conf | 14 ++ tests/topotests/ospf-topo1/r2/ospfd.conf | 10 ++ tests/topotests/ospf-topo1/r2/ospfroute.txt | 23 +++ tests/topotests/ospf-topo1/r2/zebra.conf | 14 ++ tests/topotests/ospf-topo1/r3/ospfd.conf | 11 ++ tests/topotests/ospf-topo1/r3/ospfroute.txt | 23 +++ tests/topotests/ospf-topo1/r3/zebra.conf | 17 +++ tests/topotests/ospf-topo1/r4/ospfd.conf | 10 ++ tests/topotests/ospf-topo1/r4/ospfroute.txt | 23 +++ tests/topotests/ospf-topo1/r4/zebra.conf | 14 ++ .../topotests/ospf-topo1/test_ospf_topo1.dot | 95 ++++++++++++ .../topotests/ospf-topo1/test_ospf_topo1.jpg | Bin 0 -> 48388 bytes tests/topotests/ospf-topo1/test_ospf_topo1.py | 139 ++++++++++++++++++ 16 files changed, 426 insertions(+) create mode 100755 tests/topotests/ospf-topo1/__init__.py create mode 100644 tests/topotests/ospf-topo1/r1/ospfd.conf create mode 100644 tests/topotests/ospf-topo1/r1/ospfroute.txt create mode 100644 tests/topotests/ospf-topo1/r1/zebra.conf create mode 100644 tests/topotests/ospf-topo1/r2/ospfd.conf create mode 100644 tests/topotests/ospf-topo1/r2/ospfroute.txt create mode 100644 tests/topotests/ospf-topo1/r2/zebra.conf create mode 100644 tests/topotests/ospf-topo1/r3/ospfd.conf create mode 100644 tests/topotests/ospf-topo1/r3/ospfroute.txt create mode 100644 tests/topotests/ospf-topo1/r3/zebra.conf create mode 100644 tests/topotests/ospf-topo1/r4/ospfd.conf create mode 100644 tests/topotests/ospf-topo1/r4/ospfroute.txt create mode 100644 tests/topotests/ospf-topo1/r4/zebra.conf create mode 100644 tests/topotests/ospf-topo1/test_ospf_topo1.dot create mode 100644 tests/topotests/ospf-topo1/test_ospf_topo1.jpg create mode 100755 tests/topotests/ospf-topo1/test_ospf_topo1.py diff --git a/tests/topotests/ospf-topo1/__init__.py b/tests/topotests/ospf-topo1/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tests/topotests/ospf-topo1/r1/ospfd.conf b/tests/topotests/ospf-topo1/r1/ospfd.conf new file mode 100644 index 0000000000..f1b43b8214 --- /dev/null +++ b/tests/topotests/ospf-topo1/r1/ospfd.conf @@ -0,0 +1,10 @@ +log file /tmp/r1-ospfd.log +! +router ospf + ospf router-id 10.0.255.1 + redistribute kernel + redistribute connected + redistribute static + network 10.0.1.0/24 area 0 + network 10.0.3.0/24 area 0 +! diff --git a/tests/topotests/ospf-topo1/r1/ospfroute.txt b/tests/topotests/ospf-topo1/r1/ospfroute.txt new file mode 100644 index 0000000000..db648722f5 --- /dev/null +++ b/tests/topotests/ospf-topo1/r1/ospfroute.txt @@ -0,0 +1,23 @@ +============ OSPF network routing table ============ +N 10.0.1.0/24 [10] area: 0.0.0.0 + directly attached to r1-eth0 +N 10.0.2.0/24 [20] area: 0.0.0.0 + via 10.0.3.3, r1-eth1 +N 10.0.3.0/24 [10] area: 0.0.0.0 + directly attached to r1-eth1 +N 10.0.10.0/24 [20] area: 0.0.0.0 + via 10.0.3.1, r1-eth1 +N IA 172.16.0.0/24 [20] area: 0.0.0.0 + via 10.0.3.1, r1-eth1 +N IA 172.16.1.0/24 [30] area: 0.0.0.0 + via 10.0.3.1, r1-eth1 + +============ OSPF router routing table ============= +R 10.0.255.2 [10] area: 0.0.0.0, ASBR + via 10.0.3.3, r1-eth1 +R 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR + via 10.0.3.1, r1-eth1 +R 10.0.255.4 IA [20] area: 0.0.0.0, ASBR + via 10.0.3.1, r1-eth1 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf-topo1/r1/zebra.conf b/tests/topotests/ospf-topo1/r1/zebra.conf new file mode 100644 index 0000000000..152d3c0a90 --- /dev/null +++ b/tests/topotests/ospf-topo1/r1/zebra.conf @@ -0,0 +1,14 @@ +! +hostname r1 +log file /tmp/r1-zebra.log +! +interface r1-eth0 + ip address 10.0.1.1/24 +! +interface r1-eth1 + ip address 10.0.3.2/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-topo1/r2/ospfd.conf b/tests/topotests/ospf-topo1/r2/ospfd.conf new file mode 100644 index 0000000000..11c416d574 --- /dev/null +++ b/tests/topotests/ospf-topo1/r2/ospfd.conf @@ -0,0 +1,10 @@ +log file /tmp/r1-ospfd.log +! +router ospf + ospf router-id 10.0.255.2 + redistribute kernel + redistribute connected + redistribute static + network 10.0.2.0/24 area 0 + network 10.0.3.0/24 area 0 +! diff --git a/tests/topotests/ospf-topo1/r2/ospfroute.txt b/tests/topotests/ospf-topo1/r2/ospfroute.txt new file mode 100644 index 0000000000..79b389baab --- /dev/null +++ b/tests/topotests/ospf-topo1/r2/ospfroute.txt @@ -0,0 +1,23 @@ +============ OSPF network routing table ============ +N 10.0.1.0/24 [20] area: 0.0.0.0 + via 10.0.3.2, r2-eth1 +N 10.0.2.0/24 [10] area: 0.0.0.0 + directly attached to r2-eth0 +N 10.0.3.0/24 [10] area: 0.0.0.0 + directly attached to r2-eth1 +N 10.0.10.0/24 [20] area: 0.0.0.0 + via 10.0.3.1, r2-eth1 +N IA 172.16.0.0/24 [20] area: 0.0.0.0 + via 10.0.3.1, r2-eth1 +N IA 172.16.1.0/24 [30] area: 0.0.0.0 + via 10.0.3.1, r2-eth1 + +============ OSPF router routing table ============= +R 10.0.255.1 [10] area: 0.0.0.0, ASBR + via 10.0.3.2, r2-eth1 +R 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR + via 10.0.3.1, r2-eth1 +R 10.0.255.4 IA [20] area: 0.0.0.0, ASBR + via 10.0.3.1, r2-eth1 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf-topo1/r2/zebra.conf b/tests/topotests/ospf-topo1/r2/zebra.conf new file mode 100644 index 0000000000..35d9c96b54 --- /dev/null +++ b/tests/topotests/ospf-topo1/r2/zebra.conf @@ -0,0 +1,14 @@ +! +hostname r2 +log file /tmp/r2-zebra.log +! +interface r2-eth0 + ip address 10.0.2.1/24 +! +interface r2-eth1 + ip address 10.0.3.3/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-topo1/r3/ospfd.conf b/tests/topotests/ospf-topo1/r3/ospfd.conf new file mode 100644 index 0000000000..00023e2ba9 --- /dev/null +++ b/tests/topotests/ospf-topo1/r3/ospfd.conf @@ -0,0 +1,11 @@ +log file /tmp/r3-ospfd.log +! +router ospf + ospf router-id 10.0.255.3 + redistribute kernel + redistribute connected + redistribute static + network 10.0.3.0/24 area 0 + network 10.0.10.0/24 area 0 + network 172.16.0.0/24 area 1 +! diff --git a/tests/topotests/ospf-topo1/r3/ospfroute.txt b/tests/topotests/ospf-topo1/r3/ospfroute.txt new file mode 100644 index 0000000000..c7799065d9 --- /dev/null +++ b/tests/topotests/ospf-topo1/r3/ospfroute.txt @@ -0,0 +1,23 @@ +============ OSPF network routing table ============ +N 10.0.1.0/24 [20] area: 0.0.0.0 + via 10.0.3.2, r3-eth0 +N 10.0.2.0/24 [20] area: 0.0.0.0 + via 10.0.3.3, r3-eth0 +N 10.0.3.0/24 [10] area: 0.0.0.0 + directly attached to r3-eth0 +N 10.0.10.0/24 [10] area: 0.0.0.0 + directly attached to r3-eth1 +N 172.16.0.0/24 [10] area: 0.0.0.1 + directly attached to r3-eth2 +N 172.16.1.0/24 [20] area: 0.0.0.1 + via 172.16.0.1, r3-eth2 + +============ OSPF router routing table ============= +R 10.0.255.1 [10] area: 0.0.0.0, ASBR + via 10.0.3.2, r3-eth0 +R 10.0.255.2 [10] area: 0.0.0.0, ASBR + via 10.0.3.3, r3-eth0 +R 10.0.255.4 [10] area: 0.0.0.1, ASBR + via 172.16.0.1, r3-eth2 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf-topo1/r3/zebra.conf b/tests/topotests/ospf-topo1/r3/zebra.conf new file mode 100644 index 0000000000..7521a9b95b --- /dev/null +++ b/tests/topotests/ospf-topo1/r3/zebra.conf @@ -0,0 +1,17 @@ +! +hostname r3 +log file /tmp/r3-zebra.log +! +interface r3-eth0 + ip address 10.0.3.1/24 +! +interface r3-eth1 + ip address 10.0.10.1/24 +! +interface r3-eth2 + ip address 172.16.0.2/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-topo1/r4/ospfd.conf b/tests/topotests/ospf-topo1/r4/ospfd.conf new file mode 100644 index 0000000000..6826808c52 --- /dev/null +++ b/tests/topotests/ospf-topo1/r4/ospfd.conf @@ -0,0 +1,10 @@ +log file /tmp/r4-ospfd.log +! +router ospf + ospf router-id 10.0.255.4 + redistribute kernel + redistribute connected + redistribute static + network 172.16.0.0/24 area 1 + network 172.16.1.0/24 area 1 +! diff --git a/tests/topotests/ospf-topo1/r4/ospfroute.txt b/tests/topotests/ospf-topo1/r4/ospfroute.txt new file mode 100644 index 0000000000..b582ef043b --- /dev/null +++ b/tests/topotests/ospf-topo1/r4/ospfroute.txt @@ -0,0 +1,23 @@ +============ OSPF network routing table ============ +N IA 10.0.1.0/24 [30] area: 0.0.0.1 + via 172.16.0.2, r4-eth0 +N IA 10.0.2.0/24 [30] area: 0.0.0.1 + via 172.16.0.2, r4-eth0 +N IA 10.0.3.0/24 [20] area: 0.0.0.1 + via 172.16.0.2, r4-eth0 +N IA 10.0.10.0/24 [20] area: 0.0.0.1 + via 172.16.0.2, r4-eth0 +N 172.16.0.0/24 [10] area: 0.0.0.1 + directly attached to r4-eth0 +N 172.16.1.0/24 [10] area: 0.0.0.1 + directly attached to r4-eth1 + +============ OSPF router routing table ============= +R 10.0.255.1 IA [20] area: 0.0.0.1, ASBR + via 172.16.0.2, r4-eth0 +R 10.0.255.2 IA [20] area: 0.0.0.1, ASBR + via 172.16.0.2, r4-eth0 +R 10.0.255.3 [10] area: 0.0.0.1, ABR, ASBR + via 172.16.0.2, r4-eth0 + +============ OSPF external routing table =========== diff --git a/tests/topotests/ospf-topo1/r4/zebra.conf b/tests/topotests/ospf-topo1/r4/zebra.conf new file mode 100644 index 0000000000..d90bdc6cf4 --- /dev/null +++ b/tests/topotests/ospf-topo1/r4/zebra.conf @@ -0,0 +1,14 @@ +! +hostname r4 +log file /tmp/r4-zebra.log +! +interface r4-eth0 + ip address 172.16.0.1/24 +! +interface r4-eth1 + ip address 172.16.1.100/24 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.dot b/tests/topotests/ospf-topo1/test_ospf_topo1.dot new file mode 100644 index 0000000000..25ee214b1c --- /dev/null +++ b/tests/topotests/ospf-topo1/test_ospf_topo1.dot @@ -0,0 +1,95 @@ +## 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 ospf_topo1 { + label="ospf topo1"; + + # Routers + r1 [ + label="r1\nrtr-id 10.0.255.1/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r2 [ + label="r2\nrtr-id 10.0.255.2/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r3 [ + label="r3\nrtr-id 10.0.255.3/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r4 [ + label="r4\nrtr-id 10.0.255.4/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + label="s1\n10.0.1.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + label="s2\n10.0.2.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s3 [ + label="s3\n10.0.3.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s4 [ + label="s4\n10.0.10.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s5 [ + label="s5\n172.16.0.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s6 [ + label="s6\n172.16.1.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- s1 [label="eth0\n.1"]; + r1 -- s3 [label="eth1\n.2"]; + + r2 -- s2 [label="eth0\n.1"]; + r2 -- s3 [label="eth1\n.3"]; + + r3 -- s3 [label="eth0\n.1"]; + r3 -- s4 [label="eth1\n.1"]; + r3 -- s5 [label="eth2\n.2"]; + + r4 -- s5 [label="eth0\n.1"]; + r4 -- s6 [label="eth1\n.100"]; +} diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.jpg b/tests/topotests/ospf-topo1/test_ospf_topo1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b01f46278a58cd88259d03a6d0f353fed4aab06e GIT binary patch literal 48388 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 R=#TfmpZ}-N0RNxq{{Rw5=m-D+ literal 0 HcmV?d00001 diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.py b/tests/topotests/ospf-topo1/test_ospf_topo1.py new file mode 100755 index 0000000000..4cb569da8e --- /dev/null +++ b/tests/topotests/ospf-topo1/test_ospf_topo1.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python + +# +# test_ospf_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_ospf_topo1.py: Test the FRR/Quagga OSPF routing daemon. +""" + +import os +import sys +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +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 + +class OSPFTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 4 routers + for routern in range(1, 5): + tgen.add_router('r{}'.format(routern)) + + # Create a empty network for router 1 + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + + # Create a empty network for router 2 + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + + # Interconect router 1, 2 and 3 + switch = tgen.add_switch('s3') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + + # Create empty netowrk for router3 + switch = tgen.add_switch('s4') + switch.add_link(tgen.gears['r3']) + + # Interconect router 3 and 4 + switch = tgen.add_switch('s5') + switch.add_link(tgen.gears['r3']) + switch.add_link(tgen.gears['r4']) + + # Create a empty network for router 4 + switch = tgen.add_switch('s6') + switch.add_link(tgen.gears['r4']) + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(OSPFTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, + os.path.join(CWD, '{}/ospfd.conf'.format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + +def test_ospf_convergence(): + "Test OSPF daemon convergence" + tgen = get_topogen() + + # Define test function + def compare_show_ip_ospf(rname, expected): + """ + Calls 'show ip ospf route' for router `rname` and compare the obtained + result with the expected output. + """ + current = tgen.gears[rname].vtysh_cmd('show ip ospf route') + return topotest.difflines(current, expected, + title1="Current output", + title2="Expected output") + + # Run the file comparison for all routers + for rnum in range(1, 5): + router = 'r{}'.format(rnum) + + # Load expected results from the command + reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router)) + expected = open(reffile).read() + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(compare_show_ip_ospf, router, expected) + result, diff = topotest.run_and_expect(test_func, '', + count=20, wait=3) + assert result, 'OSPF did not converge on {}:\n{}'.format(router, diff) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) -- 2.39.5