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