mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-11 05:23:59 +00:00
bgpd: BGP does not update next-hop when global V6 address is configured
When primary global v6 unicast address is configured on an unnumbered interface, BGP does not re-advertise updates out with the new global v6 address as the nexthop Signed-off-by: Pdoijode <pdoijode@nvidia.com>
This commit is contained in:
parent
7205c3bb19
commit
bc6d1b151f
@ -305,6 +305,11 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
|
||||
{
|
||||
struct connected *ifc;
|
||||
struct bgp *bgp;
|
||||
struct peer *peer;
|
||||
struct prefix *addr;
|
||||
struct listnode *node, *nnode;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
bgp = bgp_lookup_by_vrf_id(vrf_id);
|
||||
|
||||
@ -330,6 +335,48 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)
|
||||
&& !list_isempty(ifc->ifp->nbr_connected))
|
||||
bgp_start_interface_nbrs(bgp, ifc->ifp);
|
||||
else {
|
||||
addr = ifc->address;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
|
||||
if (addr->family == AF_INET)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If the Peer's interface name matches the
|
||||
* interface name for which BGP received the
|
||||
* update and if the received interface address
|
||||
* is a globalV6 and if the peer is currently
|
||||
* using a v4-mapped-v6 addr or a link local
|
||||
* address, then copy the Rxed global v6 addr
|
||||
* into peer's v6_global and send updates out
|
||||
* with new nexthop addr.
|
||||
*/
|
||||
if ((peer->conf_if &&
|
||||
(strcmp(peer->conf_if, ifc->ifp->name) ==
|
||||
0)) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) &&
|
||||
((IS_MAPPED_IPV6(
|
||||
&peer->nexthop.v6_global)) ||
|
||||
IN6_IS_ADDR_LINKLOCAL(
|
||||
&peer->nexthop.v6_global))) {
|
||||
|
||||
if (bgp_debug_zebra(ifc->address)) {
|
||||
zlog_debug(
|
||||
"Update peer %pBP's current intf addr %pI6 and send updates",
|
||||
peer,
|
||||
&peer->nexthop
|
||||
.v6_global);
|
||||
}
|
||||
memcpy(&peer->nexthop.v6_global,
|
||||
&addr->u.prefix6,
|
||||
IPV6_MAX_BYTELEN);
|
||||
FOREACH_AFI_SAFI (afi, safi)
|
||||
bgp_announce_route(peer, afi,
|
||||
safi, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -26,13 +26,17 @@ import os
|
||||
import sys
|
||||
import time
|
||||
import pytest
|
||||
import functools
|
||||
import json
|
||||
|
||||
# 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, "../../"))
|
||||
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
|
||||
from lib.common_config import (
|
||||
write_test_header,
|
||||
@ -288,7 +292,6 @@ def test_unnumbered_loopback_ebgp_nbr_p0(request):
|
||||
" received on R2 BGP and routing table , "
|
||||
"verify using show ip bgp, show ip route for IPv4 routes ."
|
||||
)
|
||||
|
||||
llip = get_llip("r1", "r2-link0")
|
||||
assert llip is not None, "Testcase {} : Failed \n Error: {}".format(tc_name, llip)
|
||||
|
||||
@ -582,6 +585,195 @@ def test_restart_frr_p2(request):
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_configure_gua_on_unnumbered_intf(request):
|
||||
"""
|
||||
Configure a global V6 address on an unnumbered interface on R1
|
||||
|
||||
"""
|
||||
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 IPv6 EBGP Unnumbered session between R1 and R2")
|
||||
step("Enable capability extended-nexthop on both the IPv6 BGP peers")
|
||||
step("Activate same IPv6 nbr from IPv4 unicast family")
|
||||
step("Enable cap ext nh on r1 and r2 and activate in ipv4 addr family")
|
||||
step("Verify bgp convergence as ipv6 nbr is enabled on ipv4 addr family.")
|
||||
bgp_convergence = verify_bgp_convergence(tgen, topo)
|
||||
assert bgp_convergence is True, "Testcase {} :Failed \n Error: {}".format(
|
||||
tc_name, bgp_convergence
|
||||
)
|
||||
|
||||
step(" Configure 5 IPv4 static" " routes on R1, Nexthop as different links of R0")
|
||||
for rte in range(0, NO_OF_RTES):
|
||||
# Create Static routes
|
||||
input_dict = {
|
||||
"r1": {
|
||||
"static_routes": [
|
||||
{
|
||||
"network": NETWORK["ipv4"][rte],
|
||||
"no_of_ip": 1,
|
||||
"next_hop": NEXT_HOP["ipv4"][rte],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
result = create_static_routes(tgen, input_dict)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
||||
tc_name, result
|
||||
)
|
||||
|
||||
step(
|
||||
"Advertise static routes from IPv4 unicast family and IPv6 "
|
||||
"unicast family respectively from R1 using red static cmd "
|
||||
"Advertise loopback from IPv4 unicast family using network command "
|
||||
"from R1"
|
||||
)
|
||||
|
||||
configure_bgp_on_r1 = {
|
||||
"r1": {
|
||||
"bgp": {
|
||||
"address_family": {
|
||||
"ipv4": {
|
||||
"unicast": {
|
||||
"redistribute": [{"redist_type": "static"}],
|
||||
"advertise_networks": [
|
||||
{"network": NETWORK_CMD_IP, "no_of_network": 1}
|
||||
],
|
||||
}
|
||||
},
|
||||
"ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result = create_router_bgp(tgen, topo, configure_bgp_on_r1)
|
||||
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
r2 = tgen.gears["r2"]
|
||||
|
||||
def bgp_prefix_received_gua_nh(router):
|
||||
output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast 11.0.20.1/32 json"))
|
||||
expected = {
|
||||
"prefix": "11.0.20.1/32",
|
||||
"paths": [
|
||||
{
|
||||
"nexthops": [
|
||||
{
|
||||
"ip": "5001:dead:beef::1",
|
||||
"hostname": "r1",
|
||||
"afi": "ipv6",
|
||||
"scope": "global",
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
return topotest.json_cmp(output, expected)
|
||||
|
||||
def bgp_prefix_received_v4_mapped_v6_nh(router):
|
||||
output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast 11.0.20.1/32 json"))
|
||||
expected = {
|
||||
"prefix": "11.0.20.1/32",
|
||||
"paths": [
|
||||
{
|
||||
"nexthops": [
|
||||
{
|
||||
"ip": "::ffff:a00:501",
|
||||
"hostname": "r1",
|
||||
"afi": "ipv6",
|
||||
"scope": "global",
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
return topotest.json_cmp(output, expected)
|
||||
|
||||
step("Configure a global V6 address on an unnumbered interface on R1")
|
||||
output = tgen.gears["r1"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
interface r1-r2-eth5
|
||||
ipv6 address 5001:dead:beef::1/126
|
||||
!
|
||||
"""
|
||||
)
|
||||
|
||||
# verify that r2 has received prefix with GUA as nexthop
|
||||
test_func = functools.partial(bgp_prefix_received_gua_nh, r2)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assert (
|
||||
result is None
|
||||
), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \
|
||||
is not 5001:dead:beef::1".format(
|
||||
tc_name
|
||||
)
|
||||
|
||||
step("Configure a secondary global V6 address on an unnumbered interface on R1")
|
||||
output = tgen.gears["r1"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
interface r1-r2-eth5
|
||||
ipv6 address 7771:dead:beef::1/126
|
||||
!
|
||||
"""
|
||||
)
|
||||
# verify that r1 did not readvertise the prefix with secondary V6 address as the nexthop
|
||||
test_func = functools.partial(bgp_prefix_received_gua_nh, r2)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assert (
|
||||
result is None
|
||||
), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \
|
||||
is not 5001:dead:beef::1".format(
|
||||
tc_name
|
||||
)
|
||||
|
||||
step("Unconfigure the secondary global V6 address from unnumbered interface on R1")
|
||||
output = tgen.gears["r1"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
interface r1-r2-eth5
|
||||
no ipv6 address 7771:dead:beef::1/126
|
||||
!
|
||||
"""
|
||||
)
|
||||
# verify that r1 still has the prefix with primary GUA as the nexthop
|
||||
test_func = functools.partial(bgp_prefix_received_gua_nh, r2)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assert (
|
||||
result is None
|
||||
), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \
|
||||
is not 5001:dead:beef::1".format(
|
||||
tc_name
|
||||
)
|
||||
|
||||
step("Unconfigure the primary global V6 address from unnumbered interface on R1")
|
||||
output = tgen.gears["r1"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
interface r1-r2-eth5
|
||||
no ipv6 address 5001:dead:beef::1/126
|
||||
!
|
||||
"""
|
||||
)
|
||||
# verify that r1 has rcvd the prefix with v4-mapped-v6 address as the nexthop
|
||||
test_func = functools.partial(bgp_prefix_received_v4_mapped_v6_nh, r2)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assert (
|
||||
result is None
|
||||
), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \
|
||||
is not ::ffff:a00:501".format(
|
||||
tc_name
|
||||
)
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
||||
|
Loading…
Reference in New Issue
Block a user