1*f1b790a5Sclaudio /* $OpenBSD: eigrpctl.c,v 1.14 2024/11/21 13:38:14 claudio Exp $ */ 2e2656810Srenato 3e2656810Srenato /* 4e2656810Srenato * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 5e2656810Srenato * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6e2656810Srenato * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 7e2656810Srenato * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 8e2656810Srenato * 9e2656810Srenato * Permission to use, copy, modify, and distribute this software for any 10e2656810Srenato * purpose with or without fee is hereby granted, provided that the above 11e2656810Srenato * copyright notice and this permission notice appear in all copies. 12e2656810Srenato * 13e2656810Srenato * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14e2656810Srenato * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15e2656810Srenato * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16e2656810Srenato * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17e2656810Srenato * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18e2656810Srenato * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19e2656810Srenato * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20e2656810Srenato */ 21e2656810Srenato 22e2656810Srenato #include <sys/types.h> 23e2656810Srenato #include <sys/socket.h> 24e2656810Srenato #include <sys/un.h> 25e2656810Srenato #include <netinet/in.h> 26e2656810Srenato #include <arpa/inet.h> 27e2656810Srenato #include <net/if_media.h> 28e2656810Srenato #include <net/if_types.h> 29e2656810Srenato 30e2656810Srenato #include <err.h> 31e2656810Srenato #include <errno.h> 32e2656810Srenato #include <stdio.h> 33e2656810Srenato #include <stdlib.h> 34e2656810Srenato #include <string.h> 35e2656810Srenato #include <unistd.h> 36e2656810Srenato 37e2656810Srenato #include "eigrp.h" 38e2656810Srenato #include "eigrpd.h" 39e2656810Srenato #include "eigrpe.h" 40e2656810Srenato #include "rde.h" 41e2656810Srenato #include "log.h" 42e2656810Srenato #include "parser.h" 43e2656810Srenato 44e2656810Srenato __dead void usage(void); 45e2656810Srenato uint64_t get_ifms_type(uint8_t); 46e2656810Srenato int show_interface_msg(struct imsg *, struct parse_result *); 47e2656810Srenato int show_interface_detail_msg(struct imsg *, 48e2656810Srenato struct parse_result *); 49e2656810Srenato const char *print_link(int); 50e2656810Srenato const char *fmt_timeframe_core(time_t); 51e2656810Srenato int show_nbr_msg(struct imsg *, struct parse_result *); 52e2656810Srenato int show_topology_msg(struct imsg *, struct parse_result *); 53e2656810Srenato int show_topology_detail_msg(struct imsg *, 54e2656810Srenato struct parse_result *); 55e2656810Srenato void show_fib_head(void); 56e2656810Srenato int show_fib_msg(struct imsg *, struct parse_result *); 57e2656810Srenato void show_interface_head(void); 58e2656810Srenato const char * get_media_descr(uint64_t); 59e2656810Srenato const char * get_linkstate(uint8_t, int); 60e2656810Srenato void print_baudrate(uint64_t); 61e2656810Srenato int show_fib_interface_msg(struct imsg *); 62dcfaa8d4Srenato int show_stats_msg(struct imsg *, struct parse_result *); 63e2656810Srenato 64e2656810Srenato struct imsgbuf *ibuf; 65e2656810Srenato 66e2656810Srenato __dead void 67e2656810Srenato usage(void) 68e2656810Srenato { 69e2656810Srenato extern char *__progname; 70e2656810Srenato 7128291a98Srenato fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n", 7228291a98Srenato __progname); 73e2656810Srenato exit(1); 74e2656810Srenato } 75e2656810Srenato 76e2656810Srenato int 77e2656810Srenato main(int argc, char *argv[]) 78e2656810Srenato { 79e2656810Srenato struct sockaddr_un sun; 80e2656810Srenato struct parse_result *res; 81e2656810Srenato struct imsg imsg; 82e2656810Srenato unsigned int ifidx = 0; 83e2656810Srenato int ctl_sock; 84e2656810Srenato int done = 0; 85e2656810Srenato int n, verbose = 0; 8628291a98Srenato int ch; 8728291a98Srenato char *sockname; 88e2656810Srenato struct ctl_show_topology_req treq; 89956c66a0Srenato struct ctl_nbr nbr; 90e2656810Srenato 9128291a98Srenato sockname = EIGRPD_SOCKET; 9228291a98Srenato while ((ch = getopt(argc, argv, "s:")) != -1) { 9328291a98Srenato switch (ch) { 9428291a98Srenato case 's': 9528291a98Srenato sockname = optarg; 9628291a98Srenato break; 9728291a98Srenato default: 9828291a98Srenato usage(); 9928291a98Srenato /* NOTREACHED */ 10028291a98Srenato } 10128291a98Srenato } 10228291a98Srenato argc -= optind; 10328291a98Srenato argv += optind; 10428291a98Srenato 105e2656810Srenato /* parse options */ 10628291a98Srenato if ((res = parse(argc, argv)) == NULL) 107e2656810Srenato exit(1); 108e2656810Srenato 109e2656810Srenato /* connect to eigrpd control socket */ 110e2656810Srenato if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 111e2656810Srenato err(1, "socket"); 112e2656810Srenato 113e2656810Srenato memset(&sun, 0, sizeof(sun)); 114e2656810Srenato sun.sun_family = AF_UNIX; 11528291a98Srenato strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); 116e2656810Srenato if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 11728291a98Srenato err(1, "connect: %s", sockname); 118e2656810Srenato 11917b561adSderaadt if (pledge("stdio", NULL) == -1) 1204581b8e5Ssemarie err(1, "pledge"); 121f0c6dc37Srenato 122e2656810Srenato if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 123e2656810Srenato err(1, NULL); 124*f1b790a5Sclaudio if (imsgbuf_init(ibuf, ctl_sock) == -1) 125*f1b790a5Sclaudio err(1, NULL); 126e2656810Srenato done = 0; 127e2656810Srenato 128e2656810Srenato /* process user request */ 129e2656810Srenato switch (res->action) { 130e2656810Srenato case NONE: 131e2656810Srenato usage(); 132e2656810Srenato /* not reached */ 133e2656810Srenato case SHOW: 134e2656810Srenato case SHOW_IFACE: 135e2656810Srenato printf("%-4s %-5s %-11s %-18s %-10s %-8s %3s\n", 136e2656810Srenato "AF", "AS", "Interface", "Address", "Linkstate", 137e2656810Srenato "Uptime", "nc"); 138e2656810Srenato /*FALLTHROUGH*/ 139e2656810Srenato case SHOW_IFACE_DTAIL: 140e2656810Srenato if (*res->ifname) { 141e2656810Srenato ifidx = if_nametoindex(res->ifname); 142e2656810Srenato if (ifidx == 0) 143e2656810Srenato errx(1, "no such interface %s", res->ifname); 144e2656810Srenato } 145e2656810Srenato imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 146e2656810Srenato &ifidx, sizeof(ifidx)); 147e2656810Srenato break; 148e2656810Srenato case SHOW_NBR: 149e2656810Srenato printf("%-4s %-5s %-18s %-11s %-10s %8s\n", "AF", "AS", 150e2656810Srenato "Address", "Iface", "Holdtime", "Uptime"); 151e2656810Srenato imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); 152e2656810Srenato break; 153e2656810Srenato case SHOW_TOPOLOGY: 154e2656810Srenato memset(&treq, 0, sizeof(treq)); 155e2656810Srenato treq.af = res->family; 156e2656810Srenato memcpy(&treq.prefix, &res->addr, sizeof(res->addr)); 157e2656810Srenato treq.prefixlen = res->prefixlen; 158e2656810Srenato treq.flags = res->flags; 159e2656810Srenato 160e2656810Srenato if (!eigrp_addrisset(res->family, &res->addr)) 161e2656810Srenato printf(" %-4s %-5s %-18s %-15s %-12s %s\n", 162e2656810Srenato "AF", "AS", "Destination", "Nexthop", "Interface", 163e2656810Srenato "Distance"); 164e2656810Srenato imsg_compose(ibuf, IMSG_CTL_SHOW_TOPOLOGY, 0, 0, -1, 165e2656810Srenato &treq, sizeof(treq)); 166e2656810Srenato break; 167e2656810Srenato case SHOW_FIB: 168e2656810Srenato show_fib_head(); 169e2656810Srenato imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1, 170e2656810Srenato &res->flags, sizeof(res->flags)); 171e2656810Srenato break; 172e2656810Srenato case SHOW_FIB_IFACE: 173e2656810Srenato if (*res->ifname) 174e2656810Srenato imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, 175e2656810Srenato res->ifname, sizeof(res->ifname)); 176e2656810Srenato else 177e2656810Srenato imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0); 178e2656810Srenato show_interface_head(); 179e2656810Srenato break; 180dcfaa8d4Srenato case SHOW_STATS: 181dcfaa8d4Srenato imsg_compose(ibuf, IMSG_CTL_SHOW_STATS, 0, 0, -1, NULL, 0); 182dcfaa8d4Srenato break; 183956c66a0Srenato case CLEAR_NBR: 184956c66a0Srenato memset(&nbr, 0, sizeof(nbr)); 185956c66a0Srenato nbr.af = res->family; 186956c66a0Srenato nbr.as = res->as; 187956c66a0Srenato memcpy(&nbr.addr, &res->addr, sizeof(res->addr)); 188956c66a0Srenato imsg_compose(ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr, 189956c66a0Srenato sizeof(nbr)); 190956c66a0Srenato done = 1; 191956c66a0Srenato break; 192e2656810Srenato case FIB: 193e2656810Srenato errx(1, "fib couple|decouple"); 194e2656810Srenato break; 195e2656810Srenato case FIB_COUPLE: 196e2656810Srenato imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0); 197e2656810Srenato printf("couple request sent.\n"); 198e2656810Srenato done = 1; 199e2656810Srenato break; 200e2656810Srenato case FIB_DECOUPLE: 201e2656810Srenato imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0); 202e2656810Srenato printf("decouple request sent.\n"); 203e2656810Srenato done = 1; 204e2656810Srenato break; 205e2656810Srenato case LOG_VERBOSE: 206e2656810Srenato verbose = 1; 207e2656810Srenato /* FALLTHROUGH */ 208e2656810Srenato case LOG_BRIEF: 209e2656810Srenato imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 210e2656810Srenato &verbose, sizeof(verbose)); 211e2656810Srenato printf("logging request sent.\n"); 212e2656810Srenato done = 1; 213e2656810Srenato break; 214e2656810Srenato case RELOAD: 215e2656810Srenato imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 216e2656810Srenato printf("reload request sent.\n"); 217e2656810Srenato done = 1; 218e2656810Srenato break; 219e2656810Srenato } 220e2656810Srenato 221dd7efffeSclaudio if (imsgbuf_flush(ibuf) == -1) 222e2656810Srenato err(1, "write error"); 223e2656810Srenato 224e2656810Srenato while (!done) { 225668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 226ef2e27a1Sclaudio err(1, "read error"); 227e2656810Srenato if (n == 0) 228e2656810Srenato errx(1, "pipe closed"); 229e2656810Srenato 230e2656810Srenato while (!done) { 231e2656810Srenato if ((n = imsg_get(ibuf, &imsg)) == -1) 232e2656810Srenato errx(1, "imsg_get error"); 233e2656810Srenato if (n == 0) 234e2656810Srenato break; 235e2656810Srenato switch (res->action) { 236e2656810Srenato case SHOW: 237e2656810Srenato case SHOW_IFACE: 238e2656810Srenato done = show_interface_msg(&imsg, res); 239e2656810Srenato break; 240e2656810Srenato case SHOW_IFACE_DTAIL: 241e2656810Srenato done = show_interface_detail_msg(&imsg, res); 242e2656810Srenato break; 243e2656810Srenato case SHOW_NBR: 244e2656810Srenato done = show_nbr_msg(&imsg, res); 245e2656810Srenato break; 246e2656810Srenato case SHOW_TOPOLOGY: 247e2656810Srenato if (eigrp_addrisset(res->family, &res->addr)) 248e2656810Srenato done = show_topology_detail_msg(&imsg, 249e2656810Srenato res); 250e2656810Srenato else 251e2656810Srenato done = show_topology_msg(&imsg, res); 252e2656810Srenato break; 253e2656810Srenato case SHOW_FIB: 254e2656810Srenato done = show_fib_msg(&imsg, res); 255e2656810Srenato break; 256e2656810Srenato case SHOW_FIB_IFACE: 257e2656810Srenato done = show_fib_interface_msg(&imsg); 258e2656810Srenato break; 259dcfaa8d4Srenato case SHOW_STATS: 260dcfaa8d4Srenato done = show_stats_msg(&imsg, res); 261dcfaa8d4Srenato break; 262956c66a0Srenato case CLEAR_NBR: 263e2656810Srenato case NONE: 264e2656810Srenato case FIB: 265e2656810Srenato case FIB_COUPLE: 266e2656810Srenato case FIB_DECOUPLE: 267e2656810Srenato case LOG_VERBOSE: 268e2656810Srenato case LOG_BRIEF: 269e2656810Srenato case RELOAD: 270e2656810Srenato break; 271e2656810Srenato } 272e2656810Srenato imsg_free(&imsg); 273e2656810Srenato } 274e2656810Srenato } 275e2656810Srenato close(ctl_sock); 276e2656810Srenato free(ibuf); 277e2656810Srenato 278e2656810Srenato return (0); 279e2656810Srenato } 280e2656810Srenato 281e2656810Srenato uint64_t 282e2656810Srenato get_ifms_type(uint8_t if_type) 283e2656810Srenato { 284e2656810Srenato switch (if_type) { 285e2656810Srenato case IFT_ETHER: 286e2656810Srenato return (IFM_ETHER); 287e2656810Srenato case IFT_FDDI: 288e2656810Srenato return (IFM_FDDI); 289e2656810Srenato case IFT_CARP: 290e2656810Srenato return (IFM_CARP); 291e2656810Srenato case IFT_PPP: 292e2656810Srenato return (IFM_TDM); 293e2656810Srenato default: 294e2656810Srenato return (0); 295e2656810Srenato } 296e2656810Srenato } 297e2656810Srenato 298e2656810Srenato int 299e2656810Srenato show_interface_msg(struct imsg *imsg, struct parse_result *res) 300e2656810Srenato { 301e2656810Srenato struct ctl_iface *iface; 302e2656810Srenato char *addr; 303e2656810Srenato 304e2656810Srenato switch (imsg->hdr.type) { 305e2656810Srenato case IMSG_CTL_SHOW_INTERFACE: 306e2656810Srenato if (imsg->hdr.len < IMSG_HEADER_SIZE + 307e2656810Srenato sizeof(struct ctl_iface)) 308e2656810Srenato errx(1, "wrong imsg len"); 309e2656810Srenato iface = imsg->data; 310e2656810Srenato 311e2656810Srenato if (res->family != AF_UNSPEC && res->family != iface->af) 312e2656810Srenato break; 313e2656810Srenato if (res->as != 0 && res->as != iface->as) 314e2656810Srenato break; 315e2656810Srenato 316e2656810Srenato if (asprintf(&addr, "%s/%d", log_addr(iface->af, &iface->addr), 317e2656810Srenato iface->prefixlen) == -1) 318e2656810Srenato err(1, NULL); 319e2656810Srenato 320e2656810Srenato printf("%-4s %-5u %-11s %-18s", af_name(iface->af), iface->as, 321e2656810Srenato iface->name, addr); 322e2656810Srenato if (strlen(addr) > 18) 323e2656810Srenato printf("\n%41s", " "); 324e2656810Srenato printf(" %-10s %-8s %3u\n", get_linkstate(iface->if_type, 325e2656810Srenato iface->linkstate), fmt_timeframe_core(iface->uptime), 326e2656810Srenato iface->nbr_cnt); 327e2656810Srenato free(addr); 328e2656810Srenato break; 329e2656810Srenato case IMSG_CTL_END: 330e2656810Srenato printf("\n"); 331e2656810Srenato return (1); 332e2656810Srenato default: 333e2656810Srenato break; 334e2656810Srenato } 335e2656810Srenato 336e2656810Srenato return (0); 337e2656810Srenato } 338e2656810Srenato 339e2656810Srenato int 340e2656810Srenato show_interface_detail_msg(struct imsg *imsg, struct parse_result *res) 341e2656810Srenato { 342e2656810Srenato struct ctl_iface *iface; 343e2656810Srenato 344e2656810Srenato switch (imsg->hdr.type) { 345e2656810Srenato case IMSG_CTL_SHOW_INTERFACE: 346e2656810Srenato if (imsg->hdr.len < IMSG_HEADER_SIZE + 347e2656810Srenato sizeof(struct ctl_iface)) 348e2656810Srenato errx(1, "wrong imsg len"); 349e2656810Srenato iface = imsg->data; 350e2656810Srenato 351e2656810Srenato if (res->family != AF_UNSPEC && res->family != iface->af) 352e2656810Srenato break; 353e2656810Srenato if (res->as != 0 && res->as != iface->as) 354e2656810Srenato break; 355e2656810Srenato 356e2656810Srenato printf("\n"); 357e2656810Srenato printf("Interface %s, line protocol is %s\n", 358e2656810Srenato iface->name, print_link(iface->flags)); 359e2656810Srenato printf(" Autonomous System %u, Address Family %s\n", 360e2656810Srenato iface->as, af_name(iface->af)); 361e2656810Srenato printf(" Internet address %s/%d\n", 362e2656810Srenato log_addr(iface->af, &iface->addr), iface->prefixlen); 363e2656810Srenato printf(" Linkstate %s, network type %s\n", 364e2656810Srenato get_linkstate(iface->if_type, iface->linkstate), 365e2656810Srenato if_type_name(iface->type)); 366e2656810Srenato printf(" Delay %u usec, Bandwidth %u Kbit/sec\n", 367e2656810Srenato iface->delay, iface->bandwidth); 368e2656810Srenato if (iface->passive) 369e2656810Srenato printf(" Passive interface (No Hellos)\n"); 370e2656810Srenato else { 371e2656810Srenato printf(" Hello interval %u, Hello holdtime %u\n", 372e2656810Srenato iface->hello_interval, iface->hello_holdtime); 373e2656810Srenato printf(" Split-horizon %s\n", 374e2656810Srenato (iface->splithorizon) ? "enabled" : "disabled"); 375e2656810Srenato printf(" Neighbor count is %d\n", iface->nbr_cnt); 376e2656810Srenato } 377e2656810Srenato printf(" Uptime %s\n", fmt_timeframe_core(iface->uptime)); 378e2656810Srenato break; 379e2656810Srenato case IMSG_CTL_END: 380e2656810Srenato printf("\n"); 381e2656810Srenato return (1); 382e2656810Srenato default: 383e2656810Srenato break; 384e2656810Srenato } 385e2656810Srenato 386e2656810Srenato return (0); 387e2656810Srenato } 388e2656810Srenato 389e2656810Srenato const char * 390e2656810Srenato print_link(int state) 391e2656810Srenato { 392e2656810Srenato if (state & IFF_UP) 393e2656810Srenato return ("UP"); 394e2656810Srenato else 395e2656810Srenato return ("DOWN"); 396e2656810Srenato } 397e2656810Srenato 398e2656810Srenato #define TF_BUFS 8 399e2656810Srenato #define TF_LEN 9 400e2656810Srenato 401e2656810Srenato const char * 402e2656810Srenato fmt_timeframe_core(time_t t) 403e2656810Srenato { 404e2656810Srenato char *buf; 405e2656810Srenato static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 406e2656810Srenato static int idx = 0; 407e2656810Srenato unsigned int sec, min, hrs, day; 408e2656810Srenato unsigned long long week; 409e2656810Srenato 410e2656810Srenato if (t == 0) 411e2656810Srenato return ("00:00:00"); 412e2656810Srenato 413e2656810Srenato buf = tfbuf[idx++]; 414e2656810Srenato if (idx == TF_BUFS) 415e2656810Srenato idx = 0; 416e2656810Srenato 417e2656810Srenato week = t; 418e2656810Srenato 419e2656810Srenato sec = week % 60; 420e2656810Srenato week /= 60; 421e2656810Srenato min = week % 60; 422e2656810Srenato week /= 60; 423e2656810Srenato hrs = week % 24; 424e2656810Srenato week /= 24; 425e2656810Srenato day = week % 7; 426e2656810Srenato week /= 7; 427e2656810Srenato 428e2656810Srenato if (week > 0) 429e2656810Srenato snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 430e2656810Srenato else if (day > 0) 431e2656810Srenato snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 432e2656810Srenato else 433e2656810Srenato snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 434e2656810Srenato 435e2656810Srenato return (buf); 436e2656810Srenato } 437e2656810Srenato 438e2656810Srenato int 439e2656810Srenato show_nbr_msg(struct imsg *imsg, struct parse_result *res) 440e2656810Srenato { 441e2656810Srenato struct ctl_nbr *nbr; 442e2656810Srenato const char *addr; 443e2656810Srenato 444e2656810Srenato switch (imsg->hdr.type) { 445e2656810Srenato case IMSG_CTL_SHOW_NBR: 446e2656810Srenato if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_nbr)) 447e2656810Srenato errx(1, "wrong imsg len"); 448e2656810Srenato nbr = imsg->data; 449e2656810Srenato 450e2656810Srenato if (res->family != AF_UNSPEC && res->family != nbr->af) 451e2656810Srenato break; 452e2656810Srenato if (res->as != 0 && res->as != nbr->as) 453e2656810Srenato break; 454e2656810Srenato 455e2656810Srenato addr = log_addr(nbr->af, &nbr->addr); 456e2656810Srenato 457e2656810Srenato printf("%-4s %-5u %-18s", af_name(nbr->af), nbr->as, addr); 458e2656810Srenato if (strlen(addr) > 18) 459e2656810Srenato printf("\n%29s", " "); 460e2656810Srenato printf(" %-11s %-10u %8s\n", nbr->ifname, nbr->hello_holdtime, 461e2656810Srenato fmt_timeframe_core(nbr->uptime)); 462e2656810Srenato break; 463e2656810Srenato case IMSG_CTL_END: 464e2656810Srenato printf("\n"); 465e2656810Srenato return (1); 466e2656810Srenato default: 467e2656810Srenato break; 468e2656810Srenato } 469e2656810Srenato 470e2656810Srenato return (0); 471e2656810Srenato } 472e2656810Srenato 473e2656810Srenato static int 474e2656810Srenato connected_check(int af, union eigrpd_addr *addr) 475e2656810Srenato { 476e2656810Srenato switch (af) { 477e2656810Srenato case AF_INET: 478e2656810Srenato if (addr->v4.s_addr == INADDR_ANY) 479e2656810Srenato return (1); 480e2656810Srenato break; 481e2656810Srenato case AF_INET6: 482e2656810Srenato if (IN6_IS_ADDR_UNSPECIFIED(&addr->v6)) 483e2656810Srenato return (1); 484e2656810Srenato break; 485e2656810Srenato default: 486e2656810Srenato break; 487e2656810Srenato } 488e2656810Srenato 489e2656810Srenato return (0); 490e2656810Srenato } 491e2656810Srenato 492e2656810Srenato int 493e2656810Srenato show_topology_msg(struct imsg *imsg, struct parse_result *res) 494e2656810Srenato { 495e2656810Srenato struct ctl_rt *rt; 496e2656810Srenato char *dstnet, *nexthop, *rdistance; 497e2656810Srenato char flag; 498e2656810Srenato 499e2656810Srenato switch (imsg->hdr.type) { 500e2656810Srenato case IMSG_CTL_SHOW_TOPOLOGY: 501e2656810Srenato if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_rt)) 502e2656810Srenato errx(1, "wrong imsg len"); 503e2656810Srenato rt = imsg->data; 504e2656810Srenato 505e2656810Srenato if (res->family != AF_UNSPEC && res->family != rt->af) 506e2656810Srenato break; 507e2656810Srenato if (res->as != 0 && res->as != rt->as) 508e2656810Srenato break; 509e2656810Srenato 510e2656810Srenato if (rt->state & DUAL_STA_ACTIVE_ALL) 511e2656810Srenato flag = 'A'; 512e2656810Srenato else if (rt->flags & F_CTL_RT_SUCCESSOR) 513e2656810Srenato flag = 'S'; 514e2656810Srenato else if (rt->flags & F_CTL_RT_FSUCCESSOR) 515e2656810Srenato flag = 'F'; 516e2656810Srenato else 517e2656810Srenato flag = ' '; 518e2656810Srenato 519e2656810Srenato if (asprintf(&dstnet, "%s/%d", log_addr(rt->af, &rt->prefix), 520e2656810Srenato rt->prefixlen) == -1) 521e2656810Srenato err(1, NULL); 522e2656810Srenato 523e2656810Srenato if (connected_check(rt->af, &rt->nexthop)) { 524e2656810Srenato if (asprintf(&nexthop, "Connected") == -1) 525e2656810Srenato err(1, NULL); 526e2656810Srenato if (asprintf(&rdistance, "-") == -1) 527e2656810Srenato err(1, NULL); 528e2656810Srenato } else { 529e2656810Srenato if (asprintf(&nexthop, "%s", log_addr(rt->af, 530e2656810Srenato &rt->nexthop)) == -1) 531e2656810Srenato err(1, NULL); 532e2656810Srenato if (asprintf(&rdistance, "%u", rt->rdistance) == -1) 533e2656810Srenato err(1, NULL); 534e2656810Srenato } 535e2656810Srenato 536e2656810Srenato printf("%c %-4s %-5u %-18s", flag, af_name(rt->af), rt->as, 537e2656810Srenato dstnet); 538e2656810Srenato if (strlen(dstnet) > 18) 539e2656810Srenato printf("\n%31s", " "); 540e2656810Srenato printf(" %-15s", nexthop); 541e2656810Srenato if (strlen(nexthop) > 15) 542e2656810Srenato printf("\n%47s", " "); 543e2656810Srenato printf(" %-12s %u/%s\n", rt->ifname, rt->distance, rdistance); 544e2656810Srenato free(dstnet); 545e2656810Srenato free(nexthop); 546e2656810Srenato free(rdistance); 547e2656810Srenato break; 548e2656810Srenato case IMSG_CTL_END: 549e2656810Srenato printf("\n"); 550e2656810Srenato return (1); 551e2656810Srenato default: 552e2656810Srenato break; 553e2656810Srenato } 554e2656810Srenato 555e2656810Srenato return (0); 556e2656810Srenato } 557e2656810Srenato 558e2656810Srenato int 559e2656810Srenato show_topology_detail_msg(struct imsg *imsg, struct parse_result *res) 560e2656810Srenato { 561e2656810Srenato struct ctl_rt *rt; 562e2656810Srenato char *dstnet = NULL, *state = NULL, *type, *nexthop; 563e2656810Srenato struct in_addr addr; 564e2656810Srenato 565e2656810Srenato switch (imsg->hdr.type) { 566e2656810Srenato case IMSG_CTL_SHOW_TOPOLOGY: 567e2656810Srenato if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_rt)) 568e2656810Srenato errx(1, "wrong imsg len"); 569e2656810Srenato rt = imsg->data; 570e2656810Srenato 571e2656810Srenato if (res->family != AF_UNSPEC && res->family != rt->af) 572e2656810Srenato break; 573e2656810Srenato if (res->as != 0 && res->as != rt->as) 574e2656810Srenato break; 575e2656810Srenato 576e2656810Srenato if (rt->flags & F_CTL_RT_FIRST) { 577e2656810Srenato if (asprintf(&dstnet, "%s/%d", log_addr(rt->af, 578e2656810Srenato &rt->prefix), rt->prefixlen) == -1) 579e2656810Srenato err(1, NULL); 580e2656810Srenato 581e2656810Srenato if (rt->state & DUAL_STA_ACTIVE_ALL) { 582e2656810Srenato if (asprintf(&state, "Active") == -1) 583e2656810Srenato err(1, NULL); 584e2656810Srenato } else { 585e2656810Srenato if (asprintf(&state, "Passive") == -1) 586e2656810Srenato err(1, NULL); 587e2656810Srenato } 588e2656810Srenato } 589e2656810Srenato 590e2656810Srenato if (rt->type == EIGRP_ROUTE_INTERNAL) { 591e2656810Srenato if (asprintf(&type, "Internal") == -1) 592e2656810Srenato err(1, NULL); 593e2656810Srenato } else { 594e2656810Srenato if (asprintf(&type, "External") == -1) 595e2656810Srenato err(1, NULL); 596e2656810Srenato } 597e2656810Srenato 598e2656810Srenato if (connected_check(rt->af, &rt->nexthop)) { 599e2656810Srenato if (asprintf(&nexthop, "Connected") == -1) 600e2656810Srenato err(1, NULL); 601e2656810Srenato } else { 602e2656810Srenato if (asprintf(&nexthop, "Neighbor %s", log_addr(rt->af, 603e2656810Srenato &rt->nexthop)) == -1) 604e2656810Srenato err(1, NULL); 605e2656810Srenato } 606e2656810Srenato 607e2656810Srenato if (rt->flags & F_CTL_RT_FIRST) { 608e2656810Srenato printf("Network %s\n", dstnet); 609e2656810Srenato printf("Autonomous System %u, Address Family %s\n", 610e2656810Srenato rt->as, af_name(rt->af)); 611e2656810Srenato printf("DUAL State: %s, Feasible Distance: %u\n", state, 612e2656810Srenato rt->fdistance); 613e2656810Srenato printf("Routes:\n"); 614e2656810Srenato } 615e2656810Srenato printf(" Interface %s - %s\n", rt->ifname, nexthop); 616e2656810Srenato printf(" Distance: %u", rt->distance); 617e2656810Srenato if (!connected_check(rt->af, &rt->nexthop)) 618e2656810Srenato printf(", Reported Distance: %u", rt->rdistance); 619e2656810Srenato printf(", route is %s\n", type); 620e2656810Srenato printf(" Vector metric:\n"); 621e2656810Srenato printf(" Minimum bandwidth is %u Kbit\n", 622e2656810Srenato rt->metric.bandwidth); 623e2656810Srenato printf(" Total delay is %u microseconds\n", 624e2656810Srenato rt->metric.delay); 625e2656810Srenato printf(" Reliability is %u/255\n", rt->metric.reliability); 626e2656810Srenato printf(" Load is %u/255\n", rt->metric.load); 627e2656810Srenato printf(" Minimum MTU is %u\n", rt->metric.mtu); 628e2656810Srenato printf(" Hop count is %u\n", rt->metric.hop_count); 629e2656810Srenato if (rt->type == EIGRP_ROUTE_EXTERNAL) { 630e2656810Srenato addr.s_addr = htonl(rt->emetric.routerid); 631e2656810Srenato printf(" External data:\n"); 632e2656810Srenato printf(" Originating router is %s\n", 633e2656810Srenato inet_ntoa(addr)); 634e2656810Srenato printf(" AS number of route is %u\n", 635e2656810Srenato rt->emetric.as); 636e2656810Srenato printf(" External protocol is %s\n", 637e2656810Srenato ext_proto_name(rt->emetric.protocol)); 638e2656810Srenato printf(" External metric is %u\n", 639e2656810Srenato rt->emetric.metric); 640e2656810Srenato printf(" Administrator tag is %u\n", 641e2656810Srenato rt->emetric.tag); 642e2656810Srenato } 643e2656810Srenato 644e2656810Srenato printf("\n"); 645e2656810Srenato free(dstnet); 646e2656810Srenato free(state); 647e2656810Srenato free(type); 648e2656810Srenato free(nexthop); 649e2656810Srenato break; 650e2656810Srenato case IMSG_CTL_END: 651e2656810Srenato return (1); 652e2656810Srenato default: 653e2656810Srenato break; 654e2656810Srenato } 655e2656810Srenato 656e2656810Srenato return (0); 657e2656810Srenato } 658e2656810Srenato 659e2656810Srenato void 660e2656810Srenato show_fib_head(void) 661e2656810Srenato { 662e2656810Srenato printf("flags: * = valid, D = EIGRP, C = Connected, S = Static\n"); 663e2656810Srenato printf("%-6s %-4s %-20s %-17s\n", "Flags", "Prio", "Destination", 664e2656810Srenato "Nexthop"); 665e2656810Srenato } 666e2656810Srenato 667e2656810Srenato int 668e2656810Srenato show_fib_msg(struct imsg *imsg, struct parse_result *res) 669e2656810Srenato { 670e2656810Srenato struct kroute *k; 671e2656810Srenato char *p; 672e2656810Srenato 673e2656810Srenato switch (imsg->hdr.type) { 674e2656810Srenato case IMSG_CTL_KROUTE: 675e2656810Srenato if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute)) 676e2656810Srenato errx(1, "wrong imsg len"); 677e2656810Srenato k = imsg->data; 678e2656810Srenato 679e2656810Srenato if (res->family != AF_UNSPEC && res->family != k->af) 680e2656810Srenato break; 681e2656810Srenato 682e2656810Srenato if (k->flags & F_DOWN) 683e2656810Srenato printf(" "); 684e2656810Srenato else 685e2656810Srenato printf("*"); 686e2656810Srenato 687e2656810Srenato if (!(k->flags & F_KERNEL)) 688e2656810Srenato printf("D"); 689e2656810Srenato else if (k->flags & F_CONNECTED) 690e2656810Srenato printf("C"); 691e2656810Srenato else if (k->flags & F_STATIC) 692e2656810Srenato printf("S"); 693e2656810Srenato else 694e2656810Srenato printf(" "); 695e2656810Srenato 696e2656810Srenato printf("%-5s", (k->flags & F_CTL_EXTERNAL) ? " EX" : ""); 697e2656810Srenato printf("%4d ", k->priority); 698e2656810Srenato if (asprintf(&p, "%s/%u", log_addr(k->af, &k->prefix), 699e2656810Srenato k->prefixlen) == -1) 700e2656810Srenato err(1, NULL); 701e2656810Srenato printf("%-20s ", p); 702e2656810Srenato if (strlen(p) > 20) 703e2656810Srenato printf("\n%33s", " "); 704e2656810Srenato free(p); 705e2656810Srenato 706e2656810Srenato if (eigrp_addrisset(k->af, &k->nexthop)) { 707e2656810Srenato switch (k->af) { 708e2656810Srenato case AF_INET: 709e2656810Srenato printf("%s", log_addr(k->af, &k->nexthop)); 710e2656810Srenato break; 711e2656810Srenato case AF_INET6: 712e2656810Srenato printf("%s", log_in6addr_scope(&k->nexthop.v6, 713e2656810Srenato k->ifindex)); 714e2656810Srenato break; 715e2656810Srenato default: 716e2656810Srenato break; 717e2656810Srenato } 718e2656810Srenato 719e2656810Srenato } else if (k->flags & F_CONNECTED) 720e2656810Srenato printf("link#%u", k->ifindex); 721e2656810Srenato printf("\n"); 722e2656810Srenato 723e2656810Srenato break; 724e2656810Srenato case IMSG_CTL_END: 725e2656810Srenato printf("\n"); 726e2656810Srenato return (1); 727e2656810Srenato default: 728e2656810Srenato break; 729e2656810Srenato } 730e2656810Srenato 731e2656810Srenato return (0); 732e2656810Srenato } 733e2656810Srenato 734e2656810Srenato void 735e2656810Srenato show_interface_head(void) 736e2656810Srenato { 737e2656810Srenato printf("%-15s%-15s%s\n", "Interface", "Flags", 738e2656810Srenato "Link state"); 739e2656810Srenato } 740e2656810Srenato 741e2656810Srenato const struct if_status_description 742e2656810Srenato if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 743e2656810Srenato const struct ifmedia_description 744e2656810Srenato ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; 745e2656810Srenato 746e2656810Srenato const char * 747e2656810Srenato get_media_descr(uint64_t media_type) 748e2656810Srenato { 749e2656810Srenato const struct ifmedia_description *p; 750e2656810Srenato 751e2656810Srenato for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++) 752e2656810Srenato if (media_type == p->ifmt_word) 753e2656810Srenato return (p->ifmt_string); 754e2656810Srenato 755e2656810Srenato return ("unknown"); 756e2656810Srenato } 757e2656810Srenato 758e2656810Srenato const char * 759e2656810Srenato get_linkstate(uint8_t if_type, int link_state) 760e2656810Srenato { 761e2656810Srenato const struct if_status_description *p; 762e2656810Srenato static char buf[8]; 763e2656810Srenato 764e2656810Srenato for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 765e2656810Srenato if (LINK_STATE_DESC_MATCH(p, if_type, link_state)) 766e2656810Srenato return (p->ifs_string); 767e2656810Srenato } 768e2656810Srenato snprintf(buf, sizeof(buf), "[#%d]", link_state); 769e2656810Srenato return (buf); 770e2656810Srenato } 771e2656810Srenato 772e2656810Srenato void 773e2656810Srenato print_baudrate(uint64_t baudrate) 774e2656810Srenato { 775e2656810Srenato if (baudrate > IF_Gbps(1)) 776e2656810Srenato printf("%llu GBit/s", baudrate / IF_Gbps(1)); 777e2656810Srenato else if (baudrate > IF_Mbps(1)) 778e2656810Srenato printf("%llu MBit/s", baudrate / IF_Mbps(1)); 779e2656810Srenato else if (baudrate > IF_Kbps(1)) 780e2656810Srenato printf("%llu KBit/s", baudrate / IF_Kbps(1)); 781e2656810Srenato else 782e2656810Srenato printf("%llu Bit/s", baudrate); 783e2656810Srenato } 784e2656810Srenato 785e2656810Srenato int 786e2656810Srenato show_fib_interface_msg(struct imsg *imsg) 787e2656810Srenato { 788e2656810Srenato struct kif *k; 789e2656810Srenato uint64_t ifms_type; 790e2656810Srenato 791e2656810Srenato switch (imsg->hdr.type) { 792e2656810Srenato case IMSG_CTL_IFINFO: 793e2656810Srenato if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kif)) 794e2656810Srenato errx(1, "wrong imsg len"); 795e2656810Srenato k = imsg->data; 796e2656810Srenato printf("%-15s", k->ifname); 797e2656810Srenato printf("%-15s", k->flags & IFF_UP ? "UP" : ""); 798e2656810Srenato ifms_type = get_ifms_type(k->if_type); 799e2656810Srenato if (ifms_type) 800e2656810Srenato printf("%s, ", get_media_descr(ifms_type)); 801e2656810Srenato 802e2656810Srenato printf("%s", get_linkstate(k->if_type, k->link_state)); 803e2656810Srenato 804e2656810Srenato if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) { 805e2656810Srenato printf(", "); 806e2656810Srenato print_baudrate(k->baudrate); 807e2656810Srenato } 808e2656810Srenato printf("\n"); 809e2656810Srenato break; 810e2656810Srenato case IMSG_CTL_END: 811e2656810Srenato printf("\n"); 812e2656810Srenato return (1); 813e2656810Srenato default: 814e2656810Srenato break; 815e2656810Srenato } 816e2656810Srenato 817e2656810Srenato return (0); 818e2656810Srenato } 819dcfaa8d4Srenato 820dcfaa8d4Srenato int 821dcfaa8d4Srenato show_stats_msg(struct imsg *imsg, struct parse_result *res) 822dcfaa8d4Srenato { 823dcfaa8d4Srenato struct ctl_stats *cs; 824dcfaa8d4Srenato 825dcfaa8d4Srenato switch (imsg->hdr.type) { 826dcfaa8d4Srenato case IMSG_CTL_SHOW_STATS: 827dcfaa8d4Srenato if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_stats)) 828dcfaa8d4Srenato errx(1, "wrong imsg len"); 829dcfaa8d4Srenato cs = imsg->data; 830dcfaa8d4Srenato 831dcfaa8d4Srenato if (res->family != AF_UNSPEC && res->family != cs->af) 832dcfaa8d4Srenato break; 833dcfaa8d4Srenato if (res->as != 0 && res->as != cs->as) 834dcfaa8d4Srenato break; 835dcfaa8d4Srenato 836dcfaa8d4Srenato printf("Address Family %s, Autonomous System %u\n", 837dcfaa8d4Srenato af_name(cs->af), cs->as); 838dcfaa8d4Srenato printf(" Hellos sent/received: %u/%u\n", 839dcfaa8d4Srenato cs->stats.hellos_sent, cs->stats.hellos_recv); 840dcfaa8d4Srenato printf(" Updates sent/received: %u/%u\n", 841dcfaa8d4Srenato cs->stats.updates_sent, cs->stats.updates_recv); 842dcfaa8d4Srenato printf(" Queries sent/received: %u/%u\n", 843dcfaa8d4Srenato cs->stats.queries_sent, cs->stats.queries_recv); 844dcfaa8d4Srenato printf(" Replies sent/received: %u/%u\n", 845dcfaa8d4Srenato cs->stats.replies_sent, cs->stats.replies_recv); 846dcfaa8d4Srenato printf(" Acks sent/received: %u/%u\n", 847dcfaa8d4Srenato cs->stats.acks_sent, cs->stats.acks_recv); 848dcfaa8d4Srenato printf(" SIA-Queries sent/received: %u/%u\n", 849dcfaa8d4Srenato cs->stats.squeries_sent, cs->stats.squeries_recv); 850dcfaa8d4Srenato printf(" SIA-Replies sent/received: %u/%u\n", 851dcfaa8d4Srenato cs->stats.sreplies_sent, cs->stats.sreplies_recv); 852dcfaa8d4Srenato break; 853dcfaa8d4Srenato case IMSG_CTL_END: 854dcfaa8d4Srenato printf("\n"); 855dcfaa8d4Srenato return (1); 856dcfaa8d4Srenato default: 857dcfaa8d4Srenato break; 858dcfaa8d4Srenato } 859dcfaa8d4Srenato 860dcfaa8d4Srenato return (0); 861dcfaa8d4Srenato } 862