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