Skip to content

Commit

Permalink
Merge pull request #15614 from louis-6wind/fix-6pe-address
Browse files Browse the repository at this point in the history
bgpd: fix ipv4-mapped ipv6 on non 6pe
  • Loading branch information
ton31337 committed May 10, 2024
2 parents 5111982 + f1b8364 commit b3600d8
Show file tree
Hide file tree
Showing 65 changed files with 2,378 additions and 99 deletions.
41 changes: 18 additions & 23 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 @@ -1041,19 +1036,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 @@ -1069,6 +1056,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 @@ -1083,15 +1071,22 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
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
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;
} 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;
}
break;
default:
Expand Down
5 changes: 1 addition & 4 deletions bgpd/bgp_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -9648,10 +9648,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,
if (!CHECK_FLAG(attr->nh_flags,
BGP_ATTR_NH_MP_PREFER_GLOBAL))
json_object_boolean_true_add(
json_nexthop_ll, "used");
Expand Down
9 changes: 3 additions & 6 deletions bgpd/bgp_updgrp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -525,12 +525,9 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,

if (peer->nexthop.v4.s_addr != INADDR_ANY &&
(IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg) ||
(peer->connection->su.sa.sa_family == AF_INET &&
paf->afi == AFI_IP6))) {
/* set a IPv4 mapped IPv6 address if no global IPv6
* address is found or if announcing IPv6 prefix
* over an IPv4 BGP session.
*/
(IN6_IS_ADDR_LINKLOCAL(mod_v6nhg) &&
peer->connection->su.sa.sa_family == AF_INET6 &&
paf->afi == AFI_IP))) {
ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, peer->nexthop.v4);
gnh_modified = 1;
}
Expand Down
150 changes: 90 additions & 60 deletions bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,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 @@ -325,56 +326,70 @@ 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 @@ -385,10 +400,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 @@ -407,7 +426,18 @@ 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 @@ -416,17 +446,17 @@ 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.
6 changes: 6 additions & 0 deletions tests/topotests/bgp_nexthop_mp_ipv4_6/h1/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ipv6 route ::/0 fd00:100::2
ip route 0.0.0.0/0 192.168.1.2
interface eth-r1
ip address 192.168.1.1/24
ipv6 address fd00:100::1/64
!
6 changes: 6 additions & 0 deletions tests/topotests/bgp_nexthop_mp_ipv4_6/h2/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ipv6 route ::/0 fd00:700::2
ip route 0.0.0.0/0 192.168.7.2
interface eth-r7
ip address 192.168.7.1/24
ipv6 address fd00:700::1/64
!
6 changes: 6 additions & 0 deletions tests/topotests/bgp_nexthop_mp_ipv4_6/h3/zebra.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ipv6 route ::/0 fd00:800::2
ip route 0.0.0.0/0 192.168.8.2
interface eth-r8
ip address 192.168.8.1/24
ipv6 address fd00:800::1/64
!
70 changes: 70 additions & 0 deletions tests/topotests/bgp_nexthop_mp_ipv4_6/r1/bgp_ipv4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"routes": {
"192.168.1.0/24": [
{
"valid": true,
"bestpath": true,
"path": "",
"nexthops": [
{
"ip": "0.0.0.0",
"afi": "ipv4",
"used": true
}
]
}
],
"192.168.7.0/24": [
{
"valid": true,
"multipath": true,
"path": "65000 65700",
"nexthops": [
{
"ip": "172.16.1.3",
"afi": "ipv4",
"used": true
}
]
},
{
"valid": true,
"bestpath": true,
"path": "65000 65700",
"nexthops": [
{
"ip": "172.16.0.2",
"afi": "ipv4",
"used": true
}
]
}
],
"192.168.8.0/24": [
{
"valid": true,
"multipath": true,
"path": "65000 65800",
"nexthops": [
{
"ip": "172.16.1.3",
"afi": "ipv4",
"used": true
}
]
},
{
"valid": true,
"bestpath": true,
"path": "65000 65800",
"nexthops": [
{
"ip": "172.16.0.2",
"afi": "ipv4",
"used": true
}
]
}
]
}
}

0 comments on commit b3600d8

Please sign in to comment.