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