--- /dev/null
+#!/usr/bin/env python
+
+#
+# test_ospf_suppres_fa.py
+# Carles Kishimoto
+#
+# 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_suppres_fa.py: Test OSPF suppress-fa feature
+- Topology: r1 --- R2 (ABR) --- R3 (redistribute static)
+
+test_ospf_set_suppress_fa()
+ 1) R1: Get a dict[LSA_ID] = fwd_addr for all type 5 LSA
+ 2) R2: Configure: area 1 nssa suppress-fa
+ 3) R1: Get a dict[LSA_ID] and compare fwd_address with 0.0.0.0
+
+test_ospf_unset_suppress_fa()
+ 4) R2: Configure: no area 1 nssa suppress-fa
+ 5) R1: Get a dict[LSA_ID] = fwd_addr and compare it with the dict obtained in 1)
+"""
+
+import os
+import sys
+import re
+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
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class NetworkTopo(Topo):
+ "OSPF topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+
+ tgen = get_topogen(self)
+
+ # Create routers
+ for router in range(1, 4):
+ tgen.add_router("r{}".format(router))
+
+ # R1-R2 backbone area
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ # R2-R3 NSSA area
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+
+ tgen = Topogen(NetworkTopo, mod.__name__)
+ tgen.start_topology()
+
+ # This is a sample of configuration loading.
+ router_list = tgen.routers()
+
+ # For all registred routers, load the zebra and ospf configuration file
+ for rname, router in router_list.items():
+ 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))
+ )
+
+ tgen.start_router()
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_converge_protocols():
+ "Wait for protocol convergence"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ topotest.sleep(10, "Waiting for OSPF convergence")
+
+def ospf_configure_suppress_fa(router_name, area):
+ "Configure OSPF suppress-fa in router_name"
+
+ tgen = get_topogen()
+ router = tgen.gears[router_name]
+ router.vtysh_cmd("conf t\nrouter ospf\narea {} nssa suppress-fa\nexit\n".format(area))
+
+def ospf_unconfigure_suppress_fa(router_name, area):
+ "Remove OSPF suppress-fa in router_name"
+
+ tgen = get_topogen()
+ router = tgen.gears[router_name]
+ router.vtysh_cmd("conf t\nrouter ospf\nno area {} nssa suppress-fa\nexit\n".format(area))
+
+def ospf_get_lsa_type5(router_name):
+ "Return a dict with link state id as key and forwarding addresses as value"
+
+ result = dict()
+ tgen = get_topogen()
+ router = tgen.gears[router_name]
+ cmd = "show ip ospf database external\n"
+ output = topotest.normalize_text(router.vtysh_cmd(cmd))
+ for line in output.splitlines():
+ re0 = re.match(r"\s+Link State ID: (\S+) \(External Network Number\)", line)
+ if re0:
+ lsa = re0.group(1)
+ re1 = re.match(r"\s+Forward Address: (\S+)", line)
+ if re1:
+ result[lsa] = re1.group(1)
+ return result
+
+@pytest.fixture(scope='module', name='original')
+def test_ospf_set_suppress_fa():
+ "Test OSPF area [x] nssa suppress-fa"
+
+ # Get current forwarding address for each LSA type-5 in r1
+ initial = ospf_get_lsa_type5("r1")
+
+ # Configure suppres-fa in r2 area 1
+ ospf_configure_suppress_fa("r2", "1")
+ topotest.sleep(10, "Waiting for OSPF convergence")
+
+ # Check forwarding address on r1 for all statics is 0.0.0.0
+ assertmsg = "Forwarding address is not 0.0.0.0 after enabling OSPF suppress-fa"
+ suppress = ospf_get_lsa_type5("r1")
+ for prefix in suppress:
+ assert suppress[prefix] == "0.0.0.0", assertmsg
+
+ # Return the original forwarding addresses so we can compare them
+ # in the test_ospf_unset_supress_fa
+ return initial
+
+def test_ospf_unset_supress_fa(original):
+ "Test OSPF no area [x] nssa suppress-fa"
+
+ # Remove suppress-fa in r2 area 1
+ ospf_unconfigure_suppress_fa("r2", "1")
+ topotest.sleep(10, "Waiting for OSPF convergence")
+
+ # Check forwarding address is the original value on r1 for all statics
+ assertmsg = "Forwarding address is not correct after removing OSPF suppress-fa"
+ restore = ospf_get_lsa_type5("r1")
+ for prefix in restore:
+ assert restore[prefix] == original[prefix], assertmsg
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))