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