From: Theo Buehler Subject: Re: bgpd: rewrite adj-out-rib code To: tech@openbsd.org Date: Tue, 23 Dec 2025 13:28:57 +0100 On Wed, Dec 17, 2025 at 03:58:46PM +0100, Claudio Jeker wrote: > Fully rewrite the adj-rib-out code to not be per peer based but instead > global with a peer bitmap to know which peer holds which prefix version. > > So a pt_entry now includes an array of struct adjout_prefix elements > each entry is for a different path (different set of attributes) and > includes a bitmap that tracks which peers include the prefix. > > This alters most of the adjout_prefix functions in some way or another. > > An optimisation on top of this is that the path_id_tx is forced to 0 for > peers that have no add-path send enabled. This way the lookup for this > common case is less deep. > > The peer_reaper is now replaced with a simple adjout_prefix_dump call. > > This is enough for a first step. Mostly reads fine, but see below. ok tb > In general this reduces memory consumption by more than 50% especially if > the outbound filters are producing the same path for many peers. My IXP > test setup dropped from over 20G to below 5GB memory usage. That's awesome. > struct adjout_prefix * > adjout_prefix_get(struct rde_peer *peer, uint32_t path_id_tx, > struct pt_entry *pte) > { > - struct adjout_prefix xp; > + struct adjout_prefix *p; > + uint32_t i; > > - memset(&xp, 0, sizeof(xp)); > - xp.pt = pte; > - xp.path_id_tx = path_id_tx; > + for (i = 0; i < pte->adjoutlen; i++) { > + p = &pte->adjout[i]; > + if (p->path_id_tx != path_id_tx) > + continue; I think you meant to check if (p->path_id_tx < path_id_tx) continue; > + if (bitmap_test(&p->peermap, peer->adjout_bid)) > + return p; > + if (p->path_id_tx > path_id_tx) > + break; Otherwise this break is unreachable. > + } > > - return RB_FIND(prefix_index, &peer->adj_rib_out, &xp); > + return NULL; > +} > + > +/* > + * Search for specified prefix in the pte adjout array that is for the > + * specified path_id_tx and attrs. Returns NULL if not found. > + */ > +static struct adjout_prefix * > +adjout_prefix_with_attrs(struct pt_entry *pte, uint32_t path_id_tx, > + struct adjout_attr *attrs) > +{ > + struct adjout_prefix *p; > + uint32_t i; > + > + for (i = 0; i < pte->adjoutlen; i++) { > + p = &pte->adjout[i]; > + if (p->path_id_tx != path_id_tx) same here > + continue; > + if (p->attrs == attrs) > + return p; > + if (p->path_id_tx > path_id_tx) > + break; > + } > + > + return NULL; > }