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