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