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