diff options
| -rw-r--r-- | bgpd/bgp_snmp_bgp4v2.c | 12 | ||||
| -rw-r--r-- | doc/developer/fpm.rst | 16 | ||||
| -rw-r--r-- | zebra/debug.c | 8 | ||||
| -rw-r--r-- | zebra/debug.h | 4 | ||||
| -rw-r--r-- | zebra/dplane_fpm_nl.c | 137 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 30 | ||||
| -rw-r--r-- | zebra/rt_netlink.h | 4 | ||||
| -rw-r--r-- | zebra/zebra_dplane.c | 188 | ||||
| -rw-r--r-- | zebra/zebra_dplane.h | 18 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 117 | ||||
| -rw-r--r-- | zebra/zebra_router.c | 11 | ||||
| -rw-r--r-- | zebra/zebra_router.h | 8 | ||||
| -rw-r--r-- | zebra/zebra_vty.c | 9 |
13 files changed, 405 insertions, 157 deletions
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index 9c91a30804..2d70aa94d3 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -440,11 +440,11 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, sockunion_init(&su); if (exact) { - if (*length - v->namelen != BGP_NLRI_ENTRY_OFFSET) + if (*length - namelen != BGP_NLRI_ENTRY_OFFSET) return NULL; /* Set OID offset for prefix */ - offset = name + v->namelen; + offset = name + namelen; if (family == AF_INET) oid2in_addr(offset, afi_len, &addr->u.prefix4); else @@ -477,8 +477,8 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, return NULL; } - offset = name + v->namelen; - offsetlen = *length - v->namelen; + offset = name + namelen; + offsetlen = *length - namelen; len = offsetlen; if (offsetlen == 0) { @@ -560,9 +560,9 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, if (min) { const struct prefix *rn_p = bgp_dest_get_prefix(dest); - *length = v->namelen + BGP_NLRI_ENTRY_OFFSET; + *length = namelen + BGP_NLRI_ENTRY_OFFSET; - offset = name + v->namelen; + offset = name + namelen; if (family == AF_INET) oid_copy_in_addr(offset, &rn_p->u.prefix4); diff --git a/doc/developer/fpm.rst b/doc/developer/fpm.rst index 9849869133..56d33671d2 100644 --- a/doc/developer/fpm.rst +++ b/doc/developer/fpm.rst @@ -101,3 +101,19 @@ Data ^^^^ The netlink or protobuf message payload. + + +Route Status Notification from ASIC +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The dplane_fpm_nl has the ability to read route netlink messages +from the underlying fpm implementation that can tell zebra +whether or not the route has been Offloaded/Failed or Trapped. +The end developer must send the data up the same socket that has +been created to listen for FPM messages from Zebra. The data sent +must have a Frame Header with Version set to 1, Message Type set to 1 +and an appropriate message Length. The message data must contain +a RTM_NEWROUTE netlink message that sends the prefix and nexthops +associated with the route. Finally rtm_flags must contain +RTM_F_OFFLOAD, RTM_F_TRAP and or RTM_F_OFFLOAD_FAILED to signify +what has happened to the route in the ASIC. diff --git a/zebra/debug.c b/zebra/debug.c index 953f0423af..977af0e198 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -341,7 +341,7 @@ DEFPY(debug_zebra_dplane_dpdk, debug_zebra_dplane_dpdk_cmd, SET_FLAG(zebra_debug_dplane_dpdk, ZEBRA_DEBUG_DPLANE_DPDK); if (detail) - SET_FLAG(zebra_debug_dplane, + SET_FLAG(zebra_debug_dplane_dpdk, ZEBRA_DEBUG_DPLANE_DPDK_DETAIL); } @@ -740,10 +740,12 @@ static int config_write_debug(struct vty *vty) write++; } - if (CHECK_FLAG(zebra_debug_dplane, ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)) { + if (CHECK_FLAG(zebra_debug_dplane_dpdk, + ZEBRA_DEBUG_DPLANE_DPDK_DETAIL)) { vty_out(vty, "debug zebra dplane dpdk detailed\n"); write++; - } else if (CHECK_FLAG(zebra_debug_dplane, ZEBRA_DEBUG_DPLANE_DPDK)) { + } else if (CHECK_FLAG(zebra_debug_dplane_dpdk, + ZEBRA_DEBUG_DPLANE_DPDK)) { vty_out(vty, "debug zebra dplane dpdk\n"); write++; } diff --git a/zebra/debug.h b/zebra/debug.h index e0c6a9e2b9..514827707a 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -111,9 +111,9 @@ extern "C" { (zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DETAILED) #define IS_ZEBRA_DEBUG_DPLANE_DPDK \ - (zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DPDK) + (zebra_debug_dplane_dpdk & ZEBRA_DEBUG_DPLANE_DPDK) #define IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL \ - (zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DPDK_DETAIL) + (zebra_debug_dplane_dpdk & ZEBRA_DEBUG_DPLANE_DPDK_DETAIL) #define IS_ZEBRA_DEBUG_MLAG (zebra_debug_mlag & ZEBRA_DEBUG_MLAG) diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 6c95be29df..337113988e 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -51,6 +51,7 @@ #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" #include "zebra/debug.h" +#include "fpm/fpm.h" #define SOUTHBOUND_DEFAULT_ADDR INADDR_LOOPBACK #define SOUTHBOUND_DEFAULT_PORT 2620 @@ -462,18 +463,17 @@ static void fpm_reconnect(struct fpm_nl_ctx *fnc) static void fpm_read(struct thread *t) { struct fpm_nl_ctx *fnc = THREAD_ARG(t); + fpm_msg_hdr_t fpm; ssize_t rv; + char buf[65535]; + struct nlmsghdr *hdr; + struct zebra_dplane_ctx *ctx; + size_t available_bytes; + size_t hdr_available_bytes; /* Let's ignore the input at the moment. */ rv = stream_read_try(fnc->ibuf, fnc->socket, STREAM_WRITEABLE(fnc->ibuf)); - /* We've got an interruption. */ - if (rv == -2) { - /* Schedule next read. */ - thread_add_read(fnc->fthread->master, fpm_read, fnc, - fnc->socket, &fnc->t_read); - return; - } if (rv == 0) { atomic_fetch_add_explicit(&fnc->counters.connection_closes, 1, memory_order_relaxed); @@ -492,14 +492,131 @@ static void fpm_read(struct thread *t) FPM_RECONNECT(fnc); return; } - stream_reset(fnc->ibuf); + + /* Schedule the next read */ + thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket, + &fnc->t_read); + + /* We've got an interruption. */ + if (rv == -2) + return; + /* Account all bytes read. */ atomic_fetch_add_explicit(&fnc->counters.bytes_read, rv, memory_order_relaxed); - thread_add_read(fnc->fthread->master, fpm_read, fnc, fnc->socket, - &fnc->t_read); + available_bytes = STREAM_READABLE(fnc->ibuf); + while (available_bytes) { + if (available_bytes < (ssize_t)FPM_MSG_HDR_LEN) { + stream_pulldown(fnc->ibuf); + return; + } + + fpm.version = stream_getc(fnc->ibuf); + fpm.msg_type = stream_getc(fnc->ibuf); + fpm.msg_len = stream_getw(fnc->ibuf); + + if (fpm.version != FPM_PROTO_VERSION && + fpm.msg_type != FPM_MSG_TYPE_NETLINK) { + stream_reset(fnc->ibuf); + zlog_warn( + "%s: Received version/msg_type %u/%u, expected 1/1", + __func__, fpm.version, fpm.msg_type); + + FPM_RECONNECT(fnc); + return; + } + + /* + * If the passed in length doesn't even fill in the header + * something is wrong and reset. + */ + if (fpm.msg_len < FPM_MSG_HDR_LEN) { + zlog_warn( + "%s: Received message length: %u that does not even fill the FPM header", + __func__, fpm.msg_len); + FPM_RECONNECT(fnc); + return; + } + + /* + * If we have not received the whole payload, reset the stream + * back to the beginning of the header and move it to the + * top. + */ + if (fpm.msg_len > available_bytes) { + stream_rewind_getp(fnc->ibuf, FPM_MSG_HDR_LEN); + stream_pulldown(fnc->ibuf); + return; + } + + available_bytes -= FPM_MSG_HDR_LEN; + + /* + * Place the data from the stream into a buffer + */ + hdr = (struct nlmsghdr *)buf; + stream_get(buf, fnc->ibuf, fpm.msg_len - FPM_MSG_HDR_LEN); + hdr_available_bytes = fpm.msg_len - FPM_MSG_HDR_LEN; + available_bytes -= hdr_available_bytes; + + /* Sanity check: must be at least header size. */ + if (hdr->nlmsg_len < sizeof(*hdr)) { + zlog_warn( + "%s: [seq=%u] invalid message length %u (< %zu)", + __func__, hdr->nlmsg_seq, hdr->nlmsg_len, + sizeof(*hdr)); + continue; + } + if (hdr->nlmsg_len > fpm.msg_len) { + zlog_warn( + "%s: Received a inner header length of %u that is greater than the fpm total length of %u", + __func__, hdr->nlmsg_len, fpm.msg_len); + FPM_RECONNECT(fnc); + } + /* Not enough bytes available. */ + if (hdr->nlmsg_len > hdr_available_bytes) { + zlog_warn( + "%s: [seq=%u] invalid message length %u (> %zu)", + __func__, hdr->nlmsg_seq, hdr->nlmsg_len, + available_bytes); + continue; + } + + if (!(hdr->nlmsg_flags & NLM_F_REQUEST)) { + if (IS_ZEBRA_DEBUG_FPM) + zlog_debug( + "%s: [seq=%u] not a request, skipping", + __func__, hdr->nlmsg_seq); + + /* + * This request is a bust, go to the next one + */ + continue; + } + + switch (hdr->nlmsg_type) { + case RTM_NEWROUTE: + ctx = dplane_ctx_alloc(); + dplane_ctx_set_op(ctx, DPLANE_OP_ROUTE_NOTIFY); + if (netlink_route_change_read_unicast_internal( + hdr, 0, false, ctx) != 1) { + dplane_ctx_fini(&ctx); + stream_pulldown(fnc->ibuf); + return; + } + break; + default: + if (IS_ZEBRA_DEBUG_FPM) + zlog_debug( + "%s: Received message type %u which is not currently handled", + __func__, hdr->nlmsg_type); + break; + } + } + + stream_reset(fnc->ibuf); } static void fpm_write(struct thread *t) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 2396dfe4d6..96ec90e549 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -692,8 +692,9 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, } /* Looking up routing table by netlink interface. */ -static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, - int startup) +int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, + ns_id_t ns_id, int startup, + struct zebra_dplane_ctx *ctx) { int len; struct rtmsg *rtm; @@ -768,9 +769,8 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, selfroute = is_selfroute(rtm->rtm_protocol); - if (!startup && selfroute - && h->nlmsg_type == RTM_NEWROUTE - && !zrouter.asic_offloaded) { + if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE && + !zrouter.asic_offloaded && !ctx) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Route type: %d Received that we think we have originated, ignoring", rtm->rtm_protocol); @@ -988,8 +988,8 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, } } if (nhe_id || ng) - rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p, re, ng, - startup); + dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p, + re, ng, startup, ctx); else { /* * I really don't see how this is possible @@ -1004,6 +1004,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, XFREE(MTYPE_RE, re); } } else { + if (ctx) { + zlog_err( + "%s: %pFX RTM_DELROUTE received but received a context as well", + __func__, &p); + return 0; + } + if (nhe_id) { rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, &src_p, NULL, nhe_id, table, metric, @@ -1028,7 +1035,14 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, } } - return 0; + return 1; +} + +static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, + int startup) +{ + return netlink_route_change_read_unicast_internal(h, ns_id, startup, + NULL); } static struct mcast_route_data *mroute = NULL; diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index b1af4b20e1..fd2b79a2bf 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -122,6 +122,10 @@ netlink_put_lsp_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); extern enum netlink_msg_status netlink_put_pw_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); +int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, + ns_id_t ns_id, int startup, + struct zebra_dplane_ctx *ctx); + #ifdef NETLINK_DEBUG const char *nlmsg_type2str(uint16_t type); const char *af_type2str(int type); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index c189408b57..84dae7f2d6 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -135,6 +135,8 @@ struct dplane_route_info { uint32_t zd_mtu; uint32_t zd_nexthop_mtu; + uint32_t zd_flags; + /* Nexthop hash entry info */ struct dplane_nexthop_info nhe; @@ -1430,6 +1432,20 @@ uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx) return ctx->u.rinfo.zd_old_instance; } +uint32_t dplane_ctx_get_flags(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rinfo.zd_flags; +} + +void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.rinfo.zd_flags = flags; +} + uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2766,25 +2782,16 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx, return AOK; } -/* - * Initialize a context block for a route update from zebra data structs. - */ -int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, - struct route_node *rn, struct route_entry *re) +int dplane_ctx_route_init_basic(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, struct route_entry *re, + const struct prefix *p, + const struct prefix_ipv6 *src_p, afi_t afi, + safi_t safi) { int ret = EINVAL; - const struct route_table *table = NULL; - const struct rib_table_info *info; - const struct prefix *p, *src_p; - struct zebra_ns *zns; - struct zebra_vrf *zvrf; - struct nexthop *nexthop; - struct zebra_l3vni *zl3vni; - const struct interface *ifp; - struct dplane_intf_extra *if_extra; - if (!ctx || !rn || !re) - goto done; + if (!ctx || !re) + return ret; TAILQ_INIT(&ctx->u.rinfo.intf_extra_q); @@ -2794,9 +2801,6 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ctx->u.rinfo.zd_type = re->type; ctx->u.rinfo.zd_old_type = re->type; - /* Prefixes: dest, and optional source */ - srcdest_rnode_prefixes(rn, &p, &src_p); - prefix_copy(&(ctx->u.rinfo.zd_dest), p); if (src_p) @@ -2806,6 +2810,7 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ctx->zd_table_id = re->table; + ctx->u.rinfo.zd_flags = re->flags; ctx->u.rinfo.zd_metric = re->metric; ctx->u.rinfo.zd_old_metric = re->metric; ctx->zd_vrf_id = re->vrf_id; @@ -2816,11 +2821,46 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ctx->u.rinfo.zd_old_tag = re->tag; ctx->u.rinfo.zd_distance = re->distance; + ctx->u.rinfo.zd_afi = afi; + ctx->u.rinfo.zd_safi = safi; + + return AOK; +} + +/* + * Initialize a context block for a route update from zebra data structs. + */ +int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, + struct route_node *rn, struct route_entry *re) +{ + int ret = EINVAL; + const struct route_table *table = NULL; + const struct rib_table_info *info; + const struct prefix *p; + const struct prefix_ipv6 *src_p; + struct zebra_ns *zns; + struct zebra_vrf *zvrf; + struct nexthop *nexthop; + struct zebra_l3vni *zl3vni; + const struct interface *ifp; + struct dplane_intf_extra *if_extra; + + if (!ctx || !rn || !re) + return ret; + + /* + * Let's grab the data from the route_node + * so that we can call a helper function + */ + + /* Prefixes: dest, and optional source */ + srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p); table = srcdest_rnode_table(rn); info = table->info; - ctx->u.rinfo.zd_afi = info->afi; - ctx->u.rinfo.zd_safi = info->safi; + if (dplane_ctx_route_init_basic(ctx, op, re, p, src_p, info->afi, + info->safi) != AOK) + return ret; /* Copy nexthops; recursive info is included too */ copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), @@ -2875,8 +2915,7 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, /* Don't need some info when capturing a system notification */ if (op == DPLANE_OP_SYS_ROUTE_ADD || op == DPLANE_OP_SYS_ROUTE_DELETE) { - ret = AOK; - goto done; + return AOK; } /* Extract ns info - can't use pointers to 'core' structs */ @@ -2897,14 +2936,12 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, * If its a delete we only use the prefix anyway, so this only * matters for INSTALL/UPDATE. */ - if (zebra_nhg_kernel_nexthops_enabled() - && (((op == DPLANE_OP_ROUTE_INSTALL) - || (op == DPLANE_OP_ROUTE_UPDATE)) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED))) { - ret = ENOENT; - goto done; - } + if (zebra_nhg_kernel_nexthops_enabled() && + (((op == DPLANE_OP_ROUTE_INSTALL) || + (op == DPLANE_OP_ROUTE_UPDATE)) && + !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) && + !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED))) + return ENOENT; re->nhe_installed_id = nhe->id; } @@ -2916,10 +2953,7 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, re->dplane_sequence = zebra_router_get_next_sequence(); ctx->zd_seq = re->dplane_sequence; - ret = AOK; - -done: - return ret; + return AOK; } static int dplane_ctx_tc_qdisc_init(struct zebra_dplane_ctx *ctx, @@ -3031,7 +3065,7 @@ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, int ret = EINVAL; if (!ctx || !nhe) - goto done; + return ret; ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; @@ -3066,7 +3100,6 @@ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ret = AOK; -done: return ret; } @@ -3088,7 +3121,7 @@ int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, bool set_pdown, unset_pdown; if (!ctx || !ifp) - goto done; + return ret; ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; @@ -3133,7 +3166,6 @@ int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ret = AOK; -done: return ret; } @@ -3161,10 +3193,8 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, /* This may be called to create/init a dplane context, not necessarily * to copy an lsp object. */ - if (lsp == NULL) { - ret = AOK; - goto done; - } + if (lsp == NULL) + return ret; if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug("init dplane ctx %s: in-label %u ecmp# %d", @@ -3207,7 +3237,7 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, } if (ret != AOK) - goto done; + return ret; /* Capture backup nhlfes/nexthops */ frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) { @@ -3228,11 +3258,6 @@ int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, new_nhlfe->nexthop->flags = nhlfe->nexthop->flags; } - /* On error the ctx will be cleaned-up, so we don't need to - * deal with any allocated nhlfe or nexthop structs here. - */ -done: - return ret; } @@ -3293,11 +3318,11 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6; table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id); if (table == NULL) - goto done; + return ret; rn = route_node_match(table, &p); if (rn == NULL) - goto done; + return ret; re = NULL; RNODE_FOREACH_RE(rn, re) { @@ -3365,10 +3390,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, } route_unlock_node(rn); - ret = AOK; - -done: - return ret; + return AOK; } /** @@ -3943,12 +3965,11 @@ enum zebra_dplane_result dplane_route_add(struct route_node *rn, enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; if (rn == NULL || re == NULL) - goto done; + return ret; ret = dplane_route_update_internal(rn, re, NULL, DPLANE_OP_ROUTE_INSTALL); -done: return ret; } @@ -3962,11 +3983,11 @@ enum zebra_dplane_result dplane_route_update(struct route_node *rn, enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; if (rn == NULL || re == NULL) - goto done; + return ret; ret = dplane_route_update_internal(rn, re, old_re, DPLANE_OP_ROUTE_UPDATE); -done: + return ret; } @@ -3979,12 +4000,11 @@ enum zebra_dplane_result dplane_route_delete(struct route_node *rn, enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; if (rn == NULL || re == NULL) - goto done; + return ret; ret = dplane_route_update_internal(rn, re, NULL, DPLANE_OP_ROUTE_DELETE); -done: return ret; } @@ -3997,18 +4017,16 @@ enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn, enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; /* Ignore this event unless a provider plugin has requested it. */ - if (!zdplane_info.dg_sys_route_notifs) { - ret = ZEBRA_DPLANE_REQUEST_SUCCESS; - goto done; - } + if (!zdplane_info.dg_sys_route_notifs) + return ZEBRA_DPLANE_REQUEST_SUCCESS; + if (rn == NULL || re == NULL) - goto done; + return ret; ret = dplane_route_update_internal(rn, re, NULL, DPLANE_OP_SYS_ROUTE_ADD); -done: return ret; } @@ -4021,18 +4039,15 @@ enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn, enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; /* Ignore this event unless a provider plugin has requested it. */ - if (!zdplane_info.dg_sys_route_notifs) { - ret = ZEBRA_DPLANE_REQUEST_SUCCESS; - goto done; - } + if (!zdplane_info.dg_sys_route_notifs) + return ZEBRA_DPLANE_REQUEST_SUCCESS; if (rn == NULL || re == NULL) - goto done; + return ret; ret = dplane_route_update_internal(rn, re, NULL, DPLANE_OP_SYS_ROUTE_DELETE); -done: return ret; } @@ -6287,6 +6302,20 @@ kernel_dplane_process_ipset_entry(struct zebra_dplane_provider *prov, dplane_provider_enqueue_out_ctx(prov, ctx); } +void dplane_rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, + struct prefix_ipv6 *src_p, struct route_entry *re, + struct nexthop_group *ng, int startup, + struct zebra_dplane_ctx *ctx) +{ + if (!ctx) + rib_add_multipath(afi, safi, p, src_p, re, ng, startup); + else { + dplane_ctx_route_init_basic(ctx, dplane_ctx_get_op(ctx), re, p, + src_p, afi, safi); + dplane_provider_enqueue_to_zebra(ctx); + } +} + /* * Kernel provider callback */ @@ -6463,7 +6492,7 @@ int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx, TAILQ_INIT(&work_list); if (context_cb == NULL) - goto done; + return AOK; /* Walk the pending context queue under the dplane lock. */ DPLANE_LOCK(); @@ -6487,9 +6516,7 @@ int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx, dplane_ctx_fini(&ctx); } -done: - - return 0; + return AOK; } /* Indicates zebra shutdown/exit is in progress. Some operations may be @@ -6553,10 +6580,8 @@ static bool dplane_work_pending(void) } DPLANE_UNLOCK(); - if (ctx != NULL) { - ret = true; - goto done; - } + if (ctx != NULL) + return true; while (prov) { @@ -6579,7 +6604,6 @@ static bool dplane_work_pending(void) if (ctx != NULL) ret = true; -done: return ret; } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index b9fd176de7..51f6f3d897 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -380,6 +380,8 @@ route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx); uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance); uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx); +uint32_t dplane_ctx_get_flags(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags); uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx); @@ -908,6 +910,12 @@ dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset); int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct route_node *rn, struct route_entry *re); +int dplane_ctx_route_init_basic(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, struct route_entry *re, + const struct prefix *p, + const struct prefix_ipv6 *src_p, afi_t afi, + safi_t safi); + /* Encode next hop information into data plane context. */ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct nhg_hash_entry *nhe); @@ -1073,6 +1081,16 @@ void zebra_dplane_pre_finish(void); void zebra_dplane_finish(void); void zebra_dplane_shutdown(void); +/* + * decision point for sending a routing update through the old + * straight to zebra master pthread or through the dplane to + * the master pthread for handling + */ +void dplane_rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, + struct prefix_ipv6 *src_p, struct route_entry *re, + struct nexthop_group *ng, int startup, + struct zebra_dplane_ctx *ctx); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 656588bb82..b86780276b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1523,8 +1523,7 @@ static bool rib_route_match_ctx(const struct route_entry *re, } done: - - return (result); + return result; } static void zebra_rib_fixup_system(struct route_node *rn) @@ -2261,10 +2260,8 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) } /* Ensure we clear the QUEUED flag */ - if (!zrouter.asic_offloaded) { - UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); - UNSET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING); - } + UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); + UNSET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING); /* Is this a notification that ... matters? We mostly care about * the route that is currently selected for installation; we may also @@ -2307,6 +2304,19 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) dplane_ctx_get_type(ctx))); } goto done; + } else { + uint32_t flags = dplane_ctx_get_flags(ctx); + + if (CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOADED)) { + UNSET_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED); + SET_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED); + } + if (CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOAD_FAILED)) { + UNSET_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED); + SET_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED); + } + if (CHECK_FLAG(flags, ZEBRA_FLAG_TRAPPED)) + SET_FLAG(re->flags, ZEBRA_FLAG_TRAPPED); } /* We'll want to determine whether the installation status of the @@ -2340,55 +2350,70 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) /* Various fib transitions: changed nexthops; from installed to * not-installed; or not-installed to installed. */ - if (start_count > 0 && end_count > 0) { - if (debug_p) - zlog_debug( - "%s(%u:%u):%pRN applied nexthop changes from dplane notification", - VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn); + if (zrouter.asic_notification_nexthop_control) { + if (start_count > 0 && end_count > 0) { + if (debug_p) + zlog_debug( + "%s(%u:%u):%pRN applied nexthop changes from dplane notification", + VRF_LOGNAME(vrf), + dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), rn); - /* Changed nexthops - update kernel/others */ - dplane_route_notif_update(rn, re, - DPLANE_OP_ROUTE_UPDATE, ctx); + /* Changed nexthops - update kernel/others */ + dplane_route_notif_update(rn, re, + DPLANE_OP_ROUTE_UPDATE, ctx); - } else if (start_count == 0 && end_count > 0) { - if (debug_p) - zlog_debug( - "%s(%u:%u):%pRN installed transition from dplane notification", - VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn); + } else if (start_count == 0 && end_count > 0) { + if (debug_p) + zlog_debug( + "%s(%u:%u):%pRN installed transition from dplane notification", + VRF_LOGNAME(vrf), + dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), rn); - /* We expect this to be the selected route, so we want - * to tell others about this transition. - */ - SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + /* We expect this to be the selected route, so we want + * to tell others about this transition. + */ + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - /* Changed nexthops - update kernel/others */ - dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_UPDATE, ctx); + /* Changed nexthops - update kernel/others */ + dplane_route_notif_update(rn, re, + DPLANE_OP_ROUTE_UPDATE, ctx); - /* Redistribute, lsp, and nht update */ - redistribute_update(rn, re, NULL); + /* Redistribute, lsp, and nht update */ + redistribute_update(rn, re, NULL); - } else if (start_count > 0 && end_count == 0) { - if (debug_p) - zlog_debug( - "%s(%u:%u):%pRN un-installed transition from dplane notification", - VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), rn); + } else if (start_count > 0 && end_count == 0) { + if (debug_p) + zlog_debug( + "%s(%u:%u):%pRN un-installed transition from dplane notification", + VRF_LOGNAME(vrf), + dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), rn); - /* Transition from _something_ installed to _nothing_ - * installed. - */ - /* We expect this to be the selected route, so we want - * to tell others about this transistion. - */ - UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + /* Transition from _something_ installed to _nothing_ + * installed. + */ + /* We expect this to be the selected route, so we want + * to tell others about this transistion. + */ + UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - /* Changed nexthops - update kernel/others */ - dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_DELETE, ctx); + /* Changed nexthops - update kernel/others */ + dplane_route_notif_update(rn, re, + DPLANE_OP_ROUTE_DELETE, ctx); - /* Redistribute, lsp, and nht update */ - redistribute_delete(rn, re, NULL); + /* Redistribute, lsp, and nht update */ + redistribute_delete(rn, re, NULL); + } + } + + if (!zebra_router_notify_on_ack()) { + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED)) + zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED); + if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED)) + zsend_route_notify_owner_ctx(ctx, + ZAPI_ROUTE_FAIL_INSTALL); } /* Make any changes visible for lsp and nexthop-tracking processing */ diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index b8923ef57d..a9a7b66ce7 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -330,6 +330,17 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) zrouter.asic_offloaded = asic_offload; zrouter.notify_on_ack = notify_on_ack; + /* + * If you start using asic_notification_nexthop_control + * come talk to the FRR community about what you are doing + * We would like to know. + */ +#if CONFDATE > 20251231 + CPP_NOTICE( + "Remove zrouter.asic_notification_nexthop_control as that it's not being maintained or used"); +#endif + zrouter.asic_notification_nexthop_control = false; + #ifdef HAVE_SCRIPTING zebra_script_init(); #endif diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 069437ef47..e0ef86f082 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -224,6 +224,14 @@ struct zebra_router { bool asic_offloaded; bool notify_on_ack; + /* + * If the asic is notifying us about successful nexthop + * allocation/control. Some developers have made their + * asic take control of how many nexthops/ecmp they can + * have and will report what is successfull or not + */ + bool asic_notification_nexthop_control; + bool supports_nhgs; bool all_mc_forwardingv4, default_mc_forwardingv4; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 91a0c1dd31..997cd0bdc7 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -4073,6 +4073,15 @@ DEFUN (show_zebra, ttable_add_row(table, "ASIC offload|%s", zrouter.asic_offloaded ? "Used" : "Unavailable"); + /* + * Do not display this unless someone is actually using it + * + * Why this distinction? I think this is effectively dead code + * and should not be exposed. Maybe someone proves me wrong. + */ + if (zrouter.asic_notification_nexthop_control) + ttable_add_row(table, "ASIC offload and nexthop control|Used"); + ttable_add_row(table, "RA|%s", rtadv_compiled_in() ? "Compiled in" : "Not Compiled in"); ttable_add_row(table, "RFC 5549|%s", |
