From: Claudio Jeker Subject: Re: bgpd: introduce pending attr and prefix queues To: Theo Buehler Cc: tech@openbsd.org Date: Wed, 10 Dec 2025 11:44:19 +0100 On Wed, Dec 10, 2025 at 11:08:23AM +0100, Theo Buehler wrote: > On Thu, Dec 04, 2025 at 05:14:15PM +0100, Claudio Jeker wrote: > > Implement a per-peer pending prefix queue and lookup table and > > a pending attribute queue and lookup table. > > > > Withdraws just end up in the peer pending prefix queue while for updates > > the prefix is queued on a pending attribute entry which itself is queued > > on the peer. This allows to aggregate multiple prefixes into a single > > UPDATE message. When prefixes are added check the lookup table if there > > is already an object. In such a case the prefix is first dequeued and then > > readded. pend_prefix_add() is therefor a bit fiddly. > > > > If the attr pointer in struct pend_prefix is NULL then it is a withdraw. > > The pend_attr needs to hold the aid so prefixes end up on the right queue. > > If the attrs pointer is NULL the pend_attr is actually the End-of-RIB > > marker. > > > > This replaces the red-black tree contraption used right now. Which is a > > big preformance bottleneck. > > It's a tricky diff with all the decoupling deep in the guts of everything, > but overall it looks like a clear win. Not only due to replacing expensive > RB operations but also because largely independent logic becomes more > isolated and therfore easier to follow. pend_prefix_add() is a bit of an > exception there and indeed fiddly. Also, fewer magic flags is always good. > > There are a ton of possible side effects that are hard to evaluate in full > detail but I failed to spot issues. I agree, this is a big change. I hope I thought of all the side effects in the old code. My goal was to reduce side effects as much as possible in this version. > I've spent quite a bit of time on the various parts of this diff and what > the changes do and I think I've crossed the point of diminishing returns. > Let's get it in and see how it works out. > > ok tb > > A few very minor things inline. See below. > > static void > > @@ -3115,13 +3116,13 @@ rde_dump_adjout_upcall(struct adjout_pre > > { > > struct rde_dump_ctx *ctx = ptr; > > struct rde_peer *peer; > > + struct adjout_attr *attrs; > > > > if ((peer = peer_get(ctx->peerid)) == NULL) > > return; > > - if (p->flags & PREFIX_ADJOUT_FLAG_WITHDRAW) > > - return; > > > > - rde_dump_adjout_filter(peer, p, &ctx->req); > > + attrs = p->attrs; > > + rde_dump_adjout_filter(peer, p, attrs, &ctx->req); > > I'm not sure what the attrs variable buys us here, but maybe that's > preparing an upcoming change. You do the same in peer_blast_upcall() > and it looks a bit odd to me. Yes, this interface will change a few more times that's why it is strange like this. I hope by the end I cleaned up all of that again :) > > Index: bgpd/rde.h > > =================================================================== > > RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v > > diff -u -p -r1.327 rde.h > > --- bgpd/rde.h 2 Dec 2025 13:03:35 -0000 1.327 > > +++ bgpd/rde.h 4 Dec 2025 15:58:51 -0000 > > @@ -27,6 +27,7 @@ > > > > #include "bgpd.h" > > #include "log.h" > > +#include "chash.h" > > I'd sort these alphabetically Done. > > @@ -84,8 +89,10 @@ struct rde_peer { > > struct capabilities capa; > > struct addpath_eval eval; > > struct prefix_index adj_rib_out; > > - struct prefix_tree updates[AID_MAX]; > > - struct prefix_tree withdraws[AID_MAX]; > > + struct pend_prefix_hash pend_prefixes; > > + struct pend_attr_hash pend_attrs; > > + struct pend_attr_queue updates[AID_MAX]; > > + struct pend_prefix_queue withdraws[AID_MAX]; > > The order is slightly strange but I understand why you did it this way. It feels like the logical order to me (but I started with pend_prefixes and so I'm biased). I reshuffled them now like this: struct pend_attr_queue updates[AID_MAX]; struct pend_prefix_queue withdraws[AID_MAX]; struct pend_attr_hash pend_attrs; struct pend_prefix_hash pend_prefixes; > > @@ -364,38 +554,28 @@ adjout_prefix_update(struct adjout_prefi > > fatalx("%s: RB index invariant violated", __func__); > > } > > > > - if ((p->flags & (PREFIX_ADJOUT_FLAG_WITHDRAW | > > - PREFIX_ADJOUT_FLAG_DEAD)) == 0) { > > + if ((p->flags & (PREFIX_ADJOUT_FLAG_DEAD)) == 0) { > > extra parens around PREFIX_ADJOUT_FLAG_DEAD Fixed -- :wq Claudio