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