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

Fix for nexthop as IPv4 mapped IPv6 address #6454

Closed
Closed
Show file tree
Hide file tree
Changes from 4 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
16 changes: 14 additions & 2 deletions bgpd/bgp_nht.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
if (!is_bgp_static_route)
afi = BGP_ATTR_NEXTHOP_AFI_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 */
Expand Down Expand Up @@ -532,6 +536,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
: 0;
struct bgp_node *net = pi->net;
const struct prefix *p_orig = bgp_node_get_prefix(net);
struct in_addr ipv4;

if (p_orig->family == AF_FLOWSPEC) {
if (!pi->peer)
Expand All @@ -547,8 +552,15 @@ 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 {
p->u.prefix4 = pi->attr->nexthop;
p->prefixlen = IPV4_MAX_BITLEN;
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.prefix4 = pi->attr->nexthop;
p->prefixlen = IPV4_MAX_BITLEN;
}
}
break;
case AFI_IP6:
Expand Down
16 changes: 15 additions & 1 deletion bgpd/bgp_updgrp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,21 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
gnh_modified = 1;
}

if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) {
if (peer->nexthop.v4.s_addr) {
ipv4_to_ipv4_mapped_ipv6(mod_v6nhg,
peer->nexthop.v4);
}
} else {
if (peer->nexthop.v4.s_addr
&& (!IN6_IS_ADDR_LINKLOCAL(
&peer->nexthop.v6_local))) {
ipv4_to_ipv4_mapped_ipv6(mod_v6nhg,
peer->nexthop.v4);
gnh_modified = 1;
}
}

if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
|| nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
stream_get_from(&v6nhlocal, s, offset_nhlocal,
Expand Down Expand Up @@ -818,7 +833,6 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
subgrp, adj);
return NULL;
}

if (BGP_DEBUG(update, UPDATE_OUT)
|| BGP_DEBUG(update, UPDATE_PREFIX)) {
memset(send_attr_str, 0, BUFSIZ);
Expand Down
7 changes: 7 additions & 0 deletions lib/ipaddr.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ static inline char *ipaddr2str(const struct ipaddr *ip, char *buf, int size)
return buf;
}

#define IS_MAPPED_IPV6(A) \
((A)->s6_addr32[0] == 0x00000000 \
? ((A)->s6_addr32[1] == 0x00000000 \
? (ntohl((A)->s6_addr32[2]) == 0xFFFF ? 1 : 0) \
: 0) \
: 0)

/*
* Convert IPv4 address to IPv4-mapped IPv6 address which is of the
* form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then
Expand Down
16 changes: 10 additions & 6 deletions zebra/rt_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1046,12 +1046,16 @@ static void _netlink_route_nl_add_gateway_info(uint8_t route_family,
addattr_l(nlmsg, req_size, RTA_VIA, &gw_fam.family,
bytelen + 2);
} else {
if (gw_family == AF_INET)
addattr_l(nlmsg, req_size, RTA_GATEWAY,
&nexthop->gate.ipv4, bytelen);
else
addattr_l(nlmsg, req_size, RTA_GATEWAY,
&nexthop->gate.ipv6, bytelen);

if (!(nexthop->rparent
&& IS_MAPPED_IPV6(&nexthop->rparent->gate.ipv6))) {
if (gw_family == AF_INET)
addattr_l(nlmsg, req_size, RTA_GATEWAY,
&nexthop->gate.ipv4, bytelen);
else
addattr_l(nlmsg, req_size, RTA_GATEWAY,
&nexthop->gate.ipv6, bytelen);
}
}
}

Expand Down
13 changes: 10 additions & 3 deletions zebra/zebra_fpm_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ static int netlink_route_info_encode(struct netlink_route_info *ri,
struct rtattr *nest;
struct vxlan_encap_info_t *vxlan;
int nest_len;
struct in6_addr ipv6;

struct {
struct nlmsghdr n;
Expand Down Expand Up @@ -420,10 +421,16 @@ static int netlink_route_info_encode(struct netlink_route_info *ri,

if (ri->num_nhs == 1) {
nhi = &ri->nhs[0];

if (nhi->gateway) {
addattr_l(&req->n, in_buf_len, RTA_GATEWAY,
nhi->gateway, bytelen);
if (nhi->type == NEXTHOP_TYPE_IPV4_IFINDEX
&& ri->af == AF_INET6) {
ipv4_to_ipv4_mapped_ipv6(&ipv6,
nhi->gateway->ipv4);
addattr_l(&req->n, in_buf_len, RTA_GATEWAY,
&ipv6, bytelen);
} else
addattr_l(&req->n, in_buf_len, RTA_GATEWAY,
nhi->gateway, bytelen);
}

if (nhi->if_index) {
Expand Down
12 changes: 11 additions & 1 deletion zebra/zebra_nhg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
struct interface *ifp;
rib_dest_t *dest;
struct zebra_vrf *zvrf;
struct in_addr ipv4;

if ((nexthop->type == NEXTHOP_TYPE_IPV4)
|| nexthop->type == NEXTHOP_TYPE_IPV6)
Expand Down Expand Up @@ -1827,13 +1828,22 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
return 0;
}

/* Validation for ipv4 mapped ipv6 nexthop. */
if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
afi = AFI_IP;
}
/* Make lookup prefix. */
memset(&p, 0, sizeof(struct prefix));
switch (afi) {
case AFI_IP:
p.family = AF_INET;
p.prefixlen = IPV4_MAX_PREFIXLEN;
p.u.prefix4 = nexthop->gate.ipv4;
if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
ipv4_mapped_ipv6_to_ipv4(&nexthop->gate.ipv6, &ipv4);
p.u.prefix4 = ipv4;
} else {
p.u.prefix4 = nexthop->gate.ipv4;
}
break;
case AFI_IP6:
p.family = AF_INET6;
Expand Down