xref: /openbsd-src/usr.sbin/eigrpctl/eigrpctl.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: eigrpctl.c,v 1.14 2024/11/21 13:38:14 claudio Exp $ */
2e2656810Srenato 
3e2656810Srenato /*
4e2656810Srenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5e2656810Srenato  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6e2656810Srenato  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7e2656810Srenato  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
8e2656810Srenato  *
9e2656810Srenato  * Permission to use, copy, modify, and distribute this software for any
10e2656810Srenato  * purpose with or without fee is hereby granted, provided that the above
11e2656810Srenato  * copyright notice and this permission notice appear in all copies.
12e2656810Srenato  *
13e2656810Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14e2656810Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15e2656810Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16e2656810Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17e2656810Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18e2656810Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19e2656810Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20e2656810Srenato  */
21e2656810Srenato 
22e2656810Srenato #include <sys/types.h>
23e2656810Srenato #include <sys/socket.h>
24e2656810Srenato #include <sys/un.h>
25e2656810Srenato #include <netinet/in.h>
26e2656810Srenato #include <arpa/inet.h>
27e2656810Srenato #include <net/if_media.h>
28e2656810Srenato #include <net/if_types.h>
29e2656810Srenato 
30e2656810Srenato #include <err.h>
31e2656810Srenato #include <errno.h>
32e2656810Srenato #include <stdio.h>
33e2656810Srenato #include <stdlib.h>
34e2656810Srenato #include <string.h>
35e2656810Srenato #include <unistd.h>
36e2656810Srenato 
37e2656810Srenato #include "eigrp.h"
38e2656810Srenato #include "eigrpd.h"
39e2656810Srenato #include "eigrpe.h"
40e2656810Srenato #include "rde.h"
41e2656810Srenato #include "log.h"
42e2656810Srenato #include "parser.h"
43e2656810Srenato 
44e2656810Srenato __dead void	 usage(void);
45e2656810Srenato uint64_t	 get_ifms_type(uint8_t);
46e2656810Srenato int		 show_interface_msg(struct imsg *, struct parse_result *);
47e2656810Srenato int		 show_interface_detail_msg(struct imsg *,
48e2656810Srenato     struct parse_result *);
49e2656810Srenato const char	*print_link(int);
50e2656810Srenato const char	*fmt_timeframe_core(time_t);
51e2656810Srenato int		 show_nbr_msg(struct imsg *, struct parse_result *);
52e2656810Srenato int		 show_topology_msg(struct imsg *, struct parse_result *);
53e2656810Srenato int		 show_topology_detail_msg(struct imsg *,
54e2656810Srenato     struct parse_result *);
55e2656810Srenato void		 show_fib_head(void);
56e2656810Srenato int		 show_fib_msg(struct imsg *, struct parse_result *);
57e2656810Srenato void		 show_interface_head(void);
58e2656810Srenato const char *	 get_media_descr(uint64_t);
59e2656810Srenato const char *	 get_linkstate(uint8_t, int);
60e2656810Srenato void		 print_baudrate(uint64_t);
61e2656810Srenato int		 show_fib_interface_msg(struct imsg *);
62dcfaa8d4Srenato int		 show_stats_msg(struct imsg *, struct parse_result *);
63e2656810Srenato 
64e2656810Srenato struct imsgbuf	*ibuf;
65e2656810Srenato 
66e2656810Srenato __dead void
67e2656810Srenato usage(void)
68e2656810Srenato {
69e2656810Srenato 	extern char *__progname;
70e2656810Srenato 
7128291a98Srenato 	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
7228291a98Srenato 	    __progname);
73e2656810Srenato 	exit(1);
74e2656810Srenato }
75e2656810Srenato 
76e2656810Srenato int
77e2656810Srenato main(int argc, char *argv[])
78e2656810Srenato {
79e2656810Srenato 	struct sockaddr_un		 sun;
80e2656810Srenato 	struct parse_result		*res;
81e2656810Srenato 	struct imsg			 imsg;
82e2656810Srenato 	unsigned int			 ifidx = 0;
83e2656810Srenato 	int				 ctl_sock;
84e2656810Srenato 	int				 done = 0;
85e2656810Srenato 	int				 n, verbose = 0;
8628291a98Srenato 	int				 ch;
8728291a98Srenato 	char				*sockname;
88e2656810Srenato 	struct ctl_show_topology_req	 treq;
89956c66a0Srenato 	struct ctl_nbr			 nbr;
90e2656810Srenato 
9128291a98Srenato 	sockname = EIGRPD_SOCKET;
9228291a98Srenato 	while ((ch = getopt(argc, argv, "s:")) != -1) {
9328291a98Srenato 		switch (ch) {
9428291a98Srenato 		case 's':
9528291a98Srenato 			sockname = optarg;
9628291a98Srenato 			break;
9728291a98Srenato 		default:
9828291a98Srenato 			usage();
9928291a98Srenato 			/* NOTREACHED */
10028291a98Srenato 		}
10128291a98Srenato 	}
10228291a98Srenato 	argc -= optind;
10328291a98Srenato 	argv += optind;
10428291a98Srenato 
105e2656810Srenato 	/* parse options */
10628291a98Srenato 	if ((res = parse(argc, argv)) == NULL)
107e2656810Srenato 		exit(1);
108e2656810Srenato 
109e2656810Srenato 	/* connect to eigrpd control socket */
110e2656810Srenato 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
111e2656810Srenato 		err(1, "socket");
112e2656810Srenato 
113e2656810Srenato 	memset(&sun, 0, sizeof(sun));
114e2656810Srenato 	sun.sun_family = AF_UNIX;
11528291a98Srenato 	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
116e2656810Srenato 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
11728291a98Srenato 		err(1, "connect: %s", sockname);
118e2656810Srenato 
11917b561adSderaadt 	if (pledge("stdio", NULL) == -1)
1204581b8e5Ssemarie 		err(1, "pledge");
121f0c6dc37Srenato 
122e2656810Srenato 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
123e2656810Srenato 		err(1, NULL);
124*f1b790a5Sclaudio 	if (imsgbuf_init(ibuf, ctl_sock) == -1)
125*f1b790a5Sclaudio 		err(1, NULL);
126e2656810Srenato 	done = 0;
127e2656810Srenato 
128e2656810Srenato 	/* process user request */
129e2656810Srenato 	switch (res->action) {
130e2656810Srenato 	case NONE:
131e2656810Srenato 		usage();
132e2656810Srenato 		/* not reached */
133e2656810Srenato 	case SHOW:
134e2656810Srenato 	case SHOW_IFACE:
135e2656810Srenato 		printf("%-4s %-5s %-11s %-18s %-10s %-8s %3s\n",
136e2656810Srenato 		    "AF", "AS", "Interface", "Address", "Linkstate",
137e2656810Srenato 		    "Uptime", "nc");
138e2656810Srenato 		/*FALLTHROUGH*/
139e2656810Srenato 	case SHOW_IFACE_DTAIL:
140e2656810Srenato 		if (*res->ifname) {
141e2656810Srenato 			ifidx = if_nametoindex(res->ifname);
142e2656810Srenato 			if (ifidx == 0)
143e2656810Srenato 				errx(1, "no such interface %s", res->ifname);
144e2656810Srenato 		}
145e2656810Srenato 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
146e2656810Srenato 		    &ifidx, sizeof(ifidx));
147e2656810Srenato 		break;
148e2656810Srenato 	case SHOW_NBR:
149e2656810Srenato 		printf("%-4s %-5s %-18s %-11s %-10s %8s\n", "AF", "AS",
150e2656810Srenato 		    "Address", "Iface", "Holdtime", "Uptime");
151e2656810Srenato 		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
152e2656810Srenato 		break;
153e2656810Srenato 	case SHOW_TOPOLOGY:
154e2656810Srenato 		memset(&treq, 0, sizeof(treq));
155e2656810Srenato 		treq.af = res->family;
156e2656810Srenato 		memcpy(&treq.prefix, &res->addr, sizeof(res->addr));
157e2656810Srenato 		treq.prefixlen = res->prefixlen;
158e2656810Srenato 		treq.flags = res->flags;
159e2656810Srenato 
160e2656810Srenato 		if (!eigrp_addrisset(res->family, &res->addr))
161e2656810Srenato 			printf("  %-4s %-5s %-18s %-15s %-12s %s\n",
162e2656810Srenato 			    "AF", "AS", "Destination", "Nexthop", "Interface",
163e2656810Srenato 			    "Distance");
164e2656810Srenato 		imsg_compose(ibuf, IMSG_CTL_SHOW_TOPOLOGY, 0, 0, -1,
165e2656810Srenato 		    &treq, sizeof(treq));
166e2656810Srenato 		break;
167e2656810Srenato 	case SHOW_FIB:
168e2656810Srenato 		show_fib_head();
169e2656810Srenato 		imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
170e2656810Srenato 		    &res->flags, sizeof(res->flags));
171e2656810Srenato 		break;
172e2656810Srenato 	case SHOW_FIB_IFACE:
173e2656810Srenato 		if (*res->ifname)
174e2656810Srenato 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
175e2656810Srenato 			    res->ifname, sizeof(res->ifname));
176e2656810Srenato 		else
177e2656810Srenato 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
178e2656810Srenato 		show_interface_head();
179e2656810Srenato 		break;
180dcfaa8d4Srenato 	case SHOW_STATS:
181dcfaa8d4Srenato 		imsg_compose(ibuf, IMSG_CTL_SHOW_STATS, 0, 0, -1, NULL, 0);
182dcfaa8d4Srenato 		break;
183956c66a0Srenato 	case CLEAR_NBR:
184956c66a0Srenato 		memset(&nbr, 0, sizeof(nbr));
185956c66a0Srenato 		nbr.af = res->family;
186956c66a0Srenato 		nbr.as = res->as;
187956c66a0Srenato 		memcpy(&nbr.addr, &res->addr, sizeof(res->addr));
188956c66a0Srenato 		imsg_compose(ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr,
189956c66a0Srenato 		    sizeof(nbr));
190956c66a0Srenato 		done = 1;
191956c66a0Srenato 		break;
192e2656810Srenato 	case FIB:
193e2656810Srenato 		errx(1, "fib couple|decouple");
194e2656810Srenato 		break;
195e2656810Srenato 	case FIB_COUPLE:
196e2656810Srenato 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
197e2656810Srenato 		printf("couple request sent.\n");
198e2656810Srenato 		done = 1;
199e2656810Srenato 		break;
200e2656810Srenato 	case FIB_DECOUPLE:
201e2656810Srenato 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
202e2656810Srenato 		printf("decouple request sent.\n");
203e2656810Srenato 		done = 1;
204e2656810Srenato 		break;
205e2656810Srenato 	case LOG_VERBOSE:
206e2656810Srenato 		verbose = 1;
207e2656810Srenato 		/* FALLTHROUGH */
208e2656810Srenato 	case LOG_BRIEF:
209e2656810Srenato 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
210e2656810Srenato 		    &verbose, sizeof(verbose));
211e2656810Srenato 		printf("logging request sent.\n");
212e2656810Srenato 		done = 1;
213e2656810Srenato 		break;
214e2656810Srenato 	case RELOAD:
215e2656810Srenato 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
216e2656810Srenato 		printf("reload request sent.\n");
217e2656810Srenato 		done = 1;
218e2656810Srenato 		break;
219e2656810Srenato 	}
220e2656810Srenato 
221dd7efffeSclaudio 	if (imsgbuf_flush(ibuf) == -1)
222e2656810Srenato 		err(1, "write error");
223e2656810Srenato 
224e2656810Srenato 	while (!done) {
225668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
226ef2e27a1Sclaudio 			err(1, "read error");
227e2656810Srenato 		if (n == 0)
228e2656810Srenato 			errx(1, "pipe closed");
229e2656810Srenato 
230e2656810Srenato 		while (!done) {
231e2656810Srenato 			if ((n = imsg_get(ibuf, &imsg)) == -1)
232e2656810Srenato 				errx(1, "imsg_get error");
233e2656810Srenato 			if (n == 0)
234e2656810Srenato 				break;
235e2656810Srenato 			switch (res->action) {
236e2656810Srenato 			case SHOW:
237e2656810Srenato 			case SHOW_IFACE:
238e2656810Srenato 				done = show_interface_msg(&imsg, res);
239e2656810Srenato 				break;
240e2656810Srenato 			case SHOW_IFACE_DTAIL:
241e2656810Srenato 				done = show_interface_detail_msg(&imsg, res);
242e2656810Srenato 				break;
243e2656810Srenato 			case SHOW_NBR:
244e2656810Srenato 				done = show_nbr_msg(&imsg, res);
245e2656810Srenato 				break;
246e2656810Srenato 			case SHOW_TOPOLOGY:
247e2656810Srenato 				if (eigrp_addrisset(res->family, &res->addr))
248e2656810Srenato 					done = show_topology_detail_msg(&imsg,
249e2656810Srenato 					    res);
250e2656810Srenato 				else
251e2656810Srenato 					done = show_topology_msg(&imsg, res);
252e2656810Srenato 				break;
253e2656810Srenato 			case SHOW_FIB:
254e2656810Srenato 				done = show_fib_msg(&imsg, res);
255e2656810Srenato 				break;
256e2656810Srenato 			case SHOW_FIB_IFACE:
257e2656810Srenato 				done = show_fib_interface_msg(&imsg);
258e2656810Srenato 				break;
259dcfaa8d4Srenato 			case SHOW_STATS:
260dcfaa8d4Srenato 				done = show_stats_msg(&imsg, res);
261dcfaa8d4Srenato 				break;
262956c66a0Srenato 			case CLEAR_NBR:
263e2656810Srenato 			case NONE:
264e2656810Srenato 			case FIB:
265e2656810Srenato 			case FIB_COUPLE:
266e2656810Srenato 			case FIB_DECOUPLE:
267e2656810Srenato 			case LOG_VERBOSE:
268e2656810Srenato 			case LOG_BRIEF:
269e2656810Srenato 			case RELOAD:
270e2656810Srenato 				break;
271e2656810Srenato 			}
272e2656810Srenato 			imsg_free(&imsg);
273e2656810Srenato 		}
274e2656810Srenato 	}
275e2656810Srenato 	close(ctl_sock);
276e2656810Srenato 	free(ibuf);
277e2656810Srenato 
278e2656810Srenato 	return (0);
279e2656810Srenato }
280e2656810Srenato 
281e2656810Srenato uint64_t
282e2656810Srenato get_ifms_type(uint8_t if_type)
283e2656810Srenato {
284e2656810Srenato 	switch (if_type) {
285e2656810Srenato 	case IFT_ETHER:
286e2656810Srenato 		return (IFM_ETHER);
287e2656810Srenato 	case IFT_FDDI:
288e2656810Srenato 		return (IFM_FDDI);
289e2656810Srenato 	case IFT_CARP:
290e2656810Srenato 		return (IFM_CARP);
291e2656810Srenato 	case IFT_PPP:
292e2656810Srenato 		return (IFM_TDM);
293e2656810Srenato 	default:
294e2656810Srenato 		return (0);
295e2656810Srenato 	}
296e2656810Srenato }
297e2656810Srenato 
298e2656810Srenato int
299e2656810Srenato show_interface_msg(struct imsg *imsg, struct parse_result *res)
300e2656810Srenato {
301e2656810Srenato 	struct ctl_iface	*iface;
302e2656810Srenato 	char			*addr;
303e2656810Srenato 
304e2656810Srenato 	switch (imsg->hdr.type) {
305e2656810Srenato 	case IMSG_CTL_SHOW_INTERFACE:
306e2656810Srenato 		if (imsg->hdr.len < IMSG_HEADER_SIZE +
307e2656810Srenato 		    sizeof(struct ctl_iface))
308e2656810Srenato 			errx(1, "wrong imsg len");
309e2656810Srenato 		iface = imsg->data;
310e2656810Srenato 
311e2656810Srenato 		if (res->family != AF_UNSPEC && res->family != iface->af)
312e2656810Srenato 			break;
313e2656810Srenato 		if (res->as != 0 && res->as != iface->as)
314e2656810Srenato 			break;
315e2656810Srenato 
316e2656810Srenato 		if (asprintf(&addr, "%s/%d", log_addr(iface->af, &iface->addr),
317e2656810Srenato 		    iface->prefixlen) == -1)
318e2656810Srenato 			err(1, NULL);
319e2656810Srenato 
320e2656810Srenato 		printf("%-4s %-5u %-11s %-18s", af_name(iface->af), iface->as,
321e2656810Srenato 		    iface->name, addr);
322e2656810Srenato 		if (strlen(addr) > 18)
323e2656810Srenato 			printf("\n%41s", " ");
324e2656810Srenato 		printf(" %-10s %-8s %3u\n", get_linkstate(iface->if_type,
325e2656810Srenato 		    iface->linkstate), fmt_timeframe_core(iface->uptime),
326e2656810Srenato 		    iface->nbr_cnt);
327e2656810Srenato 		free(addr);
328e2656810Srenato 		break;
329e2656810Srenato 	case IMSG_CTL_END:
330e2656810Srenato 		printf("\n");
331e2656810Srenato 		return (1);
332e2656810Srenato 	default:
333e2656810Srenato 		break;
334e2656810Srenato 	}
335e2656810Srenato 
336e2656810Srenato 	return (0);
337e2656810Srenato }
338e2656810Srenato 
339e2656810Srenato int
340e2656810Srenato show_interface_detail_msg(struct imsg *imsg, struct parse_result *res)
341e2656810Srenato {
342e2656810Srenato 	struct ctl_iface	*iface;
343e2656810Srenato 
344e2656810Srenato 	switch (imsg->hdr.type) {
345e2656810Srenato 	case IMSG_CTL_SHOW_INTERFACE:
346e2656810Srenato 		if (imsg->hdr.len < IMSG_HEADER_SIZE +
347e2656810Srenato 		    sizeof(struct ctl_iface))
348e2656810Srenato 			errx(1, "wrong imsg len");
349e2656810Srenato 		iface = imsg->data;
350e2656810Srenato 
351e2656810Srenato 		if (res->family != AF_UNSPEC && res->family != iface->af)
352e2656810Srenato 			break;
353e2656810Srenato 		if (res->as != 0 && res->as != iface->as)
354e2656810Srenato 			break;
355e2656810Srenato 
356e2656810Srenato 		printf("\n");
357e2656810Srenato 		printf("Interface %s, line protocol is %s\n",
358e2656810Srenato 		    iface->name, print_link(iface->flags));
359e2656810Srenato 		printf("  Autonomous System %u, Address Family %s\n",
360e2656810Srenato 		    iface->as, af_name(iface->af));
361e2656810Srenato 		printf("  Internet address %s/%d\n",
362e2656810Srenato 		    log_addr(iface->af, &iface->addr), iface->prefixlen);
363e2656810Srenato 		printf("  Linkstate %s, network type %s\n",
364e2656810Srenato 		    get_linkstate(iface->if_type, iface->linkstate),
365e2656810Srenato 		    if_type_name(iface->type));
366e2656810Srenato 		printf("  Delay %u usec, Bandwidth %u Kbit/sec\n",
367e2656810Srenato 		    iface->delay, iface->bandwidth);
368e2656810Srenato 		if (iface->passive)
369e2656810Srenato 			printf("  Passive interface (No Hellos)\n");
370e2656810Srenato 		else {
371e2656810Srenato 			printf("  Hello interval %u, Hello holdtime %u\n",
372e2656810Srenato 			    iface->hello_interval, iface->hello_holdtime);
373e2656810Srenato 			printf("  Split-horizon %s\n",
374e2656810Srenato 			    (iface->splithorizon) ? "enabled" : "disabled");
375e2656810Srenato 			printf("  Neighbor count is %d\n", iface->nbr_cnt);
376e2656810Srenato 		}
377e2656810Srenato 		printf("  Uptime %s\n", fmt_timeframe_core(iface->uptime));
378e2656810Srenato 		break;
379e2656810Srenato 	case IMSG_CTL_END:
380e2656810Srenato 		printf("\n");
381e2656810Srenato 		return (1);
382e2656810Srenato 	default:
383e2656810Srenato 		break;
384e2656810Srenato 	}
385e2656810Srenato 
386e2656810Srenato 	return (0);
387e2656810Srenato }
388e2656810Srenato 
389e2656810Srenato const char *
390e2656810Srenato print_link(int state)
391e2656810Srenato {
392e2656810Srenato 	if (state & IFF_UP)
393e2656810Srenato 		return ("UP");
394e2656810Srenato 	else
395e2656810Srenato 		return ("DOWN");
396e2656810Srenato }
397e2656810Srenato 
398e2656810Srenato #define TF_BUFS	8
399e2656810Srenato #define TF_LEN	9
400e2656810Srenato 
401e2656810Srenato const char *
402e2656810Srenato fmt_timeframe_core(time_t t)
403e2656810Srenato {
404e2656810Srenato 	char		*buf;
405e2656810Srenato 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
406e2656810Srenato 	static int	 idx = 0;
407e2656810Srenato 	unsigned int	 sec, min, hrs, day;
408e2656810Srenato 	unsigned long long	week;
409e2656810Srenato 
410e2656810Srenato 	if (t == 0)
411e2656810Srenato 		return ("00:00:00");
412e2656810Srenato 
413e2656810Srenato 	buf = tfbuf[idx++];
414e2656810Srenato 	if (idx == TF_BUFS)
415e2656810Srenato 		idx = 0;
416e2656810Srenato 
417e2656810Srenato 	week = t;
418e2656810Srenato 
419e2656810Srenato 	sec = week % 60;
420e2656810Srenato 	week /= 60;
421e2656810Srenato 	min = week % 60;
422e2656810Srenato 	week /= 60;
423e2656810Srenato 	hrs = week % 24;
424e2656810Srenato 	week /= 24;
425e2656810Srenato 	day = week % 7;
426e2656810Srenato 	week /= 7;
427e2656810Srenato 
428e2656810Srenato 	if (week > 0)
429e2656810Srenato 		snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
430e2656810Srenato 	else if (day > 0)
431e2656810Srenato 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
432e2656810Srenato 	else
433e2656810Srenato 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
434e2656810Srenato 
435e2656810Srenato 	return (buf);
436e2656810Srenato }
437e2656810Srenato 
438e2656810Srenato int
439e2656810Srenato show_nbr_msg(struct imsg *imsg, struct parse_result *res)
440e2656810Srenato {
441e2656810Srenato 	struct ctl_nbr	*nbr;
442e2656810Srenato 	const char	*addr;
443e2656810Srenato 
444e2656810Srenato 	switch (imsg->hdr.type) {
445e2656810Srenato 	case IMSG_CTL_SHOW_NBR:
446e2656810Srenato 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_nbr))
447e2656810Srenato 			errx(1, "wrong imsg len");
448e2656810Srenato 		nbr = imsg->data;
449e2656810Srenato 
450e2656810Srenato 		if (res->family != AF_UNSPEC && res->family != nbr->af)
451e2656810Srenato 			break;
452e2656810Srenato 		if (res->as != 0 && res->as != nbr->as)
453e2656810Srenato 			break;
454e2656810Srenato 
455e2656810Srenato 		addr = log_addr(nbr->af, &nbr->addr);
456e2656810Srenato 
457e2656810Srenato 		printf("%-4s %-5u %-18s", af_name(nbr->af), nbr->as, addr);
458e2656810Srenato 		if (strlen(addr) > 18)
459e2656810Srenato 			printf("\n%29s", " ");
460e2656810Srenato 		printf(" %-11s %-10u %8s\n", nbr->ifname, nbr->hello_holdtime,
461e2656810Srenato 		    fmt_timeframe_core(nbr->uptime));
462e2656810Srenato 		break;
463e2656810Srenato 	case IMSG_CTL_END:
464e2656810Srenato 		printf("\n");
465e2656810Srenato 		return (1);
466e2656810Srenato 	default:
467e2656810Srenato 		break;
468e2656810Srenato 	}
469e2656810Srenato 
470e2656810Srenato 	return (0);
471e2656810Srenato }
472e2656810Srenato 
473e2656810Srenato static int
474e2656810Srenato connected_check(int af, union eigrpd_addr *addr)
475e2656810Srenato {
476e2656810Srenato 	switch (af) {
477e2656810Srenato 	case AF_INET:
478e2656810Srenato 		if (addr->v4.s_addr == INADDR_ANY)
479e2656810Srenato 			return (1);
480e2656810Srenato 		break;
481e2656810Srenato 	case AF_INET6:
482e2656810Srenato 		if (IN6_IS_ADDR_UNSPECIFIED(&addr->v6))
483e2656810Srenato 			return (1);
484e2656810Srenato 		break;
485e2656810Srenato 	default:
486e2656810Srenato 		break;
487e2656810Srenato 	}
488e2656810Srenato 
489e2656810Srenato 	return (0);
490e2656810Srenato }
491e2656810Srenato 
492e2656810Srenato int
493e2656810Srenato show_topology_msg(struct imsg *imsg, struct parse_result *res)
494e2656810Srenato {
495e2656810Srenato 	struct ctl_rt	*rt;
496e2656810Srenato 	char		*dstnet, *nexthop, *rdistance;
497e2656810Srenato 	char		 flag;
498e2656810Srenato 
499e2656810Srenato 	switch (imsg->hdr.type) {
500e2656810Srenato 	case IMSG_CTL_SHOW_TOPOLOGY:
501e2656810Srenato 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_rt))
502e2656810Srenato 			errx(1, "wrong imsg len");
503e2656810Srenato 		rt = imsg->data;
504e2656810Srenato 
505e2656810Srenato 		if (res->family != AF_UNSPEC && res->family != rt->af)
506e2656810Srenato 			break;
507e2656810Srenato 		if (res->as != 0 && res->as != rt->as)
508e2656810Srenato 			break;
509e2656810Srenato 
510e2656810Srenato 		if (rt->state & DUAL_STA_ACTIVE_ALL)
511e2656810Srenato 			flag = 'A';
512e2656810Srenato 		else if (rt->flags & F_CTL_RT_SUCCESSOR)
513e2656810Srenato 			flag = 'S';
514e2656810Srenato 		else if (rt->flags & F_CTL_RT_FSUCCESSOR)
515e2656810Srenato 			flag = 'F';
516e2656810Srenato 		else
517e2656810Srenato 			flag = ' ';
518e2656810Srenato 
519e2656810Srenato 		if (asprintf(&dstnet, "%s/%d", log_addr(rt->af, &rt->prefix),
520e2656810Srenato 		    rt->prefixlen) == -1)
521e2656810Srenato 			err(1, NULL);
522e2656810Srenato 
523e2656810Srenato 		if (connected_check(rt->af, &rt->nexthop)) {
524e2656810Srenato 			if (asprintf(&nexthop, "Connected") == -1)
525e2656810Srenato 				err(1, NULL);
526e2656810Srenato 			if (asprintf(&rdistance, "-") == -1)
527e2656810Srenato 				err(1, NULL);
528e2656810Srenato 		} else {
529e2656810Srenato 			if (asprintf(&nexthop, "%s", log_addr(rt->af,
530e2656810Srenato 			    &rt->nexthop)) == -1)
531e2656810Srenato 				err(1, NULL);
532e2656810Srenato 			if (asprintf(&rdistance, "%u", rt->rdistance) == -1)
533e2656810Srenato 				err(1, NULL);
534e2656810Srenato 		}
535e2656810Srenato 
536e2656810Srenato 		printf("%c %-4s %-5u %-18s", flag, af_name(rt->af), rt->as,
537e2656810Srenato 		    dstnet);
538e2656810Srenato 		if (strlen(dstnet) > 18)
539e2656810Srenato 			printf("\n%31s", " ");
540e2656810Srenato 		printf(" %-15s", nexthop);
541e2656810Srenato 		if (strlen(nexthop) > 15)
542e2656810Srenato 			printf("\n%47s", " ");
543e2656810Srenato 		printf(" %-12s %u/%s\n", rt->ifname, rt->distance, rdistance);
544e2656810Srenato 		free(dstnet);
545e2656810Srenato 		free(nexthop);
546e2656810Srenato 		free(rdistance);
547e2656810Srenato 		break;
548e2656810Srenato 	case IMSG_CTL_END:
549e2656810Srenato 		printf("\n");
550e2656810Srenato 		return (1);
551e2656810Srenato 	default:
552e2656810Srenato 		break;
553e2656810Srenato 	}
554e2656810Srenato 
555e2656810Srenato 	return (0);
556e2656810Srenato }
557e2656810Srenato 
558e2656810Srenato int
559e2656810Srenato show_topology_detail_msg(struct imsg *imsg, struct parse_result *res)
560e2656810Srenato {
561e2656810Srenato 	struct ctl_rt	*rt;
562e2656810Srenato 	char		*dstnet = NULL, *state = NULL, *type, *nexthop;
563e2656810Srenato 	struct in_addr	 addr;
564e2656810Srenato 
565e2656810Srenato 	switch (imsg->hdr.type) {
566e2656810Srenato 	case IMSG_CTL_SHOW_TOPOLOGY:
567e2656810Srenato 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_rt))
568e2656810Srenato 			errx(1, "wrong imsg len");
569e2656810Srenato 		rt = imsg->data;
570e2656810Srenato 
571e2656810Srenato 		if (res->family != AF_UNSPEC && res->family != rt->af)
572e2656810Srenato 			break;
573e2656810Srenato 		if (res->as != 0 && res->as != rt->as)
574e2656810Srenato 			break;
575e2656810Srenato 
576e2656810Srenato 		if (rt->flags & F_CTL_RT_FIRST) {
577e2656810Srenato 			if (asprintf(&dstnet, "%s/%d", log_addr(rt->af,
578e2656810Srenato 			    &rt->prefix), rt->prefixlen) == -1)
579e2656810Srenato 				err(1, NULL);
580e2656810Srenato 
581e2656810Srenato 			if (rt->state & DUAL_STA_ACTIVE_ALL) {
582e2656810Srenato 				if (asprintf(&state, "Active") == -1)
583e2656810Srenato 					err(1, NULL);
584e2656810Srenato 			} else {
585e2656810Srenato 				if (asprintf(&state, "Passive") == -1)
586e2656810Srenato 					err(1, NULL);
587e2656810Srenato 			}
588e2656810Srenato 		}
589e2656810Srenato 
590e2656810Srenato 		if (rt->type == EIGRP_ROUTE_INTERNAL) {
591e2656810Srenato 			if (asprintf(&type, "Internal") == -1)
592e2656810Srenato 				err(1, NULL);
593e2656810Srenato 		} else {
594e2656810Srenato 			if (asprintf(&type, "External") == -1)
595e2656810Srenato 				err(1, NULL);
596e2656810Srenato 		}
597e2656810Srenato 
598e2656810Srenato 		if (connected_check(rt->af, &rt->nexthop)) {
599e2656810Srenato 			if (asprintf(&nexthop, "Connected") == -1)
600e2656810Srenato 				err(1, NULL);
601e2656810Srenato 		} else {
602e2656810Srenato 			if (asprintf(&nexthop, "Neighbor %s", log_addr(rt->af,
603e2656810Srenato 			    &rt->nexthop)) == -1)
604e2656810Srenato 				err(1, NULL);
605e2656810Srenato 		}
606e2656810Srenato 
607e2656810Srenato 		if (rt->flags & F_CTL_RT_FIRST) {
608e2656810Srenato 			printf("Network %s\n", dstnet);
609e2656810Srenato 			printf("Autonomous System %u, Address Family %s\n",
610e2656810Srenato 			    rt->as, af_name(rt->af));
611e2656810Srenato 			printf("DUAL State: %s, Feasible Distance: %u\n", state,
612e2656810Srenato 			    rt->fdistance);
613e2656810Srenato 			printf("Routes:\n");
614e2656810Srenato 		}
615e2656810Srenato 		printf("  Interface %s - %s\n", rt->ifname, nexthop);
616e2656810Srenato 		printf("    Distance: %u", rt->distance);
617e2656810Srenato 		if (!connected_check(rt->af, &rt->nexthop))
618e2656810Srenato 			printf(", Reported Distance: %u", rt->rdistance);
619e2656810Srenato 		printf(", route is %s\n", type);
620e2656810Srenato 		printf("    Vector metric:\n");
621e2656810Srenato 		printf("      Minimum bandwidth is %u Kbit\n",
622e2656810Srenato 		    rt->metric.bandwidth);
623e2656810Srenato 		printf("      Total delay is %u microseconds\n",
624e2656810Srenato 		    rt->metric.delay);
625e2656810Srenato 		printf("      Reliability is %u/255\n", rt->metric.reliability);
626e2656810Srenato 		printf("      Load is %u/255\n", rt->metric.load);
627e2656810Srenato 		printf("      Minimum MTU is %u\n", rt->metric.mtu);
628e2656810Srenato 		printf("      Hop count is %u\n", rt->metric.hop_count);
629e2656810Srenato 		if (rt->type == EIGRP_ROUTE_EXTERNAL) {
630e2656810Srenato 			addr.s_addr = htonl(rt->emetric.routerid);
631e2656810Srenato 			printf("    External data:\n");
632e2656810Srenato 			printf("      Originating router is %s\n",
633e2656810Srenato 			    inet_ntoa(addr));
634e2656810Srenato 			printf("      AS number of route is %u\n",
635e2656810Srenato 			    rt->emetric.as);
636e2656810Srenato 			printf("      External protocol is %s\n",
637e2656810Srenato 			    ext_proto_name(rt->emetric.protocol));
638e2656810Srenato 			printf("      External metric is %u\n",
639e2656810Srenato 			    rt->emetric.metric);
640e2656810Srenato 			printf("      Administrator tag is %u\n",
641e2656810Srenato 			    rt->emetric.tag);
642e2656810Srenato 		}
643e2656810Srenato 
644e2656810Srenato 		printf("\n");
645e2656810Srenato 		free(dstnet);
646e2656810Srenato 		free(state);
647e2656810Srenato 		free(type);
648e2656810Srenato 		free(nexthop);
649e2656810Srenato 		break;
650e2656810Srenato 	case IMSG_CTL_END:
651e2656810Srenato 		return (1);
652e2656810Srenato 	default:
653e2656810Srenato 		break;
654e2656810Srenato 	}
655e2656810Srenato 
656e2656810Srenato 	return (0);
657e2656810Srenato }
658e2656810Srenato 
659e2656810Srenato void
660e2656810Srenato show_fib_head(void)
661e2656810Srenato {
662e2656810Srenato 	printf("flags: * = valid, D = EIGRP, C = Connected, S = Static\n");
663e2656810Srenato 	printf("%-6s %-4s %-20s %-17s\n", "Flags", "Prio", "Destination",
664e2656810Srenato 	    "Nexthop");
665e2656810Srenato }
666e2656810Srenato 
667e2656810Srenato int
668e2656810Srenato show_fib_msg(struct imsg *imsg, struct parse_result *res)
669e2656810Srenato {
670e2656810Srenato 	struct kroute		*k;
671e2656810Srenato 	char			*p;
672e2656810Srenato 
673e2656810Srenato 	switch (imsg->hdr.type) {
674e2656810Srenato 	case IMSG_CTL_KROUTE:
675e2656810Srenato 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
676e2656810Srenato 			errx(1, "wrong imsg len");
677e2656810Srenato 		k = imsg->data;
678e2656810Srenato 
679e2656810Srenato 		if (res->family != AF_UNSPEC && res->family != k->af)
680e2656810Srenato 			break;
681e2656810Srenato 
682e2656810Srenato 		if (k->flags & F_DOWN)
683e2656810Srenato 			printf(" ");
684e2656810Srenato 		else
685e2656810Srenato 			printf("*");
686e2656810Srenato 
687e2656810Srenato 		if (!(k->flags & F_KERNEL))
688e2656810Srenato 			printf("D");
689e2656810Srenato 		else if (k->flags & F_CONNECTED)
690e2656810Srenato 			printf("C");
691e2656810Srenato 		else if (k->flags & F_STATIC)
692e2656810Srenato 			printf("S");
693e2656810Srenato 		else
694e2656810Srenato 			printf(" ");
695e2656810Srenato 
696e2656810Srenato 		printf("%-5s", (k->flags & F_CTL_EXTERNAL) ? " EX" : "");
697e2656810Srenato 		printf("%4d ", k->priority);
698e2656810Srenato 		if (asprintf(&p, "%s/%u", log_addr(k->af, &k->prefix),
699e2656810Srenato 		    k->prefixlen) == -1)
700e2656810Srenato 			err(1, NULL);
701e2656810Srenato 		printf("%-20s ", p);
702e2656810Srenato 		if (strlen(p) > 20)
703e2656810Srenato 			printf("\n%33s", " ");
704e2656810Srenato 		free(p);
705e2656810Srenato 
706e2656810Srenato 		if (eigrp_addrisset(k->af, &k->nexthop)) {
707e2656810Srenato 			switch (k->af) {
708e2656810Srenato 			case AF_INET:
709e2656810Srenato 				printf("%s", log_addr(k->af, &k->nexthop));
710e2656810Srenato 				break;
711e2656810Srenato 			case AF_INET6:
712e2656810Srenato 				printf("%s", log_in6addr_scope(&k->nexthop.v6,
713e2656810Srenato 				    k->ifindex));
714e2656810Srenato 				break;
715e2656810Srenato 			default:
716e2656810Srenato 				break;
717e2656810Srenato 			}
718e2656810Srenato 
719e2656810Srenato 		} else if (k->flags & F_CONNECTED)
720e2656810Srenato 			printf("link#%u", k->ifindex);
721e2656810Srenato 		printf("\n");
722e2656810Srenato 
723e2656810Srenato 		break;
724e2656810Srenato 	case IMSG_CTL_END:
725e2656810Srenato 		printf("\n");
726e2656810Srenato 		return (1);
727e2656810Srenato 	default:
728e2656810Srenato 		break;
729e2656810Srenato 	}
730e2656810Srenato 
731e2656810Srenato 	return (0);
732e2656810Srenato }
733e2656810Srenato 
734e2656810Srenato void
735e2656810Srenato show_interface_head(void)
736e2656810Srenato {
737e2656810Srenato 	printf("%-15s%-15s%s\n", "Interface", "Flags",
738e2656810Srenato 	    "Link state");
739e2656810Srenato }
740e2656810Srenato 
741e2656810Srenato const struct if_status_description
742e2656810Srenato 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
743e2656810Srenato const struct ifmedia_description
744e2656810Srenato 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
745e2656810Srenato 
746e2656810Srenato const char *
747e2656810Srenato get_media_descr(uint64_t media_type)
748e2656810Srenato {
749e2656810Srenato 	const struct ifmedia_description	*p;
750e2656810Srenato 
751e2656810Srenato 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
752e2656810Srenato 		if (media_type == p->ifmt_word)
753e2656810Srenato 			return (p->ifmt_string);
754e2656810Srenato 
755e2656810Srenato 	return ("unknown");
756e2656810Srenato }
757e2656810Srenato 
758e2656810Srenato const char *
759e2656810Srenato get_linkstate(uint8_t if_type, int link_state)
760e2656810Srenato {
761e2656810Srenato 	const struct if_status_description *p;
762e2656810Srenato 	static char buf[8];
763e2656810Srenato 
764e2656810Srenato 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
765e2656810Srenato 		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
766e2656810Srenato 			return (p->ifs_string);
767e2656810Srenato 	}
768e2656810Srenato 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
769e2656810Srenato 	return (buf);
770e2656810Srenato }
771e2656810Srenato 
772e2656810Srenato void
773e2656810Srenato print_baudrate(uint64_t baudrate)
774e2656810Srenato {
775e2656810Srenato 	if (baudrate > IF_Gbps(1))
776e2656810Srenato 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
777e2656810Srenato 	else if (baudrate > IF_Mbps(1))
778e2656810Srenato 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
779e2656810Srenato 	else if (baudrate > IF_Kbps(1))
780e2656810Srenato 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
781e2656810Srenato 	else
782e2656810Srenato 		printf("%llu Bit/s", baudrate);
783e2656810Srenato }
784e2656810Srenato 
785e2656810Srenato int
786e2656810Srenato show_fib_interface_msg(struct imsg *imsg)
787e2656810Srenato {
788e2656810Srenato 	struct kif	*k;
789e2656810Srenato 	uint64_t	 ifms_type;
790e2656810Srenato 
791e2656810Srenato 	switch (imsg->hdr.type) {
792e2656810Srenato 	case IMSG_CTL_IFINFO:
793e2656810Srenato 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kif))
794e2656810Srenato 			errx(1, "wrong imsg len");
795e2656810Srenato 		k = imsg->data;
796e2656810Srenato 		printf("%-15s", k->ifname);
797e2656810Srenato 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
798e2656810Srenato 		ifms_type = get_ifms_type(k->if_type);
799e2656810Srenato 		if (ifms_type)
800e2656810Srenato 			printf("%s, ", get_media_descr(ifms_type));
801e2656810Srenato 
802e2656810Srenato 		printf("%s", get_linkstate(k->if_type, k->link_state));
803e2656810Srenato 
804e2656810Srenato 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
805e2656810Srenato 			printf(", ");
806e2656810Srenato 			print_baudrate(k->baudrate);
807e2656810Srenato 		}
808e2656810Srenato 		printf("\n");
809e2656810Srenato 		break;
810e2656810Srenato 	case IMSG_CTL_END:
811e2656810Srenato 		printf("\n");
812e2656810Srenato 		return (1);
813e2656810Srenato 	default:
814e2656810Srenato 		break;
815e2656810Srenato 	}
816e2656810Srenato 
817e2656810Srenato 	return (0);
818e2656810Srenato }
819dcfaa8d4Srenato 
820dcfaa8d4Srenato int
821dcfaa8d4Srenato show_stats_msg(struct imsg *imsg, struct parse_result *res)
822dcfaa8d4Srenato {
823dcfaa8d4Srenato 	struct ctl_stats	*cs;
824dcfaa8d4Srenato 
825dcfaa8d4Srenato 	switch (imsg->hdr.type) {
826dcfaa8d4Srenato 	case IMSG_CTL_SHOW_STATS:
827dcfaa8d4Srenato 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct ctl_stats))
828dcfaa8d4Srenato 			errx(1, "wrong imsg len");
829dcfaa8d4Srenato 		cs = imsg->data;
830dcfaa8d4Srenato 
831dcfaa8d4Srenato 		if (res->family != AF_UNSPEC && res->family != cs->af)
832dcfaa8d4Srenato 			break;
833dcfaa8d4Srenato 		if (res->as != 0 && res->as != cs->as)
834dcfaa8d4Srenato 			break;
835dcfaa8d4Srenato 
836dcfaa8d4Srenato 		printf("Address Family %s, Autonomous System %u\n",
837dcfaa8d4Srenato 		    af_name(cs->af), cs->as);
838dcfaa8d4Srenato 		printf("  Hellos sent/received: %u/%u\n",
839dcfaa8d4Srenato 		    cs->stats.hellos_sent, cs->stats.hellos_recv);
840dcfaa8d4Srenato 		printf("  Updates sent/received: %u/%u\n",
841dcfaa8d4Srenato 		    cs->stats.updates_sent, cs->stats.updates_recv);
842dcfaa8d4Srenato 		printf("  Queries sent/received: %u/%u\n",
843dcfaa8d4Srenato 		    cs->stats.queries_sent, cs->stats.queries_recv);
844dcfaa8d4Srenato 		printf("  Replies sent/received: %u/%u\n",
845dcfaa8d4Srenato 		    cs->stats.replies_sent, cs->stats.replies_recv);
846dcfaa8d4Srenato 		printf("  Acks sent/received: %u/%u\n",
847dcfaa8d4Srenato 		    cs->stats.acks_sent, cs->stats.acks_recv);
848dcfaa8d4Srenato 		printf("  SIA-Queries sent/received: %u/%u\n",
849dcfaa8d4Srenato 		    cs->stats.squeries_sent, cs->stats.squeries_recv);
850dcfaa8d4Srenato 		printf("  SIA-Replies sent/received: %u/%u\n",
851dcfaa8d4Srenato 		    cs->stats.sreplies_sent, cs->stats.sreplies_recv);
852dcfaa8d4Srenato 		break;
853dcfaa8d4Srenato 	case IMSG_CTL_END:
854dcfaa8d4Srenato 		printf("\n");
855dcfaa8d4Srenato 		return (1);
856dcfaa8d4Srenato 	default:
857dcfaa8d4Srenato 		break;
858dcfaa8d4Srenato 	}
859dcfaa8d4Srenato 
860dcfaa8d4Srenato 	return (0);
861dcfaa8d4Srenato }
862