RDE. The actual reload logic is missing to keep the diff small.
OK tb@
-/* $OpenBSD: bgpd.h,v 1.457 2023/01/11 13:53:17 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.458 2023/01/17 16:09:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
IMSG_RECONF_ASPA_TAS,
IMSG_RECONF_ASPA_TAS_AID,
IMSG_RECONF_ASPA_DONE,
+ IMSG_RECONF_ASPA_PREP,
IMSG_RECONF_RTR_CONFIG,
IMSG_RECONF_DRAIN,
IMSG_RECONF_DONE,
PREFIX_SET,
ORIGIN_SET,
ROA_SET,
+ ASPA_SET,
} type;
};
RB_ENTRY(aspa_set) entry;
};
+struct aspa_prep {
+ size_t datasize;
+ uint32_t entries;
+};
+
struct l3vpn {
SIMPLEQ_ENTRY(l3vpn) entry;
char descr[PEER_DESCR_LEN];
-/* $OpenBSD: rde.c,v 1.586 2023/01/16 10:37:08 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.587 2023/01/17 16:09:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
static void rde_softreconfig_sync_fib(struct rib_entry *, void *);
static void rde_softreconfig_sync_done(void *, uint8_t);
static void rde_roa_reload(void);
+static void rde_aspa_reload(void);
int rde_update_queue_pending(void);
void rde_update_queue_runner(void);
void rde_update6_queue_runner(uint8_t);
static struct imsgbuf *ibuf_main;
static struct bgpd_config *conf, *nconf;
static struct rde_prefixset rde_roa, roa_new;
-static struct rde_aspa *rde_aspa /* , *aspa_new */;
+static struct rde_aspa *rde_aspa, *aspa_new;
volatile sig_atomic_t rde_quit = 0;
struct filter_head *out_rules, *out_rules_tmp;
imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
imsg.hdr.pid, -1, &cset, sizeof(cset));
+ /* then aspa set */
+ memset(&cset, 0, sizeof(cset));
+ cset.type = ASPA_SET;
+ strlcpy(cset.name, "RPKI ASPA", sizeof(cset.name));
+ aspa_table_stats(rde_aspa, &cset);
+ imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
+ imsg.hdr.pid, -1, &cset, sizeof(cset));
+
SIMPLEQ_FOREACH(aset, &conf->as_sets, entry) {
memset(&cset, 0, sizeof(cset));
cset.type = ASNUM_SET;
void
rde_dispatch_imsg_rtr(struct imsgbuf *ibuf)
{
- struct imsg imsg;
- struct roa roa;
- int n;
+ static struct aspa_set *aspa;
+ struct imsg imsg;
+ struct roa roa;
+ struct aspa_prep ap;
+ int n;
while (ibuf) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
log_addr(&p), roa.prefixlen);
}
break;
+ case IMSG_RECONF_ASPA_PREP:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(ap))
+ fatalx("IMSG_RECONF_ASPA_PREP bad len");
+ if (aspa_new)
+ fatalx("unexpected IMSG_RECONF_ASPA_PREP");
+ memcpy(&ap, imsg.data, sizeof(ap));
+ aspa_new = aspa_table_prep(ap.entries, ap.datasize);
+ break;
+ case IMSG_RECONF_ASPA:
+ if (aspa_new == NULL)
+ fatalx("unexpected IMSG_RECONF_ASPA");
+ if (aspa != NULL)
+ fatalx("IMSG_RECONF_ASPA already sent");
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(uint32_t) * 2)
+ fatalx("IMSG_RECONF_ASPA bad len");
+
+ if ((aspa = calloc(1, sizeof(*aspa))) == NULL)
+ fatal("IMSG_RECONF_ASPA");
+ memcpy(&aspa->as, imsg.data, sizeof(aspa->as));
+ memcpy(&aspa->num, (char *)imsg.data + sizeof(aspa->as),
+ sizeof(aspa->num));
+ break;
+ case IMSG_RECONF_ASPA_TAS:
+ if (aspa == NULL)
+ fatalx("unexpected IMSG_RECONF_ASPA_TAS");
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ aspa->num * sizeof(uint32_t))
+ fatalx("IMSG_RECONF_ASPA_TAS bad len");
+ aspa->tas = reallocarray(NULL, aspa->num,
+ sizeof(uint32_t));
+ if (aspa->tas == NULL)
+ fatal("IMSG_RECONF_ASPA_TAS");
+ memcpy(aspa->tas, imsg.data,
+ aspa->num * sizeof(uint32_t));
+ break;
+ case IMSG_RECONF_ASPA_TAS_AID:
+ if (aspa == NULL)
+ fatalx("unexpected IMSG_RECONF_ASPA_TAS_AID");
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ (aspa->num + 15) / 16)
+ fatalx("IMSG_RECONF_ASPA_TAS_AID bad len");
+ aspa->tas_aid = malloc((aspa->num + 15) / 16);
+ if (aspa->tas_aid == NULL)
+ fatal("IMSG_RECONF_ASPA_TAS_AID");
+ memcpy(aspa->tas_aid, imsg.data, (aspa->num + 15) / 16);
+ break;
+ case IMSG_RECONF_ASPA_DONE:
+ if (aspa_new == NULL)
+ fatalx("unexpected IMSG_RECONF_ASPA");
+ aspa_add_set(aspa_new, aspa->as, aspa->tas,
+ aspa->num, (void *)aspa->tas_aid);
+ free_aspa(aspa);
+ aspa = NULL;
+ break;
case IMSG_RECONF_DONE:
/* end of update */
rde_roa_reload();
+ rde_aspa_reload();
break;
}
imsg_free(&imsg);
}
static int roa_update_pending;
+static int aspa_update_pending;
static void
rde_roa_softreload_done(void *arg, uint8_t aid)
fatal("%s: rib_dump_new", __func__);
}
+static void
+rde_aspa_reload(void)
+{
+ struct rde_aspa *aspa_old;
+
+ if (aspa_update_pending) {
+ log_info("ASPA softreload skipped, old still running");
+ return;
+ }
+
+ aspa_old = rde_aspa;
+ rde_aspa = aspa_new;
+ aspa_new = NULL;
+
+ /* check if aspa changed */
+ if (aspa_table_equal(rde_aspa, aspa_old)) {
+ aspa_table_unchanged(rde_aspa, aspa_old);
+ aspa_table_free(aspa_old); /* old aspa no longer needed */
+ return;
+ }
+
+ aspa_table_free(aspa_old); /* old aspa no longer needed */
+ log_debug("ASPA change: reloading Adj-RIB-In");
+ /* XXX MISSING */
+}
+
/*
* generic helper function
*/
-/* $OpenBSD: rde.h,v 1.278 2023/01/12 17:35:51 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.279 2023/01/17 16:09:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
uint8_t flags;
};
+struct rde_aspa;
+
#define AS_SET 1
#define AS_SEQUENCE 2
#define AS_CONFED_SEQUENCE 3
int up_dump_mp_reach(u_char *, int, struct rde_peer *, uint8_t);
/* rde_aspa.c */
+uint8_t aspa_validation(struct rde_aspa *, enum role, struct aspath *,
+ uint8_t);
struct rde_aspa *aspa_table_prep(uint32_t, size_t);
void aspa_add_set(struct rde_aspa *, uint32_t, const uint32_t *,
uint32_t, const uint32_t *);
void aspa_table_free(struct rde_aspa *);
-uint8_t aspa_validation(struct rde_aspa *, enum role, struct aspath *,
- uint8_t);
+void aspa_table_stats(const struct rde_aspa *,
+ struct ctl_show_set *);
+int aspa_table_equal(const struct rde_aspa *,
+ const struct rde_aspa *);
+void aspa_table_unchanged(struct rde_aspa *,
+ const struct rde_aspa *);
#endif /* __RDE_H__ */
-/* $OpenBSD: rde_aspa.c,v 1.1 2023/01/11 13:53:17 claudio Exp $ */
+/* $OpenBSD: rde_aspa.c,v 1.2 2023/01/17 16:09:01 claudio Exp $ */
/*
* Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
size_t maxdata;
size_t curdata;
uint32_t curset;
+ time_t lastchange;
};
struct aspa_state {
aspa_cp_lookup(struct rde_aspa *ra, uint32_t cas, uint32_t pas, uint8_t aid)
{
struct rde_aspa_set *aspa;
- uint32_t i;
+ uint32_t i, mask;
switch (aid) {
case AID_INET:
- aid = 0x1;
+ mask = 0x1;
break;
case AID_INET6:
- aid = 0x2;
+ mask = 0x2;
break;
default:
return UNKNOWN;
if (aspa->pas_aid == NULL)
return PROVIDER;
- if (aspa->pas_aid[i / 16] & (aid << ((i % 16) * 2)))
+ if (aspa->pas_aid[i / 16] & (mask << ((i % 16) * 2)))
return PROVIDER;
return NOT_PROVIDER;
}
/*
* Preallocate all data structures needed for the aspa table.
* There are entries number of rde_aspa_sets with data_size bytes of
- * extra data.
+ * extra data (used to store SPAS and optional AFI bitmasks).
*/
struct rde_aspa *
-aspa_table_prep(uint32_t entries, size_t data_size)
+aspa_table_prep(uint32_t entries, size_t datasize)
{
struct rde_aspa *ra;
uint32_t hsize = 1024;
if ((ra->sets = calloc(entries, sizeof(ra->sets[0]))) == NULL)
fatal("aspa table prep");
- if ((ra->data = malloc(data_size)) == NULL)
+ if ((ra->data = malloc(datasize)) == NULL)
fatal("aspa table prep");
ra->mask = hsize - 1;
ra->maxset = entries;
- ra->maxdata = data_size / sizeof(ra->data[0]);
+ ra->maxdata = datasize / sizeof(ra->data[0]);
+ ra->lastchange = getmonotime();
return ra;
}
free(ra->data);
free(ra);
}
+
+void
+aspa_table_stats(const struct rde_aspa *ra, struct ctl_show_set *cset)
+{
+ if (ra == NULL)
+ return;
+ cset->lastchange = ra->lastchange;
+ cset->as_cnt = ra->maxset;
+}
+
+/*
+ * Return true if the two rde_aspa tables are contain the same data.
+ */
+int
+aspa_table_equal(const struct rde_aspa *ra, const struct rde_aspa *rb)
+{
+ uint32_t i;
+
+ /* allow NULL pointers to be passed */
+ if (ra == NULL && rb == NULL)
+ return 1;
+ if (ra == NULL || rb == NULL)
+ return 0;
+
+ if (ra->maxset != rb->maxset ||
+ ra->maxdata != rb->maxdata)
+ return 0;
+ for (i = 0; i < ra->maxset; i++)
+ if (ra->sets[i].as != rb->sets[i].as)
+ return 0;
+ if (memcmp(ra->data, rb->data, ra->maxdata * sizeof(ra->data[0])) != 0)
+ return 0;
+
+ return 1;
+}
+
+void
+aspa_table_unchanged(struct rde_aspa *ra, const struct rde_aspa *old)
+{
+ if (ra == NULL || old == NULL)
+ return;
+ ra->lastchange = old->lastchange;
+}
-/* $OpenBSD: rtr.c,v 1.9 2022/11/18 10:17:23 claudio Exp $ */
+/* $OpenBSD: rtr.c,v 1.10 2023/01/17 16:09:01 claudio Exp $ */
/*
* Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
uint32_t i, num, *newtas;
uint8_t *newtasaid;
- switch (aid) {
- case AID_INET:
- aid = 0x1;
- break;
- case AID_INET6:
- aid = 0x2;
- break;
- case AID_UNSPEC:
- aid = 0x3;
- break;
- default:
- fatalx("aspa_set bad AID");
- }
+ if (aid != AID_UNSPEC && aid != AID_INET && aid != AID_INET6)
+ fatalx("aspa set with invalid AFI %s", aid2str(aid));
for (i = 0; i < aspa->num; i++) {
if (asnum < aspa->tas[i] || aspa->tas[i] == 0)
break;
if (asnum == aspa->tas[i]) {
- aspa->tas_aid[i] |= aid;
+ if (aspa->tas_aid[i] != aid)
+ aspa->tas_aid[i] = AID_UNSPEC;
return;
}
}
aspa_set_entry(aspa, mergeset->tas[i], mergeset->tas_aid[i]);
}
+/*
+ * Compress aspa_set tas_aid into the bitfield used by the RDE.
+ * Returns the size of tas and tas_aid bitfield required for this aspa_set.
+ * At the same time tas_aid is overwritten with the bitmasks or cleared
+ * if no extra aid masks are needed.
+ */
+static size_t
+rtr_aspa_set_prep(struct aspa_set *aspa)
+{
+ uint32_t i, mask = 0;
+ int needafi = 0;
+ size_t s;
+
+ s = aspa->num * sizeof(uint32_t);
+ for (i = 0; i < aspa->num; i++) {
+ switch (aspa->tas_aid[i]) {
+ case AID_INET:
+ needafi = 1;
+ mask |= 0x1 << ((i % 16) * 2);
+ break;
+ case AID_INET6:
+ needafi = 1;
+ mask |= 0x2 << ((i % 16) * 2);
+ break;
+ default:
+ mask |= 0x3 << ((i % 16) * 2);
+ break;
+ }
+ if (i % 16 == 15) {
+ memcpy(aspa->tas_aid + (i / 16) * sizeof(mask), &mask,
+ sizeof(mask));
+ mask = 0;
+ }
+ }
+
+ if (!needafi) {
+ free(aspa->tas_aid);
+ aspa->tas_aid = NULL;
+ } else {
+ memcpy(aspa->tas_aid + (aspa->num / 16) * sizeof(mask), &mask,
+ sizeof(mask));
+ s += (aspa->num + 15) / 16;
+ }
+
+ return s;
+}
+
/*
* Merge all RPKI ROA trees into one as one big union.
* Simply try to add all roa entries into a new RB tree.
struct aspa_tree at;
struct roa *roa, *nr;
struct aspa_set *aspa;
+ struct aspa_prep ap = { 0 };
RB_INIT(&rt);
RB_INIT(&at);
imsg_compose(ibuf_rde, IMSG_RECONF_ROA_SET, 0, 0, -1, NULL, 0);
RB_FOREACH_SAFE(roa, roa_tree, &rt, nr) {
- RB_REMOVE(roa_tree, &rt, roa);
imsg_compose(ibuf_rde, IMSG_RECONF_ROA_ITEM, 0, 0, -1,
roa, sizeof(*roa));
- free(roa);
}
+ free_roatree(&rt);
RB_FOREACH(aspa, aspa_tree, &conf->aspa)
rtr_aspa_merge_set(&at, aspa);
+ RB_FOREACH(aspa, aspa_tree, &at) {
+ ap.datasize += rtr_aspa_set_prep(aspa);
+ ap.entries++;
+ }
+
+ imsg_compose(ibuf_rde, IMSG_RECONF_ASPA_PREP, 0, 0, -1,
+ &ap, sizeof(ap));
+
+ RB_FOREACH(aspa, aspa_tree, &at) {
+ uint32_t as[2];
+ as[0] = aspa->as;
+ as[1] = aspa->num;
+
+ imsg_compose(ibuf_rde, IMSG_RECONF_ASPA, 0, 0, -1,
+ &as, sizeof(as));
+ imsg_compose(ibuf_rde, IMSG_RECONF_ASPA_TAS, 0, 0, -1,
+ aspa->tas, aspa->num * sizeof(*aspa->tas));
+ if (aspa->tas_aid)
+ imsg_compose(ibuf_rde, IMSG_RECONF_ASPA_TAS, 0, 0, -1,
+ aspa->tas_aid, (aspa->num + 15) / 16);
+ imsg_compose(ibuf_rde, IMSG_RECONF_ASPA_DONE, 0, 0, -1,
+ NULL, 0);
+ }
+
free_aspatree(&at);
imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0);