Index | Thread | Search

From:
Theo Buehler <tb@theobuehler.org>
Subject:
Re: bgpd: rewrite adj-out-rib code
To:
tech@openbsd.org
Date:
Tue, 23 Dec 2025 13:28:57 +0100

Download raw body.

Thread
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;
>  }