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
usage(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
main(int argc,char * argv[])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
show_history_date(dladm_usage_t * history,void * arg)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
show_history_time(dladm_usage_t * history,void * arg)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
show_history_res(dladm_usage_t * history,void * arg)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
valid_formatspec(char * formatspec_str)684 valid_formatspec(char *formatspec_str)
685 {
686 return (strcmp(formatspec_str, "gnuplot") == 0);
687 }
688
689 /*ARGSUSED*/
690 static void
do_show_history(int argc,char * argv[],const char * use)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
dlstat_unit(char * oarg,char * unit)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
map_to_units(char * buf,uint_t bufsize,double num,char unit,boolean_t parsable)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 *
get_link_prev_stat(datalink_id_t linkid,void * arg)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
cleanup_removed_links(show_state_t * state)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 *
print_total_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_rx_generic_ring_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_tx_generic_ring_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_rx_ring_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_tx_ring_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_rx_generic_lane_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_tx_generic_lane_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_rx_lane_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_tx_lane_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_fanout_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
print_aggr_port_stats(const char * linkname,void * statentry,char unit,boolean_t parsable)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 *
query_link_stats(dladm_handle_t dh,datalink_id_t linkid,void * arg,dladm_stat_type_t stattype)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
walk_dlstat_stats(show_state_t * state,const char * linkname,dladm_stat_type_t stattype,dladm_stat_chain_t * diff_stat)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
show_queried_stats(dladm_handle_t dh,datalink_id_t linkid,void * arg)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
show_link_stats(datalink_id_t linkid,show_state_t state,uint32_t interval)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
print_all_stats(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_chain_t * stat_chain)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
dump_queried_stats(dladm_handle_t dh,datalink_id_t linkid,void * arg)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
dump_all_link_stats(datalink_id_t linkid,boolean_t * stattype)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
do_show(int argc,char * argv[],const char * use)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
do_show_phys(int argc,char * argv[],const char * use)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
do_show_link(int argc,char * argv[],const char * use)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
do_show_aggr(int argc,char * argv[],const char * use)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
warn(const char * format,...)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
die_dlerr(dladm_status_t err,const char * format,...)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
die(const char * format,...)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
die_optdup(int opt)2401 die_optdup(int opt)
2402 {
2403 die("the option -%c cannot be specified more than once", opt);
2404 }
2405
2406 static void
die_opterr(int opt,int opterr,const char * usage)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
print_default_cb(ofmt_arg_t * ofarg,char * buf,uint_t bufsize)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
dlstat_ofmt_check(ofmt_status_t oferr,boolean_t parsable,ofmt_handle_t ofmt)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