diff options
Diffstat (limited to 'tests')
158 files changed, 10153 insertions, 277 deletions
diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index 439891b559..936ffaaad5 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -1265,7 +1265,8 @@ int main(void) { int i = 0; qobj_init(); - bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE); + bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE, + list_new()); master = bm->master; bgp_option_set(BGP_OPT_NO_LISTEN); bgp_attr_init(); diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 1b3f90434b..153b83897d 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -912,7 +912,7 @@ int main(void) qobj_init(); master = thread_master_create(NULL); - bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE); + bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index 7fabaad7fa..f510760913 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -1086,7 +1086,7 @@ int main(void) cmd_init(0); bgp_vty_init(); master = thread_master_create("test mp attr"); - bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE); + bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); bgp_attr_init(); diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c index 520c460f15..92efd4c3d6 100644 --- a/tests/bgpd/test_mpath.c +++ b/tests/bgpd/test_mpath.c @@ -393,7 +393,7 @@ static int global_test_init(void) qobj_init(); master = thread_master_create(NULL); zclient = zclient_new(master, &zclient_options_default); - bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE); + bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c index d2c093fbea..db5918745d 100644 --- a/tests/bgpd/test_packet.c +++ b/tests/bgpd/test_packet.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) qobj_init(); bgp_attr_init(); master = thread_master_create(NULL); - bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE); + bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index 0a15886c10..123d97bc97 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -1399,7 +1399,7 @@ static void bgp_startup(void) master = thread_master_create(NULL); yang_init(true); nb_init(master, bgpd_yang_modules, array_size(bgpd_yang_modules), false); - bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE); + bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); bgp_option_set(BGP_OPT_NO_LISTEN); vrf_init(NULL, NULL, NULL, NULL, NULL); frr_pthread_init(); diff --git a/tests/isisd/test_common.c b/tests/isisd/test_common.c index 5fa604c749..5b2028ffd4 100644 --- a/tests/isisd/test_common.c +++ b/tests/isisd/test_common.c @@ -69,6 +69,24 @@ test_find_adjacency(const struct isis_test_node *tnode, const char *hostname) return NULL; } +mpls_label_t test_topology_node_ldp_label(const struct isis_topology *topology, + struct in_addr router_id) +{ + for (size_t i = 0; topology->nodes[i].hostname[0]; i++) { + const struct isis_test_node *tnode = &topology->nodes[i]; + struct in_addr node_router_id; + + if (!tnode->router_id) + continue; + + (void)inet_pton(AF_INET, tnode->router_id, &node_router_id); + if (IPV4_ADDR_SAME(&router_id, &node_router_id)) + return (50000 + (i + 1) * 100); + } + + return MPLS_INVALID_LABEL; +} + static struct isis_lsp *lsp_add(struct lspdb_head *lspdb, struct isis_area *area, int level, const uint8_t *sysid, uint8_t pseudonode_id) diff --git a/tests/isisd/test_common.h b/tests/isisd/test_common.h index 6fd0d3813e..3359a893ac 100644 --- a/tests/isisd/test_common.h +++ b/tests/isisd/test_common.h @@ -70,6 +70,9 @@ test_topology_find_node(const struct isis_topology *topology, const char *hostname, uint8_t pseudonode_id); extern const struct isis_topology * test_topology_find(struct isis_topology *test_topologies, uint16_t number); +extern mpls_label_t +test_topology_node_ldp_label(const struct isis_topology *topology, + struct in_addr router_id); extern int test_topology_load(const struct isis_topology *topology, struct isis_area *area, struct lspdb_head lspdb[]); diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 36ef93669b..e06944a037 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -31,6 +31,7 @@ #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" +#include "isisd/isis_route.h" #include "isisd/isis_spf.h" #include "isisd/isis_spf_private.h" @@ -40,6 +41,7 @@ enum test_type { TEST_SPF = 1, TEST_REVERSE_SPF, TEST_LFA, + TEST_RLFA, TEST_TI_LFA, }; @@ -105,6 +107,86 @@ static void test_run_lfa(struct vty *vty, const struct isis_topology *topology, isis_spftree_del(spftree_self); } +static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, + const struct isis_test_node *root, + struct isis_area *area, struct lspdb_head *lspdb, + int level, int tree, + struct lfa_protected_resource *protected_resource) +{ + struct isis_spftree *spftree_self; + struct isis_spftree *spftree_reverse; + struct isis_spftree *spftree_pc; + struct isis_spf_node *spf_node, *node; + struct rlfa *rlfa; + uint8_t flags; + + /* Run forward SPF in the root node. */ + flags = F_SPFTREE_NO_ADJACENCIES; + spftree_self = isis_spftree_new(area, lspdb, root->sysid, level, tree, + SPF_TYPE_FORWARD, flags); + isis_run_spf(spftree_self); + + /* Run reverse SPF in the root node. */ + spftree_reverse = isis_spf_reverse_run(spftree_self); + + /* Run forward SPF on all adjacent routers. */ + isis_spf_run_neighbors(spftree_self); + + /* Compute the local LFA repair paths. */ + isis_lfa_compute(area, NULL, spftree_self, protected_resource); + + /* Compute the remote LFA repair paths. */ + spftree_pc = isis_rlfa_compute(area, spftree_self, spftree_reverse, 0, + protected_resource); + + /* Print the extended P-space and Q-space. */ + vty_out(vty, "P-space (self):\n"); + RB_FOREACH (node, isis_spf_nodes, &spftree_pc->lfa.p_space) + vty_out(vty, " %s\n", print_sys_hostname(node->sysid)); + vty_out(vty, "\n"); + RB_FOREACH (spf_node, isis_spf_nodes, &spftree_self->adj_nodes) { + if (RB_EMPTY(isis_spf_nodes, &spf_node->lfa.p_space)) + continue; + vty_out(vty, "P-space (%s):\n", + print_sys_hostname(spf_node->sysid)); + RB_FOREACH (node, isis_spf_nodes, &spf_node->lfa.p_space) + vty_out(vty, " %s\n", print_sys_hostname(node->sysid)); + vty_out(vty, "\n"); + } + vty_out(vty, "Q-space:\n"); + RB_FOREACH (node, isis_spf_nodes, &spftree_pc->lfa.q_space) + vty_out(vty, " %s\n", print_sys_hostname(node->sysid)); + vty_out(vty, "\n"); + + /* Print the post-convergence SPT. */ + isis_print_spftree(vty, spftree_pc); + + /* + * Activate the computed RLFAs (if any) using artificial LDP labels for + * the PQ nodes. + */ + frr_each_safe (rlfa_tree, &spftree_self->lfa.remote.rlfas, rlfa) { + struct zapi_rlfa_response response = {}; + + response.pq_label = test_topology_node_ldp_label( + topology, rlfa->pq_address); + assert(response.pq_label != MPLS_INVALID_LABEL); + isis_rlfa_activate(spftree_self, rlfa, &response); + } + + /* Print the SPT and the corresponding main/backup routing tables. */ + isis_print_spftree(vty, spftree_self); + vty_out(vty, "Main:\n"); + isis_print_routes(vty, spftree_self, false, false); + vty_out(vty, "Backup:\n"); + isis_print_routes(vty, spftree_self, false, true); + + /* Cleanup everything. */ + isis_spftree_del(spftree_self); + isis_spftree_del(spftree_reverse); + isis_spftree_del(spftree_pc); +} + static void test_run_ti_lfa(struct vty *vty, const struct isis_topology *topology, const struct isis_test_node *root, @@ -242,6 +324,11 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, &area->lspdb[level - 1], level, tree, &protected_resource); break; + case TEST_RLFA: + test_run_rlfa(vty, topology, root, area, + &area->lspdb[level - 1], level, + tree, &protected_resource); + break; case TEST_TI_LFA: test_run_ti_lfa(vty, topology, root, area, &area->lspdb[level - 1], level, @@ -266,6 +353,7 @@ DEFUN(test_isis, test_isis_cmd, spf\ |reverse-spf\ |lfa system-id WORD [pseudonode-id <1-255>]\ + |remote-lfa system-id WORD [pseudonode-id <1-255>]\ |ti-lfa system-id WORD [pseudonode-id <1-255>] [node-protection]\ >\ [display-lspdb] [<ipv4-only|ipv6-only>] [<level-1-only|level-2-only>]", @@ -282,6 +370,11 @@ DEFUN(test_isis, test_isis_cmd, "System ID\n" "Pseudonode-ID\n" "Pseudonode-ID\n" + "Remote LFA\n" + "System ID\n" + "System ID\n" + "Pseudonode-ID\n" + "Pseudonode-ID\n" "Topology Independent LFA\n" "System ID\n" "System ID\n" @@ -335,6 +428,14 @@ DEFUN(test_isis, test_isis_cmd, fail_pseudonode_id = strtoul(argv[idx + 1]->arg, NULL, 10); protection_type = LFA_LINK_PROTECTION; + } else if (argv_find(argv, argc, "remote-lfa", &idx)) { + test_type = TEST_RLFA; + + fail_sysid_str = argv[idx + 2]->arg; + if (argv_find(argv, argc, "pseudonode-id", &idx)) + fail_pseudonode_id = + strtoul(argv[idx + 1]->arg, NULL, 10); + protection_type = LFA_LINK_PROTECTION; } else if (argv_find(argv, argc, "ti-lfa", &idx)) { test_type = TEST_TI_LFA; diff --git a/tests/isisd/test_isis_spf.in b/tests/isisd/test_isis_spf.in index 93e18124e6..f8f65ffdf7 100644 --- a/tests/isisd/test_isis_spf.in +++ b/tests/isisd/test_isis_spf.in @@ -31,6 +31,18 @@ test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1 test isis topology 14 root rt1 lfa system-id rt2 test isis topology 14 root rt5 lfa system-id rt4 +test isis topology 1 root rt1 remote-lfa system-id rt2 +test isis topology 2 root rt5 remote-lfa system-id rt1 pseudonode-id 1 +test isis topology 3 root rt5 remote-lfa system-id rt4 ipv4-only +test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only +test isis topology 5 root rt1 remote-lfa system-id rt2 ipv4-only +test isis topology 6 root rt4 remote-lfa system-id rt3 ipv4-only +test isis topology 7 root rt11 remote-lfa system-id rt8 ipv4-only +test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only +test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only +test isis topology 11 root rt2 remote-lfa system-id rt4 +test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only + test isis topology 1 root rt1 ti-lfa system-id rt2 test isis topology 2 root rt1 ti-lfa system-id rt3 test isis topology 2 root rt1 ti-lfa system-id rt1 pseudonode-id 1 diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index dced6fb103..024f7256e0 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -1807,6 +1807,1227 @@ IS-IS L1 IPv6 routing table: 2001:db8::4/128 60 - rt3 -
test#
+test# test isis topology 1 root rt1 remote-lfa system-id rt2
+P-space (self):
+ rt3
+ rt5
+
+P-space (rt3):
+ rt3
+ rt5
+ rt6
+
+Q-space:
+ rt2
+ rt4
+ rt6
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt6 TE-IS 30 rt3 - rt5(4)
+10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+rt4 TE-IS 40 rt3 - rt6(4)
+10.0.255.6/32 IP TE 40 rt3 - rt6(4)
+rt2 TE-IS 50 rt3 - rt4(4)
+10.0.255.4/32 IP TE 50 rt3 - rt4(4)
+10.0.255.2/32 IP TE 60 rt3 - rt2(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+ rt3 -
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 30 - rt2 16040
+ 10.0.255.5/32 30 - rt3 16050
+ 10.0.255.6/32 40 - rt2 16060
+ - rt3 16060
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ --------------------------------------------------------
+ 10.0.255.2/32 60 - rt3 50600/16020
+ 10.0.255.4/32 50 - rt3 50600/16040
+
+P-space (self):
+ rt3
+ rt5
+
+P-space (rt3):
+ rt3
+ rt5
+ rt6
+
+Q-space:
+ rt2
+ rt4
+ rt6
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+2001:db8::1/128 IP6 internal 0 rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+rt6 TE-IS 30 rt3 - rt5(4)
+2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+rt4 TE-IS 40 rt3 - rt6(4)
+2001:db8::6/128 IP6 internal 40 rt3 - rt6(4)
+rt2 TE-IS 50 rt3 - rt4(4)
+2001:db8::4/128 IP6 internal 50 rt3 - rt4(4)
+2001:db8::2/128 IP6 internal 60 rt3 - rt2(4)
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+2001:db8::1/128 IP6 internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+2001:db8::2/128 IP6 internal 20 rt2 - rt2(4)
+2001:db8::3/128 IP6 internal 20 rt3 - rt3(4)
+rt6 TE-IS 30 rt2 - rt4(4)
+ rt3 - rt5(4)
+2001:db8::4/128 IP6 internal 30 rt2 - rt4(4)
+2001:db8::5/128 IP6 internal 30 rt3 - rt5(4)
+2001:db8::6/128 IP6 internal 40 rt2 - rt6(4)
+ rt3 -
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 0 - - -
+ 2001:db8::2/128 20 - rt2 implicit-null
+ 2001:db8::3/128 20 - rt3 implicit-null
+ 2001:db8::4/128 30 - rt2 16041
+ 2001:db8::5/128 30 - rt3 16051
+ 2001:db8::6/128 40 - rt2 16061
+ - rt3 16061
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 2001:db8::2/128 60 - rt3 50600/16021
+ 2001:db8::4/128 50 - rt3 50600/16041
+
+test# test isis topology 2 root rt5 remote-lfa system-id rt1 pseudonode-id 1
+P-space (self):
+ rt6
+
+P-space (rt3):
+ rt1
+ rt2
+ rt3
+ rt4
+
+P-space (rt6):
+ rt4
+ rt6
+
+Q-space:
+ rt1
+ rt2
+ rt3
+ rt4
+ rt6
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+10.0.255.5/32 IP internal 0 rt5(4)
+rt6 TE-IS 10 rt6 - rt5(4)
+rt4 TE-IS 20 rt6 - rt6(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt1 pseudo_TE-IS 30 rt6 - rt4(4)
+rt1 TE-IS 30 rt6 - rt1(2)
+10.0.255.4/32 IP TE 30 rt6 - rt4(4)
+rt3 TE-IS 40 rt3 - rt5(4)
+10.0.255.1/32 IP TE 40 rt6 - rt1(4)
+rt2 TE-IS 45 rt6 - rt1(4)
+10.0.255.3/32 IP TE 50 rt3 - rt3(4)
+10.0.255.2/32 IP TE 55 rt6 - rt2(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+10.0.255.5/32 IP internal 0 rt5(4)
+rt1 TE-IS 10 rt1 - rt5(4)
+rt4 TE-IS 10 rt4 - rt5(4)
+rt6 TE-IS 10 rt6 - rt5(4)
+rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt4 - rt4(4)
+10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt2 TE-IS 25 rt1 - rt1(4)
+10.0.255.2/32 IP TE 35 rt1 - rt2(4)
+rt3 TE-IS 40 rt3 - rt5(4)
+ rt1 - rt1(4)
+10.0.255.3/32 IP TE 50 rt3 - rt3(4)
+ rt1 -
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 20 - rt1 implicit-null
+ 10.0.255.2/32 35 - rt1 16020
+ 10.0.255.3/32 50 - rt3 implicit-null
+ - rt1 implicit-null
+ 10.0.255.4/32 20 - rt4 implicit-null
+ 10.0.255.5/32 0 - - -
+ 10.0.255.6/32 20 - rt6 implicit-null
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ --------------------------------------------------------
+ 10.0.255.1/32 40 - rt6 50400/16010
+ 10.0.255.2/32 55 - rt6 50400/16020
+ 10.0.255.4/32 30 - rt6 50400/16040
+
+P-space (self):
+ rt6
+
+P-space (rt3):
+ rt1
+ rt2
+ rt3
+ rt4
+
+P-space (rt6):
+ rt4
+ rt6
+
+Q-space:
+ rt1
+ rt2
+ rt3
+ rt4
+ rt6
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+2001:db8::5/128 IP6 internal 0 rt5(4)
+rt6 TE-IS 10 rt6 - rt5(4)
+rt4 TE-IS 20 rt6 - rt6(4)
+2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+rt1 pseudo_TE-IS 30 rt6 - rt4(4)
+rt1 TE-IS 30 rt6 - rt1(2)
+2001:db8::4/128 IP6 internal 30 rt6 - rt4(4)
+rt3 TE-IS 40 rt3 - rt5(4)
+2001:db8::1/128 IP6 internal 40 rt6 - rt1(4)
+rt2 TE-IS 45 rt6 - rt1(4)
+2001:db8::3/128 IP6 internal 50 rt3 - rt3(4)
+2001:db8::2/128 IP6 internal 55 rt6 - rt2(4)
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+2001:db8::5/128 IP6 internal 0 rt5(4)
+rt1 TE-IS 10 rt1 - rt5(4)
+rt4 TE-IS 10 rt4 - rt5(4)
+rt6 TE-IS 10 rt6 - rt5(4)
+rt1 pseudo_TE-IS 20 rt1 - rt1(4)
+ rt4 - rt4(4)
+2001:db8::1/128 IP6 internal 20 rt1 - rt1(4)
+2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+2001:db8::6/128 IP6 internal 20 rt6 - rt6(4)
+rt2 TE-IS 25 rt1 - rt1(4)
+2001:db8::2/128 IP6 internal 35 rt1 - rt2(4)
+rt3 TE-IS 40 rt3 - rt5(4)
+ rt1 - rt1(4)
+2001:db8::3/128 IP6 internal 50 rt3 - rt3(4)
+ rt1 -
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 20 - rt1 implicit-null
+ 2001:db8::2/128 35 - rt1 16021
+ 2001:db8::3/128 50 - rt3 implicit-null
+ - rt1 implicit-null
+ 2001:db8::4/128 20 - rt4 implicit-null
+ 2001:db8::5/128 0 - - -
+ 2001:db8::6/128 20 - rt6 implicit-null
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 2001:db8::1/128 40 - rt6 50400/16011
+ 2001:db8::2/128 55 - rt6 50400/16021
+ 2001:db8::4/128 30 - rt6 50400/16041
+
+test# test isis topology 3 root rt5 remote-lfa system-id rt4 ipv4-only
+P-space (self):
+ rt6
+
+P-space (rt3):
+ rt1
+ rt2
+ rt3
+ rt4
+ rt6
+
+P-space (rt6):
+ rt1
+ rt2
+ rt3
+ rt4
+ rt6
+
+Q-space:
+ rt1
+ rt2
+ rt3
+ rt4
+ rt6
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+10.0.255.5/32 IP internal 0 rt5(4)
+rt6 TE-IS 10 rt6 - rt5(4)
+rt4 TE-IS 20 rt6 - rt6(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt3 TE-IS 30 rt3 - rt5(4)
+rt2 TE-IS 30 rt6 - rt4(4)
+10.0.255.4/32 IP TE 30 rt6 - rt4(4)
+rt1 TE-IS 40 rt3 - rt3(4)
+ rt6 - rt2(4)
+10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+10.0.255.2/32 IP TE 40 rt6 - rt2(4)
+10.0.255.1/32 IP TE 50 rt3 - rt1(4)
+ rt6 -
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+10.0.255.5/32 IP internal 0 rt5(4)
+rt4 TE-IS 10 rt4 - rt5(4)
+rt6 TE-IS 10 rt6 - rt5(4)
+rt2 TE-IS 20 rt4 - rt4(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt3 TE-IS 30 rt3 - rt5(4)
+ rt4 - rt2(4)
+rt1 TE-IS 30 rt4 - rt2(4)
+10.0.255.2/32 IP TE 30 rt4 - rt2(4)
+10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+ rt4 -
+10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 40 - rt4 16010
+ 10.0.255.2/32 30 - rt4 16020
+ 10.0.255.3/32 40 - rt3 implicit-null
+ - rt4 implicit-null
+ 10.0.255.4/32 20 - rt4 implicit-null
+ 10.0.255.5/32 0 - - -
+ 10.0.255.6/32 20 - rt6 implicit-null
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------
+ 10.0.255.1/32 40 - rt3 16010
+ - rt6 16010
+ 10.0.255.2/32 30 - rt3 16020
+ - rt6 16020
+ 10.0.255.4/32 20 - rt3 16040
+ - rt6 16040
+
+test# test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only
+P-space (self):
+ rt1
+ rt2
+ rt4
+ rt6
+
+P-space (rt4):
+ rt1
+ rt2
+ rt3
+ rt4
+ rt6
+
+P-space (rt6):
+ rt1
+ rt2
+ rt3
+ rt4
+ rt6
+
+Q-space:
+ rt1
+ rt2
+ rt3
+ rt4
+ rt6
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+10.0.255.5/32 IP internal 0 rt5(4)
+rt4 TE-IS 10 rt4 - rt5(4)
+rt6 TE-IS 10 rt6 - rt5(4)
+rt2 TE-IS 20 rt4 - rt4(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt1 TE-IS 30 rt4 - rt2(4)
+rt3 TE-IS 30 rt4 - rt2(4)
+10.0.255.2/32 IP TE 30 rt4 - rt2(4)
+10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+10.0.255.3/32 IP TE 40 rt4 - rt3(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt5
+10.0.255.5/32 IP internal 0 rt5(4)
+rt4 TE-IS 10 rt4 - rt5(4)
+rt6 TE-IS 10 rt6 - rt5(4)
+rt2 TE-IS 20 rt4 - rt4(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt3 TE-IS 30 rt3 - rt5(4)
+ rt4 - rt2(4)
+rt1 TE-IS 30 rt4 - rt2(4)
+10.0.255.2/32 IP TE 30 rt4 - rt2(4)
+10.0.255.3/32 IP TE 40 rt3 - rt3(4)
+ rt4 -
+10.0.255.1/32 IP TE 40 rt4 - rt1(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 40 - rt4 16010
+ 10.0.255.2/32 30 - rt4 16020
+ 10.0.255.3/32 40 - rt3 implicit-null
+ - rt4 implicit-null
+ 10.0.255.4/32 20 - rt4 implicit-null
+ 10.0.255.5/32 0 - - -
+ 10.0.255.6/32 20 - rt6 implicit-null
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+test# test isis topology 5 root rt1 remote-lfa system-id rt2 ipv4-only
+P-space (self):
+ rt3
+ rt5
+ rt7
+
+P-space (rt3):
+ rt3
+ rt5
+ rt7
+ rt8
+
+Q-space:
+ rt2
+ rt4
+ rt6
+ rt8
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt7 TE-IS 30 rt3 - rt5(4)
+10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+rt8 TE-IS 40 rt3 - rt7(4)
+10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+rt6 TE-IS 50 rt3 - rt8(4)
+10.0.255.8/32 IP TE 50 rt3 - rt8(4)
+rt4 TE-IS 60 rt3 - rt6(4)
+10.0.255.6/32 IP TE 60 rt3 - rt6(4)
+rt2 TE-IS 70 rt3 - rt4(4)
+10.0.255.4/32 IP TE 70 rt3 - rt4(4)
+10.0.255.2/32 IP TE 80 rt3 - rt2(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt6 TE-IS 30 rt2 - rt4(4)
+rt7 TE-IS 30 rt3 - rt5(4)
+10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+rt8 TE-IS 40 rt2 - rt6(4)
+ rt3 - rt7(4)
+10.0.255.6/32 IP TE 40 rt2 - rt6(4)
+10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+10.0.255.8/32 IP TE 50 rt2 - rt8(4)
+ rt3 -
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 30 - rt2 16040
+ 10.0.255.5/32 30 - rt3 16050
+ 10.0.255.6/32 40 - rt2 16060
+ 10.0.255.7/32 40 - rt3 16070
+ 10.0.255.8/32 50 - rt2 16080
+ - rt3 16080
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ --------------------------------------------------------
+ 10.0.255.2/32 80 - rt3 50800/16020
+ 10.0.255.4/32 70 - rt3 50800/16040
+ 10.0.255.6/32 60 - rt3 50800/16060
+
+test# test isis topology 6 root rt4 remote-lfa system-id rt3 ipv4-only
+P-space (self):
+ rt2
+ rt5
+ rt6
+ rt7
+ rt8
+
+P-space (rt2):
+ rt1
+ rt2
+
+P-space (rt6):
+ rt5
+ rt6
+ rt7
+ rt8
+
+Q-space:
+ rt1
+ rt3
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt4
+10.0.255.4/32 IP internal 0 rt4(4)
+rt2 TE-IS 10 rt2 - rt4(4)
+rt6 TE-IS 10 rt6 - rt4(4)
+rt1 TE-IS 20 rt2 - rt2(4)
+rt5 TE-IS 20 rt6 - rt6(4)
+rt8 TE-IS 20 rt6 - rt6(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt3 TE-IS 30 rt2 - rt1(4)
+rt7 TE-IS 30 rt6 - rt5(4)
+ rt8(4)
+10.0.255.1/32 IP TE 30 rt2 - rt1(4)
+10.0.255.5/32 IP TE 30 rt6 - rt5(4)
+10.0.255.8/32 IP TE 30 rt6 - rt8(4)
+10.0.255.3/32 IP TE 40 rt2 - rt3(4)
+10.0.255.7/32 IP TE 40 rt6 - rt7(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt4
+10.0.255.4/32 IP internal 0 rt4(4)
+rt2 TE-IS 10 rt2 - rt4(4)
+rt3 TE-IS 10 rt3 - rt4(4)
+rt6 TE-IS 10 rt6 - rt4(4)
+rt1 TE-IS 20 rt2 - rt2(4)
+ rt3 - rt3(4)
+rt5 TE-IS 20 rt6 - rt6(4)
+rt8 TE-IS 20 rt6 - rt6(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+10.0.255.6/32 IP TE 20 rt6 - rt6(4)
+rt7 TE-IS 30 rt6 - rt5(4)
+ rt8(4)
+10.0.255.1/32 IP TE 30 rt2 - rt1(4)
+ rt3 -
+10.0.255.5/32 IP TE 30 rt6 - rt5(4)
+10.0.255.8/32 IP TE 30 rt6 - rt8(4)
+10.0.255.7/32 IP TE 40 rt6 - rt7(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 30 - rt2 16010
+ - rt3 16010
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 0 - - -
+ 10.0.255.5/32 30 - rt6 16050
+ 10.0.255.6/32 20 - rt6 implicit-null
+ 10.0.255.7/32 40 - rt6 16070
+ 10.0.255.8/32 30 - rt6 16080
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ --------------------------------------------------------
+ 10.0.255.3/32 40 - rt2 50100/16030
+
+test# test isis topology 7 root rt11 remote-lfa system-id rt8 ipv4-only
+P-space (self):
+ rt10
+ rt12
+
+P-space (rt10):
+ rt1
+ rt4
+ rt7
+ rt10
+
+P-space (rt12):
+ rt9
+ rt12
+
+Q-space:
+ rt1
+ rt2
+ rt3
+ rt4
+ rt5
+ rt6
+ rt7
+ rt8
+ rt9
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt11
+10.0.255.11/32 IP internal 0 rt11(4)
+rt10 TE-IS 10 rt10 - rt11(4)
+rt12 TE-IS 10 rt12 - rt11(4)
+rt9 TE-IS 20 rt12 - rt12(4)
+10.0.255.10/32 IP TE 20 rt10 - rt10(4)
+10.0.255.12/32 IP TE 20 rt12 - rt12(4)
+rt7 TE-IS 30 rt10 - rt10(4)
+rt8 TE-IS 30 rt12 - rt9(4)
+10.0.255.9/32 IP TE 30 rt12 - rt9(4)
+rt4 TE-IS 40 rt10 - rt7(4)
+rt5 TE-IS 40 rt12 - rt8(4)
+10.0.255.7/32 IP TE 40 rt10 - rt7(4)
+10.0.255.8/32 IP TE 40 rt12 - rt8(4)
+rt6 TE-IS 50 rt12 - rt9(4)
+ rt5(4)
+rt1 TE-IS 50 rt10 - rt4(4)
+rt2 TE-IS 50 rt12 - rt5(4)
+10.0.255.4/32 IP TE 50 rt10 - rt4(4)
+10.0.255.5/32 IP TE 50 rt12 - rt5(4)
+rt3 TE-IS 60 rt12 - rt6(4)
+ rt2(4)
+10.0.255.6/32 IP TE 60 rt12 - rt6(4)
+10.0.255.1/32 IP TE 60 rt10 - rt1(4)
+10.0.255.2/32 IP TE 60 rt12 - rt2(4)
+10.0.255.3/32 IP TE 70 rt12 - rt3(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt11
+10.0.255.11/32 IP internal 0 rt11(4)
+rt8 TE-IS 10 rt8 - rt11(4)
+rt10 TE-IS 10 rt10 - rt11(4)
+rt12 TE-IS 10 rt12 - rt11(4)
+rt5 TE-IS 20 rt8 - rt8(4)
+rt7 TE-IS 20 rt8 - rt8(4)
+rt9 TE-IS 20 rt8 - rt8(4)
+ rt12 - rt12(4)
+10.0.255.8/32 IP TE 20 rt8 - rt8(4)
+10.0.255.10/32 IP TE 20 rt10 - rt10(4)
+10.0.255.12/32 IP TE 20 rt12 - rt12(4)
+rt2 TE-IS 30 rt8 - rt5(4)
+rt4 TE-IS 30 rt8 - rt5(4)
+ rt7(4)
+rt6 TE-IS 30 rt8 - rt5(4)
+10.0.255.5/32 IP TE 30 rt8 - rt5(4)
+10.0.255.7/32 IP TE 30 rt8 - rt7(4)
+10.0.255.9/32 IP TE 30 rt8 - rt9(4)
+ rt12 -
+rt3 TE-IS 40 rt8 - rt2(4)
+ rt6(4)
+rt1 TE-IS 40 rt8 - rt4(4)
+10.0.255.2/32 IP TE 40 rt8 - rt2(4)
+10.0.255.4/32 IP TE 40 rt8 - rt4(4)
+10.0.255.6/32 IP TE 40 rt8 - rt6(4)
+10.0.255.3/32 IP TE 50 rt8 - rt3(4)
+10.0.255.1/32 IP TE 50 rt8 - rt1(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------------
+ 10.0.255.1/32 50 - rt8 16010
+ 10.0.255.2/32 40 - rt8 16020
+ 10.0.255.3/32 50 - rt8 16030
+ 10.0.255.4/32 40 - rt8 16040
+ 10.0.255.5/32 30 - rt8 16050
+ 10.0.255.6/32 40 - rt8 16060
+ 10.0.255.7/32 30 - rt8 16070
+ 10.0.255.8/32 20 - rt8 implicit-null
+ 10.0.255.9/32 30 - rt8 16090
+ - rt12 16090
+ 10.0.255.10/32 20 - rt10 implicit-null
+ 10.0.255.11/32 0 - - -
+ 10.0.255.12/32 20 - rt12 implicit-null
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ --------------------------------------------------------
+ 10.0.255.1/32 50 - rt10 16010
+ 10.0.255.2/32 60 - rt12 50900/16020
+ 10.0.255.3/32 70 - rt12 50900/16030
+ 10.0.255.4/32 40 - rt10 16040
+ 10.0.255.5/32 50 - rt12 50900/16050
+ 10.0.255.6/32 60 - rt12 50900/16060
+ 10.0.255.7/32 30 - rt10 16070
+ 10.0.255.8/32 40 - rt12 50900/16080
+
+test# test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only
+P-space (self):
+ rt3
+
+P-space (rt3):
+ rt2
+ rt3
+
+P-space (rt9):
+ rt1
+ rt2
+ rt4
+ rt5
+ rt7
+ rt8
+ rt9
+ rt10
+ rt11
+ rt12
+
+Q-space:
+ rt1
+ rt2
+ rt4
+ rt5
+ rt7
+ rt8
+ rt9
+ rt10
+ rt11
+ rt12
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt6
+10.0.255.6/32 IP internal 0 rt6(4)
+rt3 TE-IS 10 rt3 - rt6(4)
+rt2 TE-IS 20 rt3 - rt3(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt9 TE-IS 30 rt9 - rt6(4)
+rt5 TE-IS 30 rt3 - rt2(4)
+10.0.255.2/32 IP TE 30 rt3 - rt2(4)
+rt8 TE-IS 40 rt9 - rt9(4)
+ rt3 - rt5(4)
+rt12 TE-IS 40 rt9 - rt9(4)
+rt4 TE-IS 40 rt3 - rt5(4)
+10.0.255.9/32 IP TE 40 rt9 - rt9(4)
+10.0.255.5/32 IP TE 40 rt3 - rt5(4)
+rt7 TE-IS 50 rt9 - rt8(4)
+ rt3 - rt4(4)
+rt11 TE-IS 50 rt9 - rt8(4)
+ rt3 - rt12(4)
+rt1 TE-IS 50 rt3 - rt4(4)
+10.0.255.8/32 IP TE 50 rt9 - rt8(4)
+ rt3 -
+10.0.255.12/32 IP TE 50 rt9 - rt12(4)
+10.0.255.4/32 IP TE 50 rt3 - rt4(4)
+rt10 TE-IS 60 rt9 - rt11(4)
+ rt3 -
+10.0.255.7/32 IP TE 60 rt9 - rt7(4)
+ rt3 -
+10.0.255.11/32 IP TE 60 rt9 - rt11(4)
+ rt3 -
+10.0.255.1/32 IP TE 60 rt3 - rt1(4)
+10.0.255.10/32 IP TE 70 rt9 - rt10(4)
+ rt3 -
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt6
+10.0.255.6/32 IP internal 0 rt6(4)
+rt3 TE-IS 10 rt3 - rt6(4)
+rt5 TE-IS 10 rt5 - rt6(4)
+rt2 TE-IS 20 rt3 - rt3(4)
+ rt5 - rt5(4)
+rt4 TE-IS 20 rt5 - rt5(4)
+rt8 TE-IS 20 rt5 - rt5(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+rt9 TE-IS 30 rt9 - rt6(4)
+ rt5 - rt8(4)
+rt1 TE-IS 30 rt5 - rt4(4)
+rt7 TE-IS 30 rt5 - rt4(4)
+ rt8(4)
+rt11 TE-IS 30 rt5 - rt8(4)
+10.0.255.2/32 IP TE 30 rt3 - rt2(4)
+ rt5 -
+10.0.255.4/32 IP TE 30 rt5 - rt4(4)
+10.0.255.8/32 IP TE 30 rt5 - rt8(4)
+rt12 TE-IS 40 rt9 - rt9(4)
+ rt5 - rt11(4)
+rt10 TE-IS 40 rt5 - rt11(4)
+10.0.255.9/32 IP TE 40 rt9 - rt9(4)
+ rt5 -
+10.0.255.1/32 IP TE 40 rt5 - rt1(4)
+10.0.255.7/32 IP TE 40 rt5 - rt7(4)
+10.0.255.11/32 IP TE 40 rt5 - rt11(4)
+10.0.255.12/32 IP TE 50 rt9 - rt12(4)
+ rt5 -
+10.0.255.10/32 IP TE 50 rt5 - rt10(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------------
+ 10.0.255.1/32 40 - rt5 16010
+ 10.0.255.2/32 30 - rt3 16020
+ - rt5 16020
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 30 - rt5 16040
+ 10.0.255.5/32 20 - rt5 implicit-null
+ 10.0.255.6/32 0 - - -
+ 10.0.255.7/32 40 - rt5 16070
+ 10.0.255.8/32 30 - rt5 16080
+ 10.0.255.9/32 40 - rt9 implicit-null
+ - rt5 implicit-null
+ 10.0.255.10/32 50 - rt5 16100
+ 10.0.255.11/32 40 - rt5 16110
+ 10.0.255.12/32 50 - rt9 16120
+ - rt5 16120
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------
+ 10.0.255.1/32 70 - rt9 16010
+ 10.0.255.4/32 60 - rt9 16040
+ 10.0.255.5/32 50 - rt9 16050
+ 10.0.255.7/32 50 - rt9 16070
+ 10.0.255.8/32 40 - rt9 16080
+ 10.0.255.10/32 60 - rt9 16100
+ 10.0.255.11/32 50 - rt9 16110
+
+test# test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only
+P-space (self):
+ rt1
+ rt3
+ rt4
+ rt7
+ rt10
+
+P-space (rt1):
+ rt1
+ rt4
+ rt7
+ rt10
+
+P-space (rt3):
+ rt3
+ rt6
+
+Q-space:
+ rt5
+ rt6
+ rt8
+ rt9
+ rt11
+ rt12
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt2
+10.0.255.2/32 IP internal 0 rt2(4)
+rt1 TE-IS 10 rt1 - rt2(4)
+rt3 TE-IS 10 rt3 - rt2(4)
+rt4 TE-IS 20 rt1 - rt1(4)
+rt6 TE-IS 20 rt3 - rt3(4)
+10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt7 TE-IS 30 rt1 - rt4(4)
+rt5 TE-IS 30 rt3 - rt6(4)
+10.0.255.4/32 IP TE 30 rt1 - rt4(4)
+10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+rt10 TE-IS 40 rt1 - rt7(4)
+rt8 TE-IS 40 rt3 - rt5(4)
+10.0.255.7/32 IP TE 40 rt1 - rt7(4)
+10.0.255.5/32 IP TE 40 rt3 - rt5(4)
+rt9 TE-IS 50 rt3 - rt8(4)
+rt11 TE-IS 50 rt3 - rt8(4)
+10.0.255.10/32 IP TE 50 rt1 - rt10(4)
+10.0.255.8/32 IP TE 50 rt3 - rt8(4)
+rt12 TE-IS 60 rt3 - rt9(4)
+ rt11(4)
+10.0.255.9/32 IP TE 60 rt3 - rt9(4)
+10.0.255.11/32 IP TE 60 rt3 - rt11(4)
+10.0.255.12/32 IP TE 70 rt3 - rt12(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt2
+10.0.255.2/32 IP internal 0 rt2(4)
+rt1 TE-IS 10 rt1 - rt2(4)
+rt3 TE-IS 10 rt3 - rt2(4)
+rt5 TE-IS 10 rt5 - rt2(4)
+rt4 TE-IS 20 rt1 - rt1(4)
+rt6 TE-IS 20 rt3 - rt3(4)
+ rt5 - rt5(4)
+rt8 TE-IS 20 rt5 - rt5(4)
+10.0.255.1/32 IP TE 20 rt1 - rt1(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+10.0.255.5/32 IP TE 20 rt5 - rt5(4)
+rt7 TE-IS 30 rt1 - rt4(4)
+rt9 TE-IS 30 rt5 - rt8(4)
+rt11 TE-IS 30 rt5 - rt8(4)
+10.0.255.4/32 IP TE 30 rt1 - rt4(4)
+10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+ rt5 -
+10.0.255.8/32 IP TE 30 rt5 - rt8(4)
+rt10 TE-IS 40 rt1 - rt7(4)
+rt12 TE-IS 40 rt5 - rt9(4)
+ rt11(4)
+10.0.255.7/32 IP TE 40 rt1 - rt7(4)
+10.0.255.9/32 IP TE 40 rt5 - rt9(4)
+10.0.255.11/32 IP TE 40 rt5 - rt11(4)
+10.0.255.10/32 IP TE 50 rt1 - rt10(4)
+10.0.255.12/32 IP TE 50 rt5 - rt12(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ -----------------------------------------------------------
+ 10.0.255.1/32 20 - rt1 implicit-null
+ 10.0.255.2/32 0 - - -
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 30 - rt1 16040
+ 10.0.255.5/32 20 - rt5 implicit-null
+ 10.0.255.6/32 30 - rt3 16060
+ - rt5 16060
+ 10.0.255.7/32 40 - rt1 16070
+ 10.0.255.8/32 30 - rt5 16080
+ 10.0.255.9/32 40 - rt5 16090
+ 10.0.255.10/32 50 - rt1 16100
+ 10.0.255.11/32 40 - rt5 16110
+ 10.0.255.12/32 50 - rt5 16120
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ---------------------------------------------------------
+ 10.0.255.5/32 40 - rt3 50600/16050
+ 10.0.255.8/32 50 - rt3 50600/16080
+ 10.0.255.9/32 60 - rt3 50600/16090
+ 10.0.255.11/32 60 - rt3 50600/16110
+ 10.0.255.12/32 70 - rt3 50600/16120
+
+test# test isis topology 11 root rt2 remote-lfa system-id rt4
+P-space (self):
+
+P-space (rt1):
+ rt1
+ rt3
+ rt5
+
+P-space (rt3):
+ rt1
+ rt3
+ rt5
+ rt6
+
+Q-space:
+ rt1
+ rt3
+ rt4
+ rt5
+ rt6
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt2
+10.0.255.2/32 IP internal 0 rt2(4)
+rt1 TE-IS 50 rt1 - rt2(4)
+rt3 TE-IS 50 rt3 - rt2(4)
+rt2
+rt5 TE-IS 60 rt3 - rt3(4)
+10.0.255.1/32 IP TE 60 rt1 - rt1(4)
+10.0.255.3/32 IP TE 60 rt3 - rt3(4)
+rt4 TE-IS 70 rt3 - rt5(4)
+rt6 TE-IS 70 rt3 - rt5(4)
+10.0.255.5/32 IP TE 70 rt3 - rt5(4)
+10.0.255.4/32 IP TE 80 rt3 - rt4(4)
+10.0.255.6/32 IP TE 80 rt3 - rt6(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt2
+10.0.255.2/32 IP internal 0 rt2(4)
+rt4 TE-IS 10 rt4 - rt2(4)
+rt5 TE-IS 20 rt4 - rt4(4)
+rt6 TE-IS 20 rt4 - rt4(4)
+10.0.255.4/32 IP TE 20 rt4 - rt4(4)
+rt3 TE-IS 30 rt4 - rt5(4)
+10.0.255.5/32 IP TE 30 rt4 - rt5(4)
+10.0.255.6/32 IP TE 30 rt4 - rt6(4)
+rt2
+rt1 TE-IS 40 rt4 - rt2(2)
+10.0.255.3/32 IP TE 40 rt4 - rt3(4)
+10.0.255.1/32 IP TE 50 rt4 - rt1(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 50 - rt4 16010
+ 10.0.255.2/32 0 - - -
+ 10.0.255.3/32 40 - rt4 16030
+ 10.0.255.4/32 20 - rt4 implicit-null
+ 10.0.255.5/32 30 - rt4 16050
+ 10.0.255.6/32 30 - rt4 16060
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 50 - rt1 implicit-null
+ - rt3 16010
+ 10.0.255.3/32 50 - rt1 16030
+ - rt3 implicit-null
+ 10.0.255.4/32 80 - rt3 50500/16040
+ 10.0.255.5/32 60 - rt1 16050
+ - rt3 16050
+ 10.0.255.6/32 70 - rt3 16060
+
+P-space (self):
+
+P-space (rt1):
+ rt1
+ rt3
+ rt5
+
+P-space (rt3):
+ rt1
+ rt3
+ rt5
+ rt6
+
+Q-space:
+ rt1
+ rt3
+ rt4
+ rt5
+ rt6
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt2
+2001:db8::2/128 IP6 internal 0 rt2(4)
+rt1 TE-IS 50 rt1 - rt2(4)
+rt3 TE-IS 50 rt3 - rt2(4)
+rt2
+rt5 TE-IS 60 rt3 - rt3(4)
+2001:db8::1/128 IP6 internal 60 rt1 - rt1(4)
+2001:db8::3/128 IP6 internal 60 rt3 - rt3(4)
+rt4 TE-IS 70 rt3 - rt5(4)
+rt6 TE-IS 70 rt3 - rt5(4)
+2001:db8::5/128 IP6 internal 70 rt3 - rt5(4)
+2001:db8::4/128 IP6 internal 80 rt3 - rt4(4)
+2001:db8::6/128 IP6 internal 80 rt3 - rt6(4)
+
+IS-IS paths to level-1 routers that speak IPv6
+Vertex Type Metric Next-Hop Interface Parent
+rt2
+2001:db8::2/128 IP6 internal 0 rt2(4)
+rt4 TE-IS 10 rt4 - rt2(4)
+rt5 TE-IS 20 rt4 - rt4(4)
+rt6 TE-IS 20 rt4 - rt4(4)
+2001:db8::4/128 IP6 internal 20 rt4 - rt4(4)
+rt3 TE-IS 30 rt4 - rt5(4)
+2001:db8::5/128 IP6 internal 30 rt4 - rt5(4)
+2001:db8::6/128 IP6 internal 30 rt4 - rt6(4)
+rt2
+rt1 TE-IS 40 rt4 - rt2(2)
+2001:db8::3/128 IP6 internal 40 rt4 - rt3(4)
+2001:db8::1/128 IP6 internal 50 rt4 - rt1(4)
+
+Main:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 50 - rt4 16011
+ 2001:db8::2/128 0 - - -
+ 2001:db8::3/128 40 - rt4 16031
+ 2001:db8::4/128 20 - rt4 implicit-null
+ 2001:db8::5/128 30 - rt4 16051
+ 2001:db8::6/128 30 - rt4 16061
+
+Backup:
+IS-IS L1 IPv6 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ------------------------------------------------------------
+ 2001:db8::1/128 50 - rt1 implicit-null
+ - rt3 16011
+ 2001:db8::3/128 50 - rt1 16031
+ - rt3 implicit-null
+ 2001:db8::4/128 80 - rt3 50500/16041
+ 2001:db8::5/128 60 - rt1 16051
+ - rt3 16051
+ 2001:db8::6/128 70 - rt3 16061
+
+test# test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only
+P-space (self):
+ rt2
+
+P-space (rt2):
+ rt2
+ rt4
+
+Q-space:
+ rt3
+ rt4
+ rt5
+ rt6
+ rt7
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+rt3 TE-IS 30 rt2 - rt4(4)
+10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+rt5 TE-IS 40 rt2 - rt3(4)
+rt6 TE-IS 40 rt2 - rt3(4)
+10.0.255.3/32 IP TE 40 rt2 - rt3(4)
+rt7 TE-IS 50 rt2 - rt5(4)
+ rt6(4)
+10.0.255.5/32 IP TE 50 rt2 - rt5(4)
+10.0.255.6/32 IP TE 50 rt2 - rt6(4)
+10.0.255.7/32 IP TE 60 rt2 - rt7(4)
+
+IS-IS paths to level-1 routers that speak IP
+Vertex Type Metric Next-Hop Interface Parent
+rt1
+10.0.255.1/32 IP internal 0 rt1(4)
+rt2 TE-IS 10 rt2 - rt1(4)
+rt3 TE-IS 10 rt3 - rt1(4)
+rt4 TE-IS 20 rt2 - rt2(4)
+ rt3 - rt3(4)
+rt5 TE-IS 20 rt3 - rt3(4)
+rt6 TE-IS 20 rt3 - rt3(4)
+10.0.255.2/32 IP TE 20 rt2 - rt2(4)
+10.0.255.3/32 IP TE 20 rt3 - rt3(4)
+rt7 TE-IS 30 rt3 - rt5(4)
+ rt6(4)
+10.0.255.4/32 IP TE 30 rt2 - rt4(4)
+ rt3 -
+10.0.255.5/32 IP TE 30 rt3 - rt5(4)
+10.0.255.6/32 IP TE 30 rt3 - rt6(4)
+10.0.255.7/32 IP TE 40 rt3 - rt7(4)
+
+Main:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ ----------------------------------------------------------
+ 10.0.255.1/32 0 - - -
+ 10.0.255.2/32 20 - rt2 implicit-null
+ 10.0.255.3/32 20 - rt3 implicit-null
+ 10.0.255.4/32 30 - rt2 16040
+ - rt3 16040
+ 10.0.255.5/32 30 - rt3 16050
+ 10.0.255.6/32 30 - rt3 16060
+ 10.0.255.7/32 40 - rt3 16070
+
+Backup:
+IS-IS L1 IPv4 routing table:
+
+ Prefix Metric Interface Nexthop Label(s)
+ --------------------------------------------------------
+ 10.0.255.3/32 40 - rt2 50400/16030
+ 10.0.255.5/32 50 - rt2 50400/16050
+ 10.0.255.6/32 50 - rt2 50400/16060
+ 10.0.255.7/32 60 - rt2 50400/16070
+
+test#
test# test isis topology 1 root rt1 ti-lfa system-id rt2
P-space (self):
rt3
diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index ab9358408e..24bef07ec2 100644 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -82,7 +82,9 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.isis +@pytest.mark.ospf +@pytest.mark.rip def setup_module(module): global topo, net global fatal_error diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py index 98a5033f53..cc1c1e3a0c 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py +++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py @@ -64,7 +64,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) - +@pytest.mark.bfd def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py index 1adfec76d8..23da7ed850 100644 --- a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py +++ b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py @@ -127,7 +127,8 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5") switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4") - +@pytest.mark.bfd +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/bfd-ospf-topo1/__init__.py b/tests/topotests/bfd-ospf-topo1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/__init__.py diff --git a/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf new file mode 100644 index 0000000000..610a20f88a --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf @@ -0,0 +1,9 @@ +log file bfdd.log +log timestamp precision 3 +! +debug bfd network +debug bfd peer +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf new file mode 100644 index 0000000000..18def599b4 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf @@ -0,0 +1,21 @@ +log file ospf6d.log +log timestamp precision 3 +! +hostname rt1 +! +password 1 +! +interface eth-rt2 + ipv6 ospf6 network broadcast + ipv6 ospf6 bfd +! +interface eth-rt3 + ipv6 ospf6 network broadcast + ipv6 ospf6 bfd +! +router ospf6 + ospf6 router-id 1.1.1.1 + interface eth-rt2 area 0.0.0.0 + interface eth-rt3 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf new file mode 100644 index 0000000000..07b42f9885 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf @@ -0,0 +1,26 @@ +log file ospfd.log +log timestamp precision 3 +! +hostname rt1 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt2 + ip ospf area 0.0.0.0 + ip ospf bfd +! +interface eth-rt3 + ip ospf area 0.0.0.0 + ip ospf bfd +! +router ospf + ospf router-id 1.1.1.1 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref new file mode 100644 index 0000000000..f354eff697 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref @@ -0,0 +1,74 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "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":"ospf", + "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":"ospf", + "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":"ospf", + "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-ospf-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref new file mode 100644 index 0000000000..6465efb8b5 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref @@ -0,0 +1,70 @@ +{ + "::ffff:202:202\/128":[ + { + "prefix":"::ffff:202:202\/128", + "protocol":"ospf6", + "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":"ospf6", + "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":"ospf6", + "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":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref new file mode 100644 index 0000000000..63f0d50784 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref @@ -0,0 +1,26 @@ +[ + { + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref new file mode 100644 index 0000000000..42051f9582 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref @@ -0,0 +1,28 @@ +[ + { + "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" + }, + { + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref new file mode 100644 index 0000000000..d844ee6813 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref @@ -0,0 +1,15 @@ +[ + { + "peer": "10.0.2.2", + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt3", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref new file mode 100644 index 0000000000..32799084fb --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref @@ -0,0 +1,15 @@ +[ + { + "peer": "10.0.1.2", + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt2", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref new file mode 100644 index 0000000000..f354eff697 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref @@ -0,0 +1,74 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"ospf", + "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":"ospf", + "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":"ospf", + "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":"ospf", + "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-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref new file mode 100644 index 0000000000..43eecd0b7a --- /dev/null +++ b/tests/topotests/bfd-ospf-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":"ospf", + "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":"ospf", + "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":"ospf", + "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":"ospf", + "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-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref new file mode 100644 index 0000000000..409af6308b --- /dev/null +++ b/tests/topotests/bfd-ospf-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":"ospf", + "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":"ospf", + "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":"ospf", + "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":"ospf", + "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-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref new file mode 100644 index 0000000000..6465efb8b5 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref @@ -0,0 +1,70 @@ +{ + "::ffff:202:202\/128":[ + { + "prefix":"::ffff:202:202\/128", + "protocol":"ospf6", + "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":"ospf6", + "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":"ospf6", + "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":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref new file mode 100644 index 0000000000..cfb1ef1bb6 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref @@ -0,0 +1,70 @@ +{ + "::ffff:202:202\/128":[ + { + "prefix":"::ffff:202:202\/128", + "protocol":"ospf6", + "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":"ospf6", + "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":"ospf6", + "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":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref new file mode 100644 index 0000000000..58b44da5c2 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref @@ -0,0 +1,70 @@ +{ + "::ffff:202:202\/128":[ + { + "prefix":"::ffff:202:202\/128", + "protocol":"ospf6", + "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":"ospf6", + "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":"ospf6", + "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":"ospf6", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf new file mode 100644 index 0000000000..6003125b6b --- /dev/null +++ b/tests/topotests/bfd-ospf-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-ospf-topo1/rt2/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf new file mode 100644 index 0000000000..437f063d8f --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf @@ -0,0 +1,7 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf new file mode 100644 index 0000000000..2f35099564 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf @@ -0,0 +1,19 @@ +log file ospf6d.log +! +hostname rt2 +! +password 1 +! +interface eth-rt1 + ipv6 ospf6 network broadcast + ipv6 ospf6 bfd +! +interface eth-rt5 + ipv6 ospf6 network broadcast +! +router ospf6 + ospf6 router-id 2.2.2.2 + interface eth-rt1 area 0.0.0.0 + interface eth-rt5 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf new file mode 100644 index 0000000000..a05d8b58c8 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf @@ -0,0 +1,24 @@ +log file ospfd.log +! +hostname rt2 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt1 + ip ospf area 0.0.0.0 + ip ospf bfd +! +interface eth-rt5 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 2.2.2.2 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref new file mode 100644 index 0000000000..d6df1ebfb2 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref @@ -0,0 +1,14 @@ +[ + { + "interface": "eth-rt1", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt1", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf new file mode 100644 index 0000000000..5fc7fc5b28 --- /dev/null +++ b/tests/topotests/bfd-ospf-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-ospf-topo1/rt3/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf new file mode 100644 index 0000000000..437f063d8f --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf @@ -0,0 +1,7 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! +bfd +! diff --git a/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf new file mode 100644 index 0000000000..3e8777019e --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf @@ -0,0 +1,19 @@ +log file ospf6d.log +! +hostname rt3 +! +password 1 +! +interface eth-rt1 + ipv6 ospf6 network broadcast + ipv6 ospf6 bfd +! +interface eth-rt4 + ipv6 ospf6 network broadcast +! +router ospf6 + ospf6 router-id 3.3.3.3 + interface eth-rt1 area 0.0.0.0 + interface eth-rt4 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf new file mode 100644 index 0000000000..1196e6d189 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf @@ -0,0 +1,24 @@ +log file ospfd.log +! +hostname rt3 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt1 + ip ospf area 0.0.0.0 + ip ospf bfd +! +interface eth-rt4 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 3.3.3.3 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref new file mode 100644 index 0000000000..d6df1ebfb2 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref @@ -0,0 +1,14 @@ +[ + { + "interface": "eth-rt1", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + }, + { + "interface": "eth-rt1", + "status": "up", + "diagnostic": "ok", + "remote-diagnostic": "ok" + } +] diff --git a/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf new file mode 100644 index 0000000000..d368de9bbe --- /dev/null +++ b/tests/topotests/bfd-ospf-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-ospf-topo1/rt4/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf new file mode 100644 index 0000000000..f35e772790 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf @@ -0,0 +1,5 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! diff --git a/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf new file mode 100644 index 0000000000..bccd1e75bd --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf @@ -0,0 +1,18 @@ +log file ospf6d.log +! +hostname rt4 +! +password 1 +! +interface eth-rt3 + ipv6 ospf6 network broadcast +! +interface eth-rt5 + ipv6 ospf6 network broadcast +! +router ospf6 + ospf6 router-id 4.4.4.4 + interface eth-rt3 area 0.0.0.0 + interface eth-rt5 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf new file mode 100644 index 0000000000..3a2568b4ab --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf @@ -0,0 +1,23 @@ +log file ospfd.log +! +hostname rt4 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt3 + ip ospf area 0.0.0.0 +! +interface eth-rt5 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 4.4.4.4 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf new file mode 100644 index 0000000000..7b053bac35 --- /dev/null +++ b/tests/topotests/bfd-ospf-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-ospf-topo1/rt5/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf new file mode 100644 index 0000000000..f35e772790 --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf @@ -0,0 +1,5 @@ +! +debug bfd network +debug bfd peer +debug bfd zebra +! diff --git a/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf new file mode 100644 index 0000000000..766862276c --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf @@ -0,0 +1,18 @@ +log file ospf6d.log +! +hostname rt5 +! +password 1 +! +interface eth-rt2 + ipv6 ospf6 network broadcast +! +interface eth-rt4 + ipv6 ospf6 network broadcast +! +router ospf6 + ospf6 router-id 5.5.5.5 + interface eth-rt2 area 0.0.0.0 + interface eth-rt4 area 0.0.0.0 + redistribute connected +! diff --git a/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf new file mode 100644 index 0000000000..a35de5f45f --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf @@ -0,0 +1,23 @@ +log file ospfd.log +! +hostname rt5 +! +password 1 +! +debug ospf event +debug ospf zebra +! +interface lo + ip ospf area 0.0.0.0 +! +interface eth-rt2 + ip ospf area 0.0.0.0 +! +interface eth-rt4 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 5.5.5.5 + passive interface lo + router-info area 0.0.0.0 +! diff --git a/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf new file mode 100644 index 0000000000..0b7c9e02f3 --- /dev/null +++ b/tests/topotests/bfd-ospf-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-ospf-topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py new file mode 100755 index 0000000000..1cec62789b --- /dev/null +++ b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python + +# +# test_bfd_ospf_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_ospf_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_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.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_ospf_step1(): + logger.info("Test (step 1): verify RIB for OSPF") + 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 ospf json", "step1/show_ip_route.ref" + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf json", "step1/show_ipv6_route.ref" + ) + + +def test_bfd_ospf_sessions_step2(): + logger.info("Test (step 2): verify BFD peers for OSPF") + 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_ospf_interface_failure_rt2_step3(): + logger.info("Test (step 3): Check failover handling with RT2 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 ospf json", "step3/show_ip_route_rt2_down.ref", 1, 0 + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf 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 ospf json", "step3/show_ip_route_healthy.ref" + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf 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_ospf_interface_failure_rt3_step3(): + logger.info("Test (step 3): Check failover handling with RT3 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 ospf json", "step3/show_ip_route_rt3_down.ref", 1, 0 + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf 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 ospf json", "step3/show_ip_route_healthy.ref" + ) + router_compare_json_output( + "rt1", "show ipv6 route ospf 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)) diff --git a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py index bd3b876eeb..6283f03ddf 100644 --- a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py +++ b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py @@ -77,7 +77,8 @@ class BFDProfTopo(Topo): switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r6"]) - +@pytest.mark.bfd +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDProfTopo, mod.__name__) diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.py b/tests/topotests/bfd-topo1/test_bfd_topo1.py index 6e589d55eb..4c13fdcfc5 100644 --- a/tests/topotests/bfd-topo1/test_bfd_topo1.py +++ b/tests/topotests/bfd-topo1/test_bfd_topo1.py @@ -69,7 +69,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r4"]) - +@pytest.mark.bfd def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.py b/tests/topotests/bfd-topo2/test_bfd_topo2.py index feb4576bd3..5181a40f47 100644 --- a/tests/topotests/bfd-topo2/test_bfd_topo2.py +++ b/tests/topotests/bfd-topo2/test_bfd_topo2.py @@ -70,7 +70,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r4"]) - +@pytest.mark.bfd def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py index 5fed135f8d..956b526583 100644 --- a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py @@ -70,7 +70,7 @@ class BFDTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r4"]) - +@pytest.mark.bfd def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(BFDTopo, mod.__name__) diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py index 6a24684649..4e37ab00a3 100644 --- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py +++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py @@ -362,7 +362,7 @@ def config_hosts(tgen, hosts): host = tgen.gears[host_name] config_host(host_name, host) - +@pytest.mark.pim def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/bgp_features/exabgp.env b/tests/topotests/bgp_features/exabgp.env new file mode 100644 index 0000000000..6c554f5fa8 --- /dev/null +++ b/tests/topotests/bgp_features/exabgp.env @@ -0,0 +1,53 @@ + +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp_features/peer1/exa_readpipe.py b/tests/topotests/bgp_features/peer1/exa_readpipe.py new file mode 100644 index 0000000000..dba1536388 --- /dev/null +++ b/tests/topotests/bgp_features/peer1/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, 'r') + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_features/peer1/exabgp.cfg b/tests/topotests/bgp_features/peer1/exabgp.cfg new file mode 100644 index 0000000000..2e95252cf6 --- /dev/null +++ b/tests/topotests/bgp_features/peer1/exabgp.cfg @@ -0,0 +1,12 @@ +group exabgp { + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer1.in"; + encoder text; + } + neighbor 192.168.101.1 { + router-id 192.168.101.3; + local-address 192.168.101.3; + local-as 65403; + peer-as 65000; + } +} diff --git a/tests/topotests/bgp_features/peer2/exa_readpipe.py b/tests/topotests/bgp_features/peer2/exa_readpipe.py new file mode 100644 index 0000000000..dba1536388 --- /dev/null +++ b/tests/topotests/bgp_features/peer2/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, 'r') + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_features/peer2/exabgp.cfg b/tests/topotests/bgp_features/peer2/exabgp.cfg new file mode 100644 index 0000000000..1f65547bc5 --- /dev/null +++ b/tests/topotests/bgp_features/peer2/exabgp.cfg @@ -0,0 +1,12 @@ +group exabgp { + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer2.in"; + encoder text; + } + neighbor 192.168.101.1 { + router-id 192.168.101.4; + local-address 192.168.101.4; + local-as 65404; + peer-as 65000; + } +} diff --git a/tests/topotests/bgp_features/peer3/exa_readpipe.py b/tests/topotests/bgp_features/peer3/exa_readpipe.py new file mode 100644 index 0000000000..dba1536388 --- /dev/null +++ b/tests/topotests/bgp_features/peer3/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, 'r') + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_features/peer3/exabgp.cfg b/tests/topotests/bgp_features/peer3/exabgp.cfg new file mode 100644 index 0000000000..8632cc86c5 --- /dev/null +++ b/tests/topotests/bgp_features/peer3/exabgp.cfg @@ -0,0 +1,12 @@ +group exabgp { + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer3.in"; + encoder text; + } + neighbor 192.168.101.1 { + router-id 192.168.101.5; + local-address 192.168.101.5; + local-as 65405; + peer-as 65000; + } +} diff --git a/tests/topotests/bgp_features/peer4/exa_readpipe.py b/tests/topotests/bgp_features/peer4/exa_readpipe.py new file mode 100644 index 0000000000..dba1536388 --- /dev/null +++ b/tests/topotests/bgp_features/peer4/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, 'r') + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_features/peer4/exabgp.cfg b/tests/topotests/bgp_features/peer4/exabgp.cfg new file mode 100644 index 0000000000..06bc0d6e64 --- /dev/null +++ b/tests/topotests/bgp_features/peer4/exabgp.cfg @@ -0,0 +1,12 @@ +group exabgp { + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer4.in"; + encoder text; + } + neighbor 192.168.101.1 { + router-id 192.168.101.6; + local-address 192.168.101.6; + local-as 65406; + peer-as 65000; + } +} diff --git a/tests/topotests/bgp_features/r1/bgp_damp_announced.json b/tests/topotests/bgp_features/r1/bgp_damp_announced.json new file mode 100644 index 0000000000..cb4a2c9b2f --- /dev/null +++ b/tests/topotests/bgp_features/r1/bgp_damp_announced.json @@ -0,0 +1,21 @@ +{ + "localAS":65000, + "routes":{ + "192.168.31.0/24": [ { "valid":true, "network":"192.168.31.0\/24", "peerId":"192.168.101.3" } ], + "192.168.32.0/24": [ { "valid":true, "network":"192.168.32.0\/24", "peerId":"192.168.101.3" } ], + "192.168.33.0/24": [ { "valid":true, "network":"192.168.33.0\/24", "peerId":"192.168.101.3" } ], + "192.168.34.0/24": [ { "valid":true, "network":"192.168.34.0\/24", "peerId":"192.168.101.3" } ], + "192.168.41.0/24": [ { "valid":true, "network":"192.168.41.0\/24", "peerId":"192.168.101.4" } ], + "192.168.42.0/24": [ { "valid":true, "network":"192.168.42.0\/24", "peerId":"192.168.101.4" } ], + "192.168.43.0/24": [ { "valid":true, "network":"192.168.43.0\/24", "peerId":"192.168.101.4" } ], + "192.168.44.0/24": [ { "valid":true, "network":"192.168.44.0\/24", "peerId":"192.168.101.4" } ], + "192.168.51.0/24": [ { "valid":true, "network":"192.168.51.0\/24", "peerId":"192.168.101.5" } ], + "192.168.52.0/24": [ { "valid":true, "network":"192.168.52.0\/24", "peerId":"192.168.101.5" } ], + "192.168.53.0/24": [ { "valid":true, "network":"192.168.53.0\/24", "peerId":"192.168.101.5" } ], + "192.168.54.0/24": [ { "valid":true, "network":"192.168.54.0\/24", "peerId":"192.168.101.5" } ], + "192.168.61.0/24": [ { "valid":true, "network":"192.168.61.0\/24", "peerId":"192.168.101.6" } ], + "192.168.62.0/24": [ { "valid":true, "network":"192.168.62.0\/24", "peerId":"192.168.101.6" } ], + "192.168.63.0/24": [ { "valid":true, "network":"192.168.63.0\/24", "peerId":"192.168.101.6" } ], + "192.168.64.0/24": [ { "valid":true, "network":"192.168.64.0\/24", "peerId":"192.168.101.6" } ] + } +} diff --git a/tests/topotests/bgp_features/r1/bgp_damp_setup.json b/tests/topotests/bgp_features/r1/bgp_damp_setup.json new file mode 100644 index 0000000000..f9f89db894 --- /dev/null +++ b/tests/topotests/bgp_features/r1/bgp_damp_setup.json @@ -0,0 +1,10 @@ +{ + "ipv4Unicast":{ + "peers":{ + "192.168.101.3":{"remoteAs":65403, "state":"Established"}, + "192.168.101.4":{"remoteAs":65404, "state":"Established"}, + "192.168.101.5":{"remoteAs":65405, "state":"Established"}, + "192.168.101.6":{"remoteAs":65406, "state":"Established"} + } + } +} diff --git a/tests/topotests/bgp_features/r2/bgp_damp_announced.json b/tests/topotests/bgp_features/r2/bgp_damp_announced.json new file mode 100644 index 0000000000..9394358f82 --- /dev/null +++ b/tests/topotests/bgp_features/r2/bgp_damp_announced.json @@ -0,0 +1,21 @@ +{ + "localAS":65000, + "routes":{ + "192.168.31.0/24": [ { "network":"192.168.31.0\/24", "peerId":"192.168.0.1" } ], + "192.168.32.0/24": [ { "network":"192.168.32.0\/24", "peerId":"192.168.0.1" } ], + "192.168.33.0/24": [ { "network":"192.168.33.0\/24", "peerId":"192.168.0.1" } ], + "192.168.34.0/24": [ { "network":"192.168.34.0\/24", "peerId":"192.168.0.1" } ], + "192.168.41.0/24": [ { "network":"192.168.41.0\/24", "peerId":"192.168.0.1" } ], + "192.168.42.0/24": [ { "network":"192.168.42.0\/24", "peerId":"192.168.0.1" } ], + "192.168.43.0/24": [ { "network":"192.168.43.0\/24", "peerId":"192.168.0.1" } ], + "192.168.44.0/24": [ { "network":"192.168.44.0\/24", "peerId":"192.168.0.1" } ], + "192.168.51.0/24": [ { "network":"192.168.51.0\/24", "peerId":"192.168.0.1" } ], + "192.168.52.0/24": [ { "network":"192.168.52.0\/24", "peerId":"192.168.0.1" } ], + "192.168.53.0/24": [ { "network":"192.168.53.0\/24", "peerId":"192.168.0.1" } ], + "192.168.54.0/24": [ { "network":"192.168.54.0\/24", "peerId":"192.168.0.1" } ], + "192.168.61.0/24": [ { "network":"192.168.61.0\/24", "peerId":"192.168.0.1" } ], + "192.168.62.0/24": [ { "network":"192.168.62.0\/24", "peerId":"192.168.0.1" } ], + "192.168.63.0/24": [ { "network":"192.168.63.0\/24", "peerId":"192.168.0.1" } ], + "192.168.64.0/24": [ { "network":"192.168.64.0\/24", "peerId":"192.168.0.1" } ] + } +} diff --git a/tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json b/tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json new file mode 100644 index 0000000000..f3c54a70a1 --- /dev/null +++ b/tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json @@ -0,0 +1,18 @@ +{ + "192.168.31.0/24": null, + "192.168.32.0/24": null, + "192.168.33.0/24": null, + "192.168.34.0/24": null, + "192.168.41.0/24": null, + "192.168.42.0/24": null, + "192.168.43.0/24": null, + "192.168.44.0/24": null, + "192.168.51.0/24": null, + "192.168.52.0/24": null, + "192.168.53.0/24": null, + "192.168.54.0/24": null, + "192.168.61.0/24": null, + "192.168.62.0/24": null, + "192.168.63.0/24": null, + "192.168.64.0/24": null +} diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index 5f3809c2b3..3d963b4cf6 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -33,6 +33,7 @@ import sys import pytest import re import time +from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -64,6 +65,14 @@ class BGPFeaturesTopo1(Topo): for rtrNum in range(1, 6): tgen.add_router("r{}".format(rtrNum)) + # create ExaBGP peers + for peer_num in range(1, 5): + tgen.add_exabgp_peer( + "peer{}".format(peer_num), + ip="192.168.101.{}".format(peer_num + 2), + defaultRoute="via 192.168.101.1", + ) + # Setup Switches and connections for swNum in range(1, 11): tgen.add_switch("sw{}".format(swNum)) @@ -89,6 +98,12 @@ class BGPFeaturesTopo1(Topo): tgen.gears["r2"].add_link(tgen.gears["sw5"]) tgen.gears["r5"].add_link(tgen.gears["sw5"]) + # Add ExaBGP peers to sw4 + tgen.gears["peer1"].add_link(tgen.gears["sw4"]) + tgen.gears["peer2"].add_link(tgen.gears["sw4"]) + tgen.gears["peer3"].add_link(tgen.gears["sw4"]) + tgen.gears["peer4"].add_link(tgen.gears["sw4"]) + ##################################################### # @@ -1093,6 +1108,662 @@ def test_bgp_delayopen_dual(): # end test_bgp_delayopen_dual +def test_bgp_dampening_setup(): + "BGP route-flap dampening test setup" + + # This test starts four ExaBGP peers, adds them as neighbors to the + # configuration of router r1 and checks if connections get established. + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Starting BGP route-flap dampening test setup") + + # Start ExaBGP peers connected to r1 via switch 4 + logger.info("Starting ExaBGP peers") + for peer_num in range(1, 5): + logger.info("Creating named pipe for ExaBGP peer peer{}".format(peer_num)) + fifo_in = "/var/run/exabgp_peer{}.in".format(peer_num) + if os.path.exists(fifo_in): + os.remove(fifo_in) + os.mkfifo(fifo_in, 0o777) + logger.info("Starting ExaBGP on peer peer{}".format(peer_num)) + peer = tgen.gears["peer{}".format(peer_num)] + peer_dir = os.path.join(CWD, "peer{}".format(peer_num)) + env_file = os.path.join(CWD, "exabgp.env") + peer.start(peer_dir, env_file) + + # Add ExaBGP peers to configuration of router r2 + logger.info("Adding ExaBGP peers as neighbors to configuration of router r2") + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.3 remote-as 65403"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 route-map testmap-in"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 route-map testmap-out"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.4 remote-as 65404"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.4 route-map testmap-in"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.4 route-map testmap-out"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.5 remote-as 65405"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 route-map testmap-in"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 route-map testmap-out"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.6 remote-as 65406"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.6 route-map testmap-in"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.6 route-map testmap-out"' + ) + + # Check if exabgp peers are up and running + logger.info("Checking for established connections to ExaBGP peers on router r1") + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/bgp_damp_setup.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = ( + "BGP session on r1 did not establish connections with one ore more ExaBGP peers" + ) + assert res is None, assertmsg + + # end test_bgp_dampening_setup + + +def test_bgp_dampening_route_announce(): + "Test of BGP route-flap dampening route announcement" + + # This test checks if the four ExaBGP peers can announce routes to router + # r1 and if these routes get forwarded to router r2. + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Starting test of BGP route-flap dampening route announcement") + + # Announce routes on exabgp peers to r2 + logger.info("Announcing routes on ExaBGP peers to r1") + for prefix_iter in range(1, 5): + for peer_num in range(1, 5): + pipe = open("/run/exabgp_peer{}.in".format(peer_num), "w") + with pipe: + pipe.write( + "announce route 192.168.{}{}.0/24 next-hop 192.168.101.{}\n".format( + (peer_num + 2), prefix_iter, (peer_num + 2) + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + + # Check if routes announced by ExaBGP peers are present in RIB of router r1 + logger.info( + "Checking if routes announced by ExaBGP peers are present in RIB of router r1" + ) + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/bgp_damp_announced.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = ( + "BGP session on router r1 did not receive routes announced by ExaBGP peers" + ) + assert res is None, assertmsg + + # Check if routes announced by ExaBGP peers to router r1 have been forwarded + # and are now present in RIB of router r2 + logger.info( + "Checking if forwarded routes announced by ExaBGP peers are present in RIB of router r2" + ) + router = tgen.gears["r2"] + reffile = os.path.join(CWD, "r2/bgp_damp_announced.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = "BGP session on router r2 did not receive routes announced by ExaBGP peers forwarded by router r1" + assert res is None, assertmsg + + # end test_bgp_dampening_route_announce + + +def test_bgp_dampening_disabled(): + "Test of BGP route-flapping with dampening disabled" + + # This test verifies that flapped routes do not get withdrawn from the RIB + # of router r1 if dampening is disabled. + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Starting test of BGP route-flapping with dampening disabled") + + # Flapping routes on ExaBGP peer peer1 + logger.info( + "Flapping routes on ExaBGP peer peer1 with route-flap dampening disabled" + ) + for _ in range(1, 5): + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer1.in", "w") + with pipe: + pipe.write( + "withdraw route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + sleep(1) # Give the BGP session on router r1 time to process routes + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer1.in", "w") + with pipe: + pipe.write( + "announce route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + + # Verify flapped routes are still present in RIB of router r1 + logger.info( + "Verifying that the flapped routes are still present in RIB of router r1" + ) + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/bgp_damp_announced.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = "BGP session on router r1 removed flapped routes despite route-flap dampening being disabled" + assert res is None, assertmsg + + # end test_bgp_dampening_disabled + + +def test_bgp_dampening_config(): + "Test of BGP route-flap dampening configuration" + + # This test adds peer-group group1 with peers peer1 and peer2 to the + # configuration of router r1, sets up dampening configurations with + # different profiles and verifies the configured dampening parameters. + + tgen = get_topogen() + r_1 = tgen.net["r1"] + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Starting test of BGP route-flap dampening configuration") + + # Add peer-group group1 with peers peer1 and peer2 + logger.info( + "Creating peer-group group1 and adding ExaBGP peers peer1 and peer2 to it" + ) + r_1.cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor group1 peer-group"') + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.3 peer-group group1"' + ) # peer1 + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.4 peer-group group1"' + ) # peer2 + + # Enable different dampening profiles for peer1, peer3, group1 and global + # configuration + logger.info( + "Enabling different dampening profiles for peer1, peer3, group1 and global configuration" + ) + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "bgp dampening 30 300 900 90"' + ) + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor group1 dampening 20 200 600 60"' + ) + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 dampening 10 100 300 30"' + ) # peer1 + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 dampening 10 100 300 30"' + ) # peer3 + + # Verify route-flap dampening configuration + logger.info("Verifying route-flap dampening configuration on router r1") + vtyout = r_1.cmd('vtysh -c "show running-config"') + assertmsg = "BGP Session on r1 does not show enabled global route-flap dampening in running configuration" + assert re.search("bgp dampening 30 300 900 90", vtyout), assertmsg + assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer-group group1 in running configuration" + assert re.search("neighbor group1 dampening 20 200 600 60", vtyout), assertmsg + assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer peer1 in running configuration" + assert re.search( + "neighbor 192.168.101.3 dampening 10 100 300 30", vtyout + ), assertmsg + assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer peer3 in running configuration" + assert re.search( + "neighbor 192.168.101.5 dampening 10 100 300 30", vtyout + ), assertmsg + + # end test_bgp_dampening_config + + +def test_bgp_dampening_profile_peer_over_group(): + "Test of BGP route-flap dampening profile preferences: peer over group" + + # This test verifies that the dampening profile of a peer takes precedence + # over the dampening profile of its peer-group by flapping the peers routes + # until dampened and comparing the reuse times to the one specified in the + # dampening configuration. + + tgen = get_topogen() + r_1 = tgen.net["r1"] + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + "Starting test of BGP route-flap dampening profile preferences: peer over group" + ) + + # Flapping routes on ExaBGP peer peer1 + logger.info( + "Flapping routes on ExaBGP peer peer1 with route-flap dampening enabled" + ) + for _ in range(1, 5): + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer1.in", "w") + with pipe: + pipe.write( + "withdraw route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + sleep(1) # Give the BGP session on router r1 time to process routes + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer1.in", "w") + with pipe: + pipe.write( + "announce route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + + # Check damped paths on r1 for routes of peer1 witn peer profile + logger.info( + "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer1" + ) + sleep(5) # Wait 5 seconds for paths to show up in dampened-paths list + vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"') + routes = re.findall(r"\*d 192\.168\.3\d\.0\/24.*", vtyout) + assertmsg = ( + "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer1" + ) + assert len(routes) == 4, assertmsg + assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer1" + for route in routes: + assert (int(route.split()[3].split(":")[0]) == 0) and ( # hours of reuse time + 35 > int(route.split()[3].split(":")[1]) > 25 + ), assertmsg # minutes of reuse time + + # end test_bgp_dampening_profile_peer_over_group + + +def test_bgp_dampening_profile_group_over_global(): + "Test of BGP route-flap dampening profile preferences: group over global" + + # This test verifies that the dampening profile of a peer-group takes + # precedence over the global dampening profile by flapping the routes of a + # peer-group member until dampened and comparing the reuse times to the one + # specified in the dampening configuration. + + tgen = get_topogen() + r_1 = tgen.net["r1"] + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + "Starting test of BGP route-flap dampening profile preferences: group over global" + ) + + # Flapping routes on ExaBGP peer peer2 + logger.info( + "Flapping routes on ExaBGP peer peer2 with route-flap dampening enabled" + ) + for _ in range(1, 5): + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer2.in", "w") + with pipe: + pipe.write( + "withdraw route 192.168.4{}.0/24 next-hop 192.168.101.4\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + sleep(1) # Give the BGP session on router r1 time to process routes + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer2.in", "w") + with pipe: + pipe.write( + "announce route 192.168.4{}.0/24 next-hop 192.168.101.4\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + + # Check damped paths on r1 for routes of peer2 witn group profile + logger.info( + "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer2" + ) + sleep(5) # wait 5 seconds for paths to shop up in damp list + vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"') + routes = re.findall(r"\*d 192\.168\.4\d\.0\/24.*", vtyout) + assertmsg = ( + "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer2" + ) + assert len(routes) == 4, assertmsg + assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer2" + for route in routes: + assert (int(route.split()[3].split(":")[0]) == 0) and ( # hours of reuse time + 65 > int(route.split()[3].split(":")[1]) > 55 + ), assertmsg # minutes of reuse time + + # end test_bgp_dampening_profile_group_over_global + + +def test_bgp_dampening_profile_peer_over_global(): + "Test of BGP route-flap dampening profile preferences: peer over global" + + # This test verifies that the dampening profile of a peer takes precedence + # over the global dampening profile by flapping the routes of the peer until + # dampened and comparing the reuse times to the one specified in the + # dampening configuration. + + tgen = get_topogen() + r_1 = tgen.net["r1"] + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + "Starting test of BGP route-flap dampening profile preferences: peer over global" + ) + + # Flapping routes on ExaBGP peer peer3 + logger.info( + "Flapping routes on ExaBGP peer peer3 with route-flap dampening enabled" + ) + for _ in range(1, 5): + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer3.in", "w") + with pipe: + pipe.write( + "withdraw route 192.168.5{}.0/24 next-hop 192.168.101.5\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + sleep(1) # Give the BGP session on router r1 time to process routes + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer3.in", "w") + with pipe: + pipe.write( + "announce route 192.168.5{}.0/24 next-hop 192.168.101.5\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + + # Check damped paths on r1 for routes of peer3 witn peer profile + logger.info( + "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer3" + ) + sleep(5) # wait 5 seconds for paths to shop up in damp list + vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"') + routes = re.findall(r"\*d 192\.168\.5\d\.0\/24.*", vtyout) + assertmsg = ( + "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer3" + ) + assert len(routes) == 4, assertmsg + assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer3" + for route in routes: + assert (int(route.split()[3].split(":")[0]) == 0) and ( # hours of reuse time + 35 > int(route.split()[3].split(":")[1]) > 25 + ), assertmsg # minutes of reuse time + + # end test_bgp_dampening_profile_peer_over_global + + +def test_bgp_dampening_profile_global(): + "Test of BGP route-flap dampening global profile" + + # This test verifies the application of the global dampening profile by + # flapping the routes of a peer until dampened and comparing the reuse times + # to the one specified in the dampening configuration. + + tgen = get_topogen() + r_1 = tgen.net["r1"] + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Starting test of BGP route-flap dampening global profile") + + # Flapping routes on ExaBGP peer peer4 + logger.info( + "Flapping routes on ExaBGP peer peer4 with route-flap dampening enabled" + ) + for _ in range(1, 5): + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer4.in", "w") + with pipe: + pipe.write( + "withdraw route 192.168.6{}.0/24 next-hop 192.168.101.6\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + sleep(1) # Give the BGP session on router r1 time to process routes + for prefix_iter in range(1, 5): + pipe = open("/run/exabgp_peer4.in", "w") + with pipe: + pipe.write( + "announce route 192.168.6{}.0/24 next-hop 192.168.101.6\n".format( + prefix_iter + ) + ) + pipe.close() + sleep(0.1) # ExaBGP API command processing delay + + # Check damped paths on r1 for routes of peer4 witn global profile + logger.info( + "Checking if router r1 used the global dampening profile on routes flapped by ExaBGP peer peer4" + ) + sleep(5) # wait 5 seconds for paths to shop up in damp list + vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"') + routes = re.findall(r"\*d 192\.168\.6\d\.0\/24.*", vtyout) + assertmsg = ( + "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer4" + ) + assert len(routes) == 4, assertmsg + assertmsg = "BGP session on router r1 did not use the global dampening profile for a route flapped by ExaBGP peer peer4" + for route in routes: + assert (int(route.split()[3].split(":")[0]) == 1) and ( # hours of reuse time + 35 > int(route.split()[3].split(":")[1]) > 25 + ), assertmsg # minutes of reuse time + + # end test_bgp_dampening_profile_global + + +def test_bgp_dampening_withdaw(): + "Test BGP route-flap dampening route withdraw" + + # This test verifies that the withrawl of dampened routes from the RIB of + # router r1 was propagated to router r2. + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Starting test of BGP route-flap dampening route withdraw") + + # Check if routes dampened on router r1 have been withdrawn from the RIB on + # router r2 + logger.info( + "Checking if routes dampened on router r1 have been withdrawn of RIB on router r2" + ) + reffile = os.path.join(CWD, "r2/bgp_damp_withdrawn.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, tgen.gears["r2"], "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=5, wait=1) + assertmsg = "BGP session on router r2 did not receive withdraw of routes dampened on router r1" + assert res is None, assertmsg + + # end test_bgp_dampening_withdaw + + +def test_bgp_dampening_cleanup(): + "BGP route-flap dampening test cleanup" + + # This test cleans up after other tests associated with route-flap dampening + # by disabling all dampening configurations, removing added peers and + # peer-groups from the configuration on router r1, and shutting down ExaBGP + # peers peer1, peer2 and peer3. + + tgen = get_topogen() + r_1 = tgen.net["r1"] + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Starting BGP route-flap dampening test cleanup") + + # Disable all dampening configurations + logger.info("Disabling all dampening configurations") + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no bgp dampening"' + ) + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor group1 dampening"' + ) + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor 192.168.101.3 dampening"' + ) + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor 192.168.101.5 dampening"' + ) + + # Remove ExaBGP peers from configuration of router r1 + logger.info("Removing ExaBGP peers from configuration of router r1") + for router_num in range(3, 7): + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.{}"'.format( + router_num + ) + ) + + # Remove peer-group group1 from configuration of router r1 + logger.info("Removing peer-group group1 peers from configuration of router r1") + r_1.cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor group1 peer-group"' + ) + + # Stop ExaBGP peers and remove associated named pipes + logger.info("Stopping ExaBGP peers and removing associated named pipes") + for peer_num in range(1, 5): + logger.info("Terminating ExaBGP on peer peer{}".format(peer_num)) + peer = tgen.gears["peer{}".format(peer_num)] + logger.info("Removing named pipe of ExaBGP peer peer{}".format(peer_num)) + fifo_in = "/var/run/exabgp_peer{}.in".format(peer_num) + peer.stop() + if os.path.exists(fifo_in): + os.remove(fifo_in) + + # end test_bgp_dampening_cleanup + + +def test_bgp_dampening_aftermath(): + "BGP route-flap dampening aftermath test" + + # This test verifies routers r1 and r2 not being affected by the route-flap + # dampening test series. + + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Check BGP Summary on routers r1 and r2 + for rtr_num in [1, 2]: + logger.info( + "Checking if BGP router on r{} remains unaffected by route-flap dampening tests".format( + rtr_num + ) + ) + router = tgen.gears["r{}".format(rtr_num)] + reffile = os.path.join(CWD, "r{}/show_bgp.json".format(rtr_num)) + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=2) + assertmsg = "BGP routes on router r{} are wrong after route-flap dampening tests".format( + rtr_num + ) + assert res is None, assertmsg + + # end test_bgp_dampening_aftermath + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json b/tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json new file mode 100644 index 0000000000..95de8cc10c --- /dev/null +++ b/tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json @@ -0,0 +1,154 @@ +{ + "ipv4base": "10.0.0.0", + "ipv4mask": 24, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 24, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "1000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "2000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "2000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": {} + } + }, + "r4": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "3000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py b/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py new file mode 100755 index 0000000000..d773e87ef6 --- /dev/null +++ b/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python + +# +# test_bgp_listen_on_multiple_addresses.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by Boeing Defence Australia +# Adriano Marto Reis +# +# 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_bgp_listen_on_multiple_addresses.py: Test BGP daemon listening for +connections on multiple addresses. + + +------+ +------+ +------+ +------+ + | | | | | | | | + | r1 |--------| r2 |--------| r3 |--------| r4 | + | | | | | | | | + +------+ +------+ +------+ +------+ + + | | | | + | AS 1000 | AS 2000 | AS 3000 | + | | | | + +------------+--------------------------------+-------------+ +""" + +import os +import sys +import json +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, "../")) + +from lib.topogen import Topogen, get_topogen +from lib.topojson import build_topo_from_json, build_config_from_json +from lib.common_config import start_topology +from lib.topotest import router_json_cmp, run_and_expect +from mininet.topo import Topo +from functools import partial + + +LISTEN_ADDRESSES = { + "r1": ["10.0.0.1"], + "r2": ["10.0.0.2", "10.0.1.1"], + "r3": ["10.0.1.2", "10.0.2.1"], + "r4": ["10.0.2.2"], +} + + +# Reads data from JSON File for topology and configuration creation. +jsonFile = "{}/bgp_listen_on_multiple_addresses.json".format(CWD) +try: + with open(jsonFile, "r") as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + + +class TemplateTopo(Topo): + "Topology builder." + + def build(self, *_args, **_opts): + "Defines the allocation and relationship between routers and switches." + tgen = get_topogen(self) + build_topo_from_json(tgen, topo) + + +def setup_module(mod): + "Sets up the test environment." + tgen = Topogen(TemplateTopo, mod.__name__) + + # Adds extra parameters to bgpd so they listen for connections on specific + # multiple addresses. + for router_name in tgen.routers().keys(): + tgen.net[router_name].daemons_options["bgpd"] = "-l " + " -l ".join( + LISTEN_ADDRESSES[router_name] + ) + + start_topology(tgen) + build_config_from_json(tgen, topo) + + +def teardown_module(_mod): + "Tears-down the test environment." + tgen = get_topogen() + tgen.stop_topology() + + +def test_peering(): + "Checks if the routers peer-up." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + _bgp_converge_initial("r1", "10.0.0.2") + _bgp_converge_initial("r2", "10.0.0.1") + _bgp_converge_initial("r2", "10.0.1.2") + _bgp_converge_initial("r3", "10.0.1.1") + _bgp_converge_initial("r3", "10.0.2.2") + _bgp_converge_initial("r4", "10.0.2.1") + + +def test_listening_address(): + """ + Checks if bgpd is only listening on the specified IP addresses. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for router in tgen.routers().values(): + # bgpd must not be listening on the default address. + output = router.run("netstat -nlt4 | grep 0.0.0.0:179") + assert output == "", "{}: bpgd is listening on 0.0.0.0:179".format(router.name) + + # bgpd must be listening on the specified addresses. + for address in LISTEN_ADDRESSES[router.name]: + output = router.run("netstat -nlt4 | grep {}:179".format(address)) + assert output != "", "{}: bpgd is not listening on {}:179".format( + router.name, address + ) + + +def _bgp_converge_initial(router_name, peer_address, timeout=180): + """ + Waits for the BGP connection between a given router and a given peer + (specified by its IP address) to be established. If the connection is + not established within a given timeout, then an exception is raised. + """ + tgen = get_topogen() + router = tgen.routers()[router_name] + expected = {"ipv4Unicast": {"peers": {peer_address: {"state": "Established"}}}} + + test_func = partial(router_json_cmp, router, "show ip bgp summary json", expected) + _, result = run_and_expect(test_func, None, count=timeout, wait=1) + assert result is None, "{}: Failed to establish connection with {}".format( + router_name, peer_address + ) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_peer-group/__init__.py b/tests/topotests/bgp_peer-group/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_peer-group/__init__.py diff --git a/tests/topotests/bgp_peer-group/r1/bgpd.conf b/tests/topotests/bgp_peer-group/r1/bgpd.conf new file mode 100644 index 0000000000..19b490a359 --- /dev/null +++ b/tests/topotests/bgp_peer-group/r1/bgpd.conf @@ -0,0 +1,8 @@ +! +router bgp 65001 + neighbor PG peer-group + neighbor PG remote-as external + neighbor PG timers 3 10 + neighbor 192.168.255.3 peer-group PG + neighbor r1-eth0 interface peer-group PG +! diff --git a/tests/topotests/bgp_peer-group/r1/zebra.conf b/tests/topotests/bgp_peer-group/r1/zebra.conf new file mode 100644 index 0000000000..e2c399e536 --- /dev/null +++ b/tests/topotests/bgp_peer-group/r1/zebra.conf @@ -0,0 +1,6 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_peer-group/r2/bgpd.conf b/tests/topotests/bgp_peer-group/r2/bgpd.conf new file mode 100644 index 0000000000..0880ee9fae --- /dev/null +++ b/tests/topotests/bgp_peer-group/r2/bgpd.conf @@ -0,0 +1,7 @@ +! +router bgp 65002 + neighbor PG peer-group + neighbor PG remote-as external + neighbor PG timers 3 10 + neighbor r2-eth0 interface peer-group PG +! diff --git a/tests/topotests/bgp_peer-group/r2/zebra.conf b/tests/topotests/bgp_peer-group/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp_peer-group/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_peer-group/r3/bgpd.conf b/tests/topotests/bgp_peer-group/r3/bgpd.conf new file mode 100644 index 0000000000..eb2fca15fb --- /dev/null +++ b/tests/topotests/bgp_peer-group/r3/bgpd.conf @@ -0,0 +1,7 @@ +! +router bgp 65003 + neighbor PG peer-group + neighbor PG remote-as external + neighbor PG timers 3 10 + neighbor 192.168.255.1 peer-group PG +! diff --git a/tests/topotests/bgp_peer-group/r3/zebra.conf b/tests/topotests/bgp_peer-group/r3/zebra.conf new file mode 100644 index 0000000000..e9fdfb70c5 --- /dev/null +++ b/tests/topotests/bgp_peer-group/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_peer-group/test_bgp_peer-group.py b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py new file mode 100644 index 0000000000..7c7a8b87ed --- /dev/null +++ b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py @@ -0,0 +1,99 @@ +#!/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 peer-group works for numbered and unnumbered configurations. +""" + +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 + + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 4): + 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"]) + + +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_peer_group(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_peer_group_configured(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor json")) + expected = { + "r1-eth0": {"peerGroup": "PG", "bgpState": "Established"}, + "192.168.255.3": {"peerGroup": "PG", "bgpState": "Established"}, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_peer_group_configured) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r1"]) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py index 3ce1472ac0..bf94d39a4b 100644 --- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py @@ -91,7 +91,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.eigrp def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py index 265124132f..07623af063 100644 --- a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py +++ b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py @@ -97,7 +97,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.pim def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py index 6f80ffd1aa..a655b418cf 100755 --- a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py @@ -163,7 +163,7 @@ class TemplateTopo(Topo): f_in.close() f_out.close() - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/isis-rlfa-topo1/__init__.py b/tests/topotests/isis-rlfa-topo1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/__init__.py diff --git a/tests/topotests/isis-rlfa-topo1/rt1/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt1/isisd.conf new file mode 100644 index 0000000000..a80f30dc7b --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/isisd.conf @@ -0,0 +1,39 @@ +password 1 +hostname rt1 +log file isisd.log +! +debug isis events +debug isis route-events +debug isis spf-events +debug isis lsp-gen +! +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 network point-to-point + isis fast-reroute lfa + isis fast-reroute remote-lfa tunnel mpls-ldp +! +interface eth-rt3 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point + isis fast-reroute lfa + isis fast-reroute remote-lfa tunnel mpls-ldp +! +ip prefix-list PLIST seq 5 permit 10.0.255.8/32 +! +router isis 1 + net 49.0000.0000.0000.0001.00 + is-type level-1-2 + lsp-gen-interval 2 + topology ipv6-unicast + fast-reroute remote-lfa prefix-list PLIST +! diff --git a/tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf new file mode 100644 index 0000000000..f60fdb9742 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf @@ -0,0 +1,30 @@ +log file ldpd.log +! +hostname rt1 +! +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 10.0.255.1 + dual-stack transport-connection prefer ipv4 + ! + address-family ipv4 + label local allocate host-routes + discovery targeted-hello accept + discovery transport-address 10.0.255.1 + ! + interface eth-rt2 + interface eth-rt3 + ! + ! + address-family ipv6 + label local allocate host-routes + discovery transport-address 2001:db8::1 + ! + interface eth-rt2 + interface eth-rt3 + ! + ! +! diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref new file mode 100644 index 0000000000..680b31eb8d --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref @@ -0,0 +1,235 @@ +{ + "10.0.255.2\/32":[ + { + "prefix":"10.0.255.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.255.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, + "onLink":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.255.3", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, + "onLink":true, + "labels":"*" + } + ] + } + ], + "10.0.255.3\/32":[ + { + "prefix":"10.0.255.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.255.3", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, + "onLink":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.255.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, + "onLink":true, + "labels":"*" + } + ] + } + ], + "10.0.255.4\/32":[ + { + "prefix":"10.0.255.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.255.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, + "onLink":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.255.3", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, + "onLink":true, + "labels":"*" + } + ] + } + ], + "10.0.255.5\/32":[ + { + "prefix":"10.0.255.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.255.3", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, + "onLink":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.255.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, + "onLink":true, + "labels":"*" + } + ] + } + ], + "10.0.255.6\/32":[ + { + "prefix":"10.0.255.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.255.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, + "onLink":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.255.3", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, + "onLink":true, + "labels":"*" + } + ] + } + ], + "10.0.255.7\/32":[ + { + "prefix":"10.0.255.7\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.255.3", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, + "onLink":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.255.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, + "onLink":true, + "labels":"*" + } + ] + } + ], + "10.0.255.8\/32":[ + { + "prefix":"10.0.255.8\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":50, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.255.2", + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, + "onLink":true + }, + { + "fib":true, + "ip":"10.0.255.3", + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, + "onLink":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref new file mode 100644 index 0000000000..c487d2740d --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8::2\/128":[ + { + "prefix":"2001:db8::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true, + "labels":"*" + } + ] + } + ], + "2001:db8::3\/128":[ + { + "prefix":"2001:db8::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "labels":"*" + } + ] + } + ], + "2001:db8::4\/128":[ + { + "prefix":"2001:db8::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true, + "labels":"*" + } + ] + } + ], + "2001:db8::5\/128":[ + { + "prefix":"2001:db8::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "labels":"*" + } + ] + } + ], + "2001:db8::6\/128":[ + { + "prefix":"2001:db8::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true, + "labels":"*" + } + ] + } + ], + "2001:db8::7\/128":[ + { + "prefix":"2001:db8::7\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true, + "labels":"*" + } + ] + } + ], + "2001:db8::8\/128":[ + { + "prefix":"2001:db8::8\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":50, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref new file mode 100644 index 0000000000..3fe2b798a0 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref @@ -0,0 +1,44 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "eth-rt2", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1-2", + "neighbor-sysid": "0000.0000.0002", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + }, + { + "name": "eth-rt3", + "vrf": "default", + "state": { + "frr-isisd:isis": { + "adjacencies": { + "adjacency": [ + { + "neighbor-sys-type": "level-1-2", + "neighbor-sysid": "0000.0000.0003", + "hold-timer": 9, + "neighbor-priority": 0, + "state": "up" + } + ] + } + } + } + } + ] + } +} diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff new file mode 100644 index 0000000000..ef5707f14a --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff @@ -0,0 +1,68 @@ +--- a/rt1/step9/show_ip_route.ref ++++ b/rt1/step10/show_ip_route.ref +@@ -15,7 +15,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -70,7 +83,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -125,7 +151,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..acd2ce003a --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff @@ -0,0 +1,62 @@ +--- a/rt1/step9/show_ipv6_route.ref ++++ b/rt1/step10/show_ipv6_route.ref +@@ -13,7 +13,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -62,7 +73,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -111,7 +133,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff new file mode 100644 index 0000000000..f7f31ac021 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff @@ -0,0 +1,134 @@ +--- a/rt1/step1/show_ip_route.ref ++++ b/rt1/step2/show_ip_route.ref +@@ -15,20 +15,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -49,20 +36,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.2", +- "afi":"ipv4", +- "interfaceName":"eth-rt2", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -83,20 +57,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -117,20 +78,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.2", +- "afi":"ipv4", +- "interfaceName":"eth-rt2", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -151,20 +99,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -185,20 +120,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.2", +- "afi":"ipv4", +- "interfaceName":"eth-rt2", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..e980031ad7 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff @@ -0,0 +1,122 @@ +--- a/rt1/step1/show_ipv6_route.ref ++++ b/rt1/step2/show_ipv6_route.ref +@@ -13,18 +13,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -43,18 +32,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -73,18 +51,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -103,18 +70,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -133,18 +89,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -163,18 +108,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff new file mode 100644 index 0000000000..f3ed764f0b --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff @@ -0,0 +1,134 @@ +--- a/rt1/step2/show_ip_route.ref ++++ b/rt1/step3/show_ip_route.ref +@@ -15,7 +15,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -36,7 +49,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.2", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -57,7 +83,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -78,7 +117,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.2", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -99,7 +151,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -120,7 +185,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.2", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..57b0b1de1a --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff @@ -0,0 +1,122 @@ +--- a/rt1/step2/show_ipv6_route.ref ++++ b/rt1/step3/show_ipv6_route.ref +@@ -13,7 +13,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -32,7 +43,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -51,7 +73,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -70,7 +103,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -89,7 +133,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -108,7 +163,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "labels":"*" + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff new file mode 100644 index 0000000000..107a0ba2f7 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff @@ -0,0 +1,68 @@ +--- a/rt1/step3/show_ip_route.ref ++++ b/rt1/step4/show_ip_route.ref +@@ -15,20 +15,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -83,20 +70,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -151,20 +125,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..9cf24082e1 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff @@ -0,0 +1,62 @@ +--- a/rt1/step3/show_ipv6_route.ref ++++ b/rt1/step4/show_ipv6_route.ref +@@ -13,18 +13,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -73,18 +62,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -133,18 +111,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff new file mode 100644 index 0000000000..09469501f5 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff @@ -0,0 +1,68 @@ +--- a/rt1/step4/show_ip_route.ref ++++ b/rt1/step5/show_ip_route.ref +@@ -36,20 +36,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.2", +- "afi":"ipv4", +- "interfaceName":"eth-rt2", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -91,20 +78,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.2", +- "afi":"ipv4", +- "interfaceName":"eth-rt2", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -146,20 +120,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.2", +- "afi":"ipv4", +- "interfaceName":"eth-rt2", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..70fb1a65c7 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff @@ -0,0 +1,62 @@ +--- a/rt1/step4/show_ipv6_route.ref ++++ b/rt1/step5/show_ipv6_route.ref +@@ -32,18 +32,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -81,18 +70,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -130,18 +108,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt2", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff new file mode 100644 index 0000000000..4e4a5692a4 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff @@ -0,0 +1,134 @@ +--- a/rt1/step5/show_ip_route.ref ++++ b/rt1/step6/show_ip_route.ref +@@ -15,7 +15,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -36,7 +49,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.2", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -57,7 +83,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -78,7 +117,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.2", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -99,7 +151,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.3", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } +@@ -120,7 +185,20 @@ + "afi":"ipv4", + "interfaceName":"eth-rt3", + "active":true, +- "onLink":true ++ "onLink":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "ip":"10.0.255.2", ++ "afi":"ipv4", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "onLink":true, ++ "labels":"*" + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..c9ebb1e3f5 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff @@ -0,0 +1,122 @@ +--- a/rt1/step5/show_ipv6_route.ref ++++ b/rt1/step6/show_ipv6_route.ref +@@ -13,7 +13,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -32,7 +43,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -51,7 +73,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -70,7 +103,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -89,7 +133,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt3", ++ "active":true, ++ "labels":"*" + } + ] + } +@@ -108,7 +163,18 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3", +- "active":true ++ "active":true, ++ "backupIndex":[ ++ 0 ++ ] ++ } ++ ], ++ "backupNexthops":[ ++ { ++ "afi":"ipv6", ++ "interfaceName":"eth-rt2", ++ "active":true, ++ "labels":"*" + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff new file mode 100644 index 0000000000..33eb6577bd --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff @@ -0,0 +1,68 @@ +--- a/rt1/step8/show_ip_route.ref ++++ b/rt1/step9/show_ip_route.ref +@@ -15,20 +15,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -83,20 +70,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } +@@ -151,20 +125,7 @@ + "afi":"ipv4", + "interfaceName":"eth-rt2", + "active":true, +- "onLink":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "ip":"10.0.255.3", +- "afi":"ipv4", +- "interfaceName":"eth-rt3", +- "active":true, +- "onLink":true, +- "labels":"*" ++ "onLink":true + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff new file mode 100644 index 0000000000..7aaca3354e --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff @@ -0,0 +1,62 @@ +--- a/rt1/step8/show_ipv6_route.ref ++++ b/rt1/step9/show_ipv6_route.ref +@@ -13,18 +13,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -73,18 +62,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } +@@ -133,18 +111,7 @@ + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2", +- "active":true, +- "backupIndex":[ +- 0 +- ] +- } +- ], +- "backupNexthops":[ +- { +- "afi":"ipv6", +- "interfaceName":"eth-rt3", +- "active":true, +- "labels":"*" ++ "active":true + } + ] + } diff --git a/tests/topotests/isis-rlfa-topo1/rt1/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt1/zebra.conf new file mode 100644 index 0000000000..741fc2d02b --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt1/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt1 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 10.0.255.1/32 + ipv6 address 2001:db8::1/128 +! +interface eth-rt2 + ip address 10.0.255.1/32 +! +interface eth-rt3 + ip address 10.0.255.1/32 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-rlfa-topo1/rt2/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt2/isisd.conf new file mode 100644 index 0000000000..7b4c6c50b9 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt2/isisd.conf @@ -0,0 +1,32 @@ +password 1 +hostname rt2 +log file isisd.log +! +debug isis events +debug isis route-events +debug isis spf-events +debug isis lsp-gen +! +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 +! +interface eth-rt4 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +router isis 1 + net 49.0000.0000.0000.0002.00 + is-type level-1-2 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf new file mode 100644 index 0000000000..0a815ef004 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf @@ -0,0 +1,30 @@ +log file ldpd.log +! +hostname rt2 +! +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 10.0.255.2 + dual-stack transport-connection prefer ipv4 + ! + address-family ipv4 + label local allocate host-routes + discovery targeted-hello accept + discovery transport-address 10.0.255.2 + ! + interface eth-rt1 + interface eth-rt4 + ! + ! + address-family ipv6 + label local allocate host-routes + discovery transport-address 2001:db8::2 + ! + interface eth-rt1 + interface eth-rt4 + ! + ! +! diff --git a/tests/topotests/isis-rlfa-topo1/rt2/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt2/zebra.conf new file mode 100644 index 0000000000..657c69bf28 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt2/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt2 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 10.0.255.2/32 + ipv6 address 2001:db8::2/128 +! +interface eth-rt1 + ip address 10.0.255.2/32 +! +interface eth-rt4 + ip address 10.0.255.2/32 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-rlfa-topo1/rt3/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt3/isisd.conf new file mode 100644 index 0000000000..17d58a9d15 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt3/isisd.conf @@ -0,0 +1,32 @@ +password 1 +hostname rt3 +log file isisd.log +! +debug isis events +debug isis route-events +debug isis spf-events +debug isis lsp-gen +! +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 +! +interface eth-rt5 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +router isis 1 + net 49.0000.0000.0000.0003.00 + is-type level-1-2 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf new file mode 100644 index 0000000000..40f1f5587a --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf @@ -0,0 +1,30 @@ +log file ldpd.log +! +hostname rt3 +! +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 10.0.255.3 + dual-stack transport-connection prefer ipv4 + ! + address-family ipv4 + label local allocate host-routes + discovery targeted-hello accept + discovery transport-address 10.0.255.3 + ! + interface eth-rt1 + interface eth-rt5 + ! + ! + address-family ipv6 + label local allocate host-routes + discovery transport-address 2001:db8::3 + ! + interface eth-rt1 + interface eth-rt5 + ! + ! +! diff --git a/tests/topotests/isis-rlfa-topo1/rt3/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt3/zebra.conf new file mode 100644 index 0000000000..86f5d2871a --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt3/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt3 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 10.0.255.3/32 + ipv6 address 2001:db8::3/128 +! +interface eth-rt1 + ip address 10.0.255.3/32 +! +interface eth-rt5 + ip address 10.0.255.3/32 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-rlfa-topo1/rt4/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt4/isisd.conf new file mode 100644 index 0000000000..1519fd4c16 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt4/isisd.conf @@ -0,0 +1,32 @@ +password 1 +hostname rt4 +log file isisd.log +! +debug isis events +debug isis route-events +debug isis spf-events +debug isis lsp-gen +! +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 network point-to-point +! +interface eth-rt6 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +router isis 1 + net 49.0000.0000.0000.0004.00 + is-type level-1-2 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf new file mode 100644 index 0000000000..569ecf733e --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf @@ -0,0 +1,30 @@ +log file ldpd.log +! +hostname rt4 +! +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 10.0.255.4 + dual-stack transport-connection prefer ipv4 + ! + address-family ipv4 + label local allocate host-routes + discovery targeted-hello accept + discovery transport-address 10.0.255.4 + ! + interface eth-rt2 + interface eth-rt6 + ! + ! + address-family ipv6 + label local allocate host-routes + discovery transport-address 2001:db8::4 + ! + interface eth-rt2 + interface eth-rt6 + ! + ! +! diff --git a/tests/topotests/isis-rlfa-topo1/rt4/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt4/zebra.conf new file mode 100644 index 0000000000..1dd09bf83b --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt4/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt4 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 10.0.255.4/32 + ipv6 address 2001:db8::4/128 +! +interface eth-rt2 + ip address 10.0.255.4/32 +! +interface eth-rt6 + ip address 10.0.255.4/32 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-rlfa-topo1/rt5/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt5/isisd.conf new file mode 100644 index 0000000000..caf7477073 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt5/isisd.conf @@ -0,0 +1,32 @@ +password 1 +hostname rt5 +log file isisd.log +! +debug isis events +debug isis route-events +debug isis spf-events +debug isis lsp-gen +! +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 + isis network point-to-point +! +interface eth-rt7 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +router isis 1 + net 49.0000.0000.0000.0005.00 + is-type level-1-2 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf new file mode 100644 index 0000000000..519c3d3628 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf @@ -0,0 +1,30 @@ +log file ldpd.log +! +hostname rt5 +! +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 10.0.255.5 + dual-stack transport-connection prefer ipv4 + ! + address-family ipv4 + label local allocate host-routes + discovery targeted-hello accept + discovery transport-address 10.0.255.5 + ! + interface eth-rt3 + interface eth-rt7 + ! + ! + address-family ipv6 + label local allocate host-routes + discovery transport-address 2001:db8::5 + ! + interface eth-rt3 + interface eth-rt7 + ! + ! +! diff --git a/tests/topotests/isis-rlfa-topo1/rt5/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt5/zebra.conf new file mode 100644 index 0000000000..7117a2a2e3 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt5/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt5 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 10.0.255.5/32 + ipv6 address 2001:db8::5/128 +! +interface eth-rt3 + ip address 10.0.255.5/32 +! +interface eth-rt7 + ip address 10.0.255.5/32 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-rlfa-topo1/rt6/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt6/isisd.conf new file mode 100644 index 0000000000..cdf6267236 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt6/isisd.conf @@ -0,0 +1,32 @@ +password 1 +hostname rt6 +log file isisd.log +! +debug isis events +debug isis route-events +debug isis spf-events +debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-rt4 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +interface eth-rt8 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +router isis 1 + net 49.0000.0000.0000.0006.00 + is-type level-1-2 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf new file mode 100644 index 0000000000..a5b7062bec --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf @@ -0,0 +1,30 @@ +log file ldpd.log +! +hostname rt6 +! +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 10.0.255.6 + dual-stack transport-connection prefer ipv4 + ! + address-family ipv4 + label local allocate host-routes + discovery targeted-hello accept + discovery transport-address 10.0.255.6 + ! + interface eth-rt4 + interface eth-rt8 + ! + ! + address-family ipv6 + label local allocate host-routes + discovery transport-address 2001:db8::6 + ! + interface eth-rt4 + interface eth-rt8 + ! + ! +! diff --git a/tests/topotests/isis-rlfa-topo1/rt6/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt6/zebra.conf new file mode 100644 index 0000000000..c6344870b7 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt6/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt6 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 10.0.255.6/32 + ipv6 address 2001:db8::6/128 +! +interface eth-rt4 + ip address 10.0.255.6/32 +! +interface eth-rt8 + ip address 10.0.255.6/32 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-rlfa-topo1/rt7/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt7/isisd.conf new file mode 100644 index 0000000000..8ab8fcb232 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt7/isisd.conf @@ -0,0 +1,32 @@ +password 1 +hostname rt7 +log file isisd.log +! +debug isis events +debug isis route-events +debug isis spf-events +debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-rt5 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +interface eth-rt8 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +router isis 1 + net 49.0000.0000.0000.0007.00 + is-type level-1-2 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf new file mode 100644 index 0000000000..26d428c4c6 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf @@ -0,0 +1,30 @@ +log file ldpd.log +! +hostname rt7 +! +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 10.0.255.7 + dual-stack transport-connection prefer ipv4 + ! + address-family ipv4 + label local allocate host-routes + discovery targeted-hello accept + discovery transport-address 10.0.255.7 + ! + interface eth-rt5 + interface eth-rt8 + ! + ! + address-family ipv6 + label local allocate host-routes + discovery transport-address 2001:db8::7 + ! + interface eth-rt5 + interface eth-rt8 + ! + ! +! diff --git a/tests/topotests/isis-rlfa-topo1/rt7/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt7/zebra.conf new file mode 100644 index 0000000000..4c5e0f1126 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt7/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt7 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 10.0.255.7/32 + ipv6 address 2001:db8::7/128 +! +interface eth-rt5 + ip address 10.0.255.7/32 +! +interface eth-rt8 + ip address 10.0.255.7/32 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-rlfa-topo1/rt8/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt8/isisd.conf new file mode 100644 index 0000000000..abdc6a53a5 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt8/isisd.conf @@ -0,0 +1,32 @@ +password 1 +hostname rt8 +log file isisd.log +! +debug isis events +debug isis route-events +debug isis spf-events +debug isis lsp-gen +! +interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive +! +interface eth-rt6 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +interface eth-rt7 + ip router isis 1 + ipv6 router isis 1 + isis hello-multiplier 3 + isis network point-to-point +! +router isis 1 + net 49.0000.0000.0000.0008.00 + is-type level-1-2 + lsp-gen-interval 2 + topology ipv6-unicast +! diff --git a/tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf new file mode 100644 index 0000000000..1629f82de1 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf @@ -0,0 +1,30 @@ +log file ldpd.log +! +hostname rt8 +! +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 10.0.255.8 + dual-stack transport-connection prefer ipv4 + ! + address-family ipv4 + label local allocate host-routes + discovery targeted-hello accept + discovery transport-address 10.0.255.8 + ! + interface eth-rt6 + interface eth-rt7 + ! + ! + address-family ipv6 + label local allocate host-routes + discovery transport-address 2001:db8::8 + ! + interface eth-rt6 + interface eth-rt7 + ! + ! +! diff --git a/tests/topotests/isis-rlfa-topo1/rt8/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt8/zebra.conf new file mode 100644 index 0000000000..f3f10f649a --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/rt8/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname rt8 +! +debug zebra kernel +debug zebra packet +debug zebra mpls +! +interface lo + ip address 10.0.255.8/32 + ipv6 address 2001:db8::8/128 +! +interface eth-rt6 + ip address 10.0.255.8/32 +! +interface eth-rt7 + ip address 10.0.255.8/32 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py new file mode 100755 index 0000000000..bb43e6b114 --- /dev/null +++ b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py @@ -0,0 +1,662 @@ +#!/usr/bin/env python + +# +# test_isis_rlfa_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_isis_rlfa_topo1.py: + + +---------+ +---------+ + | | | | + | RT1 | | RT2 | + | +---------------------+ | + | | | | + +---+-----+ +------+--+ + | | + | | + | | + +---+-----+ +------+--+ + | | | | + | RT3 | | RT4 | + | | | | + | | | | + +---+-----+ +------+--+ + | | + | | + | | + +---+-----+ +------+--+ + | | | | + | RT5 | | RT6 | + | | | | + | | | | + +---+-----+ +------+--+ + | | + | | + | | + +---+-----+ +------+--+ + | | | | + | RT7 | | RT8 | + | +---------------------+ | + | | | | + +---------+ +---------+ +""" + +import os +import sys +import pytest +import json +import re +import tempfile +from time import sleep +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 + +# Global multi-dimensional dictionary containing all expected outputs +outputs = {} + + +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", "rt6", "rt7", "rt8"]: + 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-rt4") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2") + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3") + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4") + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt7") + switch.add_link(tgen.gears["rt7"], nodeif="eth-rt5") + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt8") + switch.add_link(tgen.gears["rt8"], nodeif="eth-rt6") + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["rt7"], nodeif="eth-rt8") + switch.add_link(tgen.gears["rt8"], nodeif="eth-rt7") + + # + # Populate multi-dimensional dictionary containing all expected outputs + # + files = [ + "show_ip_route.ref", + "show_ipv6_route.ref", + "show_yang_interface_isis_adjacencies.ref", + ] + for rname in ["rt1"]: + outputs[rname] = {} + for step in range(1, 10 + 1): + outputs[rname][step] = {} + for file in files: + if step == 1: + # Get snapshots relative to the expected initial network convergence + filename = "{}/{}/step{}/{}".format(CWD, rname, step, file) + outputs[rname][step][file] = open(filename).read() + else: + if file == "show_yang_interface_isis_adjacencies.ref": + continue + + # Get diff relative to the previous step + filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file) + + # Create temporary files in order to apply the diff + f_in = tempfile.NamedTemporaryFile() + f_in.write(outputs[rname][step - 1][file]) + f_in.flush() + f_out = tempfile.NamedTemporaryFile() + os.system( + "patch -s -o %s %s %s" % (f_out.name, f_in.name, filename) + ) + + # Store the updated snapshot and remove the temporary files + outputs[rname][step][file] = open(f_out.name).read() + f_in.close() + f_out.close() + +@pytest.mark.isis +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_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.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 router_compare_json_output(rname, command, reference): + "Compare router JSON output" + + logger.info('Comparing router "%s" "%s" output', rname, command) + + tgen = get_topogen() + expected = json.loads(reference) + + # 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=120, wait=0.5) + assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +# +# Step 1 +# +# Test initial network convergence +# +def test_isis_adjacencies_step1(): + logger.info("Test (step 1): check IS-IS adjacencies") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, + "show yang operational-data /frr-interface:lib isisd", + outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"], + ) + + +def test_rib_ipv4_step1(): + logger.info("Test (step 1): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][1]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step1(): + logger.info("Test (step 1): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"] + ) + + +# +# Step 2 +# +# Action(s): +# -Configure rt8 (rt1's PQ router) to not accept targeted hello messages +# +# Expected changes: +# -All rt1 backup routes should be uninstalled +# +def test_rib_ipv4_step2(): + logger.info("Test (step 2): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Configuring rt8 to not accept targeted hello messages") + tgen.net["rt8"].cmd( + 'vtysh -c "conf t" -c "mpls ldp" -c "address-family ipv4" -c "no discovery targeted-hello accept"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][2]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step2(): + logger.info("Test (step 2): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"] + ) + + +# +# Step 3 +# +# Action(s): +# -Configure rt8 (rt1's PQ router) to accept targeted hello messages +# +# Expected changes: +# -All rt1 previously uninstalled backup routes should be reinstalled +# +def test_rib_ipv4_step3(): + logger.info("Test (step 3): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Configuring rt8 to accept targeted hello messages") + tgen.net["rt8"].cmd( + 'vtysh -c "conf t" -c "mpls ldp" -c "address-family ipv4" -c "discovery targeted-hello accept"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][3]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step3(): + logger.info("Test (step 3): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"] + ) + + +# +# Step 4 +# +# Action(s): +# -Disable RLFA on rt1's eth-rt2 interface +# +# Expected changes: +# -All non-ECMP routes whose primary nexthop is eth-rt2 should lose their backup nexthops +# +def test_rib_ipv4_step4(): + logger.info("Test (step 4): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Disabling RLFA on rt1's eth-rt2 interface") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute remote-lfa tunnel mpls-ldp"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][4]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step4(): + logger.info("Test (step 4): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"] + ) + + +# +# Step 5 +# +# Action(s): +# -Disable RLFA on rt1's eth-rt3 interface +# +# Expected changes: +# -All non-ECMP routes whose primary nexthop is eth-rt3 should lose their backup nexthops +# +def test_rib_ipv4_step5(): + logger.info("Test (step 5): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Disabling RLFA on rt1's eth-rt3 interface") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute remote-lfa tunnel mpls-ldp"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][5]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step5(): + logger.info("Test (step 5): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"] + ) + + +# +# Step 6 +# +# Action(s): +# -Re-enable RLFA on rt1's eth-rt2 and eth-rt3 interfaces +# +# Expected changes: +# -Revert changes from the previous two steps (reinstall all backup routes) +# +def test_rib_ipv4_step6(): + logger.info("Test (step 6): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Re-enabling RLFA on rt1's eth-rt2 and eth-rt3 interfaces") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa tunnel mpls-ldp"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute remote-lfa tunnel mpls-ldp"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][6]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step6(): + logger.info("Test (step 6): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"] + ) + + +# +# Step 7 +# +# Action(s): +# -Configure a PQ node prefix-list filter +# +# Expected changes: +# -All backup routes should be uninstalled +# +def test_rib_ipv4_step7(): + logger.info("Test (step 7): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Configuring a PQ node prefix-list filter") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute remote-lfa prefix-list PLIST"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][7]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step7(): + logger.info("Test (step 7): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"] + ) + + +# +# Step 8 +# +# Action(s): +# -Configure a prefix-list allowing rt8 as a PQ node +# +# Expected changes: +# -All backup routes should be installed again +# +def test_rib_ipv4_step8(): + logger.info("Test (step 8): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Configuring a prefix-list allowing rt8 as a PQ node") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "ip prefix-list PLIST seq 5 permit 10.0.255.8/32"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][8]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step8(): + logger.info("Test (step 8): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"] + ) + + +# +# Step 9 +# +# Action(s): +# -Change the maximum metric up to the PQ node to 30 on the eth-rt2 interface +# +# Expected changes: +# -All non-ECMP routes whose primary nexthop is eth-rt2 should lose their backup nexthops +# +def test_rib_ipv4_step9(): + logger.info("Test (step 9): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + "Changing the maximum metric up to the PQ node to 30 on the eth-rt2 interface" + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa maximum-metric 30"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][9]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step9(): + logger.info("Test (step 9): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"] + ) + + +# +# Step 10 +# +# Action(s): +# -Change the maximum metric up to the PQ node to 40 on the eth-rt2 interface +# +# Expected changes: +# -All non-ECMP routes whose primary nexthop is eth-rt2 should recover their backup nexthops +# +def test_rib_ipv4_step10(): + logger.info("Test (step 10): verify IPv4 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + "Changing the maximum metric up to the PQ node to 40 on the eth-rt2 interface" + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa maximum-metric 40"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][10]["show_ip_route.ref"] + ) + + +def test_rib_ipv6_step10(): + logger.info("Test (step 10): verify IPv6 RIB") + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["rt1"]: + router_compare_json_output( + rname, + "show ipv6 route isis json", + outputs[rname][10]["show_ipv6_route.ref"], + ) + + +# Memory leak test template +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)) diff --git a/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py index b1071310cf..bfd2f92a28 100755 --- a/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py +++ b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py @@ -148,6 +148,7 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears['rt6'], nodeif="eth-dst") switch.add_link(tgen.gears['dst'], nodeif="eth-rt6") +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" diff --git a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py index 34eb6d90f6..63be3f78aa 100644 --- a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py +++ b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py @@ -134,7 +134,7 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6") switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5") - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py index a1263de8ad..83751fabcd 100755 --- a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py @@ -177,7 +177,7 @@ class TemplateTopo(Topo): f_in.close() f_out.close() - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) 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 12121e4ddf..a79c8a268b 100644 --- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py @@ -82,7 +82,7 @@ class ISISTopo1(Topo): sw.add_link(tgen.gears["r4"]) sw.add_link(tgen.gears["r5"]) - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(ISISTopo1, mod.__name__) diff --git a/tests/topotests/isis-topo1/test_isis_topo1.py b/tests/topotests/isis-topo1/test_isis_topo1.py index 71005a0362..25116d9452 100644 --- a/tests/topotests/isis-topo1/test_isis_topo1.py +++ b/tests/topotests/isis-topo1/test_isis_topo1.py @@ -84,7 +84,7 @@ class ISISTopo1(Topo): sw.add_link(tgen.gears["r4"]) sw.add_link(tgen.gears["r5"]) - +@pytest.mark.isis def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(ISISTopo1, mod.__name__) diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 9822686dfc..dfe65f010e 100644 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -159,7 +159,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.ldp def setup_module(module): global topo, net global fatal_error diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py index ba94cd47d4..d659acb470 100644 --- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py @@ -121,7 +121,8 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) - +@pytest.mark.ldp +@pytest.mark.ospf def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 68a7217dd6..22602cb460 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -692,8 +692,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True): config_data.append("{} activate".format(neigh_cxt)) disable_connected = peer.setdefault("disable_connected_check", False) - keep_alive = peer.setdefault("keepalivetimer", 60) - hold_down = peer.setdefault("holddowntimer", 180) + keep_alive = peer.setdefault("keepalivetimer", 3) + hold_down = peer.setdefault("holddowntimer", 10) password = peer.setdefault("password", None) no_password = peer.setdefault("no_password", None) max_hop_limit = peer.setdefault("ebgp_multihop", 1) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 27efecb762..175d660d1e 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1659,7 +1659,7 @@ def create_interfaces_cfg(tgen, topo, build=False): interface_data.append("no ip ospf " " hello-interval") else: interface_data.append( - "ip ospf " " hello-interval {}".format(intf_ospf_hello) + "ip ospf" " hello-interval {}".format(intf_ospf_hello) ) if "dead_interval" in ospf_data: @@ -1670,7 +1670,7 @@ def create_interfaces_cfg(tgen, topo, build=False): interface_data.append("no ip ospf" " dead-interval") else: interface_data.append( - "ip ospf " " dead-interval {}".format(intf_ospf_dead) + "ip ospf" " dead-interval {}".format(intf_ospf_dead) ) if "network" in ospf_data: @@ -3065,7 +3065,11 @@ def verify_rib( errormsg = ( "[DUT: {}]: tag value {}" " is not matched for" - " route {} in RIB \n".format(dut, _tag, st_rt,) + " route {} in RIB \n".format( + dut, + _tag, + st_rt, + ) ) return errormsg @@ -3082,7 +3086,11 @@ def verify_rib( errormsg = ( "[DUT: {}]: metric value " "{} is not matched for " - "route {} in RIB \n".format(dut, metric, st_rt,) + "route {} in RIB \n".format( + dut, + metric, + st_rt, + ) ) return errormsg @@ -4333,3 +4341,58 @@ def kill_iperf(tgen, dut=None, action=None): rnode.run(cmd) logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + + +def verify_ip_nht(tgen, input_dict): + """ + Running "show ip nht" command and verifying given nexthop resolution + Parameters + ---------- + * `tgen` : topogen object + * `input_dict`: data to verify nexthop + Usage + ----- + input_dict_4 = { + "r1": { + nh: { + "Address": nh, + "resolvedVia": "connected", + "nexthops": { + "nexthop1": { + "Interface": intf + } + } + } + } + } + result = verify_ip_nht(tgen, input_dict_4) + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: verify_ip_nht()") + + for router in input_dict.keys(): + if router not in tgen.routers(): + continue + + rnode = tgen.routers()[router] + nh_list = input_dict[router] + + if validate_ip_address(nh_list.keys()[0]) is "ipv6": + show_ip_nht = run_frr_cmd(rnode, "show ipv6 nht") + else: + show_ip_nht = run_frr_cmd(rnode, "show ip nht") + + for nh in nh_list: + if nh in show_ip_nht: + logger.info("Nexthop %s is resolved on %s", nh, router) + return True + else: + errormsg = "Nexthop {} is resolved on {}".format(nh, router) + return errormsg + + logger.debug("Exiting lib API: verify_ip_nht()") + return False + diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 23b647d094..3e368cd7d3 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -62,7 +62,7 @@ def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=Tru "r1": { "ospf": { "router_id": "22.22.22.22", - "area": [{ "id":0.0.0.0, "type": "nssa"}] + "area": [{ "id": "0.0.0.0", "type": "nssa"}] } } @@ -327,7 +327,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= "links": { "r2": { "ospf": { - "authentication": 'message-digest', + "authentication": "message-digest", "authentication-key": "ospf", "message-digest-key": "10" } @@ -376,6 +376,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= if data_ospf_area: cmd = "ip ospf area {}".format(data_ospf_area) config_data.append(cmd) + # interface ospf auth if data_ospf_auth: if data_ospf_auth == "null": @@ -461,6 +462,32 @@ def clear_ospf(tgen, router): logger.debug("Exiting lib API: clear_ospf()") +def redistribute_ospf(tgen, topo, dut, route_type, **kwargs): + """ + Redstribution of routes inside ospf. + + Parameters + ---------- + * `tgen`: Topogen object + * `topo` : json file data + * `dut`: device under test + * `route_type`: "static" or "connected" or .... + * `kwargs`: pass extra information (see below) + + Usage + ----- + redistribute_ospf(tgen, topo, "r0", "static", delete=True) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") + """ + + ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": route_type}]}}} + for k, v in kwargs.items(): + ospf_red[dut]["ospf"]["redistribute"][0][k] = v + + result = create_router_ospf(tgen, topo, ospf_red) + assert result is True, "Testcase : Failed \n Error: {}".format(result) + + ################################ # Verification procs ################################ @@ -522,7 +549,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False): logger.info("Verifying OSPF neighborship on router %s:", router) show_ospf_json = run_frr_cmd( - rnode, "show ip ospf neighbor all json", isjson=True + rnode, "show ip ospf neighbor all json", isjson=True ) # Verifying output dictionary show_ospf_json is empty or not @@ -844,19 +871,23 @@ def verify_ospf_rib( if "routeType" not in ospf_rib_json[st_rt]: errormsg = ( "[DUT: {}]: routeType missing" - "for route {} in OSPF RIB \n".format(dut, st_rt) + " for route {} in OSPF RIB \n".format( + dut, st_rt + ) ) return errormsg elif _rtype != ospf_rib_json[st_rt]["routeType"]: errormsg = ( "[DUT: {}]: routeType mismatch" - "for route {} in OSPF RIB \n".format(dut, st_rt) + " for route {} in OSPF RIB \n".format( + dut, st_rt + ) ) return errormsg else: logger.info( - "DUT: {}]: Found routeType {}" - "for route {}".format(dut, _rtype, st_rt) + "[DUT: {}]: Found routeType {}" + " for route {}".format(dut, _rtype, st_rt) ) if tag: if "tag" not in ospf_rib_json[st_rt]: diff --git a/tests/topotests/ospf_basic_functionality/ospf_p2mp.json b/tests/topotests/ospf_basic_functionality/ospf_p2mp.json new file mode 100644 index 0000000000..40815f36f3 --- /dev/null +++ b/tests/topotests/ospf_basic_functionality/ospf_p2mp.json @@ -0,0 +1,198 @@ +{ + + "ipv4base": "10.0.0.0", + "ipv4mask": 24, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 24 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32 + }, + "routers": { + "r0": { + "links": { + "lo": { + "ipv4": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r2": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r3": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + } + }, + "ospf": { + "router_id": "100.1.1.0", + "neighbors": { + "r1": {}, + "r2": {}, + "r3": {} + } + } + }, + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "type": "loopback" + }, + "r0": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r2": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r3": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r3-link0": { + "ipv4": "auto", + "description": "DummyIntftoR3" + } + }, + "ospf": { + "router_id": "100.1.1.1", + "neighbors": { + "r0": {}, + "r2": {}, + "r3": {} + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "type": "loopback" + }, + "r0": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r1": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r3": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + } + }, + "ospf": { + "router_id": "100.1.1.2", + "neighbors": { + "r1": {}, + "r0": {}, + "r3": {} + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "type": "loopback" + }, + "r0": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r1": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r2": { + "ipv4": "auto", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4, + "network": "point-to-multipoint" + } + }, + "r1-link0": { + "ipv4": "auto", + "description": "DummyIntftoR1", + "ospf": { + "area": "0.0.0.0" + } + } + }, + "ospf": { + "router_id": "100.1.1.3", + "neighbors": { + "r0": {}, + "r1": {}, + "r2": {} + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index 5ef6b9b0be..441368e8fa 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -65,6 +65,7 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, verify_ospf_interface, + redistribute_ospf, ) topo = None @@ -184,38 +185,6 @@ def teardown_module(mod): logger.info("=" * 40) -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}} - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## @@ -264,7 +233,7 @@ def test_ospf_ecmp_tc16_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r0" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step("Verify that route in R2 in stalled with 8 next hops.") nh = [] @@ -345,7 +314,7 @@ def test_ospf_ecmp_tc16_p0(request): step(" Un configure static route on R0") dut = "r0" - red_static(dut, config=False) + redistribute_ospf(tgen, topo, dut, "static", delete=True) # Wait for R0 to flush external LSAs. sleep(10) @@ -376,7 +345,7 @@ def test_ospf_ecmp_tc16_p0(request): step("Re configure the static route in R0.") dut = "r0" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") dut = "r1" result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh) @@ -431,7 +400,7 @@ def test_ospf_ecmp_tc17_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r0" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step("Verify that route in R2 in stalled with 2 next hops.") @@ -450,7 +419,7 @@ def test_ospf_ecmp_tc17_p0(request): step(" Un configure static route on R0") dut = "r0" - red_static(dut, config=False) + redistribute_ospf(tgen, topo, dut, "static", delete=True) # sleep till the route gets withdrawn sleep(10) @@ -480,7 +449,7 @@ def test_ospf_ecmp_tc17_p0(request): step("Reconfigure the static route in R0.Change ECMP value to 2.") dut = "r0" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step("Configure cost on R0 as 100") r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 100}}}}} diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py index 967bc44879..2da1dcd21a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py @@ -66,6 +66,7 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, verify_ospf_interface, + redistribute_ospf, ) from ipaddress import IPv4Address @@ -187,42 +188,6 @@ def teardown_module(): pass -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "static", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## @@ -275,7 +240,7 @@ def test_ospf_lan_ecmp_tc18_p0(request): ) dut = rtr - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step( "Verify that route in R0 in stalled with 8 hops. " diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py index 0f1115f815..dac32090bc 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py @@ -183,42 +183,6 @@ def teardown_module(): pass -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "static", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py index 82a34d046c..3644bff3dc 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py @@ -30,6 +30,7 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, verify_ospf_interface, + redistribute_ospf, ) from lib.topojson import build_topo_from_json, build_config_from_json from lib.topolog import logger @@ -181,38 +182,6 @@ def teardown_module(mod): logger.info("=" * 40) -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}} - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## @@ -268,7 +237,7 @@ def test_ospf_learning_tc15_p0(request): step("Redistribute static route in R2 ospf.") dut = "r2" - red_static(dut) + redistribute_ospf(tgen, topo, dut, "static") step("Verify that Type 5 LSA is originated by R2.") dut = "r0" diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py new file mode 100644 index 0000000000..c90275ecb0 --- /dev/null +++ b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py @@ -0,0 +1,416 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. +# ("NetDEF") in this file. +# +# 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 VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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. +# + + +"""OSPF Basic Functionality Automation.""" +import os +import sys +import time +import pytest +import json +from copy import deepcopy +from ipaddress import IPv4Address + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen +import ipaddress + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + step, + create_route_maps, + shutdown_bringup_interface, + create_interfaces_cfg, + topo_daemons, +) +from lib.topolog import logger +from lib.topojson import build_topo_from_json, build_config_from_json + +from lib.ospf import ( + verify_ospf_neighbor, + config_ospf_interface, + clear_ospf, + verify_ospf_rib, + create_router_ospf, + verify_ospf_interface, + verify_ospf_database, +) + +# Global variables +topo = None + +# Reading the data from JSON File for topology creation +jsonFile = "{}/ospf_p2mp.json".format(CWD) +try: + with open(jsonFile, "r") as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + +""" +TOPOOLOGY = + Please view in a fixed-width font such as Courier. + +---+ A1 +---+ + +R1 +------------+R2 | + +-+-+- +--++ + | -- -- | + | -- A0 -- | + A0| ---- | + | ---- | A2 + | -- -- | + | -- -- | + +-+-+- +-+-+ + +R0 +-------------+R3 | + +---+ A3 +---+ + +TESTCASES = +1. OSPF P2MP -Verify state change events on p2mp network. + """ + + +class CreateTopo(Topo): + """ + Test topology builder. + + * `Topo`: Topology object + """ + + def build(self, *_args, **_opts): + """Build function.""" + tgen = get_topogen(self) + + # Building topology from json file + build_topo_from_json(tgen, topo) + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + global topo + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + tgen = Topogen(CreateTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + + # get list of daemons needs to be started for this suite. + daemons = topo_daemons(tgen, topo) + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen, daemons) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment. + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +# ################################## +# Test cases start here. +# ################################## + + +def test_ospf_p2mp_tc1_p0(request): + """OSPF IFSM -Verify state change events on p2mp network.""" + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + global topo + step("Bring up the base config as per the topology") + reset_config_on_routers(tgen) + step( + "Verify that OSPF is subscribed to multi cast services " + "(All SPF, all DR Routers)." + ) + step("Verify that interface is enabled in ospf.") + step("Verify that config is successful.") + dut = "r0" + input_dict = { + "r0": { + "links": { + "r3": {"ospf": {"mcastMemberOspfAllRouters": True, "ospfEnabled": True}} + } + } + } + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Delete the ip address") + topo1 = { + "r0": { + "links": { + "r3": { + "ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"], + "interface": topo["routers"]["r0"]["links"]["r3"]["interface"], + "delete": True, + } + } + } + } + + result = create_interfaces_cfg(tgen, topo1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Change the ip on the R0 interface") + + topo_modify_change_ip = deepcopy(topo) + intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] + topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str( + IPv4Address(unicode(intf_ip.split("/")[0])) + 3 + ) + "/{}".format(intf_ip.split("/")[1]) + + build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False) + step("Verify that interface is enabled in ospf.") + dut = "r0" + input_dict = { + "r0": { + "links": { + "r3": { + "ospf": { + "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][ + "r3" + ]["ipv4"].split("/")[0], + "ipAddressPrefixlen": int( + topo_modify_change_ip["routers"]["r0"]["links"]["r3"][ + "ipv4" + ].split("/")[1] + ), + } + } + } + } + } + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Modify the mask on the R0 interface") + ip_addr = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] + mask = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] + step("Delete the ip address") + topo1 = { + "r0": { + "links": { + "r3": { + "ipv4": ip_addr, + "interface": topo["routers"]["r0"]["links"]["r3"]["interface"], + "delete": True, + } + } + } + } + + result = create_interfaces_cfg(tgen, topo1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Change the ip on the R0 interface") + + topo_modify_change_ip = deepcopy(topo) + intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] + topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str( + IPv4Address(unicode(intf_ip.split("/")[0])) + 3 + ) + "/{}".format(int(intf_ip.split("/")[1]) + 1) + + build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False) + step("Verify that interface is enabled in ospf.") + dut = "r0" + input_dict = { + "r0": { + "links": { + "r3": { + "ospf": { + "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][ + "r3" + ]["ipv4"].split("/")[0], + "ipAddressPrefixlen": int( + topo_modify_change_ip["routers"]["r0"]["links"]["r3"][ + "ipv4" + ].split("/")[1] + ), + } + } + } + } + } + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + topo1 = { + "r0": { + "links": { + "r3": { + "ipv4": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][ + "ipv4" + ], + "interface": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][ + "interface" + ], + "delete": True, + } + } + } + } + + result = create_interfaces_cfg(tgen, topo1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + build_config_from_json(tgen, topo, save_bkup=False) + + step("Change the area id on the interface") + input_dict = { + "r0": { + "links": { + "r3": { + "interface": topo["routers"]["r0"]["links"]["r3"]["interface"], + "ospf": {"area": "0.0.0.0"}, + "delete": True, + } + } + } + } + + result = create_interfaces_cfg(tgen, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r0": { + "links": { + "r3": { + "interface": topo["routers"]["r0"]["links"]["r3"]["interface"], + "ospf": {"area": "0.0.0.1"}, + } + } + } + } + + result = create_interfaces_cfg(tgen, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + step("Verify that interface is enabled in ospf.") + dut = "r0" + input_dict = { + "r0": {"links": {"r3": {"ospf": {"area": "0.0.0.1", "ospfEnabled": True}}}} + } + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r0": { + "links": { + "r3": { + "interface": topo["routers"]["r0"]["links"]["r3"]["interface"], + "ospf": {"area": "0.0.0.1"}, + "delete": True, + } + } + } + } + + result = create_interfaces_cfg(tgen, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r0": { + "links": { + "r3": { + "interface": topo["routers"]["r0"]["links"]["r3"]["interface"], + "ospf": {"area": "0.0.0.0"}, + } + } + } + } + + result = create_interfaces_cfg(tgen, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify if interface is enabled with network type P2MP") + input_dict = { + "r0": { + "links": { + "r3": { + "interface": topo["routers"]["r0"]["links"]["r3"]["interface"], + "ospf": { + "area": "0.0.0.0", + "networkType":"POINTOMULTIPOINT" + }, + } + } + } + } + result = create_interfaces_cfg(tgen, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index 88667a6ac8..ceadb3975b 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -62,6 +62,7 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, verify_ospf_database, + redistribute_ospf, ) # Global variables @@ -226,9 +227,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request): result = create_static_routes(tgen, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r1 = {"r0": {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - result = create_router_ospf(tgen, topo, ospf_red_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static") dut = "r1" lsid = NETWORK["ipv4"][0].split("/")[0] @@ -240,13 +239,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request): result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r1 = { - "r0": { - "ospf": {"redistribute": [{"redist_type": "static", "del_action": True}]} - } - } - result = create_router_ospf(tgen, topo, ospf_red_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", delete=True) step( "Create prefix-list in R0 to permit 10.0.20.1/32 prefix &" " deny 10.0.20.2/32" @@ -293,15 +286,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request): " ospf using route map rmap1" ) - ospf_red_r1 = { - "r0": { - "ospf": { - "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") step("Change prefix rules to permit 10.0.20.2 and deny 10.0.20.1") # Create ip prefix list @@ -495,15 +480,7 @@ def test_ospf_routemaps_functionality_tc20_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Redistribute to ospf using route map ( non existent route map)") - ospf_red_r1 = { - "r0": { - "ospf": { - "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") step( "Verify that routes are not allowed in OSPF even tough no " @@ -633,15 +610,7 @@ def test_ospf_routemaps_functionality_tc21_p0(request): result = create_static_routes(tgen, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r0 = { - "r0": { - "ospf": { - "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red_r0) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") # Create route map routemaps = { @@ -877,15 +846,7 @@ def test_ospf_routemaps_functionality_tc24_p0(request): result = create_static_routes(tgen, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r0 = { - "r0": { - "ospf": { - "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red_r0) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4") # Create ip prefix list pfx_list = { diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index 434d7f8ef5..5aa2779aee 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -61,6 +61,7 @@ from lib.ospf import ( clear_ospf, verify_ospf_rib, create_router_ospf, + redistribute_ospf, ) # Global variables @@ -183,42 +184,6 @@ def teardown_module(mod): logger.info("=" * 40) -def red_static(dut, config=True): - """Local def for Redstribute static routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "static", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase : Failed \n Error: {}".format(result) - - -def red_connected(dut, config=True): - """Local def for Redstribute connected routes inside ospf.""" - global topo - tgen = get_topogen() - if config: - ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}} - else: - ospf_red = { - dut: { - "ospf": { - "redistribute": [{"redist_type": "connected", "del_action": True}] - } - } - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase: Failed \n Error: {}".format(result) - - # ################################## # Test cases start here. # ################################## @@ -486,8 +451,8 @@ def test_ospf_redistribution_tc8_p1(request): "advertised/exchaged via ospf" ) for rtr in topo["routers"]: - red_static(rtr) - red_connected(rtr) + redistribute_ospf(tgen, topo, rtr, "static") + redistribute_ospf(tgen, topo, rtr, "connected") for node in topo["routers"]: input_dict = { "r0": { @@ -544,13 +509,7 @@ def test_ospf_redistribution_tc8_p1(request): ) for rtr in topo["routers"]: - ospf_red = { - rtr: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}} - } - result = create_router_ospf(tgen, topo, ospf_red) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result - ) + redistribute_ospf(tgen, topo, rtr, "static", delete=True) input_dict = { "r0": { diff --git a/tests/topotests/pbr-topo1/test_pbr_topo1.py b/tests/topotests/pbr-topo1/test_pbr_topo1.py index fcbe3c0adf..5161d5eec7 100644 --- a/tests/topotests/pbr-topo1/test_pbr_topo1.py +++ b/tests/topotests/pbr-topo1/test_pbr_topo1.py @@ -80,7 +80,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.pbr def setup_module(module): "Setup topology" tgen = Topogen(NetworkTopo, module.__name__) diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py index e8a9f72b48..74a7fbf16e 100644 --- a/tests/topotests/pim-basic/test_pim.py +++ b/tests/topotests/pim-basic/test_pim.py @@ -80,7 +80,7 @@ class PIMTopo(Topo): sw.add_link(tgen.gears["r1"]) sw.add_link(tgen.gears["r3"]) - +@pytest.mark.pim def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(PIMTopo, mod.__name__) diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index 6e8e749092..d1b18a57bb 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -1,6 +1,16 @@ # Skip pytests example directory [pytest] norecursedirs = .git example-test example-topojson-test lib docker +markers = + babel: Tests that run against BABEL + bfd: Tests that run against BFDD + eigrp: Tests that run against EIGRPD + isis: Tests that run against ISISD + ldp: Tests that run against LDPD + ospf: Tests that run against OSPF( v2 and v3 ) + pbr: Tests that run against PBRD + pim: Tests that run against pim + rip: Tests that run against RIP, both v4 and v6 [topogen] # Default configuration values diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py index fdafa50aba..edad1ff65d 100644 --- a/tests/topotests/rip-topo1/test_rip_topo1.py +++ b/tests/topotests/rip-topo1/test_rip_topo1.py @@ -104,7 +104,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.rip def setup_module(module): global topo, net diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py index 4702d33dae..47b63e5b26 100644 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -104,7 +104,7 @@ class NetworkTopo(Topo): ## ##################################################### - +@pytest.mark.rip def setup_module(module): global topo, net diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json new file mode 100644 index 0000000000..5246a311ea --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json @@ -0,0 +1,189 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 29, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link7": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py new file mode 100644 index 0000000000..255bb073b4 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py @@ -0,0 +1,1333 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# 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 VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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. +# +""" + -Verify static route ECMP functionality with 8 next hop + + -Verify static route functionality with 8 next hop different AD value + + -Verify static route with tag option + + -Verify BGP did not install the static route when it receive route + with local next hop + +""" +import sys +import json +import time +import os +import pytest +import random +import platform +from lib.topotest import version_cmp + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, + create_route_maps, + verify_ip_nht, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology creation +jsonFile = "{}/static_routes_topo3_ebgp.json".format(CWD) +try: + with open(jsonFile, "r") as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + +# Global variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = { + "ipv4": [ + "11.0.20.1/32", + "11.0.20.2/32", + "11.0.20.3/32", + "11.0.20.4/32", + "11.0.20.5/32", + "11.0.20.6/32", + "11.0.20.7/32", + "11.0.20.8/32", + ], + "ipv6": [ + "2::1/128", + "2::2/128", + "2::3/128", + "2::4/128", + "2::5/128", + "2::6/128", + "2::7/128", + "2::8/128", + ], +} +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} +NETWORK2 = {"ipv4": ["11.0.20.1/32"], "ipv6": ["2::1/128"]} +NEXT_HOP_IP = [] + + +class CreateTopo(Topo): + """ + Test CreateTopo - topology 1. + + * `Topo`: Topology object + """ + + def build(self, *_args, **_opts): + """Build function.""" + tgen = get_topogen(self) + + # Building topology from json file + build_topo_from_json(tgen, topo) + + +def setup_module(mod): + """ + + Set up the pytest environment. + + * `mod`: module name + """ + global topo + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + tgen = Topogen(CreateTopo, mod.__name__) + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) + pytest.skip(error_msg) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # Api call verify whether BGP is converged + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def populate_nh(): + NEXT_HOP_IP = { + "nh1": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0], + }, + "nh2": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + }, + "nh3": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0], + }, + "nh4": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0], + }, + "nh5": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0], + }, + "nh6": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0], + }, + "nh7": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0], + }, + "nh8": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Tests starting +# +##################################################### + + +def test_staticroute_with_ecmp_p0_tc3_ebgp(request): + """ + Verify static route ECMP functionality with 8 next hop' + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2,") + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2), N2(22.1.1.2), N3(23.1.1.2), N4(24.1.1.2)," + "N5(25.1.1.2), N6(26.1.1.2), N7(27.1.1.2),N8(28.1.1.2), Static" + "route next-hop present on R1" + ) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + + for addr_type in ADDR_TYPES: + # Enable static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + nh = [ + NEXT_HOP_IP["nh1"][addr_type], + NEXT_HOP_IP["nh2"][addr_type], + NEXT_HOP_IP["nh3"][addr_type], + NEXT_HOP_IP["nh4"][addr_type], + NEXT_HOP_IP["nh5"][addr_type], + NEXT_HOP_IP["nh6"][addr_type], + NEXT_HOP_IP["nh7"][addr_type], + NEXT_HOP_IP["nh8"][addr_type], + ] + + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "delete": True, + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by" "one") + + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + start_router(tgen, "r2") + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_staticroute_with_ecmp_with_diff_AD_p0_tc4_ebgp(request): + """ + Verify static route ECMP functionality with 8 next hop + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2,") + step("Configure IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop" + "present on R1" + ) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop, lowest AD nexthop is active" + ) + step("On R2, static route with lowest AD nexthop installed in FIB") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + + logger.info("Configuring redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After configuring them, route is always active with lowest AD" + "value and all the nexthop populated in RIB and FIB again " + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing the static route with N1 to N8 one by one, " + "route become active with next preferred nexthop and nexthop which " + "got removed is not shown in RIB and FIB" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by" "one") + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("On R2, static route with lowest AD nexthop installed in FIB") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + start_router(tgen, "r2") + + step( + "After reload of FRR router, static route installed " + "in RIB and FIB properly ." + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_bgp_local_nexthop_p1_tc14_ebgp(request): + """ + Verify BGP did not install the static route when it receive route + with local next hop + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + step("Configure BGP IPv4 session between R2 and R3") + step("Configure IPv4 static route on R2") + reset_config_on_routers(tgen) + + for addr_type in ADDR_TYPES: + # Enable static routes + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Configure redistribute static in the BGP") + + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify R2 BGP table has IPv4 route") + dut = "r2" + result = verify_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB of R2".format(tc_name) + + step(" Verify route did not install in the R3 BGP table, RIB/FIB") + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4, expected=False) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in BGP RIB of R2".format(tc_name) + + result = verify_rib(tgen, addr_type, dut, input_dict_4, expected=False) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB of R2".format(tc_name) + + write_test_footer(tc_name) + + +def test_frr_intf_name_as_gw_gap_tc4_ebgp_p0(request): + """ + Verify static route configure with interface name as gateway' + 'address' + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + dut = "r1" + intf = topo["routers"]["r1"]["links"]["r2-link0"]["interface"] + nh = topo["routers"]["r1"]["links"]["r2-link0"] + ip_list = { + "ipv4": [(dut, intf, ["1.1.1.1/32"], nh["ipv4"].split("/")[0])], + "ipv6": [(dut, intf, ["4001::32/128"], nh["ipv6"].split("/")[0])], + } + + step( + "Configure IPv4 and IPv6 static route in FRR with different next" + "hop (ens224 as nexthop))" + ) + step("ip route 2.2.2.0/24 20.1.1.1 ens224 ----from FRR cli") + step("ipv6 route 2000::1/120 5000::1 ens224 ----from FRR cli") + + for addr_type in ADDR_TYPES: + # Enable static routes + nh = topo["routers"]["r2"]["links"]["r1-link0"][addr_type].split("/")[0] + input_dict_4 = { + "r1": { + "static_routes": [ + {"network": ip_list[addr_type][0][2][0], "next_hop": nh} + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "IPv4 and IPv6 Static route added in FRR verify using " + "show ip route , nexthop is resolved using show nht" + ) + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, next_hop=nh + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + input_dict_nh = { + "r1": { + nh: { + "Address": nh, + "resolvedVia": "connected", + "nexthops": {"nexthop1": {"Interfcae": intf}}, + } + } + } + result = verify_ip_nht(tgen, input_dict_nh) + assert result is True, "Testcase {} : Failed \nError: Nexthop is" + " missing in RIB".format(tc_name) + + step( + "Shut / no shut IPv4 and IPv6 static next hop interface from" + "kernel and FRR CLI" + ) + + shutdown_bringup_interface(tgen, dut, intf, False) + + step( + "After shut of nexthop interface, IPv4 and IPv6 route got removed " + "from RIB verify using show ip route show nht" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + protocol=protocol, + next_hop=nh, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "After no shut route got added again in RIB /FIB using " + "show ip route nexthop is resolved using show nht" + ) + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed".format(tc_name) + + for addr_type in ADDR_TYPES: + nh = topo["routers"]["r2"]["links"]["r1-link0"][addr_type].split("/")[0] + input_dict_4 = { + "r1": { + "static_routes": [ + { + "network": ip_list[addr_type][0][2][0], + "next_hop": nh, + "delete": True, + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Removing FRR configured static route verify FRR route also " + "removed from FRR" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + protocol=protocol, + next_hop=nh, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_with_tag_p0_tc_13_ebgp(request): + """ + Verify static route with tag option + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Configure 8 links between R1 and R2") + step("Configure 1 links between R2 and R3") + NEXT_HOP_IP = populate_nh() + + step( + "Configure 2 IPv4 static route (S1 and S2) in R2 with same" + "next hop N1 28.1.1.2" + ) + step("Configure static route S1 with tag 1 and static route S2 with" "tag2") + step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1") + step("S2= ip route 20.1.1.1/24 28.1.1.2 tag 2") + step("Enable redistribute static in BGP with route-map") + reset_config_on_routers(tgen) + + for addr_type in ADDR_TYPES: + # Enable static routes + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "tag": 4001, + }, + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "tag": 4002, + }, + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify routes are present in RIB") + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Configure route-map on R2 with allow tag1 and deny tag2") + + # Create route map + input_dict_3 = { + "r2": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [ + { + "action": "permit", + "seq_id": 10, + "match": {addr_type: {"tag": "4001"}}, + }, + { + "action": "deny", + "seq_id": 20, + "match": {addr_type: {"tag": "4002"}}, + }, + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + # Configure neighbor for route map + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_match_tag_1_ipv4", + "direction": "out", + } + ] + } + } + } + }, + "redistribute": [{"redist_type": "static"}], + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Verify static route S1 advetised in BGP table when tag1 permit" + "in route-map else it is denied" + ) + dut = "r3" + input_dict_0 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "tag": 4002, + } + ] + } + } + + result = verify_rib( + tgen, addr_type, dut, input_dict_0, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route with " + "tag 4002 is still present in RIB".format(tc_name) + + dut = "r2" + input_dict_1 = { + "r2": {"static_routes": [{"network": NETWORK[addr_type], "tag": 4001}]} + } + + result = verify_rib(tgen, addr_type, dut, input_dict_0, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route with " + "tag 4001 is missing in RIB".format(tc_name) + + step("Modify the route-map to allow tag2 and deny tag1") + # Create route map + input_dict_3 = { + "r2": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [ + { + "action": "deny", + "seq_id": 10, + "match": {addr_type: {"tag": "4001"}}, + }, + { + "action": "permit", + "seq_id": 20, + "match": {addr_type: {"tag": "4002"}}, + }, + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + dut = "r3" + step( + "Verify static route S2 advertised in BGP table when tag2" + "permit in route-map else it is denied" + ) + protocol = "bgp" + input_dict_0 = { + "r2": {"static_routes": [{"network": NETWORK2[addr_type], "tag": 4002}]} + } + + result = verify_rib(tgen, addr_type, dut, input_dict_0, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route with " + "tag 4002 is missing in RIB".format(tc_name) + + input_dict_1 = { + "r2": {"static_routes": [{"network": NETWORK[addr_type], "tag": 4001}]} + } + result = verify_rib( + tgen, addr_type, dut, input_dict_1, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route with " + "tag 4001 is still present in RIB".format(tc_name, result) + + step("Configure one static route with 2 ECMP nexthop N1 and N2") + step("For N1 configure tag 1 and for N2 configure tag 2") + step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1") + step("S1= ip route 10.1.1.1/24 29.1.1.2 tag 2") + step("configure the route-map to allow tag1 and deny tag 2") + step("Modify the route-map to allow tag2 and deny tag1") + + for addr_type in ADDR_TYPES: + # Enable static routes + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "tag": 4001, + }, + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "tag": 4002, + }, + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("shut/no shut of tag1 and tag2 nexthop") + + intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + shutdown_bringup_interface(tgen, dut, intf, True) + + step("configure one static route with 3 next-hop") + step("N1-tag1, N2-tag2, N3-tag3") + step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1") + step("S1= ip route 10.1.1.1/24 29.1.1.2 tag 2") + step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 3") + + for addr_type in ADDR_TYPES: + # Enable static routes + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "tag": 4001, + }, + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "tag": 4002, + }, + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh3"][addr_type], + "tag": 4003, + }, + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + dut = "r2" + protocol = "static" + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + + step("configure the route-map to allow tag2 & tag3 and deny tag1") + # Create route map + input_dict_3 = { + "r2": { + "route_maps": { + "rmap_match_tag_1_{}".format(addr_type): [ + { + "action": "deny", + "seq_id": 10, + "match": {addr_type: {"tag": "4001"}}, + }, + { + "action": "permit", + "seq_id": 20, + "match": {addr_type: {"tag": "4002"}}, + }, + { + "action": "permit", + "seq_id": 30, + "match": {addr_type: {"tag": "4003"}}, + }, + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Verify static route advertised in BGP table with tag3" + " nexthop if tag2 is down" + ) + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("shut / no shut of tag2 and tag3 next-hop") + + intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + intf = topo["routers"]["r2"]["links"]["r1-link2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + step("shut/no shut of tag2 and tag3 nexthop") + intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + intf = topo["routers"]["r2"]["links"]["r1-link2"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + step("Verify after shut/noshut of nexthop BGP table updated correctly") + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/zebra_rib/r1/iproute.ref b/tests/topotests/zebra_rib/r1/iproute.ref new file mode 100644 index 0000000000..b28182c2d1 --- /dev/null +++ b/tests/topotests/zebra_rib/r1/iproute.ref @@ -0,0 +1,512 @@ +4.5.1.0/24 via 192.168.210.2 dev r1-eth0 metric 4278198272 +4.5.2.0/24 via 192.168.211.2 dev r1-eth1 metric 16777217 +4.5.3.0/24 via 192.168.212.2 dev r1-eth2 metric 167772161 +4.5.3.0/24 via 192.168.213.2 dev r1-eth3 metric 2684354561 +10.0.0.0 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.1 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.2 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.3 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.4 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.5 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.6 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.7 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.8 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.9 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.10 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.11 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.12 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.13 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.14 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.15 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.16 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.17 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.18 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.19 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.20 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.21 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.22 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.23 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.24 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.25 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.26 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.27 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.28 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.29 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.30 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.31 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.32 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.33 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.34 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.35 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.36 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.37 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.38 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.39 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.40 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.41 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.42 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.43 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.45 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.46 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.47 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.48 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.49 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.50 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.51 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.52 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.53 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.54 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.55 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.56 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.57 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.58 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.59 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.60 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.61 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.62 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.63 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.64 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.65 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.66 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.67 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.68 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.69 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.70 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.71 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.72 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.73 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.74 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.75 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.76 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.77 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.78 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.79 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.80 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.81 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.82 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.83 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.84 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.85 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.86 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.87 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.88 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.89 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.90 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.91 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.92 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.93 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.94 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.95 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.96 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.97 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.98 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.99 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.100 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.101 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.102 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.103 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.104 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.105 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.106 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.107 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.108 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.109 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.110 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.111 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.112 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.113 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.114 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.115 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.116 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.117 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.118 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.119 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.120 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.121 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.122 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.123 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.124 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.125 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.126 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.127 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.128 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.129 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.130 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.131 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.132 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.133 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.134 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.135 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.136 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.137 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.138 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.139 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.140 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.141 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.142 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.143 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.144 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.145 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.146 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.147 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.148 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.149 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.150 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.151 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.152 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.153 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.154 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.155 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.156 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.157 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.158 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.159 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.160 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.161 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.162 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.163 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.164 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.165 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.166 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.167 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.168 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.169 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.170 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.171 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.172 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.173 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.174 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.175 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.176 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.177 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.178 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.179 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.180 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.181 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.182 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.183 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.184 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.185 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.186 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.187 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.188 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.189 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.190 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.191 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.192 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.193 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.194 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.195 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.196 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.197 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.198 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.199 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.200 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.201 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.202 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.203 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.204 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.205 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.206 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.207 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.208 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.209 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.210 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.211 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.212 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.213 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.214 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.215 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.216 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.217 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.218 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.219 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.220 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.221 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.222 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.223 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.224 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.225 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.226 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.227 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.228 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.229 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.230 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.231 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.232 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.233 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.234 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.235 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.236 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.237 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.238 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.239 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.240 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.241 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.242 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.243 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.244 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.245 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.246 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.247 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.248 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.249 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.250 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.251 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.252 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.253 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.254 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.0.255 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.213.1 metric 20 +10.0.1.0 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.1 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.2 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.3 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.4 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.5 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.6 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.7 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.8 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.9 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.10 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.11 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.12 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.13 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.14 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.15 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.16 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.17 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.18 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.19 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.20 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.21 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.22 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.23 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.24 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.25 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.26 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.27 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.28 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.29 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.30 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.31 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.32 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.33 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.34 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.35 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.36 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.37 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.38 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.39 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.40 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.41 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.42 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.43 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.44 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.45 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.46 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.47 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.48 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.49 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.50 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.51 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.52 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.53 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.54 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.55 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.56 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.57 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.58 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.59 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.60 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.61 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.62 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.63 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.64 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.65 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.66 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.67 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.68 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.69 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.70 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.71 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.72 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.73 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.74 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.75 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.76 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.77 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.78 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.79 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.80 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.81 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.82 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.83 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.84 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.85 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.86 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.87 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.88 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.89 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.90 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.91 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.92 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.93 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.94 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.95 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.96 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.97 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.98 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.99 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.100 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.101 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.102 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.103 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.104 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.105 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.106 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.107 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.108 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.109 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.110 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.111 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.112 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.113 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.114 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.115 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.116 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.117 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.118 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.119 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.120 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.121 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.122 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.123 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.124 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.125 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.126 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.127 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.128 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.129 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.130 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.131 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.132 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.133 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.134 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.135 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.136 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.137 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.138 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.139 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.140 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.141 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.142 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.143 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.144 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.145 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.146 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.147 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.148 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.149 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.150 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.151 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.152 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.153 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.154 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.155 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.156 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.157 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.158 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.159 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.160 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.161 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.162 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.163 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.164 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.165 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.166 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.167 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.168 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.169 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.170 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.171 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.172 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.173 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.174 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.175 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.176 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.177 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.178 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.179 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.180 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.181 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.182 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.183 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.184 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.185 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.186 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.187 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.188 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.189 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.190 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.191 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.192 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.193 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.194 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.195 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.196 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.197 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.198 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.199 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.200 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.201 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.202 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.203 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.204 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.205 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.206 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.207 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.208 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.209 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.210 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.211 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.212 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.213 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.214 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.215 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.216 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.217 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.218 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.219 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.220 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.221 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.222 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.223 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.224 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.225 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.226 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.227 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.228 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.229 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.230 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.231 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.232 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.233 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.234 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.235 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.236 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.237 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.238 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.239 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.240 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.241 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.242 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.0.1.243 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.214.1 metric 20 +10.100.100.100 via 192.168.216.3 dev r1-eth6 proto XXXX src 192.168.215.1 metric 20 +192.168.210.0/24 dev r1-eth0 proto XXXX scope link src 192.168.210.1 +192.168.211.0/24 dev r1-eth1 proto XXXX scope link src 192.168.211.1 +192.168.212.0/24 dev r1-eth2 proto XXXX scope link src 192.168.212.1 +192.168.213.0/24 dev r1-eth3 proto XXXX scope link src 192.168.213.1 +192.168.214.0/24 dev r1-eth4 proto XXXX scope link src 192.168.214.1 +192.168.215.0/24 dev r1-eth5 proto XXXX scope link src 192.168.215.1 +192.168.216.0/24 dev r1-eth6 proto XXXX scope link src 192.168.216.1 +192.168.217.0/24 dev r1-eth7 proto XXXX scope link src 192.168.217.1 diff --git a/tests/topotests/zebra_rib/r1/sharp_rmap.ref b/tests/topotests/zebra_rib/r1/sharp_rmap.ref new file mode 100644 index 0000000000..47a9eb6a49 --- /dev/null +++ b/tests/topotests/zebra_rib/r1/sharp_rmap.ref @@ -0,0 +1,17 @@ +ZEBRA: +route-map: sharp Invoked: 500 Optimization: enabled Processed Change: false + permit, sequence 10 Invoked 244 + Match clauses: + ip address 10 + Set clauses: + src 192.168.214.1 + Call clause: + Action: + Exit routemap + permit, sequence 20 Invoked 256 + Match clauses: + Set clauses: + src 192.168.213.1 + Call clause: + Action: + Exit routemap diff --git a/tests/topotests/zebra_rib/r1/static_rmap.ref b/tests/topotests/zebra_rib/r1/static_rmap.ref new file mode 100644 index 0000000000..2de98bd514 --- /dev/null +++ b/tests/topotests/zebra_rib/r1/static_rmap.ref @@ -0,0 +1,9 @@ +ZEBRA: +route-map: static Invoked: 2 Optimization: enabled Processed Change: false + permit, sequence 10 Invoked 2 + Match clauses: + Set clauses: + src 192.168.215.1 + Call clause: + Action: + Exit routemap diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index ef4b597206..daf8f7be20 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -41,6 +41,7 @@ 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 time import sleep # Required to instantiate the topology builder class. from mininet.topo import Topo @@ -75,8 +76,9 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))) + router.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))) # Initialize all routers. tgen.start_router() @@ -157,6 +159,111 @@ def test_zebra_kernel_override(): _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5) assert result is None, '"r1" JSON output mismatches' +def test_route_map_usage(): + "Test that FRR only reruns over routes associated with the routemap" + logger.info("Test that FRR runs on selected re's on route-map changes") + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip("Skipped because of previous test failure") + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + r1 = tgen.gears["r1"] + # set the delay timer to 1 to improve test coverage (HA) + r1.vtysh_cmd("conf\nzebra route-map delay-timer 1") + r1.vtysh_cmd("conf\nroute-map static permit 10\nset src 192.168.215.1") + r1.vtysh_cmd("conf\naccess-list 5 seq 5 permit 10.0.0.44/32") + r1.vtysh_cmd("conf\naccess-list 10 seq 5 permit 10.0.1.0/24") + r1.vtysh_cmd("conf\nroute-map sharp permit 10\nmatch ip address 10\nset src 192.168.214.1") + r1.vtysh_cmd("conf\nroute-map sharp permit 20\nset src 192.168.213.1") + r1.vtysh_cmd("conf\nip protocol static route-map static") + r1.vtysh_cmd("conf\nip protocol sharp route-map sharp") + sleep(4) + r1.vtysh_cmd("conf\nip route 10.100.100.100/32 192.168.216.3") + r1.vtysh_cmd("conf\nip route 10.100.100.101/32 10.0.0.44") + r1.vtysh_cmd("sharp install route 10.0.0.0 nexthop 192.168.216.3 500") + sleep(4) + + static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir) + expected = open(static_rmapfile).read().rstrip() + expected = ('\n'.join(expected.splitlines()) + '\n').rstrip() + actual = r1.vtysh_cmd("show route-map static") + actual = ('\n'.join(actual.splitlines()) + '\n').rstrip() + logger.info("Does the show route-map static command run the correct number of times") + + diff = topotest.get_textdiff(actual, expected, + title1 = "Actual Route-map output", + title2 = "Expected Route-map output") + if diff: + logger.info("Actual:") + logger.info(actual) + logger.info("Expected:") + logger.info(expected) + srun = r1.vtysh_cmd("show run") + srun = ('\n'.join(srun.splitlines()) + '\n').rstrip() + logger.info("Show run") + logger.info(srun) + assert 0, "r1 static route processing:\n" + + sharp_rmapfile = "%s/r1/sharp_rmap.ref" % (thisDir) + expected = open(sharp_rmapfile).read().rstrip() + expected = ('\n'.join(expected.splitlines()) + '\n').rstrip() + actual = r1.vtysh_cmd("show route-map sharp") + actual = ('\n'.join(actual.splitlines()) + '\n').rstrip() + logger.info("Does the show route-map sharp command run the correct number of times") + + diff = topotest.get_textdiff(actual, expected, + title1 = "Actual Route-map output", + title2 = "Expected Route-map output") + if diff: + logger.info("Actual:") + logger.info(actual) + logger.info("Expected:") + logger.info(expected) + srun = r1.vtysh_cmd("show run") + srun = ('\n'.join(srun.splitlines()) + '\n').rstrip() + logger.info("Show run:") + logger.info(srun) + assert 0, "r1 sharp route-map processing:\n" + + logger.info("Add a extension to the static route-map to see the static route go away") + r1.vtysh_cmd("conf\nroute-map sharp deny 5\nmatch ip address 5") + sleep(2) + # we are only checking the kernel here as that this will give us the implied + # testing of both the route-map and staticd withdrawing the route + # let's spot check that the routes were installed correctly + # in the kernel + logger.info("Test that the routes installed are correct") + sharp_ipfile = "%s/r1/iproute.ref" % (thisDir) + expected = open(sharp_ipfile).read().rstrip() + expected = ('\n'.join(expected.splitlines()) + '\n').rstrip() + actual = r1.run("ip route show") + actual = ('\n'.join(actual.splitlines()) + '\n').rstrip() + actual = re.sub(r" nhid [0-9][0-9]", "", actual) + actual = re.sub(r" proto sharp", " proto XXXX", actual) + actual = re.sub(r" proto static", " proto XXXX", actual) + actual = re.sub(r" proto 194", " proto XXXX", actual) + actual = re.sub(r" proto 196", " proto XXXX", actual) + actual = re.sub(r" proto kernel", " proto XXXX", actual) + actual = re.sub(r" proto 2", " proto XXXX", actual) + # Some platforms have double spaces? Why?????? + actual = re.sub(r" proto XXXX ", " proto XXXX ", actual) + actual = re.sub(r" metric", " metric", actual) + actual = re.sub(r" link ", " link ", actual) + diff = topotest.get_textdiff(actual, expected, + title1 = "Actual ip route show", + title2 = "Expected ip route show") + + if diff: + logger.info("Actual:") + logger.info(actual) + logger.info("Expected:") + logger.info(expected) + srun = r1.vtysh_cmd("show run") + srun = ('\n'.join(srun.splitlines()) + '\n').rstrip() + logger.info("Show run:") + logger.info(srun) + assert 0, "r1 ip route show is not correct:" def test_memory_leak(): "Run the memory leak test and report results." |
