xref: /openbsd-src/usr.sbin/eigrpd/eigrpe.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: eigrpe.c,v 1.34 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 <netinet/in.h>
24 #include <netinet/ip.h>
25 
26 #include <arpa/inet.h>
27 #include <errno.h>
28 #include <pwd.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "eigrpd.h"
35 #include "eigrpe.h"
36 #include "rde.h"
37 #include "log.h"
38 #include "control.h"
39 
40 static void		 eigrpe_sig_handler(int, short, void *);
41 static __dead void	 eigrpe_shutdown(void);
42 static void		 eigrpe_dispatch_main(int, short, void *);
43 static void		 eigrpe_dispatch_rde(int, short, void *);
44 
45 struct eigrpd_conf	*econf;
46 
47 static struct event	 ev4;
48 static struct event	 ev6;
49 static struct imsgev	*iev_main;
50 static struct imsgev	*iev_rde;
51 
52 /* ARGSUSED */
53 static void
54 eigrpe_sig_handler(int sig, short event, void *bula)
55 {
56 	switch (sig) {
57 	case SIGINT:
58 	case SIGTERM:
59 		eigrpe_shutdown();
60 		/* NOTREACHED */
61 	default:
62 		fatalx("unexpected signal");
63 	}
64 }
65 
66 /* eigrp engine */
67 void
68 eigrpe(int debug, int verbose, char *sockname)
69 {
70 	struct passwd		*pw;
71 	struct event		 ev_sigint, ev_sigterm;
72 
73 	econf = config_new_empty();
74 
75 	log_init(debug);
76 	log_verbose(verbose);
77 
78 	/* create eigrpd control socket outside chroot */
79 	global.csock = sockname;
80 	if (control_init(global.csock) == -1)
81 		fatalx("control socket setup failed");
82 
83 	if (inet_pton(AF_INET, AllEIGRPRouters_v4, &global.mcast_addr_v4) != 1)
84 		fatal("inet_pton");
85 	if (inet_pton(AF_INET6, AllEIGRPRouters_v6, &global.mcast_addr_v6) != 1)
86 		fatal("inet_pton");
87 
88 	/* create the raw ipv4 socket */
89 	if ((global.eigrp_socket_v4 = socket(AF_INET,
90 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_EIGRP)) == -1)
91 		fatal("error creating raw ipv4 socket");
92 
93 	/* set some defaults */
94 	if (if_set_ipv4_mcast_ttl(global.eigrp_socket_v4, EIGRP_IP_TTL) == -1)
95 		fatal("if_set_ipv4_mcast_ttl");
96 	if (if_set_ipv4_mcast_loop(global.eigrp_socket_v4) == -1)
97 		fatal("if_set_ipv4_mcast_loop");
98 	if (if_set_ipv4_recvif(global.eigrp_socket_v4, 1) == -1)
99 		fatal("if_set_ipv4_recvif");
100 	if (if_set_ipv4_hdrincl(global.eigrp_socket_v4) == -1)
101 		fatal("if_set_ipv4_hdrincl");
102 	if_set_sockbuf(global.eigrp_socket_v4);
103 
104 	/* create the raw ipv6 socket */
105 	if ((global.eigrp_socket_v6 = socket(AF_INET6,
106 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_EIGRP)) == -1)
107 		fatal("error creating raw ipv6 socket");
108 
109 	/* set some defaults */
110 	if (if_set_ipv6_mcast_loop(global.eigrp_socket_v6) == -1)
111 		fatal("if_set_ipv6_mcast_loop");
112 	if (if_set_ipv6_pktinfo(global.eigrp_socket_v6, 1) == -1)
113 		fatal("if_set_ipv6_pktinfo");
114 	if (if_set_ipv6_dscp(global.eigrp_socket_v6,
115 	    IPTOS_PREC_NETCONTROL) == -1)
116 		fatal("if_set_ipv6_dscp");
117 	if_set_sockbuf(global.eigrp_socket_v6);
118 
119 	if ((pw = getpwnam(EIGRPD_USER)) == NULL)
120 		fatal("getpwnam");
121 
122 	if (chroot(pw->pw_dir) == -1)
123 		fatal("chroot");
124 	if (chdir("/") == -1)
125 		fatal("chdir(\"/\")");
126 
127 	setproctitle("eigrp engine");
128 	eigrpd_process = PROC_EIGRP_ENGINE;
129 	log_procname = log_procnames[eigrpd_process];
130 
131 	if (setgroups(1, &pw->pw_gid) ||
132 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
133 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
134 		fatal("can't drop privileges");
135 
136 	if (pledge("stdio cpath inet mcast recvfd", NULL) == -1)
137 		fatal("pledge");
138 
139 	event_init();
140 
141 	/* setup signal handler */
142 	signal_set(&ev_sigint, SIGINT, eigrpe_sig_handler, NULL);
143 	signal_set(&ev_sigterm, SIGTERM, eigrpe_sig_handler, NULL);
144 	signal_add(&ev_sigint, NULL);
145 	signal_add(&ev_sigterm, NULL);
146 	signal(SIGPIPE, SIG_IGN);
147 	signal(SIGHUP, SIG_IGN);
148 
149 	/* setup pipe and event handler to the parent process */
150 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
151 		fatal(NULL);
152 	imsg_init(&iev_main->ibuf, 3);
153 	iev_main->handler = eigrpe_dispatch_main;
154 	iev_main->events = EV_READ;
155 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
156 	    iev_main->handler, iev_main);
157 	event_add(&iev_main->ev, NULL);
158 
159 	event_set(&ev4, global.eigrp_socket_v4, EV_READ|EV_PERSIST,
160 	    recv_packet, econf);
161 	event_add(&ev4, NULL);
162 
163 	event_set(&ev6, global.eigrp_socket_v6, EV_READ|EV_PERSIST,
164 	    recv_packet, econf);
165 	event_add(&ev6, NULL);
166 
167 	/* listen on eigrpd control socket */
168 	TAILQ_INIT(&ctl_conns);
169 	control_listen();
170 
171 	if ((pkt_ptr = calloc(1, READ_BUF_SIZE)) == NULL)
172 		fatal("eigrpe");
173 
174 	event_dispatch();
175 
176 	eigrpe_shutdown();
177 }
178 
179 static __dead void
180 eigrpe_shutdown(void)
181 {
182 	/* close pipes */
183 	msgbuf_write(&iev_rde->ibuf.w);
184 	msgbuf_clear(&iev_rde->ibuf.w);
185 	close(iev_rde->ibuf.fd);
186 	msgbuf_write(&iev_main->ibuf.w);
187 	msgbuf_clear(&iev_main->ibuf.w);
188 	close(iev_main->ibuf.fd);
189 
190 	control_cleanup(global.csock);
191 	config_clear(econf);
192 
193 	event_del(&ev4);
194 	event_del(&ev6);
195 	close(global.eigrp_socket_v4);
196 	close(global.eigrp_socket_v6);
197 
198 	/* clean up */
199 	free(iev_rde);
200 	free(iev_main);
201 	free(pkt_ptr);
202 
203 	log_info("eigrp engine exiting");
204 	exit(0);
205 }
206 
207 /* imesg */
208 int
209 eigrpe_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
210 {
211 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
212 }
213 
214 int
215 eigrpe_imsg_compose_rde(int type, uint32_t peerid, pid_t pid,
216     void *data, uint16_t datalen)
217 {
218 	return (imsg_compose_event(iev_rde, type, peerid, pid, -1,
219 	    data, datalen));
220 }
221 
222 /* ARGSUSED */
223 static void
224 eigrpe_dispatch_main(int fd, short event, void *bula)
225 {
226 	static struct eigrpd_conf *nconf;
227 	static struct iface	*niface;
228 	static struct eigrp	*neigrp;
229 	struct eigrp_iface	*nei;
230 	struct imsg		 imsg;
231 	struct imsgev		*iev = bula;
232 	struct imsgbuf		*ibuf = &iev->ibuf;
233 	struct iface		*iface = NULL;
234 	struct kif		*kif;
235 	struct kaddr		*ka;
236 	int			 n, shut = 0;
237 
238 	if (event & EV_READ) {
239 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
240 			fatal("imsg_read error");
241 		if (n == 0)	/* connection closed */
242 			shut = 1;
243 	}
244 	if (event & EV_WRITE) {
245 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
246 			fatal("msgbuf_write");
247 		if (n == 0)	/* connection closed */
248 			shut = 1;
249 	}
250 
251 	for (;;) {
252 		if ((n = imsg_get(ibuf, &imsg)) == -1)
253 			fatal("eigrpe_dispatch_main: imsg_get error");
254 		if (n == 0)
255 			break;
256 
257 		switch (imsg.hdr.type) {
258 		case IMSG_IFINFO:
259 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
260 			    sizeof(struct kif))
261 				fatalx("IFSTATUS imsg with wrong len");
262 			kif = imsg.data;
263 
264 			iface = if_lookup(econf, kif->ifindex);
265 			if (!iface)
266 				break;
267 
268 			iface->flags = kif->flags;
269 			iface->linkstate = kif->link_state;
270 			if_update(iface, AF_UNSPEC);
271 			break;
272 		case IMSG_NEWADDR:
273 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
274 			    sizeof(struct kaddr))
275 				fatalx("NEWADDR imsg with wrong len");
276 			ka = imsg.data;
277 
278 			iface = if_lookup(econf, ka->ifindex);
279 			if (iface == NULL)
280 				break;
281 
282 			if_addr_new(iface, ka);
283 			break;
284 		case IMSG_DELADDR:
285 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
286 			    sizeof(struct kaddr))
287 				fatalx("DELADDR imsg with wrong len");
288 			ka = imsg.data;
289 
290 			iface = if_lookup(econf, ka->ifindex);
291 			if (iface == NULL)
292 				break;
293 
294 			if_addr_del(iface, ka);
295 			break;
296 		case IMSG_SOCKET_IPC:
297 			if (iev_rde) {
298 				log_warnx("%s: received unexpected imsg fd "
299 				    "to rde", __func__);
300 				break;
301 			}
302 			if ((fd = imsg.fd) == -1) {
303 				log_warnx("%s: expected to receive imsg fd to "
304 				    "rde but didn't receive any", __func__);
305 				break;
306 			}
307 
308 			iev_rde = malloc(sizeof(struct imsgev));
309 			if (iev_rde == NULL)
310 				fatal(NULL);
311 			imsg_init(&iev_rde->ibuf, fd);
312 			iev_rde->handler = eigrpe_dispatch_rde;
313 			iev_rde->events = EV_READ;
314 			event_set(&iev_rde->ev, iev_rde->ibuf.fd,
315 			    iev_rde->events, iev_rde->handler, iev_rde);
316 			event_add(&iev_rde->ev, NULL);
317 			break;
318 		case IMSG_RECONF_CONF:
319 			if ((nconf = malloc(sizeof(struct eigrpd_conf))) ==
320 			    NULL)
321 				fatal(NULL);
322 			memcpy(nconf, imsg.data, sizeof(struct eigrpd_conf));
323 
324 			TAILQ_INIT(&nconf->iface_list);
325 			TAILQ_INIT(&nconf->instances);
326 			break;
327 		case IMSG_RECONF_INSTANCE:
328 			if ((neigrp = malloc(sizeof(struct eigrp))) == NULL)
329 				fatal(NULL);
330 			memcpy(neigrp, imsg.data, sizeof(struct eigrp));
331 
332 			SIMPLEQ_INIT(&neigrp->redist_list);
333 			TAILQ_INIT(&neigrp->ei_list);
334 			RB_INIT(&neigrp->nbrs);
335 			RB_INIT(&neigrp->topology);
336 			TAILQ_INSERT_TAIL(&nconf->instances, neigrp, entry);
337 			break;
338 		case IMSG_RECONF_IFACE:
339 			niface = imsg.data;
340 			niface = if_lookup(nconf, niface->ifindex);
341 			if (niface)
342 				break;
343 
344 			if ((niface = malloc(sizeof(struct iface))) == NULL)
345 				fatal(NULL);
346 			memcpy(niface, imsg.data, sizeof(struct iface));
347 
348 			TAILQ_INIT(&niface->ei_list);
349 			TAILQ_INIT(&niface->addr_list);
350 			TAILQ_INSERT_TAIL(&nconf->iface_list, niface, entry);
351 			break;
352 		case IMSG_RECONF_EIGRP_IFACE:
353 			if (niface == NULL)
354 				break;
355 			if ((nei = malloc(sizeof(struct eigrp_iface))) == NULL)
356 				fatal(NULL);
357 			memcpy(nei, imsg.data, sizeof(struct eigrp_iface));
358 
359 			nei->iface = niface;
360 			nei->eigrp = neigrp;
361 			TAILQ_INIT(&nei->nbr_list);
362 			TAILQ_INIT(&nei->update_list);
363 			TAILQ_INIT(&nei->query_list);
364 			TAILQ_INIT(&nei->summary_list);
365 			TAILQ_INSERT_TAIL(&niface->ei_list, nei, i_entry);
366 			TAILQ_INSERT_TAIL(&neigrp->ei_list, nei, e_entry);
367 			if (RB_INSERT(iface_id_head, &ifaces_by_id, nei) !=
368 			    NULL)
369 				fatalx("eigrpe_dispatch_main: "
370 				    "RB_INSERT(ifaces_by_id) failed");
371 			break;
372 		case IMSG_RECONF_END:
373 			merge_config(econf, nconf);
374 			nconf = NULL;
375 			break;
376 		case IMSG_CTL_KROUTE:
377 		case IMSG_CTL_IFINFO:
378 		case IMSG_CTL_END:
379 			control_imsg_relay(&imsg);
380 			break;
381 		default:
382 			log_debug("%s: error handling imsg %d", __func__,
383 			    imsg.hdr.type);
384 			break;
385 		}
386 		imsg_free(&imsg);
387 	}
388 	if (!shut)
389 		imsg_event_add(iev);
390 	else {
391 		/* this pipe is dead, so remove the event handler */
392 		event_del(&iev->ev);
393 		event_loopexit(NULL);
394 	}
395 }
396 
397 /* ARGSUSED */
398 static void
399 eigrpe_dispatch_rde(int fd, short event, void *bula)
400 {
401 	struct imsgev		*iev = bula;
402 	struct imsgbuf		*ibuf = &iev->ibuf;
403 	struct imsg		 imsg;
404 	struct nbr		*nbr;
405 	struct eigrp_iface	*ei;
406 	struct rinfo		 rinfo;
407 	int			 n, shut = 0;
408 
409 	if (event & EV_READ) {
410 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
411 			fatal("imsg_read error");
412 		if (n == 0)	/* connection closed */
413 			shut = 1;
414 	}
415 	if (event & EV_WRITE) {
416 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
417 			fatal("msgbuf_write");
418 		if (n == 0)	/* connection closed */
419 			shut = 1;
420 	}
421 
422 	for (;;) {
423 		if ((n = imsg_get(ibuf, &imsg)) == -1)
424 			fatal("eigrpe_dispatch_rde: imsg_get error");
425 		if (n == 0)
426 			break;
427 
428 		switch (imsg.hdr.type) {
429 		case IMSG_SEND_UPDATE:
430 		case IMSG_SEND_QUERY:
431 		case IMSG_SEND_REPLY:
432 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rinfo))
433 				fatalx("invalid size of rinfo");
434 			memcpy(&rinfo, imsg.data, sizeof(rinfo));
435 
436 			nbr = nbr_find_peerid(imsg.hdr.peerid);
437 			if (nbr == NULL) {
438 				log_debug("%s: cannot find rde neighbor",
439 				    __func__);
440 				break;
441 			}
442 
443 			switch (imsg.hdr.type) {
444 			case IMSG_SEND_UPDATE:
445 				message_add(&nbr->update_list, &rinfo);
446 				break;
447 			case IMSG_SEND_QUERY:
448 				message_add(&nbr->query_list, &rinfo);
449 				break;
450 			case IMSG_SEND_REPLY:
451 				message_add(&nbr->reply_list, &rinfo);
452 				break;
453 			}
454 			break;
455 		case IMSG_SEND_MUPDATE:
456 		case IMSG_SEND_MQUERY:
457 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rinfo))
458 				fatalx("invalid size of rinfo");
459 			memcpy(&rinfo, imsg.data, sizeof(rinfo));
460 
461 			ei = eigrp_if_lookup_id(imsg.hdr.peerid);
462 			if (ei == NULL) {
463 				log_debug("%s: cannot find interface",
464 				    __func__);
465 				break;
466 			}
467 
468 			switch (imsg.hdr.type) {
469 			case IMSG_SEND_MUPDATE:
470 				message_add(&ei->update_list, &rinfo);
471 				break;
472 			case IMSG_SEND_MQUERY:
473 				message_add(&ei->query_list, &rinfo);
474 				break;
475 			}
476 			break;
477 		case IMSG_SEND_UPDATE_END:
478 		case IMSG_SEND_REPLY_END:
479 		case IMSG_SEND_SIAQUERY_END:
480 		case IMSG_SEND_SIAREPLY_END:
481 			nbr = nbr_find_peerid(imsg.hdr.peerid);
482 			if (nbr == NULL) {
483 				log_debug("%s: cannot find rde neighbor",
484 				    __func__);
485 				break;
486 			}
487 
488 			switch (imsg.hdr.type) {
489 			case IMSG_SEND_UPDATE_END:
490 				send_update(nbr->ei, nbr, 0, &nbr->update_list);
491 				message_list_clr(&nbr->update_list);
492 				break;
493 			case IMSG_SEND_REPLY_END:
494 				send_reply(nbr,  &nbr->reply_list, 0);
495 				message_list_clr(&nbr->reply_list);
496 				break;
497 			case IMSG_SEND_SIAQUERY_END:
498 				send_query(nbr->ei, nbr, &nbr->query_list, 1);
499 				message_list_clr(&nbr->query_list);
500 				break;
501 			case IMSG_SEND_SIAREPLY_END:
502 				send_reply(nbr, &nbr->reply_list, 1);
503 				message_list_clr(&nbr->reply_list);
504 				break;
505 			}
506 			break;
507 		case IMSG_SEND_MUPDATE_END:
508 		case IMSG_SEND_MQUERY_END:
509 			ei = eigrp_if_lookup_id(imsg.hdr.peerid);
510 			if (ei == NULL) {
511 				log_debug("%s: cannot find interface",
512 				    __func__);
513 				break;
514 			}
515 
516 			switch (imsg.hdr.type) {
517 			case IMSG_SEND_MUPDATE_END:
518 				send_update(ei, NULL, 0, &ei->update_list);
519 				message_list_clr(&ei->update_list);
520 				break;
521 			case IMSG_SEND_MQUERY_END:
522 				send_query(ei, NULL, &ei->query_list, 0);
523 				message_list_clr(&ei->query_list);
524 				break;
525 			}
526 			break;
527 		case IMSG_NEIGHBOR_DOWN:
528 			nbr = nbr_find_peerid(imsg.hdr.peerid);
529 			if (nbr == NULL) {
530 				log_debug("%s: cannot find rde neighbor",
531 				    __func__);
532 				break;
533 			}
534 			/* announce that this neighborship is dead */
535 			send_peerterm(nbr);
536 			nbr_del(nbr);
537 			break;
538 		case IMSG_CTL_SHOW_TOPOLOGY:
539 		case IMSG_CTL_END:
540 			control_imsg_relay(&imsg);
541 			break;
542 		default:
543 			log_debug("%s: error handling imsg %d", __func__,
544 			    imsg.hdr.type);
545 			break;
546 		}
547 		imsg_free(&imsg);
548 	}
549 	if (!shut)
550 		imsg_event_add(iev);
551 	else {
552 		/* this pipe is dead, so remove the event handler */
553 		event_del(&iev->ev);
554 		event_loopexit(NULL);
555 	}
556 }
557 
558 void
559 eigrpe_instance_init(struct eigrp *eigrp)
560 {
561 }
562 
563 void
564 eigrpe_instance_del(struct eigrp *eigrp)
565 {
566 	struct eigrp_iface	*ei;
567 
568 	while ((ei = TAILQ_FIRST(&eigrp->ei_list)) != NULL)
569 		eigrp_if_del(ei);
570 
571 	free(eigrp);
572 }
573 
574 void
575 message_add(struct rinfo_head *rinfo_list, struct rinfo *rinfo)
576 {
577 	struct rinfo_entry	*re;
578 
579 	re = calloc(1, sizeof(*re));
580 	if (re == NULL)
581 		fatal("message_add");
582 	re->rinfo = *rinfo;
583 
584 	TAILQ_INSERT_TAIL(rinfo_list, re, entry);
585 }
586 
587 void
588 message_list_clr(struct rinfo_head *rinfo_list)
589 {
590 	struct rinfo_entry	*re;
591 
592 	while ((re = TAILQ_FIRST(rinfo_list)) != NULL) {
593 		TAILQ_REMOVE(rinfo_list, re, entry);
594 		free(re);
595 	}
596 }
597 
598 void
599 seq_addr_list_clr(struct seq_addr_head *seq_addr_list)
600 {
601 	struct seq_addr_entry	*sa;
602 
603 	while ((sa = TAILQ_FIRST(seq_addr_list)) != NULL) {
604 		TAILQ_REMOVE(seq_addr_list, sa, entry);
605 		free(sa);
606 	}
607 }
608 
609 void
610 eigrpe_orig_local_route(struct eigrp_iface *ei, struct if_addr *if_addr,
611     int withdraw)
612 {
613 	struct rinfo	 rinfo;
614 
615 	memset(&rinfo, 0, sizeof(rinfo));
616 	rinfo.af = if_addr->af;
617 	rinfo.type = EIGRP_ROUTE_INTERNAL;
618 	rinfo.prefix = if_addr->addr;
619 	rinfo.prefixlen = if_addr->prefixlen;
620 
621 	eigrp_applymask(rinfo.af, &rinfo.prefix, &rinfo.prefix,
622 	    rinfo.prefixlen);
623 
624 	if (withdraw)
625 		rinfo.metric.delay = EIGRP_INFINITE_METRIC;
626 	else
627 		rinfo.metric.delay = eigrp_composite_delay(ei->delay);
628 	rinfo.metric.bandwidth = eigrp_composite_bandwidth(ei->bandwidth);
629 	metric_encode_mtu(rinfo.metric.mtu, ei->iface->mtu);
630 	rinfo.metric.hop_count = 0;
631 	rinfo.metric.reliability = DEFAULT_RELIABILITY;
632 	rinfo.metric.load = DEFAULT_LOAD;
633 	rinfo.metric.tag = 0;
634 	rinfo.metric.flags = 0;
635 
636 	eigrpe_imsg_compose_rde(IMSG_RECV_UPDATE, ei->self->peerid, 0,
637 	    &rinfo, sizeof(rinfo));
638 }
639 
640 void
641 eigrpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
642 {
643 	struct eigrp		*eigrp;
644 	struct eigrp_iface	*ei;
645 	struct ctl_iface	*ictl;
646 
647 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
648 		TAILQ_FOREACH(ei, &eigrp->ei_list, e_entry) {
649 			if (idx == 0 || idx == ei->iface->ifindex) {
650 				ictl = if_to_ctl(ei);
651 				imsg_compose_event(&c->iev,
652 				    IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
653 				    ictl, sizeof(struct ctl_iface));
654 			}
655 		}
656 	}
657 }
658 
659 void
660 eigrpe_nbr_ctl(struct ctl_conn *c)
661 {
662 	struct eigrp	*eigrp;
663 	struct nbr	*nbr;
664 	struct ctl_nbr	*nctl;
665 
666 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
667 		RB_FOREACH(nbr, nbr_addr_head, &eigrp->nbrs) {
668 			if (nbr->flags & (F_EIGRP_NBR_PENDING|F_EIGRP_NBR_SELF))
669 				continue;
670 
671 			nctl = nbr_to_ctl(nbr);
672 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0,
673 			    0, -1, nctl, sizeof(struct ctl_nbr));
674 		}
675 	}
676 
677 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
678 }
679 
680 void
681 eigrpe_stats_ctl(struct ctl_conn *c)
682 {
683 	struct eigrp		*eigrp;
684 	struct ctl_stats	 sctl;
685 
686 	TAILQ_FOREACH(eigrp, &econf->instances, entry) {
687 		sctl.af = eigrp->af;
688 		sctl.as = eigrp->as;
689 		sctl.stats = eigrp->stats;
690 		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_STATS, 0,
691 		    0, -1, &sctl, sizeof(struct ctl_stats));
692 	}
693 
694 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
695 }
696