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