diff options
| -rw-r--r-- | bgpd/bgp_nht.c | 9 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 8 | ||||
| -rw-r--r-- | isisd/isis_lfa.c | 2 | ||||
| -rw-r--r-- | tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py | 289 | ||||
| -rw-r--r-- | tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py | 0 | ||||
| -rw-r--r-- | tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf | 17 | ||||
| -rw-r--r-- | tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf | 14 | ||||
| -rw-r--r-- | tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py | 103 | ||||
| -rw-r--r-- | tests/topotests/bgp_self_prefix/__init__.py | 0 | ||||
| -rw-r--r-- | tests/topotests/bgp_self_prefix/r1/frr.conf | 19 | ||||
| -rw-r--r-- | tests/topotests/bgp_self_prefix/r2/frr.conf | 20 | ||||
| -rw-r--r-- | tests/topotests/bgp_self_prefix/r3/frr.conf | 20 | ||||
| -rw-r--r-- | tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py | 111 | ||||
| -rw-r--r-- | vrrpd/vrrp_packet.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_pw.c | 35 | ||||
| -rw-r--r-- | zebra/zebra_pw.h | 1 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 25 | 
17 files changed, 345 insertions, 330 deletions
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index aaa9e223c3..59566ee6d6 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -347,12 +347,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,  				   &p.u.prefix6))  			ifindex = pi->peer->connection->su.sin6.sin6_scope_id; -		if (!is_bgp_static_route && orig_prefix -		    && prefix_same(&p, orig_prefix)) { +		if (!is_bgp_static_route && orig_prefix && prefix_same(&p, orig_prefix) && +		    CHECK_FLAG(bgp_route->flags, BGP_FLAG_IMPORT_CHECK)) {  			if (BGP_DEBUG(nht, NHT)) { -				zlog_debug( -					"%s(%pFX): prefix loops through itself", -					__func__, &p); +				zlog_debug("%s(%pFX): prefix loops through itself (import-check enabled)", +					   __func__, &p);  			}  			return 0;  		} diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8dbb4e3b04..475b709a07 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -14506,7 +14506,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,  	struct bgp_adj_out *adj = NULL;  	struct bgp_dest *dest;  	struct bgp *bgp; -	struct attr attr; +	struct attr attr, attr_unchanged;  	int ret;  	struct update_subgroup *subgrp;  	struct peer_af *paf = NULL; @@ -14686,6 +14686,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,  				}  				attr = *ain->attr; +				attr_unchanged = *ain->attr;  				route_filtered = false;  				/* Filter prefix using distribute list, @@ -14741,9 +14742,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,  							json_ar, json_net,  							"%pFX", rn_p);  				} else -					route_vty_out_tmp(vty, bgp, dest, rn_p, -							  &attr, safi, use_json, -							  json_ar, wide); +					route_vty_out_tmp(vty, bgp, dest, rn_p, &attr_unchanged, +							  safi, use_json, json_ar, wide);  				bgp_attr_flush(&attr);  				(*output_count)++;  			} diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index 887f27eec5..e0b3a4dca1 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -1064,7 +1064,7 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree,  	for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, vertex)) {  		char buf[VID2STR_BUFFER]; -		if (!VTYPE_IS(vertex->type)) +		if (vertex->type != VTYPE_NONPSEUDO_IS && vertex->type != VTYPE_NONPSEUDO_TE_IS)  			continue;  		/* Skip root node. */ 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 c97fc5f0eb..5662e5935b 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 @@ -831,7 +831,6 @@ def test_bgp_with_loopback_interface(request):          for bgp_neighbor in topo["routers"][routerN]["bgp"]["address_family"]["ipv4"][              "unicast"          ]["neighbor"].keys(): -              # Adding ['source_link'] = 'lo' key:value pair              topo["routers"][routerN]["bgp"]["address_family"]["ipv4"]["unicast"][                  "neighbor" @@ -876,294 +875,6 @@ def test_bgp_with_loopback_interface(request):      write_test_footer(tc_name) -def test_bgp_with_loopback_with_same_subnet_p1(request): -    """ -    Verify routes not installed in zebra when /32 routes received -    with loopback BGP session subnet -    """ - -    tgen = get_topogen() -    if BGP_CONVERGENCE is not True: -        pytest.skip("skipped because of BGP Convergence failure") - -    # test case name -    tc_name = request.node.name -    write_test_header(tc_name) - -    # Creating configuration from JSON -    reset_config_on_routers(tgen) -    step("Delete BGP seesion created initially") -    input_dict_r1 = { -        "r1": {"bgp": {"delete": True}}, -        "r2": {"bgp": {"delete": True}}, -        "r3": {"bgp": {"delete": True}}, -        "r4": {"bgp": {"delete": True}}, -    } -    result = create_router_bgp(tgen, topo, input_dict_r1) -    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - -    step("Create BGP session over loop address") -    topo_modify = deepcopy(topo) - -    for routerN in sorted(topo["routers"].keys()): -        for addr_type in ADDR_TYPES: -            for bgp_neighbor in topo_modify["routers"][routerN]["bgp"][ -                "address_family" -            ][addr_type]["unicast"]["neighbor"].keys(): - -                # Adding ['source_link'] = 'lo' key:value pair -                topo_modify["routers"][routerN]["bgp"]["address_family"][addr_type][ -                    "unicast" -                ]["neighbor"][bgp_neighbor]["dest_link"] = { -                    "lo": {"source_link": "lo", "ebgp_multihop": 2} -                } - -    result = create_router_bgp(tgen, topo_modify["routers"]) -    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - -    step("Disable IPv6 BGP nbr from ipv4 address family") -    raw_config = { -        "r1": { -            "raw_config": [ -                "router bgp {}".format(topo["routers"]["r1"]["bgp"]["local_as"]), -                "address-family ipv4 unicast", -                "no neighbor {} activate".format( -                    topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] -                ), -                "no neighbor {} activate".format( -                    topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0] -                ), -            ] -        }, -        "r2": { -            "raw_config": [ -                "router bgp {}".format(topo["routers"]["r2"]["bgp"]["local_as"]), -                "address-family ipv4 unicast", -                "no neighbor {} activate".format( -                    topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0] -                ), -                "no neighbor {} activate".format( -                    topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0] -                ), -            ] -        }, -        "r3": { -            "raw_config": [ -                "router bgp {}".format(topo["routers"]["r3"]["bgp"]["local_as"]), -                "address-family ipv4 unicast", -                "no neighbor {} activate".format( -                    topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0] -                ), -                "no neighbor {} activate".format( -                    topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] -                ), -                "no neighbor {} activate".format( -                    topo["routers"]["r4"]["links"]["lo"]["ipv6"].split("/")[0] -                ), -            ] -        }, -        "r4": { -            "raw_config": [ -                "router bgp {}".format(topo["routers"]["r4"]["bgp"]["local_as"]), -                "address-family ipv4 unicast", -                "no neighbor {} activate".format( -                    topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0] -                ), -            ] -        }, -    } - -    step("Configure kernel routes") -    result = apply_raw_config(tgen, raw_config) -    assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) - -    r1_ipv4_lo = topo["routers"]["r1"]["links"]["lo"]["ipv4"] -    r1_ipv6_lo = topo["routers"]["r1"]["links"]["lo"]["ipv6"] -    r2_ipv4_lo = topo["routers"]["r2"]["links"]["lo"]["ipv4"] -    r2_ipv6_lo = topo["routers"]["r2"]["links"]["lo"]["ipv6"] -    r3_ipv4_lo = topo["routers"]["r3"]["links"]["lo"]["ipv4"] -    r3_ipv6_lo = topo["routers"]["r3"]["links"]["lo"]["ipv6"] -    r4_ipv4_lo = topo["routers"]["r4"]["links"]["lo"]["ipv4"] -    r4_ipv6_lo = topo["routers"]["r4"]["links"]["lo"]["ipv6"] - -    r1_r2 = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0] -    r2_r1 = topo["routers"]["r2"]["links"]["r1"]["ipv6"].split("/")[0] -    r1_r3 = topo["routers"]["r1"]["links"]["r3"]["ipv6"].split("/")[0] -    r3_r1 = topo["routers"]["r3"]["links"]["r1"]["ipv6"].split("/")[0] -    r2_r3 = topo["routers"]["r2"]["links"]["r3"]["ipv6"].split("/")[0] -    r3_r2 = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0] -    r3_r4 = topo["routers"]["r3"]["links"]["r4"]["ipv6"].split("/")[0] -    r4_r3 = topo["routers"]["r4"]["links"]["r3"]["ipv6"].split("/")[0] - -    r1_r2_ipv4 = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0] -    r2_r1_ipv4 = topo["routers"]["r2"]["links"]["r1"]["ipv4"].split("/")[0] -    r1_r3_ipv4 = topo["routers"]["r1"]["links"]["r3"]["ipv4"].split("/")[0] -    r3_r1_ipv4 = topo["routers"]["r3"]["links"]["r1"]["ipv4"].split("/")[0] -    r2_r3_ipv4 = topo["routers"]["r2"]["links"]["r3"]["ipv4"].split("/")[0] -    r3_r2_ipv4 = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0] -    r3_r4_ipv4 = topo["routers"]["r3"]["links"]["r4"]["ipv4"].split("/")[0] -    r4_r3_ipv4 = topo["routers"]["r4"]["links"]["r3"]["ipv4"].split("/")[0] - -    r1_r2_intf = topo["routers"]["r1"]["links"]["r2"]["interface"] -    r2_r1_intf = topo["routers"]["r2"]["links"]["r1"]["interface"] -    r1_r3_intf = topo["routers"]["r1"]["links"]["r3"]["interface"] -    r3_r1_intf = topo["routers"]["r3"]["links"]["r1"]["interface"] -    r2_r3_intf = topo["routers"]["r2"]["links"]["r3"]["interface"] -    r3_r2_intf = topo["routers"]["r3"]["links"]["r2"]["interface"] -    r3_r4_intf = topo["routers"]["r3"]["links"]["r4"]["interface"] -    r4_r3_intf = topo["routers"]["r4"]["links"]["r3"]["interface"] - -    ipv4_list = [ -        ("r1", r1_r2_intf, r2_ipv4_loopback), -        ("r1", r1_r3_intf, r3_ipv4_loopback), -        ("r2", r2_r1_intf, r1_ipv4_loopback), -        ("r2", r2_r3_intf, r3_ipv4_loopback), -        ("r3", r3_r1_intf, r1_ipv4_loopback), -        ("r3", r3_r2_intf, r2_ipv4_loopback), -        ("r3", r3_r4_intf, r4_ipv4_loopback), -        ("r4", r4_r3_intf, r3_ipv4_loopback), -    ] - -    ipv6_list = [ -        ("r1", r1_r2_intf, r2_ipv6_loopback, r2_r1), -        ("r1", r1_r3_intf, r3_ipv6_loopback, r3_r1), -        ("r2", r2_r1_intf, r1_ipv6_loopback, r1_r2), -        ("r2", r2_r3_intf, r3_ipv6_loopback, r3_r2), -        ("r3", r3_r1_intf, r1_ipv6_loopback, r1_r3), -        ("r3", r3_r2_intf, r2_ipv6_loopback, r2_r3), -        ("r3", r3_r4_intf, r4_ipv6_loopback, r4_r3), -        ("r4", r4_r3_intf, r3_ipv6_loopback, r3_r4), -    ] - -    for dut, intf, loop_addr in ipv4_list: -        result = addKernelRoute(tgen, dut, intf, loop_addr) -        assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) - -    for dut, intf, loop_addr, next_hop in ipv6_list: -        result = addKernelRoute(tgen, dut, intf, loop_addr, next_hop) -        assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) - -    step("Configure static routes") - -    input_dict = { -        "r1": { -            "static_routes": [ -                {"network": r2_ipv4_loopback, "next_hop": r2_r1_ipv4}, -                {"network": r3_ipv4_loopback, "next_hop": r3_r1_ipv4}, -                {"network": r2_ipv6_loopback, "next_hop": r2_r1}, -                {"network": r3_ipv6_loopback, "next_hop": r3_r1}, -            ] -        }, -        "r2": { -            "static_routes": [ -                {"network": r1_ipv4_loopback, "next_hop": r1_r2_ipv4}, -                {"network": r3_ipv4_loopback, "next_hop": r3_r2_ipv4}, -                {"network": r1_ipv6_loopback, "next_hop": r1_r2}, -                {"network": r3_ipv6_loopback, "next_hop": r3_r2}, -            ] -        }, -        "r3": { -            "static_routes": [ -                {"network": r1_ipv4_loopback, "next_hop": r1_r3_ipv4}, -                {"network": r2_ipv4_loopback, "next_hop": r2_r3_ipv4}, -                {"network": r4_ipv4_loopback, "next_hop": r4_r3_ipv4}, -                {"network": r1_ipv6_loopback, "next_hop": r1_r3}, -                {"network": r2_ipv6_loopback, "next_hop": r2_r3}, -                {"network": r4_ipv6_loopback, "next_hop": r4_r3}, -            ] -        }, -        "r4": { -            "static_routes": [ -                {"network": r3_ipv4_loopback, "next_hop": r3_r4_ipv4}, -                {"network": r3_ipv6_loopback, "next_hop": r3_r4}, -            ] -        }, -    } -    result = create_static_routes(tgen, input_dict) -    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - -    step("Verify BGP session convergence") - -    result = verify_bgp_convergence(tgen, topo_modify) -    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - -    step("Configure redistribute connected on R2 and R4") -    input_dict_1 = { -        "r2": { -            "bgp": { -                "address_family": { -                    "ipv4": { -                        "unicast": {"redistribute": [{"redist_type": "connected"}]} -                    }, -                    "ipv6": { -                        "unicast": {"redistribute": [{"redist_type": "connected"}]} -                    }, -                } -            } -        }, -        "r4": { -            "bgp": { -                "address_family": { -                    "ipv4": { -                        "unicast": {"redistribute": [{"redist_type": "connected"}]} -                    }, -                    "ipv6": { -                        "unicast": {"redistribute": [{"redist_type": "connected"}]} -                    }, -                } -            } -        }, -    } - -    result = create_router_bgp(tgen, topo, input_dict_1) -    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - -    step("Verify Ipv4 and Ipv6 network installed in R1 RIB but not in FIB") -    input_dict_r1 = { -        "r1": { -            "static_routes": [ -                {"network": "1.0.2.17/32"}, -                {"network": "2001:db8:f::2:17/128"}, -            ] -        } -    } - -    dut = "r1" -    protocol = "bgp" -    for addr_type in ADDR_TYPES: -        result = verify_fib_routes( -            tgen, addr_type, dut, input_dict_r1, expected=False -        )  # pylint: disable=E1123 -        assert result is not True, ( -            "Testcase {} : Failed \n " -            "Expected: Routes should not be present in {} FIB \n " -            "Found: {}".format(tc_name, dut, result) -        ) - -    step("Verify Ipv4 and Ipv6 network installed in r3 RIB but not in FIB") -    input_dict_r3 = { -        "r3": { -            "static_routes": [ -                {"network": "1.0.4.17/32"}, -                {"network": "2001:db8:f::4:17/128"}, -            ] -        } -    } -    dut = "r3" -    protocol = "bgp" -    for addr_type in ADDR_TYPES: -        result = verify_fib_routes( -            tgen, addr_type, dut, input_dict_r1, expected=False -        )  # pylint: disable=E1123 -        assert result is not True, ( -            "Testcase {} : Failed \n " -            "Expected: Routes should not be present in {} FIB \n " -            "Found: {}".format(tc_name, dut, result) -        ) - -    write_test_footer(tc_name) - -  if __name__ == "__main__":      args = ["-s"] + sys.argv[1:]      sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py b/tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf b/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf new file mode 100644 index 0000000000..01dd4f3c5a --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf @@ -0,0 +1,17 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as external + address-family ipv4 unicast +  neighbor 192.168.1.2 route-map r2 in +  neighbor 192.168.1.2 soft-reconfiguration inbound + exit-address-family +! +route-map r2 permit 10 + set as-path prepend 65000 65000 65000 +exit +! diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf b/tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf new file mode 100644 index 0000000000..86dd8e3389 --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf @@ -0,0 +1,14 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + address-family ipv4 unicast +  network 10.0.0.2/32 + exit-address-family +! diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py b/tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py new file mode 100644 index 0000000000..0b933add2f --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): +    topodef = {"s1": ("r1", "r2")} +    tgen = Topogen(topodef, mod.__name__) +    tgen.start_topology() + +    router_list = tgen.routers() + +    for _, (rname, router) in enumerate(router_list.items(), 1): +        router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + +    tgen.start_router() + + +def teardown_module(mod): +    tgen = get_topogen() +    tgen.stop_topology() + + +def test_bgp_received_routes_with_soft_inbound(): +    tgen = get_topogen() + +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    r1 = tgen.gears["r1"] + +    def _bgp_converge(): +        output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) +        expected = { +            "routes": { +                "10.0.0.2/32": [ +                    { +                        "valid": True, +                        "path": "65000 65000 65000 65002", +                        "nexthops": [ +                            { +                                "ip": "192.168.1.2", +                            } +                        ], +                    } +                ] +            } +        } + +        return topotest.json_cmp(output, expected) + +    test_func = functools.partial( +        _bgp_converge, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) +    assert result is None, "Can't converge" + +    def _bgp_check_receveived_routes(): +        output = json.loads( +            r1.vtysh_cmd( +                "show bgp ipv4 unicast neighbors 192.168.1.2 received-routes json" +            ) +        ) +        expected = { +            "receivedRoutes": { +                "10.0.0.2/32": { +                    "valid": True, +                    "path": "65002", +                    "nextHop": "192.168.1.2", +                } +            } +        } + +        return topotest.json_cmp(output, expected) + +    test_func = functools.partial( +        _bgp_check_receveived_routes, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) +    assert result is None, "Can't converge" + + +if __name__ == "__main__": +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_self_prefix/__init__.py b/tests/topotests/bgp_self_prefix/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_self_prefix/__init__.py diff --git a/tests/topotests/bgp_self_prefix/r1/frr.conf b/tests/topotests/bgp_self_prefix/r1/frr.conf new file mode 100644 index 0000000000..879afb1947 --- /dev/null +++ b/tests/topotests/bgp_self_prefix/r1/frr.conf @@ -0,0 +1,19 @@ +! +int lo + ip address 10.0.0.1/32 +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.2 remote-as internal + neighbor 10.0.0.2 update-source lo + neighbor 10.0.0.2 next-hop-self + neighbor 10.0.0.3 remote-as external + neighbor 10.0.0.3 update-source lo + neighbor 10.0.0.3 next-hop-self +! +ip route 10.0.0.2/32 192.168.1.2 +ip route 10.0.0.3/32 192.168.1.3 diff --git a/tests/topotests/bgp_self_prefix/r2/frr.conf b/tests/topotests/bgp_self_prefix/r2/frr.conf new file mode 100644 index 0000000000..eb0db356ea --- /dev/null +++ b/tests/topotests/bgp_self_prefix/r2/frr.conf @@ -0,0 +1,20 @@ +! +int lo + ip address 10.0.0.2/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.1 remote-as internal + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + neighbor 10.0.0.1 update-source lo + neighbor 10.0.0.1 next-hop-self + address-family ipv4 unicast +  network 10.0.0.2/32 + exit-address-family +! +ip route 10.0.0.1/32 192.168.1.1 diff --git a/tests/topotests/bgp_self_prefix/r3/frr.conf b/tests/topotests/bgp_self_prefix/r3/frr.conf new file mode 100644 index 0000000000..e2348f4a68 --- /dev/null +++ b/tests/topotests/bgp_self_prefix/r3/frr.conf @@ -0,0 +1,20 @@ +! +int lo + ip address 10.0.0.3/32 +! +int r3-eth0 + ip address 192.168.1.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.1 remote-as external + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + neighbor 10.0.0.1 update-source lo + neighbor 10.0.0.1 next-hop-self + address-family ipv4 unicast +  network 10.0.0.3/32 + exit-address-family +! +ip route 10.0.0.1/32 192.168.1.1 diff --git a/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py b/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py new file mode 100644 index 0000000000..1045800368 --- /dev/null +++ b/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): +    topodef = {"s1": ("r1", "r2", "r3")} +    tgen = Topogen(topodef, mod.__name__) +    tgen.start_topology() + +    router_list = tgen.routers() + +    for _, (rname, router) in enumerate(router_list.items(), 1): +        router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + +    tgen.start_router() + + +def teardown_module(mod): +    tgen = get_topogen() +    tgen.stop_topology() + + +def test_bgp_self_prefix(): +    tgen = get_topogen() + +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    r1 = tgen.gears["r1"] +    r3 = tgen.gears["r3"] + +    def _bgp_converge(): +        output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) +        expected = { +            "routes": { +                "10.0.0.2/32": [ +                    { +                        "valid": True, +                        "path": "", +                        "nexthops": [ +                            {"ip": "10.0.0.2", "hostname": "r2", "afi": "ipv4"} +                        ], +                    } +                ], +                "10.0.0.3/32": [ +                    { +                        "valid": True, +                        "path": "65003", +                        "nexthops": [ +                            {"ip": "10.0.0.3", "hostname": "r3", "afi": "ipv4"} +                        ], +                    } +                ], +            } +        } + +        return topotest.json_cmp(output, expected) + +    test_func = functools.partial( +        _bgp_converge, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) +    assert result is None, "Can't converge" + +    def _bgp_check_received_routes(): +        output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast json")) +        expected = { +            "routes": { +                "10.0.0.2/32": [ +                    { +                        "valid": True, +                        "bestpath": True, +                        "nexthops": [ +                            {"ip": "10.0.0.1", "hostname": "r1", "afi": "ipv4"} +                        ], +                    } +                ], +            } +        } + +        return topotest.json_cmp(output, expected) + +    test_func = functools.partial( +        _bgp_check_received_routes, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) +    assert result is None, "Can't see 10.0.0.2/32" + + +if __name__ == "__main__": +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args)) diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index 36494c7df8..a2fb2bc321 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -234,7 +234,7 @@ ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph,  	} else if (family == AF_INET6) {  		struct cmsghdr *c; -		for (c = CMSG_FIRSTHDR(m); c != NULL; CMSG_NXTHDR(m, c)) { +		for (c = CMSG_FIRSTHDR(m); c != NULL; c = CMSG_NXTHDR(m, c)) {  			if (c->cmsg_level == IPPROTO_IPV6  			    && c->cmsg_type == IPV6_HOPLIMIT)  				break; diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index deed3b6ad3..c8ffaf0bbe 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -147,7 +147,6 @@ void zebra_pw_update(struct zebra_pw *pw)  {  	if (zebra_pw_check_reachability(pw) < 0) {  		zebra_pw_uninstall(pw); -		zebra_pw_install_failure(pw, PW_NOT_FORWARDING);  		/* wait for NHT and try again later */  	} else {  		/* @@ -167,12 +166,17 @@ static void zebra_pw_install(struct zebra_pw *pw)  	hook_call(pw_install, pw);  	if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) { +		/* +		 * Realistically this is never going to fail passing +		 * the pw data down to the dplane.  The failure modes +		 * look like impossible events but we still return +		 * on them.... but I don't see a real clean way to remove this +		 * at all.  So let's just leave the retry mechanism for +		 * the moment. +		 */  		zebra_pw_install_failure(pw, PW_NOT_FORWARDING);  		return;  	} - -	if (pw->status != PW_FORWARDING) -		zebra_pw_update_status(pw, PW_FORWARDING);  }  static void zebra_pw_uninstall(struct zebra_pw *pw) @@ -188,9 +192,28 @@ static void zebra_pw_uninstall(struct zebra_pw *pw)  	/* ignore any possible error */  	hook_call(pw_uninstall, pw);  	dplane_pw_uninstall(pw); +} -	if (zebra_pw_enabled(pw)) -		zebra_pw_update_status(pw, PW_NOT_FORWARDING); +void zebra_pw_handle_dplane_results(struct zebra_dplane_ctx *ctx) +{ +	struct zebra_pw *pw; +	struct zebra_vrf *vrf; +	enum dplane_op_e op; + +	op = dplane_ctx_get_op(ctx); + +	vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); +	pw = zebra_pw_find(vrf, dplane_ctx_get_ifname(ctx)); + +	if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { +		if (pw) +			zebra_pw_install_failure(pw, dplane_ctx_get_pw_status(ctx)); +	} else { +		if (op == DPLANE_OP_PW_INSTALL && pw->status != PW_FORWARDING) +			zebra_pw_update_status(pw, PW_FORWARDING); +		else if (op == DPLANE_OP_PW_UNINSTALL && zebra_pw_enabled(pw)) +			zebra_pw_update_status(pw, PW_NOT_FORWARDING); +	}  }  /* diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index 431d663f7c..e037a55048 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -64,6 +64,7 @@ void zebra_pw_init_vrf(struct zebra_vrf *);  void zebra_pw_exit_vrf(struct zebra_vrf *);  void zebra_pw_terminate(void);  void zebra_pw_vty_init(void); +void zebra_pw_handle_dplane_results(struct zebra_dplane_ctx *ctx);  #ifdef __cplusplus  } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 2d2be4fc78..8ebc193fba 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4851,29 +4851,6 @@ void rib_close_table(struct route_table *table)  }  /* - * Handler for async dataplane results after a pseudowire installation - */ -static void handle_pw_result(struct zebra_dplane_ctx *ctx) -{ -	struct zebra_pw *pw; -	struct zebra_vrf *vrf; - -	/* The pseudowire code assumes success - we act on an error -	 * result for installation attempts here. -	 */ -	if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL) -		return; - -	if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { -		vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); -		pw = zebra_pw_find(vrf, dplane_ctx_get_ifname(ctx)); -		if (pw) -			zebra_pw_install_failure(pw, -						 dplane_ctx_get_pw_status(ctx)); -	} -} - -/*   * Handle results from the dataplane system. Dequeue update context   * structs, dispatch to appropriate internal handlers.   */ @@ -4979,7 +4956,7 @@ static void rib_process_dplane_results(struct event *thread)  			case DPLANE_OP_PW_INSTALL:  			case DPLANE_OP_PW_UNINSTALL: -				handle_pw_result(ctx); +				zebra_pw_handle_dplane_results(ctx);  				break;  			case DPLANE_OP_SYS_ROUTE_ADD:  | 
