1 /* $OpenBSD: eigrpd.c,v 1.27 2019/03/31 03:36:18 yasuoka 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 eigrpd_process = PROC_MAIN; 115 log_procname = log_procnames[eigrpd_process]; 116 sockname = EIGRPD_SOCKET; 117 118 log_init(1); /* log to stderr until daemonized */ 119 log_verbose(1); 120 121 saved_argv0 = argv[0]; 122 if (saved_argv0 == NULL) 123 saved_argv0 = "eigrpd"; 124 125 while ((ch = getopt(argc, argv, "dD:f:ns:vRE")) != -1) { 126 switch (ch) { 127 case 'd': 128 debug = 1; 129 break; 130 case 'D': 131 if (cmdline_symset(optarg) < 0) 132 log_warnx("could not parse macro definition %s", 133 optarg); 134 break; 135 case 'f': 136 conffile = optarg; 137 break; 138 case 'n': 139 global.cmd_opts |= EIGRPD_OPT_NOACTION; 140 break; 141 case 's': 142 sockname = optarg; 143 break; 144 case 'v': 145 if (global.cmd_opts & EIGRPD_OPT_VERBOSE) 146 global.cmd_opts |= EIGRPD_OPT_VERBOSE2; 147 global.cmd_opts |= EIGRPD_OPT_VERBOSE; 148 break; 149 case 'R': 150 rflag = 1; 151 break; 152 case 'E': 153 eflag = 1; 154 break; 155 default: 156 usage(); 157 /* NOTREACHED */ 158 } 159 } 160 161 argc -= optind; 162 argv += optind; 163 if (argc > 0 || (rflag && eflag)) 164 usage(); 165 166 if (rflag) 167 rde(debug, global.cmd_opts & EIGRPD_OPT_VERBOSE); 168 else if (eflag) 169 eigrpe(debug, global.cmd_opts & EIGRPD_OPT_VERBOSE, sockname); 170 171 mib[0] = CTL_NET; 172 mib[1] = PF_INET; 173 mib[2] = IPPROTO_IP; 174 mib[3] = IPCTL_FORWARDING; 175 len = sizeof(ipforwarding); 176 if (sysctl(mib, 4, &ipforwarding, &len, NULL, 0) == -1) 177 log_warn("sysctl"); 178 179 if (ipforwarding != 1) 180 log_warnx("WARNING: IP forwarding NOT enabled"); 181 182 /* fetch interfaces early */ 183 kif_init(); 184 185 /* parse config file */ 186 if ((eigrpd_conf = parse_config(conffile)) == NULL) { 187 kif_clear(); 188 exit(1); 189 } 190 191 if (global.cmd_opts & EIGRPD_OPT_NOACTION) { 192 if (global.cmd_opts & EIGRPD_OPT_VERBOSE) 193 print_config(eigrpd_conf); 194 else 195 fprintf(stderr, "configuration OK\n"); 196 kif_clear(); 197 exit(0); 198 } 199 200 /* check for root privileges */ 201 if (geteuid()) 202 errx(1, "need root privileges"); 203 204 /* check for eigrpd user */ 205 if (getpwnam(EIGRPD_USER) == NULL) 206 errx(1, "unknown user %s", EIGRPD_USER); 207 208 log_init(debug); 209 log_verbose(global.cmd_opts & EIGRPD_OPT_VERBOSE); 210 211 if (!debug) 212 daemon(1, 0); 213 214 log_info("startup"); 215 216 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 217 PF_UNSPEC, pipe_parent2eigrpe) == -1) 218 fatal("socketpair"); 219 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 220 PF_UNSPEC, pipe_parent2rde) == -1) 221 fatal("socketpair"); 222 223 /* start children */ 224 rde_pid = start_child(PROC_RDE_ENGINE, saved_argv0, pipe_parent2rde[1], 225 debug, global.cmd_opts & EIGRPD_OPT_VERBOSE, NULL); 226 eigrpe_pid = start_child(PROC_EIGRP_ENGINE, saved_argv0, 227 pipe_parent2eigrpe[1], debug, global.cmd_opts & EIGRPD_OPT_VERBOSE, 228 sockname); 229 230 event_init(); 231 232 /* setup signal handler */ 233 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 234 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 235 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 236 signal_add(&ev_sigint, NULL); 237 signal_add(&ev_sigterm, NULL); 238 signal_add(&ev_sighup, NULL); 239 signal(SIGPIPE, SIG_IGN); 240 241 /* setup pipes to children */ 242 if ((iev_eigrpe = malloc(sizeof(struct imsgev))) == NULL || 243 (iev_rde = malloc(sizeof(struct imsgev))) == NULL) 244 fatal(NULL); 245 imsg_init(&iev_eigrpe->ibuf, pipe_parent2eigrpe[0]); 246 iev_eigrpe->handler = main_dispatch_eigrpe; 247 imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]); 248 iev_rde->handler = main_dispatch_rde; 249 250 /* setup event handler */ 251 iev_eigrpe->events = EV_READ; 252 event_set(&iev_eigrpe->ev, iev_eigrpe->ibuf.fd, iev_eigrpe->events, 253 iev_eigrpe->handler, iev_eigrpe); 254 event_add(&iev_eigrpe->ev, NULL); 255 256 iev_rde->events = EV_READ; 257 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events, 258 iev_rde->handler, iev_rde); 259 event_add(&iev_rde->ev, NULL); 260 261 if (main_imsg_send_ipc_sockets(&iev_eigrpe->ibuf, &iev_rde->ibuf)) 262 fatal("could not establish imsg links"); 263 main_imsg_send_config(eigrpd_conf); 264 265 /* notify eigrpe about existing interfaces and addresses */ 266 kif_redistribute(); 267 268 if (kr_init(!(eigrpd_conf->flags & EIGRPD_FLAG_NO_FIB_UPDATE), 269 eigrpd_conf->rdomain) == -1) 270 fatalx("kr_init failed"); 271 272 if (pledge("stdio rpath inet sendfd", NULL) == -1) 273 fatal("pledge"); 274 275 event_dispatch(); 276 277 eigrpd_shutdown(); 278 /* NOTREACHED */ 279 return (0); 280 } 281 282 static __dead void 283 eigrpd_shutdown(void) 284 { 285 pid_t pid; 286 int status; 287 288 /* close pipes */ 289 msgbuf_clear(&iev_eigrpe->ibuf.w); 290 close(iev_eigrpe->ibuf.fd); 291 msgbuf_clear(&iev_rde->ibuf.w); 292 close(iev_rde->ibuf.fd); 293 294 kr_shutdown(); 295 config_clear(eigrpd_conf); 296 297 log_debug("waiting for children to terminate"); 298 do { 299 pid = wait(&status); 300 if (pid == -1) { 301 if (errno != EINTR && errno != ECHILD) 302 fatal("wait"); 303 } else if (WIFSIGNALED(status)) 304 log_warnx("%s terminated; signal %d", 305 (pid == rde_pid) ? "route decision engine" : 306 "eigrp engine", WTERMSIG(status)); 307 } while (pid != -1 || (pid == -1 && errno == EINTR)); 308 309 free(iev_eigrpe); 310 free(iev_rde); 311 312 log_info("terminating"); 313 exit(0); 314 } 315 316 static pid_t 317 start_child(enum eigrpd_process p, char *argv0, int fd, int debug, int verbose, 318 char *sockname) 319 { 320 char *argv[7]; 321 int argc = 0; 322 pid_t pid; 323 324 switch (pid = fork()) { 325 case -1: 326 fatal("cannot fork"); 327 case 0: 328 break; 329 default: 330 close(fd); 331 return (pid); 332 } 333 334 if (fd != 3) { 335 if (dup2(fd, 3) == -1) 336 fatal("cannot setup imsg fd"); 337 } else if (fcntl(fd, F_SETFD, 0) == -1) 338 fatal("cannot setup imsg fd"); 339 340 argv[argc++] = argv0; 341 switch (p) { 342 case PROC_MAIN: 343 fatalx("Can not start main process"); 344 case PROC_RDE_ENGINE: 345 argv[argc++] = "-R"; 346 break; 347 case PROC_EIGRP_ENGINE: 348 argv[argc++] = "-E"; 349 break; 350 } 351 if (debug) 352 argv[argc++] = "-d"; 353 if (verbose) 354 argv[argc++] = "-v"; 355 if (sockname) { 356 argv[argc++] = "-s"; 357 argv[argc++] = sockname; 358 } 359 argv[argc++] = NULL; 360 361 execvp(argv0, argv); 362 fatal("execvp"); 363 } 364 365 /* imsg handling */ 366 /* ARGSUSED */ 367 static void 368 main_dispatch_eigrpe(int fd, short event, void *bula) 369 { 370 struct imsgev *iev = bula; 371 struct imsgbuf *ibuf; 372 struct imsg imsg; 373 ssize_t n; 374 int shut = 0, verbose; 375 376 ibuf = &iev->ibuf; 377 378 if (event & EV_READ) { 379 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 380 fatal("imsg_read error"); 381 if (n == 0) /* connection closed */ 382 shut = 1; 383 } 384 if (event & EV_WRITE) { 385 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 386 fatal("msgbuf_write"); 387 if (n == 0) /* connection closed */ 388 shut = 1; 389 } 390 391 for (;;) { 392 if ((n = imsg_get(ibuf, &imsg)) == -1) 393 fatal("imsg_get"); 394 395 if (n == 0) 396 break; 397 398 switch (imsg.hdr.type) { 399 case IMSG_CTL_RELOAD: 400 if (eigrp_reload() == -1) 401 log_warnx("configuration reload failed"); 402 else 403 log_debug("configuration reloaded"); 404 break; 405 case IMSG_CTL_FIB_COUPLE: 406 kr_fib_couple(); 407 break; 408 case IMSG_CTL_FIB_DECOUPLE: 409 kr_fib_decouple(); 410 break; 411 case IMSG_CTL_KROUTE: 412 kr_show_route(&imsg); 413 break; 414 case IMSG_CTL_IFINFO: 415 if (imsg.hdr.len == IMSG_HEADER_SIZE) 416 kr_ifinfo(NULL, imsg.hdr.pid); 417 else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ) 418 kr_ifinfo(imsg.data, imsg.hdr.pid); 419 else 420 log_warnx("IFINFO request with wrong len"); 421 break; 422 case IMSG_CTL_LOG_VERBOSE: 423 /* already checked by eigrpe */ 424 memcpy(&verbose, imsg.data, sizeof(verbose)); 425 log_verbose(verbose); 426 break; 427 default: 428 log_debug("%s: error handling imsg %d", __func__, 429 imsg.hdr.type); 430 break; 431 } 432 imsg_free(&imsg); 433 } 434 if (!shut) 435 imsg_event_add(iev); 436 else { 437 /* this pipe is dead, so remove the event handler */ 438 event_del(&iev->ev); 439 event_loopexit(NULL); 440 } 441 } 442 443 /* ARGSUSED */ 444 static void 445 main_dispatch_rde(int fd, short event, void *bula) 446 { 447 struct imsgev *iev = bula; 448 struct imsgbuf *ibuf; 449 struct imsg imsg; 450 ssize_t n; 451 int shut = 0; 452 453 ibuf = &iev->ibuf; 454 455 if (event & EV_READ) { 456 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 457 fatal("imsg_read error"); 458 if (n == 0) /* connection closed */ 459 shut = 1; 460 } 461 if (event & EV_WRITE) { 462 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 463 fatal("msgbuf_write"); 464 if (n == 0) /* connection closed */ 465 shut = 1; 466 } 467 468 for (;;) { 469 if ((n = imsg_get(ibuf, &imsg)) == -1) 470 fatal("imsg_get"); 471 472 if (n == 0) 473 break; 474 475 switch (imsg.hdr.type) { 476 case IMSG_KROUTE_CHANGE: 477 if (imsg.hdr.len - IMSG_HEADER_SIZE != 478 sizeof(struct kroute)) 479 fatalx("invalid size of IMSG_KROUTE_CHANGE"); 480 if (kr_change(imsg.data)) 481 log_warnx("%s: error changing route", __func__); 482 break; 483 case IMSG_KROUTE_DELETE: 484 if (imsg.hdr.len - IMSG_HEADER_SIZE != 485 sizeof(struct kroute)) 486 fatalx("invalid size of IMSG_KROUTE_DELETE"); 487 if (kr_delete(imsg.data)) 488 log_warnx("%s: error deleting route", __func__); 489 break; 490 491 default: 492 log_debug("%s: error handling imsg %d", __func__, 493 imsg.hdr.type); 494 break; 495 } 496 imsg_free(&imsg); 497 } 498 if (!shut) 499 imsg_event_add(iev); 500 else { 501 /* this pipe is dead, so remove the event handler */ 502 event_del(&iev->ev); 503 event_loopexit(NULL); 504 } 505 } 506 507 int 508 main_imsg_compose_eigrpe(int type, pid_t pid, void *data, uint16_t datalen) 509 { 510 if (iev_eigrpe == NULL) 511 return (-1); 512 return (imsg_compose_event(iev_eigrpe, type, 0, pid, -1, data, datalen)); 513 } 514 515 int 516 main_imsg_compose_rde(int type, pid_t pid, void *data, uint16_t datalen) 517 { 518 if (iev_rde == NULL) 519 return (-1); 520 return (imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen)); 521 } 522 523 void 524 imsg_event_add(struct imsgev *iev) 525 { 526 iev->events = EV_READ; 527 if (iev->ibuf.w.queued) 528 iev->events |= EV_WRITE; 529 530 event_del(&iev->ev); 531 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 532 event_add(&iev->ev, NULL); 533 } 534 535 int 536 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 537 pid_t pid, int fd, void *data, uint16_t datalen) 538 { 539 int ret; 540 541 if ((ret = imsg_compose(&iev->ibuf, type, peerid, 542 pid, fd, data, datalen)) != -1) 543 imsg_event_add(iev); 544 return (ret); 545 } 546 547 static int 548 main_imsg_send_ipc_sockets(struct imsgbuf *eigrpe_buf, struct imsgbuf *rde_buf) 549 { 550 int pipe_eigrpe2rde[2]; 551 552 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 553 PF_UNSPEC, pipe_eigrpe2rde) == -1) 554 return (-1); 555 556 if (imsg_compose(eigrpe_buf, IMSG_SOCKET_IPC, 0, 0, pipe_eigrpe2rde[0], 557 NULL, 0) == -1) 558 return (-1); 559 if (imsg_compose(rde_buf, IMSG_SOCKET_IPC, 0, 0, pipe_eigrpe2rde[1], 560 NULL, 0) == -1) 561 return (-1); 562 563 return (0); 564 } 565 566 struct eigrp * 567 eigrp_find(struct eigrpd_conf *xconf, int af, uint16_t as) 568 { 569 struct eigrp *eigrp; 570 571 TAILQ_FOREACH(eigrp, &xconf->instances, entry) 572 if (eigrp->af == af && eigrp->as == as) 573 return (eigrp); 574 575 return (NULL); 576 } 577 578 static int 579 main_imsg_send_config(struct eigrpd_conf *xconf) 580 { 581 struct eigrp *eigrp; 582 struct eigrp_iface *ei; 583 584 if (eigrp_sendboth(IMSG_RECONF_CONF, xconf, sizeof(*xconf)) == -1) 585 return (-1); 586 587 TAILQ_FOREACH(eigrp, &xconf->instances, entry) { 588 if (eigrp_sendboth(IMSG_RECONF_INSTANCE, eigrp, 589 sizeof(*eigrp)) == -1) 590 return (-1); 591 592 TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry) { 593 if (eigrp_sendboth(IMSG_RECONF_IFACE, ei->iface, 594 sizeof(struct iface)) == -1) 595 return (-1); 596 597 if (eigrp_sendboth(IMSG_RECONF_EIGRP_IFACE, ei, 598 sizeof(*ei)) == -1) 599 return (-1); 600 } 601 } 602 603 if (eigrp_sendboth(IMSG_RECONF_END, NULL, 0) == -1) 604 return (-1); 605 606 return (0); 607 } 608 609 static int 610 eigrp_reload(void) 611 { 612 struct eigrpd_conf *xconf; 613 614 if ((xconf = parse_config(conffile)) == NULL) 615 return (-1); 616 617 if (main_imsg_send_config(xconf) == -1) 618 return (-1); 619 620 merge_config(eigrpd_conf, xconf); 621 622 return (0); 623 } 624 625 static int 626 eigrp_sendboth(enum imsg_type type, void *buf, uint16_t len) 627 { 628 if (main_imsg_compose_eigrpe(type, 0, buf, len) == -1) 629 return (-1); 630 if (main_imsg_compose_rde(type, 0, buf, len) == -1) 631 return (-1); 632 return (0); 633 } 634 635 void 636 merge_config(struct eigrpd_conf *conf, struct eigrpd_conf *xconf) 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 (eigrpd_process) { 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 (eigrpd_process) { 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 (eigrpd_process == 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) 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); 745 746 free(conf); 747 } 748