summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonald Sharp <donaldsharp72@gmail.com>2023-09-05 14:03:00 -0400
committerGitHub <noreply@github.com>2023-09-05 14:03:00 -0400
commit9c36b56d4cf72f665785a7761d7c2ece3358ee59 (patch)
tree0bc4ce98e3ceefb7c6a60c4f5ac57db516070af1
parent889b21788458ba0099fb74820abbd8d9eba95f5d (diff)
parent56903202ce54c935d3940e20c3dd36d967fb49a7 (diff)
Merge pull request #14352 from FRRouting/mergify/bp/stable/9.0/pr-14318
zebra: Fix zebra crash when replacing NHE during shutdown (backport #14318)
-rw-r--r--zebra/rib.h4
-rw-r--r--zebra/zebra_nhg.c38
-rw-r--r--zebra/zebra_rib.c26
3 files changed, 48 insertions, 20 deletions
diff --git a/zebra/rib.h b/zebra/rib.h
index 65cc1ffab9..77d06762bc 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -329,8 +329,8 @@ int route_entry_update_nhe(struct route_entry *re,
struct nhg_hash_entry *new_nhghe);
/* NHG replace has happend, we have to update route_entry pointers to new one */
-void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
- struct nhg_hash_entry *new_entry);
+int rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
+ struct nhg_hash_entry *new_entry);
#define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re)
extern void _route_entry_dump(const char *func, union prefixconstptr pp,
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 717a7a7b48..2b78b828af 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -3410,6 +3410,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
struct nhg_connected *rb_node_dep = NULL;
struct nexthop *newhop;
bool replace = false;
+ int ret = 0;
if (!nhg->nexthop) {
if (IS_ZEBRA_DEBUG_NHG)
@@ -3507,22 +3508,31 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
if (CHECK_FLAG(old->flags, NEXTHOP_GROUP_PROTO_RELEASED))
zebra_nhg_increment_ref(old);
- rib_handle_nhg_replace(old, new);
+ ret = rib_handle_nhg_replace(old, new);
+ if (ret)
+ /*
+ * if ret > 0, some previous re->nhe has freed the
+ * address to which old_entry is pointing. Hence mark
+ * the old NHE as NULL
+ */
+ old = NULL;
+ else {
+ /* We have to decrement its singletons
+ * because some might not exist in NEW.
+ */
+ if (!zebra_nhg_depends_is_empty(old)) {
+ frr_each (nhg_connected_tree, &old->nhg_depends,
+ rb_node_dep)
+ zebra_nhg_decrement_ref(
+ rb_node_dep->nhe);
+ }
- /* We have to decrement its singletons
- * because some might not exist in NEW.
- */
- if (!zebra_nhg_depends_is_empty(old)) {
- frr_each (nhg_connected_tree, &old->nhg_depends,
- rb_node_dep)
- zebra_nhg_decrement_ref(rb_node_dep->nhe);
+ /* Dont call the dec API, we dont want to uninstall the ID */
+ old->refcnt = 0;
+ EVENT_OFF(old->timer);
+ zebra_nhg_free(old);
+ old = NULL;
}
-
- /* Dont call the dec API, we dont want to uninstall the ID */
- old->refcnt = 0;
- EVENT_OFF(old->timer);
- zebra_nhg_free(old);
- old = NULL;
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index b531eb7c23..ad6bcc356c 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -428,18 +428,29 @@ int route_entry_update_nhe(struct route_entry *re,
done:
/* Detach / deref previous nhg */
- if (old_nhg)
+
+ if (old_nhg) {
+ /*
+ * Return true if we are deleting the previous NHE
+ * Note: we dont check the return value of the function anywhere
+ * except at rib_handle_nhg_replace().
+ */
+ if (old_nhg->refcnt == 1)
+ ret = 1;
+
zebra_nhg_decrement_ref(old_nhg);
+ }
return ret;
}
-void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
- struct nhg_hash_entry *new_entry)
+int rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
+ struct nhg_hash_entry *new_entry)
{
struct zebra_router_table *zrt;
struct route_node *rn;
struct route_entry *re, *next;
+ int ret = 0;
if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: replacing routes nhe (%u) OLD %p NEW %p",
@@ -451,10 +462,17 @@ void rib_handle_nhg_replace(struct nhg_hash_entry *old_entry,
rn = srcdest_route_next(rn)) {
RNODE_FOREACH_RE_SAFE (rn, re, next) {
if (re->nhe && re->nhe == old_entry)
- route_entry_update_nhe(re, new_entry);
+ ret += route_entry_update_nhe(re,
+ new_entry);
}
}
}
+
+ /*
+ * if ret > 0, some previous re->nhe has freed the address to which
+ * old_entry is pointing.
+ */
+ return ret;
}
struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,