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,
+ struct nhg_hash_entry *new);
+
#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,
union prefixconstptr src_pp,
struct nhg_hash_entry lookup;
struct nhg_hash_entry *new, *old;
struct nhg_connected *rb_node_dep = NULL;
+ struct nexthop *newhop;
+ bool replace = false;
+
+ if (!nhg->nexthop) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug("%s: id %u, no nexthops passed to add",
+ __func__, id);
+ return NULL;
+ }
+
+
+ /* Set nexthop list as active, since they wont go through rib
+ * processing.
+ *
+ * Assuming valid/onlink for now.
+ *
+ * Once resolution is figured out, we won't need this!
+ */
+ for (ALL_NEXTHOPS_PTR(nhg, newhop))
+ SET_FLAG(newhop->flags, NEXTHOP_FLAG_ACTIVE);
zebra_nhe_init(&lookup, afi, nhg->nexthop);
lookup.nhg.nexthop = nhg->nexthop;
* This is a replace, just release NHE from ID for now, The
* depends/dependents may still be used in the replacement.
*/
+ replace = true;
hash_release(zrouter.nhgs_id, old);
}
new = zebra_nhg_rib_find_nhe(&lookup, afi);
+ zebra_nhg_increment_ref(new);
+
+ zebra_nhg_set_valid_if_active(new);
+
+ zebra_nhg_install_kernel(new);
+
if (old) {
- /* Now release depends/dependents in old one */
- zebra_nhg_release_all_deps(old);
- }
+ rib_handle_nhg_replace(old, new);
- if (!new)
- return NULL;
+ /* if this != 1 at this point, we have a bug */
+ assert(old->refcnt == 1);
- /* TODO: Assuming valid/onlink for now */
- SET_FLAG(new->flags, NEXTHOP_GROUP_VALID);
+ /* 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);
+ }
+
+ /* Free all the things */
+ zebra_nhg_release_all_deps(old);
- if (!zebra_nhg_depends_is_empty(new)) {
- frr_each (nhg_connected_tree, &new->nhg_depends, rb_node_dep)
- SET_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID);
+ /* Dont call the dec API, we dont want to uninstall the ID */
+ old->refcnt = 0;
+ zebra_nhg_free(old);
+ old = NULL;
}
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: %s nhe %p (%u), vrf %d, type %s", __func__,
- (old ? "replaced" : "added"), new, new->id,
+ (replace ? "replaced" : "added"), new, new->id,
new->vrf_id, zebra_route_string(new->type));
return new;
}
-/* Delete NHE from upper level proto */
+/* Delete NHE from upper level proto, caller must decrement ref */
struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id)
{
struct nhg_hash_entry *nhe;
return NULL;
}
- if (nhe->refcnt) {
+ if (nhe->refcnt > 1) {
/* TODO: should be warn? */
if (IS_ZEBRA_DEBUG_NHG)
- zlog_debug("%s: id %u, still being used refcnt %u",
- __func__, nhe->id, nhe->refcnt);
+ zlog_debug(
+ "%s: id %u, still being used by routes refcnt %u",
+ __func__, nhe->id, nhe->refcnt);
return NULL;
}
goto done;
}
- if ((re->nhe_id != 0) && (re->nhe_id != new_nhghe->id)) {
+ if ((re->nhe_id != 0) && re->nhe && (re->nhe != new_nhghe)) {
old = re->nhe;
route_entry_attach_ref(re, new_nhghe);
return ret;
}
+void rib_handle_nhg_replace(struct nhg_hash_entry *old,
+ struct nhg_hash_entry *new)
+{
+ struct zebra_router_table *zrt;
+ struct route_node *rn;
+ struct route_entry *re, *next;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: replacing routes nhe (%u) OLD %p NEW %p",
+ __func__, new->id, new, old);
+
+ /* We have to do them ALL */
+ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
+ for (rn = route_top(zrt->table); rn;
+ rn = srcdest_route_next(rn)) {
+ RNODE_FOREACH_RE_SAFE (rn, re, next) {
+ if (re->nhe && re->nhe == old)
+ route_entry_update_nhe(re, new);
+ }
+ }
+ }
+}
+
struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
union g_addr *addr, struct route_node **rn_out)
{