summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/rib.h4
-rw-r--r--zebra/zebra_nhg.c39
-rw-r--r--zebra/zebra_rib.c26
3 files changed, 49 insertions, 20 deletions
diff --git a/zebra/rib.h b/zebra/rib.h
index dd22d79835..a02a461e89 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -344,8 +344,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 58fa245eba..b3336abc3c 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -3320,6 +3320,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)
@@ -3417,22 +3418,32 @@ 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;
+ THREAD_OFF(old->timer);
+ zebra_nhg_free(old);
+ old = NULL;
}
-
- /* 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 (IS_ZEBRA_DEBUG_NHG_DETAIL)
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index bfe40f1026..186740b013 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -398,18 +398,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",
@@ -421,10 +432,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,