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