xref: /openbsd-src/usr.sbin/ripctl/ripctl.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: ripctl.c,v 1.22 2024/11/21 13:38:15 claudio Exp $
28eeeb81eSnorby  *
38eeeb81eSnorby  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
48eeeb81eSnorby  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
58eeeb81eSnorby  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
68eeeb81eSnorby  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
78eeeb81eSnorby  *
88eeeb81eSnorby  * Permission to use, copy, modify, and distribute this software for any
98eeeb81eSnorby  * purpose with or without fee is hereby granted, provided that the above
108eeeb81eSnorby  * copyright notice and this permission notice appear in all copies.
118eeeb81eSnorby  *
128eeeb81eSnorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
138eeeb81eSnorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
148eeeb81eSnorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
158eeeb81eSnorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
168eeeb81eSnorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
178eeeb81eSnorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
188eeeb81eSnorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
198eeeb81eSnorby  */
208eeeb81eSnorby 
218eeeb81eSnorby #include <sys/types.h>
228eeeb81eSnorby #include <sys/socket.h>
238eeeb81eSnorby #include <sys/un.h>
248eeeb81eSnorby #include <netinet/in.h>
258eeeb81eSnorby #include <arpa/inet.h>
268eeeb81eSnorby #include <net/if_media.h>
278eeeb81eSnorby #include <net/if_types.h>
288eeeb81eSnorby 
298eeeb81eSnorby #include <err.h>
30397afdbcSderaadt #include <errno.h>
318eeeb81eSnorby #include <stdio.h>
328eeeb81eSnorby #include <stdlib.h>
338eeeb81eSnorby #include <string.h>
348eeeb81eSnorby #include <unistd.h>
358eeeb81eSnorby 
368eeeb81eSnorby #include "rip.h"
378eeeb81eSnorby #include "ripd.h"
388eeeb81eSnorby #include "ripe.h"
398eeeb81eSnorby #include "parser.h"
408eeeb81eSnorby 
418eeeb81eSnorby __dead void	 usage(void);
428eeeb81eSnorby const char	*fmt_timeframe_core(time_t);
4316530d00Sstsp const char	*get_linkstate(uint8_t, int);
448eeeb81eSnorby int		 show_interface_msg(struct imsg *);
4516530d00Sstsp uint64_t	 get_ifms_type(uint8_t);
468eeeb81eSnorby int		 show_rib_msg(struct imsg *);
478eeeb81eSnorby int		 show_nbr_msg(struct imsg *);
488eeeb81eSnorby void		 show_fib_head(void);
498eeeb81eSnorby int		 show_fib_msg(struct imsg *);
508eeeb81eSnorby void		 show_interface_head(void);
518eeeb81eSnorby int		 show_fib_interface_msg(struct imsg *);
52e5605ae3Sderaadt const char	*get_media_descr(uint64_t);
5316530d00Sstsp void		 print_baudrate(uint64_t);
548eeeb81eSnorby 
558eeeb81eSnorby struct imsgbuf	*ibuf;
568eeeb81eSnorby 
578eeeb81eSnorby __dead void
588eeeb81eSnorby usage(void)
598eeeb81eSnorby {
608eeeb81eSnorby 	extern char *__progname;
618eeeb81eSnorby 
623dabc796Sjca 	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
633dabc796Sjca 	    __progname);
648eeeb81eSnorby 	exit(1);
658eeeb81eSnorby }
668eeeb81eSnorby 
678eeeb81eSnorby int
688eeeb81eSnorby main(int argc, char *argv[])
698eeeb81eSnorby {
708eeeb81eSnorby 	struct sockaddr_un	 sun;
718eeeb81eSnorby 	struct parse_result	*res;
728eeeb81eSnorby 	struct imsg		 imsg;
738eeeb81eSnorby 	unsigned int		 ifidx = 0;
748eeeb81eSnorby 	int			 ctl_sock;
75c3319070Sclaudio 	int			 done = 0, verbose = 0;
768eeeb81eSnorby 	int			 n;
773dabc796Sjca 	int			 ch;
783dabc796Sjca 	char			*sockname = RIPD_SOCKET;
793dabc796Sjca 
803dabc796Sjca 	while ((ch = getopt(argc, argv, "s:")) != -1) {
813dabc796Sjca 		switch (ch) {
823dabc796Sjca 		case 's':
833dabc796Sjca 			sockname = optarg;
843dabc796Sjca 			break;
853dabc796Sjca 		default:
863dabc796Sjca 			usage();
873dabc796Sjca 			/* NOTREACHED */
883dabc796Sjca 		}
893dabc796Sjca 	}
903dabc796Sjca 
913dabc796Sjca 	argc -= optind;
923dabc796Sjca 	argv += optind;
938eeeb81eSnorby 
948eeeb81eSnorby 	/* parse options */
953dabc796Sjca 	if ((res = parse(argc, argv)) == NULL)
968eeeb81eSnorby 		exit(1);
978eeeb81eSnorby 
988eeeb81eSnorby 	/* connect to ripd control socket */
998eeeb81eSnorby 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
1008eeeb81eSnorby 		err(1, "socket");
1018eeeb81eSnorby 
1028eeeb81eSnorby 	bzero(&sun, sizeof(sun));
1038eeeb81eSnorby 	sun.sun_family = AF_UNIX;
1043dabc796Sjca 	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
1058eeeb81eSnorby 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
1063dabc796Sjca 		err(1, "connect: %s", sockname);
1078eeeb81eSnorby 
1084ca91f07Sderaadt 	if (pledge("stdio", NULL) == -1)
1094ca91f07Sderaadt 		err(1, "pledge");
1104ca91f07Sderaadt 
1118eeeb81eSnorby 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
1128eeeb81eSnorby 		err(1, NULL);
113*f1b790a5Sclaudio 	if (imsgbuf_init(ibuf, ctl_sock) == -1)
114*f1b790a5Sclaudio 		err(1, NULL);
1158eeeb81eSnorby 	done = 0;
1168eeeb81eSnorby 
1178eeeb81eSnorby 	/* process user request */
1188eeeb81eSnorby 	switch (res->action) {
1198eeeb81eSnorby 	case NONE:
1208eeeb81eSnorby 		usage();
1218eeeb81eSnorby 		/* not reached */
1228eeeb81eSnorby 	case SHOW:
1238eeeb81eSnorby 	case SHOW_IFACE:
1248eeeb81eSnorby 		printf("%-11s %-18s %-10s %-10s %-8s\n",
1258eeeb81eSnorby 		    "Interface", "Address", "State", "Linkstate",
1268eeeb81eSnorby 		    "Uptime");
1278eeeb81eSnorby 		if (*res->ifname) {
1288eeeb81eSnorby 			ifidx = if_nametoindex(res->ifname);
1298eeeb81eSnorby 			if (ifidx == 0)
1308eeeb81eSnorby 				errx(1, "no such interface %s", res->ifname);
1318eeeb81eSnorby 		}
132f7ce36daSeric 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
1338eeeb81eSnorby 		    &ifidx, sizeof(ifidx));
1348eeeb81eSnorby 		break;
1358eeeb81eSnorby 	case SHOW_NBR:
1368eeeb81eSnorby 		printf("%-15s %-15s %-15s %-9s %-10s\n", "ID",
1378eeeb81eSnorby 		    "State", "Address", "Iface", "Uptime");
138f7ce36daSeric 		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
1398eeeb81eSnorby 		break;
1408eeeb81eSnorby 	case SHOW_RIB:
1418eeeb81eSnorby 		printf("%-20s %-17s %-7s\n", "Destination",
1428eeeb81eSnorby 		    "Nexthop", "Cost");
143f7ce36daSeric 		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0);
1448eeeb81eSnorby 		break;
1458eeeb81eSnorby 	case SHOW_FIB:
1468eeeb81eSnorby 		if (!res->addr.s_addr)
147f7ce36daSeric 			imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
1488eeeb81eSnorby 			    &res->flags, sizeof(res->flags));
1498eeeb81eSnorby 		else
150f7ce36daSeric 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
1518eeeb81eSnorby 			    &res->addr, sizeof(res->addr));
1528eeeb81eSnorby 		show_fib_head();
1538eeeb81eSnorby 		break;
1548eeeb81eSnorby 	case SHOW_FIB_IFACE:
1558eeeb81eSnorby 		if (*res->ifname)
156f7ce36daSeric 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
1578eeeb81eSnorby 			    res->ifname, sizeof(res->ifname));
1588eeeb81eSnorby 		else
159f7ce36daSeric 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
1608eeeb81eSnorby 		show_interface_head();
1618eeeb81eSnorby 		break;
1628eeeb81eSnorby 	case FIB:
1638eeeb81eSnorby 		errx(1, "fib couple|decouple");
1648eeeb81eSnorby 		break;
1658eeeb81eSnorby 	case FIB_COUPLE:
166f7ce36daSeric 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
1678eeeb81eSnorby 		printf("couple request sent.\n");
1688eeeb81eSnorby 		done = 1;
1698eeeb81eSnorby 		break;
1708eeeb81eSnorby 	case FIB_DECOUPLE:
171f7ce36daSeric 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
1728eeeb81eSnorby 		printf("decouple request sent.\n");
1738eeeb81eSnorby 		done = 1;
1748eeeb81eSnorby 		break;
175c3319070Sclaudio 	case LOG_VERBOSE:
176c3319070Sclaudio 		verbose = 1;
177c3319070Sclaudio 		/* FALLTHROUGH */
178c3319070Sclaudio 	case LOG_BRIEF:
179c3319070Sclaudio 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
180c3319070Sclaudio 		    &verbose, sizeof(verbose));
181c3319070Sclaudio 		printf("logging request sent.\n");
182c3319070Sclaudio 		done = 1;
183c3319070Sclaudio 		break;
1848eeeb81eSnorby 	case RELOAD:
185f7ce36daSeric 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
1868eeeb81eSnorby 		printf("reload request sent.\n");
1878eeeb81eSnorby 		done = 1;
1888eeeb81eSnorby 		break;
1898eeeb81eSnorby 	}
1908eeeb81eSnorby 
191dd7efffeSclaudio 	if (imsgbuf_flush(ibuf) == -1)
1928eeeb81eSnorby 		err(1, "write error");
1938eeeb81eSnorby 
1948eeeb81eSnorby 	while (!done) {
195668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
196ef2e27a1Sclaudio 			err(1, "read error");
1978eeeb81eSnorby 		if (n == 0)
1988eeeb81eSnorby 			errx(1, "pipe closed");
1998eeeb81eSnorby 
2008eeeb81eSnorby 		while (!done) {
2018eeeb81eSnorby 			if ((n = imsg_get(ibuf, &imsg)) == -1)
2028eeeb81eSnorby 				errx(1, "imsg_get error");
2038eeeb81eSnorby 			if (n == 0)
2048eeeb81eSnorby 				break;
2058eeeb81eSnorby 			switch (res->action) {
2068eeeb81eSnorby 			case SHOW:
2078eeeb81eSnorby 			case SHOW_IFACE:
2088eeeb81eSnorby 				done = show_interface_msg(&imsg);
2098eeeb81eSnorby 				break;
2108eeeb81eSnorby 			case SHOW_NBR:
2118eeeb81eSnorby 				done = show_nbr_msg(&imsg);
2128eeeb81eSnorby 				break;
2138eeeb81eSnorby 			case SHOW_RIB:
2148eeeb81eSnorby 				done = show_rib_msg(&imsg);
2158eeeb81eSnorby 				break;
2168eeeb81eSnorby 			case SHOW_FIB:
2178eeeb81eSnorby 				done = show_fib_msg(&imsg);
2188eeeb81eSnorby 				break;
2198eeeb81eSnorby 			case SHOW_FIB_IFACE:
2208eeeb81eSnorby 				done = show_fib_interface_msg(&imsg);
2218eeeb81eSnorby 				break;
2228eeeb81eSnorby 			case NONE:
2238eeeb81eSnorby 			case FIB:
2248eeeb81eSnorby 			case FIB_COUPLE:
2258eeeb81eSnorby 			case FIB_DECOUPLE:
226c3319070Sclaudio 			case LOG_VERBOSE:
227c3319070Sclaudio 			case LOG_BRIEF:
2288eeeb81eSnorby 			case RELOAD:
2298eeeb81eSnorby 				break;
2308eeeb81eSnorby 			}
2318eeeb81eSnorby 			imsg_free(&imsg);
2328eeeb81eSnorby 		}
2338eeeb81eSnorby 	}
2348eeeb81eSnorby 	close(ctl_sock);
2358eeeb81eSnorby 	free(ibuf);
2368eeeb81eSnorby 
2378eeeb81eSnorby 	return (0);
2388eeeb81eSnorby }
2398eeeb81eSnorby 
24016530d00Sstsp uint64_t
24116530d00Sstsp get_ifms_type(uint8_t if_type)
2428eeeb81eSnorby {
24316530d00Sstsp 	switch (if_type) {
2448eeeb81eSnorby 	case IFT_ETHER:
2458eeeb81eSnorby 		return (IFM_ETHER);
2468eeeb81eSnorby 		break;
2478eeeb81eSnorby 	case IFT_FDDI:
2488eeeb81eSnorby 		return (IFM_FDDI);
2498eeeb81eSnorby 		break;
2508eeeb81eSnorby 	case IFT_CARP:
2518eeeb81eSnorby 		return (IFM_CARP);
2528eeeb81eSnorby 		break;
2538eeeb81eSnorby 	default:
2548eeeb81eSnorby 		return (0);
2558eeeb81eSnorby 		break;
2568eeeb81eSnorby 	}
2578eeeb81eSnorby }
2588eeeb81eSnorby 
2598eeeb81eSnorby #define	TF_BUFS	8
2608eeeb81eSnorby #define	TF_LEN	9
2618eeeb81eSnorby 
2628eeeb81eSnorby const char *
2638eeeb81eSnorby fmt_timeframe_core(time_t t)
2648eeeb81eSnorby {
2658eeeb81eSnorby 	char		*buf;
2668eeeb81eSnorby 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
2678eeeb81eSnorby 	static int	 idx = 0;
268035b0708Sgilles 	unsigned int	 sec, min, hrs, day;
269035b0708Sgilles 	unsigned long long	week;
2708eeeb81eSnorby 
2718eeeb81eSnorby 	if (t == 0)
2728eeeb81eSnorby 		return ("Stopped");
2738eeeb81eSnorby 
2748eeeb81eSnorby 	buf = tfbuf[idx++];
2758eeeb81eSnorby 	if (idx == TF_BUFS)
2768eeeb81eSnorby 		idx = 0;
2778eeeb81eSnorby 
2788eeeb81eSnorby 	week = t;
2798eeeb81eSnorby 
2808eeeb81eSnorby 	sec = week % 60;
2818eeeb81eSnorby 	week /= 60;
2828eeeb81eSnorby 	min = week % 60;
2838eeeb81eSnorby 	week /= 60;
2848eeeb81eSnorby 	hrs = week % 24;
2858eeeb81eSnorby 	week /= 24;
2868eeeb81eSnorby 	day = week % 7;
2878eeeb81eSnorby 	week /= 7;
2888eeeb81eSnorby 
2898eeeb81eSnorby 	if (week > 0)
290035b0708Sgilles 		snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
2918eeeb81eSnorby 	else if (day > 0)
2928eeeb81eSnorby 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
2938eeeb81eSnorby 	else
2948eeeb81eSnorby 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
2958eeeb81eSnorby 
2968eeeb81eSnorby 	return (buf);
2978eeeb81eSnorby }
2988eeeb81eSnorby 
2998eeeb81eSnorby /* prototype defined in ripd.h and shared with the kroute.c version */
3008eeeb81eSnorby u_int8_t
3018eeeb81eSnorby mask2prefixlen(in_addr_t ina)
3028eeeb81eSnorby {
3038eeeb81eSnorby 	if (ina == 0)
3048eeeb81eSnorby 		return (0);
3058eeeb81eSnorby 	else
3068eeeb81eSnorby 		return (33 - ffs(ntohl(ina)));
3078eeeb81eSnorby }
3088eeeb81eSnorby 
3098eeeb81eSnorby int
3108eeeb81eSnorby show_interface_msg(struct imsg *imsg)
3118eeeb81eSnorby {
3128eeeb81eSnorby 	struct ctl_iface	*iface;
3138eeeb81eSnorby 	char			*netid;
3148eeeb81eSnorby 
3158eeeb81eSnorby 	switch (imsg->hdr.type) {
3168eeeb81eSnorby 	case IMSG_CTL_SHOW_IFACE:
3178eeeb81eSnorby 		iface = imsg->data;
3188eeeb81eSnorby 
3198eeeb81eSnorby 		if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr),
3208eeeb81eSnorby 		    mask2prefixlen(iface->mask.s_addr)) == -1)
3218eeeb81eSnorby 			err(1, NULL);
3228eeeb81eSnorby 		printf("%-11s %-18s %-10s %-10s %-8s\n",
3238eeeb81eSnorby 		    iface->name, netid, if_state_name(iface->state),
32416530d00Sstsp 		    get_linkstate(iface->if_type, iface->linkstate),
3250f617141Sclaudio 		    iface->uptime == 0 ? "00:00:00" :
3268eeeb81eSnorby 		    fmt_timeframe_core(iface->uptime));
3278eeeb81eSnorby 		free(netid);
3288eeeb81eSnorby 		break;
3298eeeb81eSnorby 	case IMSG_CTL_END:
3308eeeb81eSnorby 		printf("\n");
3318eeeb81eSnorby 		return (1);
3328eeeb81eSnorby 	default:
3338eeeb81eSnorby 		break;
3348eeeb81eSnorby 	}
3358eeeb81eSnorby 
3368eeeb81eSnorby 	return (0);
3378eeeb81eSnorby }
3388eeeb81eSnorby 
3398eeeb81eSnorby int
3408eeeb81eSnorby show_rib_msg(struct imsg *imsg)
3418eeeb81eSnorby {
3428eeeb81eSnorby 	struct ctl_rt	*rt;
3438eeeb81eSnorby 	char		*dstnet;
3448eeeb81eSnorby 
3458eeeb81eSnorby 	switch (imsg->hdr.type) {
3468eeeb81eSnorby 	case IMSG_CTL_SHOW_RIB:
3478eeeb81eSnorby 		rt = imsg->data;
3488eeeb81eSnorby 		if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix),
3498eeeb81eSnorby 		    mask2prefixlen(rt->netmask.s_addr)) == -1)
3508eeeb81eSnorby 			err(1, NULL);
3518eeeb81eSnorby 
3528eeeb81eSnorby 		printf("%-20s %-17s %-7d\n", dstnet,
3538eeeb81eSnorby 		    inet_ntoa(rt->nexthop),
3548eeeb81eSnorby 		    rt->metric);
3558eeeb81eSnorby 		free(dstnet);
3568eeeb81eSnorby 
3578eeeb81eSnorby 		break;
3588eeeb81eSnorby 	case IMSG_CTL_END:
3598eeeb81eSnorby 		printf("\n");
3608eeeb81eSnorby 		return (1);
3618eeeb81eSnorby 	default:
3628eeeb81eSnorby 		break;
3638eeeb81eSnorby 	}
3648eeeb81eSnorby 
3658eeeb81eSnorby 	return (0);
3668eeeb81eSnorby }
3678eeeb81eSnorby 
3688eeeb81eSnorby int
3698eeeb81eSnorby show_nbr_msg(struct imsg *imsg)
3708eeeb81eSnorby {
3718eeeb81eSnorby 	struct ctl_nbr	*nbr;
3728eeeb81eSnorby 	char		*state;
3738eeeb81eSnorby 
3748eeeb81eSnorby 	switch (imsg->hdr.type) {
3758eeeb81eSnorby 	case IMSG_CTL_SHOW_NBR:
3768eeeb81eSnorby 		nbr = imsg->data;
3778eeeb81eSnorby 		if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state),
3788eeeb81eSnorby 		    if_state_name(nbr->iface_state)) == -1)
3798eeeb81eSnorby 			err(1, NULL);
3808eeeb81eSnorby 		printf("%-15s %-16s", inet_ntoa(nbr->id),
3818eeeb81eSnorby 		    state);
3828eeeb81eSnorby 		printf("%-15s %-10s", inet_ntoa(nbr->addr), nbr->name);
3838eeeb81eSnorby 		printf("%-15s\n", nbr->uptime == 0 ? "-" :
3848eeeb81eSnorby 		    fmt_timeframe_core(nbr->uptime));
3858eeeb81eSnorby 		free(state);
3868eeeb81eSnorby 		break;
3878eeeb81eSnorby 	case IMSG_CTL_END:
3888eeeb81eSnorby 		printf("\n");
3898eeeb81eSnorby 		return (1);
3908eeeb81eSnorby 	default:
3918eeeb81eSnorby 		break;
3928eeeb81eSnorby 	}
3938eeeb81eSnorby 
3948eeeb81eSnorby 	return (0);
3958eeeb81eSnorby }
3968eeeb81eSnorby 
3978eeeb81eSnorby void
3988eeeb81eSnorby show_fib_head(void)
3998eeeb81eSnorby {
4008eeeb81eSnorby 	printf("flags: * = valid, R = RIP, C = Connected, S = Static\n");
4018eeeb81eSnorby 	printf("%-6s %-20s %-17s\n", "Flags", "Destination", "Nexthop");
4028eeeb81eSnorby }
4038eeeb81eSnorby 
4048eeeb81eSnorby int
4058eeeb81eSnorby show_fib_msg(struct imsg *imsg)
4068eeeb81eSnorby {
4078eeeb81eSnorby 	struct kroute		*k;
4088eeeb81eSnorby 	char			*p;
4098eeeb81eSnorby 
4108eeeb81eSnorby 	switch (imsg->hdr.type) {
4118eeeb81eSnorby 	case IMSG_CTL_KROUTE:
4128eeeb81eSnorby 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
4138eeeb81eSnorby 			errx(1, "wrong imsg len");
4148eeeb81eSnorby 		k = imsg->data;
4158eeeb81eSnorby 
4168eeeb81eSnorby 		if (k->flags & F_DOWN)
4178eeeb81eSnorby 			printf(" ");
4188eeeb81eSnorby 		else
4198eeeb81eSnorby 			printf("*");
4208eeeb81eSnorby 
42174ae440cSmichele 		if (k->flags & F_RIPD_INSERTED)
4228eeeb81eSnorby 			printf("R");
4238eeeb81eSnorby 		else if (k->flags & F_CONNECTED)
4248eeeb81eSnorby 			printf("C");
4258eeeb81eSnorby 		else if (k->flags & F_STATIC)
4268eeeb81eSnorby 			printf("S");
4278eeeb81eSnorby 		else
4288eeeb81eSnorby 			printf(" ");
4298eeeb81eSnorby 
4308eeeb81eSnorby 		printf("     ");
4318eeeb81eSnorby 		if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix),
4328eeeb81eSnorby 		    mask2prefixlen(k->netmask.s_addr)) == -1)
4338eeeb81eSnorby 			err(1, NULL);
4348eeeb81eSnorby 		printf("%-20s ", p);
4358eeeb81eSnorby 		free(p);
4368eeeb81eSnorby 
4378eeeb81eSnorby 		if (k->nexthop.s_addr)
4388eeeb81eSnorby 			printf("%s", inet_ntoa(k->nexthop));
4398eeeb81eSnorby 		else if (k->flags & F_CONNECTED)
4408eeeb81eSnorby 			printf("link#%u", k->ifindex);
4418eeeb81eSnorby 		printf("\n");
4428eeeb81eSnorby 
4438eeeb81eSnorby 		break;
4448eeeb81eSnorby 	case IMSG_CTL_END:
4458eeeb81eSnorby 		printf("\n");
4468eeeb81eSnorby 		return (1);
4478eeeb81eSnorby 	default:
4488eeeb81eSnorby 		break;
4498eeeb81eSnorby 	}
4508eeeb81eSnorby 
4518eeeb81eSnorby 	return (0);
4528eeeb81eSnorby }
4538eeeb81eSnorby 
4548eeeb81eSnorby void
4558eeeb81eSnorby show_interface_head(void)
4568eeeb81eSnorby {
4578eeeb81eSnorby 	printf("%-15s%-15s%s\n", "Interface", "Flags",
4588eeeb81eSnorby 	    "Link state");
4598eeeb81eSnorby }
4608eeeb81eSnorby 
4618eeeb81eSnorby int
4628eeeb81eSnorby show_fib_interface_msg(struct imsg *imsg)
4638eeeb81eSnorby {
4648eeeb81eSnorby 	struct kif	*k;
46516530d00Sstsp 	uint64_t	 ifms_type;
4668eeeb81eSnorby 
4678eeeb81eSnorby 	switch (imsg->hdr.type) {
4688eeeb81eSnorby 	case IMSG_CTL_IFINFO:
4698eeeb81eSnorby 		k = imsg->data;
4708eeeb81eSnorby 		printf("%-15s", k->ifname);
4718eeeb81eSnorby 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
47216530d00Sstsp 		ifms_type = get_ifms_type(k->if_type);
4738eeeb81eSnorby 		if (ifms_type)
4740f617141Sclaudio 			printf("%s, ", get_media_descr(ifms_type));
4750f617141Sclaudio 
47616530d00Sstsp 		printf("%s", get_linkstate(k->if_type, k->link_state));
4778eeeb81eSnorby 
4788eeeb81eSnorby 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
4798eeeb81eSnorby 			printf(", ");
4808eeeb81eSnorby 			print_baudrate(k->baudrate);
4818eeeb81eSnorby 		}
4828eeeb81eSnorby 		printf("\n");
4838eeeb81eSnorby 		break;
4848eeeb81eSnorby 	case IMSG_CTL_END:
4858eeeb81eSnorby 		printf("\n");
4868eeeb81eSnorby 		return (1);
4878eeeb81eSnorby 	default:
4888eeeb81eSnorby 		break;
4898eeeb81eSnorby 	}
4908eeeb81eSnorby 
4918eeeb81eSnorby 	return (0);
4928eeeb81eSnorby }
4938eeeb81eSnorby 
4940f617141Sclaudio const struct if_status_description
4950f617141Sclaudio 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
4968eeeb81eSnorby const struct ifmedia_description
4978eeeb81eSnorby 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
4988eeeb81eSnorby 
4998eeeb81eSnorby const char *
500e5605ae3Sderaadt get_media_descr(uint64_t media_type)
5018eeeb81eSnorby {
5028eeeb81eSnorby 	const struct ifmedia_description	*p;
5038eeeb81eSnorby 
5048eeeb81eSnorby 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
5058eeeb81eSnorby 		if (media_type == p->ifmt_word)
5068eeeb81eSnorby 			return (p->ifmt_string);
5078eeeb81eSnorby 
5088eeeb81eSnorby 	return ("unknown");
5098eeeb81eSnorby }
5108eeeb81eSnorby 
5118eeeb81eSnorby const char *
51216530d00Sstsp get_linkstate(uint8_t if_type, int link_state)
5138eeeb81eSnorby {
5140f617141Sclaudio 	const struct if_status_description *p;
5150f617141Sclaudio 	static char buf[8];
5168eeeb81eSnorby 
5170f617141Sclaudio 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
51816530d00Sstsp 		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
5190f617141Sclaudio 			return (p->ifs_string);
5208eeeb81eSnorby 	}
5210f617141Sclaudio 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
5220f617141Sclaudio 	return (buf);
5238eeeb81eSnorby }
5248eeeb81eSnorby 
5258eeeb81eSnorby void
52616530d00Sstsp print_baudrate(uint64_t baudrate)
5278eeeb81eSnorby {
5288eeeb81eSnorby 	if (baudrate > IF_Gbps(1))
52929e85e71Shenning 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
5308eeeb81eSnorby 	else if (baudrate > IF_Mbps(1))
53129e85e71Shenning 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
5328eeeb81eSnorby 	else if (baudrate > IF_Kbps(1))
53329e85e71Shenning 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
5348eeeb81eSnorby 	else
53529e85e71Shenning 		printf("%llu Bit/s", baudrate);
5368eeeb81eSnorby }
537