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