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