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