xref: /titanic_50/usr/src/cmd/flowstat/flowstat.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
1*0dc2366fSVenugopal Iyer /*
2*0dc2366fSVenugopal Iyer  * CDDL HEADER START
3*0dc2366fSVenugopal Iyer  *
4*0dc2366fSVenugopal Iyer  * The contents of this file are subject to the terms of the
5*0dc2366fSVenugopal Iyer  * Common Development and Distribution License (the "License").
6*0dc2366fSVenugopal Iyer  * You may not use this file except in compliance with the License.
7*0dc2366fSVenugopal Iyer  *
8*0dc2366fSVenugopal Iyer  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*0dc2366fSVenugopal Iyer  * or http://www.opensolaris.org/os/licensing.
10*0dc2366fSVenugopal Iyer  * See the License for the specific language governing permissions
11*0dc2366fSVenugopal Iyer  * and limitations under the License.
12*0dc2366fSVenugopal Iyer  *
13*0dc2366fSVenugopal Iyer  * When distributing Covered Code, include this CDDL HEADER in each
14*0dc2366fSVenugopal Iyer  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*0dc2366fSVenugopal Iyer  * If applicable, add the following below this CDDL HEADER, with the
16*0dc2366fSVenugopal Iyer  * fields enclosed by brackets "[]" replaced with your own identifying
17*0dc2366fSVenugopal Iyer  * information: Portions Copyright [yyyy] [name of copyright owner]
18*0dc2366fSVenugopal Iyer  *
19*0dc2366fSVenugopal Iyer  * CDDL HEADER END
20*0dc2366fSVenugopal Iyer  */
21*0dc2366fSVenugopal Iyer /*
22*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23*0dc2366fSVenugopal Iyer  * Use is subject to license terms.
24*0dc2366fSVenugopal Iyer  */
25*0dc2366fSVenugopal Iyer 
26*0dc2366fSVenugopal Iyer #include <stdio.h>
27*0dc2366fSVenugopal Iyer #include <locale.h>
28*0dc2366fSVenugopal Iyer #include <stdarg.h>
29*0dc2366fSVenugopal Iyer #include <stdlib.h>
30*0dc2366fSVenugopal Iyer #include <fcntl.h>
31*0dc2366fSVenugopal Iyer #include <string.h>
32*0dc2366fSVenugopal Iyer #include <stropts.h>
33*0dc2366fSVenugopal Iyer #include <errno.h>
34*0dc2366fSVenugopal Iyer #include <strings.h>
35*0dc2366fSVenugopal Iyer #include <getopt.h>
36*0dc2366fSVenugopal Iyer #include <unistd.h>
37*0dc2366fSVenugopal Iyer #include <priv.h>
38*0dc2366fSVenugopal Iyer #include <netdb.h>
39*0dc2366fSVenugopal Iyer #include <libintl.h>
40*0dc2366fSVenugopal Iyer #include <libdlflow.h>
41*0dc2366fSVenugopal Iyer #include <libdllink.h>
42*0dc2366fSVenugopal Iyer #include <libdlstat.h>
43*0dc2366fSVenugopal Iyer #include <sys/types.h>
44*0dc2366fSVenugopal Iyer #include <sys/socket.h>
45*0dc2366fSVenugopal Iyer #include <netinet/in.h>
46*0dc2366fSVenugopal Iyer #include <arpa/inet.h>
47*0dc2366fSVenugopal Iyer #include <sys/ethernet.h>
48*0dc2366fSVenugopal Iyer #include <inet/ip.h>
49*0dc2366fSVenugopal Iyer #include <inet/ip6.h>
50*0dc2366fSVenugopal Iyer #include <stddef.h>
51*0dc2366fSVenugopal Iyer #include <ofmt.h>
52*0dc2366fSVenugopal Iyer 
53*0dc2366fSVenugopal Iyer typedef struct flow_chain_s {
54*0dc2366fSVenugopal Iyer 	char			fc_flowname[MAXFLOWNAMELEN];
55*0dc2366fSVenugopal Iyer 	boolean_t		fc_visited;
56*0dc2366fSVenugopal Iyer 	flow_stat_t		*fc_stat;
57*0dc2366fSVenugopal Iyer 	struct flow_chain_s	*fc_next;
58*0dc2366fSVenugopal Iyer } flow_chain_t;
59*0dc2366fSVenugopal Iyer 
60*0dc2366fSVenugopal Iyer typedef struct show_flow_state {
61*0dc2366fSVenugopal Iyer 	flow_chain_t	*fs_flowchain;
62*0dc2366fSVenugopal Iyer 	ofmt_handle_t	fs_ofmt;
63*0dc2366fSVenugopal Iyer 	char		fs_unit;
64*0dc2366fSVenugopal Iyer 	boolean_t	fs_parsable;
65*0dc2366fSVenugopal Iyer } show_flow_state_t;
66*0dc2366fSVenugopal Iyer 
67*0dc2366fSVenugopal Iyer typedef struct show_history_state_s {
68*0dc2366fSVenugopal Iyer 	boolean_t	us_plot;
69*0dc2366fSVenugopal Iyer 	boolean_t	us_parsable;
70*0dc2366fSVenugopal Iyer 	boolean_t	us_printheader;
71*0dc2366fSVenugopal Iyer 	boolean_t	us_first;
72*0dc2366fSVenugopal Iyer 	boolean_t	us_showall;
73*0dc2366fSVenugopal Iyer 	ofmt_handle_t	us_ofmt;
74*0dc2366fSVenugopal Iyer } show_history_state_t;
75*0dc2366fSVenugopal Iyer 
76*0dc2366fSVenugopal Iyer static void	do_show_history(int, char **);
77*0dc2366fSVenugopal Iyer 
78*0dc2366fSVenugopal Iyer static int	query_flow_stats(dladm_handle_t, dladm_flow_attr_t *, void *);
79*0dc2366fSVenugopal Iyer static int	query_link_flow_stats(dladm_handle_t, datalink_id_t, void *);
80*0dc2366fSVenugopal Iyer 
81*0dc2366fSVenugopal Iyer static void	die(const char *, ...);
82*0dc2366fSVenugopal Iyer static void	die_optdup(int);
83*0dc2366fSVenugopal Iyer static void	die_opterr(int, int, const char *);
84*0dc2366fSVenugopal Iyer static void	die_dlerr(dladm_status_t, const char *, ...);
85*0dc2366fSVenugopal Iyer static void	warn(const char *, ...);
86*0dc2366fSVenugopal Iyer 
87*0dc2366fSVenugopal Iyer /* callback functions for printing output */
88*0dc2366fSVenugopal Iyer static ofmt_cb_t print_default_cb, print_flow_stats_cb;
89*0dc2366fSVenugopal Iyer static void flowstat_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
90*0dc2366fSVenugopal Iyer 
91*0dc2366fSVenugopal Iyer #define	NULL_OFMT		{NULL, 0, 0, NULL}
92*0dc2366fSVenugopal Iyer 
93*0dc2366fSVenugopal Iyer /*
94*0dc2366fSVenugopal Iyer  * structures for flowstat (printing live statistics)
95*0dc2366fSVenugopal Iyer  */
96*0dc2366fSVenugopal Iyer typedef enum {
97*0dc2366fSVenugopal Iyer 	FLOW_S_FLOW,
98*0dc2366fSVenugopal Iyer 	FLOW_S_IPKTS,
99*0dc2366fSVenugopal Iyer 	FLOW_S_RBYTES,
100*0dc2366fSVenugopal Iyer 	FLOW_S_IERRORS,
101*0dc2366fSVenugopal Iyer 	FLOW_S_OPKTS,
102*0dc2366fSVenugopal Iyer 	FLOW_S_OBYTES,
103*0dc2366fSVenugopal Iyer 	FLOW_S_OERRORS
104*0dc2366fSVenugopal Iyer } flow_s_field_index_t;
105*0dc2366fSVenugopal Iyer 
106*0dc2366fSVenugopal Iyer static ofmt_field_t flow_s_fields[] = {
107*0dc2366fSVenugopal Iyer /* name,	field width,	index,		callback */
108*0dc2366fSVenugopal Iyer { "FLOW",	15,	FLOW_S_FLOW,	print_flow_stats_cb},
109*0dc2366fSVenugopal Iyer { "IPKTS",	8,	FLOW_S_IPKTS,	print_flow_stats_cb},
110*0dc2366fSVenugopal Iyer { "RBYTES",	8,	FLOW_S_RBYTES,	print_flow_stats_cb},
111*0dc2366fSVenugopal Iyer { "IERRS",	8,	FLOW_S_IERRORS,	print_flow_stats_cb},
112*0dc2366fSVenugopal Iyer { "OPKTS",	8,	FLOW_S_OPKTS,	print_flow_stats_cb},
113*0dc2366fSVenugopal Iyer { "OBYTES",	8,	FLOW_S_OBYTES,	print_flow_stats_cb},
114*0dc2366fSVenugopal Iyer { "OERRS",	8,	FLOW_S_OERRORS,	print_flow_stats_cb},
115*0dc2366fSVenugopal Iyer NULL_OFMT}
116*0dc2366fSVenugopal Iyer ;
117*0dc2366fSVenugopal Iyer 
118*0dc2366fSVenugopal Iyer typedef struct flow_args_s {
119*0dc2366fSVenugopal Iyer 	char		*flow_s_flow;
120*0dc2366fSVenugopal Iyer 	flow_stat_t	*flow_s_stat;
121*0dc2366fSVenugopal Iyer 	char		flow_s_unit;
122*0dc2366fSVenugopal Iyer 	boolean_t	flow_s_parsable;
123*0dc2366fSVenugopal Iyer } flow_args_t;
124*0dc2366fSVenugopal Iyer 
125*0dc2366fSVenugopal Iyer /*
126*0dc2366fSVenugopal Iyer  * structures for 'flowstat -h'
127*0dc2366fSVenugopal Iyer  */
128*0dc2366fSVenugopal Iyer typedef struct  history_fields_buf_s {
129*0dc2366fSVenugopal Iyer 	char	history_flow[12];
130*0dc2366fSVenugopal Iyer 	char	history_duration[10];
131*0dc2366fSVenugopal Iyer 	char	history_ipackets[9];
132*0dc2366fSVenugopal Iyer 	char	history_rbytes[10];
133*0dc2366fSVenugopal Iyer 	char	history_opackets[9];
134*0dc2366fSVenugopal Iyer 	char	history_obytes[10];
135*0dc2366fSVenugopal Iyer 	char	history_bandwidth[14];
136*0dc2366fSVenugopal Iyer } history_fields_buf_t;
137*0dc2366fSVenugopal Iyer 
138*0dc2366fSVenugopal Iyer static ofmt_field_t history_fields[] = {
139*0dc2366fSVenugopal Iyer /* name,	field width,	offset */
140*0dc2366fSVenugopal Iyer { "FLOW",	13,
141*0dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_flow), print_default_cb},
142*0dc2366fSVenugopal Iyer { "DURATION",	11,
143*0dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_duration), print_default_cb},
144*0dc2366fSVenugopal Iyer { "IPACKETS",	10,
145*0dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_ipackets), print_default_cb},
146*0dc2366fSVenugopal Iyer { "RBYTES",	11,
147*0dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_rbytes), print_default_cb},
148*0dc2366fSVenugopal Iyer { "OPACKETS",	10,
149*0dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_opackets), print_default_cb},
150*0dc2366fSVenugopal Iyer { "OBYTES",	11,
151*0dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_obytes), print_default_cb},
152*0dc2366fSVenugopal Iyer { "BANDWIDTH",	15,
153*0dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_bandwidth), print_default_cb},
154*0dc2366fSVenugopal Iyer NULL_OFMT}
155*0dc2366fSVenugopal Iyer ;
156*0dc2366fSVenugopal Iyer 
157*0dc2366fSVenugopal Iyer typedef struct  history_l_fields_buf_s {
158*0dc2366fSVenugopal Iyer 	char	history_l_flow[12];
159*0dc2366fSVenugopal Iyer 	char	history_l_stime[13];
160*0dc2366fSVenugopal Iyer 	char	history_l_etime[13];
161*0dc2366fSVenugopal Iyer 	char	history_l_rbytes[8];
162*0dc2366fSVenugopal Iyer 	char	history_l_obytes[8];
163*0dc2366fSVenugopal Iyer 	char	history_l_bandwidth[14];
164*0dc2366fSVenugopal Iyer } history_l_fields_buf_t;
165*0dc2366fSVenugopal Iyer 
166*0dc2366fSVenugopal Iyer static ofmt_field_t history_l_fields[] = {
167*0dc2366fSVenugopal Iyer /* name,	field width,	offset */
168*0dc2366fSVenugopal Iyer { "FLOW",	13,
169*0dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_flow), print_default_cb},
170*0dc2366fSVenugopal Iyer { "START",	14,
171*0dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_stime), print_default_cb},
172*0dc2366fSVenugopal Iyer { "END",	14,
173*0dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_etime), print_default_cb},
174*0dc2366fSVenugopal Iyer { "RBYTES",	9,
175*0dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_rbytes), print_default_cb},
176*0dc2366fSVenugopal Iyer { "OBYTES",	9,
177*0dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_obytes), print_default_cb},
178*0dc2366fSVenugopal Iyer { "BANDWIDTH",	15,
179*0dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_bandwidth),
180*0dc2366fSVenugopal Iyer 	    print_default_cb},
181*0dc2366fSVenugopal Iyer NULL_OFMT}
182*0dc2366fSVenugopal Iyer ;
183*0dc2366fSVenugopal Iyer 
184*0dc2366fSVenugopal Iyer static char *progname;
185*0dc2366fSVenugopal Iyer 
186*0dc2366fSVenugopal Iyer /*
187*0dc2366fSVenugopal Iyer  * Handle to libdladm.  Opened in main() before the sub-command
188*0dc2366fSVenugopal Iyer  * specific function is called.
189*0dc2366fSVenugopal Iyer  */
190*0dc2366fSVenugopal Iyer static dladm_handle_t handle = NULL;
191*0dc2366fSVenugopal Iyer 
192*0dc2366fSVenugopal Iyer const char *usage_ermsg = "flowstat [-r | -t] [-i interval] "
193*0dc2366fSVenugopal Iyer 	    "[-l link] [flow]\n"
194*0dc2366fSVenugopal Iyer 	    "       flowstat [-S] [-A] [-i interval] [-p] [ -o field[,...]]\n"
195*0dc2366fSVenugopal Iyer 	    "                [-u R|K|M|G|T|P] [-l link] [flow]\n"
196*0dc2366fSVenugopal Iyer 	    "       flowstat -h [-a] [-d] [-F format]"
197*0dc2366fSVenugopal Iyer 	    " [-s <DD/MM/YYYY,HH:MM:SS>]\n"
198*0dc2366fSVenugopal Iyer 	    "                [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> "
199*0dc2366fSVenugopal Iyer 	    "[<flow>]";
200*0dc2366fSVenugopal Iyer 
201*0dc2366fSVenugopal Iyer static void
202*0dc2366fSVenugopal Iyer usage(void)
203*0dc2366fSVenugopal Iyer {
204*0dc2366fSVenugopal Iyer 	(void) fprintf(stderr, "%s\n", gettext(usage_ermsg));
205*0dc2366fSVenugopal Iyer 
206*0dc2366fSVenugopal Iyer 	/* close dladm handle if it was opened */
207*0dc2366fSVenugopal Iyer 	if (handle != NULL)
208*0dc2366fSVenugopal Iyer 		dladm_close(handle);
209*0dc2366fSVenugopal Iyer 
210*0dc2366fSVenugopal Iyer 	exit(1);
211*0dc2366fSVenugopal Iyer }
212*0dc2366fSVenugopal Iyer 
213*0dc2366fSVenugopal Iyer boolean_t
214*0dc2366fSVenugopal Iyer flowstat_unit(char *oarg, char *unit)
215*0dc2366fSVenugopal Iyer {
216*0dc2366fSVenugopal Iyer 	if ((strcmp(oarg, "R") == 0) || (strcmp(oarg, "K") == 0) ||
217*0dc2366fSVenugopal Iyer 	    (strcmp(oarg, "M") == 0) || (strcmp(oarg, "G") == 0) ||
218*0dc2366fSVenugopal Iyer 	    (strcmp(oarg, "T") == 0) || (strcmp(oarg, "P") == 0)) {
219*0dc2366fSVenugopal Iyer 		*unit = oarg[0];
220*0dc2366fSVenugopal Iyer 		return (B_TRUE);
221*0dc2366fSVenugopal Iyer 	}
222*0dc2366fSVenugopal Iyer 
223*0dc2366fSVenugopal Iyer 	return (B_FALSE);
224*0dc2366fSVenugopal Iyer }
225*0dc2366fSVenugopal Iyer 
226*0dc2366fSVenugopal Iyer void
227*0dc2366fSVenugopal Iyer map_to_units(char *buf, uint_t bufsize, double num, char unit,
228*0dc2366fSVenugopal Iyer     boolean_t parsable)
229*0dc2366fSVenugopal Iyer {
230*0dc2366fSVenugopal Iyer 	if (parsable) {
231*0dc2366fSVenugopal Iyer 		(void) snprintf(buf, bufsize, "%.0lf", num);
232*0dc2366fSVenugopal Iyer 		return;
233*0dc2366fSVenugopal Iyer 	}
234*0dc2366fSVenugopal Iyer 
235*0dc2366fSVenugopal Iyer 	if (unit == '\0') {
236*0dc2366fSVenugopal Iyer 		int index;
237*0dc2366fSVenugopal Iyer 
238*0dc2366fSVenugopal Iyer 		for (index = 0; (int)(num/1000) != 0; index++, num /= 1000)
239*0dc2366fSVenugopal Iyer 			;
240*0dc2366fSVenugopal Iyer 
241*0dc2366fSVenugopal Iyer 		switch (index) {
242*0dc2366fSVenugopal Iyer 			case 0:
243*0dc2366fSVenugopal Iyer 				unit = '\0';
244*0dc2366fSVenugopal Iyer 				break;
245*0dc2366fSVenugopal Iyer 			case 1:
246*0dc2366fSVenugopal Iyer 				unit = 'K';
247*0dc2366fSVenugopal Iyer 				break;
248*0dc2366fSVenugopal Iyer 			case 2:
249*0dc2366fSVenugopal Iyer 				unit = 'M';
250*0dc2366fSVenugopal Iyer 				break;
251*0dc2366fSVenugopal Iyer 			case 3:
252*0dc2366fSVenugopal Iyer 				unit = 'G';
253*0dc2366fSVenugopal Iyer 				break;
254*0dc2366fSVenugopal Iyer 			case 4:
255*0dc2366fSVenugopal Iyer 				unit = 'T';
256*0dc2366fSVenugopal Iyer 				break;
257*0dc2366fSVenugopal Iyer 			case 5:
258*0dc2366fSVenugopal Iyer 				/* Largest unit supported */
259*0dc2366fSVenugopal Iyer 			default:
260*0dc2366fSVenugopal Iyer 				unit = 'P';
261*0dc2366fSVenugopal Iyer 				break;
262*0dc2366fSVenugopal Iyer 		}
263*0dc2366fSVenugopal Iyer 	} else  {
264*0dc2366fSVenugopal Iyer 		switch (unit) {
265*0dc2366fSVenugopal Iyer 			case 'R':
266*0dc2366fSVenugopal Iyer 				/* Already raw numbers */
267*0dc2366fSVenugopal Iyer 				unit = '\0';
268*0dc2366fSVenugopal Iyer 				break;
269*0dc2366fSVenugopal Iyer 			case 'K':
270*0dc2366fSVenugopal Iyer 				num /= 1000;
271*0dc2366fSVenugopal Iyer 				break;
272*0dc2366fSVenugopal Iyer 			case 'M':
273*0dc2366fSVenugopal Iyer 				num /= (1000*1000);
274*0dc2366fSVenugopal Iyer 				break;
275*0dc2366fSVenugopal Iyer 			case 'G':
276*0dc2366fSVenugopal Iyer 				num /= (1000*1000*1000);
277*0dc2366fSVenugopal Iyer 				break;
278*0dc2366fSVenugopal Iyer 			case 'T':
279*0dc2366fSVenugopal Iyer 				num /= (1000.0*1000.0*1000.0*1000.0);
280*0dc2366fSVenugopal Iyer 				break;
281*0dc2366fSVenugopal Iyer 			case 'P':
282*0dc2366fSVenugopal Iyer 				/* Largest unit supported */
283*0dc2366fSVenugopal Iyer 			default:
284*0dc2366fSVenugopal Iyer 				num /= (1000.0*1000.0*1000.0*1000.0*1000.0);
285*0dc2366fSVenugopal Iyer 				break;
286*0dc2366fSVenugopal Iyer 		}
287*0dc2366fSVenugopal Iyer 	}
288*0dc2366fSVenugopal Iyer 
289*0dc2366fSVenugopal Iyer 	if (unit == '\0')
290*0dc2366fSVenugopal Iyer 		(void) snprintf(buf, bufsize, " %7.0lf%c", num, unit);
291*0dc2366fSVenugopal Iyer 	else
292*0dc2366fSVenugopal Iyer 		(void) snprintf(buf, bufsize, " %6.2lf%c", num, unit);
293*0dc2366fSVenugopal Iyer }
294*0dc2366fSVenugopal Iyer 
295*0dc2366fSVenugopal Iyer flow_chain_t *
296*0dc2366fSVenugopal Iyer get_flow_prev_stat(const char *flowname, void *arg)
297*0dc2366fSVenugopal Iyer {
298*0dc2366fSVenugopal Iyer 	show_flow_state_t	*state = arg;
299*0dc2366fSVenugopal Iyer 	flow_chain_t		*flow_curr = NULL;
300*0dc2366fSVenugopal Iyer 
301*0dc2366fSVenugopal Iyer 	/* Scan prev flowname list and look for entry matching this entry */
302*0dc2366fSVenugopal Iyer 	for (flow_curr = state->fs_flowchain; flow_curr;
303*0dc2366fSVenugopal Iyer 	    flow_curr = flow_curr->fc_next) {
304*0dc2366fSVenugopal Iyer 		if (strcmp(flow_curr->fc_flowname, flowname) == 0)
305*0dc2366fSVenugopal Iyer 			break;
306*0dc2366fSVenugopal Iyer 	}
307*0dc2366fSVenugopal Iyer 
308*0dc2366fSVenugopal Iyer 	/* New flow, add it */
309*0dc2366fSVenugopal Iyer 	if (flow_curr == NULL) {
310*0dc2366fSVenugopal Iyer 		flow_curr = (flow_chain_t *)malloc(sizeof (flow_chain_t));
311*0dc2366fSVenugopal Iyer 		if (flow_curr == NULL)
312*0dc2366fSVenugopal Iyer 			goto done;
313*0dc2366fSVenugopal Iyer 		(void) strncpy(flow_curr->fc_flowname, flowname,
314*0dc2366fSVenugopal Iyer 		    MAXFLOWNAMELEN);
315*0dc2366fSVenugopal Iyer 		flow_curr->fc_stat = NULL;
316*0dc2366fSVenugopal Iyer 		flow_curr->fc_next = state->fs_flowchain;
317*0dc2366fSVenugopal Iyer 		state->fs_flowchain = flow_curr;
318*0dc2366fSVenugopal Iyer 	}
319*0dc2366fSVenugopal Iyer done:
320*0dc2366fSVenugopal Iyer 	return (flow_curr);
321*0dc2366fSVenugopal Iyer }
322*0dc2366fSVenugopal Iyer 
323*0dc2366fSVenugopal Iyer /*
324*0dc2366fSVenugopal Iyer  * Number of flows may change while flowstat -i is executing.
325*0dc2366fSVenugopal Iyer  * Free memory allocated for flows that are no longer there.
326*0dc2366fSVenugopal Iyer  * Prepare for next iteration by marking visited = false for
327*0dc2366fSVenugopal Iyer  * existing stat entries.
328*0dc2366fSVenugopal Iyer  */
329*0dc2366fSVenugopal Iyer static void
330*0dc2366fSVenugopal Iyer cleanup_removed_flows(show_flow_state_t *state)
331*0dc2366fSVenugopal Iyer {
332*0dc2366fSVenugopal Iyer 	flow_chain_t	*fcurr;
333*0dc2366fSVenugopal Iyer 	flow_chain_t	*fprev;
334*0dc2366fSVenugopal Iyer 	flow_chain_t	*tofree;
335*0dc2366fSVenugopal Iyer 
336*0dc2366fSVenugopal Iyer 	/* Delete all nodes from the list that have fc_visited marked false */
337*0dc2366fSVenugopal Iyer 	fcurr = state->fs_flowchain;
338*0dc2366fSVenugopal Iyer 	while (fcurr != NULL) {
339*0dc2366fSVenugopal Iyer 		if (fcurr->fc_visited) {
340*0dc2366fSVenugopal Iyer 			fcurr->fc_visited = B_FALSE;
341*0dc2366fSVenugopal Iyer 			fprev = fcurr;
342*0dc2366fSVenugopal Iyer 			fcurr = fcurr->fc_next;
343*0dc2366fSVenugopal Iyer 			continue;
344*0dc2366fSVenugopal Iyer 		}
345*0dc2366fSVenugopal Iyer 
346*0dc2366fSVenugopal Iyer 		/* Is it head of the list? */
347*0dc2366fSVenugopal Iyer 		if (fcurr == state->fs_flowchain)
348*0dc2366fSVenugopal Iyer 			state->fs_flowchain = fcurr->fc_next;
349*0dc2366fSVenugopal Iyer 		else
350*0dc2366fSVenugopal Iyer 			fprev->fc_next = fcurr->fc_next;
351*0dc2366fSVenugopal Iyer 
352*0dc2366fSVenugopal Iyer 		/* fprev remains the same */
353*0dc2366fSVenugopal Iyer 		tofree = fcurr;
354*0dc2366fSVenugopal Iyer 		fcurr = fcurr->fc_next;
355*0dc2366fSVenugopal Iyer 
356*0dc2366fSVenugopal Iyer 		/* Free stats memory for the removed flow */
357*0dc2366fSVenugopal Iyer 		dladm_flow_stat_free(tofree->fc_stat);
358*0dc2366fSVenugopal Iyer 		free(tofree);
359*0dc2366fSVenugopal Iyer 	}
360*0dc2366fSVenugopal Iyer }
361*0dc2366fSVenugopal Iyer 
362*0dc2366fSVenugopal Iyer static boolean_t
363*0dc2366fSVenugopal Iyer print_flow_stats_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
364*0dc2366fSVenugopal Iyer {
365*0dc2366fSVenugopal Iyer 	flow_args_t	*fargs = of_arg->ofmt_cbarg;
366*0dc2366fSVenugopal Iyer 	flow_stat_t	*diff_stats = fargs->flow_s_stat;
367*0dc2366fSVenugopal Iyer 	char		unit = fargs->flow_s_unit;
368*0dc2366fSVenugopal Iyer 	boolean_t	parsable = fargs->flow_s_parsable;
369*0dc2366fSVenugopal Iyer 
370*0dc2366fSVenugopal Iyer 	switch (of_arg->ofmt_id) {
371*0dc2366fSVenugopal Iyer 	case FLOW_S_FLOW:
372*0dc2366fSVenugopal Iyer 		(void) snprintf(buf, bufsize, "%s", fargs->flow_s_flow);
373*0dc2366fSVenugopal Iyer 		break;
374*0dc2366fSVenugopal Iyer 	case FLOW_S_IPKTS:
375*0dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_ipackets, unit,
376*0dc2366fSVenugopal Iyer 		    parsable);
377*0dc2366fSVenugopal Iyer 		break;
378*0dc2366fSVenugopal Iyer 	case FLOW_S_RBYTES:
379*0dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_rbytes, unit,
380*0dc2366fSVenugopal Iyer 		    parsable);
381*0dc2366fSVenugopal Iyer 		break;
382*0dc2366fSVenugopal Iyer 	case FLOW_S_IERRORS:
383*0dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_ierrors, unit,
384*0dc2366fSVenugopal Iyer 		    parsable);
385*0dc2366fSVenugopal Iyer 		break;
386*0dc2366fSVenugopal Iyer 	case FLOW_S_OPKTS:
387*0dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_opackets, unit,
388*0dc2366fSVenugopal Iyer 		    parsable);
389*0dc2366fSVenugopal Iyer 		break;
390*0dc2366fSVenugopal Iyer 	case FLOW_S_OBYTES:
391*0dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_obytes, unit,
392*0dc2366fSVenugopal Iyer 		    parsable);
393*0dc2366fSVenugopal Iyer 		break;
394*0dc2366fSVenugopal Iyer 	case FLOW_S_OERRORS:
395*0dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_oerrors, unit,
396*0dc2366fSVenugopal Iyer 		    parsable);
397*0dc2366fSVenugopal Iyer 		break;
398*0dc2366fSVenugopal Iyer 	default:
399*0dc2366fSVenugopal Iyer 		die("invalid input");
400*0dc2366fSVenugopal Iyer 		break;
401*0dc2366fSVenugopal Iyer 	}
402*0dc2366fSVenugopal Iyer 	return (B_TRUE);
403*0dc2366fSVenugopal Iyer }
404*0dc2366fSVenugopal Iyer 
405*0dc2366fSVenugopal Iyer /* ARGSUSED */
406*0dc2366fSVenugopal Iyer static int
407*0dc2366fSVenugopal Iyer query_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
408*0dc2366fSVenugopal Iyer {
409*0dc2366fSVenugopal Iyer 	show_flow_state_t	*state = arg;
410*0dc2366fSVenugopal Iyer 	flow_chain_t		*flow_node;
411*0dc2366fSVenugopal Iyer 	flow_stat_t		*curr_stat;
412*0dc2366fSVenugopal Iyer 	flow_stat_t		*prev_stat;
413*0dc2366fSVenugopal Iyer 	flow_stat_t		*diff_stat;
414*0dc2366fSVenugopal Iyer 	char			*flowname = attr->fa_flowname;
415*0dc2366fSVenugopal Iyer 	flow_args_t		fargs;
416*0dc2366fSVenugopal Iyer 
417*0dc2366fSVenugopal Iyer 	/* Get previous stats for the flow */
418*0dc2366fSVenugopal Iyer 	flow_node = get_flow_prev_stat(flowname, arg);
419*0dc2366fSVenugopal Iyer 	if (flow_node == NULL)
420*0dc2366fSVenugopal Iyer 		goto done;
421*0dc2366fSVenugopal Iyer 
422*0dc2366fSVenugopal Iyer 	flow_node->fc_visited = B_TRUE;
423*0dc2366fSVenugopal Iyer 	prev_stat = flow_node->fc_stat;
424*0dc2366fSVenugopal Iyer 
425*0dc2366fSVenugopal Iyer 	/* Query library for current stats */
426*0dc2366fSVenugopal Iyer 	curr_stat = dladm_flow_stat_query(flowname);
427*0dc2366fSVenugopal Iyer 	if (curr_stat == NULL)
428*0dc2366fSVenugopal Iyer 		goto done;
429*0dc2366fSVenugopal Iyer 
430*0dc2366fSVenugopal Iyer 	/* current stats - prev iteration stats */
431*0dc2366fSVenugopal Iyer 	diff_stat = dladm_flow_stat_diff(curr_stat, prev_stat);
432*0dc2366fSVenugopal Iyer 
433*0dc2366fSVenugopal Iyer 	/* Free prev stats */
434*0dc2366fSVenugopal Iyer 	dladm_flow_stat_free(prev_stat);
435*0dc2366fSVenugopal Iyer 
436*0dc2366fSVenugopal Iyer 	/* Prev <- curr stats */
437*0dc2366fSVenugopal Iyer 	flow_node->fc_stat = curr_stat;
438*0dc2366fSVenugopal Iyer 
439*0dc2366fSVenugopal Iyer 	if (diff_stat == NULL)
440*0dc2366fSVenugopal Iyer 		goto done;
441*0dc2366fSVenugopal Iyer 
442*0dc2366fSVenugopal Iyer 	/* Print stats */
443*0dc2366fSVenugopal Iyer 	fargs.flow_s_flow = flowname;
444*0dc2366fSVenugopal Iyer 	fargs.flow_s_stat = diff_stat;
445*0dc2366fSVenugopal Iyer 	fargs.flow_s_unit = state->fs_unit;
446*0dc2366fSVenugopal Iyer 	fargs.flow_s_parsable = state->fs_parsable;
447*0dc2366fSVenugopal Iyer 	ofmt_print(state->fs_ofmt, &fargs);
448*0dc2366fSVenugopal Iyer 
449*0dc2366fSVenugopal Iyer 	/* Free diff stats */
450*0dc2366fSVenugopal Iyer 	dladm_flow_stat_free(diff_stat);
451*0dc2366fSVenugopal Iyer done:
452*0dc2366fSVenugopal Iyer 	return (DLADM_WALK_CONTINUE);
453*0dc2366fSVenugopal Iyer }
454*0dc2366fSVenugopal Iyer 
455*0dc2366fSVenugopal Iyer /*
456*0dc2366fSVenugopal Iyer  * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
457*0dc2366fSVenugopal Iyer  * dladm_walk_datalink_id(). Used for showing flow stats for
458*0dc2366fSVenugopal Iyer  * all flows on all links.
459*0dc2366fSVenugopal Iyer  */
460*0dc2366fSVenugopal Iyer static int
461*0dc2366fSVenugopal Iyer query_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg)
462*0dc2366fSVenugopal Iyer {
463*0dc2366fSVenugopal Iyer 	if (dladm_walk_flow(query_flow_stats, dh, linkid, arg, B_FALSE)
464*0dc2366fSVenugopal Iyer 	    == DLADM_STATUS_OK)
465*0dc2366fSVenugopal Iyer 		return (DLADM_WALK_CONTINUE);
466*0dc2366fSVenugopal Iyer 	else
467*0dc2366fSVenugopal Iyer 		return (DLADM_WALK_TERMINATE);
468*0dc2366fSVenugopal Iyer }
469*0dc2366fSVenugopal Iyer 
470*0dc2366fSVenugopal Iyer void
471*0dc2366fSVenugopal Iyer print_all_stats(name_value_stat_entry_t *stat_entry)
472*0dc2366fSVenugopal Iyer {
473*0dc2366fSVenugopal Iyer 	name_value_stat_t	*curr_stat;
474*0dc2366fSVenugopal Iyer 
475*0dc2366fSVenugopal Iyer 	printf("%s\n", stat_entry->nve_header);
476*0dc2366fSVenugopal Iyer 
477*0dc2366fSVenugopal Iyer 	for (curr_stat = stat_entry->nve_stats; curr_stat != NULL;
478*0dc2366fSVenugopal Iyer 	    curr_stat = curr_stat->nv_nextstat) {
479*0dc2366fSVenugopal Iyer 		printf("\t%15s", curr_stat->nv_statname);
480*0dc2366fSVenugopal Iyer 		printf("\t%15llu\n", curr_stat->nv_statval);
481*0dc2366fSVenugopal Iyer 	}
482*0dc2366fSVenugopal Iyer }
483*0dc2366fSVenugopal Iyer 
484*0dc2366fSVenugopal Iyer /* ARGSUSED */
485*0dc2366fSVenugopal Iyer static int
486*0dc2366fSVenugopal Iyer dump_one_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
487*0dc2366fSVenugopal Iyer {
488*0dc2366fSVenugopal Iyer 	char	*flowname = attr->fa_flowname;
489*0dc2366fSVenugopal Iyer 	void	*stat;
490*0dc2366fSVenugopal Iyer 
491*0dc2366fSVenugopal Iyer 	stat = dladm_flow_stat_query_all(flowname);
492*0dc2366fSVenugopal Iyer 	if (stat == NULL)
493*0dc2366fSVenugopal Iyer 		goto done;
494*0dc2366fSVenugopal Iyer 	print_all_stats(stat);
495*0dc2366fSVenugopal Iyer 	dladm_flow_stat_query_all_free(stat);
496*0dc2366fSVenugopal Iyer 
497*0dc2366fSVenugopal Iyer done:
498*0dc2366fSVenugopal Iyer 	return (DLADM_WALK_CONTINUE);
499*0dc2366fSVenugopal Iyer }
500*0dc2366fSVenugopal Iyer 
501*0dc2366fSVenugopal Iyer /*
502*0dc2366fSVenugopal Iyer  * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
503*0dc2366fSVenugopal Iyer  * dladm_walk_datalink_id(). Used for showing flow stats for
504*0dc2366fSVenugopal Iyer  * all flows on all links.
505*0dc2366fSVenugopal Iyer  */
506*0dc2366fSVenugopal Iyer static int
507*0dc2366fSVenugopal Iyer dump_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg)
508*0dc2366fSVenugopal Iyer {
509*0dc2366fSVenugopal Iyer 	if (dladm_walk_flow(dump_one_flow_stats, dh, linkid, arg, B_FALSE)
510*0dc2366fSVenugopal Iyer 	    == DLADM_STATUS_OK)
511*0dc2366fSVenugopal Iyer 		return (DLADM_WALK_CONTINUE);
512*0dc2366fSVenugopal Iyer 	else
513*0dc2366fSVenugopal Iyer 		return (DLADM_WALK_TERMINATE);
514*0dc2366fSVenugopal Iyer }
515*0dc2366fSVenugopal Iyer 
516*0dc2366fSVenugopal Iyer static void
517*0dc2366fSVenugopal Iyer dump_all_flow_stats(dladm_flow_attr_t *attrp, void *arg, datalink_id_t linkid,
518*0dc2366fSVenugopal Iyer     boolean_t flow_arg)
519*0dc2366fSVenugopal Iyer {
520*0dc2366fSVenugopal Iyer 	/* Show stats for named flow */
521*0dc2366fSVenugopal Iyer 	if (flow_arg)  {
522*0dc2366fSVenugopal Iyer 		(void) dump_one_flow_stats(handle, attrp, arg);
523*0dc2366fSVenugopal Iyer 
524*0dc2366fSVenugopal Iyer 	/* Show stats for flows on one link */
525*0dc2366fSVenugopal Iyer 	} else if (linkid != DATALINK_INVALID_LINKID) {
526*0dc2366fSVenugopal Iyer 		(void) dladm_walk_flow(dump_one_flow_stats, handle, linkid,
527*0dc2366fSVenugopal Iyer 		    arg, B_FALSE);
528*0dc2366fSVenugopal Iyer 
529*0dc2366fSVenugopal Iyer 	/* Show stats for all flows on all links */
530*0dc2366fSVenugopal Iyer 	} else {
531*0dc2366fSVenugopal Iyer 		(void) dladm_walk_datalink_id(dump_link_flow_stats,
532*0dc2366fSVenugopal Iyer 		    handle, arg, DATALINK_CLASS_ALL,
533*0dc2366fSVenugopal Iyer 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
534*0dc2366fSVenugopal Iyer 	}
535*0dc2366fSVenugopal Iyer }
536*0dc2366fSVenugopal Iyer 
537*0dc2366fSVenugopal Iyer int
538*0dc2366fSVenugopal Iyer main(int argc, char *argv[])
539*0dc2366fSVenugopal Iyer {
540*0dc2366fSVenugopal Iyer 	dladm_status_t 		status;
541*0dc2366fSVenugopal Iyer 	int			option;
542*0dc2366fSVenugopal Iyer 	boolean_t		r_arg = B_FALSE;
543*0dc2366fSVenugopal Iyer 	boolean_t		t_arg = B_FALSE;
544*0dc2366fSVenugopal Iyer 	boolean_t		p_arg = B_FALSE;
545*0dc2366fSVenugopal Iyer 	boolean_t		i_arg = B_FALSE;
546*0dc2366fSVenugopal Iyer 	boolean_t		o_arg = B_FALSE;
547*0dc2366fSVenugopal Iyer 	boolean_t		u_arg = B_FALSE;
548*0dc2366fSVenugopal Iyer 	boolean_t		A_arg = B_FALSE;
549*0dc2366fSVenugopal Iyer 	boolean_t		S_arg = B_FALSE;
550*0dc2366fSVenugopal Iyer 	boolean_t		flow_arg = B_FALSE;
551*0dc2366fSVenugopal Iyer 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
552*0dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
553*0dc2366fSVenugopal Iyer 	char			flowname[MAXFLOWNAMELEN];
554*0dc2366fSVenugopal Iyer 	uint32_t		interval = 0;
555*0dc2366fSVenugopal Iyer 	char			unit = '\0';
556*0dc2366fSVenugopal Iyer 	show_flow_state_t	state;
557*0dc2366fSVenugopal Iyer 	char			*fields_str = NULL;
558*0dc2366fSVenugopal Iyer 	char			*o_fields_str = NULL;
559*0dc2366fSVenugopal Iyer 
560*0dc2366fSVenugopal Iyer 	char			*total_stat_fields =
561*0dc2366fSVenugopal Iyer 	    "flow,ipkts,rbytes,ierrs,opkts,obytes,oerrs";
562*0dc2366fSVenugopal Iyer 	char			*rx_stat_fields =
563*0dc2366fSVenugopal Iyer 	    "flow,ipkts,rbytes,ierrs";
564*0dc2366fSVenugopal Iyer 	char			*tx_stat_fields =
565*0dc2366fSVenugopal Iyer 	    "flow,opkts,obytes,oerrs";
566*0dc2366fSVenugopal Iyer 
567*0dc2366fSVenugopal Iyer 	ofmt_handle_t		ofmt;
568*0dc2366fSVenugopal Iyer 	ofmt_status_t		oferr;
569*0dc2366fSVenugopal Iyer 	uint_t			ofmtflags = OFMT_RIGHTJUST;
570*0dc2366fSVenugopal Iyer 
571*0dc2366fSVenugopal Iyer 	dladm_flow_attr_t	attr;
572*0dc2366fSVenugopal Iyer 
573*0dc2366fSVenugopal Iyer 	(void) setlocale(LC_ALL, "");
574*0dc2366fSVenugopal Iyer #if !defined(TEXT_DOMAIN)
575*0dc2366fSVenugopal Iyer #define	TEXT_DOMAIN "SYS_TEST"
576*0dc2366fSVenugopal Iyer #endif
577*0dc2366fSVenugopal Iyer 	(void) textdomain(TEXT_DOMAIN);
578*0dc2366fSVenugopal Iyer 
579*0dc2366fSVenugopal Iyer 	progname = argv[0];
580*0dc2366fSVenugopal Iyer 
581*0dc2366fSVenugopal Iyer 	/* Open the libdladm handle */
582*0dc2366fSVenugopal Iyer 	if ((status = dladm_open(&handle)) != DLADM_STATUS_OK)
583*0dc2366fSVenugopal Iyer 		die_dlerr(status, "could not open /dev/dld");
584*0dc2366fSVenugopal Iyer 
585*0dc2366fSVenugopal Iyer 	bzero(&state, sizeof (state));
586*0dc2366fSVenugopal Iyer 
587*0dc2366fSVenugopal Iyer 	opterr = 0;
588*0dc2366fSVenugopal Iyer 	while ((option = getopt_long(argc, argv, ":rtApSi:o:u:l:h",
589*0dc2366fSVenugopal Iyer 	    NULL, NULL)) != -1) {
590*0dc2366fSVenugopal Iyer 		switch (option) {
591*0dc2366fSVenugopal Iyer 		case 'r':
592*0dc2366fSVenugopal Iyer 			if (r_arg)
593*0dc2366fSVenugopal Iyer 				die_optdup(option);
594*0dc2366fSVenugopal Iyer 
595*0dc2366fSVenugopal Iyer 			r_arg = B_TRUE;
596*0dc2366fSVenugopal Iyer 			break;
597*0dc2366fSVenugopal Iyer 		case 't':
598*0dc2366fSVenugopal Iyer 			if (t_arg)
599*0dc2366fSVenugopal Iyer 				die_optdup(option);
600*0dc2366fSVenugopal Iyer 
601*0dc2366fSVenugopal Iyer 			t_arg = B_TRUE;
602*0dc2366fSVenugopal Iyer 			break;
603*0dc2366fSVenugopal Iyer 		case 'A':
604*0dc2366fSVenugopal Iyer 			if (A_arg)
605*0dc2366fSVenugopal Iyer 				die_optdup(option);
606*0dc2366fSVenugopal Iyer 
607*0dc2366fSVenugopal Iyer 			A_arg = B_TRUE;
608*0dc2366fSVenugopal Iyer 			break;
609*0dc2366fSVenugopal Iyer 		case 'p':
610*0dc2366fSVenugopal Iyer 			if (p_arg)
611*0dc2366fSVenugopal Iyer 				die_optdup(option);
612*0dc2366fSVenugopal Iyer 
613*0dc2366fSVenugopal Iyer 			p_arg = B_TRUE;
614*0dc2366fSVenugopal Iyer 			break;
615*0dc2366fSVenugopal Iyer 		case 'S':
616*0dc2366fSVenugopal Iyer 			if (S_arg)
617*0dc2366fSVenugopal Iyer 				die_optdup(option);
618*0dc2366fSVenugopal Iyer 			S_arg = B_TRUE;
619*0dc2366fSVenugopal Iyer 			break;
620*0dc2366fSVenugopal Iyer 		case 'i':
621*0dc2366fSVenugopal Iyer 			if (i_arg)
622*0dc2366fSVenugopal Iyer 				die_optdup(option);
623*0dc2366fSVenugopal Iyer 
624*0dc2366fSVenugopal Iyer 			i_arg = B_TRUE;
625*0dc2366fSVenugopal Iyer 			if (!dladm_str2interval(optarg, &interval))
626*0dc2366fSVenugopal Iyer 				die("invalid interval value '%s'", optarg);
627*0dc2366fSVenugopal Iyer 			break;
628*0dc2366fSVenugopal Iyer 		case 'o':
629*0dc2366fSVenugopal Iyer 			o_arg = B_TRUE;
630*0dc2366fSVenugopal Iyer 			o_fields_str = optarg;
631*0dc2366fSVenugopal Iyer 			break;
632*0dc2366fSVenugopal Iyer 		case 'u':
633*0dc2366fSVenugopal Iyer 			if (u_arg)
634*0dc2366fSVenugopal Iyer 				die_optdup(option);
635*0dc2366fSVenugopal Iyer 
636*0dc2366fSVenugopal Iyer 			u_arg = B_TRUE;
637*0dc2366fSVenugopal Iyer 			if (!flowstat_unit(optarg, &unit))
638*0dc2366fSVenugopal Iyer 				die("invalid unit value '%s',"
639*0dc2366fSVenugopal Iyer 				    "unit must be R|K|M|G|T|P", optarg);
640*0dc2366fSVenugopal Iyer 			break;
641*0dc2366fSVenugopal Iyer 		case 'l':
642*0dc2366fSVenugopal Iyer 			if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
643*0dc2366fSVenugopal Iyer 			    >= MAXLINKNAMELEN)
644*0dc2366fSVenugopal Iyer 				die("link name too long\n");
645*0dc2366fSVenugopal Iyer 			if (dladm_name2info(handle, linkname, &linkid, NULL,
646*0dc2366fSVenugopal Iyer 			    NULL, NULL) != DLADM_STATUS_OK)
647*0dc2366fSVenugopal Iyer 				die("invalid link '%s'", linkname);
648*0dc2366fSVenugopal Iyer 			break;
649*0dc2366fSVenugopal Iyer 		case 'h':
650*0dc2366fSVenugopal Iyer 			if (r_arg || t_arg || p_arg || o_arg || u_arg ||
651*0dc2366fSVenugopal Iyer 			    i_arg || S_arg || A_arg) {
652*0dc2366fSVenugopal Iyer 				die("the option -h is not compatible with "
653*0dc2366fSVenugopal Iyer 				    "-r, -t, -p, -o, -u, -i, -S, -A");
654*0dc2366fSVenugopal Iyer 			}
655*0dc2366fSVenugopal Iyer 			do_show_history(argc, argv);
656*0dc2366fSVenugopal Iyer 			return (0);
657*0dc2366fSVenugopal Iyer 			break;
658*0dc2366fSVenugopal Iyer 		default:
659*0dc2366fSVenugopal Iyer 			die_opterr(optopt, option, usage_ermsg);
660*0dc2366fSVenugopal Iyer 			break;
661*0dc2366fSVenugopal Iyer 		}
662*0dc2366fSVenugopal Iyer 	}
663*0dc2366fSVenugopal Iyer 
664*0dc2366fSVenugopal Iyer 	if (r_arg && t_arg)
665*0dc2366fSVenugopal Iyer 		die("the option -t and -r are not compatible");
666*0dc2366fSVenugopal Iyer 
667*0dc2366fSVenugopal Iyer 	if (u_arg && p_arg)
668*0dc2366fSVenugopal Iyer 		die("the option -u and -p are not compatible");
669*0dc2366fSVenugopal Iyer 
670*0dc2366fSVenugopal Iyer 	if (p_arg && !o_arg)
671*0dc2366fSVenugopal Iyer 		die("-p requires -o");
672*0dc2366fSVenugopal Iyer 
673*0dc2366fSVenugopal Iyer 	if (p_arg && strcasecmp(o_fields_str, "all") == 0)
674*0dc2366fSVenugopal Iyer 		die("\"-o all\" is invalid with -p");
675*0dc2366fSVenugopal Iyer 
676*0dc2366fSVenugopal Iyer 	if (S_arg &&
677*0dc2366fSVenugopal Iyer 	    (r_arg || t_arg || p_arg || o_arg || u_arg))
678*0dc2366fSVenugopal Iyer 		die("the option -S is not compatible with "
679*0dc2366fSVenugopal Iyer 		    "-r, -t, -p, -o, -u");
680*0dc2366fSVenugopal Iyer 
681*0dc2366fSVenugopal Iyer 	if (A_arg &&
682*0dc2366fSVenugopal Iyer 	    (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg))
683*0dc2366fSVenugopal Iyer 		die("the option -A is not compatible with "
684*0dc2366fSVenugopal Iyer 		    "-r, -t, -p, -o, -u, -i");
685*0dc2366fSVenugopal Iyer 
686*0dc2366fSVenugopal Iyer 	/* get flow name (optional last argument) */
687*0dc2366fSVenugopal Iyer 	if (optind == (argc-1)) {
688*0dc2366fSVenugopal Iyer 		if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
689*0dc2366fSVenugopal Iyer 		    >= MAXFLOWNAMELEN)
690*0dc2366fSVenugopal Iyer 			die("flow name too long");
691*0dc2366fSVenugopal Iyer 		flow_arg = B_TRUE;
692*0dc2366fSVenugopal Iyer 	} else if (optind != argc) {
693*0dc2366fSVenugopal Iyer 		usage();
694*0dc2366fSVenugopal Iyer 	}
695*0dc2366fSVenugopal Iyer 
696*0dc2366fSVenugopal Iyer 	if (S_arg) {
697*0dc2366fSVenugopal Iyer 		dladm_continuous(handle, linkid, (flow_arg ? flowname : NULL),
698*0dc2366fSVenugopal Iyer 		    interval, FLOW_REPORT);
699*0dc2366fSVenugopal Iyer 		return (0);
700*0dc2366fSVenugopal Iyer 	}
701*0dc2366fSVenugopal Iyer 
702*0dc2366fSVenugopal Iyer 	if (flow_arg &&
703*0dc2366fSVenugopal Iyer 	    dladm_flow_info(handle, flowname, &attr) != DLADM_STATUS_OK)
704*0dc2366fSVenugopal Iyer 		die("invalid flow %s", flowname);
705*0dc2366fSVenugopal Iyer 
706*0dc2366fSVenugopal Iyer 	if (A_arg) {
707*0dc2366fSVenugopal Iyer 		dump_all_flow_stats(&attr, &state, linkid, flow_arg);
708*0dc2366fSVenugopal Iyer 		return (0);
709*0dc2366fSVenugopal Iyer 	}
710*0dc2366fSVenugopal Iyer 
711*0dc2366fSVenugopal Iyer 	state.fs_unit = unit;
712*0dc2366fSVenugopal Iyer 	state.fs_parsable = p_arg;
713*0dc2366fSVenugopal Iyer 
714*0dc2366fSVenugopal Iyer 	if (state.fs_parsable)
715*0dc2366fSVenugopal Iyer 		ofmtflags |= OFMT_PARSABLE;
716*0dc2366fSVenugopal Iyer 
717*0dc2366fSVenugopal Iyer 	if (r_arg)
718*0dc2366fSVenugopal Iyer 		fields_str = rx_stat_fields;
719*0dc2366fSVenugopal Iyer 	else if (t_arg)
720*0dc2366fSVenugopal Iyer 		fields_str = tx_stat_fields;
721*0dc2366fSVenugopal Iyer 	else
722*0dc2366fSVenugopal Iyer 		fields_str = total_stat_fields;
723*0dc2366fSVenugopal Iyer 
724*0dc2366fSVenugopal Iyer 	if (o_arg) {
725*0dc2366fSVenugopal Iyer 		fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
726*0dc2366fSVenugopal Iyer 		    fields_str : o_fields_str;
727*0dc2366fSVenugopal Iyer 	}
728*0dc2366fSVenugopal Iyer 
729*0dc2366fSVenugopal Iyer 	oferr = ofmt_open(fields_str, flow_s_fields, ofmtflags, 0, &ofmt);
730*0dc2366fSVenugopal Iyer 	flowstat_ofmt_check(oferr, state.fs_parsable, ofmt);
731*0dc2366fSVenugopal Iyer 	state.fs_ofmt = ofmt;
732*0dc2366fSVenugopal Iyer 
733*0dc2366fSVenugopal Iyer 	for (;;) {
734*0dc2366fSVenugopal Iyer 		/* Show stats for named flow */
735*0dc2366fSVenugopal Iyer 		if (flow_arg)  {
736*0dc2366fSVenugopal Iyer 			(void) query_flow_stats(handle, &attr, &state);
737*0dc2366fSVenugopal Iyer 
738*0dc2366fSVenugopal Iyer 		/* Show stats for flows on one link */
739*0dc2366fSVenugopal Iyer 		} else if (linkid != DATALINK_INVALID_LINKID) {
740*0dc2366fSVenugopal Iyer 			(void) dladm_walk_flow(query_flow_stats, handle, linkid,
741*0dc2366fSVenugopal Iyer 			    &state, B_FALSE);
742*0dc2366fSVenugopal Iyer 
743*0dc2366fSVenugopal Iyer 		/* Show stats for all flows on all links */
744*0dc2366fSVenugopal Iyer 		} else {
745*0dc2366fSVenugopal Iyer 			(void) dladm_walk_datalink_id(query_link_flow_stats,
746*0dc2366fSVenugopal Iyer 			    handle, &state, DATALINK_CLASS_ALL,
747*0dc2366fSVenugopal Iyer 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
748*0dc2366fSVenugopal Iyer 		}
749*0dc2366fSVenugopal Iyer 
750*0dc2366fSVenugopal Iyer 		if (interval == 0)
751*0dc2366fSVenugopal Iyer 			break;
752*0dc2366fSVenugopal Iyer 
753*0dc2366fSVenugopal Iyer 		(void) fflush(stdout);
754*0dc2366fSVenugopal Iyer 		cleanup_removed_flows(&state);
755*0dc2366fSVenugopal Iyer 		(void) sleep(interval);
756*0dc2366fSVenugopal Iyer 	}
757*0dc2366fSVenugopal Iyer 	ofmt_close(ofmt);
758*0dc2366fSVenugopal Iyer 
759*0dc2366fSVenugopal Iyer 	dladm_close(handle);
760*0dc2366fSVenugopal Iyer 	return (0);
761*0dc2366fSVenugopal Iyer }
762*0dc2366fSVenugopal Iyer 
763*0dc2366fSVenugopal Iyer /* ARGSUSED */
764*0dc2366fSVenugopal Iyer static int
765*0dc2366fSVenugopal Iyer show_history_date(dladm_usage_t *history, void *arg)
766*0dc2366fSVenugopal Iyer {
767*0dc2366fSVenugopal Iyer 	show_history_state_t	*state = (show_history_state_t *)arg;
768*0dc2366fSVenugopal Iyer 	time_t			stime;
769*0dc2366fSVenugopal Iyer 	char			timebuf[20];
770*0dc2366fSVenugopal Iyer 	dladm_flow_attr_t	attr;
771*0dc2366fSVenugopal Iyer 	dladm_status_t		status;
772*0dc2366fSVenugopal Iyer 
773*0dc2366fSVenugopal Iyer 	/*
774*0dc2366fSVenugopal Iyer 	 * Only show historical information for existing flows unless '-a'
775*0dc2366fSVenugopal Iyer 	 * is specified.
776*0dc2366fSVenugopal Iyer 	 */
777*0dc2366fSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
778*0dc2366fSVenugopal Iyer 	    history->du_name, &attr)) != DLADM_STATUS_OK)) {
779*0dc2366fSVenugopal Iyer 		return (status);
780*0dc2366fSVenugopal Iyer 	}
781*0dc2366fSVenugopal Iyer 
782*0dc2366fSVenugopal Iyer 	stime = history->du_stime;
783*0dc2366fSVenugopal Iyer 	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
784*0dc2366fSVenugopal Iyer 	    localtime(&stime));
785*0dc2366fSVenugopal Iyer 	(void) printf("%s\n", timebuf);
786*0dc2366fSVenugopal Iyer 
787*0dc2366fSVenugopal Iyer 	return (DLADM_STATUS_OK);
788*0dc2366fSVenugopal Iyer }
789*0dc2366fSVenugopal Iyer 
790*0dc2366fSVenugopal Iyer static int
791*0dc2366fSVenugopal Iyer show_history_time(dladm_usage_t *history, void *arg)
792*0dc2366fSVenugopal Iyer {
793*0dc2366fSVenugopal Iyer 	show_history_state_t	*state = (show_history_state_t *)arg;
794*0dc2366fSVenugopal Iyer 	char			buf[DLADM_STRSIZE];
795*0dc2366fSVenugopal Iyer 	history_l_fields_buf_t 	ubuf;
796*0dc2366fSVenugopal Iyer 	time_t			time;
797*0dc2366fSVenugopal Iyer 	double			bw;
798*0dc2366fSVenugopal Iyer 	dladm_flow_attr_t	attr;
799*0dc2366fSVenugopal Iyer 	dladm_status_t		status;
800*0dc2366fSVenugopal Iyer 
801*0dc2366fSVenugopal Iyer 	/*
802*0dc2366fSVenugopal Iyer 	 * Only show historical information for existing flows unless '-a'
803*0dc2366fSVenugopal Iyer 	 * is specified.
804*0dc2366fSVenugopal Iyer 	 */
805*0dc2366fSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
806*0dc2366fSVenugopal Iyer 	    history->du_name, &attr)) != DLADM_STATUS_OK)) {
807*0dc2366fSVenugopal Iyer 		return (status);
808*0dc2366fSVenugopal Iyer 	}
809*0dc2366fSVenugopal Iyer 
810*0dc2366fSVenugopal Iyer 	if (state->us_plot) {
811*0dc2366fSVenugopal Iyer 		if (!state->us_printheader) {
812*0dc2366fSVenugopal Iyer 			if (state->us_first) {
813*0dc2366fSVenugopal Iyer 				(void) printf("# Time");
814*0dc2366fSVenugopal Iyer 				state->us_first = B_FALSE;
815*0dc2366fSVenugopal Iyer 			}
816*0dc2366fSVenugopal Iyer 			(void) printf(" %s", history->du_name);
817*0dc2366fSVenugopal Iyer 			if (history->du_last) {
818*0dc2366fSVenugopal Iyer 				(void) printf("\n");
819*0dc2366fSVenugopal Iyer 				state->us_first = B_TRUE;
820*0dc2366fSVenugopal Iyer 				state->us_printheader = B_TRUE;
821*0dc2366fSVenugopal Iyer 			}
822*0dc2366fSVenugopal Iyer 		} else {
823*0dc2366fSVenugopal Iyer 			if (state->us_first) {
824*0dc2366fSVenugopal Iyer 				time = history->du_etime;
825*0dc2366fSVenugopal Iyer 				(void) strftime(buf, sizeof (buf), "%T",
826*0dc2366fSVenugopal Iyer 				    localtime(&time));
827*0dc2366fSVenugopal Iyer 				state->us_first = B_FALSE;
828*0dc2366fSVenugopal Iyer 				(void) printf("%s", buf);
829*0dc2366fSVenugopal Iyer 			}
830*0dc2366fSVenugopal Iyer 			bw = (double)history->du_bandwidth/1000;
831*0dc2366fSVenugopal Iyer 			(void) printf(" %.2f", bw);
832*0dc2366fSVenugopal Iyer 			if (history->du_last) {
833*0dc2366fSVenugopal Iyer 				(void) printf("\n");
834*0dc2366fSVenugopal Iyer 				state->us_first = B_TRUE;
835*0dc2366fSVenugopal Iyer 			}
836*0dc2366fSVenugopal Iyer 		}
837*0dc2366fSVenugopal Iyer 		return (DLADM_STATUS_OK);
838*0dc2366fSVenugopal Iyer 	}
839*0dc2366fSVenugopal Iyer 
840*0dc2366fSVenugopal Iyer 	bzero(&ubuf, sizeof (ubuf));
841*0dc2366fSVenugopal Iyer 
842*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_flow, sizeof (ubuf.history_l_flow), "%s",
843*0dc2366fSVenugopal Iyer 	    history->du_name);
844*0dc2366fSVenugopal Iyer 	time = history->du_stime;
845*0dc2366fSVenugopal Iyer 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
846*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_stime, sizeof (ubuf.history_l_stime),
847*0dc2366fSVenugopal Iyer 	    "%s", buf);
848*0dc2366fSVenugopal Iyer 	time = history->du_etime;
849*0dc2366fSVenugopal Iyer 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
850*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_etime, sizeof (ubuf.history_l_etime),
851*0dc2366fSVenugopal Iyer 	    "%s", buf);
852*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_rbytes, sizeof (ubuf.history_l_rbytes),
853*0dc2366fSVenugopal Iyer 	    "%llu", history->du_rbytes);
854*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_obytes, sizeof (ubuf.history_l_obytes),
855*0dc2366fSVenugopal Iyer 	    "%llu", history->du_obytes);
856*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_bandwidth,
857*0dc2366fSVenugopal Iyer 	    sizeof (ubuf.history_l_bandwidth), "%s Mbps",
858*0dc2366fSVenugopal Iyer 	    dladm_bw2str(history->du_bandwidth, buf));
859*0dc2366fSVenugopal Iyer 
860*0dc2366fSVenugopal Iyer 	ofmt_print(state->us_ofmt, (void *)&ubuf);
861*0dc2366fSVenugopal Iyer 	return (DLADM_STATUS_OK);
862*0dc2366fSVenugopal Iyer }
863*0dc2366fSVenugopal Iyer 
864*0dc2366fSVenugopal Iyer static int
865*0dc2366fSVenugopal Iyer show_history_res(dladm_usage_t *history, void *arg)
866*0dc2366fSVenugopal Iyer {
867*0dc2366fSVenugopal Iyer 	show_history_state_t	*state = (show_history_state_t *)arg;
868*0dc2366fSVenugopal Iyer 	char			buf[DLADM_STRSIZE];
869*0dc2366fSVenugopal Iyer 	history_fields_buf_t	ubuf;
870*0dc2366fSVenugopal Iyer 	dladm_flow_attr_t	attr;
871*0dc2366fSVenugopal Iyer 	dladm_status_t		status;
872*0dc2366fSVenugopal Iyer 
873*0dc2366fSVenugopal Iyer 	/*
874*0dc2366fSVenugopal Iyer 	 * Only show historical information for existing flows unless '-a'
875*0dc2366fSVenugopal Iyer 	 * is specified.
876*0dc2366fSVenugopal Iyer 	 */
877*0dc2366fSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
878*0dc2366fSVenugopal Iyer 	    history->du_name, &attr)) != DLADM_STATUS_OK)) {
879*0dc2366fSVenugopal Iyer 		return (status);
880*0dc2366fSVenugopal Iyer 	}
881*0dc2366fSVenugopal Iyer 
882*0dc2366fSVenugopal Iyer 	bzero(&ubuf, sizeof (ubuf));
883*0dc2366fSVenugopal Iyer 
884*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_flow, sizeof (ubuf.history_flow), "%s",
885*0dc2366fSVenugopal Iyer 	    history->du_name);
886*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_duration, sizeof (ubuf.history_duration),
887*0dc2366fSVenugopal Iyer 	    "%llu", history->du_duration);
888*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_ipackets, sizeof (ubuf.history_ipackets),
889*0dc2366fSVenugopal Iyer 	    "%llu", history->du_ipackets);
890*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_rbytes, sizeof (ubuf.history_rbytes),
891*0dc2366fSVenugopal Iyer 	    "%llu", history->du_rbytes);
892*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_opackets, sizeof (ubuf.history_opackets),
893*0dc2366fSVenugopal Iyer 	    "%llu", history->du_opackets);
894*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_obytes, sizeof (ubuf.history_obytes),
895*0dc2366fSVenugopal Iyer 	    "%llu", history->du_obytes);
896*0dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_bandwidth, sizeof (ubuf.history_bandwidth),
897*0dc2366fSVenugopal Iyer 	    "%s Mbps", dladm_bw2str(history->du_bandwidth, buf));
898*0dc2366fSVenugopal Iyer 
899*0dc2366fSVenugopal Iyer 	ofmt_print(state->us_ofmt, (void *)&ubuf);
900*0dc2366fSVenugopal Iyer 
901*0dc2366fSVenugopal Iyer 	return (DLADM_STATUS_OK);
902*0dc2366fSVenugopal Iyer }
903*0dc2366fSVenugopal Iyer 
904*0dc2366fSVenugopal Iyer static boolean_t
905*0dc2366fSVenugopal Iyer valid_formatspec(char *formatspec_str)
906*0dc2366fSVenugopal Iyer {
907*0dc2366fSVenugopal Iyer 	return (strcmp(formatspec_str, "gnuplot") == 0);
908*0dc2366fSVenugopal Iyer }
909*0dc2366fSVenugopal Iyer 
910*0dc2366fSVenugopal Iyer /* ARGSUSED */
911*0dc2366fSVenugopal Iyer static void
912*0dc2366fSVenugopal Iyer do_show_history(int argc, char *argv[])
913*0dc2366fSVenugopal Iyer {
914*0dc2366fSVenugopal Iyer 	char			*file = NULL;
915*0dc2366fSVenugopal Iyer 	int			opt;
916*0dc2366fSVenugopal Iyer 	dladm_status_t		status;
917*0dc2366fSVenugopal Iyer 	boolean_t		d_arg = B_FALSE;
918*0dc2366fSVenugopal Iyer 	char			*stime = NULL;
919*0dc2366fSVenugopal Iyer 	char			*etime = NULL;
920*0dc2366fSVenugopal Iyer 	char			*resource = NULL;
921*0dc2366fSVenugopal Iyer 	show_history_state_t	state;
922*0dc2366fSVenugopal Iyer 	boolean_t		o_arg = B_FALSE;
923*0dc2366fSVenugopal Iyer 	boolean_t		F_arg = B_FALSE;
924*0dc2366fSVenugopal Iyer 	char			*fields_str = NULL;
925*0dc2366fSVenugopal Iyer 	char			*formatspec_str = NULL;
926*0dc2366fSVenugopal Iyer 	char			*all_fields =
927*0dc2366fSVenugopal Iyer 	    "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth";
928*0dc2366fSVenugopal Iyer 	char			*all_l_fields =
929*0dc2366fSVenugopal Iyer 	    "flow,start,end,rbytes,obytes,bandwidth";
930*0dc2366fSVenugopal Iyer 	ofmt_handle_t		ofmt;
931*0dc2366fSVenugopal Iyer 	ofmt_status_t		oferr;
932*0dc2366fSVenugopal Iyer 	uint_t			ofmtflags = 0;
933*0dc2366fSVenugopal Iyer 
934*0dc2366fSVenugopal Iyer 	bzero(&state, sizeof (show_history_state_t));
935*0dc2366fSVenugopal Iyer 	state.us_parsable = B_FALSE;
936*0dc2366fSVenugopal Iyer 	state.us_printheader = B_FALSE;
937*0dc2366fSVenugopal Iyer 	state.us_plot = B_FALSE;
938*0dc2366fSVenugopal Iyer 	state.us_first = B_TRUE;
939*0dc2366fSVenugopal Iyer 
940*0dc2366fSVenugopal Iyer 	while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) {
941*0dc2366fSVenugopal Iyer 		switch (opt) {
942*0dc2366fSVenugopal Iyer 		case 'd':
943*0dc2366fSVenugopal Iyer 			d_arg = B_TRUE;
944*0dc2366fSVenugopal Iyer 			break;
945*0dc2366fSVenugopal Iyer 		case 'a':
946*0dc2366fSVenugopal Iyer 			state.us_showall = B_TRUE;
947*0dc2366fSVenugopal Iyer 			break;
948*0dc2366fSVenugopal Iyer 		case 'f':
949*0dc2366fSVenugopal Iyer 			file = optarg;
950*0dc2366fSVenugopal Iyer 			break;
951*0dc2366fSVenugopal Iyer 		case 's':
952*0dc2366fSVenugopal Iyer 			stime = optarg;
953*0dc2366fSVenugopal Iyer 			break;
954*0dc2366fSVenugopal Iyer 		case 'e':
955*0dc2366fSVenugopal Iyer 			etime = optarg;
956*0dc2366fSVenugopal Iyer 			break;
957*0dc2366fSVenugopal Iyer 		case 'o':
958*0dc2366fSVenugopal Iyer 			o_arg = B_TRUE;
959*0dc2366fSVenugopal Iyer 			fields_str = optarg;
960*0dc2366fSVenugopal Iyer 			break;
961*0dc2366fSVenugopal Iyer 		case 'F':
962*0dc2366fSVenugopal Iyer 			state.us_plot = F_arg = B_TRUE;
963*0dc2366fSVenugopal Iyer 			formatspec_str = optarg;
964*0dc2366fSVenugopal Iyer 			break;
965*0dc2366fSVenugopal Iyer 		default:
966*0dc2366fSVenugopal Iyer 			die_opterr(optopt, opt, usage_ermsg);
967*0dc2366fSVenugopal Iyer 		}
968*0dc2366fSVenugopal Iyer 	}
969*0dc2366fSVenugopal Iyer 
970*0dc2366fSVenugopal Iyer 	if (file == NULL)
971*0dc2366fSVenugopal Iyer 		die("-h requires a file");
972*0dc2366fSVenugopal Iyer 
973*0dc2366fSVenugopal Iyer 	if (optind == (argc-1)) {
974*0dc2366fSVenugopal Iyer 		dladm_flow_attr_t	attr;
975*0dc2366fSVenugopal Iyer 
976*0dc2366fSVenugopal Iyer 		resource = argv[optind];
977*0dc2366fSVenugopal Iyer 		if (!state.us_showall &&
978*0dc2366fSVenugopal Iyer 		    dladm_flow_info(handle, resource, &attr) !=
979*0dc2366fSVenugopal Iyer 		    DLADM_STATUS_OK) {
980*0dc2366fSVenugopal Iyer 			die("invalid flow: '%s'", resource);
981*0dc2366fSVenugopal Iyer 		}
982*0dc2366fSVenugopal Iyer 	}
983*0dc2366fSVenugopal Iyer 
984*0dc2366fSVenugopal Iyer 	if (state.us_parsable)
985*0dc2366fSVenugopal Iyer 		ofmtflags |= OFMT_PARSABLE;
986*0dc2366fSVenugopal Iyer 	if (resource == NULL && stime == NULL && etime == NULL) {
987*0dc2366fSVenugopal Iyer 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
988*0dc2366fSVenugopal Iyer 			fields_str = all_fields;
989*0dc2366fSVenugopal Iyer 		oferr = ofmt_open(fields_str, history_fields, ofmtflags,
990*0dc2366fSVenugopal Iyer 		    0, &ofmt);
991*0dc2366fSVenugopal Iyer 	} else {
992*0dc2366fSVenugopal Iyer 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
993*0dc2366fSVenugopal Iyer 			fields_str = all_l_fields;
994*0dc2366fSVenugopal Iyer 		oferr = ofmt_open(fields_str, history_l_fields, ofmtflags,
995*0dc2366fSVenugopal Iyer 		    0, &ofmt);
996*0dc2366fSVenugopal Iyer 	}
997*0dc2366fSVenugopal Iyer 
998*0dc2366fSVenugopal Iyer 	flowstat_ofmt_check(oferr, state.us_parsable, ofmt);
999*0dc2366fSVenugopal Iyer 	state.us_ofmt = ofmt;
1000*0dc2366fSVenugopal Iyer 
1001*0dc2366fSVenugopal Iyer 	if (F_arg && d_arg)
1002*0dc2366fSVenugopal Iyer 		die("incompatible -d and -F options");
1003*0dc2366fSVenugopal Iyer 
1004*0dc2366fSVenugopal Iyer 	if (F_arg && !valid_formatspec(formatspec_str))
1005*0dc2366fSVenugopal Iyer 		die("Format specifier %s not supported", formatspec_str);
1006*0dc2366fSVenugopal Iyer 
1007*0dc2366fSVenugopal Iyer 	if (d_arg) {
1008*0dc2366fSVenugopal Iyer 		/* Print log dates */
1009*0dc2366fSVenugopal Iyer 		status = dladm_usage_dates(show_history_date,
1010*0dc2366fSVenugopal Iyer 		    DLADM_LOGTYPE_FLOW, file, resource, &state);
1011*0dc2366fSVenugopal Iyer 	} else if (resource == NULL && stime == NULL && etime == NULL &&
1012*0dc2366fSVenugopal Iyer 	    !F_arg) {
1013*0dc2366fSVenugopal Iyer 		/* Print summary */
1014*0dc2366fSVenugopal Iyer 		status = dladm_usage_summary(show_history_res,
1015*0dc2366fSVenugopal Iyer 		    DLADM_LOGTYPE_FLOW, file, &state);
1016*0dc2366fSVenugopal Iyer 	} else if (resource != NULL) {
1017*0dc2366fSVenugopal Iyer 		/* Print log entries for named resource */
1018*0dc2366fSVenugopal Iyer 		status = dladm_walk_usage_res(show_history_time,
1019*0dc2366fSVenugopal Iyer 		    DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state);
1020*0dc2366fSVenugopal Iyer 	} else {
1021*0dc2366fSVenugopal Iyer 		/* Print time and information for each flow */
1022*0dc2366fSVenugopal Iyer 		status = dladm_walk_usage_time(show_history_time,
1023*0dc2366fSVenugopal Iyer 		    DLADM_LOGTYPE_FLOW, file, stime, etime, &state);
1024*0dc2366fSVenugopal Iyer 	}
1025*0dc2366fSVenugopal Iyer 
1026*0dc2366fSVenugopal Iyer 	ofmt_close(ofmt);
1027*0dc2366fSVenugopal Iyer 	if (status != DLADM_STATUS_OK)
1028*0dc2366fSVenugopal Iyer 		die_dlerr(status, "-h");
1029*0dc2366fSVenugopal Iyer 	dladm_close(handle);
1030*0dc2366fSVenugopal Iyer }
1031*0dc2366fSVenugopal Iyer 
1032*0dc2366fSVenugopal Iyer static void
1033*0dc2366fSVenugopal Iyer warn(const char *format, ...)
1034*0dc2366fSVenugopal Iyer {
1035*0dc2366fSVenugopal Iyer 	va_list alist;
1036*0dc2366fSVenugopal Iyer 
1037*0dc2366fSVenugopal Iyer 	format = gettext(format);
1038*0dc2366fSVenugopal Iyer 	(void) fprintf(stderr, "%s: warning: ", progname);
1039*0dc2366fSVenugopal Iyer 
1040*0dc2366fSVenugopal Iyer 	va_start(alist, format);
1041*0dc2366fSVenugopal Iyer 	(void) vfprintf(stderr, format, alist);
1042*0dc2366fSVenugopal Iyer 	va_end(alist);
1043*0dc2366fSVenugopal Iyer 
1044*0dc2366fSVenugopal Iyer 	(void) putc('\n', stderr);
1045*0dc2366fSVenugopal Iyer }
1046*0dc2366fSVenugopal Iyer 
1047*0dc2366fSVenugopal Iyer /* PRINTFLIKE1 */
1048*0dc2366fSVenugopal Iyer static void
1049*0dc2366fSVenugopal Iyer die(const char *format, ...)
1050*0dc2366fSVenugopal Iyer {
1051*0dc2366fSVenugopal Iyer 	va_list alist;
1052*0dc2366fSVenugopal Iyer 
1053*0dc2366fSVenugopal Iyer 	format = gettext(format);
1054*0dc2366fSVenugopal Iyer 	(void) fprintf(stderr, "%s: ", progname);
1055*0dc2366fSVenugopal Iyer 
1056*0dc2366fSVenugopal Iyer 	va_start(alist, format);
1057*0dc2366fSVenugopal Iyer 	(void) vfprintf(stderr, format, alist);
1058*0dc2366fSVenugopal Iyer 	va_end(alist);
1059*0dc2366fSVenugopal Iyer 
1060*0dc2366fSVenugopal Iyer 	(void) putc('\n', stderr);
1061*0dc2366fSVenugopal Iyer 
1062*0dc2366fSVenugopal Iyer 	/* close dladm handle if it was opened */
1063*0dc2366fSVenugopal Iyer 	if (handle != NULL)
1064*0dc2366fSVenugopal Iyer 		dladm_close(handle);
1065*0dc2366fSVenugopal Iyer 
1066*0dc2366fSVenugopal Iyer 	exit(EXIT_FAILURE);
1067*0dc2366fSVenugopal Iyer }
1068*0dc2366fSVenugopal Iyer 
1069*0dc2366fSVenugopal Iyer static void
1070*0dc2366fSVenugopal Iyer die_optdup(int opt)
1071*0dc2366fSVenugopal Iyer {
1072*0dc2366fSVenugopal Iyer 	die("the option -%c cannot be specified more than once", opt);
1073*0dc2366fSVenugopal Iyer }
1074*0dc2366fSVenugopal Iyer 
1075*0dc2366fSVenugopal Iyer static void
1076*0dc2366fSVenugopal Iyer die_opterr(int opt, int opterr, const char *usage)
1077*0dc2366fSVenugopal Iyer {
1078*0dc2366fSVenugopal Iyer 	switch (opterr) {
1079*0dc2366fSVenugopal Iyer 	case ':':
1080*0dc2366fSVenugopal Iyer 		die("option '-%c' requires a value\nusage: %s", opt,
1081*0dc2366fSVenugopal Iyer 		    gettext(usage));
1082*0dc2366fSVenugopal Iyer 		break;
1083*0dc2366fSVenugopal Iyer 	case '?':
1084*0dc2366fSVenugopal Iyer 	default:
1085*0dc2366fSVenugopal Iyer 		die("unrecognized option '-%c'\nusage: %s", opt,
1086*0dc2366fSVenugopal Iyer 		    gettext(usage));
1087*0dc2366fSVenugopal Iyer 		break;
1088*0dc2366fSVenugopal Iyer 	}
1089*0dc2366fSVenugopal Iyer }
1090*0dc2366fSVenugopal Iyer 
1091*0dc2366fSVenugopal Iyer /* PRINTFLIKE2 */
1092*0dc2366fSVenugopal Iyer static void
1093*0dc2366fSVenugopal Iyer die_dlerr(dladm_status_t err, const char *format, ...)
1094*0dc2366fSVenugopal Iyer {
1095*0dc2366fSVenugopal Iyer 	va_list alist;
1096*0dc2366fSVenugopal Iyer 	char	errmsg[DLADM_STRSIZE];
1097*0dc2366fSVenugopal Iyer 
1098*0dc2366fSVenugopal Iyer 	format = gettext(format);
1099*0dc2366fSVenugopal Iyer 	(void) fprintf(stderr, "%s: ", progname);
1100*0dc2366fSVenugopal Iyer 
1101*0dc2366fSVenugopal Iyer 	va_start(alist, format);
1102*0dc2366fSVenugopal Iyer 	(void) vfprintf(stderr, format, alist);
1103*0dc2366fSVenugopal Iyer 	va_end(alist);
1104*0dc2366fSVenugopal Iyer 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
1105*0dc2366fSVenugopal Iyer 
1106*0dc2366fSVenugopal Iyer 	/* close dladm handle if it was opened */
1107*0dc2366fSVenugopal Iyer 	if (handle != NULL)
1108*0dc2366fSVenugopal Iyer 		dladm_close(handle);
1109*0dc2366fSVenugopal Iyer 
1110*0dc2366fSVenugopal Iyer 	exit(EXIT_FAILURE);
1111*0dc2366fSVenugopal Iyer }
1112*0dc2366fSVenugopal Iyer 
1113*0dc2366fSVenugopal Iyer 
1114*0dc2366fSVenugopal Iyer /*
1115*0dc2366fSVenugopal Iyer  * default output callback function that, when invoked from dladm_print_output,
1116*0dc2366fSVenugopal Iyer  * prints string which is offset by of_arg->ofmt_id within buf.
1117*0dc2366fSVenugopal Iyer  */
1118*0dc2366fSVenugopal Iyer static boolean_t
1119*0dc2366fSVenugopal Iyer print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1120*0dc2366fSVenugopal Iyer {
1121*0dc2366fSVenugopal Iyer 	char *value;
1122*0dc2366fSVenugopal Iyer 
1123*0dc2366fSVenugopal Iyer 	value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id;
1124*0dc2366fSVenugopal Iyer 	(void) strlcpy(buf, value, bufsize);
1125*0dc2366fSVenugopal Iyer 	return (B_TRUE);
1126*0dc2366fSVenugopal Iyer }
1127*0dc2366fSVenugopal Iyer 
1128*0dc2366fSVenugopal Iyer static void
1129*0dc2366fSVenugopal Iyer flowstat_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
1130*0dc2366fSVenugopal Iyer     ofmt_handle_t ofmt)
1131*0dc2366fSVenugopal Iyer {
1132*0dc2366fSVenugopal Iyer 	char buf[OFMT_BUFSIZE];
1133*0dc2366fSVenugopal Iyer 
1134*0dc2366fSVenugopal Iyer 	if (oferr == OFMT_SUCCESS)
1135*0dc2366fSVenugopal Iyer 		return;
1136*0dc2366fSVenugopal Iyer 	(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
1137*0dc2366fSVenugopal Iyer 	/*
1138*0dc2366fSVenugopal Iyer 	 * All errors are considered fatal in parsable mode.
1139*0dc2366fSVenugopal Iyer 	 * NOMEM errors are always fatal, regardless of mode.
1140*0dc2366fSVenugopal Iyer 	 * For other errors, we print diagnostics in human-readable
1141*0dc2366fSVenugopal Iyer 	 * mode and processs what we can.
1142*0dc2366fSVenugopal Iyer 	 */
1143*0dc2366fSVenugopal Iyer 	if (parsable || oferr == OFMT_ENOFIELDS) {
1144*0dc2366fSVenugopal Iyer 		ofmt_close(ofmt);
1145*0dc2366fSVenugopal Iyer 		die(buf);
1146*0dc2366fSVenugopal Iyer 	} else {
1147*0dc2366fSVenugopal Iyer 		warn(buf);
1148*0dc2366fSVenugopal Iyer 	}
1149*0dc2366fSVenugopal Iyer }
1150