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