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