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