From 92d6f769880d031f4a46c4dc805284a430301a7d Mon Sep 17 00:00:00 2001 From: Kaushik Date: Wed, 29 Jul 2020 08:48:57 -0700 Subject: [PATCH] lib,zebra,bgpd: Fix for nexthop as IPv4 mapped IPv6 address Added a macro to validate the v4 mapped v6 address. Modified bgp receive & send updates for v4 mapped v6 address as nexthop and installing it as recursive nexthop in RIB. Minor change in fpm while sending the routes for nexthop as v4 mapped v6 address. Signed-off-by: Kaushik --- bgpd/bgp_nht.c | 17 +++++++++++++++-- bgpd/bgp_updgrp_packet.c | 12 ++++++++++++ lib/ipaddr.h | 7 +++++++ zebra/rt_netlink.c | 19 +++++++++++-------- zebra/zebra_fpm_netlink.c | 12 ++++++++++-- zebra/zebra_nhg.c | 13 ++++++++++++- 6 files changed, 67 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index aefcaeff3a20..a74b5f91ac08 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -146,6 +146,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, 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 */ if (make_prefix(afi, pi, &p) < 0) @@ -533,6 +538,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) : 0; struct bgp_dest *net = pi->net; const struct prefix *p_orig = bgp_dest_get_prefix(net); + struct in_addr ipv4; if (p_orig->family == AF_FLOWSPEC) { if (!pi->peer) @@ -548,8 +554,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: diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 4de5ec3b04ff..5df9e3f23f43 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -574,6 +574,18 @@ 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); + } + } + + if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) { + mod_v6nhg = &peer->nexthop.v6_global; + 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, diff --git a/lib/ipaddr.h b/lib/ipaddr.h index a96c9788bc37..f2b75c1306d8 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -89,6 +89,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: (RFC 4291). This IPv6 address can then diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 07e8e37b8232..8d38b6defe1f 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1051,14 +1051,17 @@ static bool _netlink_route_add_gateway_info(uint8_t route_family, bytelen + 2)) return false; } else { - if (gw_family == AF_INET) { - if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, - &nexthop->gate.ipv4, bytelen)) - return false; - } else { - if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, - &nexthop->gate.ipv6, bytelen)) - return false; + if (!(nexthop->rparent + && IS_MAPPED_IPV6(&nexthop->rparent->gate.ipv6))) { + if (gw_family == AF_INET) { + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, + &nexthop->gate.ipv4, bytelen)) + return false; + } else { + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, + &nexthop->gate.ipv6, bytelen)) + return false; + } } } diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index a18885ddb74e..5831093b5053 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -364,6 +364,7 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, struct rtattr *nest, *inner_nest; struct rtnexthop *rtnh; struct vxlan_encap_info_t *vxlan; + struct in6_addr ipv6; struct { struct nlmsghdr n; @@ -423,8 +424,15 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, nhi = &ri->nhs[0]; if (nhi->gateway) { - nl_attr_put(&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); + nl_attr_put(&req->n, in_buf_len, RTA_GATEWAY, + &ipv6, bytelen); + } else + nl_attr_put(&req->n, in_buf_len, RTA_GATEWAY, + nhi->gateway, bytelen); } if (nhi->if_index) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c0580908444c..43bf74589651 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1775,6 +1775,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) @@ -1835,13 +1836,23 @@ 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;