-/* $OpenBSD: rde.c,v 1.551 2022/07/07 13:55:52 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.552 2022/07/08 08:11:25 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
rde_filterstate_clean(&state);
}
+/*
+ * Check if path_id is already in use.
+ */
+static int
+pathid_conflict(struct rib_entry *re, uint32_t pathid)
+{
+ struct prefix *p;
+
+ if (re == NULL)
+ return 0;
+
+ TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib)
+ if (p->path_id_tx == pathid)
+ return 1;
+ return 0;
+}
+
+static uint32_t
+pathid_assign(struct rde_peer *peer, uint32_t path_id,
+ struct bgpd_addr *prefix, uint8_t prefixlen)
+{
+ struct rib_entry *re;
+ struct prefix *p = NULL;
+ uint32_t path_id_tx;
+
+ /* Assign a send side path_id to all paths */
+ re = rib_get(rib_byid(RIB_ADJ_IN), prefix, prefixlen);
+ if (re != NULL)
+ p = prefix_bypeer(re, peer, path_id);
+ if (p != NULL)
+ path_id_tx = p->path_id_tx;
+ else {
+ do {
+ /* assign new local path_id */
+ path_id_tx = arc4random();
+ } while (pathid_conflict(re, path_id_tx));
+ }
+ return path_id_tx;
+}
+
int
rde_update_update(struct rde_peer *peer, uint32_t path_id,
struct filterstate *in, struct bgpd_addr *prefix, uint8_t prefixlen)
enum filter_actions action;
uint8_t vstate;
uint16_t i;
+ uint32_t path_id_tx;
const char *wmsg = "filtered, withdraw";
peer->prefix_rcvd_update++;
vstate = rde_roa_validity(&rde_roa, prefix, prefixlen,
aspath_origin(in->aspath.aspath));
+ path_id_tx = pathid_assign(peer, path_id, prefix, prefixlen);
+
/* add original path to the Adj-RIB-In */
- if (prefix_update(rib_byid(RIB_ADJ_IN), peer, path_id, in,
- prefix, prefixlen, vstate) == 1)
+ if (prefix_update(rib_byid(RIB_ADJ_IN), peer, path_id, path_id_tx,
+ in, prefix, prefixlen, vstate) == 1)
peer->prefix_cnt++;
/* max prefix checker */
rde_update_log("update", i, peer,
&state.nexthop->exit_nexthop, prefix,
prefixlen);
- prefix_update(rib, peer, path_id, &state, prefix,
- prefixlen, vstate);
+ prefix_update(rib, peer, path_id, path_id_tx, &state,
+ prefix, prefixlen, vstate);
} else if (prefix_withdraw(rib, peer, path_id, prefix,
prefixlen)) {
rde_update_log(wmsg, i, peer,
if (action == ACTION_ALLOW) {
/* update Local-RIB */
- prefix_update(rib, peer, p->path_id, &state,
+ prefix_update(rib, peer, p->path_id,
+ p->path_id_tx, &state,
&prefix, pt->prefixlen,
p->validation_state);
} else if (action == ACTION_DENY) {
if (action == ACTION_ALLOW) {
/* update Local-RIB */
- prefix_update(rib, peer, p->path_id, &state,
+ prefix_update(rib, peer, p->path_id,
+ p->path_id_tx, &state,
&prefix, pt->prefixlen,
p->validation_state);
} else if (action == ACTION_DENY) {
struct in6_addr prefix6;
uint8_t vstate;
uint16_t i;
+ uint32_t path_id_tx;
if (nc->rd != 0) {
SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) {
vstate = rde_roa_validity(&rde_roa, &nc->prefix,
nc->prefixlen, aspath_origin(state->aspath.aspath));
- if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, state, &nc->prefix,
- nc->prefixlen, vstate) == 1)
+ path_id_tx = pathid_assign(peerself, 0, &nc->prefix, nc->prefixlen);
+ if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, path_id_tx,
+ state, &nc->prefix, nc->prefixlen, vstate) == 1)
peerself->prefix_cnt++;
for (i = RIB_LOC_START; i < rib_size; i++) {
struct rib *rib = rib_byid(i);
rde_update_log("announce", i, peerself,
state->nexthop ? &state->nexthop->exit_nexthop : NULL,
&nc->prefix, nc->prefixlen);
- prefix_update(rib, peerself, 0, state, &nc->prefix,
+ prefix_update(rib, peerself, 0, path_id_tx, state, &nc->prefix,
nc->prefixlen, vstate);
}
filterset_free(&nc->attrset);
-/* $OpenBSD: rde_rib.c,v 1.238 2022/05/23 13:40:12 deraadt Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.239 2022/07/08 08:11:25 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
/* prefix specific functions */
static int prefix_add(struct bgpd_addr *, int, struct rib *,
- struct rde_peer *, uint32_t, struct rde_aspath *,
+ struct rde_peer *, uint32_t, uint32_t, struct rde_aspath *,
struct rde_community *, struct nexthop *,
uint8_t, uint8_t);
static int prefix_move(struct prefix *, struct rde_peer *,
struct nexthop *, uint8_t, uint8_t);
static void prefix_link(struct prefix *, struct rib_entry *,
- struct pt_entry *, struct rde_peer *, uint32_t,
+ struct pt_entry *, struct rde_peer *, uint32_t, uint32_t,
struct rde_aspath *, struct rde_community *,
struct nexthop *, uint8_t, uint8_t);
static void prefix_unlink(struct prefix *);
*/
int
prefix_update(struct rib *rib, struct rde_peer *peer, uint32_t path_id,
- struct filterstate *state, struct bgpd_addr *prefix, int prefixlen,
- uint8_t vstate)
+ uint32_t path_id_tx, struct filterstate *state, struct bgpd_addr *prefix,
+ int prefixlen, uint8_t vstate)
{
struct rde_aspath *asp, *nasp = &state->aspath;
struct rde_community *comm, *ncomm = &state->communities;
* First try to find a prefix in the specified RIB.
*/
if ((p = prefix_get(rib, peer, path_id, prefix, prefixlen)) != NULL) {
+ if (path_id_tx != p->path_id_tx)
+ fatalx("path_id mismatch");
if (prefix_nexthop(p) == state->nexthop &&
prefix_nhflags(p) == state->nhflags &&
communities_equal(ncomm, prefix_communities(p)) &&
return (prefix_move(p, peer, asp, comm, state->nexthop,
state->nhflags, vstate));
else
- return (prefix_add(prefix, prefixlen, rib, peer, path_id, asp,
- comm, state->nexthop, state->nhflags, vstate));
+ return (prefix_add(prefix, prefixlen, rib, peer, path_id,
+ path_id_tx, asp, comm, state->nexthop, state->nhflags,
+ vstate));
}
/*
*/
static int
prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
- struct rde_peer *peer, uint32_t path_id, struct rde_aspath *asp,
- struct rde_community *comm, struct nexthop *nexthop, uint8_t nhflags,
- uint8_t vstate)
+ struct rde_peer *peer, uint32_t path_id, uint32_t path_id_tx,
+ struct rde_aspath *asp, struct rde_community *comm,
+ struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
{
struct prefix *p;
struct rib_entry *re;
re = rib_add(rib, prefix, prefixlen);
p = prefix_alloc();
- prefix_link(p, re, re->prefix, peer, path_id, asp, comm, nexthop,
- nhflags, vstate);
+ prefix_link(p, re, re->prefix, peer, path_id, path_id_tx, asp, comm,
+ nexthop, nhflags, vstate);
/* add possible pftable reference form aspath */
if (asp && asp->pftableid)
/* add new prefix node */
np = prefix_alloc();
- prefix_link(np, prefix_re(p), p->pt, peer, p->path_id, asp, comm,
- nexthop, nhflags, vstate);
+ prefix_link(np, prefix_re(p), p->pt, peer, p->path_id, p->path_id_tx,
+ asp, comm, nexthop, nhflags, vstate);
/* add possible pftable reference from new aspath */
if (asp && asp->pftableid)
comm = communities_link(&state->communities);
}
- prefix_link(p, NULL, p->pt, peer, 0, asp, comm, state->nexthop,
- state->nhflags, vstate);
+ prefix_link(p, NULL, p->pt, peer, 0, /* XXX */ 0, asp, comm,
+ state->nexthop, state->nhflags, vstate);
peer->prefix_out_cnt++;
if (p->flags & PREFIX_FLAG_MASK)
*/
static void
prefix_link(struct prefix *p, struct rib_entry *re, struct pt_entry *pt,
- struct rde_peer *peer, uint32_t path_id, struct rde_aspath *asp,
- struct rde_community *comm, struct nexthop *nexthop, uint8_t nhflags,
- uint8_t vstate)
+ struct rde_peer *peer, uint32_t path_id, uint32_t path_id_tx,
+ struct rde_aspath *asp, struct rde_community *comm,
+ struct nexthop *nexthop, uint8_t nhflags, uint8_t vstate)
{
if (re)
p->entry.list.re = re;
p->peer = peer;
p->pt = pt_ref(pt);
p->path_id = path_id;
+ p->path_id_tx = path_id_tx;
p->validation_state = vstate;
p->nhflags = nhflags;
p->nexthop = nexthop_ref(nexthop);