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