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