This diff adds the required plumbing to support local path_ids in the
output path. Mainly it extends prefix_adjout_update() to do the right
thing. Since in normal mode of operation path_id_tx does not matter and
only on prefix is in the Adj-RIB-Out the code uses prefix_adjout_lookup()
to locate the prefix first and removes the lookup in
prefix_adjout_update().
prefix_adjout_update() takes care if the passed in prefix switches
path_id_tx and does the dance of unlinking the object from all RB trees
before switching the path_id_tx.
In up_generate_default() just use 0 as the path_id_tx. There will only
be the default route in this RIB so there is no conflict possible.
--
:wq Claudio
Index: rde.h
===
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.257
diff -u -p -r1.257 rde.h
--- rde.h 8 Jul 2022 08:11:25 - 1.257
+++ rde.h 8 Jul 2022 08:56:09 -
@@ -616,8 +616,9 @@ int prefix_update(struct rib *, struct
int prefix_withdraw(struct rib *, struct rde_peer *, uint32_t,
struct bgpd_addr *, int);
voidprefix_add_eor(struct rde_peer *, uint8_t);
-voidprefix_adjout_update(struct rde_peer *, struct filterstate *,
- struct bgpd_addr *, int, uint8_t);
+voidprefix_adjout_update(struct prefix *, struct rde_peer *,
+ struct filterstate *, struct bgpd_addr *, int,
+ uint32_t, uint8_t);
voidprefix_adjout_withdraw(struct prefix *);
voidprefix_adjout_destroy(struct prefix *);
voidprefix_adjout_dump(struct rde_peer *, void *,
Index: rde_rib.c
===
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.239
diff -u -p -r1.239 rde_rib.c
--- rde_rib.c 8 Jul 2022 08:11:25 - 1.239
+++ rde_rib.c 8 Jul 2022 09:01:20 -
@@ -917,14 +917,14 @@ prefix_get(struct rib *rib, struct rde_p
* Returns NULL if not found.
*/
struct prefix *
-prefix_adjout_get(struct rde_peer *peer, uint32_t path_id,
+prefix_adjout_get(struct rde_peer *peer, uint32_t path_id_tx,
struct bgpd_addr *prefix, int prefixlen)
{
struct prefix xp;
memset(, 0, sizeof(xp));
xp.pt = pt_fill(prefix, prefixlen);
- xp.path_id_tx = path_id;
+ xp.path_id_tx = path_id_tx;
return RB_FIND(prefix_index, >adj_rib_out, );
}
@@ -1168,14 +1168,14 @@ prefix_add_eor(struct rde_peer *peer, ui
* Put a prefix from the Adj-RIB-Out onto the update queue.
*/
void
-prefix_adjout_update(struct rde_peer *peer, struct filterstate *state,
-struct bgpd_addr *prefix, int prefixlen, uint8_t vstate)
+prefix_adjout_update(struct prefix *p, struct rde_peer *peer,
+struct filterstate *state, struct bgpd_addr *prefix, int prefixlen,
+uint32_t path_id_tx, uint8_t vstate)
{
struct rde_aspath *asp;
struct rde_community *comm;
- struct prefix *p;
- if ((p = prefix_adjout_get(peer, 0, prefix, prefixlen)) == NULL) {
+ if (p == NULL) {
p = prefix_alloc();
/* initally mark DEAD so code below is skipped */
p->flags |= PREFIX_FLAG_ADJOUT | PREFIX_FLAG_DEAD;
@@ -1185,7 +1185,7 @@ prefix_adjout_update(struct rde_peer *pe
p->pt = pt_add(prefix, prefixlen);
pt_ref(p->pt);
p->peer = peer;
- p->path_id_tx = 0 /* XXX force this for now */;
+ p->path_id_tx = path_id_tx;
if (RB_INSERT(prefix_index, >adj_rib_out, p) != NULL)
fatalx("%s: RB index invariant violated", __func__);
@@ -1194,7 +1194,14 @@ prefix_adjout_update(struct rde_peer *pe
if ((p->flags & PREFIX_FLAG_ADJOUT) == 0)
fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__);
if ((p->flags & (PREFIX_FLAG_WITHDRAW | PREFIX_FLAG_DEAD)) == 0) {
- if (prefix_nhflags(p) == state->nhflags &&
+ /*
+* XXX for now treat a different path_id_tx like different
+* attributes and force out an update. It is unclear how
+* common it is to have equivalent updates from alternative
+* paths.
+*/
+ if (p->path_id_tx == path_id_tx &&
+ prefix_nhflags(p) == state->nhflags &&
prefix_nexthop(p) == state->nexthop &&
communities_equal(>communities,
prefix_communities(p)) &&
@@ -1224,6 +1231,15 @@ prefix_adjout_update(struct rde_peer *pe
/* nothing needs to be done for PREFIX_FLAG_DEAD and STALE */
p->flags &= ~PREFIX_FLAG_MASK;
+ /* update path_id_tx now that the prefix is unlinked */
+ if (p->path_id_tx != path_id_tx) {
+ /* path_id_tx is part of the index so remove and