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