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