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