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