}
}
+static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
+ struct nexthop *nh, afi_t afi)
+{
+ struct nhg_hash_entry *depend = NULL;
+ struct nexthop_group resolved_ng = {};
+
+ _nexthop_group_add_sorted(&resolved_ng, nh);
+
+ depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
+ depends_add(nhg_depends, depend);
+}
static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
struct nexthop_group *nhg,
uint32_t old_id_counter = id_counter;
bool created = false;
+ bool recursive = false;
/*
* If it has an id at this point, we must have gotten it from the kernel
*/
lookup.id = id ? id : ++id_counter;
- lookup.afi = afi;
- lookup.vrf_id = vrf_id;
lookup.type = type ? type : ZEBRA_ROUTE_NHG;
lookup.nhg = nhg;
- if (nhg_depends)
- lookup.nhg_depends = *nhg_depends;
+ if (lookup.nhg->nexthop->next) {
+ /* Groups can have all vrfs and AF's in them */
+ lookup.afi = AFI_UNSPEC;
+ lookup.vrf_id = 0;
+ } else {
+ lookup.afi = afi;
+ lookup.vrf_id = vrf_id;
+ }
if (id)
(*nhe) = zebra_nhg_lookup_id(id);
id_counter = old_id_counter;
if (!(*nhe)) {
+ /* Only hash/lookup the depends if the first lookup
+ * fails to find something. This should hopefully save a
+ * lot of cycles for larger ecmp sizes.
+ */
+ if (nhg_depends)
+ /* If you don't want to hash on each nexthop in the
+ * nexthop group struct you can pass the depends
+ * directly. Kernel-side we do this since it just looks
+ * them up via IDs.
+ */
+ lookup.nhg_depends = *nhg_depends;
+ else {
+ if (nhg->nexthop->next) {
+ nhg_connected_tree_init(&lookup.nhg_depends);
+
+ /* If its a group, create a dependency tree */
+ struct nexthop *nh = NULL;
+
+ for (nh = nhg->nexthop; nh; nh = nh->next)
+ depends_find_add(&lookup.nhg_depends,
+ nh, afi);
+ } else if (CHECK_FLAG(nhg->nexthop->flags,
+ NEXTHOP_FLAG_RECURSIVE)) {
+ nhg_connected_tree_init(&lookup.nhg_depends);
+ handle_recursive_depend(&lookup.nhg_depends,
+ nhg->nexthop->resolved,
+ afi);
+ recursive = true;
+ }
+ }
+
(*nhe) = hash_get(zrouter.nhgs, &lookup, zebra_nhg_hash_alloc);
created = true;
- }
+ if (recursive)
+ SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
+ }
return created;
}
-static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
- struct nexthop *nh, afi_t afi)
-{
- struct nhg_hash_entry *depend = NULL;
- struct nexthop_group resolved_ng = {};
-
- _nexthop_group_add_sorted(&resolved_ng, nh);
-
- depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
- depends_add(nhg_depends, depend);
-}
-
/* Find/create a single nexthop */
-static bool zebra_nhg_find_nexthop(struct nhg_hash_entry **nhe, uint32_t id,
- struct nexthop *nh, afi_t afi, int type)
+static struct nhg_hash_entry *
+zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type)
{
+ struct nhg_hash_entry *nhe = NULL;
struct nexthop_group nhg = {};
- struct nhg_connected_tree_head nhg_depends = {};
- bool created = true;
_nexthop_group_add_sorted(&nhg, nh);
- if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
- nhg_connected_tree_init(&nhg_depends);
- handle_recursive_depend(&nhg_depends, nh->resolved, afi);
- }
+ zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, 0);
- if (!zebra_nhg_find(nhe, id, &nhg, &nhg_depends, nh->vrf_id, afi, 0)) {
- created = false;
- depends_decrement_free(&nhg_depends);
- } else {
- if (zebra_nhg_depends_count(*nhe))
- SET_FLAG((*nhe)->flags, NEXTHOP_GROUP_RECURSIVE);
- }
-
- return created;
+ return nhe;
}
static struct nhg_ctx *nhg_ctx_new()
/* These got copied over in zebra_nhg_alloc() */
nexthop_group_free_delete(&nhg);
} else
- zebra_nhg_find_nexthop(&nhe, ctx->id, &ctx->u.nh, ctx->afi,
- ctx->type);
+ nhe = zebra_nhg_find_nexthop(ctx->id, &ctx->u.nh, ctx->afi,
+ ctx->type);
if (nhe) {
if (ctx->id != nhe->id) {
lookup->next = NULL;
lookup->prev = NULL;
- zebra_nhg_find_nexthop(&nhe, 0, lookup, afi, 0);
+ nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
nexthops_free(lookup);
zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
{
struct nhg_hash_entry *nhe = NULL;
- struct nhg_connected_tree_head nhg_depends = {};
- bool recursive = false;
- /* Defualt the nhe to the afi and vrf of the route */
- afi_t nhg_afi = rt_afi;
vrf_id_t nhg_vrf_id = nhg->nexthop->vrf_id;
if (!nhg) {
return NULL;
}
- if (nhg->nexthop->next) {
- nhg_connected_tree_init(&nhg_depends);
-
- /* If its a group, create a dependency tree */
- struct nexthop *nh = NULL;
-
- for (nh = nhg->nexthop; nh; nh = nh->next)
- depends_find_add(&nhg_depends, nh, rt_afi);
-
- /* change the afi/vrf_id since its a group */
- nhg_afi = AFI_UNSPEC;
- nhg_vrf_id = 0;
- } else if (CHECK_FLAG(nhg->nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) {
- nhg_connected_tree_init(&nhg_depends);
- handle_recursive_depend(&nhg_depends, nhg->nexthop->resolved,
- rt_afi);
- recursive = true;
- }
-
- if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, nhg_vrf_id, nhg_afi,
- 0))
- depends_decrement_free(&nhg_depends);
- else if (recursive)
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE);
+ zebra_nhg_find(&nhe, id, nhg, NULL, nhg_vrf_id, rt_afi, 0);
return nhe;
}