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