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