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