Commit aa75408898 for frr
commit aa7540889880ec333e60badd209c2e1127d2f9e7
Author: Nick Bouliane <nbouliane@coreweave.com>
Date: Tue Sep 29 12:42:21 2026 -0400
bgpd: skip SR-TE nexthop walk when no colored nexthops exist
bgp_nexthop_update() walks the entire nexthop cache table on every
colorless nexthop update, looking for colored entries that share the
same endpoint (a workaround for zebra's RNH subsystem not being
color-aware). The walk runs even when the table contains no colored
entries at all, in which case it cannot ever find anything.
This makes convergence O(N^2) in the number of tracked nexthops:
during a session reset with N remote EVPN VTEPs, zebra sends ~N
nexthop updates and each one triggers a full walk of the N-entry
table. Measured on an EVPN fabric across 10k/15k/25k/30k remote VTEPs,
bgpd's route-learning CPU grows quadratically, reaching ~80
CPU-seconds per restart at 30k VTEPs, with perf showing the cycles
concentrated under zclient_nexthop_update()/typed_rb_next(). With this
change those symbols disappear from the profile and learning cost
returns to linear in the number of routes. Deployments that do not use
SR-TE at all - most EVPN fabrics - currently pay the full cost of the
workaround.
The nexthop cache tree is keyed by (srte_color, ifindex, prefix), so
colored entries always sort at the end of the tree. Check the last
entry before walking: if it is colorless (or the tree is empty), no
colored entry exists and the walk is skipped. The walk itself is
unchanged when colored entries are present.
Signed-off-by: Nick Bouliane <nbouliane@coreweave.com>
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index a7c24d77c2..7a988aa968 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -1056,10 +1056,22 @@ void bgp_nexthop_update(struct vrf *vrf, struct prefix *match,
* make zebra's RNH subsystem aware of SR-TE colors (like bgpd is),
* which should provide a better infrastructure to solve this issue in
* a more efficient and elegant way.
+ *
+ * The walk below is only useful when colored entries exist. The
+ * cache tree is keyed by (srte_color, ifindex, prefix), so colored
+ * entries always sort at the end of the tree: if the last entry is
+ * colorless, there is no colored entry at all and the walk can be
+ * skipped. Without this check, every colorless NH update walks the
+ * whole table for nothing, which makes convergence O(N^2) in the
+ * number of tracked nexthops for deployments not using SR-TE.
*/
if (nhr->srte_color == 0) {
struct bgp_nexthop_cache *bnc_iter;
+ bnc_iter = bgp_nexthop_cache_last(&bgp->nexthop_cache_table[afi]);
+ if (!bnc_iter || bnc_iter->srte_color == 0)
+ return;
+
frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
bnc_iter) {
if (!prefix_same(match, &bnc_iter->prefix) ||