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