summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/user/bfd.rst28
-rw-r--r--isisd/isis_adjacency.c6
-rw-r--r--isisd/isis_bfd.c2
-rw-r--r--isisd/isis_lsp.c42
-rw-r--r--isisd/isis_spf.c15
-rw-r--r--isisd/isisd.c3
-rw-r--r--isisd/isisd.h3
-rw-r--r--tests/topotests/bfd-isis-topo1/__init__.py0
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/bfdd.conf17
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/isisd.conf35
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step1/show_ip_route.ref74
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step1/show_ipv6_route.ref70
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step2/show_bfd_peers.ref16
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_healthy.ref16
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_rt2_down.ref9
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_rt3_down.ref9
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_healthy.ref74
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_rt2_down.ref74
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_rt3_down.ref74
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_healthy.ref70
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_rt2_down.ref70
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_rt3_down.ref70
-rw-r--r--tests/topotests/bfd-isis-topo1/rt1/zebra.conf25
-rw-r--r--tests/topotests/bfd-isis-topo1/rt2/bfdd.conf12
-rw-r--r--tests/topotests/bfd-isis-topo1/rt2/isisd.conf30
-rw-r--r--tests/topotests/bfd-isis-topo1/rt2/step2/show_bfd_peers.ref9
-rw-r--r--tests/topotests/bfd-isis-topo1/rt2/zebra.conf22
-rw-r--r--tests/topotests/bfd-isis-topo1/rt3/bfdd.conf12
-rw-r--r--tests/topotests/bfd-isis-topo1/rt3/isisd.conf32
-rw-r--r--tests/topotests/bfd-isis-topo1/rt3/step2/show_bfd_peers.ref9
-rw-r--r--tests/topotests/bfd-isis-topo1/rt3/zebra.conf22
-rw-r--r--tests/topotests/bfd-isis-topo1/rt4/bfdd.conf5
-rw-r--r--tests/topotests/bfd-isis-topo1/rt4/isisd.conf29
-rw-r--r--tests/topotests/bfd-isis-topo1/rt4/zebra.conf22
-rw-r--r--tests/topotests/bfd-isis-topo1/rt5/bfdd.conf5
-rw-r--r--tests/topotests/bfd-isis-topo1/rt5/isisd.conf29
-rw-r--r--tests/topotests/bfd-isis-topo1/rt5/zebra.conf22
-rwxr-xr-xtests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py304
38 files changed, 1346 insertions, 20 deletions
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 2586b9b988..618d90a85e 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -143,7 +143,7 @@ BFD peers and profiles share the same BFD session configuration commands.
.. clicmd:: transmit-interval (10-60000)
The minimum transmission interval (less jitter) that this system
- wants to use to send BFD control packets.
+ wants to use to send BFD control packets. Defaults to 300ms.
.. index:: echo-interval (10-60000)
.. clicmd:: echo-interval (10-60000)
@@ -159,7 +159,7 @@ BFD peers and profiles share the same BFD session configuration commands.
It is recommended that the transmission interval of control packets
to be increased after enabling echo-mode to reduce bandwidth usage.
- For example: `transmission-interval 2000`.
+ For example: `transmit-interval 2000`.
Echo mode is not supported on multi-hop setups (see :rfc:`5883`
section 3).
@@ -246,6 +246,30 @@ The following commands are available inside the BGP configuration node.
Removes the BFD profile configuration from peer session(s).
+.. _bfd-isis-peer-config:
+
+IS-IS BFD Configuration
+-----------------------
+
+The following commands are available inside the interface configuration node.
+
+.. index:: isis bfd
+.. clicmd:: ip isis bfd
+
+ Listen for BFD events on peers created on the interface. Every time
+ a new neighbor is found a BFD peer is created to monitor the link
+ status for fast convergence.
+
+.. index:: no isis bfd
+.. clicmd:: no isis bfd
+
+ Removes any notification registration for this interface peers.
+
+ Note that there will be just one BFD session per interface. In case both
+ IPv4 and IPv6 support are configured then just a IPv6 based session is
+ created.
+
+
.. _bfd-ospf-peer-config:
OSPF BFD Configuration
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 66de11e6f7..425627485a 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -171,14 +171,14 @@ void isis_delete_adj(void *arg)
return;
THREAD_TIMER_OFF(adj->t_expire);
- if (adj->adj_state != ISIS_ADJ_DOWN) {
+ if (adj->adj_state != ISIS_ADJ_DOWN)
adj->adj_state = ISIS_ADJ_DOWN;
- hook_call(isis_adj_state_change_hook, adj);
- }
/* remove from SPF trees */
spftree_area_adj_del(adj->circuit->area, adj);
+ hook_call(isis_adj_state_change_hook, adj);
+
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses);
diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c
index 9f8424fcd6..69c971ee2c 100644
--- a/isisd/isis_bfd.c
+++ b/isisd/isis_bfd.c
@@ -138,6 +138,8 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
return;
}
+ adj->circuit->area->bfd_signalled_down = true;
+
isis_adj_state_change(&adj, ISIS_ADJ_DOWN, "bfd session went down");
}
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 5cf652b291..63303e2308 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -1376,7 +1376,13 @@ static int lsp_refresh(struct thread *thread)
if ((area->is_type & level) == 0)
return ISIS_ERROR;
- if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL) < 100000L) {
+ /*
+ * Throttle regeneration of LSPs (but not when BFD signalled a 'down'
+ * message)
+ */
+ if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL)
+ < 100000L
+ && !(area->bfd_force_spf_refresh)) {
sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
area->area_tag, level);
_lsp_regenerate_schedule(area, level, 0, false,
@@ -1429,7 +1435,12 @@ int _lsp_regenerate_schedule(struct isis_area *area, int level,
"ISIS (%s): Checking whether L%d needs to be scheduled",
area->area_tag, lvl);
- if (area->lsp_regenerate_pending[lvl - 1]) {
+ if (area->lsp_regenerate_pending[lvl - 1]
+ && !(area->bfd_signalled_down)) {
+ /*
+ * Note: in case of a BFD 'down' message the refresh is
+ * scheduled once again just to be sure
+ */
struct timeval remain = thread_timer_remain(
area->t_lsp_refresh[lvl - 1]);
sched_debug(
@@ -1457,7 +1468,8 @@ int _lsp_regenerate_schedule(struct isis_area *area, int level,
(long long)now);
THREAD_TIMER_OFF(area->t_lsp_refresh[lvl - 1]);
diff = now - lsp->last_generated;
- if (diff < area->lsp_gen_interval[lvl - 1]) {
+ if (diff < area->lsp_gen_interval[lvl - 1]
+ && !(area->bfd_signalled_down)) {
timeout =
1000 * (area->lsp_gen_interval[lvl - 1] - diff);
sched_debug(
@@ -1465,17 +1477,21 @@ int _lsp_regenerate_schedule(struct isis_area *area, int level,
area->area_tag, timeout);
} else {
/*
- * lsps are not regenerated if lsp_regenerate function
- * is called
- * directly. However if the lsp_regenerate call is
- * queued for
- * later execution it works.
+ * Schedule LSP refresh ASAP
*/
- timeout = 100;
- sched_debug(
- "ISIS (%s): Last generation was more than lsp_gen_interval ago."
- " Scheduling for execution in %ld ms.",
- area->area_tag, timeout);
+ timeout = 0;
+
+ if (area->bfd_signalled_down) {
+ sched_debug(
+ "ISIS (%s): Scheduling immediately due to BDF 'down' message.",
+ area->area_tag);
+ area->bfd_signalled_down = false;
+ area->bfd_force_spf_refresh = true;
+ } else {
+ sched_debug(
+ "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
+ area->area_tag);
+ }
}
area->lsp_regenerate_pending[lvl - 1] = 1;
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index dfcea9a921..fb1aad8c49 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1288,9 +1288,20 @@ int _isis_spf_schedule(struct isis_area *area, int level,
/* wait configured min_spf_interval before doing the SPF */
long timer;
- if (diff >= area->min_spf_interval[level - 1]) {
- /* Last run is more than min interval ago, schedule immediate run */
+ if (diff >= area->min_spf_interval[level - 1]
+ || area->bfd_force_spf_refresh) {
+ /*
+ * Last run is more than min interval ago or BFD signalled a
+ * 'down' message, schedule immediate run
+ */
timer = 0;
+
+ if (area->bfd_force_spf_refresh) {
+ zlog_debug(
+ "ISIS-Spf (%s) L%d SPF scheduled immediately due to BFD 'down' message",
+ area->area_tag, level);
+ area->bfd_force_spf_refresh = false;
+ }
} else {
timer = area->min_spf_interval[level - 1] - diff;
}
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 286542c8d3..53e48bd1cf 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -203,6 +203,9 @@ struct isis_area *isis_area_create(const char *area_tag)
area->lsp_refresh_arg[1].area = area;
area->lsp_refresh_arg[1].level = IS_LEVEL_2;
+ area->bfd_signalled_down = false;
+ area->bfd_force_spf_refresh = false;
+
QOBJ_REG(area, isis_area);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index def2027aa3..57d9691cc7 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -127,6 +127,9 @@ struct isis_area {
*/
int lsp_regenerate_pending[ISIS_LEVELS];
+ bool bfd_signalled_down;
+ bool bfd_force_spf_refresh;
+
struct fabricd *fabricd;
/*
diff --git a/tests/topotests/bfd-isis-topo1/__init__.py b/tests/topotests/bfd-isis-topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/__init__.py
diff --git a/tests/topotests/bfd-isis-topo1/rt1/bfdd.conf b/tests/topotests/bfd-isis-topo1/rt1/bfdd.conf
new file mode 100644
index 0000000000..4793155939
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/bfdd.conf
@@ -0,0 +1,17 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+ peer 10.0.1.2 interface eth-rt2
+ detect-multiplier 3
+ receive-interval 300
+ transmit-interval 300
+ !
+ peer 10.0.2.2 interface eth-rt3
+ detect-multiplier 3
+ receive-interval 300
+ transmit-interval 300
+ !
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt1/isisd.conf b/tests/topotests/bfd-isis-topo1/rt1/isisd.conf
new file mode 100644
index 0000000000..3219371d2e
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/isisd.conf
@@ -0,0 +1,35 @@
+log file isisd.log
+log timestamp precision 3
+!
+hostname rt1
+!
+password 1
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis adj-packets
+debug isis lsp-sched
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis bfd
+!
+interface eth-rt3
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+ isis bfd
+!
+router isis 1
+ net 49.0000.0000.0000.0001.00
+ is-type level-1
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/bfd-isis-topo1/rt1/step1/show_ip_route.ref
new file mode 100644
index 0000000000..af6e45cf33
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step1/show_ip_route.ref
@@ -0,0 +1,74 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/bfd-isis-topo1/rt1/step1/show_ipv6_route.ref
new file mode 100644
index 0000000000..68d3fe2c44
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step1/show_ipv6_route.ref
@@ -0,0 +1,70 @@
+{
+ "::ffff:202:202\/128":[
+ {
+ "prefix":"::ffff:202:202\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:303:303\/128":[
+ {
+ "prefix":"::ffff:303:303\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:404:404\/128":[
+ {
+ "prefix":"::ffff:404:404\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:505:505\/128":[
+ {
+ "prefix":"::ffff:505:505\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step2/show_bfd_peers.ref b/tests/topotests/bfd-isis-topo1/rt1/step2/show_bfd_peers.ref
new file mode 100644
index 0000000000..cb4083d2fd
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step2/show_bfd_peers.ref
@@ -0,0 +1,16 @@
+[
+ {
+ "peer": "10.0.2.2",
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "peer": "10.0.1.2",
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_healthy.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_healthy.ref
new file mode 100644
index 0000000000..cb4083d2fd
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_healthy.ref
@@ -0,0 +1,16 @@
+[
+ {
+ "peer": "10.0.2.2",
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "peer": "10.0.1.2",
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_rt2_down.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_rt2_down.ref
new file mode 100644
index 0000000000..f00b9f3d32
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_rt2_down.ref
@@ -0,0 +1,9 @@
+[
+ {
+ "peer": "10.0.2.2",
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_rt3_down.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_rt3_down.ref
new file mode 100644
index 0000000000..f5bd276a4a
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_bfd_peers_rt3_down.ref
@@ -0,0 +1,9 @@
+[
+ {
+ "peer": "10.0.1.2",
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_healthy.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_healthy.ref
new file mode 100644
index 0000000000..af6e45cf33
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_healthy.ref
@@ -0,0 +1,74 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_rt2_down.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_rt2_down.ref
new file mode 100644
index 0000000000..b8366bc0b7
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_rt2_down.ref
@@ -0,0 +1,74 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_rt3_down.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_rt3_down.ref
new file mode 100644
index 0000000000..42bd6abf82
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ip_route_rt3_down.ref
@@ -0,0 +1,74 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_healthy.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_healthy.ref
new file mode 100644
index 0000000000..68d3fe2c44
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_healthy.ref
@@ -0,0 +1,70 @@
+{
+ "::ffff:202:202\/128":[
+ {
+ "prefix":"::ffff:202:202\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:303:303\/128":[
+ {
+ "prefix":"::ffff:303:303\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:404:404\/128":[
+ {
+ "prefix":"::ffff:404:404\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:505:505\/128":[
+ {
+ "prefix":"::ffff:505:505\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_rt2_down.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_rt2_down.ref
new file mode 100644
index 0000000000..200053c3e8
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_rt2_down.ref
@@ -0,0 +1,70 @@
+{
+ "::ffff:202:202\/128":[
+ {
+ "prefix":"::ffff:202:202\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:303:303\/128":[
+ {
+ "prefix":"::ffff:303:303\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:404:404\/128":[
+ {
+ "prefix":"::ffff:404:404\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:505:505\/128":[
+ {
+ "prefix":"::ffff:505:505\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_rt3_down.ref b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_rt3_down.ref
new file mode 100644
index 0000000000..4297f163b5
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/step3/show_ipv6_route_rt3_down.ref
@@ -0,0 +1,70 @@
+{
+ "::ffff:202:202\/128":[
+ {
+ "prefix":"::ffff:202:202\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:303:303\/128":[
+ {
+ "prefix":"::ffff:303:303\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:404:404\/128":[
+ {
+ "prefix":"::ffff:404:404\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:505:505\/128":[
+ {
+ "prefix":"::ffff:505:505\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-isis-topo1/rt1/zebra.conf b/tests/topotests/bfd-isis-topo1/rt1/zebra.conf
new file mode 100644
index 0000000000..6003125b6b
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt1/zebra.conf
@@ -0,0 +1,25 @@
+log file zebra.log
+log timestamp precision 3
+!
+hostname rt1
+!
+debug zebra kernel
+debug zebra packet
+debug zebra events
+debug zebra rib
+!
+interface lo
+ ip address 1.1.1.1/32
+ ipv6 address ::ffff:0101:0101/128
+!
+interface eth-rt2
+ ip address 10.0.1.1/24
+!
+interface eth-rt3
+ ip address 10.0.2.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt2/bfdd.conf b/tests/topotests/bfd-isis-topo1/rt2/bfdd.conf
new file mode 100644
index 0000000000..a49cd4fa6b
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt2/bfdd.conf
@@ -0,0 +1,12 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+ peer 10.0.1.1 interface eth-rt1
+ detect-multiplier 3
+ receive-interval 300
+ transmit-interval 300
+ !
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt2/isisd.conf b/tests/topotests/bfd-isis-topo1/rt2/isisd.conf
new file mode 100644
index 0000000000..63ccb640a4
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt2/isisd.conf
@@ -0,0 +1,30 @@
+log file isisd.log
+!
+hostname rt2
+!
+password 1
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis bfd
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0002.00
+ is-type level-1
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt2/step2/show_bfd_peers.ref b/tests/topotests/bfd-isis-topo1/rt2/step2/show_bfd_peers.ref
new file mode 100644
index 0000000000..8a90649efa
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt2/step2/show_bfd_peers.ref
@@ -0,0 +1,9 @@
+[
+ {
+ "peer": "10.0.1.1",
+ "interface": "eth-rt1",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-isis-topo1/rt2/zebra.conf b/tests/topotests/bfd-isis-topo1/rt2/zebra.conf
new file mode 100644
index 0000000000..5fc7fc5b28
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt2/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt2
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 2.2.2.2/32
+ ipv6 address ::ffff:0202:0202/128
+!
+interface eth-rt1
+ ip address 10.0.1.2/24
+!
+interface eth-rt5
+ ip address 10.0.3.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt3/bfdd.conf b/tests/topotests/bfd-isis-topo1/rt3/bfdd.conf
new file mode 100644
index 0000000000..600054a0bc
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt3/bfdd.conf
@@ -0,0 +1,12 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+ peer 10.0.2.1 interface eth-rt1
+ detect-multiplier 3
+ receive-interval 300
+ transmit-interval 300
+ !
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt3/isisd.conf b/tests/topotests/bfd-isis-topo1/rt3/isisd.conf
new file mode 100644
index 0000000000..928f1e1a2b
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt3/isisd.conf
@@ -0,0 +1,32 @@
+log file isisd.log
+!
+hostname rt3
+!
+password 1
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+ isis bfd
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0003.00
+ is-type level-1
+!
+
diff --git a/tests/topotests/bfd-isis-topo1/rt3/step2/show_bfd_peers.ref b/tests/topotests/bfd-isis-topo1/rt3/step2/show_bfd_peers.ref
new file mode 100644
index 0000000000..13eb2a2c69
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt3/step2/show_bfd_peers.ref
@@ -0,0 +1,9 @@
+[
+ {
+ "peer": "10.0.2.1",
+ "interface": "eth-rt1",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-isis-topo1/rt3/zebra.conf b/tests/topotests/bfd-isis-topo1/rt3/zebra.conf
new file mode 100644
index 0000000000..d368de9bbe
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt3/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt3
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 3.3.3.3/32
+ ipv6 address ::ffff:0303:0303/128
+!
+interface eth-rt1
+ ip address 10.0.2.2/24
+!
+interface eth-rt4
+ ip address 10.0.4.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt4/bfdd.conf b/tests/topotests/bfd-isis-topo1/rt4/bfdd.conf
new file mode 100644
index 0000000000..f35e772790
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt4/bfdd.conf
@@ -0,0 +1,5 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt4/isisd.conf b/tests/topotests/bfd-isis-topo1/rt4/isisd.conf
new file mode 100644
index 0000000000..fde97478a9
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt4/isisd.conf
@@ -0,0 +1,29 @@
+log file isisd.log
+!
+hostname rt4
+!
+password 1
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt3
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0004.00
+ is-type level-1
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt4/zebra.conf b/tests/topotests/bfd-isis-topo1/rt4/zebra.conf
new file mode 100644
index 0000000000..7b053bac35
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt4/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt4
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 4.4.4.4/32
+ ipv6 address ::ffff:0404:0404/128
+!
+interface eth-rt3
+ ip address 10.0.4.2/24
+!
+interface eth-rt5
+ ip address 10.0.5.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt5/bfdd.conf b/tests/topotests/bfd-isis-topo1/rt5/bfdd.conf
new file mode 100644
index 0000000000..f35e772790
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt5/bfdd.conf
@@ -0,0 +1,5 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt5/isisd.conf b/tests/topotests/bfd-isis-topo1/rt5/isisd.conf
new file mode 100644
index 0000000000..fd00cb1ddb
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt5/isisd.conf
@@ -0,0 +1,29 @@
+log file isisd.log
+!
+hostname rt5
+!
+password 1
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0005.00
+ is-type level-1
+!
diff --git a/tests/topotests/bfd-isis-topo1/rt5/zebra.conf b/tests/topotests/bfd-isis-topo1/rt5/zebra.conf
new file mode 100644
index 0000000000..0b7c9e02f3
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/rt5/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt5
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 5.5.5.5/32
+ ipv6 address ::ffff:0505:0505/128
+!
+interface eth-rt2
+ ip address 10.0.3.2/24
+!
+interface eth-rt4
+ ip address 10.0.5.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
new file mode 100755
index 0000000000..a1ed0cc2af
--- /dev/null
+++ b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
@@ -0,0 +1,304 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_isis_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 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_bfd_isis_topo1.py:
+
+ +---------+
+ | |
+ eth-rt2 (.1) | RT1 | eth-rt3 (.1)
+ +----------+ 1.1.1.1 +----------+
+ | | | |
+ | +---------+ |
+ | |
+ | 10.0.2.0/24 |
+ | |
+ | eth-rt1 | (.2)
+ | 10.0.1.0/24 +----+----+
+ | | |
+ | | RT3 |
+ | | 3.3.3.3 |
+ | | |
+ (.2) | eth-rt1 +----+----+
+ +----+----+ eth-rt4 | (.1)
+ | | |
+ | RT2 | |
+ | 2.2.2.2 | 10.0.4.0/24 |
+ | | |
+ +----+----+ |
+ (.1) | eth-rt5 eth-rt3 | (.2)
+ | +----+----+
+ | | |
+ | | RT4 |
+ | | 4.4.4.4 |
+ | | |
+ | +----+----+
+ | 10.0.3.0/24 eth-rt5 | (.1)
+ | |
+ | |
+ | 10.0.5.0/24 |
+ | |
+ | +---------+ |
+ | | | |
+ +----------+ RT5 +----------+
+ eth-rt2 (.2) | 5.5.5.5 | eth-rt4 (.2)
+ | |
+ +---------+
+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+from time import sleep
+from time import time
+from functools import partial
+
+# 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 TemplateTopo(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ #
+ # Define FRR Routers
+ #
+ for router in ["rt1", "rt2", "rt3", "rt4", "rt5"]:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt5")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt2")
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt4")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt3")
+
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ 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_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def print_cmd_result(rname, command):
+ print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
+
+
+def router_compare_json_output(rname, command, reference, count=120, wait=0.5):
+ "Compare router JSON output"
+
+ logger.info('Comparing router "%s" "%s" output', rname, command)
+
+ tgen = get_topogen()
+ filename = "{}/{}/{}".format(CWD, rname, reference)
+ expected = json.loads(open(filename).read())
+
+ # Run test function until we get an result. Wait at most 60 seconds.
+ test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait)
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+
+## TEST STEPS
+
+
+def test_rib_isis_step1():
+ logger.info("Test (step 1): verify RIB (IPv4 and IPv6) for IS-IS")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router_compare_json_output(
+ "rt1", "show ip route isis json", "step1/show_ip_route.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route isis json", "step1/show_ipv6_route.ref"
+ )
+
+
+def test_bfd_isis_sessions_step2():
+ logger.info("Test (step 2): verify BFD peers for IS-IS")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # BFD is just used on three routers
+ for rt in ["rt1", "rt2", "rt3"]:
+ router_compare_json_output(
+ rt, "show bfd peers json", "step2/show_bfd_peers.ref"
+ )
+
+
+def test_bfd_isis_interface_failure_rt2_step3():
+ logger.info("Test (step 2): check failover handling when RT2 goes down")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Let's kill the interface on rt2 and see what happens with the RIB and BFD on rt1
+ tgen.gears["rt2"].link_enable("eth-rt1", enabled=False)
+
+ # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
+ # initial 2 seconds to let the CI not suffer.
+ # TODO: add check for array size
+ sleep(2)
+ router_compare_json_output(
+ "rt1", "show ip route isis json", "step3/show_ip_route_rt2_down.ref", 1, 0
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_rt2_down.ref", 1, 0
+ )
+ router_compare_json_output(
+ "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 1, 0
+ )
+
+ # Check recovery, this can take some time
+ tgen.gears["rt2"].link_enable("eth-rt1", enabled=True)
+
+ router_compare_json_output(
+ "rt1", "show ip route isis json", "step3/show_ip_route_healthy.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_healthy.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref"
+ )
+
+
+def test_bfd_isis_interface_failure_rt3_step3():
+ logger.info("Test (step 2): check failover handling when RT2 goes down")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Let's kill the interface on rt3 and see what happens with the RIB and BFD on rt1
+ tgen.gears["rt3"].link_enable("eth-rt1", enabled=False)
+
+ # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
+ # initial 2 seconds to let the CI not suffer.
+ # TODO: add check for array size
+ sleep(2)
+ router_compare_json_output(
+ "rt1", "show ip route isis json", "step3/show_ip_route_rt3_down.ref", 1, 0
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_rt3_down.ref", 1, 0
+ )
+ router_compare_json_output(
+ "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 1, 0
+ )
+
+ # Check recovery, this can take some time
+ tgen.gears["rt3"].link_enable("eth-rt1", enabled=True)
+
+ router_compare_json_output(
+ "rt1", "show ip route isis json", "step3/show_ip_route_healthy.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_healthy.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref"
+ )
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))