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