From 0885b1e3d90b1fa4d84c7e7a5fb775ba397c4103 Mon Sep 17 00:00:00 2001 From: Stephen Worley Date: Tue, 5 May 2020 15:57:35 -0400 Subject: [PATCH] zebra: implement protocol NHG Add/Del Implement the underlying zebra functionality to Add/Del an internal zebra and kernel NHG. These NHGs are managed by the upperlevel protocols that send them down via zapi messaging. They are not put into the overall zebra NHG hash table and only put into to the ID table. Therefore, different protos cannot and will not share NHGs. The proto is also set appropriately when sent to the kernel. Expand the separation of Zebra hashed/shared/created NHGs and proto created and mangaged NHGs. Signed-off-by: Stephen Worley --- lib/route_types.txt | 2 +- zebra/zapi_msg.c | 38 ++++++++-- zebra/zebra_nhg.c | 176 ++++++++++++++++++++++++++++++++++---------- zebra/zebra_nhg.h | 60 +++++++++++---- zebra/zebra_vty.c | 2 +- 5 files changed, 217 insertions(+), 61 deletions(-) diff --git a/lib/route_types.txt b/lib/route_types.txt index b549c11cf..37cc2fb59 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -84,7 +84,7 @@ ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR" ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD" ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric" ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP" -ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group" +ZEBRA_ROUTE_NHG, zebra, none, '-', 0, 0, 0, "Nexthop Group" ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE" ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-" diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 7c00ae103..dfcab080f 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1734,16 +1734,22 @@ static void zread_nhg_del(ZAPI_HANDLER_ARGS) struct stream *s = msg; uint32_t id; uint16_t proto; + struct nhg_hash_entry *nhe; STREAM_GETW(s, proto); STREAM_GETL(s, id); /* * Delete the received nhg id - * id is incremented to make compiler happy right now - * it should be removed in future code work. */ - nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVED); + + nhe = zebra_nhg_proto_del(id); + + if (nhe) { + zebra_nhg_uninstall_kernel(nhe); + nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVED); + } else + nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVE_FAIL); return; @@ -1762,6 +1768,7 @@ static void zread_nhg_reader(ZAPI_HANDLER_ARGS) struct nexthop_group *nhg = NULL; struct prefix p; uint16_t proto; + struct nhg_hash_entry *nhe; memset(&p, 0, sizeof(p)); @@ -1771,8 +1778,9 @@ static void zread_nhg_reader(ZAPI_HANDLER_ARGS) STREAM_GETL(s, id); STREAM_GETW(s, nhops); - if (zserv_nexthop_num_warn(__func__, &p, nhops)) - return; + // TODO: Can't use this without a prefix. + // if (zserv_nexthop_num_warn(__func__, &p, nhops)) + // return; for (i = 0; i < nhops; i++) { struct zapi_nexthop *znh = &zapi_nexthops[i]; @@ -1792,10 +1800,28 @@ static void zread_nhg_reader(ZAPI_HANDLER_ARGS) __func__); return; } + /* * Install the nhg */ - nhg_notify(proto, client->instance, id, ZAPI_NHG_INSTALLED); + + // TODO: Forcing AF_UNSPEC/AF_IP for now + nhe = zebra_nhg_proto_add(id, ZEBRA_ROUTE_BGP, nhg, + ((nhops > 1) ? AFI_UNSPEC : AFI_IP)); + + nexthop_group_delete(&nhg); + + /* + * TODO: + * Assume fully resolved for now and install. + * + * Resolution is going to need some more work. + */ + if (nhe) { + zebra_nhg_install_kernel(nhe); + nhg_notify(proto, client->instance, id, ZAPI_NHG_INSTALLED); + } else + nhg_notify(proto, client->instance, id, ZAPI_NHG_FAIL_INSTALL); return; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index ac972012b..59df45420 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -54,13 +54,13 @@ uint32_t id_counter; /* */ static bool g_nexthops_enabled = true; -static struct nhg_hash_entry *depends_find(const struct nexthop *nh, - afi_t afi); +static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi, + int type); 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); + afi_t afi, int type); 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); @@ -431,7 +431,6 @@ static void *zebra_nhg_hash_alloc(void *arg) nhe->nhg.nexthop->vrf_id, nhe->id); } - zebra_nhg_insert_id(nhe); return nhe; } @@ -439,17 +438,17 @@ static void *zebra_nhg_hash_alloc(void *arg) uint32_t zebra_nhg_hash_key(const void *arg) { const struct nhg_hash_entry *nhe = arg; - uint32_t val, key = 0x5a351234; - - val = nexthop_group_hash(&(nhe->nhg)); - if (nhe->backup_info) { - val = jhash_2words(val, - nexthop_group_hash( - &(nhe->backup_info->nhe->nhg)), - key); - } + uint32_t key = 0x5a351234; + uint32_t primary = 0; + uint32_t backup = 0; + + primary = nexthop_group_hash(&(nhe->nhg)); + if (nhe->backup_info) + backup = nexthop_group_hash(&(nhe->backup_info->nhe->nhg)); - key = jhash_3words(nhe->vrf_id, nhe->afi, val, key); + key = jhash_3words(primary, backup, nhe->type, key); + + key = jhash_2words(nhe->vrf_id, nhe->afi, key); return key; } @@ -512,6 +511,9 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id)) return true; + if (nhe1->type != nhe2->type) + return false; + if (nhe1->vrf_id != nhe2->vrf_id) return false; @@ -611,7 +613,7 @@ static int zebra_nhg_process_grp(struct nexthop_group *nhg, } static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends, - struct nexthop *nh, afi_t afi) + struct nexthop *nh, afi_t afi, int type) { struct nhg_hash_entry *depend = NULL; struct nexthop_group resolved_ng = {}; @@ -622,7 +624,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); + depend = zebra_nhg_rib_find(0, &resolved_ng, afi, type); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nh %pNHv => %p (%u)", @@ -672,7 +674,25 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ */ if (lookup->id == 0) lookup->id = ++id_counter; - newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc); + + if (ZEBRA_OWNED(lookup)) { + /* + * This is a zebra hashed/owned NHG. + * + * It goes in HASH and ID table. + */ + newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc); + zebra_nhg_insert_id(newnhe); + } else { + /* + * This is upperproto owned NHG and should not be hashed to. + * + * It goes in ID table. + */ + newnhe = + hash_get(zrouter.nhgs_id, lookup, zebra_nhg_hash_alloc); + } + created = true; /* Mail back the new object */ @@ -713,7 +733,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) { /* Single recursive nexthop */ handle_recursive_depend(&newnhe->nhg_depends, - nh->resolved, afi); + nh->resolved, afi, + newnhe->type); recursive = true; } } else { @@ -726,7 +747,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); + depends_find_add(&newnhe->nhg_depends, nh, afi, + newnhe->type); } } @@ -753,8 +775,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); + handle_recursive_depend(&backup_nhe->nhg_depends, nh->resolved, + afi, backup_nhe->type); recursive = true; } else { /* One or more backup NHs */ @@ -766,8 +788,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); + depends_find_add(&backup_nhe->nhg_depends, nh, afi, + backup_nhe->type); } } @@ -1014,10 +1036,10 @@ static void zebra_nhg_release(struct nhg_hash_entry *nhe) if_nhg_dependents_del(nhe->ifp, nhe); /* - * If its not zebra created, we didn't store it here and have to be + * If its not zebra owned, we didn't store it here and have to be * sure we don't clear one thats actually being used. */ - if (nhe->type == ZEBRA_ROUTE_NHG) + if (ZEBRA_OWNED(nhe)) hash_release(zrouter.nhgs, nhe); hash_release(zrouter.nhgs_id, nhe); @@ -1093,8 +1115,8 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) return -ENOENT; } - if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type, - afi)) + if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, afi, + type)) depends_decrement_free(&nhg_depends); /* These got copied over in zebra_nhg_alloc() */ @@ -1261,14 +1283,14 @@ 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) + afi_t afi, int type) { struct nhg_hash_entry *nhe; struct nexthop *lookup = NULL; lookup = nexthop_dup(nh, NULL); - nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0); + nhe = zebra_nhg_find_nexthop(0, lookup, afi, type); nexthops_free(lookup); @@ -1276,7 +1298,7 @@ static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh, } static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, - afi_t afi) + afi_t afi, int type) { struct nhg_hash_entry *nhe; struct nexthop lookup = {}; @@ -1286,7 +1308,7 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh, */ nexthop_copy_no_recurse(&lookup, nh, NULL); - nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0); + nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type); /* The copy may have allocated labels; free them if necessary. */ nexthop_del_labels(&lookup); @@ -1298,7 +1320,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) +static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi, + int type) { struct nhg_hash_entry *nhe = NULL; @@ -1309,9 +1332,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); + nhe = depends_find_recursive(nh, afi, type); else - nhe = depends_find_singleton(nh, afi); + nhe = depends_find_singleton(nh, afi, type); if (IS_ZEBRA_DEBUG_NHG_DETAIL) { @@ -1344,11 +1367,11 @@ static void depends_add(struct nhg_connected_tree_head *head, static struct nhg_hash_entry * depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh, - afi_t afi) + afi_t afi, int type) { struct nhg_hash_entry *depend = NULL; - depend = depends_find(nh, afi); + depend = depends_find(nh, afi, type); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nh %pNHv => %p", @@ -1380,8 +1403,9 @@ 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) +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 *nhe = NULL; vrf_id_t vrf_id; @@ -1393,7 +1417,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) 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, 0); + zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, type); if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: => nhe %p (%u)", @@ -2478,7 +2502,8 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { /* Change its type to us since we are installing it */ - nhe->type = ZEBRA_ROUTE_NHG; + if (!ZEBRA_NHG_CREATED(nhe)) + nhe->type = ZEBRA_ROUTE_NHG; int ret = dplane_nexthop_add(nhe); @@ -2635,3 +2660,74 @@ bool zebra_nhg_kernel_nexthops_enabled(void) { return g_nexthops_enabled; } + +/* Add NHE from upper level proto */ +struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, + struct nexthop_group *nhg, afi_t afi) +{ + struct nhg_hash_entry lookup; + struct nhg_hash_entry *new; + struct nhg_connected *rb_node_dep = NULL; + + zebra_nhe_init(&lookup, afi, nhg->nexthop); + lookup.nhg.nexthop = nhg->nexthop; + lookup.id = id; + lookup.type = type; + + new = zebra_nhg_rib_find_nhe(&lookup, afi); + + if (!new) + return NULL; + + /* TODO: Assuming valid/onlink for now */ + SET_FLAG(new->flags, NEXTHOP_GROUP_VALID); + + if (!zebra_nhg_depends_is_empty(new)) { + frr_each (nhg_connected_tree, &new->nhg_depends, rb_node_dep) + SET_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID); + } + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: added nhe %p (%u), vrf %d, type %s", __func__, + new, new->id, new->vrf_id, + zebra_route_string(new->type)); + + return new; +} + +/* Delete NHE from upper level proto */ +struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id) +{ + struct nhg_hash_entry *nhe; + + nhe = zebra_nhg_lookup_id(id); + + if (!nhe) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: id %u, lookup failed", __func__, id); + + return NULL; + } + + if (nhe->refcnt) { + /* TODO: should be warn? */ + if (IS_ZEBRA_DEBUG_NHG) + zlog_debug("%s: id %u, still being used refcnt %u", + __func__, nhe->id, nhe->refcnt); + return NULL; + } + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: deleted nhe %p (%u), vrf %d, type %s", __func__, + nhe, nhe->id, nhe->vrf_id, + zebra_route_string(nhe->type)); + + return nhe; +} + +/* Replace NHE from upper level proto */ +struct nhg_hash_entry * +zebra_nhg_proto_replace(uint32_t id, struct nexthop_group *nhg, afi_t afi) +{ + return NULL; +} diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index de5f09747..44d768648 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -102,29 +102,25 @@ struct nhg_hash_entry { * Is this a nexthop that is recursively resolved? */ #define NEXTHOP_GROUP_RECURSIVE (1 << 3) -/* - * This is a nexthop group we got from the kernel, it is identical to - * one we already have. (The kernel allows duplicate nexthops, we don't - * since we hash on them). We are only tracking it in our ID table, - * it is unusable by our created routes but may be used by routes we get - * from the kernel. Therefore, it is unhashable. - */ -#define NEXTHOP_GROUP_UNHASHABLE (1 << 4) /* * Backup nexthop support - identify groups that are backups for * another group. */ -#define NEXTHOP_GROUP_BACKUP (1 << 5) +#define NEXTHOP_GROUP_BACKUP (1 << 4) /* * Track FPM installation status.. */ -#define NEXTHOP_GROUP_FPM (1 << 6) +#define NEXTHOP_GROUP_FPM (1 << 5) }; /* Was this one we created, either this session or previously? */ -#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG) +#define ZEBRA_NHG_CREATED(NHE) \ + (((NHE->type) <= ZEBRA_ROUTE_MAX) && (NHE->type != ZEBRA_ROUTE_KERNEL)) + +/* Is this an NHE owned by zebra and not an upper level protocol? */ +#define ZEBRA_OWNED(NHE) (NHE->type == ZEBRA_ROUTE_NHG) /* * Backup nexthops: this is a group object itself, so @@ -249,13 +245,51 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, 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); +extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id, + struct nexthop_group *nhg, + afi_t rt_afi, int type); /* 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); + +/** + * Functions for Add/Del/Replace via protocol NHG creation. + * + * The NHEs will not be hashed. They will only be present in the + * ID table and therefore not sharable. + * + * It is the owning protocols job to manage these. + */ + +/* + * Add NHE. + * + * Returns allocated NHE on success, otherwise NULL. + */ +struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, + struct nexthop_group *nhg, + afi_t afi); + + +/* + * Del NHE. + * + * Returns deleted NHE on success, otherwise NULL. + * + * Caller must free the NHE. + */ +struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id); + +/* + * Replace NHE. + * + * Returns new NHE on success, otherwise NULL. + */ +struct nhg_hash_entry * +zebra_nhg_proto_replace(uint32_t id, struct nexthop_group *nhg, afi_t afi); + /* Reference counter functions */ extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe); extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index ab96a5cf1..baf7d2c14 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1300,7 +1300,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) struct nhg_connected *rb_node_dep = NULL; struct nexthop_group *backup_nhg; - vty_out(vty, "ID: %u\n", nhe->id); + vty_out(vty, "ID: %u (%s)\n", nhe->id, zebra_route_string(nhe->type)); vty_out(vty, " RefCnt: %d\n", nhe->refcnt); vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id)); -- 2.39.5