1 /* $OpenBSD: eigrpd.c,v 1.36 2024/11/21 13:38:14 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 #include <sys/wait.h> 24 #include <sys/sysctl.h> 25 26 #include <err.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <pwd.h> 30 #include <signal.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <unistd.h> 35 36 #include "eigrpd.h" 37 #include "eigrpe.h" 38 #include "rde.h" 39 #include "log.h" 40 41 static void main_sig_handler(int, short, void *); 42 static __dead void usage(void); 43 static __dead void eigrpd_shutdown(void); 44 static pid_t start_child(enum eigrpd_process, char *, int, int, int, 45 char *); 46 static void main_dispatch_eigrpe(int, short, void *); 47 static void main_dispatch_rde(int, short, void *); 48 static int main_imsg_send_ipc_sockets(struct imsgbuf *, 49 struct imsgbuf *); 50 static int main_imsg_send_config(struct eigrpd_conf *); 51 static int eigrp_reload(void); 52 static int eigrp_sendboth(enum imsg_type, void *, uint16_t); 53 static void merge_instances(struct eigrpd_conf *, struct eigrp *, 54 struct eigrp *); 55 56 struct eigrpd_conf *eigrpd_conf; 57 58 static char *conffile; 59 static struct imsgev *iev_eigrpe; 60 static struct imsgev *iev_rde; 61 static pid_t eigrpe_pid; 62 static pid_t rde_pid; 63 64 static void 65 main_sig_handler(int sig, short event, void *arg) 66 { 67 /* signal handler rules don't apply, libevent decouples for us */ 68 switch (sig) { 69 case SIGTERM: 70 case SIGINT: 71 eigrpd_shutdown(); 72 /* NOTREACHED */ 73 case SIGHUP: 74 if (eigrp_reload() == -1) 75 log_warnx("configuration reload failed"); 76 else 77 log_debug("configuration reloaded"); 78 break; 79 default: 80 fatalx("unexpected signal"); 81 /* NOTREACHED */ 82 } 83 } 84 85 static __dead void 86 usage(void) 87 { 88 extern char *__progname; 89 90 fprintf(stderr, "usage: %s [-dnv] [-D macro=value]" 91 " [-f file] [-s socket]\n", 92 __progname); 93 exit(1); 94 } 95 96 struct eigrpd_global global; 97 98 int 99 main(int argc, char *argv[]) 100 { 101 struct event ev_sigint, ev_sigterm, ev_sighup; 102 char *saved_argv0; 103 int ch; 104 int debug = 0, rflag = 0, eflag = 0; 105 int ipforwarding; 106 int mib[4]; 107 size_t len; 108 char *sockname; 109 int pipe_parent2eigrpe[2]; 110 int pipe_parent2rde[2]; 111 112 conffile = CONF_FILE; 113 log_procname = "parent"; 114 sockname = EIGRPD_SOCKET; 115 116 log_init(1); /* log to stderr until daemonized */ 117 log_verbose(1); 118 119 saved_argv0 = argv[0]; 120 if (saved_argv0 == NULL) 121 saved_argv0 = "eigrpd"; 122 123 while ((ch = getopt(argc, argv, "dD:f:ns:vRE")) != -1) { 124 switch (ch) { 125 case 'd': 126 debug = 1; 127 break; 128 case 'D': 129 if (cmdline_symset(optarg) < 0) 130 log_warnx("could not parse macro definition %s", 131 optarg); 132 break; 133 case 'f': 134 conffile = optarg; 135 break; 136 case 'n': 137 global.cmd_opts |= EIGRPD_OPT_NOACTION; 138 break; 139 case 's': 140 sockname = optarg; 141 break; 142 case 'v': 143 if (global.cmd_opts & EIGRPD_OPT_VERBOSE) 144 global.cmd_opts |= EIGRPD_OPT_VERBOSE2; 145 global.cmd_opts |= EIGRPD_OPT_VERBOSE; 146 break; 147 case 'R': 148 rflag = 1; 149 break; 150 case 'E': 151 eflag = 1; 152 break; 153 default: 154 usage(); 155 /* NOTREACHED */ 156 } 157 } 158 159 argc -= optind; 160 argv += optind; 161 if (argc > 0 || (rflag && eflag)) 162 usage(); 163 164 if (rflag) 165 rde(debug, global.cmd_opts & EIGRPD_OPT_VERBOSE); 166 else if (eflag) 167 eigrpe(debug, global.cmd_opts & EIGRPD_OPT_VERBOSE, sockname); 168 169 mib[0] = CTL_NET; 170 mib[1] = PF_INET; 171 mib[2] = IPPROTO_IP; 172 mib[3] = IPCTL_FORWARDING; 173 len = sizeof(ipforwarding); 174 if (sysctl(mib, 4, &ipforwarding, &len, NULL, 0) == -1) 175 log_warn("sysctl"); 176 177 if (ipforwarding != 1) 178 log_warnx("WARNING: IP forwarding NOT enabled"); 179 180 /* fetch interfaces early */ 181 kif_init(); 182 183 /* parse config file */ 184 if ((eigrpd_conf = parse_config(conffile)) == NULL) { 185 kif_clear(); 186 exit(1); 187 } 188 189 if (global.cmd_opts & EIGRPD_OPT_NOACTION) { 190 if (global.cmd_opts & EIGRPD_OPT_VERBOSE) 191 print_config(eigrpd_conf); 192 else 193 fprintf(stderr, "configuration OK\n"); 194 kif_clear(); 195 exit(0); 196 } 197 198 /* check for root privileges */ 199 if (geteuid()) 200 errx(1, "need root privileges"); 201 202 /* check for eigrpd user */ 203 if (getpwnam(EIGRPD_USER) == NULL) 204 errx(1, "unknown user %s", EIGRPD_USER); 205 206 log_init(debug); 207 log_verbose(global.cmd_opts & EIGRPD_OPT_VERBOSE); 208 209 if (!debug) 210 daemon(1, 0); 211 212 log_info("startup"); 213 214 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 215 PF_UNSPEC, pipe_parent2eigrpe) == -1) 216 fatal("socketpair"); 217 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 218 PF_UNSPEC, pipe_parent2rde) == -1) 219 fatal("socketpair"); 220 221 /* start children */ 222 rde_pid = start_child(PROC_RDE_ENGINE, saved_argv0, pipe_parent2rde[1], 223 debug, global.cmd_opts & EIGRPD_OPT_VERBOSE, NULL); 224 eigrpe_pid = start_child(PROC_EIGRP_ENGINE, saved_argv0, 225 pipe_parent2eigrpe[1], debug, global.cmd_opts & EIGRPD_OPT_VERBOSE, 226 sockname); 227 228 event_init(); 229 230 /* setup signal handler */ 231 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 232 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 233 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 234 signal_add(&ev_sigint, NULL); 235 signal_add(&ev_sigterm, NULL); 236 signal_add(&ev_sighup, NULL); 237 signal(SIGPIPE, SIG_IGN); 238 239 /* setup pipes to children */ 240 if ((iev_eigrpe = malloc(sizeof(struct imsgev))) == NULL || 241 (iev_rde = malloc(sizeof(struct imsgev))) == NULL) 242 fatal(NULL); 243 if (imsgbuf_init(&iev_eigrpe->ibuf, pipe_parent2eigrpe[0]) == -1) 244 fatal(NULL); 245 imsgbuf_allow_fdpass(&iev_eigrpe->ibuf); 246 iev_eigrpe->handler = main_dispatch_eigrpe; 247 if (imsgbuf_init(&iev_rde->ibuf, pipe_parent2rde[0]) == -1) 248 fatal(NULL); 249 imsgbuf_allow_fdpass(&iev_rde->ibuf); 250 iev_rde->handler = main_dispatch_rde; 251 252 /* setup event handler */ 253 iev_eigrpe->events = EV_READ; 254 event_set(&iev_eigrpe->ev, iev_eigrpe->ibuf.fd, iev_eigrpe->events, 255 iev_eigrpe->handler, iev_eigrpe); 256 event_add(&iev_eigrpe->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 (main_imsg_send_ipc_sockets(&iev_eigrpe->ibuf, &iev_rde->ibuf)) 264 fatal("could not establish imsg links"); 265 main_imsg_send_config(eigrpd_conf); 266 267 /* notify eigrpe about existing interfaces and addresses */ 268 kif_redistribute(); 269 270 if (kr_init(!(eigrpd_conf->flags & EIGRPD_FLAG_NO_FIB_UPDATE), 271 eigrpd_conf->rdomain) == -1) 272 fatalx("kr_init failed"); 273 274 if (pledge("stdio rpath inet sendfd", NULL) == -1) 275 fatal("pledge"); 276 277 event_dispatch(); 278 279 eigrpd_shutdown(); 280 /* NOTREACHED */ 281 return (0); 282 } 283 284 static __dead void 285 eigrpd_shutdown(void) 286 { 287 pid_t pid; 288 int status; 289 290 /* close pipes */ 291 imsgbuf_clear(&iev_eigrpe->ibuf); 292 close(iev_eigrpe->ibuf.fd); 293 imsgbuf_clear(&iev_rde->ibuf); 294 close(iev_rde->ibuf.fd); 295 296 kr_shutdown(); 297 config_clear(eigrpd_conf, PROC_MAIN); 298 299 log_debug("waiting for children to terminate"); 300 do { 301 pid = wait(&status); 302 if (pid == -1) { 303 if (errno != EINTR && errno != ECHILD) 304 fatal("wait"); 305 } else if (WIFSIGNALED(status)) 306 log_warnx("%s terminated; signal %d", 307 (pid == rde_pid) ? "route decision engine" : 308 "eigrp engine", WTERMSIG(status)); 309 } while (pid != -1 || (pid == -1 && errno == EINTR)); 310 311 free(iev_eigrpe); 312 free(iev_rde); 313 314 log_info("terminating"); 315 exit(0); 316 } 317 318 static pid_t 319 start_child(enum eigrpd_process p, char *argv0, int fd, int debug, int verbose, 320 char *sockname) 321 { 322 char *argv[7]; 323 int argc = 0; 324 pid_t pid; 325 326 switch (pid = fork()) { 327 case -1: 328 fatal("cannot fork"); 329 case 0: 330 break; 331 default: 332 close(fd); 333 return (pid); 334 } 335 336 if (fd != 3) { 337 if (dup2(fd, 3) == -1) 338 fatal("cannot setup imsg fd"); 339 } else if (fcntl(fd, F_SETFD, 0) == -1) 340 fatal("cannot setup imsg fd"); 341 342 argv[argc++] = argv0; 343 switch (p) { 344 case PROC_MAIN: 345 fatalx("Can not start main process"); 346 case PROC_RDE_ENGINE: 347 argv[argc++] = "-R"; 348 break; 349 case PROC_EIGRP_ENGINE: 350 argv[argc++] = "-E"; 351 break; 352 } 353 if (debug) 354 argv[argc++] = "-d"; 355 if (verbose) 356 argv[argc++] = "-v"; 357 if (sockname) { 358 argv[argc++] = "-s"; 359 argv[argc++] = sockname; 360 } 361 argv[argc++] = NULL; 362 363 execvp(argv0, argv); 364 fatal("execvp"); 365 } 366 367 /* imsg handling */ 368 static void 369 main_dispatch_eigrpe(int fd, short event, void *bula) 370 { 371 struct imsgev *iev = bula; 372 struct imsgbuf *ibuf; 373 struct imsg imsg; 374 ssize_t n; 375 int shut = 0, verbose; 376 377 ibuf = &iev->ibuf; 378 379 if (event & EV_READ) { 380 if ((n = imsgbuf_read(ibuf)) == -1) 381 fatal("imsgbuf_read error"); 382 if (n == 0) /* connection closed */ 383 shut = 1; 384 } 385 if (event & EV_WRITE) { 386 if (imsgbuf_write(ibuf) == -1) { 387 if (errno == EPIPE) /* connection closed */ 388 shut = 1; 389 else 390 fatal("imsgbuf_write"); 391 } 392 } 393 394 for (;;) { 395 if ((n = imsg_get(ibuf, &imsg)) == -1) 396 fatal("imsg_get"); 397 398 if (n == 0) 399 break; 400 401 switch (imsg.hdr.type) { 402 case IMSG_CTL_RELOAD: 403 if (eigrp_reload() == -1) 404 log_warnx("configuration reload failed"); 405 else 406 log_debug("configuration reloaded"); 407 break; 408 case IMSG_CTL_FIB_COUPLE: 409 kr_fib_couple(); 410 break; 411 case IMSG_CTL_FIB_DECOUPLE: 412 kr_fib_decouple(); 413 break; 414 case IMSG_CTL_KROUTE: 415 kr_show_route(&imsg); 416 break; 417 case IMSG_CTL_IFINFO: 418 if (imsg.hdr.len == IMSG_HEADER_SIZE) 419 kr_ifinfo(NULL, imsg.hdr.pid); 420 else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ) 421 kr_ifinfo(imsg.data, imsg.hdr.pid); 422 else 423 log_warnx("IFINFO request with wrong len"); 424 break; 425 case IMSG_CTL_LOG_VERBOSE: 426 /* already checked by eigrpe */ 427 memcpy(&verbose, imsg.data, sizeof(verbose)); 428 log_verbose(verbose); 429 break; 430 default: 431 log_debug("%s: error handling imsg %d", __func__, 432 imsg.hdr.type); 433 break; 434 } 435 imsg_free(&imsg); 436 } 437 if (!shut) 438 imsg_event_add(iev); 439 else { 440 /* this pipe is dead, so remove the event handler */ 441 event_del(&iev->ev); 442 event_loopexit(NULL); 443 } 444 } 445 446 static void 447 main_dispatch_rde(int fd, short event, void *bula) 448 { 449 struct imsgev *iev = bula; 450 struct imsgbuf *ibuf; 451 struct imsg imsg; 452 ssize_t n; 453 int shut = 0; 454 455 ibuf = &iev->ibuf; 456 457 if (event & EV_READ) { 458 if ((n = imsgbuf_read(ibuf)) == -1) 459 fatal("imsgbuf_read error"); 460 if (n == 0) /* connection closed */ 461 shut = 1; 462 } 463 if (event & EV_WRITE) { 464 if (imsgbuf_write(ibuf) == -1) { 465 if (errno == EPIPE) /* connection closed */ 466 shut = 1; 467 else 468 fatal("imsgbuf_write"); 469 } 470 } 471 472 for (;;) { 473 if ((n = imsg_get(ibuf, &imsg)) == -1) 474 fatal("imsg_get"); 475 476 if (n == 0) 477 break; 478 479 switch (imsg.hdr.type) { 480 case IMSG_KROUTE_CHANGE: 481 if (imsg.hdr.len - IMSG_HEADER_SIZE != 482 sizeof(struct kroute)) 483 fatalx("invalid size of IMSG_KROUTE_CHANGE"); 484 if (kr_change(imsg.data)) 485 log_warnx("%s: error changing route", __func__); 486 break; 487 case IMSG_KROUTE_DELETE: 488 if (imsg.hdr.len - IMSG_HEADER_SIZE != 489 sizeof(struct kroute)) 490 fatalx("invalid size of IMSG_KROUTE_DELETE"); 491 if (kr_delete(imsg.data)) 492 log_warnx("%s: error deleting route", __func__); 493 break; 494 495 default: 496 log_debug("%s: error handling imsg %d", __func__, 497 imsg.hdr.type); 498 break; 499 } 500 imsg_free(&imsg); 501 } 502 if (!shut) 503 imsg_event_add(iev); 504 else { 505 /* this pipe is dead, so remove the event handler */ 506 event_del(&iev->ev); 507 event_loopexit(NULL); 508 } 509 } 510 511 int 512 main_imsg_compose_eigrpe(int type, pid_t pid, void *data, uint16_t datalen) 513 { 514 if (iev_eigrpe == NULL) 515 return (-1); 516 return (imsg_compose_event(iev_eigrpe, type, 0, pid, -1, data, datalen)); 517 } 518 519 int 520 main_imsg_compose_rde(int type, pid_t pid, void *data, uint16_t datalen) 521 { 522 if (iev_rde == NULL) 523 return (-1); 524 return (imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen)); 525 } 526 527 void 528 imsg_event_add(struct imsgev *iev) 529 { 530 iev->events = EV_READ; 531 if (imsgbuf_queuelen(&iev->ibuf) > 0) 532 iev->events |= EV_WRITE; 533 534 event_del(&iev->ev); 535 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 536 event_add(&iev->ev, NULL); 537 } 538 539 int 540 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 541 pid_t pid, int fd, void *data, uint16_t datalen) 542 { 543 int ret; 544 545 if ((ret = imsg_compose(&iev->ibuf, type, peerid, 546 pid, fd, data, datalen)) != -1) 547 imsg_event_add(iev); 548 return (ret); 549 } 550 551 static int 552 main_imsg_send_ipc_sockets(struct imsgbuf *eigrpe_buf, struct imsgbuf *rde_buf) 553 { 554 int pipe_eigrpe2rde[2]; 555 556 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 557 PF_UNSPEC, pipe_eigrpe2rde) == -1) 558 return (-1); 559 560 if (imsg_compose(eigrpe_buf, IMSG_SOCKET_IPC, 0, 0, pipe_eigrpe2rde[0], 561 NULL, 0) == -1) 562 return (-1); 563 if (imsg_compose(rde_buf, IMSG_SOCKET_IPC, 0, 0, pipe_eigrpe2rde[1], 564 NULL, 0) == -1) 565 return (-1); 566 567 return (0); 568 } 569 570 struct eigrp * 571 eigrp_find(struct eigrpd_conf *xconf, int af, uint16_t as) 572 { 573 struct eigrp *eigrp; 574 575 TAILQ_FOREACH(eigrp, &xconf->instances, entry) 576 if (eigrp->af == af && eigrp->as == as) 577 return (eigrp); 578 579 return (NULL); 580 } 581 582 static int 583 main_imsg_send_config(struct eigrpd_conf *xconf) 584 { 585 struct eigrp *eigrp; 586 struct eigrp_iface *ei; 587 588 if (eigrp_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 589 return (-1); 590 591 TAILQ_FOREACH(eigrp, &xconf->instances, entry) { 592 if (eigrp_sendboth(IMSG_RECONF_INSTANCE, eigrp, 593 sizeof(*eigrp)) == -1) 594 return (-1); 595 596 TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry) { 597 if (eigrp_sendboth(IMSG_RECONF_IFACE, ei->iface, 598 sizeof(struct iface)) == -1) 599 return (-1); 600 601 if (eigrp_sendboth(IMSG_RECONF_EIGRP_IFACE, ei, 602 sizeof(*ei)) == -1) 603 return (-1); 604 } 605 } 606 607 if (eigrp_sendboth(IMSG_RECONF_END, NULL, 0) == -1) 608 return (-1); 609 610 return (0); 611 } 612 613 static int 614 eigrp_reload(void) 615 { 616 struct eigrpd_conf *xconf; 617 618 if ((xconf = parse_config(conffile)) == NULL) 619 return (-1); 620 621 if (main_imsg_send_config(xconf) == -1) 622 return (-1); 623 624 merge_config(eigrpd_conf, xconf, PROC_MAIN); 625 626 return (0); 627 } 628 629 static int 630 eigrp_sendboth(enum imsg_type type, void *buf, uint16_t len) 631 { 632 if (main_imsg_compose_eigrpe(type, 0, buf, len) == -1) 633 return (-1); 634 if (main_imsg_compose_rde(type, 0, buf, len) == -1) 635 return (-1); 636 return (0); 637 } 638 639 void 640 merge_config(struct eigrpd_conf *conf, struct eigrpd_conf *xconf, 641 enum eigrpd_process proc) 642 { 643 struct iface *iface, *itmp, *xi; 644 struct eigrp *eigrp, *etmp, *xe; 645 646 conf->rtr_id = xconf->rtr_id; 647 conf->flags = xconf->flags; 648 conf->rdomain= xconf->rdomain; 649 conf->fib_priority_internal = xconf->fib_priority_internal; 650 conf->fib_priority_external = xconf->fib_priority_external; 651 conf->fib_priority_summary = xconf->fib_priority_summary; 652 653 /* merge instances */ 654 TAILQ_FOREACH_SAFE(eigrp, &conf->instances, entry, etmp) { 655 /* find deleted instances */ 656 if ((xe = eigrp_find(xconf, eigrp->af, eigrp->as)) == NULL) { 657 TAILQ_REMOVE(&conf->instances, eigrp, entry); 658 659 switch (proc) { 660 case PROC_RDE_ENGINE: 661 rde_instance_del(eigrp); 662 break; 663 case PROC_EIGRP_ENGINE: 664 eigrpe_instance_del(eigrp); 665 break; 666 case PROC_MAIN: 667 free(eigrp); 668 break; 669 } 670 } 671 } 672 TAILQ_FOREACH_SAFE(xe, &xconf->instances, entry, etmp) { 673 /* find new instances */ 674 if ((eigrp = eigrp_find(conf, xe->af, xe->as)) == NULL) { 675 TAILQ_REMOVE(&xconf->instances, xe, entry); 676 TAILQ_INSERT_TAIL(&conf->instances, xe, entry); 677 678 switch (proc) { 679 case PROC_RDE_ENGINE: 680 rde_instance_init(xe); 681 break; 682 case PROC_EIGRP_ENGINE: 683 eigrpe_instance_init(xe); 684 break; 685 case PROC_MAIN: 686 break; 687 } 688 continue; 689 } 690 691 /* update existing instances */ 692 merge_instances(conf, eigrp, xe); 693 } 694 695 /* merge interfaces */ 696 TAILQ_FOREACH_SAFE(iface, &conf->iface_list, entry, itmp) { 697 /* find deleted ifaces */ 698 if ((xi = if_lookup(xconf, iface->ifindex)) == NULL) { 699 TAILQ_REMOVE(&conf->iface_list, iface, entry); 700 free(iface); 701 } 702 } 703 TAILQ_FOREACH_SAFE(xi, &xconf->iface_list, entry, itmp) { 704 /* find new ifaces */ 705 if ((iface = if_lookup(conf, xi->ifindex)) == NULL) { 706 TAILQ_REMOVE(&xconf->iface_list, xi, entry); 707 TAILQ_INSERT_TAIL(&conf->iface_list, xi, entry); 708 continue; 709 } 710 711 /* TODO update existing ifaces */ 712 } 713 714 /* resend addresses to activate new interfaces */ 715 if (proc == PROC_MAIN) 716 kif_redistribute(); 717 718 free(xconf); 719 } 720 721 static void 722 merge_instances(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct eigrp *xe) 723 { 724 /* TODO */ 725 } 726 727 struct eigrpd_conf * 728 config_new_empty(void) 729 { 730 struct eigrpd_conf *xconf; 731 732 xconf = calloc(1, sizeof(*xconf)); 733 if (xconf == NULL) 734 fatal(NULL); 735 736 TAILQ_INIT(&xconf->instances); 737 TAILQ_INIT(&xconf->iface_list); 738 739 return (xconf); 740 } 741 742 void 743 config_clear(struct eigrpd_conf *conf, enum eigrpd_process proc) 744 { 745 struct eigrpd_conf *xconf; 746 747 /* merge current config with an empty config */ 748 xconf = config_new_empty(); 749 merge_config(conf, xconf, proc); 750 751 free(conf); 752 } 753