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 cleanup_removed_links(&state); 1538 1539 if (interval == 0) 1540 break; 1541 1542 (void) sleep(interval); 1543 } 1544 } 1545 1546 void 1547 print_all_stats(dladm_handle_t dh, datalink_id_t linkid, 1548 dladm_stat_chain_t *stat_chain) 1549 { 1550 dladm_stat_chain_t *curr; 1551 name_value_stat_entry_t *stat_entry; 1552 name_value_stat_t *curr_stat; 1553 boolean_t stat_printed = B_FALSE; 1554 char linkname[MAXLINKNAMELEN]; 1555 char prev_linkname[MAXLINKNAMELEN]; 1556 1557 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1558 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) 1559 return; 1560 1561 for (curr = stat_chain; curr != NULL; curr = curr->dc_next) { 1562 stat_entry = curr->dc_statentry; 1563 /* 1564 * Print header 1565 * If link name is already printed in previous iteration, 1566 * don't print again 1567 */ 1568 if (strcmp(prev_linkname, linkname) != 0) 1569 printf("%s \n", linkname); 1570 printf(" %s \n", stat_entry->nve_header); 1571 1572 /* Print stat fields */ 1573 for (curr_stat = stat_entry->nve_stats; curr_stat != NULL; 1574 curr_stat = curr_stat->nv_nextstat) { 1575 printf("\t%15s", curr_stat->nv_statname); 1576 printf("\t\t%15llu\n", curr_stat->nv_statval); 1577 } 1578 1579 strncpy(prev_linkname, linkname, MAXLINKNAMELEN); 1580 stat_printed = B_TRUE; 1581 } 1582 if (stat_printed) 1583 printf("---------------------------------------------------\n"); 1584 } 1585 1586 static int 1587 dump_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 1588 { 1589 boolean_t *stattype = arg; 1590 int i; 1591 dladm_stat_chain_t *stat_chain; 1592 1593 for (i = 0; i < DLADM_STAT_NUM_STATS; i++) { 1594 if (stattype[i]) { 1595 stat_chain = dladm_link_stat_query_all(dh, linkid, i); 1596 print_all_stats(dh, linkid, stat_chain); 1597 dladm_link_stat_query_all_free(stat_chain); 1598 } 1599 } 1600 done: 1601 return (DLADM_WALK_CONTINUE); 1602 } 1603 1604 void 1605 dump_all_link_stats(datalink_id_t linkid, boolean_t *stattype) 1606 { 1607 if (linkid == DATALINK_ALL_LINKID) { 1608 (void) dladm_walk_datalink_id(dump_queried_stats, 1609 handle, stattype, DATALINK_CLASS_ALL, 1610 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 1611 } else { 1612 (void) dump_queried_stats(handle, linkid, stattype); 1613 } 1614 } 1615 1616 static void 1617 do_show(int argc, char *argv[], const char *use) 1618 { 1619 int option; 1620 boolean_t r_arg = B_FALSE; 1621 boolean_t t_arg = B_FALSE; 1622 boolean_t i_arg = B_FALSE; 1623 boolean_t p_arg = B_FALSE; 1624 boolean_t o_arg = B_FALSE; 1625 boolean_t u_arg = B_FALSE; 1626 boolean_t a_arg = B_FALSE; 1627 boolean_t A_arg = B_FALSE; 1628 uint32_t flags = DLADM_OPT_ACTIVE; 1629 datalink_id_t linkid = DATALINK_ALL_LINKID; 1630 uint32_t interval = 0; 1631 char unit = '\0'; 1632 show_state_t state; 1633 dladm_status_t status; 1634 char *fields_str = NULL; 1635 char *o_fields_str = NULL; 1636 1637 char *total_stat_fields = 1638 "link,ipkts,rbytes,opkts,obytes"; 1639 char *rx_total_stat_fields = 1640 "link,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50"; 1641 char *tx_total_stat_fields = 1642 "link,opkts,obytes,blkcnt,ublkcnt"; 1643 1644 ofmt_handle_t ofmt; 1645 ofmt_status_t oferr; 1646 uint_t ofmtflags = OFMT_RIGHTJUST; 1647 ofmt_field_t *oftemplate; 1648 1649 bzero(&state, sizeof (state)); 1650 opterr = 0; 1651 while ((option = getopt_long(argc, argv, ":rtaApi:o:u:", 1652 NULL, NULL)) != -1) { 1653 switch (option) { 1654 case 'r': 1655 if (r_arg) 1656 die_optdup(option); 1657 1658 r_arg = B_TRUE; 1659 break; 1660 case 't': 1661 if (t_arg) 1662 die_optdup(option); 1663 1664 t_arg = B_TRUE; 1665 break; 1666 case 'a': 1667 if (a_arg) 1668 die_optdup(option); 1669 1670 a_arg = B_TRUE; 1671 break; 1672 case 'A': 1673 if (A_arg) 1674 die_optdup(option); 1675 1676 A_arg = B_TRUE; 1677 break; 1678 case 'i': 1679 if (i_arg) 1680 die_optdup(option); 1681 1682 i_arg = B_TRUE; 1683 if (!dladm_str2interval(optarg, &interval)) 1684 die("invalid interval value '%s'", optarg); 1685 break; 1686 case 'p': 1687 if (p_arg) 1688 die_optdup(option); 1689 1690 p_arg = B_TRUE; 1691 break; 1692 case 'o': 1693 o_arg = B_TRUE; 1694 o_fields_str = optarg; 1695 break; 1696 case 'u': 1697 if (u_arg) 1698 die_optdup(option); 1699 1700 u_arg = B_TRUE; 1701 if (!dlstat_unit(optarg, &unit)) 1702 die("invalid unit value '%s'," 1703 "unit must be R|K|M|G|T|P", optarg); 1704 break; 1705 default: 1706 die_opterr(optopt, option, use); 1707 break; 1708 } 1709 } 1710 1711 if (r_arg && t_arg) 1712 die("the options -t and -r are not compatible"); 1713 1714 if (u_arg && p_arg) 1715 die("the options -u and -p are not compatible"); 1716 1717 if (p_arg && !o_arg) 1718 die("-p requires -o"); 1719 1720 if (p_arg && strcasecmp(o_fields_str, "all") == 0) 1721 die("\"-o all\" is invalid with -p"); 1722 1723 if (a_arg && A_arg) 1724 die("the options -a and -A are not compatible"); 1725 1726 if (a_arg && 1727 (p_arg || o_arg || u_arg || i_arg)) { 1728 die("the option -a is not compatible with " 1729 "-p, -o, -u, -i"); 1730 } 1731 1732 if (A_arg && 1733 (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg)) { 1734 die("the option -A is not compatible with " 1735 "-r, -t, -p, -o, -u, -i"); 1736 } 1737 1738 /* get link name (optional last argument) */ 1739 if (optind == (argc-1)) { 1740 if (strlen(argv[optind]) >= MAXLINKNAMELEN) 1741 die("link name too long"); 1742 1743 if ((status = dladm_name2info(handle, argv[optind], &linkid, 1744 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 1745 die_dlerr(status, "link %s is not valid", argv[optind]); 1746 } 1747 } else if (optind != argc) { 1748 if (argc != 0) 1749 usage(); 1750 } 1751 1752 if (a_arg) { 1753 boolean_t stattype[DLADM_STAT_NUM_STATS]; 1754 1755 bzero(&stattype, sizeof (stattype)); 1756 if (r_arg) { 1757 stattype[DLADM_STAT_RX_LANE_TOTAL] = B_TRUE; 1758 } else if (t_arg) { 1759 stattype[DLADM_STAT_TX_LANE_TOTAL] = B_TRUE; 1760 } else { /* Display both Rx and Tx lanes */ 1761 stattype[DLADM_STAT_TOTAL] = B_TRUE; 1762 } 1763 1764 dump_all_link_stats(linkid, stattype); 1765 return; 1766 } 1767 1768 if (A_arg) { 1769 boolean_t stattype[DLADM_STAT_NUM_STATS]; 1770 int i; 1771 1772 for (i = 0; i < DLADM_STAT_NUM_STATS; i++) 1773 stattype[i] = B_TRUE; 1774 1775 dump_all_link_stats(linkid, stattype); 1776 return; 1777 } 1778 1779 state.ls_unit = unit; 1780 state.ls_parsable = p_arg; 1781 1782 if (state.ls_parsable) 1783 ofmtflags |= OFMT_PARSABLE; 1784 1785 if (r_arg) { 1786 fields_str = rx_total_stat_fields; 1787 oftemplate = rx_lane_s_fields; 1788 state.ls_stattype[DLADM_STAT_RX_LANE_TOTAL] = B_TRUE; 1789 state.ls_stats2str[DLADM_STAT_RX_LANE_TOTAL] = 1790 print_rx_lane_stats; 1791 } else if (t_arg) { 1792 fields_str = tx_total_stat_fields; 1793 oftemplate = tx_lane_s_fields; 1794 state.ls_stattype[DLADM_STAT_TX_LANE_TOTAL] = B_TRUE; 1795 state.ls_stats2str[DLADM_STAT_TX_LANE_TOTAL] = 1796 print_tx_lane_stats; 1797 } else { /* Display both Rx and Tx lanes total */ 1798 fields_str = total_stat_fields; 1799 oftemplate = total_s_fields; 1800 state.ls_stattype[DLADM_STAT_TOTAL] = B_TRUE; 1801 state.ls_stats2str[DLADM_STAT_TOTAL] = print_total_stats; 1802 } 1803 1804 if (o_arg) { 1805 fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 1806 fields_str : o_fields_str; 1807 } 1808 1809 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt); 1810 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 1811 state.ls_ofmt = ofmt; 1812 1813 show_link_stats(linkid, state, interval); 1814 1815 ofmt_close(ofmt); 1816 } 1817 1818 static void 1819 do_show_phys(int argc, char *argv[], const char *use) 1820 { 1821 int option; 1822 boolean_t r_arg = B_FALSE; 1823 boolean_t t_arg = B_FALSE; 1824 boolean_t i_arg = B_FALSE; 1825 boolean_t p_arg = B_FALSE; 1826 boolean_t o_arg = B_FALSE; 1827 boolean_t u_arg = B_FALSE; 1828 boolean_t a_arg = B_FALSE; 1829 uint32_t flags = DLADM_OPT_ACTIVE; 1830 datalink_id_t linkid = DATALINK_ALL_LINKID; 1831 char linkname[MAXLINKNAMELEN]; 1832 uint32_t interval = 0; 1833 char unit = '\0'; 1834 show_state_t state; 1835 dladm_status_t status; 1836 char *fields_str = NULL; 1837 char *o_fields_str = NULL; 1838 char *ring_stat_fields = 1839 "link,type,index,pkts,bytes"; 1840 char *rx_ring_stat_fields = 1841 "link,type,index,ipkts,rbytes"; 1842 char *tx_ring_stat_fields = 1843 "link,type,index,opkts,obytes"; 1844 1845 ofmt_handle_t ofmt; 1846 ofmt_status_t oferr; 1847 uint_t ofmtflags = OFMT_RIGHTJUST; 1848 ofmt_field_t *oftemplate; 1849 1850 bzero(&state, sizeof (state)); 1851 opterr = 0; 1852 while ((option = getopt_long(argc, argv, ":rtapi:o:u:", 1853 NULL, NULL)) != -1) { 1854 switch (option) { 1855 case 'r': 1856 if (r_arg) 1857 die_optdup(option); 1858 1859 r_arg = B_TRUE; 1860 break; 1861 case 't': 1862 if (t_arg) 1863 die_optdup(option); 1864 1865 t_arg = B_TRUE; 1866 break; 1867 case 'a': 1868 if (a_arg) 1869 die_optdup(option); 1870 1871 a_arg = B_TRUE; 1872 break; 1873 case 'i': 1874 if (i_arg) 1875 die_optdup(option); 1876 1877 i_arg = B_TRUE; 1878 if (!dladm_str2interval(optarg, &interval)) 1879 die("invalid interval value '%s'", optarg); 1880 break; 1881 case 'p': 1882 if (p_arg) 1883 die_optdup(option); 1884 1885 p_arg = B_TRUE; 1886 break; 1887 case 'o': 1888 o_arg = B_TRUE; 1889 o_fields_str = optarg; 1890 break; 1891 case 'u': 1892 if (u_arg) 1893 die_optdup(option); 1894 1895 u_arg = B_TRUE; 1896 if (!dlstat_unit(optarg, &unit)) 1897 die("invalid unit value '%s'," 1898 "unit must be R|K|M|G|T|P", optarg); 1899 break; 1900 default: 1901 die_opterr(optopt, option, use); 1902 break; 1903 } 1904 } 1905 1906 if (r_arg && t_arg) 1907 die("the options -t and -r are not compatible"); 1908 1909 if (u_arg && p_arg) 1910 die("the options -u and -p are not compatible"); 1911 1912 if (p_arg && !o_arg) 1913 die("-p requires -o"); 1914 1915 if (p_arg && strcasecmp(o_fields_str, "all") == 0) 1916 die("\"-o all\" is invalid with -p"); 1917 1918 if (a_arg && 1919 (p_arg || o_arg || u_arg || i_arg)) { 1920 die("the option -a is not compatible with " 1921 "-p, -o, -u, -i"); 1922 } 1923 1924 1925 /* get link name (optional last argument) */ 1926 if (optind == (argc-1)) { 1927 if (strlen(argv[optind]) >= MAXLINKNAMELEN) 1928 die("link name too long"); 1929 1930 if ((status = dladm_name2info(handle, argv[optind], &linkid, 1931 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 1932 die_dlerr(status, "link %s is not valid", argv[optind]); 1933 } 1934 } else if (optind != argc) { 1935 usage(); 1936 } 1937 1938 if (a_arg) { 1939 boolean_t stattype[DLADM_STAT_NUM_STATS]; 1940 1941 bzero(&stattype, sizeof (stattype)); 1942 1943 if (r_arg) { 1944 stattype[DLADM_STAT_RX_RING] = B_TRUE; 1945 } else if (t_arg) { 1946 stattype[DLADM_STAT_TX_RING] = B_TRUE; 1947 } else { /* Display both Rx and Tx lanes */ 1948 stattype[DLADM_STAT_RX_RING] = B_TRUE; 1949 stattype[DLADM_STAT_TX_RING] = B_TRUE; 1950 } 1951 1952 dump_all_link_stats(linkid, stattype); 1953 return; 1954 } 1955 1956 state.ls_unit = unit; 1957 state.ls_parsable = p_arg; 1958 1959 if (state.ls_parsable) 1960 ofmtflags |= OFMT_PARSABLE; 1961 1962 if (r_arg) { 1963 fields_str = rx_ring_stat_fields; 1964 oftemplate = rx_ring_s_fields; 1965 state.ls_stattype[DLADM_STAT_RX_RING] = B_TRUE; 1966 state.ls_stats2str[DLADM_STAT_RX_RING] = print_rx_ring_stats; 1967 } else if (t_arg) { 1968 fields_str = tx_ring_stat_fields; 1969 oftemplate = tx_ring_s_fields; 1970 state.ls_stattype[DLADM_STAT_TX_RING] = B_TRUE; 1971 state.ls_stats2str[DLADM_STAT_TX_RING] = print_tx_ring_stats; 1972 } else { /* Display both Rx and Tx lanes */ 1973 fields_str = ring_stat_fields; 1974 oftemplate = ring_s_fields; 1975 state.ls_stattype[DLADM_STAT_RX_RING] = B_TRUE; 1976 state.ls_stattype[DLADM_STAT_TX_RING] = B_TRUE; 1977 state.ls_stats2str[DLADM_STAT_RX_RING] = 1978 print_rx_generic_ring_stats; 1979 state.ls_stats2str[DLADM_STAT_TX_RING] = 1980 print_tx_generic_ring_stats; 1981 } 1982 1983 if (o_arg) { 1984 fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 1985 fields_str : o_fields_str; 1986 } 1987 1988 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt); 1989 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 1990 state.ls_ofmt = ofmt; 1991 1992 show_link_stats(linkid, state, interval); 1993 1994 ofmt_close(ofmt); 1995 } 1996 1997 static void 1998 do_show_link(int argc, char *argv[], const char *use) 1999 { 2000 int option; 2001 boolean_t r_arg = B_FALSE; 2002 boolean_t F_arg = B_FALSE; 2003 boolean_t t_arg = B_FALSE; 2004 boolean_t i_arg = B_FALSE; 2005 boolean_t p_arg = B_FALSE; 2006 boolean_t o_arg = B_FALSE; 2007 boolean_t u_arg = B_FALSE; 2008 boolean_t a_arg = B_FALSE; 2009 uint32_t flags = DLADM_OPT_ACTIVE; 2010 datalink_id_t linkid = DATALINK_ALL_LINKID; 2011 uint32_t interval = 0; 2012 char unit = '\0'; 2013 show_state_t state; 2014 dladm_status_t status; 2015 char *fields_str = NULL; 2016 char *o_fields_str = NULL; 2017 2018 char *lane_stat_fields = 2019 "link,type,id,index,pkts,bytes"; 2020 char *rx_lane_stat_fields = 2021 "link,type,id,index,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50"; 2022 char *tx_lane_stat_fields = 2023 "link,type,id,index,opkts,obytes,blkcnt,ublkcnt"; 2024 char *rx_fanout_stat_fields = 2025 "link,id,index,fout,ipkts,rbytes"; 2026 2027 ofmt_handle_t ofmt; 2028 ofmt_status_t oferr; 2029 uint_t ofmtflags = OFMT_RIGHTJUST; 2030 ofmt_field_t *oftemplate; 2031 2032 bzero(&state, sizeof (state)); 2033 opterr = 0; 2034 while ((option = getopt_long(argc, argv, ":hrtFapi:o:u:", 2035 NULL, NULL)) != -1) { 2036 switch (option) { 2037 case 'h': 2038 if (r_arg || F_arg || t_arg || i_arg || p_arg || 2039 o_arg || u_arg || a_arg) { 2040 die("the option -h is not compatible with " 2041 "-r, -F, -t, -i, -p, -o, -u, -a"); 2042 } 2043 do_show_history(argc, &argv[0], use); 2044 return; 2045 case 'r': 2046 if (r_arg) 2047 die_optdup(option); 2048 2049 r_arg = B_TRUE; 2050 break; 2051 case 'F': 2052 if (F_arg) 2053 die_optdup(option); 2054 2055 F_arg = B_TRUE; 2056 break; 2057 case 't': 2058 if (t_arg) 2059 die_optdup(option); 2060 2061 t_arg = B_TRUE; 2062 break; 2063 case 'a': 2064 if (a_arg) 2065 die_optdup(option); 2066 2067 a_arg = B_TRUE; 2068 break; 2069 case 'i': 2070 if (i_arg) 2071 die_optdup(option); 2072 2073 i_arg = B_TRUE; 2074 if (!dladm_str2interval(optarg, &interval)) 2075 die("invalid interval value '%s'", optarg); 2076 break; 2077 case 'p': 2078 if (p_arg) 2079 die_optdup(option); 2080 2081 p_arg = B_TRUE; 2082 break; 2083 case 'o': 2084 o_arg = B_TRUE; 2085 o_fields_str = optarg; 2086 break; 2087 case 'u': 2088 if (u_arg) 2089 die_optdup(option); 2090 2091 u_arg = B_TRUE; 2092 if (!dlstat_unit(optarg, &unit)) 2093 die("invalid unit value '%s'," 2094 "unit must be R|K|M|G|T|P", optarg); 2095 break; 2096 default: 2097 die_opterr(optopt, option, use); 2098 break; 2099 } 2100 } 2101 2102 if (r_arg && t_arg) 2103 die("the options -t and -r are not compatible"); 2104 2105 if (u_arg && p_arg) 2106 die("the options -u and -p are not compatible"); 2107 2108 if (F_arg && !r_arg) 2109 die("-F must be used with -r"); 2110 2111 if (p_arg && !o_arg) 2112 die("-p requires -o"); 2113 2114 if (p_arg && strcasecmp(o_fields_str, "all") == 0) 2115 die("\"-o all\" is invalid with -p"); 2116 2117 if (a_arg && 2118 (p_arg || o_arg || u_arg || i_arg)) { 2119 die("the option -a is not compatible with " 2120 "-p, -o, -u, -i"); 2121 } 2122 2123 /* get link name (optional last argument) */ 2124 if (optind == (argc-1)) { 2125 if (strlen(argv[optind]) >= MAXLINKNAMELEN) 2126 die("link name too long"); 2127 2128 if ((status = dladm_name2info(handle, argv[optind], &linkid, 2129 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 2130 die_dlerr(status, "link %s is not valid", argv[optind]); 2131 } 2132 } else if (optind != argc) { 2133 usage(); 2134 } 2135 2136 if (a_arg) { 2137 boolean_t stattype[DLADM_STAT_NUM_STATS]; 2138 2139 bzero(&stattype, sizeof (stattype)); 2140 2141 if (r_arg) { 2142 if (F_arg) { 2143 stattype[DLADM_STAT_RX_LANE_FOUT] = B_TRUE; 2144 } else { 2145 stattype[DLADM_STAT_RX_LANE] = B_TRUE; 2146 } 2147 } else if (t_arg) { 2148 stattype[DLADM_STAT_TX_LANE] = B_TRUE; 2149 } else { /* Display both Rx and Tx lanes */ 2150 stattype[DLADM_STAT_RX_LANE] = B_TRUE; 2151 stattype[DLADM_STAT_TX_LANE] = B_TRUE; 2152 } 2153 2154 dump_all_link_stats(linkid, stattype); 2155 return; 2156 } 2157 2158 state.ls_unit = unit; 2159 state.ls_parsable = p_arg; 2160 2161 if (state.ls_parsable) 2162 ofmtflags |= OFMT_PARSABLE; 2163 2164 if (r_arg) { 2165 if (F_arg) { 2166 fields_str = rx_fanout_stat_fields; 2167 oftemplate = rx_fanout_lane_s_fields; 2168 state.ls_stattype[DLADM_STAT_RX_LANE_FOUT] = B_TRUE; 2169 state.ls_stats2str[DLADM_STAT_RX_LANE_FOUT] = 2170 print_fanout_stats; 2171 } else { 2172 fields_str = rx_lane_stat_fields; 2173 oftemplate = rx_lane_s_fields; 2174 state.ls_stattype[DLADM_STAT_RX_LANE] = B_TRUE; 2175 state.ls_stats2str[DLADM_STAT_RX_LANE] = 2176 print_rx_lane_stats; 2177 } 2178 } else if (t_arg) { 2179 fields_str = tx_lane_stat_fields; 2180 oftemplate = tx_lane_s_fields; 2181 state.ls_stattype[DLADM_STAT_TX_LANE] = B_TRUE; 2182 state.ls_stats2str[DLADM_STAT_TX_LANE] = print_tx_lane_stats; 2183 } else { /* Display both Rx and Tx lanes */ 2184 fields_str = lane_stat_fields; 2185 oftemplate = lane_s_fields; 2186 state.ls_stattype[DLADM_STAT_RX_LANE] = B_TRUE; 2187 state.ls_stattype[DLADM_STAT_TX_LANE] = B_TRUE; 2188 state.ls_stats2str[DLADM_STAT_RX_LANE] = 2189 print_rx_generic_lane_stats; 2190 state.ls_stats2str[DLADM_STAT_TX_LANE] = 2191 print_tx_generic_lane_stats; 2192 } 2193 if (o_arg) { 2194 fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 2195 fields_str : o_fields_str; 2196 } 2197 2198 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt); 2199 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 2200 2201 state.ls_ofmt = ofmt; 2202 2203 show_link_stats(linkid, state, interval); 2204 2205 ofmt_close(ofmt); 2206 } 2207 2208 static void 2209 do_show_aggr(int argc, char *argv[], const char *use) 2210 { 2211 int option; 2212 boolean_t r_arg = B_FALSE; 2213 boolean_t t_arg = B_FALSE; 2214 boolean_t i_arg = B_FALSE; 2215 boolean_t p_arg = B_FALSE; 2216 boolean_t o_arg = B_FALSE; 2217 boolean_t u_arg = B_FALSE; 2218 uint32_t flags = DLADM_OPT_ACTIVE; 2219 datalink_id_t linkid = DATALINK_ALL_LINKID; 2220 uint32_t interval = 0; 2221 char unit = '\0'; 2222 show_state_t state; 2223 dladm_status_t status; 2224 char *fields_str = NULL; 2225 char *o_fields_str = NULL; 2226 2227 char *aggr_stat_fields = 2228 "link,port,ipkts,rbytes,opkts,obytes"; 2229 char *rx_aggr_stat_fields = "link,port,ipkts,rbytes"; 2230 char *tx_aggr_stat_fields = "link,port,opkts,obytes"; 2231 2232 ofmt_handle_t ofmt; 2233 ofmt_status_t oferr; 2234 uint_t ofmtflags = OFMT_RIGHTJUST; 2235 ofmt_field_t *oftemplate; 2236 2237 bzero(&state, sizeof (state)); 2238 opterr = 0; 2239 while ((option = getopt_long(argc, argv, ":rtpi:o:u:", 2240 NULL, NULL)) != -1) { 2241 switch (option) { 2242 case 'r': 2243 if (r_arg) 2244 die_optdup(option); 2245 2246 r_arg = B_TRUE; 2247 break; 2248 case 't': 2249 if (t_arg) 2250 die_optdup(option); 2251 2252 t_arg = B_TRUE; 2253 break; 2254 case 'i': 2255 if (i_arg) 2256 die_optdup(option); 2257 2258 i_arg = B_TRUE; 2259 if (!dladm_str2interval(optarg, &interval)) 2260 die("invalid interval value '%s'", optarg); 2261 break; 2262 case 'p': 2263 if (p_arg) 2264 die_optdup(option); 2265 2266 p_arg = B_TRUE; 2267 break; 2268 case 'o': 2269 o_arg = B_TRUE; 2270 o_fields_str = optarg; 2271 break; 2272 case 'u': 2273 if (u_arg) 2274 die_optdup(option); 2275 2276 u_arg = B_TRUE; 2277 if (!dlstat_unit(optarg, &unit)) 2278 die("invalid unit value '%s'," 2279 "unit must be R|K|M|G|T|P", optarg); 2280 break; 2281 default: 2282 die_opterr(optopt, option, use); 2283 break; 2284 } 2285 } 2286 2287 if (r_arg && t_arg) 2288 die("the options -t and -r are not compatible"); 2289 2290 if (u_arg && p_arg) 2291 die("the options -u and -p are not compatible"); 2292 2293 if (p_arg && !o_arg) 2294 die("-p requires -o"); 2295 2296 if (p_arg && strcasecmp(o_fields_str, "all") == 0) 2297 die("\"-o all\" is invalid with -p"); 2298 2299 2300 /* get link name (optional last argument) */ 2301 if (optind == (argc-1)) { 2302 if (strlen(argv[optind]) >= MAXLINKNAMELEN) 2303 die("link name too long"); 2304 2305 if ((status = dladm_name2info(handle, argv[optind], &linkid, 2306 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 2307 die_dlerr(status, "link %s is not valid", argv[optind]); 2308 } 2309 } else if (optind != argc) { 2310 usage(); 2311 } 2312 2313 state.ls_unit = unit; 2314 state.ls_parsable = p_arg; 2315 2316 if (state.ls_parsable) 2317 ofmtflags |= OFMT_PARSABLE; 2318 2319 oftemplate = aggr_port_s_fields; 2320 state.ls_stattype[DLADM_STAT_AGGR_PORT] = B_TRUE; 2321 state.ls_stats2str[DLADM_STAT_AGGR_PORT] = print_aggr_port_stats; 2322 2323 if (r_arg) 2324 fields_str = rx_aggr_stat_fields; 2325 else if (t_arg) 2326 fields_str = tx_aggr_stat_fields; 2327 else 2328 fields_str = aggr_stat_fields; 2329 2330 if (o_arg) { 2331 fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 2332 fields_str : o_fields_str; 2333 } 2334 2335 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt); 2336 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 2337 state.ls_ofmt = ofmt; 2338 2339 show_link_stats(linkid, state, interval); 2340 2341 ofmt_close(ofmt); 2342 } 2343 2344 /* PRINTFLIKE1 */ 2345 static void 2346 warn(const char *format, ...) 2347 { 2348 va_list alist; 2349 2350 format = gettext(format); 2351 (void) fprintf(stderr, "%s: warning: ", progname); 2352 2353 va_start(alist, format); 2354 (void) vfprintf(stderr, format, alist); 2355 va_end(alist); 2356 2357 (void) putc('\n', stderr); 2358 } 2359 2360 /* 2361 * Also closes the dladm handle if it is not NULL. 2362 */ 2363 /* PRINTFLIKE2 */ 2364 static void 2365 die_dlerr(dladm_status_t err, const char *format, ...) 2366 { 2367 va_list alist; 2368 char errmsg[DLADM_STRSIZE]; 2369 2370 format = gettext(format); 2371 (void) fprintf(stderr, "%s: ", progname); 2372 2373 va_start(alist, format); 2374 (void) vfprintf(stderr, format, alist); 2375 va_end(alist); 2376 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 2377 2378 /* close dladm handle if it was opened */ 2379 if (handle != NULL) 2380 dladm_close(handle); 2381 2382 exit(EXIT_FAILURE); 2383 } 2384 2385 /* PRINTFLIKE1 */ 2386 static void 2387 die(const char *format, ...) 2388 { 2389 va_list alist; 2390 2391 format = gettext(format); 2392 (void) fprintf(stderr, "%s: ", progname); 2393 2394 va_start(alist, format); 2395 (void) vfprintf(stderr, format, alist); 2396 va_end(alist); 2397 2398 (void) putc('\n', stderr); 2399 2400 /* close dladm handle if it was opened */ 2401 if (handle != NULL) 2402 dladm_close(handle); 2403 2404 exit(EXIT_FAILURE); 2405 } 2406 2407 static void 2408 die_optdup(int opt) 2409 { 2410 die("the option -%c cannot be specified more than once", opt); 2411 } 2412 2413 static void 2414 die_opterr(int opt, int opterr, const char *usage) 2415 { 2416 switch (opterr) { 2417 case ':': 2418 die("option '-%c' requires a value\nusage: %s", opt, 2419 gettext(usage)); 2420 break; 2421 case '?': 2422 default: 2423 die("unrecognized option '-%c'\nusage: %s", opt, 2424 gettext(usage)); 2425 break; 2426 } 2427 } 2428 2429 /* 2430 * default output callback function that, when invoked, 2431 * prints string which is offset by ofmt_arg->ofmt_id within buf. 2432 */ 2433 static boolean_t 2434 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2435 { 2436 char *value; 2437 2438 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; 2439 (void) strlcpy(buf, value, bufsize); 2440 return (B_TRUE); 2441 } 2442