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