diff options
| -rw-r--r-- | zebra/rib.h | 4 | ||||
| -rw-r--r-- | zebra/zebra_nhg.c | 39 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 26 |
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, |
