summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/lib/cxxcompat.c4
-rw-r--r--tests/lib/test_atomlist.c8
-rw-r--r--tests/lib/test_heavy_wq.c6
-rw-r--r--tests/lib/test_memory.c4
-rw-r--r--tests/lib/test_typelist.h8
-rw-r--r--tests/lib/test_xref.c2
-rw-r--r--tests/lib/test_zmq.c4
-rw-r--r--tests/ospfd/test_ospf_spf.c4
-rw-r--r--tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json4
-rw-r--r--tests/topotests/bfd-profiles-topo1/r1/ospfd.conf2
-rw-r--r--tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json4
-rw-r--r--tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py0
-rw-r--r--tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf3
-rw-r--r--tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf7
-rw-r--r--tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf5
-rw-r--r--tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf4
-rw-r--r--tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf6
-rw-r--r--tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py140
-rw-r--r--tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py6
-rw-r--r--tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py6
-rw-r--r--tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py32
-rw-r--r--tests/topotests/lib/bgp.py195
-rw-r--r--tests/topotests/lib/common_config.py90
-rw-r--r--tests/topotests/lib/ospf.py9
-rw-r--r--tests/topotests/lib/topotest.py38
-rwxr-xr-xtests/topotests/ospf_suppress_fa/__init__.py0
-rw-r--r--tests/topotests/ospf_suppress_fa/r1/ospfd.conf9
-rw-r--r--tests/topotests/ospf_suppress_fa/r1/zebra.conf4
-rw-r--r--tests/topotests/ospf_suppress_fa/r2/ospfd.conf16
-rw-r--r--tests/topotests/ospf_suppress_fa/r2/zebra.conf7
-rw-r--r--tests/topotests/ospf_suppress_fa/r3/ospfd.conf11
-rw-r--r--tests/topotests/ospf_suppress_fa/r3/zebra.conf8
-rw-r--r--tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot66
-rw-r--r--tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpgbin0 -> 33501 bytes
-rw-r--r--tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py181
36 files changed, 712 insertions, 187 deletions
diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c
index 391ccd9268..fde0d6af52 100644
--- a/tests/lib/cxxcompat.c
+++ b/tests/lib/cxxcompat.c
@@ -107,7 +107,7 @@
#include "lib/zassert.h"
#include "lib/zclient.h"
-PREDECL_RBTREE_UNIQ(footree)
+PREDECL_RBTREE_UNIQ(footree);
struct foo {
int dummy;
struct footree_item item;
@@ -116,7 +116,7 @@ static int foocmp(const struct foo *a, const struct foo *b)
{
return memcmp(&a->dummy, &b->dummy, sizeof(a->dummy));
}
-DECLARE_RBTREE_UNIQ(footree, struct foo, item, foocmp)
+DECLARE_RBTREE_UNIQ(footree, struct foo, item, foocmp);
int main(int argc, char **argv)
{
diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c
index 40837b4722..83dd9f2c59 100644
--- a/tests/lib/test_atomlist.c
+++ b/tests/lib/test_atomlist.c
@@ -41,18 +41,18 @@
static struct seqlock sqlo;
-PREDECL_ATOMLIST(alist)
-PREDECL_ATOMSORT_UNIQ(asort)
+PREDECL_ATOMLIST(alist);
+PREDECL_ATOMSORT_UNIQ(asort);
struct item {
uint64_t val1;
struct alist_item chain;
struct asort_item sortc;
uint64_t val2;
};
-DECLARE_ATOMLIST(alist, struct item, chain)
+DECLARE_ATOMLIST(alist, struct item, chain);
static int icmp(const struct item *a, const struct item *b);
-DECLARE_ATOMSORT_UNIQ(asort, struct item, sortc, icmp)
+DECLARE_ATOMSORT_UNIQ(asort, struct item, sortc, icmp);
static int icmp(const struct item *a, const struct item *b)
{
diff --git a/tests/lib/test_heavy_wq.c b/tests/lib/test_heavy_wq.c
index cffd52ee02..00aa7b80dd 100644
--- a/tests/lib/test_heavy_wq.c
+++ b/tests/lib/test_heavy_wq.c
@@ -37,9 +37,9 @@
#include "tests.h"
-DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test")
-DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node")
-DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str")
+DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test");
+DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node");
+DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str");
extern struct thread_master *master;
static struct work_queue *heavy_wq;
diff --git a/tests/lib/test_memory.c b/tests/lib/test_memory.c
index 84be9cb769..9f04304a2b 100644
--- a/tests/lib/test_memory.c
+++ b/tests/lib/test_memory.c
@@ -19,8 +19,8 @@
#include <zebra.h>
#include <memory.h>
-DEFINE_MGROUP(TEST_MEMORY, "memory test")
-DEFINE_MTYPE_STATIC(TEST_MEMORY, TEST, "generic test mtype")
+DEFINE_MGROUP(TEST_MEMORY, "memory test");
+DEFINE_MTYPE_STATIC(TEST_MEMORY, TEST, "generic test mtype");
/* Memory torture tests
*
diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h
index f86cadd398..32331c14a0 100644
--- a/tests/lib/test_typelist.h
+++ b/tests/lib/test_typelist.h
@@ -47,7 +47,7 @@
#define REALTYPE TYPE
#endif
-PREDECL(REALTYPE, list)
+PREDECL(REALTYPE, list);
struct item {
uint64_t val;
struct list_item itm;
@@ -59,7 +59,7 @@ static int list_cmp(const struct item *a, const struct item *b);
#if IS_HASH(REALTYPE)
static uint32_t list_hash(const struct item *a);
-DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash)
+DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash);
static uint32_t list_hash(const struct item *a)
{
@@ -72,7 +72,7 @@ static uint32_t list_hash(const struct item *a)
}
#else
-DECLARE(REALTYPE, list, struct item, itm, list_cmp)
+DECLARE(REALTYPE, list, struct item, itm, list_cmp);
#endif
static int list_cmp(const struct item *a, const struct item *b)
@@ -85,7 +85,7 @@ static int list_cmp(const struct item *a, const struct item *b)
}
#else /* !IS_SORTED */
-DECLARE(REALTYPE, list, struct item, itm)
+DECLARE(REALTYPE, list, struct item, itm);
#endif
#define NITEM 10000
diff --git a/tests/lib/test_xref.c b/tests/lib/test_xref.c
index 700950de1f..aa179141af 100644
--- a/tests/lib/test_xref.c
+++ b/tests/lib/test_xref.c
@@ -127,7 +127,7 @@ bool (*tests[])(void) = {
test_logcall,
};
-XREF_SETUP()
+XREF_SETUP();
int main(int argc, char **argv)
{
diff --git a/tests/lib/test_zmq.c b/tests/lib/test_zmq.c
index fe330d98d4..65195aa3e1 100644
--- a/tests/lib/test_zmq.c
+++ b/tests/lib/test_zmq.c
@@ -22,8 +22,8 @@
#include "sigevent.h"
#include "frr_zmq.h"
-DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer")
-DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message")
+DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer");
+DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message");
static struct thread_master *master;
diff --git a/tests/ospfd/test_ospf_spf.c b/tests/ospfd/test_ospf_spf.c
index a85f7e14ec..7808c3d47d 100644
--- a/tests/ospfd/test_ospf_spf.c
+++ b/tests/ospfd/test_ospf_spf.c
@@ -23,9 +23,9 @@
#include "common.h"
DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item,
- p_spaces_compare_func)
+ p_spaces_compare_func);
DECLARE_RBTREE_UNIQ(q_spaces, struct q_space, q_spaces_item,
- q_spaces_compare_func)
+ q_spaces_compare_func);
static struct ospf *test_init(struct ospf_test_node *root)
{
diff --git a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json
index bab24c4fa0..86a7e5139c 100644
--- a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json
+++ b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json
@@ -6,14 +6,14 @@
"interface": "r1-eth1",
"multihop": false,
"peer": "172.16.100.2",
- "receive-interval": 300,
+ "receive-interval": 800,
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
"remote-receive-interval": 300,
"remote-transmit-interval": 300,
"status": "up",
- "transmit-interval": 300,
+ "transmit-interval": 800,
"uptime": "*",
"vrf": "default"
},
diff --git a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
index 4798d17c40..fcea5d48fc 100644
--- a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
+++ b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
@@ -2,7 +2,7 @@ interface r1-eth1
ip ospf area 0
ip ospf hello-interval 2
ip ospf dead-interval 10
- ip ospf bfd
+ ip ospf bfd profile slowtx
!
router ospf
ospf router-id 10.254.254.1
diff --git a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json
index 4e6fa869ba..ec973eb365 100644
--- a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json
+++ b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json
@@ -10,8 +10,8 @@
"remote-detect-multiplier": 3,
"remote-diagnostic": "ok",
"remote-id": "*",
- "remote-receive-interval": 300,
- "remote-transmit-interval": 300,
+ "remote-receive-interval": 800,
+ "remote-transmit-interval": 800,
"status": "up",
"transmit-interval": 300,
"uptime": "*",
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py b/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf
new file mode 100644
index 0000000000..bf39152ea8
--- /dev/null
+++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf
@@ -0,0 +1,3 @@
+!
+router bgp 65001
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf
new file mode 100644
index 0000000000..697765168d
--- /dev/null
+++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
+
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf
new file mode 100644
index 0000000000..abbd1b86fa
--- /dev/null
+++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf
@@ -0,0 +1,5 @@
+!
+router bgp 65001
+ no bgp default ipv4-unicast
+ bgp default ipv6-unicast
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf
new file mode 100644
index 0000000000..606c17bec9
--- /dev/null
+++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf
new file mode 100644
index 0000000000..a405c047ca
--- /dev/null
+++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf
@@ -0,0 +1,4 @@
+!
+router bgp 65001
+ bgp default ipv6-unicast
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf
new file mode 100644
index 0000000000..e9fdfb70c5
--- /dev/null
+++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r3-eth0
+ ip address 192.168.255.3/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py b/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py
new file mode 100644
index 0000000000..c1dbf0ebec
--- /dev/null
+++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# 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 if `bgp default ipv4-unicast` and `bgp default ipv6-unicast`
+commands work as expected.
+
+STEP 1: 'Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only'
+STEP 2: 'Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only'
+STEP 3: 'Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families'
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+from lib.common_config import step
+
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_default_ipv4_ipv6_unicast():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only")
+
+ def _bgp_neighbor_ipv4_af_only():
+ tgen.gears["r1"].vtysh_cmd(
+ "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+ )
+
+ output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp summary json"))
+
+ if "ipv4Unicast" in output and "ipv6Unicast" not in output:
+ return True
+ return False
+
+ assert _bgp_neighbor_ipv4_af_only() == True
+
+ step("Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only")
+
+ def _bgp_neighbor_ipv6_af_only():
+ tgen.gears["r2"].vtysh_cmd(
+ "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+ )
+
+ output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp summary json"))
+
+ if "ipv4Unicast" not in output and "ipv6Unicast" in output:
+ return True
+ return False
+
+ assert _bgp_neighbor_ipv6_af_only() == True
+
+ step(
+ "Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families"
+ )
+
+ def _bgp_neighbor_ipv4_and_ipv6_af():
+ tgen.gears["r3"].vtysh_cmd(
+ "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+ )
+
+ output = json.loads(tgen.gears["r3"].vtysh_cmd("show bgp summary json"))
+
+ if "ipv4Unicast" in output and "ipv6Unicast" in output:
+ return True
+ return False
+
+ assert _bgp_neighbor_ipv4_and_ipv6_af() == True
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
index ac7ee44b25..464d6eb475 100644
--- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
+++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
@@ -115,7 +115,7 @@ sys.path.append(os.path.join(CWD, "../lib/"))
# Import topogen and topotest helpers
from lib.topogen import Topogen, get_topogen
from mininet.topo import Topo
-
+from lib.topotest import iproute2_is_vrf_capable
from lib.common_config import (
step,
verify_rib,
@@ -215,6 +215,10 @@ def setup_module(mod):
if result is not True:
pytest.skip("Kernel requirements are not met")
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
index c6e1792e84..10cf1c6ae8 100644
--- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
+++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
@@ -71,7 +71,7 @@ sys.path.append(os.path.join(CWD, "../lib/"))
# Import topogen and topotest helpers
from lib.topogen import Topogen, get_topogen
from mininet.topo import Topo
-
+from lib.topotest import iproute2_is_vrf_capable
from lib.common_config import (
step,
verify_rib,
@@ -164,6 +164,10 @@ def setup_module(mod):
if result is not True:
pytest.skip("Kernel requirements are not met")
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
index 6ab78c385e..ae904ba69e 100644
--- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
@@ -40,6 +40,8 @@ sys.path.append(os.path.join(CWD, "../"))
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
+from lib.topotest import iproute2_is_vrf_capable
+from lib.common_config import required_linux_kernel_version
from mininet.topo import Topo
@@ -193,18 +195,21 @@ def test_isis_route_installation():
def test_isis_linux_route_installation():
-
- dist = platform.dist()
-
- if dist[1] == "16.04":
- pytest.skip("Kernel not supported for vrf")
-
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
logger.info("Checking routers for installed ISIS vrf routes in OS")
# Check for routes in `ip route show vrf {}-cust1`
for rname, router in tgen.routers().items():
@@ -236,18 +241,21 @@ def test_isis_route6_installation():
def test_isis_linux_route6_installation():
-
- dist = platform.dist()
-
- if dist[1] == "16.04":
- pytest.skip("Kernel not supported for vrf")
-
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("4.15")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ # iproute2 needs to support VRFs for this suite to run.
+ if not iproute2_is_vrf_capable():
+ pytest.skip("Installed iproute2 version does not support VRFs")
+
logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS")
# Check for routes in `ip -6 route show vrf {}-cust1`
for rname, router in tgen.routers().items():
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 55b11dab3c..867831e114 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -43,6 +43,7 @@ from lib.common_config import (
run_frr_cmd,
FRRCFG_FILE,
retry,
+ get_ipv6_linklocal_address
)
LOGDIR = "/tmp/topotests/"
@@ -446,7 +447,7 @@ def __create_bgp_unicast_neighbor(
cmd = "redistribute {}".format(redistribute["redist_type"])
redist_attr = redistribute.setdefault("attribute", None)
if redist_attr:
- if isinstance(redist_attr, dict):
+ if type(redist_attr) is dict:
for key, value in redist_attr.items():
cmd = "{} {} {}".format(cmd, key, value)
else:
@@ -528,7 +529,7 @@ def __create_l2vpn_evpn_address_family(
if advertise_data:
for address_type, unicast_type in advertise_data.items():
- if isinstance(unicast_type, dict):
+ if type(unicast_type) is dict:
for key, value in unicast_type.items():
cmd = "advertise {} {}".format(address_type, key)
@@ -555,7 +556,7 @@ def __create_l2vpn_evpn_address_family(
"ipv4"
].split("/")[0]
- if isinstance(action, dict):
+ if type(action) is dict:
next_hop_self = action.setdefault("next_hop_self", None)
route_maps = action.setdefault("route_maps", {})
@@ -977,10 +978,6 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict):
router_list[router].run(cmd)
except Exception as e:
- # handle any exception
- logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
- # Traceback
errormsg = traceback.format_exc()
logger.error(errormsg)
return errormsg
@@ -1085,10 +1082,10 @@ def verify_bgp_convergence(tgen, topo, dut=None):
logger.debug("Entering lib API: verify_bgp_convergence()")
for router, rnode in tgen.routers().items():
- if "bgp" not in topo["routers"][router]:
+ if dut is not None and dut != router:
continue
- if dut is not None and dut != router:
+ if "bgp" not in topo["routers"][router]:
continue
logger.info("Verifying BGP Convergence on router %s:", router)
@@ -1114,59 +1111,7 @@ def verify_bgp_convergence(tgen, topo, dut=None):
# To find neighbor ip type
bgp_addr_type = bgp_data["address_family"]
- if "l2vpn" in bgp_addr_type:
- total_evpn_peer = 0
-
- if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
- continue
-
- bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"]
- total_evpn_peer += len(bgp_neighbors)
-
- no_of_evpn_peer = 0
- for bgp_neighbor, peer_data in bgp_neighbors.items():
- for _addr_type, dest_link_dict in peer_data.items():
- data = topo["routers"][bgp_neighbor]["links"]
- for dest_link in dest_link_dict.keys():
- if dest_link in data:
- peer_details = peer_data[_addr_type][dest_link]
-
- neighbor_ip = data[dest_link][_addr_type].split("/")[0]
- nh_state = None
-
- if (
- "ipv4Unicast" in show_bgp_json[vrf]
- or "ipv6Unicast" in show_bgp_json[vrf]
- ):
- errormsg = (
- "[DUT: %s] VRF: %s, "
- "ipv4Unicast/ipv6Unicast"
- " address-family present"
- " under l2vpn" % (router, vrf)
- )
- return errormsg
-
- l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
- "peers"
- ]
- nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
-
- if nh_state == "Established":
- no_of_evpn_peer += 1
-
- if no_of_evpn_peer == total_evpn_peer:
- logger.info(
- "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
- router,
- vrf,
- )
- else:
- errormsg = (
- "[DUT: %s] VRF: %s, BGP is not converged "
- "for evpn peers" % (router, vrf)
- )
- return errormsg
- else:
+ if "ipv4" in bgp_addr_type or "ipv6" in bgp_addr_type:
for addr_type in bgp_addr_type.keys():
if not check_address_types(addr_type):
continue
@@ -1216,32 +1161,102 @@ def verify_bgp_convergence(tgen, topo, dut=None):
nh_state = None
if addr_type == "ipv4":
- ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
- "peers"
- ]
- nh_state = ipv4_data[neighbor_ip]["state"]
+ if "ipv4Unicast" in show_bgp_json[vrf]:
+ ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
+ "peers"
+ ]
+ nh_state = ipv4_data[neighbor_ip]["state"]
else:
- ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
- "peers"
- ]
- nh_state = ipv6_data[neighbor_ip]["state"]
-
+ if "ipv6Unicast" in show_bgp_json[vrf]:
+ ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
+ "peers"
+ ]
+ nh_state = ipv6_data[neighbor_ip]["state"]
if nh_state == "Established":
no_of_peer += 1
- if no_of_peer == total_peer:
- logger.info(
- "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
- router,
- vrf,
- addr_type,
- )
+ if "l2vpn" in bgp_addr_type:
+ if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
+ if no_of_peer == total_peer:
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
+ router,
+ vrf,
+ addr_type,
+ )
+ else:
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
+ % (router, vrf, addr_type)
+ )
+ return errormsg
else:
- errormsg = (
- "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
- % (router, vrf, addr_type)
- )
- return errormsg
+ if no_of_peer == total_peer:
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
+ router,
+ vrf,
+ addr_type,
+ )
+ else:
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
+ % (router, vrf, addr_type)
+ )
+ return errormsg
+
+ if "l2vpn" in bgp_addr_type:
+ total_evpn_peer = 0
+
+ if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
+ continue
+
+ bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"]
+ total_evpn_peer += len(bgp_neighbors)
+
+ no_of_evpn_peer = 0
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for _addr_type, dest_link_dict in peer_data.items():
+ data = topo["routers"][bgp_neighbor]["links"]
+ for dest_link in dest_link_dict.keys():
+ if dest_link in data:
+ peer_details = peer_data[_addr_type][dest_link]
+
+ neighbor_ip = data[dest_link][_addr_type].split("/")[0]
+ nh_state = None
+
+ if (
+ "ipv4Unicast" in show_bgp_json[vrf]
+ or "ipv6Unicast" in show_bgp_json[vrf]
+ ):
+ errormsg = (
+ "[DUT: %s] VRF: %s, "
+ "ipv4Unicast/ipv6Unicast"
+ " address-family present"
+ " under l2vpn" % (router, vrf)
+ )
+ return errormsg
+
+ l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
+ "peers"
+ ]
+ nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
+
+ if nh_state == "Established":
+ no_of_evpn_peer += 1
+
+ if no_of_evpn_peer == total_evpn_peer:
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
+ router,
+ vrf,
+ )
+ else:
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged "
+ "for evpn peers" % (router, vrf)
+ )
+ return errormsg
logger.debug("Exiting API: verify_bgp_convergence()")
return True
@@ -1400,10 +1415,6 @@ def modify_as_number(tgen, topo, input_dict):
create_router_bgp(tgen, new_topo)
except Exception as e:
- # handle any exception
- logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
- # Traceback
errormsg = traceback.format_exc()
logger.error(errormsg)
return errormsg
@@ -2621,7 +2632,7 @@ def verify_bgp_rib(
found_routes.append(st_rt)
if next_hop and multi_nh and st_found:
- if not isinstance(next_hop, list):
+ if type(next_hop) is not list:
next_hop = [next_hop]
list1 = next_hop
@@ -2661,7 +2672,7 @@ def verify_bgp_rib(
nh_found = True
elif next_hop and multi_nh is None:
- if not isinstance(next_hop, list):
+ if type(next_hop) is not list:
next_hop = [next_hop]
list1 = next_hop
found_hops = [
@@ -4092,7 +4103,7 @@ def verify_attributes_for_evpn_routes(
errormsg = (
"[DUT: %s] RD: %s, Route : %s "
"is not present in cli json "
- "output " % (dut, route)
+ "output " % (dut, _rd, route)
)
return errormsg
@@ -4170,7 +4181,7 @@ def verify_evpn_routes(
return errormsg
for key, route_data_json in evpn_value_json.items():
- if isinstance(route_data_json, dict):
+ if type(route_data_json) is dict:
rd_keys += 1
if prefix not in route_data_json:
missing_routes[key] = prefix
@@ -4184,7 +4195,7 @@ def verify_evpn_routes(
return errormsg
for key, route_data_json in evpn_value_json.items():
- if isinstance(route_data_json, dict):
+ if type(route_data_json) is dict:
if prefix not in route_data_json:
continue
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 9174389bea..a4c98924b6 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -1373,13 +1373,13 @@ def generate_ips(network, no_of_ips):
if start_ip == "0.0.0.0" and mask == 0 and no_of_ips == 1:
ipaddress_list.append("{}/{}".format(start_ip, mask))
return ipaddress_list
- start_ip = ipaddress.IPv4Address(unicode(start_ip))
+ start_ip = ipaddress.IPv4Address(frr_unicode(start_ip))
step = 2 ** (32 - mask)
elif addr_type == "ipv6":
if start_ip == "0::0" and mask == 0 and no_of_ips == 1:
ipaddress_list.append("{}/{}".format(start_ip, mask))
return ipaddress_list
- start_ip = ipaddress.IPv6Address(unicode(start_ip))
+ start_ip = ipaddress.IPv6Address(frr_unicode(start_ip))
step = 2 ** (128 - mask)
else:
return []
@@ -1480,10 +1480,6 @@ def interface_status(tgen, topo, input_dict):
load_config_to_router(tgen, router)
except Exception as e:
- # handle any exception
- logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
- # Traceback
errormsg = traceback.format_exc()
logger.error(errormsg)
return errormsg
@@ -2442,51 +2438,6 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
interface_set_status(router_list[dut], intf_name, ifaceaction)
-def stop_router(tgen, router):
- """
- Router's current config would be saved to /tmp/topotest/<suite>/<router>
- for each daemon and router and its daemons would be stopped.
-
- * `tgen` : topogen object
- * `router`: Device under test
- """
-
- router_list = tgen.routers()
-
- # Saving router config to /etc/frr, which will be loaded to router
- # when it starts
- router_list[router].vtysh_cmd("write memory")
-
- # Stop router
- router_list[router].stop()
-
-
-def start_router(tgen, router):
- """
- Router will be started and config would be loaded from
- /tmp/topotest/<suite>/<router> for each daemon
-
- * `tgen` : topogen object
- * `router`: Device under test
- """
-
- logger.debug("Entering lib API: start_router")
-
- try:
- router_list = tgen.routers()
-
- # Router and its daemons would be started and config would
- # be loaded to router for each daemon from /etc/frr
- router_list[router].start()
-
- except Exception as e:
- errormsg = traceback.format_exc()
- logger.error(errormsg)
- return errormsg
-
- logger.debug("Exiting lib API: start_router()")
-
-
def addKernelRoute(
tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None
):
@@ -3754,6 +3705,43 @@ def verify_bgp_community(tgen, addr_type, router, network, input_dict=None):
return True
+def get_ipv6_linklocal_address(topo, node, intf):
+ """
+ API to get the link local ipv6 address of a perticular interface
+
+ Parameters
+ ----------
+ * `node`: node on which link local ip to be fetched.
+ * `intf` : interface for which link local ip needs to be returned.
+ * `topo` : base topo
+
+ Usage
+ -----
+ result = get_ipv6_linklocal_address(topo, 'r1', 'r2')
+
+ Returns link local ip of interface between r1 and r2.
+
+ Returns
+ -------
+ 1) link local ipv6 address from the interface
+ 2) errormsg - when link local ip not found
+ """
+ tgen = get_topogen()
+ ext_nh = tgen.net[node].get_ipv6_linklocal()
+ req_nh = topo[node]['links'][intf]['interface']
+ llip = None
+ for llips in ext_nh:
+ if llips[0] == req_nh:
+ llip = llips[1]
+ logger.info("Link local ip found = %s", llip)
+ return llip
+
+ errormsg = "Failed: Link local ip not found on router {}, "\
+ "interface {}".format(node, intf)
+
+ return errormsg
+
+
def verify_create_community_list(tgen, input_dict):
"""
API is to verify if large community list is created for any given DUT in
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
index 79e4d97448..9f642411b5 100644
--- a/tests/topotests/lib/ospf.py
+++ b/tests/topotests/lib/ospf.py
@@ -344,10 +344,9 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
for lnk in input_dict[router]["links"].keys():
if "ospf" not in input_dict[router]["links"][lnk]:
logger.debug(
- "Router %s: ospf configs is not present in"
- "input_dict, passed input_dict",
- router,
- input_dict,
+ "Router %s: ospf config is not present in"
+ "input_dict",
+ router
)
continue
ospf_data = input_dict[router]["links"][lnk]["ospf"]
@@ -724,7 +723,7 @@ def verify_ospf6_neighbor(tgen, topo):
nh_state = neighbor["state"]
break
else:
- return "[DUT: {}] OSPF6 peer {} missing".format(router, data_rid)
+ return "[DUT: {}] OSPF6 peer {} missing".format(router, ospf_nbr_rid)
if nh_state == "Full":
no_of_peer += 1
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 7f768f5b89..104b215078 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -518,6 +518,44 @@ def normalize_text(text):
return text
+def is_linux():
+ """
+ Parses unix name output to check if running on GNU/Linux.
+
+ Returns True if running on Linux, returns False otherwise.
+ """
+
+ if os.uname()[0] == "Linux":
+ return True
+ return False
+
+
+def iproute2_is_vrf_capable():
+ """
+ Checks if the iproute2 version installed on the system is capable of
+ handling VRFs by interpreting the output of the 'ip' utility found in PATH.
+
+ Returns True if capability can be detected, returns False otherwise.
+ """
+
+ if is_linux():
+ try:
+ subp = subprocess.Popen(
+ ["ip", "route", "show", "vrf"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ encoding="utf-8"
+ )
+ iproute2_err = subp.communicate()[1].splitlines()[0].split()[0]
+
+ if iproute2_err != "Error:":
+ return True
+ except Exception:
+ pass
+ return False
+
+
def module_present_linux(module, load):
"""
Returns whether `module` is present.
diff --git a/tests/topotests/ospf_suppress_fa/__init__.py b/tests/topotests/ospf_suppress_fa/__init__.py
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/__init__.py
diff --git a/tests/topotests/ospf_suppress_fa/r1/ospfd.conf b/tests/topotests/ospf_suppress_fa/r1/ospfd.conf
new file mode 100644
index 0000000000..c02be35b14
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r1/ospfd.conf
@@ -0,0 +1,9 @@
+!
+interface r1-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 10.0.12.0/24 area 0
+!
diff --git a/tests/topotests/ospf_suppress_fa/r1/zebra.conf b/tests/topotests/ospf_suppress_fa/r1/zebra.conf
new file mode 100644
index 0000000000..c1e31fb474
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r1/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r1-eth0
+ ip address 10.0.12.1/24
+!
diff --git a/tests/topotests/ospf_suppress_fa/r2/ospfd.conf b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf
new file mode 100644
index 0000000000..ebc7d252fd
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf
@@ -0,0 +1,16 @@
+!
+interface r2-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+interface r2-eth1
+ ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 10.0.12.0/24 area 0
+ network 10.0.23.0/24 area 1
+ area 1 nssa
+!
diff --git a/tests/topotests/ospf_suppress_fa/r2/zebra.conf b/tests/topotests/ospf_suppress_fa/r2/zebra.conf
new file mode 100644
index 0000000000..9f1a26349e
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r2/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface r2-eth0
+ ip address 10.0.12.2/24
+!
+interface r2-eth1
+ ip address 10.0.23.2/24
+!
diff --git a/tests/topotests/ospf_suppress_fa/r3/ospfd.conf b/tests/topotests/ospf_suppress_fa/r3/ospfd.conf
new file mode 100644
index 0000000000..08be11a7b7
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r3/ospfd.conf
@@ -0,0 +1,11 @@
+!
+interface r3-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ redistribute static
+ network 10.0.23.0/24 area 1
+ area 1 nssa
+!
diff --git a/tests/topotests/ospf_suppress_fa/r3/zebra.conf b/tests/topotests/ospf_suppress_fa/r3/zebra.conf
new file mode 100644
index 0000000000..f76cbf74d2
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r3/zebra.conf
@@ -0,0 +1,8 @@
+!
+ip route 3.3.1.1/32 Null0
+ip route 3.3.2.2/32 Null0
+ip route 3.3.3.3/32 Null0
+!
+interface r3-eth0
+ ip address 10.0.23.3/24
+!
diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot
new file mode 100644
index 0000000000..1036658f1a
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot
@@ -0,0 +1,66 @@
+## 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 suppress-fa";
+
+ # Routers
+ r1 [
+ label="r1\nrtr-id 10.0.12.1",
+ shape=doubleoctagon,
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ label="r2 (ABR)\nrtr-id 10.0.23.2",
+ shape=doubleoctagon,
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ label="r3 (ASBR)\nrtr-id 10.0.23.3",
+ shape=doubleoctagon,
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ s1 [
+ label="s1\n10.0.12.0/24",
+ shape=oval,
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ label="s2\n10.0.23.0/24",
+ shape=oval,
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ subgraph cluster0 {
+ label="area 0"
+ r1 -- s1 [label="eth1\n.1"];
+ r2 -- s1 [label="eth1\n.2"];
+ }
+
+ subgraph cluster1 {
+ label="area 1\nNSSA"
+ r2 -- s2 [label="eth2\n.2"];
+ r3 -- s2 [label="eth1\n.3"];
+ }
+
+ { rank=same; r1; r2; r3; }
+}
diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg
new file mode 100644
index 0000000000..2907d799f5
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg
Binary files differ
diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py
new file mode 100644
index 0000000000..74d609c57e
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py
@@ -0,0 +1,181 @@
+#!/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))