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