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