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