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
main_sig_handler(int sig,short event,void * arg)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
usage(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
main(int argc,char * argv[])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
eigrpd_shutdown(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
start_child(enum eigrpd_process p,char * argv0,int fd,int debug,int verbose,char * sockname)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
main_dispatch_eigrpe(int fd,short event,void * bula)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
main_dispatch_rde(int fd,short event,void * bula)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
main_imsg_compose_eigrpe(int type,pid_t pid,void * data,uint16_t datalen)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
main_imsg_compose_rde(int type,pid_t pid,void * data,uint16_t datalen)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
imsg_event_add(struct imsgev * iev)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
imsg_compose_event(struct imsgev * iev,uint16_t type,uint32_t peerid,pid_t pid,int fd,void * data,uint16_t datalen)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
main_imsg_send_ipc_sockets(struct imsgbuf * eigrpe_buf,struct imsgbuf * rde_buf)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 *
eigrp_find(struct eigrpd_conf * xconf,int af,uint16_t as)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
main_imsg_send_config(struct eigrpd_conf * xconf)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
eigrp_reload(void)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
eigrp_sendboth(enum imsg_type type,void * buf,uint16_t len)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
merge_config(struct eigrpd_conf * conf,struct eigrpd_conf * xconf,enum eigrpd_process proc)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
merge_instances(struct eigrpd_conf * xconf,struct eigrp * eigrp,struct eigrp * xe)722 merge_instances(struct eigrpd_conf *xconf, struct eigrp *eigrp, struct eigrp *xe)
723 {
724 /* TODO */
725 }
726
727 struct eigrpd_conf *
config_new_empty(void)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
config_clear(struct eigrpd_conf * conf,enum eigrpd_process proc)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