1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <locale.h> 30 #include <stdarg.h> 31 #include <stdlib.h> 32 #include <fcntl.h> 33 #include <string.h> 34 #include <stropts.h> 35 #include <errno.h> 36 #include <kstat.h> 37 #include <strings.h> 38 #include <getopt.h> 39 #include <unistd.h> 40 #include <priv.h> 41 #include <libintl.h> 42 #include <libdlpi.h> 43 #include <libdladm.h> 44 #include <liblaadm.h> 45 #include <libmacadm.h> 46 47 #define AGGR_DRV "aggr" 48 #define MAXPORT 256 49 #define DUMP_LACP_FORMAT " %-9s %-8s %-7s %-12s " \ 50 "%-5s %-4s %-4s %-9s %-7s\n" 51 52 typedef struct pktsum_s { 53 uint64_t ipackets; 54 uint64_t opackets; 55 uint64_t rbytes; 56 uint64_t obytes; 57 uint32_t ierrors; 58 uint32_t oerrors; 59 } pktsum_t; 60 61 typedef struct show_link_state { 62 boolean_t ls_firstonly; 63 boolean_t ls_donefirst; 64 boolean_t ls_stats; 65 pktsum_t ls_prevstats; 66 boolean_t ls_parseable; 67 } show_link_state_t; 68 69 typedef struct show_grp_state { 70 uint32_t gs_key; 71 boolean_t gs_lacp; 72 boolean_t gs_found; 73 boolean_t gs_stats; 74 boolean_t gs_firstonly; 75 pktsum_t gs_prevstats[MAXPORT]; 76 boolean_t gs_parseable; 77 } show_grp_state_t; 78 79 typedef struct show_mac_state { 80 boolean_t ms_firstonly; 81 boolean_t ms_donefirst; 82 pktsum_t ms_prevstats; 83 boolean_t ms_parseable; 84 } show_mac_state_t; 85 86 typedef struct port_state { 87 char *state_name; 88 aggr_port_state_t state_num; 89 } port_state_t; 90 91 static port_state_t port_states[] = { 92 {"standby", AGGR_PORT_STATE_STANDBY }, 93 {"attached", AGGR_PORT_STATE_ATTACHED } 94 }; 95 96 #define NPORTSTATES (sizeof (port_states) / sizeof (port_state_t)) 97 98 static void do_show_link(int, char **); 99 static void do_create_aggr(int, char **); 100 static void do_delete_aggr(int, char **); 101 static void do_add_aggr(int, char **); 102 static void do_remove_aggr(int, char **); 103 static void do_modify_aggr(int, char **); 104 static void do_show_aggr(int, char **); 105 static void do_up_aggr(int, char **); 106 static void do_down_aggr(int, char **); 107 static void do_show_dev(int, char **); 108 109 static void link_stats(const char *, uint32_t); 110 static void aggr_stats(uint16_t, uint32_t); 111 static void dev_stats(const char *dev, uint32_t); 112 113 static void get_mac_stats(const char *, pktsum_t *); 114 static void get_link_stats(const char *, pktsum_t *); 115 static uint64_t mac_ifspeed(const char *); 116 static char *mac_link_state(const char *); 117 static char *mac_link_duplex(const char *); 118 static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 119 static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 120 121 typedef struct cmd { 122 char *c_name; 123 void (*c_fn)(int, char **); 124 } cmd_t; 125 126 static cmd_t cmds[] = { 127 { "show-link", do_show_link }, 128 { "show-dev", do_show_dev }, 129 130 { "create-aggr", do_create_aggr }, 131 { "delete-aggr", do_delete_aggr }, 132 { "add-aggr", do_add_aggr }, 133 { "remove-aggr", do_remove_aggr }, 134 { "modify-aggr", do_modify_aggr }, 135 { "show-aggr", do_show_aggr }, 136 { "up-aggr", do_up_aggr }, 137 { "down-aggr", do_down_aggr } 138 }; 139 140 static const struct option longopts[] = { 141 {"vlan-id", required_argument, 0, 'v'}, 142 {"dev", required_argument, 0, 'd'}, 143 {"policy", required_argument, 0, 'P'}, 144 {"lacp-mode", required_argument, 0, 'l'}, 145 {"lacp-timer", required_argument, 0, 'T'}, 146 {"unicast", required_argument, 0, 'u'}, 147 {"statistics", no_argument, 0, 's'}, 148 {"interval", required_argument, 0, 'i'}, 149 {"lacp", no_argument, 0, 'L'}, 150 {"temporary", no_argument, 0, 't'}, 151 {"root-dir", required_argument, 0, 'r'}, 152 {"parseable", no_argument, 0, 'p'}, 153 { 0, 0, 0, 0 } 154 }; 155 156 static char *progname; 157 158 #define PRINT_ERR_DIAG(s, diag, func) { \ 159 (void) fprintf(stderr, gettext(s), progname, strerror(errno)); \ 160 if (diag != 0) \ 161 (void) fprintf(stderr, " (%s)", func(diag)); \ 162 (void) fprintf(stderr, "\n"); \ 163 } 164 165 static void 166 usage(void) 167 { 168 (void) fprintf(stderr, gettext( 169 "usage: dladm create-aggr [-t] [-R <root-dir>] [-P <policy>]\n" 170 " [-l <mode>] [-T <time>]\n" 171 " [-u <address>] -d <dev> ... <key>\n" 172 " delete-aggr [-t] [-R <root-dir>] <key>\n" 173 " add-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 174 " remove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n" 175 " modify-aggr [-t] [-R <root-dir>] [-P <policy>]\n" 176 " [-l <mode>] [-T <time>] [-u <address>] <key>\n" 177 " show-aggr [-L] [-s] [-i <interval>] [-p] [<key>]\n" 178 " show-dev [-s] [-i <interval>] [-p] [<dev>]\n" 179 " show-link [-s] [-i <interval>] [-p] [<name>]\n")); 180 exit(1); 181 } 182 183 int 184 main(int argc, char *argv[]) 185 { 186 int i; 187 cmd_t *cmdp; 188 189 (void) setlocale(LC_ALL, ""); 190 #if !defined(TEXT_DOMAIN) 191 #define TEXT_DOMAIN "SYS_TEST" 192 #endif 193 (void) textdomain(TEXT_DOMAIN); 194 195 progname = argv[0]; 196 197 if (argc < 2) 198 usage(); 199 200 if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 201 !priv_ineffect(PRIV_NET_RAWACCESS)) { 202 (void) fprintf(stderr, 203 gettext("%s: insufficient privileges\n"), progname); 204 exit(1); 205 } 206 207 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 208 cmdp = &cmds[i]; 209 if (strcmp(argv[1], cmdp->c_name) == 0) { 210 cmdp->c_fn(argc - 1, &argv[1]); 211 exit(0); 212 } 213 } 214 215 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 216 progname, argv[1]); 217 usage(); 218 219 return (0); 220 } 221 222 223 static void 224 do_create_aggr(int argc, char *argv[]) 225 { 226 char option; 227 uint16_t key; 228 uint32_t policy = AGGR_POLICY_L4; 229 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 230 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 231 laadm_port_attr_db_t port[MAXPORT]; 232 uint_t nport = 0; 233 uint8_t mac_addr[ETHERADDRL]; 234 boolean_t mac_addr_fixed = B_FALSE; 235 boolean_t P_arg = B_FALSE; 236 boolean_t l_arg = B_FALSE; 237 boolean_t t_arg = B_FALSE; 238 boolean_t u_arg = B_FALSE; 239 boolean_t T_arg = B_FALSE; 240 char *altroot = NULL; 241 char *endp = NULL; 242 laadm_diag_t diag = 0; 243 244 opterr = 0; 245 while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:", 246 longopts, NULL)) != -1) { 247 switch (option) { 248 case 'd': 249 if (nport >= MAXPORT) { 250 (void) fprintf(stderr, 251 gettext("%s: too many <dev> arguments\n"), 252 progname); 253 exit(1); 254 } 255 256 if (strlcpy(port[nport].lp_devname, optarg, 257 MAXNAMELEN) >= MAXNAMELEN) { 258 (void) fprintf(stderr, 259 gettext("%s: device name too long\n"), 260 progname); 261 exit(1); 262 } 263 264 nport++; 265 break; 266 case 'P': 267 if (P_arg) { 268 (void) fprintf(stderr, gettext( 269 "%s: the option -P cannot be specified " 270 "more than once\n"), progname); 271 usage(); 272 } 273 274 P_arg = B_TRUE; 275 276 if (!laadm_str_to_policy(optarg, &policy)) { 277 (void) fprintf(stderr, 278 gettext("%s: invalid policy '%s'\n"), 279 progname, optarg); 280 exit(1); 281 } 282 break; 283 case 'u': 284 if (u_arg) { 285 (void) fprintf(stderr, gettext( 286 "%s: the option -u cannot be specified " 287 "more than once\n"), progname); 288 usage(); 289 } 290 291 u_arg = B_TRUE; 292 293 if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 294 mac_addr)) { 295 (void) fprintf(stderr, 296 gettext("%s: invalid MAC address '%s'\n"), 297 progname, optarg); 298 exit(1); 299 } 300 301 break; 302 case 'l': 303 if (l_arg) { 304 (void) fprintf(stderr, gettext( 305 "%s: the option -l cannot be specified " 306 "more than once\n"), progname); 307 usage(); 308 } 309 310 l_arg = B_TRUE; 311 312 if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) { 313 (void) fprintf(stderr, 314 gettext("%s: invalid LACP mode '%s'\n"), 315 progname, optarg); 316 exit(1); 317 } 318 319 break; 320 case 'T': 321 if (T_arg) { 322 (void) fprintf(stderr, gettext( 323 "%s: the option -T cannot be specified " 324 "more than once\n"), progname); 325 usage(); 326 } 327 328 T_arg = B_TRUE; 329 330 if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) { 331 (void) fprintf(stderr, 332 gettext("%s: invalid LACP timer value" 333 " '%s'\n"), 334 progname, optarg); 335 exit(1); 336 } 337 338 break; 339 case 't': 340 t_arg = B_TRUE; 341 break; 342 case 'R': 343 altroot = optarg; 344 break; 345 case ':': 346 (void) fprintf(stderr, 347 gettext("%s: option requires a value '-%c'\n"), 348 progname, optopt); 349 exit(1); 350 /*NOTREACHED*/ 351 case '?': 352 default: 353 (void) fprintf(stderr, 354 gettext("%s: unrecognized option '-%c'\n"), 355 progname, optopt); 356 exit(1); 357 } 358 } 359 360 if (nport == 0) 361 usage(); 362 363 /* get key value (required last argument) */ 364 if (optind != (argc-1)) 365 usage(); 366 367 errno = 0; 368 key = (int)strtol(argv[optind], &endp, 10); 369 if (errno != 0 || key < 1 || *endp != '\0') { 370 (void) fprintf(stderr, 371 gettext("%s: illegal key value '%d'\n"), 372 progname, key); 373 exit(1); 374 } 375 376 if (laadm_create(key, nport, port, policy, mac_addr_fixed, 377 mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) { 378 PRINT_ERR_DIAG("%s: create operation failed: %s", diag, 379 laadm_diag); 380 exit(1); 381 } 382 } 383 384 static void 385 do_delete_aggr(int argc, char *argv[]) 386 { 387 uint16_t key; 388 char option; 389 boolean_t t_arg = B_FALSE; 390 char *altroot = NULL; 391 char *endp = NULL; 392 laadm_diag_t diag = 0; 393 394 opterr = 0; 395 while ((option = getopt_long(argc, argv, ":R:t", longopts, 396 NULL)) != -1) { 397 switch (option) { 398 399 case 't': 400 t_arg = B_TRUE; 401 break; 402 case 'R': 403 altroot = optarg; 404 break; 405 case ':': 406 (void) fprintf(stderr, 407 gettext("%s: option requires a value '-%c'\n"), 408 progname, optopt); 409 exit(1); 410 break; 411 case '?': 412 default: 413 (void) fprintf(stderr, 414 gettext("%s: unrecognized option '-%c'\n"), 415 progname, optopt); 416 exit(1); 417 break; 418 } 419 } 420 421 /* get key value (required last argument) */ 422 if (optind != (argc-1)) 423 usage(); 424 425 errno = 0; 426 key = (int)strtol(argv[optind], &endp, 10); 427 if (errno != 0 || key < 1 || *endp != '\0') { 428 (void) fprintf(stderr, 429 gettext("%s: illegal key value '%d'\n"), 430 progname, key); 431 exit(1); 432 } 433 434 if (laadm_delete(key, t_arg, altroot, &diag) < 0) { 435 PRINT_ERR_DIAG("%s: delete operation failed: %s", diag, 436 laadm_diag); 437 exit(1); 438 } 439 } 440 441 static void 442 do_add_aggr(int argc, char *argv[]) 443 { 444 char option; 445 uint16_t key; 446 laadm_port_attr_db_t port[MAXPORT]; 447 uint_t nport = 0; 448 boolean_t t_arg = B_FALSE; 449 char *altroot = NULL; 450 char *endp = NULL; 451 laadm_diag_t diag = 0; 452 453 opterr = 0; 454 while ((option = getopt_long(argc, argv, ":d:R:t", longopts, 455 NULL)) != -1) { 456 switch (option) { 457 case 'd': 458 if (nport >= MAXPORT) { 459 (void) fprintf(stderr, 460 gettext("%s: too many <dev> arguments\n"), 461 progname); 462 exit(1); 463 } 464 465 if (strlcpy(port[nport].lp_devname, optarg, 466 MAXNAMELEN) >= MAXNAMELEN) { 467 (void) fprintf(stderr, 468 gettext("%s: device name too long\n"), 469 progname); 470 exit(1); 471 } 472 nport++; 473 break; 474 case 't': 475 t_arg = B_TRUE; 476 break; 477 case 'R': 478 altroot = optarg; 479 break; 480 case ':': 481 (void) fprintf(stderr, 482 gettext("%s: option requires a value '-%c'\n"), 483 progname, optopt); 484 exit(1); 485 /*NOTREACHED*/ 486 case '?': 487 default: 488 (void) fprintf(stderr, 489 gettext("%s: unrecognized option '-%c'\n"), 490 progname, optopt); 491 exit(1); 492 } 493 } 494 495 if (nport == 0) 496 usage(); 497 498 /* get key value (required last argument) */ 499 if (optind != (argc-1)) 500 usage(); 501 502 errno = 0; 503 key = (int)strtol(argv[optind], &endp, 10); 504 if (errno != 0 || key < 1 || *endp != '\0') { 505 (void) fprintf(stderr, 506 gettext("%s: illegal key value '%d'\n"), 507 progname, key); 508 exit(1); 509 } 510 511 if (laadm_add(key, nport, port, t_arg, altroot, &diag) < 0) { 512 /* 513 * checking ENOTSUP is a temporary workaround 514 * and should be removed once 6399681 is fixed. 515 */ 516 if (errno == ENOTSUP) { 517 (void) fprintf(stderr, 518 gettext("%s: add operation failed: %s\n"), 519 progname, 520 gettext("device capabilities don't match")); 521 exit(ENOTSUP); 522 } 523 PRINT_ERR_DIAG("%s: add operation failed: %s", diag, 524 laadm_diag); 525 exit(1); 526 } 527 } 528 529 static void 530 do_remove_aggr(int argc, char *argv[]) 531 { 532 char option; 533 uint16_t key; 534 laadm_port_attr_db_t port[MAXPORT]; 535 uint_t nport = 0; 536 boolean_t t_arg = B_FALSE; 537 char *altroot = NULL; 538 char *endp = NULL; 539 laadm_diag_t diag = 0; 540 541 opterr = 0; 542 while ((option = getopt_long(argc, argv, ":d:R:t", 543 longopts, NULL)) != -1) { 544 switch (option) { 545 case 'd': 546 if (nport >= MAXPORT) { 547 (void) fprintf(stderr, 548 gettext("%s: too many <dev> arguments\n"), 549 progname); 550 exit(1); 551 } 552 553 if (strlcpy(port[nport].lp_devname, optarg, 554 MAXNAMELEN) >= MAXNAMELEN) { 555 (void) fprintf(stderr, 556 gettext("%s: device name too long\n"), 557 progname); 558 exit(1); 559 } 560 nport++; 561 break; 562 case 't': 563 t_arg = B_TRUE; 564 break; 565 case 'R': 566 altroot = optarg; 567 break; 568 case ':': 569 (void) fprintf(stderr, 570 gettext("%s: option requires a value '-%c'\n"), 571 progname, optopt); 572 exit(1); 573 /*NOTREACHED*/ 574 case '?': 575 default: 576 (void) fprintf(stderr, 577 gettext("%s: unrecognized option '-%c'\n"), 578 progname, optopt); 579 exit(1); 580 } 581 } 582 583 if (nport == 0) 584 usage(); 585 586 /* get key value (required last argument) */ 587 if (optind != (argc-1)) 588 usage(); 589 590 errno = 0; 591 key = (int)strtol(argv[optind], &endp, 10); 592 if (errno != 0 || key < 1 || *endp != '\0') { 593 (void) fprintf(stderr, 594 gettext("%s: illegal key value '%d'\n"), 595 progname, key); 596 exit(1); 597 } 598 599 if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) { 600 PRINT_ERR_DIAG("%s: remove operation failed: %s", diag, 601 laadm_diag); 602 exit(1); 603 } 604 } 605 606 static void 607 do_modify_aggr(int argc, char *argv[]) 608 { 609 char option; 610 uint16_t key; 611 uint32_t policy = AGGR_POLICY_L4; 612 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 613 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 614 uint8_t mac_addr[ETHERADDRL]; 615 boolean_t mac_addr_fixed = B_FALSE; 616 uint8_t modify_mask = 0; 617 boolean_t t_arg = B_FALSE; 618 char *altroot = NULL; 619 char *endp = NULL; 620 laadm_diag_t diag = 0; 621 622 opterr = 0; 623 while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts, 624 NULL)) != -1) { 625 switch (option) { 626 case 'P': 627 if (modify_mask & LAADM_MODIFY_POLICY) { 628 (void) fprintf(stderr, gettext( 629 "%s: the option -P cannot be specified " 630 "more than once\n"), progname); 631 usage(); 632 } 633 634 modify_mask |= LAADM_MODIFY_POLICY; 635 636 if (!laadm_str_to_policy(optarg, &policy)) { 637 (void) fprintf(stderr, 638 gettext("%s: invalid policy '%s'\n"), 639 progname, optarg); 640 exit(1); 641 } 642 break; 643 case 'u': 644 if (modify_mask & LAADM_MODIFY_MAC) { 645 (void) fprintf(stderr, gettext( 646 "%s: the option -u cannot be specified " 647 "more than once\n"), progname); 648 usage(); 649 } 650 651 modify_mask |= LAADM_MODIFY_MAC; 652 653 if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed, 654 mac_addr)) { 655 (void) fprintf(stderr, 656 gettext("%s: invalid MAC address '%s'\n"), 657 progname, optarg); 658 exit(1); 659 } 660 661 break; 662 case 'l': 663 if (modify_mask & LAADM_MODIFY_LACP_MODE) { 664 (void) fprintf(stderr, gettext( 665 "%s: the option -l cannot be specified " 666 "more than once\n"), progname); 667 usage(); 668 } 669 670 modify_mask |= LAADM_MODIFY_LACP_MODE; 671 672 if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) { 673 (void) fprintf(stderr, 674 gettext("%s: invalid LACP mode '%s'\n"), 675 progname, optarg); 676 exit(1); 677 } 678 679 break; 680 case 'T': 681 if (modify_mask & LAADM_MODIFY_LACP_TIMER) { 682 (void) fprintf(stderr, gettext( 683 "%s: the option -T cannot be specified " 684 "more than once\n"), progname); 685 usage(); 686 } 687 688 modify_mask |= LAADM_MODIFY_LACP_TIMER; 689 690 if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) { 691 (void) fprintf(stderr, 692 gettext("%s: invalid LACP timer value" 693 " '%s'\n"), 694 progname, optarg); 695 exit(1); 696 } 697 698 break; 699 case 't': 700 t_arg = B_TRUE; 701 break; 702 case 'R': 703 altroot = optarg; 704 break; 705 case ':': 706 (void) fprintf(stderr, 707 gettext("%s: option requires a value '-%c'\n"), 708 progname, optopt); 709 exit(1); 710 /*NOTREACHED*/ 711 case '?': 712 default: 713 (void) fprintf(stderr, 714 gettext("%s: unrecognized option '-%c'\n"), 715 progname, optopt); 716 exit(1); 717 } 718 } 719 720 if (modify_mask == 0) { 721 (void) fprintf(stderr, gettext("%s: at least one of the " 722 "-PulT options must be specified\n"), progname); 723 usage(); 724 } 725 726 /* get key value (required last argument) */ 727 if (optind != (argc-1)) 728 usage(); 729 730 errno = 0; 731 key = (int)strtol(argv[optind], &endp, 10); 732 if (errno != 0 || key < 1 || *endp != '\0') { 733 (void) fprintf(stderr, 734 gettext("%s: illegal key value '%d'\n"), 735 progname, key); 736 exit(1); 737 } 738 739 740 if (laadm_modify(key, modify_mask, policy, mac_addr_fixed, mac_addr, 741 lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) { 742 PRINT_ERR_DIAG("%s: modify operation failed: %s", diag, 743 laadm_diag); 744 exit(1); 745 } 746 } 747 748 static void 749 do_up_aggr(int argc, char *argv[]) 750 { 751 uint16_t key = 0; 752 char *endp = NULL; 753 laadm_diag_t diag = 0; 754 755 /* get aggregation key (optional last argument) */ 756 if (argc == 2) { 757 errno = 0; 758 key = (int)strtol(argv[1], &endp, 10); 759 if (errno != 0 || key < 1 || *endp != '\0') { 760 (void) fprintf(stderr, 761 gettext("%s: illegal key value '%d'\n"), 762 progname, key); 763 exit(1); 764 } 765 } else if (argc > 2) { 766 usage(); 767 } 768 769 if (laadm_up(key, NULL, &diag) < 0) { 770 if (key != 0) { 771 (void) fprintf(stderr, 772 gettext("%s: could not bring up aggregation" 773 " '%u' : %s"), progname, key, strerror(errno)); 774 if (diag != 0) 775 (void) fprintf(stderr, " (%s)", 776 laadm_diag(diag)); 777 (void) fprintf(stderr, "\n"); 778 } else { 779 PRINT_ERR_DIAG( 780 "%s: could not bring aggregations up: %s", 781 diag, laadm_diag); 782 } 783 exit(1); 784 } 785 } 786 787 static void 788 do_down_aggr(int argc, char *argv[]) 789 { 790 uint16_t key = 0; 791 char *endp = NULL; 792 793 /* get aggregation key (optional last argument) */ 794 if (argc == 2) { 795 errno = 0; 796 key = (int)strtol(argv[1], &endp, 10); 797 if (errno != 0 || key < 1 || *endp != '\0') { 798 (void) fprintf(stderr, 799 gettext("%s: illegal key value '%d'\n"), 800 progname, key); 801 exit(1); 802 } 803 } else if (argc > 2) { 804 usage(); 805 } 806 807 if (laadm_down(key) < 0) { 808 if (key != 0) { 809 (void) fprintf(stderr, 810 gettext("%s: could not bring aggregation" 811 " down '%u' : %s"), 812 progname, key, strerror(errno)); 813 (void) fprintf(stderr, "\n"); 814 } else { 815 (void) fprintf(stderr, 816 gettext("%s: could not bring aggregations" 817 " down: %s"), progname, strerror(errno)); 818 } 819 exit(1); 820 } 821 } 822 823 #define TYPE_WIDTH 10 824 825 static void 826 print_link_parseable(const char *name, dladm_attr_t *dap, boolean_t legacy) 827 { 828 char type[TYPE_WIDTH]; 829 830 if (!legacy) { 831 char drv[LIFNAMSIZ]; 832 int instance; 833 834 if (dap->da_vid != 0) { 835 (void) snprintf(type, TYPE_WIDTH, "vlan %u", 836 dap->da_vid); 837 } else { 838 (void) snprintf(type, TYPE_WIDTH, "non-vlan"); 839 } 840 if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 841 return; 842 if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 843 (void) printf("%s type=%s mtu=%d key=%u\n", 844 name, type, dap->da_max_sdu, instance); 845 } else { 846 (void) printf("%s type=%s mtu=%d device=%s\n", 847 name, type, dap->da_max_sdu, dap->da_dev); 848 } 849 } else { 850 (void) printf("%s type=legacy mtu=%d device=%s\n", 851 name, dap->da_max_sdu, name); 852 } 853 } 854 855 static void 856 print_link(const char *name, dladm_attr_t *dap, boolean_t legacy) 857 { 858 char type[TYPE_WIDTH]; 859 860 if (!legacy) { 861 char drv[LIFNAMSIZ]; 862 int instance; 863 864 if (dap->da_vid != 0) { 865 (void) snprintf(type, TYPE_WIDTH, gettext("vlan %u"), 866 dap->da_vid); 867 } else { 868 (void) snprintf(type, TYPE_WIDTH, gettext("non-vlan")); 869 } 870 if (dlpi_if_parse(dap->da_dev, drv, &instance) != 0) 871 return; 872 if (strncmp(drv, AGGR_DRV, sizeof (AGGR_DRV)) == 0) { 873 (void) printf(gettext("%-9s\ttype: %s\tmtu: %d" 874 "\taggregation: key %u\n"), name, type, 875 dap->da_max_sdu, instance); 876 } else { 877 (void) printf(gettext("%-9s\ttype: %s\tmtu: " 878 "%d\tdevice: %s\n"), name, type, dap->da_max_sdu, 879 dap->da_dev); 880 } 881 } else { 882 (void) printf(gettext("%-9s\ttype: legacy\tmtu: " 883 "%d\tdevice: %s\n"), name, dap->da_max_sdu, name); 884 } 885 } 886 887 static int 888 get_if_info(const char *name, dladm_attr_t *dlattrp, boolean_t *legacy) 889 { 890 int err; 891 892 if ((err = dladm_info(name, dlattrp)) == 0) { 893 *legacy = B_FALSE; 894 } else if (err < 0 && errno == ENODEV) { 895 int fd; 896 dlpi_if_attr_t dia; 897 dl_info_ack_t dlia; 898 899 /* 900 * A return value of ENODEV means that the specified 901 * device is not gldv3. 902 */ 903 if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 && 904 dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, 905 NULL, NULL) != -1) { 906 (void) dlpi_close(fd); 907 908 *legacy = B_TRUE; 909 bzero(dlattrp, sizeof (*dlattrp)); 910 dlattrp->da_max_sdu = (uint_t)dlia.dl_max_sdu; 911 } else { 912 errno = ENOENT; 913 return (-1); 914 } 915 } else { 916 /* 917 * If the return value is not ENODEV, this means that 918 * user is either passing in a bogus interface name 919 * or a vlan interface name that doesn't exist yet. 920 */ 921 errno = ENOENT; 922 return (-1); 923 } 924 return (0); 925 } 926 927 /* ARGSUSED */ 928 static void 929 show_link(void *arg, const char *name) 930 { 931 dladm_attr_t dlattr; 932 boolean_t legacy = B_TRUE; 933 show_link_state_t *state = (show_link_state_t *)arg; 934 935 if (get_if_info(name, &dlattr, &legacy) < 0) { 936 (void) fprintf(stderr, gettext("%s: invalid device '%s'\n"), 937 progname, name); 938 exit(1); 939 } 940 941 if (state->ls_parseable) { 942 print_link_parseable(name, &dlattr, legacy); 943 } else { 944 print_link(name, &dlattr, legacy); 945 } 946 } 947 948 static void 949 show_link_stats(void *arg, const char *name) 950 { 951 show_link_state_t *state = (show_link_state_t *)arg; 952 pktsum_t stats, diff_stats; 953 954 if (state->ls_firstonly) { 955 if (state->ls_donefirst) 956 return; 957 state->ls_donefirst = B_TRUE; 958 } else { 959 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 960 } 961 962 get_link_stats(name, &stats); 963 stats_diff(&diff_stats, &stats, &state->ls_prevstats); 964 965 (void) printf("%s", name); 966 (void) printf("\t\t%-10llu", diff_stats.ipackets); 967 (void) printf("%-12llu", diff_stats.rbytes); 968 (void) printf("%-8u", diff_stats.ierrors); 969 (void) printf("%-10llu", diff_stats.opackets); 970 (void) printf("%-12llu", diff_stats.obytes); 971 (void) printf("%-8u\n", diff_stats.oerrors); 972 973 state->ls_prevstats = stats; 974 } 975 976 static void 977 dump_grp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 978 { 979 char policy_str[LAADM_POLICY_STR_LEN]; 980 char addr_str[ETHERADDRL * 3]; 981 982 if (!parseable) { 983 (void) printf(gettext("key: %d (0x%04x)"), 984 grp->lg_key, grp->lg_key); 985 986 (void) printf(gettext("\tpolicy: %s"), 987 laadm_policy_to_str(grp->lg_policy, policy_str)); 988 989 (void) printf(gettext("\taddress: %s (%s)\n"), 990 laadm_mac_addr_to_str(grp->lg_mac, addr_str), 991 (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto")); 992 } else { 993 (void) printf("aggr key=%d", grp->lg_key); 994 995 (void) printf(" policy=%s", 996 laadm_policy_to_str(grp->lg_policy, policy_str)); 997 998 (void) printf(" address=%s", 999 laadm_mac_addr_to_str(grp->lg_mac, addr_str)); 1000 1001 (void) printf(" address-type=%s\n", 1002 (grp->lg_mac_fixed) ? "fixed" : "auto"); 1003 } 1004 } 1005 1006 static void 1007 dump_grp_lacp(laadm_grp_attr_sys_t *grp, boolean_t parseable) 1008 { 1009 const char *lacp_mode_str = laadm_lacp_mode_to_str(grp->lg_lacp_mode); 1010 const char *lacp_timer_str = 1011 laadm_lacp_timer_to_str(grp->lg_lacp_timer); 1012 1013 if (!parseable) { 1014 (void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str); 1015 (void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str); 1016 } else { 1017 (void) printf(" lacp-mode=%s", lacp_mode_str); 1018 (void) printf(" lacp-timer=%s\n", lacp_timer_str); 1019 } 1020 } 1021 1022 static void 1023 dump_grp_stats(laadm_grp_attr_sys_t *grp) 1024 { 1025 (void) printf("key: %d", grp->lg_key); 1026 (void) printf("\tipackets rbytes opackets obytes "); 1027 (void) printf("%%ipkts %%opkts\n"); 1028 } 1029 1030 static void 1031 dump_ports_lacp_head(void) 1032 { 1033 (void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"), 1034 gettext("timeout"), gettext("aggregatable"), gettext("sync"), 1035 gettext("coll"), gettext("dist"), gettext("defaulted"), 1036 gettext("expired")); 1037 } 1038 1039 static void 1040 dump_ports_head(void) 1041 { 1042 (void) printf(gettext(" device\taddress\t\t speed\t\tduplex\tlink\t" 1043 "state\n")); 1044 } 1045 1046 static char * 1047 port_state_to_str(aggr_port_state_t state_num) 1048 { 1049 int i; 1050 port_state_t *state; 1051 1052 for (i = 0; i < NPORTSTATES; i++) { 1053 state = &port_states[i]; 1054 if (state->state_num == state_num) 1055 return (state->state_name); 1056 } 1057 1058 return ("unknown"); 1059 } 1060 1061 static void 1062 dump_port(laadm_port_attr_sys_t *port, boolean_t parseable) 1063 { 1064 char *dev = port->lp_devname; 1065 char buf[ETHERADDRL * 3]; 1066 1067 if (!parseable) { 1068 (void) printf(" %-9s\t%s", dev, laadm_mac_addr_to_str( 1069 port->lp_mac, buf)); 1070 (void) printf("\t %-5u Mbps", (int)(mac_ifspeed(dev) / 1071 1000000ull)); 1072 (void) printf("\t%s", mac_link_duplex(dev)); 1073 (void) printf("\t%s", mac_link_state(dev)); 1074 (void) printf("\t%s\n", port_state_to_str(port->lp_state)); 1075 1076 } else { 1077 (void) printf(" device=%s address=%s", dev, 1078 laadm_mac_addr_to_str(port->lp_mac, buf)); 1079 (void) printf(" speed=%u", (int)(mac_ifspeed(dev) / 1080 1000000ull)); 1081 (void) printf(" duplex=%s", mac_link_duplex(dev)); 1082 (void) printf(" link=%s", mac_link_state(dev)); 1083 (void) printf(" port=%s", port_state_to_str(port->lp_state)); 1084 } 1085 } 1086 1087 static void 1088 dump_port_lacp(laadm_port_attr_sys_t *port) 1089 { 1090 aggr_lacp_state_t *state = &port->lp_lacp_state; 1091 1092 (void) printf(DUMP_LACP_FORMAT, 1093 port->lp_devname, state->bit.activity ? "active" : "passive", 1094 state->bit.timeout ? "short" : "long", 1095 state->bit.aggregation ? "yes" : "no", 1096 state->bit.sync ? "yes" : "no", 1097 state->bit.collecting ? "yes" : "no", 1098 state->bit.distributing ? "yes" : "no", 1099 state->bit.defaulted ? "yes" : "no", 1100 state->bit.expired ? "yes" : "no"); 1101 } 1102 1103 static void 1104 dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats, 1105 pktsum_t *tot_stats) 1106 { 1107 pktsum_t diff_stats; 1108 pktsum_t *old_stats = &state->gs_prevstats[index]; 1109 1110 stats_diff(&diff_stats, port_stats, old_stats); 1111 1112 (void) printf("\t%-10llu", diff_stats.ipackets); 1113 (void) printf("%-12llu", diff_stats.rbytes); 1114 (void) printf("%-10llu", diff_stats.opackets); 1115 (void) printf("%-12llu", diff_stats.obytes); 1116 1117 if (tot_stats->ipackets == 0) 1118 (void) printf("\t-"); 1119 else 1120 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 1121 (double)tot_stats->ipackets * 100); 1122 1123 if (tot_stats->opackets == 0) 1124 (void) printf("\t-"); 1125 else 1126 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 1127 (double)tot_stats->opackets * 100); 1128 1129 (void) printf("\n"); 1130 1131 *old_stats = *port_stats; 1132 } 1133 1134 static int 1135 show_key(void *arg, laadm_grp_attr_sys_t *grp) 1136 { 1137 show_grp_state_t *state = (show_grp_state_t *)arg; 1138 int i; 1139 pktsum_t pktsumtot, port_stat; 1140 1141 if (state->gs_key != 0 && state->gs_key != grp->lg_key) 1142 return (0); 1143 if (state->gs_firstonly) { 1144 if (state->gs_found) 1145 return (0); 1146 } else { 1147 bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); 1148 } 1149 1150 state->gs_found = B_TRUE; 1151 1152 if (state->gs_stats) { 1153 /* show statistics */ 1154 dump_grp_stats(grp); 1155 1156 /* sum the ports statistics */ 1157 bzero(&pktsumtot, sizeof (pktsumtot)); 1158 for (i = 0; i < grp->lg_nports; i++) { 1159 get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 1160 stats_total(&pktsumtot, &port_stat, 1161 &state->gs_prevstats[i]); 1162 } 1163 1164 (void) printf(" Total"); 1165 (void) printf("\t%-10llu", pktsumtot.ipackets); 1166 (void) printf("%-12llu", pktsumtot.rbytes); 1167 (void) printf("%-10llu", pktsumtot.opackets); 1168 (void) printf("%-12llu\n", pktsumtot.obytes); 1169 1170 for (i = 0; i < grp->lg_nports; i++) { 1171 get_mac_stats(grp->lg_ports[i].lp_devname, &port_stat); 1172 (void) printf(" %s", grp->lg_ports[i].lp_devname); 1173 dump_port_stat(i, state, &port_stat, &pktsumtot); 1174 } 1175 } else if (state->gs_lacp) { 1176 /* show LACP info */ 1177 dump_grp(grp, state->gs_parseable); 1178 dump_grp_lacp(grp, state->gs_parseable); 1179 dump_ports_lacp_head(); 1180 for (i = 0; i < grp->lg_nports; i++) 1181 dump_port_lacp(&grp->lg_ports[i]); 1182 } else { 1183 dump_grp(grp, state->gs_parseable); 1184 if (!state->gs_parseable) 1185 dump_ports_head(); 1186 for (i = 0; i < grp->lg_nports; i++) { 1187 if (state->gs_parseable) 1188 (void) printf("dev key=%d", grp->lg_key); 1189 dump_port(&grp->lg_ports[i], state->gs_parseable); 1190 if (state->gs_parseable) 1191 (void) printf("\n"); 1192 } 1193 } 1194 1195 return (0); 1196 } 1197 1198 static int 1199 kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 1200 { 1201 kstat_named_t *knp; 1202 1203 if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 1204 return (-1); 1205 1206 if (knp->data_type != type) 1207 return (-1); 1208 1209 switch (type) { 1210 case KSTAT_DATA_UINT64: 1211 *(uint64_t *)buf = knp->value.ui64; 1212 break; 1213 case KSTAT_DATA_UINT32: 1214 *(uint32_t *)buf = knp->value.ui32; 1215 break; 1216 default: 1217 return (-1); 1218 } 1219 1220 return (0); 1221 } 1222 1223 static void 1224 show_dev(void *arg, const char *dev) 1225 { 1226 show_mac_state_t *state = (show_mac_state_t *)arg; 1227 1228 (void) printf("%s", dev); 1229 1230 if (!state->ms_parseable) { 1231 (void) printf(gettext("\t\tlink: %s"), 1232 mac_link_state(dev)); 1233 (void) printf(gettext("\tspeed: %-5u Mbps"), 1234 (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1235 (void) printf(gettext("\tduplex: %s\n"), 1236 mac_link_duplex(dev)); 1237 } else { 1238 (void) printf(" link=%s", mac_link_state(dev)); 1239 (void) printf(" speed=%u", 1240 (unsigned int)(mac_ifspeed(dev) / 1000000ull)); 1241 (void) printf(" duplex=%s\n", mac_link_duplex(dev)); 1242 } 1243 } 1244 1245 /*ARGSUSED*/ 1246 static void 1247 show_dev_stats(void *arg, const char *dev) 1248 { 1249 show_mac_state_t *state = (show_mac_state_t *)arg; 1250 pktsum_t stats, diff_stats; 1251 1252 if (state->ms_firstonly) { 1253 if (state->ms_donefirst) 1254 return; 1255 state->ms_donefirst = B_TRUE; 1256 } else { 1257 bzero(&state->ms_prevstats, sizeof (state->ms_prevstats)); 1258 } 1259 1260 get_mac_stats(dev, &stats); 1261 stats_diff(&diff_stats, &stats, &state->ms_prevstats); 1262 1263 (void) printf("%s", dev); 1264 (void) printf("\t\t%-10llu", diff_stats.ipackets); 1265 (void) printf("%-12llu", diff_stats.rbytes); 1266 (void) printf("%-8u", diff_stats.ierrors); 1267 (void) printf("%-10llu", diff_stats.opackets); 1268 (void) printf("%-12llu", diff_stats.obytes); 1269 (void) printf("%-8u\n", diff_stats.oerrors); 1270 1271 state->ms_prevstats = stats; 1272 } 1273 1274 static void 1275 do_show_link(int argc, char *argv[]) 1276 { 1277 char *name = NULL; 1278 int option; 1279 boolean_t s_arg = B_FALSE; 1280 boolean_t i_arg = B_FALSE; 1281 uint32_t interval = 0; 1282 show_link_state_t state; 1283 char *endp = NULL; 1284 1285 state.ls_stats = B_FALSE; 1286 state.ls_parseable = B_FALSE; 1287 1288 opterr = 0; 1289 while ((option = getopt_long(argc, argv, ":psi:", 1290 longopts, NULL)) != -1) { 1291 switch (option) { 1292 case 'p': 1293 state.ls_parseable = B_TRUE; 1294 break; 1295 case 's': 1296 if (s_arg) { 1297 (void) fprintf(stderr, gettext( 1298 "%s: the option -s cannot be specified " 1299 "more than once\n"), progname); 1300 usage(); 1301 } 1302 1303 s_arg = B_TRUE; 1304 break; 1305 case 'i': 1306 if (i_arg) { 1307 (void) fprintf(stderr, gettext( 1308 "%s: the option -i cannot be specified " 1309 "more than once\n"), progname); 1310 usage(); 1311 } 1312 1313 i_arg = B_TRUE; 1314 1315 errno = 0; 1316 interval = (int)strtol(optarg, &endp, 10); 1317 if (errno != 0 || interval == 0 || *endp != '\0') { 1318 (void) fprintf(stderr, 1319 gettext("%s: invalid interval value" 1320 " '%d'\n"), 1321 progname, interval); 1322 exit(1); 1323 } 1324 break; 1325 case ':': 1326 (void) fprintf(stderr, 1327 gettext("%s: option requires a value '-%c'\n"), 1328 progname, optopt); 1329 exit(1); 1330 /*NOTREACHED*/ 1331 case '?': 1332 default: 1333 (void) fprintf(stderr, 1334 gettext("%s: unrecognized option '-%c'\n"), 1335 progname, optopt); 1336 exit(1); 1337 } 1338 } 1339 1340 if (i_arg && !s_arg) { 1341 (void) fprintf(stderr, gettext("%s: the option -i " 1342 "can be used only with -s\n"), progname); 1343 usage(); 1344 } 1345 1346 1347 /* get link name (optional last argument) */ 1348 if (optind == (argc-1)) 1349 name = argv[optind]; 1350 else if (optind != argc) 1351 usage(); 1352 1353 if (s_arg) { 1354 link_stats(name, interval); 1355 return; 1356 } 1357 1358 if (name == NULL) { 1359 (void) dladm_walk(show_link, &state); 1360 } else { 1361 show_link(&state, name); 1362 } 1363 } 1364 1365 static void 1366 do_show_aggr(int argc, char *argv[]) 1367 { 1368 int option; 1369 uint16_t key = 0; 1370 boolean_t L_arg = B_FALSE; 1371 boolean_t s_arg = B_FALSE; 1372 boolean_t i_arg = B_FALSE; 1373 show_grp_state_t state; 1374 uint32_t interval = 0; 1375 char *endp = NULL; 1376 1377 state.gs_stats = B_FALSE; 1378 state.gs_lacp = B_FALSE; 1379 state.gs_parseable = B_FALSE; 1380 1381 opterr = 0; 1382 while ((option = getopt_long(argc, argv, ":Lpsi:", 1383 longopts, NULL)) != -1) { 1384 switch (option) { 1385 case 'L': 1386 if (L_arg) { 1387 (void) fprintf(stderr, gettext( 1388 "%s: the option -L cannot be specified " 1389 "more than once\n"), progname); 1390 usage(); 1391 } 1392 1393 if (s_arg || i_arg) { 1394 (void) fprintf(stderr, gettext( 1395 "%s: the option -L cannot be used with " 1396 "any of -is\n"), progname); 1397 usage(); 1398 } 1399 1400 L_arg = B_TRUE; 1401 1402 state.gs_lacp = B_TRUE; 1403 break; 1404 case 'p': 1405 state.gs_parseable = B_TRUE; 1406 break; 1407 case 's': 1408 if (s_arg) { 1409 (void) fprintf(stderr, gettext( 1410 "%s: the option -s cannot be specified " 1411 "more than once\n"), progname); 1412 usage(); 1413 } 1414 1415 if (L_arg) { 1416 (void) fprintf(stderr, gettext( 1417 "%s: the option -L cannot be used " 1418 "with -k\n"), progname); 1419 usage(); 1420 } 1421 1422 s_arg = B_TRUE; 1423 break; 1424 case 'i': 1425 if (i_arg) { 1426 (void) fprintf(stderr, gettext( 1427 "%s: the option -i cannot be specified " 1428 "more than once\n"), progname); 1429 usage(); 1430 } 1431 1432 if (L_arg) { 1433 (void) fprintf(stderr, gettext( 1434 "%s: the option -i cannot be used " 1435 "with -L\n"), progname); 1436 usage(); 1437 } 1438 1439 i_arg = B_TRUE; 1440 1441 errno = 0; 1442 interval = (int)strtol(optarg, &endp, 10); 1443 if (errno != 0 || interval == 0 || *endp != '\0') { 1444 (void) fprintf(stderr, 1445 gettext("%s: invalid interval value" 1446 " '%d'\n"), 1447 progname, interval); 1448 exit(1); 1449 } 1450 break; 1451 case ':': 1452 (void) fprintf(stderr, 1453 gettext("%s: option requires a value '-%c'\n"), 1454 progname, optopt); 1455 exit(1); 1456 /*NOTREACHED*/ 1457 case '?': 1458 default: 1459 (void) fprintf(stderr, 1460 gettext("%s: unrecognized option '-%c'\n"), 1461 progname, optopt); 1462 exit(1); 1463 } 1464 } 1465 1466 if (i_arg && !s_arg) { 1467 (void) fprintf(stderr, gettext("%s: the option -i " 1468 "can be used only with -s\n"), progname); 1469 usage(); 1470 } 1471 1472 /* get aggregation key (optional last argument) */ 1473 if (optind == (argc-1)) { 1474 errno = 0; 1475 key = (int)strtol(argv[optind], &endp, 10); 1476 if (errno != 0 || key < 1 || *endp != '\0') { 1477 (void) fprintf(stderr, 1478 gettext("%s: illegal key value '%d'\n"), 1479 progname, key); 1480 exit(1); 1481 } 1482 } else if (optind != argc) { 1483 usage(); 1484 } 1485 1486 if (s_arg) { 1487 aggr_stats(key, interval); 1488 return; 1489 } 1490 1491 state.gs_key = key; 1492 state.gs_found = B_FALSE; 1493 1494 (void) laadm_walk_sys(show_key, &state); 1495 1496 if (key != 0 && !state.gs_found) { 1497 (void) fprintf(stderr, 1498 gettext("%s: non-existent aggregation key '%u'\n"), 1499 progname, key); 1500 exit(1); 1501 } 1502 } 1503 1504 static void 1505 do_show_dev(int argc, char *argv[]) 1506 { 1507 int option; 1508 char *dev = NULL; 1509 boolean_t s_arg = B_FALSE; 1510 boolean_t i_arg = B_FALSE; 1511 uint32_t interval = 0; 1512 show_mac_state_t state; 1513 char *endp = NULL; 1514 1515 state.ms_parseable = B_FALSE; 1516 1517 opterr = 0; 1518 while ((option = getopt_long(argc, argv, ":psi:", 1519 longopts, NULL)) != -1) { 1520 switch (option) { 1521 case 'p': 1522 state.ms_parseable = B_TRUE; 1523 break; 1524 case 's': 1525 if (s_arg) { 1526 (void) fprintf(stderr, gettext( 1527 "%s: the option -s cannot be specified " 1528 "more than once\n"), progname); 1529 usage(); 1530 } 1531 1532 s_arg = B_TRUE; 1533 break; 1534 case 'i': 1535 if (i_arg) { 1536 (void) fprintf(stderr, gettext( 1537 "%s: the option -i cannot be specified " 1538 "more than once\n"), progname); 1539 usage(); 1540 } 1541 1542 i_arg = B_TRUE; 1543 1544 errno = 0; 1545 interval = (int)strtol(optarg, &endp, 10); 1546 if (errno != 0 || interval == 0 || *endp != '\0') { 1547 (void) fprintf(stderr, 1548 gettext("%s: invalid interval value" 1549 " '%d'\n"), 1550 progname, interval); 1551 exit(1); 1552 } 1553 break; 1554 case ':': 1555 (void) fprintf(stderr, 1556 gettext("%s: option requires a value '-%c'\n"), 1557 progname, optopt); 1558 exit(1); 1559 /*NOTREACHED*/ 1560 case '?': 1561 default: 1562 (void) fprintf(stderr, 1563 gettext("%s: unrecognized option '-%c'\n"), 1564 progname, optopt); 1565 exit(1); 1566 } 1567 } 1568 1569 if (i_arg && !s_arg) { 1570 (void) fprintf(stderr, gettext("%s: the option -i " 1571 "can be used only with -s\n"), progname); 1572 usage(); 1573 } 1574 1575 /* get dev name (optional last argument) */ 1576 if (optind == (argc-1)) 1577 dev = argv[optind]; 1578 else if (optind != argc) 1579 usage(); 1580 1581 if (dev != NULL) { 1582 int index; 1583 char drv[LIFNAMSIZ]; 1584 dladm_attr_t dlattr; 1585 boolean_t legacy; 1586 1587 /* 1588 * Check for invalid devices. 1589 * aggregations and vlans are not considered devices. 1590 */ 1591 if (strncmp(dev, "aggr", 4) == 0 || 1592 dlpi_if_parse(dev, drv, &index) < 0 || 1593 index >= 1000 || 1594 get_if_info(dev, &dlattr, &legacy) < 0) { 1595 (void) fprintf(stderr, 1596 gettext("%s: invalid device '%s'\n"), 1597 progname, dev); 1598 exit(1); 1599 } 1600 } 1601 1602 if (s_arg) { 1603 dev_stats(dev, interval); 1604 return; 1605 } 1606 1607 if (dev == NULL) 1608 (void) macadm_walk(show_dev, &state, B_TRUE); 1609 else 1610 show_dev(&state, dev); 1611 } 1612 1613 /* ARGSUSED */ 1614 static void 1615 link_stats(const char *link, uint32_t interval) 1616 { 1617 dladm_attr_t dlattr; 1618 boolean_t legacy; 1619 show_link_state_t state; 1620 1621 if (link != NULL && get_if_info(link, &dlattr, &legacy) < 0) { 1622 (void) fprintf(stderr, gettext("%s: invalid device '%s'\n"), 1623 progname, link); 1624 exit(1); 1625 } 1626 bzero(&state, sizeof (state)); 1627 1628 /* 1629 * If an interval is specified, continuously show the stats 1630 * only for the first MAC port. 1631 */ 1632 state.ls_firstonly = (interval != 0); 1633 1634 for (;;) { 1635 (void) printf("\t\tipackets rbytes ierrors "); 1636 (void) printf("opackets obytes oerrors\n"); 1637 1638 state.ls_donefirst = B_FALSE; 1639 if (link == NULL) 1640 (void) dladm_walk(show_link_stats, &state); 1641 else 1642 show_link_stats(&state, link); 1643 1644 if (interval == 0) 1645 break; 1646 1647 (void) sleep(interval); 1648 } 1649 } 1650 1651 /* ARGSUSED */ 1652 static void 1653 aggr_stats(uint16_t key, uint32_t interval) 1654 { 1655 show_grp_state_t state; 1656 1657 bzero(&state, sizeof (state)); 1658 state.gs_stats = B_TRUE; 1659 state.gs_key = key; 1660 1661 /* 1662 * If an interval is specified, continuously show the stats 1663 * only for the first group. 1664 */ 1665 state.gs_firstonly = (interval != 0); 1666 1667 for (;;) { 1668 state.gs_found = B_FALSE; 1669 (void) laadm_walk_sys(show_key, &state); 1670 if (state.gs_key != 0 && !state.gs_found) { 1671 (void) fprintf(stderr, 1672 gettext("%s: non-existent aggregation key '%u'\n"), 1673 progname, key); 1674 exit(1); 1675 } 1676 1677 if (interval == 0) 1678 break; 1679 1680 (void) sleep(interval); 1681 } 1682 } 1683 1684 /* ARGSUSED */ 1685 static void 1686 dev_stats(const char *dev, uint32_t interval) 1687 { 1688 show_mac_state_t state; 1689 1690 bzero(&state, sizeof (state)); 1691 1692 /* 1693 * If an interval is specified, continuously show the stats 1694 * only for the first MAC port. 1695 */ 1696 state.ms_firstonly = (interval != 0); 1697 1698 for (;;) { 1699 1700 (void) printf("\t\tipackets rbytes ierrors "); 1701 (void) printf("opackets obytes oerrors\n"); 1702 1703 state.ms_donefirst = B_FALSE; 1704 if (dev == NULL) 1705 (void) macadm_walk(show_dev_stats, &state, B_TRUE); 1706 else 1707 show_dev_stats(&state, dev); 1708 1709 if (interval == 0) 1710 break; 1711 1712 (void) sleep(interval); 1713 } 1714 } 1715 1716 /* accumulate stats (s1 += (s2 - s3)) */ 1717 static void 1718 stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 1719 { 1720 s1->ipackets += (s2->ipackets - s3->ipackets); 1721 s1->opackets += (s2->opackets - s3->opackets); 1722 s1->rbytes += (s2->rbytes - s3->rbytes); 1723 s1->obytes += (s2->obytes - s3->obytes); 1724 s1->ierrors += (s2->ierrors - s3->ierrors); 1725 s1->oerrors += (s2->oerrors - s3->oerrors); 1726 } 1727 1728 /* compute stats differences (s1 = s2 - s3) */ 1729 static void 1730 stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 1731 { 1732 s1->ipackets = s2->ipackets - s3->ipackets; 1733 s1->opackets = s2->opackets - s3->opackets; 1734 s1->rbytes = s2->rbytes - s3->rbytes; 1735 s1->obytes = s2->obytes - s3->obytes; 1736 s1->ierrors = s2->ierrors - s3->ierrors; 1737 s1->oerrors = s2->oerrors - s3->oerrors; 1738 } 1739 1740 /* 1741 * In the following routines, we do the first kstat_lookup() assuming that 1742 * the device is gldv3-based and that the kstat name is the one passed in 1743 * as the "name" argument. If the lookup fails, we redo the kstat_lookup() 1744 * omitting the kstat name. This second lookup is needed for getting kstats 1745 * from legacy devices. This can fail too if the device is not attached or 1746 * the device is legacy and doesn't export the kstats we need. 1747 */ 1748 static void 1749 get_stats(char *module, int instance, char *name, pktsum_t *stats) 1750 { 1751 kstat_ctl_t *kcp; 1752 kstat_t *ksp; 1753 1754 if ((kcp = kstat_open()) == NULL) { 1755 (void) fprintf(stderr, 1756 gettext("%s: kstat open operation failed\n"), 1757 progname); 1758 return; 1759 } 1760 1761 if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL && 1762 (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 1763 /* 1764 * The kstat query could fail if the underlying MAC 1765 * driver was already detached. 1766 */ 1767 (void) kstat_close(kcp); 1768 return; 1769 } 1770 1771 if (kstat_read(kcp, ksp, NULL) == -1) 1772 goto bail; 1773 1774 if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 1775 &stats->ipackets) < 0) 1776 goto bail; 1777 1778 if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 1779 &stats->opackets) < 0) 1780 goto bail; 1781 1782 if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 1783 &stats->rbytes) < 0) 1784 goto bail; 1785 1786 if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 1787 &stats->obytes) < 0) 1788 goto bail; 1789 1790 if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 1791 &stats->ierrors) < 0) 1792 goto bail; 1793 1794 if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 1795 &stats->oerrors) < 0) 1796 goto bail; 1797 1798 (void) kstat_close(kcp); 1799 return; 1800 1801 bail: 1802 (void) kstat_close(kcp); 1803 } 1804 1805 static void 1806 get_mac_stats(const char *dev, pktsum_t *stats) 1807 { 1808 char module[LIFNAMSIZ]; 1809 int instance; 1810 1811 if (dlpi_if_parse(dev, module, &instance) != 0) 1812 return; 1813 bzero(stats, sizeof (*stats)); 1814 get_stats(module, instance, "mac", stats); 1815 } 1816 1817 static void 1818 get_link_stats(const char *link, pktsum_t *stats) 1819 { 1820 char module[LIFNAMSIZ]; 1821 int instance; 1822 1823 if (dlpi_if_parse(link, module, &instance) != 0) 1824 return; 1825 bzero(stats, sizeof (*stats)); 1826 get_stats(module, instance, (char *)link, stats); 1827 } 1828 1829 static int 1830 get_single_mac_stat(const char *dev, const char *name, uint8_t type, 1831 void *val) 1832 { 1833 char module[LIFNAMSIZ]; 1834 int instance; 1835 kstat_ctl_t *kcp; 1836 kstat_t *ksp; 1837 1838 if ((kcp = kstat_open()) == NULL) { 1839 (void) fprintf(stderr, 1840 gettext("%s: kstat open operation failed\n"), 1841 progname); 1842 return (-1); 1843 } 1844 1845 if (dlpi_if_parse(dev, module, &instance) != 0) 1846 return (-1); 1847 if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 1848 (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) { 1849 /* 1850 * The kstat query could fail if the underlying MAC 1851 * driver was already detached. 1852 */ 1853 goto bail; 1854 } 1855 1856 if (kstat_read(kcp, ksp, NULL) == -1) { 1857 (void) fprintf(stderr, 1858 gettext("%s: kstat read failed\n"), 1859 progname); 1860 goto bail; 1861 } 1862 1863 if (kstat_value(ksp, name, type, val) < 0) 1864 goto bail; 1865 1866 (void) kstat_close(kcp); 1867 return (0); 1868 1869 bail: 1870 (void) kstat_close(kcp); 1871 return (-1); 1872 } 1873 1874 static uint64_t 1875 mac_ifspeed(const char *dev) 1876 { 1877 uint64_t ifspeed = 0; 1878 1879 (void) get_single_mac_stat(dev, "ifspeed", KSTAT_DATA_UINT64, &ifspeed); 1880 return (ifspeed); 1881 } 1882 1883 static char * 1884 mac_link_state(const char *dev) 1885 { 1886 link_state_t link_state; 1887 char *state_str = "unknown"; 1888 1889 if (get_single_mac_stat(dev, "link_state", KSTAT_DATA_UINT32, 1890 &link_state) != 0) { 1891 return (state_str); 1892 } 1893 1894 switch (link_state) { 1895 case LINK_STATE_UP: 1896 state_str = "up"; 1897 break; 1898 case LINK_STATE_DOWN: 1899 state_str = "down"; 1900 break; 1901 default: 1902 break; 1903 } 1904 1905 return (state_str); 1906 } 1907 1908 1909 static char * 1910 mac_link_duplex(const char *dev) 1911 { 1912 link_duplex_t link_duplex; 1913 char *duplex_str = "unknown"; 1914 1915 if (get_single_mac_stat(dev, "link_duplex", KSTAT_DATA_UINT32, 1916 &link_duplex) != 0) { 1917 return (duplex_str); 1918 } 1919 1920 switch (link_duplex) { 1921 case LINK_DUPLEX_FULL: 1922 duplex_str = "full"; 1923 break; 1924 case LINK_DUPLEX_HALF: 1925 duplex_str = "half"; 1926 break; 1927 default: 1928 break; 1929 } 1930 1931 return (duplex_str); 1932 } 1933