From 9510a86bc1a1883ac7f7f9978126c33bb346d9f2 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 20 Mar 2024 13:14:07 +0100 Subject: [PATCH] zebra: add prefix evaluation at NHG updates When a BGP configuration receives and installs a prefix with multiple nexthops, if a link down event happens, the nexthop resolution is not propagated. The below example illustrates the 10.0.5.1 prefix, where the resolution is given by BGP. > # show ip nht > [..] > 10.0.5.1 > resolved via bgp > via 10.0.7.2, r1-r2-eth2 (vrf default), weight 1 > via 10.0.8.2, r1-r2-eth3 (vrf default), weight 1 > via 10.0.9.2, r1-r2-eth4 (vrf default), weight 1 > via 10.0.10.2, r1-r2-eth5 (vrf default), weight 1 > Client list: pim(fd 45) After the r1-r2-th2 and r1-r2-eth4 interfaces are down, the nht entry for 10.0.5.1 is kept unchanged. The problem is related to nexthop groups. When using an NHG_ADD to refresh the BGP route, then NHT entry is not refreshed, and PIM is not informed about the change. Signed-off-by: Philippe Guibert --- zebra/zebra_rib.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index dee30743bbb3..c06182176e6e 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1961,7 +1961,89 @@ struct route_node *rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx) } +static void zebra_rib_evaluate_prefix_nhg(struct hash_bucket *b, void *data) +{ + struct zebra_router_table *zrt; + struct nhg_prefix_proto_nhgs *nhg_p = b->data; + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(nhg_p->vrf_id); + struct route_node *rn; + struct route_entry *re, *next; + rib_dest_t *dest; + + if (!zvrf) + return; + + zrt = zebra_router_find_zrt(zvrf, nhg_p->table_id, nhg_p->afi, + nhg_p->safi); + if (!zrt) + return; + + if (nhg_p->src_prefix.family) + rn = srcdest_rnode_get(zrt->table, &nhg_p->prefix, + (const struct prefix_ipv6 *)&nhg_p + ->src_prefix); + else + rn = srcdest_rnode_get(zrt->table, &nhg_p->prefix, NULL); + if (!rn) + return; + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: => NHG updated, evaluating prefix %pRN", + __func__, rn); + + RNODE_FOREACH_RE_SAFE (rn, re, next) { + /* re did not change, an, still selected */ + dest = rib_dest_from_rnode(rn); + /* Redistribute if this is the selected re */ + if (dest && re == dest->selected_fib) + redistribute_update(rn, re, re); + zebra_rib_evaluate_rn_nexthops(rn, + zebra_router_get_next_sequence(), + false); + zebra_rib_evaluate_mpls(rn); + } +} +/* + * update results processing after async dataplane update. + */ +static void rib_nhg_process_result(struct zebra_dplane_ctx *ctx) +{ + enum dplane_op_e op; + enum zebra_dplane_result status; + uint32_t id; + struct nhg_hash_entry *nhe; + + op = dplane_ctx_get_op(ctx); + status = dplane_ctx_get_status(ctx); + + id = dplane_ctx_get_nhe_id(ctx); + + if (op == DPLANE_OP_NH_DELETE) { + /* We already free'd the data, nothing to do */ + return; + } + + nhe = zebra_nhg_lookup_id(id); + if (!nhe) { + /* nothing to process, as there is no NHG add or update */ + return; + } + + if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) { + /* no sucess, means that the attempt to change did not work */ + return; + } + + if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: Evaluating routes using updated nhe (%u)", + __func__, id); + + /* We have to do them ALL */ + if (nhe->prefix_proto_nhgs) + hash_iterate(nhe->prefix_proto_nhgs, + zebra_rib_evaluate_prefix_nhg, NULL); +} /* * Route-update results processing after async dataplane update. */ @@ -4929,6 +5011,8 @@ static void rib_process_dplane_results(struct event *thread) case DPLANE_OP_NH_UPDATE: case DPLANE_OP_NH_DELETE: zebra_nhg_dplane_result(ctx); + if (dplane_ctx_get_notif_provider(ctx) == 0) + rib_nhg_process_result(ctx); break; case DPLANE_OP_LSP_INSTALL: