summaryrefslogtreecommitdiff
path: root/zebra/zebra_nhg.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_nhg.c')
-rw-r--r--zebra/zebra_nhg.c63
1 files changed, 44 insertions, 19 deletions
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 500f4b0f1b..9a0f48158f 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -1055,6 +1055,12 @@ static void zebra_nhg_set_invalid(struct nhg_hash_entry *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 (!zrouter.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);
@@ -1619,6 +1625,17 @@ void zebra_nhg_hash_free(void *p)
zebra_nhg_free((struct nhg_hash_entry *)p);
}
+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)
@@ -1627,6 +1644,15 @@ void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
nhe->refcnt--;
+ if (!zrouter.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);
+ }
+
if (!zebra_nhg_depends_is_empty(nhe))
nhg_connected_tree_decrement_ref(&nhe->nhg_depends);
@@ -1642,6 +1668,12 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
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);
}
@@ -2052,11 +2084,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
* 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;
@@ -2425,20 +2453,19 @@ static unsigned nexthop_active_check(struct route_node *rn,
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) {
@@ -3290,9 +3317,6 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
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.
*/
@@ -3304,6 +3328,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
/* 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;
}