Skip to content

Commit

Permalink
Merge pull request FRRouting#16990 from lsang6WIND/label-per-nexthop
Browse files Browse the repository at this point in the history
bgpd: fix prefix same as nexthop in label per nexthop
  • Loading branch information
riw777 authored Oct 29, 2024
2 parents e42dd44 + 3c2949e commit 4a6e1c0
Show file tree
Hide file tree
Showing 3 changed files with 376 additions and 36 deletions.
9 changes: 9 additions & 0 deletions bgpd/bgp_mplsvpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,15 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi,
return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]);
}

if (is_bgp_static_route && pi->nexthop->nexthop->type == NEXTHOP_TYPE_IFINDEX) {
/* "network" imported prefixes from vrf
* fallback to per-vrf label.
*/

bgp_mplsvpn_path_nh_label_unlink(pi);
return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]);
}

return _vpn_leak_from_vrf_get_per_nexthop_label(pi, to_bgp, from_bgp,
afi);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def bgp_vpnv4_table_check(
test_func = functools.partial(
check_bgp_vpnv4_prefix_presence, router, prefix, table_version
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "{}, prefix ipv4 vpn {} is not installed yet".format(
router.name, prefix
)
Expand Down Expand Up @@ -321,7 +321,7 @@ def mpls_table_check(router, blacklist=None, label_list=None, whitelist=None):
test_func = functools.partial(
check_show_mpls_table, router, blacklist, label_list, whitelist
)
success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, result = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "{}, MPLS labels check fail: {}".format(router.name, result)


Expand All @@ -347,10 +347,37 @@ def check_show_bgp_vpn_prefix_found(router, ipversion, prefix, rd):
return topotest.json_cmp(output, expected)


def check_show_mpls_table_entry_label_found(router, inlabel, interface):
output = json.loads(router.vtysh_cmd("show mpls table {} json".format(inlabel)))
def check_show_mpls_table_entry_label_found_nexthop(
expected_router, get_router, network, nexthop
):
label = get_mpls_label(get_router, network)
if label < 0:
return False

output = json.loads(
expected_router.vtysh_cmd("show mpls table {} json".format(label))
)
expected = {
"inLabel": label,
"installed": True,
"nexthops": [{"nexthop": nexthop}],
}
return topotest.json_cmp(output, expected)


def check_show_mpls_table_entry_label_found(
expected_router, get_router, interface, network=None, label=None
):
if not label:
label = get_mpls_label(get_router, network)
if label < 0:
return False

output = json.loads(
expected_router.vtysh_cmd("show mpls table {} json".format(label))
)
expected = {
"inLabel": inlabel,
"inLabel": label,
"installed": True,
"nexthops": [{"interface": interface}],
}
Expand Down Expand Up @@ -395,6 +422,17 @@ def mpls_entry_get_interface(router, label):
return outgoing_interface


def get_mpls_label(router, network):
label = router.vtysh_cmd(
"show ip route vrf vrf1 %s json" % network,
isjson=True,
)
label = label.get(f"{network}", [{}])[0].get("nexthops", [{}])[0]
label = int(label.get("labels", [-1])[0])

return label


def test_protocols_convergence():
"""
Assert that all protocols have converged
Expand All @@ -415,7 +453,7 @@ def test_protocols_convergence():
"show bgp vrf vrf1 ipv4 json",
expected,
)
_, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
_, result = topotest.run_and_expect(test_func, None, count=10, wait=3)
assertmsg = '"{}" JSON output mismatches'.format(router.name)
assert result is None, assertmsg

Expand All @@ -429,7 +467,7 @@ def test_protocols_convergence():
"show bgp ipv4 vpn json",
expected,
)
_, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
_, result = topotest.run_and_expect(test_func, None, count=10, wait=3)
assertmsg = '"{}" JSON output mismatches'.format(router.name)
assert result is None, assertmsg

Expand Down Expand Up @@ -471,7 +509,7 @@ def _bgp_prefix_not_found(router, vrf, ipversion, prefix):
test_func = functools.partial(
_bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv4", "172.31.0.11/32"
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert (
success
), "r1, prefix 172.31.0.11/32 from r11 did not disappear. r11 still connected to rr ?"
Expand Down Expand Up @@ -509,7 +547,7 @@ def test_flapping_bgp_vrf_up():
"172.31.0.11/32",
"444:1",
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert (
success
), "r2, prefix 172.31.0.11/32 from r11 not present. r11 still disconnected from rr ?"
Expand Down Expand Up @@ -539,7 +577,7 @@ def test_recursive_route():
"172.31.0.30/32",
"444:1",
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "r2, vpnv4 update 172.31.0.30 not found"

bgp_vpnv4_table_check(tgen.gears["r2"], group=PREFIXES_R11 + ["172.31.0.30/32"])
Expand All @@ -565,7 +603,7 @@ def test_recursive_route():
"172.31.0.30/32",
"444:1",
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "r2, vpnv4 update 172.31.0.30 still present"


Expand All @@ -591,7 +629,7 @@ def test_prefix_changes_interface():
"172.31.0.50/32",
"444:1",
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "r2, vpnv4 update 172.31.0.50 not found"

# diagnostic
Expand Down Expand Up @@ -637,7 +675,7 @@ def test_prefix_changes_interface():
"444:1",
label=oldlabel,
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert (
success
), "r2, vpnv4 update 172.31.0.50 with old label {0} still present".format(oldlabel)
Expand All @@ -654,7 +692,7 @@ def test_prefix_changes_interface():
"172.31.0.50/32",
"444:1",
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "r2, vpnv4 update 172.31.0.50 not found"

label_list = set()
Expand Down Expand Up @@ -719,9 +757,13 @@ def test_changing_default_label_value():
"r1, mpls table, check that MPLS entry with inLabel set to 222 has vrf1 interface"
)
test_func = functools.partial(
check_show_mpls_table_entry_label_found, router, 222, "vrf1"
check_show_mpls_table_entry_label_found,
tgen.gears["r1"],
router,
"vrf1",
label=222,
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "r1, mpls entry with label 222 not found"

# check label repartition is ok
Expand Down Expand Up @@ -769,7 +811,7 @@ def test_unconfigure_allocation_mode_nexthop():
test_func = functools.partial(
check_show_mpls_table_entry_label_not_found, router, 17
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "r1, mpls entry with label 17 still present"

# Check vpnv4 routes from r1
Expand Down Expand Up @@ -821,7 +863,7 @@ def test_reconfigure_allocation_mode_nexthop():
test_func = functools.partial(
check_show_mpls_table_entry_label_not_found, router, 17
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "r1, mpls entry with label 17 still present"

# Check vpnv4 routes from r1
Expand All @@ -837,6 +879,126 @@ def test_reconfigure_allocation_mode_nexthop():
mpls_table_check(router, label_list=label_list)


def test_network_command():
"""
Test with network declaration
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
logger.info("Disabling redistribute static")
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nno redistribute static\n",
isjson=False,
)
logger.info("Checking BGP VPNv4 labels on r2")
for p in ["172.31.0.24/32", "172.31.0.15/32"]:
test_func = functools.partial(
check_show_bgp_vpn_prefix_not_found, tgen.gears["r2"], "ipv4", p, "444:1"
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "network %s should not present on r2" % p

logger.info("Use network command for host networks declared in static instead")
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nnetwork 172.31.0.14/32\n",
isjson=False,
)
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nnetwork 172.31.0.15/32\n",
isjson=False,
)
logger.info("Checking BGP VPNv4 labels on r2")
bgp_vpnv4_table_check(tgen.gears["r2"], group=["172.31.0.12/32", "172.31.0.15/32"])
bgp_vpnv4_table_check(tgen.gears["r2"], group=["172.31.0.14/32"])
mpls_table_check(tgen.gears["r1"], whitelist=["192.0.2.14"])

logger.info(" Remove network to 172.31.0.14/32")
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nno network 172.31.0.14/32\n",
isjson=False,
)
test_func = functools.partial(
check_show_bgp_vpn_prefix_not_found,
tgen.gears["r2"],
"ipv4",
"172.31.0.14/32",
"444:1",
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "network 172.31.0.14/32 should not present on r2"
mpls_table_check(tgen.gears["r1"], blacklist=["192.0.2.14"])

logger.info("Disabling redistribute connected and enabling redistribute static")
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\n"
"redistribute static\n no redistribute connected",
isjson=False,
)
logger.info("Use network command for connect network 192.168.255.0/24 in vrf")
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\n"
"network 192.168.255.0/24\n",
isjson=False,
)
logger.info("Checking BGP VPNv4 labels on r2")
bgp_vpnv4_table_check(tgen.gears["r2"], group=["192.168.255.0/24"])
logger.info("Checking no mpls entry associated to 192.168.255.0/24")
mpls_table_check(tgen.gears["r1"], blacklist=["192.168.255.0"])
logger.info("Checking 192.168.255.0/24 fallback to vrf")
test_func = functools.partial(
check_show_mpls_table_entry_label_found,
tgen.gears["r1"],
tgen.gears["r2"],
"vrf1",
network="192.168.255.0/24",
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "192.168.255.0/24 does not fallback to vrf"

logger.info(
"Use network command for statically routed network 192.168.3.0/24 in vrf"
)
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nvrf vrf1\n" "ip route 192.168.3.0/24 192.0.2.11\n"
)
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\n"
"network 192.168.3.0/24\n",
isjson=False,
)
logger.info("Checking 192.168.3.0/24 route on r2")
test_func = functools.partial(
check_show_mpls_table_entry_label_found_nexthop,
tgen.gears["r1"],
tgen.gears["r2"],
"192.168.3.0/24",
"192.0.2.11",
)
success, _ = topotest.run_and_expect(test_func, None, count=10, wait=3)
assert success, "label from r2 is not present on r1 for 192.168.3.0/24"

# diagnostic
logger.info("Dumping label nexthop table")
tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 label-nexthop detail", isjson=False)
logger.info("Dumping bgp network import-check-table")
tgen.gears["r1"].vtysh_cmd(
"show bgp vrf vrf1 import-check-table detail", isjson=False
)

logger.info("Restoring 172.31.0.14 prefix on r1")
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nnetwork 172.31.0.14/32\n",
isjson=False,
)
logger.info("Restoring redistribute connected")
tgen.gears["r1"].vtysh_cmd(
"configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\n"
"no redistribute static\n redistribute connected",
isjson=False,
)


def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
Expand Down
Loading

0 comments on commit 4a6e1c0

Please sign in to comment.