Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bgpd: fix ipv4-mapped ipv6 use cases #17019

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 29 additions & 27 deletions bgpd/bgp_nht.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,6 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
afi = BGP_ATTR_MP_NEXTHOP_LEN_IP6(pi->attr) ? AFI_IP6
: AFI_IP;

/* Validation for the ipv4 mapped ipv6 nexthop. */
if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
afi = AFI_IP;
}

/* This will return true if the global IPv6 NH is a link local
* addr */
if (make_prefix(afi, pi, &p) < 0)
Expand Down Expand Up @@ -355,7 +350,9 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
}
return 0;
}

if (afi == AFI_IP6 && p.family == AF_INET)
/* IPv4 mapped IPv6 nexthop address */
afi = AFI_IP;
srte_color = bgp_attr_get_color(pi->attr);

} else if (peer) {
Expand Down Expand Up @@ -1047,19 +1044,11 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
p->u.prefix4 = p_orig->u.prefix4;
p->prefixlen = p_orig->prefixlen;
} else {
if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
ipv4_mapped_ipv6_to_ipv4(
&pi->attr->mp_nexthop_global, &ipv4);
p->u.prefix4 = ipv4;
p->prefixlen = IPV4_MAX_BITLEN;
} else {
if (p_orig->family == AF_EVPN)
p->u.prefix4 =
pi->attr->mp_nexthop_global_in;
else
p->u.prefix4 = pi->attr->nexthop;
p->prefixlen = IPV4_MAX_BITLEN;
}
if (p_orig->family == AF_EVPN)
p->u.prefix4 = pi->attr->mp_nexthop_global_in;
else
p->u.prefix4 = pi->attr->nexthop;
p->prefixlen = IPV4_MAX_BITLEN;
}
break;
case AFI_IP6:
Expand All @@ -1075,6 +1064,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
/* If we receive MP_REACH nexthop with ::(LL)
* or LL(LL), use LL address as nexthop cache.
*/
p->prefixlen = IPV6_MAX_BITLEN;
if (pi->attr &&
pi->attr->mp_nexthop_len ==
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL &&
Expand All @@ -1088,16 +1078,28 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
else if (pi->attr &&
pi->attr->mp_nexthop_len ==
BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
if (CHECK_FLAG(pi->attr->nh_flags,
BGP_ATTR_NH_MP_PREFER_GLOBAL))
p->u.prefix6 =
pi->attr->mp_nexthop_global;
else
if (CHECK_FLAG(pi->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL)) {
if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
ipv4_mapped_ipv6_to_ipv4(&pi->attr->mp_nexthop_global,
&ipv4);
p->u.prefix4 = ipv4;
p->prefixlen = IPV4_MAX_BITLEN;
p->family = AF_INET;
} else
p->u.prefix6 = pi->attr->mp_nexthop_global;
} else
p->u.prefix6 =
pi->attr->mp_nexthop_local;
} else
p->u.prefix6 = pi->attr->mp_nexthop_global;
p->prefixlen = IPV6_MAX_BITLEN;
} else {
if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
ipv4_mapped_ipv6_to_ipv4(&pi->attr->mp_nexthop_global,
&ipv4);
p->u.prefix4 = ipv4;
p->prefixlen = IPV4_MAX_BITLEN;
p->family = AF_INET;
} else
p->u.prefix6 = pi->attr->mp_nexthop_global;
}
}
break;
default:
Expand Down
6 changes: 1 addition & 5 deletions bgpd/bgp_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -9710,11 +9710,7 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
json_object_string_add(json_nexthop_ll, "scope",
"link-local");

if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global,
&attr->mp_nexthop_local) !=
0) &&
!CHECK_FLAG(attr->nh_flags,
BGP_ATTR_NH_MP_PREFER_GLOBAL))
if (!CHECK_FLAG(attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(
json_nexthop_ll, "used");
else
Expand Down
27 changes: 22 additions & 5 deletions bgpd/bgp_updgrp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,9 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
gnh_modified = 1;
}
} else if (IN6_IS_ADDR_UNSPECIFIED(&v6nhglobal)) {
/* the UPDATE is originating from the local router.
* Build the global nexthop.
*/
mod_v6nhg = &peer->nexthop.v6_global;
gnh_modified = 1;
} else if ((peer->sort == BGP_PEER_EBGP)
Expand All @@ -521,16 +524,30 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
*/
mod_v6nhg = &peer->nexthop.v6_global;
gnh_modified = 1;
} else if (IS_MAPPED_IPV6(&v6nhglobal) &&
!IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) {
/* prefer a IPv6 native global address over
* an IPv4-mapped IPv6 address as nexthop when
* forwarding UPDATEs.
*/
mod_v6nhg = &peer->nexthop.v6_global;
gnh_modified = 1;
}

if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) {
if (peer->nexthop.v4.s_addr != INADDR_ANY) {
ipv4_to_ipv4_mapped_ipv6(mod_v6nhg,
peer->nexthop.v4);
}
if (!peer->conf_if && peer->nexthop.v4.s_addr != INADDR_ANY &&
(IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg) ||
(IN6_IS_ADDR_LINKLOCAL(mod_v6nhg) &&
((peer->connection->su.sa.sa_family == AF_INET6 && paf->afi == AFI_IP) ||
(peer->connection->su.sa.sa_family == AF_INET && paf->afi == AFI_IP6))))) {
ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, peer->nexthop.v4);
gnh_modified = 1;
}

if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) {
/* If the interface to the peer has no global IPv6
* address, replace the nexthop in UPDATE with
* the IPv4-mapped IPv6 address if any.
*/
mod_v6nhg = &peer->nexthop.v6_global;
gnh_modified = 1;
}
Expand Down
136 changes: 76 additions & 60 deletions bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,11 +302,12 @@ static int bgp_ifp_down(struct interface *ifp)

static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
{
struct connected *ifc;
struct connected *ifc, *connected;
struct bgp *bgp;
struct peer *peer;
struct prefix *addr;
struct listnode *node, *nnode;
bool v6_ll_in_nh_global;
afi_t afi;
safi_t safi;

Expand All @@ -324,56 +325,61 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
if (!bgp)
return 0;

if (if_is_operative(ifc->ifp)) {
bgp_connected_add(bgp, ifc);
if (!if_is_operative(ifc->ifp))
return 0;

/* If we have learnt of any neighbors on this interface,
* check to kick off any BGP interface-based neighbors,
* but only if this is a link-local address.
*/
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;
bgp_connected_add(bgp, ifc);

for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
if (addr->family == AF_INET)
continue;
/* If we have learnt of any neighbors on this interface,
* check to kick off any BGP interface-based neighbors,
* but only if this is a link-local address.
*/
if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) &&
!list_isempty(ifc->ifp->nbr_connected))
bgp_start_interface_nbrs(bgp, ifc->ifp);
else if (ifc->address->family == AF_INET6 &&
!IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) {
addr = ifc->address;

/*
* 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);
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
v6_ll_in_nh_global = false;

if (IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) {
frr_each (if_connected, ifc->ifp->connected, connected) {
if (connected->address->family != AF_INET6)
continue;
if (!IPV6_ADDR_SAME(&connected->address->u.prefix6,
&peer->nexthop.v6_global))
continue;
/* peer->nexthop.v6_global contains a link-local address
* that needs to be replaced by the global address.
*/
v6_ll_in_nh_global = true;
break;
}
}

/*
* 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 (v6_ll_in_nh_global ||
(peer->conf_if && strcmp(peer->conf_if, ifc->ifp->name) == 0 &&
(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 global addr from %pI6 to %pI6 and send updates",
peer, &peer->nexthop.v6_global, &addr->u.prefix6);
}
memcpy(&peer->nexthop.v6_global, &addr->u.prefix6, IPV6_MAX_BYTELEN);
FOREACH_AFI_SAFI (afi, safi)
bgp_announce_route(peer, afi, safi, true);
}
}
}
Expand All @@ -384,10 +390,14 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
{
struct listnode *node, *nnode;
struct connected *ifc;
struct connected *ifc, *connected;
struct peer *peer;
struct bgp *bgp;
struct prefix *addr;
struct in6_addr *v6_global = NULL;
struct in6_addr *v6_local = NULL;
afi_t afi;
safi_t safi;

bgp = bgp_lookup_by_vrf_id(vrf_id);

Expand All @@ -406,7 +416,17 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)

addr = ifc->address;

if (bgp) {
if (bgp && addr->family == AF_INET6 && !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)) {
/* find another IPv6 global if possible and find the IPv6 link-local */
frr_each (if_connected, ifc->ifp->connected, connected) {
if (connected->address->family != AF_INET6)
continue;
if (IN6_IS_ADDR_LINKLOCAL(&connected->address->u.prefix6))
v6_local = &connected->address->u.prefix6;
else
v6_global = &connected->address->u.prefix6;
}

/*
* When we are using the v6 global as part of the peering
* nexthops and we are removing it, then we need to
Expand All @@ -415,17 +435,13 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
* we do not want the peering to bounce.
*/
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
afi_t afi;
safi_t safi;

if (addr->family == AF_INET)
continue;

if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)
&& memcmp(&peer->nexthop.v6_global,
&addr->u.prefix6, 16)
== 0) {
memset(&peer->nexthop.v6_global, 0, 16);
if (IPV6_ADDR_SAME(&peer->nexthop.v6_global, &addr->u.prefix6)) {
if (v6_global)
IPV6_ADDR_COPY(&peer->nexthop.v6_global, v6_global);
else if (v6_local)
IPV6_ADDR_COPY(&peer->nexthop.v6_global, v6_local);
else
memset(&peer->nexthop.v6_global, 0, IPV6_MAX_BYTELEN);
FOREACH_AFI_SAFI (afi, safi)
bgp_announce_route(peer, afi, safi,
true);
Expand Down
Empty file.
4 changes: 4 additions & 0 deletions tests/topotests/bgp_6vpe_ebgp_topo1/h1/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ipv6 route fd00:200::/64 fd00:100::2
interface eth-pe1
ipv6 address fd00:100::1/64
!
8 changes: 8 additions & 0 deletions tests/topotests/bgp_6vpe_ebgp_topo1/h2/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
ipv6 route fd00:100::/64 fd00:200::5
interface eth-pe2
ipv6 address fd00:200::6/64
ipv6 address fd00:201::6/64
ipv6 address fd00:300::6/64
ipv6 address fd00:400::6/64
ipv6 address fd01:200::6/64
!
13 changes: 13 additions & 0 deletions tests/topotests/bgp_6vpe_ebgp_topo1/pe1/bgp_summary.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ipv6Vpn": {
"routerId": "198.51.100.2",
"as": 65500,
"peers": {
"192.0.2.5": {
"remoteAs": 65501,
"state": "Established",
"peerState": "OK"
}
}
}
}
Loading
Loading