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