if (hash_lookup(zrouter.nhgs_id, nhe)) {
flog_err(
EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
- "Failed inserting NHG id=%u into the ID hash table, entry already exists",
- nhe->id);
+ "Failed inserting NHG %pNG into the ID hash table, entry already exists",
+ nhe);
return -1;
}
- hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
+ (void)hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
return 0;
}
if (!zebra_nhg_depends_is_empty(nhe)) {
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%u), dep %p (%u)",
- __func__, nhe, nhe->id,
- rb_node_dep->nhe,
- rb_node_dep->nhe->id);
+ zlog_debug("%s: nhe %p (%pNG), dep %p (%pNG)",
+ __func__, nhe, nhe, rb_node_dep->nhe,
+ rb_node_dep->nhe);
zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
}
else {
if (IS_ZEBRA_DEBUG_NHG)
zlog_debug(
- "Failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
+ "Failed to lookup an interface with ifindex=%d in vrf=%u for NHE %pNG",
nhe->nhg.nexthop->ifindex,
- nhe->nhg.nexthop->vrf_id, nhe->id);
+ nhe->nhg.nexthop->vrf_id, nhe);
}
}
(*nhe) = hash_lookup(zrouter.nhgs, lookup);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: lookup => %p (%u)",
- __func__, (*nhe),
- (*nhe) ? (*nhe)->id : 0);
+ zlog_debug("%s: lookup => %p (%pNG)", __func__, *nhe, *nhe);
/* If we found an existing object, we're done */
if (*nhe)
*nhe = newnhe;
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: => created %p (%u)", __func__, newnhe,
- newnhe->id);
+ zlog_debug("%s: => created %p (%pNG)", __func__, newnhe,
+ newnhe);
/* Only hash/lookup the depends if the first lookup
* fails to find something. This should hopefully save a
zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type, from_dplane);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nh %pNHv => %p (%u)",
- __func__, nh, nhe, nhe ? nhe->id : 0);
+ zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__, nh, nhe, nhe);
return nhe;
}
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+ /* If we're in shutdown, this interface event needs to clean
+ * up installed NHGs, so don't clear that flag directly.
+ */
+ if (!zebra_router_in_shutdown())
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+
/* Update validity of nexthops depending on it */
frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep)
zebra_nhg_check_valid(rb_node_dep->nhe);
static void zebra_nhg_release(struct nhg_hash_entry *nhe)
{
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%u)", __func__, nhe, nhe->id);
+ zlog_debug("%s: nhe %p (%pNG)", __func__, nhe, nhe);
zebra_nhg_release_all_deps(nhe);
if (nhe->refcnt) {
flog_err(
EC_ZEBRA_NHG_SYNC,
- "Kernel %s a nexthop group with ID (%u) that we are still using for a route, sending it back down",
- (is_delete ? "deleted" : "updated"), nhe->id);
+ "Kernel %s a nexthop group with ID (%pNG) that we are still using for a route, sending it back down",
+ (is_delete ? "deleted" : "updated"), nhe);
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
zebra_nhg_install_kernel(nhe);
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%u) is new", __func__, nhe, nhe->id);
+ zlog_debug("%s: nhe %p (%pNG) is new", __func__, nhe, nhe);
/*
* If daemon nhg from the kernel, add a refcnt here to indicate the
nexthop_del_srv6_seg6(&lookup);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nh %pNHv => %p (%u)",
- __func__, nh, nhe, nhe ? nhe->id : 0);
+ zlog_debug("%s: nh %pNHv => %p (%pNG)", __func__, nh, nhe, nhe);
return nhe;
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
- zlog_debug("%s: nh %pNHv %s => %p (%u)", __func__, nh,
+ zlog_debug("%s: nh %pNHv %s => %p (%pNG)", __func__, nh,
CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE) ? "(R)"
: "",
- nhe, nhe ? nhe->id : 0);
+ nhe, nhe);
}
done:
zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, type, false);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: => nhe %p (%u)",
- __func__, nhe, nhe ? nhe->id : 0);
+ zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe);
return nhe;
}
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: rt_nhe %p (%u)", __func__, rt_nhe, rt_nhe->id);
+ zlog_debug("%s: rt_nhe %p (%pNG)", __func__, rt_nhe, rt_nhe);
zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi, false);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: => nhe %p (%u)",
- __func__, nhe, nhe ? nhe->id : 0);
+ zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe);
return nhe;
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
/* Group or singleton? */
if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
- zlog_debug("%s: nhe %p (%u), refcnt %d",
- __func__, nhe, nhe->id, nhe->refcnt);
+ zlog_debug("%s: nhe %p (%pNG), refcnt %d", __func__,
+ nhe, nhe, nhe->refcnt);
else
- zlog_debug("%s: nhe %p (%u), refcnt %d, NH %pNHv",
- __func__, nhe, nhe->id, nhe->refcnt,
+ zlog_debug("%s: nhe %p (%pNG), refcnt %d, NH %pNHv",
+ __func__, nhe, nhe, nhe->refcnt,
nhe->nhg.nexthop);
}
- if (nhe->refcnt)
- zlog_debug("nhe_id=%u hash refcnt=%d", nhe->id, nhe->refcnt);
+ THREAD_OFF(nhe->timer);
zebra_nhg_free_members(nhe);
XFREE(MTYPE_NHG, nhe);
}
+/*
+ * Let's just drop the memory associated with each item
+ */
void zebra_nhg_hash_free(void *p)
{
- zebra_nhg_release_all_deps((struct nhg_hash_entry *)p);
- zebra_nhg_free((struct nhg_hash_entry *)p);
+ struct nhg_hash_entry *nhe = p;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
+ /* Group or singleton? */
+ if (nhe->nhg.nexthop && nhe->nhg.nexthop->next)
+ zlog_debug("%s: nhe %p (%u), refcnt %d", __func__, nhe,
+ nhe->id, nhe->refcnt);
+ else
+ zlog_debug("%s: nhe %p (%pNG), refcnt %d, NH %pNHv",
+ __func__, nhe, nhe, nhe->refcnt,
+ nhe->nhg.nexthop);
+ }
+
+ THREAD_OFF(nhe->timer);
+
+ nexthops_free(nhe->nhg.nexthop);
+
+ XFREE(MTYPE_NHG, nhe);
+}
+
+/*
+ * On cleanup there are nexthop groups that have not
+ * been resolved at all( a nhe->id of 0 ). As such
+ * zebra needs to clean up the memory associated with
+ * those entries.
+ */
+void zebra_nhg_hash_free_zero_id(struct hash_bucket *b, void *arg)
+{
+ struct nhg_hash_entry *nhe = b->data;
+ struct nhg_connected *dep;
+
+ while ((dep = nhg_connected_tree_pop(&nhe->nhg_depends))) {
+ if (dep->nhe->id == 0)
+ zebra_nhg_hash_free(dep->nhe);
+
+ nhg_connected_free(dep);
+ }
+
+ while ((dep = nhg_connected_tree_pop(&nhe->nhg_dependents)))
+ nhg_connected_free(dep);
+
+ if (nhe->backup_info && nhe->backup_info->nhe->id == 0) {
+ while ((dep = nhg_connected_tree_pop(
+ &nhe->backup_info->nhe->nhg_depends)))
+ nhg_connected_free(dep);
+
+ zebra_nhg_hash_free(nhe->backup_info->nhe);
+
+ XFREE(MTYPE_NHG, nhe->backup_info);
+ }
+}
+
+static void zebra_nhg_timer(struct thread *thread)
+{
+ struct nhg_hash_entry *nhe = THREAD_ARG(thread);
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("Nexthop Timer for nhe: %pNG", nhe);
+
+ if (nhe->refcnt == 1)
+ zebra_nhg_decrement_ref(nhe);
}
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
{
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%u) %d => %d",
- __func__, nhe, nhe->id, nhe->refcnt,
- nhe->refcnt - 1);
+ zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__, nhe, nhe,
+ nhe->refcnt, nhe->refcnt - 1);
nhe->refcnt--;
+ if (!zebra_router_in_shutdown() && nhe->refcnt <= 0 &&
+ CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) &&
+ !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND)) {
+ nhe->refcnt = 1;
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND);
+ thread_add_timer(zrouter.master, zebra_nhg_timer, nhe,
+ zrouter.nhg_keep, &nhe->timer);
+ return;
+ }
+
if (!zebra_nhg_depends_is_empty(nhe))
nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
{
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%u) %d => %d",
- __func__, nhe, nhe->id, nhe->refcnt,
- nhe->refcnt + 1);
+ zlog_debug("%s: nhe %p (%pNG) %d => %d", __func__, nhe, nhe,
+ nhe->refcnt, nhe->refcnt + 1);
nhe->refcnt++;
+ if (thread_is_scheduled(nhe->timer)) {
+ THREAD_OFF(nhe->timer);
+ nhe->refcnt--;
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_KEEP_AROUND);
+ }
+
if (!zebra_nhg_depends_is_empty(nhe))
nhg_connected_tree_increment_ref(&nhe->nhg_depends);
}
* route and interface is up, its active. We trust kernel routes
* to be good.
*/
- if (ifp
- && (if_is_operative(ifp)
- || (if_is_up(ifp)
- && (type == ZEBRA_ROUTE_KERNEL
- || type == ZEBRA_ROUTE_SYSTEM))))
+ if (ifp && (if_is_operative(ifp)))
return 1;
else
return 0;
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: CONNECT match %p (%u), newhop %pNHv",
- __func__, match,
- match->nhe->id, newhop);
+ zlog_debug(
+ "%s: CONNECT match %p (%pNG), newhop %pNHv",
+ __func__, match, match->nhe, newhop);
return 1;
} else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
/* Only useful if installed */
if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug("%s: match %p (%u) not installed",
- __func__, match,
- match->nhe->id);
+ zlog_debug(
+ "%s: match %p (%pNG) not installed",
+ __func__, match, match->nhe);
goto done_with_match;
}
continue;
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: RECURSIVE match %p (%u), newhop %pNHv",
- __func__, match,
- match->nhe->id, newhop);
+ zlog_debug(
+ "%s: RECURSIVE match %p (%pNG), newhop %pNHv",
+ __func__, match, match->nhe,
+ newhop);
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
continue;
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: RECURSIVE match backup %p (%u), newhop %pNHv",
- __func__, match,
- match->nhe->id, newhop);
+ zlog_debug(
+ "%s: RECURSIVE match backup %p (%pNG), newhop %pNHv",
+ __func__, match, match->nhe,
+ newhop);
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop);
/*
- * If the kernel has sent us a NEW route, then
+ * If this is a kernel route, then if the interface is *up* then
* by golly gee whiz it's a good route.
- *
- * If its an already INSTALLED route we have already handled, then the
- * kernel route's nexthop might have became unreachable
- * and we have to handle that.
*/
- if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) &&
- (re->type == ZEBRA_ROUTE_KERNEL ||
- re->type == ZEBRA_ROUTE_SYSTEM)) {
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
- goto skip_check;
- }
+ if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_SYSTEM) {
+ struct interface *ifp;
+ ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
+
+ if (ifp && (if_is_operative(ifp) || if_is_up(ifp))) {
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ goto skip_check;
+ }
+ }
vrf_id = zvrf_id(rib_dest_vrf(rib_dest_from_rnode(rn)));
switch (nexthop->type) {
curr_nhe = zebra_nhe_copy(re->nhe, re->nhe->id);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: re %p nhe %p (%u), curr_nhe %p",
- __func__, re, re->nhe, re->nhe->id,
- curr_nhe);
+ zlog_debug("%s: re %p nhe %p (%pNG), curr_nhe %p", __func__, re,
+ re->nhe, re->nhe, curr_nhe);
/* Clear the existing id, if any: this will avoid any confusion
* if the id exists, and will also force the creation
new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: re %p CHANGED: nhe %p (%u) => new_nhe %p (%u)",
- __func__, re, re->nhe,
- re->nhe->id, new_nhe, new_nhe->id);
+ zlog_debug(
+ "%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)",
+ __func__, re, re->nhe, re->nhe, new_nhe,
+ new_nhe);
route_entry_update_nhe(re, new_nhe);
}
if (!depend) {
flog_err(
EC_ZEBRA_NHG_FIB_UPDATE,
- "Failed to recursively resolve Nexthop Hash Entry in the group id=%u",
- nhe->id);
+ "Failed to recursively resolve Nexthop Hash Entry in the group id=%pNG",
+ nhe);
continue;
}
}
case ZEBRA_DPLANE_REQUEST_FAILURE:
flog_err(
EC_ZEBRA_DP_INSTALL_FAIL,
- "Failed to install Nexthop ID (%u) into the kernel",
- nhe->id);
+ "Failed to install Nexthop ID (%pNG) into the kernel",
+ nhe);
break;
case ZEBRA_DPLANE_REQUEST_SUCCESS:
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
case ZEBRA_DPLANE_REQUEST_FAILURE:
flog_err(
EC_ZEBRA_DP_DELETE_FAIL,
- "Failed to uninstall Nexthop ID (%u) from the kernel",
- nhe->id);
+ "Failed to uninstall Nexthop ID (%pNG) from the kernel",
+ nhe);
break;
case ZEBRA_DPLANE_REQUEST_SUCCESS:
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
!PROTO_OWNED(nhe)))
flog_err(
EC_ZEBRA_DP_INSTALL_FAIL,
- "Failed to install Nexthop ID (%u) into the kernel",
- nhe->id);
+ "Failed to install Nexthop (%pNG) into the kernel",
+ nhe);
}
break;
case DPLANE_OP_INTF_INSTALL:
case DPLANE_OP_INTF_UPDATE:
case DPLANE_OP_INTF_DELETE:
+ case DPLANE_OP_TC_INSTALL:
+ case DPLANE_OP_TC_UPDATE:
+ case DPLANE_OP_TC_DELETE:
break;
}
-
- dplane_ctx_fini(&ctx);
}
static int zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg)
rib_handle_nhg_replace(old, new);
- /* if this != 1 at this point, we have a bug */
- assert(old->refcnt == 1);
-
/* We have to decrement its singletons
* because some might not exist in NEW.
*/
/* Dont call the dec API, we dont want to uninstall the ID */
old->refcnt = 0;
+ THREAD_OFF(old->timer);
zebra_nhg_free(old);
old = NULL;
}
if (nhe->refcnt > 1) {
if (IS_ZEBRA_DEBUG_NHG)
zlog_debug(
- "%s: id %u, still being used by routes refcnt %u",
- __func__, nhe->id, nhe->refcnt);
+ "%s: %pNG, still being used by routes refcnt %u",
+ __func__, nhe, nhe->refcnt);
return nhe;
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: deleted nhe %p (%u), vrf %d, type %s", __func__,
- nhe, nhe->id, nhe->vrf_id,
+ zlog_debug("%s: deleted nhe %p (%pNG), vrf %d, type %s",
+ __func__, nhe, nhe, nhe->vrf_id,
zebra_route_string(nhe->type));
return nhe;
if (nhe->type == iter->type && PROTO_OWNED(nhe)) {
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug(
- "%s: found nhe %p (%u), vrf %d, type %s after client disconnect",
- __func__, nhe, nhe->id, nhe->vrf_id,
+ "%s: found nhe %p (%pNG), vrf %d, type %s after client disconnect",
+ __func__, nhe, nhe, nhe->vrf_id,
zebra_route_string(nhe->type));
/* Add to removal list */
return count;
}
+
+printfrr_ext_autoreg_p("NG", printfrr_nhghe);
+static ssize_t printfrr_nhghe(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ const struct nhg_hash_entry *nhe = ptr;
+ const struct nhg_connected *dep;
+ ssize_t ret = 0;
+
+ if (!nhe)
+ return bputs(buf, "[NULL]");
+
+ ret += bprintfrr(buf, "%u[", nhe->id);
+ if (nhe->ifp)
+ ret += printfrr_nhs(buf, nhe->nhg.nexthop);
+ else {
+ int count = zebra_nhg_depends_count(nhe);
+
+ frr_each (nhg_connected_tree_const, &nhe->nhg_depends, dep) {
+ ret += bprintfrr(buf, "%u", dep->nhe->id);
+ if (count > 1)
+ ret += bputs(buf, "/");
+ count--;
+ }
+ }
+
+ ret += bputs(buf, "]");
+ return ret;
+}