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