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