1 /*	$OpenBSD: rde.c,v 1.651 2025/02/04 18:16:56 denis Exp $ */
2 
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 2016 Job Snijders <job@instituut.net>
6  * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
7  * Copyright (c) 2018 Sebastian Benoit <benno@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/resource.h>
25 
26 #include <errno.h>
27 #include <pwd.h>
28 #include <poll.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <syslog.h>
34 #include <unistd.h>
35 
36 #include "bgpd.h"
37 #include "session.h"
38 #include "rde.h"
39 #include "log.h"
40 
41 #define PFD_PIPE_MAIN		0
42 #define PFD_PIPE_SESSION	1
43 #define PFD_PIPE_SESSION_CTL	2
44 #define PFD_PIPE_ROA		3
45 #define PFD_PIPE_COUNT		4
46 
47 void		 rde_sighdlr(int);
48 void		 rde_dispatch_imsg_session(struct imsgbuf *);
49 void		 rde_dispatch_imsg_parent(struct imsgbuf *);
50 void		 rde_dispatch_imsg_rtr(struct imsgbuf *);
51 void		 rde_dispatch_imsg_peer(struct rde_peer *, void *);
52 void		 rde_update_dispatch(struct rde_peer *, struct ibuf *);
53 int		 rde_update_update(struct rde_peer *, uint32_t,
54 		    struct filterstate *, struct bgpd_addr *, uint8_t);
55 void		 rde_update_withdraw(struct rde_peer *, uint32_t,
56 		    struct bgpd_addr *, uint8_t);
57 int		 rde_attr_parse(struct ibuf *, struct rde_peer *,
58 		    struct filterstate *, struct ibuf *, struct ibuf *);
59 int		 rde_attr_add(struct filterstate *, struct ibuf *);
60 uint8_t		 rde_attr_missing(struct rde_aspath *, int, uint16_t);
61 int		 rde_get_mp_nexthop(struct ibuf *, uint8_t,
62 		    struct rde_peer *, struct filterstate *);
63 void		 rde_as4byte_fixup(struct rde_peer *, struct rde_aspath *);
64 uint8_t		 rde_aspa_validity(struct rde_peer *, struct rde_aspath *,
65 		    uint8_t);
66 void		 rde_reflector(struct rde_peer *, struct rde_aspath *);
67 
68 void		 rde_dump_ctx_new(struct ctl_show_rib_request *, pid_t,
69 		    enum imsg_type);
70 void		 rde_dump_ctx_throttle(pid_t, int);
71 void		 rde_dump_ctx_terminate(pid_t);
72 void		 rde_dump_mrt_new(struct mrt *, pid_t, int);
73 
74 int		 rde_l3vpn_import(struct rde_community *, struct l3vpn *);
75 static void	 rde_commit_pftable(void);
76 void		 rde_reload_done(void);
77 static void	 rde_softreconfig_in_done(void *, uint8_t);
78 static void	 rde_softreconfig_out_done(void *, uint8_t);
79 static void	 rde_softreconfig_done(void);
80 static void	 rde_softreconfig_out(struct rib_entry *, void *);
81 static void	 rde_softreconfig_in(struct rib_entry *, void *);
82 static void	 rde_softreconfig_sync_reeval(struct rib_entry *, void *);
83 static void	 rde_softreconfig_sync_fib(struct rib_entry *, void *);
84 static void	 rde_softreconfig_sync_done(void *, uint8_t);
85 static void	 rde_rpki_reload(void);
86 static int	 rde_roa_reload(void);
87 static int	 rde_aspa_reload(void);
88 int		 rde_update_queue_pending(void);
89 void		 rde_update_queue_runner(uint8_t);
90 struct rde_prefixset *rde_find_prefixset(char *, struct rde_prefixset_head *);
91 void		 rde_mark_prefixsets_dirty(struct rde_prefixset_head *,
92 		    struct rde_prefixset_head *);
93 uint8_t		 rde_roa_validity(struct rde_prefixset *,
94 		    struct bgpd_addr *, uint8_t, uint32_t);
95 
96 static void	 rde_peer_recv_eor(struct rde_peer *, uint8_t);
97 static void	 rde_peer_send_eor(struct rde_peer *, uint8_t);
98 
99 void		 network_add(struct network_config *, struct filterstate *);
100 void		 network_delete(struct network_config *);
101 static void	 network_dump_upcall(struct rib_entry *, void *);
102 static void	 network_flush_upcall(struct rib_entry *, void *);
103 
104 void		 flowspec_add(struct flowspec *, struct filterstate *,
105 		    struct filter_set_head *);
106 void		 flowspec_delete(struct flowspec *);
107 static void	 flowspec_flush_upcall(struct rib_entry *, void *);
108 static void	 flowspec_dump_upcall(struct rib_entry *, void *);
109 static void	 flowspec_dump_done(void *, uint8_t);
110 
111 void		 rde_shutdown(void);
112 static int	 ovs_match(struct prefix *, uint32_t);
113 static int	 avs_match(struct prefix *, uint32_t);
114 
115 static struct imsgbuf		*ibuf_se;
116 static struct imsgbuf		*ibuf_se_ctl;
117 static struct imsgbuf		*ibuf_rtr;
118 static struct imsgbuf		*ibuf_main;
119 static struct bgpd_config	*conf, *nconf;
120 static struct rde_prefixset	 rde_roa, roa_new;
121 static struct rde_aspa		*rde_aspa, *aspa_new;
122 static uint8_t			 rde_aspa_generation;
123 
124 volatile sig_atomic_t	 rde_quit = 0;
125 struct filter_head	*out_rules, *out_rules_tmp;
126 struct rde_memstats	 rdemem;
127 int			 softreconfig;
128 static int		 rde_eval_all;
129 
130 extern struct peer_tree	 peertable;
131 extern struct rde_peer	*peerself;
132 
133 struct rde_dump_ctx {
134 	LIST_ENTRY(rde_dump_ctx)	entry;
135 	struct ctl_show_rib_request	req;
136 	uint32_t			peerid;
137 	uint8_t				throttled;
138 };
139 
140 LIST_HEAD(, rde_dump_ctx) rde_dump_h = LIST_HEAD_INITIALIZER(rde_dump_h);
141 
142 struct rde_mrt_ctx {
143 	LIST_ENTRY(rde_mrt_ctx)	entry;
144 	struct mrt		mrt;
145 };
146 
147 LIST_HEAD(, rde_mrt_ctx) rde_mrts = LIST_HEAD_INITIALIZER(rde_mrts);
148 u_int rde_mrt_cnt;
149 
150 void
rde_sighdlr(int sig)151 rde_sighdlr(int sig)
152 {
153 	switch (sig) {
154 	case SIGINT:
155 	case SIGTERM:
156 		rde_quit = 1;
157 		break;
158 	}
159 }
160 
161 void
rde_main(int debug,int verbose)162 rde_main(int debug, int verbose)
163 {
164 	struct passwd		*pw;
165 	struct pollfd		*pfd = NULL;
166 	struct rde_mrt_ctx	*mctx, *xmctx;
167 	void			*newp;
168 	u_int			 pfd_elms = 0, i, j;
169 	int			 timeout;
170 	uint8_t			 aid;
171 
172 	log_init(debug, LOG_DAEMON);
173 	log_setverbose(verbose);
174 
175 	log_procinit(log_procnames[PROC_RDE]);
176 
177 	if ((pw = getpwnam(BGPD_USER)) == NULL)
178 		fatal("getpwnam");
179 
180 	if (chroot(pw->pw_dir) == -1)
181 		fatal("chroot");
182 	if (chdir("/") == -1)
183 		fatal("chdir(\"/\")");
184 
185 	setproctitle("route decision engine");
186 
187 	if (setgroups(1, &pw->pw_gid) ||
188 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
189 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
190 		fatal("can't drop privileges");
191 
192 	if (pledge("stdio recvfd", NULL) == -1)
193 		fatal("pledge");
194 
195 	signal(SIGTERM, rde_sighdlr);
196 	signal(SIGINT, rde_sighdlr);
197 	signal(SIGPIPE, SIG_IGN);
198 	signal(SIGHUP, SIG_IGN);
199 	signal(SIGALRM, SIG_IGN);
200 	signal(SIGUSR1, SIG_IGN);
201 
202 	if ((ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL)
203 		fatal(NULL);
204 	if (imsgbuf_init(ibuf_main, 3) == -1 ||
205 	    imsgbuf_set_maxsize(ibuf_main, MAX_BGPD_IMSGSIZE) == -1)
206 		fatal(NULL);
207 	imsgbuf_allow_fdpass(ibuf_main);
208 
209 	/* initialize the RIB structures */
210 	if ((out_rules = calloc(1, sizeof(struct filter_head))) == NULL)
211 		fatal(NULL);
212 	TAILQ_INIT(out_rules);
213 
214 	pt_init();
215 	peer_init(out_rules);
216 
217 	/* make sure the default RIBs are setup */
218 	rib_new("Adj-RIB-In", 0, F_RIB_NOFIB | F_RIB_NOEVALUATE);
219 
220 	conf = new_config();
221 	log_info("route decision engine ready");
222 
223 	while (rde_quit == 0) {
224 		if (pfd_elms < PFD_PIPE_COUNT + rde_mrt_cnt) {
225 			if ((newp = reallocarray(pfd,
226 			    PFD_PIPE_COUNT + rde_mrt_cnt,
227 			    sizeof(struct pollfd))) == NULL) {
228 				/* panic for now  */
229 				log_warn("could not resize pfd from %u -> %u"
230 				    " entries", pfd_elms, PFD_PIPE_COUNT +
231 				    rde_mrt_cnt);
232 				fatalx("exiting");
233 			}
234 			pfd = newp;
235 			pfd_elms = PFD_PIPE_COUNT + rde_mrt_cnt;
236 		}
237 		timeout = -1;
238 		memset(pfd, 0, sizeof(struct pollfd) * pfd_elms);
239 
240 		set_pollfd(&pfd[PFD_PIPE_MAIN], ibuf_main);
241 		set_pollfd(&pfd[PFD_PIPE_SESSION], ibuf_se);
242 		set_pollfd(&pfd[PFD_PIPE_SESSION_CTL], ibuf_se_ctl);
243 		set_pollfd(&pfd[PFD_PIPE_ROA], ibuf_rtr);
244 
245 		i = PFD_PIPE_COUNT;
246 		for (mctx = LIST_FIRST(&rde_mrts); mctx != 0; mctx = xmctx) {
247 			xmctx = LIST_NEXT(mctx, entry);
248 
249 			if (i >= pfd_elms)
250 				fatalx("poll pfd too small");
251 			if (msgbuf_queuelen(mctx->mrt.wbuf) > 0) {
252 				pfd[i].fd = mctx->mrt.fd;
253 				pfd[i].events = POLLOUT;
254 				i++;
255 			} else if (mctx->mrt.state == MRT_STATE_REMOVE) {
256 				mrt_clean(&mctx->mrt);
257 				LIST_REMOVE(mctx, entry);
258 				free(mctx);
259 				rde_mrt_cnt--;
260 			}
261 		}
262 
263 		if (peer_work_pending() || rde_update_queue_pending() ||
264 		    nexthop_pending() || rib_dump_pending())
265 			timeout = 0;
266 
267 		if (poll(pfd, i, timeout) == -1) {
268 			if (errno == EINTR)
269 				continue;
270 			fatal("poll error");
271 		}
272 
273 		if (handle_pollfd(&pfd[PFD_PIPE_MAIN], ibuf_main) == -1)
274 			fatalx("Lost connection to parent");
275 		else
276 			rde_dispatch_imsg_parent(ibuf_main);
277 
278 		if (handle_pollfd(&pfd[PFD_PIPE_SESSION], ibuf_se) == -1) {
279 			log_warnx("RDE: Lost connection to SE");
280 			imsgbuf_clear(ibuf_se);
281 			free(ibuf_se);
282 			ibuf_se = NULL;
283 		} else
284 			rde_dispatch_imsg_session(ibuf_se);
285 
286 		if (handle_pollfd(&pfd[PFD_PIPE_SESSION_CTL], ibuf_se_ctl) ==
287 		    -1) {
288 			log_warnx("RDE: Lost connection to SE control");
289 			imsgbuf_clear(ibuf_se_ctl);
290 			free(ibuf_se_ctl);
291 			ibuf_se_ctl = NULL;
292 		} else
293 			rde_dispatch_imsg_session(ibuf_se_ctl);
294 
295 		if (handle_pollfd(&pfd[PFD_PIPE_ROA], ibuf_rtr) == -1) {
296 			log_warnx("RDE: Lost connection to ROA");
297 			imsgbuf_clear(ibuf_rtr);
298 			free(ibuf_rtr);
299 			ibuf_rtr = NULL;
300 		} else
301 			rde_dispatch_imsg_rtr(ibuf_rtr);
302 
303 		for (j = PFD_PIPE_COUNT, mctx = LIST_FIRST(&rde_mrts);
304 		    j < i && mctx != 0; j++) {
305 			if (pfd[j].fd == mctx->mrt.fd &&
306 			    pfd[j].revents & POLLOUT)
307 				mrt_write(&mctx->mrt);
308 			mctx = LIST_NEXT(mctx, entry);
309 		}
310 
311 		peer_foreach(rde_dispatch_imsg_peer, NULL);
312 		peer_reaper(NULL);
313 		rib_dump_runner();
314 		nexthop_runner();
315 		if (ibuf_se && imsgbuf_queuelen(ibuf_se) < SESS_MSG_HIGH_MARK) {
316 			for (aid = AID_MIN; aid < AID_MAX; aid++)
317 				rde_update_queue_runner(aid);
318 		}
319 		/* commit pftable once per poll loop */
320 		rde_commit_pftable();
321 	}
322 
323 	/* do not clean up on shutdown on production, it takes ages. */
324 	if (debug)
325 		rde_shutdown();
326 
327 	free_config(conf);
328 	free(pfd);
329 
330 	/* close pipes */
331 	if (ibuf_se) {
332 		imsgbuf_clear(ibuf_se);
333 		close(ibuf_se->fd);
334 		free(ibuf_se);
335 	}
336 	if (ibuf_se_ctl) {
337 		imsgbuf_clear(ibuf_se_ctl);
338 		close(ibuf_se_ctl->fd);
339 		free(ibuf_se_ctl);
340 	}
341 	if (ibuf_rtr) {
342 		imsgbuf_clear(ibuf_rtr);
343 		close(ibuf_rtr->fd);
344 		free(ibuf_rtr);
345 	}
346 	imsgbuf_clear(ibuf_main);
347 	close(ibuf_main->fd);
348 	free(ibuf_main);
349 
350 	while ((mctx = LIST_FIRST(&rde_mrts)) != NULL) {
351 		mrt_clean(&mctx->mrt);
352 		LIST_REMOVE(mctx, entry);
353 		free(mctx);
354 	}
355 
356 	log_info("route decision engine exiting");
357 	exit(0);
358 }
359 
360 struct network_config	netconf_s, netconf_p;
361 struct filterstate	netconf_state;
362 struct filter_set_head	session_set = TAILQ_HEAD_INITIALIZER(session_set);
363 struct filter_set_head	parent_set = TAILQ_HEAD_INITIALIZER(parent_set);
364 
365 void
rde_dispatch_imsg_session(struct imsgbuf * imsgbuf)366 rde_dispatch_imsg_session(struct imsgbuf *imsgbuf)
367 {
368 	static struct flowspec	*curflow;
369 	struct imsg		 imsg;
370 	struct ibuf		 ibuf;
371 	struct rde_peer_stats	 stats;
372 	struct ctl_show_set	 cset;
373 	struct ctl_show_rib	 csr;
374 	struct ctl_show_rib_request	req;
375 	struct session_up	 sup;
376 	struct peer_config	 pconf;
377 	struct rde_peer		*peer;
378 	struct rde_aspath	*asp;
379 	struct filter_set	*s;
380 	struct as_set		*aset;
381 	struct rde_prefixset	*pset;
382 	ssize_t			 n;
383 	uint32_t		 peerid;
384 	pid_t			 pid;
385 	int			 verbose;
386 	uint8_t			 aid;
387 
388 	while (imsgbuf) {
389 		if ((n = imsg_get(imsgbuf, &imsg)) == -1)
390 			fatal("rde_dispatch_imsg_session: imsg_get error");
391 		if (n == 0)
392 			break;
393 
394 		peerid = imsg_get_id(&imsg);
395 		pid = imsg_get_pid(&imsg);
396 		switch (imsg_get_type(&imsg)) {
397 		case IMSG_UPDATE:
398 		case IMSG_REFRESH:
399 			if ((peer = peer_get(peerid)) == NULL) {
400 				log_warnx("rde_dispatch: unknown peer id %d",
401 				    peerid);
402 				break;
403 			}
404 			if (peer_is_up(peer))
405 				peer_imsg_push(peer, &imsg);
406 			break;
407 		case IMSG_SESSION_ADD:
408 			if (imsg_get_data(&imsg, &pconf, sizeof(pconf)) == -1)
409 				fatalx("incorrect size of session request");
410 			peer = peer_add(peerid, &pconf, out_rules);
411 			/* make sure rde_eval_all is on if needed. */
412 			if (peer->conf.flags & PEERFLAG_EVALUATE_ALL)
413 				rde_eval_all = 1;
414 			break;
415 		case IMSG_SESSION_UP:
416 			if ((peer = peer_get(peerid)) == NULL) {
417 				log_warnx("%s: unknown peer id %d",
418 				    "IMSG_SESSION_UP", peerid);
419 				break;
420 			}
421 			if (imsg_get_data(&imsg, &sup, sizeof(sup)) == -1)
422 				fatalx("incorrect size of session request");
423 			peer_up(peer, &sup);
424 			/* make sure rde_eval_all is on if needed. */
425 			if (peer_has_add_path(peer, AID_UNSPEC, CAPA_AP_SEND))
426 				rde_eval_all = 1;
427 			break;
428 		case IMSG_SESSION_DOWN:
429 			if ((peer = peer_get(peerid)) == NULL) {
430 				log_warnx("%s: unknown peer id %d",
431 				    "IMSG_SESSION_DOWN", peerid);
432 				break;
433 			}
434 			peer_down(peer);
435 			break;
436 		case IMSG_SESSION_DELETE:
437 			/* silently ignore deletes for unknown peers */
438 			if ((peer = peer_get(peerid)) == NULL)
439 				break;
440 			peer_delete(peer);
441 			break;
442 		case IMSG_SESSION_STALE:
443 		case IMSG_SESSION_NOGRACE:
444 		case IMSG_SESSION_FLUSH:
445 		case IMSG_SESSION_RESTARTED:
446 			if ((peer = peer_get(peerid)) == NULL) {
447 				log_warnx("%s: unknown peer id %d",
448 				    "graceful restart", peerid);
449 				break;
450 			}
451 			if (imsg_get_data(&imsg, &aid, sizeof(aid)) == -1) {
452 				log_warnx("%s: wrong imsg len", __func__);
453 				break;
454 			}
455 			if (aid < AID_MIN || aid >= AID_MAX) {
456 				log_warnx("%s: bad AID", __func__);
457 				break;
458 			}
459 
460 			switch (imsg_get_type(&imsg)) {
461 			case IMSG_SESSION_STALE:
462 				peer_stale(peer, aid, 0);
463 				break;
464 			case IMSG_SESSION_NOGRACE:
465 				peer_stale(peer, aid, 1);
466 				break;
467 			case IMSG_SESSION_FLUSH:
468 				peer_flush(peer, aid, peer->staletime[aid]);
469 				break;
470 			case IMSG_SESSION_RESTARTED:
471 				if (peer->staletime[aid])
472 					peer_flush(peer, aid,
473 					    peer->staletime[aid]);
474 				break;
475 			}
476 			break;
477 		case IMSG_NETWORK_ADD:
478 			if (imsg_get_data(&imsg, &netconf_s,
479 			    sizeof(netconf_s)) == -1) {
480 				log_warnx("rde_dispatch: wrong imsg len");
481 				break;
482 			}
483 			TAILQ_INIT(&netconf_s.attrset);
484 			rde_filterstate_init(&netconf_state);
485 			asp = &netconf_state.aspath;
486 			asp->aspath = aspath_get(NULL, 0);
487 			asp->origin = ORIGIN_IGP;
488 			asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
489 			    F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED |
490 			    F_ANN_DYNAMIC;
491 			break;
492 		case IMSG_NETWORK_ASPATH:
493 			if (imsg_get_ibuf(&imsg, &ibuf) == -1) {
494 				log_warnx("rde_dispatch: bad imsg");
495 				memset(&netconf_s, 0, sizeof(netconf_s));
496 				break;
497 			}
498 			if (ibuf_get(&ibuf, &csr, sizeof(csr)) == -1) {
499 				log_warnx("rde_dispatch: wrong imsg len");
500 				memset(&netconf_s, 0, sizeof(netconf_s));
501 				break;
502 			}
503 			asp = &netconf_state.aspath;
504 			asp->lpref = csr.local_pref;
505 			asp->med = csr.med;
506 			asp->weight = csr.weight;
507 			asp->flags = csr.flags;
508 			asp->origin = csr.origin;
509 			asp->flags |= F_PREFIX_ANNOUNCED | F_ANN_DYNAMIC;
510 			aspath_put(asp->aspath);
511 			asp->aspath = aspath_get(ibuf_data(&ibuf),
512 			    ibuf_size(&ibuf));
513 			break;
514 		case IMSG_NETWORK_ATTR:
515 			/* parse optional path attributes */
516 			if (imsg_get_ibuf(&imsg, &ibuf) == -1 ||
517 			    rde_attr_add(&netconf_state, &ibuf) == -1) {
518 				log_warnx("rde_dispatch: bad network "
519 				    "attribute");
520 				rde_filterstate_clean(&netconf_state);
521 				memset(&netconf_s, 0, sizeof(netconf_s));
522 				break;
523 			}
524 			break;
525 		case IMSG_NETWORK_DONE:
526 			TAILQ_CONCAT(&netconf_s.attrset, &session_set, entry);
527 			switch (netconf_s.prefix.aid) {
528 			case AID_INET:
529 				if (netconf_s.prefixlen > 32)
530 					goto badnet;
531 				network_add(&netconf_s, &netconf_state);
532 				break;
533 			case AID_INET6:
534 				if (netconf_s.prefixlen > 128)
535 					goto badnet;
536 				network_add(&netconf_s, &netconf_state);
537 				break;
538 			case 0:
539 				/* something failed beforehand */
540 				break;
541 			default:
542 badnet:
543 				log_warnx("request to insert invalid network");
544 				break;
545 			}
546 			rde_filterstate_clean(&netconf_state);
547 			break;
548 		case IMSG_NETWORK_REMOVE:
549 			if (imsg_get_data(&imsg, &netconf_s,
550 			    sizeof(netconf_s)) == -1) {
551 				log_warnx("rde_dispatch: wrong imsg len");
552 				break;
553 			}
554 			TAILQ_INIT(&netconf_s.attrset);
555 
556 			switch (netconf_s.prefix.aid) {
557 			case AID_INET:
558 				if (netconf_s.prefixlen > 32)
559 					goto badnetdel;
560 				network_delete(&netconf_s);
561 				break;
562 			case AID_INET6:
563 				if (netconf_s.prefixlen > 128)
564 					goto badnetdel;
565 				network_delete(&netconf_s);
566 				break;
567 			default:
568 badnetdel:
569 				log_warnx("request to remove invalid network");
570 				break;
571 			}
572 			break;
573 		case IMSG_NETWORK_FLUSH:
574 			if (rib_dump_new(RIB_ADJ_IN, AID_UNSPEC,
575 			    RDE_RUNNER_ROUNDS, NULL, network_flush_upcall,
576 			    NULL, NULL) == -1)
577 				log_warn("rde_dispatch: IMSG_NETWORK_FLUSH");
578 			break;
579 		case IMSG_FLOWSPEC_ADD:
580 			if (curflow != NULL) {
581 				log_warnx("rde_dispatch: "
582 				    "unexpected flowspec add");
583 				break;
584 			}
585 			if (imsg_get_ibuf(&imsg, &ibuf) == -1 ||
586 			    ibuf_size(&ibuf) <= FLOWSPEC_SIZE) {
587 				log_warnx("rde_dispatch: wrong imsg len");
588 				break;
589 			}
590 			curflow = malloc(ibuf_size(&ibuf));
591 			if (curflow == NULL)
592 				fatal(NULL);
593 			memcpy(curflow, ibuf_data(&ibuf), ibuf_size(&ibuf));
594 			if (curflow->len + FLOWSPEC_SIZE != ibuf_size(&ibuf)) {
595 				free(curflow);
596 				curflow = NULL;
597 				log_warnx("rde_dispatch: wrong flowspec len");
598 				break;
599 			}
600 			rde_filterstate_init(&netconf_state);
601 			asp = &netconf_state.aspath;
602 			asp->aspath = aspath_get(NULL, 0);
603 			asp->origin = ORIGIN_IGP;
604 			asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
605 			    F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED |
606 			    F_ANN_DYNAMIC;
607 			break;
608 		case IMSG_FLOWSPEC_DONE:
609 			if (curflow == NULL) {
610 				log_warnx("rde_dispatch: "
611 				    "unexpected flowspec done");
612 				break;
613 			}
614 
615 			if (flowspec_valid(curflow->data, curflow->len,
616 			    curflow->aid == AID_FLOWSPECv6) == -1)
617 				log_warnx("invalid flowspec update received "
618 				    "from bgpctl");
619 			else
620 				flowspec_add(curflow, &netconf_state,
621 				    &session_set);
622 
623 			rde_filterstate_clean(&netconf_state);
624 			filterset_free(&session_set);
625 			free(curflow);
626 			curflow = NULL;
627 			break;
628 		case IMSG_FLOWSPEC_REMOVE:
629 			if (curflow != NULL) {
630 				log_warnx("rde_dispatch: "
631 				    "unexpected flowspec remove");
632 				break;
633 			}
634 			if (imsg_get_ibuf(&imsg, &ibuf) == -1 ||
635 			    ibuf_size(&ibuf) <= FLOWSPEC_SIZE) {
636 				log_warnx("rde_dispatch: wrong imsg len");
637 				break;
638 			}
639 			curflow = malloc(ibuf_size(&ibuf));
640 			if (curflow == NULL)
641 				fatal(NULL);
642 			memcpy(curflow, ibuf_data(&ibuf), ibuf_size(&ibuf));
643 			if (curflow->len + FLOWSPEC_SIZE != ibuf_size(&ibuf)) {
644 				free(curflow);
645 				curflow = NULL;
646 				log_warnx("rde_dispatch: wrong flowspec len");
647 				break;
648 			}
649 
650 			if (flowspec_valid(curflow->data, curflow->len,
651 			    curflow->aid == AID_FLOWSPECv6) == -1)
652 				log_warnx("invalid flowspec withdraw received "
653 				    "from bgpctl");
654 			else
655 				flowspec_delete(curflow);
656 
657 			free(curflow);
658 			curflow = NULL;
659 			break;
660 		case IMSG_FLOWSPEC_FLUSH:
661 			prefix_flowspec_dump(AID_UNSPEC, NULL,
662 			    flowspec_flush_upcall, NULL);
663 			break;
664 		case IMSG_FILTER_SET:
665 			if ((s = malloc(sizeof(struct filter_set))) == NULL)
666 				fatal(NULL);
667 			if (imsg_get_data(&imsg, s, sizeof(struct filter_set))
668 			    == -1) {
669 				log_warnx("rde_dispatch: wrong imsg len");
670 				free(s);
671 				break;
672 			}
673 			if (s->type == ACTION_SET_NEXTHOP) {
674 				s->action.nh_ref =
675 				    nexthop_get(&s->action.nexthop);
676 				s->type = ACTION_SET_NEXTHOP_REF;
677 			}
678 			TAILQ_INSERT_TAIL(&session_set, s, entry);
679 			break;
680 		case IMSG_CTL_SHOW_NETWORK:
681 		case IMSG_CTL_SHOW_RIB:
682 		case IMSG_CTL_SHOW_RIB_PREFIX:
683 			if (imsg_get_data(&imsg, &req, sizeof(req)) == -1) {
684 				log_warnx("rde_dispatch: wrong imsg len");
685 				break;
686 			}
687 			rde_dump_ctx_new(&req, pid, imsg_get_type(&imsg));
688 			break;
689 		case IMSG_CTL_SHOW_FLOWSPEC:
690 			if (imsg_get_data(&imsg, &req, sizeof(req)) == -1) {
691 				log_warnx("rde_dispatch: wrong imsg len");
692 				break;
693 			}
694 			prefix_flowspec_dump(req.aid, &pid,
695 			    flowspec_dump_upcall, flowspec_dump_done);
696 			break;
697 		case IMSG_CTL_SHOW_NEIGHBOR:
698 			peer = peer_get(peerid);
699 			if (peer != NULL)
700 				memcpy(&stats, &peer->stats, sizeof(stats));
701 			else
702 				memset(&stats, 0, sizeof(stats));
703 			imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NEIGHBOR,
704 			    peerid, pid, -1, &stats, sizeof(stats));
705 			break;
706 		case IMSG_CTL_SHOW_RIB_MEM:
707 			imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_RIB_MEM, 0,
708 			    pid, -1, &rdemem, sizeof(rdemem));
709 			break;
710 		case IMSG_CTL_SHOW_SET:
711 			/* first roa set */
712 			pset = &rde_roa;
713 			memset(&cset, 0, sizeof(cset));
714 			cset.type = ROA_SET;
715 			strlcpy(cset.name, "RPKI ROA", sizeof(cset.name));
716 			cset.lastchange = pset->lastchange;
717 			cset.v4_cnt = pset->th.v4_cnt;
718 			cset.v6_cnt = pset->th.v6_cnt;
719 			imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
720 			    pid, -1, &cset, sizeof(cset));
721 
722 			/* then aspa set */
723 			memset(&cset, 0, sizeof(cset));
724 			cset.type = ASPA_SET;
725 			strlcpy(cset.name, "RPKI ASPA", sizeof(cset.name));
726 			aspa_table_stats(rde_aspa, &cset);
727 			imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
728 			    pid, -1, &cset, sizeof(cset));
729 
730 			SIMPLEQ_FOREACH(aset, &conf->as_sets, entry) {
731 				memset(&cset, 0, sizeof(cset));
732 				cset.type = ASNUM_SET;
733 				strlcpy(cset.name, aset->name,
734 				    sizeof(cset.name));
735 				cset.lastchange = aset->lastchange;
736 				cset.as_cnt = set_nmemb(aset->set);
737 				imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
738 				    pid, -1, &cset, sizeof(cset));
739 			}
740 			SIMPLEQ_FOREACH(pset, &conf->rde_prefixsets, entry) {
741 				memset(&cset, 0, sizeof(cset));
742 				cset.type = PREFIX_SET;
743 				strlcpy(cset.name, pset->name,
744 				    sizeof(cset.name));
745 				cset.lastchange = pset->lastchange;
746 				cset.v4_cnt = pset->th.v4_cnt;
747 				cset.v6_cnt = pset->th.v6_cnt;
748 				imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
749 				    pid, -1, &cset, sizeof(cset));
750 			}
751 			SIMPLEQ_FOREACH(pset, &conf->rde_originsets, entry) {
752 				memset(&cset, 0, sizeof(cset));
753 				cset.type = ORIGIN_SET;
754 				strlcpy(cset.name, pset->name,
755 				    sizeof(cset.name));
756 				cset.lastchange = pset->lastchange;
757 				cset.v4_cnt = pset->th.v4_cnt;
758 				cset.v6_cnt = pset->th.v6_cnt;
759 				imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
760 				    pid, -1, &cset, sizeof(cset));
761 			}
762 			imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, pid,
763 			    -1, NULL, 0);
764 			break;
765 		case IMSG_CTL_LOG_VERBOSE:
766 			/* already checked by SE */
767 			if (imsg_get_data(&imsg, &verbose, sizeof(verbose)) ==
768 			    -1) {
769 				log_warnx("rde_dispatch: wrong imsg len");
770 				break;
771 			}
772 			log_setverbose(verbose);
773 			break;
774 		case IMSG_CTL_END:
775 			imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, pid,
776 			    -1, NULL, 0);
777 			break;
778 		case IMSG_CTL_TERMINATE:
779 			rde_dump_ctx_terminate(pid);
780 			break;
781 		case IMSG_XON:
782 			if (peerid) {
783 				peer = peer_get(peerid);
784 				if (peer)
785 					peer->throttled = 0;
786 			} else {
787 				rde_dump_ctx_throttle(pid, 0);
788 			}
789 			break;
790 		case IMSG_XOFF:
791 			if (peerid) {
792 				peer = peer_get(peerid);
793 				if (peer)
794 					peer->throttled = 1;
795 			} else {
796 				rde_dump_ctx_throttle(pid, 1);
797 			}
798 			break;
799 		case IMSG_RECONF_DRAIN:
800 			imsg_compose(ibuf_se, IMSG_RECONF_DRAIN, 0, 0,
801 			    -1, NULL, 0);
802 			break;
803 		default:
804 			break;
805 		}
806 		imsg_free(&imsg);
807 	}
808 }
809 
810 void
rde_dispatch_imsg_parent(struct imsgbuf * imsgbuf)811 rde_dispatch_imsg_parent(struct imsgbuf *imsgbuf)
812 {
813 	static struct rde_prefixset	*last_prefixset;
814 	static struct as_set	*last_as_set;
815 	static struct l3vpn	*vpn;
816 	static struct flowspec	*curflow;
817 	struct imsg		 imsg;
818 	struct ibuf		 ibuf;
819 	struct bgpd_config	 tconf;
820 	struct filterstate	 state;
821 	struct kroute_nexthop	 knext;
822 	struct mrt		 xmrt;
823 	struct prefixset_item	 psi;
824 	struct rde_rib		 rr;
825 	struct roa		 roa;
826 	char			 name[SET_NAME_LEN];
827 	struct imsgbuf		*i;
828 	struct filter_head	*nr;
829 	struct filter_rule	*r;
830 	struct filter_set	*s;
831 	struct rib		*rib;
832 	struct rde_prefixset	*ps;
833 	struct rde_aspath	*asp;
834 	size_t			 nmemb;
835 	int			 n, fd, rv;
836 	uint16_t		 rid;
837 
838 	while (imsgbuf) {
839 		if ((n = imsg_get(imsgbuf, &imsg)) == -1)
840 			fatal("rde_dispatch_imsg_parent: imsg_get error");
841 		if (n == 0)
842 			break;
843 
844 		switch (imsg_get_type(&imsg)) {
845 		case IMSG_SOCKET_CONN:
846 		case IMSG_SOCKET_CONN_CTL:
847 		case IMSG_SOCKET_CONN_RTR:
848 			if ((fd = imsg_get_fd(&imsg)) == -1) {
849 				log_warnx("expected to receive imsg fd "
850 				    "but didn't receive any");
851 				break;
852 			}
853 			if ((i = malloc(sizeof(struct imsgbuf))) == NULL)
854 				fatal(NULL);
855 			if (imsgbuf_init(i, fd) == -1 ||
856 			    imsgbuf_set_maxsize(i, MAX_BGPD_IMSGSIZE) == -1)
857 				fatal(NULL);
858 			switch (imsg_get_type(&imsg)) {
859 			case IMSG_SOCKET_CONN:
860 				if (ibuf_se) {
861 					log_warnx("Unexpected imsg connection "
862 					    "to SE received");
863 					imsgbuf_clear(ibuf_se);
864 					free(ibuf_se);
865 				}
866 				ibuf_se = i;
867 				break;
868 			case IMSG_SOCKET_CONN_CTL:
869 				if (ibuf_se_ctl) {
870 					log_warnx("Unexpected imsg ctl "
871 					    "connection to SE received");
872 					imsgbuf_clear(ibuf_se_ctl);
873 					free(ibuf_se_ctl);
874 				}
875 				ibuf_se_ctl = i;
876 				break;
877 			case IMSG_SOCKET_CONN_RTR:
878 				if (ibuf_rtr) {
879 					log_warnx("Unexpected imsg ctl "
880 					    "connection to ROA received");
881 					imsgbuf_clear(ibuf_rtr);
882 					free(ibuf_rtr);
883 				}
884 				ibuf_rtr = i;
885 				break;
886 			}
887 			break;
888 		case IMSG_NETWORK_ADD:
889 			if (imsg_get_data(&imsg, &netconf_p,
890 			    sizeof(netconf_p)) == -1) {
891 				log_warnx("rde_dispatch: wrong imsg len");
892 				break;
893 			}
894 			TAILQ_INIT(&netconf_p.attrset);
895 			break;
896 		case IMSG_NETWORK_DONE:
897 			TAILQ_CONCAT(&netconf_p.attrset, &parent_set, entry);
898 
899 			rde_filterstate_init(&state);
900 			asp = &state.aspath;
901 			asp->aspath = aspath_get(NULL, 0);
902 			asp->origin = ORIGIN_IGP;
903 			asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
904 			    F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED;
905 
906 			network_add(&netconf_p, &state);
907 			rde_filterstate_clean(&state);
908 			break;
909 		case IMSG_NETWORK_REMOVE:
910 			if (imsg_get_data(&imsg, &netconf_p,
911 			    sizeof(netconf_p)) == -1) {
912 				log_warnx("rde_dispatch: wrong imsg len");
913 				break;
914 			}
915 			TAILQ_INIT(&netconf_p.attrset);
916 			network_delete(&netconf_p);
917 			break;
918 		case IMSG_FLOWSPEC_ADD:
919 			if (curflow != NULL) {
920 				log_warnx("rde_dispatch: "
921 				    "unexpected flowspec add");
922 				break;
923 			}
924 			if (imsg_get_ibuf(&imsg, &ibuf) == -1 ||
925 			    ibuf_size(&ibuf) <= FLOWSPEC_SIZE) {
926 				log_warnx("rde_dispatch: wrong imsg len");
927 				break;
928 			}
929 			curflow = malloc(ibuf_size(&ibuf));
930 			if (curflow == NULL)
931 				fatal(NULL);
932 			memcpy(curflow, ibuf_data(&ibuf), ibuf_size(&ibuf));
933 			if (curflow->len + FLOWSPEC_SIZE != ibuf_size(&ibuf)) {
934 				free(curflow);
935 				curflow = NULL;
936 				log_warnx("rde_dispatch: wrong flowspec len");
937 				break;
938 			}
939 			break;
940 		case IMSG_FLOWSPEC_DONE:
941 			if (curflow == NULL) {
942 				log_warnx("rde_dispatch: "
943 				    "unexpected flowspec done");
944 				break;
945 			}
946 
947 			rde_filterstate_init(&state);
948 			asp = &state.aspath;
949 			asp->aspath = aspath_get(NULL, 0);
950 			asp->origin = ORIGIN_IGP;
951 			asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
952 			    F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED;
953 
954 			if (flowspec_valid(curflow->data, curflow->len,
955 			    curflow->aid == AID_FLOWSPECv6) == -1)
956 				log_warnx("invalid flowspec update received "
957 				    "from parent");
958 			else
959 				flowspec_add(curflow, &state, &parent_set);
960 
961 			rde_filterstate_clean(&state);
962 			filterset_free(&parent_set);
963 			free(curflow);
964 			curflow = NULL;
965 			break;
966 		case IMSG_FLOWSPEC_REMOVE:
967 			if (curflow != NULL) {
968 				log_warnx("rde_dispatch: "
969 				    "unexpected flowspec remove");
970 				break;
971 			}
972 			if (imsg_get_ibuf(&imsg, &ibuf) == -1 ||
973 			    ibuf_size(&ibuf) <= FLOWSPEC_SIZE) {
974 				log_warnx("rde_dispatch: wrong imsg len");
975 				break;
976 			}
977 			curflow = malloc(ibuf_size(&ibuf));
978 			if (curflow == NULL)
979 				fatal(NULL);
980 			memcpy(curflow, ibuf_data(&ibuf), ibuf_size(&ibuf));
981 			if (curflow->len + FLOWSPEC_SIZE != ibuf_size(&ibuf)) {
982 				free(curflow);
983 				curflow = NULL;
984 				log_warnx("rde_dispatch: wrong flowspec len");
985 				break;
986 			}
987 
988 			if (flowspec_valid(curflow->data, curflow->len,
989 			    curflow->aid == AID_FLOWSPECv6) == -1)
990 				log_warnx("invalid flowspec withdraw received "
991 				    "from parent");
992 			else
993 				flowspec_delete(curflow);
994 
995 			free(curflow);
996 			curflow = NULL;
997 			break;
998 		case IMSG_RECONF_CONF:
999 			if (imsg_get_data(&imsg, &tconf, sizeof(tconf)) == -1)
1000 				fatalx("IMSG_RECONF_CONF bad len");
1001 			out_rules_tmp = calloc(1, sizeof(struct filter_head));
1002 			if (out_rules_tmp == NULL)
1003 				fatal(NULL);
1004 			TAILQ_INIT(out_rules_tmp);
1005 			nconf = new_config();
1006 			copy_config(nconf, &tconf);
1007 
1008 			for (rid = 0; rid < rib_size; rid++) {
1009 				if ((rib = rib_byid(rid)) == NULL)
1010 					continue;
1011 				rib->state = RECONF_DELETE;
1012 				rib->fibstate = RECONF_NONE;
1013 			}
1014 			break;
1015 		case IMSG_RECONF_RIB:
1016 			if (imsg_get_data(&imsg, &rr, sizeof(rr)) == -1)
1017 				fatalx("IMSG_RECONF_RIB bad len");
1018 			rib = rib_byid(rib_find(rr.name));
1019 			if (rib == NULL) {
1020 				rib = rib_new(rr.name, rr.rtableid, rr.flags);
1021 			} else if (rib->flags == rr.flags &&
1022 			    rib->rtableid == rr.rtableid) {
1023 				/* no change to rib apart from filters */
1024 				rib->state = RECONF_KEEP;
1025 			} else {
1026 				/* reload rib because something changed */
1027 				rib->flags_tmp = rr.flags;
1028 				rib->rtableid_tmp = rr.rtableid;
1029 				rib->state = RECONF_RELOAD;
1030 			}
1031 			break;
1032 		case IMSG_RECONF_FILTER:
1033 			if ((r = malloc(sizeof(struct filter_rule))) == NULL)
1034 				fatal(NULL);
1035 			if (imsg_get_data(&imsg, r, sizeof(*r)) == -1)
1036 				fatalx("IMSG_RECONF_FILTER bad len");
1037 			if (r->match.prefixset.name[0] != '\0') {
1038 				r->match.prefixset.ps =
1039 				    rde_find_prefixset(r->match.prefixset.name,
1040 					&nconf->rde_prefixsets);
1041 				if (r->match.prefixset.ps == NULL)
1042 					log_warnx("%s: no prefixset for %s",
1043 					    __func__, r->match.prefixset.name);
1044 			}
1045 			if (r->match.originset.name[0] != '\0') {
1046 				r->match.originset.ps =
1047 				    rde_find_prefixset(r->match.originset.name,
1048 					&nconf->rde_originsets);
1049 				if (r->match.originset.ps == NULL)
1050 					log_warnx("%s: no origin-set for %s",
1051 					    __func__, r->match.originset.name);
1052 			}
1053 			if (r->match.as.flags & AS_FLAG_AS_SET_NAME) {
1054 				struct as_set * aset;
1055 
1056 				aset = as_sets_lookup(&nconf->as_sets,
1057 				    r->match.as.name);
1058 				if (aset == NULL) {
1059 					log_warnx("%s: no as-set for %s",
1060 					    __func__, r->match.as.name);
1061 				} else {
1062 					r->match.as.flags = AS_FLAG_AS_SET;
1063 					r->match.as.aset = aset;
1064 				}
1065 			}
1066 			TAILQ_INIT(&r->set);
1067 			TAILQ_CONCAT(&r->set, &parent_set, entry);
1068 			if ((rib = rib_byid(rib_find(r->rib))) == NULL) {
1069 				log_warnx("IMSG_RECONF_FILTER: filter rule "
1070 				    "for nonexistent rib %s", r->rib);
1071 				filterset_free(&r->set);
1072 				free(r);
1073 				break;
1074 			}
1075 			r->peer.ribid = rib->id;
1076 			if (r->dir == DIR_IN) {
1077 				nr = rib->in_rules_tmp;
1078 				if (nr == NULL) {
1079 					nr = calloc(1,
1080 					    sizeof(struct filter_head));
1081 					if (nr == NULL)
1082 						fatal(NULL);
1083 					TAILQ_INIT(nr);
1084 					rib->in_rules_tmp = nr;
1085 				}
1086 				TAILQ_INSERT_TAIL(nr, r, entry);
1087 			} else {
1088 				TAILQ_INSERT_TAIL(out_rules_tmp, r, entry);
1089 			}
1090 			break;
1091 		case IMSG_RECONF_PREFIX_SET:
1092 		case IMSG_RECONF_ORIGIN_SET:
1093 			ps = calloc(1, sizeof(struct rde_prefixset));
1094 			if (ps == NULL)
1095 				fatal(NULL);
1096 			if (imsg_get_data(&imsg, ps->name, sizeof(ps->name)) ==
1097 			    -1)
1098 				fatalx("IMSG_RECONF_PREFIX_SET bad len");
1099 			if (imsg_get_type(&imsg) == IMSG_RECONF_ORIGIN_SET) {
1100 				SIMPLEQ_INSERT_TAIL(&nconf->rde_originsets, ps,
1101 				    entry);
1102 			} else {
1103 				SIMPLEQ_INSERT_TAIL(&nconf->rde_prefixsets, ps,
1104 				    entry);
1105 			}
1106 			last_prefixset = ps;
1107 			break;
1108 		case IMSG_RECONF_ROA_ITEM:
1109 			if (imsg_get_data(&imsg, &roa, sizeof(roa)) == -1)
1110 				fatalx("IMSG_RECONF_ROA_ITEM bad len");
1111 			rv = trie_roa_add(&last_prefixset->th, &roa);
1112 			break;
1113 		case IMSG_RECONF_PREFIX_SET_ITEM:
1114 			if (imsg_get_data(&imsg, &psi, sizeof(psi)) == -1)
1115 				fatalx("IMSG_RECONF_PREFIX_SET_ITEM bad len");
1116 			if (last_prefixset == NULL)
1117 				fatalx("King Bula has no prefixset");
1118 			rv = trie_add(&last_prefixset->th,
1119 			    &psi.p.addr, psi.p.len,
1120 			    psi.p.len_min, psi.p.len_max);
1121 			if (rv == -1)
1122 				log_warnx("trie_add(%s) %s/%u failed",
1123 				    last_prefixset->name, log_addr(&psi.p.addr),
1124 				    psi.p.len);
1125 			break;
1126 		case IMSG_RECONF_AS_SET:
1127 			if (imsg_get_ibuf(&imsg, &ibuf) == -1 ||
1128 			    ibuf_get(&ibuf, &nmemb, sizeof(nmemb)) == -1 ||
1129 			    ibuf_get(&ibuf, name, sizeof(name)) == -1)
1130 				fatalx("IMSG_RECONF_AS_SET bad len");
1131 			if (as_sets_lookup(&nconf->as_sets, name) != NULL)
1132 				fatalx("duplicate as-set %s", name);
1133 			last_as_set = as_sets_new(&nconf->as_sets, name, nmemb,
1134 			    sizeof(uint32_t));
1135 			break;
1136 		case IMSG_RECONF_AS_SET_ITEMS:
1137 			if (imsg_get_ibuf(&imsg, &ibuf) == -1 ||
1138 			    ibuf_size(&ibuf) == 0 ||
1139 			    ibuf_size(&ibuf) % sizeof(uint32_t) != 0)
1140 				fatalx("IMSG_RECONF_AS_SET_ITEMS bad len");
1141 			nmemb = ibuf_size(&ibuf) / sizeof(uint32_t);
1142 			if (set_add(last_as_set->set, ibuf_data(&ibuf),
1143 			    nmemb) != 0)
1144 				fatal(NULL);
1145 			break;
1146 		case IMSG_RECONF_AS_SET_DONE:
1147 			set_prep(last_as_set->set);
1148 			last_as_set = NULL;
1149 			break;
1150 		case IMSG_RECONF_VPN:
1151 			if ((vpn = malloc(sizeof(*vpn))) == NULL)
1152 				fatal(NULL);
1153 			if (imsg_get_data(&imsg, vpn, sizeof(*vpn)) == -1)
1154 				fatalx("IMSG_RECONF_VPN bad len");
1155 			TAILQ_INIT(&vpn->import);
1156 			TAILQ_INIT(&vpn->export);
1157 			TAILQ_INIT(&vpn->net_l);
1158 			SIMPLEQ_INSERT_TAIL(&nconf->l3vpns, vpn, entry);
1159 			break;
1160 		case IMSG_RECONF_VPN_EXPORT:
1161 			if (vpn == NULL) {
1162 				log_warnx("rde_dispatch_imsg_parent: "
1163 				    "IMSG_RECONF_VPN_EXPORT unexpected");
1164 				break;
1165 			}
1166 			TAILQ_CONCAT(&vpn->export, &parent_set, entry);
1167 			break;
1168 		case IMSG_RECONF_VPN_IMPORT:
1169 			if (vpn == NULL) {
1170 				log_warnx("rde_dispatch_imsg_parent: "
1171 				    "IMSG_RECONF_VPN_IMPORT unexpected");
1172 				break;
1173 			}
1174 			TAILQ_CONCAT(&vpn->import, &parent_set, entry);
1175 			break;
1176 		case IMSG_RECONF_VPN_DONE:
1177 			break;
1178 		case IMSG_RECONF_DRAIN:
1179 			imsg_compose(ibuf_main, IMSG_RECONF_DRAIN, 0, 0,
1180 			    -1, NULL, 0);
1181 			break;
1182 		case IMSG_RECONF_DONE:
1183 			if (nconf == NULL)
1184 				fatalx("got IMSG_RECONF_DONE but no config");
1185 			last_prefixset = NULL;
1186 
1187 			rde_reload_done();
1188 			break;
1189 		case IMSG_NEXTHOP_UPDATE:
1190 			if (imsg_get_data(&imsg, &knext, sizeof(knext)) == -1)
1191 				fatalx("IMSG_NEXTHOP_UPDATE bad len");
1192 			nexthop_update(&knext);
1193 			break;
1194 		case IMSG_FILTER_SET:
1195 			if ((s = malloc(sizeof(*s))) == NULL)
1196 				fatal(NULL);
1197 			if (imsg_get_data(&imsg, s, sizeof(*s)) == -1)
1198 				fatalx("IMSG_FILTER_SET bad len");
1199 			if (s->type == ACTION_SET_NEXTHOP) {
1200 				s->action.nh_ref =
1201 				    nexthop_get(&s->action.nexthop);
1202 				s->type = ACTION_SET_NEXTHOP_REF;
1203 			}
1204 			TAILQ_INSERT_TAIL(&parent_set, s, entry);
1205 			break;
1206 		case IMSG_MRT_OPEN:
1207 		case IMSG_MRT_REOPEN:
1208 			if (imsg_get_data(&imsg, &xmrt, sizeof(xmrt)) == -1) {
1209 				log_warnx("wrong imsg len");
1210 				break;
1211 			}
1212 			if ((fd = imsg_get_fd(&imsg)) == -1)
1213 				log_warnx("expected to receive fd for mrt dump "
1214 				    "but didn't receive any");
1215 			else if (xmrt.type == MRT_TABLE_DUMP ||
1216 			    xmrt.type == MRT_TABLE_DUMP_MP ||
1217 			    xmrt.type == MRT_TABLE_DUMP_V2) {
1218 				rde_dump_mrt_new(&xmrt, imsg_get_pid(&imsg),
1219 				    fd);
1220 			} else
1221 				close(fd);
1222 			break;
1223 		case IMSG_MRT_CLOSE:
1224 			/* ignore end message because a dump is atomic */
1225 			break;
1226 		default:
1227 			fatalx("unhandled IMSG %u", imsg_get_type(&imsg));
1228 		}
1229 		imsg_free(&imsg);
1230 	}
1231 }
1232 
1233 void
rde_dispatch_imsg_rtr(struct imsgbuf * imsgbuf)1234 rde_dispatch_imsg_rtr(struct imsgbuf *imsgbuf)
1235 {
1236 	static struct aspa_set	*aspa;
1237 	struct imsg		 imsg;
1238 	struct roa		 roa;
1239 	struct aspa_prep	 ap;
1240 	int			 n;
1241 
1242 	while (imsgbuf) {
1243 		if ((n = imsg_get(imsgbuf, &imsg)) == -1)
1244 			fatal("rde_dispatch_imsg_parent: imsg_get error");
1245 		if (n == 0)
1246 			break;
1247 
1248 		switch (imsg_get_type(&imsg)) {
1249 		case IMSG_RECONF_ROA_SET:
1250 			/* start of update */
1251 			trie_free(&roa_new.th);	/* clear new roa */
1252 			break;
1253 		case IMSG_RECONF_ROA_ITEM:
1254 			if (imsg_get_data(&imsg, &roa, sizeof(roa)) == -1)
1255 				fatalx("IMSG_RECONF_ROA_ITEM bad len");
1256 			if (trie_roa_add(&roa_new.th, &roa) != 0) {
1257 #if defined(__GNUC__) && __GNUC__ < 4
1258 				struct bgpd_addr p = {
1259 					.aid = roa.aid
1260 				};
1261 				p.v6 = roa.prefix.inet6;
1262 #else
1263 				struct bgpd_addr p = {
1264 					.aid = roa.aid,
1265 					.v6 = roa.prefix.inet6
1266 				};
1267 #endif
1268 				log_warnx("trie_roa_add %s/%u failed",
1269 				    log_addr(&p), roa.prefixlen);
1270 			}
1271 			break;
1272 		case IMSG_RECONF_ASPA_PREP:
1273 			if (imsg_get_data(&imsg, &ap, sizeof(ap)) == -1)
1274 				fatalx("IMSG_RECONF_ASPA_PREP bad len");
1275 			if (aspa_new)
1276 				fatalx("unexpected IMSG_RECONF_ASPA_PREP");
1277 			aspa_new = aspa_table_prep(ap.entries, ap.datasize);
1278 			break;
1279 		case IMSG_RECONF_ASPA:
1280 			if (aspa_new == NULL)
1281 				fatalx("unexpected IMSG_RECONF_ASPA");
1282 			if (aspa != NULL)
1283 				fatalx("IMSG_RECONF_ASPA already sent");
1284 			if ((aspa = calloc(1, sizeof(*aspa))) == NULL)
1285 				fatal("IMSG_RECONF_ASPA");
1286 			if (imsg_get_data(&imsg, aspa,
1287 			    offsetof(struct aspa_set, tas)) == -1)
1288 				fatal("IMSG_RECONF_ASPA bad len");
1289 			break;
1290 		case IMSG_RECONF_ASPA_TAS:
1291 			if (aspa == NULL)
1292 				fatalx("unexpected IMSG_RECONF_ASPA_TAS");
1293 			aspa->tas = reallocarray(NULL, aspa->num,
1294 			    sizeof(uint32_t));
1295 			if (aspa->tas == NULL)
1296 				fatal("IMSG_RECONF_ASPA_TAS");
1297 			if (imsg_get_data(&imsg, aspa->tas,
1298 			    aspa->num * sizeof(uint32_t)) == -1)
1299 				fatal("IMSG_RECONF_ASPA_TAS bad len");
1300 			break;
1301 		case IMSG_RECONF_ASPA_DONE:
1302 			if (aspa_new == NULL)
1303 				fatalx("unexpected IMSG_RECONF_ASPA");
1304 			aspa_add_set(aspa_new, aspa->as, aspa->tas,
1305 			    aspa->num);
1306 			free_aspa(aspa);
1307 			aspa = NULL;
1308 			break;
1309 		case IMSG_RECONF_DONE:
1310 			/* end of update */
1311 			if (rde_roa_reload() + rde_aspa_reload() != 0)
1312 				rde_rpki_reload();
1313 			break;
1314 		}
1315 		imsg_free(&imsg);
1316 	}
1317 }
1318 
1319 void
rde_dispatch_imsg_peer(struct rde_peer * peer,void * bula)1320 rde_dispatch_imsg_peer(struct rde_peer *peer, void *bula)
1321 {
1322 	struct route_refresh rr;
1323 	struct imsg imsg;
1324 	struct ibuf ibuf;
1325 
1326 	if (!peer_is_up(peer)) {
1327 		peer_imsg_flush(peer);
1328 		return;
1329 	}
1330 
1331 	if (!peer_imsg_pop(peer, &imsg))
1332 		return;
1333 
1334 	switch (imsg_get_type(&imsg)) {
1335 	case IMSG_UPDATE:
1336 		if (imsg_get_ibuf(&imsg, &ibuf) == -1)
1337 			log_warn("update: bad imsg");
1338 		else
1339 			rde_update_dispatch(peer, &ibuf);
1340 		break;
1341 	case IMSG_REFRESH:
1342 		if (imsg_get_data(&imsg, &rr, sizeof(rr)) == -1) {
1343 			log_warnx("route refresh: wrong imsg len");
1344 			break;
1345 		}
1346 		if (rr.aid < AID_MIN || rr.aid >= AID_MAX) {
1347 			log_peer_warnx(&peer->conf,
1348 			    "route refresh: bad AID %d", rr.aid);
1349 			break;
1350 		}
1351 		if (peer->capa.mp[rr.aid] == 0) {
1352 			log_peer_warnx(&peer->conf,
1353 			    "route refresh: AID %s not negotiated",
1354 			    aid2str(rr.aid));
1355 			break;
1356 		}
1357 		switch (rr.subtype) {
1358 		case ROUTE_REFRESH_REQUEST:
1359 			peer_blast(peer, rr.aid);
1360 			break;
1361 		case ROUTE_REFRESH_BEGIN_RR:
1362 			/* check if graceful restart EOR was received */
1363 			if ((peer->recv_eor & (1 << rr.aid)) == 0) {
1364 				log_peer_warnx(&peer->conf,
1365 				    "received %s BoRR before EoR",
1366 				    aid2str(rr.aid));
1367 				break;
1368 			}
1369 			peer_begin_rrefresh(peer, rr.aid);
1370 			break;
1371 		case ROUTE_REFRESH_END_RR:
1372 			if ((peer->recv_eor & (1 << rr.aid)) != 0 &&
1373 			    peer->staletime[rr.aid])
1374 				peer_flush(peer, rr.aid,
1375 				    peer->staletime[rr.aid]);
1376 			else
1377 				log_peer_warnx(&peer->conf,
1378 				    "received unexpected %s EoRR",
1379 				    aid2str(rr.aid));
1380 			break;
1381 		default:
1382 			log_peer_warnx(&peer->conf,
1383 			    "route refresh: bad subtype %d", rr.subtype);
1384 			break;
1385 		}
1386 		break;
1387 	default:
1388 		log_warnx("%s: unhandled imsg type %d", __func__,
1389 		    imsg_get_type(&imsg));
1390 		break;
1391 	}
1392 
1393 	imsg_free(&imsg);
1394 }
1395 
1396 /* handle routing updates from the session engine. */
1397 void
rde_update_dispatch(struct rde_peer * peer,struct ibuf * buf)1398 rde_update_dispatch(struct rde_peer *peer, struct ibuf *buf)
1399 {
1400 	struct filterstate	 state;
1401 	struct bgpd_addr	 prefix;
1402 	struct ibuf		 wdbuf, attrbuf, nlribuf, reachbuf, unreachbuf;
1403 	uint16_t		 afi, len;
1404 	uint8_t			 aid, prefixlen, safi, subtype;
1405 	uint32_t		 fas, pathid;
1406 
1407 	if (ibuf_get_n16(buf, &len) == -1 ||
1408 	    ibuf_get_ibuf(buf, len, &wdbuf) == -1 ||
1409 	    ibuf_get_n16(buf, &len) == -1 ||
1410 	    ibuf_get_ibuf(buf, len, &attrbuf) == -1 ||
1411 	    ibuf_get_ibuf(buf, ibuf_size(buf), &nlribuf) == -1) {
1412 		rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL);
1413 		return;
1414 	}
1415 
1416 	if (ibuf_size(&attrbuf) == 0) {
1417 		/* 0 = no NLRI information in this message */
1418 		if (ibuf_size(&nlribuf) != 0) {
1419 			/* crap at end of update which should not be there */
1420 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST,
1421 			    NULL);
1422 			return;
1423 		}
1424 		if (ibuf_size(&wdbuf) == 0) {
1425 			/* EoR marker */
1426 			rde_peer_recv_eor(peer, AID_INET);
1427 			return;
1428 		}
1429 	}
1430 
1431 	ibuf_from_buffer(&reachbuf, NULL, 0);
1432 	ibuf_from_buffer(&unreachbuf, NULL, 0);
1433 	rde_filterstate_init(&state);
1434 	if (ibuf_size(&attrbuf) != 0) {
1435 		/* parse path attributes */
1436 		while (ibuf_size(&attrbuf) > 0) {
1437 			if (rde_attr_parse(&attrbuf, peer, &state, &reachbuf,
1438 			    &unreachbuf) == -1)
1439 				goto done;
1440 		}
1441 
1442 		/* check for missing but necessary attributes */
1443 		if ((subtype = rde_attr_missing(&state.aspath, peer->conf.ebgp,
1444 		    ibuf_size(&nlribuf)))) {
1445 			struct ibuf sbuf;
1446 			ibuf_from_buffer(&sbuf, &subtype, sizeof(subtype));
1447 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,
1448 			    &sbuf);
1449 			goto done;
1450 		}
1451 
1452 		rde_as4byte_fixup(peer, &state.aspath);
1453 
1454 		/* enforce remote AS if requested */
1455 		if (state.aspath.flags & F_ATTR_ASPATH &&
1456 		    peer->conf.enforce_as == ENFORCE_AS_ON) {
1457 			fas = aspath_neighbor(state.aspath.aspath);
1458 			if (peer->conf.remote_as != fas) {
1459 				log_peer_warnx(&peer->conf, "bad path, "
1460 				    "starting with %s expected %u, "
1461 				    "enforce neighbor-as enabled",
1462 				    log_as(fas), peer->conf.remote_as);
1463 				rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
1464 				    NULL);
1465 				goto done;
1466 			}
1467 		}
1468 
1469 		/* aspath needs to be loop free. This is not a hard error. */
1470 		if (state.aspath.flags & F_ATTR_ASPATH &&
1471 		    peer->conf.ebgp &&
1472 		    peer->conf.enforce_local_as == ENFORCE_AS_ON &&
1473 		    !aspath_loopfree(state.aspath.aspath, peer->conf.local_as))
1474 			state.aspath.flags |= F_ATTR_LOOP;
1475 
1476 		rde_reflector(peer, &state.aspath);
1477 
1478 		/* Cache aspa lookup for all updates from ebgp sessions. */
1479 		if (state.aspath.flags & F_ATTR_ASPATH && peer->conf.ebgp) {
1480 			aspa_validation(rde_aspa, state.aspath.aspath,
1481 			    &state.aspath.aspa_state);
1482 			state.aspath.aspa_generation = rde_aspa_generation;
1483 		}
1484 	}
1485 
1486 	/* withdraw prefix */
1487 	if (ibuf_size(&wdbuf) > 0) {
1488 		if (peer->capa.mp[AID_INET] == 0) {
1489 			log_peer_warnx(&peer->conf,
1490 			    "bad withdraw, %s disabled", aid2str(AID_INET));
1491 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
1492 			    NULL);
1493 			goto done;
1494 		}
1495 	}
1496 	while (ibuf_size(&wdbuf) > 0) {
1497 		if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
1498 			if (ibuf_get_n32(&wdbuf, &pathid) == -1) {
1499 				log_peer_warnx(&peer->conf,
1500 				    "bad withdraw prefix");
1501 				rde_update_err(peer, ERR_UPDATE,
1502 				    ERR_UPD_NETWORK, NULL);
1503 				goto done;
1504 			}
1505 		} else
1506 			pathid = 0;
1507 
1508 		if (nlri_get_prefix(&wdbuf, &prefix, &prefixlen) == -1) {
1509 			/*
1510 			 * the RFC does not mention what we should do in
1511 			 * this case. Let's do the same as in the NLRI case.
1512 			 */
1513 			log_peer_warnx(&peer->conf, "bad withdraw prefix");
1514 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
1515 			    NULL);
1516 			goto done;
1517 		}
1518 
1519 		rde_update_withdraw(peer, pathid, &prefix, prefixlen);
1520 	}
1521 
1522 	/* withdraw MP_UNREACH_NLRI if available */
1523 	if (ibuf_size(&unreachbuf) != 0) {
1524 		if (ibuf_get_n16(&unreachbuf, &afi) == -1 ||
1525 		    ibuf_get_n8(&unreachbuf, &safi) == -1 ||
1526 		    afi2aid(afi, safi, &aid) == -1) {
1527 			log_peer_warnx(&peer->conf,
1528 			    "bad AFI/SAFI pair in withdraw");
1529 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1530 			    &unreachbuf);
1531 			goto done;
1532 		}
1533 
1534 		if (peer->capa.mp[aid] == 0) {
1535 			log_peer_warnx(&peer->conf,
1536 			    "bad withdraw, %s disabled", aid2str(aid));
1537 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1538 			    &unreachbuf);
1539 			goto done;
1540 		}
1541 
1542 		if ((state.aspath.flags & ~F_ATTR_MP_UNREACH) == 0 &&
1543 		    ibuf_size(&unreachbuf) == 0) {
1544 			/* EoR marker */
1545 			rde_peer_recv_eor(peer, aid);
1546 		}
1547 
1548 		while (ibuf_size(&unreachbuf) > 0) {
1549 			if (peer_has_add_path(peer, aid, CAPA_AP_RECV)) {
1550 				if (ibuf_get_n32(&unreachbuf,
1551 				    &pathid) == -1) {
1552 					log_peer_warnx(&peer->conf,
1553 					    "bad %s withdraw prefix",
1554 					    aid2str(aid));
1555 					rde_update_err(peer, ERR_UPDATE,
1556 					    ERR_UPD_OPTATTR, &unreachbuf);
1557 					goto done;
1558 				}
1559 			} else
1560 				pathid = 0;
1561 
1562 			switch (aid) {
1563 			case AID_INET:
1564 				log_peer_warnx(&peer->conf,
1565 				    "bad MP withdraw for %s", aid2str(aid));
1566 				rde_update_err(peer, ERR_UPDATE,
1567 				    ERR_UPD_OPTATTR, &unreachbuf);
1568 				goto done;
1569 			case AID_INET6:
1570 				if (nlri_get_prefix6(&unreachbuf,
1571 				    &prefix, &prefixlen) == -1) {
1572 					log_peer_warnx(&peer->conf,
1573 					    "bad IPv6 withdraw prefix");
1574 					rde_update_err(peer, ERR_UPDATE,
1575 					    ERR_UPD_OPTATTR, &unreachbuf);
1576 					goto done;
1577 				}
1578 				break;
1579 			case AID_VPN_IPv4:
1580 				if (nlri_get_vpn4(&unreachbuf,
1581 				    &prefix, &prefixlen, 1) == -1) {
1582 					log_peer_warnx(&peer->conf,
1583 					    "bad VPNv4 withdraw prefix");
1584 					rde_update_err(peer, ERR_UPDATE,
1585 					    ERR_UPD_OPTATTR, &unreachbuf);
1586 					goto done;
1587 				}
1588 				break;
1589 			case AID_VPN_IPv6:
1590 				if (nlri_get_vpn6(&unreachbuf,
1591 				    &prefix, &prefixlen, 1) == -1) {
1592 					log_peer_warnx(&peer->conf,
1593 					    "bad VPNv6 withdraw prefix");
1594 					rde_update_err(peer, ERR_UPDATE,
1595 					    ERR_UPD_OPTATTR, &unreachbuf);
1596 					goto done;
1597 				}
1598 				break;
1599 			case AID_EVPN:
1600 				if (nlri_get_evpn(&unreachbuf,
1601 				    &prefix, &prefixlen) == -1) {
1602 					log_peer_warnx(&peer->conf,
1603 					    "bad EVPN withdraw prefix");
1604 					rde_update_err(peer, ERR_UPDATE,
1605 					    ERR_UPD_OPTATTR, &unreachbuf);
1606 					goto done;
1607 				}
1608 				break;
1609 			case AID_FLOWSPECv4:
1610 			case AID_FLOWSPECv6:
1611 				/* ignore flowspec for now */
1612 			default:
1613 				/* ignore unsupported multiprotocol AF */
1614 				if (ibuf_skip(&unreachbuf,
1615 				    ibuf_size(&unreachbuf)) == -1) {
1616 					log_peer_warnx(&peer->conf,
1617 					    "bad withdraw prefix");
1618 					rde_update_err(peer, ERR_UPDATE,
1619 					    ERR_UPD_OPTATTR, &unreachbuf);
1620 					goto done;
1621 				}
1622 				continue;
1623 			}
1624 
1625 			rde_update_withdraw(peer, pathid, &prefix, prefixlen);
1626 		}
1627 
1628 		if ((state.aspath.flags & ~F_ATTR_MP_UNREACH) == 0)
1629 			goto done;
1630 	}
1631 
1632 	/* parse nlri prefix */
1633 	if (ibuf_size(&nlribuf) > 0) {
1634 		if (peer->capa.mp[AID_INET] == 0) {
1635 			log_peer_warnx(&peer->conf,
1636 			    "bad update, %s disabled", aid2str(AID_INET));
1637 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
1638 			    NULL);
1639 			goto done;
1640 		}
1641 
1642 		/* inject open policy OTC attribute if needed */
1643 		if ((state.aspath.flags & F_ATTR_OTC) == 0) {
1644 			uint32_t tmp;
1645 			switch (peer->role) {
1646 			case ROLE_CUSTOMER:
1647 			case ROLE_RS_CLIENT:
1648 			case ROLE_PEER:
1649 				tmp = htonl(peer->conf.remote_as);
1650 				if (attr_optadd(&state.aspath,
1651 				    ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_OTC,
1652 				    &tmp, sizeof(tmp)) == -1) {
1653 					rde_update_err(peer, ERR_UPDATE,
1654 					    ERR_UPD_ATTRLIST, NULL);
1655 					goto done;
1656 				}
1657 				state.aspath.flags |= F_ATTR_OTC;
1658 				break;
1659 			default:
1660 				break;
1661 			}
1662 		}
1663 	}
1664 	while (ibuf_size(&nlribuf) > 0) {
1665 		if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
1666 			if (ibuf_get_n32(&nlribuf, &pathid) == -1) {
1667 				log_peer_warnx(&peer->conf,
1668 				    "bad nlri prefix");
1669 				rde_update_err(peer, ERR_UPDATE,
1670 				    ERR_UPD_NETWORK, NULL);
1671 				goto done;
1672 			}
1673 		} else
1674 			pathid = 0;
1675 
1676 		if (nlri_get_prefix(&nlribuf, &prefix, &prefixlen) == -1) {
1677 			log_peer_warnx(&peer->conf, "bad nlri prefix");
1678 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
1679 			    NULL);
1680 			goto done;
1681 		}
1682 
1683 		if (rde_update_update(peer, pathid, &state,
1684 		    &prefix, prefixlen) == -1)
1685 			goto done;
1686 	}
1687 
1688 	/* add MP_REACH_NLRI if available */
1689 	if (ibuf_size(&reachbuf) != 0) {
1690 		if (ibuf_get_n16(&reachbuf, &afi) == -1 ||
1691 		    ibuf_get_n8(&reachbuf, &safi) == -1 ||
1692 		    afi2aid(afi, safi, &aid) == -1) {
1693 			log_peer_warnx(&peer->conf,
1694 			    "bad AFI/SAFI pair in update");
1695 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1696 			    &reachbuf);
1697 			goto done;
1698 		}
1699 
1700 		if (peer->capa.mp[aid] == 0) {
1701 			log_peer_warnx(&peer->conf,
1702 			    "bad update, %s disabled", aid2str(aid));
1703 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1704 			    &reachbuf);
1705 			goto done;
1706 		}
1707 
1708 		if (aid == AID_INET6 || aid == AID_INET) {
1709 			/* inject open policy OTC attribute if needed */
1710 			if ((state.aspath.flags & F_ATTR_OTC) == 0) {
1711 				uint32_t tmp;
1712 				switch (peer->role) {
1713 				case ROLE_CUSTOMER:
1714 				case ROLE_RS_CLIENT:
1715 				case ROLE_PEER:
1716 					tmp = htonl(peer->conf.remote_as);
1717 					if (attr_optadd(&state.aspath,
1718 					    ATTR_OPTIONAL|ATTR_TRANSITIVE,
1719 					    ATTR_OTC, &tmp,
1720 					    sizeof(tmp)) == -1) {
1721 						rde_update_err(peer, ERR_UPDATE,
1722 						    ERR_UPD_ATTRLIST, NULL);
1723 						goto done;
1724 					}
1725 					state.aspath.flags |= F_ATTR_OTC;
1726 					break;
1727 				default:
1728 					break;
1729 				}
1730 			}
1731 		} else {
1732 			/* Only IPv4 and IPv6 unicast do OTC handling */
1733 			state.aspath.flags &= ~F_ATTR_OTC_LEAK;
1734 		}
1735 
1736 		/* unlock the previously locked nexthop, it is no longer used */
1737 		nexthop_unref(state.nexthop);
1738 		state.nexthop = NULL;
1739 		if (rde_get_mp_nexthop(&reachbuf, aid, peer, &state) == -1) {
1740 			log_peer_warnx(&peer->conf, "bad nlri nexthop");
1741 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
1742 			    &reachbuf);
1743 			goto done;
1744 		}
1745 
1746 		while (ibuf_size(&reachbuf) > 0) {
1747 			if (peer_has_add_path(peer, aid, CAPA_AP_RECV)) {
1748 				if (ibuf_get_n32(&reachbuf, &pathid) == -1) {
1749 					log_peer_warnx(&peer->conf,
1750 					    "bad %s nlri prefix", aid2str(aid));
1751 					rde_update_err(peer, ERR_UPDATE,
1752 					    ERR_UPD_OPTATTR, &reachbuf);
1753 					goto done;
1754 				}
1755 			} else
1756 				pathid = 0;
1757 
1758 			switch (aid) {
1759 			case AID_INET:
1760 				/*
1761 				 * rde_get_mp_nexthop already enforces that
1762 				 * this is only used for RFC 8950.
1763 				 */
1764 				if (nlri_get_prefix(&reachbuf,
1765 				    &prefix, &prefixlen) == -1) {
1766 					log_peer_warnx(&peer->conf,
1767 					    "bad IPv4 MP nlri prefix");
1768 					rde_update_err(peer, ERR_UPDATE,
1769 					    ERR_UPD_OPTATTR, &reachbuf);
1770 					goto done;
1771 				}
1772 				break;
1773 			case AID_INET6:
1774 				if (nlri_get_prefix6(&reachbuf,
1775 				    &prefix, &prefixlen) == -1) {
1776 					log_peer_warnx(&peer->conf,
1777 					    "bad IPv6 nlri prefix");
1778 					rde_update_err(peer, ERR_UPDATE,
1779 					    ERR_UPD_OPTATTR, &reachbuf);
1780 					goto done;
1781 				}
1782 				break;
1783 			case AID_VPN_IPv4:
1784 				if (nlri_get_vpn4(&reachbuf,
1785 				    &prefix, &prefixlen, 0) == -1) {
1786 					log_peer_warnx(&peer->conf,
1787 					    "bad VPNv4 nlri prefix");
1788 					rde_update_err(peer, ERR_UPDATE,
1789 					    ERR_UPD_OPTATTR, &reachbuf);
1790 					goto done;
1791 				}
1792 				break;
1793 			case AID_VPN_IPv6:
1794 				if (nlri_get_vpn6(&reachbuf,
1795 				    &prefix, &prefixlen, 0) == -1) {
1796 					log_peer_warnx(&peer->conf,
1797 					    "bad VPNv6 nlri prefix");
1798 					rde_update_err(peer, ERR_UPDATE,
1799 					    ERR_UPD_OPTATTR, &reachbuf);
1800 					goto done;
1801 				}
1802 				break;
1803 			case AID_EVPN:
1804 				if (nlri_get_evpn(&reachbuf,
1805 				    &prefix, &prefixlen) == -1) {
1806 					log_peer_warnx(&peer->conf,
1807 					    "bad EVPN nlri prefix");
1808 					rde_update_err(peer, ERR_UPDATE,
1809 					    ERR_UPD_OPTATTR, &reachbuf);
1810 					goto done;
1811 				}
1812 				break;
1813 			case AID_FLOWSPECv4:
1814 			case AID_FLOWSPECv6:
1815 				/* ignore flowspec for now */
1816 			default:
1817 				/* ignore unsupported multiprotocol AF */
1818 				if (ibuf_skip(&reachbuf,
1819 				    ibuf_size(&reachbuf)) == -1) {
1820 					log_peer_warnx(&peer->conf,
1821 					    "bad nlri prefix");
1822 					rde_update_err(peer, ERR_UPDATE,
1823 					    ERR_UPD_OPTATTR, &reachbuf);
1824 					goto done;
1825 				}
1826 				continue;
1827 			}
1828 
1829 			if (rde_update_update(peer, pathid, &state,
1830 			    &prefix, prefixlen) == -1)
1831 				goto done;
1832 		}
1833 	}
1834 
1835 done:
1836 	rde_filterstate_clean(&state);
1837 }
1838 
1839 /*
1840  * Check if path_id is already in use.
1841  */
1842 static int
pathid_conflict(struct rib_entry * re,uint32_t pathid)1843 pathid_conflict(struct rib_entry *re, uint32_t pathid)
1844 {
1845 	struct prefix *p;
1846 
1847 	if (re == NULL)
1848 		return 0;
1849 
1850 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib)
1851 		if (p->path_id_tx == pathid)
1852 			return 1;
1853 	return 0;
1854 }
1855 
1856 /*
1857  * Assign a send side path_id to all paths.
1858  */
1859 static uint32_t
pathid_assign(struct rde_peer * peer,uint32_t path_id,struct bgpd_addr * prefix,uint8_t prefixlen)1860 pathid_assign(struct rde_peer *peer, uint32_t path_id,
1861     struct bgpd_addr *prefix, uint8_t prefixlen)
1862 {
1863 	struct rib_entry *re;
1864 	uint32_t path_id_tx;
1865 
1866 	/* If peer has no add-path use the per peer path_id */
1867 	if (!peer_has_add_path(peer, prefix->aid, CAPA_AP_RECV))
1868 		return peer->path_id_tx;
1869 
1870 	/* peer uses add-path, therefore new path_ids need to be assigned */
1871 	re = rib_get_addr(rib_byid(RIB_ADJ_IN), prefix, prefixlen);
1872 	if (re != NULL) {
1873 		struct prefix *p;
1874 
1875 		p = prefix_bypeer(re, peer, path_id);
1876 		if (p != NULL)
1877 			return p->path_id_tx;
1878 	}
1879 
1880 	/*
1881 	 * Assign new local path_id, must be an odd number.
1882 	 * Even numbers are used by the per peer path_id_tx.
1883 	 */
1884 	do {
1885 		path_id_tx = arc4random() | 1;
1886 	} while (pathid_conflict(re, path_id_tx));
1887 
1888 	return path_id_tx;
1889 }
1890 
1891 int
rde_update_update(struct rde_peer * peer,uint32_t path_id,struct filterstate * in,struct bgpd_addr * prefix,uint8_t prefixlen)1892 rde_update_update(struct rde_peer *peer, uint32_t path_id,
1893     struct filterstate *in, struct bgpd_addr *prefix, uint8_t prefixlen)
1894 {
1895 	struct filterstate	 state;
1896 	enum filter_actions	 action;
1897 	uint32_t		 path_id_tx;
1898 	uint16_t		 i;
1899 	uint8_t			 roa_state, aspa_state;
1900 	const char		*wmsg = "filtered, withdraw";
1901 
1902 	peer->stats.prefix_rcvd_update++;
1903 
1904 	roa_state = rde_roa_validity(&rde_roa, prefix, prefixlen,
1905 	    aspath_origin(in->aspath.aspath));
1906 	aspa_state = rde_aspa_validity(peer, &in->aspath, prefix->aid);
1907 	rde_filterstate_set_vstate(in, roa_state, aspa_state);
1908 
1909 	path_id_tx = pathid_assign(peer, path_id, prefix, prefixlen);
1910 	/* add original path to the Adj-RIB-In */
1911 	if (prefix_update(rib_byid(RIB_ADJ_IN), peer, path_id, path_id_tx,
1912 	    in, 0, prefix, prefixlen) == 1)
1913 		peer->stats.prefix_cnt++;
1914 
1915 	/* max prefix checker */
1916 	if (peer->conf.max_prefix &&
1917 	    peer->stats.prefix_cnt > peer->conf.max_prefix) {
1918 		log_peer_warnx(&peer->conf, "prefix limit reached (>%u/%u)",
1919 		    peer->stats.prefix_cnt, peer->conf.max_prefix);
1920 		rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX, NULL);
1921 		return (-1);
1922 	}
1923 
1924 	if (in->aspath.flags & F_ATTR_PARSE_ERR)
1925 		wmsg = "path invalid, withdraw";
1926 
1927 	for (i = RIB_LOC_START; i < rib_size; i++) {
1928 		struct rib *rib = rib_byid(i);
1929 		if (rib == NULL)
1930 			continue;
1931 		rde_filterstate_copy(&state, in);
1932 		/* input filter */
1933 		action = rde_filter(rib->in_rules, peer, peer, prefix,
1934 		    prefixlen, &state);
1935 
1936 		if (action == ACTION_ALLOW) {
1937 			rde_update_log("update", i, peer,
1938 			    &state.nexthop->exit_nexthop, prefix,
1939 			    prefixlen);
1940 			prefix_update(rib, peer, path_id, path_id_tx, &state,
1941 			    0, prefix, prefixlen);
1942 		} else if (conf->filtered_in_locrib && i == RIB_LOC_START) {
1943 			rde_update_log(wmsg, i, peer, NULL, prefix, prefixlen);
1944 			prefix_update(rib, peer, path_id, path_id_tx, &state,
1945 			    1, prefix, prefixlen);
1946 		} else {
1947 			if (prefix_withdraw(rib, peer, path_id, prefix,
1948 			    prefixlen))
1949 				rde_update_log(wmsg, i, peer,
1950 				    NULL, prefix, prefixlen);
1951 		}
1952 
1953 		rde_filterstate_clean(&state);
1954 	}
1955 	return (0);
1956 }
1957 
1958 void
rde_update_withdraw(struct rde_peer * peer,uint32_t path_id,struct bgpd_addr * prefix,uint8_t prefixlen)1959 rde_update_withdraw(struct rde_peer *peer, uint32_t path_id,
1960     struct bgpd_addr *prefix, uint8_t prefixlen)
1961 {
1962 	uint16_t i;
1963 
1964 	for (i = RIB_LOC_START; i < rib_size; i++) {
1965 		struct rib *rib = rib_byid(i);
1966 		if (rib == NULL)
1967 			continue;
1968 		if (prefix_withdraw(rib, peer, path_id, prefix, prefixlen))
1969 			rde_update_log("withdraw", i, peer, NULL, prefix,
1970 			    prefixlen);
1971 	}
1972 
1973 	/* remove original path form the Adj-RIB-In */
1974 	if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peer, path_id,
1975 	    prefix, prefixlen))
1976 		peer->stats.prefix_cnt--;
1977 
1978 	peer->stats.prefix_rcvd_withdraw++;
1979 }
1980 
1981 /*
1982  * BGP UPDATE parser functions
1983  */
1984 
1985 /* attribute parser specific macros */
1986 #define CHECK_FLAGS(s, t, m)	\
1987 	(((s) & ~(ATTR_DEFMASK | (m))) == (t))
1988 
1989 int
rde_attr_parse(struct ibuf * buf,struct rde_peer * peer,struct filterstate * state,struct ibuf * reach,struct ibuf * unreach)1990 rde_attr_parse(struct ibuf *buf, struct rde_peer *peer,
1991     struct filterstate *state, struct ibuf *reach, struct ibuf *unreach)
1992 {
1993 	struct bgpd_addr nexthop;
1994 	struct rde_aspath *a = &state->aspath;
1995 	struct ibuf	 attrbuf, tmpbuf, *npath = NULL;
1996 	size_t		 alen, hlen;
1997 	uint32_t	 tmp32, zero = 0;
1998 	int		 error;
1999 	uint8_t		 flags, type;
2000 
2001 	ibuf_from_ibuf(&attrbuf, buf);
2002 	if (ibuf_get_n8(&attrbuf, &flags) == -1 ||
2003 	    ibuf_get_n8(&attrbuf, &type) == -1)
2004 		goto bad_list;
2005 
2006 	if (flags & ATTR_EXTLEN) {
2007 		uint16_t attr_len;
2008 		if (ibuf_get_n16(&attrbuf, &attr_len) == -1)
2009 			goto bad_list;
2010 		alen = attr_len;
2011 		hlen = 4;
2012 	} else {
2013 		uint8_t attr_len;
2014 		if (ibuf_get_n8(&attrbuf, &attr_len) == -1)
2015 			goto bad_list;
2016 		alen = attr_len;
2017 		hlen = 3;
2018 	}
2019 
2020 	if (ibuf_truncate(&attrbuf, alen) == -1)
2021 		goto bad_list;
2022 	/* consume the attribute in buf before moving forward */
2023 	if (ibuf_skip(buf, hlen + alen) == -1)
2024 		goto bad_list;
2025 
2026 	switch (type) {
2027 	case ATTR_UNDEF:
2028 		/* ignore and drop path attributes with a type code of 0 */
2029 		break;
2030 	case ATTR_ORIGIN:
2031 		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
2032 			goto bad_flags;
2033 		if (ibuf_size(&attrbuf) != 1)
2034 			goto bad_len;
2035 		if (a->flags & F_ATTR_ORIGIN)
2036 			goto bad_list;
2037 		if (ibuf_get_n8(&attrbuf, &a->origin) == -1)
2038 			goto bad_len;
2039 		if (a->origin > ORIGIN_INCOMPLETE) {
2040 			/*
2041 			 * mark update as bad and withdraw all routes as per
2042 			 * RFC 7606
2043 			 */
2044 			a->flags |= F_ATTR_PARSE_ERR;
2045 			log_peer_warnx(&peer->conf, "bad ORIGIN %u, "
2046 			    "path invalidated and prefix withdrawn",
2047 			    a->origin);
2048 			return (-1);
2049 		}
2050 		a->flags |= F_ATTR_ORIGIN;
2051 		break;
2052 	case ATTR_ASPATH:
2053 		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
2054 			goto bad_flags;
2055 		if (a->flags & F_ATTR_ASPATH)
2056 			goto bad_list;
2057 		error = aspath_verify(&attrbuf, peer_has_as4byte(peer),
2058 		    peer_permit_as_set(peer));
2059 		if (error != 0 && error != AS_ERR_SOFT) {
2060 			log_peer_warnx(&peer->conf, "bad ASPATH, %s",
2061 			    log_aspath_error(error));
2062 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
2063 			    NULL);
2064 			return (-1);
2065 		}
2066 		if (peer_has_as4byte(peer)) {
2067 			ibuf_from_ibuf(&tmpbuf, &attrbuf);
2068 		} else {
2069 			if ((npath = aspath_inflate(&attrbuf)) == NULL)
2070 				fatal("aspath_inflate");
2071 			ibuf_from_ibuf(&tmpbuf, npath);
2072 		}
2073 		if (error == AS_ERR_SOFT) {
2074 			char *str;
2075 
2076 			/*
2077 			 * soft errors like unexpected segment types are
2078 			 * not considered fatal and the path is just
2079 			 * marked invalid.
2080 			 */
2081 			a->flags |= F_ATTR_PARSE_ERR;
2082 
2083 			aspath_asprint(&str, &tmpbuf);
2084 			log_peer_warnx(&peer->conf, "bad ASPATH %s, "
2085 			    "path invalidated and prefix withdrawn",
2086 			    str ? str : "(bad aspath)");
2087 			free(str);
2088 		}
2089 		a->flags |= F_ATTR_ASPATH;
2090 		a->aspath = aspath_get(ibuf_data(&tmpbuf), ibuf_size(&tmpbuf));
2091 		ibuf_free(npath);
2092 		break;
2093 	case ATTR_NEXTHOP:
2094 		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
2095 			goto bad_flags;
2096 		if (ibuf_size(&attrbuf) != 4)
2097 			goto bad_len;
2098 		if (a->flags & F_ATTR_NEXTHOP)
2099 			goto bad_list;
2100 		a->flags |= F_ATTR_NEXTHOP;
2101 
2102 		memset(&nexthop, 0, sizeof(nexthop));
2103 		nexthop.aid = AID_INET;
2104 		if (ibuf_get_h32(&attrbuf, &nexthop.v4.s_addr) == -1)
2105 			goto bad_len;
2106 		/*
2107 		 * Check if the nexthop is a valid IP address. We consider
2108 		 * multicast addresses as invalid.
2109 		 */
2110 		tmp32 = ntohl(nexthop.v4.s_addr);
2111 		if (IN_MULTICAST(tmp32)) {
2112 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_NEXTHOP,
2113 			    &attrbuf);
2114 			return (-1);
2115 		}
2116 		nexthop_unref(state->nexthop);	/* just to be sure */
2117 		state->nexthop = nexthop_get(&nexthop);
2118 		break;
2119 	case ATTR_MED:
2120 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
2121 			goto bad_flags;
2122 		if (ibuf_size(&attrbuf) != 4)
2123 			goto bad_len;
2124 		if (a->flags & F_ATTR_MED)
2125 			goto bad_list;
2126 		if (ibuf_get_n32(&attrbuf, &a->med) == -1)
2127 			goto bad_len;
2128 		a->flags |= F_ATTR_MED;
2129 		break;
2130 	case ATTR_LOCALPREF:
2131 		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
2132 			goto bad_flags;
2133 		if (ibuf_size(&attrbuf) != 4)
2134 			goto bad_len;
2135 		if (peer->conf.ebgp) {
2136 			/* ignore local-pref attr on non ibgp peers */
2137 			break;
2138 		}
2139 		if (a->flags & F_ATTR_LOCALPREF)
2140 			goto bad_list;
2141 		if (ibuf_get_n32(&attrbuf, &a->lpref) == -1)
2142 			goto bad_len;
2143 		a->flags |= F_ATTR_LOCALPREF;
2144 		break;
2145 	case ATTR_ATOMIC_AGGREGATE:
2146 		if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
2147 			goto bad_flags;
2148 		if (ibuf_size(&attrbuf) != 0)
2149 			goto bad_len;
2150 		goto optattr;
2151 	case ATTR_AGGREGATOR:
2152 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
2153 		    ATTR_PARTIAL))
2154 			goto bad_flags;
2155 		if ((!peer_has_as4byte(peer) && ibuf_size(&attrbuf) != 6) ||
2156 		    (peer_has_as4byte(peer) && ibuf_size(&attrbuf) != 8)) {
2157 			/*
2158 			 * ignore attribute in case of error as per
2159 			 * RFC 7606
2160 			 */
2161 			log_peer_warnx(&peer->conf, "bad AGGREGATOR, "
2162 			    "attribute discarded");
2163 			break;
2164 		}
2165 		if (!peer_has_as4byte(peer)) {
2166 			/* need to inflate aggregator AS to 4-byte */
2167 			u_char	t[8];
2168 			t[0] = t[1] = 0;
2169 			if (ibuf_get(&attrbuf, &t[2], 6) == -1)
2170 				goto bad_list;
2171 			if (memcmp(t, &zero, sizeof(uint32_t)) == 0) {
2172 				/* As per RFC7606 use "attribute discard". */
2173 				log_peer_warnx(&peer->conf, "bad AGGREGATOR, "
2174 				    "AS 0 not allowed, attribute discarded");
2175 				break;
2176 			}
2177 			if (attr_optadd(a, flags, type, t, sizeof(t)) == -1)
2178 				goto bad_list;
2179 			break;
2180 		}
2181 		/* 4-byte ready server take the default route */
2182 		ibuf_from_ibuf(&tmpbuf, &attrbuf);
2183 		if (ibuf_get_n32(&tmpbuf, &tmp32) == -1)
2184 			goto bad_len;
2185 		if (tmp32 == 0) {
2186 			/* As per RFC7606 use "attribute discard" here. */
2187 			char *pfmt = log_fmt_peer(&peer->conf);
2188 			log_debug("%s: bad AGGREGATOR, "
2189 			    "AS 0 not allowed, attribute discarded", pfmt);
2190 			free(pfmt);
2191 			break;
2192 		}
2193 		goto optattr;
2194 	case ATTR_COMMUNITIES:
2195 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
2196 		    ATTR_PARTIAL))
2197 			goto bad_flags;
2198 		if (community_add(&state->communities, flags,
2199 		    &attrbuf) == -1) {
2200 			/*
2201 			 * mark update as bad and withdraw all routes as per
2202 			 * RFC 7606
2203 			 */
2204 			a->flags |= F_ATTR_PARSE_ERR;
2205 			log_peer_warnx(&peer->conf, "bad COMMUNITIES, "
2206 			    "path invalidated and prefix withdrawn");
2207 		}
2208 		break;
2209 	case ATTR_LARGE_COMMUNITIES:
2210 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
2211 		    ATTR_PARTIAL))
2212 			goto bad_flags;
2213 		if (community_large_add(&state->communities, flags,
2214 		    &attrbuf) == -1) {
2215 			/*
2216 			 * mark update as bad and withdraw all routes as per
2217 			 * RFC 7606
2218 			 */
2219 			a->flags |= F_ATTR_PARSE_ERR;
2220 			log_peer_warnx(&peer->conf, "bad LARGE COMMUNITIES, "
2221 			    "path invalidated and prefix withdrawn");
2222 		}
2223 		break;
2224 	case ATTR_EXT_COMMUNITIES:
2225 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
2226 		    ATTR_PARTIAL))
2227 			goto bad_flags;
2228 		if (community_ext_add(&state->communities, flags,
2229 		    peer->conf.ebgp, &attrbuf) == -1) {
2230 			/*
2231 			 * mark update as bad and withdraw all routes as per
2232 			 * RFC 7606
2233 			 */
2234 			a->flags |= F_ATTR_PARSE_ERR;
2235 			log_peer_warnx(&peer->conf, "bad EXT_COMMUNITIES, "
2236 			    "path invalidated and prefix withdrawn");
2237 		}
2238 		break;
2239 	case ATTR_ORIGINATOR_ID:
2240 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
2241 			goto bad_flags;
2242 		if (ibuf_size(&attrbuf) != 4)
2243 			goto bad_len;
2244 		goto optattr;
2245 	case ATTR_CLUSTER_LIST:
2246 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
2247 			goto bad_flags;
2248 		if (peer->conf.ebgp) {
2249 			/* As per RFC7606 use "attribute discard" here. */
2250 			log_peer_warnx(&peer->conf, "bad CLUSTER_LIST, "
2251 			    "received from external peer, attribute discarded");
2252 			break;
2253 		}
2254 		if (ibuf_size(&attrbuf) % 4 != 0 || ibuf_size(&attrbuf) == 0) {
2255 			/*
2256 			 * mark update as bad and withdraw all routes as per
2257 			 * RFC 7606
2258 			 */
2259 			a->flags |= F_ATTR_PARSE_ERR;
2260 			log_peer_warnx(&peer->conf, "bad CLUSTER_LIST, "
2261 			    "path invalidated and prefix withdrawn");
2262 			break;
2263 		}
2264 		goto optattr;
2265 	case ATTR_MP_REACH_NLRI:
2266 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
2267 			goto bad_flags;
2268 		if (ibuf_size(&attrbuf) < 5)
2269 			goto bad_len;
2270 		/* the validity is checked in rde_update_dispatch() */
2271 		if (a->flags & F_ATTR_MP_REACH)
2272 			goto bad_list;
2273 		a->flags |= F_ATTR_MP_REACH;
2274 
2275 		*reach = attrbuf;
2276 		break;
2277 	case ATTR_MP_UNREACH_NLRI:
2278 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
2279 			goto bad_flags;
2280 		if (ibuf_size(&attrbuf) < 3)
2281 			goto bad_len;
2282 		/* the validity is checked in rde_update_dispatch() */
2283 		if (a->flags & F_ATTR_MP_UNREACH)
2284 			goto bad_list;
2285 		a->flags |= F_ATTR_MP_UNREACH;
2286 
2287 		*unreach = attrbuf;
2288 		break;
2289 	case ATTR_AS4_AGGREGATOR:
2290 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
2291 		    ATTR_PARTIAL))
2292 			goto bad_flags;
2293 		if (ibuf_size(&attrbuf) != 8) {
2294 			/* see ATTR_AGGREGATOR ... */
2295 			log_peer_warnx(&peer->conf, "bad AS4_AGGREGATOR, "
2296 			    "attribute discarded");
2297 			break;
2298 		}
2299 		ibuf_from_ibuf(&tmpbuf, &attrbuf);
2300 		if (ibuf_get_n32(&tmpbuf, &tmp32) == -1)
2301 			goto bad_len;
2302 		if (tmp32 == 0) {
2303 			/* As per RFC6793 use "attribute discard" here. */
2304 			log_peer_warnx(&peer->conf, "bad AS4_AGGREGATOR, "
2305 			    "AS 0 not allowed, attribute discarded");
2306 			break;
2307 		}
2308 		a->flags |= F_ATTR_AS4BYTE_NEW;
2309 		goto optattr;
2310 	case ATTR_AS4_PATH:
2311 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
2312 		    ATTR_PARTIAL))
2313 			goto bad_flags;
2314 		if ((error = aspath_verify(&attrbuf, 1,
2315 		    peer_permit_as_set(peer))) != 0) {
2316 			/* As per RFC6793 use "attribute discard" here. */
2317 			log_peer_warnx(&peer->conf, "bad AS4_PATH, "
2318 			    "attribute discarded");
2319 			break;
2320 		}
2321 		a->flags |= F_ATTR_AS4BYTE_NEW;
2322 		goto optattr;
2323 	case ATTR_OTC:
2324 		if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
2325 		    ATTR_PARTIAL))
2326 			goto bad_flags;
2327 		if (ibuf_size(&attrbuf) != 4) {
2328 			/* treat-as-withdraw */
2329 			a->flags |= F_ATTR_PARSE_ERR;
2330 			log_peer_warnx(&peer->conf, "bad OTC, "
2331 			    "path invalidated and prefix withdrawn");
2332 			break;
2333 		}
2334 		switch (peer->role) {
2335 		case ROLE_PROVIDER:
2336 		case ROLE_RS:
2337 			a->flags |= F_ATTR_OTC_LEAK;
2338 			break;
2339 		case ROLE_PEER:
2340 			if (ibuf_get_n32(&attrbuf, &tmp32) == -1)
2341 				goto bad_len;
2342 			if (tmp32 != peer->conf.remote_as)
2343 				a->flags |= F_ATTR_OTC_LEAK;
2344 			break;
2345 		default:
2346 			break;
2347 		}
2348 		a->flags |= F_ATTR_OTC;
2349 		goto optattr;
2350 	default:
2351 		if ((flags & ATTR_OPTIONAL) == 0) {
2352 			rde_update_err(peer, ERR_UPDATE, ERR_UPD_UNKNWN_WK_ATTR,
2353 			    &attrbuf);
2354 			return (-1);
2355 		}
2356  optattr:
2357 		if (attr_optadd(a, flags, type, ibuf_data(&attrbuf),
2358 		    ibuf_size(&attrbuf)) == -1)
2359 			goto bad_list;
2360 		break;
2361 	}
2362 
2363 	return (0);
2364 
2365  bad_len:
2366 	rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLEN, &attrbuf);
2367 	return (-1);
2368  bad_flags:
2369 	rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRFLAGS, &attrbuf);
2370 	return (-1);
2371  bad_list:
2372 	rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL);
2373 	return (-1);
2374 }
2375 
2376 #undef CHECK_FLAGS
2377 
2378 int
rde_attr_add(struct filterstate * state,struct ibuf * buf)2379 rde_attr_add(struct filterstate *state, struct ibuf *buf)
2380 {
2381 	uint16_t	 attr_len;
2382 	uint8_t		 flags;
2383 	uint8_t		 type;
2384 	uint8_t		 tmp8;
2385 
2386 	if (ibuf_get_n8(buf, &flags) == -1 ||
2387 	    ibuf_get_n8(buf, &type) == -1)
2388 		return (-1);
2389 
2390 	if (flags & ATTR_EXTLEN) {
2391 		if (ibuf_get_n16(buf, &attr_len) == -1)
2392 			return (-1);
2393 	} else {
2394 		if (ibuf_get_n8(buf, &tmp8) == -1)
2395 			return (-1);
2396 		attr_len = tmp8;
2397 	}
2398 
2399 	if (ibuf_size(buf) != attr_len)
2400 		return (-1);
2401 
2402 	switch (type) {
2403 	case ATTR_COMMUNITIES:
2404 		return community_add(&state->communities, flags, buf);
2405 	case ATTR_LARGE_COMMUNITIES:
2406 		return community_large_add(&state->communities, flags, buf);
2407 	case ATTR_EXT_COMMUNITIES:
2408 		return community_ext_add(&state->communities, flags, 0, buf);
2409 	}
2410 
2411 	if (attr_optadd(&state->aspath, flags, type, ibuf_data(buf),
2412 	    attr_len) == -1)
2413 		return (-1);
2414 	return (0);
2415 }
2416 
2417 uint8_t
rde_attr_missing(struct rde_aspath * a,int ebgp,uint16_t nlrilen)2418 rde_attr_missing(struct rde_aspath *a, int ebgp, uint16_t nlrilen)
2419 {
2420 	/* ATTR_MP_UNREACH_NLRI may be sent alone */
2421 	if (nlrilen == 0 && a->flags & F_ATTR_MP_UNREACH &&
2422 	    (a->flags & F_ATTR_MP_REACH) == 0)
2423 		return (0);
2424 
2425 	if ((a->flags & F_ATTR_ORIGIN) == 0)
2426 		return (ATTR_ORIGIN);
2427 	if ((a->flags & F_ATTR_ASPATH) == 0)
2428 		return (ATTR_ASPATH);
2429 	if ((a->flags & F_ATTR_MP_REACH) == 0 &&
2430 	    (a->flags & F_ATTR_NEXTHOP) == 0)
2431 		return (ATTR_NEXTHOP);
2432 	if (!ebgp)
2433 		if ((a->flags & F_ATTR_LOCALPREF) == 0)
2434 			return (ATTR_LOCALPREF);
2435 	return (0);
2436 }
2437 
2438 int
rde_get_mp_nexthop(struct ibuf * buf,uint8_t aid,struct rde_peer * peer,struct filterstate * state)2439 rde_get_mp_nexthop(struct ibuf *buf, uint8_t aid,
2440     struct rde_peer *peer, struct filterstate *state)
2441 {
2442 	struct bgpd_addr	nexthop;
2443 	struct ibuf		nhbuf;
2444 	uint8_t			nhlen;
2445 
2446 	if (ibuf_get_n8(buf, &nhlen) == -1)
2447 		return (-1);
2448 	if (ibuf_get_ibuf(buf, nhlen, &nhbuf) == -1)
2449 		return (-1);
2450 	/* ignore reserved (old SNPA) field as per RFC4760 */
2451 	if (ibuf_skip(buf, 1) == -1)
2452 		return (-1);
2453 
2454 	if (aid == AID_INET && peer_has_ext_nexthop(peer, AID_INET) &&
2455 	    (nhlen == 16 || nhlen == 32))
2456 		aid = AID_INET6;
2457 	if (aid == AID_VPN_IPv4 && peer_has_ext_nexthop(peer, AID_VPN_IPv4) &&
2458 	    (nhlen == 24 || nhlen == 48))
2459 		aid = AID_VPN_IPv6;
2460 
2461 	memset(&nexthop, 0, sizeof(nexthop));
2462 	switch (aid) {
2463 	case AID_INET:
2464 		log_peer_warnx(&peer->conf, "bad multiprotocol nexthop, "
2465 		    "IPv4 unexpected");
2466 		return (-1);
2467 	case AID_INET6:
2468 		/*
2469 		 * RFC2545 describes that there may be a link-local
2470 		 * address carried in nexthop. Yikes!
2471 		 * This is not only silly, it is wrong and we just ignore
2472 		 * this link-local nexthop. The bgpd session doesn't run
2473 		 * over the link-local address so why should all other
2474 		 * traffic.
2475 		 */
2476 		if (nhlen != 16 && nhlen != 32) {
2477 			log_peer_warnx(&peer->conf, "bad %s nexthop, "
2478 			    "bad size %d", aid2str(aid), nhlen);
2479 			return (-1);
2480 		}
2481 		if (ibuf_get(&nhbuf, &nexthop.v6, sizeof(nexthop.v6)) == -1)
2482 			return (-1);
2483 		nexthop.aid = AID_INET6;
2484 		if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6)) {
2485 			if (peer->local_if_scope != 0) {
2486 				nexthop.scope_id = peer->local_if_scope;
2487 			} else {
2488 				log_peer_warnx(&peer->conf,
2489 				    "unexpected link-local nexthop: %s",
2490 				    log_addr(&nexthop));
2491 				return (-1);
2492 			}
2493 		}
2494 		break;
2495 	case AID_VPN_IPv4:
2496 		/*
2497 		 * Neither RFC4364 nor RFC3107 specify the format of the
2498 		 * nexthop in an explicit way. The quality of RFC went down
2499 		 * the toilet the larger the number got.
2500 		 * RFC4364 is very confusing about VPN-IPv4 address and the
2501 		 * VPN-IPv4 prefix that carries also a MPLS label.
2502 		 * So the nexthop is a 12-byte address with a 64bit RD and
2503 		 * an IPv4 address following. In the nexthop case the RD can
2504 		 * be ignored.
2505 		 * Since the nexthop has to be in the main IPv4 table just
2506 		 * create an AID_INET nexthop. So we don't need to handle
2507 		 * AID_VPN_IPv4 in nexthop and kroute.
2508 		 */
2509 		if (nhlen != 12) {
2510 			log_peer_warnx(&peer->conf, "bad %s nexthop, "
2511 			    "bad size %d", aid2str(aid), nhlen);
2512 			return (-1);
2513 		}
2514 		if (ibuf_skip(&nhbuf, sizeof(uint64_t)) == -1 ||
2515 		    ibuf_get(&nhbuf, &nexthop.v4, sizeof(nexthop.v4)) == -1)
2516 			return (-1);
2517 		nexthop.aid = AID_INET;
2518 		break;
2519 	case AID_VPN_IPv6:
2520 		if (nhlen != 24 && nhlen != 48) {
2521 			log_peer_warnx(&peer->conf, "bad %s nexthop, "
2522 			    "bad size %d", aid2str(aid), nhlen);
2523 			return (-1);
2524 		}
2525 		if (ibuf_skip(&nhbuf, sizeof(uint64_t)) == -1 ||
2526 		    ibuf_get(&nhbuf, &nexthop.v6, sizeof(nexthop.v6)) == -1)
2527 			return (-1);
2528 		nexthop.aid = AID_INET6;
2529 		if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6)) {
2530 			if (peer->local_if_scope != 0) {
2531 				nexthop.scope_id = peer->local_if_scope;
2532 			} else {
2533 				log_peer_warnx(&peer->conf,
2534 				    "unexpected link-local nexthop: %s",
2535 				    log_addr(&nexthop));
2536 				return (-1);
2537 			}
2538 		}
2539 		break;
2540 	case AID_EVPN:
2541 		switch (nhlen) {
2542 		case 4:
2543 			if (ibuf_get_h32(&nhbuf, &nexthop.v4.s_addr) == -1)
2544 				return (-1);
2545 			nexthop.aid = AID_INET;
2546 			break;
2547 		case 16:
2548 		case 32:
2549 			if (ibuf_get(&nhbuf, &nexthop.v6,
2550 			    sizeof(nexthop.v6)) == -1)
2551 				return (-1);
2552 			nexthop.aid = AID_INET6;
2553 			if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6)) {
2554 				if (peer->local_if_scope != 0) {
2555 					nexthop.scope_id = peer->local_if_scope;
2556 				} else {
2557 					log_peer_warnx(&peer->conf,
2558 					    "unexpected link-local nexthop: %s",
2559 					    log_addr(&nexthop));
2560 					return (-1);
2561 				}
2562 			}
2563 			break;
2564 		default:
2565 			log_peer_warnx(&peer->conf, "bad %s nexthop, "
2566 			    "bad size %d", aid2str(aid), nhlen);
2567 			return (-1);
2568 		}
2569 		break;
2570 	case AID_FLOWSPECv4:
2571 	case AID_FLOWSPECv6:
2572 		/* nexthop must be 0 and ignored for flowspec */
2573 		if (nhlen != 0) {
2574 			log_peer_warnx(&peer->conf, "bad %s nexthop, "
2575 			    "bad size %d", aid2str(aid), nhlen);
2576 			return (-1);
2577 		}
2578 		return (0);
2579 	default:
2580 		log_peer_warnx(&peer->conf, "bad multiprotocol nexthop, "
2581 		    "bad AID");
2582 		return (-1);
2583 	}
2584 
2585 	state->nexthop = nexthop_get(&nexthop);
2586 
2587 	return (0);
2588 }
2589 
2590 void
rde_update_err(struct rde_peer * peer,uint8_t error,uint8_t suberr,struct ibuf * opt)2591 rde_update_err(struct rde_peer *peer, uint8_t error, uint8_t suberr,
2592     struct ibuf *opt)
2593 {
2594 	struct ibuf *wbuf;
2595 	size_t size = 0;
2596 
2597 	if (opt != NULL) {
2598 		ibuf_rewind(opt);
2599 		size = ibuf_size(opt);
2600 	}
2601 	if ((wbuf = imsg_create(ibuf_se, IMSG_UPDATE_ERR, peer->conf.id, 0,
2602 	    size + sizeof(error) + sizeof(suberr))) == NULL)
2603 		fatal("%s %d imsg_create error", __func__, __LINE__);
2604 	if (imsg_add(wbuf, &error, sizeof(error)) == -1 ||
2605 	    imsg_add(wbuf, &suberr, sizeof(suberr)) == -1)
2606 		fatal("%s %d imsg_add error", __func__, __LINE__);
2607 	if (opt != NULL)
2608 		if (ibuf_add_ibuf(wbuf, opt) == -1)
2609 			fatal("%s %d ibuf_add_ibuf error", __func__, __LINE__);
2610 	imsg_close(ibuf_se, wbuf);
2611 	peer->state = PEER_ERR;
2612 }
2613 
2614 void
rde_update_log(const char * message,uint16_t rid,const struct rde_peer * peer,const struct bgpd_addr * next,const struct bgpd_addr * prefix,uint8_t prefixlen)2615 rde_update_log(const char *message, uint16_t rid,
2616     const struct rde_peer *peer, const struct bgpd_addr *next,
2617     const struct bgpd_addr *prefix, uint8_t prefixlen)
2618 {
2619 	char		*l = NULL;
2620 	char		*n = NULL;
2621 	char		*p = NULL;
2622 
2623 	if (!((conf->log & BGPD_LOG_UPDATES) ||
2624 	    (peer->flags & PEERFLAG_LOG_UPDATES)))
2625 		return;
2626 
2627 	if (next != NULL)
2628 		if (asprintf(&n, " via %s", log_addr(next)) == -1)
2629 			n = NULL;
2630 	if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
2631 		p = NULL;
2632 	l = log_fmt_peer(&peer->conf);
2633 	log_info("Rib %s: %s AS%s: %s %s%s", rib_byid(rid)->name,
2634 	    l, log_as(peer->conf.remote_as), message,
2635 	    p ? p : "out of memory", n ? n : "");
2636 
2637 	free(l);
2638 	free(n);
2639 	free(p);
2640 }
2641 
2642 /*
2643  * 4-Byte ASN helper function.
2644  * Two scenarios need to be considered:
2645  * - NEW session with NEW attributes present -> just remove the attributes
2646  * - OLD session with NEW attributes present -> try to merge them
2647  */
2648 void
rde_as4byte_fixup(struct rde_peer * peer,struct rde_aspath * a)2649 rde_as4byte_fixup(struct rde_peer *peer, struct rde_aspath *a)
2650 {
2651 	struct attr	*nasp, *naggr, *oaggr;
2652 	uint32_t	 as;
2653 
2654 	/*
2655 	 * if either ATTR_AS4_AGGREGATOR or ATTR_AS4_PATH is present
2656 	 * try to fixup the attributes.
2657 	 * Do not fixup if F_ATTR_PARSE_ERR is set.
2658 	 */
2659 	if (!(a->flags & F_ATTR_AS4BYTE_NEW) || a->flags & F_ATTR_PARSE_ERR)
2660 		return;
2661 
2662 	/* first get the attributes */
2663 	nasp = attr_optget(a, ATTR_AS4_PATH);
2664 	naggr = attr_optget(a, ATTR_AS4_AGGREGATOR);
2665 
2666 	if (peer_has_as4byte(peer)) {
2667 		/* NEW session using 4-byte ASNs */
2668 		if (nasp) {
2669 			log_peer_warnx(&peer->conf, "uses 4-byte ASN "
2670 			    "but sent AS4_PATH attribute.");
2671 			attr_free(a, nasp);
2672 		}
2673 		if (naggr) {
2674 			log_peer_warnx(&peer->conf, "uses 4-byte ASN "
2675 			    "but sent AS4_AGGREGATOR attribute.");
2676 			attr_free(a, naggr);
2677 		}
2678 		return;
2679 	}
2680 	/* OLD session using 2-byte ASNs */
2681 	/* try to merge the new attributes into the old ones */
2682 	if ((oaggr = attr_optget(a, ATTR_AGGREGATOR))) {
2683 		memcpy(&as, oaggr->data, sizeof(as));
2684 		if (ntohl(as) != AS_TRANS) {
2685 			/* per RFC ignore AS4_PATH and AS4_AGGREGATOR */
2686 			if (nasp)
2687 				attr_free(a, nasp);
2688 			if (naggr)
2689 				attr_free(a, naggr);
2690 			return;
2691 		}
2692 		if (naggr) {
2693 			/* switch over to new AGGREGATOR */
2694 			attr_free(a, oaggr);
2695 			if (attr_optadd(a, ATTR_OPTIONAL | ATTR_TRANSITIVE,
2696 			    ATTR_AGGREGATOR, naggr->data, naggr->len))
2697 				fatalx("attr_optadd failed but impossible");
2698 		}
2699 	}
2700 	/* there is no need for AS4_AGGREGATOR any more */
2701 	if (naggr)
2702 		attr_free(a, naggr);
2703 
2704 	/* merge AS4_PATH with ASPATH */
2705 	if (nasp)
2706 		aspath_merge(a, nasp);
2707 }
2708 
2709 
2710 uint8_t
rde_aspa_validity(struct rde_peer * peer,struct rde_aspath * asp,uint8_t aid)2711 rde_aspa_validity(struct rde_peer *peer, struct rde_aspath *asp, uint8_t aid)
2712 {
2713 	if (!peer->conf.ebgp)	/* ASPA is only performed on ebgp sessions */
2714 		return ASPA_NEVER_KNOWN;
2715 	if (aid != AID_INET && aid != AID_INET6) /* skip uncovered aids */
2716 		return ASPA_NEVER_KNOWN;
2717 
2718 #ifdef MAYBE
2719 	/*
2720 	 * By default enforce neighbor-as is set for all ebgp sessions.
2721 	 * So if a admin disables this check should we really "reenable"
2722 	 * it here in such a dubious way?
2723 	 * This just fails the ASPA validation for these paths so maybe
2724 	 * this can be helpful. But it is not transparent to the admin.
2725 	 */
2726 
2727 	/* skip neighbor-as check for transparent RS sessions */
2728 	if (peer->role != ROLE_RS_CLIENT &&
2729 	    peer->conf.enforce_as != ENFORCE_AS_ON) {
2730 		uint32_t fas;
2731 
2732 		fas = aspath_neighbor(asp->aspath);
2733 		if (peer->conf.remote_as != fas)
2734 			return ASPA_INVALID;
2735 	}
2736 #endif
2737 
2738 	/* if no role is set, the outcome is unknown */
2739 	if (peer->role == ROLE_NONE)
2740 		return ASPA_UNKNOWN;
2741 
2742 	if (peer->role == ROLE_CUSTOMER)
2743 		return asp->aspa_state.downup;
2744 	else
2745 		return asp->aspa_state.onlyup;
2746 }
2747 
2748 /*
2749  * route reflector helper function
2750  */
2751 void
rde_reflector(struct rde_peer * peer,struct rde_aspath * asp)2752 rde_reflector(struct rde_peer *peer, struct rde_aspath *asp)
2753 {
2754 	struct attr	*a;
2755 	uint8_t		*p;
2756 	uint16_t	 len;
2757 	uint32_t	 id;
2758 
2759 	/* do not consider updates with parse errors */
2760 	if (asp->flags & F_ATTR_PARSE_ERR)
2761 		return;
2762 
2763 	/* check for originator id if eq router_id drop */
2764 	if ((a = attr_optget(asp, ATTR_ORIGINATOR_ID)) != NULL) {
2765 		id = htonl(conf->bgpid);
2766 		if (memcmp(&id, a->data, sizeof(id)) == 0) {
2767 			/* this is coming from myself */
2768 			asp->flags |= F_ATTR_LOOP;
2769 			return;
2770 		}
2771 	} else if (conf->flags & BGPD_FLAG_REFLECTOR) {
2772 		if (peer->conf.ebgp)
2773 			id = htonl(conf->bgpid);
2774 		else
2775 			id = htonl(peer->remote_bgpid);
2776 		if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_ORIGINATOR_ID,
2777 		    &id, sizeof(id)) == -1)
2778 			fatalx("attr_optadd failed but impossible");
2779 	}
2780 
2781 	/* check for own id in the cluster list */
2782 	if (conf->flags & BGPD_FLAG_REFLECTOR) {
2783 		id = htonl(conf->clusterid);
2784 		if ((a = attr_optget(asp, ATTR_CLUSTER_LIST)) != NULL) {
2785 			for (len = 0; len < a->len; len += sizeof(id))
2786 				/* check if coming from my cluster */
2787 				if (memcmp(&id, a->data + len,
2788 				    sizeof(id)) == 0) {
2789 					asp->flags |= F_ATTR_LOOP;
2790 					return;
2791 				}
2792 
2793 			/* prepend own clusterid by replacing attribute */
2794 			len = a->len + sizeof(id);
2795 			if (len < a->len)
2796 				fatalx("rde_reflector: cluster-list overflow");
2797 			if ((p = malloc(len)) == NULL)
2798 				fatal("rde_reflector");
2799 			memcpy(p, &id, sizeof(id));
2800 			memcpy(p + sizeof(id), a->data, a->len);
2801 			attr_free(asp, a);
2802 			if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_CLUSTER_LIST,
2803 			    p, len) == -1)
2804 				fatalx("attr_optadd failed but impossible");
2805 			free(p);
2806 		} else if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_CLUSTER_LIST,
2807 		    &id, sizeof(id)) == -1)
2808 			fatalx("attr_optadd failed but impossible");
2809 	}
2810 }
2811 
2812 /*
2813  * control specific functions
2814  */
2815 static void
rde_dump_rib_as(struct prefix * p,struct rde_aspath * asp,pid_t pid,int flags,int adjout)2816 rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags,
2817     int adjout)
2818 {
2819 	struct ctl_show_rib	 rib;
2820 	struct ibuf		*wbuf;
2821 	struct attr		*a;
2822 	struct nexthop		*nexthop;
2823 	struct rib_entry	*re;
2824 	struct prefix		*xp;
2825 	struct rde_peer		*peer;
2826 	time_t			 staletime;
2827 	size_t			 aslen;
2828 	uint8_t			 l;
2829 
2830 	nexthop = prefix_nexthop(p);
2831 	peer = prefix_peer(p);
2832 	memset(&rib, 0, sizeof(rib));
2833 	rib.age = getmonotime() - p->lastchange;
2834 	rib.local_pref = asp->lpref;
2835 	rib.med = asp->med;
2836 	rib.weight = asp->weight;
2837 	strlcpy(rib.descr, peer->conf.descr, sizeof(rib.descr));
2838 	memcpy(&rib.remote_addr, &peer->remote_addr,
2839 	    sizeof(rib.remote_addr));
2840 	rib.remote_id = peer->remote_bgpid;
2841 	if (nexthop != NULL) {
2842 		rib.exit_nexthop = nexthop->exit_nexthop;
2843 		rib.true_nexthop = nexthop->true_nexthop;
2844 	} else {
2845 		/* announced network can have a NULL nexthop */
2846 		rib.exit_nexthop.aid = p->pt->aid;
2847 		rib.true_nexthop.aid = p->pt->aid;
2848 	}
2849 	pt_getaddr(p->pt, &rib.prefix);
2850 	rib.prefixlen = p->pt->prefixlen;
2851 	rib.origin = asp->origin;
2852 	rib.roa_validation_state = prefix_roa_vstate(p);
2853 	rib.aspa_validation_state = prefix_aspa_vstate(p);
2854 	rib.dmetric = p->dmetric;
2855 	rib.flags = 0;
2856 	if (!adjout && prefix_eligible(p)) {
2857 		re = prefix_re(p);
2858 		TAILQ_FOREACH(xp, &re->prefix_h, entry.list.rib) {
2859 			switch (xp->dmetric) {
2860 			case PREFIX_DMETRIC_BEST:
2861 				if (xp == p)
2862 					rib.flags |= F_PREF_BEST;
2863 				break;
2864 			case PREFIX_DMETRIC_ECMP:
2865 				if (xp == p)
2866 					rib.flags |= F_PREF_ECMP;
2867 				break;
2868 			case PREFIX_DMETRIC_AS_WIDE:
2869 				if (xp == p)
2870 					rib.flags |= F_PREF_AS_WIDE;
2871 				break;
2872 			default:
2873 				xp = NULL;	/* stop loop */
2874 				break;
2875 			}
2876 			if (xp == NULL || xp == p)
2877 				break;
2878 		}
2879 	}
2880 	if (!peer->conf.ebgp)
2881 		rib.flags |= F_PREF_INTERNAL;
2882 	if (asp->flags & F_PREFIX_ANNOUNCED)
2883 		rib.flags |= F_PREF_ANNOUNCE;
2884 	if (prefix_eligible(p))
2885 		rib.flags |= F_PREF_ELIGIBLE;
2886 	if (prefix_filtered(p))
2887 		rib.flags |= F_PREF_FILTERED;
2888 	/* otc loop includes parse err so skip the latter if the first is set */
2889 	if (asp->flags & F_ATTR_OTC_LEAK)
2890 		rib.flags |= F_PREF_OTC_LEAK;
2891 	else if (asp->flags & F_ATTR_PARSE_ERR)
2892 		rib.flags |= F_PREF_INVALID;
2893 	staletime = peer->staletime[p->pt->aid];
2894 	if (staletime && p->lastchange <= staletime)
2895 		rib.flags |= F_PREF_STALE;
2896 	if (!adjout) {
2897 		if (peer_has_add_path(peer, p->pt->aid, CAPA_AP_RECV)) {
2898 			rib.path_id = p->path_id;
2899 			rib.flags |= F_PREF_PATH_ID;
2900 		}
2901 	} else {
2902 		if (peer_has_add_path(peer, p->pt->aid, CAPA_AP_SEND)) {
2903 			rib.path_id = p->path_id_tx;
2904 			rib.flags |= F_PREF_PATH_ID;
2905 		}
2906 	}
2907 	aslen = aspath_length(asp->aspath);
2908 
2909 	if ((wbuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_RIB, 0, pid,
2910 	    sizeof(rib) + aslen)) == NULL)
2911 		return;
2912 	if (imsg_add(wbuf, &rib, sizeof(rib)) == -1 ||
2913 	    imsg_add(wbuf, aspath_dump(asp->aspath), aslen) == -1)
2914 		return;
2915 	imsg_close(ibuf_se_ctl, wbuf);
2916 
2917 	if (flags & F_CTL_DETAIL) {
2918 		struct rde_community *comm = prefix_communities(p);
2919 		size_t len = comm->nentries * sizeof(struct community);
2920 		if (comm->nentries > 0) {
2921 			if (imsg_compose(ibuf_se_ctl,
2922 			    IMSG_CTL_SHOW_RIB_COMMUNITIES, 0, pid, -1,
2923 			    comm->communities, len) == -1)
2924 				return;
2925 		}
2926 		for (l = 0; l < asp->others_len; l++) {
2927 			if ((a = asp->others[l]) == NULL)
2928 				break;
2929 			if ((wbuf = imsg_create(ibuf_se_ctl,
2930 			    IMSG_CTL_SHOW_RIB_ATTR, 0, pid, 0)) == NULL)
2931 				return;
2932 			if (attr_writebuf(wbuf, a->flags, a->type, a->data,
2933 			    a->len) == -1) {
2934 				ibuf_free(wbuf);
2935 				return;
2936 			}
2937 			imsg_close(ibuf_se_ctl, wbuf);
2938 		}
2939 	}
2940 }
2941 
2942 int
rde_match_peer(struct rde_peer * p,struct ctl_neighbor * n)2943 rde_match_peer(struct rde_peer *p, struct ctl_neighbor *n)
2944 {
2945 	char *s;
2946 
2947 	if (n && n->addr.aid) {
2948 		if (memcmp(&p->conf.remote_addr, &n->addr,
2949 		    sizeof(p->conf.remote_addr)))
2950 			return 0;
2951 	} else if (n && n->descr[0]) {
2952 		s = n->is_group ? p->conf.group : p->conf.descr;
2953 		/* cannot trust n->descr to be properly terminated */
2954 		if (strncmp(s, n->descr, sizeof(n->descr)))
2955 			return 0;
2956 	}
2957 	return 1;
2958 }
2959 
2960 static void
rde_dump_filter(struct prefix * p,struct ctl_show_rib_request * req,int adjout)2961 rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req, int adjout)
2962 {
2963 	struct rde_aspath	*asp;
2964 
2965 	if (!rde_match_peer(prefix_peer(p), &req->neighbor))
2966 		return;
2967 
2968 	asp = prefix_aspath(p);
2969 	if ((req->flags & F_CTL_BEST) && p->dmetric != PREFIX_DMETRIC_BEST)
2970 		return;
2971 	if ((req->flags & F_CTL_INVALID) &&
2972 	    (asp->flags & F_ATTR_PARSE_ERR) == 0)
2973 		return;
2974 	if ((req->flags & F_CTL_FILTERED) && !prefix_filtered(p))
2975 		return;
2976 	if ((req->flags & F_CTL_INELIGIBLE) && prefix_eligible(p))
2977 		return;
2978 	if ((req->flags & F_CTL_LEAKED) &&
2979 	    (asp->flags & F_ATTR_OTC_LEAK) == 0)
2980 		return;
2981 	if ((req->flags & F_CTL_HAS_PATHID)) {
2982 		/* Match against the transmit path id if adjout is used.  */
2983 		if (adjout) {
2984 			if (req->path_id != p->path_id_tx)
2985 				return;
2986 		} else {
2987 			if (req->path_id != p->path_id)
2988 				return;
2989 		}
2990 	}
2991 	if (req->as.type != AS_UNDEF &&
2992 	    !aspath_match(asp->aspath, &req->as, 0))
2993 		return;
2994 	if (req->community.flags != 0) {
2995 		if (!community_match(prefix_communities(p), &req->community,
2996 		    NULL))
2997 			return;
2998 	}
2999 	if (!ovs_match(p, req->flags))
3000 		return;
3001 	if (!avs_match(p, req->flags))
3002 		return;
3003 	rde_dump_rib_as(p, asp, req->pid, req->flags, adjout);
3004 }
3005 
3006 static void
rde_dump_upcall(struct rib_entry * re,void * ptr)3007 rde_dump_upcall(struct rib_entry *re, void *ptr)
3008 {
3009 	struct rde_dump_ctx	*ctx = ptr;
3010 	struct prefix		*p;
3011 
3012 	if (re == NULL)
3013 		return;
3014 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib)
3015 		rde_dump_filter(p, &ctx->req, 0);
3016 }
3017 
3018 static void
rde_dump_adjout_upcall(struct prefix * p,void * ptr)3019 rde_dump_adjout_upcall(struct prefix *p, void *ptr)
3020 {
3021 	struct rde_dump_ctx	*ctx = ptr;
3022 
3023 	if ((p->flags & PREFIX_FLAG_ADJOUT) == 0)
3024 		fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__);
3025 	if (p->flags & (PREFIX_FLAG_WITHDRAW | PREFIX_FLAG_DEAD))
3026 		return;
3027 	rde_dump_filter(p, &ctx->req, 1);
3028 }
3029 
3030 static int
rde_dump_throttled(void * arg)3031 rde_dump_throttled(void *arg)
3032 {
3033 	struct rde_dump_ctx	*ctx = arg;
3034 
3035 	return (ctx->throttled != 0);
3036 }
3037 
3038 static void
rde_dump_done(void * arg,uint8_t aid)3039 rde_dump_done(void *arg, uint8_t aid)
3040 {
3041 	struct rde_dump_ctx	*ctx = arg;
3042 	struct rde_peer		*peer;
3043 	u_int			 error;
3044 
3045 	if (ctx->req.flags & F_CTL_ADJ_OUT) {
3046 		peer = peer_match(&ctx->req.neighbor, ctx->peerid);
3047 		if (peer == NULL)
3048 			goto done;
3049 		ctx->peerid = peer->conf.id;
3050 		switch (ctx->req.type) {
3051 		case IMSG_CTL_SHOW_RIB:
3052 			if (prefix_dump_new(peer, ctx->req.aid,
3053 			    CTL_MSG_HIGH_MARK, ctx, rde_dump_adjout_upcall,
3054 			    rde_dump_done, rde_dump_throttled) == -1)
3055 				goto nomem;
3056 			break;
3057 		case IMSG_CTL_SHOW_RIB_PREFIX:
3058 			if (prefix_dump_subtree(peer, &ctx->req.prefix,
3059 			    ctx->req.prefixlen, CTL_MSG_HIGH_MARK, ctx,
3060 			    rde_dump_adjout_upcall, rde_dump_done,
3061 			    rde_dump_throttled) == -1)
3062 				goto nomem;
3063 			break;
3064 		default:
3065 			fatalx("%s: unsupported imsg type", __func__);
3066 		}
3067 		return;
3068 	}
3069 done:
3070 	imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid, -1, NULL, 0);
3071 	LIST_REMOVE(ctx, entry);
3072 	free(ctx);
3073 	return;
3074 
3075 nomem:
3076 	log_warn(__func__);
3077 	error = CTL_RES_NOMEM;
3078 	imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, ctx->req.pid, -1, &error,
3079 	    sizeof(error));
3080 	return;
3081 }
3082 
3083 void
rde_dump_ctx_new(struct ctl_show_rib_request * req,pid_t pid,enum imsg_type type)3084 rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid,
3085     enum imsg_type type)
3086 {
3087 	struct rde_dump_ctx	*ctx;
3088 	struct rib_entry	*re;
3089 	struct prefix		*p;
3090 	u_int			 error;
3091 	uint8_t			 hostplen, plen;
3092 	uint16_t		 rid;
3093 
3094 	if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
3095  nomem:
3096 		log_warn(__func__);
3097 		error = CTL_RES_NOMEM;
3098 		imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error,
3099 		    sizeof(error));
3100 		free(ctx);
3101 		return;
3102 	}
3103 
3104 	if (strcmp(req->rib, "Adj-RIB-Out") == 0)
3105 		req->flags |= F_CTL_ADJ_OUT;
3106 
3107 	memcpy(&ctx->req, req, sizeof(struct ctl_show_rib_request));
3108 	ctx->req.pid = pid;
3109 	ctx->req.type = type;
3110 
3111 	if (req->flags & (F_CTL_ADJ_IN | F_CTL_INVALID)) {
3112 		rid = RIB_ADJ_IN;
3113 	} else if (req->flags & F_CTL_ADJ_OUT) {
3114 		struct rde_peer *peer;
3115 
3116 		peer = peer_match(&req->neighbor, 0);
3117 		if (peer == NULL) {
3118 			error = CTL_RES_NOSUCHPEER;
3119 			imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1,
3120 			    &error, sizeof(error));
3121 			free(ctx);
3122 			return;
3123 		}
3124 		ctx->peerid = peer->conf.id;
3125 		switch (ctx->req.type) {
3126 		case IMSG_CTL_SHOW_RIB:
3127 			if (prefix_dump_new(peer, ctx->req.aid,
3128 			    CTL_MSG_HIGH_MARK, ctx, rde_dump_adjout_upcall,
3129 			    rde_dump_done, rde_dump_throttled) == -1)
3130 				goto nomem;
3131 			break;
3132 		case IMSG_CTL_SHOW_RIB_PREFIX:
3133 			if (req->flags & F_LONGER) {
3134 				if (prefix_dump_subtree(peer, &req->prefix,
3135 				    req->prefixlen, CTL_MSG_HIGH_MARK, ctx,
3136 				    rde_dump_adjout_upcall,
3137 				    rde_dump_done, rde_dump_throttled) == -1)
3138 					goto nomem;
3139 				break;
3140 			}
3141 			switch (req->prefix.aid) {
3142 			case AID_INET:
3143 			case AID_VPN_IPv4:
3144 				hostplen = 32;
3145 				break;
3146 			case AID_INET6:
3147 			case AID_VPN_IPv6:
3148 				hostplen = 128;
3149 				break;
3150 			default:
3151 				fatalx("%s: unknown af", __func__);
3152 			}
3153 
3154 			do {
3155 				if (req->flags & F_SHORTER) {
3156 					for (plen = 0; plen <= req->prefixlen;
3157 					    plen++) {
3158 						p = prefix_adjout_lookup(peer,
3159 						    &req->prefix, plen);
3160 						/* dump all matching paths */
3161 						while (p != NULL) {
3162 							rde_dump_adjout_upcall(
3163 							    p, ctx);
3164 							p = prefix_adjout_next(
3165 							    peer, p);
3166 						}
3167 					}
3168 					p = NULL;
3169 				} else if (req->prefixlen == hostplen) {
3170 					p = prefix_adjout_match(peer,
3171 					    &req->prefix);
3172 				} else {
3173 					p = prefix_adjout_lookup(peer,
3174 					    &req->prefix, req->prefixlen);
3175 				}
3176 				/* dump all matching paths */
3177 				while (p != NULL) {
3178 					rde_dump_adjout_upcall(p, ctx);
3179 					p = prefix_adjout_next(peer, p);
3180 				}
3181 			} while ((peer = peer_match(&req->neighbor,
3182 			    peer->conf.id)));
3183 
3184 			imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid,
3185 			    -1, NULL, 0);
3186 			free(ctx);
3187 			return;
3188 		default:
3189 			fatalx("%s: unsupported imsg type", __func__);
3190 		}
3191 
3192 		LIST_INSERT_HEAD(&rde_dump_h, ctx, entry);
3193 		return;
3194 	} else if ((rid = rib_find(req->rib)) == RIB_NOTFOUND) {
3195 		log_warnx("%s: no such rib %s", __func__, req->rib);
3196 		error = CTL_RES_NOSUCHRIB;
3197 		imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error,
3198 		    sizeof(error));
3199 		free(ctx);
3200 		return;
3201 	}
3202 
3203 	switch (ctx->req.type) {
3204 	case IMSG_CTL_SHOW_NETWORK:
3205 		if (rib_dump_new(rid, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx,
3206 		    network_dump_upcall, rde_dump_done,
3207 		    rde_dump_throttled) == -1)
3208 			goto nomem;
3209 		break;
3210 	case IMSG_CTL_SHOW_RIB:
3211 		if (rib_dump_new(rid, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx,
3212 		    rde_dump_upcall, rde_dump_done, rde_dump_throttled) == -1)
3213 			goto nomem;
3214 		break;
3215 	case IMSG_CTL_SHOW_RIB_PREFIX:
3216 		if (req->flags & F_LONGER) {
3217 			if (rib_dump_subtree(rid, &req->prefix, req->prefixlen,
3218 			    CTL_MSG_HIGH_MARK, ctx, rde_dump_upcall,
3219 			    rde_dump_done, rde_dump_throttled) == -1)
3220 				goto nomem;
3221 			break;
3222 		}
3223 		switch (req->prefix.aid) {
3224 		case AID_INET:
3225 		case AID_VPN_IPv4:
3226 			hostplen = 32;
3227 			break;
3228 		case AID_INET6:
3229 		case AID_VPN_IPv6:
3230 			hostplen = 128;
3231 			break;
3232 		default:
3233 			fatalx("%s: unknown af", __func__);
3234 		}
3235 
3236 		if (req->flags & F_SHORTER) {
3237 			for (plen = 0; plen <= req->prefixlen; plen++) {
3238 				re = rib_get_addr(rib_byid(rid), &req->prefix,
3239 				    plen);
3240 				rde_dump_upcall(re, ctx);
3241 			}
3242 		} else if (req->prefixlen == hostplen) {
3243 			re = rib_match(rib_byid(rid), &req->prefix);
3244 			rde_dump_upcall(re, ctx);
3245 		} else {
3246 			re = rib_get_addr(rib_byid(rid), &req->prefix,
3247 			    req->prefixlen);
3248 			rde_dump_upcall(re, ctx);
3249 		}
3250 		imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid,
3251 		    -1, NULL, 0);
3252 		free(ctx);
3253 		return;
3254 	default:
3255 		fatalx("%s: unsupported imsg type", __func__);
3256 	}
3257 	LIST_INSERT_HEAD(&rde_dump_h, ctx, entry);
3258 }
3259 
3260 void
rde_dump_ctx_throttle(pid_t pid,int throttle)3261 rde_dump_ctx_throttle(pid_t pid, int throttle)
3262 {
3263 	struct rde_dump_ctx	*ctx;
3264 
3265 	LIST_FOREACH(ctx, &rde_dump_h, entry) {
3266 		if (ctx->req.pid == pid) {
3267 			ctx->throttled = throttle;
3268 			return;
3269 		}
3270 	}
3271 }
3272 
3273 void
rde_dump_ctx_terminate(pid_t pid)3274 rde_dump_ctx_terminate(pid_t pid)
3275 {
3276 	struct rde_dump_ctx	*ctx;
3277 
3278 	LIST_FOREACH(ctx, &rde_dump_h, entry) {
3279 		if (ctx->req.pid == pid) {
3280 			rib_dump_terminate(ctx);
3281 			return;
3282 		}
3283 	}
3284 }
3285 
3286 static int
rde_mrt_throttled(void * arg)3287 rde_mrt_throttled(void *arg)
3288 {
3289 	struct mrt	*mrt = arg;
3290 
3291 	return (msgbuf_queuelen(mrt->wbuf) > SESS_MSG_LOW_MARK);
3292 }
3293 
3294 static void
rde_mrt_done(void * ptr,uint8_t aid)3295 rde_mrt_done(void *ptr, uint8_t aid)
3296 {
3297 	mrt_done(ptr);
3298 }
3299 
3300 void
rde_dump_mrt_new(struct mrt * mrt,pid_t pid,int fd)3301 rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd)
3302 {
3303 	struct rde_mrt_ctx *ctx;
3304 	uint16_t rid;
3305 
3306 	if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
3307 		log_warn("rde_dump_mrt_new");
3308 		return;
3309 	}
3310 	memcpy(&ctx->mrt, mrt, sizeof(struct mrt));
3311 	if ((ctx->mrt.wbuf = msgbuf_new()) == NULL) {
3312 		log_warn("rde_dump_mrt_new");
3313 		free(ctx);
3314 		return;
3315 	}
3316 	ctx->mrt.fd = fd;
3317 	ctx->mrt.state = MRT_STATE_RUNNING;
3318 	rid = rib_find(ctx->mrt.rib);
3319 	if (rid == RIB_NOTFOUND) {
3320 		log_warnx("non existing RIB %s for mrt dump", ctx->mrt.rib);
3321 		free(ctx);
3322 		return;
3323 	}
3324 
3325 	if (ctx->mrt.type == MRT_TABLE_DUMP_V2)
3326 		mrt_dump_v2_hdr(&ctx->mrt, conf);
3327 
3328 	if (rib_dump_new(rid, AID_UNSPEC, CTL_MSG_HIGH_MARK, &ctx->mrt,
3329 	    mrt_dump_upcall, rde_mrt_done, rde_mrt_throttled) == -1)
3330 		fatal("%s: rib_dump_new", __func__);
3331 
3332 	LIST_INSERT_HEAD(&rde_mrts, ctx, entry);
3333 	rde_mrt_cnt++;
3334 }
3335 
3336 /*
3337  * kroute specific functions
3338  */
3339 int
rde_l3vpn_import(struct rde_community * comm,struct l3vpn * rd)3340 rde_l3vpn_import(struct rde_community *comm, struct l3vpn *rd)
3341 {
3342 	struct filter_set	*s;
3343 
3344 	TAILQ_FOREACH(s, &rd->import, entry) {
3345 		if (community_match(comm, &s->action.community, 0))
3346 			return (1);
3347 	}
3348 	return (0);
3349 }
3350 
3351 void
rde_send_kroute_flush(struct rib * rib)3352 rde_send_kroute_flush(struct rib *rib)
3353 {
3354 	if (imsg_compose(ibuf_main, IMSG_KROUTE_FLUSH, rib->rtableid, 0, -1,
3355 	    NULL, 0) == -1)
3356 		fatal("%s %d imsg_compose error", __func__, __LINE__);
3357 }
3358 
3359 void
rde_send_kroute(struct rib * rib,struct prefix * new,struct prefix * old)3360 rde_send_kroute(struct rib *rib, struct prefix *new, struct prefix *old)
3361 {
3362 	struct kroute_full	 kf;
3363 	struct prefix		*p;
3364 	struct l3vpn		*vpn;
3365 	enum imsg_type		 type;
3366 
3367 	/*
3368 	 * Make sure that self announce prefixes are not committed to the
3369 	 * FIB. If both prefixes are unreachable no update is needed.
3370 	 */
3371 	if ((old == NULL || prefix_aspath(old)->flags & F_PREFIX_ANNOUNCED) &&
3372 	    (new == NULL || prefix_aspath(new)->flags & F_PREFIX_ANNOUNCED))
3373 		return;
3374 
3375 	if (new == NULL || prefix_aspath(new)->flags & F_PREFIX_ANNOUNCED) {
3376 		type = IMSG_KROUTE_DELETE;
3377 		p = old;
3378 	} else {
3379 		type = IMSG_KROUTE_CHANGE;
3380 		p = new;
3381 	}
3382 
3383 	memset(&kf, 0, sizeof(kf));
3384 	pt_getaddr(p->pt, &kf.prefix);
3385 	kf.prefixlen = p->pt->prefixlen;
3386 	if (type == IMSG_KROUTE_CHANGE) {
3387 		if (prefix_nhflags(p) == NEXTHOP_REJECT)
3388 			kf.flags |= F_REJECT;
3389 		if (prefix_nhflags(p) == NEXTHOP_BLACKHOLE)
3390 			kf.flags |= F_BLACKHOLE;
3391 		kf.nexthop = prefix_nexthop(p)->exit_nexthop;
3392 		strlcpy(kf.label, rtlabel_id2name(prefix_aspath(p)->rtlabelid),
3393 		    sizeof(kf.label));
3394 	}
3395 
3396 	switch (kf.prefix.aid) {
3397 	case AID_VPN_IPv4:
3398 		/* XXX FIB can not handle non-IPv4 nexthop */
3399 		if (kf.nexthop.aid != AID_INET)
3400 			type = IMSG_KROUTE_DELETE;
3401 		/* FALLTHROUGH */
3402 	case AID_VPN_IPv6:
3403 		if (!(rib->flags & F_RIB_LOCAL))
3404 			/* not Loc-RIB, no update for VPNs */
3405 			break;
3406 
3407 		SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) {
3408 			if (!rde_l3vpn_import(prefix_communities(p), vpn))
3409 				continue;
3410 			/* XXX not ideal but this will change */
3411 			kf.ifindex = if_nametoindex(vpn->ifmpe);
3412 			if (imsg_compose(ibuf_main, type, vpn->rtableid, 0, -1,
3413 			    &kf, sizeof(kf)) == -1)
3414 				fatal("%s %d imsg_compose error", __func__,
3415 				    __LINE__);
3416 		}
3417 		break;
3418 	case AID_INET:
3419 		/* XXX FIB can not handle non-IPv4 nexthop */
3420 		if (kf.nexthop.aid != AID_INET)
3421 			type = IMSG_KROUTE_DELETE;
3422 		/* FALLTHROUGH */
3423 	default:
3424 		if (imsg_compose(ibuf_main, type, rib->rtableid, 0, -1,
3425 		    &kf, sizeof(kf)) == -1)
3426 			fatal("%s %d imsg_compose error", __func__, __LINE__);
3427 		break;
3428 	}
3429 }
3430 
3431 /*
3432  * update specific functions
3433  */
3434 int
rde_evaluate_all(void)3435 rde_evaluate_all(void)
3436 {
3437 	return rde_eval_all;
3438 }
3439 
3440 /* flush Adj-RIB-Out by withdrawing all prefixes */
3441 static void
rde_up_flush_upcall(struct prefix * p,void * ptr)3442 rde_up_flush_upcall(struct prefix *p, void *ptr)
3443 {
3444 	prefix_adjout_withdraw(p);
3445 }
3446 
3447 int
rde_update_queue_pending(void)3448 rde_update_queue_pending(void)
3449 {
3450 	struct rde_peer *peer;
3451 	uint8_t aid;
3452 
3453 	if (ibuf_se && imsgbuf_queuelen(ibuf_se) >= SESS_MSG_HIGH_MARK)
3454 		return 0;
3455 
3456 	RB_FOREACH(peer, peer_tree, &peertable) {
3457 		if (peer->conf.id == 0)
3458 			continue;
3459 		if (!peer_is_up(peer))
3460 			continue;
3461 		if (peer->throttled)
3462 			continue;
3463 		for (aid = AID_MIN; aid < AID_MAX; aid++) {
3464 			if (!RB_EMPTY(&peer->updates[aid]) ||
3465 			    !RB_EMPTY(&peer->withdraws[aid]))
3466 				return 1;
3467 		}
3468 	}
3469 	return 0;
3470 }
3471 
3472 void
rde_update_queue_runner(uint8_t aid)3473 rde_update_queue_runner(uint8_t aid)
3474 {
3475 	struct rde_peer		*peer;
3476 	struct ibuf		*buf;
3477 	int			 sent, max = RDE_RUNNER_ROUNDS;
3478 
3479 	/* first withdraws ... */
3480 	do {
3481 		sent = 0;
3482 		RB_FOREACH(peer, peer_tree, &peertable) {
3483 			if (peer->conf.id == 0)
3484 				continue;
3485 			if (!peer_is_up(peer))
3486 				continue;
3487 			if (peer->throttled)
3488 				continue;
3489 			if (RB_EMPTY(&peer->withdraws[aid]))
3490 				continue;
3491 
3492 			if ((buf = up_dump_withdraws(peer, aid)) == NULL) {
3493 				continue;
3494 			}
3495 			if (imsg_compose_ibuf(ibuf_se, IMSG_UPDATE,
3496 			    peer->conf.id, 0, buf) == -1)
3497 				fatal("%s: imsg_create error", __func__);
3498 			sent++;
3499 		}
3500 		max -= sent;
3501 	} while (sent != 0 && max > 0);
3502 
3503 	/* ... then updates */
3504 	max = RDE_RUNNER_ROUNDS;
3505 	do {
3506 		sent = 0;
3507 		RB_FOREACH(peer, peer_tree, &peertable) {
3508 			if (peer->conf.id == 0)
3509 				continue;
3510 			if (!peer_is_up(peer))
3511 				continue;
3512 			if (peer->throttled)
3513 				continue;
3514 			if (RB_EMPTY(&peer->updates[aid]))
3515 				continue;
3516 
3517 			if (up_is_eor(peer, aid)) {
3518 				int sent_eor = peer->sent_eor & (1 << aid);
3519 				if (peer->capa.grestart.restart && !sent_eor)
3520 					rde_peer_send_eor(peer, aid);
3521 				if (peer->capa.enhanced_rr && sent_eor)
3522 					rde_peer_send_rrefresh(peer, aid,
3523 					    ROUTE_REFRESH_END_RR);
3524 				continue;
3525 			}
3526 
3527 			if ((buf = up_dump_update(peer, aid)) == NULL) {
3528 				continue;
3529 			}
3530 			if (imsg_compose_ibuf(ibuf_se, IMSG_UPDATE,
3531 			    peer->conf.id, 0, buf) == -1)
3532 				fatal("%s: imsg_compose_ibuf error", __func__);
3533 			sent++;
3534 		}
3535 		max -= sent;
3536 	} while (sent != 0 && max > 0);
3537 }
3538 
3539 /*
3540  * pf table specific functions
3541  */
3542 struct rde_pftable_node {
3543 	RB_ENTRY(rde_pftable_node)	 entry;
3544 	struct pt_entry			*prefix;
3545 	int				 refcnt;
3546 	uint16_t			 id;
3547 };
3548 RB_HEAD(rde_pftable_tree, rde_pftable_node);
3549 
3550 static inline int
rde_pftable_cmp(struct rde_pftable_node * a,struct rde_pftable_node * b)3551 rde_pftable_cmp(struct rde_pftable_node *a, struct rde_pftable_node *b)
3552 {
3553 	if (a->prefix > b->prefix)
3554 		return 1;
3555 	if (a->prefix < b->prefix)
3556 		return -1;
3557 	return (a->id - b->id);
3558 }
3559 
3560 RB_GENERATE_STATIC(rde_pftable_tree, rde_pftable_node, entry, rde_pftable_cmp);
3561 
3562 struct rde_pftable_tree pftable_tree = RB_INITIALIZER(&pftable_tree);
3563 int need_commit;
3564 
3565 static void
rde_pftable_send(uint16_t id,struct pt_entry * pt,int del)3566 rde_pftable_send(uint16_t id, struct pt_entry *pt, int del)
3567 {
3568 	struct pftable_msg pfm;
3569 
3570 	if (id == 0)
3571 		return;
3572 
3573 	/* do not run while cleaning up */
3574 	if (rde_quit)
3575 		return;
3576 
3577 	memset(&pfm, 0, sizeof(pfm));
3578 	strlcpy(pfm.pftable, pftable_id2name(id), sizeof(pfm.pftable));
3579 	pt_getaddr(pt, &pfm.addr);
3580 	pfm.len = pt->prefixlen;
3581 
3582 	if (imsg_compose(ibuf_main,
3583 	    del ? IMSG_PFTABLE_REMOVE : IMSG_PFTABLE_ADD,
3584 	    0, 0, -1, &pfm, sizeof(pfm)) == -1)
3585 		fatal("%s %d imsg_compose error", __func__, __LINE__);
3586 
3587 	need_commit = 1;
3588 }
3589 
3590 void
rde_pftable_add(uint16_t id,struct prefix * p)3591 rde_pftable_add(uint16_t id, struct prefix *p)
3592 {
3593 	struct rde_pftable_node *pfn, node;
3594 
3595 	memset(&node, 0, sizeof(node));
3596 	node.prefix = p->pt;
3597 	node.id = id;
3598 
3599 	pfn = RB_FIND(rde_pftable_tree, &pftable_tree, &node);
3600 	if (pfn == NULL) {
3601 		if ((pfn = calloc(1, sizeof(*pfn))) == NULL)
3602 			fatal("%s", __func__);
3603 		pfn->prefix = pt_ref(p->pt);
3604 		pfn->id = id;
3605 
3606 		if (RB_INSERT(rde_pftable_tree, &pftable_tree, pfn) != NULL)
3607 			fatalx("%s: tree corrupt", __func__);
3608 
3609 		rde_pftable_send(id, p->pt, 0);
3610 	}
3611 	pfn->refcnt++;
3612 }
3613 
3614 void
rde_pftable_del(uint16_t id,struct prefix * p)3615 rde_pftable_del(uint16_t id, struct prefix *p)
3616 {
3617 	struct rde_pftable_node *pfn, node;
3618 
3619 	memset(&node, 0, sizeof(node));
3620 	node.prefix = p->pt;
3621 	node.id = id;
3622 
3623 	pfn = RB_FIND(rde_pftable_tree, &pftable_tree, &node);
3624 	if (pfn == NULL)
3625 		return;
3626 
3627 	if (--pfn->refcnt <= 0) {
3628 		rde_pftable_send(id, p->pt, 1);
3629 
3630 		if (RB_REMOVE(rde_pftable_tree, &pftable_tree, pfn) == NULL)
3631 			fatalx("%s: tree corrupt", __func__);
3632 
3633 		pt_unref(pfn->prefix);
3634 		free(pfn);
3635 	}
3636 }
3637 
3638 void
rde_commit_pftable(void)3639 rde_commit_pftable(void)
3640 {
3641 	/* do not run while cleaning up */
3642 	if (rde_quit)
3643 		return;
3644 
3645 	if (!need_commit)
3646 		return;
3647 
3648 	if (imsg_compose(ibuf_main, IMSG_PFTABLE_COMMIT, 0, 0, -1, NULL, 0) ==
3649 	    -1)
3650 		fatal("%s %d imsg_compose error", __func__, __LINE__);
3651 
3652 	need_commit = 0;
3653 }
3654 
3655 /*
3656  * nexthop specific functions
3657  */
3658 void
rde_send_nexthop(struct bgpd_addr * next,int insert)3659 rde_send_nexthop(struct bgpd_addr *next, int insert)
3660 {
3661 	int			 type;
3662 
3663 	if (insert)
3664 		type = IMSG_NEXTHOP_ADD;
3665 	else
3666 		type = IMSG_NEXTHOP_REMOVE;
3667 
3668 	if (imsg_compose(ibuf_main, type, 0, 0, -1, next,
3669 	    sizeof(struct bgpd_addr)) == -1)
3670 		fatal("%s %d imsg_compose error", __func__, __LINE__);
3671 }
3672 
3673 /*
3674  * soft reconfig specific functions
3675  */
3676 void
rde_reload_done(void)3677 rde_reload_done(void)
3678 {
3679 	struct rde_peer		*peer;
3680 	struct filter_head	*fh;
3681 	struct rde_prefixset_head prefixsets_old;
3682 	struct rde_prefixset_head originsets_old;
3683 	struct as_set_head	 as_sets_old;
3684 	uint16_t		 rid;
3685 	int			 reload = 0, force_locrib = 0;
3686 
3687 	softreconfig = 0;
3688 
3689 	SIMPLEQ_INIT(&prefixsets_old);
3690 	SIMPLEQ_INIT(&originsets_old);
3691 	SIMPLEQ_INIT(&as_sets_old);
3692 	SIMPLEQ_CONCAT(&prefixsets_old, &conf->rde_prefixsets);
3693 	SIMPLEQ_CONCAT(&originsets_old, &conf->rde_originsets);
3694 	SIMPLEQ_CONCAT(&as_sets_old, &conf->as_sets);
3695 
3696 	/* run softreconfig in if filter mode changed */
3697 	if (conf->filtered_in_locrib != nconf->filtered_in_locrib) {
3698 		log_debug("filter mode changed, reloading Loc-Rib");
3699 		force_locrib = 1;
3700 	}
3701 
3702 	/* merge the main config */
3703 	copy_config(conf, nconf);
3704 
3705 	/* need to copy the sets and roa table and clear them in nconf */
3706 	SIMPLEQ_CONCAT(&conf->rde_prefixsets, &nconf->rde_prefixsets);
3707 	SIMPLEQ_CONCAT(&conf->rde_originsets, &nconf->rde_originsets);
3708 	SIMPLEQ_CONCAT(&conf->as_sets, &nconf->as_sets);
3709 
3710 	/* apply new set of l3vpn, sync will be done later */
3711 	free_l3vpns(&conf->l3vpns);
3712 	SIMPLEQ_CONCAT(&conf->l3vpns, &nconf->l3vpns);
3713 	/* XXX WHERE IS THE SYNC ??? */
3714 
3715 	free_config(nconf);
3716 	nconf = NULL;
3717 
3718 	/* sync peerself with conf */
3719 	peerself->remote_bgpid = conf->bgpid;
3720 	peerself->conf.local_as = conf->as;
3721 	peerself->conf.remote_as = conf->as;
3722 	peerself->conf.remote_addr.aid = AID_INET;
3723 	peerself->conf.remote_addr.v4.s_addr = htonl(conf->bgpid);
3724 	peerself->conf.remote_masklen = 32;
3725 	peerself->short_as = conf->short_as;
3726 
3727 	rde_mark_prefixsets_dirty(&prefixsets_old, &conf->rde_prefixsets);
3728 	rde_mark_prefixsets_dirty(&originsets_old, &conf->rde_originsets);
3729 	as_sets_mark_dirty(&as_sets_old, &conf->as_sets);
3730 
3731 
3732 	/* make sure that rde_eval_all is correctly set after a config change */
3733 	rde_eval_all = 0;
3734 
3735 	/* Make the new outbound filter rules the active one. */
3736 	filterlist_free(out_rules);
3737 	out_rules = out_rules_tmp;
3738 	out_rules_tmp = NULL;
3739 
3740 	/* check if filter changed */
3741 	RB_FOREACH(peer, peer_tree, &peertable) {
3742 		if (peer->conf.id == 0)	/* ignore peerself */
3743 			continue;
3744 		peer->reconf_out = 0;
3745 		peer->reconf_rib = 0;
3746 
3747 		/* max prefix checker */
3748 		if (peer->conf.max_prefix &&
3749 		    peer->stats.prefix_cnt > peer->conf.max_prefix) {
3750 			log_peer_warnx(&peer->conf,
3751 			    "prefix limit reached (>%u/%u)",
3752 			    peer->stats.prefix_cnt, peer->conf.max_prefix);
3753 			rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX,
3754 			    NULL);
3755 		}
3756 		/* max prefix checker outbound */
3757 		if (peer->conf.max_out_prefix &&
3758 		    peer->stats.prefix_out_cnt > peer->conf.max_out_prefix) {
3759 			log_peer_warnx(&peer->conf,
3760 			    "outbound prefix limit reached (>%u/%u)",
3761 			    peer->stats.prefix_out_cnt,
3762 			    peer->conf.max_out_prefix);
3763 			rde_update_err(peer, ERR_CEASE,
3764 			    ERR_CEASE_MAX_SENT_PREFIX, NULL);
3765 		}
3766 
3767 		if (peer->export_type != peer->conf.export_type) {
3768 			log_peer_info(&peer->conf, "export type change, "
3769 			    "reloading");
3770 			peer->reconf_rib = 1;
3771 		}
3772 		if ((peer->flags & PEERFLAG_EVALUATE_ALL) !=
3773 		    (peer->conf.flags & PEERFLAG_EVALUATE_ALL)) {
3774 			log_peer_info(&peer->conf, "rde evaluate change, "
3775 			    "reloading");
3776 			peer->reconf_rib = 1;
3777 		}
3778 		if ((peer->flags & PEERFLAG_TRANS_AS) !=
3779 		    (peer->conf.flags & PEERFLAG_TRANS_AS)) {
3780 			log_peer_info(&peer->conf, "transparent-as change, "
3781 			    "reloading");
3782 			peer->reconf_rib = 1;
3783 		}
3784 		if (peer->loc_rib_id != rib_find(peer->conf.rib)) {
3785 			log_peer_info(&peer->conf, "rib change, reloading");
3786 			peer->loc_rib_id = rib_find(peer->conf.rib);
3787 			if (peer->loc_rib_id == RIB_NOTFOUND)
3788 				fatalx("King Bula's peer met an unknown RIB");
3789 			peer->reconf_rib = 1;
3790 		}
3791 		/*
3792 		 * Update add-path settings but only if the session is
3793 		 * running with add-path and the config uses add-path
3794 		 * as well.
3795 		 */
3796 		if (peer_has_add_path(peer, AID_UNSPEC, CAPA_AP_SEND)) {
3797 			if (peer->conf.eval.mode != ADDPATH_EVAL_NONE &&
3798 			    memcmp(&peer->eval, &peer->conf.eval,
3799 			    sizeof(peer->eval)) != 0) {
3800 				log_peer_info(&peer->conf,
3801 				    "addpath eval change, reloading");
3802 				peer->reconf_out = 1;
3803 				peer->eval = peer->conf.eval;
3804 			}
3805 			/* add-path send needs rde_eval_all */
3806 			rde_eval_all = 1;
3807 		}
3808 		if (peer->role != peer->conf.role) {
3809 			if (reload == 0)
3810 				log_debug("peer role change: "
3811 				    "reloading Adj-RIB-In");
3812 			peer->role = peer->conf.role;
3813 			reload++;
3814 		}
3815 		peer->export_type = peer->conf.export_type;
3816 		peer->flags = peer->conf.flags;
3817 		if (peer->flags & PEERFLAG_EVALUATE_ALL)
3818 			rde_eval_all = 1;
3819 
3820 		if (peer->reconf_rib) {
3821 			if (prefix_dump_new(peer, AID_UNSPEC,
3822 			    RDE_RUNNER_ROUNDS, NULL, rde_up_flush_upcall,
3823 			    rde_softreconfig_in_done, NULL) == -1)
3824 				fatal("%s: prefix_dump_new", __func__);
3825 			log_peer_info(&peer->conf, "flushing Adj-RIB-Out");
3826 			softreconfig++;	/* account for the running flush */
3827 			continue;
3828 		}
3829 
3830 		/* reapply outbound filters for this peer */
3831 		fh = peer_apply_out_filter(peer, out_rules);
3832 
3833 		if (!rde_filter_equal(peer->out_rules, fh)) {
3834 			char *p = log_fmt_peer(&peer->conf);
3835 			log_debug("out filter change: reloading peer %s", p);
3836 			free(p);
3837 			peer->reconf_out = 1;
3838 		}
3839 		filterlist_free(fh);
3840 	}
3841 
3842 	/* bring ribs in sync */
3843 	for (rid = RIB_LOC_START; rid < rib_size; rid++) {
3844 		struct rib *rib = rib_byid(rid);
3845 		if (rib == NULL)
3846 			continue;
3847 		rde_filter_calc_skip_steps(rib->in_rules_tmp);
3848 
3849 		/* flip rules, make new active */
3850 		fh = rib->in_rules;
3851 		rib->in_rules = rib->in_rules_tmp;
3852 		rib->in_rules_tmp = fh;
3853 
3854 		switch (rib->state) {
3855 		case RECONF_DELETE:
3856 			rib_free(rib);
3857 			break;
3858 		case RECONF_RELOAD:
3859 			if (rib_update(rib)) {
3860 				RB_FOREACH(peer, peer_tree, &peertable) {
3861 					/* ignore peerself */
3862 					if (peer->conf.id == 0)
3863 						continue;
3864 					/* skip peers using a different rib */
3865 					if (peer->loc_rib_id != rib->id)
3866 						continue;
3867 					/* peer rib is already being flushed */
3868 					if (peer->reconf_rib)
3869 						continue;
3870 
3871 					if (prefix_dump_new(peer, AID_UNSPEC,
3872 					    RDE_RUNNER_ROUNDS, NULL,
3873 					    rde_up_flush_upcall,
3874 					    rde_softreconfig_in_done,
3875 					    NULL) == -1)
3876 						fatal("%s: prefix_dump_new",
3877 						    __func__);
3878 
3879 					log_peer_info(&peer->conf,
3880 					    "flushing Adj-RIB-Out");
3881 					/* account for the running flush */
3882 					softreconfig++;
3883 				}
3884 			}
3885 
3886 			rib->state = RECONF_KEEP;
3887 			/* FALLTHROUGH */
3888 		case RECONF_KEEP:
3889 			if (!(force_locrib && rid == RIB_LOC_START) &&
3890 			    rde_filter_equal(rib->in_rules, rib->in_rules_tmp))
3891 				/* rib is in sync */
3892 				break;
3893 			log_debug("filter change: reloading RIB %s",
3894 			    rib->name);
3895 			rib->state = RECONF_RELOAD;
3896 			reload++;
3897 			break;
3898 		case RECONF_REINIT:
3899 			/* new rib */
3900 			rib->state = RECONF_RELOAD;
3901 			reload++;
3902 			break;
3903 		case RECONF_NONE:
3904 			break;
3905 		}
3906 		filterlist_free(rib->in_rules_tmp);
3907 		rib->in_rules_tmp = NULL;
3908 	}
3909 
3910 	/* old filters removed, free all sets */
3911 	free_rde_prefixsets(&prefixsets_old);
3912 	free_rde_prefixsets(&originsets_old);
3913 	as_sets_free(&as_sets_old);
3914 
3915 	log_info("RDE reconfigured");
3916 
3917 	softreconfig++;
3918 	if (reload > 0) {
3919 		if (rib_dump_new(RIB_ADJ_IN, AID_UNSPEC, RDE_RUNNER_ROUNDS,
3920 		    NULL, rde_softreconfig_in, rde_softreconfig_in_done,
3921 		    NULL) == -1)
3922 			fatal("%s: rib_dump_new", __func__);
3923 		log_info("running softreconfig in");
3924 	} else {
3925 		rde_softreconfig_in_done((void *)1, AID_UNSPEC);
3926 	}
3927 }
3928 
3929 static void
rde_softreconfig_in_done(void * arg,uint8_t dummy)3930 rde_softreconfig_in_done(void *arg, uint8_t dummy)
3931 {
3932 	struct rde_peer	*peer;
3933 	uint16_t	 i;
3934 
3935 	softreconfig--;
3936 	/* one guy done but other dumps are still running */
3937 	if (softreconfig > 0)
3938 		return;
3939 
3940 	if (arg == NULL)
3941 		log_info("softreconfig in done");
3942 
3943 	/* now do the Adj-RIB-Out sync and a possible FIB sync */
3944 	softreconfig = 0;
3945 	for (i = 0; i < rib_size; i++) {
3946 		struct rib *rib = rib_byid(i);
3947 		if (rib == NULL)
3948 			continue;
3949 		rib->state = RECONF_NONE;
3950 		if (rib->fibstate == RECONF_RELOAD) {
3951 			if (rib_dump_new(i, AID_UNSPEC, RDE_RUNNER_ROUNDS,
3952 			    rib, rde_softreconfig_sync_fib,
3953 			    rde_softreconfig_sync_done, NULL) == -1)
3954 				fatal("%s: rib_dump_new", __func__);
3955 			softreconfig++;
3956 			log_info("starting fib sync for rib %s",
3957 			    rib->name);
3958 		} else if (rib->fibstate == RECONF_REINIT) {
3959 			if (rib_dump_new(i, AID_UNSPEC, RDE_RUNNER_ROUNDS,
3960 			    rib, rde_softreconfig_sync_reeval,
3961 			    rde_softreconfig_sync_done, NULL) == -1)
3962 				fatal("%s: rib_dump_new", __func__);
3963 			softreconfig++;
3964 			log_info("starting re-evaluation of rib %s",
3965 			    rib->name);
3966 		}
3967 	}
3968 
3969 	RB_FOREACH(peer, peer_tree, &peertable) {
3970 		uint8_t aid;
3971 
3972 		if (peer->reconf_out) {
3973 			if (peer->export_type == EXPORT_NONE) {
3974 				/* nothing to do here */
3975 				peer->reconf_out = 0;
3976 			} else if (peer->export_type == EXPORT_DEFAULT_ROUTE) {
3977 				/* just resend the default route */
3978 				for (aid = AID_MIN; aid < AID_MAX; aid++) {
3979 					if (peer->capa.mp[aid])
3980 						up_generate_default(peer, aid);
3981 				}
3982 				peer->reconf_out = 0;
3983 			} else
3984 				rib_byid(peer->loc_rib_id)->state =
3985 				    RECONF_RELOAD;
3986 		} else if (peer->reconf_rib) {
3987 			/* dump the full table to neighbors that changed rib */
3988 			for (aid = AID_MIN; aid < AID_MAX; aid++) {
3989 				if (peer->capa.mp[aid])
3990 					peer_dump(peer, aid);
3991 			}
3992 		}
3993 	}
3994 
3995 	for (i = 0; i < rib_size; i++) {
3996 		struct rib *rib = rib_byid(i);
3997 		if (rib == NULL)
3998 			continue;
3999 		if (rib->state == RECONF_RELOAD) {
4000 			if (rib_dump_new(i, AID_UNSPEC, RDE_RUNNER_ROUNDS,
4001 			    rib, rde_softreconfig_out,
4002 			    rde_softreconfig_out_done, NULL) == -1)
4003 				fatal("%s: rib_dump_new", __func__);
4004 			softreconfig++;
4005 			log_info("starting softreconfig out for rib %s",
4006 			    rib->name);
4007 		}
4008 	}
4009 
4010 	/* if nothing to do move to last stage */
4011 	if (softreconfig == 0)
4012 		rde_softreconfig_done();
4013 }
4014 
4015 static void
rde_softreconfig_out_done(void * arg,uint8_t aid)4016 rde_softreconfig_out_done(void *arg, uint8_t aid)
4017 {
4018 	struct rib	*rib = arg;
4019 
4020 	/* this RIB dump is done */
4021 	log_info("softreconfig out done for %s", rib->name);
4022 
4023 	/* check if other dumps are still running */
4024 	if (--softreconfig == 0)
4025 		rde_softreconfig_done();
4026 }
4027 
4028 static void
rde_softreconfig_done(void)4029 rde_softreconfig_done(void)
4030 {
4031 	uint16_t	i;
4032 
4033 	for (i = 0; i < rib_size; i++) {
4034 		struct rib *rib = rib_byid(i);
4035 		if (rib == NULL)
4036 			continue;
4037 		rib->state = RECONF_NONE;
4038 	}
4039 
4040 	log_info("RDE soft reconfiguration done");
4041 	imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0,
4042 	    -1, NULL, 0);
4043 }
4044 
4045 static void
rde_softreconfig_in(struct rib_entry * re,void * bula)4046 rde_softreconfig_in(struct rib_entry *re, void *bula)
4047 {
4048 	struct filterstate	 state;
4049 	struct rib		*rib;
4050 	struct prefix		*p;
4051 	struct pt_entry		*pt;
4052 	struct rde_peer		*peer;
4053 	struct rde_aspath	*asp;
4054 	enum filter_actions	 action;
4055 	struct bgpd_addr	 prefix;
4056 	uint16_t		 i;
4057 	uint8_t			 aspa_vstate;
4058 
4059 	pt = re->prefix;
4060 	pt_getaddr(pt, &prefix);
4061 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
4062 		asp = prefix_aspath(p);
4063 		peer = prefix_peer(p);
4064 
4065 		/* possible role change update ASPA validation state */
4066 		if (prefix_aspa_vstate(p) == ASPA_NEVER_KNOWN)
4067 			aspa_vstate = ASPA_NEVER_KNOWN;
4068 		else
4069 			aspa_vstate = rde_aspa_validity(peer, asp, pt->aid);
4070 		prefix_set_vstate(p, prefix_roa_vstate(p), aspa_vstate);
4071 
4072 		/* skip announced networks, they are never filtered */
4073 		if (asp->flags & F_PREFIX_ANNOUNCED)
4074 			continue;
4075 
4076 		for (i = RIB_LOC_START; i < rib_size; i++) {
4077 			rib = rib_byid(i);
4078 			if (rib == NULL)
4079 				continue;
4080 
4081 			if (rib->state != RECONF_RELOAD)
4082 				continue;
4083 
4084 			rde_filterstate_prep(&state, p);
4085 			action = rde_filter(rib->in_rules, peer, peer, &prefix,
4086 			    pt->prefixlen, &state);
4087 
4088 			if (action == ACTION_ALLOW) {
4089 				/* update Local-RIB */
4090 				prefix_update(rib, peer, p->path_id,
4091 				    p->path_id_tx, &state, 0,
4092 				    &prefix, pt->prefixlen);
4093 			} else if (conf->filtered_in_locrib &&
4094 			    i == RIB_LOC_START) {
4095 				prefix_update(rib, peer, p->path_id,
4096 				    p->path_id_tx, &state, 1,
4097 				    &prefix, pt->prefixlen);
4098 			} else {
4099 				/* remove from Local-RIB */
4100 				prefix_withdraw(rib, peer, p->path_id, &prefix,
4101 				    pt->prefixlen);
4102 			}
4103 
4104 			rde_filterstate_clean(&state);
4105 		}
4106 	}
4107 }
4108 
4109 static void
rde_softreconfig_out(struct rib_entry * re,void * arg)4110 rde_softreconfig_out(struct rib_entry *re, void *arg)
4111 {
4112 	if (prefix_best(re) == NULL)
4113 		/* no valid path for prefix */
4114 		return;
4115 
4116 	rde_generate_updates(re, NULL, NULL, EVAL_RECONF);
4117 }
4118 
4119 static void
rde_softreconfig_sync_reeval(struct rib_entry * re,void * arg)4120 rde_softreconfig_sync_reeval(struct rib_entry *re, void *arg)
4121 {
4122 	struct prefix_queue	prefixes = TAILQ_HEAD_INITIALIZER(prefixes);
4123 	struct prefix		*p, *next;
4124 	struct rib		*rib = arg;
4125 
4126 	if (rib->flags & F_RIB_NOEVALUATE) {
4127 		/*
4128 		 * evaluation process is turned off
4129 		 * all dependent adj-rib-out were already flushed
4130 		 * unlink nexthop if it was linked
4131 		 */
4132 		TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
4133 			if (p->flags & PREFIX_NEXTHOP_LINKED)
4134 				nexthop_unlink(p);
4135 			p->dmetric = PREFIX_DMETRIC_INVALID;
4136 		}
4137 		return;
4138 	}
4139 
4140 	/* evaluation process is turned on, so evaluate all prefixes again */
4141 	TAILQ_CONCAT(&prefixes, &re->prefix_h, entry.list.rib);
4142 
4143 	/*
4144 	 * TODO: this code works but is not optimal. prefix_evaluate()
4145 	 * does a lot of extra work in the worst case. Would be better
4146 	 * to resort the list once and then call rde_generate_updates()
4147 	 * and rde_send_kroute() once.
4148 	 */
4149 	TAILQ_FOREACH_SAFE(p, &prefixes, entry.list.rib, next) {
4150 		/* need to re-link the nexthop if not already linked */
4151 		TAILQ_REMOVE(&prefixes, p, entry.list.rib);
4152 		if ((p->flags & PREFIX_NEXTHOP_LINKED) == 0)
4153 			nexthop_link(p);
4154 		prefix_evaluate(re, p, NULL);
4155 	}
4156 }
4157 
4158 static void
rde_softreconfig_sync_fib(struct rib_entry * re,void * bula)4159 rde_softreconfig_sync_fib(struct rib_entry *re, void *bula)
4160 {
4161 	struct prefix *p;
4162 
4163 	if ((p = prefix_best(re)) != NULL)
4164 		rde_send_kroute(re_rib(re), p, NULL);
4165 }
4166 
4167 static void
rde_softreconfig_sync_done(void * arg,uint8_t aid)4168 rde_softreconfig_sync_done(void *arg, uint8_t aid)
4169 {
4170 	struct rib *rib = arg;
4171 
4172 	/* this RIB dump is done */
4173 	if (rib->fibstate == RECONF_RELOAD)
4174 		log_info("fib sync done for %s", rib->name);
4175 	else
4176 		log_info("re-evaluation done for %s", rib->name);
4177 	rib->fibstate = RECONF_NONE;
4178 
4179 	/* check if other dumps are still running */
4180 	if (--softreconfig == 0)
4181 		rde_softreconfig_done();
4182 }
4183 
4184 /*
4185  * ROA specific functions. The roa set is updated independent of the config
4186  * so this runs outside of the softreconfig handlers.
4187  */
4188 static void
rde_rpki_softreload(struct rib_entry * re,void * bula)4189 rde_rpki_softreload(struct rib_entry *re, void *bula)
4190 {
4191 	struct filterstate	 state;
4192 	struct rib		*rib;
4193 	struct prefix		*p;
4194 	struct pt_entry		*pt;
4195 	struct rde_peer		*peer;
4196 	struct rde_aspath	*asp;
4197 	enum filter_actions	 action;
4198 	struct bgpd_addr	 prefix;
4199 	uint8_t			 roa_vstate, aspa_vstate;
4200 	uint16_t		 i;
4201 
4202 	pt = re->prefix;
4203 	pt_getaddr(pt, &prefix);
4204 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
4205 		asp = prefix_aspath(p);
4206 		peer = prefix_peer(p);
4207 
4208 		/* ROA validation state update */
4209 		roa_vstate = rde_roa_validity(&rde_roa,
4210 		    &prefix, pt->prefixlen, aspath_origin(asp->aspath));
4211 
4212 		/* ASPA validation state update (if needed) */
4213 		if (prefix_aspa_vstate(p) == ASPA_NEVER_KNOWN) {
4214 			aspa_vstate = ASPA_NEVER_KNOWN;
4215 		} else {
4216 			if (asp->aspa_generation != rde_aspa_generation) {
4217 				asp->aspa_generation = rde_aspa_generation;
4218 				aspa_validation(rde_aspa, asp->aspath,
4219 				    &asp->aspa_state);
4220 			}
4221 			aspa_vstate = rde_aspa_validity(peer, asp, pt->aid);
4222 		}
4223 
4224 		if (roa_vstate == prefix_roa_vstate(p) &&
4225 		    aspa_vstate == prefix_aspa_vstate(p))
4226 			continue;
4227 
4228 		prefix_set_vstate(p, roa_vstate, aspa_vstate);
4229 		/* skip announced networks, they are never filtered */
4230 		if (asp->flags & F_PREFIX_ANNOUNCED)
4231 			continue;
4232 
4233 		for (i = RIB_LOC_START; i < rib_size; i++) {
4234 			rib = rib_byid(i);
4235 			if (rib == NULL)
4236 				continue;
4237 
4238 			rde_filterstate_prep(&state, p);
4239 			action = rde_filter(rib->in_rules, peer, peer, &prefix,
4240 			    pt->prefixlen, &state);
4241 
4242 			if (action == ACTION_ALLOW) {
4243 				/* update Local-RIB */
4244 				prefix_update(rib, peer, p->path_id,
4245 				    p->path_id_tx, &state, 0,
4246 				    &prefix, pt->prefixlen);
4247 			} else if (conf->filtered_in_locrib &&
4248 			    i == RIB_LOC_START) {
4249 				prefix_update(rib, peer, p->path_id,
4250 				    p->path_id_tx, &state, 1,
4251 				    &prefix, pt->prefixlen);
4252 			} else {
4253 				/* remove from Local-RIB */
4254 				prefix_withdraw(rib, peer, p->path_id, &prefix,
4255 				    pt->prefixlen);
4256 			}
4257 
4258 			rde_filterstate_clean(&state);
4259 		}
4260 	}
4261 }
4262 
4263 static int rpki_update_pending;
4264 
4265 static void
rde_rpki_softreload_done(void * arg,uint8_t aid)4266 rde_rpki_softreload_done(void *arg, uint8_t aid)
4267 {
4268 	/* the roa update is done */
4269 	log_info("RPKI softreload done");
4270 	rpki_update_pending = 0;
4271 }
4272 
4273 static void
rde_rpki_reload(void)4274 rde_rpki_reload(void)
4275 {
4276 	if (rpki_update_pending) {
4277 		log_info("RPKI softreload skipped, old still running");
4278 		return;
4279 	}
4280 
4281 	rpki_update_pending = 1;
4282 	if (rib_dump_new(RIB_ADJ_IN, AID_UNSPEC, RDE_RUNNER_ROUNDS,
4283 	    rib_byid(RIB_ADJ_IN), rde_rpki_softreload,
4284 	    rde_rpki_softreload_done, NULL) == -1)
4285 		fatal("%s: rib_dump_new", __func__);
4286 }
4287 
4288 static int
rde_roa_reload(void)4289 rde_roa_reload(void)
4290 {
4291 	struct rde_prefixset roa_old;
4292 
4293 	if (rpki_update_pending) {
4294 		trie_free(&roa_new.th);	/* can't use new roa table */
4295 		return 1;		/* force call to rde_rpki_reload */
4296 	}
4297 
4298 	roa_old = rde_roa;
4299 	rde_roa = roa_new;
4300 	memset(&roa_new, 0, sizeof(roa_new));
4301 
4302 	/* check if roa changed */
4303 	if (trie_equal(&rde_roa.th, &roa_old.th)) {
4304 		rde_roa.lastchange = roa_old.lastchange;
4305 		trie_free(&roa_old.th);	/* old roa no longer needed */
4306 		return 0;
4307 	}
4308 
4309 	rde_roa.lastchange = getmonotime();
4310 	trie_free(&roa_old.th);		/* old roa no longer needed */
4311 
4312 	log_debug("ROA change: reloading Adj-RIB-In");
4313 	return 1;
4314 }
4315 
4316 static int
rde_aspa_reload(void)4317 rde_aspa_reload(void)
4318 {
4319 	struct rde_aspa *aspa_old;
4320 
4321 	if (rpki_update_pending) {
4322 		aspa_table_free(aspa_new);	/* can't use new aspa table */
4323 		aspa_new = NULL;
4324 		return 1;			/* rpki_client_relaod warns */
4325 	}
4326 
4327 	aspa_old = rde_aspa;
4328 	rde_aspa = aspa_new;
4329 	aspa_new = NULL;
4330 
4331 	/* check if aspa changed */
4332 	if (aspa_table_equal(rde_aspa, aspa_old)) {
4333 		aspa_table_unchanged(rde_aspa, aspa_old);
4334 		aspa_table_free(aspa_old);	/* old aspa no longer needed */
4335 		return 0;
4336 	}
4337 
4338 	aspa_table_free(aspa_old);		/* old aspa no longer needed */
4339 	log_debug("ASPA change: reloading Adj-RIB-In");
4340 	rde_aspa_generation++;
4341 	return 1;
4342 }
4343 
4344 /*
4345  * generic helper function
4346  */
4347 uint32_t
rde_local_as(void)4348 rde_local_as(void)
4349 {
4350 	return (conf->as);
4351 }
4352 
4353 int
rde_decisionflags(void)4354 rde_decisionflags(void)
4355 {
4356 	return (conf->flags & BGPD_FLAG_DECISION_MASK);
4357 }
4358 
4359 /* End-of-RIB marker, RFC 4724 */
4360 static void
rde_peer_recv_eor(struct rde_peer * peer,uint8_t aid)4361 rde_peer_recv_eor(struct rde_peer *peer, uint8_t aid)
4362 {
4363 	peer->stats.prefix_rcvd_eor++;
4364 	peer->recv_eor |= 1 << aid;
4365 
4366 	/*
4367 	 * First notify SE to avert a possible race with the restart timeout.
4368 	 * If the timeout fires before this imsg is processed by the SE it will
4369 	 * result in the same operation since the timeout issues a FLUSH which
4370 	 * does the same as the RESTARTED action (flushing stale routes).
4371 	 * The logic in the SE is so that only one of FLUSH or RESTARTED will
4372 	 * be sent back to the RDE and so peer_flush is only called once.
4373 	 */
4374 	if (imsg_compose(ibuf_se, IMSG_SESSION_RESTARTED, peer->conf.id,
4375 	    0, -1, &aid, sizeof(aid)) == -1)
4376 		fatal("imsg_compose error while receiving EoR");
4377 
4378 	log_peer_info(&peer->conf, "received %s EOR marker",
4379 	    aid2str(aid));
4380 }
4381 
4382 static void
rde_peer_send_eor(struct rde_peer * peer,uint8_t aid)4383 rde_peer_send_eor(struct rde_peer *peer, uint8_t aid)
4384 {
4385 	uint16_t	afi;
4386 	uint8_t		safi;
4387 
4388 	peer->stats.prefix_sent_eor++;
4389 	peer->sent_eor |= 1 << aid;
4390 
4391 	if (aid == AID_INET) {
4392 		u_char null[4];
4393 
4394 		memset(&null, 0, 4);
4395 		if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
4396 		    0, -1, &null, 4) == -1)
4397 			fatal("imsg_compose error while sending EoR");
4398 	} else {
4399 		uint16_t	i;
4400 		u_char		buf[10];
4401 
4402 		if (aid2afi(aid, &afi, &safi) == -1)
4403 			fatalx("peer_send_eor: bad AID");
4404 
4405 		i = 0;	/* v4 withdrawn len */
4406 		memcpy(&buf[0], &i, sizeof(i));
4407 		i = htons(6);	/* path attr len */
4408 		memcpy(&buf[2], &i, sizeof(i));
4409 		buf[4] = ATTR_OPTIONAL;
4410 		buf[5] = ATTR_MP_UNREACH_NLRI;
4411 		buf[6] = 3;	/* withdrawn len */
4412 		i = htons(afi);
4413 		memcpy(&buf[7], &i, sizeof(i));
4414 		buf[9] = safi;
4415 
4416 		if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id,
4417 		    0, -1, &buf, 10) == -1)
4418 			fatal("%s %d imsg_compose error", __func__, __LINE__);
4419 	}
4420 
4421 	log_peer_info(&peer->conf, "sending %s EOR marker",
4422 	    aid2str(aid));
4423 }
4424 
4425 void
rde_peer_send_rrefresh(struct rde_peer * peer,uint8_t aid,uint8_t subtype)4426 rde_peer_send_rrefresh(struct rde_peer *peer, uint8_t aid, uint8_t subtype)
4427 {
4428 	struct route_refresh rr;
4429 
4430 	/* not strickly needed, the SE checks as well */
4431 	if (peer->capa.enhanced_rr == 0)
4432 		return;
4433 
4434 	switch (subtype) {
4435 	case ROUTE_REFRESH_END_RR:
4436 	case ROUTE_REFRESH_BEGIN_RR:
4437 		break;
4438 	default:
4439 		fatalx("%s unexpected subtype %d", __func__, subtype);
4440 	}
4441 
4442 	rr.aid = aid;
4443 	rr.subtype = subtype;
4444 
4445 	if (imsg_compose(ibuf_se, IMSG_REFRESH, peer->conf.id, 0, -1,
4446 	    &rr, sizeof(rr)) == -1)
4447 		fatal("%s %d imsg_compose error", __func__, __LINE__);
4448 
4449 	log_peer_info(&peer->conf, "sending %s %s marker",
4450 	    aid2str(aid), subtype == ROUTE_REFRESH_END_RR ? "EoRR" : "BoRR");
4451 }
4452 
4453 /*
4454  * network announcement stuff
4455  */
4456 void
network_add(struct network_config * nc,struct filterstate * state)4457 network_add(struct network_config *nc, struct filterstate *state)
4458 {
4459 	struct l3vpn		*vpn;
4460 	struct filter_set_head	*vpnset = NULL;
4461 	struct in_addr		 prefix4;
4462 	struct in6_addr		 prefix6;
4463 	uint32_t		 path_id_tx;
4464 	uint16_t		 i;
4465 	uint8_t			 vstate;
4466 
4467 	if (nc->rd != 0) {
4468 		SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) {
4469 			if (vpn->rd != nc->rd)
4470 				continue;
4471 			switch (nc->prefix.aid) {
4472 			case AID_INET:
4473 				prefix4 = nc->prefix.v4;
4474 				memset(&nc->prefix, 0, sizeof(nc->prefix));
4475 				nc->prefix.aid = AID_VPN_IPv4;
4476 				nc->prefix.rd = vpn->rd;
4477 				nc->prefix.v4 = prefix4;
4478 				nc->prefix.labellen = 3;
4479 				nc->prefix.labelstack[0] =
4480 				    (vpn->label >> 12) & 0xff;
4481 				nc->prefix.labelstack[1] =
4482 				    (vpn->label >> 4) & 0xff;
4483 				nc->prefix.labelstack[2] =
4484 				    (vpn->label << 4) & 0xf0;
4485 				nc->prefix.labelstack[2] |= BGP_MPLS_BOS;
4486 				vpnset = &vpn->export;
4487 				break;
4488 			case AID_INET6:
4489 				prefix6 = nc->prefix.v6;
4490 				memset(&nc->prefix, 0, sizeof(nc->prefix));
4491 				nc->prefix.aid = AID_VPN_IPv6;
4492 				nc->prefix.rd = vpn->rd;
4493 				nc->prefix.v6 = prefix6;
4494 				nc->prefix.labellen = 3;
4495 				nc->prefix.labelstack[0] =
4496 				    (vpn->label >> 12) & 0xff;
4497 				nc->prefix.labelstack[1] =
4498 				    (vpn->label >> 4) & 0xff;
4499 				nc->prefix.labelstack[2] =
4500 				    (vpn->label << 4) & 0xf0;
4501 				nc->prefix.labelstack[2] |= BGP_MPLS_BOS;
4502 				vpnset = &vpn->export;
4503 				break;
4504 			default:
4505 				log_warnx("unable to VPNize prefix");
4506 				filterset_free(&nc->attrset);
4507 				return;
4508 			}
4509 			break;
4510 		}
4511 		if (vpn == NULL) {
4512 			log_warnx("network_add: "
4513 			    "prefix %s/%u in non-existing l3vpn %s",
4514 			    log_addr(&nc->prefix), nc->prefixlen,
4515 			    log_rd(nc->rd));
4516 			return;
4517 		}
4518 	}
4519 
4520 	rde_apply_set(&nc->attrset, peerself, peerself, state, nc->prefix.aid);
4521 	if (vpnset)
4522 		rde_apply_set(vpnset, peerself, peerself, state,
4523 		    nc->prefix.aid);
4524 
4525 	vstate = rde_roa_validity(&rde_roa, &nc->prefix, nc->prefixlen,
4526 	    aspath_origin(state->aspath.aspath));
4527 	rde_filterstate_set_vstate(state, vstate, ASPA_NEVER_KNOWN);
4528 
4529 	path_id_tx = pathid_assign(peerself, 0, &nc->prefix, nc->prefixlen);
4530 	if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, path_id_tx,
4531 	    state, 0, &nc->prefix, nc->prefixlen) == 1)
4532 		peerself->stats.prefix_cnt++;
4533 	for (i = RIB_LOC_START; i < rib_size; i++) {
4534 		struct rib *rib = rib_byid(i);
4535 		if (rib == NULL)
4536 			continue;
4537 		rde_update_log("announce", i, peerself,
4538 		    state->nexthop ? &state->nexthop->exit_nexthop : NULL,
4539 		    &nc->prefix, nc->prefixlen);
4540 		prefix_update(rib, peerself, 0, path_id_tx, state, 0,
4541 		    &nc->prefix, nc->prefixlen);
4542 	}
4543 	filterset_free(&nc->attrset);
4544 }
4545 
4546 void
network_delete(struct network_config * nc)4547 network_delete(struct network_config *nc)
4548 {
4549 	struct l3vpn	*vpn;
4550 	struct in_addr	 prefix4;
4551 	struct in6_addr	 prefix6;
4552 	uint32_t	 i;
4553 
4554 	if (nc->rd) {
4555 		SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) {
4556 			if (vpn->rd != nc->rd)
4557 				continue;
4558 			switch (nc->prefix.aid) {
4559 			case AID_INET:
4560 				prefix4 = nc->prefix.v4;
4561 				memset(&nc->prefix, 0, sizeof(nc->prefix));
4562 				nc->prefix.aid = AID_VPN_IPv4;
4563 				nc->prefix.rd = vpn->rd;
4564 				nc->prefix.v4 = prefix4;
4565 				nc->prefix.labellen = 3;
4566 				nc->prefix.labelstack[0] =
4567 				    (vpn->label >> 12) & 0xff;
4568 				nc->prefix.labelstack[1] =
4569 				    (vpn->label >> 4) & 0xff;
4570 				nc->prefix.labelstack[2] =
4571 				    (vpn->label << 4) & 0xf0;
4572 				nc->prefix.labelstack[2] |= BGP_MPLS_BOS;
4573 				break;
4574 			case AID_INET6:
4575 				prefix6 = nc->prefix.v6;
4576 				memset(&nc->prefix, 0, sizeof(nc->prefix));
4577 				nc->prefix.aid = AID_VPN_IPv6;
4578 				nc->prefix.rd = vpn->rd;
4579 				nc->prefix.v6 = prefix6;
4580 				nc->prefix.labellen = 3;
4581 				nc->prefix.labelstack[0] =
4582 				    (vpn->label >> 12) & 0xff;
4583 				nc->prefix.labelstack[1] =
4584 				    (vpn->label >> 4) & 0xff;
4585 				nc->prefix.labelstack[2] =
4586 				    (vpn->label << 4) & 0xf0;
4587 				nc->prefix.labelstack[2] |= BGP_MPLS_BOS;
4588 				break;
4589 			default:
4590 				log_warnx("unable to VPNize prefix");
4591 				return;
4592 			}
4593 		}
4594 	}
4595 
4596 	for (i = RIB_LOC_START; i < rib_size; i++) {
4597 		struct rib *rib = rib_byid(i);
4598 		if (rib == NULL)
4599 			continue;
4600 		if (prefix_withdraw(rib, peerself, 0, &nc->prefix,
4601 		    nc->prefixlen))
4602 			rde_update_log("withdraw announce", i, peerself,
4603 			    NULL, &nc->prefix, nc->prefixlen);
4604 	}
4605 	if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, 0, &nc->prefix,
4606 	    nc->prefixlen))
4607 		peerself->stats.prefix_cnt--;
4608 }
4609 
4610 static void
network_dump_upcall(struct rib_entry * re,void * ptr)4611 network_dump_upcall(struct rib_entry *re, void *ptr)
4612 {
4613 	struct prefix		*p;
4614 	struct rde_aspath	*asp;
4615 	struct kroute_full	 kf;
4616 	struct bgpd_addr	 addr;
4617 	struct rde_dump_ctx	*ctx = ptr;
4618 
4619 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
4620 		asp = prefix_aspath(p);
4621 		if (!(asp->flags & F_PREFIX_ANNOUNCED))
4622 			continue;
4623 		pt_getaddr(p->pt, &addr);
4624 
4625 		memset(&kf, 0, sizeof(kf));
4626 		kf.prefix = addr;
4627 		kf.prefixlen = p->pt->prefixlen;
4628 		if (prefix_nhvalid(p) && prefix_nexthop(p) != NULL)
4629 			kf.nexthop = prefix_nexthop(p)->true_nexthop;
4630 		else
4631 			kf.nexthop.aid = kf.prefix.aid;
4632 		if ((asp->flags & F_ANN_DYNAMIC) == 0)
4633 			kf.flags = F_STATIC;
4634 		if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0,
4635 		    ctx->req.pid, -1, &kf, sizeof(kf)) == -1)
4636 			log_warnx("%s: imsg_compose error", __func__);
4637 	}
4638 }
4639 
4640 static void
network_flush_upcall(struct rib_entry * re,void * ptr)4641 network_flush_upcall(struct rib_entry *re, void *ptr)
4642 {
4643 	struct bgpd_addr addr;
4644 	struct prefix *p;
4645 	uint32_t i;
4646 	uint8_t prefixlen;
4647 
4648 	p = prefix_bypeer(re, peerself, 0);
4649 	if (p == NULL)
4650 		return;
4651 	if ((prefix_aspath(p)->flags & F_ANN_DYNAMIC) != F_ANN_DYNAMIC)
4652 		return;
4653 
4654 	pt_getaddr(re->prefix, &addr);
4655 	prefixlen = re->prefix->prefixlen;
4656 
4657 	for (i = RIB_LOC_START; i < rib_size; i++) {
4658 		struct rib *rib = rib_byid(i);
4659 		if (rib == NULL)
4660 			continue;
4661 		if (prefix_withdraw(rib, peerself, 0, &addr, prefixlen) == 1)
4662 			rde_update_log("flush announce", i, peerself,
4663 			    NULL, &addr, prefixlen);
4664 	}
4665 
4666 	if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, 0, &addr,
4667 	    prefixlen) == 1)
4668 		peerself->stats.prefix_cnt--;
4669 }
4670 
4671 /*
4672  * flowspec announcement stuff
4673  */
4674 void
flowspec_add(struct flowspec * f,struct filterstate * state,struct filter_set_head * attrset)4675 flowspec_add(struct flowspec *f, struct filterstate *state,
4676     struct filter_set_head *attrset)
4677 {
4678 	struct pt_entry *pte;
4679 	uint32_t path_id_tx;
4680 
4681 	rde_apply_set(attrset, peerself, peerself, state, f->aid);
4682 	rde_filterstate_set_vstate(state, ROA_NOTFOUND, ASPA_NEVER_KNOWN);
4683 	path_id_tx = peerself->path_id_tx; /* XXX should use pathid_assign() */
4684 
4685 	pte = pt_get_flow(f);
4686 	if (pte == NULL)
4687 		pte = pt_add_flow(f);
4688 
4689 	if (prefix_flowspec_update(peerself, state, pte, path_id_tx) == 1)
4690 		peerself->stats.prefix_cnt++;
4691 }
4692 
4693 void
flowspec_delete(struct flowspec * f)4694 flowspec_delete(struct flowspec *f)
4695 {
4696 	struct pt_entry *pte;
4697 
4698 	pte = pt_get_flow(f);
4699 	if (pte == NULL)
4700 		return;
4701 
4702 	if (prefix_flowspec_withdraw(peerself, pte) == 1)
4703 		peerself->stats.prefix_cnt--;
4704 }
4705 
4706 static void
flowspec_flush_upcall(struct rib_entry * re,void * ptr)4707 flowspec_flush_upcall(struct rib_entry *re, void *ptr)
4708 {
4709 	struct prefix *p;
4710 
4711 	p = prefix_bypeer(re, peerself, 0);
4712 	if (p == NULL)
4713 		return;
4714 	if ((prefix_aspath(p)->flags & F_ANN_DYNAMIC) != F_ANN_DYNAMIC)
4715 		return;
4716 	if (prefix_flowspec_withdraw(peerself, re->prefix) == 1)
4717 		peerself->stats.prefix_cnt--;
4718 }
4719 
4720 static void
flowspec_dump_upcall(struct rib_entry * re,void * ptr)4721 flowspec_dump_upcall(struct rib_entry *re, void *ptr)
4722 {
4723 	pid_t *pid = ptr;
4724 	struct prefix		*p;
4725 	struct rde_aspath	*asp;
4726 	struct rde_community	*comm;
4727 	struct flowspec		ff;
4728 	struct ibuf		*ibuf;
4729 	uint8_t			*flow;
4730 	int			len;
4731 
4732 	TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) {
4733 		asp = prefix_aspath(p);
4734 		if (!(asp->flags & F_PREFIX_ANNOUNCED))
4735 			continue;
4736 		comm = prefix_communities(p);
4737 
4738 		len = pt_getflowspec(p->pt, &flow);
4739 
4740 		memset(&ff, 0, sizeof(ff));
4741 		ff.aid = p->pt->aid;
4742 		ff.len = len;
4743 		if ((asp->flags & F_ANN_DYNAMIC) == 0)
4744 			ff.flags = F_STATIC;
4745 		if ((ibuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_FLOWSPEC, 0,
4746 		    *pid, FLOWSPEC_SIZE + len)) == NULL)
4747 				continue;
4748 		if (imsg_add(ibuf, &ff, FLOWSPEC_SIZE) == -1 ||
4749 		    imsg_add(ibuf, flow, len) == -1)
4750 			continue;
4751 		imsg_close(ibuf_se_ctl, ibuf);
4752 		if (comm->nentries > 0) {
4753 			if (imsg_compose(ibuf_se_ctl,
4754 			    IMSG_CTL_SHOW_RIB_COMMUNITIES, 0, *pid, -1,
4755 			    comm->communities,
4756 			    comm->nentries * sizeof(struct community)) == -1)
4757 				continue;
4758 		}
4759 	}
4760 }
4761 
4762 static void
flowspec_dump_done(void * ptr,uint8_t aid)4763 flowspec_dump_done(void *ptr, uint8_t aid)
4764 {
4765 	pid_t *pid = ptr;
4766 
4767 	imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, *pid, -1, NULL, 0);
4768 }
4769 
4770 
4771 /* clean up */
4772 void
rde_shutdown(void)4773 rde_shutdown(void)
4774 {
4775 	/*
4776 	 * the decision process is turned off if rde_quit = 1 and
4777 	 * rde_shutdown depends on this.
4778 	 */
4779 
4780 	/* First all peers go down */
4781 	peer_shutdown();
4782 
4783 	/* free filters */
4784 	filterlist_free(out_rules);
4785 	filterlist_free(out_rules_tmp);
4786 
4787 	/* kill the VPN configs */
4788 	free_l3vpns(&conf->l3vpns);
4789 
4790 	/* now check everything */
4791 	rib_shutdown();
4792 	nexthop_shutdown();
4793 	path_shutdown();
4794 	attr_shutdown();
4795 	pt_shutdown();
4796 }
4797 
4798 struct rde_prefixset *
rde_find_prefixset(char * name,struct rde_prefixset_head * p)4799 rde_find_prefixset(char *name, struct rde_prefixset_head *p)
4800 {
4801 	struct rde_prefixset *ps;
4802 
4803 	SIMPLEQ_FOREACH(ps, p, entry) {
4804 		if (!strcmp(ps->name, name))
4805 			return (ps);
4806 	}
4807 	return (NULL);
4808 }
4809 
4810 void
rde_mark_prefixsets_dirty(struct rde_prefixset_head * psold,struct rde_prefixset_head * psnew)4811 rde_mark_prefixsets_dirty(struct rde_prefixset_head *psold,
4812     struct rde_prefixset_head *psnew)
4813 {
4814 	struct rde_prefixset *new, *old;
4815 
4816 	SIMPLEQ_FOREACH(new, psnew, entry) {
4817 		if ((psold == NULL) ||
4818 		    (old = rde_find_prefixset(new->name, psold)) == NULL) {
4819 			new->dirty = 1;
4820 			new->lastchange = getmonotime();
4821 		} else {
4822 			if (trie_equal(&new->th, &old->th) == 0) {
4823 				new->dirty = 1;
4824 				new->lastchange = getmonotime();
4825 			} else
4826 				new->lastchange = old->lastchange;
4827 		}
4828 	}
4829 }
4830 
4831 uint8_t
rde_roa_validity(struct rde_prefixset * ps,struct bgpd_addr * prefix,uint8_t plen,uint32_t as)4832 rde_roa_validity(struct rde_prefixset *ps, struct bgpd_addr *prefix,
4833     uint8_t plen, uint32_t as)
4834 {
4835 	int r;
4836 
4837 	r = trie_roa_check(&ps->th, prefix, plen, as);
4838 	return (r & ROA_MASK);
4839 }
4840 
4841 static int
ovs_match(struct prefix * p,uint32_t flag)4842 ovs_match(struct prefix *p, uint32_t flag)
4843 {
4844 	if (flag & (F_CTL_OVS_VALID|F_CTL_OVS_INVALID|F_CTL_OVS_NOTFOUND)) {
4845 		switch (prefix_roa_vstate(p)) {
4846 		case ROA_VALID:
4847 			if (!(flag & F_CTL_OVS_VALID))
4848 				return 0;
4849 			break;
4850 		case ROA_INVALID:
4851 			if (!(flag & F_CTL_OVS_INVALID))
4852 				return 0;
4853 			break;
4854 		case ROA_NOTFOUND:
4855 			if (!(flag & F_CTL_OVS_NOTFOUND))
4856 				return 0;
4857 			break;
4858 		default:
4859 			break;
4860 		}
4861 	}
4862 
4863 	return 1;
4864 }
4865 
4866 static int
avs_match(struct prefix * p,uint32_t flag)4867 avs_match(struct prefix *p, uint32_t flag)
4868 {
4869 	if (flag & (F_CTL_AVS_VALID|F_CTL_AVS_INVALID|F_CTL_AVS_UNKNOWN)) {
4870 		switch (prefix_aspa_vstate(p) & ASPA_MASK) {
4871 		case ASPA_VALID:
4872 			if (!(flag & F_CTL_AVS_VALID))
4873 				return 0;
4874 			break;
4875 		case ASPA_INVALID:
4876 			if (!(flag & F_CTL_AVS_INVALID))
4877 				return 0;
4878 			break;
4879 		case ASPA_UNKNOWN:
4880 			if (!(flag & F_CTL_AVS_UNKNOWN))
4881 				return 0;
4882 			break;
4883 		default:
4884 			break;
4885 		}
4886 	}
4887 
4888 	return 1;
4889 }
4890