1 /* $OpenBSD: eigrpd.c,v 1.29 2023/03/08 04:43:13 guenther 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 imsg_init(&iev_eigrpe->ibuf, pipe_parent2eigrpe[0]); 244 iev_eigrpe->handler = main_dispatch_eigrpe; 245 imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]); 246 iev_rde->handler = main_dispatch_rde; 247 248 /* setup event handler */ 249 iev_eigrpe->events = EV_READ; 250 event_set(&iev_eigrpe->ev, iev_eigrpe->ibuf.fd, iev_eigrpe->events, 251 iev_eigrpe->handler, iev_eigrpe); 252 event_add(&iev_eigrpe->ev, NULL); 253 254 iev_rde->events = EV_READ; 255 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 256 iev_rde->handler, iev_rde); 257 event_add(&iev_rde->ev, NULL); 258 259 if (main_imsg_send_ipc_sockets(&iev_eigrpe->ibuf, &iev_rde->ibuf)) 260 fatal("could not establish imsg links"); 261 main_imsg_send_config(eigrpd_conf); 262 263 /* notify eigrpe about existing interfaces and addresses */ 264 kif_redistribute(); 265 266 if (kr_init(!(eigrpd_conf->flags & EIGRPD_FLAG_NO_FIB_UPDATE), 267 eigrpd_conf->rdomain) == -1) 268 fatalx("kr_init failed"); 269 270 if (pledge("stdio rpath inet sendfd", NULL) == -1) 271 fatal("pledge"); 272 273 event_dispatch(); 274 275 eigrpd_shutdown(); 276 /* NOTREACHED */ 277 return (0); 278 } 279 280 static __dead void 281 eigrpd_shutdown(void) 282 { 283 pid_t pid; 284 int status; 285 286 /* close pipes */ 287 msgbuf_clear(&iev_eigrpe->ibuf.w); 288 close(iev_eigrpe->ibuf.fd); 289 msgbuf_clear(&iev_rde->ibuf.w); 290 close(iev_rde->ibuf.fd); 291 292 kr_shutdown(); 293 config_clear(eigrpd_conf, PROC_MAIN); 294 295 log_debug("waiting for children to terminate"); 296 do { 297 pid = wait(&status); 298 if (pid == -1) { 299 if (errno != EINTR && errno != ECHILD) 300 fatal("wait"); 301 } else if (WIFSIGNALED(status)) 302 log_warnx("%s terminated; signal %d", 303 (pid == rde_pid) ? "route decision engine" : 304 "eigrp engine", WTERMSIG(status)); 305 } while (pid != -1 || (pid == -1 && errno == EINTR)); 306 307 free(iev_eigrpe); 308 free(iev_rde); 309 310 log_info("terminating"); 311 exit(0); 312 } 313 314 static pid_t 315 start_child(enum eigrpd_process p, char *argv0, int fd, int debug, int verbose, 316 char *sockname) 317 { 318 char *argv[7]; 319 int argc = 0; 320 pid_t pid; 321 322 switch (pid = fork()) { 323 case -1: 324 fatal("cannot fork"); 325 case 0: 326 break; 327 default: 328 close(fd); 329 return (pid); 330 } 331 332 if (fd != 3) { 333 if (dup2(fd, 3) == -1) 334 fatal("cannot setup imsg fd"); 335 } else if (fcntl(fd, F_SETFD, 0) == -1) 336 fatal("cannot setup imsg fd"); 337 338 argv[argc++] = argv0; 339 switch (p) { 340 case PROC_MAIN: 341 fatalx("Can not start main process"); 342 case PROC_RDE_ENGINE: 343 argv[argc++] = "-R"; 344 break; 345 case PROC_EIGRP_ENGINE: 346 argv[argc++] = "-E"; 347 break; 348 } 349 if (debug) 350 argv[argc++] = "-d"; 351 if (verbose) 352 argv[argc++] = "-v"; 353 if (sockname) { 354 argv[argc++] = "-s"; 355 argv[argc++] = sockname; 356 } 357 argv[argc++] = NULL; 358 359 execvp(argv0, argv); 360 fatal("execvp"); 361 } 362 363 /* imsg handling */ 364 static void 365 main_dispatch_eigrpe(int fd, short event, void *bula) 366 { 367 struct imsgev *iev = bula; 368 struct imsgbuf *ibuf; 369 struct imsg imsg; 370 ssize_t n; 371 int shut = 0, verbose; 372 373 ibuf = &iev->ibuf; 374 375 if (event & EV_READ) { 376 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 377 fatal("imsg_read error"); 378 if (n == 0) /* connection closed */ 379 shut = 1; 380 } 381 if (event & EV_WRITE) { 382 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 383 fatal("msgbuf_write"); 384 if (n == 0) /* connection closed */ 385 shut = 1; 386 } 387 388 for (;;) { 389 if ((n = imsg_get(ibuf, &imsg)) == -1) 390 fatal("imsg_get"); 391 392 if (n == 0) 393 break; 394 395 switch (imsg.hdr.type) { 396 case IMSG_CTL_RELOAD: 397 if (eigrp_reload() == -1) 398 log_warnx("configuration reload failed"); 399 else 400 log_debug("configuration reloaded"); 401 break; 402 case IMSG_CTL_FIB_COUPLE: 403 kr_fib_couple(); 404 break; 405 case IMSG_CTL_FIB_DECOUPLE: 406 kr_fib_decouple(); 407 break; 408 case IMSG_CTL_KROUTE: 409 kr_show_route(&imsg); 410 break; 411 case IMSG_CTL_IFINFO: 412 if (imsg.hdr.len == IMSG_HEADER_SIZE) 413 kr_ifinfo(NULL, imsg.hdr.pid); 414 else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ) 415 kr_ifinfo(imsg.data, imsg.hdr.pid); 416 else 417 log_warnx("IFINFO request with wrong len"); 418 break; 419 case IMSG_CTL_LOG_VERBOSE: 420 /* already checked by eigrpe */ 421 memcpy(&verbose, imsg.data, sizeof(verbose)); 422 log_verbose(verbose); 423 break; 424 default: 425 log_debug("%s: error handling imsg %d", __func__, 426 imsg.hdr.type); 427 break; 428 } 429 imsg_free(&imsg); 430 } 431 if (!shut) 432 imsg_event_add(iev); 433 else { 434 /* this pipe is dead, so remove the event handler */ 435 event_del(&iev->ev); 436 event_loopexit(NULL); 437 } 438 } 439 440 static void 441 main_dispatch_rde(int fd, short event, void *bula) 442 { 443 struct imsgev *iev = bula; 444 struct imsgbuf *ibuf; 445 struct imsg imsg; 446 ssize_t n; 447 int shut = 0; 448 449 ibuf = &iev->ibuf; 450 451 if (event & EV_READ) { 452 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 453 fatal("imsg_read error"); 454 if (n == 0) /* connection closed */ 455 shut = 1; 456 } 457 if (event & EV_WRITE) { 458 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 459 fatal("msgbuf_write"); 460 if (n == 0) /* connection closed */ 461 shut = 1; 462 } 463 464 for (;;) { 465 if ((n = imsg_get(ibuf, &imsg)) == -1) 466 fatal("imsg_get"); 467 468 if (n == 0) 469 break; 470 471 switch (imsg.hdr.type) { 472 case IMSG_KROUTE_CHANGE: 473 if (imsg.hdr.len - IMSG_HEADER_SIZE != 474 sizeof(struct kroute)) 475 fatalx("invalid size of IMSG_KROUTE_CHANGE"); 476 if (kr_change(imsg.data)) 477 log_warnx("%s: error changing route", __func__); 478 break; 479 case IMSG_KROUTE_DELETE: 480 if (imsg.hdr.len - IMSG_HEADER_SIZE != 481 sizeof(struct kroute)) 482 fatalx("invalid size of IMSG_KROUTE_DELETE"); 483 if (kr_delete(imsg.data)) 484 log_warnx("%s: error deleting route", __func__); 485 break; 486 487 default: 488 log_debug("%s: error handling imsg %d", __func__, 489 imsg.hdr.type); 490 break; 491 } 492 imsg_free(&imsg); 493 } 494 if (!shut) 495 imsg_event_add(iev); 496 else { 497 /* this pipe is dead, so remove the event handler */ 498 event_del(&iev->ev); 499 event_loopexit(NULL); 500 } 501 } 502 503 int 504 main_imsg_compose_eigrpe(int type, pid_t pid, void *data, uint16_t datalen) 505 { 506 if (iev_eigrpe == NULL) 507 return (-1); 508 return (imsg_compose_event(iev_eigrpe, type, 0, pid, -1, data, datalen)); 509 } 510 511 int 512 main_imsg_compose_rde(int type, pid_t pid, void *data, uint16_t datalen) 513 { 514 if (iev_rde == NULL) 515 return (-1); 516 return (imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen)); 517 } 518 519 void 520 imsg_event_add(struct imsgev *iev) 521 { 522 iev->events = EV_READ; 523 if (iev->ibuf.w.queued) 524 iev->events |= EV_WRITE; 525 526 event_del(&iev->ev); 527 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 528 event_add(&iev->ev, NULL); 529 } 530 531 int 532 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 533 pid_t pid, int fd, void *data, uint16_t datalen) 534 { 535 int ret; 536 537 if ((ret = imsg_compose(&iev->ibuf, type, peerid, 538 pid, fd, data, datalen)) != -1) 539 imsg_event_add(iev); 540 return (ret); 541 } 542 543 static int 544 main_imsg_send_ipc_sockets(struct imsgbuf *eigrpe_buf, struct imsgbuf *rde_buf) 545 { 546 int pipe_eigrpe2rde[2]; 547 548 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 549 PF_UNSPEC, pipe_eigrpe2rde) == -1) 550 return (-1); 551 552 if (imsg_compose(eigrpe_buf, IMSG_SOCKET_IPC, 0, 0, pipe_eigrpe2rde[0], 553 NULL, 0) == -1) 554 return (-1); 555 if (imsg_compose(rde_buf, IMSG_SOCKET_IPC, 0, 0, pipe_eigrpe2rde[1], 556 NULL, 0) == -1) 557 return (-1); 558 559 return (0); 560 } 561 562 struct eigrp * 563 eigrp_find(struct eigrpd_conf *xconf, int af, uint16_t as) 564 { 565 struct eigrp *eigrp; 566 567 TAILQ_FOREACH(eigrp, &xconf->instances, entry) 568 if (eigrp->af == af && eigrp->as == as) 569 return (eigrp); 570 571 return (NULL); 572 } 573 574 static int 575 main_imsg_send_config(struct eigrpd_conf *xconf) 576 { 577 struct eigrp *eigrp; 578 struct eigrp_iface *ei; 579 580 if (eigrp_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 581 return (-1); 582 583 TAILQ_FOREACH(eigrp, &xconf->instances, entry) { 584 if (eigrp_sendboth(IMSG_RECONF_INSTANCE, eigrp, 585 sizeof(*eigrp)) == -1) 586 return (-1); 587 588 TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry) { 589 if (eigrp_sendboth(IMSG_RECONF_IFACE, ei->iface, 590 sizeof(struct iface)) == -1) 591 return (-1); 592 593 if (eigrp_sendboth(IMSG_RECONF_EIGRP_IFACE, ei, 594 sizeof(*ei)) == -1) 595 return (-1); 596 } 597 } 598 599 if (eigrp_sendboth(IMSG_RECONF_END, NULL, 0) == -1) 600 return (-1); 601 602 return (0); 603 } 604 605 static int 606 eigrp_reload(void) 607 { 608 struct eigrpd_conf *xconf; 609 610 if ((xconf = parse_config(conffile)) == NULL) 611 return (-1); 612 613 if (main_imsg_send_config(xconf) == -1) 614 return (-1); 615 616 merge_config(eigrpd_conf, xconf, PROC_MAIN); 617 618 return (0); 619 } 620 621 static int 622 eigrp_sendboth(enum imsg_type type, void *buf, uint16_t len) 623 { 624 if (main_imsg_compose_eigrpe(type, 0, buf, len) == -1) 625 return (-1); 626 if (main_imsg_compose_rde(type, 0, buf, len) == -1) 627 return (-1); 628 return (0); 629 } 630 631 void 632 merge_config(struct eigrpd_conf *conf, struct eigrpd_conf *xconf, 633 enum eigrpd_process proc) 634 { 635 struct iface *iface, *itmp, *xi; 636 struct eigrp *eigrp, *etmp, *xe; 637 638 conf->rtr_id = xconf->rtr_id; 639 conf->flags = xconf->flags; 640 conf->rdomain= xconf->rdomain; 641 conf->fib_priority_internal = xconf->fib_priority_internal; 642 conf->fib_priority_external = xconf->fib_priority_external; 643 conf->fib_priority_summary = xconf->fib_priority_summary; 644 645 /* merge instances */ 646 TAILQ_FOREACH_SAFE(eigrp, &conf->instances, entry, etmp) { 647 /* find deleted instances */ 648 if ((xe = eigrp_find(xconf, eigrp->af, eigrp->as)) == NULL) { 649 TAILQ_REMOVE(&conf->instances, eigrp, entry); 650 651 switch (proc) { 652 case PROC_RDE_ENGINE: 653 rde_instance_del(eigrp); 654 break; 655 case PROC_EIGRP_ENGINE: 656 eigrpe_instance_del(eigrp); 657 break; 658 case PROC_MAIN: 659 free(eigrp); 660 break; 661 } 662 } 663 } 664 TAILQ_FOREACH_SAFE(xe, &xconf->instances, entry, etmp) { 665 /* find new instances */ 666 if ((eigrp = eigrp_find(conf, xe->af, xe->as)) == NULL) { 667 TAILQ_REMOVE(&xconf->instances, xe, entry); 668 TAILQ_INSERT_TAIL(&conf->instances, xe, entry); 669 670 switch (proc) { 671 case PROC_RDE_ENGINE: 672 rde_instance_init(xe); 673 break; 674 case PROC_EIGRP_ENGINE: 675 eigrpe_instance_init(xe); 676 break; 677 case PROC_MAIN: 678 break; 679 } 680 continue; 681 } 682 683 /* update existing instances */ 684 merge_instances(conf, eigrp, xe); 685 } 686 687 /* merge interfaces */ 688 TAILQ_FOREACH_SAFE(iface, &conf->iface_list, entry, itmp) { 689 /* find deleted ifaces */ 690 if ((xi = if_lookup(xconf, iface->ifindex)) == NULL) { 691 TAILQ_REMOVE(&conf->iface_list, iface, entry); 692 free(iface); 693 } 694 } 695 TAILQ_FOREACH_SAFE(xi, &xconf->iface_list, entry, itmp) { 696 /* find new ifaces */ 697 if ((iface = if_lookup(conf, xi->ifindex)) == NULL) { 698 TAILQ_REMOVE(&xconf->iface_list, xi, entry); 699 TAILQ_INSERT_TAIL(&conf->iface_list, xi, entry); 700 continue; 701 } 702 703 /* TODO update existing ifaces */ 704 } 705 706 /* resend addresses to activate new interfaces */ 707 if (proc == PROC_MAIN) 708 kif_redistribute(); 709 710 free(xconf); 711 } 712 713 static void 714 merge_instances(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct eigrp *xe) 715 { 716 /* TODO */ 717 } 718 719 struct eigrpd_conf * 720 config_new_empty(void) 721 { 722 struct eigrpd_conf *xconf; 723 724 xconf = calloc(1, sizeof(*xconf)); 725 if (xconf == NULL) 726 fatal(NULL); 727 728 TAILQ_INIT(&xconf->instances); 729 TAILQ_INIT(&xconf->iface_list); 730 731 return (xconf); 732 } 733 734 void 735 config_clear(struct eigrpd_conf *conf, enum eigrpd_process proc) 736 { 737 struct eigrpd_conf *xconf; 738 739 /* merge current config with an empty config */ 740 xconf = config_new_empty(); 741 merge_config(conf, xconf, proc); 742 743 free(conf); 744 } 745