1 /* $OpenBSD: mrt.c,v 1.114 2023/04/19 09:03:00 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <limits.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <time.h> 28 #include <unistd.h> 29 30 #include "bgpd.h" 31 #include "rde.h" 32 #include "session.h" 33 34 #include "mrt.h" 35 #include "log.h" 36 37 int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct rde_community *, 38 struct bgpd_addr *, int); 39 int mrt_dump_entry_mp(struct mrt *, struct prefix *, uint16_t, 40 struct rde_peer*); 41 int mrt_dump_entry(struct mrt *, struct prefix *, uint16_t, struct rde_peer*); 42 int mrt_dump_entry_v2(struct mrt *, struct rib_entry *, uint32_t); 43 int mrt_dump_peer(struct ibuf *, struct rde_peer *); 44 int mrt_dump_hdr_se(struct ibuf **, struct peer *, uint16_t, uint16_t, 45 uint32_t, int); 46 int mrt_dump_hdr_rde(struct ibuf **, uint16_t type, uint16_t, uint32_t); 47 int mrt_open(struct mrt *, time_t); 48 49 #define DUMP_BYTE(x, b) \ 50 do { \ 51 u_char t = (b); \ 52 if (ibuf_add((x), &t, sizeof(t)) == -1) { \ 53 log_warn("mrt_dump1: ibuf_add error"); \ 54 goto fail; \ 55 } \ 56 } while (0) 57 58 #define DUMP_SHORT(x, s) \ 59 do { \ 60 uint16_t t; \ 61 t = htons((s)); \ 62 if (ibuf_add((x), &t, sizeof(t)) == -1) { \ 63 log_warn("mrt_dump2: ibuf_add error"); \ 64 goto fail; \ 65 } \ 66 } while (0) 67 68 #define DUMP_LONG(x, l) \ 69 do { \ 70 uint32_t t; \ 71 t = htonl((l)); \ 72 if (ibuf_add((x), &t, sizeof(t)) == -1) { \ 73 log_warn("mrt_dump3: ibuf_add error"); \ 74 goto fail; \ 75 } \ 76 } while (0) 77 78 #define DUMP_NLONG(x, l) \ 79 do { \ 80 uint32_t t = (l); \ 81 if (ibuf_add((x), &t, sizeof(t)) == -1) { \ 82 log_warn("mrt_dump4: ibuf_add error"); \ 83 goto fail; \ 84 } \ 85 } while (0) 86 87 #define RDEIDX 0 88 #define SEIDX 1 89 #define TYPE2IDX(x) ((x == MRT_TABLE_DUMP || \ 90 x == MRT_TABLE_DUMP_MP || \ 91 x == MRT_TABLE_DUMP_V2) ? RDEIDX : SEIDX \ 92 ) 93 94 static uint8_t 95 mrt_update_msg_guess_aid(uint8_t *pkg, uint16_t pkglen) 96 { 97 uint16_t wlen, alen, len, afi; 98 uint8_t type, aid; 99 100 pkg += MSGSIZE_HEADER; 101 pkglen -= MSGSIZE_HEADER; 102 103 if (pkglen < 4) 104 goto bad; 105 106 memcpy(&wlen, pkg, 2); 107 wlen = ntohs(wlen); 108 pkg += 2; 109 pkglen -= 2; 110 111 if (wlen > 0) { 112 /* UPDATE has withdraw routes, therefore IPv4 */ 113 return AID_INET; 114 } 115 116 memcpy(&alen, pkg, 2); 117 alen = ntohs(alen); 118 pkg += 2; 119 pkglen -= 2; 120 121 if (alen < pkglen) { 122 /* UPDATE has NLRI prefixes, therefore IPv4 */ 123 return AID_INET; 124 } 125 126 if (wlen == 0 && alen == 0) { 127 /* UPDATE is an IPv4 EoR marker */ 128 return AID_INET; 129 } 130 131 /* bad attribute length */ 132 if (alen > pkglen) 133 goto bad; 134 135 /* try to extract AFI/SAFI from the MP attributes */ 136 while (alen > 0) { 137 if (alen < 3) 138 goto bad; 139 type = pkg[1]; 140 if (pkg[0] & ATTR_EXTLEN) { 141 if (alen < 4) 142 goto bad; 143 memcpy(&len, pkg + 2, 2); 144 len = ntohs(len); 145 pkg += 4; 146 alen -= 4; 147 } else { 148 len = pkg[2]; 149 pkg += 3; 150 alen -= 3; 151 } 152 if (len > alen) 153 goto bad; 154 155 if (type == ATTR_MP_REACH_NLRI || 156 type == ATTR_MP_UNREACH_NLRI) { 157 if (alen < 3) 158 goto bad; 159 memcpy(&afi, pkg, 2); 160 afi = ntohs(afi); 161 if (afi2aid(afi, pkg[2], &aid) == -1) 162 goto bad; 163 return aid; 164 } 165 166 pkg += len; 167 alen -= len; 168 } 169 170 bad: 171 return AID_UNSPEC; 172 } 173 174 static uint16_t 175 mrt_bgp_msg_subtype(struct mrt *mrt, void *pkg, uint16_t pkglen, 176 struct peer *peer, enum msg_type msgtype, int in) 177 { 178 uint16_t subtype = BGP4MP_MESSAGE; 179 uint8_t aid, mask; 180 181 if (peer->capa.neg.as4byte) 182 subtype = BGP4MP_MESSAGE_AS4; 183 184 if (msgtype != UPDATE) 185 return subtype; 186 187 /* 188 * RFC8050 adjust types for add-path enabled sessions. 189 * It is necessary to extract the AID from UPDATES to decide 190 * if the add-path types are needed or not. The ADDPATH 191 * subtypes only matter for BGP UPDATES. 192 */ 193 194 mask = in ? CAPA_AP_RECV : CAPA_AP_SEND; 195 /* only guess if add-path could be active */ 196 if (peer->capa.neg.add_path[0] & mask) { 197 aid = mrt_update_msg_guess_aid(pkg, pkglen); 198 if (aid != AID_UNSPEC && 199 (peer->capa.neg.add_path[aid] & mask)) { 200 if (peer->capa.neg.as4byte) 201 subtype = BGP4MP_MESSAGE_AS4_ADDPATH; 202 else 203 subtype = BGP4MP_MESSAGE_ADDPATH; 204 } 205 } 206 207 return subtype; 208 } 209 210 void 211 mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, uint16_t pkglen, 212 struct peer *peer, enum msg_type msgtype) 213 { 214 struct ibuf *buf; 215 int in = 0; 216 uint16_t subtype = BGP4MP_MESSAGE; 217 218 /* get the direction of the message to swap address and AS fields */ 219 if (mrt->type == MRT_ALL_IN || mrt->type == MRT_UPDATE_IN) 220 in = 1; 221 222 subtype = mrt_bgp_msg_subtype(mrt, pkg, pkglen, peer, msgtype, in); 223 224 if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype, 225 pkglen, in) == -1) 226 return; 227 228 if (ibuf_add(buf, pkg, pkglen) == -1) { 229 log_warn("mrt_dump_bgp_msg: ibuf_add error"); 230 ibuf_free(buf); 231 return; 232 } 233 234 ibuf_close(&mrt->wbuf, buf); 235 } 236 237 void 238 mrt_dump_state(struct mrt *mrt, uint16_t old_state, uint16_t new_state, 239 struct peer *peer) 240 { 241 struct ibuf *buf; 242 uint16_t subtype = BGP4MP_STATE_CHANGE; 243 244 if (peer->capa.neg.as4byte) 245 subtype = BGP4MP_STATE_CHANGE_AS4; 246 247 if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype, 248 2 * sizeof(short), 0) == -1) 249 return; 250 251 DUMP_SHORT(buf, old_state); 252 DUMP_SHORT(buf, new_state); 253 254 ibuf_close(&mrt->wbuf, buf); 255 return; 256 257 fail: 258 ibuf_free(buf); 259 } 260 261 int 262 mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct rde_community *c, 263 struct bgpd_addr *nexthop, int v2) 264 { 265 struct attr *oa; 266 u_char *pdata; 267 uint32_t tmp; 268 int neednewpath = 0; 269 uint16_t plen, afi; 270 uint8_t l, safi; 271 272 /* origin */ 273 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN, 274 &a->origin, 1) == -1) 275 return (-1); 276 277 /* aspath */ 278 plen = aspath_length(a->aspath); 279 pdata = aspath_dump(a->aspath); 280 281 if (!v2) 282 pdata = aspath_deflate(pdata, &plen, &neednewpath); 283 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata, 284 plen) == -1) { 285 if (!v2) 286 free(pdata); 287 return (-1); 288 } 289 if (!v2) 290 free(pdata); 291 292 if (nexthop && nexthop->aid == AID_INET) { 293 /* nexthop, already network byte order */ 294 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP, 295 &nexthop->v4.s_addr, 4) == -1) 296 return (-1); 297 } 298 299 /* MED, non transitive */ 300 if (a->med != 0) { 301 tmp = htonl(a->med); 302 if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MED, &tmp, 4) == -1) 303 return (-1); 304 } 305 306 /* local preference */ 307 tmp = htonl(a->lpref); 308 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1) 309 return (-1); 310 311 /* communities */ 312 if (community_writebuf(buf, c) == -1) 313 return (-1); 314 315 /* dump all other path attributes without modification */ 316 for (l = 0; l < a->others_len; l++) { 317 if ((oa = a->others[l]) == NULL) 318 break; 319 if (attr_writebuf(buf, oa->flags, oa->type, 320 oa->data, oa->len) == -1) 321 return (-1); 322 } 323 324 if (nexthop && nexthop->aid != AID_INET) { 325 struct ibuf *nhbuf; 326 327 if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL) 328 return (-1); 329 if (!v2) { 330 if (aid2afi(nexthop->aid, &afi, &safi)) 331 return (-1); 332 DUMP_SHORT(nhbuf, afi); 333 DUMP_BYTE(nhbuf, safi); 334 } 335 switch (nexthop->aid) { 336 case AID_INET6: 337 DUMP_BYTE(nhbuf, sizeof(struct in6_addr)); 338 if (ibuf_add(nhbuf, &nexthop->v6, 339 sizeof(struct in6_addr)) == -1) 340 goto fail; 341 break; 342 case AID_VPN_IPv4: 343 DUMP_BYTE(nhbuf, sizeof(uint64_t) + 344 sizeof(struct in_addr)); 345 DUMP_NLONG(nhbuf, 0); /* set RD to 0 */ 346 DUMP_NLONG(nhbuf, 0); 347 DUMP_NLONG(nhbuf, nexthop->v4.s_addr); 348 break; 349 case AID_VPN_IPv6: 350 DUMP_BYTE(nhbuf, sizeof(uint64_t) + 351 sizeof(struct in6_addr)); 352 DUMP_NLONG(nhbuf, 0); /* set RD to 0 */ 353 DUMP_NLONG(nhbuf, 0); 354 if (ibuf_add(nhbuf, &nexthop->v6, 355 sizeof(struct in6_addr)) == -1) 356 goto fail; 357 break; 358 } 359 if (!v2) 360 DUMP_BYTE(nhbuf, 0); 361 if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI, 362 nhbuf->buf, ibuf_size(nhbuf)) == -1) { 363 fail: 364 ibuf_free(nhbuf); 365 return (-1); 366 } 367 ibuf_free(nhbuf); 368 } 369 370 if (neednewpath) { 371 pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen); 372 if (plen != 0) 373 if (attr_writebuf(buf, ATTR_OPTIONAL|ATTR_TRANSITIVE, 374 ATTR_AS4_PATH, pdata, plen) == -1) { 375 free(pdata); 376 return (-1); 377 } 378 free(pdata); 379 } 380 381 return (0); 382 } 383 384 int 385 mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, uint16_t snum, 386 struct rde_peer *peer) 387 { 388 struct ibuf *buf, *hbuf = NULL, *h2buf = NULL; 389 struct nexthop *n; 390 struct bgpd_addr nexthop, *nh; 391 uint16_t len; 392 uint8_t aid; 393 394 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 395 log_warn("mrt_dump_entry_mp: ibuf_dynamic"); 396 return (-1); 397 } 398 399 if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p), 400 NULL, 0) == -1) { 401 log_warnx("mrt_dump_entry_mp: mrt_attr_dump error"); 402 goto fail; 403 } 404 len = ibuf_size(buf); 405 406 if ((h2buf = ibuf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE + 407 MRT_BGP4MP_IPv4_ENTRY_SIZE, MRT_BGP4MP_IPv6_HEADER_SIZE + 408 MRT_BGP4MP_IPv6_ENTRY_SIZE + MRT_BGP4MP_MAX_PREFIXLEN)) == NULL) { 409 log_warn("mrt_dump_entry_mp: ibuf_dynamic"); 410 goto fail; 411 } 412 413 DUMP_SHORT(h2buf, peer->conf.local_short_as); 414 DUMP_SHORT(h2buf, peer->short_as); 415 DUMP_SHORT(h2buf, /* ifindex */ 0); 416 417 /* XXX is this for peer self? */ 418 aid = peer->remote_addr.aid == AID_UNSPEC ? p->pt->aid : 419 peer->remote_addr.aid; 420 switch (aid) { 421 case AID_INET: 422 case AID_VPN_IPv4: 423 DUMP_SHORT(h2buf, AFI_IPv4); 424 DUMP_NLONG(h2buf, peer->local_v4_addr.v4.s_addr); 425 DUMP_NLONG(h2buf, peer->remote_addr.v4.s_addr); 426 break; 427 case AID_INET6: 428 case AID_VPN_IPv6: 429 DUMP_SHORT(h2buf, AFI_IPv6); 430 if (ibuf_add(h2buf, &peer->local_v6_addr.v6, 431 sizeof(struct in6_addr)) == -1 || 432 ibuf_add(h2buf, &peer->remote_addr.v6, 433 sizeof(struct in6_addr)) == -1) { 434 log_warn("mrt_dump_entry_mp: ibuf_add error"); 435 goto fail; 436 } 437 break; 438 default: 439 log_warnx("king bula found new AF %d in %s", aid, __func__); 440 goto fail; 441 } 442 443 DUMP_SHORT(h2buf, 0); /* view */ 444 DUMP_SHORT(h2buf, 1); /* status */ 445 /* originated timestamp */ 446 DUMP_LONG(h2buf, time(NULL) - (getmonotime() - p->lastchange)); 447 448 n = prefix_nexthop(p); 449 if (n == NULL) { 450 memset(&nexthop, 0, sizeof(struct bgpd_addr)); 451 nexthop.aid = p->pt->aid; 452 nh = &nexthop; 453 } else 454 nh = &n->exit_nexthop; 455 456 switch (p->pt->aid) { 457 case AID_INET: 458 DUMP_SHORT(h2buf, AFI_IPv4); /* afi */ 459 DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */ 460 DUMP_BYTE(h2buf, 4); /* nhlen */ 461 DUMP_NLONG(h2buf, nh->v4.s_addr); /* nexthop */ 462 break; 463 case AID_INET6: 464 DUMP_SHORT(h2buf, AFI_IPv6); /* afi */ 465 DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */ 466 DUMP_BYTE(h2buf, 16); /* nhlen */ 467 if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) { 468 log_warn("mrt_dump_entry_mp: ibuf_add error"); 469 goto fail; 470 } 471 break; 472 case AID_VPN_IPv4: 473 DUMP_SHORT(h2buf, AFI_IPv4); /* afi */ 474 DUMP_BYTE(h2buf, SAFI_MPLSVPN); /* safi */ 475 DUMP_BYTE(h2buf, sizeof(uint64_t) + sizeof(struct in_addr)); 476 DUMP_NLONG(h2buf, 0); /* set RD to 0 */ 477 DUMP_NLONG(h2buf, 0); 478 DUMP_NLONG(h2buf, nh->v4.s_addr); /* nexthop */ 479 break; 480 case AID_VPN_IPv6: 481 DUMP_SHORT(h2buf, AFI_IPv6); /* afi */ 482 DUMP_BYTE(h2buf, SAFI_MPLSVPN); /* safi */ 483 DUMP_BYTE(h2buf, sizeof(uint64_t) + sizeof(struct in6_addr)); 484 DUMP_NLONG(h2buf, 0); /* set RD to 0 */ 485 DUMP_NLONG(h2buf, 0); 486 if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) { 487 log_warn("mrt_dump_entry_mp: ibuf_add error"); 488 goto fail; 489 } 490 break; 491 case AID_FLOWSPECv4: 492 case AID_FLOWSPECv6: 493 if (p->pt->aid == AID_FLOWSPECv4) 494 DUMP_SHORT(h2buf, AFI_IPv4); /* afi */ 495 else 496 DUMP_SHORT(h2buf, AFI_IPv6); /* afi */ 497 DUMP_BYTE(h2buf, SAFI_FLOWSPEC); /* safi */ 498 DUMP_BYTE(h2buf, 0); /* nhlen */ 499 break; 500 default: 501 log_warnx("king bula found new AF in %s", __func__); 502 goto fail; 503 } 504 505 if (pt_writebuf(h2buf, p->pt) == -1) { 506 log_warnx("%s: pt_writebuf error", __func__); 507 goto fail; 508 } 509 510 DUMP_SHORT(h2buf, len); 511 len += ibuf_size(h2buf); 512 513 if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY, 514 len) == -1) 515 goto fail; 516 517 ibuf_close(&mrt->wbuf, hbuf); 518 ibuf_close(&mrt->wbuf, h2buf); 519 ibuf_close(&mrt->wbuf, buf); 520 521 return (len + MRT_HEADER_SIZE); 522 523 fail: 524 ibuf_free(hbuf); 525 ibuf_free(h2buf); 526 ibuf_free(buf); 527 return (-1); 528 } 529 530 int 531 mrt_dump_entry(struct mrt *mrt, struct prefix *p, uint16_t snum, 532 struct rde_peer *peer) 533 { 534 struct ibuf *buf, *hbuf; 535 struct nexthop *nexthop; 536 struct bgpd_addr addr, *nh; 537 size_t len; 538 uint16_t subtype; 539 uint8_t dummy; 540 541 if (p->pt->aid != peer->remote_addr.aid && 542 p->pt->aid != AID_INET && p->pt->aid != AID_INET6) 543 /* only able to dump pure IPv4/IPv6 */ 544 return (0); 545 546 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 547 log_warn("mrt_dump_entry: ibuf_dynamic"); 548 return (-1); 549 } 550 551 nexthop = prefix_nexthop(p); 552 if (nexthop == NULL) { 553 memset(&addr, 0, sizeof(struct bgpd_addr)); 554 addr.aid = p->pt->aid; 555 nh = &addr; 556 } else 557 nh = &nexthop->exit_nexthop; 558 if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p), 559 nh, 0) == -1) { 560 log_warnx("mrt_dump_entry: mrt_attr_dump error"); 561 ibuf_free(buf); 562 return (-1); 563 } 564 len = ibuf_size(buf); 565 aid2afi(p->pt->aid, &subtype, &dummy); 566 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1) { 567 ibuf_free(buf); 568 return (-1); 569 } 570 571 DUMP_SHORT(hbuf, 0); 572 DUMP_SHORT(hbuf, snum); 573 574 pt_getaddr(p->pt, &addr); 575 switch (p->pt->aid) { 576 case AID_INET: 577 DUMP_NLONG(hbuf, addr.v4.s_addr); 578 break; 579 case AID_INET6: 580 if (ibuf_add(hbuf, &addr.v6, sizeof(struct in6_addr)) == -1) { 581 log_warn("mrt_dump_entry: ibuf_add error"); 582 goto fail; 583 } 584 break; 585 } 586 DUMP_BYTE(hbuf, p->pt->prefixlen); 587 588 DUMP_BYTE(hbuf, 1); /* state */ 589 /* originated timestamp */ 590 DUMP_LONG(hbuf, time(NULL) - (getmonotime() - p->lastchange)); 591 switch (p->pt->aid) { 592 case AID_INET: 593 DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr); 594 break; 595 case AID_INET6: 596 if (ibuf_add(hbuf, &peer->remote_addr.v6, 597 sizeof(struct in6_addr)) == -1) { 598 log_warn("mrt_dump_entry: ibuf_add error"); 599 goto fail; 600 } 601 break; 602 } 603 DUMP_SHORT(hbuf, peer->short_as); 604 DUMP_SHORT(hbuf, len); 605 606 ibuf_close(&mrt->wbuf, hbuf); 607 ibuf_close(&mrt->wbuf, buf); 608 609 return (len + MRT_HEADER_SIZE); 610 611 fail: 612 ibuf_free(hbuf); 613 ibuf_free(buf); 614 return (-1); 615 } 616 617 static int 618 mrt_dump_entry_v2_rib(struct rib_entry *re, struct ibuf **nb, struct ibuf **apb, 619 uint16_t *np, uint16_t *app) 620 { 621 struct bgpd_addr addr; 622 struct ibuf *buf, **bp; 623 struct prefix *p; 624 size_t len; 625 int addpath; 626 627 *np = 0; 628 *app = 0; 629 630 TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) { 631 struct nexthop *nexthop; 632 struct bgpd_addr *nh; 633 struct ibuf *tbuf; 634 635 addpath = peer_has_add_path(prefix_peer(p), re->prefix->aid, 636 CAPA_AP_RECV); 637 638 if (addpath) { 639 bp = apb; 640 *app += 1; 641 } else { 642 bp = nb; 643 *np += 1; 644 } 645 if ((buf = *bp) == NULL) { 646 if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { 647 log_warn("%s: ibuf_dynamic", __func__); 648 goto fail; 649 } 650 *bp = buf; 651 } 652 653 nexthop = prefix_nexthop(p); 654 if (nexthop == NULL) { 655 memset(&addr, 0, sizeof(struct bgpd_addr)); 656 addr.aid = re->prefix->aid; 657 nh = &addr; 658 } else 659 nh = &nexthop->exit_nexthop; 660 661 DUMP_SHORT(buf, prefix_peer(p)->mrt_idx); 662 /* originated timestamp */ 663 DUMP_LONG(buf, time(NULL) - (getmonotime() - p->lastchange)); 664 665 /* RFC8050: path-id if add-path is used */ 666 if (addpath) 667 DUMP_LONG(buf, p->path_id); 668 669 if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 670 log_warn("%s: ibuf_dynamic", __func__); 671 goto fail; 672 } 673 if (mrt_attr_dump(tbuf, prefix_aspath(p), prefix_communities(p), 674 nh, 1) == -1) { 675 log_warnx("%s: mrt_attr_dump error", __func__); 676 ibuf_free(tbuf); 677 goto fail; 678 } 679 len = ibuf_size(tbuf); 680 DUMP_SHORT(buf, (uint16_t)len); 681 if (ibuf_add(buf, tbuf->buf, len) == -1) { 682 log_warn("%s: ibuf_add error", __func__); 683 ibuf_free(tbuf); 684 goto fail; 685 } 686 ibuf_free(tbuf); 687 } 688 689 return 0; 690 691 fail: 692 return -1; 693 } 694 695 int 696 mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, uint32_t snum) 697 { 698 struct ibuf *hbuf = NULL, *nbuf = NULL, *apbuf = NULL, *pbuf; 699 size_t hlen, len; 700 uint16_t subtype, apsubtype, nump, apnump, afi; 701 uint8_t safi; 702 703 if ((pbuf = ibuf_dynamic(0, UINT_MAX)) == NULL) { 704 log_warn("%s: ibuf_dynamic", __func__); 705 return -1; 706 } 707 708 switch (re->prefix->aid) { 709 case AID_INET: 710 subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST; 711 apsubtype = MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH; 712 break; 713 case AID_INET6: 714 subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST; 715 apsubtype = MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH; 716 break; 717 default: 718 /* 719 * XXX The RFC defined the format for this type differently 720 * and it is prohibitly expensive to implement that format. 721 * Instead do what gobgp does and encode it like the other 722 * types. 723 */ 724 subtype = MRT_DUMP_V2_RIB_GENERIC; 725 apsubtype = MRT_DUMP_V2_RIB_GENERIC_ADDPATH; 726 aid2afi(re->prefix->aid, &afi, &safi); 727 728 /* first add 3-bytes AFI/SAFI */ 729 DUMP_SHORT(pbuf, afi); 730 DUMP_BYTE(pbuf, safi); 731 break; 732 } 733 734 if (pt_writebuf(pbuf, re->prefix) == -1) { 735 log_warnx("%s: pt_writebuf error", __func__); 736 goto fail; 737 } 738 739 hlen = sizeof(snum) + sizeof(nump) + ibuf_size(pbuf); 740 741 if (mrt_dump_entry_v2_rib(re, &nbuf, &apbuf, &nump, &apnump)) 742 goto fail; 743 744 if (nump > 0) { 745 len = ibuf_size(nbuf) + hlen; 746 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype, 747 len) == -1) 748 goto fail; 749 750 DUMP_LONG(hbuf, snum); 751 if (ibuf_add(hbuf, pbuf->buf, ibuf_size(pbuf)) == -1) { 752 log_warn("%s: ibuf_add error", __func__); 753 goto fail; 754 } 755 DUMP_SHORT(hbuf, nump); 756 757 ibuf_close(&mrt->wbuf, hbuf); 758 ibuf_close(&mrt->wbuf, nbuf); 759 hbuf = NULL; 760 nbuf = NULL; 761 } 762 763 if (apnump > 0) { 764 len = ibuf_size(apbuf) + hlen; 765 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, apsubtype, 766 len) == -1) 767 goto fail; 768 769 DUMP_LONG(hbuf, snum); 770 if (ibuf_add(hbuf, pbuf->buf, ibuf_size(pbuf)) == -1) { 771 log_warn("%s: ibuf_add error", __func__); 772 goto fail; 773 } 774 DUMP_SHORT(hbuf, apnump); 775 776 ibuf_close(&mrt->wbuf, hbuf); 777 ibuf_close(&mrt->wbuf, apbuf); 778 hbuf = NULL; 779 apbuf = NULL; 780 } 781 782 ibuf_free(pbuf); 783 return (0); 784 fail: 785 ibuf_free(apbuf); 786 ibuf_free(nbuf); 787 ibuf_free(hbuf); 788 ibuf_free(pbuf); 789 return (-1); 790 } 791 792 struct cb_arg { 793 struct ibuf *buf; 794 int nump; 795 }; 796 797 static void 798 mrt_dump_v2_hdr_peer(struct rde_peer *peer, void *arg) 799 { 800 struct cb_arg *a = arg; 801 802 if (a->nump == -1) 803 return; 804 peer->mrt_idx = a->nump; 805 if (mrt_dump_peer(a->buf, peer) == -1) { 806 a->nump = -1; 807 return; 808 } 809 a->nump++; 810 } 811 812 int 813 mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf) 814 { 815 struct ibuf *buf, *hbuf = NULL; 816 size_t len, off; 817 uint16_t nlen, nump; 818 struct cb_arg arg; 819 820 if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { 821 log_warn("%s: ibuf_dynamic", __func__); 822 return (-1); 823 } 824 825 DUMP_NLONG(buf, conf->bgpid); 826 nlen = strlen(mrt->rib); 827 if (nlen > 0) 828 nlen += 1; 829 DUMP_SHORT(buf, nlen); 830 if (ibuf_add(buf, mrt->rib, nlen) == -1) { 831 log_warn("%s: ibuf_add error", __func__); 832 goto fail; 833 } 834 835 off = ibuf_size(buf); 836 if (ibuf_reserve(buf, sizeof(nump)) == NULL) { 837 log_warn("%s: ibuf_reserve error", __func__); 838 goto fail; 839 } 840 arg.nump = 0; 841 arg.buf = buf; 842 peer_foreach(mrt_dump_v2_hdr_peer, &arg); 843 if (arg.nump == -1) 844 goto fail; 845 846 nump = htons(arg.nump); 847 memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump)); 848 849 len = ibuf_size(buf); 850 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, 851 MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1) 852 goto fail; 853 854 ibuf_close(&mrt->wbuf, hbuf); 855 ibuf_close(&mrt->wbuf, buf); 856 857 return (0); 858 fail: 859 ibuf_free(hbuf); 860 ibuf_free(buf); 861 return (-1); 862 } 863 864 int 865 mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer) 866 { 867 uint8_t type = 0; 868 869 if (peer->capa.as4byte) 870 type |= MRT_DUMP_V2_PEER_BIT_A; 871 if (peer->remote_addr.aid == AID_INET6) 872 type |= MRT_DUMP_V2_PEER_BIT_I; 873 874 DUMP_BYTE(buf, type); 875 DUMP_LONG(buf, peer->remote_bgpid); 876 877 switch (peer->remote_addr.aid) { 878 case AID_INET: 879 DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); 880 break; 881 case AID_INET6: 882 if (ibuf_add(buf, &peer->remote_addr.v6, 883 sizeof(struct in6_addr)) == -1) { 884 log_warn("mrt_dump_peer: ibuf_add error"); 885 goto fail; 886 } 887 break; 888 case AID_UNSPEC: /* XXX special handling for peerself? */ 889 DUMP_NLONG(buf, 0); 890 break; 891 default: 892 log_warnx("king bula found new AF in %s", __func__); 893 goto fail; 894 } 895 896 if (peer->capa.as4byte) 897 DUMP_LONG(buf, peer->conf.remote_as); 898 else 899 DUMP_SHORT(buf, peer->short_as); 900 901 return (0); 902 fail: 903 return (-1); 904 } 905 906 void 907 mrt_dump_upcall(struct rib_entry *re, void *ptr) 908 { 909 struct mrt *mrtbuf = ptr; 910 struct prefix *p; 911 912 if (mrtbuf->type == MRT_TABLE_DUMP_V2) { 913 mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++); 914 return; 915 } 916 917 /* 918 * dump all prefixes even the inactive ones. That is the way zebra 919 * dumps the table so we do the same. If only the active route should 920 * be dumped p should be set to p = pt->active. 921 */ 922 TAILQ_FOREACH(p, &re->prefix_h, entry.list.rib) { 923 if (mrtbuf->type == MRT_TABLE_DUMP) 924 mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++, 925 prefix_peer(p)); 926 else 927 mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++, 928 prefix_peer(p)); 929 } 930 } 931 932 void 933 mrt_done(struct mrt *mrtbuf) 934 { 935 mrtbuf->state = MRT_STATE_REMOVE; 936 } 937 938 int 939 mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, uint16_t type, 940 uint16_t subtype, uint32_t len, int swap) 941 { 942 struct timespec time; 943 944 if ((*bp = ibuf_dynamic(MRT_ET_HEADER_SIZE, MRT_ET_HEADER_SIZE + 945 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL) { 946 log_warn("mrt_dump_hdr_se: ibuf_dynamic error"); 947 return (-1); 948 } 949 950 clock_gettime(CLOCK_REALTIME, &time); 951 952 DUMP_LONG(*bp, time.tv_sec); 953 DUMP_SHORT(*bp, type); 954 DUMP_SHORT(*bp, subtype); 955 956 switch (peer->local.aid) { 957 case AID_INET: 958 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 959 subtype == BGP4MP_MESSAGE_AS4 || 960 subtype == BGP4MP_MESSAGE_AS4_ADDPATH) 961 len += MRT_BGP4MP_ET_AS4_IPv4_HEADER_SIZE; 962 else 963 len += MRT_BGP4MP_ET_IPv4_HEADER_SIZE; 964 break; 965 case AID_INET6: 966 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 967 subtype == BGP4MP_MESSAGE_AS4 || 968 subtype == BGP4MP_MESSAGE_AS4_ADDPATH) 969 len += MRT_BGP4MP_ET_AS4_IPv6_HEADER_SIZE; 970 else 971 len += MRT_BGP4MP_ET_IPv6_HEADER_SIZE; 972 break; 973 case 0: 974 goto fail; 975 default: 976 log_warnx("king bula found new AF in %s", __func__); 977 goto fail; 978 } 979 980 DUMP_LONG(*bp, len); 981 /* millisecond field use by the _ET format */ 982 DUMP_LONG(*bp, time.tv_nsec / 1000); 983 984 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 985 subtype == BGP4MP_MESSAGE_AS4 || 986 subtype == BGP4MP_MESSAGE_AS4_ADDPATH) { 987 if (!swap) 988 DUMP_LONG(*bp, peer->conf.local_as); 989 DUMP_LONG(*bp, peer->conf.remote_as); 990 if (swap) 991 DUMP_LONG(*bp, peer->conf.local_as); 992 } else { 993 if (!swap) 994 DUMP_SHORT(*bp, peer->conf.local_short_as); 995 DUMP_SHORT(*bp, peer->short_as); 996 if (swap) 997 DUMP_SHORT(*bp, peer->conf.local_short_as); 998 } 999 1000 DUMP_SHORT(*bp, /* ifindex */ 0); 1001 1002 switch (peer->local.aid) { 1003 case AID_INET: 1004 DUMP_SHORT(*bp, AFI_IPv4); 1005 if (!swap) 1006 DUMP_NLONG(*bp, peer->local.v4.s_addr); 1007 DUMP_NLONG(*bp, peer->remote.v4.s_addr); 1008 if (swap) 1009 DUMP_NLONG(*bp, peer->local.v4.s_addr); 1010 break; 1011 case AID_INET6: 1012 DUMP_SHORT(*bp, AFI_IPv6); 1013 if (!swap) 1014 if (ibuf_add(*bp, &peer->local.v6, 1015 sizeof(struct in6_addr)) == -1) { 1016 log_warn("mrt_dump_hdr_se: ibuf_add error"); 1017 goto fail; 1018 } 1019 if (ibuf_add(*bp, &peer->remote.v6, 1020 sizeof(struct in6_addr)) == -1) { 1021 log_warn("mrt_dump_hdr_se: ibuf_add error"); 1022 goto fail; 1023 } 1024 if (swap) 1025 if (ibuf_add(*bp, &peer->local.v6, 1026 sizeof(struct in6_addr)) == -1) { 1027 log_warn("mrt_dump_hdr_se: ibuf_add error"); 1028 goto fail; 1029 } 1030 break; 1031 } 1032 1033 return (0); 1034 1035 fail: 1036 ibuf_free(*bp); 1037 return (-1); 1038 } 1039 1040 int 1041 mrt_dump_hdr_rde(struct ibuf **bp, uint16_t type, uint16_t subtype, 1042 uint32_t len) 1043 { 1044 struct timespec time; 1045 1046 if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE + 1047 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) == 1048 NULL) { 1049 log_warn("mrt_dump_hdr_rde: ibuf_dynamic error"); 1050 return (-1); 1051 } 1052 1053 clock_gettime(CLOCK_REALTIME, &time); 1054 1055 DUMP_LONG(*bp, time.tv_sec); 1056 DUMP_SHORT(*bp, type); 1057 DUMP_SHORT(*bp, subtype); 1058 1059 switch (type) { 1060 case MSG_TABLE_DUMP: 1061 switch (subtype) { 1062 case AFI_IPv4: 1063 len += MRT_DUMP_HEADER_SIZE; 1064 break; 1065 case AFI_IPv6: 1066 len += MRT_DUMP_HEADER_SIZE_V6; 1067 break; 1068 } 1069 DUMP_LONG(*bp, len); 1070 break; 1071 case MSG_PROTOCOL_BGP4MP: 1072 case MSG_TABLE_DUMP_V2: 1073 DUMP_LONG(*bp, len); 1074 break; 1075 default: 1076 log_warnx("mrt_dump_hdr_rde: unsupported type"); 1077 goto fail; 1078 } 1079 return (0); 1080 1081 fail: 1082 ibuf_free(*bp); 1083 *bp = NULL; 1084 return (-1); 1085 } 1086 1087 void 1088 mrt_write(struct mrt *mrt) 1089 { 1090 int r; 1091 1092 if ((r = ibuf_write(&mrt->wbuf)) == -1 && errno != EAGAIN) { 1093 log_warn("mrt dump aborted, mrt_write"); 1094 mrt_clean(mrt); 1095 mrt_done(mrt); 1096 } 1097 } 1098 1099 void 1100 mrt_clean(struct mrt *mrt) 1101 { 1102 struct ibuf *b; 1103 1104 close(mrt->wbuf.fd); 1105 while ((b = TAILQ_FIRST(&mrt->wbuf.bufs))) { 1106 TAILQ_REMOVE(&mrt->wbuf.bufs, b, entry); 1107 ibuf_free(b); 1108 } 1109 mrt->wbuf.queued = 0; 1110 } 1111 1112 static struct imsgbuf *mrt_imsgbuf[2]; 1113 1114 void 1115 mrt_init(struct imsgbuf *rde, struct imsgbuf *se) 1116 { 1117 mrt_imsgbuf[RDEIDX] = rde; 1118 mrt_imsgbuf[SEIDX] = se; 1119 } 1120 1121 int 1122 mrt_open(struct mrt *mrt, time_t now) 1123 { 1124 enum imsg_type type; 1125 int fd; 1126 1127 if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file), 1128 MRT2MC(mrt)->name, localtime(&now)) == 0) { 1129 log_warnx("mrt_open: strftime conversion failed"); 1130 return (-1); 1131 } 1132 1133 fd = open(MRT2MC(mrt)->file, 1134 O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC|O_CLOEXEC, 0644); 1135 if (fd == -1) { 1136 log_warn("mrt_open %s", MRT2MC(mrt)->file); 1137 return (1); 1138 } 1139 1140 if (mrt->state == MRT_STATE_OPEN) 1141 type = IMSG_MRT_OPEN; 1142 else 1143 type = IMSG_MRT_REOPEN; 1144 1145 if (imsg_compose(mrt_imsgbuf[TYPE2IDX(mrt->type)], type, 0, 0, fd, 1146 mrt, sizeof(struct mrt)) == -1) 1147 log_warn("mrt_open"); 1148 1149 return (1); 1150 } 1151 1152 time_t 1153 mrt_timeout(struct mrt_head *mrt) 1154 { 1155 struct mrt *m; 1156 time_t now; 1157 time_t timeout = -1; 1158 1159 now = time(NULL); 1160 LIST_FOREACH(m, mrt, entry) { 1161 if (m->state == MRT_STATE_RUNNING && 1162 MRT2MC(m)->ReopenTimerInterval != 0) { 1163 if (MRT2MC(m)->ReopenTimer <= now) { 1164 mrt_open(m, now); 1165 MRT2MC(m)->ReopenTimer = 1166 now + MRT2MC(m)->ReopenTimerInterval; 1167 } 1168 if (timeout == -1 || 1169 MRT2MC(m)->ReopenTimer - now < timeout) 1170 timeout = MRT2MC(m)->ReopenTimer - now; 1171 } 1172 } 1173 return (timeout); 1174 } 1175 1176 void 1177 mrt_reconfigure(struct mrt_head *mrt) 1178 { 1179 struct mrt *m, *xm; 1180 time_t now; 1181 1182 now = time(NULL); 1183 for (m = LIST_FIRST(mrt); m != NULL; m = xm) { 1184 xm = LIST_NEXT(m, entry); 1185 if (m->state == MRT_STATE_OPEN || 1186 m->state == MRT_STATE_REOPEN) { 1187 if (mrt_open(m, now) == -1) 1188 continue; 1189 if (MRT2MC(m)->ReopenTimerInterval != 0) 1190 MRT2MC(m)->ReopenTimer = 1191 now + MRT2MC(m)->ReopenTimerInterval; 1192 m->state = MRT_STATE_RUNNING; 1193 } 1194 if (m->state == MRT_STATE_REMOVE) { 1195 if (imsg_compose(mrt_imsgbuf[TYPE2IDX(m->type)], 1196 IMSG_MRT_CLOSE, 0, 0, -1, m, sizeof(struct mrt)) == 1197 -1) 1198 log_warn("mrt_reconfigure"); 1199 LIST_REMOVE(m, entry); 1200 free(m); 1201 continue; 1202 } 1203 } 1204 } 1205 1206 void 1207 mrt_handler(struct mrt_head *mrt) 1208 { 1209 struct mrt *m; 1210 time_t now; 1211 1212 now = time(NULL); 1213 LIST_FOREACH(m, mrt, entry) { 1214 if (m->state == MRT_STATE_RUNNING && 1215 (MRT2MC(m)->ReopenTimerInterval != 0 || 1216 m->type == MRT_TABLE_DUMP || 1217 m->type == MRT_TABLE_DUMP_MP || 1218 m->type == MRT_TABLE_DUMP_V2)) { 1219 if (mrt_open(m, now) == -1) 1220 continue; 1221 MRT2MC(m)->ReopenTimer = 1222 now + MRT2MC(m)->ReopenTimerInterval; 1223 } 1224 } 1225 } 1226 1227 struct mrt * 1228 mrt_get(struct mrt_head *c, struct mrt *m) 1229 { 1230 struct mrt *t; 1231 1232 LIST_FOREACH(t, c, entry) { 1233 if (t->type != m->type) 1234 continue; 1235 if (strcmp(t->rib, m->rib)) 1236 continue; 1237 if (t->peer_id == m->peer_id && 1238 t->group_id == m->group_id) 1239 return (t); 1240 } 1241 return (NULL); 1242 } 1243 1244 void 1245 mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf) 1246 { 1247 struct mrt *m, *xm; 1248 1249 /* both lists here are actually struct mrt_conifg nodes */ 1250 LIST_FOREACH(m, nconf, entry) { 1251 if ((xm = mrt_get(xconf, m)) == NULL) { 1252 /* NEW */ 1253 if ((xm = malloc(sizeof(struct mrt_config))) == NULL) 1254 fatal("mrt_mergeconfig"); 1255 memcpy(xm, m, sizeof(struct mrt_config)); 1256 xm->state = MRT_STATE_OPEN; 1257 LIST_INSERT_HEAD(xconf, xm, entry); 1258 } else { 1259 /* MERGE */ 1260 if (strlcpy(MRT2MC(xm)->name, MRT2MC(m)->name, 1261 sizeof(MRT2MC(xm)->name)) >= 1262 sizeof(MRT2MC(xm)->name)) 1263 fatalx("mrt_mergeconfig: strlcpy"); 1264 MRT2MC(xm)->ReopenTimerInterval = 1265 MRT2MC(m)->ReopenTimerInterval; 1266 xm->state = MRT_STATE_REOPEN; 1267 } 1268 } 1269 1270 LIST_FOREACH(xm, xconf, entry) 1271 if (mrt_get(nconf, xm) == NULL) 1272 /* REMOVE */ 1273 xm->state = MRT_STATE_REMOVE; 1274 1275 /* free config */ 1276 while ((m = LIST_FIRST(nconf)) != NULL) { 1277 LIST_REMOVE(m, entry); 1278 free(m); 1279 } 1280 } 1281