1 /* $OpenBSD: ldpctl.c,v 1.32 2016/07/15 17:09:25 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 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 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 imsg_init(ibuf, ctl_sock); 105 done = 0; 106 107 /* process user request */ 108 switch (res->action) { 109 case NONE: 110 usage(); 111 /* not reached */ 112 case SHOW: 113 case SHOW_IFACE: 114 printf("%-4s %-11s %-6s %-10s %-8s %-12s %3s\n", 115 "AF", "Interface", "State", "Linkstate", "Uptime", 116 "Hello Timers", "ac"); 117 if (*res->ifname) { 118 ifidx = if_nametoindex(res->ifname); 119 if (ifidx == 0) 120 errx(1, "no such interface %s", res->ifname); 121 } 122 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 123 &ifidx, sizeof(ifidx)); 124 break; 125 case SHOW_DISC: 126 printf("%-4s %-15s %-8s %-15s %9s\n", 127 "AF", "ID", "Type", "Source", "Holdtime"); 128 imsg_compose(ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, 129 NULL, 0); 130 break; 131 case SHOW_NBR: 132 printf("%-4s %-15s %-11s %-15s %8s\n", 133 "AF", "ID", "State", "Remote Address", "Uptime"); 134 imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); 135 break; 136 case SHOW_LIB: 137 printf("%-4s %-20s %-15s %-11s %-13s %6s\n", "AF", 138 "Destination", "Nexthop", "Local Label", "Remote Label", 139 "In Use"); 140 imsg_compose(ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0); 141 break; 142 case SHOW_FIB: 143 if (!ldp_addrisset(res->family, &res->addr)) 144 imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1, 145 &res->flags, sizeof(res->flags)); 146 else { 147 memset(&kr, 0, sizeof(kr)); 148 kr.af = res->family; 149 kr.prefix = res->addr; 150 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, 151 &kr, sizeof(kr)); 152 } 153 show_fib_head(); 154 break; 155 case SHOW_FIB_IFACE: 156 if (*res->ifname) 157 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, 158 res->ifname, sizeof(res->ifname)); 159 else 160 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0); 161 show_interface_head(); 162 break; 163 case SHOW_L2VPN_PW: 164 printf("%-11s %-15s %-14s %-10s\n", 165 "Interface", "Neighbor", "PWID", "Status"); 166 imsg_compose(ibuf, IMSG_CTL_SHOW_L2VPN_PW, 0, 0, -1, NULL, 0); 167 break; 168 case SHOW_L2VPN_BINDING: 169 imsg_compose(ibuf, IMSG_CTL_SHOW_L2VPN_BINDING, 0, 0, -1, 170 NULL, 0); 171 break; 172 case CLEAR_NBR: 173 memset(&nbr, 0, sizeof(nbr)); 174 nbr.af = res->family; 175 memcpy(&nbr.raddr, &res->addr, sizeof(nbr.raddr)); 176 imsg_compose(ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr, 177 sizeof(nbr)); 178 done = 1; 179 break; 180 case FIB: 181 errx(1, "fib couple|decouple"); 182 break; 183 case FIB_COUPLE: 184 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0); 185 printf("couple request sent.\n"); 186 done = 1; 187 break; 188 case FIB_DECOUPLE: 189 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0); 190 printf("decouple request sent.\n"); 191 done = 1; 192 break; 193 case LOG_VERBOSE: 194 verbose = 1; 195 /* FALLTHROUGH */ 196 case LOG_BRIEF: 197 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 198 &verbose, sizeof(verbose)); 199 printf("logging request sent.\n"); 200 done = 1; 201 break; 202 case RELOAD: 203 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 204 printf("reload request sent.\n"); 205 done = 1; 206 break; 207 } 208 209 while (ibuf->w.queued) 210 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 211 err(1, "write error"); 212 213 while (!done) { 214 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 215 errx(1, "imsg_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 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 * 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 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 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 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 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 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 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 542 show_interface_head(void) 543 { 544 printf("%-15s%-15s%s\n", "Interface", "Flags", 545 "Link state"); 546 } 547 548 int 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 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 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 * 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 * 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 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