diff options
59 files changed, 1608 insertions, 240 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 88581736a3..cbd29c146a 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2385,6 +2385,7 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, memcpy(&pi->extra->label, &parent_pi->extra->label, sizeof(pi->extra->label)); pi->extra->num_labels = parent_pi->extra->num_labels; + pi->extra->igpmetric = parent_pi->extra->igpmetric; } bgp_path_info_add(dest, pi); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index a031b78971..27f147a4aa 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -15982,6 +15982,7 @@ static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp, afi_t afi) { int indent = 2; + uint32_t tovpn_sid_index = 0; if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN]) { if (CHECK_FLAG(bgp->af_flags[afi][SAFI_UNICAST], @@ -16011,6 +16012,16 @@ static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp, bgp->vpn_policy[afi].tovpn_label); } } + + tovpn_sid_index = bgp->vpn_policy[afi].tovpn_sid_index; + if (CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_SID_AUTO)) { + vty_out(vty, "%*ssid vpn export %s\n", indent, "", "auto"); + } else if (tovpn_sid_index != 0) { + vty_out(vty, "%*ssid vpn export %d\n", indent, "", + tovpn_sid_index); + } + if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET)) { char buf[RD_ADDRSTRLEN]; @@ -17152,6 +17163,7 @@ int bgp_config_write(struct vty *vty) if (strlen(bgp->srv6_locator_name)) vty_out(vty, " locator %s\n", bgp->srv6_locator_name); + vty_endframe(vty, " exit\n"); } diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index c090f3496a..dd4e7d6dc1 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -389,15 +389,6 @@ Showing OSPF6 information This command shows the graceful-restart helper details including helper configuration parameters. -Debugging OSPF6 -=============== - -.. clicmd:: debug ospf6 graceful-restart - - This command enables/disables debug information for ospf6 graceful restart - helper functionality. - - .. _ospf6-debugging: OSPFv3 Debugging @@ -457,6 +448,10 @@ The following debug commands are supported: Toggle OSPFv3 zebra interaction debugging messages. +.. clicmd:: debug ospf6 graceful-restart + + Toggle OSPFv3 graceful-restart helper debugging messages. + Sample configuration ==================== diff --git a/lib/frrlua.c b/lib/frrlua.c index 928780f2d4..00491568f6 100644 --- a/lib/frrlua.c +++ b/lib/frrlua.c @@ -240,7 +240,9 @@ void lua_pushsockunion(lua_State *L, const union sockunion *su) void lua_decode_sockunion(lua_State *L, int idx, union sockunion *su) { lua_getfield(L, idx, "string"); - (void)str2sockunion(lua_tostring(L, -1), su); + if (str2sockunion(lua_tostring(L, -1), su) < 0) + zlog_err("Lua hook call: Failed to decode sockunion"); + lua_pop(L, 1); /* pop the table */ lua_pop(L, 1); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 5cf879b8cf..2b11d89a31 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1643,10 +1643,15 @@ DEFUN (ospf6_redistribute, return CMD_WARNING_CONFIG_FAILED; red = ospf6_redist_lookup(ospf6, type, 0); - if (!red) + if (!red) { ospf6_redist_add(ospf6, type, 0); - else + } else { + /* To check, if user is providing same config */ + if (ROUTEMAP_NAME(red) == NULL) + return CMD_SUCCESS; + ospf6_asbr_redistribute_unset(ospf6, red, type); + } ospf6_asbr_redistribute_set(ospf6, type); @@ -1674,10 +1679,16 @@ DEFUN (ospf6_redistribute_routemap, return CMD_WARNING_CONFIG_FAILED; red = ospf6_redist_lookup(ospf6, type, 0); - if (!red) + if (!red) { red = ospf6_redist_add(ospf6, type, 0); - else + } else { + /* To check, if user is providing same route map */ + if ((ROUTEMAP_NAME(red) != NULL) + && (strcmp(argv[idx_word]->arg, ROUTEMAP_NAME(red)) == 0)) + return CMD_SUCCESS; + ospf6_asbr_redistribute_unset(ospf6, red, type); + } ospf6_asbr_routemap_set(red, argv[idx_word]->arg); ospf6_asbr_redistribute_set(ospf6, type); diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 892d264a2d..268fb81e52 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -298,8 +298,6 @@ static int nsm_negotiation_done(struct ospf_neighbor *nbr) ospf_db_summary_add(nbr, lsa); LSDB_LOOP (SUMMARY_LSDB(area), rn, lsa) ospf_db_summary_add(nbr, lsa); - LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa) - ospf_db_summary_add(nbr, lsa); /* Process only if the neighbor is opaque capable. */ if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) { @@ -314,10 +312,14 @@ static int nsm_negotiation_done(struct ospf_neighbor *nbr) ospf_db_summary_add(nbr, lsa); } + /* For Stub/NSSA area, we should not send Type-4 and Type-5 LSAs */ if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK - && area->external_routing == OSPF_AREA_DEFAULT) + && area->external_routing == OSPF_AREA_DEFAULT) { + LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa) + ospf_db_summary_add(nbr, lsa); LSDB_LOOP (EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa) ospf_db_summary_add(nbr, lsa); + } if (CHECK_FLAG(nbr->options, OSPF_OPTION_O) && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index fca9652db1..51252ede0c 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -322,6 +322,7 @@ parts: - bison - flex - python3-dev + - libprotobuf-c-dev - protobuf-c-compiler - python3-sphinx stage-packages: diff --git a/staticd/static_vty.c b/staticd/static_vty.c index ea09054a23..f16b40a23f 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -325,7 +325,8 @@ static int static_route_leak(struct vty *vty, const char *svrf, dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath); if (!dnode) { - /* Silently return */ + vty_out(vty, + "%% Refusing to remove a non-existent route\n"); return CMD_SUCCESS; } diff --git a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf index 5e736a7fcc..fd57b2c4d5 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf @@ -4,7 +4,7 @@ debug bfd peer debug bfd zebra ! bfd - peer 192.168.0.2 vrf r1-cust1 + peer 192.168.0.2 vrf r1-bfd-cust1 echo-mode no shutdown ! diff --git a/tests/topotests/bfd_vrf_topo1/r1/bgpd.conf b/tests/topotests/bfd_vrf_topo1/r1/bgpd.conf index 5bb45b9863..cf72f30d66 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/bgpd.conf +++ b/tests/topotests/bfd_vrf_topo1/r1/bgpd.conf @@ -1,4 +1,4 @@ -router bgp 101 vrf r1-cust1 +router bgp 101 vrf r1-bfd-cust1 no bgp ebgp-requires-policy no bgp network import-check neighbor 192.168.0.2 remote-as 102 diff --git a/tests/topotests/bfd_vrf_topo1/r1/zebra.conf b/tests/topotests/bfd_vrf_topo1/r1/zebra.conf index fcd1e7db17..62ed36fdb8 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/zebra.conf +++ b/tests/topotests/bfd_vrf_topo1/r1/zebra.conf @@ -1,3 +1,3 @@ -interface r1-eth0 vrf r1-cust1 +interface r1-eth0 vrf r1-bfd-cust1 ip address 192.168.0.1/24 ! diff --git a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf index 94f502c7d9..e5539f14e5 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf @@ -4,13 +4,13 @@ debug bfd peer debug bfd zebra ! bfd - peer 192.168.0.1 vrf r2-cust1 + peer 192.168.0.1 vrf r2-bfd-cust1 receive-interval 1000 transmit-interval 500 echo-mode no shutdown ! - peer 192.168.1.1 vrf r2-cust1 + peer 192.168.1.1 vrf r2-bfd-cust1 echo-mode no shutdown ! diff --git a/tests/topotests/bfd_vrf_topo1/r2/bgpd.conf b/tests/topotests/bfd_vrf_topo1/r2/bgpd.conf index b2aac74685..132011cf86 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/bgpd.conf +++ b/tests/topotests/bfd_vrf_topo1/r2/bgpd.conf @@ -1,4 +1,4 @@ -router bgp 102 vrf r2-cust1 +router bgp 102 vrf r2-bfd-cust1 no bgp ebgp-requires-policy no bgp network import-check neighbor 192.168.0.1 remote-as 101 diff --git a/tests/topotests/bfd_vrf_topo1/r2/zebra.conf b/tests/topotests/bfd_vrf_topo1/r2/zebra.conf index daffd1912e..1e817b19f6 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/zebra.conf +++ b/tests/topotests/bfd_vrf_topo1/r2/zebra.conf @@ -1,9 +1,9 @@ -interface r2-eth0 vrf r2-cust1 +interface r2-eth0 vrf r2-bfd-cust1 ip address 192.168.0.2/24 ! -interface r2-eth1 vrf r2-cust1 +interface r2-eth1 vrf r2-bfd-cust1 ip address 192.168.1.2/24 ! -interface r2-eth2 vrf r2-cust1 +interface r2-eth2 vrf r2-bfd-cust1 ip address 192.168.2.2/24 ! diff --git a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf index 76910ac927..e1f53e1abc 100644 --- a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf @@ -4,7 +4,7 @@ debug bfd peer debug bfd zebra ! bfd - peer 192.168.1.2 vrf r3-cust1 + peer 192.168.1.2 vrf r3-bfd-cust1 echo-interval 100 echo-mode no shutdown diff --git a/tests/topotests/bfd_vrf_topo1/r3/bgpd.conf b/tests/topotests/bfd_vrf_topo1/r3/bgpd.conf index 1d7c730395..f764647920 100644 --- a/tests/topotests/bfd_vrf_topo1/r3/bgpd.conf +++ b/tests/topotests/bfd_vrf_topo1/r3/bgpd.conf @@ -1,4 +1,4 @@ -router bgp 103 vrf r3-cust1 +router bgp 103 vrf r3-bfd-cust1 no bgp ebgp-requires-policy no bgp network import-check neighbor 192.168.1.2 remote-as 102 diff --git a/tests/topotests/bfd_vrf_topo1/r3/zebra.conf b/tests/topotests/bfd_vrf_topo1/r3/zebra.conf index f727c2d633..e67345948e 100644 --- a/tests/topotests/bfd_vrf_topo1/r3/zebra.conf +++ b/tests/topotests/bfd_vrf_topo1/r3/zebra.conf @@ -1,3 +1,3 @@ -interface r3-eth0 vrf r3-cust1 +interface r3-eth0 vrf r3-bfd-cust1 ip address 192.168.1.1/24 ! diff --git a/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf index 63d0da7805..9ef2023b21 100644 --- a/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf @@ -4,7 +4,7 @@ debug bfd peer debug bfd zebra ! bfd - peer 192.168.2.2 vrf r4-cust1 + peer 192.168.2.2 vrf r4-bfd-cust1 transmit-interval 2000 receive-interval 2000 no shutdown diff --git a/tests/topotests/bfd_vrf_topo1/r4/bgpd.conf b/tests/topotests/bfd_vrf_topo1/r4/bgpd.conf index f34035d460..03353e45e3 100644 --- a/tests/topotests/bfd_vrf_topo1/r4/bgpd.conf +++ b/tests/topotests/bfd_vrf_topo1/r4/bgpd.conf @@ -1,4 +1,4 @@ -router bgp 104 vrf r4-cust1 +router bgp 104 vrf r4-bfd-cust1 no bgp ebgp-requires-policy no bgp network import-check neighbor 192.168.2.2 remote-as 102 diff --git a/tests/topotests/bfd_vrf_topo1/r4/zebra.conf b/tests/topotests/bfd_vrf_topo1/r4/zebra.conf index 69770dd2bf..15d3ec1d90 100644 --- a/tests/topotests/bfd_vrf_topo1/r4/zebra.conf +++ b/tests/topotests/bfd_vrf_topo1/r4/zebra.conf @@ -1,3 +1,3 @@ -interface r4-eth0 vrf r4-cust1 +interface r4-eth0 vrf r4-bfd-cust1 ip address 192.168.2.1/24 ! 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 8a1ffe085d..a342997912 100644 --- a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py @@ -95,20 +95,18 @@ def setup_module(mod): logger.info("Testing with VRF Namespace support") cmds = [ - "if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi", - "ip netns add {0}-cust1", - "ip link set dev {0}-eth0 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth0 up", + "if [ -e /var/run/netns/{0}-bfd-cust1 ] ; then ip netns del {0}-bfd-cust1 ; fi", + "ip netns add {0}-bfd-cust1", + "ip link set dev {0}-eth0 netns {0}-bfd-cust1 up", ] cmds2 = [ - "ip link set dev {0}-eth1 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth1 up", - "ip link set dev {0}-eth2 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth2 up", + "ip link set dev {0}-eth1 netns {0}-bfd-cust1", + "ip netns exec {0}-bfd-cust1 ip link set {0}-eth1 up", + "ip link set dev {0}-eth2 netns {0}-bfd-cust1 up", ] for rname, router in router_list.items(): - # create VRF rx-cust1 and link rx-eth0 to rx-cust1 + # create VRF rx-bfd-cust1 and link rx-eth0 to rx-bfd-cust1 for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) if rname == "r2": @@ -138,11 +136,11 @@ def teardown_module(_mod): # move back rx-eth0 to default VRF # delete rx-vrf cmds = [ - "ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1", - "ip netns delete {0}-cust1", + "ip netns exec {0}-bfd-cust1 ip link set {0}-eth0 netns 1", + "ip netns delete {0}-bfd-cust1", ] cmds2 = [ - "ip netns exec {0}-cust1 ip link set {0}-eth1 netns 1", + "ip netns exec {0}-bfd-cust1 ip link set {0}-eth1 netns 1", "ip netns exec {0}-cust2 ip link set {0}-eth1 netns 1", ] @@ -189,7 +187,7 @@ def test_bgp_convergence(): test_func = partial( topotest.router_json_cmp, router, - "show ip bgp vrf {}-cust1 summary json".format(router.name), + "show ip bgp vrf {}-bfd-cust1 summary json".format(router.name), expected, ) _, res = topotest.run_and_expect(test_func, None, count=125, wait=1.0) @@ -211,7 +209,7 @@ def test_bgp_fast_convergence(): test_func = partial( topotest.router_json_cmp, router, - "show ip bgp vrf {}-cust1 json".format(router.name), + "show ip bgp vrf {}-bfd-cust1 json".format(router.name), expected, ) _, res = topotest.run_and_expect(test_func, None, count=40, wait=1) @@ -231,7 +229,7 @@ def test_bfd_fast_convergence(): # Disable r2-eth0 link router2 = tgen.gears["r2"] topotest.interface_set_status( - router2, "r2-eth0", ifaceaction=False, vrf_name="r2-cust1" + router2, "r2-eth0", ifaceaction=False, vrf_name="r2-bfd-cust1" ) # Wait the minimum time we can before checking that BGP/BFD @@ -286,7 +284,7 @@ def test_bgp_fast_reconvergence(): test_func = partial( topotest.router_json_cmp, router, - "show ip bgp vrf {}-cust1 json".format(router.name), + "show ip bgp vrf {}-bfd-cust1 json".format(router.name), expected, ) _, res = topotest.run_and_expect(test_func, None, count=16, wait=1) diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py index c9a93bd75f..84e10af5b3 100644 --- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py +++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py @@ -178,14 +178,10 @@ NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} LOOPBACK_1 = { "ipv4": "10.10.10.10/32", "ipv6": "10::10:10/128", - "ipv4_mask": "255.255.255.255", - "ipv6_mask": None, } LOOPBACK_2 = { "ipv4": "20.20.20.20/32", "ipv6": "20::20:20/128", - "ipv4_mask": "255.255.255.255", - "ipv6_mask": None, } @@ -1911,7 +1907,6 @@ def test_static_routes_for_inter_vrf_route_leaking_p0(request): "loopback1", LOOPBACK_1[addr_type], "RED_A", - LOOPBACK_1["{}_mask".format(addr_type)], ) create_interface_in_kernel( tgen, @@ -1919,7 +1914,6 @@ def test_static_routes_for_inter_vrf_route_leaking_p0(request): "loopback2", LOOPBACK_2[addr_type], "RED_B", - LOOPBACK_2["{}_mask".format(addr_type)], ) step( @@ -2047,7 +2041,6 @@ def test_inter_vrf_and_intra_vrf_communication_iBGP_p0(request): "loopback1", LOOPBACK_1[addr_type], "RED_A", - LOOPBACK_1["{}_mask".format(addr_type)], ) create_interface_in_kernel( @@ -2056,7 +2049,6 @@ def test_inter_vrf_and_intra_vrf_communication_iBGP_p0(request): "loopback2", LOOPBACK_2[addr_type], "BLUE_A", - LOOPBACK_2["{}_mask".format(addr_type)], ) step( @@ -2216,7 +2208,6 @@ def test_inter_vrf_and_intra_vrf_communication_eBGP_p0(request): "loopback1", LOOPBACK_1[addr_type], "RED_A", - LOOPBACK_1["{}_mask".format(addr_type)], ) create_interface_in_kernel( tgen, @@ -2224,7 +2215,6 @@ def test_inter_vrf_and_intra_vrf_communication_eBGP_p0(request): "loopback2", LOOPBACK_2[addr_type], "BLUE_A", - LOOPBACK_2["{}_mask".format(addr_type)], ) step( diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index 37da53fc31..31569e69b4 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -131,8 +131,6 @@ NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} LOOPBACK_2 = { "ipv4": "20.20.20.20/32", "ipv6": "20::20:20/128", - "ipv4_mask": "255.255.255.255", - "ipv6_mask": None, } MAX_PATHS = 2 @@ -1928,7 +1926,6 @@ def test_vrf_route_leaking_next_hop_interface_flapping_p1(request): "loopback2", LOOPBACK_2[addr_type], "RED_B", - LOOPBACK_2["{}_mask".format(addr_type)], ) intf_red1_r11 = topo["routers"]["red1"]["links"]["r1-link2"]["interface"] diff --git a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py index e7d70f6d8e..2fe80c77f0 100644 --- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py +++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py @@ -1103,7 +1103,7 @@ def test_next_hop_with_recursive_lookup_p1(request): tc_name, result ) - step("Toggle the interface on R3(ifconfig 192.34).") + step("Toggle the interface on R3.") intf_r3_r4 = topo["routers"]["r3"]["links"]["r4"]["interface"] shutdown_bringup_interface(tgen, "r3", intf_r3_r4) @@ -1161,7 +1161,7 @@ def test_next_hop_with_recursive_lookup_p1(request): tc_name, result ) - step("Toggle the interface on R4(ifconfig 192.34).") + step("Toggle the interface on R4.") intf_r4_r3 = topo["routers"]["r4"]["links"]["r3"]["interface"] shutdown_bringup_interface(tgen, "r4", intf_r4_r3) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py index d6f1058a98..ea1b1a42d7 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py @@ -123,8 +123,6 @@ LOOPBACK_1 = { LOOPBACK_2 = { "ipv4": "10.0.0.16/24", "ipv6": "fd00:0:0:3::5/64", - "ipv4_mask": "255.255.255.0", - "ipv6_mask": None, } PREFERRED_NEXT_HOP = "global" @@ -692,14 +690,13 @@ def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): "loopback2", LOOPBACK_2[addr_type], "ISR", - LOOPBACK_2["{}_mask".format(addr_type)], ) for addr_type in ADDR_TYPES: step( "On router R1 Change the next-hop of static routes in vrf " - "ISR to LOOPBACK_1" + "ISR to LOOPBACK_2" ) input_routes_r1 = { diff --git a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf index cfe3f2e2b5..572dce7455 100644 --- a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf +++ b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf @@ -1,5 +1,5 @@ ! -router bgp 100 vrf r1-cust1 +router bgp 100 vrf r1-bgp-cust1 bgp router-id 10.0.1.1 bgp bestpath as-path multipath-relax no bgp ebgp-requires-policy diff --git a/tests/topotests/bgp_vrf_netns/r1/summary.txt b/tests/topotests/bgp_vrf_netns/r1/summary.txt index 1a079ff130..819f26133f 100644 --- a/tests/topotests/bgp_vrf_netns/r1/summary.txt +++ b/tests/topotests/bgp_vrf_netns/r1/summary.txt @@ -2,7 +2,7 @@ "ipv4Unicast":{ "routerId":"10.0.1.1", "as":100, - "vrfName":"r1-cust1", + "vrfName":"r1-bgp-cust1", "peerCount":1, "peers":{ "10.0.1.101":{ diff --git a/tests/topotests/bgp_vrf_netns/r1/summary20.txt b/tests/topotests/bgp_vrf_netns/r1/summary20.txt index 2b5787e6da..ea04a56d85 100644 --- a/tests/topotests/bgp_vrf_netns/r1/summary20.txt +++ b/tests/topotests/bgp_vrf_netns/r1/summary20.txt @@ -1,7 +1,7 @@ { "routerId":"10.0.1.1", "as":100, - "vrfName":"re1-cust1", + "vrfName":"re1-bgp-cust1", "peerCount":1, "peers":{ "10.0.1.101":{ diff --git a/tests/topotests/bgp_vrf_netns/r1/zebra.conf b/tests/topotests/bgp_vrf_netns/r1/zebra.conf index 817d9544d3..fd0e18f5fd 100644 --- a/tests/topotests/bgp_vrf_netns/r1/zebra.conf +++ b/tests/topotests/bgp_vrf_netns/r1/zebra.conf @@ -1,5 +1,5 @@ ! -interface r1-eth0 vrf r1-cust1 +interface r1-eth0 vrf r1-bgp-cust1 ip address 10.0.1.1/24 ! line vty diff --git a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py index 9889e1cdd5..60511aebde 100644 --- a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py +++ b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py @@ -106,13 +106,12 @@ def setup_module(module): if CustomizeVrfWithNetns == True: logger.info("Testing with VRF Namespace support") - # create VRF r1-cust1 - # move r1-eth0 to VRF r1-cust1 + # create VRF r1-bgp-cust1 + # move r1-eth0 to VRF r1-bgp-cust1 cmds = [ - "if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi", - "ip netns add {0}-cust1", - "ip link set dev {0}-eth0 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth0 up", + "if [ -e /var/run/netns/{0}-bgp-cust1 ] ; then ip netns del {0}-bgp-cust1 ; fi", + "ip netns add {0}-bgp-cust1", + "ip link set {0}-eth0 netns {0}-bgp-cust1 up", ] for cmd in cmds: cmd = cmd.format("r1") @@ -154,10 +153,10 @@ def setup_module(module): def teardown_module(module): tgen = get_topogen() # move back r1-eth0 to default VRF - # delete VRF r1-cust1 + # delete VRF r1-bgp-cust1 cmds = [ - "ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1", - "ip netns delete {0}-cust1", + "ip netns exec {0}-bgp-cust1 ip link set {0}-eth0 netns 1", + "ip netns delete {0}-bgp-cust1", ] for cmd in cmds: tgen.net["r1"].cmd(cmd.format("r1")) @@ -203,7 +202,7 @@ def test_bgp_convergence(): expected = json.loads(open(reffile).read()) test_func = functools.partial( - topotest.router_json_cmp, router, "show bgp vrf r1-cust1 summary json", expected + topotest.router_json_cmp, router, "show bgp vrf r1-bgp-cust1 summary json", expected ) _, res = topotest.run_and_expect(test_func, None, count=90, wait=0.5) assertmsg = "BGP router network did not converge" @@ -231,11 +230,11 @@ def test_bgp_vrf_netns(): test_func = functools.partial( topotest.router_json_cmp, tgen.gears["r1"], - "show ip bgp vrf r1-cust1 ipv4 json", + "show ip bgp vrf r1-bgp-cust1 ipv4 json", expect, ) _, res = topotest.run_and_expect(test_func, None, count=12, wait=0.5) - assertmsg = 'expected routes in "show ip bgp vrf r1-cust1 ipv4" output' + assertmsg = 'expected routes in "show ip bgp vrf r1-bgp-cust1 ipv4" output' assert res is None, assertmsg diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 22a678862a..2abab6b255 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -34,6 +34,7 @@ import socket import subprocess import ipaddress import platform +import pytest try: # Imports from python2 @@ -971,22 +972,31 @@ def add_interfaces_to_vlan(tgen, input_dict): for intf_dict in interfaces: for interface, data in intf_dict.items(): # Adding interface to VLAN - cmd = "vconfig add {} {}".format(interface, vlan) + vlan_intf = "{}.{}".format(interface, vlan) + cmd = "ip link add link {} name {} type vlan id {}".format( + interface, + vlan_intf, + vlan + ) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) - vlan_intf = "{}.{}".format(interface, vlan) - - ip = data["ip"] - subnet = data["subnet"] - # Bringing interface up - cmd = "ip link set up {}".format(vlan_intf) + cmd = "ip link set {} up".format(vlan_intf) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) # Assigning IP address - cmd = "ifconfig {} {} netmask {}".format(vlan_intf, ip, subnet) + ifaddr = ipaddress.ip_interface( + u"{}/{}".format( + frr_unicode(data["ip"]), + frr_unicode(data["subnet"]) + ) + ) + + cmd = "ip -{0} a flush {1} scope global && ip a add {2} dev {1} && ip l set {1} up".format( + ifaddr.version, vlan_intf, ifaddr + ) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) @@ -1391,15 +1401,20 @@ def create_interface_in_kernel( rnode = tgen.routers()[dut] if create: - cmd = "sudo ip link add name {} type dummy".format(name) + cmd = "ip link show {0} >/dev/null || ip link add {0} type dummy".format(name) rnode.run(cmd) - addr_type = validate_ip_address(ip_addr) - if addr_type == "ipv4": - cmd = "ifconfig {} {} netmask {}".format(name, ip_addr, netmask) + if not netmask: + ifaddr = ipaddress.ip_interface(frr_unicode(ip_addr)) else: - cmd = "ifconfig {} inet6 add {}/{}".format(name, ip_addr, netmask) - + ifaddr = ipaddress.ip_interface(u"{}/{}".format( + frr_unicode(ip_addr), + frr_unicode(netmask) + )) + cmd = "ip -{0} a flush {1} scope global && ip a add {2} dev {1} && ip l set {1} up".format( + ifaddr.version, name, ifaddr + ) + logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) if vrf: @@ -1587,7 +1602,7 @@ def find_interface_with_greater_ip(topo, router, loopback=True, interface=True): def write_test_header(tc_name): - """ Display message at beginning of test case""" + """Display message at beginning of test case""" count = 20 logger.info("*" * (len(tc_name) + count)) step("START -> Testcase : %s" % tc_name, reset=True) @@ -1595,7 +1610,7 @@ def write_test_header(tc_name): def write_test_footer(tc_name): - """ Display message at end of test case""" + """Display message at end of test case""" count = 21 logger.info("=" * (len(tc_name) + count)) logger.info("Testcase : %s -> PASSED", tc_name) @@ -1878,7 +1893,7 @@ def create_interfaces_cfg(tgen, topo, build=False): "network", "priority", "cost", - "mtu_ignore" + "mtu_ignore", ] if "ospf" in data: interface_data += _create_interfaces_ospf_cfg( @@ -2933,7 +2948,7 @@ def configure_interface_mac(tgen, input_dict): rnode = tgen.routers()[dut] for intf, mac in input_dict[dut].items(): - cmd = "ifconfig {} hw ether {}".format(intf, mac) + cmd = "ip link set {} address {}".format(intf, mac) logger.info("[DUT: %s]: Running command: %s", dut, cmd) try: @@ -4577,3 +4592,64 @@ def verify_ip_nht(tgen, input_dict): logger.debug("Exiting lib API: verify_ip_nht()") return False + + +def scapy_send_raw_packet( + tgen, topo, senderRouter, intf, packet=None, interval=1, count=1 +): + """ + Using scapy Raw() method to send BSR raw packet from one FRR + to other + + Parameters: + ----------- + * `tgen` : Topogen object + * `topo` : json file data + * `senderRouter` : Sender router + * `packet` : packet in raw format + * `interval` : Interval between the packets + * `count` : Number of packets to be sent + + returns: + -------- + errormsg or True + """ + + global CD + result = "" + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + sender_interface = intf + rnode = tgen.routers()[senderRouter] + + for destLink, data in topo["routers"][senderRouter]["links"].items(): + if "type" in data and data["type"] == "loopback": + continue + + if not packet: + packet = topo["routers"][senderRouter]["pkt"]["test_packets"][packet][ + "data" + ] + + if interval > 1 or count > 1: + cmd = ( + "nohup /usr/bin/python {}/send_bsr_packet.py '{}' '{}' " + "--interval={} --count={} &".format( + CD, packet, sender_interface, interval, count + ) + ) + else: + cmd = ( + "/usr/bin/python {}/send_bsr_packet.py '{}' '{}' " + "--interval={} --count={}".format( + CD, packet, sender_interface, interval, count + ) + ) + + logger.info("Scapy cmd: \n %s", cmd) + result = rnode.run(cmd) + + if result == "": + return result + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return True diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 40da7c8fbe..9646daf725 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -28,6 +28,7 @@ from time import sleep from lib.topolog import logger from lib.topotest import frr_unicode from ipaddress import IPv6Address +import sys # Import common_config to use commomnly used APIs from lib.common_config import ( @@ -324,8 +325,47 @@ def __create_ospf_global( cmd = "no {}".format(cmd) config_data.append(cmd) + # ospf gr information + gr_data = ospf_data.setdefault("graceful-restart", {}) + if gr_data: + + if "opaque" in gr_data and gr_data["opaque"]: + cmd = "capability opaque" + if gr_data.setdefault("delete", False): + cmd = "no {}".format(cmd) + config_data.append(cmd) + + if "helper-only" in gr_data and not gr_data["helper-only"]: + cmd = "graceful-restart helper-only" + if gr_data.setdefault("delete", False): + cmd = "no {}".format(cmd) + config_data.append(cmd) + elif "helper-only" in gr_data and type(gr_data["helper-only"]) is list: + for rtrs in gr_data["helper-only"]: + cmd = "graceful-restart helper-only {}".format(rtrs) + if gr_data.setdefault("delete", False): + cmd = "no {}".format(cmd) + config_data.append(cmd) + + if "helper" in gr_data: + if type(gr_data["helper"]) is not list: + gr_data["helper"] = list(gr_data["helper"]) + for helper_role in gr_data["helper"]: + cmd = "graceful-restart helper {}".format(helper_role) + if gr_data.setdefault("delete", False): + cmd = "no {}".format(cmd) + config_data.append(cmd) + + if "supported-grace-time" in gr_data: + cmd = "graceful-restart helper supported-grace-time {}".format( + gr_data["supported-grace-time"] + ) + if gr_data.setdefault("delete", False): + cmd = "no {}".format(cmd) + config_data.append(cmd) + result = create_common_configuration( - tgen, router, config_data, ospf, build, load_config + tgen, router, config_data, "ospf", build, load_config ) except InvalidCLIError: @@ -2375,3 +2415,66 @@ def config_ospf6_interface(tgen, topo, input_dict=None, build=False, load_config ) logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return result + +@retry(retry_timeout=20) +def verify_ospf_gr_helper(tgen, topo, dut, input_dict=None): + """ + This API is used to vreify gr helper using command + show ip ospf graceful-restart helper + + Parameters + ---------- + * `tgen` : Topogen object + * `topo` : topology descriptions + * 'dut' : router + * 'input_dict' - values to be verified + + Usage: + ------- + input_dict = { + "helperSupport":"Disabled", + "strictLsaCheck":"Enabled", + "restartSupoort":"Planned and Unplanned Restarts", + "supportedGracePeriod":1800 + } + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + + """ + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + result = False + + if 'ospf' not in topo['routers'][dut]: + errormsg = "[DUT: {}] OSPF is not configured on the router.".format( + dut) + return errormsg + + rnode = tgen.routers()[dut] + logger.info("Verifying OSPF GR details on router %s:", dut) + show_ospf_json = run_frr_cmd(rnode, "show ip ospf graceful-restart helper json", + isjson=True) + + # Verifying output dictionary show_ospf_json is empty or not + if not bool(show_ospf_json): + errormsg = "OSPF is not running" + raise ValueError (errormsg) + return errormsg + + for ospf_gr, gr_data in input_dict.items(): + try: + if input_dict[ospf_gr] == show_ospf_json[ospf_gr]: + logger.info("[DUT: FRR] OSPF GR Helper: %s is %s", ospf_gr, + show_ospf_json[ospf_gr]) + result = True + else: + errormsg = ("[DUT: FRR] OSPF GR Helper: {} expected is {}, Found " + "is {}".format(ospf_gr, input_dict[ospf_gr], show_ospf_json[ + ospf_gr])) + raise ValueError (errormsg) + return errormsg + + except KeyError: + errormsg = ("[DUT: FRR] OSPF GR Helper: {}".format(ospf_gr)) + return errormsg + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return result diff --git a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py index 98af4433ab..894326f19f 100644 --- a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py +++ b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py @@ -1008,8 +1008,8 @@ def test_BSM_fragmentation_p1(request): # set mtu of fhr(f1) to i1 interface to 100 so that bsm fragments step("set mtu of fhr(f1) to i1 interface to 100 so that bsm fragments") - fhr_node.run("ifconfig f1-i1-eth2 mtu 100") - inter_node.run("ifconfig i1-f1-eth0 mtu 100") + fhr_node.run("ip link set f1-i1-eth2 mtu 100") + inter_node.run("ip link set i1-f1-eth0 mtu 100") # Use scapy to send pre-defined packet from senser to receiver result = scapy_send_bsr_raw_packet(tgen, topo, "b1", "f1", "packet2") diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index bc6c248ad2..066f53aa58 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -53,6 +53,7 @@ from lib.common_config import ( create_route_maps, verify_prefix_lists, topo_daemons, + shutdown_bringup_interface ) from lib.topolog import logger from lib.topojson import build_topo_from_json, build_config_from_json @@ -1046,6 +1047,336 @@ def test_ospf_routemaps_functionality_tc24_p0(request): write_test_footer(tc_name) +def test_ospf_routemaps_functionality_tc25_p0(request): + """ + OSPF route map support functionality. + + Verify OSPF route map support functionality + when route map actions are toggled. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config as per the topology") + + reset_config_on_routers(tgen) + + step( + "Create static routes(10.0.20.1/32) in R1 and redistribute " + "to OSPF using route map.") + + # Create Static routes + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK['ipv4'][0], + "no_of_ip": 5, + "next_hop": 'Null0', + } + ] + } + } + 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) + step("Configure route map with permit rule") + # Create route map + routemaps = { + "r0": { + "route_maps": { + "rmap_ipv4": [{ + "action": "permit" + }] + } + } + } + result = create_route_maps(tgen, routemaps) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify that route is advertised to R1.") + dut = 'r1' + protocol = 'ospf' + result = verify_ospf_rib(tgen, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + step("Configure route map with deny rule") + # Create route map + routemaps = { + "r0": { + "route_maps": { + "rmap_ipv4": [{ + "seq_id": 10, + "action": "deny" + }] + } + } + } + result = create_route_maps(tgen, routemaps) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Api call verify whether OSPF is converged + ospf_covergence = verify_ospf_neighbor(tgen, topo) + assert ospf_covergence is True, ("setup_module :Failed \n Error:" + " {}".format(ospf_covergence)) + + step("Verify that route is not advertised to R1.") + dut = 'r1' + protocol = 'ospf' + result = verify_ospf_rib(tgen, dut, input_dict, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, + expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) + + +def test_ospf_routemaps_functionality_tc22_p0(request): + """ + OSPF Route map - Multiple sequence numbers. + + Verify OSPF route map support functionality with multiple sequence + numbers in a single route-map for different match/set clauses. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config as per the topology") + + reset_config_on_routers(tgen) + + step( + "Configure route map with seq number 10 to with ip prefix" + " permitting route 10.0.20.1/32 in R1") + step( + "Configure route map with seq number 20 to with ip prefix" + " permitting route 10.0.20.2/32 in R1") + + # Create route map + input_dict_3 = { + "r0": { + "route_maps": { + "rmap_ipv4": [{ + "action": "permit", + 'seq_id': '10', + "match": { + "ipv4": { + "prefix_lists": "pf_list_1_ipv4" + } + } + }, + { + "action": "permit", + 'seq_id': '20', + "match": { + "ipv4": { + "prefix_lists": "pf_list_2_ipv4" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + 'r0': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_1_ipv4': [{ + 'seqid': 10, + 'network': NETWORK['ipv4'][0], + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + # Create ip prefix list + input_dict_2 = { + 'r0': { + 'prefix_lists': { + 'ipv4': { + 'pf_list_2_ipv4': [{ + 'seqid': 10, + 'network': NETWORK['ipv4'][1], + 'action': 'permit' + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + step("Configure static routes 10.0.20.1/32 and 10.0.20.2 in R1") + # Create Static routes + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK['ipv4'][0], + "no_of_ip": 5, + "next_hop": 'Null0', + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Configure redistribute static route with route map.") + 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) + + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK['ipv4'][0], + "no_of_ip": 2, + "next_hop": 'Null0', + } + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Verify that both routes are learned in R1 and R2") + dut = 'r1' + protocol = 'ospf' + result = verify_ospf_rib(tgen, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + dut = 'r2' + protocol = 'ospf' + result = verify_ospf_rib(tgen, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step("Change route map with seq number 20 to deny.") + # Create route map + input_dict_3 = { + "r0": { + "route_maps": { + "rmap_ipv4": [ + { + "action": "deny", + 'seq_id': '20', + "match": { + "ipv4": { + "prefix_lists": "pf_list_2_ipv4" + } + } + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + + step( + "Verify the route 10.0.20.2/32 is withdrawn and not present " + "in the routing table of R0 and R1.") + + input_dict = { + "r0": { + "static_routes": [ + { + "network": NETWORK['ipv4'][1], + "next_hop": 'Null0' + } + ] + } + } + + dut = 'r1' + protocol = 'ospf' + result = verify_ospf_rib(tgen, dut, input_dict, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, + expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + dut = 'r2' + protocol = 'ospf' + result = verify_ospf_rib(tgen, dut, input_dict, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, + expected=False) + assert result is not 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_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py index a595bc0491..0d0668a931 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -1011,7 +1011,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): r0_r1_intf = topo["routers"]["r0"]["links"]["r1"]["interface"] r1_r0_intf = topo["routers"]["r1"]["links"]["r0"]["interface"] - rtr0.run("ifconfig {} mtu 1200".format(r0_r1_intf)) + rtr0.run("ip link set {} mtu 1200".format(r0_r1_intf)) clear_ospf(tgen, "r0") @@ -1037,7 +1037,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): "Modify the MTU to non default Value on R0 to R1 interface. " "Reset ospf neighbors on R0." ) - rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf)) + rtr0.run("ip link set {} mtu 1500".format(r0_r1_intf)) clear_ospf(tgen, "r0") @@ -1062,7 +1062,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): result = config_ospf_interface(tgen, topo, r1_ospf_mtu) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - rtr0.run("ifconfig {} mtu 1200".format(r0_r1_intf)) + rtr0.run("ip link set {} mtu 1200".format(r0_r1_intf)) clear_ospf(tgen, "r0") @@ -1076,7 +1076,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): ) r1_ospf_mtu = { - "r1": {"links": {"r0": {"ospf": {"mtu_ignore": True, "delete": True}}}} + "r1": {"links": {"r0": {"ospf": {"mtu_ignore": True, "del_action": True}}}} } result = config_ospf_interface(tgen, topo, r1_ospf_mtu) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) @@ -1094,7 +1094,7 @@ def test_ospf_tc4_mtu_ignore_p0(request): step("Modify the MTU to again default valaue on R0 to R1 interface.") - rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf)) + rtr0.run("ip link set {} mtu 1500".format(r0_r1_intf)) clear_ospf(tgen, "r0") @@ -1106,8 +1106,8 @@ def test_ospf_tc4_mtu_ignore_p0(request): "Configure ospf interface with jumbo MTU (9216)." "Reset ospf neighbors on R0." ) - rtr0.run("ifconfig {} mtu 9216".format(r0_r1_intf)) - rtr1.run("ifconfig {} mtu 9216".format(r1_r0_intf)) + rtr0.run("ip link set {} mtu 9216".format(r0_r1_intf)) + rtr1.run("ip link set {} mtu 9216".format(r1_r0_intf)) clear_ospf(tgen, "r0") clear_ospf(tgen, "r1") diff --git a/tests/topotests/ospf_gr_helper/ospf_gr_helper.json b/tests/topotests/ospf_gr_helper/ospf_gr_helper.json new file mode 100644 index 0000000000..efd339ef88 --- /dev/null +++ b/tests/topotests/ospf_gr_helper/ospf_gr_helper.json @@ -0,0 +1,119 @@ +{ + "ipv4base": "10.0.0.0", + "ipv4mask": 24, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 24 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32 + }, + "switches": { + "s1": { + "links": { + "r0": { + "ipv4": "17.1.1.2/24", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 40, + "priority": 98 + } + }, + "r1": { + "ipv4": "17.1.1.1/24", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 40, + "priority": 99 + } + }, + "r2": { + "ipv4": "17.1.1.3/24", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 40, + "priority": 0 + } + }, + "r3": { + "ipv4": "17.1.1.4/24", + "ospf": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 40, + "priority": 0 + } + } + } + } + }, + "routers": { + "r0": { + "links": { + "lo": { + "ipv4": "auto", + "type": "loopback" + } + }, + "ospf": { + "router_id": "100.1.1.0", + "neighbors": { + "r1": {}, + "r2": {}, + "r3": {} + } + } + }, + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "type": "loopback" + } + }, + "ospf": { + "router_id": "1.1.1.1", + "neighbors": { + "r0": {}, + "r2": {}, + "r3": {} + } + }, + "opq_lsa_hex": "01005e00000570708bd051ef080045c0005cc18b0000015904f711010101e00000050204004801010101000000001e8d0000000000000000000000000001000102090300000001010101800000013bd1002c000100040000070800020001010000000003000411010101" + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "type": "loopback" + } + }, + "ospf": { + "router_id": "100.1.1.2", + "neighbors": { + "r1": {}, + "r0": {} + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "type": "loopback" + } + }, + "ospf": { + "router_id": "100.1.1.3", + "neighbors": { + "r0": {}, + "r1": {} + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py new file mode 100644 index 0000000000..5363822134 --- /dev/null +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py @@ -0,0 +1,752 @@ +#!/usr/bin/python + +# +# Copyright (c) 2021 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 time import sleep +from copy import deepcopy +import ipaddress + +# 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 mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +# 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, + scapy_send_raw_packet +) + +from lib.topolog import logger +from lib.topojson import build_topo_from_json, build_config_from_json + +from lib.ospf import ( + verify_ospf_neighbor, + clear_ospf, + verify_ospf_gr_helper, + create_router_ospf, + verify_ospf_interface, + verify_ospf_database, +) + +# Global variables +topo = None +Iters = 5 +sw_name = None +intf = None +intf1 = None +pkt = None + +# Reading the data from JSON File for topology creation +jsonFile = "{}/ospf_gr_helper.json".format(CWD) +try: + with open(jsonFile, "r") as topoJson: + topo = json.load(topoJson) +except IOError: + assert False, "Could not read file {}".format(jsonFile) + +""" +Topology: + + Please view in a fixed-width font such as Courier. + Topo : Broadcast Networks + DUT - HR RR + +---+ +---+ +---+ +---+ + |R0 + +R1 + +R2 + +R3 | + +-+-+ +-+-+ +-+-+ +-+-+ + | | | | + | | | | + --+-----------+--------------+---------------+----- + Ethernet Segment + +Testcases: + +TC1. Verify by default helper support is disabled for FRR ospf +TC2. OSPF GR on Broadcast : Verify DUT enters Helper mode when neighbor + sends grace lsa, helps RR to restart gracefully (RR = DR) +TC3. OSPF GR on Broadcast : Verify DUT enters Helper mode when neighbor + sends grace lsa, helps RR to restart gracefully (RR = BDR) +TC4. OSPF GR on Broadcast : Verify DUT enters Helper mode when neighbor + sends grace lsa, helps RR to restart gracefully (RR = DRother) +TC5. OSPF GR on P2P : Verify DUT enters Helper mode when neighbor sends + grace lsa, helps RR to restart gracefully. +TC6. Verify all the show commands newly introducted as part of ospf + helper support - Json Key verification wrt to show commands. +TC7. Verify helper when grace lsa is received with different configured + value in process level (higher, lower, grace lsa timer above 1800) +TC8. Verify helper functionality when dut is helping RR and new grace lsa + is received from RR. +""" + + +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, intf, intf1, sw_name, pkt + 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) + + ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) + + sw_name = topo["switches"].keys()[0] + intf = topo["routers"]["r0"]["links"][sw_name]["interface"] + intf1 = topo["routers"]["r1"]["links"][sw_name]["interface"] + pkt = topo["routers"]["r1"]["opq_lsa_hex"] + + logger.info("Running setup_module() done") + + +def teardown_module(): + """Teardown the pytest environment""" + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + try: + # Stop toplogy and Remove tmp files + tgen.stop_topology + + except OSError: + # OSError exception is raised when mininet tries to stop switch + # though switch is stopped once but mininet tries to stop same + # switch again, where it ended up with exception + pass + + +def delete_ospf(): + """delete ospf process after each test""" + tgen = get_topogen() + step("Delete ospf process") + for rtr in topo["routers"]: + ospf_del = {rtr: {"ospf": {"delete": True}}} + result = create_router_ospf(tgen, topo, ospf_del) + assert result is True, "Testcase: Failed \n Error: {}".format(result) + + +# ################################## +# Test cases start here. +# ################################## + + +def test_ospf_gr_helper_tc1_p0(request): + """Verify by default helper support is disabled for FRR ospf""" + + 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, intf, intf1, pkt + + step("Bring up the base config as per the topology") + reset_config_on_routers(tgen) + ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True) + assert ( + ospf_covergence is True + ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence) + + step("Verify that GR helper route is disabled by default to the in" "the DUT.") + input_dict = { + "helperSupport": "Disabled", + "strictLsaCheck": "Enabled", + "restartSupoort": "Planned and Unplanned Restarts", + "supportedGracePeriod": 1800, + } + dut = "r0" + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that DUT does not enter helper mode upon receiving the " "grace lsa.") + + # send grace lsa + scapy_send_raw_packet(tgen, topo, "r1", intf1, pkt) + + input_dict = {"activeRestarterCnt": 1} + dut = "r0" + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict, expected=False) + assert ( + result is not True + ), "Testcase {} : Failed. DUT entered helper role " " \n Error: {}".format( + tc_name, result + ) + + step("Configure graceful restart in the DUT") + ospf_gr_r0 = { + "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that GR helper route is enabled in the DUT.") + input_dict = { + "helperSupport": "Enabled", + "strictLsaCheck": "Enabled", + "restartSupoort": "Planned and Unplanned Restarts", + "supportedGracePeriod": 1800, + } + dut = "r0" + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ospf_gr_r1 = { + "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Perform GR in RR.") + step("Verify that DUT does enter helper mode upon receiving" " the grace lsa.") + input_dict = {"activeRestarterCnt": 1} + gracelsa_sent = False + repeat = 0 + dut = "r0" + while not gracelsa_sent and repeat < Iters: + gracelsa_sent = scapy_send_raw_packet(tgen, topo, "r1", intf1, pkt) + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + if isinstance(result, str): + repeat += 1 + gracelsa_sent = False + + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Unconfigure the GR helper command.") + ospf_gr_r0 = { + "r0": { + "ospf": { + "graceful-restart": {"helper-only": [], "opaque": True, "delete": True} + } + } + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + input_dict = {"helperSupport": "Disabled"} + dut = "r0" + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure gr helper using the router id") + ospf_gr_r0 = { + "r0": { + "ospf": {"graceful-restart": {"helper-only": ["1.1.1.1"], "opaque": True}} + } + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that DUT does enter helper mode upon receiving" " the grace lsa.") + input_dict = {"activeRestarterCnt": 1} + gracelsa_sent = False + repeat = 0 + dut = "r0" + while not gracelsa_sent and repeat < Iters: + gracelsa_sent = scapy_send_raw_packet(tgen, topo, "r1", intf1, pkt) + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + if isinstance(result, str): + repeat += 1 + gracelsa_sent = False + + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Un Configure gr helper using the router id") + ospf_gr_r0 = { + "r0": { + "ospf": { + "graceful-restart": { + "helper-only": ["1.1.1.1"], + "opaque": True, + "delete": True, + } + } + } + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that GR helper router is disabled in the DUT for" " router id x.x.x.x") + input_dict = {"enabledRouterIds": [{"routerId": "1.1.1.1"}]} + dut = "r0" + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict, expected=False) + assert ( + result is not True + ), "Testcase {} : Failed, Helper role enabled for RR\n Error: {}".format( + tc_name, result + ) + delete_ospf() + write_test_footer(tc_name) + + +def test_ospf_gr_helper_tc2_p0(request): + """ + OSPF GR on Broadcast : Verify DUT enters Helper mode when neighbor + sends grace lsa, helps RR to restart gracefully (RR = DR) + """ + 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, intf, intf1, pkt + + step("Bring up the base config as per the topology") + step( + "Configure DR priority as 99 in RR , DUT dr priority = 98 " + "& reset ospf process in all the routers" + ) + reset_config_on_routers(tgen) + ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True) + assert ( + ospf_covergence is True + ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence) + ospf_gr_r0 = { + "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ospf_gr_r1 = { + "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that DUT enters into helper mode.") + + input_dict = {"activeRestarterCnt": 1} + gracelsa_sent = False + repeat = 0 + dut = "r0" + while not gracelsa_sent and repeat < Iters: + gracelsa_sent = scapy_send_raw_packet(tgen, topo, "r1", intf1, pkt) + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + if isinstance(result, str): + repeat += 1 + gracelsa_sent = False + + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + delete_ospf() + write_test_footer(tc_name) + + +def test_ospf_gr_helper_tc3_p1(request): + """ + OSPF GR on Broadcast : Verify DUT enters Helper mode when neighbor + sends grace lsa, helps RR to restart gracefully (RR = BDR) + """ + 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, intf, intf1, pkt + + step("Bring up the base config as per the topology") + step( + "Configure DR priority as 99 in RR , DUT dr priority = 98 " + "& reset ospf process in all the routers" + ) + reset_config_on_routers(tgen) + ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True) + assert ( + ospf_covergence is True + ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence) + step( + "Configure DR pririty 100 on R0 and clear ospf neighbors " "on all the routers." + ) + + input_dict = { + "r0": { + "links": { + sw_name: { + "interface": topo["routers"]["r0"]["links"][sw_name]["interface"], + "ospf": {"priority": 100}, + } + } + } + } + + result = create_interfaces_cfg(tgen, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Clear ospf neighbours in all routers") + for rtr in topo["routers"]: + clear_ospf(tgen, rtr) + + step("Verify that DR election is triggered and R0 is elected as DR") + input_dict = { + "r0": { + "ospf": { + "neighbors": { + "r1": {"state": "Full", "role": "Backup"}, + "r2": {"state": "Full", "role": "DROther"}, + "r3": {"state": "Full", "role": "DROther"}, + } + } + } + } + dut = "r0" + result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ospf_gr_r0 = { + "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ospf_gr_r1 = { + "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that DUT enters into helper mode.") + + input_dict = {"activeRestarterCnt": 1} + gracelsa_sent = False + repeat = 0 + dut = "r0" + while not gracelsa_sent and repeat < Iters: + gracelsa_sent = scapy_send_raw_packet(tgen, topo, "r1", intf1, pkt) + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + if isinstance(result, str): + repeat += 1 + gracelsa_sent = False + + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + delete_ospf() + write_test_footer(tc_name) + + +def test_ospf_gr_helper_tc4_p1(request): + """ + OSPF GR on Broadcast : Verify DUT enters Helper mode when neighbor + sends grace lsa, helps RR to restart gracefully (RR = DRother) + """ + 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, intf, intf1, pkt + + step("Bring up the base config as per the topology") + step( + "Configure DR priority as 99 in RR , DUT dr priority = 98 " + "& reset ospf process in all the routers" + ) + reset_config_on_routers(tgen) + ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True) + assert ( + ospf_covergence is True + ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence) + step( + "Configure DR pririty 100 on R0 and clear ospf neighbors " "on all the routers." + ) + + input_dict = { + "r0": { + "links": { + sw_name: { + "interface": topo["routers"]["r0"]["links"][sw_name]["interface"], + "ospf": {"priority": 0}, + } + } + } + } + + result = create_interfaces_cfg(tgen, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Clear ospf neighbours in all routers") + for rtr in topo["routers"]: + clear_ospf(tgen, rtr) + + step("Verify that DR election is triggered and R0 is elected as 2-Way") + input_dict = { + "r0": { + "ospf": { + "neighbors": { + "r1": {"state": "Full", "role": "DR"}, + "r2": {"state": "2-Way", "role": "DROther"}, + "r3": {"state": "2-Way", "role": "DROther"}, + } + } + } + } + dut = "r0" + result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ospf_gr_r0 = { + "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ospf_gr_r1 = { + "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that DUT enters into helper mode.") + + input_dict = {"activeRestarterCnt": 1} + gracelsa_sent = False + repeat = 0 + dut = "r0" + while not gracelsa_sent and repeat < Iters: + gracelsa_sent = scapy_send_raw_packet(tgen, topo, "r1", intf1, pkt) + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + if isinstance(result, str): + repeat += 1 + gracelsa_sent = False + + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + delete_ospf() + + write_test_footer(tc_name) + + +def test_ospf_gr_helper_tc7_p1(request): + """ + Test ospf gr helper + Verify helper when grace lsa is received with different configured + value in process level (higher, lower, grace lsa timer above 1800) + """ + 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, intf, intf1, pkt + + step("Bring up the base config as per the topology") + step( + "Configure DR priority as 99 in RR , DUT dr priority = 98 " + "& reset ospf process in all the routers" + ) + step( + "Enable GR on RR and DUT with grace period on RR = 333" + "and grace period on DUT = 300" + ) + reset_config_on_routers(tgen) + ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True) + assert ( + ospf_covergence is True + ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence) + ospf_gr_r0 = { + "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ospf_gr_r1 = { + "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + input_dict = {"supportedGracePeriod": 1800} + dut = "r0" + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure grace period = 1801 on RR and restart ospf .") + grace_period_1801 = "01005e00000570708bd051ef080045c0005cbeb10000015907d111010101e00000050204004801010101000000009714000000000000000000000000000100010209030000000101010180000001c8e9002c000100040000016800020001010000000003000411010101" + gracelsa_sent = scapy_send_raw_packet(tgen, topo, "r1", intf1, grace_period_1801) + + step("Verify R0 does not enter helper mode.") + input_dict = {"activeRestarterCnt": 1} + dut = "r0" + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict, expected=False) + assert ( + result is not True + ), "Testcase {} : Failed. DUT entered helper role " " \n Error: {}".format( + tc_name, result + ) + + delete_ospf() + + write_test_footer(tc_name) + + +def test_ospf_gr_helper_tc8_p1(request): + """ + Test ospf gr helper + + Verify helper functionality when dut is helping RR and new grace lsa + is received from RR. + """ + 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, intf, intf1, pkt + + step("Bring up the base config as per the topology") + step("Enable GR") + reset_config_on_routers(tgen) + ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True) + assert ( + ospf_covergence is True + ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence) + ospf_gr_r0 = { + "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r0) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ospf_gr_r1 = { + "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}} + } + result = create_router_ospf(tgen, topo, ospf_gr_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + input_dict = {"supportedGracePeriod": 1800} + dut = "r0" + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that DUT enters into helper mode.") + + input_dict = {"activeRestarterCnt": 1} + gracelsa_sent = False + repeat = 0 + dut = "r0" + while not gracelsa_sent and repeat < Iters: + gracelsa_sent = scapy_send_raw_packet(tgen, topo, "r1", intf1, pkt) + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + if isinstance(result, str): + repeat += 1 + gracelsa_sent = False + + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Send the Grace LSA again to DUT when RR is in GR.") + input_dict = {"activeRestarterCnt": 1} + gracelsa_sent = False + repeat = 0 + dut = "r0" + while not gracelsa_sent and repeat < Iters: + gracelsa_sent = scapy_send_raw_packet(tgen, topo, "r1", intf1, pkt) + result = verify_ospf_gr_helper(tgen, topo, dut, input_dict) + if isinstance(result, str): + repeat += 1 + gracelsa_sent = False + + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + delete_ospf() + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf index 9a68635568..e1e2bfb99a 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf +++ b/tests/topotests/ospf_topo1_vrf/r1/ospfd.conf @@ -3,7 +3,7 @@ hostname r1 password zebra log file /tmp/r1-ospfd.log ! -router ospf vrf r1-cust1 +router ospf vrf r1-ospf-cust1 ospf router-id 10.0.255.1 redistribute kernel redistribute connected diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt index 134a10a454..d617ab36d9 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r1/ospfroute.txt @@ -1,4 +1,4 @@ -VRF Name: r1-cust1 +VRF Name: r1-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [10] area: 0.0.0.0 directly attached to r1-eth0 diff --git a/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt index 083d77126c..4f7fd699cf 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt +++ b/tests/topotests/ospf_topo1_vrf/r1/ospfroute_down.txt @@ -1,4 +1,4 @@ -VRF Name: r1-cust1 +VRF Name: r1-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [10] area: 0.0.0.0 directly attached to r1-eth0 diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebra.conf b/tests/topotests/ospf_topo1_vrf/r1/zebra.conf index e826793657..e100d3b121 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/zebra.conf +++ b/tests/topotests/ospf_topo1_vrf/r1/zebra.conf @@ -7,10 +7,10 @@ hostname r1 password zebra log file /tmp/r1-zebra.log ! -interface r1-eth0 vrf r1-cust1 +interface r1-eth0 vrf r1-ospf-cust1 ip address 10.0.1.1/24 ! -interface r1-eth1 vrf r1-cust1 +interface r1-eth1 vrf r1-ospf-cust1 ip address 10.0.3.2/24 ! ip forwarding diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt index d72aa3b8e5..979af20c59 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r1/zebraroute.txt @@ -1,4 +1,4 @@ -VRF r1-cust1: +VRF r1-ospf-cust1: O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt index 5ea6bdc04d..ec99fad762 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt +++ b/tests/topotests/ospf_topo1_vrf/r1/zebraroutedown.txt @@ -1,4 +1,4 @@ -VRF r1-cust1: +VRF r1-ospf-cust1: O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf index ad481a996d..c1984276f4 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf +++ b/tests/topotests/ospf_topo1_vrf/r2/ospfd.conf @@ -4,7 +4,7 @@ password zebra log file /tmp/r2-ospfd.log ! ! -router ospf vrf r2-cust1 +router ospf vrf r2-ospf-cust1 ospf router-id 10.0.255.2 redistribute kernel redistribute connected diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt index a49cb77249..89763ff733 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r2/ospfroute.txt @@ -1,4 +1,4 @@ -VRF Name: r2-cust1 +VRF Name: r2-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [20] area: 0.0.0.0 via 10.0.3.2, r2-eth1 diff --git a/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt index 2227bedf07..d946f02dfd 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt +++ b/tests/topotests/ospf_topo1_vrf/r2/ospfroute_down.txt @@ -1,4 +1,4 @@ -VRF Name: r2-cust1 +VRF Name: r2-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [20] area: 0.0.0.0 via 10.0.3.2, r2-eth1 diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebra.conf b/tests/topotests/ospf_topo1_vrf/r2/zebra.conf index 8dcb713da6..6ff72d1267 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/zebra.conf +++ b/tests/topotests/ospf_topo1_vrf/r2/zebra.conf @@ -3,10 +3,10 @@ hostname r2 password zebra log file /tmp/r2-zebra.log ! -interface r2-eth0 vrf r2-cust1 +interface r2-eth0 vrf r2-ospf-cust1 ip address 10.0.2.1/24 ! -interface r2-eth1 vrf r2-cust1 +interface r2-eth1 vrf r2-ospf-cust1 ip address 10.0.3.3/24 ! ip forwarding diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt index ce5e5f3bab..df66e92abc 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r2/zebraroute.txt @@ -1,4 +1,4 @@ -VRF r2-cust1: +VRF r2-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt index 157811ec77..4afc354ca7 100644 --- a/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt +++ b/tests/topotests/ospf_topo1_vrf/r2/zebraroutedown.txt @@ -1,4 +1,4 @@ -VRF r2-cust1: +VRF r2-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf b/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf index d5214f734e..b73d547e3e 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf +++ b/tests/topotests/ospf_topo1_vrf/r3/ospfd.conf @@ -4,7 +4,7 @@ password zebra log file /tmp/r3-ospfd.log ! ! -router ospf vrf r3-cust1 +router ospf vrf r3-ospf-cust1 ospf router-id 10.0.255.3 redistribute kernel redistribute connected diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt b/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt index 3b16bfbd55..917702b14c 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r3/ospfroute.txt @@ -1,4 +1,4 @@ -VRF Name: r3-cust1 +VRF Name: r3-ospf-cust1 ============ OSPF network routing table ============ N 10.0.1.0/24 [20] area: 0.0.0.0 via 10.0.3.2, r3-eth0 diff --git a/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt b/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt index 39beac7a73..966185e495 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt +++ b/tests/topotests/ospf_topo1_vrf/r3/ospfroute_down.txt @@ -1,4 +1,4 @@ -VRF Name: r3-cust1 +VRF Name: r3-ospf-cust1 ============ OSPF network routing table ============ N 10.0.10.0/24 [10] area: 0.0.0.0 directly attached to r3-eth1 diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebra.conf b/tests/topotests/ospf_topo1_vrf/r3/zebra.conf index b548694330..1534150048 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/zebra.conf +++ b/tests/topotests/ospf_topo1_vrf/r3/zebra.conf @@ -3,10 +3,10 @@ hostname r3 password zebra log file /tmp/r3-zebra.log ! -interface r3-eth0 vrf r3-cust1 +interface r3-eth0 vrf r3-ospf-cust1 ip address 10.0.3.1/24 ! -interface r3-eth1 vrf r3-cust1 +interface r3-eth1 vrf r3-ospf-cust1 ip address 10.0.10.1/24 ! ip forwarding diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt b/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt index f40b7b09af..b435c2ebe5 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt +++ b/tests/topotests/ospf_topo1_vrf/r3/zebraroute.txt @@ -1,4 +1,4 @@ -VRF r3-cust1: +VRF r3-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r3-eth0, weight 1, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r3-eth0, weight 1, XX:XX:XX O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt b/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt index 89cd6f56c4..f30a4be6c6 100644 --- a/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt +++ b/tests/topotests/ospf_topo1_vrf/r3/zebraroutedown.txt @@ -1,4 +1,4 @@ -VRF r3-cust1: +VRF r3-ospf-cust1: O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX diff --git a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py b/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py index e2cb7bff03..713a65a812 100644 --- a/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py +++ b/tests/topotests/ospf_topo1_vrf/test_ospf_topo1_vrf.py @@ -100,17 +100,17 @@ def setup_module(mod): logger.info("Testing with VRF Namespace support") cmds = [ - "if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi", - "ip netns add {0}-cust1", - "ip link set dev {0}-eth0 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth0 up", - "ip link set dev {0}-eth1 netns {0}-cust1", - "ip netns exec {0}-cust1 ifconfig {0}-eth1 up", + "if [ -e /var/run/netns/{0}-ospf-cust1 ] ; then ip netns del {0}-ospf-cust1 ; fi", + "ip netns add {0}-ospf-cust1", + "ip link set dev {0}-eth0 netns {0}-ospf-cust1", + "ip netns exec {0}-ospf-cust1 ip link set {0}-eth0 up", + "ip link set dev {0}-eth1 netns {0}-ospf-cust1", + "ip netns exec {0}-ospf-cust1 ip link set {0}-eth1 up", ] for rname, router in router_list.items(): - # create VRF rx-cust1 and link rx-eth0 to rx-cust1 + # create VRF rx-ospf-cust1 and link rx-eth0 to rx-ospf-cust1 for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) @@ -137,9 +137,9 @@ def teardown_module(mod): # move back rx-eth0 to default VRF # delete rx-vrf cmds = [ - "ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1", - "ip netns exec {0}-cust1 ip link set {0}-eth1 netns 1", - "ip netns delete {0}-cust1", + "ip netns exec {0}-ospf-cust1 ip link set {0}-eth0 netns 1", + "ip netns exec {0}-ospf-cust1 ip link set {0}-eth1 netns 1", + "ip netns delete {0}-ospf-cust1", ] router_list = tgen.routers() @@ -152,11 +152,11 @@ def teardown_module(mod): # Shared test function to validate expected output. def compare_show_ip_route_vrf(rname, expected): """ - Calls 'show ip ospf vrf [rname]-cust1 route' for router `rname` and compare the obtained + Calls 'show ip ospf vrf [rname]-ospf-cust1 route' for router `rname` and compare the obtained result with the expected output. """ tgen = get_topogen() - vrf_name = "{0}-cust1".format(rname) + vrf_name = "{0}-ospf-cust1".format(rname) current = topotest.ip4_route_zebra(tgen.gears[rname], vrf_name) ret = topotest.difflines( current, expected, title1="Current output", title2="Expected output" @@ -182,7 +182,7 @@ def test_ospf_convergence(): test_func = partial( topotest.router_output_cmp, router, - "show ip ospf vrf {0}-cust1 route".format(rname), + "show ip ospf vrf {0}-ospf-cust1 route".format(rname), expected, ) result, diff = topotest.run_and_expect(test_func, "", count=160, wait=0.5) @@ -220,13 +220,13 @@ def test_ospf_json(): for rname, router in tgen.routers().items(): logger.info( - 'Comparing router "%s" "show ip ospf vrf %s-cust1 json" output', + 'Comparing router "%s" "show ip ospf vrf %s-ospf-cust1 json" output', router.name, router.name, ) expected = { - "{}-cust1".format(router.name): { - "vrfName": "{}-cust1".format(router.name), + "{}-ospf-cust1".format(router.name): { + "vrfName": "{}-ospf-cust1".format(router.name), "routerId": "10.0.255.{}".format(rname[1:]), "tosRoutesOnly": True, "rfc2328Conform": True, @@ -244,7 +244,7 @@ def test_ospf_json(): } # Area specific additional checks if router.name == "r1" or router.name == "r2" or router.name == "r3": - expected["{}-cust1".format(router.name)]["areas"]["0.0.0.0"] = { + expected["{}-ospf-cust1".format(router.name)]["areas"]["0.0.0.0"] = { "areaIfActiveCounter": 2, "areaIfTotalCounter": 2, "authentication": "authenticationNone", @@ -263,7 +263,7 @@ def test_ospf_json(): test_func = partial( topotest.router_json_cmp, router, - "show ip ospf vrf {0}-cust1 json".format(rname), + "show ip ospf vrf {0}-ospf-cust1 json".format(rname), expected, ) _, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) @@ -281,7 +281,7 @@ def test_ospf_link_down(): # Simulate a network down event on router3 switch3 interface. router3 = tgen.gears["r3"] topotest.interface_set_status( - router3, "r3-eth0", ifaceaction=False, vrf_name="r3-cust1" + router3, "r3-eth0", ifaceaction=False, vrf_name="r3-ospf-cust1" ) # Expect convergence on all routers @@ -295,7 +295,7 @@ def test_ospf_link_down(): test_func = partial( topotest.router_output_cmp, router, - "show ip ospf vrf {0}-cust1 route".format(rname), + "show ip ospf vrf {0}-ospf-cust1 route".format(rname), expected, ) result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) @@ -316,7 +316,7 @@ def test_ospf_link_down_kernel_route(): 'Checking OSPF IPv4 kernel routes in "%s" after link down', router.name ) - str = "{0}-cust1".format(router.name) + str = "{0}-ospf-cust1".format(router.name) reffile = os.path.join(CWD, "{}/zebraroutedown.txt".format(router.name)) expected = open(reffile).read() # Run test function until we get an result. Wait at most 60 seconds. diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index 56d112b7c3..778a710ee3 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -104,13 +104,19 @@ def test_zebra_kernel_admin_distance(): r1 = tgen.gears["r1"] # Route with 255/8192 metric - r1.run("ip route add 4.5.1.0/24 via 192.168.210.2 dev r1-eth0 metric 4278198272") + + distance = 255 + metric = 8192 + def makekmetric(dist, metric): + return (dist << 24) + metric + + r1.run("ip route add 4.5.1.0/24 via 192.168.210.2 dev r1-eth0 metric " + str(makekmetric(255, 8192))) # Route with 1/1 metric - r1.run("ip route add 4.5.2.0/24 via 192.168.211.2 dev r1-eth1 metric 16777217") + r1.run("ip route add 4.5.2.0/24 via 192.168.211.2 dev r1-eth1 metric " + str(makekmetric(1, 1))) # Route with 10/1 metric - r1.run("ip route add 4.5.3.0/24 via 192.168.212.2 dev r1-eth2 metric 167772161") + r1.run("ip route add 4.5.3.0/24 via 192.168.212.2 dev r1-eth2 metric " + str(makekmetric(10, 1))) # Same route with a 160/1 metric - r1.run("ip route add 4.5.3.0/24 via 192.168.213.2 dev r1-eth3 metric 2684354561") + r1.run("ip route add 4.5.3.0/24 via 192.168.213.2 dev r1-eth3 metric " + str(makekmetric(160, 1))) # Currently I believe we have a bug here with the same route and different # metric. That needs to be properly resolved. Making a note for @@ -194,93 +200,69 @@ def test_route_map_usage(): 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" + def check_static_map_correct_runs(): + actual = r1.vtysh_cmd("show route-map static") + actual = ("\n".join(actual.splitlines()) + "\n").rstrip() + return topotest.get_textdiff( + actual, + expected, + title1="Actual Route-map output", + title2="Expected Route-map output", + ) + ok, result = topotest.run_and_expect(check_static_map_correct_runs, "", count=5, wait=1) + assert ok, result 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" + def check_sharp_map_correct_runs(): + actual = r1.vtysh_cmd("show route-map sharp") + actual = ("\n".join(actual.splitlines()) + "\n").rstrip() + return topotest.get_textdiff( + actual, + expected, + title1="Actual Route-map output", + title2="Expected Route-map output", + ) + ok, result = topotest.run_and_expect(check_sharp_map_correct_runs, "", count=5, wait=1) + assert ok, result logger.info( "Add a extension to the static route-map to see the static route go away" + " and test that the routes installed are correct" ) + 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 check_routes_installed(): + 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) + return topotest.get_textdiff( + actual, expected, title1="Actual ip route show", title2="Expected ip route show" + ) + ok, result = topotest.run_and_expect(check_routes_installed, "", count=5, wait=1) + assert ok, result def test_memory_leak(): diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 998ead6b76..97637d23ab 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -830,7 +830,8 @@ int vtysh_mark_file(const char *filename) } else if ((prev_node == KEYCHAIN_KEY_NODE) && (tried == 1)) { vty_out(vty, "exit\n"); - } else if ((prev_node == BFD_PEER_NODE) + } else if ((prev_node == BFD_PEER_NODE + || prev_node == BFD_PROFILE_NODE) && (tried == 1)) { vty_out(vty, "exit\n"); } else if (((prev_node == SEGMENT_ROUTING_NODE) diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index 1ef70270f8..fd9b1ae387 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -67,11 +67,6 @@ static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, return CMD_WARNING_CONFIG_FAILED; } - if (gate_str == NULL) { - vty_out(vty, "%% No Nexthop Information\n"); - return CMD_WARNING_CONFIG_FAILED; - } - out_label = MPLS_LABEL_IMPLICIT_NULL; /* as initialization */ label = atoi(inlabel_str); if (!IS_MPLS_UNRESERVED_LABEL(label)) { @@ -91,18 +86,21 @@ static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, } in_label = label; + gtype = NEXTHOP_TYPE_BLACKHOLE; /* as initialization */ - /* Gateway is a IPv4 or IPv6 nexthop. */ - ret = inet_pton(AF_INET6, gate_str, &gate.ipv6); - if (ret == 1) - gtype = NEXTHOP_TYPE_IPV6; - else { - ret = inet_pton(AF_INET, gate_str, &gate.ipv4); + if (gate_str) { + /* Gateway is a IPv4 or IPv6 nexthop. */ + ret = inet_pton(AF_INET6, gate_str, &gate.ipv6); if (ret == 1) - gtype = NEXTHOP_TYPE_IPV4; + gtype = NEXTHOP_TYPE_IPV6; else { - vty_out(vty, "%% Invalid nexthop\n"); - return CMD_WARNING_CONFIG_FAILED; + ret = inet_pton(AF_INET, gate_str, &gate.ipv4); + if (ret == 1) + gtype = NEXTHOP_TYPE_IPV4; + else { + vty_out(vty, "%% Invalid nexthop\n"); + return CMD_WARNING_CONFIG_FAILED; + } } } |
