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