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