diff options
| -rw-r--r-- | lib/route_types.txt | 2 | ||||
| -rw-r--r-- | zebra/zapi_msg.c | 38 | ||||
| -rw-r--r-- | zebra/zebra_nhg.c | 176 | ||||
| -rw-r--r-- | zebra/zebra_nhg.h | 60 | ||||
| -rw-r--r-- | 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 b549c11cfc..37cc2fb590 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 7c00ae1032..dfcab080f1 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 ac972012b2..59df45420b 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 de5f097472..44d768648f 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 ab96a5cf1f..baf7d2c14d 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)); |
