diff options
| author | Mark Stapp <mjs@voltanet.io> | 2020-03-11 16:08:19 -0400 |
|---|---|---|
| committer | Mark Stapp <mjs@voltanet.io> | 2020-03-27 09:39:14 -0400 |
| commit | 62e46303f45e063e82abc600fc412c6765daf300 (patch) | |
| tree | 1743305520e3e8785c9d0af8629c0a1a4cf986eb | |
| parent | 018c64886402f7f21ba0d227058098f4fae7760c (diff) | |
zebra: support backup nexthops in zapi route messages
Initial support to decode backup nexthops in zapi route
messages.
Signed-off-by: Mark Stapp <mjs@voltanet.io>
| -rw-r--r-- | zebra/zapi_msg.c | 279 |
1 files changed, 188 insertions, 91 deletions
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 93a32b31b7..ea24333cb2 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1413,6 +1413,123 @@ void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, } } +/* + * Create a new nexthop based on a zapi nexthop. + */ +static struct nexthop *nexthop_from_zapi(struct route_entry *re, + const struct zapi_nexthop *api_nh, + const struct zapi_route *api) +{ + struct nexthop *nexthop = NULL; + struct ipaddr vtep_ip; + struct interface *ifp; + char nhbuf[INET6_ADDRSTRLEN] = ""; + + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("nh type %d", api_nh->type); + + switch (api_nh->type) { + case NEXTHOP_TYPE_IFINDEX: + nexthop = nexthop_from_ifindex(api_nh->ifindex, api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV4: + if (IS_ZEBRA_DEBUG_RECV) { + inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, + sizeof(nhbuf)); + zlog_debug("%s: nh=%s, vrf_id=%d", __func__, + nhbuf, api_nh->vrf_id); + } + nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4, NULL, + api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (IS_ZEBRA_DEBUG_RECV) { + inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, + sizeof(nhbuf)); + zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d", + __func__, nhbuf, api_nh->vrf_id, + api_nh->ifindex); + } + + nexthop = nexthop_from_ipv4_ifindex( + &api_nh->gate.ipv4, NULL, api_nh->ifindex, + api_nh->vrf_id); + + ifp = if_lookup_by_index(api_nh->ifindex, api_nh->vrf_id); + if (ifp && connected_is_unnumbered(ifp)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + + /* Special handling for IPv4 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. + */ + if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) { + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + vtep_ip.ipa_type = IPADDR_V4; + memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4), + sizeof(struct in_addr)); + zebra_vxlan_evpn_vrf_route_add( + api_nh->vrf_id, &api_nh->rmac, + &vtep_ip, &api->prefix); + } + break; + case NEXTHOP_TYPE_IPV6: + if (IS_ZEBRA_DEBUG_RECV) { + inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf, + sizeof(nhbuf)); + zlog_debug("%s: nh=%s, vrf_id=%d", __func__, + nhbuf, api_nh->vrf_id); + } + nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6, api_nh->vrf_id); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (IS_ZEBRA_DEBUG_RECV) { + inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf, + sizeof(nhbuf)); + zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d", + __func__, nhbuf, api_nh->vrf_id, + api_nh->ifindex); + } + nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6, + api_nh->ifindex, + api_nh->vrf_id); + + /* Special handling for IPv6 routes sourced from EVPN: + * the nexthop and associated MAC need to be installed. + */ + if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) { + memset(&vtep_ip, 0, sizeof(struct ipaddr)); + vtep_ip.ipa_type = IPADDR_V6; + memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), + sizeof(struct in6_addr)); + zebra_vxlan_evpn_vrf_route_add( + api_nh->vrf_id, &api_nh->rmac, + &vtep_ip, &api->prefix); + } + break; + case NEXTHOP_TYPE_BLACKHOLE: + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: nh blackhole %d", + __func__, api_nh->bh_type); + + nexthop = nexthop_from_blackhole(api_nh->bh_type); + break; + } + + /* Return early if we couldn't process the zapi nexthop */ + if (nexthop == NULL) { + goto done; + } + + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); + + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT)) + nexthop->weight = api_nh->weight; + +done: + return nexthop; +} + static void zread_route_add(ZAPI_HANDLER_ARGS) { struct stream *s; @@ -1421,12 +1538,11 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) afi_t afi; struct prefix_ipv6 *src_p = NULL; struct route_entry *re; - struct nexthop *nexthop = NULL; + struct nexthop *nexthop = NULL, *last_nh; struct nexthop_group *ng = NULL; + struct nexthop_group *backup_ng = NULL; int i, ret; vrf_id_t vrf_id; - struct ipaddr vtep_ip; - struct interface *ifp; s = msg; if (zapi_route_decode(s, &api) < 0) { @@ -1469,6 +1585,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) return; } + /* Report misuse of the backup flag */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS) && + api.backup_nexthop_num == 0) { + if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: client %s: BACKUP flag set but no backup nexthops, prefix %pFX", + __func__, + zebra_route_string(client->proto), &api.prefix); + } + /* Use temporary list of nexthops */ ng = nexthop_group_new(); @@ -1479,112 +1604,74 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) */ for (i = 0; i < api.nexthop_num; i++) { api_nh = &api.nexthops[i]; - ifindex_t ifindex = 0; - nexthop = NULL; - - if (IS_ZEBRA_DEBUG_RECV) - zlog_debug("nh type %d", api_nh->type); + /* Convert zapi nexthop */ + nexthop = nexthop_from_zapi(re, api_nh, &api); + if (!nexthop) { + flog_warn( + EC_ZEBRA_NEXTHOP_CREATION_FAILED, + "%s: Nexthops Specified: %d but we failed to properly create one", + __func__, api.nexthop_num); + nexthop_group_delete(&ng); + XFREE(MTYPE_RE, re); + return; + } - switch (api_nh->type) { - case NEXTHOP_TYPE_IFINDEX: - nexthop = nexthop_from_ifindex(api_nh->ifindex, - api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV4: - if (IS_ZEBRA_DEBUG_RECV) { - char nhbuf[INET6_ADDRSTRLEN] = {0}; + /* MPLS labels for BGP-LU or Segment Routing */ + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) + && api_nh->type != NEXTHOP_TYPE_IFINDEX + && api_nh->type != NEXTHOP_TYPE_BLACKHOLE + && api_nh->label_num > 0) { + enum lsp_types_t label_type; - inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, - INET6_ADDRSTRLEN); - zlog_debug("%s: nh=%s, vrf_id=%d", __func__, - nhbuf, api_nh->vrf_id); - } - nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4, - NULL, api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV4_IFINDEX: + label_type = lsp_type_from_re_type(client->proto); - memset(&vtep_ip, 0, sizeof(struct ipaddr)); - ifindex = api_nh->ifindex; if (IS_ZEBRA_DEBUG_RECV) { - char nhbuf[INET6_ADDRSTRLEN] = {0}; - - inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf, - INET6_ADDRSTRLEN); zlog_debug( - "%s: nh=%s, vrf_id=%d (re->vrf_id=%d), ifindex=%d", - __func__, nhbuf, api_nh->vrf_id, - re->vrf_id, ifindex); - } - nexthop = nexthop_from_ipv4_ifindex( - &api_nh->gate.ipv4, NULL, ifindex, - api_nh->vrf_id); - - ifp = if_lookup_by_index(ifindex, api_nh->vrf_id); - if (ifp && connected_is_unnumbered(ifp)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - /* Special handling for IPv4 routes sourced from EVPN: - * the nexthop and associated MAC need to be installed. - */ - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - vtep_ip.ipa_type = IPADDR_V4; - memcpy(&(vtep_ip.ipaddr_v4), - &(api_nh->gate.ipv4), - sizeof(struct in_addr)); - zebra_vxlan_evpn_vrf_route_add( - api_nh->vrf_id, &api_nh->rmac, - &vtep_ip, &api.prefix); - } - break; - case NEXTHOP_TYPE_IPV6: - nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6, - api_nh->vrf_id); - break; - case NEXTHOP_TYPE_IPV6_IFINDEX: - memset(&vtep_ip, 0, sizeof(struct ipaddr)); - ifindex = api_nh->ifindex; - nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6, - ifindex, - api_nh->vrf_id); - - /* Special handling for IPv6 routes sourced from EVPN: - * the nexthop and associated MAC need to be installed. - */ - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { - vtep_ip.ipa_type = IPADDR_V6; - memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6), - sizeof(struct in6_addr)); - zebra_vxlan_evpn_vrf_route_add( - api_nh->vrf_id, &api_nh->rmac, - &vtep_ip, &api.prefix); + "%s: adding %d labels of type %d (1st=%u)", + __func__, api_nh->label_num, label_type, + api_nh->labels[0]); } - break; - case NEXTHOP_TYPE_BLACKHOLE: - nexthop = nexthop_from_blackhole(api_nh->bh_type); - break; + + nexthop_add_labels(nexthop, label_type, + api_nh->label_num, + &api_nh->labels[0]); } + /* Add new nexthop to temporary list */ + nexthop_group_add_sorted(ng, nexthop); + nexthop = NULL; + } + + /* Allocate temporary list of backup nexthops, if necessary */ + if (api.backup_nexthop_num > 0) { + backup_ng = nexthop_group_new(); + nexthop = NULL; + last_nh = NULL; + } + + /* Copy backup nexthops also, if present */ + for (i = 0; i < api.backup_nexthop_num; i++) { + api_nh = &api.backup_nexthops[i]; + + /* Convert zapi backup nexthop */ + nexthop = nexthop_from_zapi(re, api_nh, &api); if (!nexthop) { flog_warn( EC_ZEBRA_NEXTHOP_CREATION_FAILED, - "%s: Nexthops Specified: %d but we failed to properly create one", - __func__, api.nexthop_num); + "%s: Backup Nexthops Specified: %d but we failed to properly create one", + __func__, api.backup_nexthop_num); nexthop_group_delete(&ng); + nexthop_group_delete(&backup_ng); XFREE(MTYPE_RE, re); return; } - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK)) - SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK); - - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT)) - nexthop->weight = api_nh->weight; - /* MPLS labels for BGP-LU or Segment Routing */ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) && api_nh->type != NEXTHOP_TYPE_IFINDEX - && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) { + && api_nh->type != NEXTHOP_TYPE_BLACKHOLE + && api_nh->label_num > 0) { enum lsp_types_t label_type; label_type = lsp_type_from_re_type(client->proto); @@ -1601,8 +1688,17 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) &api_nh->labels[0]); } - /* Add new nexthop to temporary list */ - nexthop_group_add_sorted(ng, nexthop); + /* Note that the order of the backup nexthops is significant + * at this point - we don't sort this list as we do the + * primary nexthops, we just append. + */ + if (last_nh) { + NEXTHOP_APPEND(last_nh, nexthop); + } else { + backup_ng->nexthop = nexthop; + } + + last_nh = nexthop; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) @@ -1620,6 +1716,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) "%s: Received SRC Prefix but afi is not v6", __func__); nexthop_group_delete(&ng); + nexthop_group_delete(&backup_ng); XFREE(MTYPE_RE, re); return; } |
