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