xref: /illumos-gate/usr/src/cmd/dlstat/dlstat.c (revision e911ecb791559853d0e073c67e845f96ea058b7c)
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 		cleanup_removed_links(&state);
1538 
1539 		if (interval == 0)
1540 			break;
1541 
1542 		(void) sleep(interval);
1543 	}
1544 }
1545 
1546 void
print_all_stats(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_chain_t * stat_chain)1547 print_all_stats(dladm_handle_t dh, datalink_id_t linkid,
1548     dladm_stat_chain_t *stat_chain)
1549 {
1550 	dladm_stat_chain_t	*curr;
1551 	name_value_stat_entry_t	*stat_entry;
1552 	name_value_stat_t	*curr_stat;
1553 	boolean_t		stat_printed = B_FALSE;
1554 	char			linkname[MAXLINKNAMELEN];
1555 	char			prev_linkname[MAXLINKNAMELEN];
1556 
1557 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1558 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK)
1559 		return;
1560 
1561 	for (curr = stat_chain; curr != NULL; curr = curr->dc_next) {
1562 		stat_entry = curr->dc_statentry;
1563 		/*
1564 		 * Print header
1565 		 * If link name is already printed in previous iteration,
1566 		 * don't print again
1567 		 */
1568 		if (strcmp(prev_linkname, linkname) != 0)
1569 			printf("%s \n", linkname);
1570 		printf("  %s \n", stat_entry->nve_header);
1571 
1572 		/* Print stat fields */
1573 		for (curr_stat = stat_entry->nve_stats; curr_stat != NULL;
1574 		    curr_stat = curr_stat->nv_nextstat) {
1575 			printf("\t%15s", curr_stat->nv_statname);
1576 			printf("\t\t%15llu\n", curr_stat->nv_statval);
1577 		}
1578 
1579 		strncpy(prev_linkname, linkname, MAXLINKNAMELEN);
1580 		stat_printed = B_TRUE;
1581 	}
1582 	if (stat_printed)
1583 		printf("---------------------------------------------------\n");
1584 }
1585 
1586 static int
dump_queried_stats(dladm_handle_t dh,datalink_id_t linkid,void * arg)1587 dump_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1588 {
1589 	boolean_t		*stattype = arg;
1590 	int			i;
1591 	dladm_stat_chain_t	*stat_chain;
1592 
1593 	for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
1594 		if (stattype[i]) {
1595 			stat_chain = dladm_link_stat_query_all(dh, linkid, i);
1596 			print_all_stats(dh, linkid, stat_chain);
1597 			dladm_link_stat_query_all_free(stat_chain);
1598 		}
1599 	}
1600 done:
1601 	return (DLADM_WALK_CONTINUE);
1602 }
1603 
1604 void
dump_all_link_stats(datalink_id_t linkid,boolean_t * stattype)1605 dump_all_link_stats(datalink_id_t linkid, boolean_t *stattype)
1606 {
1607 	if (linkid == DATALINK_ALL_LINKID) {
1608 		(void) dladm_walk_datalink_id(dump_queried_stats,
1609 		    handle, stattype, DATALINK_CLASS_ALL,
1610 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1611 	} else {
1612 		(void) dump_queried_stats(handle, linkid, stattype);
1613 	}
1614 }
1615 
1616 static void
do_show(int argc,char * argv[],const char * use)1617 do_show(int argc, char *argv[], const char *use)
1618 {
1619 	int			option;
1620 	boolean_t		r_arg = B_FALSE;
1621 	boolean_t		t_arg = B_FALSE;
1622 	boolean_t		i_arg = B_FALSE;
1623 	boolean_t		p_arg = B_FALSE;
1624 	boolean_t		o_arg = B_FALSE;
1625 	boolean_t		u_arg = B_FALSE;
1626 	boolean_t		a_arg = B_FALSE;
1627 	boolean_t		A_arg = B_FALSE;
1628 	uint32_t		flags = DLADM_OPT_ACTIVE;
1629 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
1630 	uint32_t		interval = 0;
1631 	char			unit = '\0';
1632 	show_state_t		state;
1633 	dladm_status_t		status;
1634 	char			*fields_str = NULL;
1635 	char			*o_fields_str = NULL;
1636 
1637 	char			*total_stat_fields =
1638 	    "link,ipkts,rbytes,opkts,obytes";
1639 	char			*rx_total_stat_fields =
1640 	    "link,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50";
1641 	char			*tx_total_stat_fields =
1642 	    "link,opkts,obytes,blkcnt,ublkcnt";
1643 
1644 	ofmt_handle_t		ofmt;
1645 	ofmt_status_t		oferr;
1646 	uint_t			ofmtflags = OFMT_RIGHTJUST;
1647 	ofmt_field_t		*oftemplate;
1648 
1649 	bzero(&state, sizeof (state));
1650 	opterr = 0;
1651 	while ((option = getopt_long(argc, argv, ":rtaApi:o:u:",
1652 	    NULL, NULL)) != -1) {
1653 		switch (option) {
1654 		case 'r':
1655 			if (r_arg)
1656 				die_optdup(option);
1657 
1658 			r_arg = B_TRUE;
1659 			break;
1660 		case 't':
1661 			if (t_arg)
1662 				die_optdup(option);
1663 
1664 			t_arg = B_TRUE;
1665 			break;
1666 		case 'a':
1667 			if (a_arg)
1668 				die_optdup(option);
1669 
1670 			a_arg = B_TRUE;
1671 			break;
1672 		case 'A':
1673 			if (A_arg)
1674 				die_optdup(option);
1675 
1676 			A_arg = B_TRUE;
1677 			break;
1678 		case 'i':
1679 			if (i_arg)
1680 				die_optdup(option);
1681 
1682 			i_arg = B_TRUE;
1683 			if (!dladm_str2interval(optarg, &interval))
1684 				die("invalid interval value '%s'", optarg);
1685 			break;
1686 		case 'p':
1687 			if (p_arg)
1688 				die_optdup(option);
1689 
1690 			p_arg = B_TRUE;
1691 			break;
1692 		case 'o':
1693 			o_arg = B_TRUE;
1694 			o_fields_str = optarg;
1695 			break;
1696 		case 'u':
1697 			if (u_arg)
1698 				die_optdup(option);
1699 
1700 			u_arg = B_TRUE;
1701 			if (!dlstat_unit(optarg, &unit))
1702 				die("invalid unit value '%s',"
1703 				    "unit must be R|K|M|G|T|P", optarg);
1704 			break;
1705 		default:
1706 			die_opterr(optopt, option, use);
1707 			break;
1708 		}
1709 	}
1710 
1711 	if (r_arg && t_arg)
1712 		die("the options -t and -r are not compatible");
1713 
1714 	if (u_arg && p_arg)
1715 		die("the options -u and -p are not compatible");
1716 
1717 	if (p_arg && !o_arg)
1718 		die("-p requires -o");
1719 
1720 	if (p_arg && strcasecmp(o_fields_str, "all") == 0)
1721 		die("\"-o all\" is invalid with -p");
1722 
1723 	if (a_arg && A_arg)
1724 		die("the options -a and -A are not compatible");
1725 
1726 	if (a_arg &&
1727 	    (p_arg || o_arg || u_arg || i_arg)) {
1728 		die("the option -a is not compatible with "
1729 		    "-p, -o, -u, -i");
1730 	}
1731 
1732 	if (A_arg &&
1733 	    (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg)) {
1734 		die("the option -A is not compatible with "
1735 		    "-r, -t, -p, -o, -u, -i");
1736 	}
1737 
1738 	/* get link name (optional last argument) */
1739 	if (optind == (argc-1)) {
1740 		if (strlen(argv[optind]) >= MAXLINKNAMELEN)
1741 			die("link name too long");
1742 
1743 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
1744 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
1745 			die_dlerr(status, "link %s is not valid", argv[optind]);
1746 		}
1747 	} else if (optind != argc) {
1748 		if (argc != 0)
1749 			usage();
1750 	}
1751 
1752 	if (a_arg) {
1753 		boolean_t	stattype[DLADM_STAT_NUM_STATS];
1754 
1755 		bzero(&stattype, sizeof (stattype));
1756 		if (r_arg) {
1757 			stattype[DLADM_STAT_RX_LANE_TOTAL] = B_TRUE;
1758 		} else if (t_arg) {
1759 			stattype[DLADM_STAT_TX_LANE_TOTAL] = B_TRUE;
1760 		} else {		/* Display both Rx and Tx lanes */
1761 			stattype[DLADM_STAT_TOTAL] = B_TRUE;
1762 		}
1763 
1764 		dump_all_link_stats(linkid, stattype);
1765 		return;
1766 	}
1767 
1768 	if (A_arg) {
1769 		boolean_t	stattype[DLADM_STAT_NUM_STATS];
1770 		int		i;
1771 
1772 		for (i = 0; i < DLADM_STAT_NUM_STATS; i++)
1773 			stattype[i] = B_TRUE;
1774 
1775 		dump_all_link_stats(linkid, stattype);
1776 		return;
1777 	}
1778 
1779 	state.ls_unit = unit;
1780 	state.ls_parsable = p_arg;
1781 
1782 	if (state.ls_parsable)
1783 		ofmtflags |= OFMT_PARSABLE;
1784 
1785 	if (r_arg) {
1786 		fields_str = rx_total_stat_fields;
1787 		oftemplate = rx_lane_s_fields;
1788 		state.ls_stattype[DLADM_STAT_RX_LANE_TOTAL] = B_TRUE;
1789 		state.ls_stats2str[DLADM_STAT_RX_LANE_TOTAL] =
1790 		    print_rx_lane_stats;
1791 	} else if (t_arg) {
1792 		fields_str = tx_total_stat_fields;
1793 		oftemplate = tx_lane_s_fields;
1794 		state.ls_stattype[DLADM_STAT_TX_LANE_TOTAL] = B_TRUE;
1795 		state.ls_stats2str[DLADM_STAT_TX_LANE_TOTAL] =
1796 		    print_tx_lane_stats;
1797 	} else {		/* Display both Rx and Tx lanes total */
1798 		fields_str = total_stat_fields;
1799 		oftemplate = total_s_fields;
1800 		state.ls_stattype[DLADM_STAT_TOTAL] = B_TRUE;
1801 		state.ls_stats2str[DLADM_STAT_TOTAL] = print_total_stats;
1802 	}
1803 
1804 	if (o_arg) {
1805 		fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
1806 		    fields_str : o_fields_str;
1807 	}
1808 
1809 	oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
1810 	ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
1811 	state.ls_ofmt = ofmt;
1812 
1813 	show_link_stats(linkid, state, interval);
1814 
1815 	ofmt_close(ofmt);
1816 }
1817 
1818 static void
do_show_phys(int argc,char * argv[],const char * use)1819 do_show_phys(int argc, char *argv[], const char *use)
1820 {
1821 	int			option;
1822 	boolean_t		r_arg = B_FALSE;
1823 	boolean_t		t_arg = B_FALSE;
1824 	boolean_t		i_arg = B_FALSE;
1825 	boolean_t		p_arg = B_FALSE;
1826 	boolean_t		o_arg = B_FALSE;
1827 	boolean_t		u_arg = B_FALSE;
1828 	boolean_t		a_arg = B_FALSE;
1829 	uint32_t		flags = DLADM_OPT_ACTIVE;
1830 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
1831 	char			linkname[MAXLINKNAMELEN];
1832 	uint32_t		interval = 0;
1833 	char			unit = '\0';
1834 	show_state_t		state;
1835 	dladm_status_t		status;
1836 	char			*fields_str = NULL;
1837 	char			*o_fields_str = NULL;
1838 	char			*ring_stat_fields =
1839 	    "link,type,index,pkts,bytes";
1840 	char			*rx_ring_stat_fields =
1841 	    "link,type,index,ipkts,rbytes";
1842 	char			*tx_ring_stat_fields =
1843 	    "link,type,index,opkts,obytes";
1844 
1845 	ofmt_handle_t		ofmt;
1846 	ofmt_status_t		oferr;
1847 	uint_t			ofmtflags = OFMT_RIGHTJUST;
1848 	ofmt_field_t		*oftemplate;
1849 
1850 	bzero(&state, sizeof (state));
1851 	opterr = 0;
1852 	while ((option = getopt_long(argc, argv, ":rtapi:o:u:",
1853 	    NULL, NULL)) != -1) {
1854 		switch (option) {
1855 		case 'r':
1856 			if (r_arg)
1857 				die_optdup(option);
1858 
1859 			r_arg = B_TRUE;
1860 			break;
1861 		case 't':
1862 			if (t_arg)
1863 				die_optdup(option);
1864 
1865 			t_arg = B_TRUE;
1866 			break;
1867 		case 'a':
1868 			if (a_arg)
1869 				die_optdup(option);
1870 
1871 			a_arg = B_TRUE;
1872 			break;
1873 		case 'i':
1874 			if (i_arg)
1875 				die_optdup(option);
1876 
1877 			i_arg = B_TRUE;
1878 			if (!dladm_str2interval(optarg, &interval))
1879 				die("invalid interval value '%s'", optarg);
1880 			break;
1881 		case 'p':
1882 			if (p_arg)
1883 				die_optdup(option);
1884 
1885 			p_arg = B_TRUE;
1886 			break;
1887 		case 'o':
1888 			o_arg = B_TRUE;
1889 			o_fields_str = optarg;
1890 			break;
1891 		case 'u':
1892 			if (u_arg)
1893 				die_optdup(option);
1894 
1895 			u_arg = B_TRUE;
1896 			if (!dlstat_unit(optarg, &unit))
1897 				die("invalid unit value '%s',"
1898 				    "unit must be R|K|M|G|T|P", optarg);
1899 			break;
1900 		default:
1901 			die_opterr(optopt, option, use);
1902 			break;
1903 		}
1904 	}
1905 
1906 	if (r_arg && t_arg)
1907 		die("the options -t and -r are not compatible");
1908 
1909 	if (u_arg && p_arg)
1910 		die("the options -u and -p are not compatible");
1911 
1912 	if (p_arg && !o_arg)
1913 		die("-p requires -o");
1914 
1915 	if (p_arg && strcasecmp(o_fields_str, "all") == 0)
1916 		die("\"-o all\" is invalid with -p");
1917 
1918 	if (a_arg &&
1919 	    (p_arg || o_arg || u_arg || i_arg)) {
1920 		die("the option -a is not compatible with "
1921 		    "-p, -o, -u, -i");
1922 	}
1923 
1924 
1925 	/* get link name (optional last argument) */
1926 	if (optind == (argc-1)) {
1927 		if (strlen(argv[optind]) >= MAXLINKNAMELEN)
1928 			die("link name too long");
1929 
1930 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
1931 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
1932 			die_dlerr(status, "link %s is not valid", argv[optind]);
1933 		}
1934 	} else if (optind != argc) {
1935 		usage();
1936 	}
1937 
1938 	if (a_arg) {
1939 		boolean_t	stattype[DLADM_STAT_NUM_STATS];
1940 
1941 		bzero(&stattype, sizeof (stattype));
1942 
1943 		if (r_arg) {
1944 			stattype[DLADM_STAT_RX_RING] = B_TRUE;
1945 		} else if (t_arg) {
1946 			stattype[DLADM_STAT_TX_RING] = B_TRUE;
1947 		} else {		/* Display both Rx and Tx lanes */
1948 			stattype[DLADM_STAT_RX_RING] = B_TRUE;
1949 			stattype[DLADM_STAT_TX_RING] = B_TRUE;
1950 		}
1951 
1952 		dump_all_link_stats(linkid, stattype);
1953 		return;
1954 	}
1955 
1956 	state.ls_unit = unit;
1957 	state.ls_parsable = p_arg;
1958 
1959 	if (state.ls_parsable)
1960 		ofmtflags |= OFMT_PARSABLE;
1961 
1962 	if (r_arg) {
1963 		fields_str = rx_ring_stat_fields;
1964 		oftemplate = rx_ring_s_fields;
1965 		state.ls_stattype[DLADM_STAT_RX_RING] = B_TRUE;
1966 		state.ls_stats2str[DLADM_STAT_RX_RING] = print_rx_ring_stats;
1967 	} else if (t_arg) {
1968 		fields_str = tx_ring_stat_fields;
1969 		oftemplate = tx_ring_s_fields;
1970 		state.ls_stattype[DLADM_STAT_TX_RING] = B_TRUE;
1971 		state.ls_stats2str[DLADM_STAT_TX_RING] = print_tx_ring_stats;
1972 	} else {		/* Display both Rx and Tx lanes */
1973 		fields_str = ring_stat_fields;
1974 		oftemplate = ring_s_fields;
1975 		state.ls_stattype[DLADM_STAT_RX_RING] = B_TRUE;
1976 		state.ls_stattype[DLADM_STAT_TX_RING] = B_TRUE;
1977 		state.ls_stats2str[DLADM_STAT_RX_RING] =
1978 		    print_rx_generic_ring_stats;
1979 		state.ls_stats2str[DLADM_STAT_TX_RING] =
1980 		    print_tx_generic_ring_stats;
1981 	}
1982 
1983 	if (o_arg) {
1984 		fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
1985 		    fields_str : o_fields_str;
1986 	}
1987 
1988 	oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
1989 	ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
1990 	state.ls_ofmt = ofmt;
1991 
1992 	show_link_stats(linkid, state, interval);
1993 
1994 	ofmt_close(ofmt);
1995 }
1996 
1997 static void
do_show_link(int argc,char * argv[],const char * use)1998 do_show_link(int argc, char *argv[], const char *use)
1999 {
2000 	int			option;
2001 	boolean_t		r_arg = B_FALSE;
2002 	boolean_t		F_arg = B_FALSE;
2003 	boolean_t		t_arg = B_FALSE;
2004 	boolean_t		i_arg = B_FALSE;
2005 	boolean_t		p_arg = B_FALSE;
2006 	boolean_t		o_arg = B_FALSE;
2007 	boolean_t		u_arg = B_FALSE;
2008 	boolean_t		a_arg = B_FALSE;
2009 	uint32_t		flags = DLADM_OPT_ACTIVE;
2010 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
2011 	uint32_t		interval = 0;
2012 	char			unit = '\0';
2013 	show_state_t		state;
2014 	dladm_status_t		status;
2015 	char			*fields_str = NULL;
2016 	char			*o_fields_str = NULL;
2017 
2018 	char			*lane_stat_fields =
2019 	    "link,type,id,index,pkts,bytes";
2020 	char			*rx_lane_stat_fields =
2021 	    "link,type,id,index,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50";
2022 	char			*tx_lane_stat_fields =
2023 	    "link,type,id,index,opkts,obytes,blkcnt,ublkcnt";
2024 	char			*rx_fanout_stat_fields =
2025 	    "link,id,index,fout,ipkts,rbytes";
2026 
2027 	ofmt_handle_t		ofmt;
2028 	ofmt_status_t		oferr;
2029 	uint_t			ofmtflags = OFMT_RIGHTJUST;
2030 	ofmt_field_t		*oftemplate;
2031 
2032 	bzero(&state, sizeof (state));
2033 	opterr = 0;
2034 	while ((option = getopt_long(argc, argv, ":hrtFapi:o:u:",
2035 	    NULL, NULL)) != -1) {
2036 		switch (option) {
2037 		case 'h':
2038 			if (r_arg || F_arg || t_arg || i_arg || p_arg ||
2039 			    o_arg || u_arg || a_arg) {
2040 				die("the option -h is not compatible with "
2041 				    "-r, -F, -t, -i, -p, -o, -u, -a");
2042 			}
2043 			do_show_history(argc, &argv[0], use);
2044 			return;
2045 		case 'r':
2046 			if (r_arg)
2047 				die_optdup(option);
2048 
2049 			r_arg = B_TRUE;
2050 			break;
2051 		case 'F':
2052 			if (F_arg)
2053 				die_optdup(option);
2054 
2055 			F_arg = B_TRUE;
2056 			break;
2057 		case 't':
2058 			if (t_arg)
2059 				die_optdup(option);
2060 
2061 			t_arg = B_TRUE;
2062 			break;
2063 		case 'a':
2064 			if (a_arg)
2065 				die_optdup(option);
2066 
2067 			a_arg = B_TRUE;
2068 			break;
2069 		case 'i':
2070 			if (i_arg)
2071 				die_optdup(option);
2072 
2073 			i_arg = B_TRUE;
2074 			if (!dladm_str2interval(optarg, &interval))
2075 				die("invalid interval value '%s'", optarg);
2076 			break;
2077 		case 'p':
2078 			if (p_arg)
2079 				die_optdup(option);
2080 
2081 			p_arg = B_TRUE;
2082 			break;
2083 		case 'o':
2084 			o_arg = B_TRUE;
2085 			o_fields_str = optarg;
2086 			break;
2087 		case 'u':
2088 			if (u_arg)
2089 				die_optdup(option);
2090 
2091 			u_arg = B_TRUE;
2092 			if (!dlstat_unit(optarg, &unit))
2093 				die("invalid unit value '%s',"
2094 				    "unit must be R|K|M|G|T|P", optarg);
2095 			break;
2096 		default:
2097 			die_opterr(optopt, option, use);
2098 			break;
2099 		}
2100 	}
2101 
2102 	if (r_arg && t_arg)
2103 		die("the options -t and -r are not compatible");
2104 
2105 	if (u_arg && p_arg)
2106 		die("the options -u and -p are not compatible");
2107 
2108 	if (F_arg && !r_arg)
2109 		die("-F must be used with -r");
2110 
2111 	if (p_arg && !o_arg)
2112 		die("-p requires -o");
2113 
2114 	if (p_arg && strcasecmp(o_fields_str, "all") == 0)
2115 		die("\"-o all\" is invalid with -p");
2116 
2117 	if (a_arg &&
2118 	    (p_arg || o_arg || u_arg || i_arg)) {
2119 		die("the option -a is not compatible with "
2120 		    "-p, -o, -u, -i");
2121 	}
2122 
2123 	/* get link name (optional last argument) */
2124 	if (optind == (argc-1)) {
2125 		if (strlen(argv[optind]) >= MAXLINKNAMELEN)
2126 			die("link name too long");
2127 
2128 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
2129 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
2130 			die_dlerr(status, "link %s is not valid", argv[optind]);
2131 		}
2132 	} else if (optind != argc) {
2133 		usage();
2134 	}
2135 
2136 	if (a_arg) {
2137 		boolean_t	stattype[DLADM_STAT_NUM_STATS];
2138 
2139 		bzero(&stattype, sizeof (stattype));
2140 
2141 		if (r_arg) {
2142 			if (F_arg) {
2143 				stattype[DLADM_STAT_RX_LANE_FOUT] = B_TRUE;
2144 			} else {
2145 				stattype[DLADM_STAT_RX_LANE] = B_TRUE;
2146 			}
2147 		} else if (t_arg) {
2148 			stattype[DLADM_STAT_TX_LANE] = B_TRUE;
2149 		} else {		/* Display both Rx and Tx lanes */
2150 			stattype[DLADM_STAT_RX_LANE] = B_TRUE;
2151 			stattype[DLADM_STAT_TX_LANE] = B_TRUE;
2152 		}
2153 
2154 		dump_all_link_stats(linkid, stattype);
2155 		return;
2156 	}
2157 
2158 	state.ls_unit = unit;
2159 	state.ls_parsable = p_arg;
2160 
2161 	if (state.ls_parsable)
2162 		ofmtflags |= OFMT_PARSABLE;
2163 
2164 	if (r_arg) {
2165 		if (F_arg) {
2166 			fields_str = rx_fanout_stat_fields;
2167 			oftemplate = rx_fanout_lane_s_fields;
2168 			state.ls_stattype[DLADM_STAT_RX_LANE_FOUT] = B_TRUE;
2169 			state.ls_stats2str[DLADM_STAT_RX_LANE_FOUT] =
2170 			    print_fanout_stats;
2171 		} else {
2172 			fields_str = rx_lane_stat_fields;
2173 			oftemplate = rx_lane_s_fields;
2174 			state.ls_stattype[DLADM_STAT_RX_LANE] = B_TRUE;
2175 			state.ls_stats2str[DLADM_STAT_RX_LANE] =
2176 			    print_rx_lane_stats;
2177 		}
2178 	} else if (t_arg) {
2179 		fields_str = tx_lane_stat_fields;
2180 		oftemplate = tx_lane_s_fields;
2181 		state.ls_stattype[DLADM_STAT_TX_LANE] = B_TRUE;
2182 		state.ls_stats2str[DLADM_STAT_TX_LANE] = print_tx_lane_stats;
2183 	} else {		/* Display both Rx and Tx lanes */
2184 		fields_str = lane_stat_fields;
2185 		oftemplate = lane_s_fields;
2186 		state.ls_stattype[DLADM_STAT_RX_LANE] = B_TRUE;
2187 		state.ls_stattype[DLADM_STAT_TX_LANE] = B_TRUE;
2188 		state.ls_stats2str[DLADM_STAT_RX_LANE] =
2189 		    print_rx_generic_lane_stats;
2190 		state.ls_stats2str[DLADM_STAT_TX_LANE] =
2191 		    print_tx_generic_lane_stats;
2192 	}
2193 	if (o_arg) {
2194 		fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
2195 		    fields_str : o_fields_str;
2196 	}
2197 
2198 	oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
2199 	ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
2200 
2201 	state.ls_ofmt = ofmt;
2202 
2203 	show_link_stats(linkid, state, interval);
2204 
2205 	ofmt_close(ofmt);
2206 }
2207 
2208 static void
do_show_aggr(int argc,char * argv[],const char * use)2209 do_show_aggr(int argc, char *argv[], const char *use)
2210 {
2211 	int			option;
2212 	boolean_t		r_arg = B_FALSE;
2213 	boolean_t		t_arg = B_FALSE;
2214 	boolean_t		i_arg = B_FALSE;
2215 	boolean_t		p_arg = B_FALSE;
2216 	boolean_t		o_arg = B_FALSE;
2217 	boolean_t		u_arg = B_FALSE;
2218 	uint32_t		flags = DLADM_OPT_ACTIVE;
2219 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
2220 	uint32_t		interval = 0;
2221 	char			unit = '\0';
2222 	show_state_t		state;
2223 	dladm_status_t		status;
2224 	char			*fields_str = NULL;
2225 	char			*o_fields_str = NULL;
2226 
2227 	char			*aggr_stat_fields =
2228 	    "link,port,ipkts,rbytes,opkts,obytes";
2229 	char			*rx_aggr_stat_fields = "link,port,ipkts,rbytes";
2230 	char			*tx_aggr_stat_fields = "link,port,opkts,obytes";
2231 
2232 	ofmt_handle_t		ofmt;
2233 	ofmt_status_t		oferr;
2234 	uint_t			ofmtflags = OFMT_RIGHTJUST;
2235 	ofmt_field_t		*oftemplate;
2236 
2237 	bzero(&state, sizeof (state));
2238 	opterr = 0;
2239 	while ((option = getopt_long(argc, argv, ":rtpi:o:u:",
2240 	    NULL, NULL)) != -1) {
2241 		switch (option) {
2242 		case 'r':
2243 			if (r_arg)
2244 				die_optdup(option);
2245 
2246 			r_arg = B_TRUE;
2247 			break;
2248 		case 't':
2249 			if (t_arg)
2250 				die_optdup(option);
2251 
2252 			t_arg = B_TRUE;
2253 			break;
2254 		case 'i':
2255 			if (i_arg)
2256 				die_optdup(option);
2257 
2258 			i_arg = B_TRUE;
2259 			if (!dladm_str2interval(optarg, &interval))
2260 				die("invalid interval value '%s'", optarg);
2261 			break;
2262 		case 'p':
2263 			if (p_arg)
2264 				die_optdup(option);
2265 
2266 			p_arg = B_TRUE;
2267 			break;
2268 		case 'o':
2269 			o_arg = B_TRUE;
2270 			o_fields_str = optarg;
2271 			break;
2272 		case 'u':
2273 			if (u_arg)
2274 				die_optdup(option);
2275 
2276 			u_arg = B_TRUE;
2277 			if (!dlstat_unit(optarg, &unit))
2278 				die("invalid unit value '%s',"
2279 				    "unit must be R|K|M|G|T|P", optarg);
2280 			break;
2281 		default:
2282 			die_opterr(optopt, option, use);
2283 			break;
2284 		}
2285 	}
2286 
2287 	if (r_arg && t_arg)
2288 		die("the options -t and -r are not compatible");
2289 
2290 	if (u_arg && p_arg)
2291 		die("the options -u and -p are not compatible");
2292 
2293 	if (p_arg && !o_arg)
2294 		die("-p requires -o");
2295 
2296 	if (p_arg && strcasecmp(o_fields_str, "all") == 0)
2297 		die("\"-o all\" is invalid with -p");
2298 
2299 
2300 	/* get link name (optional last argument) */
2301 	if (optind == (argc-1)) {
2302 		if (strlen(argv[optind]) >= MAXLINKNAMELEN)
2303 			die("link name too long");
2304 
2305 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
2306 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
2307 			die_dlerr(status, "link %s is not valid", argv[optind]);
2308 		}
2309 	} else if (optind != argc) {
2310 		usage();
2311 	}
2312 
2313 	state.ls_unit = unit;
2314 	state.ls_parsable = p_arg;
2315 
2316 	if (state.ls_parsable)
2317 		ofmtflags |= OFMT_PARSABLE;
2318 
2319 	oftemplate = aggr_port_s_fields;
2320 	state.ls_stattype[DLADM_STAT_AGGR_PORT] = B_TRUE;
2321 	state.ls_stats2str[DLADM_STAT_AGGR_PORT] = print_aggr_port_stats;
2322 
2323 	if (r_arg)
2324 		fields_str = rx_aggr_stat_fields;
2325 	else if (t_arg)
2326 		fields_str = tx_aggr_stat_fields;
2327 	else
2328 		fields_str = aggr_stat_fields;
2329 
2330 	if (o_arg) {
2331 		fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
2332 		    fields_str : o_fields_str;
2333 	}
2334 
2335 	oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
2336 	ofmt_check(oferr, state.ls_parsable, ofmt, die, warn);
2337 	state.ls_ofmt = ofmt;
2338 
2339 	show_link_stats(linkid, state, interval);
2340 
2341 	ofmt_close(ofmt);
2342 }
2343 
2344 /* PRINTFLIKE1 */
2345 static void
warn(const char * format,...)2346 warn(const char *format, ...)
2347 {
2348 	va_list alist;
2349 
2350 	format = gettext(format);
2351 	(void) fprintf(stderr, "%s: warning: ", progname);
2352 
2353 	va_start(alist, format);
2354 	(void) vfprintf(stderr, format, alist);
2355 	va_end(alist);
2356 
2357 	(void) putc('\n', stderr);
2358 }
2359 
2360 /*
2361  * Also closes the dladm handle if it is not NULL.
2362  */
2363 /* PRINTFLIKE2 */
2364 static void
die_dlerr(dladm_status_t err,const char * format,...)2365 die_dlerr(dladm_status_t err, const char *format, ...)
2366 {
2367 	va_list alist;
2368 	char	errmsg[DLADM_STRSIZE];
2369 
2370 	format = gettext(format);
2371 	(void) fprintf(stderr, "%s: ", progname);
2372 
2373 	va_start(alist, format);
2374 	(void) vfprintf(stderr, format, alist);
2375 	va_end(alist);
2376 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
2377 
2378 	/* close dladm handle if it was opened */
2379 	if (handle != NULL)
2380 		dladm_close(handle);
2381 
2382 	exit(EXIT_FAILURE);
2383 }
2384 
2385 /* PRINTFLIKE1 */
2386 static void
die(const char * format,...)2387 die(const char *format, ...)
2388 {
2389 	va_list alist;
2390 
2391 	format = gettext(format);
2392 	(void) fprintf(stderr, "%s: ", progname);
2393 
2394 	va_start(alist, format);
2395 	(void) vfprintf(stderr, format, alist);
2396 	va_end(alist);
2397 
2398 	(void) putc('\n', stderr);
2399 
2400 	/* close dladm handle if it was opened */
2401 	if (handle != NULL)
2402 		dladm_close(handle);
2403 
2404 	exit(EXIT_FAILURE);
2405 }
2406 
2407 static void
die_optdup(int opt)2408 die_optdup(int opt)
2409 {
2410 	die("the option -%c cannot be specified more than once", opt);
2411 }
2412 
2413 static void
die_opterr(int opt,int opterr,const char * usage)2414 die_opterr(int opt, int opterr, const char *usage)
2415 {
2416 	switch (opterr) {
2417 	case ':':
2418 		die("option '-%c' requires a value\nusage: %s", opt,
2419 		    gettext(usage));
2420 		break;
2421 	case '?':
2422 	default:
2423 		die("unrecognized option '-%c'\nusage: %s", opt,
2424 		    gettext(usage));
2425 		break;
2426 	}
2427 }
2428 
2429 /*
2430  * default output callback function that, when invoked,
2431  * prints string which is offset by ofmt_arg->ofmt_id within buf.
2432  */
2433 static boolean_t
print_default_cb(ofmt_arg_t * ofarg,char * buf,uint_t bufsize)2434 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2435 {
2436 	char *value;
2437 
2438 	value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id;
2439 	(void) strlcpy(buf, value, bufsize);
2440 	return (B_TRUE);
2441 }
2442