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