diff options
| -rw-r--r-- | bgpd/bgp_attr.c | 11 | ||||
| -rw-r--r-- | bgpd/bgp_attr.h | 3 | ||||
| -rw-r--r-- | bgpd/bgp_mplsvpn.c | 18 | ||||
| -rw-r--r-- | bgpd/bgp_nexthop.h | 1 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.c | 222 |
5 files changed, 175 insertions, 80 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a8ba892f39..1380c9cd09 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -520,6 +520,8 @@ unsigned int attrhash_key_make(void *p) MIX(attr->mp_nexthop_len); key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key); key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key); + MIX(attr->nh_ifindex); + MIX(attr->nh_lla_ifindex); return key; } @@ -559,7 +561,9 @@ int attrhash_cmp(const void *p1, const void *p2) &attr2->mp_nexthop_global_in) && IPV4_ADDR_SAME(&attr1->originator_id, &attr2->originator_id) - && overlay_index_same(attr1, attr2)) + && overlay_index_same(attr1, attr2) + && attr1->nh_ifindex == attr2->nh_ifindex + && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex) return 1; } @@ -1683,6 +1687,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_getl(s); /* RD low */ } stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); + if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) + attr->nh_ifindex = peer->nexthop.ifp->ifindex; break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL: @@ -1692,6 +1698,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, stream_getl(s); /* RD low */ } stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN); + if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) + attr->nh_ifindex = peer->nexthop.ifp->ifindex; if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { stream_getl(s); /* RD high */ @@ -1715,6 +1723,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, attr->mp_nexthop_len = IPV6_MAX_BYTELEN; } + attr->nh_lla_ifindex = peer->nexthop.ifp->ifindex; break; default: zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d", diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 758db4a447..d59eae5f14 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -144,6 +144,9 @@ struct attr { struct in6_addr mp_nexthop_global; struct in6_addr mp_nexthop_local; + /* ifIndex corresponding to mp_nexthop_local. */ + ifindex_t nh_lla_ifindex; + /* Extended Communities attribute. */ struct ecommunity *ecommunity; diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 7c6a3a37f8..8cacb62c17 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -770,20 +770,19 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ static_attr.flag &= ~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); } } else { - switch (afi) { - case AFI_IP: + /* Update based on next-hop family to account for + * RFC 5549 (BGP unnumbered) scenario. Note that + * specific action is only needed for the case of + * IPv4 nexthops as the attr has been copied + * otherwise. + */ + if (afi == AFI_IP && + !BGP_ATTR_NEXTHOP_AFI_IP6(info_vrf->attr)) { static_attr.mp_nexthop_global_in.s_addr = static_attr.nexthop.s_addr; static_attr.mp_nexthop_len = 4; static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); - break; - case AFI_IP6: - break; - case AFI_L2VPN: - case AFI_MAX: - assert(!"Unexpected AFI to process"); - break; } } nexthop_self_flag = 1; @@ -1076,7 +1075,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT)) { static_attr.mp_nexthop_global = nexthop_orig.u.prefix6; - static_attr.mp_nexthop_len = 16; } break; } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 519f092762..a771bead23 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -29,6 +29,7 @@ (((nexthop_len) == 4 || (nexthop_len) == 12 \ ? AF_INET \ : ((nexthop_len) == 16 || (nexthop_len) == 24 \ + || (nexthop_len) == 32 \ || (nexthop_len) == 48 \ ? AF_INET6 \ : AF_UNSPEC))) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 7872897234..257f4c32fa 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -583,13 +583,20 @@ static int zebra_read_route(int command, struct zclient *zclient, char buf[2][PREFIX_STRLEN]; prefix2str(&api.prefix, buf[0], sizeof(buf[0])); - inet_ntop(api.prefix.family, &nexthop, buf[1], sizeof(buf[1])); - zlog_debug( - "Rx route %s VRF %u %s[%d] %s " - "nexthop %s metric %u tag %" ROUTE_TAG_PRI, - (add) ? "add" : "delete", vrf_id, - zebra_route_string(api.type), api.instance, buf[0], - buf[1], api.metric, api.tag); + if (add) { + inet_ntop(api.prefix.family, &nexthop, buf[1], + sizeof(buf[1])); + zlog_debug( + "Rx route ADD VRF %u %s[%d] %s nexthop %s (type %d if %u) metric %u tag %" ROUTE_TAG_PRI, + vrf_id, zebra_route_string(api.type), + api.instance, buf[0], buf[1], nhtype, + ifindex, api.metric, api.tag); + } else { + zlog_debug( + "Rx route DEL VRF %u %s[%d] %s", + vrf_id, zebra_route_string(api.type), + api.instance, buf[0]); + } } return 0; @@ -906,28 +913,40 @@ int bgp_nexthop_set(union sockunion *local, union sockunion *remote, return 0; } -static struct in6_addr *bgp_info_to_ipv6_nexthop(struct bgp_info *info) +static struct in6_addr *bgp_info_to_ipv6_nexthop(struct bgp_info *info, + ifindex_t *ifindex) { struct in6_addr *nexthop = NULL; /* Only global address nexthop exists. */ - if (info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) + if (info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { nexthop = &info->attr->mp_nexthop_global; + if (IN6_IS_ADDR_LINKLOCAL(nexthop)) + *ifindex = info->attr->nh_ifindex; + + } /* If both global and link-local address present. */ if (info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ - if (info->attr->mp_nexthop_prefer_global) + if (info->attr->mp_nexthop_prefer_global) { nexthop = &info->attr->mp_nexthop_global; - else { + if (IN6_IS_ADDR_LINKLOCAL(nexthop)) + *ifindex = info->attr->nh_ifindex; + } else { /* Workaround for Cisco's nexthop bug. */ if (IN6_IS_ADDR_UNSPECIFIED( &info->attr->mp_nexthop_global) - && info->peer->su_remote->sa.sa_family == AF_INET6) + && info->peer->su_remote->sa.sa_family == AF_INET6) { nexthop = &info->peer->su_remote->sin6.sin6_addr; - else + if (IN6_IS_ADDR_LINKLOCAL(nexthop)) + *ifindex = info->peer->nexthop.ifp->ifindex; + } else { nexthop = &info->attr->mp_nexthop_local; + if (IN6_IS_ADDR_LINKLOCAL(nexthop)) + *ifindex = info->attr->nh_lla_ifindex; + } } } @@ -958,13 +977,16 @@ static int bgp_table_map_apply(struct route_map *map, struct prefix *p, } if (p->family == AF_INET6) { char buf[2][INET6_ADDRSTRLEN]; + ifindex_t ifindex; + struct in6_addr *nexthop; + + nexthop = bgp_info_to_ipv6_nexthop(info, &ifindex); zlog_debug( "Zebra rmap deny: IPv6 route %s/%d nexthop %s", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, - inet_ntop(AF_INET6, - bgp_info_to_ipv6_nexthop(info), + inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1]))); } } @@ -1029,6 +1051,91 @@ int bgp_zebra_get_table_range(uint32_t chunk_size, return 0; } +static int update_ipv4nh_for_route_install(int nh_othervrf, + struct in_addr *nexthop, + struct attr *attr, + bool is_evpn, + struct zapi_nexthop *api_nh) +{ + api_nh->gate.ipv4 = *nexthop; + + /* Need to set fields appropriately for EVPN routes imported into + * a VRF (which are programmed as onlink on l3-vni SVI) as well as + * connected routes leaked into a VRF. + */ + if (is_evpn) + api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + else if (nh_othervrf && + api_nh->gate.ipv4.s_addr == INADDR_ANY) { + api_nh->type = NEXTHOP_TYPE_IFINDEX; + api_nh->ifindex = attr->nh_ifindex; + } else + api_nh->type = NEXTHOP_TYPE_IPV4; + + return 1; +} + +static int update_ipv6nh_for_route_install(int nh_othervrf, + struct in6_addr *nexthop, + ifindex_t ifindex, + struct bgp_info *ri, + struct bgp_info *best_ri, + bool is_evpn, + struct zapi_nexthop *api_nh) +{ + struct attr *attr; + + attr = ri->attr; + + if (is_evpn) + api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; + else if (nh_othervrf) { + if (IN6_IS_ADDR_UNSPECIFIED(nexthop)) { + api_nh->type = NEXTHOP_TYPE_IFINDEX; + api_nh->ifindex = attr->nh_ifindex; + } else if (IN6_IS_ADDR_LINKLOCAL(nexthop)) { + if (ifindex == 0) + return 0; + api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; + api_nh->ifindex = ifindex; + } else { + api_nh->type = NEXTHOP_TYPE_IPV6; + api_nh->ifindex = 0; + } + } else { + if (IN6_IS_ADDR_LINKLOCAL(nexthop)) { + if (ri == best_ri && + attr->mp_nexthop_len + == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + if (ri->peer->nexthop.ifp) + ifindex = ri->peer->nexthop.ifp + ->ifindex; + if (!ifindex) { + if (ri->peer->conf_if) + ifindex = ri->peer->ifp->ifindex; + else if (ri->peer->ifname) + ifindex = ifname2ifindex( + ri->peer->ifname, + ri->peer->bgp->vrf_id); + else if (ri->peer->nexthop.ifp) + ifindex = ri->peer->nexthop.ifp + ->ifindex; + } + + if (ifindex == 0) + return 0; + api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; + api_nh->ifindex = ifindex; + } else { + api_nh->type = NEXTHOP_TYPE_IPV6; + api_nh->ifindex = 0; + } + } + api_nh->gate.ipv6 = *nexthop; + + return 1; +} + void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, struct bgp_info *info, struct bgp *bgp, afi_t afi, safi_t safi) @@ -1049,6 +1156,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, mpls_label_t label; int nh_othervrf = 0; char buf_prefix[PREFIX_STRLEN]; /* filled in if we are debugging */ + bool is_evpn = false; + int nh_updated; /* Don't try to install if we're not connected to Zebra or Zebra doesn't * know of this instance. @@ -1096,7 +1205,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, zapi_route_set_blackhole(&api, BLACKHOLE_NULL); /* If the route's source is EVPN, flag as such. */ - if (is_route_parent_evpn(info)) + is_evpn = is_route_parent_evpn(info); + if (is_evpn) SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE); if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED @@ -1134,8 +1244,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, api_nh->vrf_id = nh_othervrf ? info->extra->bgp_orig->vrf_id : bgp->vrf_id; if (nh_family == AF_INET) { - struct in_addr *nexthop; - if (bgp_debug_zebra(&api.prefix)) { if (mpinfo->extra) { zlog_debug( @@ -1178,22 +1286,14 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, } } - nexthop = &mpinfo_cp->attr->nexthop; - api_nh->gate.ipv4 = *nexthop; - - /* EVPN type-2 routes are - programmed as onlink on l3-vni SVI - */ - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) - api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - else - api_nh->type = NEXTHOP_TYPE_IPV4; + nh_updated = update_ipv4nh_for_route_install( + nh_othervrf, + &mpinfo_cp->attr->nexthop, + mpinfo_cp->attr, is_evpn, api_nh); } else { ifindex_t ifindex; struct in6_addr *nexthop; - ifindex = 0; - if (bgp->table_map[afi][safi].name || nh_othervrf) { /* Copy info and attributes, so the route-map apply doesn't modify the BGP route info. */ @@ -1227,39 +1327,17 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, tag = mpinfo_cp->attr->tag; } } - nexthop = bgp_info_to_ipv6_nexthop(mpinfo_cp); - - if ((mpinfo == info) - && mpinfo->attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - if (mpinfo->peer->nexthop.ifp) - ifindex = mpinfo->peer->nexthop.ifp - ->ifindex; - - if (!ifindex) { - if (mpinfo->peer->conf_if) - ifindex = mpinfo->peer->ifp->ifindex; - else if (mpinfo->peer->ifname) - ifindex = ifname2ifindex( - mpinfo->peer->ifname, - bgp->vrf_id); - else if (mpinfo->peer->nexthop.ifp) - ifindex = mpinfo->peer->nexthop.ifp - ->ifindex; - } - - if (IN6_IS_ADDR_LINKLOCAL(nexthop)) { - if (ifindex == 0) - continue; - } else - ifindex = 0; - - api_nh->gate.ipv6 = *nexthop; - api_nh->ifindex = ifindex; - api_nh->type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX - : NEXTHOP_TYPE_IPV6; + nexthop = bgp_info_to_ipv6_nexthop(mpinfo_cp, + &ifindex); + nh_updated = update_ipv6nh_for_route_install( + nh_othervrf, nexthop, ifindex, + mpinfo, info, is_evpn, api_nh); } + /* Did we get proper nexthop info to update zebra? */ + if (!nh_updated) + continue; + if (mpinfo->extra && bgp_is_valid_label(&mpinfo->extra->label[0]) && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { @@ -1272,6 +1350,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, valid_nh_count++; } + /* if this is a evpn route we don't have to include the label */ if (has_valid_label && !(CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))) SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); @@ -1307,20 +1386,25 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, for (i = 0; i < api.nexthop_num; i++) { api_nh = &api.nexthops[i]; - if (api_nh->type == NEXTHOP_TYPE_IPV4) - nh_family = AF_INET; - else - nh_family = AF_INET6; - inet_ntop(nh_family, &api_nh->gate, nh_buf, - sizeof(nh_buf)); + if (api_nh->type == NEXTHOP_TYPE_IFINDEX) + nh_buf[0] = '\0'; + else { + if (api_nh->type == NEXTHOP_TYPE_IPV4) + nh_family = AF_INET; + else + nh_family = AF_INET6; + inet_ntop(nh_family, &api_nh->gate, nh_buf, + sizeof(nh_buf)); + } label_buf[0] = '\0'; if (has_valid_label && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) sprintf(label_buf, "label %u", api_nh->labels[0]); - zlog_debug(" nhop [%d]: %s %s", i + 1, nh_buf, - label_buf); + zlog_debug(" nhop [%d]: %s if %u VRF %u %s", + i + 1, nh_buf, api_nh->ifindex, + api_nh->vrf_id, label_buf); } } |
