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