1 /* $OpenBSD: ospf6d.c,v 1.15 2009/06/06 09:02:46 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2007 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/queue.h> 24 #include <sys/time.h> 25 #include <sys/stat.h> 26 #include <sys/wait.h> 27 #include <sys/param.h> 28 #include <sys/sysctl.h> 29 30 #include <netinet/in.h> 31 #include <arpa/inet.h> 32 33 #include <event.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <pwd.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <signal.h> 41 #include <unistd.h> 42 43 #include "ospf6d.h" 44 #include "ospf6.h" 45 #include "ospfe.h" 46 #include "control.h" 47 #include "log.h" 48 #include "rde.h" 49 50 void main_sig_handler(int, short, void *); 51 __dead void usage(void); 52 void ospfd_shutdown(void); 53 int check_child(pid_t, const char *); 54 55 void main_dispatch_ospfe(int, short, void *); 56 void main_dispatch_rde(int, short, void *); 57 58 void ospf_redistribute_default(int); 59 60 int ospf_reload(void); 61 int ospf_sendboth(enum imsg_type, void *, u_int16_t); 62 int merge_interfaces(struct area *, struct area *); 63 struct iface *iface_lookup(struct area *, struct iface *); 64 65 int pipe_parent2ospfe[2]; 66 int pipe_parent2rde[2]; 67 int pipe_ospfe2rde[2]; 68 69 struct ospfd_conf *ospfd_conf = NULL; 70 struct imsgev *iev_ospfe; 71 struct imsgev *iev_rde; 72 char *conffile; 73 74 pid_t ospfe_pid = 0; 75 pid_t rde_pid = 0; 76 77 /* ARGSUSED */ 78 void 79 main_sig_handler(int sig, short event, void *arg) 80 { 81 /* 82 * signal handler rules don't apply, libevent decouples for us 83 */ 84 85 int die = 0; 86 87 switch (sig) { 88 case SIGTERM: 89 case SIGINT: 90 die = 1; 91 /* FALLTHROUGH */ 92 case SIGCHLD: 93 if (check_child(ospfe_pid, "ospf engine")) { 94 ospfe_pid = 0; 95 die = 1; 96 } 97 if (check_child(rde_pid, "route decision engine")) { 98 rde_pid = 0; 99 die = 1; 100 } 101 if (die) 102 ospfd_shutdown(); 103 break; 104 case SIGHUP: 105 if (ospf_reload() == -1) 106 log_warnx("configuration reload failed"); 107 else 108 log_debug("configuration reloaded"); 109 break; 110 default: 111 fatalx("unexpected signal"); 112 /* NOTREACHED */ 113 } 114 } 115 116 __dead void 117 usage(void) 118 { 119 extern char *__progname; 120 121 fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 122 __progname); 123 exit(1); 124 } 125 126 int 127 main(int argc, char *argv[]) 128 { 129 struct event ev_sigint, ev_sigterm, ev_sigchld, ev_sighup; 130 int ch, opts = 0; 131 int debug = 0; 132 int ipforwarding; 133 int mib[4]; 134 size_t len; 135 136 conffile = CONF_FILE; 137 ospfd_process = PROC_MAIN; 138 139 log_init(1); /* log to stderr until daemonized */ 140 141 while ((ch = getopt(argc, argv, "cdD:f:nv")) != -1) { 142 switch (ch) { 143 case 'c': 144 opts |= OSPFD_OPT_FORCE_DEMOTE; 145 break; 146 case 'd': 147 debug = 1; 148 break; 149 case 'D': 150 if (cmdline_symset(optarg) < 0) 151 log_warnx("could not parse macro definition %s", 152 optarg); 153 break; 154 case 'f': 155 conffile = optarg; 156 break; 157 case 'n': 158 opts |= OSPFD_OPT_NOACTION; 159 break; 160 case 'v': 161 if (opts & OSPFD_OPT_VERBOSE) 162 opts |= OSPFD_OPT_VERBOSE2; 163 opts |= OSPFD_OPT_VERBOSE; 164 break; 165 166 default: 167 usage(); 168 /* NOTREACHED */ 169 } 170 } 171 172 argc -= optind; 173 argv += optind; 174 if (argc > 0) 175 usage(); 176 177 mib[0] = CTL_NET; 178 mib[1] = PF_INET6; 179 mib[2] = IPPROTO_IPV6; 180 mib[3] = IPCTL_FORWARDING; 181 len = sizeof(ipforwarding); 182 if (sysctl(mib, 4, &ipforwarding, &len, NULL, 0) == -1) 183 err(1, "sysctl"); 184 185 if (ipforwarding != 1) { 186 log_warnx("WARNING: IPv6 forwarding NOT enabled, " 187 "running as stub router"); 188 opts |= OSPFD_OPT_STUB_ROUTER; 189 } 190 191 /* prepare and fetch interfaces early */ 192 if_init(); 193 194 /* parse config file */ 195 if ((ospfd_conf = parse_config(conffile, opts)) == NULL ) 196 exit(1); 197 198 if (ospfd_conf->opts & OSPFD_OPT_NOACTION) { 199 if (ospfd_conf->opts & OSPFD_OPT_VERBOSE) 200 print_config(ospfd_conf); 201 else 202 fprintf(stderr, "configuration OK\n"); 203 exit(0); 204 } 205 206 /* check for root privileges */ 207 if (geteuid()) 208 errx(1, "need root privileges"); 209 210 /* check for ospfd user */ 211 if (getpwnam(OSPF6D_USER) == NULL) 212 errx(1, "unknown user %s", OSPF6D_USER); 213 214 log_init(debug); 215 216 if (!debug) 217 daemon(1, 0); 218 219 log_info("startup"); 220 221 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, 222 pipe_parent2ospfe) == -1) 223 fatal("socketpair"); 224 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2rde) == -1) 225 fatal("socketpair"); 226 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_ospfe2rde) == -1) 227 fatal("socketpair"); 228 session_socket_blockmode(pipe_parent2ospfe[0], BM_NONBLOCK); 229 session_socket_blockmode(pipe_parent2ospfe[1], BM_NONBLOCK); 230 session_socket_blockmode(pipe_parent2rde[0], BM_NONBLOCK); 231 session_socket_blockmode(pipe_parent2rde[1], BM_NONBLOCK); 232 session_socket_blockmode(pipe_ospfe2rde[0], BM_NONBLOCK); 233 session_socket_blockmode(pipe_ospfe2rde[1], BM_NONBLOCK); 234 235 /* start children */ 236 rde_pid = rde(ospfd_conf, pipe_parent2rde, pipe_ospfe2rde, 237 pipe_parent2ospfe); 238 ospfe_pid = ospfe(ospfd_conf, pipe_parent2ospfe, pipe_ospfe2rde, 239 pipe_parent2rde); 240 241 /* show who we are */ 242 setproctitle("parent"); 243 244 event_init(); 245 246 /* setup signal handler */ 247 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 248 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 249 signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, NULL); 250 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 251 signal_add(&ev_sigint, NULL); 252 signal_add(&ev_sigterm, NULL); 253 signal_add(&ev_sigchld, NULL); 254 signal_add(&ev_sighup, NULL); 255 signal(SIGPIPE, SIG_IGN); 256 257 /* setup pipes to children */ 258 close(pipe_parent2ospfe[1]); 259 close(pipe_parent2rde[1]); 260 close(pipe_ospfe2rde[0]); 261 close(pipe_ospfe2rde[1]); 262 263 if ((iev_ospfe = malloc(sizeof(struct imsgev))) == NULL || 264 (iev_rde = malloc(sizeof(struct imsgev))) == NULL) 265 fatal(NULL); 266 imsg_init(&iev_ospfe->ibuf, pipe_parent2ospfe[0]); 267 iev_ospfe->handler = main_dispatch_ospfe; 268 imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]); 269 iev_rde->handler = main_dispatch_rde; 270 271 /* setup event handler */ 272 iev_ospfe->events = EV_READ; 273 event_set(&iev_ospfe->ev, iev_ospfe->ibuf.fd, iev_ospfe->events, 274 iev_ospfe->handler, iev_ospfe); 275 event_add(&iev_ospfe->ev, NULL); 276 277 iev_rde->events = EV_READ; 278 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 279 iev_rde->handler, iev_rde); 280 event_add(&iev_rde->ev, NULL); 281 282 if (kr_init(!(ospfd_conf->flags & OSPFD_FLAG_NO_FIB_UPDATE)) == -1) 283 fatalx("kr_init failed"); 284 285 /* redistribute default */ 286 ospf_redistribute_default(IMSG_NETWORK_ADD); 287 288 event_dispatch(); 289 290 ospfd_shutdown(); 291 /* NOTREACHED */ 292 return (0); 293 } 294 295 void 296 ospfd_shutdown(void) 297 { 298 pid_t pid; 299 300 if (ospfe_pid) 301 kill(ospfe_pid, SIGTERM); 302 303 if (rde_pid) 304 kill(rde_pid, SIGTERM); 305 306 control_cleanup(); 307 kr_shutdown(); 308 carp_demote_shutdown(); 309 310 do { 311 if ((pid = wait(NULL)) == -1 && 312 errno != EINTR && errno != ECHILD) 313 fatal("wait"); 314 } while (pid != -1 || (pid == -1 && errno == EINTR)); 315 316 msgbuf_clear(&iev_ospfe->ibuf.w); 317 free(iev_ospfe); 318 msgbuf_clear(&iev_rde->ibuf.w); 319 free(iev_rde); 320 free(ospfd_conf); 321 322 log_info("terminating"); 323 exit(0); 324 } 325 326 int 327 check_child(pid_t pid, const char *pname) 328 { 329 int status; 330 331 if (waitpid(pid, &status, WNOHANG) > 0) { 332 if (WIFEXITED(status)) { 333 log_warnx("lost child: %s exited", pname); 334 return (1); 335 } 336 if (WIFSIGNALED(status)) { 337 log_warnx("lost child: %s terminated; signal %d", 338 pname, WTERMSIG(status)); 339 return (1); 340 } 341 } 342 343 return (0); 344 } 345 346 /* imsg handling */ 347 /* ARGSUSED */ 348 void 349 main_dispatch_ospfe(int fd, short event, void *bula) 350 { 351 struct imsgev *iev = bula; 352 struct imsgbuf *ibuf = &iev->ibuf; 353 struct imsg imsg; 354 struct demote_msg dmsg; 355 ssize_t n; 356 int shut = 0; 357 358 if (event & EV_READ) { 359 if ((n = imsg_read(ibuf)) == -1) 360 fatal("imsg_read error"); 361 if (n == 0) /* connection closed */ 362 shut = 1; 363 } 364 if (event & EV_WRITE) { 365 if (msgbuf_write(&ibuf->w) == -1) 366 fatal("msgbuf_write"); 367 } 368 369 for (;;) { 370 if ((n = imsg_get(ibuf, &imsg)) == -1) 371 fatal("imsg_get"); 372 373 if (n == 0) 374 break; 375 376 switch (imsg.hdr.type) { 377 case IMSG_CTL_RELOAD: 378 if (ospf_reload() == -1) 379 log_warnx("configuration reload failed"); 380 else 381 log_debug("configuration reloaded"); 382 break; 383 case IMSG_CTL_FIB_COUPLE: 384 kr_fib_couple(); 385 break; 386 case IMSG_CTL_FIB_DECOUPLE: 387 kr_fib_decouple(); 388 break; 389 case IMSG_CTL_KROUTE: 390 case IMSG_CTL_KROUTE_ADDR: 391 kr_show_route(&imsg); 392 break; 393 case IMSG_DEMOTE: 394 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(dmsg)) 395 fatalx("invalid size of OE request"); 396 memcpy(&dmsg, imsg.data, sizeof(dmsg)); 397 carp_demote_set(dmsg.demote_group, dmsg.level); 398 break; 399 default: 400 log_debug("main_dispatch_ospfe: error handling imsg %d", 401 imsg.hdr.type); 402 break; 403 } 404 imsg_free(&imsg); 405 } 406 if (!shut) 407 imsg_event_add(iev); 408 else { 409 /* this pipe is dead, so remove the event handler */ 410 event_del(&iev->ev); 411 event_loopexit(NULL); 412 } 413 } 414 415 /* ARGSUSED */ 416 void 417 main_dispatch_rde(int fd, short event, void *bula) 418 { 419 struct imsgev *iev = bula; 420 struct imsgbuf *ibuf = &iev->ibuf; 421 struct imsg imsg; 422 ssize_t n; 423 int shut = 0; 424 425 if (event & EV_READ) { 426 if ((n = imsg_read(ibuf)) == -1) 427 fatal("imsg_read error"); 428 if (n == 0) /* connection closed */ 429 shut = 1; 430 } 431 if (event & EV_WRITE) { 432 if (msgbuf_write(&ibuf->w) == -1) 433 fatal("msgbuf_write"); 434 } 435 436 for (;;) { 437 if ((n = imsg_get(ibuf, &imsg)) == -1) 438 fatal("imsg_get"); 439 440 if (n == 0) 441 break; 442 443 switch (imsg.hdr.type) { 444 case IMSG_KROUTE_CHANGE: 445 if (kr_change(imsg.data)) 446 log_warn("main_dispatch_rde: error changing " 447 "route"); 448 break; 449 case IMSG_KROUTE_DELETE: 450 if (kr_delete(imsg.data)) 451 log_warn("main_dispatch_rde: error deleting " 452 "route"); 453 break; 454 default: 455 log_debug("main_dispatch_rde: error handling imsg %d", 456 imsg.hdr.type); 457 break; 458 } 459 imsg_free(&imsg); 460 } 461 if (!shut) 462 imsg_event_add(iev); 463 else { 464 /* this pipe is dead, so remove the event handler */ 465 event_del(&iev->ev); 466 event_loopexit(NULL); 467 } 468 } 469 470 void 471 main_imsg_compose_ospfe(int type, pid_t pid, void *data, u_int16_t datalen) 472 { 473 imsg_compose_event(iev_ospfe, type, 0, pid, -1, data, datalen); 474 } 475 476 void 477 main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen) 478 { 479 imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen); 480 } 481 482 void 483 imsg_event_add(struct imsgev *iev) 484 { 485 iev->events = EV_READ; 486 if (iev->ibuf.w.queued) 487 iev->events |= EV_WRITE; 488 489 event_del(&iev->ev); 490 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 491 event_add(&iev->ev, NULL); 492 } 493 494 int 495 imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 496 pid_t pid, int fd, void *data, u_int16_t datalen) 497 { 498 int ret; 499 500 if ((ret = imsg_compose(&iev->ibuf, type, peerid, 501 pid, fd, data, datalen)) != -1) 502 imsg_event_add(iev); 503 return (ret); 504 } 505 506 int 507 ospf_redistribute(struct kroute *kr, u_int32_t *metric) 508 { 509 struct redistribute *r; 510 struct in6_addr ina, inb; 511 512 /* only allow 0.0.0.0/0 via REDISTRIBUTE_DEFAULT */ 513 if (IN6_IS_ADDR_UNSPECIFIED(&kr->prefix) && kr->prefixlen == 0) 514 return (0); 515 516 SIMPLEQ_FOREACH(r, &ospfd_conf->redist_list, entry) { 517 switch (r->type & ~REDIST_NO) { 518 case REDIST_LABEL: 519 if (kr->rtlabel == r->label) { 520 *metric = r->metric; 521 return (r->type & REDIST_NO ? 0 : 1); 522 } 523 break; 524 case REDIST_STATIC: 525 /* 526 * Dynamic routes are not redistributable. Placed here 527 * so that link local addresses can be redistributed 528 * via a rtlabel. 529 */ 530 if (kr->flags & F_DYNAMIC) 531 continue; 532 if (kr->flags & F_STATIC) { 533 *metric = r->metric; 534 return (r->type & REDIST_NO ? 0 : 1); 535 } 536 break; 537 case REDIST_CONNECTED: 538 if (kr->flags & F_DYNAMIC) 539 continue; 540 if (kr->flags & F_CONNECTED) { 541 *metric = r->metric; 542 return (r->type & REDIST_NO ? 0 : 1); 543 } 544 break; 545 case REDIST_ADDR: 546 if (kr->flags & F_DYNAMIC) 547 continue; 548 inet6applymask(&ina, &kr->prefix, kr->prefixlen); 549 inet6applymask(&inb, &r->addr, r->prefixlen); 550 if (IN6_ARE_ADDR_EQUAL(&ina, &inb) && 551 kr->prefixlen >= r->prefixlen) { 552 *metric = r->metric; 553 return (r->type & REDIST_NO ? 0 : 1); 554 } 555 break; 556 } 557 } 558 559 return (0); 560 } 561 562 void 563 ospf_redistribute_default(int type) 564 { 565 struct rroute rr; 566 567 if (!(ospfd_conf->redistribute & REDISTRIBUTE_DEFAULT)) 568 return; 569 570 bzero(&rr, sizeof(rr)); 571 rr.metric = ospfd_conf->defaultmetric; 572 main_imsg_compose_rde(type, 0, &rr, sizeof(struct rroute)); 573 } 574 575 int 576 ospf_reload(void) 577 { 578 struct area *area; 579 struct ospfd_conf *xconf; 580 581 if ((xconf = parse_config(conffile, ospfd_conf->opts)) == NULL) 582 return (-1); 583 584 /* send config to childs */ 585 if (ospf_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 586 return (-1); 587 588 /* send areas, interfaces happen out of band */ 589 LIST_FOREACH(area, &xconf->area_list, entry) { 590 if (ospf_sendboth(IMSG_RECONF_AREA, area, sizeof(*area)) == -1) 591 return (-1); 592 } 593 594 if (ospf_sendboth(IMSG_RECONF_END, NULL, 0) == -1) 595 return (-1); 596 597 /* XXX send newly available interfaces to the childs */ 598 599 merge_config(ospfd_conf, xconf); 600 /* update redistribute lists */ 601 kr_reload(); 602 return (0); 603 } 604 605 int 606 ospf_sendboth(enum imsg_type type, void *buf, u_int16_t len) 607 { 608 if (imsg_compose_event(iev_ospfe, type, 0, 0, -1, buf, len) == -1) 609 return (-1); 610 if (imsg_compose_event(iev_rde, type, 0, 0, -1, buf, len) == -1) 611 return (-1); 612 return (0); 613 } 614 615 void 616 merge_config(struct ospfd_conf *conf, struct ospfd_conf *xconf) 617 { 618 struct area *a, *xa, *na; 619 struct iface *iface; 620 struct redistribute *r; 621 622 /* change of rtr_id needs a restart */ 623 conf->flags = xconf->flags; 624 conf->spf_delay = xconf->spf_delay; 625 conf->spf_hold_time = xconf->spf_hold_time; 626 conf->redistribute = xconf->redistribute; 627 628 if (ospfd_process == PROC_MAIN) { 629 /* main process does neither use areas nor interfaces */ 630 while ((r = SIMPLEQ_FIRST(&conf->redist_list)) != NULL) { 631 SIMPLEQ_REMOVE_HEAD(&conf->redist_list, entry); 632 free(r); 633 } 634 while ((r = SIMPLEQ_FIRST(&xconf->redist_list)) != NULL) { 635 SIMPLEQ_REMOVE_HEAD(&xconf->redist_list, entry); 636 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, entry); 637 } 638 goto done; 639 } 640 641 /* merge areas and interfaces */ 642 for (a = LIST_FIRST(&conf->area_list); a != NULL; a = na) { 643 na = LIST_NEXT(a, entry); 644 /* find deleted areas */ 645 if ((xa = area_find(xconf, a->id)) == NULL) { 646 if (ospfd_process == PROC_OSPF_ENGINE) { 647 LIST_FOREACH(iface, &a->iface_list, entry) 648 if_fsm(iface, IF_EVT_DOWN); 649 } 650 LIST_REMOVE(a, entry); 651 area_del(a); 652 } 653 } 654 655 for (xa = LIST_FIRST(&xconf->area_list); xa != NULL; xa = na) { 656 na = LIST_NEXT(xa, entry); 657 if ((a = area_find(conf, xa->id)) == NULL) { 658 LIST_REMOVE(xa, entry); 659 LIST_INSERT_HEAD(&conf->area_list, xa, entry); 660 if (ospfd_process == PROC_OSPF_ENGINE) { 661 /* start interfaces */ 662 ospfe_demote_area(xa, 0); 663 LIST_FOREACH(iface, &xa->iface_list, entry) 664 if_start(conf, iface); 665 } 666 /* no need to merge interfaces */ 667 continue; 668 } 669 /* 670 * stub is not yet used but switching between stub and normal 671 * will be another painful job. 672 */ 673 a->stub = xa->stub; 674 a->stub_default_cost = xa->stub_default_cost; 675 if (ospfd_process == PROC_RDE_ENGINE) 676 a->dirty = 1; /* force SPF tree recalculation */ 677 678 /* merge interfaces */ 679 if (merge_interfaces(a, xa) && 680 ospfd_process == PROC_OSPF_ENGINE) 681 a->dirty = 1; /* force rtr LSA update */ 682 } 683 684 if (ospfd_process == PROC_OSPF_ENGINE) { 685 LIST_FOREACH(a, &conf->area_list, entry) { 686 LIST_FOREACH(iface, &a->iface_list, entry) { 687 if (iface->state == IF_STA_NEW) { 688 iface->state = IF_STA_DOWN; 689 if_start(conf, iface); 690 } 691 } 692 if (a->dirty) { 693 a->dirty = 0; 694 orig_rtr_lsa(LIST_FIRST(&a->iface_list)); 695 } 696 } 697 } 698 699 done: 700 while ((a = LIST_FIRST(&xconf->area_list)) != NULL) { 701 LIST_REMOVE(a, entry); 702 area_del(a); 703 } 704 free(xconf); 705 } 706 707 int 708 merge_interfaces(struct area *a, struct area *xa) 709 { 710 struct iface *i, *xi, *ni; 711 int dirty = 0; 712 713 /* problems: 714 * - new interfaces (easy) 715 * - deleted interfaces (needs to be done via fsm?) 716 * - changing passive (painful?) 717 */ 718 for (i = LIST_FIRST(&a->iface_list); i != NULL; i = ni) { 719 ni = LIST_NEXT(i, entry); 720 if (iface_lookup(xa, i) == NULL) { 721 log_debug("merge_interfaces: proc %d area %s removing " 722 "interface %s", ospfd_process, inet_ntoa(a->id), 723 i->name); 724 if (ospfd_process == PROC_OSPF_ENGINE) 725 if_fsm(i, IF_EVT_DOWN); 726 LIST_REMOVE(i, entry); 727 if_del(i); 728 } 729 } 730 731 for (xi = LIST_FIRST(&xa->iface_list); xi != NULL; xi = ni) { 732 ni = LIST_NEXT(xi, entry); 733 if ((i = iface_lookup(a, xi)) == NULL) { 734 /* new interface but delay initialisation */ 735 log_debug("merge_interfaces: proc %d area %s adding " 736 "interface %s", ospfd_process, inet_ntoa(a->id), 737 xi->name); 738 LIST_REMOVE(xi, entry); 739 LIST_INSERT_HEAD(&a->iface_list, xi, entry); 740 if (ospfd_process == PROC_OSPF_ENGINE) 741 xi->state = IF_STA_NEW; 742 continue; 743 } 744 log_debug("merge_interfaces: proc %d area %s merging " 745 "interface %s", ospfd_process, inet_ntoa(a->id), i->name); 746 i->addr = xi->addr; 747 i->dst = xi->dst; 748 i->abr_id = xi->abr_id; 749 i->baudrate = xi->baudrate; 750 i->dead_interval = xi->dead_interval; 751 i->mtu = xi->mtu; 752 i->transmit_delay = xi->transmit_delay; 753 i->hello_interval = xi->hello_interval; 754 i->rxmt_interval = xi->rxmt_interval; 755 if (i->metric != xi->metric) 756 dirty = 1; 757 i->metric = xi->metric; 758 i->priority = xi->priority; 759 i->flags = xi->flags; /* needed? */ 760 i->type = xi->type; /* needed? */ 761 i->media_type = xi->media_type; /* needed? */ 762 i->linkstate = xi->linkstate; /* needed? */ 763 764 #if 0 /* XXX needs some kind of love */ 765 if (i->passive != xi->passive) { 766 /* need to restart interface to cope with this change */ 767 if (ospfd_process == PROC_OSPF_ENGINE) 768 if_fsm(i, IF_EVT_DOWN); 769 i->passive = xi->passive; 770 if (ospfd_process == PROC_OSPF_ENGINE) 771 if_fsm(i, IF_EVT_UP); 772 } 773 #endif 774 } 775 return (dirty); 776 } 777 778 struct iface * 779 iface_lookup(struct area *area, struct iface *iface) 780 { 781 struct iface *i; 782 783 LIST_FOREACH(i, &area->iface_list, entry) 784 if (i->ifindex == iface->ifindex) 785 return (i); 786 return (NULL); 787 } 788