1 /* $OpenBSD: ospf6d.c,v 1.22 2011/08/20 19:02:28 sthen 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 int ospf_reload(void); 59 int ospf_sendboth(enum imsg_type, void *, u_int16_t); 60 int merge_interfaces(struct area *, struct area *); 61 struct iface *iface_lookup(struct area *, struct iface *); 62 63 int pipe_parent2ospfe[2]; 64 int pipe_parent2rde[2]; 65 int pipe_ospfe2rde[2]; 66 67 struct ospfd_conf *ospfd_conf = NULL; 68 struct imsgev *iev_ospfe; 69 struct imsgev *iev_rde; 70 char *conffile; 71 72 pid_t ospfe_pid = 0; 73 pid_t rde_pid = 0; 74 75 /* ARGSUSED */ 76 void 77 main_sig_handler(int sig, short event, void *arg) 78 { 79 /* 80 * signal handler rules don't apply, libevent decouples for us 81 */ 82 83 int die = 0; 84 85 switch (sig) { 86 case SIGTERM: 87 case SIGINT: 88 die = 1; 89 /* FALLTHROUGH */ 90 case SIGCHLD: 91 if (check_child(ospfe_pid, "ospf engine")) { 92 ospfe_pid = 0; 93 die = 1; 94 } 95 if (check_child(rde_pid, "route decision engine")) { 96 rde_pid = 0; 97 die = 1; 98 } 99 if (die) 100 ospfd_shutdown(); 101 break; 102 case SIGHUP: 103 if (ospf_reload() == -1) 104 log_warnx("configuration reload failed"); 105 else 106 log_debug("configuration reloaded"); 107 break; 108 default: 109 fatalx("unexpected signal"); 110 /* NOTREACHED */ 111 } 112 } 113 114 __dead void 115 usage(void) 116 { 117 extern char *__progname; 118 119 fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 120 __progname); 121 exit(1); 122 } 123 124 int 125 main(int argc, char *argv[]) 126 { 127 struct event ev_sigint, ev_sigterm, ev_sigchld, ev_sighup; 128 int ch, opts = 0; 129 int debug = 0; 130 int ipforwarding; 131 int mib[4]; 132 size_t len; 133 134 conffile = CONF_FILE; 135 ospfd_process = PROC_MAIN; 136 137 log_init(1); /* log to stderr until daemonized */ 138 log_verbose(1); 139 140 while ((ch = getopt(argc, argv, "cdD:f:nv")) != -1) { 141 switch (ch) { 142 case 'c': 143 opts |= OSPFD_OPT_FORCE_DEMOTE; 144 break; 145 case 'd': 146 debug = 1; 147 break; 148 case 'D': 149 if (cmdline_symset(optarg) < 0) 150 log_warnx("could not parse macro definition %s", 151 optarg); 152 break; 153 case 'f': 154 conffile = optarg; 155 break; 156 case 'n': 157 opts |= OSPFD_OPT_NOACTION; 158 break; 159 case 'v': 160 if (opts & OSPFD_OPT_VERBOSE) 161 opts |= OSPFD_OPT_VERBOSE2; 162 opts |= OSPFD_OPT_VERBOSE; 163 log_verbose(1); 164 break; 165 default: 166 usage(); 167 /* NOTREACHED */ 168 } 169 } 170 171 argc -= optind; 172 argv += optind; 173 if (argc > 0) 174 usage(); 175 176 mib[0] = CTL_NET; 177 mib[1] = PF_INET6; 178 mib[2] = IPPROTO_IPV6; 179 mib[3] = IPCTL_FORWARDING; 180 len = sizeof(ipforwarding); 181 if (sysctl(mib, 4, &ipforwarding, &len, NULL, 0) == -1) 182 err(1, "sysctl"); 183 184 if (ipforwarding != 1) { 185 log_warnx("WARNING: IPv6 forwarding NOT enabled, " 186 "running as stub router"); 187 opts |= OSPFD_OPT_STUB_ROUTER; 188 } 189 190 /* prepare and fetch interfaces early */ 191 if_init(); 192 193 /* parse config file */ 194 if ((ospfd_conf = parse_config(conffile, opts)) == NULL ) 195 exit(1); 196 197 if (ospfd_conf->opts & OSPFD_OPT_NOACTION) { 198 if (ospfd_conf->opts & OSPFD_OPT_VERBOSE) 199 print_config(ospfd_conf); 200 else 201 fprintf(stderr, "configuration OK\n"); 202 exit(0); 203 } 204 205 /* check for root privileges */ 206 if (geteuid()) 207 errx(1, "need root privileges"); 208 209 /* check for ospfd user */ 210 if (getpwnam(OSPF6D_USER) == NULL) 211 errx(1, "unknown user %s", OSPF6D_USER); 212 213 log_init(debug); 214 log_verbose(ospfd_conf->opts & OSPFD_OPT_VERBOSE); 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 event_dispatch(); 286 287 ospfd_shutdown(); 288 /* NOTREACHED */ 289 return (0); 290 } 291 292 void 293 ospfd_shutdown(void) 294 { 295 pid_t pid; 296 297 if (ospfe_pid) 298 kill(ospfe_pid, SIGTERM); 299 300 if (rde_pid) 301 kill(rde_pid, SIGTERM); 302 303 control_cleanup(); 304 kr_shutdown(); 305 carp_demote_shutdown(); 306 307 do { 308 if ((pid = wait(NULL)) == -1 && 309 errno != EINTR && errno != ECHILD) 310 fatal("wait"); 311 } while (pid != -1 || (pid == -1 && errno == EINTR)); 312 313 msgbuf_clear(&iev_ospfe->ibuf.w); 314 free(iev_ospfe); 315 msgbuf_clear(&iev_rde->ibuf.w); 316 free(iev_rde); 317 free(ospfd_conf); 318 319 log_info("terminating"); 320 exit(0); 321 } 322 323 int 324 check_child(pid_t pid, const char *pname) 325 { 326 int status; 327 328 if (waitpid(pid, &status, WNOHANG) > 0) { 329 if (WIFEXITED(status)) { 330 log_warnx("lost child: %s exited", pname); 331 return (1); 332 } 333 if (WIFSIGNALED(status)) { 334 log_warnx("lost child: %s terminated; signal %d", 335 pname, WTERMSIG(status)); 336 return (1); 337 } 338 } 339 340 return (0); 341 } 342 343 /* imsg handling */ 344 /* ARGSUSED */ 345 void 346 main_dispatch_ospfe(int fd, short event, void *bula) 347 { 348 struct imsgev *iev = bula; 349 struct imsgbuf *ibuf = &iev->ibuf; 350 struct imsg imsg; 351 struct demote_msg dmsg; 352 ssize_t n; 353 int shut = 0, verbose; 354 355 if (event & EV_READ) { 356 if ((n = imsg_read(ibuf)) == -1) 357 fatal("imsg_read error"); 358 if (n == 0) /* connection closed */ 359 shut = 1; 360 } 361 if (event & EV_WRITE) { 362 if (msgbuf_write(&ibuf->w) == -1) 363 fatal("msgbuf_write"); 364 } 365 366 for (;;) { 367 if ((n = imsg_get(ibuf, &imsg)) == -1) 368 fatal("imsg_get"); 369 370 if (n == 0) 371 break; 372 373 switch (imsg.hdr.type) { 374 case IMSG_CTL_RELOAD: 375 if (ospf_reload() == -1) 376 log_warnx("configuration reload failed"); 377 else 378 log_debug("configuration reloaded"); 379 break; 380 case IMSG_CTL_FIB_COUPLE: 381 kr_fib_couple(); 382 break; 383 case IMSG_CTL_FIB_DECOUPLE: 384 kr_fib_decouple(); 385 break; 386 case IMSG_CTL_KROUTE: 387 case IMSG_CTL_KROUTE_ADDR: 388 kr_show_route(&imsg); 389 break; 390 case IMSG_DEMOTE: 391 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(dmsg)) 392 fatalx("invalid size of OE request"); 393 memcpy(&dmsg, imsg.data, sizeof(dmsg)); 394 carp_demote_set(dmsg.demote_group, dmsg.level); 395 break; 396 case IMSG_CTL_LOG_VERBOSE: 397 /* already checked by ospfe */ 398 memcpy(&verbose, imsg.data, sizeof(verbose)); 399 log_verbose(verbose); 400 break; 401 default: 402 log_debug("main_dispatch_ospfe: error handling imsg %d", 403 imsg.hdr.type); 404 break; 405 } 406 imsg_free(&imsg); 407 } 408 if (!shut) 409 imsg_event_add(iev); 410 else { 411 /* this pipe is dead, so remove the event handler */ 412 event_del(&iev->ev); 413 event_loopexit(NULL); 414 } 415 } 416 417 /* ARGSUSED */ 418 void 419 main_dispatch_rde(int fd, short event, void *bula) 420 { 421 struct imsgev *iev = bula; 422 struct imsgbuf *ibuf = &iev->ibuf; 423 struct imsg imsg; 424 ssize_t n; 425 int shut = 0; 426 427 if (event & EV_READ) { 428 if ((n = imsg_read(ibuf)) == -1) 429 fatal("imsg_read error"); 430 if (n == 0) /* connection closed */ 431 shut = 1; 432 } 433 if (event & EV_WRITE) { 434 if (msgbuf_write(&ibuf->w) == -1) 435 fatal("msgbuf_write"); 436 } 437 438 for (;;) { 439 if ((n = imsg_get(ibuf, &imsg)) == -1) 440 fatal("imsg_get"); 441 442 if (n == 0) 443 break; 444 445 switch (imsg.hdr.type) { 446 case IMSG_KROUTE_CHANGE: 447 if (kr_change(imsg.data)) 448 log_warn("main_dispatch_rde: error changing " 449 "route"); 450 break; 451 case IMSG_KROUTE_DELETE: 452 if (kr_delete(imsg.data)) 453 log_warn("main_dispatch_rde: error deleting " 454 "route"); 455 break; 456 default: 457 log_debug("main_dispatch_rde: error handling imsg %d", 458 imsg.hdr.type); 459 break; 460 } 461 imsg_free(&imsg); 462 } 463 if (!shut) 464 imsg_event_add(iev); 465 else { 466 /* this pipe is dead, so remove the event handler */ 467 event_del(&iev->ev); 468 event_loopexit(NULL); 469 } 470 } 471 472 void 473 main_imsg_compose_ospfe(int type, pid_t pid, void *data, u_int16_t datalen) 474 { 475 if (iev_ospfe == NULL) 476 return; 477 imsg_compose_event(iev_ospfe, type, 0, pid, -1, data, datalen); 478 } 479 480 void 481 main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen) 482 { 483 if (iev_rde == NULL) 484 return; 485 imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen); 486 } 487 488 void 489 imsg_event_add(struct imsgev *iev) 490 { 491 iev->events = EV_READ; 492 if (iev->ibuf.w.queued) 493 iev->events |= EV_WRITE; 494 495 event_del(&iev->ev); 496 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 497 event_add(&iev->ev, NULL); 498 } 499 500 int 501 imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 502 pid_t pid, int fd, void *data, u_int16_t datalen) 503 { 504 int ret; 505 506 if ((ret = imsg_compose(&iev->ibuf, type, peerid, 507 pid, fd, data, datalen)) != -1) 508 imsg_event_add(iev); 509 return (ret); 510 } 511 512 int 513 ospf_redistribute(struct kroute *kr, u_int32_t *metric) 514 { 515 struct redistribute *r; 516 struct in6_addr ina, inb; 517 u_int8_t is_default = 0; 518 519 /* only allow ::/0 via REDIST_DEFAULT */ 520 if (IN6_IS_ADDR_UNSPECIFIED(&kr->prefix) && kr->prefixlen == 0) 521 is_default = 1; 522 523 SIMPLEQ_FOREACH(r, &ospfd_conf->redist_list, entry) { 524 switch (r->type & ~REDIST_NO) { 525 case REDIST_LABEL: 526 if (kr->rtlabel == r->label) { 527 *metric = r->metric; 528 return (r->type & REDIST_NO ? 0 : 1); 529 } 530 break; 531 case REDIST_STATIC: 532 /* 533 * Dynamic routes are not redistributable. Placed here 534 * so that link local addresses can be redistributed 535 * via a rtlabel. 536 */ 537 if (is_default) 538 continue; 539 if (kr->flags & F_DYNAMIC) 540 continue; 541 if (kr->flags & F_STATIC) { 542 *metric = r->metric; 543 return (r->type & REDIST_NO ? 0 : 1); 544 } 545 break; 546 case REDIST_CONNECTED: 547 if (is_default) 548 continue; 549 if (kr->flags & F_DYNAMIC) 550 continue; 551 if (kr->flags & F_CONNECTED) { 552 *metric = r->metric; 553 return (r->type & REDIST_NO ? 0 : 1); 554 } 555 break; 556 case REDIST_ADDR: 557 if (kr->flags & F_DYNAMIC) 558 continue; 559 560 if (IN6_IS_ADDR_UNSPECIFIED(&r->addr) && 561 r->prefixlen == 0) { 562 if (is_default) { 563 *metric = r->metric; 564 return (r->type & REDIST_NO ? 0 : 1); 565 } else 566 return (0); 567 } 568 569 inet6applymask(&ina, &kr->prefix, r->prefixlen); 570 inet6applymask(&inb, &r->addr, r->prefixlen); 571 if (IN6_ARE_ADDR_EQUAL(&ina, &inb) && 572 kr->prefixlen >= r->prefixlen) { 573 *metric = r->metric; 574 return (r->type & REDIST_NO ? 0 : 1); 575 } 576 break; 577 case REDIST_DEFAULT: 578 if (is_default) { 579 *metric = r->metric; 580 return (r->type & REDIST_NO ? 0 : 1); 581 } 582 break; 583 } 584 } 585 586 return (0); 587 } 588 589 int 590 ospf_reload(void) 591 { 592 struct area *area; 593 struct ospfd_conf *xconf; 594 595 if ((xconf = parse_config(conffile, ospfd_conf->opts)) == NULL) 596 return (-1); 597 598 /* send config to childs */ 599 if (ospf_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 600 return (-1); 601 602 /* send areas, interfaces happen out of band */ 603 LIST_FOREACH(area, &xconf->area_list, entry) { 604 if (ospf_sendboth(IMSG_RECONF_AREA, area, sizeof(*area)) == -1) 605 return (-1); 606 } 607 608 if (ospf_sendboth(IMSG_RECONF_END, NULL, 0) == -1) 609 return (-1); 610 611 /* XXX send newly available interfaces to the childs */ 612 613 merge_config(ospfd_conf, xconf); 614 /* update redistribute lists */ 615 kr_reload(); 616 return (0); 617 } 618 619 int 620 ospf_sendboth(enum imsg_type type, void *buf, u_int16_t len) 621 { 622 if (imsg_compose_event(iev_ospfe, type, 0, 0, -1, buf, len) == -1) 623 return (-1); 624 if (imsg_compose_event(iev_rde, type, 0, 0, -1, buf, len) == -1) 625 return (-1); 626 return (0); 627 } 628 629 void 630 merge_config(struct ospfd_conf *conf, struct ospfd_conf *xconf) 631 { 632 struct area *a, *xa, *na; 633 struct iface *iface; 634 struct redistribute *r; 635 636 /* change of rtr_id needs a restart */ 637 conf->flags = xconf->flags; 638 conf->spf_delay = xconf->spf_delay; 639 conf->spf_hold_time = xconf->spf_hold_time; 640 conf->redistribute = xconf->redistribute; 641 642 if (ospfd_process == PROC_MAIN) { 643 /* main process does neither use areas nor interfaces */ 644 while ((r = SIMPLEQ_FIRST(&conf->redist_list)) != NULL) { 645 SIMPLEQ_REMOVE_HEAD(&conf->redist_list, entry); 646 free(r); 647 } 648 while ((r = SIMPLEQ_FIRST(&xconf->redist_list)) != NULL) { 649 SIMPLEQ_REMOVE_HEAD(&xconf->redist_list, entry); 650 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, entry); 651 } 652 goto done; 653 } 654 655 /* merge areas and interfaces */ 656 for (a = LIST_FIRST(&conf->area_list); a != NULL; a = na) { 657 na = LIST_NEXT(a, entry); 658 /* find deleted areas */ 659 if ((xa = area_find(xconf, a->id)) == NULL) { 660 if (ospfd_process == PROC_OSPF_ENGINE) { 661 LIST_FOREACH(iface, &a->iface_list, entry) 662 if_fsm(iface, IF_EVT_DOWN); 663 } 664 LIST_REMOVE(a, entry); 665 area_del(a); 666 } 667 } 668 669 for (xa = LIST_FIRST(&xconf->area_list); xa != NULL; xa = na) { 670 na = LIST_NEXT(xa, entry); 671 if ((a = area_find(conf, xa->id)) == NULL) { 672 LIST_REMOVE(xa, entry); 673 LIST_INSERT_HEAD(&conf->area_list, xa, entry); 674 if (ospfd_process == PROC_OSPF_ENGINE) { 675 /* start interfaces */ 676 ospfe_demote_area(xa, 0); 677 LIST_FOREACH(iface, &xa->iface_list, entry) 678 if_start(conf, iface); 679 } 680 /* no need to merge interfaces */ 681 continue; 682 } 683 /* 684 * stub is not yet used but switching between stub and normal 685 * will be another painful job. 686 */ 687 a->stub = xa->stub; 688 a->stub_default_cost = xa->stub_default_cost; 689 if (ospfd_process == PROC_RDE_ENGINE) 690 a->dirty = 1; /* force SPF tree recalculation */ 691 692 /* merge interfaces */ 693 if (merge_interfaces(a, xa) && 694 ospfd_process == PROC_OSPF_ENGINE) 695 a->dirty = 1; /* force rtr LSA update */ 696 } 697 698 if (ospfd_process == PROC_OSPF_ENGINE) { 699 LIST_FOREACH(a, &conf->area_list, entry) { 700 LIST_FOREACH(iface, &a->iface_list, entry) { 701 if (iface->state == IF_STA_NEW) { 702 iface->state = IF_STA_DOWN; 703 if_start(conf, iface); 704 } 705 } 706 if (a->dirty) { 707 a->dirty = 0; 708 orig_rtr_lsa(LIST_FIRST(&a->iface_list)); 709 } 710 } 711 } 712 713 done: 714 while ((a = LIST_FIRST(&xconf->area_list)) != NULL) { 715 LIST_REMOVE(a, entry); 716 area_del(a); 717 } 718 free(xconf); 719 } 720 721 int 722 merge_interfaces(struct area *a, struct area *xa) 723 { 724 struct iface *i, *xi, *ni; 725 int dirty = 0; 726 727 /* problems: 728 * - new interfaces (easy) 729 * - deleted interfaces (needs to be done via fsm?) 730 * - changing passive (painful?) 731 */ 732 for (i = LIST_FIRST(&a->iface_list); i != NULL; i = ni) { 733 ni = LIST_NEXT(i, entry); 734 if (iface_lookup(xa, i) == NULL) { 735 log_debug("merge_interfaces: proc %d area %s removing " 736 "interface %s", ospfd_process, inet_ntoa(a->id), 737 i->name); 738 if (ospfd_process == PROC_OSPF_ENGINE) 739 if_fsm(i, IF_EVT_DOWN); 740 LIST_REMOVE(i, entry); 741 if_del(i); 742 } 743 } 744 745 for (xi = LIST_FIRST(&xa->iface_list); xi != NULL; xi = ni) { 746 ni = LIST_NEXT(xi, entry); 747 if ((i = iface_lookup(a, xi)) == NULL) { 748 /* new interface but delay initialisation */ 749 log_debug("merge_interfaces: proc %d area %s adding " 750 "interface %s", ospfd_process, inet_ntoa(a->id), 751 xi->name); 752 LIST_REMOVE(xi, entry); 753 LIST_INSERT_HEAD(&a->iface_list, xi, entry); 754 if (ospfd_process == PROC_OSPF_ENGINE) 755 xi->state = IF_STA_NEW; 756 continue; 757 } 758 log_debug("merge_interfaces: proc %d area %s merging " 759 "interface %s", ospfd_process, inet_ntoa(a->id), i->name); 760 i->addr = xi->addr; 761 i->dst = xi->dst; 762 i->abr_id = xi->abr_id; 763 i->baudrate = xi->baudrate; 764 i->dead_interval = xi->dead_interval; 765 i->mtu = xi->mtu; 766 i->transmit_delay = xi->transmit_delay; 767 i->hello_interval = xi->hello_interval; 768 i->rxmt_interval = xi->rxmt_interval; 769 if (i->metric != xi->metric) 770 dirty = 1; 771 i->metric = xi->metric; 772 i->priority = xi->priority; 773 i->flags = xi->flags; /* needed? */ 774 i->type = xi->type; /* needed? */ 775 i->media_type = xi->media_type; /* needed? */ 776 i->linkstate = xi->linkstate; /* needed? */ 777 778 #if 0 /* XXX needs some kind of love */ 779 if (i->passive != xi->passive) { 780 /* need to restart interface to cope with this change */ 781 if (ospfd_process == PROC_OSPF_ENGINE) 782 if_fsm(i, IF_EVT_DOWN); 783 i->passive = xi->passive; 784 if (ospfd_process == PROC_OSPF_ENGINE) 785 if_fsm(i, IF_EVT_UP); 786 } 787 #endif 788 } 789 return (dirty); 790 } 791 792 struct iface * 793 iface_lookup(struct area *area, struct iface *iface) 794 { 795 struct iface *i; 796 797 LIST_FOREACH(i, &area->iface_list, entry) 798 if (i->ifindex == iface->ifindex) 799 return (i); 800 return (NULL); 801 } 802