1 /* $OpenBSD: ldpctl.c,v 1.18 2015/04/04 16:29:48 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 "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 const char *get_media_descr(int); 56 void print_baudrate(u_int64_t); 57 58 struct imsgbuf *ibuf; 59 60 __dead void 61 usage(void) 62 { 63 extern char *__progname; 64 65 fprintf(stderr, "usage: %s command [argument ...]\n", __progname); 66 exit(1); 67 } 68 69 int 70 main(int argc, char *argv[]) 71 { 72 struct sockaddr_un sun; 73 struct parse_result *res; 74 struct imsg imsg; 75 unsigned int ifidx = 0; 76 int ctl_sock; 77 int done = 0, verbose = 0; 78 int n; 79 80 /* parse options */ 81 if ((res = parse(argc - 1, argv + 1)) == NULL) 82 exit(1); 83 84 /* connect to ldpd control socket */ 85 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 86 err(1, "socket"); 87 88 bzero(&sun, sizeof(sun)); 89 sun.sun_family = AF_UNIX; 90 strlcpy(sun.sun_path, LDPD_SOCKET, sizeof(sun.sun_path)); 91 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 92 err(1, "connect: %s", LDPD_SOCKET); 93 94 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 95 err(1, NULL); 96 imsg_init(ibuf, ctl_sock); 97 done = 0; 98 99 /* process user request */ 100 switch (res->action) { 101 case NONE: 102 usage(); 103 /* not reached */ 104 case SHOW: 105 case SHOW_IFACE: 106 printf("%-11s %-10s %-10s %-8s %-12s %3s\n", 107 "Interface", "State", "Linkstate", "Uptime", 108 "Hello Timers", "ac"); 109 if (*res->ifname) { 110 ifidx = if_nametoindex(res->ifname); 111 if (ifidx == 0) 112 errx(1, "no such interface %s", res->ifname); 113 } 114 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 115 &ifidx, sizeof(ifidx)); 116 break; 117 case SHOW_DISC: 118 printf("%-15s %-9s %-15s %-9s\n", 119 "ID", "Type", "Source", "Holdtime"); 120 imsg_compose(ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, 121 NULL, 0); 122 break; 123 case SHOW_NBR: 124 printf("%-15s %-18s %-15s %-10s\n", "ID", 125 "State", "Address", "Uptime"); 126 imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); 127 break; 128 case SHOW_LIB: 129 printf("%-20s %-17s %-14s %-14s %-10s\n", "Destination", 130 "Nexthop", "Local Label", "Remote Label", "In Use"); 131 imsg_compose(ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0); 132 break; 133 case SHOW_FIB: 134 if (!res->addr.s_addr) 135 imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1, 136 &res->flags, sizeof(res->flags)); 137 else 138 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, 139 &res->addr, sizeof(res->addr)); 140 show_fib_head(); 141 break; 142 case SHOW_FIB_IFACE: 143 if (*res->ifname) 144 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, 145 res->ifname, sizeof(res->ifname)); 146 else 147 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0); 148 show_interface_head(); 149 break; 150 case FIB: 151 errx(1, "fib couple|decouple"); 152 break; 153 case FIB_COUPLE: 154 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0); 155 printf("couple request sent.\n"); 156 done = 1; 157 break; 158 case FIB_DECOUPLE: 159 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0); 160 printf("decouple request sent.\n"); 161 done = 1; 162 break; 163 case LOG_VERBOSE: 164 verbose = 1; 165 /* FALLTHROUGH */ 166 case LOG_BRIEF: 167 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 168 &verbose, sizeof(verbose)); 169 printf("logging request sent.\n"); 170 done = 1; 171 break; 172 case RELOAD: 173 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 174 printf("reload request sent.\n"); 175 done = 1; 176 break; 177 } 178 179 while (ibuf->w.queued) 180 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 181 err(1, "write error"); 182 183 while (!done) { 184 if ((n = imsg_read(ibuf)) == -1) 185 errx(1, "imsg_read error"); 186 if (n == 0) 187 errx(1, "pipe closed"); 188 189 while (!done) { 190 if ((n = imsg_get(ibuf, &imsg)) == -1) 191 errx(1, "imsg_get error"); 192 if (n == 0) 193 break; 194 switch (res->action) { 195 case SHOW: 196 case SHOW_IFACE: 197 done = show_interface_msg(&imsg); 198 break; 199 case SHOW_DISC: 200 done = show_discovery_msg(&imsg); 201 break; 202 case SHOW_NBR: 203 done = show_nbr_msg(&imsg); 204 break; 205 case SHOW_LIB: 206 done = show_lib_msg(&imsg); 207 break; 208 case SHOW_FIB: 209 done = show_fib_msg(&imsg); 210 break; 211 case SHOW_FIB_IFACE: 212 done = show_fib_interface_msg(&imsg); 213 break; 214 case NONE: 215 case FIB: 216 case FIB_COUPLE: 217 case FIB_DECOUPLE: 218 case LOG_VERBOSE: 219 case LOG_BRIEF: 220 case RELOAD: 221 break; 222 } 223 imsg_free(&imsg); 224 } 225 } 226 close(ctl_sock); 227 free(ibuf); 228 229 return (0); 230 } 231 232 int 233 get_ifms_type(int mediatype) 234 { 235 switch (mediatype) { 236 case IFT_ETHER: 237 return (IFM_ETHER); 238 break; 239 case IFT_FDDI: 240 return (IFM_FDDI); 241 break; 242 case IFT_CARP: 243 return (IFM_CARP); 244 break; 245 default: 246 return (0); 247 break; 248 } 249 } 250 251 #define TF_BUFS 8 252 #define TF_LEN 9 253 254 const char * 255 fmt_timeframe_core(time_t t) 256 { 257 char *buf; 258 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 259 static int idx = 0; 260 unsigned int sec, min, hrs, day, week; 261 262 if (t == 0) 263 return ("Stopped"); 264 265 buf = tfbuf[idx++]; 266 if (idx == TF_BUFS) 267 idx = 0; 268 269 week = t; 270 271 sec = week % 60; 272 week /= 60; 273 min = week % 60; 274 week /= 60; 275 hrs = week % 24; 276 week /= 24; 277 day = week % 7; 278 week /= 7; 279 280 if (week > 0) 281 snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs); 282 else if (day > 0) 283 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 284 else 285 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 286 287 return (buf); 288 } 289 290 /* prototype defined in ldpd.h and shared with the kroute.c version */ 291 u_int8_t 292 mask2prefixlen(in_addr_t ina) 293 { 294 if (ina == 0) 295 return (0); 296 else 297 return (33 - ffs(ntohl(ina))); 298 } 299 300 int 301 show_interface_msg(struct imsg *imsg) 302 { 303 struct ctl_iface *iface; 304 char *timers; 305 306 switch (imsg->hdr.type) { 307 case IMSG_CTL_SHOW_INTERFACE: 308 iface = imsg->data; 309 310 if (asprintf(&timers, "%u/%u", iface->hello_interval, 311 iface->hello_holdtime) == -1) 312 err(1, NULL); 313 314 printf("%-11s %-10s %-10s %-8s %12s %3u\n", 315 iface->name, if_state_name(iface->state), 316 get_linkstate(iface->mediatype, iface->linkstate), 317 iface->uptime == 0 ? "00:00:00" : 318 fmt_timeframe_core(iface->uptime), timers, 319 iface->adj_cnt); 320 free(timers); 321 break; 322 case IMSG_CTL_END: 323 printf("\n"); 324 return (1); 325 default: 326 break; 327 } 328 329 return (0); 330 } 331 332 int 333 show_discovery_msg(struct imsg *imsg) 334 { 335 struct ctl_adj *adj; 336 337 switch (imsg->hdr.type) { 338 case IMSG_CTL_SHOW_DISCOVERY: 339 adj = imsg->data; 340 341 printf("%-15s ", inet_ntoa(adj->id)); 342 switch(adj->type) { 343 case HELLO_LINK: 344 printf("%-9s %-15s ", "Link", adj->ifname); 345 break; 346 case HELLO_TARGETED: 347 printf("%-9s %-15s ", "Targeted", 348 inet_ntoa(adj->src_addr)); 349 break; 350 } 351 printf("%-9u\n", adj->holdtime); 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_lib_msg(struct imsg *imsg) 365 { 366 struct ctl_rt *rt; 367 char *dstnet, *remote; 368 369 switch (imsg->hdr.type) { 370 case IMSG_CTL_SHOW_LIB: 371 rt = imsg->data; 372 if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix), 373 rt->prefixlen) == -1) 374 err(1, NULL); 375 376 if (rt->remote_label == NO_LABEL) { 377 if (asprintf(&remote, "No Label") == -1) 378 err(1, NULL); 379 } else if (rt->remote_label == MPLS_LABEL_IMPLNULL) { 380 if (asprintf(&remote, "Pop tag") == -1) 381 err(1, NULL); 382 } else { 383 if (asprintf(&remote, "%u", rt->remote_label) == -1) 384 err(1, NULL); 385 } 386 387 printf("%-20s %-17s %-14u %-14s %s\n", dstnet, 388 inet_ntoa(rt->nexthop), rt->local_label, remote, 389 rt->in_use ? "yes" : "no"); 390 free(remote); 391 free(dstnet); 392 393 break; 394 case IMSG_CTL_END: 395 printf("\n"); 396 return (1); 397 default: 398 break; 399 } 400 401 return (0); 402 } 403 404 int 405 show_nbr_msg(struct imsg *imsg) 406 { 407 struct ctl_nbr *nbr; 408 409 switch (imsg->hdr.type) { 410 case IMSG_CTL_SHOW_NBR: 411 nbr = imsg->data; 412 printf("%-15s %-19s", inet_ntoa(nbr->id), 413 nbr_state_name(nbr->nbr_state)); 414 printf("%-15s %-15s\n", inet_ntoa(nbr->addr), 415 nbr->uptime == 0 ? "-" : fmt_timeframe_core(nbr->uptime)); 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 void 428 show_fib_head(void) 429 { 430 printf("Flags: C = Connected, S = Static\n"); 431 printf(" %-4s %-20s %-17s %-17s %s\n", "Prio", "Destination", 432 "Nexthop", "Local Label", "Remote Label"); 433 } 434 435 int 436 show_fib_msg(struct imsg *imsg) 437 { 438 struct kroute *k; 439 char *p; 440 441 switch (imsg->hdr.type) { 442 case IMSG_CTL_KROUTE: 443 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute)) 444 errx(1, "wrong imsg len"); 445 k = imsg->data; 446 447 if (k->flags & F_CONNECTED) 448 printf("C"); 449 else if (k->flags & F_STATIC) 450 printf("S"); 451 else 452 printf(" "); 453 454 printf(" %3d ", k->priority); 455 if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), 456 k->prefixlen) == -1) 457 err(1, NULL); 458 printf("%-20s ", p); 459 free(p); 460 461 if (k->nexthop.s_addr) 462 printf("%-18s", inet_ntoa(k->nexthop)); 463 else if (k->flags & F_CONNECTED) 464 printf("link#%-13u", k->ifindex); 465 466 if (k->local_label == NO_LABEL) { 467 printf("%-18s", "-"); 468 } else if (k->local_label == MPLS_LABEL_IMPLNULL) { 469 printf("%-18s", "imp-null"); 470 } else 471 printf("%-18u", k->local_label); 472 473 if (k->remote_label == NO_LABEL) { 474 printf("-"); 475 } else if (k->remote_label == MPLS_LABEL_IMPLNULL) { 476 printf("Pop"); 477 } else { 478 printf("%u", k->remote_label); 479 } 480 481 printf("\n"); 482 483 break; 484 case IMSG_CTL_END: 485 printf("\n"); 486 return (1); 487 default: 488 break; 489 } 490 491 return (0); 492 } 493 494 void 495 show_interface_head(void) 496 { 497 printf("%-15s%-15s%s\n", "Interface", "Flags", 498 "Link state"); 499 } 500 501 int 502 show_fib_interface_msg(struct imsg *imsg) 503 { 504 struct kif *k; 505 int ifms_type; 506 507 switch (imsg->hdr.type) { 508 case IMSG_CTL_IFINFO: 509 k = imsg->data; 510 printf("%-15s", k->ifname); 511 printf("%-15s", k->flags & IFF_UP ? "UP" : ""); 512 ifms_type = get_ifms_type(k->media_type); 513 if (ifms_type) 514 printf("%s, ", get_media_descr(ifms_type)); 515 516 printf("%s", get_linkstate(k->media_type, k->link_state)); 517 518 if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) { 519 printf(", "); 520 print_baudrate(k->baudrate); 521 } 522 printf("\n"); 523 break; 524 case IMSG_CTL_END: 525 printf("\n"); 526 return (1); 527 default: 528 break; 529 } 530 531 return (0); 532 } 533 534 const struct if_status_description 535 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 536 const struct ifmedia_description 537 ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; 538 539 const char * 540 get_media_descr(int media_type) 541 { 542 const struct ifmedia_description *p; 543 544 for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++) 545 if (media_type == p->ifmt_word) 546 return (p->ifmt_string); 547 548 return ("unknown"); 549 } 550 551 const char * 552 get_linkstate(int media_type, int link_state) 553 { 554 const struct if_status_description *p; 555 static char buf[8]; 556 557 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 558 if (LINK_STATE_DESC_MATCH(p, media_type, link_state)) 559 return (p->ifs_string); 560 } 561 snprintf(buf, sizeof(buf), "[#%d]", link_state); 562 return (buf); 563 } 564 565 void 566 print_baudrate(u_int64_t baudrate) 567 { 568 if (baudrate > IF_Gbps(1)) 569 printf("%llu GBit/s", baudrate / IF_Gbps(1)); 570 else if (baudrate > IF_Mbps(1)) 571 printf("%llu MBit/s", baudrate / IF_Mbps(1)); 572 else if (baudrate > IF_Kbps(1)) 573 printf("%llu KBit/s", baudrate / IF_Kbps(1)); 574 else 575 printf("%llu Bit/s", baudrate); 576 } 577