From: Claudio Jeker Subject: bgpd: adjust Adj-RIB-Out operations to support down peers To: tech@openbsd.org Date: Tue, 10 Dec 2024 17:03:23 +0100 Both prefix_adjout_update() and prefix_adjout_withdraw() insert a RB tree node into the update / withdraw tree structures. Those RB_INSERTs result in the update to be sent out. In preparation for caching the Adj-RIB-Out over a session restart add a check in the two functions to only do this RB tree insert if the peer is up. For prefix_adjout_update() nothing else needs to be done (the prefix is still linked in the actual Adj-RIB-Out (called adj_rib_out) but on a withdraw the prefix is already unlinked for the adj_rib_out and needs to be destroyed. To make this work correctly mark the prefix as dead since it is already unlinked and therefor dead. Right now this is a no-op since prefix_adjout_update() and prefix_adjout_withdraw() are only called for peers that are up but this diff is complex enough to send it out alone. -- :wq Claudio Index: rde_rib.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v diff -u -p -r1.263 rde_rib.c --- rde_rib.c 14 Aug 2024 19:09:51 -0000 1.263 +++ rde_rib.c 10 Dec 2024 15:42:04 -0000 @@ -1321,10 +1321,12 @@ prefix_adjout_update(struct prefix *p, s if (p->flags & PREFIX_FLAG_MASK) fatalx("%s: bad flags %x", __func__, p->flags); - p->flags |= PREFIX_FLAG_UPDATE; - if (RB_INSERT(prefix_tree, &peer->updates[pte->aid], p) != NULL) - fatalx("%s: RB tree invariant violated", __func__); - peer->stats.pending_update++; + if (peer_is_up(peer)) { + p->flags |= PREFIX_FLAG_UPDATE; + if (RB_INSERT(prefix_tree, &peer->updates[pte->aid], p) != NULL) + fatalx("%s: RB tree invariant violated", __func__); + peer->stats.pending_update++; + } } /* @@ -1360,10 +1362,17 @@ prefix_adjout_withdraw(struct prefix *p) p->flags &= ~PREFIX_FLAG_MASK; p->lastchange = getmonotime(); - p->flags |= PREFIX_FLAG_WITHDRAW; - if (RB_INSERT(prefix_tree, &peer->withdraws[p->pt->aid], p) != NULL) - fatalx("%s: RB tree invariant violated", __func__); - peer->stats.pending_withdraw++; + if (peer_is_up(peer)) { + p->flags |= PREFIX_FLAG_WITHDRAW; + if (RB_INSERT(prefix_tree, &peer->withdraws[p->pt->aid], + p) != NULL) + fatalx("%s: RB tree invariant violated", __func__); + peer->stats.pending_withdraw++; + } else { + /* mark prefix dead to skip unlink on destroy */ + p->flags |= PREFIX_FLAG_DEAD; + prefix_adjout_destroy(p); + } } void