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