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