1*aaaf7e1fSclaudio /* $OpenBSD: rtr.c,v 1.29 2024/12/02 15:13:57 claudio Exp $ */ 2bd9df44eSclaudio 3bd9df44eSclaudio /* 4bd9df44eSclaudio * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org> 5bd9df44eSclaudio * 6bd9df44eSclaudio * Permission to use, copy, modify, and distribute this software for any 7bd9df44eSclaudio * purpose with or without fee is hereby granted, provided that the above 8bd9df44eSclaudio * copyright notice and this permission notice appear in all copies. 9bd9df44eSclaudio * 10bd9df44eSclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11bd9df44eSclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12bd9df44eSclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13bd9df44eSclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14bd9df44eSclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15bd9df44eSclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16bd9df44eSclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17bd9df44eSclaudio */ 18bd9df44eSclaudio #include <sys/tree.h> 19bd9df44eSclaudio #include <errno.h> 20bd9df44eSclaudio #include <poll.h> 21bd9df44eSclaudio #include <pwd.h> 22bd9df44eSclaudio #include <signal.h> 23ff84f55eSclaudio #include <stddef.h> 24bd9df44eSclaudio #include <stdint.h> 25bd9df44eSclaudio #include <stdio.h> 26bd9df44eSclaudio #include <stdlib.h> 27bd9df44eSclaudio #include <string.h> 28bd9df44eSclaudio #include <syslog.h> 29bd9df44eSclaudio #include <unistd.h> 30bd9df44eSclaudio 31bd9df44eSclaudio #include "bgpd.h" 32bd9df44eSclaudio #include "session.h" 33bd9df44eSclaudio #include "log.h" 34bd9df44eSclaudio 35bd9df44eSclaudio static void rtr_dispatch_imsg_parent(struct imsgbuf *); 36bd9df44eSclaudio static void rtr_dispatch_imsg_rde(struct imsgbuf *); 37bd9df44eSclaudio 38bd9df44eSclaudio volatile sig_atomic_t rtr_quit; 39bd9df44eSclaudio static struct imsgbuf *ibuf_main; 40bd9df44eSclaudio static struct imsgbuf *ibuf_rde; 41bd9df44eSclaudio static struct bgpd_config *conf, *nconf; 42fc51cb50Sclaudio static struct timer_head expire_timer; 43dfd27b08Sclaudio static int rtr_recalc_semaphore; 44bd9df44eSclaudio 45bd9df44eSclaudio static void 46bd9df44eSclaudio rtr_sighdlr(int sig) 47bd9df44eSclaudio { 48bd9df44eSclaudio switch (sig) { 49bd9df44eSclaudio case SIGINT: 50bd9df44eSclaudio case SIGTERM: 51bd9df44eSclaudio rtr_quit = 1; 52bd9df44eSclaudio break; 53bd9df44eSclaudio } 54bd9df44eSclaudio } 55bd9df44eSclaudio 56bd9df44eSclaudio #define PFD_PIPE_MAIN 0 57bd9df44eSclaudio #define PFD_PIPE_RDE 1 58bd9df44eSclaudio #define PFD_PIPE_COUNT 2 59bd9df44eSclaudio 60fc51cb50Sclaudio #define EXPIRE_TIMEOUT 300 61fc51cb50Sclaudio 62dfd27b08Sclaudio void 63dfd27b08Sclaudio rtr_sem_acquire(int cnt) 64dfd27b08Sclaudio { 65dfd27b08Sclaudio rtr_recalc_semaphore += cnt; 66dfd27b08Sclaudio } 67dfd27b08Sclaudio 68dfd27b08Sclaudio void 69dfd27b08Sclaudio rtr_sem_release(int cnt) 70dfd27b08Sclaudio { 71dfd27b08Sclaudio rtr_recalc_semaphore -= cnt; 72dfd27b08Sclaudio if (rtr_recalc_semaphore < 0) 73dfd27b08Sclaudio fatalx("rtr recalc semaphore underflow"); 74dfd27b08Sclaudio } 75dfd27b08Sclaudio 76fc51cb50Sclaudio /* 77fc51cb50Sclaudio * Every EXPIRE_TIMEOUT seconds traverse the static roa-set table and expire 78fc51cb50Sclaudio * all elements where the expires timestamp is smaller or equal to now. 79fc51cb50Sclaudio * If any change is done recalculate the RTR table. 80fc51cb50Sclaudio */ 81fc51cb50Sclaudio static unsigned int 82fc51cb50Sclaudio rtr_expire_roas(time_t now) 83fc51cb50Sclaudio { 84fc51cb50Sclaudio struct roa *roa, *nr; 85fc51cb50Sclaudio unsigned int recalc = 0; 86fc51cb50Sclaudio 87fc51cb50Sclaudio RB_FOREACH_SAFE(roa, roa_tree, &conf->roa, nr) { 88fc51cb50Sclaudio if (roa->expires != 0 && roa->expires <= now) { 89fc51cb50Sclaudio recalc++; 90fc51cb50Sclaudio RB_REMOVE(roa_tree, &conf->roa, roa); 91fc51cb50Sclaudio free(roa); 92fc51cb50Sclaudio } 93fc51cb50Sclaudio } 94fc51cb50Sclaudio if (recalc != 0) 956f8eff73Sclaudio log_info("%u roa-set entries expired", recalc); 96fc51cb50Sclaudio return recalc; 97fc51cb50Sclaudio } 98fc51cb50Sclaudio 99ff84f55eSclaudio static unsigned int 100ff84f55eSclaudio rtr_expire_aspa(time_t now) 101ff84f55eSclaudio { 102ff84f55eSclaudio struct aspa_set *aspa, *na; 103ff84f55eSclaudio unsigned int recalc = 0; 104ff84f55eSclaudio 105ff84f55eSclaudio RB_FOREACH_SAFE(aspa, aspa_tree, &conf->aspa, na) { 106ff84f55eSclaudio if (aspa->expires != 0 && aspa->expires <= now) { 107ff84f55eSclaudio recalc++; 108ff84f55eSclaudio RB_REMOVE(aspa_tree, &conf->aspa, aspa); 109ff84f55eSclaudio free_aspa(aspa); 110ff84f55eSclaudio } 111ff84f55eSclaudio } 112ff84f55eSclaudio if (recalc != 0) 113ff84f55eSclaudio log_info("%u aspa-set entries expired", recalc); 114ff84f55eSclaudio return recalc; 115ff84f55eSclaudio } 116ff84f55eSclaudio 117bd9df44eSclaudio void 11883072fb6Sclaudio rtr_roa_insert(struct roa_tree *rt, struct roa *in) 119bd9df44eSclaudio { 120bd9df44eSclaudio struct roa *roa; 121bd9df44eSclaudio 122bd9df44eSclaudio if ((roa = malloc(sizeof(*roa))) == NULL) 123bd9df44eSclaudio fatal("roa alloc"); 124bd9df44eSclaudio memcpy(roa, in, sizeof(*roa)); 125bd9df44eSclaudio if (RB_INSERT(roa_tree, rt, roa) != NULL) 126bd9df44eSclaudio /* just ignore duplicates */ 127bd9df44eSclaudio free(roa); 128bd9df44eSclaudio } 129bd9df44eSclaudio 13083072fb6Sclaudio /* 13183072fb6Sclaudio * Add an asnum to the aspa_set. The aspa_set is sorted by asnum. 13283072fb6Sclaudio */ 13383072fb6Sclaudio static void 134c0c9c169Sclaudio aspa_set_entry(struct aspa_set *aspa, uint32_t asnum) 13583072fb6Sclaudio { 13683072fb6Sclaudio uint32_t i, num, *newtas; 13783072fb6Sclaudio 13883072fb6Sclaudio for (i = 0; i < aspa->num; i++) { 13983072fb6Sclaudio if (asnum < aspa->tas[i]) 14083072fb6Sclaudio break; 141c0c9c169Sclaudio if (asnum == aspa->tas[i]) 14283072fb6Sclaudio return; 14383072fb6Sclaudio } 14483072fb6Sclaudio 14583072fb6Sclaudio num = aspa->num + 1; 146c2b3ae36Sclaudio newtas = reallocarray(aspa->tas, num, sizeof(uint32_t)); 147c0c9c169Sclaudio if (newtas == NULL) 14883072fb6Sclaudio fatal("aspa_set merge"); 14983072fb6Sclaudio 15083072fb6Sclaudio if (i < aspa->num) { 15183072fb6Sclaudio memmove(newtas + i + 1, newtas + i, 15283072fb6Sclaudio (aspa->num - i) * sizeof(uint32_t)); 15383072fb6Sclaudio } 15483072fb6Sclaudio newtas[i] = asnum; 15583072fb6Sclaudio 15683072fb6Sclaudio aspa->num = num; 15783072fb6Sclaudio aspa->tas = newtas; 15883072fb6Sclaudio } 15983072fb6Sclaudio 16083072fb6Sclaudio /* 16183072fb6Sclaudio * Insert and merge an aspa_set into the aspa_tree at. 16283072fb6Sclaudio */ 16383072fb6Sclaudio void 16483072fb6Sclaudio rtr_aspa_insert(struct aspa_tree *at, struct aspa_set *mergeset) 16583072fb6Sclaudio { 16683072fb6Sclaudio struct aspa_set *aspa, needle = { .as = mergeset->as }; 16783072fb6Sclaudio uint32_t i; 16883072fb6Sclaudio 16983072fb6Sclaudio aspa = RB_FIND(aspa_tree, at, &needle); 17083072fb6Sclaudio if (aspa == NULL) { 17183072fb6Sclaudio if ((aspa = calloc(1, sizeof(*aspa))) == NULL) 17283072fb6Sclaudio fatal("aspa insert"); 17383072fb6Sclaudio aspa->as = mergeset->as; 17483072fb6Sclaudio RB_INSERT(aspa_tree, at, aspa); 17583072fb6Sclaudio } 17683072fb6Sclaudio 17783072fb6Sclaudio for (i = 0; i < mergeset->num; i++) 178c0c9c169Sclaudio aspa_set_entry(aspa, mergeset->tas[i]); 17983072fb6Sclaudio } 18083072fb6Sclaudio 181bd9df44eSclaudio void 182bd9df44eSclaudio rtr_main(int debug, int verbose) 183bd9df44eSclaudio { 184bd9df44eSclaudio struct passwd *pw; 185bd9df44eSclaudio struct pollfd *pfd = NULL; 186bd9df44eSclaudio void *newp; 187bd9df44eSclaudio size_t pfd_elms = 0, i; 188634e7080Sclaudio time_t timeout; 189bd9df44eSclaudio 190bd9df44eSclaudio log_init(debug, LOG_DAEMON); 191bd9df44eSclaudio log_setverbose(verbose); 192bd9df44eSclaudio 193bd9df44eSclaudio log_procinit(log_procnames[PROC_RTR]); 194bd9df44eSclaudio 195bd9df44eSclaudio if ((pw = getpwnam(BGPD_USER)) == NULL) 196bd9df44eSclaudio fatal("getpwnam"); 197bd9df44eSclaudio 198bd9df44eSclaudio if (chroot(pw->pw_dir) == -1) 199bd9df44eSclaudio fatal("chroot"); 200bd9df44eSclaudio if (chdir("/") == -1) 201bd9df44eSclaudio fatal("chdir(\"/\")"); 202bd9df44eSclaudio 203bd9df44eSclaudio setproctitle("rtr engine"); 204bd9df44eSclaudio 205bd9df44eSclaudio if (setgroups(1, &pw->pw_gid) || 206bd9df44eSclaudio setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 207bd9df44eSclaudio setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 208bd9df44eSclaudio fatal("can't drop privileges"); 209bd9df44eSclaudio 210bd9df44eSclaudio if (pledge("stdio recvfd", NULL) == -1) 211bd9df44eSclaudio fatal("pledge"); 212bd9df44eSclaudio 213bd9df44eSclaudio signal(SIGTERM, rtr_sighdlr); 214bd9df44eSclaudio signal(SIGINT, rtr_sighdlr); 215bd9df44eSclaudio signal(SIGPIPE, SIG_IGN); 216bd9df44eSclaudio signal(SIGHUP, SIG_IGN); 217bd9df44eSclaudio signal(SIGALRM, SIG_IGN); 218bd9df44eSclaudio signal(SIGUSR1, SIG_IGN); 219bd9df44eSclaudio 220bd9df44eSclaudio if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL) 221bd9df44eSclaudio fatal(NULL); 22204e12482Sclaudio if (imsgbuf_init(ibuf_main, 3) == -1 || 22304e12482Sclaudio imsgbuf_set_maxsize(ibuf_main, MAX_BGPD_IMSGSIZE) == -1) 224f1b790a5Sclaudio fatal(NULL); 225f1b790a5Sclaudio imsgbuf_allow_fdpass(ibuf_main); 226bd9df44eSclaudio 227bd9df44eSclaudio conf = new_config(); 228bd9df44eSclaudio log_info("rtr engine ready"); 229bd9df44eSclaudio 230fc51cb50Sclaudio TAILQ_INIT(&expire_timer); 231fc51cb50Sclaudio timer_set(&expire_timer, Timer_Rtr_Expire, EXPIRE_TIMEOUT); 232fc51cb50Sclaudio 233bd9df44eSclaudio while (rtr_quit == 0) { 234bd9df44eSclaudio i = rtr_count(); 235bd9df44eSclaudio if (pfd_elms < PFD_PIPE_COUNT + i) { 236bd9df44eSclaudio if ((newp = reallocarray(pfd, 237bd9df44eSclaudio PFD_PIPE_COUNT + i, 238bd9df44eSclaudio sizeof(struct pollfd))) == NULL) 239bd9df44eSclaudio fatal("realloc pollfd"); 240bd9df44eSclaudio pfd = newp; 241bd9df44eSclaudio pfd_elms = PFD_PIPE_COUNT + i; 242bd9df44eSclaudio } 243fc51cb50Sclaudio 244fc51cb50Sclaudio /* run the expire timeout every EXPIRE_TIMEOUT seconds */ 245fc51cb50Sclaudio timeout = timer_nextduein(&expire_timer, getmonotime()); 246fc51cb50Sclaudio if (timeout == -1) 2479c5d31d7Sjob fatalx("roa-set expire timer no longer running"); 248fc51cb50Sclaudio 249eafe309eSclaudio memset(pfd, 0, sizeof(struct pollfd) * pfd_elms); 250bd9df44eSclaudio 251bd9df44eSclaudio set_pollfd(&pfd[PFD_PIPE_MAIN], ibuf_main); 252bd9df44eSclaudio set_pollfd(&pfd[PFD_PIPE_RDE], ibuf_rde); 253bd9df44eSclaudio 254bd9df44eSclaudio i = PFD_PIPE_COUNT; 255bd9df44eSclaudio i += rtr_poll_events(pfd + i, pfd_elms - i, &timeout); 256bd9df44eSclaudio 257bd9df44eSclaudio if (poll(pfd, i, timeout * 1000) == -1) { 258468ac036Sclaudio if (errno == EINTR) 259bd9df44eSclaudio continue; 260468ac036Sclaudio fatal("poll error"); 261bd9df44eSclaudio } 262bd9df44eSclaudio 263bd9df44eSclaudio if (handle_pollfd(&pfd[PFD_PIPE_MAIN], ibuf_main) == -1) 264bd9df44eSclaudio fatalx("Lost connection to parent"); 265bd9df44eSclaudio else 266bd9df44eSclaudio rtr_dispatch_imsg_parent(ibuf_main); 267bd9df44eSclaudio 268bd9df44eSclaudio if (handle_pollfd(&pfd[PFD_PIPE_RDE], ibuf_rde) == -1) { 269bd9df44eSclaudio log_warnx("RTR: Lost connection to RDE"); 2709cbf9e90Sclaudio imsgbuf_clear(ibuf_rde); 271bd9df44eSclaudio free(ibuf_rde); 272bd9df44eSclaudio ibuf_rde = NULL; 273bd9df44eSclaudio } else 274bd9df44eSclaudio rtr_dispatch_imsg_rde(ibuf_rde); 275bd9df44eSclaudio 276bd9df44eSclaudio i = PFD_PIPE_COUNT; 277bd9df44eSclaudio rtr_check_events(pfd + i, pfd_elms - i); 278fc51cb50Sclaudio 279fc51cb50Sclaudio if (timer_nextisdue(&expire_timer, getmonotime()) != NULL) { 280fc51cb50Sclaudio timer_set(&expire_timer, Timer_Rtr_Expire, 281fc51cb50Sclaudio EXPIRE_TIMEOUT); 282fc51cb50Sclaudio if (rtr_expire_roas(time(NULL)) != 0) 283fc51cb50Sclaudio rtr_recalc(); 284ff84f55eSclaudio if (rtr_expire_aspa(time(NULL)) != 0) 285ff84f55eSclaudio rtr_recalc(); 286fc51cb50Sclaudio } 287bd9df44eSclaudio } 288bd9df44eSclaudio 289bd9df44eSclaudio rtr_shutdown(); 290bd9df44eSclaudio 291bd9df44eSclaudio free_config(conf); 292bd9df44eSclaudio free(pfd); 293bd9df44eSclaudio 294bd9df44eSclaudio /* close pipes */ 295bd9df44eSclaudio if (ibuf_rde) { 2969cbf9e90Sclaudio imsgbuf_clear(ibuf_rde); 297bd9df44eSclaudio close(ibuf_rde->fd); 298bd9df44eSclaudio free(ibuf_rde); 299bd9df44eSclaudio } 3009cbf9e90Sclaudio imsgbuf_clear(ibuf_main); 301bd9df44eSclaudio close(ibuf_main->fd); 302bd9df44eSclaudio free(ibuf_main); 303bd9df44eSclaudio 304bd9df44eSclaudio log_info("rtr engine exiting"); 305bd9df44eSclaudio exit(0); 306bd9df44eSclaudio } 307bd9df44eSclaudio 308bd9df44eSclaudio static void 309d1ee0d19Sclaudio rtr_dispatch_imsg_parent(struct imsgbuf *imsgbuf) 310bd9df44eSclaudio { 311ff84f55eSclaudio static struct aspa_set *aspa; 312bd9df44eSclaudio struct imsg imsg; 313ed5572f8Sclaudio struct bgpd_config tconf; 314ed5572f8Sclaudio struct roa roa; 315d87cfbccSclaudio struct rtr_config_msg rtrconf; 316bd9df44eSclaudio struct rtr_session *rs; 317ed5572f8Sclaudio uint32_t rtrid; 318bd9df44eSclaudio int n, fd; 319bd9df44eSclaudio 320d1ee0d19Sclaudio while (imsgbuf) { 321d1ee0d19Sclaudio if ((n = imsg_get(imsgbuf, &imsg)) == -1) 322bd9df44eSclaudio fatal("%s: imsg_get error", __func__); 323bd9df44eSclaudio if (n == 0) 324bd9df44eSclaudio break; 325bd9df44eSclaudio 326ed5572f8Sclaudio rtrid = imsg_get_id(&imsg); 327ed5572f8Sclaudio switch (imsg_get_type(&imsg)) { 328bd9df44eSclaudio case IMSG_SOCKET_CONN_RTR: 32901a115c6Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) { 330bd9df44eSclaudio log_warnx("expected to receive imsg fd " 331bd9df44eSclaudio "but didn't receive any"); 332bd9df44eSclaudio break; 333bd9df44eSclaudio } 334bd9df44eSclaudio if (ibuf_rde) { 335bd9df44eSclaudio log_warnx("Unexpected imsg ctl " 336bd9df44eSclaudio "connection to RDE received"); 3379cbf9e90Sclaudio imsgbuf_clear(ibuf_rde); 338bd9df44eSclaudio free(ibuf_rde); 339bd9df44eSclaudio } 340bd9df44eSclaudio if ((ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL) 341bd9df44eSclaudio fatal(NULL); 34204e12482Sclaudio if (imsgbuf_init(ibuf_rde, fd) == -1 || 34304e12482Sclaudio imsgbuf_set_maxsize(ibuf_rde, MAX_BGPD_IMSGSIZE) == 34404e12482Sclaudio -1) 345f1b790a5Sclaudio fatal(NULL); 346bd9df44eSclaudio break; 347cd16358eSclaudio case IMSG_SOCKET_SETUP: 34801a115c6Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) { 349bd9df44eSclaudio log_warnx("expected to receive imsg fd " 350bd9df44eSclaudio "but didn't receive any"); 351bd9df44eSclaudio break; 352bd9df44eSclaudio } 353ed5572f8Sclaudio if ((rs = rtr_get(rtrid)) == NULL) { 354cd16358eSclaudio log_warnx("IMSG_SOCKET_SETUP: " 355cd16358eSclaudio "unknown rtr id %d", rtrid); 356d9aaae8aSclaudio close(fd); 357bd9df44eSclaudio break; 358bd9df44eSclaudio } 359bd9df44eSclaudio rtr_open(rs, fd); 360bd9df44eSclaudio break; 361bd9df44eSclaudio case IMSG_RECONF_CONF: 362ed5572f8Sclaudio if (imsg_get_data(&imsg, &tconf, sizeof(tconf)) == -1) 363ed5572f8Sclaudio fatal("imsg_get_data"); 364ed5572f8Sclaudio 365bd9df44eSclaudio nconf = new_config(); 366ed5572f8Sclaudio copy_config(nconf, &tconf); 367bd9df44eSclaudio rtr_config_prep(); 368bd9df44eSclaudio break; 369bd9df44eSclaudio case IMSG_RECONF_ROA_ITEM: 370ed5572f8Sclaudio if (imsg_get_data(&imsg, &roa, sizeof(roa)) == -1) 371ed5572f8Sclaudio fatal("imsg_get_data"); 372ed5572f8Sclaudio rtr_roa_insert(&nconf->roa, &roa); 373bd9df44eSclaudio break; 374ff84f55eSclaudio case IMSG_RECONF_ASPA: 375ff84f55eSclaudio if (aspa != NULL) 376ff84f55eSclaudio fatalx("unexpected IMSG_RECONF_ASPA"); 377ff84f55eSclaudio if ((aspa = calloc(1, sizeof(*aspa))) == NULL) 378ff84f55eSclaudio fatal("aspa alloc"); 379ed5572f8Sclaudio if (imsg_get_data(&imsg, aspa, 380ed5572f8Sclaudio offsetof(struct aspa_set, tas)) == -1) 381ed5572f8Sclaudio fatal("imsg_get_data"); 382ff84f55eSclaudio break; 383ff84f55eSclaudio case IMSG_RECONF_ASPA_TAS: 384ff84f55eSclaudio if (aspa == NULL) 385ff84f55eSclaudio fatalx("unexpected IMSG_RECONF_ASPA_TAS"); 386ff84f55eSclaudio aspa->tas = reallocarray(NULL, aspa->num, 387ff84f55eSclaudio sizeof(*aspa->tas)); 388ff84f55eSclaudio if (aspa->tas == NULL) 389ff84f55eSclaudio fatal("aspa tas alloc"); 390ed5572f8Sclaudio if (imsg_get_data(&imsg, aspa->tas, 391ed5572f8Sclaudio aspa->num * sizeof(*aspa->tas)) == -1) 392ed5572f8Sclaudio fatal("imsg_get_data"); 393ff84f55eSclaudio break; 394ff84f55eSclaudio case IMSG_RECONF_ASPA_DONE: 395ff84f55eSclaudio if (aspa == NULL) 396ff84f55eSclaudio fatalx("unexpected IMSG_RECONF_ASPA_DONE"); 397ff84f55eSclaudio if (RB_INSERT(aspa_tree, &nconf->aspa, aspa) != NULL) { 398ff84f55eSclaudio log_warnx("duplicate ASPA set received"); 399ff84f55eSclaudio free_aspa(aspa); 400ff84f55eSclaudio } 401ff84f55eSclaudio aspa = NULL; 402ff84f55eSclaudio break; 403bd9df44eSclaudio case IMSG_RECONF_RTR_CONFIG: 404d87cfbccSclaudio if (imsg_get_data(&imsg, &rtrconf, 405d87cfbccSclaudio sizeof(rtrconf)) == -1) 406ed5572f8Sclaudio fatal("imsg_get_data"); 407ed5572f8Sclaudio rs = rtr_get(rtrid); 408bd9df44eSclaudio if (rs == NULL) 409d87cfbccSclaudio rtr_new(rtrid, &rtrconf); 410bd9df44eSclaudio else 411d87cfbccSclaudio rtr_config_keep(rs, &rtrconf); 412bd9df44eSclaudio break; 413bd9df44eSclaudio case IMSG_RECONF_DRAIN: 414bd9df44eSclaudio imsg_compose(ibuf_main, IMSG_RECONF_DRAIN, 0, 0, 415bd9df44eSclaudio -1, NULL, 0); 416bd9df44eSclaudio break; 417bd9df44eSclaudio case IMSG_RECONF_DONE: 418bd9df44eSclaudio if (nconf == NULL) 419bd9df44eSclaudio fatalx("got IMSG_RECONF_DONE but no config"); 420bd9df44eSclaudio copy_config(conf, nconf); 421bd9df44eSclaudio /* switch the roa, first remove the old one */ 422bd9df44eSclaudio free_roatree(&conf->roa); 423bd9df44eSclaudio /* then move the RB tree root */ 424bd9df44eSclaudio RB_ROOT(&conf->roa) = RB_ROOT(&nconf->roa); 425bd9df44eSclaudio RB_ROOT(&nconf->roa) = NULL; 426ff84f55eSclaudio /* switch the aspa tree, first remove the old one */ 427ff84f55eSclaudio free_aspatree(&conf->aspa); 428ff84f55eSclaudio /* then move the RB tree root */ 429ff84f55eSclaudio RB_ROOT(&conf->aspa) = RB_ROOT(&nconf->aspa); 430ff84f55eSclaudio RB_ROOT(&nconf->aspa) = NULL; 431bd9df44eSclaudio /* finally merge the rtr session */ 432bd9df44eSclaudio rtr_config_merge(); 433fc51cb50Sclaudio rtr_expire_roas(time(NULL)); 434ff84f55eSclaudio rtr_expire_aspa(time(NULL)); 435bd9df44eSclaudio rtr_recalc(); 436bd9df44eSclaudio log_info("RTR engine reconfigured"); 437bd9df44eSclaudio imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0, 438bd9df44eSclaudio -1, NULL, 0); 439bd9df44eSclaudio free_config(nconf); 440bd9df44eSclaudio nconf = NULL; 441bd9df44eSclaudio break; 442bd9df44eSclaudio case IMSG_CTL_SHOW_RTR: 443ed5572f8Sclaudio if ((rs = rtr_get(rtrid)) == NULL) { 444bd9df44eSclaudio log_warnx("IMSG_CTL_SHOW_RTR: " 445ed5572f8Sclaudio "unknown rtr id %d", rtrid); 446bd9df44eSclaudio break; 447bd9df44eSclaudio } 448ed5572f8Sclaudio rtr_show(rs, imsg_get_pid(&imsg)); 449bd9df44eSclaudio break; 450bd9df44eSclaudio case IMSG_CTL_END: 451ed5572f8Sclaudio imsg_compose(ibuf_main, IMSG_CTL_END, 0, 452ed5572f8Sclaudio imsg_get_pid(&imsg), -1, NULL, 0); 453bd9df44eSclaudio break; 454bd9df44eSclaudio } 455bd9df44eSclaudio imsg_free(&imsg); 456bd9df44eSclaudio } 457bd9df44eSclaudio } 458bd9df44eSclaudio 459bd9df44eSclaudio static void 460d1ee0d19Sclaudio rtr_dispatch_imsg_rde(struct imsgbuf *imsgbuf) 461bd9df44eSclaudio { 462bd9df44eSclaudio struct imsg imsg; 463bd9df44eSclaudio int n; 464bd9df44eSclaudio 465d1ee0d19Sclaudio while (imsgbuf) { 466d1ee0d19Sclaudio if ((n = imsg_get(imsgbuf, &imsg)) == -1) 467bd9df44eSclaudio fatal("%s: imsg_get error", __func__); 468bd9df44eSclaudio if (n == 0) 469bd9df44eSclaudio break; 470bd9df44eSclaudio 471bd9df44eSclaudio /* NOTHING */ 472bd9df44eSclaudio 473bd9df44eSclaudio imsg_free(&imsg); 474bd9df44eSclaudio } 475bd9df44eSclaudio } 476bd9df44eSclaudio 477bd9df44eSclaudio void 478bd9df44eSclaudio rtr_imsg_compose(int type, uint32_t id, pid_t pid, void *data, size_t datalen) 479bd9df44eSclaudio { 480bd9df44eSclaudio imsg_compose(ibuf_main, type, id, pid, -1, data, datalen); 481bd9df44eSclaudio } 482bd9df44eSclaudio 483bd9df44eSclaudio /* 484d7e93531Sclaudio * Compress aspa_set tas_aid into the bitfield used by the RDE. 485d7e93531Sclaudio * Returns the size of tas and tas_aid bitfield required for this aspa_set. 486d7e93531Sclaudio * At the same time tas_aid is overwritten with the bitmasks or cleared 487d7e93531Sclaudio * if no extra aid masks are needed. 488d7e93531Sclaudio */ 489d7e93531Sclaudio static size_t 490c0c9c169Sclaudio rtr_aspa_set_size(struct aspa_set *aspa) 491d7e93531Sclaudio { 492c0c9c169Sclaudio return aspa->num * sizeof(uint32_t); 493d7e93531Sclaudio } 494d7e93531Sclaudio 495d7e93531Sclaudio /* 496bd9df44eSclaudio * Merge all RPKI ROA trees into one as one big union. 497bd9df44eSclaudio * Simply try to add all roa entries into a new RB tree. 498bd9df44eSclaudio * This could be made a fair bit faster but for now this is good enough. 499bd9df44eSclaudio */ 500bd9df44eSclaudio void 501bd9df44eSclaudio rtr_recalc(void) 502bd9df44eSclaudio { 503bd9df44eSclaudio struct roa_tree rt; 504ff84f55eSclaudio struct aspa_tree at; 505bd9df44eSclaudio struct roa *roa, *nr; 506ff84f55eSclaudio struct aspa_set *aspa; 507d7e93531Sclaudio struct aspa_prep ap = { 0 }; 508bd9df44eSclaudio 509dfd27b08Sclaudio if (rtr_recalc_semaphore > 0) 510dfd27b08Sclaudio return; 511dfd27b08Sclaudio 512bd9df44eSclaudio RB_INIT(&rt); 513ff84f55eSclaudio RB_INIT(&at); 514bd9df44eSclaudio 515bd9df44eSclaudio RB_FOREACH(roa, roa_tree, &conf->roa) 51683072fb6Sclaudio rtr_roa_insert(&rt, roa); 517bd9df44eSclaudio rtr_roa_merge(&rt); 518bd9df44eSclaudio 519bd9df44eSclaudio imsg_compose(ibuf_rde, IMSG_RECONF_ROA_SET, 0, 0, -1, NULL, 0); 520bd9df44eSclaudio RB_FOREACH_SAFE(roa, roa_tree, &rt, nr) { 521bd9df44eSclaudio imsg_compose(ibuf_rde, IMSG_RECONF_ROA_ITEM, 0, 0, -1, 522bd9df44eSclaudio roa, sizeof(*roa)); 523bd9df44eSclaudio } 524d7e93531Sclaudio free_roatree(&rt); 525ff84f55eSclaudio 526ff84f55eSclaudio RB_FOREACH(aspa, aspa_tree, &conf->aspa) 52783072fb6Sclaudio rtr_aspa_insert(&at, aspa); 52883072fb6Sclaudio rtr_aspa_merge(&at); 529ff84f55eSclaudio 530d7e93531Sclaudio RB_FOREACH(aspa, aspa_tree, &at) { 531c0c9c169Sclaudio ap.datasize += rtr_aspa_set_size(aspa); 532d7e93531Sclaudio ap.entries++; 533d7e93531Sclaudio } 534d7e93531Sclaudio 535d7e93531Sclaudio imsg_compose(ibuf_rde, IMSG_RECONF_ASPA_PREP, 0, 0, -1, 536d7e93531Sclaudio &ap, sizeof(ap)); 537d7e93531Sclaudio 53810b93d6aSclaudio /* walk tree in reverse because aspa_add_set requires that */ 53910b93d6aSclaudio RB_FOREACH_REVERSE(aspa, aspa_tree, &at) { 540d1ecb0c5Sclaudio struct aspa_set as = { .as = aspa->as, .num = aspa->num }; 541d7e93531Sclaudio 542d7e93531Sclaudio imsg_compose(ibuf_rde, IMSG_RECONF_ASPA, 0, 0, -1, 543d1ecb0c5Sclaudio &as, offsetof(struct aspa_set, tas)); 544d7e93531Sclaudio imsg_compose(ibuf_rde, IMSG_RECONF_ASPA_TAS, 0, 0, -1, 545d7e93531Sclaudio aspa->tas, aspa->num * sizeof(*aspa->tas)); 546d7e93531Sclaudio imsg_compose(ibuf_rde, IMSG_RECONF_ASPA_DONE, 0, 0, -1, 547d7e93531Sclaudio NULL, 0); 548d7e93531Sclaudio } 549d7e93531Sclaudio 550ff84f55eSclaudio free_aspatree(&at); 551ff84f55eSclaudio 552bd9df44eSclaudio imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0); 553bd9df44eSclaudio } 554