1 /* $OpenBSD: ospfd.c,v 1.64 2009/04/07 14:57:33 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004 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 "ospfd.h" 44 #include "ospf.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 imsgbuf *ibuf_ospfe; 69 struct imsgbuf *ibuf_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 [-cdnv] [-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 struct area *a; 130 int ch, opts = 0; 131 int debug = 0; 132 int ipforwarding; 133 int mib[4]; 134 size_t len; 135 char *sockname; 136 137 conffile = CONF_FILE; 138 ospfd_process = PROC_MAIN; 139 sockname = OSPFD_SOCKET; 140 141 log_init(1); /* log to stderr until daemonized */ 142 143 while ((ch = getopt(argc, argv, "cdD:f:ns:v")) != -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 break; 170 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_INET; 184 mib[2] = IPPROTO_IP; 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: IP forwarding NOT enabled, " 192 "running as stub router"); 193 opts |= OSPFD_OPT_STUB_ROUTER; 194 } 195 196 197 /* fetch interfaces early */ 198 kif_init(); 199 200 /* parse config file */ 201 if ((ospfd_conf = parse_config(conffile, opts)) == NULL) { 202 kr_shutdown(); 203 exit(1); 204 } 205 ospfd_conf->csock = sockname; 206 207 if (ospfd_conf->opts & OSPFD_OPT_NOACTION) { 208 if (ospfd_conf->opts & OSPFD_OPT_VERBOSE) 209 print_config(ospfd_conf); 210 else 211 fprintf(stderr, "configuration OK\n"); 212 kr_shutdown(); 213 exit(0); 214 } 215 216 /* check for root privileges */ 217 if (geteuid()) 218 errx(1, "need root privileges"); 219 220 /* check for ospfd user */ 221 if (getpwnam(OSPFD_USER) == NULL) 222 errx(1, "unknown user %s", OSPFD_USER); 223 224 log_init(debug); 225 226 if (!debug) 227 daemon(1, 0); 228 229 log_info("startup"); 230 231 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, 232 pipe_parent2ospfe) == -1) 233 fatal("socketpair"); 234 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2rde) == -1) 235 fatal("socketpair"); 236 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_ospfe2rde) == -1) 237 fatal("socketpair"); 238 session_socket_blockmode(pipe_parent2ospfe[0], BM_NONBLOCK); 239 session_socket_blockmode(pipe_parent2ospfe[1], BM_NONBLOCK); 240 session_socket_blockmode(pipe_parent2rde[0], BM_NONBLOCK); 241 session_socket_blockmode(pipe_parent2rde[1], BM_NONBLOCK); 242 session_socket_blockmode(pipe_ospfe2rde[0], BM_NONBLOCK); 243 session_socket_blockmode(pipe_ospfe2rde[1], BM_NONBLOCK); 244 245 /* start children */ 246 rde_pid = rde(ospfd_conf, pipe_parent2rde, pipe_ospfe2rde, 247 pipe_parent2ospfe); 248 ospfe_pid = ospfe(ospfd_conf, pipe_parent2ospfe, pipe_ospfe2rde, 249 pipe_parent2rde); 250 251 /* show who we are */ 252 setproctitle("parent"); 253 254 event_init(); 255 256 /* setup signal handler */ 257 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 258 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 259 signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, NULL); 260 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 261 signal_add(&ev_sigint, NULL); 262 signal_add(&ev_sigterm, NULL); 263 signal_add(&ev_sigchld, NULL); 264 signal_add(&ev_sighup, NULL); 265 signal(SIGPIPE, SIG_IGN); 266 267 /* setup pipes to children */ 268 close(pipe_parent2ospfe[1]); 269 close(pipe_parent2rde[1]); 270 close(pipe_ospfe2rde[0]); 271 close(pipe_ospfe2rde[1]); 272 273 if ((ibuf_ospfe = malloc(sizeof(struct imsgbuf))) == NULL || 274 (ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL) 275 fatal(NULL); 276 imsg_init(ibuf_ospfe, pipe_parent2ospfe[0], main_dispatch_ospfe); 277 imsg_init(ibuf_rde, pipe_parent2rde[0], main_dispatch_rde); 278 279 /* setup event handler */ 280 ibuf_ospfe->events = EV_READ; 281 event_set(&ibuf_ospfe->ev, ibuf_ospfe->fd, ibuf_ospfe->events, 282 ibuf_ospfe->handler, ibuf_ospfe); 283 event_add(&ibuf_ospfe->ev, NULL); 284 285 ibuf_rde->events = EV_READ; 286 event_set(&ibuf_rde->ev, ibuf_rde->fd, ibuf_rde->events, 287 ibuf_rde->handler, ibuf_rde); 288 event_add(&ibuf_rde->ev, NULL); 289 290 if (kr_init(!(ospfd_conf->flags & OSPFD_FLAG_NO_FIB_UPDATE)) == -1) 291 fatalx("kr_init failed"); 292 293 /* remove unneded stuff from config */ 294 while ((a = LIST_FIRST(&ospfd_conf->area_list)) != NULL) { 295 LIST_REMOVE(a, entry); 296 area_del(a); 297 } 298 299 event_dispatch(); 300 301 ospfd_shutdown(); 302 /* NOTREACHED */ 303 return (0); 304 } 305 306 void 307 ospfd_shutdown(void) 308 { 309 pid_t pid; 310 311 if (ospfe_pid) 312 kill(ospfe_pid, SIGTERM); 313 314 if (rde_pid) 315 kill(rde_pid, SIGTERM); 316 317 control_cleanup(ospfd_conf->csock); 318 kr_shutdown(); 319 carp_demote_shutdown(); 320 321 do { 322 if ((pid = wait(NULL)) == -1 && 323 errno != EINTR && errno != ECHILD) 324 fatal("wait"); 325 } while (pid != -1 || (pid == -1 && errno == EINTR)); 326 327 msgbuf_clear(&ibuf_ospfe->w); 328 free(ibuf_ospfe); 329 msgbuf_clear(&ibuf_rde->w); 330 free(ibuf_rde); 331 free(ospfd_conf); 332 333 log_info("terminating"); 334 exit(0); 335 } 336 337 int 338 check_child(pid_t pid, const char *pname) 339 { 340 int status; 341 342 if (waitpid(pid, &status, WNOHANG) > 0) { 343 if (WIFEXITED(status)) { 344 log_warnx("lost child: %s exited", pname); 345 return (1); 346 } 347 if (WIFSIGNALED(status)) { 348 log_warnx("lost child: %s terminated; signal %d", 349 pname, WTERMSIG(status)); 350 return (1); 351 } 352 } 353 354 return (0); 355 } 356 357 /* imsg handling */ 358 /* ARGSUSED */ 359 void 360 main_dispatch_ospfe(int fd, short event, void *bula) 361 { 362 struct imsgbuf *ibuf = bula; 363 struct imsg imsg; 364 struct demote_msg dmsg; 365 ssize_t n; 366 int shut = 0; 367 368 switch (event) { 369 case EV_READ: 370 if ((n = imsg_read(ibuf)) == -1) 371 fatal("imsg_read error"); 372 if (n == 0) /* connection closed */ 373 shut = 1; 374 break; 375 case EV_WRITE: 376 if (msgbuf_write(&ibuf->w) == -1) 377 fatal("msgbuf_write"); 378 imsg_event_add(ibuf); 379 return; 380 default: 381 fatalx("unknown event"); 382 } 383 384 for (;;) { 385 if ((n = imsg_get(ibuf, &imsg)) == -1) 386 fatal("imsg_get"); 387 388 if (n == 0) 389 break; 390 391 switch (imsg.hdr.type) { 392 case IMSG_CTL_RELOAD: 393 if (ospf_reload() == -1) 394 log_warnx("configuration reload failed"); 395 else 396 log_debug("configuration reloaded"); 397 break; 398 case IMSG_CTL_FIB_COUPLE: 399 kr_fib_couple(); 400 break; 401 case IMSG_CTL_FIB_DECOUPLE: 402 kr_fib_decouple(); 403 break; 404 case IMSG_CTL_KROUTE: 405 case IMSG_CTL_KROUTE_ADDR: 406 kr_show_route(&imsg); 407 break; 408 case IMSG_CTL_IFINFO: 409 if (imsg.hdr.len == IMSG_HEADER_SIZE) 410 kr_ifinfo(NULL, imsg.hdr.pid); 411 else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ) 412 kr_ifinfo(imsg.data, imsg.hdr.pid); 413 else 414 log_warnx("IFINFO request with wrong len"); 415 break; 416 case IMSG_DEMOTE: 417 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(dmsg)) 418 fatalx("invalid size of OE request"); 419 memcpy(&dmsg, imsg.data, sizeof(dmsg)); 420 carp_demote_set(dmsg.demote_group, dmsg.level); 421 break; 422 default: 423 log_debug("main_dispatch_ospfe: error handling imsg %d", 424 imsg.hdr.type); 425 break; 426 } 427 imsg_free(&imsg); 428 } 429 if (!shut) 430 imsg_event_add(ibuf); 431 else { 432 /* this pipe is dead, so remove the event handler */ 433 event_del(&ibuf->ev); 434 event_loopexit(NULL); 435 } 436 } 437 438 /* ARGSUSED */ 439 void 440 main_dispatch_rde(int fd, short event, void *bula) 441 { 442 struct imsgbuf *ibuf = bula; 443 struct imsg imsg; 444 ssize_t n; 445 int count, shut = 0; 446 447 switch (event) { 448 case EV_READ: 449 if ((n = imsg_read(ibuf)) == -1) 450 fatal("imsg_read error"); 451 if (n == 0) /* connection closed */ 452 shut = 1; 453 break; 454 case EV_WRITE: 455 if (msgbuf_write(&ibuf->w) == -1) 456 fatal("msgbuf_write"); 457 imsg_event_add(ibuf); 458 return; 459 default: 460 fatalx("unknown event"); 461 } 462 463 for (;;) { 464 if ((n = imsg_get(ibuf, &imsg)) == -1) 465 fatal("imsg_get"); 466 467 if (n == 0) 468 break; 469 470 switch (imsg.hdr.type) { 471 case IMSG_KROUTE_CHANGE: 472 count = (imsg.hdr.len - IMSG_HEADER_SIZE) / 473 sizeof(struct kroute); 474 if (kr_change(imsg.data, count)) 475 log_warn("main_dispatch_rde: error changing " 476 "route"); 477 break; 478 case IMSG_KROUTE_DELETE: 479 if (kr_delete(imsg.data)) 480 log_warn("main_dispatch_rde: error deleting " 481 "route"); 482 break; 483 default: 484 log_debug("main_dispatch_rde: error handling imsg %d", 485 imsg.hdr.type); 486 break; 487 } 488 imsg_free(&imsg); 489 } 490 if (!shut) 491 imsg_event_add(ibuf); 492 else { 493 /* this pipe is dead, so remove the event handler */ 494 event_del(&ibuf->ev); 495 event_loopexit(NULL); 496 } 497 } 498 499 void 500 main_imsg_compose_ospfe(int type, pid_t pid, void *data, u_int16_t datalen) 501 { 502 imsg_compose(ibuf_ospfe, type, 0, pid, data, datalen); 503 } 504 505 void 506 main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen) 507 { 508 imsg_compose(ibuf_rde, type, 0, pid, data, datalen); 509 } 510 511 /* this needs to be added here so that ospfctl can be used without libevent */ 512 void 513 imsg_event_add(struct imsgbuf *ibuf) 514 { 515 ibuf->events = EV_READ; 516 if (ibuf->w.queued) 517 ibuf->events |= EV_WRITE; 518 519 event_del(&ibuf->ev); 520 event_set(&ibuf->ev, ibuf->fd, ibuf->events, ibuf->handler, ibuf); 521 event_add(&ibuf->ev, NULL); 522 } 523 524 int 525 ospf_redistribute(struct kroute *kr, u_int32_t *metric) 526 { 527 struct redistribute *r; 528 u_int8_t is_default = 0; 529 530 /* only allow 0.0.0.0/0 via REDIST_DEFAULT */ 531 if (kr->prefix.s_addr == INADDR_ANY && 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 (r->addr.s_addr == INADDR_ANY && 572 r->mask.s_addr == INADDR_ANY) { 573 if (is_default) 574 return (r->type & REDIST_NO? 0 : 1); 575 else 576 return (0); 577 } 578 579 if ((kr->prefix.s_addr & r->mask.s_addr) == 580 (r->addr.s_addr & r->mask.s_addr) && 581 kr->prefixlen >= mask2prefixlen(r->mask.s_addr)) { 582 *metric = r->metric; 583 return (r->type & REDIST_NO ? 0 : 1); 584 } 585 break; 586 case REDIST_DEFAULT: 587 if (is_default) 588 return (r->type & REDIST_NO ? 0 : 1); 589 break; 590 } 591 } 592 593 return (0); 594 } 595 596 int 597 ospf_reload(void) 598 { 599 struct area *area; 600 struct iface *iface; 601 struct ospfd_conf *xconf; 602 struct redistribute *r; 603 604 if ((xconf = parse_config(conffile, ospfd_conf->opts)) == NULL) 605 return (-1); 606 607 /* send config to childs */ 608 if (ospf_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 609 return (-1); 610 611 /* send interfaces */ 612 LIST_FOREACH(area, &xconf->area_list, entry) { 613 if (ospf_sendboth(IMSG_RECONF_AREA, area, sizeof(*area)) == -1) 614 return (-1); 615 616 SIMPLEQ_FOREACH(r, &area->redist_list, entry) { 617 main_imsg_compose_rde(IMSG_RECONF_REDIST, 0, r, 618 sizeof(*r)); 619 } 620 LIST_FOREACH(iface, &area->iface_list, entry) { 621 if (ospf_sendboth(IMSG_RECONF_IFACE, iface, 622 sizeof(*iface)) == -1) 623 return (-1); 624 if (iface->auth_type == AUTH_CRYPT) 625 if (md_list_send(&iface->auth_md_list, 626 ibuf_ospfe) == -1) 627 return (-1); 628 } 629 } 630 631 if (ospf_sendboth(IMSG_RECONF_END, NULL, 0) == -1) 632 return (-1); 633 634 merge_config(ospfd_conf, xconf); 635 /* update redistribute lists */ 636 kr_reload(); 637 return (0); 638 } 639 640 int 641 ospf_sendboth(enum imsg_type type, void *buf, u_int16_t len) 642 { 643 if (imsg_compose(ibuf_ospfe, type, 0, 0, buf, len) == -1) 644 return (-1); 645 if (imsg_compose(ibuf_rde, type, 0, 0, buf, len) == -1) 646 return (-1); 647 return (0); 648 } 649 650 void 651 merge_config(struct ospfd_conf *conf, struct ospfd_conf *xconf) 652 { 653 struct area *a, *xa, *na; 654 struct iface *iface; 655 struct redistribute *r; 656 int rchange = 0; 657 658 /* change of rtr_id needs a restart */ 659 conf->flags = xconf->flags; 660 conf->spf_delay = xconf->spf_delay; 661 conf->spf_hold_time = xconf->spf_hold_time; 662 if (SIMPLEQ_EMPTY(&conf->redist_list) != 663 SIMPLEQ_EMPTY(&xconf->redist_list)) 664 rchange = 1; 665 conf->rfc1583compat = xconf->rfc1583compat; 666 667 if (ospfd_process == PROC_MAIN) { 668 /* main process does neither use areas nor interfaces */ 669 while ((r = SIMPLEQ_FIRST(&conf->redist_list)) != NULL) { 670 SIMPLEQ_REMOVE_HEAD(&conf->redist_list, entry); 671 free(r); 672 } 673 while ((r = SIMPLEQ_FIRST(&xconf->redist_list)) != NULL) { 674 SIMPLEQ_REMOVE_HEAD(&xconf->redist_list, entry); 675 SIMPLEQ_INSERT_TAIL(&conf->redist_list, r, entry); 676 } 677 goto done; 678 } 679 680 /* merge areas and interfaces */ 681 for (a = LIST_FIRST(&conf->area_list); a != NULL; a = na) { 682 na = LIST_NEXT(a, entry); 683 /* find deleted areas */ 684 if ((xa = area_find(xconf, a->id)) == NULL) { 685 if (ospfd_process == PROC_OSPF_ENGINE) { 686 LIST_FOREACH(iface, &a->iface_list, entry) 687 if_fsm(iface, IF_EVT_DOWN); 688 } 689 LIST_REMOVE(a, entry); 690 area_del(a); 691 } 692 } 693 694 for (xa = LIST_FIRST(&xconf->area_list); xa != NULL; xa = na) { 695 na = LIST_NEXT(xa, entry); 696 if ((a = area_find(conf, xa->id)) == NULL) { 697 LIST_REMOVE(xa, entry); 698 LIST_INSERT_HEAD(&conf->area_list, xa, entry); 699 if (ospfd_process == PROC_OSPF_ENGINE) { 700 /* start interfaces */ 701 ospfe_demote_area(xa, 0); 702 LIST_FOREACH(iface, &xa->iface_list, entry) { 703 if_init(conf, iface); 704 if (if_fsm(iface, IF_EVT_UP)) { 705 log_debug("error starting " 706 "interface %s", 707 iface->name); 708 } 709 } 710 } 711 /* no need to merge interfaces */ 712 continue; 713 } 714 /* 715 * stub is not yet used but switching between stub and normal 716 * will be another painful job. 717 */ 718 if (a->stub != xa->stub && ospfd_process == PROC_OSPF_ENGINE) 719 a->dirty = 1; /* force rtr LSA update */ 720 if (xa->stub && ospfd_process == PROC_RDE_ENGINE) { 721 while ((r = SIMPLEQ_FIRST(&a->redist_list)) != NULL) { 722 SIMPLEQ_REMOVE_HEAD(&a->redist_list, entry); 723 free(r); 724 } 725 726 while ((r = SIMPLEQ_FIRST(&xa->redist_list)) != NULL) { 727 SIMPLEQ_REMOVE_HEAD(&xa->redist_list, entry); 728 SIMPLEQ_INSERT_TAIL(&a->redist_list, r, entry); 729 } 730 } 731 732 a->stub = xa->stub; 733 a->stub_default_cost = xa->stub_default_cost; 734 if (ospfd_process == PROC_RDE_ENGINE) 735 a->dirty = 1; /* force SPF tree recalculation */ 736 737 /* merge interfaces */ 738 if (merge_interfaces(a, xa) && 739 ospfd_process == PROC_OSPF_ENGINE) 740 a->dirty = 1; /* force rtr LSA update */ 741 } 742 743 if (ospfd_process == PROC_OSPF_ENGINE) { 744 LIST_FOREACH(a, &conf->area_list, entry) { 745 LIST_FOREACH(iface, &a->iface_list, entry) { 746 if (iface->state == IF_STA_NEW) { 747 iface->state = IF_STA_DOWN; 748 if_init(conf, iface); 749 if (if_fsm(iface, IF_EVT_UP)) { 750 log_debug("error starting " 751 "interface %s", 752 iface->name); 753 } 754 } 755 } 756 if (a->dirty || rchange) { 757 a->dirty = 0; 758 orig_rtr_lsa(a); 759 } 760 } 761 } 762 if (ospfd_process == PROC_RDE_ENGINE) { 763 LIST_FOREACH(a, &conf->area_list, entry) { 764 if (a->dirty) { 765 start_spf_timer(); 766 break; 767 } 768 } 769 } 770 771 done: 772 while ((a = LIST_FIRST(&xconf->area_list)) != NULL) { 773 LIST_REMOVE(a, entry); 774 area_del(a); 775 } 776 free(xconf); 777 } 778 779 int 780 merge_interfaces(struct area *a, struct area *xa) 781 { 782 struct iface *i, *xi, *ni; 783 int dirty = 0; 784 785 /* problems: 786 * - new interfaces (easy) 787 * - deleted interfaces (needs to be done via fsm?) 788 * - changing passive (painful?) 789 */ 790 for (i = LIST_FIRST(&a->iface_list); i != NULL; i = ni) { 791 ni = LIST_NEXT(i, entry); 792 if (iface_lookup(xa, i) == NULL) { 793 log_debug("merge_interfaces: proc %d area %s removing " 794 "interface %s", ospfd_process, inet_ntoa(a->id), 795 i->name); 796 if (ospfd_process == PROC_OSPF_ENGINE) 797 if_fsm(i, IF_EVT_DOWN); 798 LIST_REMOVE(i, entry); 799 if_del(i); 800 } 801 } 802 803 for (xi = LIST_FIRST(&xa->iface_list); xi != NULL; xi = ni) { 804 ni = LIST_NEXT(xi, entry); 805 if ((i = iface_lookup(a, xi)) == NULL) { 806 /* new interface but delay initialisation */ 807 log_debug("merge_interfaces: proc %d area %s adding " 808 "interface %s", ospfd_process, inet_ntoa(a->id), 809 xi->name); 810 LIST_REMOVE(xi, entry); 811 LIST_INSERT_HEAD(&a->iface_list, xi, entry); 812 xi->area = a; 813 if (ospfd_process == PROC_OSPF_ENGINE) 814 xi->state = IF_STA_NEW; 815 continue; 816 } 817 log_debug("merge_interfaces: proc %d area %s merging " 818 "interface %s", ospfd_process, inet_ntoa(a->id), i->name); 819 i->addr = xi->addr; 820 i->dst = xi->dst; 821 i->mask = xi->mask; 822 i->abr_id = xi->abr_id; 823 i->baudrate = xi->baudrate; 824 i->dead_interval = xi->dead_interval; 825 i->mtu = xi->mtu; 826 i->transmit_delay = xi->transmit_delay; 827 i->hello_interval = xi->hello_interval; 828 i->rxmt_interval = xi->rxmt_interval; 829 if (i->metric != xi->metric) 830 dirty = 1; 831 i->metric = xi->metric; 832 i->priority = xi->priority; 833 i->flags = xi->flags; /* needed? */ 834 i->type = xi->type; /* needed? */ 835 i->media_type = xi->media_type; /* needed? */ 836 i->linkstate = xi->linkstate; /* needed? */ 837 838 i->auth_type = xi->auth_type; 839 strncpy(i->auth_key, xi->auth_key, MAX_SIMPLE_AUTH_LEN); 840 md_list_clr(&i->auth_md_list); 841 md_list_copy(&i->auth_md_list, &xi->auth_md_list); 842 843 if (i->passive != xi->passive) { 844 /* need to restart interface to cope with this change */ 845 if (ospfd_process == PROC_OSPF_ENGINE) 846 if_fsm(i, IF_EVT_DOWN); 847 i->passive = xi->passive; 848 if (ospfd_process == PROC_OSPF_ENGINE) 849 if_fsm(i, IF_EVT_UP); 850 } 851 } 852 return (dirty); 853 } 854 855 struct iface * 856 iface_lookup(struct area *area, struct iface *iface) 857 { 858 struct iface *i; 859 860 LIST_FOREACH(i, &area->iface_list, entry) 861 if (i->ifindex == iface->ifindex) 862 return (i); 863 return (NULL); 864 } 865