1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright 2017 Joyent, Inc. 28 */ 29 30 /* 31 * Copyright 2020 Peter Tribble. 32 */ 33 34 #include <stdio.h> 35 #include <ctype.h> 36 #include <locale.h> 37 #include <signal.h> 38 #include <stdarg.h> 39 #include <stdlib.h> 40 #include <fcntl.h> 41 #include <string.h> 42 #include <stropts.h> 43 #include <sys/stat.h> 44 #include <errno.h> 45 #include <strings.h> 46 #include <getopt.h> 47 #include <unistd.h> 48 #include <priv.h> 49 #include <termios.h> 50 #include <pwd.h> 51 #include <auth_attr.h> 52 #include <auth_list.h> 53 #include <libintl.h> 54 #include <libdevinfo.h> 55 #include <libdlpi.h> 56 #include <libdladm.h> 57 #include <libdllink.h> 58 #include <libdlstat.h> 59 #include <libdlaggr.h> 60 #include <libinetutil.h> 61 #include <bsm/adt.h> 62 #include <bsm/adt_event.h> 63 #include <stddef.h> 64 #include <ofmt.h> 65 66 typedef struct link_chain_s { 67 datalink_id_t lc_linkid; 68 boolean_t lc_visited; 69 dladm_stat_chain_t *lc_statchain[DLADM_STAT_NUM_STATS]; 70 struct link_chain_s *lc_next; 71 } link_chain_t; 72 73 typedef void * (*stats2str_t)(const char *, void *, 74 char, boolean_t); 75 76 typedef struct show_state { 77 link_chain_t *ls_linkchain; 78 boolean_t ls_stattype[DLADM_STAT_NUM_STATS]; 79 stats2str_t ls_stats2str[DLADM_STAT_NUM_STATS]; 80 ofmt_handle_t ls_ofmt; 81 char ls_unit; 82 boolean_t ls_parsable; 83 } show_state_t; 84 85 typedef struct show_history_state_s { 86 boolean_t hs_plot; 87 boolean_t hs_parsable; 88 boolean_t hs_printheader; 89 boolean_t hs_first; 90 boolean_t hs_showall; 91 ofmt_handle_t hs_ofmt; 92 } show_history_state_t; 93 94 /* 95 * callback functions for printing output and error diagnostics. 96 */ 97 static ofmt_cb_t print_default_cb; 98 99 typedef void cmdfunc_t(int, char **, const char *); 100 101 static cmdfunc_t do_show, do_show_history, do_show_phys, do_show_link; 102 static cmdfunc_t do_show_aggr; 103 104 static void die(const char *, ...); 105 static void die_optdup(int); 106 static void die_opterr(int, int, const char *); 107 static void die_dlerr(dladm_status_t, const char *, ...); 108 static void warn(const char *, ...); 109 110 typedef struct cmd { 111 char *c_name; 112 cmdfunc_t *c_fn; 113 const char *c_usage; 114 } cmd_t; 115 116 static cmd_t cmds[] = { 117 { "", do_show, 118 "dlstat [-r | -t] [-i <interval>] [link]\n" 119 " dlstat [-a | -A] [-i <interval>] [-p] [ -o field[,...]]\n" 120 " [-u R|K|M|G|T|P] [link]"}, 121 { "show-phys", do_show_phys, 122 "dlstat show-phys [-r | -t] [-i interval] [-a]\n" 123 " [-p] [ -o field[,...]] [-u R|K|M|G|T|P] " 124 "[link]"}, 125 { "show-link", do_show_link, 126 "dlstat show-link [-r [-F] | -t] [-i interval] [-a]\n" 127 " [-p] [ -o field[,...]] [-u R|K|M|G|T|P] " 128 "[link]\n" 129 " dlstat show-link -h [-a] [-d] [-F <format>]\n" 130 " [-s <DD/MM/YYYY,HH:MM:SS>] " 131 "[-e <DD/MM/YYYY,HH:MM:SS>]\n" 132 " -f <logfile> [<link>]" }, 133 { "show-aggr", do_show_aggr, 134 "dlstat show-aggr [-r | -t] [-i interval] [-p]\n" 135 " [ -o field[,...]] [-u R|K|M|G|T|P] " 136 " [link]" } 137 }; 138 139 #define MAXSTATLEN 15 140 141 /* 142 * dlstat : total stat fields 143 */ 144 typedef struct total_fields_buf_s { 145 char t_linkname[MAXLINKNAMELEN]; 146 char t_ipackets[MAXSTATLEN]; 147 char t_rbytes[MAXSTATLEN]; 148 char t_opackets[MAXSTATLEN]; 149 char t_obytes[MAXSTATLEN]; 150 } total_fields_buf_t; 151 152 static ofmt_field_t total_s_fields[] = { 153 { "LINK", 15, 154 offsetof(total_fields_buf_t, t_linkname), print_default_cb}, 155 { "IPKTS", 8, 156 offsetof(total_fields_buf_t, t_ipackets), print_default_cb}, 157 { "RBYTES", 8, 158 offsetof(total_fields_buf_t, t_rbytes), print_default_cb}, 159 { "OPKTS", 8, 160 offsetof(total_fields_buf_t, t_opackets), print_default_cb}, 161 { "OBYTES", 8, 162 offsetof(total_fields_buf_t, t_obytes), print_default_cb}, 163 { NULL, 0, 0, NULL}}; 164 165 /* 166 * dlstat show-phys: both Rx and Tx stat fields 167 */ 168 typedef struct ring_fields_buf_s { 169 char r_linkname[MAXLINKNAMELEN]; 170 char r_type[MAXSTATLEN]; 171 char r_id[MAXSTATLEN]; 172 char r_index[MAXSTATLEN]; 173 char r_packets[MAXSTATLEN]; 174 char r_bytes[MAXSTATLEN]; 175 } ring_fields_buf_t; 176 177 static ofmt_field_t ring_s_fields[] = { 178 { "LINK", 15, 179 offsetof(ring_fields_buf_t, r_linkname), print_default_cb}, 180 { "TYPE", 5, 181 offsetof(ring_fields_buf_t, r_type), print_default_cb}, 182 { "ID", 7, 183 offsetof(ring_fields_buf_t, r_id), print_default_cb}, 184 { "INDEX", 6, 185 offsetof(ring_fields_buf_t, r_index), print_default_cb}, 186 { "PKTS", 8, 187 offsetof(ring_fields_buf_t, r_packets), print_default_cb}, 188 { "BYTES", 8, 189 offsetof(ring_fields_buf_t, r_bytes), print_default_cb}, 190 { NULL, 0, 0, NULL}}; 191 192 /* 193 * dlstat show-phys -r: Rx Ring stat fields 194 */ 195 typedef struct rx_ring_fields_buf_s { 196 char rr_linkname[MAXLINKNAMELEN]; 197 char rr_type[MAXSTATLEN]; 198 char rr_id[MAXSTATLEN]; 199 char rr_index[MAXSTATLEN]; 200 char rr_ipackets[MAXSTATLEN]; 201 char rr_rbytes[MAXSTATLEN]; 202 } rx_ring_fields_buf_t; 203 204 static ofmt_field_t rx_ring_s_fields[] = { 205 { "LINK", 15, 206 offsetof(rx_ring_fields_buf_t, rr_linkname), print_default_cb}, 207 { "TYPE", 5, 208 offsetof(rx_ring_fields_buf_t, rr_type), print_default_cb}, 209 { "ID", 7, 210 offsetof(rx_ring_fields_buf_t, rr_id), print_default_cb}, 211 { "INDEX", 6, 212 offsetof(rx_ring_fields_buf_t, rr_index), print_default_cb}, 213 { "IPKTS", 8, 214 offsetof(rx_ring_fields_buf_t, rr_ipackets), print_default_cb}, 215 { "RBYTES", 8, 216 offsetof(rx_ring_fields_buf_t, rr_rbytes), print_default_cb}, 217 { NULL, 0, 0, NULL}}; 218 219 /* 220 * dlstat show-phys -t: Tx Ring stat fields 221 */ 222 typedef struct tx_ring_fields_buf_s { 223 char tr_linkname[MAXLINKNAMELEN]; 224 char tr_type[MAXSTATLEN]; 225 char tr_id[MAXSTATLEN]; 226 char tr_index[MAXSTATLEN]; 227 char tr_opackets[MAXSTATLEN]; 228 char tr_obytes[MAXSTATLEN]; 229 } tx_ring_fields_buf_t; 230 231 static ofmt_field_t tx_ring_s_fields[] = { 232 { "LINK", 15, 233 offsetof(tx_ring_fields_buf_t, tr_linkname), print_default_cb}, 234 { "TYPE", 5, 235 offsetof(tx_ring_fields_buf_t, tr_type), print_default_cb}, 236 { "ID", 7, 237 offsetof(tx_ring_fields_buf_t, tr_id), print_default_cb}, 238 { "INDEX", 6, 239 offsetof(tx_ring_fields_buf_t, tr_index), print_default_cb}, 240 { "OPKTS", 8, 241 offsetof(tx_ring_fields_buf_t, tr_opackets), print_default_cb}, 242 { "OBYTES", 8, 243 offsetof(tx_ring_fields_buf_t, tr_obytes), print_default_cb}, 244 { NULL, 0, 0, NULL}}; 245 246 /* 247 * dlstat show-link: both Rx and Tx lane fields 248 */ 249 typedef struct lane_fields_buf_s { 250 char l_linkname[MAXLINKNAMELEN]; 251 char l_type[MAXSTATLEN]; 252 char l_id[MAXSTATLEN]; 253 char l_index[MAXSTATLEN]; 254 char l_packets[MAXSTATLEN]; 255 char l_bytes[MAXSTATLEN]; 256 } lane_fields_buf_t; 257 258 static ofmt_field_t lane_s_fields[] = { 259 { "LINK", 15, 260 offsetof(lane_fields_buf_t, l_linkname), print_default_cb}, 261 { "TYPE", 5, 262 offsetof(lane_fields_buf_t, l_type), print_default_cb}, 263 { "ID", 7, 264 offsetof(lane_fields_buf_t, l_id), print_default_cb}, 265 { "INDEX", 6, 266 offsetof(lane_fields_buf_t, l_index), print_default_cb}, 267 { "PKTS", 8, 268 offsetof(lane_fields_buf_t, l_packets), print_default_cb}, 269 { "BYTES", 8, 270 offsetof(lane_fields_buf_t, l_bytes), print_default_cb}, 271 { NULL, 0, 0, NULL}}; 272 273 /* 274 * dlstat show-link -r, dlstat -r: Rx Lane stat fields 275 */ 276 typedef struct rx_lane_fields_buf_s { 277 char rl_linkname[MAXLINKNAMELEN]; 278 char rl_type[MAXSTATLEN]; 279 char rl_id[MAXSTATLEN]; 280 char rl_index[MAXSTATLEN]; 281 char rl_ipackets[MAXSTATLEN]; 282 char rl_rbytes[MAXSTATLEN]; 283 char rl_intrs[MAXSTATLEN]; 284 char rl_polls[MAXSTATLEN]; 285 char rl_sdrops[MAXSTATLEN]; 286 char rl_chl10[MAXSTATLEN]; 287 char rl_ch10_50[MAXSTATLEN]; 288 char rl_chg50[MAXSTATLEN]; 289 } rx_lane_fields_buf_t; 290 291 static ofmt_field_t rx_lane_s_fields[] = { 292 { "LINK", 10, 293 offsetof(rx_lane_fields_buf_t, rl_linkname), print_default_cb}, 294 { "TYPE", 5, 295 offsetof(rx_lane_fields_buf_t, rl_type), print_default_cb}, 296 { "ID", 7, 297 offsetof(rx_lane_fields_buf_t, rl_id), print_default_cb}, 298 { "INDEX", 6, 299 offsetof(rx_lane_fields_buf_t, rl_index), print_default_cb}, 300 { "IPKTS", 8, 301 offsetof(rx_lane_fields_buf_t, rl_ipackets), print_default_cb}, 302 { "RBYTES", 8, 303 offsetof(rx_lane_fields_buf_t, rl_rbytes), print_default_cb}, 304 { "INTRS", 8, 305 offsetof(rx_lane_fields_buf_t, rl_intrs), print_default_cb}, 306 { "POLLS", 8, 307 offsetof(rx_lane_fields_buf_t, rl_polls), print_default_cb}, 308 { "SDROPS", 8, 309 offsetof(rx_lane_fields_buf_t, rl_sdrops), print_default_cb}, 310 { "CH<10", 8, 311 offsetof(rx_lane_fields_buf_t, rl_chl10), print_default_cb}, 312 { "CH10-50", 8, 313 offsetof(rx_lane_fields_buf_t, rl_ch10_50), print_default_cb}, 314 { "CH>50", 8, 315 offsetof(rx_lane_fields_buf_t, rl_chg50), print_default_cb}, 316 { NULL, 0, 0, NULL}}; 317 318 /* 319 * dlstat show-link -r -F: Rx fanout stat fields 320 */ 321 typedef struct rx_fanout_lane_fields_buf_s { 322 char rfl_linkname[MAXLINKNAMELEN]; 323 char rfl_type[MAXSTATLEN]; 324 char rfl_id[MAXSTATLEN]; 325 char rfl_index[MAXSTATLEN]; 326 char rfl_fout[MAXSTATLEN]; 327 char rfl_ipackets[MAXSTATLEN]; 328 char rfl_rbytes[MAXSTATLEN]; 329 } rx_fanout_lane_fields_buf_t; 330 331 static ofmt_field_t rx_fanout_lane_s_fields[] = { 332 { "LINK", 15, 333 offsetof(rx_fanout_lane_fields_buf_t, rfl_linkname), print_default_cb}, 334 { "TYPE", 5, 335 offsetof(rx_fanout_lane_fields_buf_t, rfl_type), print_default_cb}, 336 { "ID", 7, 337 offsetof(rx_fanout_lane_fields_buf_t, rfl_id), print_default_cb}, 338 { "INDEX", 6, 339 offsetof(rx_fanout_lane_fields_buf_t, rfl_index), print_default_cb}, 340 { "FOUT", 6, 341 offsetof(rx_fanout_lane_fields_buf_t, rfl_fout), print_default_cb}, 342 { "IPKTS", 8, 343 offsetof(rx_fanout_lane_fields_buf_t, rfl_ipackets), print_default_cb}, 344 { "RBYTES", 8, 345 offsetof(rx_fanout_lane_fields_buf_t, rfl_rbytes), print_default_cb}, 346 { NULL, 0, 0, NULL}}; 347 348 /* 349 * dlstat show-link -t: Tx Lane stat fields 350 */ 351 typedef struct tx_lane_fields_buf_s { 352 char tl_linkname[MAXLINKNAMELEN]; 353 char tl_index[MAXSTATLEN]; 354 char tl_type[MAXSTATLEN]; 355 char tl_id[MAXSTATLEN]; 356 char tl_opackets[MAXSTATLEN]; 357 char tl_obytes[MAXSTATLEN]; 358 char tl_blockcnt[MAXSTATLEN]; 359 char tl_unblockcnt[MAXSTATLEN]; 360 char tl_sdrops[MAXSTATLEN]; 361 } tx_lane_fields_buf_t; 362 363 static ofmt_field_t tx_lane_s_fields[] = { 364 { "LINK", 15, 365 offsetof(tx_lane_fields_buf_t, tl_linkname), print_default_cb}, 366 { "TYPE", 5, 367 offsetof(tx_lane_fields_buf_t, tl_type), print_default_cb}, 368 { "ID", 7, 369 offsetof(tx_lane_fields_buf_t, tl_id), print_default_cb}, 370 { "INDEX", 6, 371 offsetof(tx_lane_fields_buf_t, tl_index), print_default_cb}, 372 { "OPKTS", 8, 373 offsetof(tx_lane_fields_buf_t, tl_opackets), print_default_cb}, 374 { "OBYTES", 8, 375 offsetof(tx_lane_fields_buf_t, tl_obytes), print_default_cb}, 376 { "BLKCNT", 8, 377 offsetof(tx_lane_fields_buf_t, tl_blockcnt), print_default_cb}, 378 { "UBLKCNT", 8, 379 offsetof(tx_lane_fields_buf_t, tl_unblockcnt), print_default_cb}, 380 { "SDROPS", 8, 381 offsetof(tx_lane_fields_buf_t, tl_sdrops), print_default_cb}, 382 { NULL, 0, 0, NULL}}; 383 384 /* 385 * dlstat show-aggr: aggr port stat fields 386 */ 387 typedef struct aggr_port_fields_buf_s { 388 char ap_linkname[MAXLINKNAMELEN]; 389 char ap_portname[MAXLINKNAMELEN]; 390 char ap_ipackets[MAXSTATLEN]; 391 char ap_rbytes[MAXSTATLEN]; 392 char ap_opackets[MAXSTATLEN]; 393 char ap_obytes[MAXSTATLEN]; 394 } aggr_port_fields_buf_t; 395 396 static ofmt_field_t aggr_port_s_fields[] = { 397 { "LINK", 15, 398 offsetof(aggr_port_fields_buf_t, ap_linkname), print_default_cb}, 399 { "PORT", 15, 400 offsetof(aggr_port_fields_buf_t, ap_portname), print_default_cb}, 401 { "IPKTS", 8, 402 offsetof(aggr_port_fields_buf_t, ap_ipackets), print_default_cb}, 403 { "RBYTES", 8, 404 offsetof(aggr_port_fields_buf_t, ap_rbytes), print_default_cb}, 405 { "OPKTS", 8, 406 offsetof(aggr_port_fields_buf_t, ap_opackets), print_default_cb}, 407 { "OBYTES", 8, 408 offsetof(aggr_port_fields_buf_t, ap_obytes), print_default_cb}, 409 { NULL, 0, 0, NULL}}; 410 411 /* 412 * structures for 'dlstat show-link -h' 413 */ 414 typedef struct history_fields_buf_s { 415 char h_link[12]; 416 char h_duration[10]; 417 char h_ipackets[9]; 418 char h_rbytes[10]; 419 char h_opackets[9]; 420 char h_obytes[10]; 421 char h_bandwidth[15]; 422 } history_fields_buf_t; 423 424 static ofmt_field_t history_fields[] = { 425 { "LINK", 13, 426 offsetof(history_fields_buf_t, h_link), print_default_cb}, 427 { "DURATION", 11, 428 offsetof(history_fields_buf_t, h_duration), print_default_cb}, 429 { "IPKTS", 10, 430 offsetof(history_fields_buf_t, h_ipackets), print_default_cb}, 431 { "RBYTES", 11, 432 offsetof(history_fields_buf_t, h_rbytes), print_default_cb}, 433 { "OPKTS", 10, 434 offsetof(history_fields_buf_t, h_opackets), print_default_cb}, 435 { "OBYTES", 11, 436 offsetof(history_fields_buf_t, h_obytes), print_default_cb}, 437 { "BANDWIDTH", 16, 438 offsetof(history_fields_buf_t, h_bandwidth), print_default_cb}, 439 { NULL, 0, 0, NULL}}; 440 441 /* 442 * structures for 'dlstat show-link -h link' 443 */ 444 typedef struct history_l_fields_buf_s { 445 char hl_link[12]; 446 char hl_stime[13]; 447 char hl_etime[13]; 448 char hl_rbytes[8]; 449 char hl_obytes[8]; 450 char hl_bandwidth[15]; 451 } history_l_fields_buf_t; 452 453 static ofmt_field_t history_l_fields[] = { 454 /* name, field width, offset */ 455 { "LINK", 13, 456 offsetof(history_l_fields_buf_t, hl_link), print_default_cb}, 457 { "START", 14, 458 offsetof(history_l_fields_buf_t, hl_stime), print_default_cb}, 459 { "END", 14, 460 offsetof(history_l_fields_buf_t, hl_etime), print_default_cb}, 461 { "RBYTES", 9, 462 offsetof(history_l_fields_buf_t, hl_rbytes), print_default_cb}, 463 { "OBYTES", 9, 464 offsetof(history_l_fields_buf_t, hl_obytes), print_default_cb}, 465 { "BANDWIDTH", 16, 466 offsetof(history_l_fields_buf_t, hl_bandwidth), print_default_cb}, 467 { NULL, 0, 0, NULL}} 468 ; 469 470 static char *progname; 471 472 /* 473 * Handle to libdladm. Opened in main() before the sub-command 474 * specific function is called. 475 */ 476 static dladm_handle_t handle = NULL; 477 478 static void 479 usage(void) 480 { 481 int i; 482 cmd_t *cmdp; 483 484 (void) fprintf(stderr, gettext("usage: ")); 485 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 486 cmdp = &cmds[i]; 487 if (cmdp->c_usage != NULL) 488 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 489 } 490 491 /* close dladm handle if it was opened */ 492 if (handle != NULL) 493 dladm_close(handle); 494 495 exit(1); 496 } 497 498 int 499 main(int argc, char *argv[]) 500 { 501 int i; 502 cmd_t *cmdp; 503 dladm_status_t status; 504 505 (void) setlocale(LC_ALL, ""); 506 #if !defined(TEXT_DOMAIN) 507 #define TEXT_DOMAIN "SYS_TEST" 508 #endif 509 (void) textdomain(TEXT_DOMAIN); 510 511 progname = argv[0]; 512 513 /* Open the libdladm handle */ 514 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) 515 die_dlerr(status, "could not open /dev/dld"); 516 517 if (argc == 1) { 518 do_show(argc - 1, NULL, cmds[0].c_usage); 519 goto done; 520 } 521 522 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 523 cmdp = &cmds[i]; 524 if (strcmp(argv[1], cmdp->c_name) == 0) { 525 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 526 goto done; 527 } 528 } 529 530 do_show(argc, &argv[0], cmds[0].c_usage); 531 532 done: 533 dladm_close(handle); 534 return (0); 535 } 536 537 /*ARGSUSED*/ 538 static int 539 show_history_date(dladm_usage_t *history, void *arg) 540 { 541 show_history_state_t *state = arg; 542 time_t stime; 543 char timebuf[20]; 544 dladm_status_t status; 545 uint32_t flags; 546 547 /* 548 * Only show history information for existing links unless '-a' 549 * is specified. 550 */ 551 if (!state->hs_showall) { 552 if ((status = dladm_name2info(handle, history->du_name, 553 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 554 return (status); 555 } 556 if ((flags & DLADM_OPT_ACTIVE) == 0) 557 return (DLADM_STATUS_LINKINVAL); 558 } 559 560 stime = history->du_stime; 561 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 562 localtime(&stime)); 563 (void) printf("%s\n", timebuf); 564 565 return (DLADM_STATUS_OK); 566 } 567 568 static int 569 show_history_time(dladm_usage_t *history, void *arg) 570 { 571 show_history_state_t *state = arg; 572 char buf[DLADM_STRSIZE]; 573 history_l_fields_buf_t ubuf; 574 time_t time; 575 double bw; 576 dladm_status_t status; 577 uint32_t flags; 578 579 /* 580 * Only show history information for existing links unless '-a' 581 * is specified. 582 */ 583 if (!state->hs_showall) { 584 if ((status = dladm_name2info(handle, history->du_name, 585 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 586 return (status); 587 } 588 if ((flags & DLADM_OPT_ACTIVE) == 0) 589 return (DLADM_STATUS_LINKINVAL); 590 } 591 592 if (state->hs_plot) { 593 if (!state->hs_printheader) { 594 if (state->hs_first) { 595 (void) printf("# Time"); 596 state->hs_first = B_FALSE; 597 } 598 (void) printf(" %s", history->du_name); 599 if (history->du_last) { 600 (void) printf("\n"); 601 state->hs_first = B_TRUE; 602 state->hs_printheader = B_TRUE; 603 } 604 } else { 605 if (state->hs_first) { 606 time = history->du_etime; 607 (void) strftime(buf, sizeof (buf), "%T", 608 localtime(&time)); 609 state->hs_first = B_FALSE; 610 (void) printf("%s", buf); 611 } 612 bw = (double)history->du_bandwidth/1000; 613 (void) printf(" %.2f", bw); 614 if (history->du_last) { 615 (void) printf("\n"); 616 state->hs_first = B_TRUE; 617 } 618 } 619 return (DLADM_STATUS_OK); 620 } 621 622 bzero(&ubuf, sizeof (ubuf)); 623 624 (void) snprintf(ubuf.hl_link, sizeof (ubuf.hl_link), "%s", 625 history->du_name); 626 time = history->du_stime; 627 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 628 (void) snprintf(ubuf.hl_stime, sizeof (ubuf.hl_stime), "%s", 629 buf); 630 time = history->du_etime; 631 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 632 (void) snprintf(ubuf.hl_etime, sizeof (ubuf.hl_etime), "%s", 633 buf); 634 (void) snprintf(ubuf.hl_rbytes, sizeof (ubuf.hl_rbytes), 635 "%llu", history->du_rbytes); 636 (void) snprintf(ubuf.hl_obytes, sizeof (ubuf.hl_obytes), 637 "%llu", history->du_obytes); 638 (void) snprintf(ubuf.hl_bandwidth, sizeof (ubuf.hl_bandwidth), 639 "%s Mbps", dladm_bw2str(history->du_bandwidth, buf)); 640 641 ofmt_print(state->hs_ofmt, &ubuf); 642 return (DLADM_STATUS_OK); 643 } 644 645 static int 646 show_history_res(dladm_usage_t *history, void *arg) 647 { 648 show_history_state_t *state = arg; 649 char buf[DLADM_STRSIZE]; 650 history_fields_buf_t ubuf; 651 dladm_status_t status; 652 uint32_t flags; 653 654 /* 655 * Only show history information for existing links unless '-a' 656 * is specified. 657 */ 658 if (!state->hs_showall) { 659 if ((status = dladm_name2info(handle, history->du_name, 660 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 661 return (status); 662 } 663 if ((flags & DLADM_OPT_ACTIVE) == 0) 664 return (DLADM_STATUS_LINKINVAL); 665 } 666 667 bzero(&ubuf, sizeof (ubuf)); 668 669 (void) snprintf(ubuf.h_link, sizeof (ubuf.h_link), "%s", 670 history->du_name); 671 (void) snprintf(ubuf.h_duration, sizeof (ubuf.h_duration), 672 "%llu", history->du_duration); 673 (void) snprintf(ubuf.h_ipackets, sizeof (ubuf.h_ipackets), 674 "%llu", history->du_ipackets); 675 (void) snprintf(ubuf.h_rbytes, sizeof (ubuf.h_rbytes), 676 "%llu", history->du_rbytes); 677 (void) snprintf(ubuf.h_opackets, sizeof (ubuf.h_opackets), 678 "%llu", history->du_opackets); 679 (void) snprintf(ubuf.h_obytes, sizeof (ubuf.h_obytes), 680 "%llu", history->du_obytes); 681 (void) snprintf(ubuf.h_bandwidth, sizeof (ubuf.h_bandwidth), 682 "%s Mbps", dladm_bw2str(history->du_bandwidth, buf)); 683 684 ofmt_print(state->hs_ofmt, &ubuf); 685 686 return (DLADM_STATUS_OK); 687 } 688 689 static boolean_t 690 valid_formatspec(char *formatspec_str) 691 { 692 return (strcmp(formatspec_str, "gnuplot") == 0); 693 } 694 695 /*ARGSUSED*/ 696 static void 697 do_show_history(int argc, char *argv[], const char *use) 698 { 699 char *file = NULL; 700 int opt; 701 dladm_status_t status; 702 boolean_t d_arg = B_FALSE; 703 char *stime = NULL; 704 char *etime = NULL; 705 char *resource = NULL; 706 show_history_state_t state; 707 boolean_t o_arg = B_FALSE; 708 boolean_t F_arg = B_FALSE; 709 char *fields_str = NULL; 710 char *formatspec_str = NULL; 711 char *all_l_fields = 712 "link,start,end,rbytes,obytes,bandwidth"; 713 ofmt_handle_t ofmt; 714 ofmt_status_t oferr; 715 uint_t ofmtflags = 0; 716 717 bzero(&state, sizeof (show_history_state_t)); 718 state.hs_parsable = B_FALSE; 719 state.hs_printheader = B_FALSE; 720 state.hs_plot = B_FALSE; 721 state.hs_first = B_TRUE; 722 723 while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) { 724 switch (opt) { 725 case 'd': 726 d_arg = B_TRUE; 727 break; 728 case 'a': 729 state.hs_showall = B_TRUE; 730 break; 731 case 'f': 732 file = optarg; 733 break; 734 case 's': 735 stime = optarg; 736 break; 737 case 'e': 738 etime = optarg; 739 break; 740 case 'o': 741 o_arg = B_TRUE; 742 fields_str = optarg; 743 break; 744 case 'F': 745 state.hs_plot = F_arg = B_TRUE; 746 formatspec_str = optarg; 747 break; 748 default: 749 die_opterr(optopt, opt, use); 750 break; 751 } 752 } 753 754 if (file == NULL) 755 die("show-link -h requires a file"); 756 757 if (optind == (argc-1)) { 758 uint32_t flags; 759 760 resource = argv[optind]; 761 if (!state.hs_showall && 762 (((status = dladm_name2info(handle, resource, NULL, &flags, 763 NULL, NULL)) != DLADM_STATUS_OK) || 764 ((flags & DLADM_OPT_ACTIVE) == 0))) { 765 die("invalid link: '%s'", resource); 766 } 767 } 768 769 if (F_arg && d_arg) 770 die("incompatible -d and -F options"); 771 772 if (F_arg && !valid_formatspec(formatspec_str)) 773 die("Format specifier %s not supported", formatspec_str); 774 775 if (state.hs_parsable) 776 ofmtflags |= OFMT_PARSABLE; 777 778 if (resource == NULL && stime == NULL && etime == NULL) { 779 oferr = ofmt_open(fields_str, history_fields, ofmtflags, 0, 780 &ofmt); 781 } else { 782 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 783 fields_str = all_l_fields; 784 oferr = ofmt_open(fields_str, history_l_fields, ofmtflags, 0, 785 &ofmt); 786 787 } 788 ofmt_check(oferr, state.hs_parsable, ofmt, die, warn); 789 state.hs_ofmt = ofmt; 790 791 if (d_arg) { 792 /* Print log dates */ 793 status = dladm_usage_dates(show_history_date, 794 DLADM_LOGTYPE_LINK, file, resource, &state); 795 } else if (resource == NULL && stime == NULL && etime == NULL && 796 !F_arg) { 797 /* Print summary */ 798 status = dladm_usage_summary(show_history_res, 799 DLADM_LOGTYPE_LINK, file, &state); 800 } else if (resource != NULL) { 801 /* Print log entries for named resource */ 802 status = dladm_walk_usage_res(show_history_time, 803 DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 804 } else { 805 /* Print time and information for each link */ 806 status = dladm_walk_usage_time(show_history_time, 807 DLADM_LOGTYPE_LINK, file, stime, etime, &state); 808 } 809 810 if (status != DLADM_STATUS_OK) 811 die_dlerr(status, "show-link -h"); 812 ofmt_close(ofmt); 813 } 814 815 boolean_t 816 dlstat_unit(char *oarg, char *unit) 817 { 818 if ((strcmp(oarg, "R") == 0) || (strcmp(oarg, "K") == 0) || 819 (strcmp(oarg, "M") == 0) || (strcmp(oarg, "G") == 0) || 820 (strcmp(oarg, "T") == 0) || (strcmp(oarg, "P") == 0)) { 821 *unit = oarg[0]; 822 return (B_TRUE); 823 } 824 825 return (B_FALSE); 826 } 827 828 void 829 map_to_units(char *buf, uint_t bufsize, double num, char unit, 830 boolean_t parsable) 831 { 832 if (parsable) { 833 (void) snprintf(buf, bufsize, "%.0lf", num); 834 return; 835 } 836 837 if (unit == '\0') { 838 int index; 839 840 for (index = 0; (int)(num/1000) != 0; index++, num /= 1000) 841 ; 842 843 switch (index) { 844 case 0: 845 unit = '\0'; 846 break; 847 case 1: 848 unit = 'K'; 849 break; 850 case 2: 851 unit = 'M'; 852 break; 853 case 3: 854 unit = 'G'; 855 break; 856 case 4: 857 unit = 'T'; 858 break; 859 case 5: 860 /* Largest unit supported */ 861 default: 862 unit = 'P'; 863 break; 864 } 865 } else { 866 switch (unit) { 867 case 'R': 868 /* Already raw numbers */ 869 unit = '\0'; 870 break; 871 case 'K': 872 num /= 1000; 873 break; 874 case 'M': 875 num /= (1000*1000); 876 break; 877 case 'G': 878 num /= (1000*1000*1000); 879 break; 880 case 'T': 881 num /= (1000.0*1000.0*1000.0*1000.0); 882 break; 883 case 'P': 884 /* Largest unit supported */ 885 default: 886 num /= (1000.0*1000.0*1000.0*1000.0*1000.0); 887 break; 888 } 889 } 890 891 if (unit == '\0') 892 (void) snprintf(buf, bufsize, " %7.0lf%c", num, unit); 893 else 894 (void) snprintf(buf, bufsize, " %6.2lf%c", num, unit); 895 } 896 897 link_chain_t * 898 get_link_prev_stat(datalink_id_t linkid, void *arg) 899 { 900 show_state_t *state = (show_state_t *)arg; 901 link_chain_t *link_curr = NULL; 902 903 /* Scan prev linkid list and look for entry matching this entry */ 904 for (link_curr = state->ls_linkchain; link_curr; 905 link_curr = link_curr->lc_next) { 906 if (link_curr->lc_linkid == linkid) 907 break; 908 } 909 /* New link, add it */ 910 if (link_curr == NULL) { 911 link_curr = (link_chain_t *)malloc(sizeof (link_chain_t)); 912 if (link_curr == NULL) 913 goto done; 914 link_curr->lc_linkid = linkid; 915 bzero(&link_curr->lc_statchain, 916 sizeof (link_curr->lc_statchain)); 917 link_curr->lc_next = state->ls_linkchain; 918 state->ls_linkchain = link_curr; 919 } 920 done: 921 return (link_curr); 922 } 923 924 /* 925 * Number of links may change while dlstat with -i is executing. 926 * Free memory allocated for links that are no longer there. 927 * Prepare for next iteration by marking visited = false for existing stat 928 * entries. 929 */ 930 static void 931 cleanup_removed_links(show_state_t *state) 932 { 933 link_chain_t *lcurr; 934 link_chain_t *lprev; 935 link_chain_t *tofree; 936 int i; 937 938 /* Delete all nodes from the list that have lc_visited marked false */ 939 lcurr = state->ls_linkchain; 940 while (lcurr != NULL) { 941 if (lcurr->lc_visited) { 942 lcurr->lc_visited = B_FALSE; 943 lprev = lcurr; 944 lcurr = lcurr->lc_next; 945 continue; 946 } 947 /* Is it head of the list? */ 948 if (lcurr == state->ls_linkchain) 949 state->ls_linkchain = lcurr->lc_next; 950 else 951 lprev->lc_next = lcurr->lc_next; 952 /* lprev remains the same */ 953 tofree = lcurr; 954 lcurr = lcurr->lc_next; 955 956 /* Free stats memory for the removed link */ 957 for (i = 0; i < DLADM_STAT_NUM_STATS; i++) { 958 if (state->ls_stattype[i]) 959 dladm_link_stat_free(tofree->lc_statchain[i]); 960 } 961 free(tofree); 962 } 963 } 964 965 void * 966 print_total_stats(const char *linkname, void *statentry, char unit, 967 boolean_t parsable) 968 { 969 total_stat_entry_t *sentry = statentry; 970 total_stat_t *link_stats = &sentry->tse_stats; 971 total_fields_buf_t *buf; 972 973 buf = malloc(sizeof (total_fields_buf_t)); 974 if (buf == NULL) 975 goto done; 976 977 (void) snprintf(buf->t_linkname, sizeof (buf->t_linkname), "%s", 978 linkname); 979 980 map_to_units(buf->t_ipackets, sizeof (buf->t_ipackets), 981 link_stats->ts_ipackets, unit, parsable); 982 983 map_to_units(buf->t_rbytes, sizeof (buf->t_rbytes), 984 link_stats->ts_rbytes, unit, parsable); 985 986 map_to_units(buf->t_opackets, sizeof (buf->t_opackets), 987 link_stats->ts_opackets, unit, parsable); 988 989 map_to_units(buf->t_obytes, sizeof (buf->t_obytes), 990 link_stats->ts_obytes, unit, parsable); 991 992 done: 993 return (buf); 994 } 995 996 void * 997 print_rx_generic_ring_stats(const char *linkname, void *statentry, char unit, 998 boolean_t parsable) 999 { 1000 ring_stat_entry_t *sentry = statentry; 1001 ring_stat_t *link_stats = &sentry->re_stats; 1002 ring_fields_buf_t *buf; 1003 1004 buf = malloc(sizeof (ring_fields_buf_t)); 1005 if (buf == NULL) 1006 goto done; 1007 1008 (void) snprintf(buf->r_linkname, sizeof (buf->r_linkname), "%s", 1009 linkname); 1010 1011 (void) snprintf(buf->r_type, sizeof (buf->r_type), "rx"); 1012 1013 if (sentry->re_index == DLSTAT_INVALID_ENTRY) { 1014 (void) snprintf(buf->r_index, sizeof (buf->r_index), "--"); 1015 } else { 1016 (void) snprintf(buf->r_index, sizeof (buf->r_index), 1017 "%llu", sentry->re_index); 1018 } 1019 1020 map_to_units(buf->r_packets, sizeof (buf->r_packets), 1021 link_stats->r_packets, unit, parsable); 1022 1023 map_to_units(buf->r_bytes, sizeof (buf->r_bytes), 1024 link_stats->r_bytes, unit, parsable); 1025 1026 done: 1027 return (buf); 1028 } 1029 1030 void * 1031 print_tx_generic_ring_stats(const char *linkname, void *statentry, char unit, 1032 boolean_t parsable) 1033 { 1034 ring_stat_entry_t *sentry = statentry; 1035 ring_stat_t *link_stats = &sentry->re_stats; 1036 ring_fields_buf_t *buf; 1037 1038 buf = malloc(sizeof (ring_fields_buf_t)); 1039 if (buf == NULL) 1040 goto done; 1041 1042 (void) snprintf(buf->r_linkname, sizeof (buf->r_linkname), "%s", 1043 linkname); 1044 1045 (void) snprintf(buf->r_type, sizeof (buf->r_type), "tx"); 1046 1047 if (sentry->re_index == DLSTAT_INVALID_ENTRY) { 1048 (void) snprintf(buf->r_index, sizeof (buf->r_index), "--"); 1049 } else { 1050 (void) snprintf(buf->r_index, sizeof (buf->r_index), 1051 "%llu", sentry->re_index); 1052 } 1053 1054 map_to_units(buf->r_packets, sizeof (buf->r_packets), 1055 link_stats->r_packets, unit, parsable); 1056 1057 map_to_units(buf->r_bytes, sizeof (buf->r_bytes), 1058 link_stats->r_bytes, unit, parsable); 1059 1060 done: 1061 return (buf); 1062 } 1063 1064 void * 1065 print_rx_ring_stats(const char *linkname, void *statentry, char unit, 1066 boolean_t parsable) 1067 { 1068 ring_stat_entry_t *sentry = statentry; 1069 ring_stat_t *link_stats = &sentry->re_stats; 1070 rx_ring_fields_buf_t *buf; 1071 1072 buf = malloc(sizeof (rx_ring_fields_buf_t)); 1073 if (buf == NULL) 1074 goto done; 1075 1076 (void) snprintf(buf->rr_linkname, sizeof (buf->rr_linkname), "%s", 1077 linkname); 1078 1079 (void) snprintf(buf->rr_type, sizeof (buf->rr_type), "rx"); 1080 1081 if (sentry->re_index == DLSTAT_INVALID_ENTRY) { 1082 (void) snprintf(buf->rr_index, sizeof (buf->rr_index), "--"); 1083 } else { 1084 (void) snprintf(buf->rr_index, sizeof (buf->rr_index), 1085 "%llu", sentry->re_index); 1086 } 1087 1088 map_to_units(buf->rr_ipackets, sizeof (buf->rr_ipackets), 1089 link_stats->r_packets, unit, parsable); 1090 1091 map_to_units(buf->rr_rbytes, sizeof (buf->rr_rbytes), 1092 link_stats->r_bytes, unit, parsable); 1093 1094 done: 1095 return (buf); 1096 } 1097 1098 void * 1099 print_tx_ring_stats(const char *linkname, void *statentry, char unit, 1100 boolean_t parsable) 1101 { 1102 ring_stat_entry_t *sentry = statentry; 1103 ring_stat_t *link_stats = &sentry->re_stats; 1104 tx_ring_fields_buf_t *buf; 1105 1106 buf = malloc(sizeof (tx_ring_fields_buf_t)); 1107 if (buf == NULL) 1108 goto done; 1109 1110 (void) snprintf(buf->tr_linkname, sizeof (buf->tr_linkname), "%s", 1111 linkname); 1112 1113 (void) snprintf(buf->tr_type, sizeof (buf->tr_type), "tx"); 1114 1115 if (sentry->re_index == DLSTAT_INVALID_ENTRY) { 1116 (void) snprintf(buf->tr_index, sizeof (buf->tr_index), "--"); 1117 } else { 1118 (void) snprintf(buf->tr_index, sizeof (buf->tr_index), 1119 "%llu", sentry->re_index); 1120 } 1121 1122 map_to_units(buf->tr_opackets, sizeof (buf->tr_opackets), 1123 link_stats->r_packets, unit, parsable); 1124 1125 map_to_units(buf->tr_obytes, sizeof (buf->tr_obytes), 1126 link_stats->r_bytes, unit, parsable); 1127 1128 done: 1129 return (buf); 1130 } 1131 1132 void * 1133 print_rx_generic_lane_stats(const char *linkname, void *statentry, char unit, 1134 boolean_t parsable) 1135 { 1136 rx_lane_stat_entry_t *sentry = statentry; 1137 rx_lane_stat_t *link_stats = &sentry->rle_stats; 1138 lane_fields_buf_t *buf; 1139 1140 if (sentry->rle_id == L_DFNCT) 1141 return (NULL); 1142 1143 buf = malloc(sizeof (lane_fields_buf_t)); 1144 if (buf == NULL) 1145 goto done; 1146 1147 (void) snprintf(buf->l_linkname, sizeof (buf->l_linkname), "%s", 1148 linkname); 1149 1150 (void) snprintf(buf->l_type, sizeof (buf->l_type), "rx"); 1151 1152 if (sentry->rle_id == L_HWLANE) 1153 (void) snprintf(buf->l_id, sizeof (buf->l_id), "hw"); 1154 else if (sentry->rle_id == L_SWLANE) 1155 (void) snprintf(buf->l_id, sizeof (buf->l_id), "sw"); 1156 else if (sentry->rle_id == L_LOCAL) 1157 (void) snprintf(buf->l_id, sizeof (buf->l_id), "local"); 1158 else if (sentry->rle_id == L_BCAST) 1159 (void) snprintf(buf->l_id, sizeof (buf->l_id), "bcast"); 1160 else 1161 (void) snprintf(buf->l_id, sizeof (buf->l_id), "--"); 1162 1163 if (sentry->rle_index == DLSTAT_INVALID_ENTRY) { 1164 (void) snprintf(buf->l_index, sizeof (buf->l_index), "--"); 1165 } else { 1166 (void) snprintf(buf->l_index, sizeof (buf->l_index), 1167 "%llu", sentry->rle_index); 1168 } 1169 1170 map_to_units(buf->l_packets, sizeof (buf->l_packets), 1171 link_stats->rl_ipackets, unit, parsable); 1172 1173 map_to_units(buf->l_bytes, sizeof (buf->l_bytes), 1174 link_stats->rl_rbytes, unit, parsable); 1175 1176 done: 1177 return (buf); 1178 } 1179 1180 void * 1181 print_tx_generic_lane_stats(const char *linkname, void *statentry, char unit, 1182 boolean_t parsable) 1183 { 1184 tx_lane_stat_entry_t *sentry = statentry; 1185 tx_lane_stat_t *link_stats = &sentry->tle_stats; 1186 lane_fields_buf_t *buf; 1187 1188 if (sentry->tle_id == L_DFNCT) 1189 return (NULL); 1190 1191 buf = malloc(sizeof (lane_fields_buf_t)); 1192 if (buf == NULL) 1193 goto done; 1194 1195 (void) snprintf(buf->l_linkname, sizeof (buf->l_linkname), "%s", 1196 linkname); 1197 1198 (void) snprintf(buf->l_type, sizeof (buf->l_type), "tx"); 1199 1200 if (sentry->tle_id == L_HWLANE) 1201 (void) snprintf(buf->l_id, sizeof (buf->l_id), "hw"); 1202 else if (sentry->tle_id == L_SWLANE) 1203 (void) snprintf(buf->l_id, sizeof (buf->l_id), "sw"); 1204 else if (sentry->tle_id == L_BCAST) 1205 (void) snprintf(buf->l_id, sizeof (buf->l_id), "bcast"); 1206 else 1207 (void) snprintf(buf->l_id, sizeof (buf->l_id), "--"); 1208 1209 if (sentry->tle_index == DLSTAT_INVALID_ENTRY) { 1210 (void) snprintf(buf->l_index, sizeof (buf->l_index), "--"); 1211 } else { 1212 (void) snprintf(buf->l_index, sizeof (buf->l_index), 1213 "%llu", sentry->tle_index); 1214 } 1215 map_to_units(buf->l_packets, sizeof (buf->l_packets), 1216 link_stats->tl_opackets, unit, parsable); 1217 1218 map_to_units(buf->l_bytes, sizeof (buf->l_bytes), 1219 link_stats->tl_obytes, unit, parsable); 1220 1221 done: 1222 return (buf); 1223 } 1224 1225 void * 1226 print_rx_lane_stats(const char *linkname, void *statentry, char unit, 1227 boolean_t parsable) 1228 { 1229 rx_lane_stat_entry_t *sentry = statentry; 1230 rx_lane_stat_t *link_stats = &sentry->rle_stats; 1231 rx_lane_fields_buf_t *buf; 1232 1233 if (sentry->rle_id == L_DFNCT) 1234 return (NULL); 1235 1236 buf = malloc(sizeof (rx_lane_fields_buf_t)); 1237 if (buf == NULL) 1238 goto done; 1239 1240 (void) snprintf(buf->rl_linkname, sizeof (buf->rl_linkname), "%s", 1241 linkname); 1242 1243 (void) snprintf(buf->rl_type, sizeof (buf->rl_type), "rx"); 1244 1245 if (sentry->rle_id == L_HWLANE) 1246 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "hw"); 1247 else if (sentry->rle_id == L_SWLANE) 1248 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "sw"); 1249 else if (sentry->rle_id == L_LOCAL) 1250 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "local"); 1251 else if (sentry->rle_id == L_BCAST) 1252 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "bcast"); 1253 else 1254 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "--"); 1255 1256 if (sentry->rle_index == DLSTAT_INVALID_ENTRY) { 1257 (void) snprintf(buf->rl_index, sizeof (buf->rl_index), "--"); 1258 } else { 1259 (void) snprintf(buf->rl_index, sizeof (buf->rl_index), 1260 "%llu", sentry->rle_index); 1261 } 1262 1263 map_to_units(buf->rl_ipackets, sizeof (buf->rl_ipackets), 1264 link_stats->rl_ipackets, unit, parsable); 1265 1266 map_to_units(buf->rl_rbytes, sizeof (buf->rl_rbytes), 1267 link_stats->rl_rbytes, unit, parsable); 1268 1269 map_to_units(buf->rl_intrs, sizeof (buf->rl_intrs), 1270 link_stats->rl_intrs, unit, parsable); 1271 1272 map_to_units(buf->rl_polls, sizeof (buf->rl_polls), 1273 link_stats->rl_polls, unit, parsable); 1274 1275 map_to_units(buf->rl_sdrops, sizeof (buf->rl_sdrops), 1276 link_stats->rl_sdrops, unit, parsable); 1277 1278 map_to_units(buf->rl_chl10, sizeof (buf->rl_chl10), 1279 link_stats->rl_chl10, unit, parsable); 1280 1281 map_to_units(buf->rl_ch10_50, sizeof (buf->rl_ch10_50), 1282 link_stats->rl_ch10_50, unit, parsable); 1283 1284 map_to_units(buf->rl_chg50, sizeof (buf->rl_chg50), 1285 link_stats->rl_chg50, unit, parsable); 1286 1287 done: 1288 return (buf); 1289 } 1290 1291 void * 1292 print_tx_lane_stats(const char *linkname, void *statentry, char unit, 1293 boolean_t parsable) 1294 { 1295 tx_lane_stat_entry_t *sentry = statentry; 1296 tx_lane_stat_t *link_stats = &sentry->tle_stats; 1297 tx_lane_fields_buf_t *buf = NULL; 1298 1299 if (sentry->tle_id == L_DFNCT) 1300 return (NULL); 1301 1302 buf = malloc(sizeof (tx_lane_fields_buf_t)); 1303 if (buf == NULL) 1304 goto done; 1305 1306 (void) snprintf(buf->tl_linkname, sizeof (buf->tl_linkname), "%s", 1307 linkname); 1308 1309 (void) snprintf(buf->tl_type, sizeof (buf->tl_type), "tx"); 1310 1311 if (sentry->tle_id == L_HWLANE) 1312 (void) snprintf(buf->tl_id, sizeof (buf->tl_id), "hw"); 1313 else if (sentry->tle_id == L_SWLANE) 1314 (void) snprintf(buf->tl_id, sizeof (buf->tl_id), "sw"); 1315 else if (sentry->tle_id == L_BCAST) 1316 (void) snprintf(buf->tl_id, sizeof (buf->tl_id), "bcast"); 1317 else 1318 (void) snprintf(buf->tl_id, sizeof (buf->tl_id), "--"); 1319 1320 if (sentry->tle_index == DLSTAT_INVALID_ENTRY) { 1321 (void) snprintf(buf->tl_index, sizeof (buf->tl_index), "--"); 1322 } else { 1323 (void) snprintf(buf->tl_index, sizeof (buf->tl_index), 1324 "%llu", sentry->tle_index); 1325 } 1326 1327 map_to_units(buf->tl_opackets, sizeof (buf->tl_opackets), 1328 link_stats->tl_opackets, unit, parsable); 1329 1330 map_to_units(buf->tl_obytes, sizeof (buf->tl_obytes), 1331 link_stats->tl_obytes, unit, parsable); 1332 1333 map_to_units(buf->tl_blockcnt, sizeof (buf->tl_blockcnt), 1334 link_stats->tl_blockcnt, unit, parsable); 1335 1336 map_to_units(buf->tl_unblockcnt, sizeof (buf->tl_unblockcnt), 1337 link_stats->tl_unblockcnt, unit, parsable); 1338 1339 map_to_units(buf->tl_sdrops, sizeof (buf->tl_sdrops), 1340 link_stats->tl_sdrops, unit, parsable); 1341 1342 done: 1343 return (buf); 1344 } 1345 1346 void * 1347 print_fanout_stats(const char *linkname, void *statentry, char unit, 1348 boolean_t parsable) 1349 { 1350 fanout_stat_entry_t *sentry = statentry; 1351 fanout_stat_t *link_stats = &sentry->fe_stats; 1352 rx_fanout_lane_fields_buf_t *buf; 1353 1354 buf = malloc(sizeof (rx_fanout_lane_fields_buf_t)); 1355 if (buf == NULL) 1356 goto done; 1357 1358 (void) snprintf(buf->rfl_linkname, sizeof (buf->rfl_linkname), "%s", 1359 linkname); 1360 1361 (void) snprintf(buf->rfl_type, sizeof (buf->rfl_type), "rx"); 1362 1363 if (sentry->fe_id == L_HWLANE) 1364 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "hw"); 1365 else if (sentry->fe_id == L_SWLANE) 1366 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "sw"); 1367 else if (sentry->fe_id == L_LCLSWLANE) 1368 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "lcl/sw"); 1369 else if (sentry->fe_id == L_LOCAL) 1370 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "local"); 1371 else if (sentry->fe_id == L_BCAST) 1372 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "bcast"); 1373 else 1374 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "--"); 1375 1376 if (sentry->fe_index == DLSTAT_INVALID_ENTRY) { 1377 (void) snprintf(buf->rfl_index, sizeof (buf->rfl_index), "--"); 1378 } else { 1379 (void) snprintf(buf->rfl_index, sizeof (buf->rfl_index), 1380 "%llu", sentry->fe_index); 1381 } 1382 1383 if (sentry->fe_foutindex == DLSTAT_INVALID_ENTRY) 1384 (void) snprintf(buf->rfl_fout, sizeof (buf->rfl_fout), "--"); 1385 else { 1386 (void) snprintf(buf->rfl_fout, sizeof (buf->rfl_fout), "%llu", 1387 sentry->fe_foutindex); 1388 } 1389 1390 map_to_units(buf->rfl_ipackets, sizeof (buf->rfl_ipackets), 1391 link_stats->f_ipackets, unit, parsable); 1392 1393 map_to_units(buf->rfl_rbytes, sizeof (buf->rfl_rbytes), 1394 link_stats->f_rbytes, unit, parsable); 1395 1396 done: 1397 return (buf); 1398 } 1399 1400 void * 1401 print_aggr_port_stats(const char *linkname, void *statentry, char unit, 1402 boolean_t parsable) 1403 { 1404 aggr_port_stat_entry_t *sentry = statentry; 1405 aggr_port_stat_t *link_stats = &sentry->ape_stats; 1406 aggr_port_fields_buf_t *buf; 1407 char portname[MAXLINKNAMELEN]; 1408 1409 buf = malloc(sizeof (aggr_port_fields_buf_t)); 1410 if (buf == NULL) 1411 goto done; 1412 1413 (void) snprintf(buf->ap_linkname, sizeof (buf->ap_linkname), "%s", 1414 linkname); 1415 1416 if (dladm_datalink_id2info(handle, sentry->ape_portlinkid, NULL, 1417 NULL, NULL, portname, DLPI_LINKNAME_MAX) 1418 != DLADM_STATUS_OK) { 1419 (void) snprintf(buf->ap_portname, 1420 sizeof (buf->ap_portname), "--"); 1421 } else { 1422 (void) snprintf(buf->ap_portname, 1423 sizeof (buf->ap_portname), "%s", portname); 1424 } 1425 1426 map_to_units(buf->ap_ipackets, sizeof (buf->ap_ipackets), 1427 link_stats->ap_ipackets, unit, parsable); 1428 1429 map_to_units(buf->ap_rbytes, sizeof (buf->ap_rbytes), 1430 link_stats->ap_rbytes, unit, parsable); 1431 1432 map_to_units(buf->ap_opackets, sizeof (buf->ap_opackets), 1433 link_stats->ap_opackets, unit, parsable); 1434 1435 map_to_units(buf->ap_obytes, sizeof (buf->ap_obytes), 1436 link_stats->ap_obytes, unit, parsable); 1437 1438 done: 1439 return (buf); 1440 } 1441 1442 dladm_stat_chain_t * 1443 query_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg, 1444 dladm_stat_type_t stattype) 1445 { 1446 link_chain_t *link_node; 1447 dladm_stat_chain_t *curr_stat; 1448 dladm_stat_chain_t *prev_stat = NULL; 1449 dladm_stat_chain_t *diff_stat = NULL; 1450 1451 /* Get prev iteration stat for this link */ 1452 link_node = get_link_prev_stat(linkid, arg); 1453 if (link_node == NULL) 1454 goto done; 1455 1456 link_node->lc_visited = B_TRUE; 1457 prev_stat = link_node->lc_statchain[stattype]; 1458 1459 /* Query library for current stats */ 1460 curr_stat = dladm_link_stat_query(dh, linkid, stattype); 1461 if (curr_stat == NULL) 1462 goto done; 1463 1464 /* current stats - prev iteration stats */ 1465 diff_stat = dladm_link_stat_diffchain(curr_stat, prev_stat, stattype); 1466 1467 /* Free prev stats */ 1468 dladm_link_stat_free(prev_stat); 1469 1470 /* Prev <- curr stats */ 1471 link_node->lc_statchain[stattype] = curr_stat; 1472 1473 done: 1474 return (diff_stat); 1475 } 1476 1477 void 1478 walk_dlstat_stats(show_state_t *state, const char *linkname, 1479 dladm_stat_type_t stattype, dladm_stat_chain_t *diff_stat) 1480 { 1481 dladm_stat_chain_t *curr; 1482 1483 /* Unpack invidual stat entry and call library consumer's callback */ 1484 for (curr = diff_stat; curr != NULL; curr = curr->dc_next) { 1485 void *fields_buf; 1486 1487 /* Format the raw numbers for printing */ 1488 fields_buf = state->ls_stats2str[stattype](linkname, 1489 curr->dc_statentry, state->ls_unit, state->ls_parsable); 1490 /* Print the stats */ 1491 if (fields_buf != NULL) 1492 ofmt_print(state->ls_ofmt, fields_buf); 1493 free(fields_buf); 1494 } 1495 } 1496 1497 static int 1498 show_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 1499 { 1500 show_state_t *state = arg; 1501 int i; 1502 dladm_stat_chain_t *diff_stat; 1503 char linkname[DLPI_LINKNAME_MAX]; 1504 1505 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1506 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1507 goto done; 1508 } 1509 1510 for (i = 0; i < DLADM_STAT_NUM_STATS; i++) { 1511 if (state->ls_stattype[i]) { 1512 /* 1513 * Query library for stats 1514 * Stats are returned as chain of raw numbers 1515 */ 1516 diff_stat = query_link_stats(handle, linkid, arg, i); 1517 walk_dlstat_stats(state, linkname, i, diff_stat); 1518 dladm_link_stat_free(diff_stat); 1519 } 1520 } 1521 done: 1522 return (DLADM_WALK_CONTINUE); 1523 } 1524 1525 void 1526 show_link_stats(datalink_id_t linkid, show_state_t state, uint32_t interval) 1527 { 1528 for (;;) { 1529 if (linkid == DATALINK_ALL_LINKID) { 1530 (void) dladm_walk_datalink_id(show_queried_stats, 1531 handle, &state, DATALINK_CLASS_ALL, 1532 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 1533 } else { 1534 (void) show_queried_stats(handle, linkid, &state); 1535 } 1536 1537 if (interval == 0) 1538 break; 1539 1540 cleanup_removed_links(&state); 1541 (void) sleep(interval); 1542 } 1543 } 1544 1545 void 1546 print_all_stats(dladm_handle_t dh, datalink_id_t linkid, 1547 dladm_stat_chain_t *stat_chain) 1548 { 1549 dladm_stat_chain_t *curr; 1550 name_value_stat_entry_t *stat_entry; 1551 name_value_stat_t *curr_stat; 1552 boolean_t stat_printed = B_FALSE; 1553 char linkname[MAXLINKNAMELEN]; 1554 char prev_linkname[MAXLINKNAMELEN]; 1555 1556 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1557 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) 1558 return; 1559 1560 for (curr = stat_chain; curr != NULL; curr = curr->dc_next) { 1561 stat_entry = curr->dc_statentry; 1562 /* 1563 * Print header 1564 * If link name is already printed in previous iteration, 1565 * don't print again 1566 */ 1567 if (strcmp(prev_linkname, linkname) != 0) 1568 printf("%s \n", linkname); 1569 printf(" %s \n", stat_entry->nve_header); 1570 1571 /* Print stat fields */ 1572 for (curr_stat = stat_entry->nve_stats; curr_stat != NULL; 1573 curr_stat = curr_stat->nv_nextstat) { 1574 printf("\t%15s", curr_stat->nv_statname); 1575 printf("\t\t%15llu\n", curr_stat->nv_statval); 1576 } 1577 1578 strncpy(prev_linkname, linkname, MAXLINKNAMELEN); 1579 stat_printed = B_TRUE; 1580 } 1581 if (stat_printed) 1582 printf("---------------------------------------------------\n"); 1583 } 1584 1585 static int 1586 dump_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 1587 { 1588 boolean_t *stattype = arg; 1589 int i; 1590 dladm_stat_chain_t *stat_chain; 1591 1592 for (i = 0; i < DLADM_STAT_NUM_STATS; i++) { 1593 if (stattype[i]) { 1594 stat_chain = dladm_link_stat_query_all(dh, linkid, i); 1595 print_all_stats(dh, linkid, stat_chain); 1596 dladm_link_stat_query_all_free(stat_chain); 1597 } 1598 } 1599 done: 1600 return (DLADM_WALK_CONTINUE); 1601 } 1602 1603 void 1604 dump_all_link_stats(datalink_id_t linkid, boolean_t *stattype) 1605 { 1606 if (linkid == DATALINK_ALL_LINKID) { 1607 (void) dladm_walk_datalink_id(dump_queried_stats, 1608 handle, stattype, DATALINK_CLASS_ALL, 1609 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 1610 } else { 1611 (void) dump_queried_stats(handle, linkid, stattype); 1612 } 1613 } 1614 1615 static void 1616 do_show(int argc, char *argv[], const char *use) 1617 { 1618 int option; 1619 boolean_t r_arg = B_FALSE; 1620 boolean_t t_arg = B_FALSE; 1621 boolean_t i_arg = B_FALSE; 1622 boolean_t p_arg = B_FALSE; 1623 boolean_t o_arg = B_FALSE; 1624 boolean_t u_arg = B_FALSE; 1625 boolean_t a_arg = B_FALSE; 1626 boolean_t A_arg = B_FALSE; 1627 uint32_t flags = DLADM_OPT_ACTIVE; 1628 datalink_id_t linkid = DATALINK_ALL_LINKID; 1629 uint32_t interval = 0; 1630 char unit = '\0'; 1631 show_state_t state; 1632 dladm_status_t status; 1633 char *fields_str = NULL; 1634 char *o_fields_str = NULL; 1635 1636 char *total_stat_fields = 1637 "link,ipkts,rbytes,opkts,obytes"; 1638 char *rx_total_stat_fields = 1639 "link,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50"; 1640 char *tx_total_stat_fields = 1641 "link,opkts,obytes,blkcnt,ublkcnt"; 1642 1643 ofmt_handle_t ofmt; 1644 ofmt_status_t oferr; 1645 uint_t ofmtflags = OFMT_RIGHTJUST; 1646 ofmt_field_t *oftemplate; 1647 1648 bzero(&state, sizeof (state)); 1649 opterr = 0; 1650 while ((option = getopt_long(argc, argv, ":rtaApi:o:u:", 1651 NULL, NULL)) != -1) { 1652 switch (option) { 1653 case 'r': 1654 if (r_arg) 1655 die_optdup(option); 1656 1657 r_arg = B_TRUE; 1658 break; 1659 case 't': 1660 if (t_arg) 1661 die_optdup(option); 1662 1663 t_arg = B_TRUE; 1664 break; 1665 case 'a': 1666 if (a_arg) 1667 die_optdup(option); 1668 1669 a_arg = B_TRUE; 1670 break; 1671 case 'A': 1672 if (A_arg) 1673 die_optdup(option); 1674 1675 A_arg = B_TRUE; 1676 break; 1677 case 'i': 1678 if (i_arg) 1679 die_optdup(option); 1680 1681 i_arg = B_TRUE; 1682 if (!dladm_str2interval(optarg, &interval)) 1683 die("invalid interval value '%s'", optarg); 1684 break; 1685 case 'p': 1686 if (p_arg) 1687 die_optdup(option); 1688 1689 p_arg = B_TRUE; 1690 break; 1691 case 'o': 1692 o_arg = B_TRUE; 1693 o_fields_str = optarg; 1694 break; 1695 case 'u': 1696 if (u_arg) 1697 die_optdup(option); 1698 1699 u_arg = B_TRUE; 1700 if (!dlstat_unit(optarg, &unit)) 1701 die("invalid unit value '%s'," 1702 "unit must be R|K|M|G|T|P", optarg); 1703 break; 1704 default: 1705 die_opterr(optopt, option, use); 1706 break; 1707 } 1708 } 1709 1710 if (r_arg && t_arg) 1711 die("the options -t and -r are not compatible"); 1712 1713 if (u_arg && p_arg) 1714 die("the options -u and -p are not compatible"); 1715 1716 if (p_arg && !o_arg) 1717 die("-p requires -o"); 1718 1719 if (p_arg && strcasecmp(o_fields_str, "all") == 0) 1720 die("\"-o all\" is invalid with -p"); 1721 1722 if (a_arg && A_arg) 1723 die("the options -a and -A are not compatible"); 1724 1725 if (a_arg && 1726 (p_arg || o_arg || u_arg || i_arg)) { 1727 die("the option -a is not compatible with " 1728 "-p, -o, -u, -i"); 1729 } 1730 1731 if (A_arg && 1732 (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg)) { 1733 die("the option -A is not compatible with " 1734 "-r, -t, -p, -o, -u, -i"); 1735 } 1736 1737 /* get link name (optional last argument) */ 1738 if (optind == (argc-1)) { 1739 if (strlen(argv[optind]) >= MAXLINKNAMELEN) 1740 die("link name too long"); 1741 1742 if ((status = dladm_name2info(handle, argv[optind], &linkid, 1743 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 1744 die_dlerr(status, "link %s is not valid", argv[optind]); 1745 } 1746 } else if (optind != argc) { 1747 if (argc != 0) 1748 usage(); 1749 } 1750 1751 if (a_arg) { 1752 boolean_t stattype[DLADM_STAT_NUM_STATS]; 1753 1754 bzero(&stattype, sizeof (stattype)); 1755 if (r_arg) { 1756 stattype[DLADM_STAT_RX_LANE_TOTAL] = B_TRUE; 1757 } else if (t_arg) { 1758 stattype[DLADM_STAT_TX_LANE_TOTAL] = B_TRUE; 1759 } else { /* Display both Rx and Tx lanes */ 1760 stattype[DLADM_STAT_TOTAL] = B_TRUE; 1761 } 1762 1763 dump_all_link_stats(linkid, stattype); 1764 return; 1765 } 1766 1767 if (A_arg) { 1768 boolean_t stattype[DLADM_STAT_NUM_STATS]; 1769 int i; 1770 1771 for (i = 0; i < DLADM_STAT_NUM_STATS; i++) 1772 stattype[i] = B_TRUE; 1773 1774 dump_all_link_stats(linkid, stattype); 1775 return; 1776 } 1777 1778 state.ls_unit = unit; 1779 state.ls_parsable = p_arg; 1780 1781 if (state.ls_parsable) 1782 ofmtflags |= OFMT_PARSABLE; 1783 1784 if (r_arg) { 1785 fields_str = rx_total_stat_fields; 1786 oftemplate = rx_lane_s_fields; 1787 state.ls_stattype[DLADM_STAT_RX_LANE_TOTAL] = B_TRUE; 1788 state.ls_stats2str[DLADM_STAT_RX_LANE_TOTAL] = 1789 print_rx_lane_stats; 1790 } else if (t_arg) { 1791 fields_str = tx_total_stat_fields; 1792 oftemplate = tx_lane_s_fields; 1793 state.ls_stattype[DLADM_STAT_TX_LANE_TOTAL] = B_TRUE; 1794 state.ls_stats2str[DLADM_STAT_TX_LANE_TOTAL] = 1795 print_tx_lane_stats; 1796 } else { /* Display both Rx and Tx lanes total */ 1797 fields_str = total_stat_fields; 1798 oftemplate = total_s_fields; 1799 state.ls_stattype[DLADM_STAT_TOTAL] = B_TRUE; 1800 state.ls_stats2str[DLADM_STAT_TOTAL] = print_total_stats; 1801 } 1802 1803 if (o_arg) { 1804 fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 1805 fields_str : o_fields_str; 1806 } 1807 1808 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt); 1809 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 1810 state.ls_ofmt = ofmt; 1811 1812 show_link_stats(linkid, state, interval); 1813 1814 ofmt_close(ofmt); 1815 } 1816 1817 static void 1818 do_show_phys(int argc, char *argv[], const char *use) 1819 { 1820 int option; 1821 boolean_t r_arg = B_FALSE; 1822 boolean_t t_arg = B_FALSE; 1823 boolean_t i_arg = B_FALSE; 1824 boolean_t p_arg = B_FALSE; 1825 boolean_t o_arg = B_FALSE; 1826 boolean_t u_arg = B_FALSE; 1827 boolean_t a_arg = B_FALSE; 1828 uint32_t flags = DLADM_OPT_ACTIVE; 1829 datalink_id_t linkid = DATALINK_ALL_LINKID; 1830 char linkname[MAXLINKNAMELEN]; 1831 uint32_t interval = 0; 1832 char unit = '\0'; 1833 show_state_t state; 1834 dladm_status_t status; 1835 char *fields_str = NULL; 1836 char *o_fields_str = NULL; 1837 char *ring_stat_fields = 1838 "link,type,index,pkts,bytes"; 1839 char *rx_ring_stat_fields = 1840 "link,type,index,ipkts,rbytes"; 1841 char *tx_ring_stat_fields = 1842 "link,type,index,opkts,obytes"; 1843 1844 ofmt_handle_t ofmt; 1845 ofmt_status_t oferr; 1846 uint_t ofmtflags = OFMT_RIGHTJUST; 1847 ofmt_field_t *oftemplate; 1848 1849 bzero(&state, sizeof (state)); 1850 opterr = 0; 1851 while ((option = getopt_long(argc, argv, ":rtapi:o:u:", 1852 NULL, NULL)) != -1) { 1853 switch (option) { 1854 case 'r': 1855 if (r_arg) 1856 die_optdup(option); 1857 1858 r_arg = B_TRUE; 1859 break; 1860 case 't': 1861 if (t_arg) 1862 die_optdup(option); 1863 1864 t_arg = B_TRUE; 1865 break; 1866 case 'a': 1867 if (a_arg) 1868 die_optdup(option); 1869 1870 a_arg = B_TRUE; 1871 break; 1872 case 'i': 1873 if (i_arg) 1874 die_optdup(option); 1875 1876 i_arg = B_TRUE; 1877 if (!dladm_str2interval(optarg, &interval)) 1878 die("invalid interval value '%s'", optarg); 1879 break; 1880 case 'p': 1881 if (p_arg) 1882 die_optdup(option); 1883 1884 p_arg = B_TRUE; 1885 break; 1886 case 'o': 1887 o_arg = B_TRUE; 1888 o_fields_str = optarg; 1889 break; 1890 case 'u': 1891 if (u_arg) 1892 die_optdup(option); 1893 1894 u_arg = B_TRUE; 1895 if (!dlstat_unit(optarg, &unit)) 1896 die("invalid unit value '%s'," 1897 "unit must be R|K|M|G|T|P", optarg); 1898 break; 1899 default: 1900 die_opterr(optopt, option, use); 1901 break; 1902 } 1903 } 1904 1905 if (r_arg && t_arg) 1906 die("the options -t and -r are not compatible"); 1907 1908 if (u_arg && p_arg) 1909 die("the options -u and -p are not compatible"); 1910 1911 if (p_arg && !o_arg) 1912 die("-p requires -o"); 1913 1914 if (p_arg && strcasecmp(o_fields_str, "all") == 0) 1915 die("\"-o all\" is invalid with -p"); 1916 1917 if (a_arg && 1918 (p_arg || o_arg || u_arg || i_arg)) { 1919 die("the option -a is not compatible with " 1920 "-p, -o, -u, -i"); 1921 } 1922 1923 1924 /* get link name (optional last argument) */ 1925 if (optind == (argc-1)) { 1926 if (strlen(argv[optind]) >= MAXLINKNAMELEN) 1927 die("link name too long"); 1928 1929 if ((status = dladm_name2info(handle, argv[optind], &linkid, 1930 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 1931 die_dlerr(status, "link %s is not valid", argv[optind]); 1932 } 1933 } else if (optind != argc) { 1934 usage(); 1935 } 1936 1937 if (a_arg) { 1938 boolean_t stattype[DLADM_STAT_NUM_STATS]; 1939 1940 bzero(&stattype, sizeof (stattype)); 1941 1942 if (r_arg) { 1943 stattype[DLADM_STAT_RX_RING] = B_TRUE; 1944 } else if (t_arg) { 1945 stattype[DLADM_STAT_TX_RING] = B_TRUE; 1946 } else { /* Display both Rx and Tx lanes */ 1947 stattype[DLADM_STAT_RX_RING] = B_TRUE; 1948 stattype[DLADM_STAT_TX_RING] = B_TRUE; 1949 } 1950 1951 dump_all_link_stats(linkid, stattype); 1952 return; 1953 } 1954 1955 state.ls_unit = unit; 1956 state.ls_parsable = p_arg; 1957 1958 if (state.ls_parsable) 1959 ofmtflags |= OFMT_PARSABLE; 1960 1961 if (r_arg) { 1962 fields_str = rx_ring_stat_fields; 1963 oftemplate = rx_ring_s_fields; 1964 state.ls_stattype[DLADM_STAT_RX_RING] = B_TRUE; 1965 state.ls_stats2str[DLADM_STAT_RX_RING] = print_rx_ring_stats; 1966 } else if (t_arg) { 1967 fields_str = tx_ring_stat_fields; 1968 oftemplate = tx_ring_s_fields; 1969 state.ls_stattype[DLADM_STAT_TX_RING] = B_TRUE; 1970 state.ls_stats2str[DLADM_STAT_TX_RING] = print_tx_ring_stats; 1971 } else { /* Display both Rx and Tx lanes */ 1972 fields_str = ring_stat_fields; 1973 oftemplate = ring_s_fields; 1974 state.ls_stattype[DLADM_STAT_RX_RING] = B_TRUE; 1975 state.ls_stattype[DLADM_STAT_TX_RING] = B_TRUE; 1976 state.ls_stats2str[DLADM_STAT_RX_RING] = 1977 print_rx_generic_ring_stats; 1978 state.ls_stats2str[DLADM_STAT_TX_RING] = 1979 print_tx_generic_ring_stats; 1980 } 1981 1982 if (o_arg) { 1983 fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 1984 fields_str : o_fields_str; 1985 } 1986 1987 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt); 1988 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 1989 state.ls_ofmt = ofmt; 1990 1991 show_link_stats(linkid, state, interval); 1992 1993 ofmt_close(ofmt); 1994 } 1995 1996 static void 1997 do_show_link(int argc, char *argv[], const char *use) 1998 { 1999 int option; 2000 boolean_t r_arg = B_FALSE; 2001 boolean_t F_arg = B_FALSE; 2002 boolean_t t_arg = B_FALSE; 2003 boolean_t i_arg = B_FALSE; 2004 boolean_t p_arg = B_FALSE; 2005 boolean_t o_arg = B_FALSE; 2006 boolean_t u_arg = B_FALSE; 2007 boolean_t a_arg = B_FALSE; 2008 uint32_t flags = DLADM_OPT_ACTIVE; 2009 datalink_id_t linkid = DATALINK_ALL_LINKID; 2010 uint32_t interval = 0; 2011 char unit = '\0'; 2012 show_state_t state; 2013 dladm_status_t status; 2014 char *fields_str = NULL; 2015 char *o_fields_str = NULL; 2016 2017 char *lane_stat_fields = 2018 "link,type,id,index,pkts,bytes"; 2019 char *rx_lane_stat_fields = 2020 "link,type,id,index,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50"; 2021 char *tx_lane_stat_fields = 2022 "link,type,id,index,opkts,obytes,blkcnt,ublkcnt"; 2023 char *rx_fanout_stat_fields = 2024 "link,id,index,fout,ipkts,rbytes"; 2025 2026 ofmt_handle_t ofmt; 2027 ofmt_status_t oferr; 2028 uint_t ofmtflags = OFMT_RIGHTJUST; 2029 ofmt_field_t *oftemplate; 2030 2031 bzero(&state, sizeof (state)); 2032 opterr = 0; 2033 while ((option = getopt_long(argc, argv, ":hrtFapi:o:u:", 2034 NULL, NULL)) != -1) { 2035 switch (option) { 2036 case 'h': 2037 if (r_arg || F_arg || t_arg || i_arg || p_arg || 2038 o_arg || u_arg || a_arg) { 2039 die("the option -h is not compatible with " 2040 "-r, -F, -t, -i, -p, -o, -u, -a"); 2041 } 2042 do_show_history(argc, &argv[0], use); 2043 return; 2044 case 'r': 2045 if (r_arg) 2046 die_optdup(option); 2047 2048 r_arg = B_TRUE; 2049 break; 2050 case 'F': 2051 if (F_arg) 2052 die_optdup(option); 2053 2054 F_arg = B_TRUE; 2055 break; 2056 case 't': 2057 if (t_arg) 2058 die_optdup(option); 2059 2060 t_arg = B_TRUE; 2061 break; 2062 case 'a': 2063 if (a_arg) 2064 die_optdup(option); 2065 2066 a_arg = B_TRUE; 2067 break; 2068 case 'i': 2069 if (i_arg) 2070 die_optdup(option); 2071 2072 i_arg = B_TRUE; 2073 if (!dladm_str2interval(optarg, &interval)) 2074 die("invalid interval value '%s'", optarg); 2075 break; 2076 case 'p': 2077 if (p_arg) 2078 die_optdup(option); 2079 2080 p_arg = B_TRUE; 2081 break; 2082 case 'o': 2083 o_arg = B_TRUE; 2084 o_fields_str = optarg; 2085 break; 2086 case 'u': 2087 if (u_arg) 2088 die_optdup(option); 2089 2090 u_arg = B_TRUE; 2091 if (!dlstat_unit(optarg, &unit)) 2092 die("invalid unit value '%s'," 2093 "unit must be R|K|M|G|T|P", optarg); 2094 break; 2095 default: 2096 die_opterr(optopt, option, use); 2097 break; 2098 } 2099 } 2100 2101 if (r_arg && t_arg) 2102 die("the options -t and -r are not compatible"); 2103 2104 if (u_arg && p_arg) 2105 die("the options -u and -p are not compatible"); 2106 2107 if (F_arg && !r_arg) 2108 die("-F must be used with -r"); 2109 2110 if (p_arg && !o_arg) 2111 die("-p requires -o"); 2112 2113 if (p_arg && strcasecmp(o_fields_str, "all") == 0) 2114 die("\"-o all\" is invalid with -p"); 2115 2116 if (a_arg && 2117 (p_arg || o_arg || u_arg || i_arg)) { 2118 die("the option -a is not compatible with " 2119 "-p, -o, -u, -i"); 2120 } 2121 2122 /* get link name (optional last argument) */ 2123 if (optind == (argc-1)) { 2124 if (strlen(argv[optind]) >= MAXLINKNAMELEN) 2125 die("link name too long"); 2126 2127 if ((status = dladm_name2info(handle, argv[optind], &linkid, 2128 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 2129 die_dlerr(status, "link %s is not valid", argv[optind]); 2130 } 2131 } else if (optind != argc) { 2132 usage(); 2133 } 2134 2135 if (a_arg) { 2136 boolean_t stattype[DLADM_STAT_NUM_STATS]; 2137 2138 bzero(&stattype, sizeof (stattype)); 2139 2140 if (r_arg) { 2141 if (F_arg) { 2142 stattype[DLADM_STAT_RX_LANE_FOUT] = B_TRUE; 2143 } else { 2144 stattype[DLADM_STAT_RX_LANE] = B_TRUE; 2145 } 2146 } else if (t_arg) { 2147 stattype[DLADM_STAT_TX_LANE] = B_TRUE; 2148 } else { /* Display both Rx and Tx lanes */ 2149 stattype[DLADM_STAT_RX_LANE] = B_TRUE; 2150 stattype[DLADM_STAT_TX_LANE] = B_TRUE; 2151 } 2152 2153 dump_all_link_stats(linkid, stattype); 2154 return; 2155 } 2156 2157 state.ls_unit = unit; 2158 state.ls_parsable = p_arg; 2159 2160 if (state.ls_parsable) 2161 ofmtflags |= OFMT_PARSABLE; 2162 2163 if (r_arg) { 2164 if (F_arg) { 2165 fields_str = rx_fanout_stat_fields; 2166 oftemplate = rx_fanout_lane_s_fields; 2167 state.ls_stattype[DLADM_STAT_RX_LANE_FOUT] = B_TRUE; 2168 state.ls_stats2str[DLADM_STAT_RX_LANE_FOUT] = 2169 print_fanout_stats; 2170 } else { 2171 fields_str = rx_lane_stat_fields; 2172 oftemplate = rx_lane_s_fields; 2173 state.ls_stattype[DLADM_STAT_RX_LANE] = B_TRUE; 2174 state.ls_stats2str[DLADM_STAT_RX_LANE] = 2175 print_rx_lane_stats; 2176 } 2177 } else if (t_arg) { 2178 fields_str = tx_lane_stat_fields; 2179 oftemplate = tx_lane_s_fields; 2180 state.ls_stattype[DLADM_STAT_TX_LANE] = B_TRUE; 2181 state.ls_stats2str[DLADM_STAT_TX_LANE] = print_tx_lane_stats; 2182 } else { /* Display both Rx and Tx lanes */ 2183 fields_str = lane_stat_fields; 2184 oftemplate = lane_s_fields; 2185 state.ls_stattype[DLADM_STAT_RX_LANE] = B_TRUE; 2186 state.ls_stattype[DLADM_STAT_TX_LANE] = B_TRUE; 2187 state.ls_stats2str[DLADM_STAT_RX_LANE] = 2188 print_rx_generic_lane_stats; 2189 state.ls_stats2str[DLADM_STAT_TX_LANE] = 2190 print_tx_generic_lane_stats; 2191 } 2192 if (o_arg) { 2193 fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 2194 fields_str : o_fields_str; 2195 } 2196 2197 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt); 2198 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 2199 2200 state.ls_ofmt = ofmt; 2201 2202 show_link_stats(linkid, state, interval); 2203 2204 ofmt_close(ofmt); 2205 } 2206 2207 static void 2208 do_show_aggr(int argc, char *argv[], const char *use) 2209 { 2210 int option; 2211 boolean_t r_arg = B_FALSE; 2212 boolean_t t_arg = B_FALSE; 2213 boolean_t i_arg = B_FALSE; 2214 boolean_t p_arg = B_FALSE; 2215 boolean_t o_arg = B_FALSE; 2216 boolean_t u_arg = B_FALSE; 2217 uint32_t flags = DLADM_OPT_ACTIVE; 2218 datalink_id_t linkid = DATALINK_ALL_LINKID; 2219 uint32_t interval = 0; 2220 char unit = '\0'; 2221 show_state_t state; 2222 dladm_status_t status; 2223 char *fields_str = NULL; 2224 char *o_fields_str = NULL; 2225 2226 char *aggr_stat_fields = 2227 "link,port,ipkts,rbytes,opkts,obytes"; 2228 char *rx_aggr_stat_fields = "link,port,ipkts,rbytes"; 2229 char *tx_aggr_stat_fields = "link,port,opkts,obytes"; 2230 2231 ofmt_handle_t ofmt; 2232 ofmt_status_t oferr; 2233 uint_t ofmtflags = OFMT_RIGHTJUST; 2234 ofmt_field_t *oftemplate; 2235 2236 bzero(&state, sizeof (state)); 2237 opterr = 0; 2238 while ((option = getopt_long(argc, argv, ":rtpi:o:u:", 2239 NULL, NULL)) != -1) { 2240 switch (option) { 2241 case 'r': 2242 if (r_arg) 2243 die_optdup(option); 2244 2245 r_arg = B_TRUE; 2246 break; 2247 case 't': 2248 if (t_arg) 2249 die_optdup(option); 2250 2251 t_arg = B_TRUE; 2252 break; 2253 case 'i': 2254 if (i_arg) 2255 die_optdup(option); 2256 2257 i_arg = B_TRUE; 2258 if (!dladm_str2interval(optarg, &interval)) 2259 die("invalid interval value '%s'", optarg); 2260 break; 2261 case 'p': 2262 if (p_arg) 2263 die_optdup(option); 2264 2265 p_arg = B_TRUE; 2266 break; 2267 case 'o': 2268 o_arg = B_TRUE; 2269 o_fields_str = optarg; 2270 break; 2271 case 'u': 2272 if (u_arg) 2273 die_optdup(option); 2274 2275 u_arg = B_TRUE; 2276 if (!dlstat_unit(optarg, &unit)) 2277 die("invalid unit value '%s'," 2278 "unit must be R|K|M|G|T|P", optarg); 2279 break; 2280 default: 2281 die_opterr(optopt, option, use); 2282 break; 2283 } 2284 } 2285 2286 if (r_arg && t_arg) 2287 die("the options -t and -r are not compatible"); 2288 2289 if (u_arg && p_arg) 2290 die("the options -u and -p are not compatible"); 2291 2292 if (p_arg && !o_arg) 2293 die("-p requires -o"); 2294 2295 if (p_arg && strcasecmp(o_fields_str, "all") == 0) 2296 die("\"-o all\" is invalid with -p"); 2297 2298 2299 /* get link name (optional last argument) */ 2300 if (optind == (argc-1)) { 2301 if (strlen(argv[optind]) >= MAXLINKNAMELEN) 2302 die("link name too long"); 2303 2304 if ((status = dladm_name2info(handle, argv[optind], &linkid, 2305 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 2306 die_dlerr(status, "link %s is not valid", argv[optind]); 2307 } 2308 } else if (optind != argc) { 2309 usage(); 2310 } 2311 2312 state.ls_unit = unit; 2313 state.ls_parsable = p_arg; 2314 2315 if (state.ls_parsable) 2316 ofmtflags |= OFMT_PARSABLE; 2317 2318 oftemplate = aggr_port_s_fields; 2319 state.ls_stattype[DLADM_STAT_AGGR_PORT] = B_TRUE; 2320 state.ls_stats2str[DLADM_STAT_AGGR_PORT] = print_aggr_port_stats; 2321 2322 if (r_arg) 2323 fields_str = rx_aggr_stat_fields; 2324 else if (t_arg) 2325 fields_str = tx_aggr_stat_fields; 2326 else 2327 fields_str = aggr_stat_fields; 2328 2329 if (o_arg) { 2330 fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 2331 fields_str : o_fields_str; 2332 } 2333 2334 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt); 2335 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 2336 state.ls_ofmt = ofmt; 2337 2338 show_link_stats(linkid, state, interval); 2339 2340 ofmt_close(ofmt); 2341 } 2342 2343 /* PRINTFLIKE1 */ 2344 static void 2345 warn(const char *format, ...) 2346 { 2347 va_list alist; 2348 2349 format = gettext(format); 2350 (void) fprintf(stderr, "%s: warning: ", progname); 2351 2352 va_start(alist, format); 2353 (void) vfprintf(stderr, format, alist); 2354 va_end(alist); 2355 2356 (void) putc('\n', stderr); 2357 } 2358 2359 /* 2360 * Also closes the dladm handle if it is not NULL. 2361 */ 2362 /* PRINTFLIKE2 */ 2363 static void 2364 die_dlerr(dladm_status_t err, const char *format, ...) 2365 { 2366 va_list alist; 2367 char errmsg[DLADM_STRSIZE]; 2368 2369 format = gettext(format); 2370 (void) fprintf(stderr, "%s: ", progname); 2371 2372 va_start(alist, format); 2373 (void) vfprintf(stderr, format, alist); 2374 va_end(alist); 2375 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 2376 2377 /* close dladm handle if it was opened */ 2378 if (handle != NULL) 2379 dladm_close(handle); 2380 2381 exit(EXIT_FAILURE); 2382 } 2383 2384 /* PRINTFLIKE1 */ 2385 static void 2386 die(const char *format, ...) 2387 { 2388 va_list alist; 2389 2390 format = gettext(format); 2391 (void) fprintf(stderr, "%s: ", progname); 2392 2393 va_start(alist, format); 2394 (void) vfprintf(stderr, format, alist); 2395 va_end(alist); 2396 2397 (void) putc('\n', stderr); 2398 2399 /* close dladm handle if it was opened */ 2400 if (handle != NULL) 2401 dladm_close(handle); 2402 2403 exit(EXIT_FAILURE); 2404 } 2405 2406 static void 2407 die_optdup(int opt) 2408 { 2409 die("the option -%c cannot be specified more than once", opt); 2410 } 2411 2412 static void 2413 die_opterr(int opt, int opterr, const char *usage) 2414 { 2415 switch (opterr) { 2416 case ':': 2417 die("option '-%c' requires a value\nusage: %s", opt, 2418 gettext(usage)); 2419 break; 2420 case '?': 2421 default: 2422 die("unrecognized option '-%c'\nusage: %s", opt, 2423 gettext(usage)); 2424 break; 2425 } 2426 } 2427 2428 /* 2429 * default output callback function that, when invoked, 2430 * prints string which is offset by ofmt_arg->ofmt_id within buf. 2431 */ 2432 static boolean_t 2433 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2434 { 2435 char *value; 2436 2437 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; 2438 (void) strlcpy(buf, value, bufsize); 2439 return (B_TRUE); 2440 } 2441