ospfctl.c revision 1.1
1/*	$OpenBSD: ospfctl.c,v 1.1 2005/01/28 14:18:46 claudio Exp $ */
2
3/*
4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2004 Esben Norby <esben.norby@ericsson.com>
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
27#include <err.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "ospf.h"
34#include "ospfd.h"
35#include "ospfe.h"
36#include "parser.h"
37#include "log.h"
38
39void		 usage(void);
40int		 show_summary_msg(struct imsg *, int);
41int		 show_interface_msg(struct imsg *);
42void		 print_baudrate(u_long);
43const char	*print_if_type(enum iface_type type);
44const char	*print_if_state(int);
45const char	*print_nbr_state(int);
46const char	*print_link(int);
47const char	*fmt_timeframe(time_t t);
48const char	*fmt_timeframe_core(time_t t);
49const char	*log_id(u_int32_t );
50const char	*log_adv_rtr(u_int32_t);
51u_int8_t	 mask2prefixlen(struct in_addr);
52void		 show_database_head(struct in_addr, u_int8_t);
53int		 show_database_msg(struct imsg *);
54int		 show_nbr_msg(struct imsg *);
55const char	*print_ospf_options(u_int8_t);
56int		 show_nbr_detail_msg(struct imsg *);
57
58struct imsgbuf	*ibuf;
59
60void
61usage(void)
62{
63	extern char *__progname;
64
65	fprintf(stderr, "usage: %s <command> [arg [...]]\n", __progname);
66	exit(1);
67}
68
69void
70imsg_event_add(struct imsgbuf *i)
71{
72}
73
74int
75main(int argc, char *argv[])
76{
77	struct sockaddr_un	 sun;
78	struct parse_result	*res;
79	struct imsg		 imsg;
80	unsigned int		 ifidx = 0;
81	int			 ctl_sock;
82	int			 nodescr = 0;
83	int			 done = 0;
84	int			 n;
85
86	/* parse options */
87	if ((res = parse(argc - 1, argv + 1)) == NULL)
88		exit(1);
89
90	/* connect to ospfd control socket */
91	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
92		err(1, "socket");
93
94	bzero(&sun, sizeof(sun));
95	sun.sun_family = AF_UNIX;
96	strlcpy(sun.sun_path, OSPFD_SOCKET, sizeof(sun.sun_path));
97	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
98		err(1, "connect: %s", OSPFD_SOCKET);
99
100	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
101		fatal(NULL);
102	imsg_init(ibuf, ctl_sock, NULL);
103	done = 0;
104
105	/* process user request */
106	switch (res->action) {
107	case NONE:
108		usage();
109		/* not reached */
110	case SHOW:
111	case SHOW_SUMMARY:
112		break;
113	case SHOW_IFACE:
114		if (*res->ifname) {
115			ifidx = if_nametoindex(res->ifname);
116			if (ifidx == 0)
117				errx(1, "no such interface %s", res->ifname);
118		}
119		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
120		    &ifidx, sizeof(ifidx));
121		break;
122	case SHOW_NBR:
123		printf("%-15s %-3s %-17s %-9s %-15s %s\n",
124		    "ID", "Pri", "State", "DeadTime", "Address", "Interface");
125	case SHOW_NBR_DTAIL:
126		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
127		break;
128	case SHOW_DB:
129		imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, NULL, 0);
130		break;
131	case SHOW_DBBYAREA:
132		imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1,
133		    &res->addr, sizeof(res->addr));
134		break;
135	case RELOAD:
136		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
137		printf("reload request sent.\n");
138		done = 1;
139		break;
140	}
141
142	while (ibuf->w.queued)
143		if (msgbuf_write(&ibuf->w) < 0)
144			err(1, "write error");
145
146	while (!done) {
147		if ((n = imsg_read(ibuf)) == -1)
148			errx(1, "imsg_read error");
149		if (n == 0)
150			errx(1, "pipe closed");
151
152		while (!done) {
153			if ((n = imsg_get(ibuf, &imsg)) == -1)
154				errx(1, "imsg_get error");
155			if (n == 0)
156				break;
157			switch (res->action) {
158			case SHOW:
159			case SHOW_SUMMARY:
160				done = show_summary_msg(&imsg, nodescr);
161				break;
162			case SHOW_IFACE:
163				done = show_interface_msg(&imsg);
164				break;
165			case SHOW_NBR:
166				done = show_nbr_msg(&imsg);
167				break;
168			case SHOW_NBR_DTAIL:
169				done = show_nbr_detail_msg(&imsg);
170				break;
171			case SHOW_DB:
172			case SHOW_DBBYAREA:
173				done = show_database_msg(&imsg);
174				break;
175			case NONE:
176			case RELOAD:
177				break;
178			}
179			imsg_free(&imsg);
180		}
181	}
182	close(ctl_sock);
183	free(ibuf);
184
185	return (0);
186}
187
188int
189show_summary_msg(struct imsg *imsg, int nodescr)
190{
191
192	return (0);
193}
194
195int
196show_interface_msg(struct imsg *imsg)
197{
198	struct ctl_iface	*iface;
199
200	switch (imsg->hdr.type) {
201	case IMSG_CTL_SHOW_INTERFACE:
202		iface = imsg->data;
203		printf("\n");
204		printf("Interface %s is %d, line protocol is %s\n",
205		    iface->name, iface->linkstate, print_link(iface->flags));
206		printf("  Internet address %s/%d, ",
207		    inet_ntoa(iface->addr),
208		    mask2prefixlen(iface->mask));
209		printf("Area %s\n", inet_ntoa(iface->area));
210		printf("  Router ID %s, network type %s, cost: %d\n",
211		    inet_ntoa(iface->rtr_id),
212		    print_if_type(iface->type), iface->metric);
213		printf("  Transmit delay is %d sec, state %s, priority %d\n",
214		    iface->transfer_delay, print_if_state(iface->state),
215		    iface->priority);
216		printf("  Designated Router (ID) %s, ",
217		    inet_ntoa(iface->dr_id));
218		printf("interface address %s\n", inet_ntoa(iface->dr_addr));
219		printf("  Backup Designated Router (ID) %s, ",
220		    inet_ntoa(iface->bdr_id));
221		printf("interface address %s\n", inet_ntoa(iface->bdr_addr));
222		printf("  Timer intervals configured, "
223		    "hello %d, dead %d, wait %d, retransmit %d\n",
224		     iface->hello_interval, iface->dead_interval,
225		     iface->dead_interval, iface->rxmt_interval);
226		if (iface->hello_timer < 0)
227			printf("    Hello timer not running\n");
228		else
229			printf("    Hello timer due in %s\n",
230			    fmt_timeframe_core(iface->hello_timer));
231		printf("  Neighbor count is %d, adjacent neighbor count is "
232		    "%d\n", iface->nbr_cnt, iface->adj_cnt);
233		break;
234	case IMSG_CTL_END:
235		printf("\n");
236		return (1);
237	default:
238		break;
239	}
240
241	return (0);
242}
243
244const char *
245print_if_type(enum iface_type type)
246{
247	switch (type) {
248	case IF_TYPE_POINTOPOINT:
249		return ("POINTOPOINT");
250	case IF_TYPE_BROADCAST:
251		return ("BROADCAST");
252	case IF_TYPE_NBMA:
253		return ("NBMA");
254	case IF_TYPE_POINTOMULTIPOINT:
255		return ("POINTOMULTIPOINT");
256	case IF_TYPE_VIRTUALLINK:
257		return ("VIRTUALLINK");
258	default:
259		return ("UNKNOWN");
260	}
261}
262
263const char *
264print_if_state(int state)
265{
266	switch (state) {
267	case IF_STA_DOWN:
268		return ("DOWN");
269	case IF_STA_LOOPBACK:
270		return ("LOOPBACK");
271	case IF_STA_WAITING:
272		return ("WAITING");
273	case IF_STA_POINTTOPOINT:
274		return ("P2P");
275	case IF_STA_DROTHER:
276		return ("DROTHER");
277	case IF_STA_BACKUP:
278		return ("BACKUP");
279	case IF_STA_DR:
280		return ("DR");
281	default:
282		return ("UNKNOWN");
283	}
284}
285
286const char *
287print_nbr_state(int state)
288{
289	switch (state) {
290	case NBR_STA_DOWN:
291		return ("DOWN");
292	case NBR_STA_ATTEMPT:
293		return ("ATTEMPT");
294	case NBR_STA_INIT:
295		return ("INIT");
296	case NBR_STA_2_WAY:
297		return ("2-WAY");
298	case NBR_STA_XSTRT:
299		return ("EXSTART");
300	case NBR_STA_SNAP:
301		return ("SNAPSHOT");
302	case NBR_STA_XCHNG:
303		return ("EXCHANGE");
304	case NBR_STA_LOAD:
305		return ("LOADING");
306	case NBR_STA_FULL:
307		return ("FULL");
308	default:
309		return ("UNKNOWN");
310	}
311}
312
313const char *
314print_link(int state)
315{
316	if (state & IFF_UP)
317		return ("UP");
318	else
319		return ("DOWN");
320}
321
322#define TF_BUFS	8
323#define TF_LEN	9
324
325const char *
326fmt_timeframe(time_t t)
327{
328	if (t == 0)
329		return ("Never");
330	else
331		return (fmt_timeframe_core(time(NULL) - t));
332}
333
334const char *
335fmt_timeframe_core(time_t t)
336{
337	char		*buf;
338	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
339	static int	 idx = 0;
340	unsigned	 sec, min, hrs, day, week;
341
342	if (t == 0)
343		return ("Stopped");
344
345	buf = tfbuf[idx++];
346	if (idx == TF_BUFS)
347		idx = 0;
348
349	week = t;
350
351	sec = week % 60;
352	week /= 60;
353	min = week % 60;
354	week /= 60;
355	hrs = week % 24;
356	week /= 24;
357	day = week % 7;
358	week /= 7;
359
360	if (week > 0)
361		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
362	else if (day > 0)
363		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
364	else
365		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
366
367	return (buf);
368}
369
370const char *
371log_id(u_int32_t id)
372{
373	static char	buf[48];
374	struct in_addr	addr;
375
376	addr.s_addr = id;
377
378	if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL)
379		return ("?");
380	else
381		return (buf);
382}
383
384const char *
385log_adv_rtr(u_int32_t adv_rtr)
386{
387	static char	buf[48];
388	struct in_addr	addr;
389
390	addr.s_addr = adv_rtr;
391
392	if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL)
393		return ("?");
394	else
395		return (buf);
396}
397
398u_int8_t
399mask2prefixlen(struct in_addr ina)
400{
401	if (ina.s_addr == 0)
402		return (0);
403	else
404		return (33 - ffs(ntohl(ina.s_addr)));
405}
406
407void
408show_database_head(struct in_addr aid, u_int8_t type)
409{
410	char	*header, *format;
411
412	switch (type) {
413	case LSA_TYPE_ROUTER:
414		format = "Router Link States";
415		break;
416	case LSA_TYPE_NETWORK:
417		format = "Net Link States";
418		break;
419	case LSA_TYPE_SUM_NETWORK:
420		format = "Summary Net Link States";
421		break;
422	case LSA_TYPE_SUM_ROUTER:
423		format = "Summary Router Link States";
424		break;
425	case LSA_TYPE_EXTERNAL:
426		format = NULL;
427		if ((header = strdup("Type-5 AS External Link States")) == NULL)
428			err(1, NULL);
429		break;
430	default:
431		errx(1, "unknown LSA type");
432	}
433	if (type != LSA_TYPE_EXTERNAL)
434		if (asprintf(&header, "%s (Area %s)", format,
435		    inet_ntoa(aid)) == -1)
436			err(1, NULL);
437
438	printf("\n%-15s %s\n", "", header);
439	free(header);
440
441	printf("\n%-15s %-15s %-4s %-10s %-8s\n",
442	    "Link ID", "Adv Router", "Age", "Seq#", "Checksum");
443}
444
445int
446show_database_msg(struct imsg *imsg)
447{
448	static struct in_addr	 area_id;
449	static u_int8_t		 lasttype;
450	struct area		*area;
451	struct lsa_hdr		*lsa;
452
453	switch (imsg->hdr.type) {
454	case IMSG_CTL_SHOW_DATABASE:
455		lsa = imsg->data;
456		if (lsa->type != lasttype)
457			show_database_head(area_id, lsa->type);
458		printf("%-15s %-15s %-4d 0x%08x 0x%04x\n",
459		    log_id(lsa->ls_id), log_adv_rtr(lsa->adv_rtr),
460		    ntohs(lsa->age), ntohl(lsa->seq_num),
461		    ntohs(lsa->ls_chksum));
462		lasttype = lsa->type;
463		break;
464	case IMSG_CTL_AREA:
465		area = imsg->data;
466		area_id = area->id;
467		break;
468	case IMSG_CTL_END:
469		return (1);
470	default:
471		break;
472	}
473
474	return (0);
475}
476
477int
478show_nbr_msg(struct imsg *imsg)
479{
480	struct ctl_nbr	*nbr;
481	char		*state;
482
483	switch (imsg->hdr.type) {
484	case IMSG_CTL_SHOW_NBR:
485		nbr = imsg->data;
486		if (asprintf(&state, "%s/%s", print_nbr_state(nbr->nbr_state),
487		    print_if_state(nbr->iface_state)) == -1)
488			err(1, NULL);
489		printf("%-15s %-3d %-17s %-9s ", inet_ntoa(nbr->id),
490		    nbr->priority, state, fmt_timeframe_core(nbr->dead_timer));
491		printf("%-15s %s\n", inet_ntoa(nbr->addr), nbr->name);
492		free(state);
493		break;
494	case IMSG_CTL_END:
495		printf("\n");
496		return (1);
497	default:
498		break;
499	}
500
501	return (0);
502}
503
504const char *
505print_ospf_options(u_int8_t opts)
506{
507	static char	optbuf[32];
508
509	snprintf(optbuf, sizeof(optbuf), "*|*|%s|%s|%s|%s|%s|*",
510	    opts & OSPF_OPTION_DC ? "DC" : "-",
511	    opts & OSPF_OPTION_EA ? "EA" : "-",
512	    opts & OSPF_OPTION_NP ? "N/P" : "-",
513	    opts & OSPF_OPTION_MC ? "MC" : "-",
514	    opts & OSPF_OPTION_E ? "E" : "-");
515	return (optbuf);
516}
517
518int
519show_nbr_detail_msg(struct imsg *imsg)
520{
521	struct ctl_nbr	*nbr;
522
523	switch (imsg->hdr.type) {
524	case IMSG_CTL_SHOW_NBR:
525		nbr = imsg->data;
526		printf("\nNeighbor %s, ", inet_ntoa(nbr->id));
527		printf("interface address %s\n", inet_ntoa(nbr->addr));
528		printf("  In the area %s via interface %s\n",
529		    inet_ntoa(nbr->area), nbr->name);
530		printf("  Neighbor priority is %d, "
531		    "State is %s, %d state changes\n",
532		    nbr->priority, print_nbr_state(nbr->nbr_state),
533		    nbr->state_chng_cnt);
534		printf("  DR is %s, ", inet_ntoa(nbr->dr));
535		printf("BDR is %s\n", inet_ntoa(nbr->bdr));
536		printf("  Options is 0x%x  %s\n", nbr->options,
537		    print_ospf_options(nbr->options));
538		printf("  Dead timer due in %s\n",
539		    fmt_timeframe_core(nbr->dead_timer));
540		printf("  Database Summary List %d\n", nbr->db_sum_lst_cnt);
541		printf("  Link State Request List %d\n", nbr->ls_req_lst_cnt);
542		printf("  Link State Retransmission List %d\n",
543		    nbr->ls_retrans_lst_cnt);
544		break;
545	case IMSG_CTL_END:
546		printf("\n");
547		return (1);
548	default:
549		break;
550	}
551
552	return (0);
553}
554