xref: /openbsd-src/usr.sbin/eigrpd/eigrpd.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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