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