1 /* $OpenBSD: mrt.c,v 1.103 2020/01/09 11:55:25 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 *, u_int16_t, 40 struct rde_peer*); 41 int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, struct rde_peer*); 42 int mrt_dump_entry_v2(struct mrt *, struct rib_entry *, u_int32_t); 43 int mrt_dump_peer(struct ibuf *, struct rde_peer *); 44 int mrt_dump_hdr_se(struct ibuf **, struct peer *, u_int16_t, u_int16_t, 45 u_int32_t, int); 46 int mrt_dump_hdr_rde(struct ibuf **, u_int16_t type, u_int16_t, u_int32_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 u_int16_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 u_int32_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 u_int32_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 void 95 mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen, 96 struct peer *peer) 97 { 98 struct ibuf *buf; 99 int incoming = 0; 100 u_int16_t subtype = BGP4MP_MESSAGE; 101 102 if (peer->capa.neg.as4byte) 103 subtype = BGP4MP_MESSAGE_AS4; 104 105 /* get the direction of the message to swap address and AS fields */ 106 if (mrt->type == MRT_ALL_IN || mrt->type == MRT_UPDATE_IN) 107 incoming = 1; 108 109 if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype, 110 pkglen, incoming) == -1) 111 return; 112 113 if (ibuf_add(buf, pkg, pkglen) == -1) { 114 log_warn("mrt_dump_bgp_msg: ibuf_add error"); 115 ibuf_free(buf); 116 return; 117 } 118 119 ibuf_close(&mrt->wbuf, buf); 120 } 121 122 void 123 mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state, 124 struct peer *peer) 125 { 126 struct ibuf *buf; 127 u_int16_t subtype = BGP4MP_STATE_CHANGE; 128 129 if (peer->capa.neg.as4byte) 130 subtype = BGP4MP_STATE_CHANGE_AS4; 131 132 if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP_ET, subtype, 133 2 * sizeof(short), 0) == -1) 134 return; 135 136 DUMP_SHORT(buf, old_state); 137 DUMP_SHORT(buf, new_state); 138 139 ibuf_close(&mrt->wbuf, buf); 140 return; 141 142 fail: 143 ibuf_free(buf); 144 } 145 146 int 147 mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct rde_community *c, 148 struct bgpd_addr *nexthop, int v2) 149 { 150 struct attr *oa; 151 u_char *pdata; 152 u_int32_t tmp; 153 int neednewpath = 0; 154 u_int16_t plen, afi; 155 u_int8_t l, safi; 156 157 /* origin */ 158 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN, 159 &a->origin, 1) == -1) 160 return (-1); 161 162 /* aspath */ 163 pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen); 164 if (!v2) 165 pdata = aspath_deflate(pdata, &plen, &neednewpath); 166 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata, 167 plen) == -1) { 168 free(pdata); 169 return (-1); 170 } 171 free(pdata); 172 173 if (nexthop && nexthop->aid == AID_INET) { 174 /* nexthop, already network byte order */ 175 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP, 176 &nexthop->v4.s_addr, 4) == -1) 177 return (-1); 178 } 179 180 /* MED, non transitive */ 181 if (a->med != 0) { 182 tmp = htonl(a->med); 183 if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MED, &tmp, 4) == -1) 184 return (-1); 185 } 186 187 /* local preference */ 188 tmp = htonl(a->lpref); 189 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1) 190 return (-1); 191 192 /* communities */ 193 if (community_writebuf(buf, c) == -1) 194 return (-1); 195 196 /* dump all other path attributes without modification */ 197 for (l = 0; l < a->others_len; l++) { 198 if ((oa = a->others[l]) == NULL) 199 break; 200 if (attr_writebuf(buf, oa->flags, oa->type, 201 oa->data, oa->len) == -1) 202 return (-1); 203 } 204 205 if (nexthop && nexthop->aid != AID_INET) { 206 struct ibuf *nhbuf; 207 208 if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL) 209 return (-1); 210 if (!v2) { 211 if (aid2afi(nexthop->aid, &afi, &safi)) 212 return (-1); 213 DUMP_SHORT(nhbuf, afi); 214 DUMP_BYTE(nhbuf, safi); 215 } 216 switch (nexthop->aid) { 217 case AID_INET6: 218 DUMP_BYTE(nhbuf, sizeof(struct in6_addr)); 219 if (ibuf_add(nhbuf, &nexthop->v6, 220 sizeof(struct in6_addr)) == -1) 221 goto fail; 222 break; 223 case AID_VPN_IPv4: 224 DUMP_BYTE(nhbuf, sizeof(u_int64_t) + 225 sizeof(struct in_addr)); 226 DUMP_NLONG(nhbuf, 0); /* set RD to 0 */ 227 DUMP_NLONG(nhbuf, 0); 228 DUMP_NLONG(nhbuf, nexthop->v4.s_addr); 229 break; 230 case AID_VPN_IPv6: 231 DUMP_BYTE(nhbuf, sizeof(u_int64_t) + 232 sizeof(struct in6_addr)); 233 DUMP_NLONG(nhbuf, 0); /* set RD to 0 */ 234 DUMP_NLONG(nhbuf, 0); 235 if (ibuf_add(nhbuf, &nexthop->v6, 236 sizeof(struct in6_addr)) == -1) 237 goto fail; 238 break; 239 } 240 if (!v2) 241 DUMP_BYTE(nhbuf, 0); 242 if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI, 243 nhbuf->buf, ibuf_size(nhbuf)) == -1) { 244 fail: 245 ibuf_free(nhbuf); 246 return (-1); 247 } 248 ibuf_free(nhbuf); 249 } 250 251 if (neednewpath) { 252 pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen); 253 if (plen != 0) 254 if (attr_writebuf(buf, ATTR_OPTIONAL|ATTR_TRANSITIVE, 255 ATTR_AS4_PATH, pdata, plen) == -1) { 256 free(pdata); 257 return (-1); 258 } 259 free(pdata); 260 } 261 262 return (0); 263 } 264 265 int 266 mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum, 267 struct rde_peer *peer) 268 { 269 struct ibuf *buf, *hbuf = NULL, *h2buf = NULL; 270 struct nexthop *n; 271 struct bgpd_addr addr, nexthop, *nh; 272 u_int16_t len; 273 u_int8_t aid; 274 275 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 276 log_warn("mrt_dump_entry_mp: ibuf_dynamic"); 277 return (-1); 278 } 279 280 if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p), 281 NULL, 0) == -1) { 282 log_warnx("mrt_dump_entry_mp: mrt_attr_dump error"); 283 goto fail; 284 } 285 len = ibuf_size(buf); 286 287 if ((h2buf = ibuf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE + 288 MRT_BGP4MP_IPv4_ENTRY_SIZE, MRT_BGP4MP_IPv6_HEADER_SIZE + 289 MRT_BGP4MP_IPv6_ENTRY_SIZE + MRT_BGP4MP_MAX_PREFIXLEN)) == NULL) { 290 log_warn("mrt_dump_entry_mp: ibuf_dynamic"); 291 goto fail; 292 } 293 294 DUMP_SHORT(h2buf, peer->conf.local_short_as); 295 DUMP_SHORT(h2buf, peer->short_as); 296 DUMP_SHORT(h2buf, /* ifindex */ 0); 297 298 /* XXX is this for peer self? */ 299 aid = peer->remote_addr.aid == AID_UNSPEC ? p->pt->aid : 300 peer->remote_addr.aid; 301 switch (aid) { 302 case AID_INET: 303 case AID_VPN_IPv4: 304 DUMP_SHORT(h2buf, AFI_IPv4); 305 DUMP_NLONG(h2buf, peer->local_v4_addr.v4.s_addr); 306 DUMP_NLONG(h2buf, peer->remote_addr.v4.s_addr); 307 break; 308 case AID_INET6: 309 case AID_VPN_IPv6: 310 DUMP_SHORT(h2buf, AFI_IPv6); 311 if (ibuf_add(h2buf, &peer->local_v6_addr.v6, 312 sizeof(struct in6_addr)) == -1 || 313 ibuf_add(h2buf, &peer->remote_addr.v6, 314 sizeof(struct in6_addr)) == -1) { 315 log_warn("mrt_dump_entry_mp: ibuf_add error"); 316 goto fail; 317 } 318 break; 319 default: 320 log_warnx("king bula found new AF %d in %s", aid, __func__); 321 goto fail; 322 } 323 324 DUMP_SHORT(h2buf, 0); /* view */ 325 DUMP_SHORT(h2buf, 1); /* status */ 326 /* originated timestamp */ 327 DUMP_LONG(h2buf, time(NULL) - (getmonotime() - p->lastchange)); 328 329 pt_getaddr(p->pt, &addr); 330 331 n = prefix_nexthop(p); 332 if (n == NULL) { 333 bzero(&nexthop, sizeof(struct bgpd_addr)); 334 nexthop.aid = addr.aid; 335 nh = &nexthop; 336 } else 337 nh = &n->exit_nexthop; 338 339 switch (addr.aid) { 340 case AID_INET: 341 DUMP_SHORT(h2buf, AFI_IPv4); /* afi */ 342 DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */ 343 DUMP_BYTE(h2buf, 4); /* nhlen */ 344 DUMP_NLONG(h2buf, nh->v4.s_addr); /* nexthop */ 345 break; 346 case AID_INET6: 347 DUMP_SHORT(h2buf, AFI_IPv6); /* afi */ 348 DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */ 349 DUMP_BYTE(h2buf, 16); /* nhlen */ 350 if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) { 351 log_warn("mrt_dump_entry_mp: ibuf_add error"); 352 goto fail; 353 } 354 break; 355 case AID_VPN_IPv4: 356 DUMP_SHORT(h2buf, AFI_IPv4); /* afi */ 357 DUMP_BYTE(h2buf, SAFI_MPLSVPN); /* safi */ 358 DUMP_BYTE(h2buf, sizeof(u_int64_t) + sizeof(struct in_addr)); 359 DUMP_NLONG(h2buf, 0); /* set RD to 0 */ 360 DUMP_NLONG(h2buf, 0); 361 DUMP_NLONG(h2buf, nh->v4.s_addr); /* nexthop */ 362 break; 363 case AID_VPN_IPv6: 364 DUMP_SHORT(h2buf, AFI_IPv6); /* afi */ 365 DUMP_BYTE(h2buf, SAFI_MPLSVPN); /* safi */ 366 DUMP_BYTE(h2buf, sizeof(u_int64_t) + sizeof(struct in6_addr)); 367 DUMP_NLONG(h2buf, 0); /* set RD to 0 */ 368 DUMP_NLONG(h2buf, 0); 369 if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) { 370 log_warn("mrt_dump_entry_mp: ibuf_add error"); 371 goto fail; 372 } 373 break; 374 default: 375 log_warnx("king bula found new AF in %s", __func__); 376 goto fail; 377 } 378 379 if (prefix_writebuf(h2buf, &addr, p->pt->prefixlen) == -1) { 380 log_warnx("%s: prefix_writebuf error", __func__); 381 goto fail; 382 } 383 384 DUMP_SHORT(h2buf, len); 385 len += ibuf_size(h2buf); 386 387 if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY, 388 len) == -1) 389 goto fail; 390 391 ibuf_close(&mrt->wbuf, hbuf); 392 ibuf_close(&mrt->wbuf, h2buf); 393 ibuf_close(&mrt->wbuf, buf); 394 395 return (len + MRT_HEADER_SIZE); 396 397 fail: 398 ibuf_free(hbuf); 399 ibuf_free(h2buf); 400 ibuf_free(buf); 401 return (-1); 402 } 403 404 int 405 mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, 406 struct rde_peer *peer) 407 { 408 struct ibuf *buf, *hbuf; 409 struct nexthop *nexthop; 410 struct bgpd_addr addr, *nh; 411 size_t len; 412 u_int16_t subtype; 413 u_int8_t dummy; 414 415 if (p->pt->aid != peer->remote_addr.aid && 416 p->pt->aid != AID_INET && p->pt->aid != AID_INET6) 417 /* only able to dump pure IPv4/IPv6 */ 418 return (0); 419 420 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 421 log_warn("mrt_dump_entry: ibuf_dynamic"); 422 return (-1); 423 } 424 425 nexthop = prefix_nexthop(p); 426 if (nexthop == NULL) { 427 bzero(&addr, sizeof(struct bgpd_addr)); 428 addr.aid = p->pt->aid; 429 nh = &addr; 430 } else 431 nh = &nexthop->exit_nexthop; 432 if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p), 433 nh, 0) == -1) { 434 log_warnx("mrt_dump_entry: mrt_attr_dump error"); 435 ibuf_free(buf); 436 return (-1); 437 } 438 len = ibuf_size(buf); 439 aid2afi(p->pt->aid, &subtype, &dummy); 440 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1) { 441 ibuf_free(buf); 442 return (-1); 443 } 444 445 DUMP_SHORT(hbuf, 0); 446 DUMP_SHORT(hbuf, snum); 447 448 pt_getaddr(p->pt, &addr); 449 switch (p->pt->aid) { 450 case AID_INET: 451 DUMP_NLONG(hbuf, addr.v4.s_addr); 452 break; 453 case AID_INET6: 454 if (ibuf_add(hbuf, &addr.v6, sizeof(struct in6_addr)) == -1) { 455 log_warn("mrt_dump_entry: ibuf_add error"); 456 goto fail; 457 } 458 break; 459 } 460 DUMP_BYTE(hbuf, p->pt->prefixlen); 461 462 DUMP_BYTE(hbuf, 1); /* state */ 463 /* originated timestamp */ 464 DUMP_LONG(hbuf, time(NULL) - (getmonotime() - p->lastchange)); 465 switch (p->pt->aid) { 466 case AID_INET: 467 DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr); 468 break; 469 case AID_INET6: 470 if (ibuf_add(hbuf, &peer->remote_addr.v6, 471 sizeof(struct in6_addr)) == -1) { 472 log_warn("mrt_dump_entry: ibuf_add error"); 473 goto fail; 474 } 475 break; 476 } 477 DUMP_SHORT(hbuf, peer->short_as); 478 DUMP_SHORT(hbuf, len); 479 480 ibuf_close(&mrt->wbuf, hbuf); 481 ibuf_close(&mrt->wbuf, buf); 482 483 return (len + MRT_HEADER_SIZE); 484 485 fail: 486 ibuf_free(hbuf); 487 ibuf_free(buf); 488 return (-1); 489 } 490 491 int 492 mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, u_int32_t snum) 493 { 494 struct ibuf *buf, *hbuf = NULL; 495 struct prefix *p; 496 struct bgpd_addr addr; 497 size_t len, off; 498 u_int16_t subtype, nump; 499 500 switch (re->prefix->aid) { 501 case AID_INET: 502 subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST; 503 break; 504 case AID_INET6: 505 subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST; 506 break; 507 default: 508 subtype = MRT_DUMP_V2_RIB_GENERIC; 509 break; 510 } 511 512 if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { 513 log_warn("%s: ibuf_dynamic", __func__); 514 return (-1); 515 } 516 517 DUMP_LONG(buf, snum); 518 pt_getaddr(re->prefix, &addr); 519 if (subtype == MRT_DUMP_V2_RIB_GENERIC) { 520 u_int16_t afi; 521 u_int8_t safi; 522 523 aid2afi(re->prefix->aid, &afi, &safi); 524 DUMP_SHORT(buf, afi); 525 DUMP_BYTE(buf, safi); 526 } 527 if (prefix_writebuf(buf, &addr, re->prefix->prefixlen) == -1) { 528 log_warnx("%s: prefix_writebuf error", __func__); 529 goto fail; 530 } 531 532 off = ibuf_size(buf); 533 if (ibuf_reserve(buf, sizeof(nump)) == NULL) { 534 log_warn("%s: ibuf_reserve error", __func__); 535 goto fail; 536 } 537 nump = 0; 538 LIST_FOREACH(p, &re->prefix_h, entry.list.rib) { 539 struct nexthop *nexthop; 540 struct bgpd_addr *nh; 541 struct ibuf *tbuf; 542 543 nexthop = prefix_nexthop(p); 544 if (nexthop == NULL) { 545 bzero(&addr, sizeof(struct bgpd_addr)); 546 addr.aid = re->prefix->aid; 547 nh = &addr; 548 } else 549 nh = &nexthop->exit_nexthop; 550 551 DUMP_SHORT(buf, prefix_peer(p)->mrt_idx); 552 /* originated timestamp */ 553 DUMP_LONG(buf, time(NULL) - (getmonotime() - p->lastchange)); 554 555 if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 556 log_warn("%s: ibuf_dynamic", __func__); 557 goto fail; 558 } 559 if (mrt_attr_dump(tbuf, prefix_aspath(p), prefix_communities(p), 560 nh, 1) == -1) { 561 log_warnx("%s: mrt_attr_dump error", __func__); 562 ibuf_free(tbuf); 563 goto fail; 564 } 565 len = ibuf_size(tbuf); 566 DUMP_SHORT(buf, (u_int16_t)len); 567 if (ibuf_add(buf, tbuf->buf, len) == -1) { 568 log_warn("%s: ibuf_add error", __func__); 569 ibuf_free(tbuf); 570 goto fail; 571 } 572 ibuf_free(tbuf); 573 nump++; 574 } 575 nump = htons(nump); 576 memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump)); 577 578 len = ibuf_size(buf); 579 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype, len) == -1) { 580 ibuf_free(buf); 581 return (-1); 582 } 583 584 ibuf_close(&mrt->wbuf, hbuf); 585 ibuf_close(&mrt->wbuf, buf); 586 587 return (0); 588 fail: 589 ibuf_free(hbuf); 590 ibuf_free(buf); 591 return (-1); 592 } 593 594 int 595 mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf, 596 struct rde_peer_head *ph) 597 { 598 struct rde_peer *peer; 599 struct ibuf *buf, *hbuf = NULL; 600 size_t len, off; 601 u_int16_t nlen, nump; 602 603 if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { 604 log_warn("%s: ibuf_dynamic", __func__); 605 return (-1); 606 } 607 608 DUMP_NLONG(buf, conf->bgpid); 609 nlen = strlen(mrt->rib); 610 if (nlen > 0) 611 nlen += 1; 612 DUMP_SHORT(buf, nlen); 613 if (ibuf_add(buf, mrt->rib, nlen) == -1) { 614 log_warn("%s: ibuf_add error", __func__); 615 goto fail; 616 } 617 618 off = ibuf_size(buf); 619 if (ibuf_reserve(buf, sizeof(nump)) == NULL) { 620 log_warn("%s: ibuf_reserve error", __func__); 621 goto fail; 622 } 623 nump = 0; 624 LIST_FOREACH(peer, ph, peer_l) { 625 peer->mrt_idx = nump; 626 if (mrt_dump_peer(buf, peer) == -1) 627 goto fail; 628 nump++; 629 } 630 nump = htons(nump); 631 memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump)); 632 633 len = ibuf_size(buf); 634 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, 635 MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1) 636 goto fail; 637 638 ibuf_close(&mrt->wbuf, hbuf); 639 ibuf_close(&mrt->wbuf, buf); 640 641 return (0); 642 fail: 643 ibuf_free(hbuf); 644 ibuf_free(buf); 645 return (-1); 646 } 647 648 int 649 mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer) 650 { 651 u_int8_t type = 0; 652 653 if (peer->capa.as4byte) 654 type |= MRT_DUMP_V2_PEER_BIT_A; 655 if (peer->remote_addr.aid == AID_INET6) 656 type |= MRT_DUMP_V2_PEER_BIT_I; 657 658 DUMP_BYTE(buf, type); 659 DUMP_LONG(buf, peer->remote_bgpid); 660 661 switch (peer->remote_addr.aid) { 662 case AID_INET: 663 DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); 664 break; 665 case AID_INET6: 666 if (ibuf_add(buf, &peer->remote_addr.v6, 667 sizeof(struct in6_addr)) == -1) { 668 log_warn("mrt_dump_peer: ibuf_add error"); 669 goto fail; 670 } 671 break; 672 case AID_UNSPEC: /* XXX special handling for peerself? */ 673 DUMP_NLONG(buf, 0); 674 break; 675 default: 676 log_warnx("king bula found new AF in %s", __func__); 677 goto fail; 678 } 679 680 if (peer->capa.as4byte) 681 DUMP_LONG(buf, peer->conf.remote_as); 682 else 683 DUMP_SHORT(buf, peer->short_as); 684 685 return (0); 686 fail: 687 return (-1); 688 } 689 690 void 691 mrt_dump_upcall(struct rib_entry *re, void *ptr) 692 { 693 struct mrt *mrtbuf = ptr; 694 struct prefix *p; 695 696 if (mrtbuf->type == MRT_TABLE_DUMP_V2) { 697 mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++); 698 return; 699 } 700 701 /* 702 * dump all prefixes even the inactive ones. That is the way zebra 703 * dumps the table so we do the same. If only the active route should 704 * be dumped p should be set to p = pt->active. 705 */ 706 LIST_FOREACH(p, &re->prefix_h, entry.list.rib) { 707 if (mrtbuf->type == MRT_TABLE_DUMP) 708 mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++, 709 prefix_peer(p)); 710 else 711 mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++, 712 prefix_peer(p)); 713 } 714 } 715 716 void 717 mrt_done(struct mrt *mrtbuf) 718 { 719 mrtbuf->state = MRT_STATE_REMOVE; 720 } 721 722 int 723 mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, u_int16_t type, 724 u_int16_t subtype, u_int32_t len, int swap) 725 { 726 struct timespec time; 727 728 if ((*bp = ibuf_dynamic(MRT_ET_HEADER_SIZE, MRT_ET_HEADER_SIZE + 729 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL) { 730 log_warn("mrt_dump_hdr_se: ibuf_dynamic error"); 731 return (-1); 732 } 733 734 clock_gettime(CLOCK_REALTIME, &time); 735 736 DUMP_LONG(*bp, time.tv_sec); 737 DUMP_SHORT(*bp, type); 738 DUMP_SHORT(*bp, subtype); 739 740 switch (peer->local.aid) { 741 case AID_INET: 742 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 743 subtype == BGP4MP_MESSAGE_AS4) 744 len += MRT_BGP4MP_ET_AS4_IPv4_HEADER_SIZE; 745 else 746 len += MRT_BGP4MP_ET_IPv4_HEADER_SIZE; 747 break; 748 case AID_INET6: 749 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 750 subtype == BGP4MP_MESSAGE_AS4) 751 len += MRT_BGP4MP_ET_AS4_IPv6_HEADER_SIZE; 752 else 753 len += MRT_BGP4MP_ET_IPv6_HEADER_SIZE; 754 break; 755 case 0: 756 goto fail; 757 default: 758 log_warnx("king bula found new AF in %s", __func__); 759 goto fail; 760 } 761 762 DUMP_LONG(*bp, len); 763 /* milisecond field use by the _ET format */ 764 DUMP_LONG(*bp, time.tv_nsec / 1000); 765 766 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 767 subtype == BGP4MP_MESSAGE_AS4) { 768 if (!swap) 769 DUMP_LONG(*bp, peer->conf.local_as); 770 DUMP_LONG(*bp, peer->conf.remote_as); 771 if (swap) 772 DUMP_LONG(*bp, peer->conf.local_as); 773 } else { 774 if (!swap) 775 DUMP_SHORT(*bp, peer->conf.local_short_as); 776 DUMP_SHORT(*bp, peer->short_as); 777 if (swap) 778 DUMP_SHORT(*bp, peer->conf.local_short_as); 779 } 780 781 DUMP_SHORT(*bp, /* ifindex */ 0); 782 783 switch (peer->local.aid) { 784 case AID_INET: 785 DUMP_SHORT(*bp, AFI_IPv4); 786 if (!swap) 787 DUMP_NLONG(*bp, peer->local.v4.s_addr); 788 DUMP_NLONG(*bp, peer->remote.v4.s_addr); 789 if (swap) 790 DUMP_NLONG(*bp, peer->local.v4.s_addr); 791 break; 792 case AID_INET6: 793 DUMP_SHORT(*bp, AFI_IPv6); 794 if (!swap) 795 if (ibuf_add(*bp, &peer->local.v6, 796 sizeof(struct in6_addr)) == -1) { 797 log_warn("mrt_dump_hdr_se: ibuf_add error"); 798 goto fail; 799 } 800 if (ibuf_add(*bp, &peer->remote.v6, 801 sizeof(struct in6_addr)) == -1) { 802 log_warn("mrt_dump_hdr_se: ibuf_add error"); 803 goto fail; 804 } 805 if (swap) 806 if (ibuf_add(*bp, &peer->local.v6, 807 sizeof(struct in6_addr)) == -1) { 808 log_warn("mrt_dump_hdr_se: ibuf_add error"); 809 goto fail; 810 } 811 break; 812 } 813 814 return (0); 815 816 fail: 817 ibuf_free(*bp); 818 return (-1); 819 } 820 821 int 822 mrt_dump_hdr_rde(struct ibuf **bp, u_int16_t type, u_int16_t subtype, 823 u_int32_t len) 824 { 825 struct timespec time; 826 827 if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE + 828 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) == 829 NULL) { 830 log_warn("mrt_dump_hdr_rde: ibuf_dynamic error"); 831 return (-1); 832 } 833 834 clock_gettime(CLOCK_REALTIME, &time); 835 836 DUMP_LONG(*bp, time.tv_sec); 837 DUMP_SHORT(*bp, type); 838 DUMP_SHORT(*bp, subtype); 839 840 switch (type) { 841 case MSG_TABLE_DUMP: 842 switch (subtype) { 843 case AFI_IPv4: 844 len += MRT_DUMP_HEADER_SIZE; 845 break; 846 case AFI_IPv6: 847 len += MRT_DUMP_HEADER_SIZE_V6; 848 break; 849 } 850 DUMP_LONG(*bp, len); 851 break; 852 case MSG_PROTOCOL_BGP4MP: 853 case MSG_TABLE_DUMP_V2: 854 DUMP_LONG(*bp, len); 855 break; 856 default: 857 log_warnx("mrt_dump_hdr_rde: unsupported type"); 858 goto fail; 859 } 860 return (0); 861 862 fail: 863 ibuf_free(*bp); 864 *bp = NULL; 865 return (-1); 866 } 867 868 void 869 mrt_write(struct mrt *mrt) 870 { 871 int r; 872 873 if ((r = ibuf_write(&mrt->wbuf)) == -1 && errno != EAGAIN) { 874 log_warn("mrt dump aborted, mrt_write"); 875 mrt_clean(mrt); 876 mrt_done(mrt); 877 } 878 } 879 880 void 881 mrt_clean(struct mrt *mrt) 882 { 883 struct ibuf *b; 884 885 close(mrt->wbuf.fd); 886 while ((b = TAILQ_FIRST(&mrt->wbuf.bufs))) { 887 TAILQ_REMOVE(&mrt->wbuf.bufs, b, entry); 888 ibuf_free(b); 889 } 890 mrt->wbuf.queued = 0; 891 } 892 893 static struct imsgbuf *mrt_imsgbuf[2]; 894 895 void 896 mrt_init(struct imsgbuf *rde, struct imsgbuf *se) 897 { 898 mrt_imsgbuf[RDEIDX] = rde; 899 mrt_imsgbuf[SEIDX] = se; 900 } 901 902 int 903 mrt_open(struct mrt *mrt, time_t now) 904 { 905 enum imsg_type type; 906 int fd; 907 908 if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file), 909 MRT2MC(mrt)->name, localtime(&now)) == 0) { 910 log_warnx("mrt_open: strftime conversion failed"); 911 return (-1); 912 } 913 914 fd = open(MRT2MC(mrt)->file, 915 O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC|O_CLOEXEC, 0644); 916 if (fd == -1) { 917 log_warn("mrt_open %s", MRT2MC(mrt)->file); 918 return (1); 919 } 920 921 if (mrt->state == MRT_STATE_OPEN) 922 type = IMSG_MRT_OPEN; 923 else 924 type = IMSG_MRT_REOPEN; 925 926 if (imsg_compose(mrt_imsgbuf[TYPE2IDX(mrt->type)], type, 0, 0, fd, 927 mrt, sizeof(struct mrt)) == -1) 928 log_warn("mrt_open"); 929 930 return (1); 931 } 932 933 time_t 934 mrt_timeout(struct mrt_head *mrt) 935 { 936 struct mrt *m; 937 time_t now; 938 time_t timeout = -1; 939 940 now = time(NULL); 941 LIST_FOREACH(m, mrt, entry) { 942 if (m->state == MRT_STATE_RUNNING && 943 MRT2MC(m)->ReopenTimerInterval != 0) { 944 if (MRT2MC(m)->ReopenTimer <= now) { 945 mrt_open(m, now); 946 MRT2MC(m)->ReopenTimer = 947 now + MRT2MC(m)->ReopenTimerInterval; 948 } 949 if (timeout == -1 || 950 MRT2MC(m)->ReopenTimer - now < timeout) 951 timeout = MRT2MC(m)->ReopenTimer - now; 952 } 953 } 954 return (timeout); 955 } 956 957 void 958 mrt_reconfigure(struct mrt_head *mrt) 959 { 960 struct mrt *m, *xm; 961 time_t now; 962 963 now = time(NULL); 964 for (m = LIST_FIRST(mrt); m != NULL; m = xm) { 965 xm = LIST_NEXT(m, entry); 966 if (m->state == MRT_STATE_OPEN || 967 m->state == MRT_STATE_REOPEN) { 968 if (mrt_open(m, now) == -1) 969 continue; 970 if (MRT2MC(m)->ReopenTimerInterval != 0) 971 MRT2MC(m)->ReopenTimer = 972 now + MRT2MC(m)->ReopenTimerInterval; 973 m->state = MRT_STATE_RUNNING; 974 } 975 if (m->state == MRT_STATE_REMOVE) { 976 if (imsg_compose(mrt_imsgbuf[TYPE2IDX(m->type)], 977 IMSG_MRT_CLOSE, 0, 0, -1, m, sizeof(struct mrt)) == 978 -1) 979 log_warn("mrt_reconfigure"); 980 LIST_REMOVE(m, entry); 981 free(m); 982 continue; 983 } 984 } 985 } 986 987 void 988 mrt_handler(struct mrt_head *mrt) 989 { 990 struct mrt *m; 991 time_t now; 992 993 now = time(NULL); 994 LIST_FOREACH(m, mrt, entry) { 995 if (m->state == MRT_STATE_RUNNING && 996 (MRT2MC(m)->ReopenTimerInterval != 0 || 997 m->type == MRT_TABLE_DUMP || 998 m->type == MRT_TABLE_DUMP_MP || 999 m->type == MRT_TABLE_DUMP_V2)) { 1000 if (mrt_open(m, now) == -1) 1001 continue; 1002 MRT2MC(m)->ReopenTimer = 1003 now + MRT2MC(m)->ReopenTimerInterval; 1004 } 1005 } 1006 } 1007 1008 struct mrt * 1009 mrt_get(struct mrt_head *c, struct mrt *m) 1010 { 1011 struct mrt *t; 1012 1013 LIST_FOREACH(t, c, entry) { 1014 if (t->type != m->type) 1015 continue; 1016 if (strcmp(t->rib, m->rib)) 1017 continue; 1018 if (t->peer_id == m->peer_id && 1019 t->group_id == m->group_id) 1020 return (t); 1021 } 1022 return (NULL); 1023 } 1024 1025 void 1026 mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf) 1027 { 1028 struct mrt *m, *xm; 1029 1030 /* both lists here are actually struct mrt_conifg nodes */ 1031 LIST_FOREACH(m, nconf, entry) { 1032 if ((xm = mrt_get(xconf, m)) == NULL) { 1033 /* NEW */ 1034 if ((xm = malloc(sizeof(struct mrt_config))) == NULL) 1035 fatal("mrt_mergeconfig"); 1036 memcpy(xm, m, sizeof(struct mrt_config)); 1037 xm->state = MRT_STATE_OPEN; 1038 LIST_INSERT_HEAD(xconf, xm, entry); 1039 } else { 1040 /* MERGE */ 1041 if (strlcpy(MRT2MC(xm)->name, MRT2MC(m)->name, 1042 sizeof(MRT2MC(xm)->name)) >= 1043 sizeof(MRT2MC(xm)->name)) 1044 fatalx("mrt_mergeconfig: strlcpy"); 1045 MRT2MC(xm)->ReopenTimerInterval = 1046 MRT2MC(m)->ReopenTimerInterval; 1047 xm->state = MRT_STATE_REOPEN; 1048 } 1049 } 1050 1051 LIST_FOREACH(xm, xconf, entry) 1052 if (mrt_get(nconf, xm) == NULL) 1053 /* REMOVE */ 1054 xm->state = MRT_STATE_REMOVE; 1055 1056 /* free config */ 1057 while ((m = LIST_FIRST(nconf)) != NULL) { 1058 LIST_REMOVE(m, entry); 1059 free(m); 1060 } 1061 } 1062