xref: /openbsd-src/usr.sbin/bgpd/rtr.c (revision aaaf7e1f1544a702208f80d2ec69a43fade8a78c)
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