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