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