Download raw body.
bgpd: bring back up_generate_addpath_all using the rib entry queue
add-path send all can take a fair amount of shortcuts compared to the
other add-path send modes. The rib entry queue (struct pq_entry) holds
all the information to update the adj-rib-out.
For general updates just walk the pq list and insert / withdraw all
paths. A path can only be once on the list so the code just needs to
walk it and call up_process_prefix for updates. If up_process_prefix()
returns UP_FILTERED or UP_EXCLUDED then try to withdraw the prefix. This
uses the same codepath as for any withdraw in the queue.
A version of this is running on the NLNOG ring looking glass with good
success.
--
:wq Claudio
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
diff -u -p -r1.358 rde.h
--- rde.h 15 Jul 2026 11:59:27 -0000 1.358
+++ rde.h 15 Jul 2026 20:43:45 -0000
@@ -321,6 +321,12 @@ struct prefix {
#define NEXTHOP_MASK 0x0f
#define NEXTHOP_VALID 0x80
+struct pq_entry {
+ TAILQ_ENTRY(pq_entry) entry;
+ struct prefix *p; /* NULL for withdraws */
+ uint32_t path_id_tx;
+};
+
struct adjout_attr {
uint64_t hash;
struct rde_aspath *aspath;
Index: rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
diff -u -p -r1.302 rde_rib.c
--- rde_rib.c 2 Jul 2026 07:40:12 -0000 1.302
+++ rde_rib.c 15 Jul 2026 20:43:45 -0000
@@ -41,12 +41,6 @@ uint16_t rib_size;
struct rib **ribs;
struct rib flowrib = { .id = 1, .tree = RB_INITIALIZER(&flowrib.tree) };
-struct pq_entry {
- TAILQ_ENTRY(pq_entry) entry;
- struct prefix *p; /* NULL for withdraws */
- uint32_t path_id_tx;
-};
-
struct rib_entry *rib_add(struct rib *, struct pt_entry *);
static inline int rib_compare(const struct rib_entry *,
const struct rib_entry *);
Index: rde_update.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
diff -u -p -r1.201 rde_update.c
--- rde_update.c 15 Jul 2026 11:59:27 -0000 1.201
+++ rde_update.c 15 Jul 2026 20:43:45 -0000
@@ -367,51 +367,44 @@ void
up_generate_addpath_all(struct rde_peer *peer, struct rib_entry *re,
enum eval_mode mode)
{
-#if 0
- /* XXX needs to be rewritten */
struct adjout_prefix *p;
+ struct pt_entry *pte;
+ struct pq_entry *pq;
/*
- * If old and new are NULL then re-insert all prefixes from re,
- * use up_generate_addpath() for that.
+ * If this is a sync or reeval of all prefixes from re,
+ * then use up_generate_addpath().
*/
- if (old_pathid_tx == 0 && new == NULL) {
+ if (mode == EVAL_SYNC || mode == EVAL_REEVAL) {
up_generate_addpath(peer, re, mode);
return;
}
- if (new != NULL && !prefix_eligible(new)) {
- /* only allow valid prefixes */
- new = NULL;
- }
-
- if (new != NULL) {
- /* add new path */
- switch (up_process_prefix(peer, new, (void *)-1, mode)) {
- case UP_OK:
- /* don't remove old if an existing prefix was updated */
- if (old_pathid_tx == new->path_id_tx)
- old_pathid_tx = 0;
- break;
- case UP_FILTERED:
- case UP_EXCLUDED:
- break;
- case UP_ERR_LIMIT:
- /* just give up */
- return;
+ pte = re->prefix;
+ TAILQ_FOREACH(pq, &re->pq_head, entry) {
+ if (pq->p != NULL && prefix_eligible(pq->p)) {
+ /* add new path */
+ switch (up_process_prefix(peer, pq->p, (void *)-1,
+ mode)) {
+ case UP_OK:
+ /* update processed, go to next */
+ continue;
+ case UP_FILTERED:
+ case UP_EXCLUDED:
+ /* update needs to be withdrawn */
+ break;
+ case UP_ERR_LIMIT:
+ /* just give up */
+ return;
+ }
}
- }
- if (old_pathid_tx != 0) {
- /* withdraw old path */
- p = adjout_prefix_get(peer, old_pathid_tx, re->prefix);
+ /* prefix was withdrawn or got filtered, withdraw from adjout */
+ p = adjout_prefix_get(peer, pq->path_id_tx, pte);
if (p != NULL)
adjout_prefix_withdraw(peer, re->prefix, p,
mode == EVAL_SYNC);
}
-#else
- up_generate_addpath(peer, re, mode);
-#endif
}
/* send a default route to the specified peer, always force the update out */
bgpd: bring back up_generate_addpath_all using the rib entry queue