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