eigrpctl.c revision 1.9
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);
45uint64_t	 get_ifms_type(uint8_t);
46int		 show_interface_msg(struct imsg *, struct parse_result *);
47int		 show_interface_detail_msg(struct imsg *,
48    struct parse_result *);
49const char	*print_link(int);
50const char	*fmt_timeframe_core(time_t);
51int		 show_nbr_msg(struct imsg *, struct parse_result *);
52int		 show_topology_msg(struct imsg *, struct parse_result *);
53int		 show_topology_detail_msg(struct imsg *,
54    struct parse_result *);
55void		 show_fib_head(void);
56int		 show_fib_msg(struct imsg *, struct parse_result *);
57void		 show_interface_head(void);
58const char *	 get_media_descr(uint64_t);
59const char *	 get_linkstate(uint8_t, int);
60void		 print_baudrate(uint64_t);
61int		 show_fib_interface_msg(struct imsg *);
62int		 show_stats_msg(struct imsg *, struct parse_result *);
63
64struct imsgbuf	*ibuf;
65
66__dead void
67usage(void)
68{
69	extern char *__progname;
70
71	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
72	    __progname);
73	exit(1);
74}
75
76int
77main(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
281uint64_t
282get_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
298int
299show_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
339int
340show_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
389const char *
390print_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
401const char *
402fmt_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
438int
439show_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
473static int
474connected_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
492int
493show_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
558int
559show_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
659void
660show_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
667int
668show_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
734void
735show_interface_head(void)
736{
737	printf("%-15s%-15s%s\n", "Interface", "Flags",
738	    "Link state");
739}
740
741const struct if_status_description
742		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
743const struct ifmedia_description
744		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
745
746const char *
747get_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
758const char *
759get_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
772void
773print_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
785int
786show_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
820int
821show_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