xref: /openbsd-src/usr.sbin/ospf6ctl/ospf6ctl.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: ospf6ctl.c,v 1.38 2013/11/13 22:52:41 sthen Exp $ */
2 
3 /*
4  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <net/if_media.h>
27 #include <net/if_types.h>
28 
29 #include <err.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include "ospf6.h"
37 #include "ospf6d.h"
38 #include "ospfe.h"
39 #include "parser.h"
40 #include "log.h"
41 
42 __dead void	 usage(void);
43 int		 show_summary_msg(struct imsg *);
44 int		 get_ifms_type(int);
45 int		 show_interface_msg(struct imsg *);
46 int		 show_interface_detail_msg(struct imsg *);
47 const char	*print_link(int);
48 const char	*fmt_timeframe(time_t t);
49 const char	*fmt_timeframe_core(time_t t);
50 const char	*log_id(u_int32_t );
51 const char	*log_adv_rtr(u_int32_t);
52 void		 show_database_head(struct in_addr, char *, u_int16_t);
53 int		 show_database_msg(struct imsg *);
54 char		*print_ls_type(u_int16_t);
55 void		 show_db_hdr_msg_detail(struct lsa_hdr *);
56 char		*print_rtr_link_type(u_int8_t);
57 const char	*print_ospf_flags(u_int8_t);
58 const char	*print_asext_flags(u_int32_t);
59 const char	*print_prefix_opt(u_int8_t);
60 int		 show_db_msg_detail(struct imsg *imsg);
61 int		 show_nbr_msg(struct imsg *);
62 const char	*print_ospf_options(u_int32_t);
63 int		 show_nbr_detail_msg(struct imsg *);
64 int		 show_rib_msg(struct imsg *);
65 void		 show_rib_head(struct in_addr, u_int8_t, u_int8_t);
66 const char	*print_ospf_rtr_flags(u_int8_t);
67 int		 show_rib_detail_msg(struct imsg *);
68 void		 show_fib_head(void);
69 int		 show_fib_msg(struct imsg *);
70 const char *	 get_media_descr(int);
71 const char *	 get_linkstate(int, int);
72 void		 print_baudrate(u_int64_t);
73 
74 struct imsgbuf	*ibuf;
75 
76 __dead void
77 usage(void)
78 {
79 	extern char *__progname;
80 
81 	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
82 	    __progname);
83 	exit(1);
84 }
85 
86 int
87 main(int argc, char *argv[])
88 {
89 	struct sockaddr_un	 sun;
90 	struct parse_result	*res;
91 	struct imsg		 imsg;
92 	unsigned int		 ifidx = 0;
93 	int			 ctl_sock;
94 	int			 done = 0, verbose = 0;
95 	int			 n;
96 	int			 ch;
97 	char			*sockname;
98 
99 	sockname = OSPF6D_SOCKET;
100 	while ((ch = getopt(argc, argv, "s:")) != -1) {
101 		switch (ch) {
102 		case 's':
103 			sockname = optarg;
104 			break;
105 		default:
106 			usage();
107 			/* NOTREACHED */
108 		}
109 	}
110 	argc -= optind;
111 	argv += optind;
112 
113 	/* parse options */
114 	if ((res = parse(argc, argv)) == NULL)
115 		exit(1);
116 
117 	/* connect to ospf6d control socket */
118 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
119 		err(1, "socket");
120 
121 	bzero(&sun, sizeof(sun));
122 	sun.sun_family = AF_UNIX;
123 	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
124 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
125 		err(1, "connect: %s", sockname);
126 
127 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
128 		err(1, NULL);
129 	imsg_init(ibuf, ctl_sock);
130 	done = 0;
131 
132 	/* process user request */
133 	switch (res->action) {
134 	case NONE:
135 		usage();
136 		/* not reached */
137 	case SHOW:
138 	case SHOW_SUM:
139 		imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0);
140 		break;
141 	case SHOW_IFACE:
142 		printf("%-11s %-29s %-6s %-10s %-10s %-8s\n",
143 		    "Interface", "Address", "State", "HelloTimer", "Linkstate",
144 		    "Uptime");
145 		/*FALLTHROUGH*/
146 	case SHOW_IFACE_DTAIL:
147 		if (*res->ifname) {
148 			ifidx = if_nametoindex(res->ifname);
149 			if (ifidx == 0)
150 				errx(1, "no such interface %s", res->ifname);
151 		}
152 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
153 		    &ifidx, sizeof(ifidx));
154 		break;
155 	case SHOW_NBR:
156 		printf("%-15s %-3s %-12s %-9s %-11s %s\n", "ID", "Pri",
157 		    "State", "DeadTime", "Iface","Uptime");
158 		/*FALLTHROUGH*/
159 	case SHOW_NBR_DTAIL:
160 		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
161 		break;
162 	case SHOW_DB:
163 		imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, NULL, 0);
164 		break;
165 	case SHOW_DBBYAREA:
166 		imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1,
167 		    &res->addr, sizeof(res->addr));
168 		break;
169 	case SHOW_DBEXT:
170 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_EXT, 0, 0, -1, NULL, 0);
171 		break;
172 	case SHOW_DBLINK:
173 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_LINK, 0, 0, -1, NULL, 0);
174 		break;
175 	case SHOW_DBNET:
176 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_NET, 0, 0, -1, NULL, 0);
177 		break;
178 	case SHOW_DBRTR:
179 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_RTR, 0, 0, -1, NULL, 0);
180 		break;
181 	case SHOW_DBINTRA:
182 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_INTRA, 0, 0, -1, NULL, 0);
183 		break;
184 	case SHOW_DBSELF:
185 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SELF, 0, 0, -1, NULL, 0);
186 		break;
187 	case SHOW_DBSUM:
188 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SUM, 0, 0, -1, NULL, 0);
189 		break;
190 	case SHOW_DBASBR:
191 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0);
192 		break;
193 	case SHOW_RIB:
194 		printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination",
195 		    "Nexthop", "Path Type", "Type", "Cost", "Uptime");
196 		/*FALLTHROUGH*/
197 	case SHOW_RIB_DTAIL:
198 		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0);
199 		break;
200 	case SHOW_FIB:
201 		if (IN6_IS_ADDR_UNSPECIFIED(&res->addr))
202 			imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
203 			    &res->flags, sizeof(res->flags));
204 		else
205 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
206 			    &res->addr, sizeof(res->addr));
207 		show_fib_head();
208 		break;
209 	case FIB:
210 		errx(1, "fib couple|decouple");
211 		break;
212 	case FIB_COUPLE:
213 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
214 		printf("couple request sent.\n");
215 		done = 1;
216 		break;
217 	case FIB_DECOUPLE:
218 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
219 		printf("decouple request sent.\n");
220 		done = 1;
221 		break;
222 	case LOG_VERBOSE:
223 		verbose = 1;
224 		/* FALLTHROUGH */
225 	case LOG_BRIEF:
226 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
227 		    &verbose, sizeof(verbose));
228 		printf("logging request sent.\n");
229 		done = 1;
230 		break;
231 	case RELOAD:
232 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
233 		printf("reload request sent.\n");
234 		done = 1;
235 		break;
236 	}
237 
238 	while (ibuf->w.queued)
239 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
240 			err(1, "write error");
241 
242 	while (!done) {
243 		if ((n = imsg_read(ibuf)) == -1)
244 			errx(1, "imsg_read error");
245 		if (n == 0)
246 			errx(1, "pipe closed");
247 
248 		while (!done) {
249 			if ((n = imsg_get(ibuf, &imsg)) == -1)
250 				errx(1, "imsg_get error");
251 			if (n == 0)
252 				break;
253 			switch (res->action) {
254 			case SHOW:
255 			case SHOW_SUM:
256 				done = show_summary_msg(&imsg);
257 				break;
258 			case SHOW_IFACE:
259 				done = show_interface_msg(&imsg);
260 				break;
261 			case SHOW_IFACE_DTAIL:
262 				done = show_interface_detail_msg(&imsg);
263 				break;
264 			case SHOW_NBR:
265 				done = show_nbr_msg(&imsg);
266 				break;
267 			case SHOW_NBR_DTAIL:
268 				done = show_nbr_detail_msg(&imsg);
269 				break;
270 			case SHOW_DB:
271 			case SHOW_DBBYAREA:
272 			case SHOW_DBSELF:
273 				done = show_database_msg(&imsg);
274 				break;
275 			case SHOW_DBEXT:
276 			case SHOW_DBLINK:
277 			case SHOW_DBNET:
278 			case SHOW_DBRTR:
279 			case SHOW_DBINTRA:
280 			case SHOW_DBSUM:
281 			case SHOW_DBASBR:
282 				done = show_db_msg_detail(&imsg);
283 				break;
284 			case SHOW_RIB:
285 				done = show_rib_msg(&imsg);
286 				break;
287 			case SHOW_RIB_DTAIL:
288 				done = show_rib_detail_msg(&imsg);
289 				break;
290 			case SHOW_FIB:
291 				done = show_fib_msg(&imsg);
292 				break;
293 			case NONE:
294 			case FIB:
295 			case FIB_COUPLE:
296 			case FIB_DECOUPLE:
297 			case LOG_VERBOSE:
298 			case LOG_BRIEF:
299 			case RELOAD:
300 				break;
301 			}
302 			imsg_free(&imsg);
303 		}
304 	}
305 	close(ctl_sock);
306 	free(ibuf);
307 
308 	return (0);
309 }
310 
311 int
312 show_summary_msg(struct imsg *imsg)
313 {
314 	struct ctl_sum		*sum;
315 	struct ctl_sum_area	*sumarea;
316 
317 	switch (imsg->hdr.type) {
318 	case IMSG_CTL_SHOW_SUM:
319 		sum = imsg->data;
320 		printf("Router ID: %s\n", inet_ntoa(sum->rtr_id));
321 		printf("Uptime: %s\n", fmt_timeframe_core(sum->uptime));
322 
323 		printf("SPF delay is %d sec(s), hold time between two SPFs "
324 		    "is %d sec(s)\n", sum->spf_delay, sum->spf_hold_time);
325 		printf("Number of external LSA(s) %d\n", sum->num_ext_lsa);
326 		printf("Number of areas attached to this router: %d\n",
327 		    sum->num_area);
328 		break;
329 	case IMSG_CTL_SHOW_SUM_AREA:
330 		sumarea = imsg->data;
331 		printf("\nArea ID: %s\n", inet_ntoa(sumarea->area));
332 		printf("  Number of interfaces in this area: %d\n",
333 		    sumarea->num_iface);
334 		printf("  Number of fully adjacent neighbors in this "
335 		    "area: %d\n", sumarea->num_adj_nbr);
336 		printf("  SPF algorithm executed %d time(s)\n",
337 		    sumarea->num_spf_calc);
338 		printf("  Number LSA(s) %d\n", sumarea->num_lsa);
339 		break;
340 	case IMSG_CTL_END:
341 		printf("\n");
342 		return (1);
343 	default:
344 		break;
345 	}
346 
347 	return (0);
348 }
349 
350 int
351 get_ifms_type(int mediatype)
352 {
353 	switch (mediatype) {
354 	case IFT_ETHER:
355 		return (IFM_ETHER);
356 	case IFT_FDDI:
357 		return (IFM_FDDI);
358 	case IFT_CARP:
359 		return (IFM_CARP);
360 	case IFT_PPP:
361 		return (IFM_TDM);
362 	default:
363 		return (0);
364 	}
365 }
366 
367 int
368 show_interface_msg(struct imsg *imsg)
369 {
370 	struct ctl_iface	*iface;
371 	char			*netid;
372 
373 	switch (imsg->hdr.type) {
374 	case IMSG_CTL_SHOW_INTERFACE:
375 		iface = imsg->data;
376 
377 		if (asprintf(&netid, "%s", log_in6addr(&iface->addr)) == -1)
378 			err(1, NULL);
379 		printf("%-11s %-29s %-6s %-10s %-10s %s\n",
380 		    iface->name, netid, if_state_name(iface->state),
381 		    fmt_timeframe_core(iface->hello_timer),
382 		    get_linkstate(iface->mediatype, iface->linkstate),
383 		    fmt_timeframe_core(iface->uptime));
384 		free(netid);
385 		break;
386 	case IMSG_CTL_END:
387 		printf("\n");
388 		return (1);
389 	default:
390 		break;
391 	}
392 
393 	return (0);
394 }
395 
396 int
397 show_interface_detail_msg(struct imsg *imsg)
398 {
399 	struct ctl_iface	*iface;
400 
401 	switch (imsg->hdr.type) {
402 	case IMSG_CTL_SHOW_INTERFACE:
403 		iface = imsg->data;
404 		printf("\n");
405 		printf("Interface %s, line protocol is %s\n",
406 		    iface->name, print_link(iface->flags));
407 		printf("  Internet address %s Area %s\n",
408 		    log_in6addr(&iface->addr), inet_ntoa(iface->area));
409 		printf("  Link type %s, state %s",
410 		    get_media_descr(get_ifms_type(iface->mediatype)),
411 		    get_linkstate(iface->mediatype, iface->linkstate));
412 		if (iface->linkstate != LINK_STATE_DOWN &&
413 		    iface->baudrate > 0) {
414 		    printf(", ");
415 		    print_baudrate(iface->baudrate);
416 		}
417 		printf("\n");
418 		printf("  Router ID %s, network type %s, cost: %d\n",
419 		    inet_ntoa(iface->rtr_id),
420 		    if_type_name(iface->type), iface->metric);
421 		printf("  Transmit delay is %d sec(s), state %s, priority %d\n",
422 		    iface->transmit_delay, if_state_name(iface->state),
423 		    iface->priority);
424 		printf("  Designated Router (ID) %s\n",
425 		    inet_ntoa(iface->dr_id));
426 		printf("    Interface address %s\n",
427 		    log_in6addr(&iface->dr_addr));
428 		printf("  Backup Designated Router (ID) %s\n",
429 		    inet_ntoa(iface->bdr_id));
430 		printf("    Interface address %s\n",
431 		    log_in6addr(&iface->bdr_addr));
432 		printf("  Timer intervals configured, "
433 		    "hello %d, dead %d, wait %d, retransmit %d\n",
434 		     iface->hello_interval, iface->dead_interval,
435 		     iface->dead_interval, iface->rxmt_interval);
436 		if (iface->passive)
437 			printf("    Passive interface (No Hellos)\n");
438 		else if (iface->hello_timer < 0)
439 			printf("    Hello timer not running\n");
440 		else
441 			printf("    Hello timer due in %s\n",
442 			    fmt_timeframe_core(iface->hello_timer));
443 		printf("    Uptime %s\n", fmt_timeframe_core(iface->uptime));
444 		printf("  Neighbor count is %d, adjacent neighbor count is "
445 		    "%d\n", iface->nbr_cnt, iface->adj_cnt);
446 		break;
447 	case IMSG_CTL_END:
448 		printf("\n");
449 		return (1);
450 	default:
451 		break;
452 	}
453 
454 	return (0);
455 }
456 
457 const char *
458 print_link(int state)
459 {
460 	if (state & IFF_UP)
461 		return ("UP");
462 	else
463 		return ("DOWN");
464 }
465 
466 #define TF_BUFS	8
467 #define TF_LEN	9
468 
469 const char *
470 fmt_timeframe(time_t t)
471 {
472 	if (t == 0)
473 		return ("Never");
474 	else
475 		return (fmt_timeframe_core(time(NULL) - t));
476 }
477 
478 const char *
479 fmt_timeframe_core(time_t t)
480 {
481 	char		*buf;
482 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
483 	static int	 idx = 0;
484 	unsigned int	 sec, min, hrs, day, week;
485 
486 	if (t == 0)
487 		return ("00:00:00");
488 
489 	buf = tfbuf[idx++];
490 	if (idx == TF_BUFS)
491 		idx = 0;
492 
493 	week = t;
494 
495 	sec = week % 60;
496 	week /= 60;
497 	min = week % 60;
498 	week /= 60;
499 	hrs = week % 24;
500 	week /= 24;
501 	day = week % 7;
502 	week /= 7;
503 
504 	if (week > 0)
505 		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
506 	else if (day > 0)
507 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
508 	else
509 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
510 
511 	return (buf);
512 }
513 
514 const char *
515 log_id(u_int32_t id)
516 {
517 	static char	buf[48];
518 	struct in_addr	addr;
519 
520 	addr.s_addr = id;
521 
522 	if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL)
523 		return ("?");
524 	else
525 		return (buf);
526 }
527 
528 const char *
529 log_adv_rtr(u_int32_t adv_rtr)
530 {
531 	static char	buf[48];
532 	struct in_addr	addr;
533 
534 	addr.s_addr = adv_rtr;
535 
536 	if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL)
537 		return ("?");
538 	else
539 		return (buf);
540 }
541 
542 void
543 show_database_head(struct in_addr aid, char *ifname, u_int16_t type)
544 {
545 	char	*header, *format;
546 	int	cleanup = 0;
547 
548 	switch (ntohs(type)) {
549 	case LSA_TYPE_LINK:
550 		format = "Link (Type-8) Link States";
551 		break;
552 	case LSA_TYPE_ROUTER:
553 		format = "Router Link States";
554 		break;
555 	case LSA_TYPE_NETWORK:
556 		format = "Net Link States";
557 		break;
558 	case LSA_TYPE_INTER_A_PREFIX:
559 		format = "Inter Area Prefix Link States";
560 		break;
561 	case LSA_TYPE_INTER_A_ROUTER:
562 		format = "Inter Area Router Link States";
563 		break;
564 	case LSA_TYPE_INTRA_A_PREFIX:
565 		format = "Intra Area Prefix Link States";
566 		break;
567 	case LSA_TYPE_EXTERNAL:
568 		printf("\n%-15s %s\n\n", "", "Type-5 AS External Link States");
569 		return;
570 	default:
571 		if (asprintf(&format, "LSA type %x", ntohs(type)) == -1)
572 			err(1, NULL);
573 		cleanup = 1;
574 		break;
575 	}
576 	if (LSA_IS_SCOPE_AREA(ntohs(type))) {
577 		if (asprintf(&header, "%s (Area %s)", format,
578 		    inet_ntoa(aid)) == -1)
579 			err(1, NULL);
580 	} else if (LSA_IS_SCOPE_LLOCAL(ntohs(type))) {
581 		if (asprintf(&header, "%s (Area %s Interface %s)", format,
582 		    inet_ntoa(aid), ifname) == -1)
583 			err(1, NULL);
584 	}
585 
586 	printf("\n%-15s %s\n\n", "", header);
587 	free(header);
588 	if (cleanup)
589 		free(format);
590 }
591 
592 int
593 show_database_msg(struct imsg *imsg)
594 {
595 	static struct in_addr	 area_id;
596 	static char		 ifname[IF_NAMESIZE];
597 	static u_int16_t	 lasttype;
598 	struct area		*area;
599 	struct iface		*iface;
600 	struct lsa_hdr		*lsa;
601 
602 	switch (imsg->hdr.type) {
603 	case IMSG_CTL_SHOW_DATABASE:
604 	case IMSG_CTL_SHOW_DB_SELF:
605 		lsa = imsg->data;
606 		if (lsa->type != lasttype) {
607 			show_database_head(area_id, ifname, lsa->type);
608 			printf("%-15s %-15s %-4s %-10s %-8s\n", "Link ID",
609 			    "Adv Router", "Age", "Seq#", "Checksum");
610 		}
611 		printf("%-15s %-15s %-4d 0x%08x 0x%04x\n",
612 		    log_id(lsa->ls_id), log_adv_rtr(lsa->adv_rtr),
613 		    ntohs(lsa->age), ntohl(lsa->seq_num),
614 		    ntohs(lsa->ls_chksum));
615 		lasttype = lsa->type;
616 		break;
617 	case IMSG_CTL_AREA:
618 		area = imsg->data;
619 		area_id = area->id;
620 		lasttype = 0;
621 		break;
622 	case IMSG_CTL_IFACE:
623 		iface = imsg->data;
624 		strlcpy(ifname, iface->name, sizeof(ifname));
625 		lasttype = 0;
626 		break;
627 	case IMSG_CTL_END:
628 		printf("\n");
629 		return (1);
630 	default:
631 		break;
632 	}
633 
634 	return (0);
635 }
636 
637 char *
638 print_ls_type(u_int16_t type)
639 {
640 	switch (ntohs(type)) {
641 	case LSA_TYPE_LINK:
642 		return ("Link");
643 	case LSA_TYPE_ROUTER:
644 		return ("Router");
645 	case LSA_TYPE_NETWORK:
646 		return ("Network");
647 	case LSA_TYPE_INTER_A_PREFIX:
648 		return ("Inter Area (Prefix)");
649 	case LSA_TYPE_INTER_A_ROUTER:
650 		return ("Inter Area (Router)");
651 	case LSA_TYPE_INTRA_A_PREFIX:
652 		return ("Intra Area (Prefix)");
653 	case LSA_TYPE_EXTERNAL:
654 		return ("AS External");
655 	default:
656 		return ("Unknown");
657 	}
658 }
659 
660 void
661 show_db_hdr_msg_detail(struct lsa_hdr *lsa)
662 {
663 	printf("LS age: %d\n", ntohs(lsa->age));
664 	printf("LS Type: %s\n", print_ls_type(lsa->type));
665 
666 	switch (ntohs(lsa->type)) {
667 	case LSA_TYPE_ROUTER:
668 	case LSA_TYPE_INTER_A_PREFIX:
669 	case LSA_TYPE_INTER_A_ROUTER:
670 	case LSA_TYPE_INTRA_A_PREFIX:
671 	case LSA_TYPE_EXTERNAL:
672 		printf("Link State ID: %s\n", log_id(lsa->ls_id));
673 		break;
674 	case LSA_TYPE_LINK:
675 		printf("Link State ID: %s (Interface ID of Advertising "
676 		    "Router)\n", log_id(lsa->ls_id));
677 		break;
678 	case LSA_TYPE_NETWORK:
679 		printf("Link State ID: %s (Interface ID of Designated "
680 		    "Router)\n", log_id(lsa->ls_id));
681 		break;
682 	}
683 
684 	printf("Advertising Router: %s\n", log_adv_rtr(lsa->adv_rtr));
685 	printf("LS Seq Number: 0x%08x\n", ntohl(lsa->seq_num));
686 	printf("Checksum: 0x%04x\n", ntohs(lsa->ls_chksum));
687 	printf("Length: %d\n", ntohs(lsa->len));
688 }
689 
690 char *
691 print_rtr_link_type(u_int8_t type)
692 {
693 	switch (type) {
694 	case LINK_TYPE_POINTTOPOINT:
695 		return ("Point-to-Point");
696 	case LINK_TYPE_TRANSIT_NET:
697 		return ("Transit Network");
698 	case LINK_TYPE_RESERVED:
699 		return ("Reserved");
700 	case LINK_TYPE_VIRTUAL:
701 		return ("Virtual Link");
702 	default:
703 		return ("Unknown");
704 	}
705 }
706 
707 const char *
708 print_ospf_flags(u_int8_t opts)
709 {
710 	static char	optbuf[32];
711 
712 	snprintf(optbuf, sizeof(optbuf), "*|*|*|*|*|%s|%s|%s",
713 	    opts & OSPF_RTR_V ? "V" : "-",
714 	    opts & OSPF_RTR_E ? "E" : "-",
715 	    opts & OSPF_RTR_B ? "B" : "-");
716 	return (optbuf);
717 }
718 
719 const char *
720 print_asext_flags(u_int32_t opts)
721 {
722 	static char	optbuf[32];
723 
724 	snprintf(optbuf, sizeof(optbuf), "*|*|*|*|*|%s|%s|%s",
725 	    opts & LSA_ASEXT_E_FLAG ? "E" : "-",
726 	    opts & LSA_ASEXT_F_FLAG ? "F" : "-",
727 	    opts & LSA_ASEXT_T_FLAG ? "T" : "-");
728 	return (optbuf);
729 }
730 
731 const char *
732 print_prefix_opt(u_int8_t opts)
733 {
734 	static char	optbuf[32];
735 
736 	if (opts) {
737 		snprintf(optbuf, sizeof(optbuf),
738 		    " Options: *|*|*|%s|%s|x|%s|%s",
739 		    opts & OSPF_PREFIX_DN ? "DN" : "-",
740 		    opts & OSPF_PREFIX_P ? "P" : "-",
741 		    opts & OSPF_PREFIX_LA ? "LA" : "-",
742 		    opts & OSPF_PREFIX_NU ? "NU" : "-");
743 		return (optbuf);
744 	}
745 	return ("");
746 }
747 
748 int
749 show_db_msg_detail(struct imsg *imsg)
750 {
751 	static struct in_addr	 area_id;
752 	static char		 ifname[IF_NAMESIZE];
753 	static u_int16_t	 lasttype;
754 	struct in6_addr		 ia6;
755 	struct in_addr		 addr, data;
756 	struct area		*area;
757 	struct iface		*iface;
758 	struct lsa		*lsa;
759 	struct lsa_rtr_link	*rtr_link;
760 	struct lsa_net_link	*net_link;
761 	struct lsa_prefix	*prefix;
762 	struct lsa_asext	*asext;
763 	u_int32_t		 ext_tag;
764 	u_int16_t		 i, nlinks, off;
765 
766 	/* XXX sanity checks! */
767 
768 	switch (imsg->hdr.type) {
769 	case IMSG_CTL_SHOW_DB_EXT:
770 		lsa = imsg->data;
771 		if (lsa->hdr.type != lasttype)
772 			show_database_head(area_id, ifname, lsa->hdr.type);
773 		show_db_hdr_msg_detail(&lsa->hdr);
774 
775 		asext = (struct lsa_asext *)((char *)lsa + sizeof(lsa->hdr));
776 
777 		printf("    Flags: %s\n",
778 		    print_asext_flags(ntohl(lsa->data.asext.metric)));
779 		printf("    Metric: %d Type: ", ntohl(asext->metric)
780 		    & LSA_METRIC_MASK);
781 		if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_E_FLAG)
782 			printf("2\n");
783 		else
784 			printf("1\n");
785 
786 		prefix = &asext->prefix;
787 		bzero(&ia6, sizeof(ia6));
788 		bcopy(prefix + 1, &ia6, LSA_PREFIXSIZE(prefix->prefixlen));
789 		printf("    Prefix: %s/%d%s\n", log_in6addr(&ia6),
790 		    prefix->prefixlen, print_prefix_opt(prefix->options));
791 
792 		off = sizeof(*asext) + LSA_PREFIXSIZE(prefix->prefixlen);
793 		if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_F_FLAG) {
794 			bcopy((char *)asext + off, &ia6, sizeof(ia6));
795 			printf("    Forwarding Address: %s\n",
796 			    log_in6addr(&ia6));
797 			off += sizeof(ia6);
798 		}
799 		if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_T_FLAG) {
800 			bcopy((char *)asext + off, &ext_tag, sizeof(ext_tag));
801 			printf("    External Route Tag: %d\n", ntohl(ext_tag));
802 		}
803 		printf("\n");
804 		lasttype = lsa->hdr.type;
805 		break;
806 	case IMSG_CTL_SHOW_DB_LINK:
807 		lsa = imsg->data;
808 		if (lsa->hdr.type != lasttype)
809 			show_database_head(area_id, ifname, lsa->hdr.type);
810 		show_db_hdr_msg_detail(&lsa->hdr);
811 		printf("Options: %s\n", print_ospf_options(LSA_24_GETLO(
812 		    ntohl(lsa->data.link.opts))));
813 		printf("Link Local Address: %s\n",
814 		    log_in6addr(&lsa->data.link.lladdr));
815 
816 		nlinks = ntohl(lsa->data.link.numprefix);
817 		printf("Number of Prefixes: %d\n", nlinks);
818 		off = sizeof(lsa->hdr) + sizeof(struct lsa_link);
819 
820 		for (i = 0; i < nlinks; i++) {
821 			prefix = (struct lsa_prefix *)((char *)lsa + off);
822 			bzero(&ia6, sizeof(ia6));
823 			bcopy(prefix + 1, &ia6,
824 			    LSA_PREFIXSIZE(prefix->prefixlen));
825 
826 			printf("    Prefix: %s/%d%s\n", log_in6addr(&ia6),
827 			    prefix->prefixlen,
828 			    print_prefix_opt(prefix->options));
829 
830 			off += sizeof(struct lsa_prefix)
831 			    + LSA_PREFIXSIZE(prefix->prefixlen);
832 		}
833 
834 		printf("\n");
835 		lasttype = lsa->hdr.type;
836 		break;
837 	case IMSG_CTL_SHOW_DB_NET:
838 		lsa = imsg->data;
839 		if (lsa->hdr.type != lasttype)
840 			show_database_head(area_id, ifname, lsa->hdr.type);
841 		show_db_hdr_msg_detail(&lsa->hdr);
842 		printf("Options: %s\n",
843 		    print_ospf_options(LSA_24_GETLO(ntohl(lsa->data.net.opts))));
844 
845 		nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr) -
846 		    sizeof(struct lsa_net)) / sizeof(struct lsa_net_link);
847 		net_link = (struct lsa_net_link *)((char *)lsa +
848 		    sizeof(lsa->hdr) + sizeof(lsa->data.net));
849 		printf("Number of Routers: %d\n", nlinks);
850 
851 		for (i = 0; i < nlinks; i++) {
852 			addr.s_addr = net_link->att_rtr;
853 			printf("    Attached Router: %s\n", inet_ntoa(addr));
854 			net_link++;
855 		}
856 
857 		printf("\n");
858 		lasttype = lsa->hdr.type;
859 		break;
860 	case IMSG_CTL_SHOW_DB_RTR:
861 		lsa = imsg->data;
862 		if (lsa->hdr.type != lasttype)
863 			show_database_head(area_id, ifname, lsa->hdr.type);
864 		show_db_hdr_msg_detail(&lsa->hdr);
865 		printf("Flags: %s\n",
866 		    print_ospf_flags(LSA_24_GETHI(ntohl(lsa->data.rtr.opts))));
867 		printf("Options: %s\n",
868 		    print_ospf_options(LSA_24_GETLO(ntohl(lsa->data.rtr.opts))));
869 
870 		nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr)
871 		    - sizeof(u_int32_t)) / sizeof(struct lsa_rtr_link);
872 		printf("Number of Links: %d\n\n", nlinks);
873 
874 		off = sizeof(lsa->hdr) + sizeof(struct lsa_rtr);
875 
876 		for (i = 0; i < nlinks; i++) {
877 			rtr_link = (struct lsa_rtr_link *)((char *)lsa + off);
878 
879 			printf("    Link (Interface ID %s) connected to: %s\n",
880 			    log_id(rtr_link->iface_id),
881 			    print_rtr_link_type(rtr_link->type));
882 
883 			addr.s_addr = rtr_link->nbr_rtr_id;
884 			data.s_addr = rtr_link->nbr_iface_id;
885 
886 			switch (rtr_link->type) {
887 			case LINK_TYPE_POINTTOPOINT:
888 			case LINK_TYPE_VIRTUAL:
889 				printf("    Router ID: %s\n", inet_ntoa(addr));
890 				printf("    Interface ID: %s\n",
891 				    inet_ntoa(data));
892 				break;
893 			case LINK_TYPE_TRANSIT_NET:
894 				printf("    Designated Router ID: %s\n",
895 				    inet_ntoa(addr));
896 				printf("    DR Interface ID: %s\n",
897 				    inet_ntoa(data));
898 				break;
899 			default:
900 				printf("    Link ID (Unknown type %d): %s\n",
901 				    rtr_link->type, inet_ntoa(addr));
902 				printf("    Link Data (Unknown): %s\n",
903 				    inet_ntoa(data));
904 				break;
905 			}
906 
907 			printf("    Metric: %d\n\n", ntohs(rtr_link->metric));
908 
909 			off += sizeof(struct lsa_rtr_link);
910 		}
911 
912 		lasttype = lsa->hdr.type;
913 		break;
914 	case IMSG_CTL_SHOW_DB_INTRA:
915 		lsa = imsg->data;
916 		if (lsa->hdr.type != lasttype)
917 			show_database_head(area_id, ifname, lsa->hdr.type);
918 		show_db_hdr_msg_detail(&lsa->hdr);
919 		printf("Referenced LS Type: %s\n",
920 		    print_ls_type(lsa->data.pref_intra.ref_type));
921 		addr.s_addr = lsa->data.pref_intra.ref_ls_id;
922 		printf("Referenced Link State ID: %s\n", inet_ntoa(addr));
923 		addr.s_addr = lsa->data.pref_intra.ref_adv_rtr;
924 		printf("Referenced Advertising Router: %s\n", inet_ntoa(addr));
925 		nlinks = ntohs(lsa->data.pref_intra.numprefix);
926 		printf("Number of Prefixes: %d\n", nlinks);
927 
928 		off = sizeof(lsa->hdr) + sizeof(struct lsa_intra_prefix);
929 
930 		for (i = 0; i < nlinks; i++) {
931 			prefix = (struct lsa_prefix *)((char *)lsa + off);
932 			bzero(&ia6, sizeof(ia6));
933 			bcopy(prefix + 1, &ia6,
934 			    LSA_PREFIXSIZE(prefix->prefixlen));
935 
936 			printf("    Prefix: %s/%d%s\n", log_in6addr(&ia6),
937 			    prefix->prefixlen,
938 			    print_prefix_opt(prefix->options));
939 
940 			off += sizeof(struct lsa_prefix)
941 			    + LSA_PREFIXSIZE(prefix->prefixlen);
942 		}
943 
944 		printf("\n");
945 		lasttype = lsa->hdr.type;
946 		break;
947 	case IMSG_CTL_SHOW_DB_SUM:
948 		lsa = imsg->data;
949 		if (lsa->hdr.type != lasttype)
950 			show_database_head(area_id, ifname, lsa->hdr.type);
951 		show_db_hdr_msg_detail(&lsa->hdr);
952 		printf("Prefix: XXX\n");
953 		printf("Metric: %d\n", ntohl(lsa->data.pref_sum.metric) &
954 		    LSA_METRIC_MASK);
955 		lasttype = lsa->hdr.type;
956 		break;
957 	case IMSG_CTL_SHOW_DB_ASBR:
958 		lsa = imsg->data;
959 		if (lsa->hdr.type != lasttype)
960 			show_database_head(area_id, ifname, lsa->hdr.type);
961 		show_db_hdr_msg_detail(&lsa->hdr);
962 
963 		addr.s_addr = lsa->data.rtr_sum.dest_rtr_id;
964 		printf("Destination Router ID: %s\n", inet_ntoa(addr));
965 		printf("Options: %s\n",
966 		    print_ospf_options(ntohl(lsa->data.rtr_sum.opts)));
967 		printf("Metric: %d\n\n", ntohl(lsa->data.rtr_sum.metric) &
968 		    LSA_METRIC_MASK);
969 	case IMSG_CTL_AREA:
970 		area = imsg->data;
971 		area_id = area->id;
972 		lasttype = 0;
973 		break;
974 	case IMSG_CTL_IFACE:
975 		iface = imsg->data;
976 		strlcpy(ifname, iface->name, sizeof(ifname));
977 		lasttype = 0;
978 		break;
979 	case IMSG_CTL_END:
980 		return (1);
981 	default:
982 		break;
983 	}
984 
985 	return (0);
986 }
987 
988 int
989 show_nbr_msg(struct imsg *imsg)
990 {
991 	struct ctl_nbr	*nbr;
992 	char		*state;
993 
994 	switch (imsg->hdr.type) {
995 	case IMSG_CTL_SHOW_NBR:
996 		nbr = imsg->data;
997 		if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state),
998 		    if_state_name(nbr->iface_state)) == -1)
999 			err(1, NULL);
1000 		printf("%-15s %-3d %-12s %-10s", inet_ntoa(nbr->id),
1001 		    nbr->priority, state, fmt_timeframe_core(nbr->dead_timer));
1002 		printf("%-11s %s\n", nbr->name,
1003 		    nbr->uptime == 0 ? "-" : fmt_timeframe_core(nbr->uptime));
1004 		free(state);
1005 		break;
1006 	case IMSG_CTL_END:
1007 		printf("\n");
1008 		return (1);
1009 	default:
1010 		break;
1011 	}
1012 
1013 	return (0);
1014 }
1015 
1016 const char *
1017 print_ospf_options(u_int32_t opts)
1018 {
1019 	static char	optbuf[32];
1020 
1021 	snprintf(optbuf, sizeof(optbuf), "*|*|%s|%s|%s|*|%s|%s",
1022 	    opts & OSPF_OPTION_DC ? "DC" : "-",
1023 	    opts & OSPF_OPTION_R ? "R" : "-",
1024 	    opts & OSPF_OPTION_N ? "N" : "-",
1025 	    opts & OSPF_OPTION_E ? "E" : "-",
1026 	    opts & OSPF_OPTION_V6 ? "V6" : "-");
1027 	return (optbuf);
1028 }
1029 
1030 int
1031 show_nbr_detail_msg(struct imsg *imsg)
1032 {
1033 	struct ctl_nbr	*nbr;
1034 
1035 	switch (imsg->hdr.type) {
1036 	case IMSG_CTL_SHOW_NBR:
1037 		nbr = imsg->data;
1038 		printf("\nNeighbor %s, ", inet_ntoa(nbr->id));
1039 		printf("interface address %s\n", log_in6addr(&nbr->addr));
1040 		printf("  Area %s, interface %s\n", inet_ntoa(nbr->area),
1041 		    nbr->name);
1042 		printf("  Neighbor priority is %d, "
1043 		    "State is %s, %d state changes\n",
1044 		    nbr->priority, nbr_state_name(nbr->nbr_state),
1045 		    nbr->state_chng_cnt);
1046 		printf("  DR is %s, ", inet_ntoa(nbr->dr));
1047 		printf("BDR is %s\n", inet_ntoa(nbr->bdr));
1048 		printf("  Options %s\n", print_ospf_options(nbr->options));
1049 		printf("  Dead timer due in %s\n",
1050 		    fmt_timeframe_core(nbr->dead_timer));
1051 		printf("  Uptime %s\n", fmt_timeframe_core(nbr->uptime));
1052 		printf("  Database Summary List %d\n", nbr->db_sum_lst_cnt);
1053 		printf("  Link State Request List %d\n", nbr->ls_req_lst_cnt);
1054 		printf("  Link State Retransmission List %d\n",
1055 		    nbr->ls_retrans_lst_cnt);
1056 		break;
1057 	case IMSG_CTL_END:
1058 		printf("\n");
1059 		return (1);
1060 	default:
1061 		break;
1062 	}
1063 
1064 	return (0);
1065 }
1066 
1067 int
1068 show_rib_msg(struct imsg *imsg)
1069 {
1070 	struct ctl_rt	*rt;
1071 	char		*dstnet;
1072 
1073 	switch (imsg->hdr.type) {
1074 	case IMSG_CTL_SHOW_RIB:
1075 		rt = imsg->data;
1076 		switch (rt->d_type) {
1077 		case DT_NET:
1078 			if (asprintf(&dstnet, "%s/%d", log_in6addr(&rt->prefix),
1079 			    rt->prefixlen) == -1)
1080 				err(1, NULL);
1081 			break;
1082 		case DT_RTR:
1083 			if (asprintf(&dstnet, "%s",
1084 			    log_in6addr(&rt->prefix)) == -1)
1085 				err(1, NULL);
1086 			break;
1087 		default:
1088 			errx(1, "Invalid route type");
1089 		}
1090 
1091 		printf("%-20s %-17s %-12s %-9s %-7d %s\n", dstnet,
1092 		    log_in6addr_scope(&rt->nexthop, rt->ifindex),
1093 		    path_type_name(rt->p_type), dst_type_name(rt->d_type),
1094 		    rt->cost,
1095 		    rt->uptime == 0 ? "-" : fmt_timeframe_core(rt->uptime));
1096 		free(dstnet);
1097 		break;
1098 	case IMSG_CTL_END:
1099 		printf("\n");
1100 		return (1);
1101 	default:
1102 		break;
1103 	}
1104 
1105 	return (0);
1106 }
1107 
1108 void
1109 show_rib_head(struct in_addr aid, u_int8_t d_type, u_int8_t p_type)
1110 {
1111 	char	*header, *format, *format2;
1112 
1113 	switch (p_type) {
1114 	case PT_INTRA_AREA:
1115 	case PT_INTER_AREA:
1116 		switch (d_type) {
1117 		case DT_NET:
1118 			format = "Network Routing Table";
1119 			format2 = "";
1120 			break;
1121 		case DT_RTR:
1122 			format = "Router Routing Table";
1123 			format2 = "Type";
1124 			break;
1125 		default:
1126 			errx(1, "unknown route type");
1127 		}
1128 		break;
1129 	case PT_TYPE1_EXT:
1130 	case PT_TYPE2_EXT:
1131 		format = NULL;
1132 		format2 = "Cost 2";
1133 		if ((header = strdup("External Routing Table")) == NULL)
1134 			err(1, NULL);
1135 		break;
1136 	default:
1137 		errx(1, "unknown route type");
1138 	}
1139 
1140 	if (p_type != PT_TYPE1_EXT && p_type != PT_TYPE2_EXT)
1141 		if (asprintf(&header, "%s (Area %s)", format,
1142 		    inet_ntoa(aid)) == -1)
1143 			err(1, NULL);
1144 
1145 	printf("\n%-18s %s\n", "", header);
1146 	free(header);
1147 
1148 	printf("\n%-18s %-15s %-15s %-12s %-7s %-7s\n", "Destination",
1149 	    "Nexthop", "Adv Router", "Path type", "Cost", format2);
1150 }
1151 
1152 const char *
1153 print_ospf_rtr_flags(u_int8_t opts)
1154 {
1155 	static char	optbuf[32];
1156 
1157 	snprintf(optbuf, sizeof(optbuf), "%s%s%s",
1158 	    opts & OSPF_RTR_E ? "AS" : "",
1159 	    opts & OSPF_RTR_E && opts & OSPF_RTR_B ? "+" : "",
1160 	    opts & OSPF_RTR_B ? "ABR" : "");
1161 	return (optbuf);
1162 }
1163 
1164 int
1165 show_rib_detail_msg(struct imsg *imsg)
1166 {
1167 	static struct in_addr	 area_id;
1168 	struct ctl_rt		*rt;
1169 	struct area		*area;
1170 	char			*dstnet;
1171 	static u_int8_t		 lasttype;
1172 
1173 	switch (imsg->hdr.type) {
1174 	case IMSG_CTL_SHOW_RIB:
1175 		rt = imsg->data;
1176 
1177 		switch (rt->p_type) {
1178 		case PT_INTRA_AREA:
1179 		case PT_INTER_AREA:
1180 			switch (rt->d_type) {
1181 			case DT_NET:
1182 				if (lasttype != RIB_NET)
1183 					show_rib_head(rt->area, rt->d_type,
1184 					     rt->p_type);
1185 				if (asprintf(&dstnet, "%s/%d",
1186 				    log_in6addr(&rt->prefix),
1187 				    rt->prefixlen) == -1)
1188 					err(1, NULL);
1189 				lasttype = RIB_NET;
1190 				break;
1191 			case DT_RTR:
1192 				if (lasttype != RIB_RTR)
1193 					show_rib_head(rt->area, rt->d_type,
1194 					     rt->p_type);
1195 				if (asprintf(&dstnet, "%s",
1196 				    log_in6addr(&rt->prefix)) == -1)
1197 					err(1, NULL);
1198 				lasttype = RIB_RTR;
1199 				break;
1200 			default:
1201 				errx(1, "unknown route type");
1202 			}
1203 			printf("%-18s %-15s ", dstnet,
1204 			    log_in6addr_scope(&rt->nexthop, rt->ifindex));
1205 			printf("%-15s %-12s %-7d", inet_ntoa(rt->adv_rtr),
1206 			    path_type_name(rt->p_type), rt->cost);
1207 			free(dstnet);
1208 
1209 			if (rt->d_type == DT_RTR)
1210 				printf(" %-7s",
1211 				    print_ospf_rtr_flags(rt->flags));
1212 
1213 			printf("\n");
1214 			break;
1215 		case PT_TYPE1_EXT:
1216 		case PT_TYPE2_EXT:
1217 			if (lasttype != RIB_EXT)
1218 				show_rib_head(rt->area, rt->d_type, rt->p_type);
1219 
1220 			if (asprintf(&dstnet, "%s/%d",
1221 			    log_in6addr(&rt->prefix), rt->prefixlen) == -1)
1222 				err(1, NULL);
1223 
1224 			printf("%-18s %-15s ", dstnet,
1225 			    log_in6addr_scope(&rt->nexthop, rt->ifindex));
1226 			printf("%-15s %-12s %-7d %-7d\n",
1227 			    inet_ntoa(rt->adv_rtr), path_type_name(rt->p_type),
1228 			    rt->cost, rt->cost2);
1229 			free(dstnet);
1230 
1231 			lasttype = RIB_EXT;
1232 			break;
1233 		default:
1234 			errx(1, "unknown route type");
1235 		}
1236 		break;
1237 	case IMSG_CTL_AREA:
1238 		area = imsg->data;
1239 		area_id = area->id;
1240 		break;
1241 	case IMSG_CTL_END:
1242 		printf("\n");
1243 		return (1);
1244 	default:
1245 		break;
1246 	}
1247 
1248 	return (0);
1249 }
1250 
1251 void
1252 show_fib_head(void)
1253 {
1254 	printf("flags: * = valid, O = OSPF, C = Connected, S = Static\n");
1255 	printf("%-6s %-20s %-17s\n", "Flags", "Destination", "Nexthop");
1256 }
1257 
1258 int
1259 show_fib_msg(struct imsg *imsg)
1260 {
1261 	struct kroute		*k;
1262 	char			*p;
1263 
1264 	switch (imsg->hdr.type) {
1265 	case IMSG_CTL_KROUTE:
1266 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
1267 			errx(1, "wrong imsg len");
1268 		k = imsg->data;
1269 
1270 		if (k->flags & F_DOWN)
1271 			printf(" ");
1272 		else
1273 			printf("*");
1274 
1275 		if (!(k->flags & F_KERNEL))
1276 			printf("O");
1277 		else if (k->flags & F_CONNECTED)
1278 			printf("C");
1279 		else if (k->flags & F_STATIC)
1280 			printf("S");
1281 		else
1282 			printf(" ");
1283 
1284 		printf("     ");
1285 		if (asprintf(&p, "%s/%u", log_in6addr(&k->prefix),
1286 		    k->prefixlen) == -1)
1287 			err(1, NULL);
1288 		printf("%-20s ", p);
1289 		free(p);
1290 
1291 		if (!IN6_IS_ADDR_UNSPECIFIED(&k->nexthop))
1292 			printf("%s", log_in6addr_scope(&k->nexthop, k->scope));
1293 		else if (k->flags & F_CONNECTED)
1294 			printf("link#%u", k->ifindex);
1295 		printf("\n");
1296 
1297 		break;
1298 	case IMSG_CTL_END:
1299 		printf("\n");
1300 		return (1);
1301 	default:
1302 		break;
1303 	}
1304 
1305 	return (0);
1306 }
1307 
1308 const struct if_status_description
1309 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
1310 const struct ifmedia_description
1311 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
1312 
1313 const char *
1314 get_media_descr(int media_type)
1315 {
1316 	const struct ifmedia_description	*p;
1317 
1318 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
1319 		if (media_type == p->ifmt_word)
1320 			return (p->ifmt_string);
1321 
1322 	return ("unknown");
1323 }
1324 
1325 const char *
1326 get_linkstate(int media_type, int link_state)
1327 {
1328 	const struct if_status_description *p;
1329 	static char buf[8];
1330 
1331 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
1332 		if (LINK_STATE_DESC_MATCH(p, media_type, link_state))
1333 			return (p->ifs_string);
1334 	}
1335 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
1336 	return (buf);
1337 }
1338 
1339 void
1340 print_baudrate(u_int64_t baudrate)
1341 {
1342 	if (baudrate > IF_Gbps(1))
1343 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
1344 	else if (baudrate > IF_Mbps(1))
1345 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
1346 	else if (baudrate > IF_Kbps(1))
1347 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
1348 	else
1349 		printf("%llu Bit/s", baudrate);
1350 }
1351