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