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