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