1 /* $OpenBSD: mrt.c,v 1.70 2010/09/02 14:03:21 sobrado 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 <stdlib.h> 25 #include <string.h> 26 #include <time.h> 27 #include <unistd.h> 28 29 #include "bgpd.h" 30 #include "rde.h" 31 #include "session.h" 32 33 #include "mrt.h" 34 35 int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct bgpd_addr *); 36 int mrt_dump_entry_mp(struct mrt *, struct prefix *, u_int16_t, 37 struct rde_peer*); 38 int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, struct rde_peer*); 39 int mrt_dump_hdr_se(struct ibuf **, struct peer *, u_int16_t, u_int16_t, 40 u_int32_t, int); 41 int mrt_dump_hdr_rde(struct ibuf **, u_int16_t type, u_int16_t, u_int32_t); 42 int mrt_open(struct mrt *, time_t); 43 44 #define DUMP_BYTE(x, b) \ 45 do { \ 46 u_char t = (b); \ 47 if (ibuf_add((x), &t, sizeof(t)) == -1) { \ 48 log_warnx("mrt_dump1: ibuf_add error"); \ 49 goto fail; \ 50 } \ 51 } while (0) 52 53 #define DUMP_SHORT(x, s) \ 54 do { \ 55 u_int16_t t; \ 56 t = htons((s)); \ 57 if (ibuf_add((x), &t, sizeof(t)) == -1) { \ 58 log_warnx("mrt_dump2: ibuf_add error"); \ 59 goto fail; \ 60 } \ 61 } while (0) 62 63 #define DUMP_LONG(x, l) \ 64 do { \ 65 u_int32_t t; \ 66 t = htonl((l)); \ 67 if (ibuf_add((x), &t, sizeof(t)) == -1) { \ 68 log_warnx("mrt_dump3: ibuf_add error"); \ 69 goto fail; \ 70 } \ 71 } while (0) 72 73 #define DUMP_NLONG(x, l) \ 74 do { \ 75 u_int32_t t = (l); \ 76 if (ibuf_add((x), &t, sizeof(t)) == -1) { \ 77 log_warnx("mrt_dump4: ibuf_add error"); \ 78 goto fail; \ 79 } \ 80 } while (0) 81 82 void 83 mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen, 84 struct peer *peer) 85 { 86 struct ibuf *buf; 87 int incoming = 0; 88 u_int16_t subtype = BGP4MP_MESSAGE; 89 90 if (peer->capa.neg.as4byte) 91 subtype = BGP4MP_MESSAGE_AS4; 92 93 /* get the direction of the message to swap address and AS fields */ 94 if (mrt->type == MRT_ALL_IN || mrt->type == MRT_UPDATE_IN) 95 incoming = 1; 96 97 if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, subtype, 98 pkglen, incoming) == -1) 99 return; 100 101 if (ibuf_add(buf, pkg, pkglen) == -1) { 102 log_warnx("mrt_dump_bgp_msg: buf_add error"); 103 ibuf_free(buf); 104 return; 105 } 106 107 ibuf_close(&mrt->wbuf, buf); 108 } 109 110 void 111 mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state, 112 struct peer *peer) 113 { 114 struct ibuf *buf; 115 u_int16_t subtype = BGP4MP_STATE_CHANGE; 116 117 if (peer->capa.neg.as4byte) 118 subtype = BGP4MP_STATE_CHANGE_AS4; 119 120 if (mrt_dump_hdr_se(&buf, peer, MSG_PROTOCOL_BGP4MP, subtype, 121 2 * sizeof(short), 0) == -1) 122 return; 123 124 DUMP_SHORT(buf, old_state); 125 DUMP_SHORT(buf, new_state); 126 127 ibuf_close(&mrt->wbuf, buf); 128 return; 129 130 fail: 131 ibuf_free(buf); 132 } 133 134 int 135 mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop) 136 { 137 struct attr *oa; 138 u_char *pdata; 139 u_int32_t tmp; 140 int neednewpath = 0; 141 u_int16_t plen, afi; 142 u_int8_t l, mpattr[21]; 143 144 /* origin */ 145 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN, 146 &a->origin, 1) == -1) 147 return (-1); 148 149 /* aspath */ 150 pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen); 151 pdata = aspath_deflate(pdata, &plen, &neednewpath); 152 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata, 153 plen) == -1) { 154 free(pdata); 155 return (-1); 156 } 157 free(pdata); 158 159 if (nexthop && nexthop->aid == AID_INET) { 160 /* nexthop, already network byte order */ 161 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_NEXTHOP, 162 &nexthop->v4.s_addr, 4) == -1) 163 return (-1); 164 } 165 166 /* MED, non transitive */ 167 if (a->med != 0) { 168 tmp = htonl(a->med); 169 if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MED, &tmp, 4) == -1) 170 return (-1); 171 } 172 173 /* local preference, only valid for ibgp */ 174 tmp = htonl(a->lpref); 175 if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1) 176 return (-1); 177 178 /* dump all other path attributes without modification */ 179 for (l = 0; l < a->others_len; l++) { 180 if ((oa = a->others[l]) == NULL) 181 break; 182 if (attr_writebuf(buf, oa->flags, oa->type, 183 oa->data, oa->len) == -1) 184 return (-1); 185 } 186 187 if (nexthop && nexthop->aid != AID_INET) { 188 if (aid2afi(nexthop->aid, &afi, &mpattr[2])) 189 return (-1); 190 afi = htons(afi); 191 memcpy(mpattr, &afi, sizeof(afi)); 192 mpattr[3] = sizeof(struct in6_addr); 193 memcpy(&mpattr[4], &nexthop->v6, sizeof(struct in6_addr)); 194 mpattr[20] = 0; /* Reserved must be 0 */ 195 if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI, 196 mpattr, sizeof(mpattr)) == -1) 197 return (-1); 198 } 199 200 if (neednewpath) { 201 pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen); 202 if (plen != 0) 203 if (attr_writebuf(buf, ATTR_OPTIONAL|ATTR_TRANSITIVE, 204 ATTR_AS4_PATH, pdata, plen) == -1) { 205 free(pdata); 206 return (-1); 207 } 208 free(pdata); 209 } 210 211 return (0); 212 } 213 214 int 215 mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum, 216 struct rde_peer *peer) 217 { 218 struct ibuf *buf, *hbuf = NULL, *h2buf = NULL; 219 void *bptr; 220 struct bgpd_addr addr, nexthop, *nh; 221 u_int16_t len; 222 u_int8_t p_len; 223 u_int8_t aid; 224 225 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 226 log_warn("mrt_dump_entry_mp: buf_dynamic"); 227 return (-1); 228 } 229 230 if (mrt_attr_dump(buf, p->aspath, NULL) == -1) { 231 log_warnx("mrt_dump_entry_mp: mrt_attr_dump error"); 232 goto fail; 233 } 234 len = ibuf_size(buf); 235 236 if ((h2buf = ibuf_dynamic(MRT_BGP4MP_IPv4_HEADER_SIZE + 237 MRT_BGP4MP_IPv4_ENTRY_SIZE, MRT_BGP4MP_IPv6_HEADER_SIZE + 238 MRT_BGP4MP_IPv6_ENTRY_SIZE + MRT_BGP4MP_MAX_PREFIXLEN)) == NULL) { 239 log_warn("mrt_dump_entry_mp: buf_dynamic"); 240 goto fail; 241 } 242 243 DUMP_SHORT(h2buf, rde_local_as()); 244 DUMP_SHORT(h2buf, peer->short_as); 245 DUMP_SHORT(h2buf, /* ifindex */ 0); 246 247 /* XXX is this for peer self? */ 248 aid = peer->remote_addr.aid == AID_UNSPEC ? p->prefix->aid : 249 peer->remote_addr.aid; 250 switch (aid) { 251 case AID_INET: 252 DUMP_SHORT(h2buf, AFI_IPv4); 253 DUMP_NLONG(h2buf, peer->local_v4_addr.v4.s_addr); 254 DUMP_NLONG(h2buf, peer->remote_addr.v4.s_addr); 255 break; 256 case AID_INET6: 257 DUMP_SHORT(h2buf, AFI_IPv6); 258 if (ibuf_add(h2buf, &peer->local_v6_addr.v6, 259 sizeof(struct in6_addr)) == -1 || 260 ibuf_add(h2buf, &peer->remote_addr.v6, 261 sizeof(struct in6_addr)) == -1) { 262 log_warnx("mrt_dump_entry_mp: buf_add error"); 263 goto fail; 264 } 265 break; 266 default: 267 log_warnx("king bula found new AF in mrt_dump_entry_mp"); 268 goto fail; 269 } 270 271 DUMP_SHORT(h2buf, 0); /* view */ 272 DUMP_SHORT(h2buf, 1); /* status */ 273 DUMP_LONG(h2buf, p->lastchange); /* originated */ 274 275 if (p->aspath->nexthop == NULL) { 276 bzero(&nexthop, sizeof(struct bgpd_addr)); 277 nexthop.aid = addr.aid; 278 nh = &nexthop; 279 } else 280 nh = &p->aspath->nexthop->exit_nexthop; 281 282 pt_getaddr(p->prefix, &addr); 283 switch (addr.aid) { 284 case AID_INET: 285 DUMP_SHORT(h2buf, AFI_IPv4); /* afi */ 286 DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */ 287 DUMP_BYTE(h2buf, 4); /* nhlen */ 288 DUMP_NLONG(h2buf, nh->v4.s_addr); /* nexthop */ 289 break; 290 case AID_INET6: 291 DUMP_SHORT(h2buf, AFI_IPv6); /* afi */ 292 DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */ 293 DUMP_BYTE(h2buf, 16); /* nhlen */ 294 if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) { 295 log_warnx("mrt_dump_entry_mp: buf_add error"); 296 goto fail; 297 } 298 break; 299 default: 300 log_warnx("king bula found new AF in mrt_dump_entry_mp"); 301 goto fail; 302 } 303 304 p_len = PREFIX_SIZE(p->prefix->prefixlen); 305 if ((bptr = ibuf_reserve(h2buf, p_len)) == NULL) { 306 log_warnx("mrt_dump_entry_mp: buf_reserve error"); 307 goto fail; 308 } 309 if (prefix_write(bptr, p_len, &addr, p->prefix->prefixlen) == -1) { 310 log_warnx("mrt_dump_entry_mp: prefix_write error"); 311 goto fail; 312 } 313 314 DUMP_SHORT(h2buf, len); 315 len += ibuf_size(h2buf); 316 317 if (mrt_dump_hdr_rde(&hbuf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY, 318 len) == -1) 319 goto fail; 320 321 ibuf_close(&mrt->wbuf, hbuf); 322 ibuf_close(&mrt->wbuf, h2buf); 323 ibuf_close(&mrt->wbuf, buf); 324 325 return (len + MRT_HEADER_SIZE); 326 327 fail: 328 if (hbuf) 329 ibuf_free(hbuf); 330 if (h2buf) 331 ibuf_free(h2buf); 332 ibuf_free(buf); 333 return (-1); 334 } 335 336 int 337 mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, 338 struct rde_peer *peer) 339 { 340 struct ibuf *buf, *hbuf; 341 struct bgpd_addr addr, *nh; 342 size_t len; 343 u_int16_t subtype; 344 u_int8_t dummy; 345 346 if (p->prefix->aid != peer->remote_addr.aid && 347 p->prefix->aid != AID_INET && p->prefix->aid != AID_INET6) 348 /* only able to dump pure IPv4/IPv6 */ 349 return (0); 350 351 if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) { 352 log_warnx("mrt_dump_entry: buf_dynamic"); 353 return (-1); 354 } 355 356 if (p->aspath->nexthop == NULL) { 357 bzero(&addr, sizeof(struct bgpd_addr)); 358 addr.aid = p->prefix->aid; 359 nh = &addr; 360 } else 361 nh = &p->aspath->nexthop->exit_nexthop; 362 if (mrt_attr_dump(buf, p->aspath, nh) == -1) { 363 log_warnx("mrt_dump_entry: mrt_attr_dump error"); 364 ibuf_free(buf); 365 return (-1); 366 } 367 len = ibuf_size(buf); 368 aid2afi(p->prefix->aid, &subtype, &dummy); 369 if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP, subtype, len) == -1) { 370 ibuf_free(buf); 371 return (-1); 372 } 373 374 DUMP_SHORT(hbuf, 0); 375 DUMP_SHORT(hbuf, snum); 376 377 pt_getaddr(p->prefix, &addr); 378 switch (p->prefix->aid) { 379 case AID_INET: 380 DUMP_NLONG(hbuf, addr.v4.s_addr); 381 break; 382 case AID_INET6: 383 if (ibuf_add(hbuf, &addr.v6, sizeof(struct in6_addr)) == -1) { 384 log_warnx("mrt_dump_entry: buf_add error"); 385 goto fail; 386 } 387 break; 388 } 389 DUMP_BYTE(hbuf, p->prefix->prefixlen); 390 391 DUMP_BYTE(hbuf, 1); /* state */ 392 DUMP_LONG(hbuf, p->lastchange); /* originated */ 393 switch (p->prefix->aid) { 394 case AID_INET: 395 DUMP_NLONG(hbuf, peer->remote_addr.v4.s_addr); 396 break; 397 case AID_INET6: 398 if (ibuf_add(hbuf, &peer->remote_addr.v6, 399 sizeof(struct in6_addr)) == -1) { 400 log_warnx("mrt_dump_entry: buf_add error"); 401 goto fail; 402 } 403 break; 404 } 405 DUMP_SHORT(hbuf, peer->short_as); 406 DUMP_SHORT(hbuf, len); 407 408 ibuf_close(&mrt->wbuf, hbuf); 409 ibuf_close(&mrt->wbuf, buf); 410 411 return (len + MRT_HEADER_SIZE); 412 413 fail: 414 ibuf_free(hbuf); 415 ibuf_free(buf); 416 return (-1); 417 } 418 419 void 420 mrt_dump_upcall(struct rib_entry *re, void *ptr) 421 { 422 struct mrt *mrtbuf = ptr; 423 struct prefix *p; 424 425 /* 426 * dump all prefixes even the inactive ones. That is the way zebra 427 * dumps the table so we do the same. If only the active route should 428 * be dumped p should be set to p = pt->active. 429 */ 430 LIST_FOREACH(p, &re->prefix_h, rib_l) { 431 if (mrtbuf->type == MRT_TABLE_DUMP) 432 mrt_dump_entry(mrtbuf, p, mrtbuf->seqnum++, 433 p->aspath->peer); 434 else 435 mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++, 436 p->aspath->peer); 437 } 438 } 439 440 void 441 mrt_done(void *ptr) 442 { 443 struct mrt *mrtbuf = ptr; 444 445 mrtbuf->state = MRT_STATE_REMOVE; 446 } 447 448 int 449 mrt_dump_hdr_se(struct ibuf ** bp, struct peer *peer, u_int16_t type, 450 u_int16_t subtype, u_int32_t len, int swap) 451 { 452 time_t now; 453 454 if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE + 455 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL) { 456 log_warnx("mrt_dump_hdr_se: buf_open error"); 457 return (-1); 458 } 459 460 now = time(NULL); 461 462 DUMP_LONG(*bp, now); 463 DUMP_SHORT(*bp, type); 464 DUMP_SHORT(*bp, subtype); 465 466 switch (peer->sa_local.ss_family) { 467 case AF_INET: 468 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 469 subtype == BGP4MP_MESSAGE_AS4) 470 len += MRT_BGP4MP_AS4_IPv4_HEADER_SIZE; 471 else 472 len += MRT_BGP4MP_IPv4_HEADER_SIZE; 473 break; 474 case AF_INET6: 475 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 476 subtype == BGP4MP_MESSAGE_AS4) 477 len += MRT_BGP4MP_AS4_IPv6_HEADER_SIZE; 478 else 479 len += MRT_BGP4MP_IPv6_HEADER_SIZE; 480 break; 481 case 0: 482 goto fail; 483 default: 484 log_warnx("king bula found new AF in mrt_dump_hdr_se"); 485 goto fail; 486 } 487 488 DUMP_LONG(*bp, len); 489 490 if (subtype == BGP4MP_STATE_CHANGE_AS4 || 491 subtype == BGP4MP_MESSAGE_AS4) { 492 if (!swap) 493 DUMP_LONG(*bp, peer->conf.local_as); 494 DUMP_LONG(*bp, peer->conf.remote_as); 495 if (swap) 496 DUMP_LONG(*bp, peer->conf.local_as); 497 } else { 498 if (!swap) 499 DUMP_SHORT(*bp, peer->conf.local_short_as); 500 DUMP_SHORT(*bp, peer->short_as); 501 if (swap) 502 DUMP_SHORT(*bp, peer->conf.local_short_as); 503 } 504 505 DUMP_SHORT(*bp, /* ifindex */ 0); 506 507 switch (peer->sa_local.ss_family) { 508 case AF_INET: 509 DUMP_SHORT(*bp, AFI_IPv4); 510 if (!swap) 511 DUMP_NLONG(*bp, ((struct sockaddr_in *) 512 &peer->sa_local)->sin_addr.s_addr); 513 DUMP_NLONG(*bp, 514 ((struct sockaddr_in *)&peer->sa_remote)->sin_addr.s_addr); 515 if (swap) 516 DUMP_NLONG(*bp, ((struct sockaddr_in *) 517 &peer->sa_local)->sin_addr.s_addr); 518 break; 519 case AF_INET6: 520 DUMP_SHORT(*bp, AFI_IPv6); 521 if (!swap) 522 if (ibuf_add(*bp, &((struct sockaddr_in6 *) 523 &peer->sa_local)->sin6_addr, 524 sizeof(struct in6_addr)) == -1) { 525 log_warnx("mrt_dump_hdr_se: buf_add error"); 526 goto fail; 527 } 528 if (ibuf_add(*bp, 529 &((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr, 530 sizeof(struct in6_addr)) == -1) { 531 log_warnx("mrt_dump_hdr_se: buf_add error"); 532 goto fail; 533 } 534 if (swap) 535 if (ibuf_add(*bp, &((struct sockaddr_in6 *) 536 &peer->sa_local)->sin6_addr, 537 sizeof(struct in6_addr)) == -1) { 538 log_warnx("mrt_dump_hdr_se: buf_add error"); 539 goto fail; 540 } 541 break; 542 } 543 544 return (0); 545 546 fail: 547 ibuf_free(*bp); 548 return (-1); 549 } 550 551 int 552 mrt_dump_hdr_rde(struct ibuf **bp, u_int16_t type, u_int16_t subtype, 553 u_int32_t len) 554 { 555 time_t now; 556 557 if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE + 558 MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) == 559 NULL) { 560 log_warnx("mrt_dump_hdr_rde: buf_dynamic error"); 561 return (-1); 562 } 563 564 now = time(NULL); 565 DUMP_LONG(*bp, now); 566 DUMP_SHORT(*bp, type); 567 DUMP_SHORT(*bp, subtype); 568 569 switch (type) { 570 case MSG_TABLE_DUMP: 571 switch (subtype) { 572 case AFI_IPv4: 573 len += MRT_DUMP_HEADER_SIZE; 574 break; 575 case AFI_IPv6: 576 len += MRT_DUMP_HEADER_SIZE_V6; 577 break; 578 } 579 DUMP_LONG(*bp, len); 580 break; 581 case MSG_PROTOCOL_BGP4MP: 582 DUMP_LONG(*bp, len); 583 break; 584 default: 585 log_warnx("mrt_dump_hdr_rde: unsupported type"); 586 goto fail; 587 } 588 return (0); 589 590 fail: 591 ibuf_free(*bp); 592 return (-1); 593 } 594 595 void 596 mrt_write(struct mrt *mrt) 597 { 598 int r; 599 600 if ((r = ibuf_write(&mrt->wbuf)) < 0) { 601 log_warn("mrt dump aborted, mrt_write"); 602 mrt_clean(mrt); 603 mrt_done(mrt); 604 } 605 } 606 607 void 608 mrt_clean(struct mrt *mrt) 609 { 610 struct ibuf *b; 611 612 close(mrt->wbuf.fd); 613 while ((b = TAILQ_FIRST(&mrt->wbuf.bufs))) { 614 TAILQ_REMOVE(&mrt->wbuf.bufs, b, entry); 615 ibuf_free(b); 616 } 617 mrt->wbuf.queued = 0; 618 } 619 620 static struct imsgbuf *mrt_imsgbuf[2]; 621 622 void 623 mrt_init(struct imsgbuf *rde, struct imsgbuf *se) 624 { 625 mrt_imsgbuf[0] = rde; 626 mrt_imsgbuf[1] = se; 627 } 628 629 int 630 mrt_open(struct mrt *mrt, time_t now) 631 { 632 enum imsg_type type; 633 int i = 1, fd; 634 635 if (strftime(MRT2MC(mrt)->file, sizeof(MRT2MC(mrt)->file), 636 MRT2MC(mrt)->name, localtime(&now)) == 0) { 637 log_warnx("mrt_open: strftime conversion failed"); 638 return (-1); 639 } 640 641 fd = open(MRT2MC(mrt)->file, 642 O_WRONLY|O_NONBLOCK|O_CREAT|O_TRUNC, 0644); 643 if (fd == -1) { 644 log_warn("mrt_open %s", MRT2MC(mrt)->file); 645 return (1); 646 } 647 648 if (mrt->state == MRT_STATE_OPEN) 649 type = IMSG_MRT_OPEN; 650 else 651 type = IMSG_MRT_REOPEN; 652 653 if (mrt->type == MRT_TABLE_DUMP || mrt->type == MRT_TABLE_DUMP_MP) 654 i = 0; 655 656 if (imsg_compose(mrt_imsgbuf[i], type, 0, 0, fd, 657 mrt, sizeof(struct mrt)) == -1) 658 log_warn("mrt_open"); 659 660 return (1); 661 } 662 663 int 664 mrt_timeout(struct mrt_head *mrt) 665 { 666 struct mrt *m; 667 time_t now; 668 int timeout = MRT_MAX_TIMEOUT; 669 670 now = time(NULL); 671 LIST_FOREACH(m, mrt, entry) { 672 if (m->state == MRT_STATE_RUNNING && 673 MRT2MC(m)->ReopenTimerInterval != 0) { 674 if (MRT2MC(m)->ReopenTimer <= now) { 675 mrt_open(m, now); 676 MRT2MC(m)->ReopenTimer = 677 now + MRT2MC(m)->ReopenTimerInterval; 678 } 679 if (MRT2MC(m)->ReopenTimer - now < timeout) 680 timeout = MRT2MC(m)->ReopenTimer - now; 681 } 682 } 683 return (timeout > 0 ? timeout : 0); 684 } 685 686 void 687 mrt_reconfigure(struct mrt_head *mrt) 688 { 689 struct mrt *m, *xm; 690 time_t now; 691 692 now = time(NULL); 693 for (m = LIST_FIRST(mrt); m != NULL; m = xm) { 694 xm = LIST_NEXT(m, entry); 695 if (m->state == MRT_STATE_OPEN || 696 m->state == MRT_STATE_REOPEN) { 697 if (mrt_open(m, now) == -1) 698 continue; 699 if (MRT2MC(m)->ReopenTimerInterval != 0) 700 MRT2MC(m)->ReopenTimer = 701 now + MRT2MC(m)->ReopenTimerInterval; 702 m->state = MRT_STATE_RUNNING; 703 } 704 if (m->state == MRT_STATE_REMOVE) { 705 LIST_REMOVE(m, entry); 706 free(m); 707 continue; 708 } 709 } 710 } 711 712 void 713 mrt_handler(struct mrt_head *mrt) 714 { 715 struct mrt *m; 716 time_t now; 717 718 now = time(NULL); 719 LIST_FOREACH(m, mrt, entry) { 720 if (m->state == MRT_STATE_RUNNING && 721 (MRT2MC(m)->ReopenTimerInterval != 0 || 722 m->type == MRT_TABLE_DUMP)) { 723 if (mrt_open(m, now) == -1) 724 continue; 725 MRT2MC(m)->ReopenTimer = 726 now + MRT2MC(m)->ReopenTimerInterval; 727 } 728 } 729 } 730 731 struct mrt * 732 mrt_get(struct mrt_head *c, struct mrt *m) 733 { 734 struct mrt *t; 735 736 LIST_FOREACH(t, c, entry) { 737 if (t->type != m->type) 738 continue; 739 if (strcmp(t->rib, m->rib)) 740 continue; 741 if (t->peer_id == m->peer_id && 742 t->group_id == m->group_id) 743 return (t); 744 } 745 return (NULL); 746 } 747 748 int 749 mrt_mergeconfig(struct mrt_head *xconf, struct mrt_head *nconf) 750 { 751 struct mrt *m, *xm; 752 753 LIST_FOREACH(m, nconf, entry) { 754 if ((xm = mrt_get(xconf, m)) == NULL) { 755 /* NEW */ 756 if ((xm = calloc(1, sizeof(struct mrt_config))) == NULL) 757 fatal("mrt_mergeconfig"); 758 memcpy(xm, m, sizeof(struct mrt_config)); 759 xm->state = MRT_STATE_OPEN; 760 LIST_INSERT_HEAD(xconf, xm, entry); 761 } else { 762 /* MERGE */ 763 if (strlcpy(MRT2MC(xm)->name, MRT2MC(m)->name, 764 sizeof(MRT2MC(xm)->name)) >= 765 sizeof(MRT2MC(xm)->name)) 766 fatalx("mrt_mergeconfig: strlcpy"); 767 MRT2MC(xm)->ReopenTimerInterval = 768 MRT2MC(m)->ReopenTimerInterval; 769 xm->state = MRT_STATE_REOPEN; 770 } 771 } 772 773 LIST_FOREACH(xm, xconf, entry) 774 if (mrt_get(nconf, xm) == NULL) 775 /* REMOVE */ 776 xm->state = MRT_STATE_REMOVE; 777 778 /* free config */ 779 while ((m = LIST_FIRST(nconf)) != NULL) { 780 LIST_REMOVE(m, entry); 781 free(m); 782 } 783 784 return (0); 785 } 786