/* */
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);
nhe->nhg.nexthop->vrf_id, nhe->id);
}
- zebra_nhg_insert_id(nhe);
return nhe;
}
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;
}
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;
}
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 = {};
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)",
*/
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 */
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 {
NEXTHOP_FLAG_RECURSIVE) ?
"(R)" : "");
- depends_find_add(&newnhe->nhg_depends, nh, afi);
+ depends_find_add(&newnhe->nhg_depends, nh, afi,
+ newnhe->type);
}
}
__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 */
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);
}
}
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);
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() */
/* 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);
}
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 = {};
*/
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);
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;
* 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) {
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",
}
/* 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;
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)",
&& !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);
{
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;
+}
* 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
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);