diff options
Diffstat (limited to 'zebra/zebra_nhg.c')
| -rw-r--r-- | zebra/zebra_nhg.c | 63 |
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; } |
