From ccfc679a2f6809969dafb3747cd8a60c339cc7d6 Mon Sep 17 00:00:00 2001 From: "hanyu.zly" Date: Mon, 28 Oct 2024 17:44:53 +0800 Subject: [PATCH] zebra:Add PIC support in the srv6 VPN scenario. This PR implements the separation of nh_srv6-related information, which was originally stored in the nexthop, in the srv6-vpn scenario. It generates a new pic nexthop that contains only the next-hop forwarding information. Meanwhile, the original nexthop containing nh_srv6 is used as pic context information and indexed separately. With this modification, we can converge the nexthop group and update the FIB before notifying other protocols (such as BGP) when a route is withdrawn. This can significantly reduce packet loss duration during link failures. Signed-off-by: hanyu.zly&freddy --- lib/nexthop.c | 32 +++++ lib/nexthop.h | 6 + lib/nexthop_group.c | 73 +++++++++++ lib/nexthop_group.h | 4 + zebra/dpdk/zebra_dplane_dpdk.c | 6 + zebra/dplane_fpm_nl.c | 10 +- zebra/kernel_netlink.c | 4 + zebra/kernel_socket.c | 3 + zebra/main.c | 39 +++--- zebra/rib.h | 6 + zebra/zebra_dplane.c | 47 ++++++- zebra/zebra_dplane.h | 8 ++ zebra/zebra_nhg.c | 217 ++++++++++++++++++++++++--------- zebra/zebra_nhg.h | 10 +- zebra/zebra_rib.c | 76 ++++++++++++ zebra/zebra_script.c | 3 + zebra/zebra_vty.c | 43 +++++-- 17 files changed, 498 insertions(+), 89 deletions(-) diff --git a/lib/nexthop.c b/lib/nexthop.c index 98b05295b996..56db5b8d1950 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -940,6 +940,38 @@ struct nexthop *nexthop_dup(const struct nexthop *nexthop, return new; } +void nexthop_copy_no_context(struct nexthop *copy, const struct nexthop *nexthop, + struct nexthop *rparent) +{ + copy->vrf_id = nexthop->vrf_id; + copy->ifindex = nexthop->ifindex; + copy->type = nexthop->type; + copy->flags = nexthop->flags; + copy->weight = nexthop->weight; + + assert(nexthop->backup_num < NEXTHOP_MAX_BACKUPS); + copy->backup_num = nexthop->backup_num; + if (copy->backup_num > 0) + memcpy(copy->backup_idx, nexthop->backup_idx, copy->backup_num); + + copy->srte_color = nexthop->srte_color; + memcpy(©->gate, &nexthop->gate, sizeof(nexthop->gate)); + memcpy(©->src, &nexthop->src, sizeof(nexthop->src)); + memcpy(©->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src)); + copy->rparent = rparent; + + if (CHECK_FLAG(copy->flags, NEXTHOP_FLAG_RECURSIVE)) + copy_nexthops_nocontext(©->resolved, nexthop->resolved, copy); +} + +struct nexthop *nexthop_dup_no_context(const struct nexthop *nexthop, struct nexthop *rparent) +{ + struct nexthop *new = nexthop_new(); + + nexthop_copy_no_context(new, nexthop, rparent); + return new; +} + /* * Parse one or more backup index values, as comma-separated numbers, * into caller's array of uint8_ts. The array must be NEXTHOP_MAX_BACKUPS diff --git a/lib/nexthop.h b/lib/nexthop.h index 02ea4d96f2df..c654efd7f847 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -237,6 +237,10 @@ extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, extern void nexthop_copy_no_recurse(struct nexthop *copy, const struct nexthop *nexthop, struct nexthop *rparent); + +extern struct nexthop *nexthop_dup_no_context(const struct nexthop *nexthop, + struct nexthop *rparent); + /* Duplicates a nexthop and returns the newly allocated nexthop */ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop, struct nexthop *rparent); @@ -255,6 +259,8 @@ extern bool nexthop_is_blackhole(const struct nexthop *nh); */ int nexthop_str2backups(const char *str, int *num_backups, uint8_t *backups); +extern void nexthop_copy_no_context(struct nexthop *copy, const struct nexthop *nexthop, + struct nexthop *rparent); void nexthop_json_helper(json_object *json_nexthop, const struct nexthop *nexthop, bool display_vrfid, diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index cb1ebb5d09b9..bea8d4dbe59f 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -341,6 +341,67 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg, _nexthop_add_sorted(&nhg->nexthop, nexthop); } +/* Add nexthop to sorted list of nexthops. + * The difference with _nexthop_add_sorted is that it filters out duplicate nexthops. + */ +static bool _nexthop_add_no_dup(struct nexthop **head, struct nexthop *nexthop) +{ + struct nexthop *position, *prev; + int ret = 0; + + assert(!nexthop->next); + + for (position = *head, prev = NULL; position; prev = position, position = position->next) { + ret = nexthop_cmp(position, nexthop); + if (ret == 0) + return false; + else if (nexthop_cmp(position, nexthop) > 0) { + nexthop->next = position; + nexthop->prev = prev; + + if (nexthop->prev) + nexthop->prev->next = nexthop; + else + *head = nexthop; + + position->prev = nexthop; + return true; + } + } + + nexthop->prev = prev; + if (prev) + prev->next = nexthop; + else + *head = nexthop; + return true; +} + +bool nexthop_group_add_sorted_nodup(struct nexthop_group *nhg, struct nexthop *nexthop) +{ + struct nexthop *tail; + int ret = 0; + + assert(!nexthop->next); + + /* Try to just append to the end first; + * trust the list is already sorted + */ + tail = nexthop_group_tail(nhg); + if (tail) { + ret = nexthop_cmp(tail, nexthop); + if (ret == 0) + return false; + if (ret < 0) { + tail->next = nexthop; + nexthop->prev = tail; + return true; + } + } + + return _nexthop_add_no_dup(&nhg->nexthop, nexthop); +} + /* Delete nexthop from a nexthop list. */ void _nexthop_del(struct nexthop_group *nhg, struct nexthop *nh) { @@ -430,6 +491,18 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh, } } +/* Copy a list of nexthops, filtered the part of context. */ +void copy_nexthops_nocontext(struct nexthop **tnh, const struct nexthop *nh, struct nexthop *rparent) +{ + struct nexthop *nexthop; + const struct nexthop *nh1; + + for (nh1 = nh; nh1; nh1 = nh1->next) { + nexthop = nexthop_dup_no_context(nh1, rparent); + _nexthop_add(tnh, nexthop); + } +} + uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg) { struct nexthop *nh; diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 910329941884..282c143c44d2 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -51,6 +51,10 @@ void nexthop_group_copy_nh_sorted(struct nexthop_group *nhg, void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh, struct nexthop *rparent); +void copy_nexthops_nocontext(struct nexthop **tnh, const struct nexthop *nh, + struct nexthop *rparent); +bool nexthop_group_add_sorted_nodup(struct nexthop_group *nhg, struct nexthop *nexthop); + uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg); uint32_t nexthop_group_hash(const struct nexthop_group *nhg); void nexthop_group_mark_duplicates(struct nexthop_group *nhg); diff --git a/zebra/dpdk/zebra_dplane_dpdk.c b/zebra/dpdk/zebra_dplane_dpdk.c index ae1a3743ce58..e80faf4d9a93 100644 --- a/zebra/dpdk/zebra_dplane_dpdk.c +++ b/zebra/dpdk/zebra_dplane_dpdk.c @@ -365,6 +365,9 @@ static void zd_dpdk_rule_update(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_DELETE: case DPLANE_OP_LSP_INSTALL: case DPLANE_OP_LSP_UPDATE: case DPLANE_OP_LSP_DELETE: @@ -425,6 +428,9 @@ static void zd_dpdk_process_update(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_DELETE: case DPLANE_OP_LSP_INSTALL: case DPLANE_OP_LSP_UPDATE: case DPLANE_OP_LSP_DELETE: diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index e6b4af367429..30fe55669911 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -909,9 +909,10 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) * If we were configured to not use next hop groups, then quit as soon * as possible. */ - if ((!fnc->use_nhg) - && (op == DPLANE_OP_NH_DELETE || op == DPLANE_OP_NH_INSTALL - || op == DPLANE_OP_NH_UPDATE)) + if ((!fnc->use_nhg) && + (op == DPLANE_OP_NH_DELETE || op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE || + op == DPLANE_OP_PIC_CONTEXT_DELETE || op == DPLANE_OP_PIC_CONTEXT_INSTALL || + op == DPLANE_OP_PIC_CONTEXT_UPDATE)) return 0; nl_buf_len = 0; @@ -1059,6 +1060,9 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_NONE: case DPLANE_OP_STARTUP_STAGE: case DPLANE_OP_VLAN_INSTALL: + case DPLANE_OP_PIC_CONTEXT_DELETE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: break; } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 0c607dfa67cb..8a31ba09b473 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1654,6 +1654,10 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: return netlink_put_sr_tunsrc_set_msg(bth, ctx); + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_DELETE: + return FRR_NETLINK_SUCCESS; } return FRR_NETLINK_ERROR; diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 4789cb62f257..4fb51eab1fa5 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1604,6 +1604,9 @@ void kernel_update_multi(struct dplane_ctx_list_head *ctx_list) case DPLANE_OP_SYS_ROUTE_DELETE: case DPLANE_OP_ROUTE_NOTIFY: case DPLANE_OP_LSP_NOTIFY: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_DELETE: res = ZEBRA_DPLANE_REQUEST_SUCCESS; break; diff --git a/zebra/main.c b/zebra/main.c index 138a955bc313..41178eea3e65 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -67,6 +67,8 @@ struct mgmt_be_client *mgmt_be_client; /* Route retain mode flag. */ int retain_mode = 0; +bool fpm_pic_nexthop; + /* Receive buffer size for kernel control sockets */ #define RCVBUFSIZE_MIN 4194304 #ifdef HAVE_NETLINK @@ -82,22 +84,22 @@ uint32_t rt_table_main_id = RT_TABLE_MAIN; #define OPTION_V6_WITH_V4_NEXTHOP 2002 /* Command line options. */ -const struct option longopts[] = { - { "batch", no_argument, NULL, 'b' }, - { "allow_delete", no_argument, NULL, 'a' }, - { "socket", required_argument, NULL, 'z' }, - { "ecmp", required_argument, NULL, 'e' }, - { "retain", no_argument, NULL, 'r' }, - { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, - { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, +const struct option longopts[] = { { "pic", no_argument, NULL, 'p' }, + { "batch", no_argument, NULL, 'b' }, + { "allow_delete", no_argument, NULL, 'a' }, + { "socket", required_argument, NULL, 'z' }, + { "ecmp", required_argument, NULL, 'e' }, + { "retain", no_argument, NULL, 'r' }, + { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, + { "v6-with-v4-nexthops", no_argument, NULL, + OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK - { "vrfwnetns", no_argument, NULL, 'n' }, - { "nl-bufsize", required_argument, NULL, 's' }, - { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, + { "vrfwnetns", no_argument, NULL, 'n' }, + { "nl-bufsize", required_argument, NULL, 's' }, + { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - { "routing-table", optional_argument, NULL, 'R' }, - { 0 } -}; + { "routing-table", optional_argument, NULL, 'R' }, + { 0 } }; zebra_capabilities_t _caps_p[] = {ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, @@ -356,16 +358,19 @@ int main(int argc, char **argv) zserv_path = NULL; + fpm_pic_nexthop = false; + vrf_configure_backend(VRF_BACKEND_VRF_LITE); frr_preinit(&zebra_di, argc, argv); - frr_opt_add("baz:e:rK:s:R:" + frr_opt_add("pbaz:e:rK:s:R:" #ifdef HAVE_NETLINK "n" #endif , longopts, + " -p, --pic Runs in pic mode\n" " -b, --batch Runs in batch mode\n" " -a, --allow_delete Allow other processes to delete zebra routes\n" " -z, --socket Set path of zebra socket\n" @@ -452,6 +457,10 @@ int main(int argc, char **argv) v6_with_v4_nexthop = true; break; #endif /* HAVE_NETLINK */ + case 'p': + fpm_pic_nexthop = true; + break; + default: frr_help_exit(1); } diff --git a/zebra/rib.h b/zebra/rib.h index 5fedb07335ef..479348f31635 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -91,6 +91,9 @@ struct route_entry { uint32_t nhe_id; uint32_t nhe_installed_id; + uint32_t pic_nhe_id; + uint32_t pic_nhe_installed_id; + /* Type of this route. */ int type; @@ -471,6 +474,7 @@ extern int rib_gc_dest(struct route_node *rn); extern struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter); extern uint8_t route_distance(int type); +extern bool zebra_update_pic_nhe(struct route_node *rn); extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, bool rt_delete); @@ -641,6 +645,8 @@ void route_entry_dump_nh(const struct route_entry *re, const char *straddr, /* Name of hook calls */ #define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results" +extern bool fpm_pic_nexthop; + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 88c1a049382b..16ac7b1e1483 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -82,6 +82,7 @@ const uint32_t DPLANE_DEFAULT_NEW_WORK = 100; struct dplane_nexthop_info { uint32_t id; uint32_t old_id; + uint32_t pic_nhe_id; afi_t afi; vrf_id_t vrf_id; int type; @@ -771,7 +772,10 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: { + case DPLANE_OP_NH_DELETE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_DELETE: { if (ctx->u.rinfo.nhe.ng.nexthop) { /* This deals with recursive nexthops too */ nexthops_free(ctx->u.rinfo.nhe.ng.nexthop); @@ -1067,6 +1071,12 @@ const char *dplane_op2str(enum dplane_op_e op) return "NH_UPDATE"; case DPLANE_OP_NH_DELETE: return "NH_DELETE"; + case DPLANE_OP_PIC_CONTEXT_INSTALL: + return "PIC_CONTEXT_INSTALL"; + case DPLANE_OP_PIC_CONTEXT_UPDATE: + return "PIC_CONTEXT_UPDATE"; + case DPLANE_OP_PIC_CONTEXT_DELETE: + return "PIC_CONTEXT_DELETE"; case DPLANE_OP_LSP_INSTALL: return "LSP_INSTALL"; @@ -2237,6 +2247,12 @@ uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx) return ctx->u.rinfo.nhe.id; } +uint32_t dplane_ctx_get_pic_nhe_id(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + return ctx->u.rinfo.nhe.pic_nhe_id; +} + uint32_t dplane_ctx_get_old_nhe_id(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -3514,6 +3530,8 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ctx->u.rinfo.nhe.id = nhe->id; ctx->u.rinfo.nhe.old_id = 0; + if (nhe->pic_nhe) + ctx->u.rinfo.nhe.pic_nhe_id = nhe->pic_nhe->id; /* * Check if the nhe is installed/queued before doing anything * with this route. @@ -3529,6 +3547,8 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, return ENOENT; re->nhe_installed_id = nhe->id; + if (nhe->pic_nhe) + re->pic_nhe_installed_id = nhe->pic_nhe->id; } #endif /* HAVE_NETLINK */ @@ -4681,6 +4701,25 @@ dplane_route_notif_update(struct route_node *rn, return result; } +enum zebra_dplane_result dplane_pic_context_add(struct nhg_hash_entry *nhe) +{ + enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; + + if (nhe) + ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_PIC_CONTEXT_INSTALL); + return ret; +} + +enum zebra_dplane_result dplane_pic_context_delete(struct nhg_hash_entry *nhe) +{ + enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE; + + if (nhe) + ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_PIC_CONTEXT_DELETE); + + return ret; +} + /* * Enqueue a nexthop add for the dataplane. */ @@ -6550,6 +6589,9 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_DELETE: zlog_debug("ID (%u) Dplane nexthop update ctx %p op %s", dplane_ctx_get_nhe_id(ctx), ctx, dplane_op2str(dplane_ctx_get_op(ctx))); @@ -6755,6 +6797,9 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_DELETE: if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) atomic_fetch_add_explicit( &zdplane_info.dg_nexthop_errors, 1, diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 285b00c9b7ea..a940e486b479 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -125,6 +125,11 @@ enum dplane_op_e { DPLANE_OP_NH_UPDATE, DPLANE_OP_NH_DELETE, + /* Pic Context update*/ + DPLANE_OP_PIC_CONTEXT_INSTALL, + DPLANE_OP_PIC_CONTEXT_UPDATE, + DPLANE_OP_PIC_CONTEXT_DELETE, + /* LSP update */ DPLANE_OP_LSP_INSTALL, DPLANE_OP_LSP_UPDATE, @@ -601,6 +606,7 @@ dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx); /* Accessors for nexthop information */ uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx); +uint32_t dplane_ctx_get_pic_nhe_id(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_old_nhe_id(const struct zebra_dplane_ctx *ctx); afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx); vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx); @@ -870,6 +876,8 @@ struct nhg_hash_entry; /* * Enqueue a nexthop change operation for the dataplane. */ +enum zebra_dplane_result dplane_pic_context_add(struct nhg_hash_entry *nhe); +enum zebra_dplane_result dplane_pic_context_delete(struct nhg_hash_entry *nhe); enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe); enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe); enum zebra_dplane_result dplane_nexthop_delete(struct nhg_hash_entry *nhe); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1519246c179e..9bc5c91db657 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -52,13 +52,13 @@ static bool g_nexthops_enabled = true; static bool proto_nexthops_only; static bool use_recursive_backups = true; -static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi, - int type, bool from_dplane); +static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi, int type, + bool from_dplane, bool pic); static void depends_add(struct nhg_connected_tree_head *head, struct nhg_hash_entry *depend); -static struct nhg_hash_entry * -depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, - afi_t afi, int type, bool from_dplane); +static struct nhg_hash_entry *depends_find_add(struct nhg_connected_tree_head *head, + struct nexthop *nh, afi_t afi, int type, + bool from_dplane, bool pic); static struct nhg_hash_entry * depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id); static void depends_decrement_free(struct nhg_connected_tree_head *head); @@ -664,8 +664,8 @@ static int zebra_nhg_process_grp(struct nexthop_group *nhg, struct nhg_connected return 0; } -static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, - struct nexthop *nh, afi_t afi, int type) +static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, struct nexthop *nh, + afi_t afi, int type, bool pic) { struct nhg_hash_entry *depend = NULL; struct nexthop_group resolved_ng = {}; @@ -676,7 +676,7 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, zlog_debug("%s: head %p, nh %pNHv", __func__, nhg_depends, nh); - depend = zebra_nhg_rib_find(0, &resolved_ng, afi, type); + depend = zebra_nhg_rib_find(0, &resolved_ng, afi, type, pic); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nh %pNHv => %p (%u)", @@ -687,18 +687,28 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, depends_add(nhg_depends, depend); } +static bool zebra_need_to_create_pic(struct nexthop *nh) +{ + if (!fpm_pic_nexthop) + return false; + if (nh && nh->nh_srv6 && !sid_zero(nh->nh_srv6->seg6_segs)) + return true; + return false; +} + /* * Lookup an nhe in the global hash, using data from another nhe. If 'lookup' * has an id value, that's used. Create a new global/shared nhe if not found. */ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ struct nhg_hash_entry *lookup, - struct nhg_connected_tree_head *nhg_depends, - afi_t afi, bool from_dplane) + struct nhg_connected_tree_head *nhg_depends, afi_t afi, bool from_dplane, + bool pic) { bool created = false; + bool createdPic = false; bool recursive = false; - struct nhg_hash_entry *newnhe, *backup_nhe; + struct nhg_hash_entry *newnhe, *backup_nhe, *pic_nhe; struct nexthop *nh = NULL; @@ -781,9 +791,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ if (nh->next == NULL && newnhe->id < ZEBRA_NHG_PROTO_LOWER) { if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { /* Single recursive nexthop */ - handle_recursive_depend(&newnhe->nhg_depends, - nh->resolved, afi, - newnhe->type); + handle_recursive_depend(&newnhe->nhg_depends, nh->resolved, afi, + newnhe->type, pic); recursive = true; } } else { @@ -797,8 +806,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ NEXTHOP_FLAG_RECURSIVE) ? "(R)" : ""); - depends_find_add(&newnhe->nhg_depends, nh, afi, - newnhe->type, from_dplane); + depends_find_add(&newnhe->nhg_depends, nh, afi, newnhe->type, from_dplane, + pic); } } @@ -832,8 +841,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ __func__, nh); /* Single recursive nexthop */ - handle_recursive_depend(&backup_nhe->nhg_depends, nh->resolved, - afi, backup_nhe->type); + handle_recursive_depend(&backup_nhe->nhg_depends, nh->resolved, afi, + backup_nhe->type, pic); recursive = true; } else { /* One or more backup NHs */ @@ -845,8 +854,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ NEXTHOP_FLAG_RECURSIVE) ? "(R)" : ""); - depends_find_add(&backup_nhe->nhg_depends, nh, afi, - backup_nhe->type, from_dplane); + depends_find_add(&backup_nhe->nhg_depends, nh, afi, backup_nhe->type, + from_dplane, pic); } } @@ -854,20 +863,101 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE); done: + nh = (*nhe)->nhg.nexthop; + createdPic = zebra_need_to_create_pic(nh); + + if (createdPic && !pic) { + zebra_pic_nhe_find(&pic_nhe, *nhe, afi, from_dplane); + if (pic_nhe && ((*nhe)->pic_nhe) == NULL) { + (*nhe)->pic_nhe = pic_nhe; + zebra_nhg_increment_ref(pic_nhe); + } + } + /* Reset time since last update */ (*nhe)->uptime = monotime(NULL); return created; } +/*find or create pic*/ +bool zebra_pic_nhe_find(struct nhg_hash_entry **pic_nhe, /* return value */ + struct nhg_hash_entry *nhe, afi_t afi, bool from_dplane) +{ + bool created = false; + struct nhg_hash_entry *picnhe; + struct nexthop *nh = NULL; + struct nhg_hash_entry pic_nh_lookup = {}; + //struct nexthop *nexthop_tmp; + struct nexthop *pic_nexthop_tmp; + bool ret = 0; + + if (nhe->pic_nhe) { + *pic_nhe = nhe->pic_nhe; + return false; + } + /* Use a temporary nhe to find pic nh */ + pic_nh_lookup.type = ZEBRA_ROUTE_NHG; + pic_nh_lookup.vrf_id = nhe->vrf_id; + SET_FLAG(pic_nh_lookup.flags, NEXTHOP_GROUP_PIC_NHT); + /* the nhg.nexthop is sorted */ + for (nh = nhe->nhg.nexthop; nh; nh = nh->next) { + if (nh->type == NEXTHOP_TYPE_IFINDEX) + continue; + pic_nexthop_tmp = nexthop_dup_no_context(nh, NULL); + ret = nexthop_group_add_sorted_nodup(&pic_nh_lookup.nhg, pic_nexthop_tmp); + if (!ret) + nexthop_free(pic_nexthop_tmp); + } + if (pic_nh_lookup.nhg.nexthop == NULL) { + *pic_nhe = NULL; + return false; + } + + if (!zebra_nhg_depends_is_empty(nhe) || pic_nh_lookup.nhg.nexthop->next) { + /* Groups can have all vrfs and AF's in them */ + pic_nh_lookup.afi = AFI_UNSPEC; + } else { + switch (pic_nh_lookup.nhg.nexthop->type) { + case (NEXTHOP_TYPE_IFINDEX): + case (NEXTHOP_TYPE_BLACKHOLE): + /* + * This switch case handles setting the afi different + * for ipv4/v6 routes. Ifindex/blackhole nexthop + * objects cannot be ambiguous, they must be Address + * Family specific. If we get here, we will either use + * the AF of the route, or the one we got passed from + * here from the kernel. + */ + pic_nh_lookup.afi = afi; + break; + case (NEXTHOP_TYPE_IPV4_IFINDEX): + case (NEXTHOP_TYPE_IPV4): + pic_nh_lookup.afi = AFI_IP; + break; + case (NEXTHOP_TYPE_IPV6_IFINDEX): + case (NEXTHOP_TYPE_IPV6): + pic_nh_lookup.afi = AFI_IP6; + break; + } + } + + created = zebra_nhe_find(&picnhe, &pic_nh_lookup, NULL, afi, from_dplane, true); + + *pic_nhe = picnhe; + if (pic_nh_lookup.nhg.nexthop) + nexthops_free(pic_nh_lookup.nhg.nexthop); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: create PIC nhe id %d for nhe %d", __func__, picnhe->id, nhe->id); + return created; +} + /* * Lookup or create an nhe, based on an nhg or an nhe id. */ -static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, - struct nexthop_group *nhg, - struct nhg_connected_tree_head *nhg_depends, - vrf_id_t vrf_id, afi_t afi, int type, - bool from_dplane) +static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, struct nexthop_group *nhg, + struct nhg_connected_tree_head *nhg_depends, vrf_id_t vrf_id, afi_t afi, + int type, bool from_dplane, bool pic) { struct nhg_hash_entry lookup = {}; bool created = false; @@ -911,16 +1001,14 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, } } - created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi, from_dplane); + created = zebra_nhe_find(nhe, &lookup, nhg_depends, afi, from_dplane, pic); return created; } /* Find/create a single nexthop */ -static struct nhg_hash_entry *zebra_nhg_find_nexthop(uint32_t id, - struct nexthop *nh, - afi_t afi, int type, - bool from_dplane) +static struct nhg_hash_entry *zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, + int type, bool from_dplane, bool pic) { struct nhg_hash_entry *nhe = NULL; struct nexthop_group nhg = {}; @@ -928,7 +1016,7 @@ static struct nhg_hash_entry *zebra_nhg_find_nexthop(uint32_t id, nexthop_group_add_sorted(&nhg, nh); - zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type, from_dplane); + zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type, from_dplane, pic); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__, nh, nhe, nhe); @@ -1231,15 +1319,13 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) return -ENOENT; } - if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, afi, - type, true)) + if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, afi, type, true, false)) depends_decrement_free(&nhg_depends); /* These got copied over in zebra_nhg_alloc() */ nexthop_group_delete(&nhg); } else - nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi, type, - true); + nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi, type, true, false); if (!nhe) { flog_err( @@ -1406,24 +1492,23 @@ int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id) } /* Some dependency helper functions */ -static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh, - afi_t afi, int type) +static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh, afi_t afi, int type, + bool pic) { struct nhg_hash_entry *nhe; struct nexthop *lookup = NULL; lookup = nexthop_dup(nh, NULL); - nhe = zebra_nhg_find_nexthop(0, lookup, afi, type, false); + nhe = zebra_nhg_find_nexthop(0, lookup, afi, type, false, pic); nexthops_free(lookup); return nhe; } -static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, - afi_t afi, int type, - bool from_dplane) +static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, afi_t afi, int type, + bool from_dplane, bool pic) { struct nhg_hash_entry *nhe; struct nexthop lookup = {}; @@ -1438,7 +1523,7 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, * to be created with a weight of 1. */ lookup.weight = 1; - nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type, from_dplane); + nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type, from_dplane, pic); /* The copy may have allocated labels; free them if necessary. */ nexthop_del_labels(&lookup); @@ -1451,8 +1536,8 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, return nhe; } -static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi, - int type, bool from_dplane) +static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi, int type, + bool from_dplane, bool pic) { struct nhg_hash_entry *nhe = NULL; @@ -1463,9 +1548,9 @@ static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi, * in the non-recursive case (by not alloc/freeing) */ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) - nhe = depends_find_recursive(nh, afi, type); + nhe = depends_find_recursive(nh, afi, type, pic); else - nhe = depends_find_singleton(nh, afi, type, from_dplane); + nhe = depends_find_singleton(nh, afi, type, from_dplane, pic); if (IS_ZEBRA_DEBUG_NHG_DETAIL) { @@ -1496,13 +1581,13 @@ static void depends_add(struct nhg_connected_tree_head *head, zebra_nhg_increment_ref(depend); } -static struct nhg_hash_entry * -depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, - afi_t afi, int type, bool from_dplane) +static struct nhg_hash_entry *depends_find_add(struct nhg_connected_tree_head *head, + struct nexthop *nh, afi_t afi, int type, + bool from_dplane, bool pic) { struct nhg_hash_entry *depend = NULL; - depend = depends_find(nh, afi, type, from_dplane); + depend = depends_find(nh, afi, type, from_dplane, pic); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nh %pNHv => %p", @@ -1534,9 +1619,8 @@ static void depends_decrement_free(struct nhg_connected_tree_head *head) } /* Find an nhe based on a list of nexthops */ -struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, - struct nexthop_group *nhg, - afi_t rt_afi, int type) +struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi, + int type, bool pic) { struct nhg_hash_entry *nhe = NULL; vrf_id_t vrf_id; @@ -1548,7 +1632,7 @@ struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, assert(nhg->nexthop); vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id; - zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, type, false); + zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, type, false, pic); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe); @@ -1574,7 +1658,7 @@ zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi) return NULL; } - zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi, false); + zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi, false, false); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: rt_nhe %p(%pNG) => nhe %p(%pNG)", __func__, @@ -1653,6 +1737,9 @@ static void zebra_nhg_free_members(struct nhg_hash_entry *nhe) /* Decrement to remove connection ref */ nhg_connected_tree_decrement_ref(&nhe->nhg_depends); + if (nhe->pic_nhe) + zebra_nhg_decrement_ref(nhe->pic_nhe); + nhe->pic_nhe = NULL; nhg_connected_tree_free(&nhe->nhg_depends); nhg_connected_tree_free(&nhe->nhg_dependents); } @@ -3315,6 +3402,7 @@ uint16_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, int m void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type) { struct nhg_connected *rb_node_dep = NULL; + enum zebra_dplane_result ret; /* Resolve it first */ nhe = zebra_nhg_resolve(nhe); @@ -3336,6 +3424,8 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type) frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { zebra_nhg_install_kernel(rb_node_dep->nhe, type); } + if (nhe->pic_nhe) + zebra_nhg_install_kernel(nhe->pic_nhe, ZEBRA_ROUTE_MAX); if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) && (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) || @@ -3345,7 +3435,10 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type) if (!ZEBRA_NHG_CREATED(nhe)) nhe->type = ZEBRA_ROUTE_NHG; - enum zebra_dplane_result ret = dplane_nexthop_add(nhe); + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_PIC_NHT) || !nhe->pic_nhe) + ret = dplane_nexthop_add(nhe); + else + ret = dplane_pic_context_add(nhe); switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: @@ -3365,8 +3458,13 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type) void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe) { + enum zebra_dplane_result ret; + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { - int ret = dplane_nexthop_delete(nhe); + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_PIC_NHT) || !nhe->pic_nhe) + ret = dplane_nexthop_delete(nhe); + else + ret = dplane_pic_context_delete(nhe); switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: @@ -3404,7 +3502,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s", ctx, dplane_op2str(op), id, dplane_res2str(status)); - if (op == DPLANE_OP_NH_DELETE) { + if (op == DPLANE_OP_NH_DELETE || op == DPLANE_OP_PIC_CONTEXT_DELETE) { if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) flog_err( EC_ZEBRA_DP_DELETE_FAIL, @@ -3412,7 +3510,8 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) id); /* We already free'd the data, nothing to do */ - } else if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE) { + } else if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE || + op == DPLANE_OP_PIC_CONTEXT_INSTALL || op == DPLANE_OP_PIC_CONTEXT_UPDATE) { nhe = zebra_nhg_lookup_id(id); if (!nhe) { diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 0f90627a0d15..baf648e25b48 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -88,7 +88,7 @@ struct nhg_hash_entry { * nhg(2)->nhg_dependents is 3 in the tree */ struct nhg_connected_tree_head nhg_depends, nhg_dependents; - + struct nhg_hash_entry *pic_nhe; struct event *timer; /* @@ -171,6 +171,7 @@ struct nhg_hash_entry { * chooses this NHG then we can install it then. */ #define NEXTHOP_GROUP_INITIAL_DELAY_INSTALL (1 << 9) +#define NEXTHOP_GROUP_PIC_NHT (1 << 10) }; /* Upper 4 bits of the NHG are reserved for indicating the NHG type */ @@ -324,13 +325,14 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id); /* Find an nhe based on a nexthop_group */ -extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, - struct nexthop_group *nhg, - afi_t rt_afi, int type); +extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, + afi_t rt_afi, int type, bool pic); /* Find an nhe based on a route's nhe, used during route creation */ struct nhg_hash_entry * zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi); +extern bool zebra_pic_nhe_find(struct nhg_hash_entry **pic_nhe, /* return value */ + struct nhg_hash_entry *nhe, afi_t afi, bool from_dplane); /** diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b2543ca0e8b1..5adca3c77469 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -414,6 +414,9 @@ static void route_entry_attach_ref(struct route_entry *re, re->nhe_id = new->id; re->nhe_installed_id = 0; + if (new->pic_nhe) + re->pic_nhe_id = new->pic_nhe->id; + zebra_nhg_increment_ref(new); } @@ -429,6 +432,7 @@ int route_entry_update_nhe(struct route_entry *re, re->nhe_id = 0; re->nhe_installed_id = 0; + re->pic_nhe_id = 0; re->nhe = NULL; goto done; } @@ -736,6 +740,72 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) return; } +bool zebra_update_pic_nhe(struct route_node *rn) +{ + afi_t afi; + int ret = 0; + struct nhg_hash_entry *picnhe; + struct nexthop *nh = NULL; + struct nhg_hash_entry pic_nh_lookup = { 0 }; + //struct nexthop *nexthop_tmp; + struct prefix *p; + struct zebra_vrf *zvrf; + struct nhg_connected *rb_node_dep = NULL; + rib_dest_t *dest = rib_dest_from_rnode(rn); + if (!dest) + return false; + zvrf = rib_dest_vrf(dest); + p = &rn->p; + afi = family2afi(p->family); + pic_nh_lookup.afi = afi; + /* Use a temporary nhe to find pic nh */ + pic_nh_lookup.type = ZEBRA_ROUTE_NHG; + pic_nh_lookup.vrf_id = zvrf_id(zvrf); + SET_FLAG(pic_nh_lookup.flags, NEXTHOP_GROUP_PIC_NHT); + /* the nhg.nexthop is sorted */ + switch (afi) { + case AFI_IP: + nh = nexthop_from_ipv4(&p->u.prefix4, NULL, zvrf_id(zvrf)); + + break; + case AFI_IP6: + nh = nexthop_from_ipv6(&p->u.prefix6, zvrf_id(zvrf)); + break; + case AFI_UNSPEC: + case AFI_L2VPN: + case AFI_MAX: + return false; + } + + SET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE); + ret = nexthop_group_add_sorted_nodup(&pic_nh_lookup.nhg, nh); + if (!ret) { + nexthop_free(nh); + return false; + } + + picnhe = hash_lookup(zrouter.nhgs, &pic_nh_lookup); + + if (pic_nh_lookup.nhg.nexthop) + nexthops_free(pic_nh_lookup.nhg.nexthop); + + if (!picnhe) + return false; + + UNSET_FLAG(picnhe->flags, NEXTHOP_GROUP_VALID); + + frr_each_safe (nhg_connected_tree, &picnhe->nhg_dependents, rb_node_dep) { + //zebra_nhg_set_invalid(rb_node_dep->nhe); + if (ZEBRA_DEBUG_DPLANE_DETAILED) + zlog_debug("%s: pic_nhe %ul become invaild during route %pRN deleted, update pic_nh dependents %ul", + __func__, picnhe->id, rn, rb_node_dep->nhe->id); + UNSET_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_INSTALLED); + zebra_nhg_install_kernel(rb_node_dep->nhe, ZEBRA_ROUTE_MAX); + } + + return true; +} + /* * rib_can_delete_dest * @@ -774,6 +844,9 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, rib_dest_t *dest = rib_dest_from_rnode(rn); struct rnh *rnh; + if (rt_delete) + zebra_update_pic_nhe(rn); + /* * We are storing the rnh's associated with * the tracked nexthop as a list of the rnh's @@ -4970,6 +5043,9 @@ static void rib_process_dplane_results(struct event *thread) case DPLANE_OP_ROUTE_INSTALL: case DPLANE_OP_ROUTE_UPDATE: case DPLANE_OP_ROUTE_DELETE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_DELETE: /* Bit of special case for route updates * that were generated by async notifications: * we don't want to continue processing these diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c index a0d5e2054cca..b945491896d0 100644 --- a/zebra/zebra_script.c +++ b/zebra/zebra_script.c @@ -56,6 +56,9 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: + case DPLANE_OP_PIC_CONTEXT_INSTALL: + case DPLANE_OP_PIC_CONTEXT_UPDATE: + case DPLANE_OP_PIC_CONTEXT_DELETE: /* rinfo */ lua_newtable(L); { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b65097e725b4..e3533b50dab1 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -583,12 +583,31 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, vty_out(vty, " Last update %s ago\n", buf); if (show_ng) { - vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); - if (re->nhe_installed_id != 0 - && re->nhe_id != re->nhe_installed_id) - vty_out(vty, - " Installed Nexthop Group ID: %u\n", - re->nhe_installed_id); + if (fpm_pic_nexthop) { + if (re->pic_nhe_id != 0) { + vty_out(vty, " Nexthop Group ID: %u\n", re->pic_nhe_id); + vty_out(vty, " PIC Context ID: %u\n", re->nhe_id); + if (re->pic_nhe_installed_id != 0 && + re->pic_nhe_installed_id != re->pic_nhe_id) + vty_out(vty, " Installed Nexthop Group ID: %u\n", + re->pic_nhe_installed_id); + if (re->nhe_installed_id != 0 && + re->nhe_installed_id != re->nhe_id) + vty_out(vty, " Installed PIC Context ID: %u\n", + re->pic_nhe_installed_id); + } else { + vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); + if (re->nhe_installed_id != 0 && + re->nhe_installed_id != re->nhe_id) + vty_out(vty, " Installed Nexthop Group ID: %u\n", + re->pic_nhe_installed_id); + } + } else { + vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); + if (re->nhe_installed_id != 0 && re->nhe_id != re->nhe_installed_id) + vty_out(vty, " Installed Nexthop Group ID: %u\n", + re->nhe_installed_id); + } } for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { @@ -696,11 +715,16 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, nexthop_group_active_nexthop_num( &(re->nhe->nhg))); json_object_int_add(json_route, "nexthopGroupId", re->nhe_id); + if (re->pic_nhe_id != 0) + json_object_int_add(json_route, "picNexthopId", re->pic_nhe_id); if (re->nhe_installed_id != 0) json_object_int_add(json_route, "installedNexthopGroupId", re->nhe_installed_id); + if (re->pic_nhe_installed_id != 0) + json_object_int_add(json_route, "installedPicNexthopGroupId", + re->pic_nhe_installed_id); json_object_string_add(json_route, "uptime", up_str); @@ -775,8 +799,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, len += vty_out(vty, " [%u/%u]", re->distance, re->metric); - if (show_ng) + if (show_ng) { len += vty_out(vty, " (%u)", re->nhe_id); + len += vty_out(vty, " (pic_nh %u)", re->pic_nhe_id); + } /* Nexthop information. */ for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { @@ -1402,6 +1428,9 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, vty_out(vty, "\n"); } + if (nhe->pic_nhe) + vty_out(vty, " pic nhe:%d \n", nhe->pic_nhe->id); + if (nhe->nhg.nhgr.buckets) { if (json) { json_object_int_add(json, "buckets",