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