8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / dlstat / dlstat.c
bloba931ba82ff08b7f66d806a4919ffe0f4c378f3af
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
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;
65 typedef void * (*stats2str_t)(const char *, void *,
66 char, boolean_t);
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;
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;
87 * callback functions for printing output and error diagnostics.
89 static ofmt_cb_t print_default_cb;
91 static void dlstat_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
93 typedef void cmdfunc_t(int, char **, const char *);
95 static cmdfunc_t do_show, do_show_history, do_show_phys, do_show_link;
96 static cmdfunc_t do_show_aggr;
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 *, ...);
104 typedef struct cmd {
105 char *c_name;
106 cmdfunc_t *c_fn;
107 const char *c_usage;
108 } cmd_t;
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]" }
133 #define MAXSTATLEN 15
136 * dlstat : total stat fields
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;
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}};
160 * dlstat show-phys: both Rx and Tx stat fields
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;
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}};
187 * dlstat show-phys -r: Rx Ring stat fields
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;
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}};
214 * dlstat show-phys -t: Tx Ring stat fields
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;
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}};
241 * dlstat show-link: both Rx and Tx lane fields
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;
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}};
268 * dlstat show-link -r, dlstat -r: Rx Lane stat fields
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;
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}};
313 * dlstat show-link -r -F: Rx fanout stat fields
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;
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}};
343 * dlstat show-link -t: Tx Lane stat fields
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;
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}};
379 * dlstat show-aggr: aggr port stat fields
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;
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}};
406 * structures for 'dlstat show-link -h'
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;
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}};
436 * structures for 'dlstat show-link -h link'
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;
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}}
464 static char *progname;
467 * Handle to libdladm. Opened in main() before the sub-command
468 * specific function is called.
470 static dladm_handle_t handle = NULL;
472 static void
473 usage(void)
475 int i;
476 cmd_t *cmdp;
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));
485 /* close dladm handle if it was opened */
486 if (handle != NULL)
487 dladm_close(handle);
489 exit(1);
493 main(int argc, char *argv[])
495 int i;
496 cmd_t *cmdp;
497 dladm_status_t status;
499 (void) setlocale(LC_ALL, "");
500 #if !defined(TEXT_DOMAIN)
501 #define TEXT_DOMAIN "SYS_TEST"
502 #endif
503 (void) textdomain(TEXT_DOMAIN);
505 progname = argv[0];
507 /* Open the libdladm handle */
508 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK)
509 die_dlerr(status, "could not open /dev/dld");
511 if (argc == 1) {
512 do_show(argc - 1, NULL, cmds[0].c_usage);
513 goto done;
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;
524 do_show(argc, &argv[0], cmds[0].c_usage);
526 done:
527 dladm_close(handle);
528 return (0);
531 /*ARGSUSED*/
532 static int
533 show_history_date(dladm_usage_t *history, void *arg)
535 show_history_state_t *state = arg;
536 time_t stime;
537 char timebuf[20];
538 dladm_status_t status;
539 uint32_t flags;
542 * Only show history information for existing links unless '-a'
543 * is specified.
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);
550 if ((flags & DLADM_OPT_ACTIVE) == 0)
551 return (DLADM_STATUS_LINKINVAL);
554 stime = history->du_stime;
555 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
556 localtime(&stime));
557 (void) printf("%s\n", timebuf);
559 return (DLADM_STATUS_OK);
562 static int
563 show_history_time(dladm_usage_t *history, void *arg)
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;
574 * Only show history information for existing links unless '-a'
575 * is specified.
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);
582 if ((flags & DLADM_OPT_ACTIVE) == 0)
583 return (DLADM_STATUS_LINKINVAL);
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;
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;
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);
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;
613 return (DLADM_STATUS_OK);
616 bzero(&ubuf, sizeof (ubuf));
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));
635 ofmt_print(state->hs_ofmt, &ubuf);
636 return (DLADM_STATUS_OK);
639 static int
640 show_history_res(dladm_usage_t *history, void *arg)
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;
649 * Only show history information for existing links unless '-a'
650 * is specified.
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);
657 if ((flags & DLADM_OPT_ACTIVE) == 0)
658 return (DLADM_STATUS_LINKINVAL);
661 bzero(&ubuf, sizeof (ubuf));
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));
678 ofmt_print(state->hs_ofmt, &ubuf);
680 return (DLADM_STATUS_OK);
683 static boolean_t
684 valid_formatspec(char *formatspec_str)
686 return (strcmp(formatspec_str, "gnuplot") == 0);
689 /*ARGSUSED*/
690 static void
691 do_show_history(int argc, char *argv[], const char *use)
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;
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;
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;
748 if (file == NULL)
749 die("show-link -h requires a file");
751 if (optind == (argc-1)) {
752 uint32_t flags;
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);
763 if (F_arg && d_arg)
764 die("incompatible -d and -F options");
766 if (F_arg && !valid_formatspec(formatspec_str))
767 die("Format specifier %s not supported", formatspec_str);
769 if (state.hs_parsable)
770 ofmtflags |= OFMT_PARSABLE;
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);
782 dlstat_ofmt_check(oferr, state.hs_parsable, ofmt);
783 state.hs_ofmt = ofmt;
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);
804 if (status != DLADM_STATUS_OK)
805 die_dlerr(status, "show-link -h");
806 ofmt_close(ofmt);
809 boolean_t
810 dlstat_unit(char *oarg, char *unit)
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);
819 return (B_FALSE);
822 void
823 map_to_units(char *buf, uint_t bufsize, double num, char unit,
824 boolean_t parsable)
826 if (parsable) {
827 (void) snprintf(buf, bufsize, "%.0lf", num);
828 return;
831 if (unit == '\0') {
832 int index;
834 for (index = 0; (int)(num/1000) != 0; index++, num /= 1000)
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;
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;
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);
891 link_chain_t *
892 get_link_prev_stat(datalink_id_t linkid, void *arg)
894 show_state_t *state = (show_state_t *)arg;
895 link_chain_t *link_curr = NULL;
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;
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;
914 done:
915 return (link_curr);
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.
924 static void
925 cleanup_removed_links(show_state_t *state)
927 link_chain_t *lcurr;
928 link_chain_t *lprev;
929 link_chain_t *tofree;
930 int i;
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;
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;
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]);
955 free(tofree);
959 void *
960 print_total_stats(const char *linkname, void *statentry, char unit,
961 boolean_t parsable)
963 total_stat_entry_t *sentry = statentry;
964 total_stat_t *link_stats = &sentry->tse_stats;
965 total_fields_buf_t *buf;
967 buf = malloc(sizeof (total_fields_buf_t));
968 if (buf == NULL)
969 goto done;
971 (void) snprintf(buf->t_linkname, sizeof (buf->t_linkname), "%s",
972 linkname);
974 map_to_units(buf->t_ipackets, sizeof (buf->t_ipackets),
975 link_stats->ts_ipackets, unit, parsable);
977 map_to_units(buf->t_rbytes, sizeof (buf->t_rbytes),
978 link_stats->ts_rbytes, unit, parsable);
980 map_to_units(buf->t_opackets, sizeof (buf->t_opackets),
981 link_stats->ts_opackets, unit, parsable);
983 map_to_units(buf->t_obytes, sizeof (buf->t_obytes),
984 link_stats->ts_obytes, unit, parsable);
986 done:
987 return (buf);
990 void *
991 print_rx_generic_ring_stats(const char *linkname, void *statentry, char unit,
992 boolean_t parsable)
994 ring_stat_entry_t *sentry = statentry;
995 ring_stat_t *link_stats = &sentry->re_stats;
996 ring_fields_buf_t *buf;
998 buf = malloc(sizeof (ring_fields_buf_t));
999 if (buf == NULL)
1000 goto done;
1002 (void) snprintf(buf->r_linkname, sizeof (buf->r_linkname), "%s",
1003 linkname);
1005 (void) snprintf(buf->r_type, sizeof (buf->r_type), "rx");
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);
1014 map_to_units(buf->r_packets, sizeof (buf->r_packets),
1015 link_stats->r_packets, unit, parsable);
1017 map_to_units(buf->r_bytes, sizeof (buf->r_bytes),
1018 link_stats->r_bytes, unit, parsable);
1020 done:
1021 return (buf);
1024 void *
1025 print_tx_generic_ring_stats(const char *linkname, void *statentry, char unit,
1026 boolean_t parsable)
1028 ring_stat_entry_t *sentry = statentry;
1029 ring_stat_t *link_stats = &sentry->re_stats;
1030 ring_fields_buf_t *buf;
1032 buf = malloc(sizeof (ring_fields_buf_t));
1033 if (buf == NULL)
1034 goto done;
1036 (void) snprintf(buf->r_linkname, sizeof (buf->r_linkname), "%s",
1037 linkname);
1039 (void) snprintf(buf->r_type, sizeof (buf->r_type), "tx");
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);
1048 map_to_units(buf->r_packets, sizeof (buf->r_packets),
1049 link_stats->r_packets, unit, parsable);
1051 map_to_units(buf->r_bytes, sizeof (buf->r_bytes),
1052 link_stats->r_bytes, unit, parsable);
1054 done:
1055 return (buf);
1058 void *
1059 print_rx_ring_stats(const char *linkname, void *statentry, char unit,
1060 boolean_t parsable)
1062 ring_stat_entry_t *sentry = statentry;
1063 ring_stat_t *link_stats = &sentry->re_stats;
1064 rx_ring_fields_buf_t *buf;
1066 buf = malloc(sizeof (rx_ring_fields_buf_t));
1067 if (buf == NULL)
1068 goto done;
1070 (void) snprintf(buf->rr_linkname, sizeof (buf->rr_linkname), "%s",
1071 linkname);
1073 (void) snprintf(buf->rr_type, sizeof (buf->rr_type), "rx");
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);
1082 map_to_units(buf->rr_ipackets, sizeof (buf->rr_ipackets),
1083 link_stats->r_packets, unit, parsable);
1085 map_to_units(buf->rr_rbytes, sizeof (buf->rr_rbytes),
1086 link_stats->r_bytes, unit, parsable);
1088 done:
1089 return (buf);
1092 void *
1093 print_tx_ring_stats(const char *linkname, void *statentry, char unit,
1094 boolean_t parsable)
1096 ring_stat_entry_t *sentry = statentry;
1097 ring_stat_t *link_stats = &sentry->re_stats;
1098 tx_ring_fields_buf_t *buf;
1100 buf = malloc(sizeof (tx_ring_fields_buf_t));
1101 if (buf == NULL)
1102 goto done;
1104 (void) snprintf(buf->tr_linkname, sizeof (buf->tr_linkname), "%s",
1105 linkname);
1107 (void) snprintf(buf->tr_type, sizeof (buf->tr_type), "tx");
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);
1116 map_to_units(buf->tr_opackets, sizeof (buf->tr_opackets),
1117 link_stats->r_packets, unit, parsable);
1119 map_to_units(buf->tr_obytes, sizeof (buf->tr_obytes),
1120 link_stats->r_bytes, unit, parsable);
1122 done:
1123 return (buf);
1126 void *
1127 print_rx_generic_lane_stats(const char *linkname, void *statentry, char unit,
1128 boolean_t parsable)
1130 rx_lane_stat_entry_t *sentry = statentry;
1131 rx_lane_stat_t *link_stats = &sentry->rle_stats;
1132 lane_fields_buf_t *buf;
1134 if (sentry->rle_id == L_DFNCT)
1135 return (NULL);
1137 buf = malloc(sizeof (lane_fields_buf_t));
1138 if (buf == NULL)
1139 goto done;
1141 (void) snprintf(buf->l_linkname, sizeof (buf->l_linkname), "%s",
1142 linkname);
1144 (void) snprintf(buf->l_type, sizeof (buf->l_type), "rx");
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), "--");
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);
1164 map_to_units(buf->l_packets, sizeof (buf->l_packets),
1165 link_stats->rl_ipackets, unit, parsable);
1167 map_to_units(buf->l_bytes, sizeof (buf->l_bytes),
1168 link_stats->rl_rbytes, unit, parsable);
1170 done:
1171 return (buf);
1174 void *
1175 print_tx_generic_lane_stats(const char *linkname, void *statentry, char unit,
1176 boolean_t parsable)
1178 tx_lane_stat_entry_t *sentry = statentry;
1179 tx_lane_stat_t *link_stats = &sentry->tle_stats;
1180 lane_fields_buf_t *buf;
1182 if (sentry->tle_id == L_DFNCT)
1183 return (NULL);
1185 buf = malloc(sizeof (lane_fields_buf_t));
1186 if (buf == NULL)
1187 goto done;
1189 (void) snprintf(buf->l_linkname, sizeof (buf->l_linkname), "%s",
1190 linkname);
1192 (void) snprintf(buf->l_type, sizeof (buf->l_type), "tx");
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), "--");
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);
1209 map_to_units(buf->l_packets, sizeof (buf->l_packets),
1210 link_stats->tl_opackets, unit, parsable);
1212 map_to_units(buf->l_bytes, sizeof (buf->l_bytes),
1213 link_stats->tl_obytes, unit, parsable);
1215 done:
1216 return (buf);
1219 void *
1220 print_rx_lane_stats(const char *linkname, void *statentry, char unit,
1221 boolean_t parsable)
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;
1227 if (sentry->rle_id == L_DFNCT)
1228 return (NULL);
1230 buf = malloc(sizeof (rx_lane_fields_buf_t));
1231 if (buf == NULL)
1232 goto done;
1234 (void) snprintf(buf->rl_linkname, sizeof (buf->rl_linkname), "%s",
1235 linkname);
1237 (void) snprintf(buf->rl_type, sizeof (buf->rl_type), "rx");
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), "--");
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);
1257 map_to_units(buf->rl_ipackets, sizeof (buf->rl_ipackets),
1258 link_stats->rl_ipackets, unit, parsable);
1260 map_to_units(buf->rl_rbytes, sizeof (buf->rl_rbytes),
1261 link_stats->rl_rbytes, unit, parsable);
1263 map_to_units(buf->rl_intrs, sizeof (buf->rl_intrs),
1264 link_stats->rl_intrs, unit, parsable);
1266 map_to_units(buf->rl_polls, sizeof (buf->rl_polls),
1267 link_stats->rl_polls, unit, parsable);
1269 map_to_units(buf->rl_sdrops, sizeof (buf->rl_sdrops),
1270 link_stats->rl_sdrops, unit, parsable);
1272 map_to_units(buf->rl_chl10, sizeof (buf->rl_chl10),
1273 link_stats->rl_chl10, unit, parsable);
1275 map_to_units(buf->rl_ch10_50, sizeof (buf->rl_ch10_50),
1276 link_stats->rl_ch10_50, unit, parsable);
1278 map_to_units(buf->rl_chg50, sizeof (buf->rl_chg50),
1279 link_stats->rl_chg50, unit, parsable);
1281 done:
1282 return (buf);
1285 void *
1286 print_tx_lane_stats(const char *linkname, void *statentry, char unit,
1287 boolean_t parsable)
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;
1293 if (sentry->tle_id == L_DFNCT)
1294 return (NULL);
1296 buf = malloc(sizeof (tx_lane_fields_buf_t));
1297 if (buf == NULL)
1298 goto done;
1300 (void) snprintf(buf->tl_linkname, sizeof (buf->tl_linkname), "%s",
1301 linkname);
1303 (void) snprintf(buf->tl_type, sizeof (buf->tl_type), "tx");
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), "--");
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);
1321 map_to_units(buf->tl_opackets, sizeof (buf->tl_opackets),
1322 link_stats->tl_opackets, unit, parsable);
1324 map_to_units(buf->tl_obytes, sizeof (buf->tl_obytes),
1325 link_stats->tl_obytes, unit, parsable);
1327 map_to_units(buf->tl_blockcnt, sizeof (buf->tl_blockcnt),
1328 link_stats->tl_blockcnt, unit, parsable);
1330 map_to_units(buf->tl_unblockcnt, sizeof (buf->tl_unblockcnt),
1331 link_stats->tl_unblockcnt, unit, parsable);
1333 map_to_units(buf->tl_sdrops, sizeof (buf->tl_sdrops),
1334 link_stats->tl_sdrops, unit, parsable);
1336 done:
1337 return (buf);
1340 void *
1341 print_fanout_stats(const char *linkname, void *statentry, char unit,
1342 boolean_t parsable)
1344 fanout_stat_entry_t *sentry = statentry;
1345 fanout_stat_t *link_stats = &sentry->fe_stats;
1346 rx_fanout_lane_fields_buf_t *buf;
1348 buf = malloc(sizeof (rx_fanout_lane_fields_buf_t));
1349 if (buf == NULL)
1350 goto done;
1352 (void) snprintf(buf->rfl_linkname, sizeof (buf->rfl_linkname), "%s",
1353 linkname);
1355 (void) snprintf(buf->rfl_type, sizeof (buf->rfl_type), "rx");
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), "--");
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);
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);
1384 map_to_units(buf->rfl_ipackets, sizeof (buf->rfl_ipackets),
1385 link_stats->f_ipackets, unit, parsable);
1387 map_to_units(buf->rfl_rbytes, sizeof (buf->rfl_rbytes),
1388 link_stats->f_rbytes, unit, parsable);
1390 done:
1391 return (buf);
1394 void *
1395 print_aggr_port_stats(const char *linkname, void *statentry, char unit,
1396 boolean_t parsable)
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];
1403 buf = malloc(sizeof (aggr_port_fields_buf_t));
1404 if (buf == NULL)
1405 goto done;
1407 (void) snprintf(buf->ap_linkname, sizeof (buf->ap_linkname), "%s",
1408 linkname);
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);
1420 map_to_units(buf->ap_ipackets, sizeof (buf->ap_ipackets),
1421 link_stats->ap_ipackets, unit, parsable);
1423 map_to_units(buf->ap_rbytes, sizeof (buf->ap_rbytes),
1424 link_stats->ap_rbytes, unit, parsable);
1426 map_to_units(buf->ap_opackets, sizeof (buf->ap_opackets),
1427 link_stats->ap_opackets, unit, parsable);
1429 map_to_units(buf->ap_obytes, sizeof (buf->ap_obytes),
1430 link_stats->ap_obytes, unit, parsable);
1432 done:
1433 return (buf);
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)
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;
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;
1450 link_node->lc_visited = B_TRUE;
1451 prev_stat = link_node->lc_statchain[stattype];
1453 /* Query library for current stats */
1454 curr_stat = dladm_link_stat_query(dh, linkid, stattype);
1455 if (curr_stat == NULL)
1456 goto done;
1458 /* current stats - prev iteration stats */
1459 diff_stat = dladm_link_stat_diffchain(curr_stat, prev_stat, stattype);
1461 /* Free prev stats */
1462 dladm_link_stat_free(prev_stat);
1464 /* Prev <- curr stats */
1465 link_node->lc_statchain[stattype] = curr_stat;
1467 done:
1468 return (diff_stat);
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)
1475 dladm_stat_chain_t *curr;
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;
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);
1491 static int
1492 show_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1494 show_state_t *state = arg;
1495 int i;
1496 dladm_stat_chain_t *diff_stat;
1497 char linkname[DLPI_LINKNAME_MAX];
1499 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1500 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1501 goto done;
1504 for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
1505 if (state->ls_stattype[i]) {
1507 * Query library for stats
1508 * Stats are returned as chain of raw numbers
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);
1515 done:
1516 return (DLADM_WALK_CONTINUE);
1519 void
1520 show_link_stats(datalink_id_t linkid, show_state_t state, uint32_t interval)
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);
1531 if (interval == 0)
1532 break;
1534 cleanup_removed_links(&state);
1535 (void) sleep(interval);
1539 void
1540 print_all_stats(dladm_handle_t dh, datalink_id_t linkid,
1541 dladm_stat_chain_t *stat_chain)
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];
1550 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1551 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK)
1552 return;
1554 for (curr = stat_chain; curr != NULL; curr = curr->dc_next) {
1555 stat_entry = curr->dc_statentry;
1557 * Print header
1558 * If link name is already printed in previous iteration,
1559 * don't print again
1561 if (strcmp(prev_linkname, linkname) != 0)
1562 printf("%s \n", linkname);
1563 printf(" %s \n", stat_entry->nve_header);
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);
1572 strncpy(prev_linkname, linkname, MAXLINKNAMELEN);
1573 stat_printed = B_TRUE;
1575 if (stat_printed)
1576 printf("---------------------------------------------------\n");
1579 static int
1580 dump_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1582 boolean_t *stattype = arg;
1583 int i;
1584 dladm_stat_chain_t *stat_chain;
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);
1593 done:
1594 return (DLADM_WALK_CONTINUE);
1597 void
1598 dump_all_link_stats(datalink_id_t linkid, boolean_t *stattype)
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);
1609 static void
1610 do_show(int argc, char *argv[], const char *use)
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;
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";
1637 ofmt_handle_t ofmt;
1638 ofmt_status_t oferr;
1639 uint_t ofmtflags = OFMT_RIGHTJUST;
1640 ofmt_field_t *oftemplate;
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);
1651 r_arg = B_TRUE;
1652 break;
1653 case 't':
1654 if (t_arg)
1655 die_optdup(option);
1657 t_arg = B_TRUE;
1658 break;
1659 case 'a':
1660 if (a_arg)
1661 die_optdup(option);
1663 a_arg = B_TRUE;
1664 break;
1665 case 'A':
1666 if (A_arg)
1667 die_optdup(option);
1669 A_arg = B_TRUE;
1670 break;
1671 case 'i':
1672 if (i_arg)
1673 die_optdup(option);
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);
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);
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;
1704 if (r_arg && t_arg)
1705 die("the options -t and -r are not compatible");
1707 if (u_arg && p_arg)
1708 die("the options -u and -p are not compatible");
1710 if (p_arg && !o_arg)
1711 die("-p requires -o");
1713 if (p_arg && strcasecmp(o_fields_str, "all") == 0)
1714 die("\"-o all\" is invalid with -p");
1716 if (a_arg && A_arg)
1717 die("the options -a and -A are not compatible");
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");
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");
1731 /* get link name (optional last argument) */
1732 if (optind == (argc-1)) {
1733 if (strlen(argv[optind]) >= MAXLINKNAMELEN)
1734 die("link name too long");
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]);
1740 } else if (optind != argc) {
1741 if (argc != 0)
1742 usage();
1745 if (a_arg) {
1746 boolean_t stattype[DLADM_STAT_NUM_STATS];
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;
1757 dump_all_link_stats(linkid, stattype);
1758 return;
1761 if (A_arg) {
1762 boolean_t stattype[DLADM_STAT_NUM_STATS];
1763 int i;
1765 for (i = 0; i < DLADM_STAT_NUM_STATS; i++)
1766 stattype[i] = B_TRUE;
1768 dump_all_link_stats(linkid, stattype);
1769 return;
1772 state.ls_unit = unit;
1773 state.ls_parsable = p_arg;
1775 if (state.ls_parsable)
1776 ofmtflags |= OFMT_PARSABLE;
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;
1797 if (o_arg) {
1798 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
1799 fields_str : o_fields_str;
1802 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
1803 dlstat_ofmt_check(oferr, state.ls_parsable, ofmt);
1804 state.ls_ofmt = ofmt;
1806 show_link_stats(linkid, state, interval);
1808 ofmt_close(ofmt);
1811 static void
1812 do_show_phys(int argc, char *argv[], const char *use)
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";
1838 ofmt_handle_t ofmt;
1839 ofmt_status_t oferr;
1840 uint_t ofmtflags = OFMT_RIGHTJUST;
1841 ofmt_field_t *oftemplate;
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);
1852 r_arg = B_TRUE;
1853 break;
1854 case 't':
1855 if (t_arg)
1856 die_optdup(option);
1858 t_arg = B_TRUE;
1859 break;
1860 case 'a':
1861 if (a_arg)
1862 die_optdup(option);
1864 a_arg = B_TRUE;
1865 break;
1866 case 'i':
1867 if (i_arg)
1868 die_optdup(option);
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);
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);
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;
1899 if (r_arg && t_arg)
1900 die("the options -t and -r are not compatible");
1902 if (u_arg && p_arg)
1903 die("the options -u and -p are not compatible");
1905 if (p_arg && !o_arg)
1906 die("-p requires -o");
1908 if (p_arg && strcasecmp(o_fields_str, "all") == 0)
1909 die("\"-o all\" is invalid with -p");
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");
1918 /* get link name (optional last argument) */
1919 if (optind == (argc-1)) {
1920 if (strlen(argv[optind]) >= MAXLINKNAMELEN)
1921 die("link name too long");
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]);
1927 } else if (optind != argc) {
1928 usage();
1931 if (a_arg) {
1932 boolean_t stattype[DLADM_STAT_NUM_STATS];
1934 bzero(&stattype, sizeof (stattype));
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;
1945 dump_all_link_stats(linkid, stattype);
1946 return;
1949 state.ls_unit = unit;
1950 state.ls_parsable = p_arg;
1952 if (state.ls_parsable)
1953 ofmtflags |= OFMT_PARSABLE;
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;
1976 if (o_arg) {
1977 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
1978 fields_str : o_fields_str;
1981 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
1982 dlstat_ofmt_check(oferr, state.ls_parsable, ofmt);
1983 state.ls_ofmt = ofmt;
1985 show_link_stats(linkid, state, interval);
1987 ofmt_close(ofmt);
1990 static void
1991 do_show_link(int argc, char *argv[], const char *use)
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;
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";
2020 ofmt_handle_t ofmt;
2021 ofmt_status_t oferr;
2022 uint_t ofmtflags = OFMT_RIGHTJUST;
2023 ofmt_field_t *oftemplate;
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");
2036 do_show_history(argc, &argv[0], use);
2037 return;
2038 case 'r':
2039 if (r_arg)
2040 die_optdup(option);
2042 r_arg = B_TRUE;
2043 break;
2044 case 'F':
2045 if (F_arg)
2046 die_optdup(option);
2048 F_arg = B_TRUE;
2049 break;
2050 case 't':
2051 if (t_arg)
2052 die_optdup(option);
2054 t_arg = B_TRUE;
2055 break;
2056 case 'a':
2057 if (a_arg)
2058 die_optdup(option);
2060 a_arg = B_TRUE;
2061 break;
2062 case 'i':
2063 if (i_arg)
2064 die_optdup(option);
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);
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);
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;
2095 if (r_arg && t_arg)
2096 die("the options -t and -r are not compatible");
2098 if (u_arg && p_arg)
2099 die("the options -u and -p are not compatible");
2101 if (F_arg && !r_arg)
2102 die("-F must be used with -r");
2104 if (p_arg && !o_arg)
2105 die("-p requires -o");
2107 if (p_arg && strcasecmp(o_fields_str, "all") == 0)
2108 die("\"-o all\" is invalid with -p");
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");
2116 /* get link name (optional last argument) */
2117 if (optind == (argc-1)) {
2118 if (strlen(argv[optind]) >= MAXLINKNAMELEN)
2119 die("link name too long");
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]);
2125 } else if (optind != argc) {
2126 usage();
2129 if (a_arg) {
2130 boolean_t stattype[DLADM_STAT_NUM_STATS];
2132 bzero(&stattype, sizeof (stattype));
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;
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;
2147 dump_all_link_stats(linkid, stattype);
2148 return;
2151 state.ls_unit = unit;
2152 state.ls_parsable = p_arg;
2154 if (state.ls_parsable)
2155 ofmtflags |= OFMT_PARSABLE;
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;
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;
2186 if (o_arg) {
2187 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
2188 fields_str : o_fields_str;
2191 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
2192 dlstat_ofmt_check(oferr, state.ls_parsable, ofmt);
2194 state.ls_ofmt = ofmt;
2196 show_link_stats(linkid, state, interval);
2198 ofmt_close(ofmt);
2201 static void
2202 do_show_aggr(int argc, char *argv[], const char *use)
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;
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";
2225 ofmt_handle_t ofmt;
2226 ofmt_status_t oferr;
2227 uint_t ofmtflags = OFMT_RIGHTJUST;
2228 ofmt_field_t *oftemplate;
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);
2239 r_arg = B_TRUE;
2240 break;
2241 case 't':
2242 if (t_arg)
2243 die_optdup(option);
2245 t_arg = B_TRUE;
2246 break;
2247 case 'i':
2248 if (i_arg)
2249 die_optdup(option);
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);
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);
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;
2280 if (r_arg && t_arg)
2281 die("the options -t and -r are not compatible");
2283 if (u_arg && p_arg)
2284 die("the options -u and -p are not compatible");
2286 if (p_arg && !o_arg)
2287 die("-p requires -o");
2289 if (p_arg && strcasecmp(o_fields_str, "all") == 0)
2290 die("\"-o all\" is invalid with -p");
2293 /* get link name (optional last argument) */
2294 if (optind == (argc-1)) {
2295 if (strlen(argv[optind]) >= MAXLINKNAMELEN)
2296 die("link name too long");
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]);
2302 } else if (optind != argc) {
2303 usage();
2306 state.ls_unit = unit;
2307 state.ls_parsable = p_arg;
2309 if (state.ls_parsable)
2310 ofmtflags |= OFMT_PARSABLE;
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;
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;
2323 if (o_arg) {
2324 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
2325 fields_str : o_fields_str;
2328 oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
2329 dlstat_ofmt_check(oferr, state.ls_parsable, ofmt);
2330 state.ls_ofmt = ofmt;
2332 show_link_stats(linkid, state, interval);
2334 ofmt_close(ofmt);
2337 /* PRINTFLIKE1 */
2338 static void
2339 warn(const char *format, ...)
2341 va_list alist;
2343 format = gettext(format);
2344 (void) fprintf(stderr, "%s: warning: ", progname);
2346 va_start(alist, format);
2347 (void) vfprintf(stderr, format, alist);
2348 va_end(alist);
2350 (void) putc('\n', stderr);
2354 * Also closes the dladm handle if it is not NULL.
2356 /* PRINTFLIKE2 */
2357 static void
2358 die_dlerr(dladm_status_t err, const char *format, ...)
2360 va_list alist;
2361 char errmsg[DLADM_STRSIZE];
2363 format = gettext(format);
2364 (void) fprintf(stderr, "%s: ", progname);
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));
2371 /* close dladm handle if it was opened */
2372 if (handle != NULL)
2373 dladm_close(handle);
2375 exit(EXIT_FAILURE);
2378 /* PRINTFLIKE1 */
2379 static void
2380 die(const char *format, ...)
2382 va_list alist;
2384 format = gettext(format);
2385 (void) fprintf(stderr, "%s: ", progname);
2387 va_start(alist, format);
2388 (void) vfprintf(stderr, format, alist);
2389 va_end(alist);
2391 (void) putc('\n', stderr);
2393 /* close dladm handle if it was opened */
2394 if (handle != NULL)
2395 dladm_close(handle);
2397 exit(EXIT_FAILURE);
2400 static void
2401 die_optdup(int opt)
2403 die("the option -%c cannot be specified more than once", opt);
2406 static void
2407 die_opterr(int opt, int opterr, const char *usage)
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;
2423 * default output callback function that, when invoked,
2424 * prints string which is offset by ofmt_arg->ofmt_id within buf.
2426 static boolean_t
2427 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2429 char *value;
2431 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id;
2432 (void) strlcpy(buf, value, bufsize);
2433 return (B_TRUE);
2436 static void
2437 dlstat_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
2438 ofmt_handle_t ofmt)
2440 char buf[OFMT_BUFSIZE];
2442 if (oferr == OFMT_SUCCESS)
2443 return;
2444 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
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.
2451 if (parsable || oferr == OFMT_ENOFIELDS) {
2452 ofmt_close(ofmt);
2453 die(buf);
2454 } else {
2455 warn(buf);