eigrpctl.c revision 1.8
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);
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 command [argument ...]\n", __progname);
72	exit(1);
73}
74
75int
76main(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
264uint64_t
265get_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
281int
282show_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
322int
323show_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
372const char *
373print_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
384const char *
385fmt_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
421int
422show_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
456static int
457connected_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
475int
476show_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
541int
542show_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
642void
643show_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
650int
651show_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
717void
718show_interface_head(void)
719{
720	printf("%-15s%-15s%s\n", "Interface", "Flags",
721	    "Link state");
722}
723
724const struct if_status_description
725		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
726const struct ifmedia_description
727		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
728
729const char *
730get_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
741const char *
742get_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
755void
756print_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
768int
769show_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
803int
804show_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