diff options
65 files changed, 12977 insertions, 1189 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 61bc0ade65..c3a0fdedf0 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -2,6 +2,7 @@ # git blame --ignore-revs-file .git-blame-ignore-revs <...> # or to make it permanent # git config blame.ignoreRevsFile .git-blame-ignore-revs +9fa6ec14737b94fdfb41539d96c7e4f84f3514b6 701a01920eee5431d2052aad92aefbdf50ac2139 bf2394f08bdc91a6cbd3784a1bfa3af3247bb06f 0157c327715ca367d13b7f02b2981f3484ccdeeb diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 0782461670..e0e16aaeeb 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -798,6 +798,38 @@ The following functionality is provided by graceful restart: <---------------------------------------------------------------------> +.. _bgp-GR-preserve-forwarding-state: + +BGP-GR Preserve-Forwarding State +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +BGP OPEN message carrying optional capabilities for Graceful Restart has +8 bit “Flags for Address Family” for given AFI and SAFI. This field contains +bit flags relating to routes that were advertised with the given AFI and SAFI. + +.. code-block:: frr + + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |F| Reserved | + +-+-+-+-+-+-+-+-+ + +The most significant bit is defined as the Forwarding State (F) bit, which +can be used to indicate whether the forwarding state for routes that were +advertised with the given AFI and SAFI has indeed been preserved during the +previous BGP restart. When set (value 1), the bit indicates that the +forwarding state has been preserved. +The remaining bits are reserved and MUST be set to zero by the sender and +ignored by the receiver. + +.. index:: bgp graceful-restart preserve-fw-state +.. clicmd:: bgp graceful-restart preserve-fw-state + +FRR gives us the option to enable/disable the "F" flag using this specific +vty command. However, it doesn't have the option to enable/disable +this flag only for specific AFI/SAFI i.e. when this command is used, it +applied to all the supported AFI/SAFI combinations for this peer. + .. _bgp-end-of-rib-message: End-of-RIB (EOR) message diff --git a/pathd/path_cli.c b/pathd/path_cli.c index a55e6ba406..8beb428135 100644 --- a/pathd/path_cli.c +++ b/pathd/path_cli.c @@ -550,7 +550,7 @@ DEFPY_NOSH( "Symbolic Name\n" "Dynamic Path\n") { - char xpath[XPATH_CANDIDATE_BASELEN]; + char xpath[XPATH_MAXLEN + XPATH_CANDIDATE_BASELEN]; int ret; snprintf(xpath, sizeof(xpath), "%s/candidate-path[preference='%s']", diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index ce7780ed49..8fd7ac9e3c 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -719,8 +719,51 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc, { bool is_valid = pnhc->valid; - if (!pnhi->nhr) /* It doesn't care about non-nexthop updates */ + /* + * If we have an interface down event, let's note that + * it is happening and find all the nexthops that depend + * on that interface. As that if we have an interface + * flapping fast enough it means that zebra might turn + * those nexthop tracking events into a no-update + * So let's search and do the right thing on the + * interface event. + */ + if (!pnhi->nhr && pnhi->ifp) { + struct connected *connected; + struct listnode *node; + struct prefix p; + + switch (pnhc->nexthop.type) { + case NEXTHOP_TYPE_BLACKHOLE: + goto done; + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV6_IFINDEX: + is_valid = if_is_up(pnhi->ifp); + goto done; + break; + case NEXTHOP_TYPE_IPV4: + p.family = AF_INET; + p.prefixlen = IPV4_MAX_BITLEN; + p.u.prefix4 = pnhc->nexthop.gate.ipv4; + break; + case NEXTHOP_TYPE_IPV6: + p.family = AF_INET6; + p.prefixlen = IPV6_MAX_BITLEN; + memcpy(&p.u.prefix6, &pnhc->nexthop.gate.ipv6, + sizeof(struct in6_addr)); + break; + } + + FOR_ALL_INTERFACES_ADDRESSES (pnhi->ifp, connected, node) { + if (prefix_match(connected->address, &p)) { + is_valid = if_is_up(pnhi->ifp); + break; + } + } goto done; + } switch (pnhi->nhr->prefix.family) { case AF_INET: @@ -983,7 +1026,6 @@ static void pbr_nht_nexthop_vrf_handle(struct hash_bucket *b, void *data) struct pbr_vrf *pbr_vrf = data; struct pbr_nht_individual pnhi = {}; - zlog_debug("pnhgc iterating"); hash_iterate(pnhgc->nhh, pbr_nht_clear_looked_at, NULL); memset(&pnhi, 0, sizeof(pnhi)); pnhi.pbr_vrf = pbr_vrf; @@ -1097,6 +1139,7 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b, { struct pbr_nexthop_group_cache *pnhgc = b->data; struct pbr_nht_individual pnhi = {}; + struct nexthop_group nhg = {}; bool old_valid; old_valid = pnhgc->valid; @@ -1111,6 +1154,15 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b, */ pnhgc->valid = pnhi.valid; + pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc); + + if (pnhgc->valid) + pbr_nht_install_nexthop_group(pnhgc, nhg); + else + pbr_nht_uninstall_nexthop_group(pnhgc, nhg, 0); + + nexthops_free(nhg.nexthop); + if (old_valid != pnhgc->valid) pbr_map_check_nh_group_change(pnhgc->name); } 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 08378d9b58..ab9358408e 100644 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -1016,6 +1016,7 @@ def test_bgp_ipv6_summary(): # For debugging after starting FRR daemons, uncomment the next line # CLI(net) + def test_nht(): print("\n\n**** Test that nexthop tracking is at least nominally working ****\n") @@ -1026,13 +1027,16 @@ def test_nht(): expected = open(nhtFile).read().rstrip() expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) - actual = (net["r%s" %i].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()) + actual = net["r%s" % i].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip() actual = re.sub(r"fd [0-9][0-9]", "fd XX", actual) actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1) - diff = topotest.get_textdiff(actual, expected, - title1="Actual `show ip nht`", - title2="Expected `show ip nht`") + diff = topotest.get_textdiff( + actual, + expected, + title1="Actual `show ip nht`", + title2="Expected `show ip nht`", + ) if diff: assert 0, "r%s failed ip nht check:\n%s\n" % (i, diff) @@ -1043,19 +1047,23 @@ def test_nht(): expected = open(nhtFile).read().rstrip() expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) - actual = (net["r%s" %i].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()) + actual = net["r%s" % i].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip() actual = re.sub(r"fd [0-9][0-9]", "fd XX", actual) actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1) - diff = topotest.get_textdiff(actual, expected, - title1="Actual `show ip nht`", - title2="Expected `show ip nht`") + diff = topotest.get_textdiff( + actual, + expected, + title1="Actual `show ip nht`", + title2="Expected `show ip nht`", + ) if diff: assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i, diff) else: print("show ipv6 nht is ok\n") + def test_bgp_ipv4(): global fatal_error global net 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 595132214b..98a5033f53 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 @@ -74,7 +74,8 @@ def setup_module(mod): 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_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname)) diff --git a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py index b3b7256ac4..b701a0d61e 100644 --- a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py +++ b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py @@ -282,10 +282,26 @@ def test_BGP_config_with_invalid_ASN_p2(request): # Api call to modify AS number input_dict = { - "r1": {"bgp": {"local_as": 0,}}, - "r2": {"bgp": {"local_as": 0,}}, - "r3": {"bgp": {"local_as": 0,}}, - "r4": {"bgp": {"local_as": 64000,}}, + "r1": { + "bgp": { + "local_as": 0, + } + }, + "r2": { + "bgp": { + "local_as": 0, + } + }, + "r3": { + "bgp": { + "local_as": 0, + } + }, + "r4": { + "bgp": { + "local_as": 64000, + } + }, } result = modify_as_number(tgen, topo, input_dict) try: @@ -819,7 +835,11 @@ def test_bgp_with_loopback_interface(request): # Adding ['source_link'] = 'lo' key:value pair topo["routers"][routerN]["bgp"]["address_family"]["ipv4"]["unicast"][ "neighbor" - ][bgp_neighbor]["dest_link"] = {"lo": {"source_link": "lo",}} + ][bgp_neighbor]["dest_link"] = { + "lo": { + "source_link": "lo", + } + } # Creating configuration from JSON build_config_from_json(tgen, topo) diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py index 54a3c699f3..353df0684b 100644 --- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py +++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py @@ -273,8 +273,20 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type): "r3": { "bgp": { "address_family": { - "ipv4": {"unicast": {"maximum_paths": {"ebgp": ecmp_num,}}}, - "ipv6": {"unicast": {"maximum_paths": {"ebgp": ecmp_num,}}}, + "ipv4": { + "unicast": { + "maximum_paths": { + "ebgp": ecmp_num, + } + } + }, + "ipv6": { + "unicast": { + "maximum_paths": { + "ebgp": ecmp_num, + } + } + }, } } } @@ -303,7 +315,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type): input_dict_1, next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)], protocol=protocol, - count_only=True + count_only=True, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( @@ -312,9 +324,9 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type): write_test_footer(tc_name) - +@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"]) @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"]) -def test_ecmp_after_clear_bgp(request, test_type): +def test_ecmp_after_clear_bgp(request, ecmp_num, test_type): """ Verify BGP table and RIB in DUT after clear BGP routes and neighbors""" tc_name = request.node.name @@ -337,7 +349,7 @@ def test_ecmp_after_clear_bgp(request, test_type): addr_type, dut, input_dict_1, - next_hop=NEXT_HOPS[addr_type], + next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)], protocol=protocol, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( @@ -360,7 +372,7 @@ def test_ecmp_after_clear_bgp(request, test_type): addr_type, dut, input_dict_1, - next_hop=NEXT_HOPS[addr_type], + next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)], protocol=protocol, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( @@ -371,8 +383,8 @@ def test_ecmp_after_clear_bgp(request, test_type): def test_ecmp_remove_redistribute_static(request): - """ Verify routes are cleared from BGP and RIB table of DUT when - redistribute static configuration is removed.""" + """Verify routes are cleared from BGP and RIB table of DUT when + redistribute static configuration is removed.""" tc_name = request.node.name write_test_header(tc_name) @@ -481,8 +493,8 @@ def test_ecmp_remove_redistribute_static(request): @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"]) def test_ecmp_shut_bgp_neighbor(request, test_type): - """ Shut BGP neigbors one by one and verify BGP and routing table updated - accordingly in DUT """ + """Shut BGP neigbors one by one and verify BGP and routing table updated + accordingly in DUT""" tc_name = request.node.name write_test_header(tc_name) diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py index 73724ac069..2f73bdb1b8 100644 --- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py +++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py @@ -274,8 +274,20 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type): "r3": { "bgp": { "address_family": { - "ipv4": {"unicast": {"maximum_paths": {"ibgp": ecmp_num,}}}, - "ipv6": {"unicast": {"maximum_paths": {"ibgp": ecmp_num,}}}, + "ipv4": { + "unicast": { + "maximum_paths": { + "ibgp": ecmp_num, + } + } + }, + "ipv6": { + "unicast": { + "maximum_paths": { + "ibgp": ecmp_num, + } + } + }, } } } @@ -304,7 +316,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type): input_dict_1, next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)], protocol=protocol, - count_only=True + count_only=True, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( @@ -313,9 +325,9 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type): write_test_footer(tc_name) - +@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"]) @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"]) -def test_ecmp_after_clear_bgp(request, test_type): +def test_ecmp_after_clear_bgp(request, ecmp_num, test_type): """ Verify BGP table and RIB in DUT after clear BGP routes and neighbors""" tc_name = request.node.name @@ -338,7 +350,7 @@ def test_ecmp_after_clear_bgp(request, test_type): addr_type, dut, input_dict_1, - next_hop=NEXT_HOPS[addr_type], + next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)], protocol=protocol, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( @@ -361,7 +373,7 @@ def test_ecmp_after_clear_bgp(request, test_type): addr_type, dut, input_dict_1, - next_hop=NEXT_HOPS[addr_type], + next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)], protocol=protocol, ) assert result is True, "Testcase {} : Failed \n Error: {}".format( @@ -372,8 +384,8 @@ def test_ecmp_after_clear_bgp(request, test_type): def test_ecmp_remove_redistribute_static(request): - """ Verify routes are cleared from BGP and RIB table of DUT when - redistribute static configuration is removed.""" + """Verify routes are cleared from BGP and RIB table of DUT when + redistribute static configuration is removed.""" tc_name = request.node.name write_test_header(tc_name) @@ -482,8 +494,8 @@ def test_ecmp_remove_redistribute_static(request): @pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"]) def test_ecmp_shut_bgp_neighbor(request, test_type): - """ Shut BGP neigbors one by one and verify BGP and routing table updated - accordingly in DUT """ + """Shut BGP neigbors one by one and verify BGP and routing table updated + accordingly in DUT""" tc_name = request.node.name write_test_header(tc_name) diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py index 4c56d1a02d..6a24684649 100644 --- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py +++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py @@ -658,10 +658,11 @@ def test_evpn_mac(): assertmsg = '"{}" remote MAC content incorrect'.format(tor.name) assert result is None, assertmsg + def check_df_role(dut, esi, role): - ''' + """ Return error string if the df role on the dut is different - ''' + """ es_json = dut.vtysh_cmd("show evpn es %s json" % esi) es = json.loads(es_json) @@ -676,12 +677,13 @@ def check_df_role(dut, esi, role): return None + def test_evpn_df(): - ''' + """ 1. Check the DF role on all the PEs on rack-1. 2. Increase the DF preference on the non-DF and check if it becomes the DF winner. - ''' + """ tgen = get_topogen() @@ -720,10 +722,11 @@ def test_evpn_df(): # tgen.mininet_cli() + def check_protodown_rc(dut, protodown_rc): - ''' + """ check if specified protodown reason code is set - ''' + """ out = dut.vtysh_cmd("show evpn json") @@ -739,13 +742,14 @@ def check_protodown_rc(dut, protodown_rc): return None + def test_evpn_uplink_tracking(): - ''' + """ 1. Wait for access ports to come out of startup-delay 2. disable uplinks and check if access ports have been protodowned 3. enable uplinks and check if access ports have been moved out of protodown - ''' + """ tgen = get_topogen() @@ -778,6 +782,7 @@ def test_evpn_uplink_tracking(): assertmsg = '"{}" protodown rc incorrect'.format(dut_name) assert result is None, assertmsg + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py b/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py index 5098808d55..9a38158b2b 100755 --- a/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py +++ b/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py @@ -310,8 +310,10 @@ def ip_learn_test(tgen, host, local, remote, ip_addr): assertmsg = "local learned mac wrong type: {} ".format(mac_type) assert mac_type == "local", assertmsg - assertmsg = "learned address mismatch with configured address host: {} learned: {}".format( - ip_addr, learned_ip + assertmsg = ( + "learned address mismatch with configured address host: {} learned: {}".format( + ip_addr, learned_ip + ) ) assert ip_addr == learned_ip, assertmsg diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py index 607b036c6a..a9541a55c5 100644 --- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py +++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py @@ -238,9 +238,10 @@ def test_next_hop_attribute(request): result = verify_rib( tgen, addr_type, dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ( - "Testcase {} : Failed \n Error: " - "{} routes are not present in RIB".format(addr_type, tc_name) + assert ( + result is not True + ), "Testcase {} : Failed \n Error: " "{} routes are not present in RIB".format( + addr_type, tc_name ) # Configure next-hop-self to bgp neighbor diff --git a/tests/topotests/bgp-route-map/test_route_map_topo1.py b/tests/topotests/bgp-route-map/test_route_map_topo1.py index 1aa951edaa..0158e24d31 100644 --- a/tests/topotests/bgp-route-map/test_route_map_topo1.py +++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py @@ -807,7 +807,9 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request): "prefix_lists": "pf_list_2_{}".format(addr_type) } }, - "set": {"locPrf": 150,}, + "set": { + "locPrf": 150, + }, }, { "action": "permit", @@ -906,7 +908,17 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request): dut = "r3" protocol = "bgp" input_dict = { - "r3": {"route_maps": {"rmap_match_pf_list1": [{"set": {"metric": 50,}}],}} + "r3": { + "route_maps": { + "rmap_match_pf_list1": [ + { + "set": { + "metric": 50, + } + } + ], + } + } } static_routes = [NETWORK[adt][0]] @@ -1093,7 +1105,14 @@ def test_route_map_set_only_no_match_p0(request): input_dict_4 = { "r3": { "route_maps": { - "rmap_match_pf_1": [{"action": "permit", "set": {"metric": 50,}}] + "rmap_match_pf_1": [ + { + "action": "permit", + "set": { + "metric": 50, + }, + } + ] } } } @@ -1210,7 +1229,13 @@ def test_route_map_match_only_no_set_p0(request): "r1": { "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [ - {"action": "permit", "set": {"metric": 50, "locPrf": 150,}} + { + "action": "permit", + "set": { + "metric": 50, + "locPrf": 150, + }, + } ] } } diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py index 3056aa29f3..958eceba62 100644 --- a/tests/topotests/bgp-route-map/test_route_map_topo2.py +++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py @@ -268,12 +268,20 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): "prefix_lists": { "ipv4": { "pf_list_1_ipv4": [ - {"seqid": 10, "network": "any", "action": "permit",} + { + "seqid": 10, + "network": "any", + "action": "permit", + } ] }, "ipv6": { "pf_list_1_ipv6": [ - {"seqid": 10, "network": "any", "action": "permit",} + { + "seqid": 10, + "network": "any", + "action": "permit", + } ] }, } @@ -472,7 +480,11 @@ def test_modify_set_match_clauses_in_rmap_p0(): "prefix_lists": { "ipv4": { "pf_list_1_ipv4": [ - {"seqid": 10, "network": "any", "action": "permit",} + { + "seqid": 10, + "network": "any", + "action": "permit", + } ], "pf_list_2_ipv4": [ {"seqid": 10, "network": "any", "action": "permit"} @@ -480,7 +492,11 @@ def test_modify_set_match_clauses_in_rmap_p0(): }, "ipv6": { "pf_list_1_ipv6": [ - {"seqid": 10, "network": "any", "action": "permit",} + { + "seqid": 10, + "network": "any", + "action": "permit", + } ], "pf_list_2_ipv6": [ {"seqid": 10, "network": "any", "action": "permit"} @@ -506,7 +522,9 @@ def test_modify_set_match_clauses_in_rmap_p0(): "prefix_lists": "pf_list_1_{}".format(addr_type) } }, - "set": {"locPrf": 150,}, + "set": { + "locPrf": 150, + }, } ], "rmap_match_pf_2_{}".format(addr_type): [ @@ -666,7 +684,9 @@ def test_modify_set_match_clauses_in_rmap_p0(): "prefix_lists": "pf_list_1_{}".format(addr_type) } }, - "set": {"locPrf": 1000,}, + "set": { + "locPrf": 1000, + }, } ], "rmap_match_pf_2_{}".format(addr_type): [ @@ -816,12 +836,20 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): "prefix_lists": { "ipv4": { "pf_list_1_ipv4": [ - {"seqid": 10, "network": "any", "action": "permit",} + { + "seqid": 10, + "network": "any", + "action": "permit", + } ] }, "ipv6": { "pf_list_1_ipv6": [ - {"seqid": 100, "network": "any", "action": "permit",} + { + "seqid": 100, + "network": "any", + "action": "permit", + } ] }, } @@ -1090,7 +1118,9 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): "prefix_lists": "pf_list_1_{}".format(addr_type) } }, - "set": {"locPrf": 150,}, + "set": { + "locPrf": 150, + }, } ], "rmap_match_pf_2_{}".format(addr_type): [ @@ -1894,7 +1924,9 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1(): "prefix_lists": "pf_list_1_{}".format(addr_type) } }, - "set": {"locPrf": 150,}, + "set": { + "locPrf": 150, + }, } ] } @@ -1921,7 +1953,9 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1(): } } }, - "set": {"locPrf": 150,}, + "set": { + "locPrf": 150, + }, } ] } @@ -2048,7 +2082,9 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): "prefix_lists": "pf_list_1_{}".format(addr_type) } }, - "set": {"locPrf": 150,}, + "set": { + "locPrf": 150, + }, } ] } @@ -3505,7 +3541,9 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): "prefix_lists": "pf_list_1_{}".format(addr_type) } }, - "set": {"locPrf": 150,}, + "set": { + "locPrf": 150, + }, } ], "rmap_match_pf_2_{}".format(addr_type): [ diff --git a/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py index 36f1d8cd56..71f64e9b70 100644 --- a/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py @@ -90,7 +90,11 @@ def test_vrf_route_leak(): # Test DONNA VRF. expect = { - "10.0.0.0/24": [{"protocol": "connected",}], + "10.0.0.0/24": [ + { + "protocol": "connected", + } + ], "10.0.1.0/24": [ {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} ], @@ -111,11 +115,19 @@ def test_vrf_route_leak(): "10.0.0.0/24": [ {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} ], - "10.0.1.0/24": [{"protocol": "connected",}], + "10.0.1.0/24": [ + { + "protocol": "connected", + } + ], "10.0.2.0/24": [ {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} ], - "10.0.3.0/24": [{"protocol": "connected",}], + "10.0.3.0/24": [ + { + "protocol": "connected", + } + ], } test_func = partial( diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index bc821bd7a0..5f3809c2b3 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -753,41 +753,71 @@ def test_bgp_delayopen_without(): pytest.skip(tgen.errors) # part 1: no delay r1 <=> no delay r4 - logger.info("Starting optional test of BGP functionality without DelayOpenTimer enabled to establish a reference for following tests") + logger.info( + "Starting optional test of BGP functionality without DelayOpenTimer enabled to establish a reference for following tests" + ) # 1.1 enable peering shutdown logger.info("Enable shutdown of peering between r1 and r4") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"') - tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"') + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"' + ) # 1.2 wait for peers to shut down (poll output) for router_num in [1, 4]: - logger.info("Checking BGP summary after enabling shutdown of peering on r{}".format(router_num)) + logger.info( + "Checking BGP summary after enabling shutdown of peering on r{}".format( + router_num + ) + ) router = tgen.gears["r{}".format(router_num)] - reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)) + reffile = os.path.join( + CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num) + ) expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=3, wait=1) assertmsg = "BGP session on r{} did not shut down peer".format(router_num) assert res is None, assertmsg # 1.3 disable peering shutdown logger.info("Disable shutdown of peering between r1 and r4") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"') - tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"') + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"' + ) # 1.4 wait for peers to establish connection (poll output) for router_num in [1, 4]: - logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num)) + logger.info( + "Checking BGP summary after disabling shutdown of peering on r{}".format( + router_num + ) + ) router = tgen.gears["r{}".format(router_num)] - reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)) + reffile = os.path.join( + CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num) + ) expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=5, wait=1) - assertmsg = "BGP session on r{} did not establish a connection with peer".format(router_num) + assertmsg = ( + "BGP session on r{} did not establish a connection with peer".format( + router_num + ) + ) assert res is None, assertmsg - #tgen.mininet_cli() + # tgen.mininet_cli() # end test_bgp_delayopen_without @@ -800,65 +830,107 @@ def test_bgp_delayopen_singular(): pytest.skip(tgen.errors) # part 2: delay 240s r1 <=> no delay r4 - logger.info("Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on one side of the peering") + logger.info( + "Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on one side of the peering" + ) # 2.1 enable peering shutdown logger.info("Enable shutdown of peering between r1 and r4") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"') - tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"') + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"' + ) # 2.2 wait for peers to shut down (poll output) for router_num in [1, 4]: - logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num)) + logger.info( + "Checking BGP summary after disabling shutdown of peering on r{}".format( + router_num + ) + ) router = tgen.gears["r{}".format(router_num)] - reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)) + reffile = os.path.join( + CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num) + ) expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=3, wait=1) assertmsg = "BGP session on r{} did not shut down peer".format(router_num) assert res is None, assertmsg # 2.3 set delayopen on R1 to 240 logger.info("Setting DelayOpenTime for neighbor r4 to 240 seconds on r1") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 timers delayopen 240"') + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 timers delayopen 240"' + ) # 2.4 check config (poll output) logger.info("Checking BGP neighbor configuration after setting DelayOpenTime on r1") router = tgen.gears["r1"] reffile = os.path.join(CWD, "r1/bgp_delayopen_neighbor.json") expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show bgp neighbors json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show bgp neighbors json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=3, wait=1) assertmsg = "BGP session on r1 failed to set DelayOpenTime for r4" assert res is None, assertmsg # 2.5 disable peering shutdown logger.info("Disable shutdown of peering between r1 and r4") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"') - tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"') + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"' + ) # 2.6 wait for peers to establish connection (poll output) for router_num in [1, 4]: - logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num)) + logger.info( + "Checking BGP summary after disabling shutdown of peering on r{}".format( + router_num + ) + ) router = tgen.gears["r{}".format(router_num)] - reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)) + reffile = os.path.join( + CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num) + ) expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=5, wait=1) - assertmsg = "BGP session on r{} did not establish a connection with peer".format(router_num) + assertmsg = ( + "BGP session on r{} did not establish a connection with peer".format( + router_num + ) + ) assert res is None, assertmsg # 2.7 unset delayopen on R1 logger.info("Disabling DelayOpenTimer for neighbor r4 on r1") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 timers delayopen"') + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 timers delayopen"' + ) # 2.8 check config (poll output) - logger.info("Checking BGP neighbor configuration after disabling DelayOpenTimer on r1") - delayopen_cfg = tgen.net["r1"].cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"').rstrip() + logger.info( + "Checking BGP neighbor configuration after disabling DelayOpenTimer on r1" + ) + delayopen_cfg = ( + tgen.net["r1"] + .cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"') + .rstrip() + ) assertmsg = "BGP session on r1 failed disable DelayOpenTimer for peer r4" assert delayopen_cfg == "", assertmsg - #tgen.mininet_cli() + # tgen.mininet_cli() # end test_bgp_delayopen_singular @@ -870,67 +942,119 @@ def test_bgp_delayopen_dual(): pytest.skip(tgen.errors) # part 3: delay 60s R2 <=> delay 30s R5 - logger.info("Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on both sides of the peering with different timer intervals") + logger.info( + "Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on both sides of the peering with different timer intervals" + ) # 3.1 enable peering shutdown logger.info("Enable shutdown of peering between r2 and r5") - tgen.net["r2"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 shutdown"') - tgen.net["r5"].cmd('vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 shutdown"') + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 shutdown"' + ) + tgen.net["r5"].cmd( + 'vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 shutdown"' + ) # 3.2 wait for peers to shut down (pool output) for router_num in [2, 5]: - logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num)) + logger.info( + "Checking BGP summary after disabling shutdown of peering on r{}".format( + router_num + ) + ) router = tgen.gears["r{}".format(router_num)] - reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)) + reffile = os.path.join( + CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num) + ) expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=3, wait=1) assertmsg = "BGP session on r{} did not shut down peer".format(router_num) assert res is None, assertmsg # 3.3 set delayopen on R2 to 60s and on R5 to 30s logger.info("Setting DelayOpenTime for neighbor r5 to 60 seconds on r2") - tgen.net["r2"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 timers delayopen 60"') + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 timers delayopen 60"' + ) logger.info("Setting DelayOpenTime for neighbor r2 to 30 seconds on r5") - tgen.net["r5"].cmd('vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 timers delayopen 30"') + tgen.net["r5"].cmd( + 'vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 timers delayopen 30"' + ) # 3.4 check config (poll output) for router_num in [2, 5]: - logger.info("Checking BGP neighbor configuration after setting DelayOpenTime on r{}i".format(router_num)) + logger.info( + "Checking BGP neighbor configuration after setting DelayOpenTime on r{}i".format( + router_num + ) + ) router = tgen.gears["r{}".format(router_num)] - reffile = os.path.join(CWD, "r{}/bgp_delayopen_neighbor.json".format(router_num)) + reffile = os.path.join( + CWD, "r{}/bgp_delayopen_neighbor.json".format(router_num) + ) expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show bgp neighbors json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show bgp neighbors json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=3, wait=1) assertmsg = "BGP session on r{} failed to set DelayOpenTime".format(router_num) assert res is None, assertmsg ## 3.5 disable peering shutdown logger.info("Disable shutdown of peering between r2 and r5") - tgen.net["r2"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 shutdown"') - tgen.net["r5"].cmd('vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 shutdown"') + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 shutdown"' + ) + tgen.net["r5"].cmd( + 'vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 shutdown"' + ) ## 3.6 wait for peers to reach connect or active state (poll output) delay_start = int(time.time()) for router_num in [2, 5]: - logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num)) + logger.info( + "Checking BGP summary after disabling shutdown of peering on r{}".format( + router_num + ) + ) router = tgen.gears["r{}".format(router_num)] - reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_connect.json".format(router_num)) + reffile = os.path.join( + CWD, "r{}/bgp_delayopen_summary_connect.json".format(router_num) + ) expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=3, wait=1) - assertmsg = "BGP session on r{} did not enter Connect state with peer".format(router_num) + assertmsg = "BGP session on r{} did not enter Connect state with peer".format( + router_num + ) assert res is None, assertmsg ## 3.7 wait for peers to establish connection (poll output) for router_num in [2, 5]: - logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num)) + logger.info( + "Checking BGP summary after disabling shutdown of peering on r{}".format( + router_num + ) + ) router = tgen.gears["r{}".format(router_num)] - reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)) + reffile = os.path.join( + CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num) + ) expected = json.loads(open(reffile).read()) - test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp summary json", expected + ) _, res = topotest.run_and_expect(test_func, None, count=35, wait=1) - assertmsg = "BGP session on r{} did not establish a connection with peer".format(router_num) + assertmsg = ( + "BGP session on r{} did not establish a connection with peer".format( + router_num + ) + ) assert res is None, assertmsg delay_stop = int(time.time()) @@ -939,18 +1063,32 @@ def test_bgp_delayopen_dual(): # 3.8 unset delayopen on R2 and R5 logger.info("Disabling DelayOpenTimer for neighbor r5 on r2") - tgen.net["r2"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 timers delayopen"') + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 timers delayopen"' + ) logger.info("Disabling DelayOpenTimer for neighbor r2 on r5") - tgen.net["r5"].cmd('vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 timers delayopen"') + tgen.net["r5"].cmd( + 'vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 timers delayopen"' + ) # 3.9 check config (poll output) for router_num in [2, 5]: - logger.info("Checking BGP neighbor configuration after disabling DelayOpenTimer on r{}".format(router_num)) - delayopen_cfg = tgen.net["r{}".format(router_num)].cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"').rstrip() - assertmsg = "BGP session on r{} failed disable DelayOpenTimer".format(router_num) + logger.info( + "Checking BGP neighbor configuration after disabling DelayOpenTimer on r{}".format( + router_num + ) + ) + delayopen_cfg = ( + tgen.net["r{}".format(router_num)] + .cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"') + .rstrip() + ) + assertmsg = "BGP session on r{} failed disable DelayOpenTimer".format( + router_num + ) assert delayopen_cfg == "", assertmsg - #tgen.mininet_cli() + # tgen.mininet_cli() # end test_bgp_delayopen_dual diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py index 097b654e77..94fd17e012 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py @@ -316,7 +316,9 @@ def test_BGP_GR_TC_46_p1(request): input_dict = { "r1": { "bgp": { - "graceful-restart": {"graceful-restart": True,}, + "graceful-restart": { + "graceful-restart": True, + }, "address_family": { "ipv4": { "unicast": { @@ -1184,8 +1186,8 @@ def test_BGP_GR_TC_53_p1(request): def test_BGP_GR_TC_4_p0(request): """ - Test Objective : Verify that the restarting node sets "R" bit while sending the - BGP open messages after the node restart, only if GR is enabled. + Test Objective : Verify that the restarting node sets "R" bit while sending the + BGP open messages after the node restart, only if GR is enabled. """ tgen = get_topogen() @@ -1368,9 +1370,9 @@ def test_BGP_GR_TC_4_p0(request): def test_BGP_GR_TC_5_1_2_p1(request): """ - Test Objective : Verify if restarting node resets R bit in BGP open message - during normal BGP session flaps as well, even when GR restarting mode is enabled. - Here link flap happen due to interface UP/DOWN. + Test Objective : Verify if restarting node resets R bit in BGP open message + during normal BGP session flaps as well, even when GR restarting mode is enabled. + Here link flap happen due to interface UP/DOWN. """ tgen = get_topogen() @@ -1815,8 +1817,8 @@ def test_BGP_GR_TC_6_1_2_p1(request): def test_BGP_GR_TC_8_p1(request): """ - Test Objective : Verify that restarting nodes set "F" bit while sending - the BGP open messages after it restarts, only when BGP GR is enabled. + Test Objective : Verify that restarting nodes set "F" bit while sending + the BGP open messages after it restarts, only when BGP GR is enabled. """ tgen = get_topogen() @@ -1959,8 +1961,8 @@ def test_BGP_GR_TC_8_p1(request): def test_BGP_GR_TC_17_p1(request): """ - Test Objective : Verify that only GR helper routers keep the stale - route entries, not any GR disabled router. + Test Objective : Verify that only GR helper routers keep the stale + route entries, not any GR disabled router. """ tgen = get_topogen() @@ -2145,8 +2147,8 @@ def test_BGP_GR_TC_17_p1(request): def test_BGP_GR_TC_19_p1(request): """ - Test Objective : Verify that GR helper routers keeps all the routes received - from restarting node if both the routers are configured as GR restarting node. + Test Objective : Verify that GR helper routers keeps all the routes received + from restarting node if both the routers are configured as GR restarting node. """ tgen = get_topogen() @@ -2325,8 +2327,8 @@ def test_BGP_GR_TC_19_p1(request): def test_BGP_GR_TC_20_p1(request): """ - Test Objective : Verify that GR helper routers delete all the routes - received from a node if both the routers are configured as GR helper node. + Test Objective : Verify that GR helper routers delete all the routes + received from a node if both the routers are configured as GR helper node. """ tgen = get_topogen() tc_name = request.node.name @@ -3090,8 +3092,8 @@ def test_BGP_GR_TC_31_2_p1(request): def test_BGP_GR_TC_9_p1(request): """ - Test Objective : Verify that restarting nodes reset "F" bit while sending - the BGP open messages after it's restarts, when BGP GR is **NOT** enabled. + Test Objective : Verify that restarting nodes reset "F" bit while sending + the BGP open messages after it's restarts, when BGP GR is **NOT** enabled. """ tgen = get_topogen() @@ -3264,8 +3266,8 @@ def test_BGP_GR_TC_9_p1(request): def test_BGP_GR_TC_17_p1(request): """ - Test Objective : Verify that only GR helper routers keep the stale - route entries, not any GR disabled router. + Test Objective : Verify that only GR helper routers keep the stale + route entries, not any GR disabled router. """ tgen = get_topogen() @@ -3467,7 +3469,13 @@ def test_BGP_GR_TC_43_p1(request): step("Configure R1 and R2 as GR restarting node in global level") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -3560,7 +3568,13 @@ def test_BGP_GR_TC_43_p1(request): step("Verify on R2 that R1 doesn't advertise any GR capabilities") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart-disable": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -3659,7 +3673,13 @@ def test_BGP_GR_TC_43_p1(request): step("Verify on R2 that R1 advertises GR capabilities as a restarting node") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -3779,7 +3799,13 @@ def test_BGP_GR_TC_44_p1(request): step("Verify on R2 that R1 advertises GR capabilities as a helper node") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart-helper": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -3849,7 +3875,13 @@ def test_BGP_GR_TC_44_p1(request): start_router_daemons(tgen, "r2", ["bgpd"]) input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}} + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart-disable": True, + } + } + } } configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") @@ -3857,7 +3889,13 @@ def test_BGP_GR_TC_44_p1(request): step("Verify on R2 that R1 doesn't advertise any GR capabilities") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart-disable": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -3941,7 +3979,13 @@ def test_BGP_GR_TC_44_p1(request): step("Verify on R2 that R1 advertises GR capabilities as a helper node") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart-helper": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -4108,14 +4152,28 @@ def test_BGP_GR_TC_45_p1(request): start_router_daemons(tgen, "r1", ["bgpd"]) - input_dict = {"r1": {"bgp": {"graceful-restart": {"graceful-restart": False,}}}} + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": False, + } + } + } + } configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") step("Verify on R2 that R1 advertises GR capabilities as a helper node") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart-helper": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -4199,14 +4257,28 @@ def test_BGP_GR_TC_45_p1(request): start_router_daemons(tgen, "r2", ["bgpd"]) - input_dict = {"r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}} + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + } + } configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") step("Verify on R2 that R1 advertises GR capabilities as a restarting node") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -4307,7 +4379,9 @@ def test_BGP_GR_TC_46_p1(request): input_dict = { "r1": { "bgp": { - "graceful-restart": {"graceful-restart": True,}, + "graceful-restart": { + "graceful-restart": True, + }, "address_family": { "ipv4": { "unicast": { @@ -4559,7 +4633,9 @@ def test_BGP_GR_TC_47_p1(request): input_dict = { "r1": { "bgp": { - "graceful-restart": {"graceful-restart": True,}, + "graceful-restart": { + "graceful-restart": True, + }, "address_family": { "ipv4": { "unicast": { @@ -4698,7 +4774,13 @@ def test_BGP_GR_TC_47_p1(request): step("Verify on R2 that R1 still advertises GR capabilities as a restarting node") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, } @@ -4814,7 +4896,9 @@ def test_BGP_GR_TC_48_p1(request): input_dict = { "r1": { "bgp": { - "graceful-restart": {"graceful-restart": True,}, + "graceful-restart": { + "graceful-restart": True, + }, "address_family": { "ipv4": { "unicast": { @@ -4960,7 +5044,13 @@ def test_BGP_GR_TC_48_p1(request): step("Verify on R2 that R1 advertises GR capabilities as a restarting node") input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, "r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, } diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py index 6926121a6b..2ddeab13f6 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py @@ -456,7 +456,9 @@ def test_BGP_GR_TC_3_p0(request): input_dict = { "r1": { "bgp": { - "graceful-restart": {"disable-eor": True,}, + "graceful-restart": { + "disable-eor": True, + }, "address_family": { "ipv4": { "unicast": { @@ -2095,7 +2097,10 @@ def test_BGP_GR_chaos_33_p1(request): "ipv4": { "unicast": { "advertise_networks": [ - {"network": "200.0.20.1/32", "no_of_network": 2,} + { + "network": "200.0.20.1/32", + "no_of_network": 2, + } ] } }, @@ -2207,13 +2212,13 @@ def test_BGP_GR_chaos_33_p1(request): else: next_hop_6 = NEXT_HOP_6[1] - result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6, - expected=False) - assert result is not True,\ - "Testcase {} :Failed \n Error {}". \ - format(tc_name, result) - logger.info(" Expected behavior: {}".\ - format(result)) + result = verify_rib( + tgen, addr_type, dut, input_dict_2, next_hop_6, expected=False + ) + assert result is not True, "Testcase {} :Failed \n Error {}".format( + tc_name, result + ) + logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 4] : Start BGPd daemon on R1 and R4..") @@ -3960,7 +3965,13 @@ def test_BGP_GR_21_p2(request): } } }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}, + "r2": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, } configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py index 9c0355a3e9..c2858a4bd0 100644 --- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py @@ -2132,7 +2132,11 @@ def test_large_community_lists_with_rmap_match_regex(request): { "action": "permit", "seq_id": "10", - "match": {"large_community_list": {"id": "ALL",},}, + "match": { + "large_community_list": { + "id": "ALL", + }, + }, } ] } @@ -2208,7 +2212,11 @@ def test_large_community_lists_with_rmap_match_regex(request): { "action": "permit", "seq_id": "20", - "match": {"large_community_list": {"id": "EXP_ALL",},}, + "match": { + "large_community_list": { + "id": "EXP_ALL", + }, + }, } ] } 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 9703cf8d57..d34446e2ee 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 @@ -95,7 +95,7 @@ from lib.common_config import ( kill_router_daemons, start_router_daemons, stop_router, - start_router + start_router, ) from lib.topolog import logger @@ -129,7 +129,7 @@ LOOPBACK_2 = { "ipv4": "20.20.20.20/32", "ipv6": "20::20:20/128", "ipv4_mask": "255.255.255.255", - "ipv6_mask": None + "ipv6_mask": None, } MAX_PATHS = 2 @@ -724,16 +724,40 @@ def test_vrf_with_multiple_links_p1(request): "local_as": "200", "vrf": "RED_A", "address_family": { - "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}}, - "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}}, + "ipv4": { + "unicast": { + "maximum_paths": { + "ebgp": MAX_PATHS, + } + } + }, + "ipv6": { + "unicast": { + "maximum_paths": { + "ebgp": MAX_PATHS, + } + } + }, }, }, { "local_as": "200", "vrf": "BLUE_A", "address_family": { - "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}}, - "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}}, + "ipv4": { + "unicast": { + "maximum_paths": { + "ebgp": MAX_PATHS, + } + } + }, + "ipv6": { + "unicast": { + "maximum_paths": { + "ebgp": MAX_PATHS, + } + } + }, }, }, ] @@ -2148,7 +2172,7 @@ def test_restart_bgpd_daemon_p1(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) result = verify_bgp_convergence(tgen, topo) - assert result is True, "Testcase () :Failed\n Error {}". format(tc_name, result) + assert result is True, "Testcase () :Failed\n Error {}".format(tc_name, result) step("Kill BGPd daemon on R1.") kill_router_daemons(tgen, "r1", ["bgpd"]) diff --git a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py index 6d7131e1e5..ceac84709b 100644 --- a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py +++ b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py @@ -101,7 +101,11 @@ def test_r1_receive_and_advertise_prefix_sid_type1(): "prefix": prefix, "advertisedTo": {"10.0.0.101": {}, "10.0.0.102": {}}, "paths": [ - {"valid": True, "remoteLabel": remoteLabel, "labelIndex": labelIndex,} + { + "valid": True, + "remoteLabel": remoteLabel, + "labelIndex": labelIndex, + } ], } return topotest.json_cmp(output, expected) 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 3af944473d..3f9009967d 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 @@ -1042,9 +1042,10 @@ def test_next_hop_with_recursive_lookup_p1(request): next_hop=next_hop, expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "Route is still present \n Error : {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format( + tc_name, result ) step("Re-apply redistribution on R4.") @@ -1125,9 +1126,10 @@ def test_next_hop_with_recursive_lookup_p1(request): next_hop=next_hop, expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "Route is still present \n Error : {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format( + tc_name, result ) shutdown_bringup_interface(tgen, "r3", intf_r3_r4, True) @@ -1182,9 +1184,10 @@ def test_next_hop_with_recursive_lookup_p1(request): next_hop=next_hop, expected=False, ) - assert result is not True, ( - "Testcase {} : Failed \n " - "Route is still present \n Error : {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format( + tc_name, result ) shutdown_bringup_interface(tgen, "r4", intf_r4_r3, True) @@ -2101,8 +2104,20 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request): "r4": { "bgp": { "address_family": { - "ipv4": {"unicast": {"maximum_paths": {"ebgp": 1,}}}, - "ipv6": {"unicast": {"maximum_paths": {"ebgp": 1,}}}, + "ipv4": { + "unicast": { + "maximum_paths": { + "ebgp": 1, + } + } + }, + "ipv6": { + "unicast": { + "maximum_paths": { + "ebgp": 1, + } + } + }, } } } @@ -2131,8 +2146,20 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request): "r4": { "bgp": { "address_family": { - "ipv4": {"unicast": {"maximum_paths": {"ebgp": 2,}}}, - "ipv6": {"unicast": {"maximum_paths": {"ebgp": 2,}}}, + "ipv4": { + "unicast": { + "maximum_paths": { + "ebgp": 2, + } + } + }, + "ipv6": { + "unicast": { + "maximum_paths": { + "ebgp": 2, + } + } + }, } } } diff --git a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py index 0fabd90341..0467bf1bfb 100644 --- a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py +++ b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py @@ -415,9 +415,10 @@ def test_route_summarisation_with_summary_only_p1(request): result = verify_rib( tgen, addr_type, "r3", input_static, protocol="bgp", expected=False ) - assert result is not True, ( - "Testcase : Failed \n " - "Routes are still present \n Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase : Failed \n " "Routes are still present \n Error: {}".format( + tc_name, result ) result = verify_rib(tgen, addr_type, "r1", input_static_agg, protocol="bgp") @@ -614,7 +615,9 @@ def test_route_summarisation_with_summary_only_p1(request): addr_type: { "unicast": { "advertise_networks": [ - {"network": NETWORK_4_1[addr_type],} + { + "network": NETWORK_4_1[addr_type], + } ] } } @@ -1014,7 +1017,11 @@ def test_route_summarisation_with_as_set_p1(request): assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - for pfx, seq_id, network, in zip([6, 7], [60, 70], [NETWORK_3_1, NETWORK_4_1]): + for ( + pfx, + seq_id, + network, + ) in zip([6, 7], [60, 70], [NETWORK_3_1, NETWORK_4_1]): prefix_list = { "r1": { "prefix_lists": { diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py index cf8be5f44f..c75055c26f 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -56,6 +56,7 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) + def setup_module(mod): tgen = Topogen(TemplateTopo, mod.__name__) tgen.start_topology() @@ -114,6 +115,7 @@ def test_bgp_route(): assertmsg = '"r3" JSON output mismatches' assert result is None, assertmsg + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py index 9106c163cd..6e7495d929 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py @@ -943,9 +943,10 @@ def test_modify_route_map_match_set_clauses_p1(request): } result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n Error : Routes are still " - "present {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n Error : Routes are still " "present {}".format( + tc_name, result ) write_test_footer(tc_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 67edcae90e..6f80ffd1aa 100755 --- a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py @@ -62,7 +62,7 @@ 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, '../')) +sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 # Import topogen and topotest helpers @@ -76,8 +76,10 @@ 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) @@ -85,59 +87,58 @@ class TemplateTopo(Topo): # # Define FRR Routers # - for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']: + for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: 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['rt2'], nodeif="eth-rt3") - switch.add_link(tgen.gears['rt3'], nodeif="eth-rt2") - switch = tgen.add_switch('s3') - switch.add_link(tgen.gears['rt1'], nodeif="eth-rt3") - switch.add_link(tgen.gears['rt3'], nodeif="eth-rt1") - switch = tgen.add_switch('s4') - switch.add_link(tgen.gears['rt1'], nodeif="eth-rt4") - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt1") - switch = tgen.add_switch('s5') - switch.add_link(tgen.gears['rt1'], nodeif="eth-rt5") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt1") - switch = tgen.add_switch('s6') - switch.add_link(tgen.gears['rt1'], nodeif="eth-rt6") - switch.add_link(tgen.gears['rt6'], nodeif="eth-rt1") - switch = tgen.add_switch('s7') - switch.add_link(tgen.gears['rt2'], nodeif="eth-rt7") - switch.add_link(tgen.gears['rt7'], nodeif="eth-rt2") - switch = tgen.add_switch('s8') - switch.add_link(tgen.gears['rt3'], nodeif="eth-rt7") - switch.add_link(tgen.gears['rt7'], nodeif="eth-rt3") - switch = tgen.add_switch('s9') - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt7") - switch.add_link(tgen.gears['rt7'], nodeif="eth-rt4") - switch = tgen.add_switch('s10') - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt7") - switch.add_link(tgen.gears['rt7'], nodeif="eth-rt5") - switch = tgen.add_switch('s11') - switch.add_link(tgen.gears['rt6'], nodeif="eth-rt7") - switch.add_link(tgen.gears['rt7'], nodeif="eth-rt6") + 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["rt2"], nodeif="eth-rt3") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt2") + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1") + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["rt1"], nodeif="eth-rt4") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt1") + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["rt1"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt1") + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["rt1"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt1") + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt7") + switch.add_link(tgen.gears["rt7"], nodeif="eth-rt2") + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt7") + switch.add_link(tgen.gears["rt7"], nodeif="eth-rt3") + switch = tgen.add_switch("s9") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt7") + switch.add_link(tgen.gears["rt7"], nodeif="eth-rt4") + switch = tgen.add_switch("s10") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt7") + switch.add_link(tgen.gears["rt7"], nodeif="eth-rt5") + switch = tgen.add_switch("s11") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt7") + switch.add_link(tgen.gears["rt7"], nodeif="eth-rt6") # # Populate multi-dimensional dictionary containing all expected outputs # - files = ["show_ipv6_route.ref", - "show_yang_interface_isis_adjacencies.ref"] - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']: + files = ["show_ipv6_route.ref", "show_yang_interface_isis_adjacencies.ref"] + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: outputs[rname] = {} for step in range(1, 13 + 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) + filename = "{}/{}/step{}/{}".format(CWD, rname, step, file) outputs[rname][step][file] = open(filename).read() else: if rname != "rt1": @@ -146,20 +147,23 @@ class TemplateTopo(Topo): continue # Get diff relative to the previous step - filename = '{}/{}/step{}/{}.diff'.format(CWD, rname, step, file) + 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)) + 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() + def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) @@ -170,16 +174,15 @@ def setup_module(mod): # 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)) + 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)) + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) ) tgen.start_router() + def teardown_module(mod): "Teardown the pytest environment" tgen = get_topogen() @@ -187,6 +190,7 @@ def teardown_module(mod): # This function tears down the whole topology. tgen.stop_topology() + def router_compare_json_output(rname, command, reference): "Compare router JSON output" @@ -196,12 +200,12 @@ def router_compare_json_output(rname, command, reference): 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) + 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 # @@ -215,9 +219,13 @@ def test_isis_adjacencies_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']: - router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd", - outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: + 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_ipv6_step1(): logger.info("Test (step 1): verify IPv6 RIB") @@ -227,9 +235,11 @@ def test_rib_ipv6_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][1]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"] + ) + # # Step 2 @@ -248,16 +258,28 @@ def test_rib_ipv6_step2(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Disabling LFA protection on all rt1 interfaces') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute lfa"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "no isis fast-reroute lfa"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "no isis fast-reroute lfa"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt6" -c "no isis fast-reroute lfa"') + logger.info("Disabling LFA protection on all rt1 interfaces") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute lfa"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt4" -c "no isis fast-reroute lfa"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt5" -c "no isis fast-reroute lfa"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt6" -c "no isis fast-reroute lfa"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"] + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][2]["show_ipv6_route.ref"]) # # Step 3 @@ -276,16 +298,28 @@ def test_rib_ipv6_step3(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Re-enabling LFA protection on all rt1 interfaces') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute lfa"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "isis fast-reroute lfa"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "isis fast-reroute lfa"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt6" -c "isis fast-reroute lfa"') + logger.info("Re-enabling LFA protection on all rt1 interfaces") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute lfa"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt4" -c "isis fast-reroute lfa"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt5" -c "isis fast-reroute lfa"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt6" -c "isis fast-reroute lfa"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"] + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][3]["show_ipv6_route.ref"]) # # Step 4 @@ -304,12 +338,16 @@ def test_rib_ipv6_step4(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Disabling LFA load-sharing on rt1') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute load-sharing disable"') + logger.info("Disabling LFA load-sharing on rt1") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute load-sharing disable"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"] + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][4]["show_ipv6_route.ref"]) # # Step 5 @@ -328,12 +366,16 @@ def test_rib_ipv6_step5(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Re-enabling LFA load-sharing on rt1') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute load-sharing disable"') + logger.info("Re-enabling LFA load-sharing on rt1") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute load-sharing disable"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"] + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][5]["show_ipv6_route.ref"]) # # Step 6 @@ -352,12 +394,16 @@ def test_rib_ipv6_step6(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Limiting backup computation to critical priority prefixes only') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute priority-limit critical"') + logger.info("Limiting backup computation to critical priority prefixes only") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute priority-limit critical"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"] + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][6]["show_ipv6_route.ref"]) # # Step 7 @@ -377,13 +423,19 @@ def test_rib_ipv6_step7(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Configuring a prefix priority list') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "spf prefix-priority critical CRITICAL_DESTINATIONS"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"') + logger.info("Configuring a prefix priority list") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "spf prefix-priority critical CRITICAL_DESTINATIONS"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"] + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][7]["show_ipv6_route.ref"]) # # Step 8 @@ -402,14 +454,22 @@ def test_rib_ipv6_step8(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Reverting previous changes related to prefix priorities') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "no ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute priority-limit critical"') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf prefix-priority critical CRITICAL_DESTINATIONS"') + logger.info("Reverting previous changes related to prefix priorities") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "no ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute priority-limit critical"' + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no spf prefix-priority critical CRITICAL_DESTINATIONS"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"] + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][8]["show_ipv6_route.ref"]) # # Step 9 @@ -428,12 +488,16 @@ def test_rib_ipv6_step9(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Excluding eth-rt6 from LFA computation for eth-rt2\'s failure') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa exclude interface eth-rt6"') + logger.info("Excluding eth-rt6 from LFA computation for eth-rt2's failure") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa exclude interface eth-rt6"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"] + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][9]["show_ipv6_route.ref"]) # # Step 10 @@ -452,12 +516,20 @@ def test_rib_ipv6_step10(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Removing exclusion of eth-rt6 from LFA computation for eth-rt2\'s failure') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa exclude interface eth-rt6"') + logger.info( + "Removing exclusion of eth-rt6 from LFA computation for eth-rt2's failure" + ) + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa exclude interface eth-rt6"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, + "show ipv6 route isis json", + outputs[rname][10]["show_ipv6_route.ref"], + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][10]["show_ipv6_route.ref"]) # # Step 11 @@ -476,12 +548,18 @@ def test_rib_ipv6_step11(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Adding LFA tiebreaker: prefer node protecting backup path') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker node-protecting index 10"') + logger.info("Adding LFA tiebreaker: prefer node protecting backup path") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker node-protecting index 10"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, + "show ipv6 route isis json", + outputs[rname][11]["show_ipv6_route.ref"], + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][11]["show_ipv6_route.ref"]) # # Step 12 @@ -500,12 +578,18 @@ def test_rib_ipv6_step12(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Adding LFA tiebreaker: prefer backup path via downstream node') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker downstream index 20"') + logger.info("Adding LFA tiebreaker: prefer backup path via downstream node") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker downstream index 20"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, + "show ipv6 route isis json", + outputs[rname][12]["show_ipv6_route.ref"], + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][12]["show_ipv6_route.ref"]) # # Step 13 @@ -524,22 +608,29 @@ def test_rib_ipv6_step13(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Adding LFA tiebreaker: prefer backup path with lowest total metric') - tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker lowest-backup-metric index 30"') + logger.info("Adding LFA tiebreaker: prefer backup path with lowest total metric") + tgen.net["rt1"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker lowest-backup-metric index 30"' + ) + + for rname in ["rt1"]: + router_compare_json_output( + rname, + "show ipv6 route isis json", + outputs[rname][13]["show_ipv6_route.ref"], + ) - for rname in ['rt1']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][13]["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') + pytest.skip("Memory leak test/report is disabled") tgen.report_memory_leaks() -if __name__ == '__main__': + +if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) 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 514ea53552..a1263de8ad 100755 --- a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py @@ -74,7 +74,7 @@ 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, '../')) +sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 # Import topogen and topotest helpers @@ -88,8 +88,10 @@ 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) @@ -97,80 +99,85 @@ class TemplateTopo(Topo): # # Define FRR Routers # - for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: + for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: tgen.add_router(router) # # Define connections # - switch = tgen.add_switch('s1') - switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1") - switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1") - switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1") + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["rt1"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt2"], nodeif="eth-sw1") + switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1") - switch = tgen.add_switch('s2') - switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-1") - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-1") + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-1") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-1") - switch = tgen.add_switch('s3') - switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-2") - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-2") + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2") - switch = tgen.add_switch('s4') - switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-1") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-1") + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-1") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-1") - switch = tgen.add_switch('s5') - switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-2") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-2") + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-2") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-2") - switch = tgen.add_switch('s6') - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt5") - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt4") + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4") - switch = tgen.add_switch('s7') - switch.add_link(tgen.gears['rt4'], nodeif="eth-rt6") - switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4") + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4") - switch = tgen.add_switch('s8') - switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6") - switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5") + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6") + switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5") # # Populate multi-dimensional dictionary containing all expected outputs # - files = ["show_ip_route.ref", - "show_ipv6_route.ref", - "show_mpls_table.ref", - "show_yang_interface_isis_adjacencies.ref"] - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: + files = [ + "show_ip_route.ref", + "show_ipv6_route.ref", + "show_mpls_table.ref", + "show_yang_interface_isis_adjacencies.ref", + ] + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: outputs[rname] = {} for step in range(1, 9 + 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) + 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) + 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)) + 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() + def setup_module(mod): "Sets up the pytest environment" tgen = Topogen(TemplateTopo, mod.__name__) @@ -181,16 +188,15 @@ def setup_module(mod): # For all registered routers, load the zebra configuration file 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_ISIS, - os.path.join(CWD, '{}/isisd.conf'.format(rname)) + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) ) tgen.start_router() + def teardown_module(mod): "Teardown the pytest environment" tgen = get_topogen() @@ -198,6 +204,7 @@ def teardown_module(mod): # This function tears down the whole topology. tgen.stop_topology() + def router_compare_json_output(rname, command, reference): "Compare router JSON output" @@ -207,12 +214,12 @@ def router_compare_json_output(rname, command, reference): 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) + 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 # @@ -226,9 +233,13 @@ def test_isis_adjacencies_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd", - outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + 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") @@ -238,9 +249,11 @@ def test_rib_ipv4_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ip route isis json", - outputs[rname][1]["show_ip_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + 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") @@ -250,9 +263,11 @@ def test_rib_ipv6_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][1]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step1(): logger.info("Test (step 1): verify MPLS LIB") @@ -262,9 +277,11 @@ def test_mpls_lib_step1(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][1]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][1]["show_mpls_table.ref"] + ) + # # Step 2 @@ -283,12 +300,16 @@ def test_rib_ipv4_step2(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Disabling TI-LFA link protection on rt2\'s eth-sw1 interface') - tgen.net['rt2'].cmd('vtysh -c "conf t" -c "interface eth-sw1" -c "no isis fast-reroute ti-lfa"') + logger.info("Disabling TI-LFA link protection on rt2's eth-sw1 interface") + tgen.net["rt2"].cmd( + 'vtysh -c "conf t" -c "interface eth-sw1" -c "no isis fast-reroute ti-lfa"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][2]["show_ip_route.ref"] + ) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - 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") @@ -298,9 +319,11 @@ def test_rib_ipv6_step2(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][2]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step2(): logger.info("Test (step 2): verify MPLS LIB") @@ -310,9 +333,11 @@ def test_mpls_lib_step2(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][2]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][2]["show_mpls_table.ref"] + ) + # # Step 3 @@ -331,12 +356,16 @@ def test_rib_ipv4_step3(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Enabling TI-LFA link protection on rt2\'s eth-sw1 interface') - tgen.net['rt2'].cmd('vtysh -c "conf t" -c "interface eth-sw1" -c "isis fast-reroute ti-lfa"') + logger.info("Enabling TI-LFA link protection on rt2's eth-sw1 interface") + tgen.net["rt2"].cmd( + 'vtysh -c "conf t" -c "interface eth-sw1" -c "isis fast-reroute ti-lfa"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][3]["show_ip_route.ref"] + ) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - 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") @@ -346,9 +375,11 @@ def test_rib_ipv6_step3(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][3]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step3(): logger.info("Test (step 3): verify MPLS LIB") @@ -358,9 +389,11 @@ def test_mpls_lib_step3(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][3]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][3]["show_mpls_table.ref"] + ) + # # Step 4 @@ -384,12 +417,16 @@ def test_rib_ipv4_step4(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Disabling SR on rt4') - tgen.net['rt4'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing on"') + logger.info("Disabling SR on rt4") + tgen.net["rt4"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing on"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][4]["show_ip_route.ref"] + ) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - 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") @@ -399,9 +436,11 @@ def test_rib_ipv6_step4(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][4]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step4(): logger.info("Test (step 4): verify MPLS LIB") @@ -411,9 +450,11 @@ def test_mpls_lib_step4(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][4]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][4]["show_mpls_table.ref"] + ) + # # Step 5 @@ -432,12 +473,14 @@ def test_rib_ipv4_step5(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Enabling SR on rt4') - tgen.net['rt4'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing on"') + logger.info("Enabling SR on rt4") + tgen.net["rt4"].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing on"') + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][5]["show_ip_route.ref"] + ) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - 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") @@ -447,9 +490,11 @@ def test_rib_ipv6_step5(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][5]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step5(): logger.info("Test (step 5): verify MPLS LIB") @@ -459,9 +504,11 @@ def test_mpls_lib_step5(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][5]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][5]["show_mpls_table.ref"] + ) + # # Step 6 @@ -480,12 +527,16 @@ def test_rib_ipv4_step6(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Changing rt5\'s SRGB') - tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 30000 37999"') + logger.info("Changing rt5's SRGB") + tgen.net["rt5"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 30000 37999"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][6]["show_ip_route.ref"] + ) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - 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") @@ -495,9 +546,11 @@ def test_rib_ipv6_step6(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][6]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step6(): logger.info("Test (step 6): verify MPLS LIB") @@ -507,9 +560,11 @@ def test_mpls_lib_step6(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][6]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][6]["show_mpls_table.ref"] + ) + # # Step 7 @@ -529,13 +584,19 @@ def test_rib_ipv4_step7(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Deleting rt5\'s Prefix-SIDs') - tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 5.5.5.5/32 index 50"') - tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 2001:db8:1000::5/128 index 51"') + logger.info("Deleting rt5's Prefix-SIDs") + tgen.net["rt5"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 5.5.5.5/32 index 50"' + ) + tgen.net["rt5"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 2001:db8:1000::5/128 index 51"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][7]["show_ip_route.ref"] + ) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - 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") @@ -545,9 +606,11 @@ def test_rib_ipv6_step7(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][7]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step7(): logger.info("Test (step 7): verify MPLS LIB") @@ -557,9 +620,11 @@ def test_mpls_lib_step7(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][7]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][7]["show_mpls_table.ref"] + ) + # # Step 8 @@ -578,13 +643,19 @@ def test_rib_ipv4_step8(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Re-adding rt5\'s Prefix-SIDs') - tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 50"') - tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 51"') + logger.info("Re-adding rt5's Prefix-SIDs") + tgen.net["rt5"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 50"' + ) + tgen.net["rt5"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 51"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][8]["show_ip_route.ref"] + ) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - 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") @@ -594,9 +665,11 @@ def test_rib_ipv6_step8(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][8]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step8(): logger.info("Test (step 8): verify MPLS LIB") @@ -606,9 +679,11 @@ def test_mpls_lib_step8(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][8]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][8]["show_mpls_table.ref"] + ) + # # Step 9 @@ -628,13 +703,19 @@ def test_rib_ipv4_step9(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info('Re-adding rt5\'s Prefix-SIDs') - tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 500"') - tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 501"') + logger.info("Re-adding rt5's Prefix-SIDs") + tgen.net["rt5"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 500"' + ) + tgen.net["rt5"].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 501"' + ) + + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ip route isis json", outputs[rname][9]["show_ip_route.ref"] + ) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - 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") @@ -644,9 +725,11 @@ def test_rib_ipv6_step9(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show ipv6 route isis json", - outputs[rname][9]["show_ipv6_route.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"] + ) + def test_mpls_lib_step9(): logger.info("Test (step 9): verify MPLS LIB") @@ -656,19 +739,22 @@ def test_mpls_lib_step9(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']: - router_compare_json_output(rname, "show mpls table json", - outputs[rname][9]["show_mpls_table.ref"]) + for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + router_compare_json_output( + rname, "show mpls table json", outputs[rname][9]["show_mpls_table.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') + pytest.skip("Memory leak test/report is disabled") tgen.report_memory_leaks() -if __name__ == '__main__': + +if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py index 31adeafbf6..9822686dfc 100644 --- a/tests/topotests/ldp-topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py @@ -647,9 +647,11 @@ def test_zebra_ipv4_routingTable(): else: print("r%s ok" % i) - assert failures == 0, ( - "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" - % (i, diff) + assert ( + failures == 0 + ), "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" % ( + i, + diff, ) # Make sure that all daemons are running diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 0462cfbff8..68a7217dd6 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -21,6 +21,7 @@ from copy import deepcopy from time import sleep import traceback +import ipaddr import ipaddress import os import sys @@ -1615,8 +1616,6 @@ def clear_bgp(tgen, addr_type, router, vrf=None): else: run_frr_cmd(rnode, "clear bgp *") - sleep(5) - logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) @@ -2115,8 +2114,8 @@ def verify_bgp_attributes( errormsg(str) or True """ - logger.debug("Entering lib API: verify_bgp_attributes()") - for router, rnode in tgen.routers().items(): + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + for router, rnode in tgen.routers().iteritems(): if router != dut: continue @@ -2196,7 +2195,7 @@ def verify_bgp_attributes( ) return errormsg - logger.debug("Exiting lib API: verify_bgp_attributes()") + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return True @@ -2516,8 +2515,9 @@ def verify_best_path_as_per_admin_distance( return True -@retry(attempts=6, wait=2, return_is_str=True) -def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None): +@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2) +def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, +aspath=None, multi_nh=None): """ This API is to verify whether bgp rib has any matching route for a nexthop. @@ -2552,6 +2552,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None) additional_nexthops_in_required_nhs = [] list1 = [] list2 = [] + found_hops = [] for routerInput in input_dict.keys(): for router, rnode in router_list.items(): if router != dut: @@ -2618,44 +2619,73 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None) st_found = True found_routes.append(st_rt) - if next_hop: + if next_hop and multi_nh and st_found: if not isinstance(next_hop, list): next_hop = [next_hop] list1 = next_hop - found_hops = [ - rib_r["ip"] - for rib_r in rib_routes_json["routes"][st_rt][0][ - "nexthops" - ] - ] - list2 = found_hops - - missing_list_of_nexthops = set(list2).difference(list1) - additional_nexthops_in_required_nhs = set( - list1 - ).difference(list2) + for mnh in range( + 0, len(rib_routes_json["routes"][st_rt]) + ): + found_hops.append( + [ + rib_r["ip"] + for rib_r in rib_routes_json["routes"][ + st_rt + ][mnh]["nexthops"] + ] + ) + for mnh in found_hops: + for each_nh_in_multipath in mnh: + list2.append(each_nh_in_multipath) + if found_hops[0]: + missing_list_of_nexthops = set(list2).difference( + list1 + ) + additional_nexthops_in_required_nhs = set( + list1 + ).difference(list2) - if list2: - if additional_nexthops_in_required_nhs: - logger.info( - "Missing nexthop %s for route" - " %s in RIB of router %s\n", - additional_nexthops_in_required_nhs, - st_rt, - dut, - ) - errormsg = ( - "Nexthop {} is Missing for " - "route {} in RIB of router {}\n".format( + if list2: + if additional_nexthops_in_required_nhs: + logger.info( + "Missing nexthop %s for route" + " %s in RIB of router %s\n", additional_nexthops_in_required_nhs, st_rt, dut, ) - ) return errormsg else: nh_found = True + + elif next_hop and multi_nh is None: + if not isinstance(next_hop, list): + next_hop = [next_hop] + list1 = next_hop + found_hops = [rib_r["ip"] for rib_r in + rib_routes_json["routes"][ + st_rt][0]["nexthops"]] + list2 = found_hops + missing_list_of_nexthops = \ + set(list2).difference(list1) + additional_nexthops_in_required_nhs = \ + set(list1).difference(list2) + + if list2: + if additional_nexthops_in_required_nhs: + logger.info("Missing nexthop %s for route"\ + " %s in RIB of router %s\n", \ + additional_nexthops_in_required_nhs, \ + st_rt, dut) + errormsg=("Nexthop {} is Missing for "\ + "route {} in RIB of router {}\n".format( + additional_nexthops_in_required_nhs, + st_rt, dut)) + return errormsg + else: + nh_found = True + if aspath: found_paths = rib_routes_json["routes"][st_rt][0][ "path" @@ -3678,7 +3708,6 @@ def verify_attributes_for_evpn_routes( """ API to verify rd and rt value using "sh bgp l2vpn evpn 10.1.1.1" command. - Parameters ---------- * `tgen`: topogen object @@ -3692,7 +3721,6 @@ def verify_attributes_for_evpn_routes( * `ipLen` : IP prefix length * `rd_peer` : Peer name from which RD will be auto-generated * `rt_peer` : Peer name from which RT will be auto-generated - Usage ----- input_dict_1 = { @@ -4069,7 +4097,6 @@ def verify_evpn_routes( """ API to verify evpn routes using "sh bgp l2vpn evpn" command. - Parameters ---------- * `tgen`: topogen object @@ -4080,7 +4107,6 @@ def verify_evpn_routes( * `route_type` : Route type 5 is supported as of now * `EthTag` : Ethernet tag, by-default is 0 * `next_hop` : Prefered nexthop for the evpn routes - Usage ----- input_dict_1 = { @@ -4093,7 +4119,6 @@ def verify_evpn_routes( } } result = verify_evpn_routes(tgen, topo, input_dict) - Returns ------- errormsg(str) or True diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 6c24b6ddbb..70c4c061f8 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -37,7 +37,6 @@ import traceback import socket import ipaddress import platform - if sys.version_info[0] > 2: import configparser else: @@ -755,7 +754,7 @@ def start_topology(tgen, daemon=None): def stop_router(tgen, router): """ - Router"s current config would be saved to /etc/frr/ for each deamon + Router"s current config would be saved to /tmp/topotest/<suite>/<router> for each deamon and router and its deamons would be stopped. * `tgen` : topogen object @@ -774,7 +773,7 @@ def stop_router(tgen, router): def start_router(tgen, router): """ - Router will started and config would be loaded from /etc/frr/ for each + Router will started and config would be loaded from /tmp/topotest/<suite>/<router> for each deamon * `tgen` : topogen object @@ -1152,14 +1151,20 @@ def generate_ips(network, no_of_ips): mask = int(start_ipaddr.split("/")[1]) else: logger.debug("start_ipaddr {} must have a / in it".format(start_ipaddr)) - assert(0) + assert 0 addr_type = validate_ip_address(start_ip) if addr_type == "ipv4": - start_ip = ipaddress.IPv4Address(frr_unicode(start_ip)) + if start_ip == "0.0.0.0" and mask == 0 and no_of_ips == 1: + ipaddress_list.append("{}/{}".format(start_ip, mask)) + return ipaddress_list + start_ip = ipaddress.IPv4Address(unicode(start_ip)) step = 2 ** (32 - mask) if addr_type == "ipv6": - start_ip = ipaddress.IPv6Address(frr_unicode(start_ip)) + if start_ip == "0::0" and mask == 0 and no_of_ips == 1: + ipaddress_list.append("{}/{}".format(start_ip, mask)) + return ipaddress_list + start_ip = ipaddress.IPv6Address(unicode(start_ip)) step = 2 ** (128 - mask) next_ip = start_ip @@ -2240,6 +2245,51 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False): interface_set_status(router_list[dut], intf_name, ifaceaction) +def stop_router(tgen, router): + """ + Router's current config would be saved to /tmp/topotest/<suite>/<router> + for each deamon and router and its deamons would be stopped. + + * `tgen` : topogen object + * `router`: Device under test + """ + + router_list = tgen.routers() + + # Saving router config to /etc/frr, which will be loaded to router + # when it starts + router_list[router].vtysh_cmd("write memory") + + # Stop router + router_list[router].stop() + + +def start_router(tgen, router): + """ + Router will be started and config would be loaded from + /tmp/topotest/<suite>/<router> for each deamon + + * `tgen` : topogen object + * `router`: Device under test + """ + + logger.debug("Entering lib API: start_router") + + try: + router_list = tgen.routers() + + # Router and its deamons would be started and config would + # be loaded to router for each deamon from /etc/frr + router_list[router].start() + + except Exception as e: + errormsg = traceback.format_exc() + logger.error(errormsg) + return errormsg + + logger.debug("Exiting lib API: start_router()") + + def addKernelRoute( tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None ): @@ -2562,7 +2612,7 @@ def verify_rib( tag=None, metric=None, fib=None, - count_only=False + count_only=False, ): """ Data will be read from input_dict or input JSON file, API will generate @@ -2754,8 +2804,10 @@ def verify_rib( "Nexthops are missing for " "route {} in RIB of router {}: " "expected {}, found {}\n".format( - st_rt, dut, len(next_hop), - len(found_hops) + st_rt, + dut, + len(next_hop), + len(found_hops), ) ) return errormsg @@ -2802,7 +2854,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 @@ -2819,7 +2875,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 @@ -2868,7 +2928,9 @@ def verify_rib( for advertise_network_dict in advertise_network: if "vrf" in advertise_network_dict: - cmd = "{} vrf {} json".format(command, advertise_network_dict["vrf"]) + cmd = "{} vrf {} json".format( + command, advertise_network_dict["vrf"] + ) else: cmd = "{} json".format(command) @@ -2947,6 +3009,7 @@ def verify_rib( logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return True + @retry(attempts=6, wait=2, return_is_str=True) def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None): """ @@ -3327,7 +3390,12 @@ def verify_prefix_lists(tgen, input_dict): for addr_type in prefix_lists_addr: if not check_address_types(addr_type): continue - + # show ip prefix list + if addr_type == "ipv4": + cmd = "show ip prefix-list" + else: + cmd = "show {} prefix-list".format(addr_type) + show_prefix_list = run_frr_cmd(rnode, cmd) for prefix_list in prefix_lists_addr[addr_type].keys(): if prefix_list in show_prefix_list: errormsg = ( @@ -3550,7 +3618,6 @@ def verify_cli_json(tgen, input_dict): """ API to verify if JSON is available for clis command. - Parameters ---------- * `tgen`: topogen object @@ -3720,7 +3787,6 @@ def verify_vrf_vni(tgen, input_dict): """ API to verify vrf vni details using "show vrf vni json" command. - Parameters ---------- * `tgen`: topogen object diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 9f3d4841b0..5c7514a641 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -874,7 +874,11 @@ def verify_ospf_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 @@ -891,7 +895,11 @@ def verify_ospf_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 diff --git a/tests/topotests/lib/test/test_json.py b/tests/topotests/lib/test/test_json.py index b85e193d3b..7b3c8593cc 100755 --- a/tests/topotests/lib/test/test_json.py +++ b/tests/topotests/lib/test/test_json.py @@ -107,16 +107,25 @@ def test_json_intersect_multilevel_true(): dcomplete = { "i1": "item1", "i2": "item2", - "i3": {"i100": "item100",}, + "i3": { + "i100": "item100", + }, "i4": { - "i41": {"i411": "item411",}, - "i42": {"i421": "item421", "i422": "item422",}, + "i41": { + "i411": "item411", + }, + "i42": { + "i421": "item421", + "i422": "item422", + }, }, } dsub1 = { "i1": "item1", - "i3": {"i100": "item100",}, + "i3": { + "i100": "item100", + }, "i10": None, } dsub2 = { @@ -126,10 +135,36 @@ def test_json_intersect_multilevel_true(): } dsub3 = { "i2": "item2", - "i4": {"i41": {"i411": "item411",}, "i42": {"i422": "item422", "i450": None,}}, + "i4": { + "i41": { + "i411": "item411", + }, + "i42": { + "i422": "item422", + "i450": None, + }, + }, + } + dsub4 = { + "i2": "item2", + "i4": { + "i41": {}, + "i42": { + "i450": None, + }, + }, + } + dsub5 = { + "i2": "item2", + "i3": { + "i100": "item100", + }, + "i4": { + "i42": { + "i450": None, + } + }, } - dsub4 = {"i2": "item2", "i4": {"i41": {}, "i42": {"i450": None,}}} - dsub5 = {"i2": "item2", "i3": {"i100": "item100",}, "i4": {"i42": {"i450": None,}}} assert json_cmp(dcomplete, dsub1) is None assert json_cmp(dcomplete, dsub2) is None @@ -144,17 +179,26 @@ def test_json_intersect_multilevel_false(): dcomplete = { "i1": "item1", "i2": "item2", - "i3": {"i100": "item100",}, + "i3": { + "i100": "item100", + }, "i4": { - "i41": {"i411": "item411",}, - "i42": {"i421": "item421", "i422": "item422",}, + "i41": { + "i411": "item411", + }, + "i42": { + "i421": "item421", + "i422": "item422", + }, }, } # Incorrect sub-level value dsub1 = { "i1": "item1", - "i3": {"i100": "item00",}, + "i3": { + "i100": "item00", + }, "i10": None, } # Inexistent sub-level @@ -166,14 +210,41 @@ def test_json_intersect_multilevel_false(): # Inexistent sub-level value dsub3 = { "i1": "item1", - "i3": {"i100": None,}, + "i3": { + "i100": None, + }, } # Inexistent sub-sub-level value - dsub4 = {"i4": {"i41": {"i412": "item412",}, "i42": {"i421": "item421",}}} + dsub4 = { + "i4": { + "i41": { + "i412": "item412", + }, + "i42": { + "i421": "item421", + }, + } + } # Invalid sub-sub-level value - dsub5 = {"i4": {"i41": {"i411": "item411",}, "i42": {"i421": "item420000",}}} + dsub5 = { + "i4": { + "i41": { + "i411": "item411", + }, + "i42": { + "i421": "item420000", + }, + } + } # sub-sub-level should be value - dsub6 = {"i4": {"i41": {"i411": "item411",}, "i42": "foobar",}} + dsub6 = { + "i4": { + "i41": { + "i411": "item411", + }, + "i42": "foobar", + } + } assert json_cmp(dcomplete, dsub1) is not None assert json_cmp(dcomplete, dsub2) is not None @@ -187,7 +258,15 @@ def test_json_with_list_sucess(): "Test successful json comparisons that have lists." dcomplete = { - "list": [{"i1": "item 1", "i2": "item 2",}, {"i10": "item 10",},], + "list": [ + { + "i1": "item 1", + "i2": "item 2", + }, + { + "i10": "item 10", + }, + ], "i100": "item 100", } @@ -197,12 +276,19 @@ def test_json_with_list_sucess(): } # Test list correct list items dsub2 = { - "list": [{"i1": "item 1",},], + "list": [ + { + "i1": "item 1", + }, + ], "i100": "item 100", } # Test list correct list size dsub3 = { - "list": [{}, {},], + "list": [ + {}, + {}, + ], } assert json_cmp(dcomplete, dsub1) is None @@ -214,7 +300,15 @@ def test_json_with_list_failure(): "Test failed json comparisons that have lists." dcomplete = { - "list": [{"i1": "item 1", "i2": "item 2",}, {"i10": "item 10",},], + "list": [ + { + "i1": "item 1", + "i2": "item 2", + }, + { + "i10": "item 10", + }, + ], "i100": "item 100", } @@ -224,12 +318,20 @@ def test_json_with_list_failure(): } # Test list incorrect list items dsub2 = { - "list": [{"i1": "item 2",},], + "list": [ + { + "i1": "item 2", + }, + ], "i100": "item 100", } # Test list correct list size dsub3 = { - "list": [{}, {}, {},], + "list": [ + {}, + {}, + {}, + ], } assert json_cmp(dcomplete, dsub1) is not None @@ -241,20 +343,52 @@ def test_json_list_start_success(): "Test JSON encoded data that starts with a list that should succeed." dcomplete = [ - {"id": 100, "value": "abc",}, - {"id": 200, "value": "abcd",}, - {"id": 300, "value": "abcde",}, + { + "id": 100, + "value": "abc", + }, + { + "id": 200, + "value": "abcd", + }, + { + "id": 300, + "value": "abcde", + }, ] - dsub1 = [{"id": 100, "value": "abc",}] + dsub1 = [ + { + "id": 100, + "value": "abc", + } + ] - dsub2 = [{"id": 100, "value": "abc",}, {"id": 200, "value": "abcd",}] + dsub2 = [ + { + "id": 100, + "value": "abc", + }, + { + "id": 200, + "value": "abcd", + }, + ] - dsub3 = [{"id": 300, "value": "abcde",}] + dsub3 = [ + { + "id": 300, + "value": "abcde", + } + ] dsub4 = [] - dsub5 = [{"id": 100,}] + dsub5 = [ + { + "id": 100, + } + ] assert json_cmp(dcomplete, dsub1) is None assert json_cmp(dcomplete, dsub2) is None @@ -272,13 +406,44 @@ def test_json_list_start_failure(): {"id": 300, "value": "abcde"}, ] - dsub1 = [{"id": 100, "value": "abcd",}] + dsub1 = [ + { + "id": 100, + "value": "abcd", + } + ] - dsub2 = [{"id": 100, "value": "abc",}, {"id": 200, "value": "abc",}] + dsub2 = [ + { + "id": 100, + "value": "abc", + }, + { + "id": 200, + "value": "abc", + }, + ] - dsub3 = [{"id": 100, "value": "abc",}, {"id": 350, "value": "abcde",}] + dsub3 = [ + { + "id": 100, + "value": "abc", + }, + { + "id": 350, + "value": "abcde", + }, + ] - dsub4 = [{"value": "abcx",}, {"id": 300, "value": "abcde",}] + dsub4 = [ + { + "value": "abcx", + }, + { + "id": 300, + "value": "abcde", + }, + ] assert json_cmp(dcomplete, dsub1) is not None assert json_cmp(dcomplete, dsub2) is not None diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 86f06b2af7..7c52e824c1 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -336,7 +336,9 @@ class Topogen(object): for gear in self.gears.values(): errors += gear.stop() if len(errors) > 0: - logger.error("Errors found post shutdown - details follow: {}".format(errors)) + logger.error( + "Errors found post shutdown - details follow: {}".format(errors) + ) self.net.stop() diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py index f2fafa5e2a..0e59f90a20 100644 --- a/tests/topotests/lib/topojson.py +++ b/tests/topotests/lib/topojson.py @@ -96,6 +96,7 @@ def build_topo_from_json(tgen, topo): for router in listRouters: topo["routers"][router]["nextIfname"] = 0 + router_count = 0 while listRouters != []: curRouter = listRouters.pop(0) # Physical Interfaces @@ -116,13 +117,14 @@ def build_topo_from_json(tgen, topo): currRouter_lo_json = topo["routers"][curRouter]["links"][destRouterLink] # Loopback interfaces if "type" in data and data["type"] == "loopback": + router_count += 1 if ( "ipv4" in currRouter_lo_json and currRouter_lo_json["ipv4"] == "auto" ): currRouter_lo_json["ipv4"] = "{}{}.{}/{}".format( topo["lo_prefix"]["ipv4"], - number_to_row(curRouter), + router_count, number_to_column(curRouter), topo["lo_prefix"]["v4mask"], ) @@ -132,7 +134,7 @@ def build_topo_from_json(tgen, topo): ): currRouter_lo_json["ipv6"] = "{}{}:{}/{}".format( topo["lo_prefix"]["ipv6"], - number_to_row(curRouter), + router_count, number_to_column(curRouter), topo["lo_prefix"]["v6mask"], ) @@ -167,6 +169,14 @@ def build_topo_from_json(tgen, topo): destRouter, curRouter, topo["routers"][destRouter]["nextIfname"] ) + # add link interface + destRouter_link_json["peer-interface"] = "{}-{}-eth{}".format( + curRouter, destRouter, topo["routers"][curRouter]["nextIfname"] + ) + currRouter_link_json["peer-interface"] = "{}-{}-eth{}".format( + destRouter, curRouter, topo["routers"][destRouter]["nextIfname"] + ) + topo["routers"][curRouter]["nextIfname"] += 1 topo["routers"][destRouter]["nextIfname"] += 1 diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index d1e76866a7..ef0ac27118 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -609,8 +609,10 @@ def interface_set_status(node, ifacename, ifaceaction=False, vrf_name=None): ifacename, str_ifaceaction ) else: - cmd = 'vtysh -c "configure terminal" -c "interface {0} vrf {1}" -c "{2}"'.format( - ifacename, vrf_name, str_ifaceaction + cmd = ( + 'vtysh -c "configure terminal" -c "interface {0} vrf {1}" -c "{2}"'.format( + ifacename, vrf_name, str_ifaceaction + ) ) node.run(cmd) @@ -924,40 +926,44 @@ def checkAddressSanitizerError(output, router, component, logdir=""): ) if addressSanitizerLog: # Find Calling Test. Could be multiple steps back - testframe=sys._current_frames().values()[0] - level=0 + testframe = sys._current_frames().values()[0] + level = 0 while level < 10: - test=os.path.splitext(os.path.basename(testframe.f_globals["__file__"]))[0] + test = os.path.splitext( + os.path.basename(testframe.f_globals["__file__"]) + )[0] if (test != "topotest") and (test != "topogen"): # Found the calling test - callingTest=os.path.basename(testframe.f_globals["__file__"]) + callingTest = os.path.basename(testframe.f_globals["__file__"]) break - level=level+1 - testframe=testframe.f_back - if (level >= 10): + level = level + 1 + testframe = testframe.f_back + if level >= 10: # somehow couldn't find the test script. - callingTest="unknownTest" + callingTest = "unknownTest" # # Now finding Calling Procedure - level=0 + level = 0 while level < 20: - callingProc=sys._getframe(level).f_code.co_name - if ((callingProc != "processAddressSanitizerError") and - (callingProc != "checkAddressSanitizerError") and - (callingProc != "checkRouterCores") and - (callingProc != "stopRouter") and - (callingProc != "__stop_internal") and - (callingProc != "stop") and - (callingProc != "stop_topology") and - (callingProc != "checkRouterRunning") and - (callingProc != "check_router_running") and - (callingProc != "routers_have_failure")): + callingProc = sys._getframe(level).f_code.co_name + if ( + (callingProc != "processAddressSanitizerError") + and (callingProc != "checkAddressSanitizerError") + and (callingProc != "checkRouterCores") + and (callingProc != "stopRouter") + and (callingProc != "__stop_internal") + and (callingProc != "stop") + and (callingProc != "stop_topology") + and (callingProc != "checkRouterRunning") + and (callingProc != "check_router_running") + and (callingProc != "routers_have_failure") + ): # Found the calling test break - level=level+1 - if (level >= 20): + level = level + 1 + if level >= 20: # something wrong - couldn't found the calling test function - callingProc="unknownProc" + callingProc = "unknownProc" with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile: sys.stderr.write( "AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n" @@ -979,7 +985,6 @@ def checkAddressSanitizerError(output, router, component, logdir=""): addrSanFile.write("\n---------------\n") return - addressSanitizerError = re.search( "(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ", output ) @@ -989,16 +994,20 @@ def checkAddressSanitizerError(output, router, component, logdir=""): # No Address Sanitizer Error in Output. Now check for AddressSanitizer daemon file if logdir: - filepattern=logdir+"/"+router+"/"+component+".asan.*" - logger.debug("Log check for %s on %s, pattern %s\n" % (component, router, filepattern)) + filepattern = logdir + "/" + router + "/" + component + ".asan.*" + logger.debug( + "Log check for %s on %s, pattern %s\n" % (component, router, filepattern) + ) for file in glob.glob(filepattern): with open(file, "r") as asanErrorFile: - asanError=asanErrorFile.read() + asanError = asanErrorFile.read() addressSanitizerError = re.search( "(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ", asanError - ) + ) if addressSanitizerError: - processAddressSanitizerError(addressSanitizerError, asanError, router, component) + processAddressSanitizerError( + addressSanitizerError, asanError, router, component + ) return True return False @@ -1065,7 +1074,7 @@ class Router(Node): if self.logdir is None: cur_test = os.environ["PYTEST_CURRENT_TEST"] self.logdir = "/tmp/topotests/" + cur_test[ - cur_test.find("/")+1 : cur_test.find(".py") + cur_test.find("/") + 1 : cur_test.find(".py") ].replace("/", ".") # If the logdir is not created, then create it and set the @@ -1073,7 +1082,7 @@ class Router(Node): if not os.path.isdir(self.logdir): os.system("mkdir -p " + self.logdir + "/" + name) os.system("chmod -R go+rw /tmp/topotests") - # Erase logs of previous run + # Erase logs of previous run os.system("rm -rf " + self.logdir + "/" + name) self.daemondir = None 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 6d44d02e5e..2421b312d2 100644 --- a/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py +++ b/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py @@ -320,8 +320,10 @@ def test_ospf_link_down_kernel_route(): # Run test function until we get an result. Wait at most 60 seconds. test_func = partial(compare_show_ip_route_vrf, router.name, expected) result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5) - assertmsg = 'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format( - router.name, diff + assertmsg = ( + 'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format( + router.name, diff + ) ) assert result, assertmsg diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.py b/tests/topotests/ospf-topo1/test_ospf_topo1.py index 95193afb2a..24806dd8fc 100644 --- a/tests/topotests/ospf-topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf-topo1/test_ospf_topo1.py @@ -310,7 +310,10 @@ def test_ospf_json(): # r4 has more interfaces for area 0.0.0.1 if router.name == "r4": expected["areas"]["0.0.0.1"].update( - {"areaIfActiveCounter": 2, "areaIfTotalCounter": 2,} + { + "areaIfActiveCounter": 2, + "areaIfTotalCounter": 2, + } ) # router 3 has an additional area @@ -372,16 +375,25 @@ def test_ospf_link_down_kernel_route(): } if router.name == "r1" or router.name == "r2": expected.update( - {"10.0.10.0/24": None, "172.16.0.0/24": None, "172.16.1.0/24": None,} + { + "10.0.10.0/24": None, + "172.16.0.0/24": None, + "172.16.1.0/24": None, + } ) elif router.name == "r3" or router.name == "r4": expected.update( - {"10.0.1.0/24": None, "10.0.2.0/24": None,} + { + "10.0.1.0/24": None, + "10.0.2.0/24": None, + } ) # Route '10.0.3.0' is no longer available for r4 since it is down. if router.name == "r4": expected.update( - {"10.0.3.0/24": None,} + { + "10.0.3.0/24": None, + } ) assertmsg = 'OSPF IPv4 route mismatch in router "{}" after link down'.format( router.name @@ -443,12 +455,17 @@ def test_ospf6_link_down_kernel_route(): ) elif router.name == "r3" or router.name == "r4": expected.update( - {"2001:db8:1::/64": None, "2001:db8:2::/64": None,} + { + "2001:db8:1::/64": None, + "2001:db8:2::/64": None, + } ) # Route '2001:db8:3::/64' is no longer available for r4 since it is down. if router.name == "r4": expected.update( - {"2001:db8:3::/64": None,} + { + "2001:db8:3::/64": None, + } ) assertmsg = 'OSPF IPv6 route mismatch in router "{}" after link down'.format( router.name diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index 3b37b8a92f..5ef6b9b0be 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -252,7 +252,11 @@ def test_ospf_ecmp_tc16_p0(request): input_dict = { "r0": { "static_routes": [ - {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",} + { + "network": NETWORK["ipv4"][0], + "no_of_ip": 5, + "next_hop": "Null0", + } ] } } @@ -415,7 +419,11 @@ def test_ospf_ecmp_tc17_p0(request): input_dict = { "r0": { "static_routes": [ - {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",} + { + "network": NETWORK["ipv4"][0], + "no_of_ip": 5, + "next_hop": "Null0", + } ] } } diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index 04b1f4b878..88667a6ac8 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -197,6 +197,7 @@ def teardown_module(mod): # Test cases start here. # ################################## + def test_ospf_routemaps_functionality_tc19_p0(request): """ OSPF Route map - Verify OSPF route map support functionality. @@ -215,121 +216,92 @@ def test_ospf_routemaps_functionality_tc19_p0(request): "r0": { "static_routes": [ { - "network": NETWORK['ipv4'][0], + "network": NETWORK["ipv4"][0], "no_of_ip": 5, - "next_hop": 'Null0', + "next_hop": "Null0", } ] } } result = create_static_routes(tgen, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - ospf_red_r1 = { - "r0": { - "ospf": { - "redistribute": [{ - "redist_type": "static" - }] - } - } - } + 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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - dut = 'r1' - lsid = NETWORK['ipv4'][0].split("/")[0] - rid = routerids[0] - protocol = 'ospf' + dut = "r1" + lsid = NETWORK["ipv4"][0].split("/")[0] + rid = routerids[0] + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + 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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) ospf_red_r1 = { "r0": { - "ospf": { - "redistribute": [{ - "redist_type": "static", - "del_action": True - }] - } + "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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step( - 'Create prefix-list in R0 to permit 10.0.20.1/32 prefix &' - ' deny 10.0.20.2/32') + "Create prefix-list in R0 to permit 10.0.20.1/32 prefix &" " deny 10.0.20.2/32" + ) # Create ip prefix list pfx_list = { "r0": { "prefix_lists": { "ipv4": { - "pf_list_1_ipv4": [{ - "seqid": 10, - "network": NETWORK['ipv4'][0], - "action": "permit" - }, - { - "seqid": 11, - "network": "any", - "action": "deny" - } + "pf_list_1_ipv4": [ + { + "seqid": 10, + "network": NETWORK["ipv4"][0], + "action": "permit", + }, + {"seqid": 11, "network": "any", "action": "deny"}, ] } } } } result = create_prefix_lists(tgen, pfx_list) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Create route map routemaps = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ + "r0": { + "route_maps": { + "rmap_ipv4": [ + { "action": "permit", - "match": { - "ipv4": { - "prefix_lists": - "pf_list_1_ipv4" - } - } - }] - } + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + } + ] } + } } result = create_route_maps(tgen, routemaps) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step( "Configure route map rmap1 and redistribute static routes to" - " ospf using route map rmap1") + " ospf using route map rmap1" + ) ospf_red_r1 = { "r0": { "ospf": { - "redistribute": [{ - "redist_type": "static", - "route_map": "rmap_ipv4" - }] + "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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Change prefix rules to permit 10.0.20.2 and deny 10.0.20.1") # Create ip prefix list @@ -337,65 +309,54 @@ def test_ospf_routemaps_functionality_tc19_p0(request): "r0": { "prefix_lists": { "ipv4": { - "pf_list_1_ipv4": [{ - "seqid": 10, - "network": NETWORK['ipv4'][1], - "action": "permit" - }, - { - "seqid": 11, - "network": "any", - "action": "deny" - } + "pf_list_1_ipv4": [ + { + "seqid": 10, + "network": NETWORK["ipv4"][1], + "action": "permit", + }, + {"seqid": 11, "network": "any", "action": "deny"}, ] } } } } result = create_prefix_lists(tgen, pfx_list) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify that route 10.0.20.2 is allowed and 10.0.20.1 is denied.") - dut = 'r1' + dut = "r1" input_dict = { "r0": { "static_routes": [ - { - "network": NETWORK['ipv4'][1], - "no_of_ip": 1, - "next_hop": 'Null0' - } + {"network": NETWORK["ipv4"][1], "no_of_ip": 1, "next_hop": "Null0"} ] } } result = verify_ospf_rib(tgen, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + 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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) input_dict = { "r0": { "static_routes": [ - { - "network": NETWORK['ipv4'][0], - "no_of_ip": 1, - "next_hop": 'Null0' - } + {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0"} ] } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + tc_name, result + ) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - expected=False) + 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) + tc_name, result + ) step("Delete and reconfigure prefix list.") # Create ip prefix list @@ -403,114 +364,101 @@ def test_ospf_routemaps_functionality_tc19_p0(request): "r0": { "prefix_lists": { "ipv4": { - "pf_list_1_ipv4": [{ - "seqid": 10, - "network": NETWORK['ipv4'][1], - "action": "permit", - "delete": True - }, - { - "seqid": 11, - "network": "any", - "action": "deny", - "delete": True - } + "pf_list_1_ipv4": [ + { + "seqid": 10, + "network": NETWORK["ipv4"][1], + "action": "permit", + "delete": True, + }, + { + "seqid": 11, + "network": "any", + "action": "deny", + "delete": True, + }, ] } } } } result = create_prefix_lists(tgen, pfx_list) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) result = verify_prefix_lists(tgen, pfx_list) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) input_dict = { "r0": { "static_routes": [ - { - "network": NETWORK['ipv4'][0], - "no_of_ip": 5, - "next_hop": 'Null0' - } + {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0"} ] } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + tc_name, result + ) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - expected=False) + 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) + tc_name, result + ) pfx_list = { "r0": { "prefix_lists": { "ipv4": { - "pf_list_1_ipv4": [{ - "seqid": 10, - "network": NETWORK['ipv4'][1], - "action": "permit" - }, - { - "seqid": 11, - "network": "any", - "action": "deny" - } + "pf_list_1_ipv4": [ + { + "seqid": 10, + "network": NETWORK["ipv4"][1], + "action": "permit", + }, + {"seqid": 11, "network": "any", "action": "deny"}, ] } } } } result = create_prefix_lists(tgen, pfx_list) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify that route 10.0.20.2 is allowed and 10.0.20.1 is denied.") - dut = 'r1' + dut = "r1" input_dict = { "r0": { "static_routes": [ - { - "network": NETWORK['ipv4'][1], - "no_of_ip": 1, - "next_hop": 'Null0' - } + {"network": NETWORK["ipv4"][1], "no_of_ip": 1, "next_hop": "Null0"} ] } } result = verify_ospf_rib(tgen, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + 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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) input_dict = { "r0": { "static_routes": [ - { - "network": NETWORK['ipv4'][0], - "no_of_ip": 1, - "next_hop": 'Null0' - } + {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0"} ] } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + tc_name, result + ) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - expected=False) + 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) + tc_name, result + ) write_test_footer(tc_name) @@ -535,7 +483,11 @@ def test_ospf_routemaps_functionality_tc20_p0(request): input_dict = { "r0": { "static_routes": [ - {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",} + { + "network": NETWORK["ipv4"][0], + "no_of_ip": 5, + "next_hop": "Null0", + } ] } } @@ -663,318 +615,229 @@ def test_ospf_routemaps_functionality_tc21_p0(request): step( "Create static routes(10.0.20.1/32) in R1 and redistribute " - "to OSPF using route map.") + "to OSPF using route map." + ) # Create Static routes input_dict = { "r0": { "static_routes": [ { - "network": NETWORK['ipv4'][0], + "network": NETWORK["ipv4"][0], "no_of_ip": 5, - "next_hop": 'Null0', + "next_hop": "Null0", } ] } } result = create_static_routes(tgen, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + 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" - }] + "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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Create route map routemaps = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ - "action": "permit", - "seq_id": 10 - }] - } - } + "r0": {"route_maps": {"rmap_ipv4": [{"action": "permit", "seq_id": 10}]}} } result = create_route_maps(tgen, routemaps) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify that route is advertised to R2.") - dut = 'r1' - protocol = 'ospf' + dut = "r1" + protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + 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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Create route map routemaps = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ - "action": "permit", - "delete": True, - "seq_id": 10 - }] + "r0": { + "route_maps": { + "rmap_ipv4": [{"action": "permit", "delete": True, "seq_id": 10}] + } } } - } result = create_route_maps(tgen, routemaps) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - step(' Configure route map with set clause (set metric)') + step(" Configure route map with set clause (set metric)") # Create route map routemaps = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ - "action": "permit", - "set": { - "med": 123 - }, - "seq_id": 10 - }] + "r0": { + "route_maps": { + "rmap_ipv4": [{"action": "permit", "set": {"med": 123}, "seq_id": 10}] + } } } - } result = create_route_maps(tgen, routemaps) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify that configured metric is applied to ospf routes.") - dut = 'r1' - protocol = 'ospf' + dut = "r1" + protocol = "ospf" result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step( "Configure route map with match clause (match metric) with " - "some actions(change metric).") + "some actions(change metric)." + ) # Create route map routemaps = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ - "action": "permit", - "match": { - "med": 123 - }, - "set": { - "med": 150 - }, - "seq_id": 10 - }] + "r0": { + "route_maps": { + "rmap_ipv4": [ + { + "action": "permit", + "match": {"med": 123}, + "set": {"med": 150}, + "seq_id": 10, + } + ] + } } } - } result = create_route_maps(tgen, routemaps) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Configure route map with call clause") # Create ip prefix list input_dict_2 = { - 'r0': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' - }] - } + "r0": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [ + {"seqid": 10, "network": "any", "action": "permit"} + ] + } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Create route map input_dict_3 = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ - "action": "permit", - "match": { - "ipv4": { - "prefix_lists": "pf_list_1_ipv4" - } - }, - "set": { - "med": 150 - }, - "call": "rmap_match_pf_2_ipv4", - "seq_id": 10 - }], - "rmap_match_pf_2_ipv4": [{ - "action": "permit", - "match": { - "ipv4": { - "prefix_lists": "pf_list_1_ipv4" - } - }, - "set": { - "med": 200 - }, - "seq_id": 10 - }] + "r0": { + "route_maps": { + "rmap_ipv4": [ + { + "action": "permit", + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + "set": {"med": 150}, + "call": "rmap_match_pf_2_ipv4", + "seq_id": 10, + } + ], + "rmap_match_pf_2_ipv4": [ + { + "action": "permit", + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + "set": {"med": 200}, + "seq_id": 10, + } + ], + } } } - } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) result = verify_ospf_rib(tgen, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + 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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Create route map - routemaps = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ - "delete": True - }] - } - } - } + routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"delete": True}]}}} result = create_route_maps(tgen, routemaps) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Configure route map with continue clause") # Create route map input_dict_3 = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ - "action": "permit", - 'seq_id': '10', - "match": { - "ipv4": { - "prefix_lists": "pf_list_1_ipv4" - } - }, - "set": { - "med": 150 - }, - "continue": "30", - "seq_id": 10 - }, - { - "action": "permit", - "match": { - "ipv4": { - "prefix_lists": "pf_list_1_ipv4" - } - }, - "set": { - "med": 100 + "r0": { + "route_maps": { + "rmap_ipv4": [ + { + "action": "permit", + "seq_id": "10", + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + "set": {"med": 150}, + "continue": "30", + "seq_id": 10, }, - "seq_id": 20 - }, - { - "action": "permit", - "match": { - "ipv4": { - "prefix_lists": "pf_list_1_ipv4" - } + { + "action": "permit", + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + "set": {"med": 100}, + "seq_id": 20, }, - "set": { - "med": 50 + { + "action": "permit", + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + "set": {"med": 50}, + "seq_id": 30, }, - "seq_id": 30 - } - ] + ] + } } } - } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) result = verify_ospf_rib(tgen, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + 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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Configure route map with goto clause") # Create route map input_dict_3 = { - "r0": { - "route_maps": { - "rmap_ipv4": [{ - "action": "permit", - 'seq_id': '10', - "match": { - "ipv4": { - "prefix_lists": "pf_list_1_ipv4" - } + "r0": { + "route_maps": { + "rmap_ipv4": [ + { + "action": "permit", + "seq_id": "10", + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + "goto": "30", }, - "goto": "30", - }, - { - "action": "permit", - 'seq_id': '20', - "match": { - "ipv4": { - "prefix_lists": "pf_list_1_ipv4" - } + { + "action": "permit", + "seq_id": "20", + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + "set": {"med": 100}, }, - "set": { - "med": 100 - } - }, - { - "action": "permit", - 'seq_id': '30', - "match": { - "ipv4": { - "prefix_lists": "pf_list_1_ipv4" - } + { + "action": "permit", + "seq_id": "30", + "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}}, + "set": {"med": 200}, }, - "set": { - "med": 200 - } - } - ] + ] + } } } - } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( - tc_name, result) + 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) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) write_test_footer(tc_name) @@ -1003,7 +866,11 @@ def test_ospf_routemaps_functionality_tc24_p0(request): input_dict = { "r0": { "static_routes": [ - {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0",} + { + "network": NETWORK["ipv4"][0], + "no_of_ip": 1, + "next_hop": "Null0", + } ] } } @@ -1037,9 +904,10 @@ def test_ospf_routemaps_functionality_tc24_p0(request): step("verify that prefix-list is created in R0.") result = verify_prefix_lists(tgen, pfx_list) - assert result is not True, ( - "Testcase {} : Failed \n Prefix list not " - "present. Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n Prefix list not " "present. Error: {}".format( + tc_name, result ) # Create route map @@ -1105,9 +973,10 @@ def test_ospf_routemaps_functionality_tc24_p0(request): step("verify that prefix-list is created in R0.") result = verify_prefix_lists(tgen, pfx_list) - assert result is not True, ( - "Testcase {} : Failed \n Prefix list not " - "present. Error: {}".format(tc_name, result) + assert ( + result is not True + ), "Testcase {} : Failed \n Prefix list not " "present. Error: {}".format( + tc_name, result ) # Create route map 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 6ac0b515df..434d7f8ef5 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -407,7 +407,13 @@ def test_ospf_redistribution_tc6_p0(request): protocol = "ospf" result = verify_rib( - tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False, + tgen, + "ipv4", + dut, + input_dict, + protocol=protocol, + next_hop=nh, + expected=False, ) assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result @@ -549,7 +555,11 @@ def test_ospf_redistribution_tc8_p1(request): input_dict = { "r0": { "static_routes": [ - {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",} + { + "network": NETWORK["ipv4"][0], + "no_of_ip": 5, + "next_hop": "Null0", + } ] } } 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 b2b0fb8d44..6f6b119abc 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -777,7 +777,6 @@ def test_ospf_show_p1(request): write_test_footer(tc_name) - def test_ospf_dead_tc11_p0(request): """ OSPF timers. @@ -799,224 +798,146 @@ def test_ospf_dead_tc11_p0(request): step("modify dead interval from default value to some other value on r1") topo1 = { - 'r1': { - 'links': { - 'r0': { - 'interface': topo['routers']['r1']['links']['r0'][ - 'interface'], - 'ospf': { - 'hello_interval': 12, - 'dead_interval': 48 - } + "r1": { + "links": { + "r0": { + "interface": topo["routers"]["r1"]["links"]["r0"]["interface"], + "ospf": {"hello_interval": 12, "dead_interval": 48}, } } } } - result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step( "verify that new timer value is configured and applied using " - "the show ip ospf interface command.") - dut = 'r1' - input_dict= { - 'r1': { - 'links':{ - 'r0': { - 'ospf':{ - 'timerDeadSecs': 48 - } - } - } - } - } + "the show ip ospf interface command." + ) + dut = "r1" + input_dict = {"r1": {"links": {"r0": {"ospf": {"timerDeadSecs": 48}}}}} result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - step( - "modify dead interval from default value to r1" - "dead interval timer on r2") + step("modify dead interval from default value to r1" "dead interval timer on r2") topo1 = { - 'r0': { - 'links': { - 'r1': { - 'interface': topo['routers']['r0']['links']['r1'][ - 'interface'], - 'ospf': { - 'dead_interval': 48, - 'hello_interval': 12 - } + "r0": { + "links": { + "r1": { + "interface": topo["routers"]["r0"]["links"]["r1"]["interface"], + "ospf": {"dead_interval": 48, "hello_interval": 12}, } } } } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) - + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("verify that new timer value is configured.") - input_dict= { - 'r0': { - 'links':{ - 'r1': { - 'ospf':{ - 'timerDeadSecs': 48 - } - } - } - } - } - dut = 'r0' + input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 48}}}}} + dut = "r0" result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) - step( - "reconfigure the default dead interval timer value to " - "default on r1 and r2") + step("reconfigure the default dead interval timer value to " "default on r1 and r2") topo1 = { - 'r0': { - 'links': { - 'r1': { - 'interface': topo['routers']['r0']['links']['r1'][ - 'interface'], - 'ospf': { - 'dead_interval': 40 - } + "r0": { + "links": { + "r1": { + "interface": topo["routers"]["r0"]["links"]["r1"]["interface"], + "ospf": {"dead_interval": 40}, } } } } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) topo1 = { - 'r1': { - 'links': { - 'r0': { - 'interface': topo['routers']['r1']['links']['r0'][ - 'interface'], - 'ospf': { - 'dead_interval': 40 - } + "r1": { + "links": { + "r0": { + "interface": topo["routers"]["r1"]["links"]["r0"]["interface"], + "ospf": {"dead_interval": 40}, } } } } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("verify that new timer value is configured.") - input_dict= { - 'r0': { - 'links':{ - 'r1': { - 'ospf':{ - 'timerDeadSecs': 40 - } - } - } - } - } - dut = 'r0' + input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 40}}}}} + dut = "r0" result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) - + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) - + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step(" Configure dead timer = 65535 on r1 and r2") topo1 = { - 'r0': { - 'links': { - 'r1': { - 'interface': topo['routers']['r0']['links']['r1'][ - 'interface'], - 'ospf': { - 'dead_interval': 65535 - } + "r0": { + "links": { + "r1": { + "interface": topo["routers"]["r0"]["links"]["r1"]["interface"], + "ospf": {"dead_interval": 65535}, } } } } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) topo1 = { - 'r1': { - 'links': { - 'r0': { - 'interface': topo['routers']['r1']['links']['r0'][ - 'interface'], - 'ospf': { - 'dead_interval': 65535 - } + "r1": { + "links": { + "r0": { + "interface": topo["routers"]["r1"]["links"]["r0"]["interface"], + "ospf": {"dead_interval": 65535}, } } } } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("verify that new timer value is configured.") - input_dict= { - 'r0': { - 'links':{ - 'r1': { - 'ospf':{ - 'timerDeadSecs': 65535 - } - } - } - } - } - dut = 'r0' + input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 65535}}}}} + dut = "r0" result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, ("setup_module :Failed \n Error:" - " {}".format(ospf_covergence)) - + assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format( + ospf_covergence + ) step(" Try configuring timer values outside range for example 65536") topo1 = { - 'r0': { - 'links': { - 'r1': { - 'interface': topo['routers']['r0']['links']['r1'][ - 'interface'], - 'ospf': { - 'dead_interval': 65536 - } + "r0": { + "links": { + "r1": { + "interface": topo["routers"]["r0"]["links"]["r1"]["interface"], + "ospf": {"dead_interval": 65536}, } } } @@ -1024,47 +945,33 @@ def test_ospf_dead_tc11_p0(request): result = create_interfaces_cfg(tgen, topo1) assert result is not True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + tc_name, result + ) step("Unconfigure the dead timer from the interface from r1 and r2.") topo1 = { - 'r1': { - 'links': { - 'r0': { - 'interface': topo['routers']['r1']['links']['r0'][ - 'interface'], - 'ospf': { - 'dead_interval': 65535 - }, - 'delete': True + "r1": { + "links": { + "r0": { + "interface": topo["routers"]["r1"]["links"]["r0"]["interface"], + "ospf": {"dead_interval": 65535}, + "delete": True, } } } } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step( - "Verify that timer value is deleted from intf & " - "set to default value 40 sec.") - input_dict= { - 'r1': { - 'links':{ - 'r0': { - 'ospf':{ - 'timerDeadSecs': 40 - } - } - } - } - } - dut = 'r1' + "Verify that timer value is deleted from intf & " "set to default value 40 sec." + ) + input_dict = {"r1": {"links": {"r0": {"ospf": {"timerDeadSecs": 40}}}}} + dut = "r1" result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) write_test_footer(tc_name) diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py index de11b78824..fdafa50aba 100644 --- a/tests/topotests/rip-topo1/test_rip_topo1.py +++ b/tests/topotests/rip-topo1/test_rip_topo1.py @@ -352,9 +352,11 @@ def test_zebra_ipv4_routingTable(): else: print("r%s ok" % i) - assert failures == 0, ( - "Zebra IPv4 Routing Table verification failed for router r%s:\n%s" - % (i, diff) + assert ( + failures == 0 + ), "Zebra IPv4 Routing Table verification failed for router r%s:\n%s" % ( + i, + diff, ) # Make sure that all daemons are still running diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py index 2976cdefe4..4702d33dae 100644 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -373,9 +373,11 @@ def test_zebra_ipv6_routingTable(): else: print("r%s ok" % i) - assert failures == 0, ( - "Zebra IPv6 Routing Table verification failed for router r%s:\n%s" - % (i, diff) + assert ( + failures == 0 + ), "Zebra IPv6 Routing Table verification failed for router r%s:\n%s" % ( + i, + diff, ) # Make sure that all daemons are running diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json new file mode 100644 index 0000000000..7099043adc --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json @@ -0,0 +1,157 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "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" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "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" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json new file mode 100644 index 0000000000..91820b0491 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json @@ -0,0 +1,363 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "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" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link2": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link3": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link4": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link5": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link6": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link7": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + }, + "redistribute": [{ + "redist_type": "static" + }] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link2": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link3": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link4": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link5": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link6": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link7": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + }, + "redistribute": [{ + "redist_type": "static" + }] + } + } + } + } + }, + "r3": { + "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" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link5": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link6": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link7": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link5": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link6": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link7": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json new file mode 100644 index 0000000000..bb72578ff3 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json @@ -0,0 +1,428 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "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" + }, + "vm4": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + } + } + } + }, + "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" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + }, + "r3": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + }, + "r3": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + } + } + } + } + } + } + }, + "r3": { + "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" + }, + "vm5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + } + } + } + }, + "vm1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm6": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py new file mode 100644 index 0000000000..a33257de65 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py @@ -0,0 +1,1261 @@ +#!/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 2 next hop. + + -Verify static route functionality with 2 next hop and different AD + value. + + -Verify RIB status when same route advertise via BGP and static route. + +""" +import sys +import json +import time +import os +import pytest +import platform +# 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.topotest import version_cmp +# 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, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +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_topo1_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"], "ipv6": ["2::1/128", "2::2/128"]} +NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"} + +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} + + +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): + """ + 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. + + # 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], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Testcases +# +##################################################### + + +def test_static_route_2nh_p0_tc_1_ebgp(request): + """ + Verify static route ECMP functionality with 2 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 IPv4 static route (10.1.1.1) in R2 with next hop N1" + "(28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present on" + "R1" + ) + step("ex :- ip route 10.1.1.1/24 28.1.1.2 & ip route 10.1.1.1/24 29.1.1.1") + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + }, + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][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 + ) + + step( + "On R2, static route installed in RIB using show ip route" + " with 2 ECMP next hop " + ) + nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][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" "Error: Routes is missing in RIB".format(tc_name) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + step("Configure redistribute static in BGP on R2 router") + + 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 from running config") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][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 + ) + + step( + "On R2, after removing the static route with N1 , " + "route become active with nexthop N2 and vice versa." + ) + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed" "Error: Routes is still present in RIB".format( + tc_name + ) + + nh = [NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + step("Configure the static route with nexthop N1") + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][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 + ) + + step("Remove the static route configured with nexthop N2 from" "running config") + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][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 + ) + + step( + "On R2, after removing the static route with N2 , " + "route become active with nexthop N1 and vice versa." + ) + nh = NEXT_HOP_IP["nh2"][addr_type] + 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 is" + " still present in RIB".format(tc_name) + + 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 is" + " missing in RIB".format(tc_name) + + step("Configure the static route with nexthop N2") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][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 + ) + + step("Shut nexthop interface N1") + intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"] + + shutdown_bringup_interface(tgen, dut, intf, False) + + step("Only one the nexthops should be active in RIB.") + + nh = NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + nh = NEXT_HOP_IP["nh1"][addr_type] + 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 is" + " still present in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + 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: Route is" + " still present in RIB".format(tc_name) + + dut = "r2" + nh = [NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + dut = "r2" + step("No shut the nexthop interface N1") + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "after shut of nexthop N1 , route become active " + "with nexthop N2 and vice versa." + ) + nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + step("Shut nexthop interface N2") + intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"] + dut = "r2" + shutdown_bringup_interface(tgen, dut, intf, False) + + step( + " after shut of nexthop N1 , route become active with " + "nexthop N2 and vice versa." + ) + nh = NEXT_HOP_IP["nh2"][addr_type] + + 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 is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh1"][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 is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("No shut nexthop interface N2") + dut = "r2" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "after shut of nexthop N1 , route become active " + "with nexthop N2 and vice versa." + ) + nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present 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") + + dut = "r2" + step( + "After reload of FRR router , static route installed" + " in RIB and FIB properly ." + ) + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_2nh_admin_dist_p0_tc_2_ebgp(request): + """ + Verify static route functionality with 2 next hop & different AD value. + + """ + 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 IPv4 static route (10.1.1.1) in R2 with next hop N1" + "(28.1.1.2 ) AD 10 and N2 (29.1.1.2) AD 20 , Static route next-hop" + "present on R1 \n ex :- ip route 10.1.1.1/24 28.1.1.2 10 & " + "ip route 10.1.1.1/24 29.1.1.2 20" + ) + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + }, + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + }, + ] + } + } + 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 installed in RIB using " + "show ip route with 2 next hop , lowest AD nexthop is active " + ) + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + nh = [NEXT_HOP_IP["nh1"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + nh = [NEXT_HOP_IP["nh2"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + step("Explicit route is added in R3 for R2 nexthop rechability") + rt3_rtes = { + "r3": { + "static_routes": [ + { + "network": NEXT_HOP_IP["nh1"][addr_type] + "/32", + "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type], + }, + { + "network": NEXT_HOP_IP["nh2"][addr_type] + "/32", + "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type], + }, + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, rt3_rtes) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("Configure redistribute static in BGP on R2 router") + + 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 from" "running config") + rt1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + "delete": True, + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, rt1_nh1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "On R2, after removing the static route with N1 , " + "route become active with nexthop N2 and vice versa." + ) + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + nh = [NEXT_HOP_IP["nh1"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + rte1_nh1, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + nh = [NEXT_HOP_IP["nh2"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + step("Configure the static route with nexthop N1") + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, rte1_nh1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Remove the static route configured with nexthop N2 from" "running config") + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + "delete": True, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, rte2_nh2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "On R2, after removing the static route with N2 , " + "route become active with nexthop N1 and vice versa." + ) + nh = NEXT_HOP_IP["nh2"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh1"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("Configure the static route with nexthop N2") + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, rte2_nh2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Shut nexthop interface N1") + intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"] + + shutdown_bringup_interface(tgen, dut, intf, False) + + step("after shut of nexthop N1 , route become active with nexthop N2") + + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + rte1_nh1, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh2"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("No shut the nexthop interface N1") + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "after shut of nexthop N1 , route become active " + "with nexthop N2 and vice versa." + ) + nh = [NEXT_HOP_IP["nh1"][addr_type]] + + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("Shut nexthop interface N2") + intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"] + + shutdown_bringup_interface(tgen, dut, intf, False) + + step( + " after shut of nexthop N1 , route become active with " + "nexthop N2 and vice versa." + ) + nh = NEXT_HOP_IP["nh2"][addr_type] + + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh1"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("No shut nexthop interface N2") + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "after shut of nexthop N1 , route become active " + "with nexthop N2 and vice versa." + ) + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + nh = [NEXT_HOP_IP["nh1"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + nh = [NEXT_HOP_IP["nh2"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + dut = "r3" + protocol = "bgp" + + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + dut = "r2" + 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 ." + ) + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + nh = [NEXT_HOP_IP["nh1"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, rte1_nh1, next_hop=nh) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + nh = [NEXT_HOP_IP["nh2"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, rte2_nh2, next_hop=nh) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_same_rte_from_bgp_static_p0_tc5_ebgp(request): + """ + Verify RIB status when same route advertise via BGP and static + route + + """ + 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 EBGP IPv4 peering between R2 and R3 router.") + + step( + "Configure IPv4 static route (10.1.1.1/24) in R2 with next hop" + "N1 (28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present" + "on R1" + ) + + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + }, + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][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 + ) + + step("Configure redistribute static in BGP.") + 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("Verify on R3 , route receive on R3 BGP table ") + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("Verify route installed in the RIB and FIB of R3") + protocol = "bgp" + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step( + "Configure 2 links/interfaces between R1 and R3 , keep one" + "interface in shut (active) state and other interface in no shut" + "(inactive) state" + ) + dut = "r3" + intf = topo["routers"]["r3"]["links"]["r1-link0"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + step( + "Configure same static route (10.1.1.1/24) in R3 with inactive" + "nexthop interface" + ) + + step( + "Configure same static route 10.1.1.1/24) again in R3 with" + "active nexthop interface" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r3": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r3-link0"][ + addr_type + ], + }, + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r3-link1"][ + 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 + ) + + step( + "Verify when static route configure with inactive nexthop , " + "verify BGP received route is active in the RIB and FIB" + ) + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in BGP RIB".format(tc_name) + + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + step("Remove the static route on R3 configured with active" "interface") + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r3": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r3-link0"][ + addr_type + ], + "delete": True, + }, + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r3-link1"][ + 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 + ) + step( + "After removing the static route with active nexthop verify " + "BGP received route is became active in RIB and FIB" + ) + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in BGP RIB".format(tc_name) + + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py new file mode 100644 index 0000000000..93320df327 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py @@ -0,0 +1,1711 @@ +#!/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 functionality with 8 next hop different AD value + and BGP ECMP + + -Verify 8 static route functionality with 8 next hop different AD + + -Verify static route with 8 next hop with different AD value and 8 + EBGP neighbors + + -Verify static route with 8 next hop with different AD value and 8 + IBGP neighbors + + -Delete the static route and verify the RIB and FIB state + + -Verify 8 static route functionality with 8 ECMP next hop +""" +import sys +import json +import time +import os +import pytest +import platform +import random +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 + +# 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, + check_address_types, + step, + shutdown_bringup_interface, + stop_router, + start_router, +) +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_topo2_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"} +PREFIX2 = {"ipv4": "110.0.20.2/32", "ipv6": "20::2/128"} +NEXT_HOP_IP = [] +topo_diag = """ + Please view in a fixed-width font such as Courier. + +------+ +------+ +------+ + | +--------------+ +--------------+ | + | | | | | | + | R1 +---8 links----+ R2 +---8 links----+ R3 | + | | | | | | + | +--------------+ +--------------+ | + +------+ +------+ +------+ + +""" + + +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 + + +##################################################### +# +# Testcases +# +##################################################### + + +def test_static_rte_with_8ecmp_nh_p1_tc9_ebgp(request): + """ + Verify 8 static route functionality with 8 ECMP 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) + NEXT_HOP_IP = populate_nh() + step("Configure 8 interfaces / links between R1 and R2") + step("Configure 8 interfaces / links between R2 and R3") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + step( + "Configure 8 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" + ) + nh_all = {} + 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_all[addr_type] = [ + 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_all[addr_type], + 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 + ) + + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + dut = "r2" + protocol = "static" + step( + "After removing the static route with N1 to N8 one by one , " + "verify that entry is removed from RIB and FIB of R3 " + ) + 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], + "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 , " + "verify that entry is removed from RIB and FIB of R3 " + ) + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + 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 is" + " 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: + 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 + ) + + nh = NEXT_HOP_IP["nh" + str(nhp)][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) + + protocol = "static" + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + # Shutdown interface + dut = "r2" + step( + " interface which is about to be shut no shut between r1 and r2 is " "%s", + topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"], + ) + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + step("Random no shut of the nexthop interfaces") + # Bringup interface + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "After random shut/no shut of nexthop , only that " + "nexthop deleted/added from all the routes , other nexthop remain " + "unchanged" + ) + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Remove random static route with all the nexthop") + dut = "r2" + randnum = random.randint(1, 7) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum)][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 + ) + + step( + "After delete of random route , that route only got deleted from" + " RIB/FIB other route are showing properly" + ) + nh = NEXT_HOP_IP["nh{}".format(randnum)][addr_type] + 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" + " missing in RIB".format(tc_name) + + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum)][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 + ) + + 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: + # Enable static routes + nhp = 1 + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + logger.info("Verifying %s routes on r2", addr_type) + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing the BGP neighbor or redistribute static knob , " + "verify route got clear from RIB and FIB of R3 routes " + ) + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ebgp(request): + """ + Verify static route functionality with 8 next hop different AD + value and BGP ECMP + + """ + 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 interfaces / links between R1 and R2 ,") + step("Configure 8 interlaces/links between R2 and R3") + step( + "Configure IBGP IPv4 peering over loopback interface between" + "R2 and R3 router." + ) + step("Configure redistribute static in BGP on R2 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" + ) + 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: Routes are" + " 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, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + 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: Routes are" + " 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, + wait=2, + attempts=3, + ) + assert result is not 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) + + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + protocol = "bgp" + dut = "r3" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, 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") + + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_ebgp_ecmp_p1_tc8_ebgp(request): + """ + Verify static route with 8 next hop with different AD value and 8 + EBGP neighbors + """ + 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 interfaces / links between R1 and R2") + step("Configure 8 interlaces/links between R2 and R3") + step("Configure 8 EBGP IPv4 peering between R2 and R3") + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + + 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( + "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" + ) + 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]) + 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" + ) + 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: Routes are" + " 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 " + " are 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + 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: Routes are" + " 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 " + " 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) + + dut = "r2" + protocol = "static" + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + + start_router(tgen, "r2") + + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ebgp(request): + """ + Verify 8 static route functionality with 8 next hop different AD' + + """ + 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) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2 ") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + 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" + ) + step( + "Configure nexthop AD in such way for static route S1 , N1 is" + "preferred and for S2 , N2 is preferred and so on .." + ) + 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]) + + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[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, second_rte) + 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" + ) + 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: Routes are" + " missing in RIB".format(tc_name) + + step("Verify that highest AD nexthop are inactive") + 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, + wait=2, + attempts=3, + ) + assert result is not 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], + "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, + 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + 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("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("Remove random static route with all the nexthop") + 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" + ) + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + 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: Route " + " is still present in RIB".format(tc_name) + + step("Reconfigure the deleted routes and verify they are installed") + 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 + ) + + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route " + " is still present 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 reloading, verify that routes are still present in R2.") + result = verify_rib( + tgen, + addr_type, + dut, + second_rte, + next_hop=nh, + protocol=protocol, + fib=True, + ) + assert result is True, ( + "Testcase {} : Failed \nError: Route " + " is missing in RIB".format(tc_name) + ) + + write_test_footer(tc_name) + + +def test_static_route_delete_p0_tc11_ebgp(request): + """ + Delete the static route and verify the RIB and FIB state + """ + 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) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2 ") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + 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" + ) + step( + "Configure nexthop AD in such way for static route S1 , N1 is" + "preferred and for S2 , N2 is preferred and so on .." + ) + 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]) + + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[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, second_rte) + 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" + ) + 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: Routes are" + " missing in RIB".format(tc_name) + + step("Verify that highest AD nexthop are inactive") + 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 " + " 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 redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Verify after removing the redistribute static from BGP all the" + "routes got delete from RIB and FIB of R3 " + ) + + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + 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, + "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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[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, second_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + " After removing all the routes and nexthop from R2 , " + " verify R2 RIB and FIB is cleared" + ) + 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, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still active in RIB".format(tc_name) + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py new file mode 100644 index 0000000000..75657a8895 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -0,0 +1,994 @@ +#!/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. +# + +""" + +Following tests are covered in the script. + +- Verify static route are blocked from route-map and prefix-list + applied in BGP nbrs +- Verify Static route when FRR connected to 2 TOR +""" + +import sys +import json +import time +import os +import pytest +import platform +import ipaddress +from copy import deepcopy + +# 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.topotest import version_cmp + +# 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, + check_address_types, + step, + create_prefix_lists, + create_route_maps, + create_interfaces_cfg, + verify_prefix_lists, + verify_route_maps, +) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, + create_router_bgp, + clear_bgp_and_verify, + clear_bgp, +) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology creation +jsonFile = "{}/static_routes_topo4_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": "2.2.2.2/32", "ipv6": "22:22::2/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) + + +##################################################### +# +# Tests starting +# +##################################################### +def static_routes_rmap_pfxlist_p0_tc7_ebgp(request): + """ + Verify static route are blocked from route-map & prefix-list applied in BGP + nbrs + + """ + 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) + step("Configure holddown timer = 1 keep alive = 3 in all the neighbors") + step("verify bgp convergence before starting test case") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Configure 4 IPv4 and 4 IPv6 nbrs with password with mismatch " + " authentication between FRR routers " + ) + + for addr_type in ADDR_TYPES: + # Api call to modfiy BGP timerse + input_dict = { + "r2": { + "bgp": { + "local_as": "200", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": {"password": "r2"}, + "r2-link1": {"password": "r2"}, + "r2-link2": {"password": "r2"}, + "r2-link3": {"password": "r2"}, + } + }, + "r3": { + "dest_link": { + "r2-link0": {"password": "r2"}, + "r2-link1": {"password": "r2"}, + "r2-link2": {"password": "r2"}, + "r2-link3": {"password": "r2"}, + } + }, + } + } + } + }, + } + } + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + clear_bgp(tgen, addr_type, "r2") + + step(" All BGP nbrs are down as authentication is mismatch on both" " the sides") + + bgp_convergence = verify_bgp_convergence(tgen, topo, expected=False) + assert bgp_convergence is not True, "Testcase {} : " + "Failed \n BGP nbrs must be down. Error: {}".format(tc_name, bgp_convergence) + + step( + "Configure 4 IPv4 and 4 IPv6 nbrs with macthing password " + " authentication between FRR routers " + ) + for addr_type in ADDR_TYPES: + input_dict = { + "r2": { + "bgp": { + "local_as": "200", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": {"password": "r1"}, + "r2-link1": {"password": "r1"}, + "r2-link2": {"password": "r1"}, + "r2-link3": {"password": "r1"}, + } + }, + "r3": { + "dest_link": { + "r2-link0": {"password": "r1"}, + "r2-link1": {"password": "r1"}, + "r2-link2": {"password": "r1"}, + "r2-link3": {"password": "r1"}, + } + }, + } + } + } + }, + } + } + } + result = create_router_bgp(tgen, topo, deepcopy(input_dict)) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + step("All BGP nbrs are up as authentication is matched now") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n " "Error: {}".format( + tc_name, bgp_convergence + ) + + step("Create prefix list P1 to permit VM3 & deny VM1 v4 & v6 routes") + step("Create prefix list P2 to permit VM6 IPv4 and IPv6 routes") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "prefix_lists": { + addr_type: { + "pf_list_1_{}".format(addr_type): [ + { + "seqid": 10, + "network": topo["routers"]["r2"]["links"]["vm3"][ + addr_type + ], + "action": "permit", + }, + { + "seqid": 20, + "network": topo["routers"]["r2"]["links"]["vm1"][ + addr_type + ], + "action": "deny", + }, + ], + "pf_list_2_{}".format(addr_type): [ + { + "seqid": 10, + "network": topo["routers"]["r2"]["links"]["vm6"][ + addr_type + ], + "action": "permit", + } + ], + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Prefix list created with matching networks deny or permit " + "show ip prefix list" + ) + result = verify_prefix_lists(tgen, input_dict_2) + assert result is not True, "Testcase {} : Failed \n" + " Error: {}".format(tc_name, result) + + step("Redistribute all the routes (connected, static)") + input_dict_2_r1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r3 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("configure redistribute connected in Router BGP") + + input_dict_2_r1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r3 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply prefix list P1 on BGP neighbors 1 2 3 4 connected from " "frr r1") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply prefix list P2 on BGP nbrs 5 & 6 connected from FRR-2") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + clear_bgp_and_verify(tgen, topo, "r2") + + step( + "VM1 IPv4 and IPv6 Route which is denied using prefix list is " + "not present on FRR1 side routing table , also not able to " + "ping the routes show ip route" + ) + + dut = "r1" + protocol = "bgp" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib( + tgen, addr_type, dut, input_dict, protocol=protocol, expected=False + ) + assert result4 is not True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + step( + "VM4 and VM6 IPV4 and IPv6 address are present in local and " + "FRR2 routing table show ip bgp show ip route" + ) + + dut = "r2" + ntwk_r2_vm6 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + ).network + ) + input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed.\n Error: {}".format( + tc_name, result4 + ) + + step("Remove prefix list from all the neighbors") + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + clear_bgp_and_verify(tgen, topo, "r2") + + step("Create RouteMap_1 with prefix list P1 and weight 50") + # Create route map + rmap_dict = { + "r2": { + "route_maps": { + "rmap_pf_list_1_{}".format(addr_type): [ + { + "action": "permit", + "set": {"weight": 50}, + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, rmap_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Create RouteMap_2 with prefix list P2 and weight 50") + # Create route map + rmap_dict = { + "r2": { + "route_maps": { + "rmap_pf_list_2_{}".format(addr_type): [ + { + "action": "permit", + "set": {"weight": 50}, + "match": { + addr_type: { + "prefix_lists": "pf_list_2_{}".format(addr_type) + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, rmap_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify Route-map created verify using show route-map") + # verify rmap_pf_list_1 and rmap_pf_list_2 are present in router r2 + input_dict = { + "r2": { + "route_maps": [ + "rmap_pf_list_1_{}".format(addr_type), + "rmap_pf_list_2_{}".format(addr_type), + ] + } + } + result = verify_route_maps(tgen, input_dict, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply policy RouteMap_1 nbrs 1 2 3 4 to FRR 1") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link1": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link2": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link3": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply policy RouteMap_2 nbrs 5 and 6 to FRR2") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link1": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link2": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link3": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After applying to BGP neighbors verify VM1 IPv4 and IPv6 Route" + " which is denied using prefix list is not present on FRR side" + " routing table , also not able to ping the routes show ip route" + " and VM4 and VM6 IPV4 and IPv6 address are present in local and" + " FRR routing table show ip bgp show ip route" + ) + + dut = "r1" + protocol = "bgp" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib( + tgen, addr_type, dut, input_dict, protocol=protocol, expected=False + ) + assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format( + tc_name, result4 + ) + + step("vm4 should be present in FRR1") + dut = "r1" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + step("vm4 should be present in FRR2") + dut = "r2" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + dut = "r3" + protocol = "bgp" + ntwk_r2_vm6 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + ).network + ) + input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result4 is True, "Testcase {} : Failed.\n Error: {}".format( + tc_name, result4 + ) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json new file mode 100644 index 0000000000..99b197366a --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json @@ -0,0 +1,157 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "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" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "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" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json new file mode 100644 index 0000000000..47596a0a1a --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json @@ -0,0 +1,371 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "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" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + + + "dest_link": { + "r2-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link2": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link3": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link4": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link5": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link6": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link7": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + }, + "redistribute": [{ + "redist_type": "static" + }] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + + + "dest_link": { + "r2-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link2": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link3": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link4": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link5": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link6": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r2-link7": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + }, + "redistribute": [{ + "redist_type": "static" + }] + } + } + } + } + }, + "r3": { + "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" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + + + "dest_link": { + "r3-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link5": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link6": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link7": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + + + "dest_link": { + "r3-link0": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link5": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link6": { + "keepalivetimer": 1, + "holddowntimer": 4 + }, + "r3-link7": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json new file mode 100644 index 0000000000..4e27229f34 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.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": "100", + "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_ibgp/static_routes_topo4_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json new file mode 100644 index 0000000000..bb72578ff3 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json @@ -0,0 +1,428 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "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" + }, + "vm4": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + } + } + } + }, + "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" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + }, + "r3": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + }, + "r3": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + } + } + } + } + } + } + }, + "r3": { + "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" + }, + "vm5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + } + } + } + }, + "vm1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm6": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + } + } +}
\ No newline at end of file diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py new file mode 100644 index 0000000000..130f4fd9aa --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py @@ -0,0 +1,1083 @@ +#!/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 2 next hop + + -Verify static route functionality with 2 next hop and different AD + value + + -Verify RIB status when same route advertise via BGP and static route + +""" +import sys +import json +import time +import os +import pytest +import platform +from copy import deepcopy + +# 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.topotest import version_cmp + +# 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, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +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_topo1_ibgp.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"], "ipv6": ["2::1/128", "2::2/128"]} +NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"} + +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} + + +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], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Tests starting +# +##################################################### + + +def test_static_route_2nh_p0_tc_1_ibgp(request): + """ + Verify static route ECMP functionality with 2 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 IPv4 static route (10.1.1.1) in R2 with next hop N1" + "(28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present on" + "R1" + ) + step("ex :- ip route 10.1.1.1/24 28.1.1.2 & ip route 10.1.1.1/24 29.1.1.1") + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + }, + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][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 + ) + + step( + "On R2, static route installed in RIB using show ip route" + " with 2 ECMP next hop " + ) + nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + step("Configure redistribute static in BGP on R2 router") + + 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 from running config") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][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 + ) + + step( + "On R2, after removing the static route with N1 , " + "route become active with nexthop N2 and vice versa." + ) + nh = NEXT_HOP_IP["nh1"][addr_type] + 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 is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + step("Configure the static route with nexthop N1") + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][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 + ) + + step("Remove the static route configured with nexthop N2 from running config") + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][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 + ) + + step( + "On R2, after removing the static route with N2 , " + "route become active with nexthop N1 and vice versa." + ) + nh = NEXT_HOP_IP["nh2"][addr_type] + 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 is" + " still present in RIB".format(tc_name) + + 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 is" + " missing in RIB".format(tc_name) + + step("Configure the static route with nexthop N2") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][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 + ) + + step("Shut nexthop interface N1") + intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"] + + shutdown_bringup_interface(tgen, dut, intf, False) + + step("Only one the nexthops should be active in RIB.") + + nh = NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + nh = NEXT_HOP_IP["nh1"][addr_type] + 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 is" + " still present in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + 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: Route is" + " still present in RIB".format(tc_name) + + dut = "r2" + nh = [NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + dut = "r2" + step("No shut the nexthop interface N1") + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "after shut of nexthop N1 , route become active " + "with nexthop N2 and vice versa." + ) + nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + step("Shut nexthop interface N2") + intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"] + dut = "r2" + shutdown_bringup_interface(tgen, dut, intf, False) + + step( + " after shut of nexthop N1 , route become active with " + "nexthop N2 and vice versa." + ) + nh = NEXT_HOP_IP["nh2"][addr_type] + + 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 is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh1"][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 is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("No shut nexthop interface N2") + dut = "r2" + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "after shut of nexthop N1 , route become active " + "with nexthop N2 and vice versa." + ) + nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][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 is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present 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") + + dut = "r2" + step( + "After reload of FRR router , static route installed" + " in RIB and FIB properly ." + ) + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_2nh_admin_dist_p0_tc_2_ibgp(request): + """ + Verify static route functionality with 2 next hop & different AD value + + """ + 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 IPv4 static route (10.1.1.1) in R2 with next hop N1" + "(28.1.1.2 ) AD 10 and N2 (29.1.1.2) AD 20 , Static route next-hop" + "present on R1 \n ex :- ip route 10.1.1.1/24 28.1.1.2 10 & " + "ip route 10.1.1.1/24 29.1.1.2 20" + ) + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + }, + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + }, + ] + } + } + 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 installed in RIB using " + "show ip route with 2 next hop , lowest AD nexthop is active " + ) + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + nh = [NEXT_HOP_IP["nh1"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + nh = [NEXT_HOP_IP["nh2"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + step("Explicit route is added in R3 for R2 nexthop rechability") + rt3_rtes = { + "r3": { + "static_routes": [ + { + "network": NEXT_HOP_IP["nh1"][addr_type] + "/32", + "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type], + }, + { + "network": NEXT_HOP_IP["nh2"][addr_type] + "/32", + "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type], + }, + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, rt3_rtes) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("Configure redistribute static in BGP on R2 router") + + 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 from running config") + rt1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + "delete": True, + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, rt1_nh1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "On R2, after removing the static route with N1 , " + "route become active with nexthop N2 and vice versa." + ) + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + nh = [NEXT_HOP_IP["nh1"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + rte1_nh1, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + nh = [NEXT_HOP_IP["nh2"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + step("Configure the static route with nexthop N1") + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, rte1_nh1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Remove the static route configured with nexthop N2 from running config") + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + "delete": True, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, rte2_nh2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "On R2, after removing the static route with N2 , " + "route become active with nexthop N1 and vice versa." + ) + nh = NEXT_HOP_IP["nh2"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh1"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("Configure the static route with nexthop N2") + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + + logger.info("Configure static routes") + result = create_static_routes(tgen, rte2_nh2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Shut nexthop interface N1") + intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"] + + shutdown_bringup_interface(tgen, dut, intf, False) + + step("after shut of nexthop N1 , route become active with nexthop N2") + + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + rte1_nh1, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh2"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("No shut the nexthop interface N1") + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "after shut of nexthop N1 , route become active " + "with nexthop N2 and vice versa." + ) + nh = [NEXT_HOP_IP["nh1"][addr_type]] + + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("Shut nexthop interface N2") + intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"] + + shutdown_bringup_interface(tgen, dut, intf, False) + + step( + " after shut of nexthop N1 , route become active with " + "nexthop N2 and vice versa." + ) + nh = NEXT_HOP_IP["nh2"][addr_type] + + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB".format(tc_name) + + nh = [NEXT_HOP_IP["nh1"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("No shut nexthop interface N2") + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "after shut of nexthop N1 , route become active " + "with nexthop N2 and vice versa." + ) + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + nh = [NEXT_HOP_IP["nh1"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + nh = [NEXT_HOP_IP["nh2"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + dut = "r3" + protocol = "bgp" + + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + dut = "r2" + 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 ." + ) + rte1_nh1 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + nh = [NEXT_HOP_IP["nh1"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, rte1_nh1, next_hop=nh) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "missing in RIB".format(tc_name) + + rte2_nh2 = { + "r2": { + "static_routes": [ + { + "network": NETWORK2[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "admin_distance": 20, + } + ] + } + } + nh = [NEXT_HOP_IP["nh2"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, rte2_nh2, next_hop=nh) + assert result is True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + result = verify_rib( + tgen, + addr_type, + dut, + rte2_nh2, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + "not active in RIB".format(tc_name) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py new file mode 100644 index 0000000000..0a757c9f28 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py @@ -0,0 +1,1974 @@ +#!/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 functionality with 8 next hop different AD value + and BGP ECMP + + -Verify 8 static route functionality with 8 next hop different AD + + -Verify static route with 8 next hop with different AD value and 8 + EBGP neighbors + + -Verify static route with 8 next hop with different AD value and 8 + IBGP neighbors + + -Delete the static route and verify the RIB and FIB state + + -Verify 8 static route functionality with 8 ECMP next hop +""" +import sys +import json +import time +import os +import pytest +import platform +from time import sleep +import random + +# 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 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, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +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 +from lib.topotest import version_cmp + +# Reading the data from JSON File for topology creation +jsonFile = "{}/static_routes_topo2_ibgp.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"} +PREFIX2 = {"ipv4": "110.0.20.2/32", "ipv6": "20::2/128"} +NEXT_HOP_IP = [] +topo_diag = """ + Please view in a fixed-width font such as Courier. + +------+ +------+ +------+ + | +--------------+ +--------------+ | + | | | | | | + | R1 +---8 links----+ R2 +---8 links----+ R3 | + | | | | | | + | +--------------+ +--------------+ | + +------+ +------+ +------+ + +""" + + +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_static_rte_with_8ecmp_nh_p1_tc9_ibgp(request): + """ + Verify 8 static route functionality with 8 ECMP 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) + NEXT_HOP_IP = populate_nh() + step("Configure 8 interfaces / links between R1 and R2") + step("Configure 8 interfaces / links between R2 and R3") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + step( + "Configure 8 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" + ) + nh_all = {} + 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_all[addr_type] = [ + 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_all[addr_type], + 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 + ) + + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + dut = "r2" + protocol = "static" + step( + "After removing the static route with N1 to N8 one by one , " + "verify that entry is removed from RIB and FIB of R3 " + ) + 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], + "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 , " + "verify that entry is removed from RIB and FIB of R3 " + ) + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + 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 is" + " 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: + 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 + ) + + nh = NEXT_HOP_IP["nh" + str(nhp)][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) + + protocol = "static" + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + # Shutdown interface + dut = "r2" + step( + " interface which is about to be shut no shut between r1 and r2 is " "%s", + topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"], + ) + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + step("Random no shut of the nexthop interfaces") + # Bringup interface + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "After random shut/no shut of nexthop , only that " + "nexthop deleted/added from all the routes , other nexthop remain " + "unchanged" + ) + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Remove random static route with all the nexthop") + dut = "r2" + randnum = random.randint(1, 7) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum)][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 + ) + + step( + "After delete of random route , that route only got deleted from" + " RIB/FIB other route are showing properly" + ) + nh = NEXT_HOP_IP["nh{}".format(randnum)][addr_type] + 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" + " missing in RIB".format(tc_name) + + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum)][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 + ) + + 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: + # Enable static routes + nhp = 1 + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + logger.info("Verifying %s routes on r2", addr_type) + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing the BGP neighbor or redistribute static knob , " + "verify route got clear from RIB and FIB of R3 routes " + ) + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request): + """ + Verify static route functionality with 8 next hop different AD + value and BGP ECMP + + """ + 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 interfaces / links between R1 and R2 ,") + step("Configure 8 interlaces/links between R2 and R3") + step( + "Configure IBGP IPv4 peering over loopback interface between" + "R2 and R3 router." + ) + step("Configure redistribute static in BGP on R2 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" + ) + 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: Routes are" + " 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, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + 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: Routes are" + " 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, + wait=2, + attempts=3, + ) + assert result is not 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) + + protocol = "bgp" + # this is next hop reachability route in r3 as we are using ibgp + dut = "r3" + for addr_type in ADDR_TYPES: + nh_as_rte = NEXT_HOP_IP["nh1"][addr_type] + "/32" + # add static routes + nh_static_rte = { + "r3": {"static_routes": [{"network": nh_as_rte, "next_hop": "Null0"}]} + } + logger.info("Configure static routes") + result = create_static_routes(tgen, nh_static_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After each interface shut and no shut between R2 -R3 ,verify static" + "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain" + " unchanged" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + protocol = "static" + dut = "r2" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + protocol = "bgp" + dut = "r3" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, 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") + + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("BGP neighbor remove and add") + for rtr in ["r2", "r3"]: + if "bgp" in topo["routers"][rtr].keys(): + delete_bgp = {rtr: {"bgp": {"delete": True}}} + result = create_router_bgp(tgen, topo, delete_bgp) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + create_router_bgp(tgen, topo["routers"]) + + NEXT_HOP_IP = populate_nh() + step("Verify routes are still present after delete and add bgp") + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + + dut = "r3" + protocol = "bgp" + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + 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" + " strill present in RIB of R3".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_ibgp_ecmp_p1_tc7_ibgp(request): + """ + Verify static route with 8 next hop with different AD value and 8 + IBGP neighbors + """ + 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 interfaces / links between R1 and R2") + step("Configure 8 interlaces/links between R2 and R3") + step("Configure 8 IBGP IPv4 peering between R2 and R3") + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + + 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( + "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" + ) + 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]) + 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" + ) + 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: Routes are" + " 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 " + " are 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + 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: Routes are" + " 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 " + " 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) + + dut = "r2" + protocol = "bgp" + + # this is next hop reachability route in r3 as we are using ibgp + dut = "r3" + for addr_type in ADDR_TYPES: + nh_as_rte = NEXT_HOP_IP["nh1"][addr_type] + "/32" + # add static routes + nh_static_rte = { + "r3": {"static_routes": [{"network": nh_as_rte, "next_hop": "Null0"}]} + } + logger.info("Configure static routes") + result = create_static_routes(tgen, nh_static_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After each interface shut and no shut between R2 -R3 ,verify static" + "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain" + " unchanged" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + protocol = "static" + dut = "r2" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + protocol = "bgp" + dut = "r3" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, 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") + + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("BGP neighbor remove and add") + for rtr in ["r2", "r3"]: + if "bgp" in topo["routers"][rtr].keys(): + delete_bgp = {rtr: {"bgp": {"delete": True}}} + result = create_router_bgp(tgen, topo, delete_bgp) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + create_router_bgp(tgen, topo["routers"]) + + NEXT_HOP_IP = populate_nh() + step("Verify routes are still present after delete and add bgp") + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + + dut = "r3" + protocol = "bgp" + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + 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 of R3".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ibgp(request): + """ + Verify 8 static route functionality with 8 next hop different AD' + + """ + 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) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2 ") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + 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" + ) + step( + "Configure nexthop AD in such way for static route S1 , N1 is" + "preferred and for S2 , N2 is preferred and so on .." + ) + 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]) + + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[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, second_rte) + 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" + ) + 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: Routes are" + " missing in RIB".format(tc_name) + + step("Verify that highest AD nexthop are inactive") + 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, + wait=2, + attempts=3, + ) + assert result is not 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], + "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, + 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + 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("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("Remove random static route with all the nexthop") + 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" + ) + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + 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: Route " + " is still present in RIB".format(tc_name) + + step("Reconfigure the deleted routes and verify they are installed") + 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 + ) + + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route " + " is still present 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 reloading, verify that routes are still present in R2.") + result = verify_rib( + tgen, + addr_type, + dut, + second_rte, + next_hop=nh, + protocol=protocol, + fib=True, + ) + assert result is True, ( + "Testcase {} : Failed \nError: Route " + " is missing in RIB".format(tc_name) + ) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing the BGP neighbor or redistribute static knob , " + "verify route got clear from RIB and FIB of R3 routes " + ) + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_delete_p0_tc11_ibgp(request): + """ + Delete the static route and verify the RIB and FIB state + """ + 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) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2 ") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + 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" + ) + step( + "Configure nexthop AD in such way for static route S1 , N1 is" + "preferred and for S2 , N2 is preferred and so on .." + ) + 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]) + + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[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, second_rte) + 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" + ) + 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: Routes are" + " missing in RIB".format(tc_name) + + step("Verify that highest AD nexthop are inactive") + 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 " + " 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 redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Verify after removing the redistribute static from BGP all the" + "routes got delete from RIB and FIB of R3 " + ) + + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + 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, + "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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[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, second_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + " After removing all the routes and nexthop from R2 , " + " verify R2 RIB and FIB is cleared" + ) + 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, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still active in RIB".format(tc_name) + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py new file mode 100644 index 0000000000..924fb3a598 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py @@ -0,0 +1,875 @@ +#!/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 platform +from copy import deepcopy +import random +from re import search as re_search + + +# 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.topotest import version_cmp + +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, +) +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_ibgp.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_ibgp(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_ibgp(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) + + step("Remove the redistribute static knob") + + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + dut = "r3" + protocol = "bgp" + 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" + " strill present in RIB of R3".format(tc_name) + + write_test_footer(tc_name) + + +def test_bgp_local_nexthop_p1_tc14_ibgp(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) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py new file mode 100644 index 0000000000..fdbfad25b3 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -0,0 +1,991 @@ +#!/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. +# + +""" + +Following tests are covered in the script. + +- Verify static route are blocked from route-map and prefix-list + applied in BGP nbrs +""" + +import sys +import json +import time +import os +import pytest +import platform +import ipaddress +from copy import deepcopy + +# 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, + check_address_types, + step, + create_prefix_lists, + create_route_maps, + create_interfaces_cfg, + verify_prefix_lists, + verify_route_maps, +) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, + create_router_bgp, + clear_bgp_and_verify, + clear_bgp, +) +from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topotest import version_cmp +# Reading the data from JSON File for topology creation +jsonFile = "{}/static_routes_topo4_ibgp.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": "2.2.2.2/32", "ipv6": "22:22::2/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) + + +##################################################### +# +# Tests starting +# +##################################################### +def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): + """ + Verify static route are blocked from route-map & prefix-list applied in BGP + nbrs + + """ + 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) + step("Configure holddown timer = 1 keep alive = 3 in all the neighbors") + step("verify bgp convergence before starting test case") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Configure 4 IPv4 and 4 IPv6 nbrs with password with mismatch " + " authentication between FRR routers " + ) + + for addr_type in ADDR_TYPES: + # Api call to modfiy BGP timerse + input_dict = { + "r2": { + "bgp": { + "local_as": "200", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": {"password": "r2"}, + "r2-link1": {"password": "r2"}, + "r2-link2": {"password": "r2"}, + "r2-link3": {"password": "r2"}, + } + }, + "r3": { + "dest_link": { + "r2-link0": {"password": "r2"}, + "r2-link1": {"password": "r2"}, + "r2-link2": {"password": "r2"}, + "r2-link3": {"password": "r2"}, + } + }, + } + } + } + }, + } + } + } + result = create_router_bgp(tgen, topo, deepcopy(input_dict)) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + clear_bgp(tgen, addr_type, "r2") + + step(" All BGP nbrs are down as authentication is mismatch on both" " the sides") + + bgp_convergence = verify_bgp_convergence(tgen, topo, expected=False) + assert bgp_convergence is not True, "Testcase {} : " + "Failed \n BGP nbrs must be down. Error: {}".format(tc_name, bgp_convergence) + + step( + "Configure 4 IPv4 and 4 IPv6 nbrs with macthing password " + " authentication between FRR routers " + ) + for addr_type in ADDR_TYPES: + input_dict = { + "r2": { + "bgp": { + "local_as": "200", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": {"password": "r1"}, + "r2-link1": {"password": "r1"}, + "r2-link2": {"password": "r1"}, + "r2-link3": {"password": "r1"}, + } + }, + "r3": { + "dest_link": { + "r2-link0": {"password": "r1"}, + "r2-link1": {"password": "r1"}, + "r2-link2": {"password": "r1"}, + "r2-link3": {"password": "r1"}, + } + }, + } + } + } + }, + } + } + } + result = create_router_bgp(tgen, topo, deepcopy(input_dict)) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + step("All BGP nbrs are up as authentication is matched now") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n " "Error: {}".format( + tc_name, bgp_convergence + ) + + step("Create prefix list P1 to permit VM3 & deny VM1 v4 & v6 routes") + step("Create prefix list P2 to permit VM6 IPv4 and IPv6 routes") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "prefix_lists": { + addr_type: { + "pf_list_1_{}".format(addr_type): [ + { + "seqid": 10, + "network": topo["routers"]["r2"]["links"]["vm3"][ + addr_type + ], + "action": "permit", + }, + { + "seqid": 20, + "network": topo["routers"]["r2"]["links"]["vm1"][ + addr_type + ], + "action": "deny", + }, + ], + "pf_list_2_{}".format(addr_type): [ + { + "seqid": 10, + "network": topo["routers"]["r2"]["links"]["vm6"][ + addr_type + ], + "action": "permit", + } + ], + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Prefix list created with matching networks deny or permit " + "show ip prefix list" + ) + result = verify_prefix_lists(tgen, input_dict_2) + assert result is not True, "Testcase {} : Failed \n" + " Error: {}".format(tc_name, result) + + step("Redistribute all the routes (connected, static)") + input_dict_2_r1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r3 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("configure redistribute connected in Router BGP") + + input_dict_2_r1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r3 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply prefix list P1 on BGP neighbors 1 2 3 4 connected from " "frr r1") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply prefix list P2 on BGP nbrs 5 & 6 connected from FRR-2") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + clear_bgp_and_verify(tgen, topo, "r2") + + step( + "VM1 IPv4 and IPv6 Route which is denied using prefix list is " + "not present on FRR1 side routing table , also not able to " + "ping the routes show ip route" + ) + + dut = "r1" + protocol = "bgp" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib( + tgen, addr_type, dut, input_dict, protocol=protocol, expected=False + ) + assert result4 is not True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + step( + "VM4 and VM6 IPV4 and IPv6 address are present in local and " + "FRR2 routing table show ip bgp show ip route" + ) + + dut = "r2" + ntwk_r2_vm6 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + ).network + ) + input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed.\n Error: {}".format( + tc_name, result4 + ) + + step("Remove prefix list from all the neighbors") + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + clear_bgp_and_verify(tgen, topo, "r2") + + step("Create RouteMap_1 with prefix list P1 and weight 50") + # Create route map + rmap_dict = { + "r2": { + "route_maps": { + "rmap_pf_list_1_{}".format(addr_type): [ + { + "action": "permit", + "set": {"weight": 50}, + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, rmap_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Create RouteMap_2 with prefix list P2 and weight 50") + # Create route map + rmap_dict = { + "r2": { + "route_maps": { + "rmap_pf_list_2_{}".format(addr_type): [ + { + "action": "permit", + "set": {"weight": 50}, + "match": { + addr_type: { + "prefix_lists": "pf_list_2_{}".format(addr_type) + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, rmap_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify Route-map created verify using show route-map") + # verify rmap_pf_list_1 and rmap_pf_list_2 are present in router r2 + input_dict = { + "r2": { + "route_maps": [ + "rmap_pf_list_1_{}".format(addr_type), + "rmap_pf_list_2_{}".format(addr_type), + ] + } + } + result = verify_route_maps(tgen, input_dict, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply policy RouteMap_1 nbrs 1 2 3 4 to FRR 1") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link1": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link2": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link3": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply policy RouteMap_2 nbrs 5 and 6 to FRR2") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link1": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link2": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link3": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After applying to BGP neighbors verify VM1 IPv4 and IPv6 Route" + " which is denied using prefix list is not present on FRR side" + " routing table , also not able to ping the routes show ip route" + " and VM4 and VM6 IPV4 and IPv6 address are present in local and" + " FRR routing table show ip bgp show ip route" + ) + + dut = "r1" + protocol = "bgp" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib( + tgen, addr_type, dut, input_dict, protocol=protocol, expected=False + ) + assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format( + tc_name, result4 + ) + + step("vm4 should be present in FRR1") + dut = "r1" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + step("vm4 should be present in FRR2") + dut = "r2" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + dut = "r3" + protocol = "bgp" + ntwk_r2_vm6 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + ).network + ) + input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result4 is True, "Testcase {} : Failed.\n Error: {}".format( + tc_name, result4 + ) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/zebra_netlink/test_zebra_netlink.py b/tests/topotests/zebra_netlink/test_zebra_netlink.py index 4da5303641..94baf8438f 100644 --- a/tests/topotests/zebra_netlink/test_zebra_netlink.py +++ b/tests/topotests/zebra_netlink/test_zebra_netlink.py @@ -118,7 +118,12 @@ def test_zebra_netlink_batching(): r1.vtysh_cmd("sharp install routes 2.1.3.7 nexthop 192.168.1.1 100") json_file = "{}/r1/v4_route.json".format(CWD) expected = json.loads(open(json_file).read()) - test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expected,) + test_func = partial( + topotest.router_json_cmp, + r1, + "show ip route json", + expected, + ) _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5) assertmsg = '"r1" JSON output mismatches' assert result is None, assertmsg diff --git a/zebra/connected.c b/zebra/connected.c index 70ea2e3805..c885c533e6 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -402,10 +402,10 @@ void connected_down(struct interface *ifp, struct connected *ifc) * head. */ rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true); + 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true); + 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 9d74aeca28..adbdf54c1f 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1107,7 +1107,7 @@ void rtm_read(struct rt_msghdr *rtm) if (rtm->rtm_type == RTM_CHANGE) rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, NULL, 0, RT_TABLE_MAIN, 0, - 0, true, false); + 0, true); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, @@ -1116,7 +1116,7 @@ void rtm_read(struct rt_msghdr *rtm) else rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0, - 0, true, false); + 0, true); } /* Interface function for the kernel routing table updates. Support diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 1f075cfb4b..370dbaa240 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -715,7 +715,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE, re->table, re->flags, &p, NULL, re->nhe->nhg.nexthop, re->nhe_id, zvrf->table_id, re->metric, re->distance, - false, false); + false); return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index fe7073656c..c385d7326c 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -393,7 +393,7 @@ extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, uint8_t distance, - bool fromkernel, bool connected_down); + bool fromkernel); extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, union g_addr *addr, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index c034ea2fd2..c1a0e6ccd1 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -873,7 +873,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (nhe_id) { rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, NULL, nhe_id, table, metric, - distance, true, false); + distance, true); } else { if (!tb[RTA_MULTIPATH]) { struct nexthop nh; @@ -883,13 +883,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, gate, afi, vrf_id); rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, &nh, 0, table, - metric, distance, true, false); + metric, distance, true); } else { /* XXX: need to compare the entire list of * nexthops here for NLM_F_APPEND stupidity */ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, NULL, 0, table, - metric, distance, true, false); + metric, distance, true); } } } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index f2ff8d53f2..90c6a24e7b 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2080,7 +2080,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance, api.flags, &api.prefix, src_p, NULL, 0, table_id, api.metric, - api.distance, false, false); + api.distance, false); /* Stats */ switch (api.prefix.family) { diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0aea0b6cfa..f4be9a8504 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3088,7 +3088,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, unsigned short instance, uint32_t flags, struct prefix *p, struct prefix_ipv6 *src_p, const struct nexthop *nh, uint32_t nhe_id, uint32_t table_id, uint32_t metric, - uint8_t distance, bool fromkernel, bool connected_down) + uint8_t distance, bool fromkernel) { struct route_table *table; struct route_node *rn; @@ -3294,19 +3294,6 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, rib_delnode(rn, same); } - /* - * This is to force an immediate re-eval of this particular - * node via nexthop tracking. Why? Because there are scenarios - * where the interface is flapping and the normal queuing methodology - * will cause down/up events to very very rarely be combined into - * a non-event from nexthop tracking perspective. Leading - * to some fun timing situations with upper level routing protocol - * trying to and failing to install routes during this blip. Especially - * when zebra is under load. - */ - if (connected_down) - zebra_rib_evaluate_rn_nexthops(rn, - zebra_router_get_next_sequence()); route_unlock_node(rn); return; } |
