1 /* $OpenBSD: eigrpd.c,v 1.21 2016/09/02 17:59:58 benno 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 <pwd.h> 29 #include <signal.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "eigrpd.h" 36 #include "eigrpe.h" 37 #include "rde.h" 38 #include "log.h" 39 40 static void main_sig_handler(int, short, void *); 41 static __dead void usage(void); 42 static __dead void eigrpd_shutdown(void); 43 static pid_t start_child(enum eigrpd_process, char *, int, int, int, 44 char *); 45 static void main_dispatch_eigrpe(int, short, void *); 46 static void main_dispatch_rde(int, short, void *); 47 static int main_imsg_send_ipc_sockets(struct imsgbuf *, 48 struct imsgbuf *); 49 static int main_imsg_send_config(struct eigrpd_conf *); 50 static int eigrp_reload(void); 51 static int eigrp_sendboth(enum imsg_type, void *, uint16_t); 52 static void merge_instances(struct eigrpd_conf *, struct eigrp *, 53 struct eigrp *); 54 55 struct eigrpd_conf *eigrpd_conf; 56 57 static char *conffile; 58 static struct imsgev *iev_eigrpe; 59 static struct imsgev *iev_rde; 60 static pid_t eigrpe_pid; 61 static pid_t rde_pid; 62 63 /* ARGSUSED */ 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 eigrpd_process = PROC_MAIN; 114 log_procname = log_procnames[eigrpd_process]; 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("inet rpath stdio 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); 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 (dup2(fd, 3) == -1) 334 fatal("cannot setup imsg fd"); 335 336 argv[argc++] = argv0; 337 switch (p) { 338 case PROC_MAIN: 339 fatalx("Can not start main process"); 340 case PROC_RDE_ENGINE: 341 argv[argc++] = "-R"; 342 break; 343 case PROC_EIGRP_ENGINE: 344 argv[argc++] = "-E"; 345 break; 346 } 347 if (debug) 348 argv[argc++] = "-d"; 349 if (verbose) 350 argv[argc++] = "-v"; 351 if (sockname) { 352 argv[argc++] = "-s"; 353 argv[argc++] = sockname; 354 } 355 argv[argc++] = NULL; 356 357 execvp(argv0, argv); 358 fatal("execvp"); 359 } 360 361 /* imsg handling */ 362 /* ARGSUSED */ 363 static void 364 main_dispatch_eigrpe(int fd, short event, void *bula) 365 { 366 struct imsgev *iev = bula; 367 struct imsgbuf *ibuf; 368 struct imsg imsg; 369 ssize_t n; 370 int shut = 0, verbose; 371 372 ibuf = &iev->ibuf; 373 374 if (event & EV_READ) { 375 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 376 fatal("imsg_read error"); 377 if (n == 0) /* connection closed */ 378 shut = 1; 379 } 380 if (event & EV_WRITE) { 381 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 382 fatal("msgbuf_write"); 383 if (n == 0) /* connection closed */ 384 shut = 1; 385 } 386 387 for (;;) { 388 if ((n = imsg_get(ibuf, &imsg)) == -1) 389 fatal("imsg_get"); 390 391 if (n == 0) 392 break; 393 394 switch (imsg.hdr.type) { 395 case IMSG_CTL_RELOAD: 396 if (eigrp_reload() == -1) 397 log_warnx("configuration reload failed"); 398 else 399 log_debug("configuration reloaded"); 400 break; 401 case IMSG_CTL_FIB_COUPLE: 402 kr_fib_couple(); 403 break; 404 case IMSG_CTL_FIB_DECOUPLE: 405 kr_fib_decouple(); 406 break; 407 case IMSG_CTL_KROUTE: 408 kr_show_route(&imsg); 409 break; 410 case IMSG_CTL_IFINFO: 411 if (imsg.hdr.len == IMSG_HEADER_SIZE) 412 kr_ifinfo(NULL, imsg.hdr.pid); 413 else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ) 414 kr_ifinfo(imsg.data, imsg.hdr.pid); 415 else 416 log_warnx("IFINFO request with wrong len"); 417 break; 418 case IMSG_CTL_LOG_VERBOSE: 419 /* already checked by eigrpe */ 420 memcpy(&verbose, imsg.data, sizeof(verbose)); 421 log_verbose(verbose); 422 break; 423 default: 424 log_debug("%s: error handling imsg %d", __func__, 425 imsg.hdr.type); 426 break; 427 } 428 imsg_free(&imsg); 429 } 430 if (!shut) 431 imsg_event_add(iev); 432 else { 433 /* this pipe is dead, so remove the event handler */ 434 event_del(&iev->ev); 435 event_loopexit(NULL); 436 } 437 } 438 439 /* ARGSUSED */ 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); 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 { 634 struct iface *iface, *itmp, *xi; 635 struct eigrp *eigrp, *etmp, *xe; 636 637 conf->rtr_id = xconf->rtr_id; 638 conf->flags = xconf->flags; 639 conf->rdomain= xconf->rdomain; 640 conf->fib_priority_internal = xconf->fib_priority_internal; 641 conf->fib_priority_external = xconf->fib_priority_external; 642 conf->fib_priority_summary = xconf->fib_priority_summary; 643 644 /* merge interfaces */ 645 TAILQ_FOREACH_SAFE(iface, &conf->iface_list, entry, itmp) { 646 /* find deleted ifaces */ 647 if ((xi = if_lookup(xconf, iface->ifindex)) == NULL) { 648 TAILQ_REMOVE(&conf->iface_list, iface, entry); 649 free(iface); 650 } 651 } 652 TAILQ_FOREACH_SAFE(xi, &xconf->iface_list, entry, itmp) { 653 /* find new ifaces */ 654 if ((iface = if_lookup(conf, xi->ifindex)) == NULL) { 655 TAILQ_REMOVE(&xconf->iface_list, xi, entry); 656 TAILQ_INSERT_TAIL(&conf->iface_list, xi, entry); 657 continue; 658 } 659 660 /* TODO update existing ifaces */ 661 } 662 663 /* merge instances */ 664 TAILQ_FOREACH_SAFE(eigrp, &conf->instances, entry, etmp) { 665 /* find deleted instances */ 666 if ((xe = eigrp_find(xconf, eigrp->af, eigrp->as)) == NULL) { 667 TAILQ_REMOVE(&conf->instances, eigrp, entry); 668 669 switch (eigrpd_process) { 670 case PROC_RDE_ENGINE: 671 rde_instance_del(eigrp); 672 break; 673 case PROC_EIGRP_ENGINE: 674 eigrpe_instance_del(eigrp); 675 break; 676 case PROC_MAIN: 677 free(eigrp); 678 break; 679 } 680 } 681 } 682 TAILQ_FOREACH_SAFE(xe, &xconf->instances, entry, etmp) { 683 /* find new instances */ 684 if ((eigrp = eigrp_find(conf, xe->af, xe->as)) == NULL) { 685 TAILQ_REMOVE(&xconf->instances, xe, entry); 686 TAILQ_INSERT_TAIL(&conf->instances, xe, entry); 687 688 switch (eigrpd_process) { 689 case PROC_RDE_ENGINE: 690 rde_instance_init(xe); 691 break; 692 case PROC_EIGRP_ENGINE: 693 eigrpe_instance_init(xe); 694 break; 695 case PROC_MAIN: 696 break; 697 } 698 continue; 699 } 700 701 /* update existing instances */ 702 merge_instances(conf, eigrp, xe); 703 } 704 705 /* resend addresses to activate new interfaces */ 706 if (eigrpd_process == PROC_MAIN) 707 kif_redistribute(); 708 709 free(xconf); 710 } 711 712 static void 713 merge_instances(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct eigrp *xe) 714 { 715 /* TODO */ 716 } 717 718 struct eigrpd_conf * 719 config_new_empty(void) 720 { 721 struct eigrpd_conf *xconf; 722 723 xconf = calloc(1, sizeof(*xconf)); 724 if (xconf == NULL) 725 fatal(NULL); 726 727 TAILQ_INIT(&xconf->instances); 728 TAILQ_INIT(&xconf->iface_list); 729 730 return (xconf); 731 } 732 733 void 734 config_clear(struct eigrpd_conf *conf) 735 { 736 struct eigrpd_conf *xconf; 737 738 /* merge current config with an empty config */ 739 xconf = config_new_empty(); 740 merge_config(conf, xconf); 741 742 free(conf); 743 } 744