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