xref: /openbsd-src/usr.sbin/ldpctl/ldpctl.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: ldpctl.c,v 1.16 2013/11/14 20:48:52 deraadt Exp $
2  *
3  * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
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 #include <netmpls/mpls.h>
29 
30 #include <err.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include "ldp.h"
38 #include "ldpd.h"
39 #include "ldpe.h"
40 #include "parser.h"
41 
42 __dead void	 usage(void);
43 const char	*fmt_timeframe_core(time_t);
44 const char	*get_linkstate(int, int);
45 int		 show_interface_msg(struct imsg *);
46 int		 show_discovery_msg(struct imsg *);
47 int		 get_ifms_type(int);
48 int		 show_lib_msg(struct imsg *);
49 int		 show_nbr_msg(struct imsg *);
50 void		 show_fib_head(void);
51 int		 show_fib_msg(struct imsg *);
52 void		 show_interface_head(void);
53 int		 show_fib_interface_msg(struct imsg *);
54 const char	*get_media_descr(int);
55 void		 print_baudrate(u_int64_t);
56 
57 struct imsgbuf	*ibuf;
58 
59 __dead void
60 usage(void)
61 {
62 	extern char *__progname;
63 
64 	fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
65 	exit(1);
66 }
67 
68 int
69 main(int argc, char *argv[])
70 {
71 	struct sockaddr_un	 sun;
72 	struct parse_result	*res;
73 	struct imsg		 imsg;
74 	unsigned int		 ifidx = 0;
75 	int			 ctl_sock;
76 	int			 done = 0, verbose = 0;
77 	int			 n;
78 
79 	/* parse options */
80 	if ((res = parse(argc - 1, argv + 1)) == NULL)
81 		exit(1);
82 
83 	/* connect to ldpd control socket */
84 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
85 		err(1, "socket");
86 
87 	bzero(&sun, sizeof(sun));
88 	sun.sun_family = AF_UNIX;
89 	strlcpy(sun.sun_path, LDPD_SOCKET, sizeof(sun.sun_path));
90 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
91 		err(1, "connect: %s", LDPD_SOCKET);
92 
93 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
94 		err(1, NULL);
95 	imsg_init(ibuf, ctl_sock);
96 	done = 0;
97 
98 	/* process user request */
99 	switch (res->action) {
100 	case NONE:
101 		usage();
102 		/* not reached */
103 	case SHOW:
104 	case SHOW_IFACE:
105 		printf("%-11s %-10s %-10s %-8s %-12s %3s\n",
106 		    "Interface", "State", "Linkstate", "Uptime",
107 		    "Hello Timers", "ac");
108 		if (*res->ifname) {
109 			ifidx = if_nametoindex(res->ifname);
110 			if (ifidx == 0)
111 				errx(1, "no such interface %s", res->ifname);
112 		}
113 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
114 		    &ifidx, sizeof(ifidx));
115 		break;
116 	case SHOW_DISC:
117 		printf("%-15s %-9s %-15s %-9s\n",
118 		    "ID", "Type", "Source", "Holdtime");
119 		imsg_compose(ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1,
120 		    NULL, 0);
121 		break;
122 	case SHOW_NBR:
123 		printf("%-15s %-18s %-15s %-10s\n", "ID",
124 		    "State", "Address", "Uptime");
125 		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
126 		break;
127 	case SHOW_LIB:
128 		printf("%-20s %-17s %-14s %-14s %-10s\n", "Destination",
129 		    "Nexthop", "Local Label", "Remote Label", "In Use");
130 		imsg_compose(ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0);
131 		break;
132 	case SHOW_FIB:
133 		if (!res->addr.s_addr)
134 			imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
135 			    &res->flags, sizeof(res->flags));
136 		else
137 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
138 			    &res->addr, sizeof(res->addr));
139 		show_fib_head();
140 		break;
141 	case SHOW_FIB_IFACE:
142 		if (*res->ifname)
143 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
144 			    res->ifname, sizeof(res->ifname));
145 		else
146 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
147 		show_interface_head();
148 		break;
149 	case FIB:
150 		errx(1, "fib couple|decouple");
151 		break;
152 	case FIB_COUPLE:
153 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
154 		printf("couple request sent.\n");
155 		done = 1;
156 		break;
157 	case FIB_DECOUPLE:
158 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
159 		printf("decouple request sent.\n");
160 		done = 1;
161 		break;
162 	case LOG_VERBOSE:
163 		verbose = 1;
164 		/* FALLTHROUGH */
165 	case LOG_BRIEF:
166 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
167 		    &verbose, sizeof(verbose));
168 		printf("logging request sent.\n");
169 		done = 1;
170 		break;
171 	case RELOAD:
172 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
173 		printf("reload request sent.\n");
174 		done = 1;
175 		break;
176 	}
177 
178 	while (ibuf->w.queued)
179 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
180 			err(1, "write error");
181 
182 	while (!done) {
183 		if ((n = imsg_read(ibuf)) == -1)
184 			errx(1, "imsg_read error");
185 		if (n == 0)
186 			errx(1, "pipe closed");
187 
188 		while (!done) {
189 			if ((n = imsg_get(ibuf, &imsg)) == -1)
190 				errx(1, "imsg_get error");
191 			if (n == 0)
192 				break;
193 			switch (res->action) {
194 			case SHOW:
195 			case SHOW_IFACE:
196 				done = show_interface_msg(&imsg);
197 				break;
198 			case SHOW_DISC:
199 				done = show_discovery_msg(&imsg);
200 				break;
201 			case SHOW_NBR:
202 				done = show_nbr_msg(&imsg);
203 				break;
204 			case SHOW_LIB:
205 				done = show_lib_msg(&imsg);
206 				break;
207 			case SHOW_FIB:
208 				done = show_fib_msg(&imsg);
209 				break;
210 			case SHOW_FIB_IFACE:
211 				done = show_fib_interface_msg(&imsg);
212 				break;
213 			case NONE:
214 			case FIB:
215 			case FIB_COUPLE:
216 			case FIB_DECOUPLE:
217 			case LOG_VERBOSE:
218 			case LOG_BRIEF:
219 			case RELOAD:
220 				break;
221 			}
222 			imsg_free(&imsg);
223 		}
224 	}
225 	close(ctl_sock);
226 	free(ibuf);
227 
228 	return (0);
229 }
230 
231 int
232 get_ifms_type(int mediatype)
233 {
234 	switch (mediatype) {
235 	case IFT_ETHER:
236 		return (IFM_ETHER);
237 		break;
238 	case IFT_FDDI:
239 		return (IFM_FDDI);
240 		break;
241 	case IFT_CARP:
242 		return (IFM_CARP);
243 		break;
244 	default:
245 		return (0);
246 		break;
247 	}
248 }
249 
250 #define	TF_BUFS	8
251 #define	TF_LEN	9
252 
253 const char *
254 fmt_timeframe_core(time_t t)
255 {
256 	char		*buf;
257 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
258 	static int	 idx = 0;
259 	unsigned int	 sec, min, hrs, day, week;
260 
261 	if (t == 0)
262 		return ("Stopped");
263 
264 	buf = tfbuf[idx++];
265 	if (idx == TF_BUFS)
266 		idx = 0;
267 
268 	week = t;
269 
270 	sec = week % 60;
271 	week /= 60;
272 	min = week % 60;
273 	week /= 60;
274 	hrs = week % 24;
275 	week /= 24;
276 	day = week % 7;
277 	week /= 7;
278 
279 	if (week > 0)
280 		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
281 	else if (day > 0)
282 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
283 	else
284 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
285 
286 	return (buf);
287 }
288 
289 /* prototype defined in ldpd.h and shared with the kroute.c version */
290 u_int8_t
291 mask2prefixlen(in_addr_t ina)
292 {
293 	if (ina == 0)
294 		return (0);
295 	else
296 		return (33 - ffs(ntohl(ina)));
297 }
298 
299 int
300 show_interface_msg(struct imsg *imsg)
301 {
302 	struct ctl_iface	*iface;
303 	char			*timers;
304 
305 	switch (imsg->hdr.type) {
306 	case IMSG_CTL_SHOW_INTERFACE:
307 		iface = imsg->data;
308 
309 		if (asprintf(&timers, "%u/%u", iface->hello_interval,
310 		    iface->hello_holdtime) == -1)
311 			err(1, NULL);
312 
313 		printf("%-11s %-10s %-10s %-8s %12s %3u\n",
314 		    iface->name, if_state_name(iface->state),
315 		    get_linkstate(iface->mediatype, iface->linkstate),
316 		    iface->uptime == 0 ? "00:00:00" :
317 		    fmt_timeframe_core(iface->uptime), timers,
318 		    iface->adj_cnt);
319 		free(timers);
320 		break;
321 	case IMSG_CTL_END:
322 		printf("\n");
323 		return (1);
324 	default:
325 		break;
326 	}
327 
328 	return (0);
329 }
330 
331 int
332 show_discovery_msg(struct imsg *imsg)
333 {
334 	struct ctl_adj		*adj;
335 
336 	switch (imsg->hdr.type) {
337 	case IMSG_CTL_SHOW_DISCOVERY:
338 		adj = imsg->data;
339 
340 		printf("%-15s ", inet_ntoa(adj->id));
341 		switch(adj->type) {
342 		case HELLO_LINK:
343 			printf("%-9s %-15s ", "Link", adj->ifname);
344 			break;
345 		case HELLO_TARGETED:
346 			printf("%-9s %-15s ", "Targeted",
347 			    inet_ntoa(adj->src_addr));
348 			break;
349 		}
350 		printf("%-9u\n", adj->holdtime);
351 		break;
352 	case IMSG_CTL_END:
353 		printf("\n");
354 		return (1);
355 	default:
356 		break;
357 	}
358 
359 	return (0);
360 }
361 
362 int
363 show_lib_msg(struct imsg *imsg)
364 {
365 	struct ctl_rt	*rt;
366 	char		*dstnet, *remote;
367 
368 	switch (imsg->hdr.type) {
369 	case IMSG_CTL_SHOW_LIB:
370 		rt = imsg->data;
371 		if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix),
372 		    rt->prefixlen) == -1)
373 			err(1, NULL);
374 		if (!rt->in_use) {
375 			if (asprintf(&remote, "-") == -1)
376 				err(1, NULL);
377 		} else if (rt->connected || rt->remote_label == NO_LABEL) {
378 			if (asprintf(&remote, "Untagged") == -1)
379 				err(1, NULL);
380 		} else if (rt->remote_label == MPLS_LABEL_IMPLNULL) {
381 			if (asprintf(&remote, "Pop tag") == -1)
382 				err(1, NULL);
383 		} else {
384 			if (asprintf(&remote, "%u", rt->remote_label) == -1)
385 				err(1, NULL);
386 		}
387 
388 		printf("%-20s %-17s %-14u %-14s %s\n", dstnet,
389 		    inet_ntoa(rt->nexthop), rt->local_label, remote,
390 		    rt->in_use ? "yes" : "no");
391 		free(remote);
392 		free(dstnet);
393 
394 		break;
395 	case IMSG_CTL_END:
396 		printf("\n");
397 		return (1);
398 	default:
399 		break;
400 	}
401 
402 	return (0);
403 }
404 
405 int
406 show_nbr_msg(struct imsg *imsg)
407 {
408 	struct ctl_nbr	*nbr;
409 
410 	switch (imsg->hdr.type) {
411 	case IMSG_CTL_SHOW_NBR:
412 		nbr = imsg->data;
413 		printf("%-15s %-19s", inet_ntoa(nbr->id),
414 		    nbr_state_name(nbr->nbr_state));
415 		printf("%-15s %-15s\n", inet_ntoa(nbr->addr),
416 		    nbr->uptime == 0 ? "-" : fmt_timeframe_core(nbr->uptime));
417 		break;
418 	case IMSG_CTL_END:
419 		printf("\n");
420 		return (1);
421 	default:
422 		break;
423 	}
424 
425 	return (0);
426 }
427 
428 void
429 show_fib_head(void)
430 {
431 	printf("Flags: C = Connected, S = Static\n");
432 	printf(" %-4s %-20s %-17s %-17s %s\n", "Prio", "Destination",
433 	    "Nexthop", "Local Label", "Remote Label");
434 }
435 
436 int
437 show_fib_msg(struct imsg *imsg)
438 {
439 	struct kroute		*k;
440 	char			*p;
441 
442 	switch (imsg->hdr.type) {
443 	case IMSG_CTL_KROUTE:
444 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
445 			errx(1, "wrong imsg len");
446 		k = imsg->data;
447 
448 		if (k->flags & F_CONNECTED)
449 			printf("C");
450 		else if (k->flags & F_STATIC)
451 			printf("S");
452 		else
453 			printf(" ");
454 
455 		printf(" %3d ", k->priority);
456 		if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix),
457 		    k->prefixlen) == -1)
458 			err(1, NULL);
459 		printf("%-20s ", p);
460 		free(p);
461 
462 		if (k->nexthop.s_addr)
463 			printf("%-18s", inet_ntoa(k->nexthop));
464 		else if (k->flags & F_CONNECTED)
465 			printf("link#%-13u", k->ifindex);
466 
467 		if (k->local_label == NO_LABEL) {
468 			printf("%-18s", "-");
469 		} else if (k->local_label == MPLS_LABEL_IMPLNULL) {
470 			printf("%-18s", "imp-null");
471 		} else
472 			printf("%-18u", k->local_label);
473 
474 		if (k->remote_label == NO_LABEL) {
475 			printf("-");
476 		} else if (k->remote_label == MPLS_LABEL_IMPLNULL) {
477 			printf("Pop");
478 		} else {
479 			printf("%u", k->remote_label);
480 		}
481 
482 		printf("\n");
483 
484 		break;
485 	case IMSG_CTL_END:
486 		printf("\n");
487 		return (1);
488 	default:
489 		break;
490 	}
491 
492 	return (0);
493 }
494 
495 void
496 show_interface_head(void)
497 {
498 	printf("%-15s%-15s%s\n", "Interface", "Flags",
499 	    "Link state");
500 }
501 
502 int
503 show_fib_interface_msg(struct imsg *imsg)
504 {
505 	struct kif	*k;
506 	int		 ifms_type;
507 
508 	switch (imsg->hdr.type) {
509 	case IMSG_CTL_IFINFO:
510 		k = imsg->data;
511 		printf("%-15s", k->ifname);
512 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
513 		ifms_type = get_ifms_type(k->media_type);
514 		if (ifms_type)
515 			printf("%s, ", get_media_descr(ifms_type));
516 
517 		printf("%s", get_linkstate(k->media_type, k->link_state));
518 
519 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
520 			printf(", ");
521 			print_baudrate(k->baudrate);
522 		}
523 		printf("\n");
524 		break;
525 	case IMSG_CTL_END:
526 		printf("\n");
527 		return (1);
528 	default:
529 		break;
530 	}
531 
532 	return (0);
533 }
534 
535 const struct if_status_description
536 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
537 const struct ifmedia_description
538 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
539 
540 const char *
541 get_media_descr(int media_type)
542 {
543 	const struct ifmedia_description	*p;
544 
545 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
546 		if (media_type == p->ifmt_word)
547 			return (p->ifmt_string);
548 
549 	return ("unknown");
550 }
551 
552 const char *
553 get_linkstate(int media_type, int link_state)
554 {
555 	const struct if_status_description *p;
556 	static char buf[8];
557 
558 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
559 		if (LINK_STATE_DESC_MATCH(p, media_type, link_state))
560 			return (p->ifs_string);
561 	}
562 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
563 	return (buf);
564 }
565 
566 void
567 print_baudrate(u_int64_t baudrate)
568 {
569 	if (baudrate > IF_Gbps(1))
570 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
571 	else if (baudrate > IF_Mbps(1))
572 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
573 	else if (baudrate > IF_Kbps(1))
574 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
575 	else
576 		printf("%llu Bit/s", baudrate);
577 }
578