1 /* $OpenBSD: mrt.c,v 1.77 2014/04/19 15:43:17 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 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 if (hbuf) 359 ibuf_free(hbuf); 360 if (h2buf) 361 ibuf_free(h2buf); 362 ibuf_free(buf); 363 return (-1); 364 } 365 366 int 367 mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, 368 struct rde_peer *peer) 369 { 370 struct ibuf *buf, *hbuf; 371 struct bgpd_addr addr, *nh; 372 size_t len; 373 u_int16_t subtype; 374 u_int8_t dummy; 375 376 if (p->prefix->aid != peer->remote_addr.aid && 377 p->prefix->aid != AID_INET && p->prefix->aid != AID_INET6) 378 /* only able to dump pure IPv4/IPv6 */ 379 return (0); 380 381 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 382 log_warn("mrt_dump_entry: ibuf_dynamic"); 383 return (-1); 384 } 385 386 if (p->aspath->nexthop == NULL) { 387 bzero(&addr, sizeof(struct bgpd_addr)); 388 addr.aid = p->prefix->aid; 389 nh = &addr; 390 } else 391 nh = &p->aspath->nexthop->exit_nexthop; 392 if (mrt_attr_dump(buf, p->aspath, nh, 0) == -1) { 393 log_warnx("mrt_dump_entry: mrt_attr_dump error"); 394 ibuf_free(buf); 395 return (-1); 396 } 397 len = ibuf_size(buf); 398 aid2afi(p->prefix->aid, &subtype, &dummy); 399 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1) { 400 ibuf_free(buf); 401 return (-1); 402 } 403 404 DUMP_SHORT(hbuf, 0); 405 DUMP_SHORT(hbuf, snum); 406 407 pt_getaddr(p->prefix, &addr); 408 switch (p->prefix->aid) { 409 case AID_INET: 410 DUMP_NLONG(hbuf, addr.v4.s_addr); 411 break; 412 case AID_INET6: 413 if (ibuf_add(hbuf, &addr.v6, sizeof(struct in6_addr)) == -1) { 414 log_warn("mrt_dump_entry: ibuf_add error"); 415 goto fail; 416 } 417 break; 418 } 419 DUMP_BYTE(hbuf, p->prefix->prefixlen); 420 421 DUMP_BYTE(hbuf, 1); /* state */ 422 DUMP_LONG(hbuf, p->lastchange); /* originated */ 423 switch (p->prefix->aid) { 424 case AID_INET: 425 DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr); 426 break; 427 case AID_INET6: 428 if (ibuf_add(hbuf, &peer->remote_addr.v6, 429 sizeof(struct in6_addr)) == -1) { 430 log_warn("mrt_dump_entry: ibuf_add error"); 431 goto fail; 432 } 433 break; 434 } 435 DUMP_SHORT(hbuf, peer->short_as); 436 DUMP_SHORT(hbuf, len); 437 438 ibuf_close(&mrt->wbuf, hbuf); 439 ibuf_close(&mrt->wbuf, buf); 440 441 return (len + MRT_HEADER_SIZE); 442 443 fail: 444 ibuf_free(hbuf); 445 ibuf_free(buf); 446 return (-1); 447 } 448 449 int 450 mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, u_int32_t snum) 451 { 452 struct ibuf *buf, *hbuf = NULL; 453 struct prefix *p; 454 struct bgpd_addr addr; 455 size_t len, off; 456 u_int16_t subtype, nump; 457 458 switch (re->prefix->aid) { 459 case AID_INET: 460 subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST; 461 break; 462 case AID_INET6: 463 subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST; 464 break; 465 default: 466 subtype = MRT_DUMP_V2_RIB_GENERIC; 467 break; 468 } 469 470 if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { 471 log_warn("mrt_dump_entry: ibuf_dynamic"); 472 return (-1); 473 } 474 475 DUMP_LONG(buf, snum); 476 pt_getaddr(re->prefix, &addr); 477 if (subtype == MRT_DUMP_V2_RIB_GENERIC) { 478 u_int16_t afi; 479 u_int8_t safi; 480 481 aid2afi(re->prefix->aid, &afi, &safi); 482 DUMP_SHORT(buf, afi); 483 DUMP_BYTE(buf, safi); 484 } 485 if (prefix_writebuf(buf, &addr, re->prefix->prefixlen) == -1) { 486 log_warn("mrt_dump_entry_mp: prefix_writebuf error"); 487 goto fail; 488 } 489 490 off = ibuf_size(buf); 491 if (ibuf_reserve(buf, sizeof(nump)) == NULL) { 492 log_warn("mrt_dump_v2_hdr: ibuf_reserve error"); 493 goto fail; 494 } 495 nump = 0; 496 LIST_FOREACH(p, &re->prefix_h, rib_l) { 497 struct bgpd_addr *nh; 498 struct ibuf *tbuf; 499 500 if (p->aspath->nexthop == NULL) { 501 bzero(&addr, sizeof(struct bgpd_addr)); 502 addr.aid = p->prefix->aid; 503 nh = &addr; 504 } else 505 nh = &p->aspath->nexthop->exit_nexthop; 506 507 DUMP_SHORT(buf, p->aspath->peer->mrt_idx); 508 DUMP_LONG(buf, p->lastchange); /* originated */ 509 510 if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 511 log_warn("mrt_dump_entry_v2: ibuf_dynamic"); 512 return (-1); 513 } 514 if (mrt_attr_dump(tbuf, p->aspath, nh, 1) == -1) { 515 log_warnx("mrt_dump_entry_v2: mrt_attr_dump error"); 516 ibuf_free(buf); 517 return (-1); 518 } 519 len = ibuf_size(tbuf); 520 DUMP_SHORT(buf, (u_int16_t)len); 521 if (ibuf_add(buf, tbuf->buf, ibuf_size(tbuf)) == -1) { 522 log_warn("mrt_dump_entry_v2: ibuf_add error"); 523 ibuf_free(tbuf); 524 return (-1); 525 } 526 ibuf_free(tbuf); 527 nump++; 528 } 529 nump = htons(nump); 530 memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump)); 531 532 len = ibuf_size(buf); 533 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype, len) == -1) { 534 ibuf_free(buf); 535 return (-1); 536 } 537 538 ibuf_close(&mrt->wbuf, hbuf); 539 ibuf_close(&mrt->wbuf, buf); 540 541 return (0); 542 fail: 543 if (hbuf) 544 ibuf_free(hbuf); 545 ibuf_free(buf); 546 return (-1); 547 } 548 549 int 550 mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf, 551 struct rde_peer_head *ph) 552 { 553 struct rde_peer *peer; 554 struct ibuf *buf, *hbuf = NULL; 555 size_t len, off; 556 u_int16_t nlen, nump; 557 558 if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) { 559 log_warn("mrt_dump_v2_hdr: ibuf_dynamic"); 560 return (-1); 561 } 562 563 DUMP_NLONG(buf, conf->bgpid); 564 nlen = strlen(mrt->rib); 565 if (nlen > 0) 566 nlen += 1; 567 DUMP_SHORT(buf, nlen); 568 if (ibuf_add(buf, mrt->rib, nlen) == -1) { 569 log_warn("mrt_dump_v2_hdr: ibuf_add error"); 570 goto fail; 571 } 572 573 off = ibuf_size(buf); 574 if (ibuf_reserve(buf, sizeof(nump)) == NULL) { 575 log_warn("mrt_dump_v2_hdr: ibuf_reserve error"); 576 goto fail; 577 } 578 nump = 0; 579 LIST_FOREACH(peer, ph, peer_l) { 580 peer->mrt_idx = nump; 581 if (mrt_dump_peer(buf, peer) == -1) 582 goto fail; 583 nump++; 584 } 585 nump = htons(nump); 586 memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump)); 587 588 len = ibuf_size(buf); 589 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, 590 MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1) 591 goto fail; 592 593 ibuf_close(&mrt->wbuf, hbuf); 594 ibuf_close(&mrt->wbuf, buf); 595 596 return (0); 597 fail: 598 if (hbuf) 599 ibuf_free(hbuf); 600 ibuf_free(buf); 601 return (-1); 602 } 603 604 int 605 mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer) 606 { 607 u_int8_t type = 0; 608 609 if (peer->capa.as4byte) 610 type |= MRT_DUMP_V2_PEER_BIT_A; 611 if (peer->remote_addr.aid == AID_INET6) 612 type |= MRT_DUMP_V2_PEER_BIT_I; 613 614 DUMP_BYTE(buf, type); 615 DUMP_LONG(buf, peer->remote_bgpid); 616 617 switch (peer->remote_addr.aid) { 618 case AID_INET: 619 DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); 620 break; 621 case AID_INET6: 622 if (ibuf_add(buf, &peer->remote_addr.v6, 623 sizeof(struct in6_addr)) == -1) { 624 log_warn("mrt_dump_peer: ibuf_add error"); 625 goto fail; 626 } 627 break; 628 case AID_UNSPEC: /* XXX special handling for peer_self? */ 629 DUMP_NLONG(buf, 0); 630 break; 631 default: 632 log_warnx("king bula found new AF in mrt_dump_entry_mp"); 633 goto fail; 634 } 635 636 if (peer->capa.as4byte) 637 DUMP_LONG(buf, peer->conf.remote_as); 638 else 639 DUMP_SHORT(buf, peer->short_as); 640 641 return (0); 642 fail: 643 return (-1); 644 } 645 646 void 647 mrt_dump_upcall(struct rib_entry *re, void *ptr) 648 { 649 struct mrt *mrtbuf = ptr; 650 struct prefix *p; 651 652 if (mrtbuf->type == MRT_TABLE_DUMP_V2) { 653 mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++); 654 return; 655 } 656 657 /* 658 * dump all prefixes even the inactive ones. That is the way zebra 659 * dumps the table so we do the same. If only the active route should 660 * be dumped p should be set to p = pt->active. 661 */ 662 LIST_FOREACH(p, &re->prefix_h, rib_l) { 663 if (mrtbuf->type == MRT_TABLE_DUMP) 664 mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++, 665 p->aspath->peer); 666 else 667 mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++, 668 p->aspath->peer); 669 } 670 } 671 672 void 673 mrt_done(void *ptr) 674 { 675 struct mrt *mrtbuf = ptr; 676 677 mrtbuf->state = MRT_STATE_REMOVE; 678 } 679 680 int 681 mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, u_int16_t type, 682 u_int16_t subtype, u_int32_t len, int swap) 683 { 684 time_t now; 685 686 if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE + 687 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL) { 688 log_warn("mrt_dump_hdr_se: ibuf_dynamic error"); 689 return (-1); 690 } 691 692 now = time(NULL); 693 694 DUMP_LONG(*bp, now); 695 DUMP_SHORT(*bp, type); 696 DUMP_SHORT(*bp, subtype); 697 698 switch (peer->sa_local.ss_family) { 699 case AF_INET: 700 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 701 subtype == BGP4MP_MESSAGE_AS4) 702 len += MRT_BGP4MP_AS4_IPv4_HEADER_SIZE; 703 else 704 len += MRT_BGP4MP_IPv4_HEADER_SIZE; 705 break; 706 case AF_INET6: 707 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 708 subtype == BGP4MP_MESSAGE_AS4) 709 len += MRT_BGP4MP_AS4_IPv6_HEADER_SIZE; 710 else 711 len += MRT_BGP4MP_IPv6_HEADER_SIZE; 712 break; 713 case 0: 714 goto fail; 715 default: 716 log_warnx("king bula found new AF in mrt_dump_hdr_se"); 717 goto fail; 718 } 719 720 DUMP_LONG(*bp, len); 721 722 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 723 subtype == BGP4MP_MESSAGE_AS4) { 724 if (!swap) 725 DUMP_LONG(*bp, peer->conf.local_as); 726 DUMP_LONG(*bp, peer->conf.remote_as); 727 if (swap) 728 DUMP_LONG(*bp, peer->conf.local_as); 729 } else { 730 if (!swap) 731 DUMP_SHORT(*bp, peer->conf.local_short_as); 732 DUMP_SHORT(*bp, peer->short_as); 733 if (swap) 734 DUMP_SHORT(*bp, peer->conf.local_short_as); 735 } 736 737 DUMP_SHORT(*bp, /* ifindex */ 0); 738 739 switch (peer->sa_local.ss_family) { 740 case AF_INET: 741 DUMP_SHORT(*bp, AFI_IPv4); 742 if (!swap) 743 DUMP_NLONG(*bp, ((struct sockaddr_in *) 744 &peer->sa_local)->sin_addr.s_addr); 745 DUMP_NLONG(*bp, 746 ((struct sockaddr_in *)&peer->sa_remote)->sin_addr.s_addr); 747 if (swap) 748 DUMP_NLONG(*bp, ((struct sockaddr_in *) 749 &peer->sa_local)->sin_addr.s_addr); 750 break; 751 case AF_INET6: 752 DUMP_SHORT(*bp, AFI_IPv6); 753 if (!swap) 754 if (ibuf_add(*bp, &((struct sockaddr_in6 *) 755 &peer->sa_local)->sin6_addr, 756 sizeof(struct in6_addr)) == -1) { 757 log_warn("mrt_dump_hdr_se: ibuf_add error"); 758 goto fail; 759 } 760 if (ibuf_add(*bp, 761 &((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr, 762 sizeof(struct in6_addr)) == -1) { 763 log_warn("mrt_dump_hdr_se: ibuf_add error"); 764 goto fail; 765 } 766 if (swap) 767 if (ibuf_add(*bp, &((struct sockaddr_in6 *) 768 &peer->sa_local)->sin6_addr, 769 sizeof(struct in6_addr)) == -1) { 770 log_warn("mrt_dump_hdr_se: ibuf_add error"); 771 goto fail; 772 } 773 break; 774 } 775 776 return (0); 777 778 fail: 779 ibuf_free(*bp); 780 return (-1); 781 } 782 783 int 784 mrt_dump_hdr_rde(struct ibuf **bp, u_int16_t type, u_int16_t subtype, 785 u_int32_t len) 786 { 787 time_t now; 788 789 if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE + 790 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) == 791 NULL) { 792 log_warn("mrt_dump_hdr_rde: ibuf_dynamic error"); 793 return (-1); 794 } 795 796 now = time(NULL); 797 DUMP_LONG(*bp, now); 798 DUMP_SHORT(*bp, type); 799 DUMP_SHORT(*bp, subtype); 800 801 switch (type) { 802 case MSG_TABLE_DUMP: 803 switch (subtype) { 804 case AFI_IPv4: 805 len += MRT_DUMP_HEADER_SIZE; 806 break; 807 case AFI_IPv6: 808 len += MRT_DUMP_HEADER_SIZE_V6; 809 break; 810 } 811 DUMP_LONG(*bp, len); 812 break; 813 case MSG_PROTOCOL_BGP4MP: 814 case MSG_TABLE_DUMP_V2: 815 DUMP_LONG(*bp, len); 816 break; 817 default: 818 log_warnx("mrt_dump_hdr_rde: unsupported type"); 819 goto fail; 820 } 821 return (0); 822 823 fail: 824 ibuf_free(*bp); 825 return (-1); 826 } 827 828 void 829 mrt_write(struct mrt *mrt) 830 { 831 int r; 832 833 if ((r = ibuf_write(&mrt->wbuf)) < 0 && errno != EAGAIN) { 834 log_warn("mrt dump aborted, mrt_write"); 835 mrt_clean(mrt); 836 mrt_done(mrt); 837 } 838 } 839 840 void 841 mrt_clean(struct mrt *mrt) 842 { 843 struct ibuf *b; 844 845 close(mrt->wbuf.fd); 846 while ((b = TAILQ_FIRST(&mrt->wbuf.bufs))) { 847 TAILQ_REMOVE(&mrt->wbuf.bufs, b, entry); 848 ibuf_free(b); 849 } 850 mrt->wbuf.queued = 0; 851 } 852 853 static struct imsgbuf *mrt_imsgbuf[2]; 854 855 void 856 mrt_init(struct imsgbuf *rde, struct imsgbuf *se) 857 { 858 mrt_imsgbuf[RDEIDX] = rde; 859 mrt_imsgbuf[SEIDX] = se; 860 } 861 862 int 863 mrt_open(struct mrt *mrt, time_t now) 864 { 865 enum imsg_type type; 866 int fd; 867 868 if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file), 869 MRT2MC(mrt)->name, localtime(&now)) == 0) { 870 log_warnx("mrt_open: strftime conversion failed"); 871 return (-1); 872 } 873 874 fd = open(MRT2MC(mrt)->file, 875 O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC, 0644); 876 if (fd == -1) { 877 log_warn("mrt_open %s", MRT2MC(mrt)->file); 878 return (1); 879 } 880 881 if (mrt->state == MRT_STATE_OPEN) 882 type = IMSG_MRT_OPEN; 883 else 884 type = IMSG_MRT_REOPEN; 885 886 if (imsg_compose(mrt_imsgbuf[TYPE2IDX(mrt->type)], type, 0, 0, fd, 887 mrt, sizeof(struct mrt)) == -1) 888 log_warn("mrt_open"); 889 890 return (1); 891 } 892 893 int 894 mrt_timeout(struct mrt_head *mrt) 895 { 896 struct mrt *m; 897 time_t now; 898 int timeout = MRT_MAX_TIMEOUT; 899 900 now = time(NULL); 901 LIST_FOREACH(m, mrt, entry) { 902 if (m->state == MRT_STATE_RUNNING && 903 MRT2MC(m)->ReopenTimerInterval != 0) { 904 if (MRT2MC(m)->ReopenTimer <= now) { 905 mrt_open(m, now); 906 MRT2MC(m)->ReopenTimer = 907 now + MRT2MC(m)->ReopenTimerInterval; 908 } 909 if (MRT2MC(m)->ReopenTimer - now < timeout) 910 timeout = MRT2MC(m)->ReopenTimer - now; 911 } 912 } 913 return (timeout > 0 ? timeout : 0); 914 } 915 916 void 917 mrt_reconfigure(struct mrt_head *mrt) 918 { 919 struct mrt *m, *xm; 920 time_t now; 921 922 now = time(NULL); 923 for (m = LIST_FIRST(mrt); m != NULL; m = xm) { 924 xm = LIST_NEXT(m, entry); 925 if (m->state == MRT_STATE_OPEN || 926 m->state == MRT_STATE_REOPEN) { 927 if (mrt_open(m, now) == -1) 928 continue; 929 if (MRT2MC(m)->ReopenTimerInterval != 0) 930 MRT2MC(m)->ReopenTimer = 931 now + MRT2MC(m)->ReopenTimerInterval; 932 m->state = MRT_STATE_RUNNING; 933 } 934 if (m->state == MRT_STATE_REMOVE) { 935 if (imsg_compose(mrt_imsgbuf[TYPE2IDX(m->type)], 936 IMSG_MRT_CLOSE, 0, 0, -1, m, sizeof(struct mrt)) == 937 -1) 938 log_warn("mrt_reconfigure"); 939 LIST_REMOVE(m, entry); 940 free(m); 941 continue; 942 } 943 } 944 } 945 946 void 947 mrt_handler(struct mrt_head *mrt) 948 { 949 struct mrt *m; 950 time_t now; 951 952 now = time(NULL); 953 LIST_FOREACH(m, mrt, entry) { 954 if (m->state == MRT_STATE_RUNNING && 955 (MRT2MC(m)->ReopenTimerInterval != 0 || 956 m->type == MRT_TABLE_DUMP || 957 m->type == MRT_TABLE_DUMP_MP || 958 m->type == MRT_TABLE_DUMP_V2)) { 959 if (mrt_open(m, now) == -1) 960 continue; 961 MRT2MC(m)->ReopenTimer = 962 now + MRT2MC(m)->ReopenTimerInterval; 963 } 964 } 965 } 966 967 struct mrt * 968 mrt_get(struct mrt_head *c, struct mrt *m) 969 { 970 struct mrt *t; 971 972 LIST_FOREACH(t, c, entry) { 973 if (t->type != m->type) 974 continue; 975 if (strcmp(t->rib, m->rib)) 976 continue; 977 if (t->peer_id == m->peer_id && 978 t->group_id == m->group_id) 979 return (t); 980 } 981 return (NULL); 982 } 983 984 int 985 mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf) 986 { 987 struct mrt *m, *xm; 988 989 /* both lists here are actually struct mrt_conifg nodes */ 990 LIST_FOREACH(m, nconf, entry) { 991 if ((xm = mrt_get(xconf, m)) == NULL) { 992 /* NEW */ 993 if ((xm = (struct mrt *)calloc(1, 994 sizeof(struct mrt_config))) == NULL) 995 fatal("mrt_mergeconfig"); 996 memcpy(xm, m, sizeof(struct mrt_config)); 997 xm->state = MRT_STATE_OPEN; 998 LIST_INSERT_HEAD(xconf, xm, entry); 999 } else { 1000 /* MERGE */ 1001 if (strlcpy(MRT2MC(xm)->name, MRT2MC(m)->name, 1002 sizeof(MRT2MC(xm)->name)) >= 1003 sizeof(MRT2MC(xm)->name)) 1004 fatalx("mrt_mergeconfig: strlcpy"); 1005 MRT2MC(xm)->ReopenTimerInterval = 1006 MRT2MC(m)->ReopenTimerInterval; 1007 xm->state = MRT_STATE_REOPEN; 1008 } 1009 } 1010 1011 LIST_FOREACH(xm, xconf, entry) 1012 if (mrt_get(nconf, xm) == NULL) 1013 /* REMOVE */ 1014 xm->state = MRT_STATE_REMOVE; 1015 1016 /* free config */ 1017 while ((m = LIST_FIRST(nconf)) != NULL) { 1018 LIST_REMOVE(m, entry); 1019 free(m); 1020 } 1021 1022 return (0); 1023 } 1024