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