xref: /illumos-gate/usr/src/cmd/flowstat/flowstat.c (revision 62ef8476)
10dc2366fSVenugopal Iyer /*
20dc2366fSVenugopal Iyer  * CDDL HEADER START
30dc2366fSVenugopal Iyer  *
40dc2366fSVenugopal Iyer  * The contents of this file are subject to the terms of the
50dc2366fSVenugopal Iyer  * Common Development and Distribution License (the "License").
60dc2366fSVenugopal Iyer  * You may not use this file except in compliance with the License.
70dc2366fSVenugopal Iyer  *
80dc2366fSVenugopal Iyer  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90dc2366fSVenugopal Iyer  * or http://www.opensolaris.org/os/licensing.
100dc2366fSVenugopal Iyer  * See the License for the specific language governing permissions
110dc2366fSVenugopal Iyer  * and limitations under the License.
120dc2366fSVenugopal Iyer  *
130dc2366fSVenugopal Iyer  * When distributing Covered Code, include this CDDL HEADER in each
140dc2366fSVenugopal Iyer  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150dc2366fSVenugopal Iyer  * If applicable, add the following below this CDDL HEADER, with the
160dc2366fSVenugopal Iyer  * fields enclosed by brackets "[]" replaced with your own identifying
170dc2366fSVenugopal Iyer  * information: Portions Copyright [yyyy] [name of copyright owner]
180dc2366fSVenugopal Iyer  *
190dc2366fSVenugopal Iyer  * CDDL HEADER END
200dc2366fSVenugopal Iyer  */
210dc2366fSVenugopal Iyer /*
220dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230dc2366fSVenugopal Iyer  * Use is subject to license terms.
240dc2366fSVenugopal Iyer  */
250dc2366fSVenugopal Iyer 
260dc2366fSVenugopal Iyer #include <stdio.h>
270dc2366fSVenugopal Iyer #include <locale.h>
280dc2366fSVenugopal Iyer #include <stdarg.h>
290dc2366fSVenugopal Iyer #include <stdlib.h>
300dc2366fSVenugopal Iyer #include <fcntl.h>
310dc2366fSVenugopal Iyer #include <string.h>
320dc2366fSVenugopal Iyer #include <stropts.h>
330dc2366fSVenugopal Iyer #include <errno.h>
340dc2366fSVenugopal Iyer #include <strings.h>
350dc2366fSVenugopal Iyer #include <getopt.h>
360dc2366fSVenugopal Iyer #include <unistd.h>
370dc2366fSVenugopal Iyer #include <priv.h>
380dc2366fSVenugopal Iyer #include <netdb.h>
390dc2366fSVenugopal Iyer #include <libintl.h>
400dc2366fSVenugopal Iyer #include <libdlflow.h>
410dc2366fSVenugopal Iyer #include <libdllink.h>
420dc2366fSVenugopal Iyer #include <libdlstat.h>
430dc2366fSVenugopal Iyer #include <sys/types.h>
440dc2366fSVenugopal Iyer #include <sys/socket.h>
450dc2366fSVenugopal Iyer #include <netinet/in.h>
460dc2366fSVenugopal Iyer #include <arpa/inet.h>
470dc2366fSVenugopal Iyer #include <sys/ethernet.h>
480dc2366fSVenugopal Iyer #include <inet/ip.h>
490dc2366fSVenugopal Iyer #include <inet/ip6.h>
500dc2366fSVenugopal Iyer #include <stddef.h>
510dc2366fSVenugopal Iyer #include <ofmt.h>
520dc2366fSVenugopal Iyer 
530dc2366fSVenugopal Iyer typedef struct flow_chain_s {
540dc2366fSVenugopal Iyer 	char			fc_flowname[MAXFLOWNAMELEN];
550dc2366fSVenugopal Iyer 	boolean_t		fc_visited;
560dc2366fSVenugopal Iyer 	flow_stat_t		*fc_stat;
570dc2366fSVenugopal Iyer 	struct flow_chain_s	*fc_next;
580dc2366fSVenugopal Iyer } flow_chain_t;
590dc2366fSVenugopal Iyer 
600dc2366fSVenugopal Iyer typedef struct show_flow_state {
610dc2366fSVenugopal Iyer 	flow_chain_t	*fs_flowchain;
620dc2366fSVenugopal Iyer 	ofmt_handle_t	fs_ofmt;
630dc2366fSVenugopal Iyer 	char		fs_unit;
640dc2366fSVenugopal Iyer 	boolean_t	fs_parsable;
650dc2366fSVenugopal Iyer } show_flow_state_t;
660dc2366fSVenugopal Iyer 
670dc2366fSVenugopal Iyer typedef struct show_history_state_s {
680dc2366fSVenugopal Iyer 	boolean_t	us_plot;
690dc2366fSVenugopal Iyer 	boolean_t	us_parsable;
700dc2366fSVenugopal Iyer 	boolean_t	us_printheader;
710dc2366fSVenugopal Iyer 	boolean_t	us_first;
720dc2366fSVenugopal Iyer 	boolean_t	us_showall;
730dc2366fSVenugopal Iyer 	ofmt_handle_t	us_ofmt;
740dc2366fSVenugopal Iyer } show_history_state_t;
750dc2366fSVenugopal Iyer 
760dc2366fSVenugopal Iyer static void	do_show_history(int, char **);
770dc2366fSVenugopal Iyer 
780dc2366fSVenugopal Iyer static int	query_flow_stats(dladm_handle_t, dladm_flow_attr_t *, void *);
790dc2366fSVenugopal Iyer static int	query_link_flow_stats(dladm_handle_t, datalink_id_t, void *);
800dc2366fSVenugopal Iyer 
810dc2366fSVenugopal Iyer static void	die(const char *, ...);
820dc2366fSVenugopal Iyer static void	die_optdup(int);
830dc2366fSVenugopal Iyer static void	die_opterr(int, int, const char *);
840dc2366fSVenugopal Iyer static void	die_dlerr(dladm_status_t, const char *, ...);
850dc2366fSVenugopal Iyer static void	warn(const char *, ...);
860dc2366fSVenugopal Iyer 
870dc2366fSVenugopal Iyer /* callback functions for printing output */
880dc2366fSVenugopal Iyer static ofmt_cb_t print_default_cb, print_flow_stats_cb;
890dc2366fSVenugopal Iyer static void flowstat_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
900dc2366fSVenugopal Iyer 
910dc2366fSVenugopal Iyer #define	NULL_OFMT		{NULL, 0, 0, NULL}
920dc2366fSVenugopal Iyer 
930dc2366fSVenugopal Iyer /*
940dc2366fSVenugopal Iyer  * structures for flowstat (printing live statistics)
950dc2366fSVenugopal Iyer  */
960dc2366fSVenugopal Iyer typedef enum {
970dc2366fSVenugopal Iyer 	FLOW_S_FLOW,
980dc2366fSVenugopal Iyer 	FLOW_S_IPKTS,
990dc2366fSVenugopal Iyer 	FLOW_S_RBYTES,
1000dc2366fSVenugopal Iyer 	FLOW_S_IERRORS,
1010dc2366fSVenugopal Iyer 	FLOW_S_OPKTS,
1020dc2366fSVenugopal Iyer 	FLOW_S_OBYTES,
1030dc2366fSVenugopal Iyer 	FLOW_S_OERRORS
1040dc2366fSVenugopal Iyer } flow_s_field_index_t;
1050dc2366fSVenugopal Iyer 
1060dc2366fSVenugopal Iyer static ofmt_field_t flow_s_fields[] = {
1070dc2366fSVenugopal Iyer /* name,	field width,	index,		callback */
1080dc2366fSVenugopal Iyer { "FLOW",	15,	FLOW_S_FLOW,	print_flow_stats_cb},
1090dc2366fSVenugopal Iyer { "IPKTS",	8,	FLOW_S_IPKTS,	print_flow_stats_cb},
1100dc2366fSVenugopal Iyer { "RBYTES",	8,	FLOW_S_RBYTES,	print_flow_stats_cb},
1110dc2366fSVenugopal Iyer { "IERRS",	8,	FLOW_S_IERRORS,	print_flow_stats_cb},
1120dc2366fSVenugopal Iyer { "OPKTS",	8,	FLOW_S_OPKTS,	print_flow_stats_cb},
1130dc2366fSVenugopal Iyer { "OBYTES",	8,	FLOW_S_OBYTES,	print_flow_stats_cb},
1140dc2366fSVenugopal Iyer { "OERRS",	8,	FLOW_S_OERRORS,	print_flow_stats_cb},
1150dc2366fSVenugopal Iyer NULL_OFMT}
1160dc2366fSVenugopal Iyer ;
1170dc2366fSVenugopal Iyer 
1180dc2366fSVenugopal Iyer typedef struct flow_args_s {
1190dc2366fSVenugopal Iyer 	char		*flow_s_flow;
1200dc2366fSVenugopal Iyer 	flow_stat_t	*flow_s_stat;
1210dc2366fSVenugopal Iyer 	char		flow_s_unit;
1220dc2366fSVenugopal Iyer 	boolean_t	flow_s_parsable;
1230dc2366fSVenugopal Iyer } flow_args_t;
1240dc2366fSVenugopal Iyer 
1250dc2366fSVenugopal Iyer /*
1260dc2366fSVenugopal Iyer  * structures for 'flowstat -h'
1270dc2366fSVenugopal Iyer  */
1280dc2366fSVenugopal Iyer typedef struct  history_fields_buf_s {
1290dc2366fSVenugopal Iyer 	char	history_flow[12];
1300dc2366fSVenugopal Iyer 	char	history_duration[10];
1310dc2366fSVenugopal Iyer 	char	history_ipackets[9];
1320dc2366fSVenugopal Iyer 	char	history_rbytes[10];
1330dc2366fSVenugopal Iyer 	char	history_opackets[9];
1340dc2366fSVenugopal Iyer 	char	history_obytes[10];
1350dc2366fSVenugopal Iyer 	char	history_bandwidth[14];
1360dc2366fSVenugopal Iyer } history_fields_buf_t;
1370dc2366fSVenugopal Iyer 
1380dc2366fSVenugopal Iyer static ofmt_field_t history_fields[] = {
1390dc2366fSVenugopal Iyer /* name,	field width,	offset */
1400dc2366fSVenugopal Iyer { "FLOW",	13,
1410dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_flow), print_default_cb},
1420dc2366fSVenugopal Iyer { "DURATION",	11,
1430dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_duration), print_default_cb},
1440dc2366fSVenugopal Iyer { "IPACKETS",	10,
1450dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_ipackets), print_default_cb},
1460dc2366fSVenugopal Iyer { "RBYTES",	11,
1470dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_rbytes), print_default_cb},
1480dc2366fSVenugopal Iyer { "OPACKETS",	10,
1490dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_opackets), print_default_cb},
1500dc2366fSVenugopal Iyer { "OBYTES",	11,
1510dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_obytes), print_default_cb},
1520dc2366fSVenugopal Iyer { "BANDWIDTH",	15,
1530dc2366fSVenugopal Iyer 	offsetof(history_fields_buf_t, history_bandwidth), print_default_cb},
1540dc2366fSVenugopal Iyer NULL_OFMT}
1550dc2366fSVenugopal Iyer ;
1560dc2366fSVenugopal Iyer 
1570dc2366fSVenugopal Iyer typedef struct  history_l_fields_buf_s {
1580dc2366fSVenugopal Iyer 	char	history_l_flow[12];
1590dc2366fSVenugopal Iyer 	char	history_l_stime[13];
1600dc2366fSVenugopal Iyer 	char	history_l_etime[13];
1610dc2366fSVenugopal Iyer 	char	history_l_rbytes[8];
1620dc2366fSVenugopal Iyer 	char	history_l_obytes[8];
1630dc2366fSVenugopal Iyer 	char	history_l_bandwidth[14];
1640dc2366fSVenugopal Iyer } history_l_fields_buf_t;
1650dc2366fSVenugopal Iyer 
1660dc2366fSVenugopal Iyer static ofmt_field_t history_l_fields[] = {
1670dc2366fSVenugopal Iyer /* name,	field width,	offset */
1680dc2366fSVenugopal Iyer { "FLOW",	13,
1690dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_flow), print_default_cb},
1700dc2366fSVenugopal Iyer { "START",	14,
1710dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_stime), print_default_cb},
1720dc2366fSVenugopal Iyer { "END",	14,
1730dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_etime), print_default_cb},
1740dc2366fSVenugopal Iyer { "RBYTES",	9,
1750dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_rbytes), print_default_cb},
1760dc2366fSVenugopal Iyer { "OBYTES",	9,
1770dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_obytes), print_default_cb},
1780dc2366fSVenugopal Iyer { "BANDWIDTH",	15,
1790dc2366fSVenugopal Iyer 	offsetof(history_l_fields_buf_t, history_l_bandwidth),
1800dc2366fSVenugopal Iyer 	    print_default_cb},
1810dc2366fSVenugopal Iyer NULL_OFMT}
1820dc2366fSVenugopal Iyer ;
1830dc2366fSVenugopal Iyer 
1840dc2366fSVenugopal Iyer static char *progname;
1850dc2366fSVenugopal Iyer 
1860dc2366fSVenugopal Iyer /*
1870dc2366fSVenugopal Iyer  * Handle to libdladm.  Opened in main() before the sub-command
1880dc2366fSVenugopal Iyer  * specific function is called.
1890dc2366fSVenugopal Iyer  */
1900dc2366fSVenugopal Iyer static dladm_handle_t handle = NULL;
1910dc2366fSVenugopal Iyer 
1920dc2366fSVenugopal Iyer const char *usage_ermsg = "flowstat [-r | -t] [-i interval] "
1930dc2366fSVenugopal Iyer 	    "[-l link] [flow]\n"
194*62ef8476SYuri Pankov 	    "       flowstat [-A] [-i interval] [-p] [ -o field[,...]]\n"
1950dc2366fSVenugopal Iyer 	    "                [-u R|K|M|G|T|P] [-l link] [flow]\n"
1960dc2366fSVenugopal Iyer 	    "       flowstat -h [-a] [-d] [-F format]"
1970dc2366fSVenugopal Iyer 	    " [-s <DD/MM/YYYY,HH:MM:SS>]\n"
1980dc2366fSVenugopal Iyer 	    "                [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> "
1990dc2366fSVenugopal Iyer 	    "[<flow>]";
2000dc2366fSVenugopal Iyer 
2010dc2366fSVenugopal Iyer static void
2020dc2366fSVenugopal Iyer usage(void)
2030dc2366fSVenugopal Iyer {
2040dc2366fSVenugopal Iyer 	(void) fprintf(stderr, "%s\n", gettext(usage_ermsg));
2050dc2366fSVenugopal Iyer 
2060dc2366fSVenugopal Iyer 	/* close dladm handle if it was opened */
2070dc2366fSVenugopal Iyer 	if (handle != NULL)
2080dc2366fSVenugopal Iyer 		dladm_close(handle);
2090dc2366fSVenugopal Iyer 
2100dc2366fSVenugopal Iyer 	exit(1);
2110dc2366fSVenugopal Iyer }
2120dc2366fSVenugopal Iyer 
2130dc2366fSVenugopal Iyer boolean_t
2140dc2366fSVenugopal Iyer flowstat_unit(char *oarg, char *unit)
2150dc2366fSVenugopal Iyer {
2160dc2366fSVenugopal Iyer 	if ((strcmp(oarg, "R") == 0) || (strcmp(oarg, "K") == 0) ||
2170dc2366fSVenugopal Iyer 	    (strcmp(oarg, "M") == 0) || (strcmp(oarg, "G") == 0) ||
2180dc2366fSVenugopal Iyer 	    (strcmp(oarg, "T") == 0) || (strcmp(oarg, "P") == 0)) {
2190dc2366fSVenugopal Iyer 		*unit = oarg[0];
2200dc2366fSVenugopal Iyer 		return (B_TRUE);
2210dc2366fSVenugopal Iyer 	}
2220dc2366fSVenugopal Iyer 
2230dc2366fSVenugopal Iyer 	return (B_FALSE);
2240dc2366fSVenugopal Iyer }
2250dc2366fSVenugopal Iyer 
2260dc2366fSVenugopal Iyer void
2270dc2366fSVenugopal Iyer map_to_units(char *buf, uint_t bufsize, double num, char unit,
2280dc2366fSVenugopal Iyer     boolean_t parsable)
2290dc2366fSVenugopal Iyer {
2300dc2366fSVenugopal Iyer 	if (parsable) {
2310dc2366fSVenugopal Iyer 		(void) snprintf(buf, bufsize, "%.0lf", num);
2320dc2366fSVenugopal Iyer 		return;
2330dc2366fSVenugopal Iyer 	}
2340dc2366fSVenugopal Iyer 
2350dc2366fSVenugopal Iyer 	if (unit == '\0') {
2360dc2366fSVenugopal Iyer 		int index;
2370dc2366fSVenugopal Iyer 
2380dc2366fSVenugopal Iyer 		for (index = 0; (int)(num/1000) != 0; index++, num /= 1000)
2390dc2366fSVenugopal Iyer 			;
2400dc2366fSVenugopal Iyer 
2410dc2366fSVenugopal Iyer 		switch (index) {
2420dc2366fSVenugopal Iyer 			case 0:
2430dc2366fSVenugopal Iyer 				unit = '\0';
2440dc2366fSVenugopal Iyer 				break;
2450dc2366fSVenugopal Iyer 			case 1:
2460dc2366fSVenugopal Iyer 				unit = 'K';
2470dc2366fSVenugopal Iyer 				break;
2480dc2366fSVenugopal Iyer 			case 2:
2490dc2366fSVenugopal Iyer 				unit = 'M';
2500dc2366fSVenugopal Iyer 				break;
2510dc2366fSVenugopal Iyer 			case 3:
2520dc2366fSVenugopal Iyer 				unit = 'G';
2530dc2366fSVenugopal Iyer 				break;
2540dc2366fSVenugopal Iyer 			case 4:
2550dc2366fSVenugopal Iyer 				unit = 'T';
2560dc2366fSVenugopal Iyer 				break;
2570dc2366fSVenugopal Iyer 			case 5:
2580dc2366fSVenugopal Iyer 				/* Largest unit supported */
2590dc2366fSVenugopal Iyer 			default:
2600dc2366fSVenugopal Iyer 				unit = 'P';
2610dc2366fSVenugopal Iyer 				break;
2620dc2366fSVenugopal Iyer 		}
2630dc2366fSVenugopal Iyer 	} else  {
2640dc2366fSVenugopal Iyer 		switch (unit) {
2650dc2366fSVenugopal Iyer 			case 'R':
2660dc2366fSVenugopal Iyer 				/* Already raw numbers */
2670dc2366fSVenugopal Iyer 				unit = '\0';
2680dc2366fSVenugopal Iyer 				break;
2690dc2366fSVenugopal Iyer 			case 'K':
2700dc2366fSVenugopal Iyer 				num /= 1000;
2710dc2366fSVenugopal Iyer 				break;
2720dc2366fSVenugopal Iyer 			case 'M':
2730dc2366fSVenugopal Iyer 				num /= (1000*1000);
2740dc2366fSVenugopal Iyer 				break;
2750dc2366fSVenugopal Iyer 			case 'G':
2760dc2366fSVenugopal Iyer 				num /= (1000*1000*1000);
2770dc2366fSVenugopal Iyer 				break;
2780dc2366fSVenugopal Iyer 			case 'T':
2790dc2366fSVenugopal Iyer 				num /= (1000.0*1000.0*1000.0*1000.0);
2800dc2366fSVenugopal Iyer 				break;
2810dc2366fSVenugopal Iyer 			case 'P':
2820dc2366fSVenugopal Iyer 				/* Largest unit supported */
2830dc2366fSVenugopal Iyer 			default:
2840dc2366fSVenugopal Iyer 				num /= (1000.0*1000.0*1000.0*1000.0*1000.0);
2850dc2366fSVenugopal Iyer 				break;
2860dc2366fSVenugopal Iyer 		}
2870dc2366fSVenugopal Iyer 	}
2880dc2366fSVenugopal Iyer 
2890dc2366fSVenugopal Iyer 	if (unit == '\0')
2900dc2366fSVenugopal Iyer 		(void) snprintf(buf, bufsize, " %7.0lf%c", num, unit);
2910dc2366fSVenugopal Iyer 	else
2920dc2366fSVenugopal Iyer 		(void) snprintf(buf, bufsize, " %6.2lf%c", num, unit);
2930dc2366fSVenugopal Iyer }
2940dc2366fSVenugopal Iyer 
2950dc2366fSVenugopal Iyer flow_chain_t *
2960dc2366fSVenugopal Iyer get_flow_prev_stat(const char *flowname, void *arg)
2970dc2366fSVenugopal Iyer {
2980dc2366fSVenugopal Iyer 	show_flow_state_t	*state = arg;
2990dc2366fSVenugopal Iyer 	flow_chain_t		*flow_curr = NULL;
3000dc2366fSVenugopal Iyer 
3010dc2366fSVenugopal Iyer 	/* Scan prev flowname list and look for entry matching this entry */
3020dc2366fSVenugopal Iyer 	for (flow_curr = state->fs_flowchain; flow_curr;
3030dc2366fSVenugopal Iyer 	    flow_curr = flow_curr->fc_next) {
3040dc2366fSVenugopal Iyer 		if (strcmp(flow_curr->fc_flowname, flowname) == 0)
3050dc2366fSVenugopal Iyer 			break;
3060dc2366fSVenugopal Iyer 	}
3070dc2366fSVenugopal Iyer 
3080dc2366fSVenugopal Iyer 	/* New flow, add it */
3090dc2366fSVenugopal Iyer 	if (flow_curr == NULL) {
3100dc2366fSVenugopal Iyer 		flow_curr = (flow_chain_t *)malloc(sizeof (flow_chain_t));
3110dc2366fSVenugopal Iyer 		if (flow_curr == NULL)
3120dc2366fSVenugopal Iyer 			goto done;
3130dc2366fSVenugopal Iyer 		(void) strncpy(flow_curr->fc_flowname, flowname,
3140dc2366fSVenugopal Iyer 		    MAXFLOWNAMELEN);
3150dc2366fSVenugopal Iyer 		flow_curr->fc_stat = NULL;
3160dc2366fSVenugopal Iyer 		flow_curr->fc_next = state->fs_flowchain;
3170dc2366fSVenugopal Iyer 		state->fs_flowchain = flow_curr;
3180dc2366fSVenugopal Iyer 	}
3190dc2366fSVenugopal Iyer done:
3200dc2366fSVenugopal Iyer 	return (flow_curr);
3210dc2366fSVenugopal Iyer }
3220dc2366fSVenugopal Iyer 
3230dc2366fSVenugopal Iyer /*
3240dc2366fSVenugopal Iyer  * Number of flows may change while flowstat -i is executing.
3250dc2366fSVenugopal Iyer  * Free memory allocated for flows that are no longer there.
3260dc2366fSVenugopal Iyer  * Prepare for next iteration by marking visited = false for
3270dc2366fSVenugopal Iyer  * existing stat entries.
3280dc2366fSVenugopal Iyer  */
3290dc2366fSVenugopal Iyer static void
3300dc2366fSVenugopal Iyer cleanup_removed_flows(show_flow_state_t *state)
3310dc2366fSVenugopal Iyer {
3320dc2366fSVenugopal Iyer 	flow_chain_t	*fcurr;
3330dc2366fSVenugopal Iyer 	flow_chain_t	*fprev;
3340dc2366fSVenugopal Iyer 	flow_chain_t	*tofree;
3350dc2366fSVenugopal Iyer 
3360dc2366fSVenugopal Iyer 	/* Delete all nodes from the list that have fc_visited marked false */
3370dc2366fSVenugopal Iyer 	fcurr = state->fs_flowchain;
3380dc2366fSVenugopal Iyer 	while (fcurr != NULL) {
3390dc2366fSVenugopal Iyer 		if (fcurr->fc_visited) {
3400dc2366fSVenugopal Iyer 			fcurr->fc_visited = B_FALSE;
3410dc2366fSVenugopal Iyer 			fprev = fcurr;
3420dc2366fSVenugopal Iyer 			fcurr = fcurr->fc_next;
3430dc2366fSVenugopal Iyer 			continue;
3440dc2366fSVenugopal Iyer 		}
3450dc2366fSVenugopal Iyer 
3460dc2366fSVenugopal Iyer 		/* Is it head of the list? */
3470dc2366fSVenugopal Iyer 		if (fcurr == state->fs_flowchain)
3480dc2366fSVenugopal Iyer 			state->fs_flowchain = fcurr->fc_next;
3490dc2366fSVenugopal Iyer 		else
3500dc2366fSVenugopal Iyer 			fprev->fc_next = fcurr->fc_next;
3510dc2366fSVenugopal Iyer 
3520dc2366fSVenugopal Iyer 		/* fprev remains the same */
3530dc2366fSVenugopal Iyer 		tofree = fcurr;
3540dc2366fSVenugopal Iyer 		fcurr = fcurr->fc_next;
3550dc2366fSVenugopal Iyer 
3560dc2366fSVenugopal Iyer 		/* Free stats memory for the removed flow */
3570dc2366fSVenugopal Iyer 		dladm_flow_stat_free(tofree->fc_stat);
3580dc2366fSVenugopal Iyer 		free(tofree);
3590dc2366fSVenugopal Iyer 	}
3600dc2366fSVenugopal Iyer }
3610dc2366fSVenugopal Iyer 
3620dc2366fSVenugopal Iyer static boolean_t
3630dc2366fSVenugopal Iyer print_flow_stats_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
3640dc2366fSVenugopal Iyer {
3650dc2366fSVenugopal Iyer 	flow_args_t	*fargs = of_arg->ofmt_cbarg;
3660dc2366fSVenugopal Iyer 	flow_stat_t	*diff_stats = fargs->flow_s_stat;
3670dc2366fSVenugopal Iyer 	char		unit = fargs->flow_s_unit;
3680dc2366fSVenugopal Iyer 	boolean_t	parsable = fargs->flow_s_parsable;
3690dc2366fSVenugopal Iyer 
3700dc2366fSVenugopal Iyer 	switch (of_arg->ofmt_id) {
3710dc2366fSVenugopal Iyer 	case FLOW_S_FLOW:
3720dc2366fSVenugopal Iyer 		(void) snprintf(buf, bufsize, "%s", fargs->flow_s_flow);
3730dc2366fSVenugopal Iyer 		break;
3740dc2366fSVenugopal Iyer 	case FLOW_S_IPKTS:
3750dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_ipackets, unit,
3760dc2366fSVenugopal Iyer 		    parsable);
3770dc2366fSVenugopal Iyer 		break;
3780dc2366fSVenugopal Iyer 	case FLOW_S_RBYTES:
3790dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_rbytes, unit,
3800dc2366fSVenugopal Iyer 		    parsable);
3810dc2366fSVenugopal Iyer 		break;
3820dc2366fSVenugopal Iyer 	case FLOW_S_IERRORS:
3830dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_ierrors, unit,
3840dc2366fSVenugopal Iyer 		    parsable);
3850dc2366fSVenugopal Iyer 		break;
3860dc2366fSVenugopal Iyer 	case FLOW_S_OPKTS:
3870dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_opackets, unit,
3880dc2366fSVenugopal Iyer 		    parsable);
3890dc2366fSVenugopal Iyer 		break;
3900dc2366fSVenugopal Iyer 	case FLOW_S_OBYTES:
3910dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_obytes, unit,
3920dc2366fSVenugopal Iyer 		    parsable);
3930dc2366fSVenugopal Iyer 		break;
3940dc2366fSVenugopal Iyer 	case FLOW_S_OERRORS:
3950dc2366fSVenugopal Iyer 		map_to_units(buf, bufsize, diff_stats->fl_oerrors, unit,
3960dc2366fSVenugopal Iyer 		    parsable);
3970dc2366fSVenugopal Iyer 		break;
3980dc2366fSVenugopal Iyer 	default:
3990dc2366fSVenugopal Iyer 		die("invalid input");
4000dc2366fSVenugopal Iyer 		break;
4010dc2366fSVenugopal Iyer 	}
4020dc2366fSVenugopal Iyer 	return (B_TRUE);
4030dc2366fSVenugopal Iyer }
4040dc2366fSVenugopal Iyer 
4050dc2366fSVenugopal Iyer /* ARGSUSED */
4060dc2366fSVenugopal Iyer static int
4070dc2366fSVenugopal Iyer query_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
4080dc2366fSVenugopal Iyer {
4090dc2366fSVenugopal Iyer 	show_flow_state_t	*state = arg;
4100dc2366fSVenugopal Iyer 	flow_chain_t		*flow_node;
4110dc2366fSVenugopal Iyer 	flow_stat_t		*curr_stat;
4120dc2366fSVenugopal Iyer 	flow_stat_t		*prev_stat;
4130dc2366fSVenugopal Iyer 	flow_stat_t		*diff_stat;
4140dc2366fSVenugopal Iyer 	char			*flowname = attr->fa_flowname;
4150dc2366fSVenugopal Iyer 	flow_args_t		fargs;
4160dc2366fSVenugopal Iyer 
4170dc2366fSVenugopal Iyer 	/* Get previous stats for the flow */
4180dc2366fSVenugopal Iyer 	flow_node = get_flow_prev_stat(flowname, arg);
4190dc2366fSVenugopal Iyer 	if (flow_node == NULL)
4200dc2366fSVenugopal Iyer 		goto done;
4210dc2366fSVenugopal Iyer 
4220dc2366fSVenugopal Iyer 	flow_node->fc_visited = B_TRUE;
4230dc2366fSVenugopal Iyer 	prev_stat = flow_node->fc_stat;
4240dc2366fSVenugopal Iyer 
4250dc2366fSVenugopal Iyer 	/* Query library for current stats */
4260dc2366fSVenugopal Iyer 	curr_stat = dladm_flow_stat_query(flowname);
4270dc2366fSVenugopal Iyer 	if (curr_stat == NULL)
4280dc2366fSVenugopal Iyer 		goto done;
4290dc2366fSVenugopal Iyer 
4300dc2366fSVenugopal Iyer 	/* current stats - prev iteration stats */
4310dc2366fSVenugopal Iyer 	diff_stat = dladm_flow_stat_diff(curr_stat, prev_stat);
4320dc2366fSVenugopal Iyer 
4330dc2366fSVenugopal Iyer 	/* Free prev stats */
4340dc2366fSVenugopal Iyer 	dladm_flow_stat_free(prev_stat);
4350dc2366fSVenugopal Iyer 
4360dc2366fSVenugopal Iyer 	/* Prev <- curr stats */
4370dc2366fSVenugopal Iyer 	flow_node->fc_stat = curr_stat;
4380dc2366fSVenugopal Iyer 
4390dc2366fSVenugopal Iyer 	if (diff_stat == NULL)
4400dc2366fSVenugopal Iyer 		goto done;
4410dc2366fSVenugopal Iyer 
4420dc2366fSVenugopal Iyer 	/* Print stats */
4430dc2366fSVenugopal Iyer 	fargs.flow_s_flow = flowname;
4440dc2366fSVenugopal Iyer 	fargs.flow_s_stat = diff_stat;
4450dc2366fSVenugopal Iyer 	fargs.flow_s_unit = state->fs_unit;
4460dc2366fSVenugopal Iyer 	fargs.flow_s_parsable = state->fs_parsable;
4470dc2366fSVenugopal Iyer 	ofmt_print(state->fs_ofmt, &fargs);
4480dc2366fSVenugopal Iyer 
4490dc2366fSVenugopal Iyer 	/* Free diff stats */
4500dc2366fSVenugopal Iyer 	dladm_flow_stat_free(diff_stat);
4510dc2366fSVenugopal Iyer done:
4520dc2366fSVenugopal Iyer 	return (DLADM_WALK_CONTINUE);
4530dc2366fSVenugopal Iyer }
4540dc2366fSVenugopal Iyer 
4550dc2366fSVenugopal Iyer /*
4560dc2366fSVenugopal Iyer  * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
4570dc2366fSVenugopal Iyer  * dladm_walk_datalink_id(). Used for showing flow stats for
4580dc2366fSVenugopal Iyer  * all flows on all links.
4590dc2366fSVenugopal Iyer  */
4600dc2366fSVenugopal Iyer static int
4610dc2366fSVenugopal Iyer query_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg)
4620dc2366fSVenugopal Iyer {
4630dc2366fSVenugopal Iyer 	if (dladm_walk_flow(query_flow_stats, dh, linkid, arg, B_FALSE)
4640dc2366fSVenugopal Iyer 	    == DLADM_STATUS_OK)
4650dc2366fSVenugopal Iyer 		return (DLADM_WALK_CONTINUE);
4660dc2366fSVenugopal Iyer 	else
4670dc2366fSVenugopal Iyer 		return (DLADM_WALK_TERMINATE);
4680dc2366fSVenugopal Iyer }
4690dc2366fSVenugopal Iyer 
4700dc2366fSVenugopal Iyer void
4710dc2366fSVenugopal Iyer print_all_stats(name_value_stat_entry_t *stat_entry)
4720dc2366fSVenugopal Iyer {
4730dc2366fSVenugopal Iyer 	name_value_stat_t	*curr_stat;
4740dc2366fSVenugopal Iyer 
4750dc2366fSVenugopal Iyer 	printf("%s\n", stat_entry->nve_header);
4760dc2366fSVenugopal Iyer 
4770dc2366fSVenugopal Iyer 	for (curr_stat = stat_entry->nve_stats; curr_stat != NULL;
4780dc2366fSVenugopal Iyer 	    curr_stat = curr_stat->nv_nextstat) {
4790dc2366fSVenugopal Iyer 		printf("\t%15s", curr_stat->nv_statname);
4800dc2366fSVenugopal Iyer 		printf("\t%15llu\n", curr_stat->nv_statval);
4810dc2366fSVenugopal Iyer 	}
4820dc2366fSVenugopal Iyer }
4830dc2366fSVenugopal Iyer 
4840dc2366fSVenugopal Iyer /* ARGSUSED */
4850dc2366fSVenugopal Iyer static int
4860dc2366fSVenugopal Iyer dump_one_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
4870dc2366fSVenugopal Iyer {
4880dc2366fSVenugopal Iyer 	char	*flowname = attr->fa_flowname;
4890dc2366fSVenugopal Iyer 	void	*stat;
4900dc2366fSVenugopal Iyer 
4910dc2366fSVenugopal Iyer 	stat = dladm_flow_stat_query_all(flowname);
4920dc2366fSVenugopal Iyer 	if (stat == NULL)
4930dc2366fSVenugopal Iyer 		goto done;
4940dc2366fSVenugopal Iyer 	print_all_stats(stat);
4950dc2366fSVenugopal Iyer 	dladm_flow_stat_query_all_free(stat);
4960dc2366fSVenugopal Iyer 
4970dc2366fSVenugopal Iyer done:
4980dc2366fSVenugopal Iyer 	return (DLADM_WALK_CONTINUE);
4990dc2366fSVenugopal Iyer }
5000dc2366fSVenugopal Iyer 
5010dc2366fSVenugopal Iyer /*
5020dc2366fSVenugopal Iyer  * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
5030dc2366fSVenugopal Iyer  * dladm_walk_datalink_id(). Used for showing flow stats for
5040dc2366fSVenugopal Iyer  * all flows on all links.
5050dc2366fSVenugopal Iyer  */
5060dc2366fSVenugopal Iyer static int
5070dc2366fSVenugopal Iyer dump_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg)
5080dc2366fSVenugopal Iyer {
5090dc2366fSVenugopal Iyer 	if (dladm_walk_flow(dump_one_flow_stats, dh, linkid, arg, B_FALSE)
5100dc2366fSVenugopal Iyer 	    == DLADM_STATUS_OK)
5110dc2366fSVenugopal Iyer 		return (DLADM_WALK_CONTINUE);
5120dc2366fSVenugopal Iyer 	else
5130dc2366fSVenugopal Iyer 		return (DLADM_WALK_TERMINATE);
5140dc2366fSVenugopal Iyer }
5150dc2366fSVenugopal Iyer 
5160dc2366fSVenugopal Iyer static void
5170dc2366fSVenugopal Iyer dump_all_flow_stats(dladm_flow_attr_t *attrp, void *arg, datalink_id_t linkid,
5180dc2366fSVenugopal Iyer     boolean_t flow_arg)
5190dc2366fSVenugopal Iyer {
5200dc2366fSVenugopal Iyer 	/* Show stats for named flow */
5210dc2366fSVenugopal Iyer 	if (flow_arg)  {
5220dc2366fSVenugopal Iyer 		(void) dump_one_flow_stats(handle, attrp, arg);
5230dc2366fSVenugopal Iyer 
5240dc2366fSVenugopal Iyer 	/* Show stats for flows on one link */
5250dc2366fSVenugopal Iyer 	} else if (linkid != DATALINK_INVALID_LINKID) {
5260dc2366fSVenugopal Iyer 		(void) dladm_walk_flow(dump_one_flow_stats, handle, linkid,
5270dc2366fSVenugopal Iyer 		    arg, B_FALSE);
5280dc2366fSVenugopal Iyer 
5290dc2366fSVenugopal Iyer 	/* Show stats for all flows on all links */
5300dc2366fSVenugopal Iyer 	} else {
5310dc2366fSVenugopal Iyer 		(void) dladm_walk_datalink_id(dump_link_flow_stats,
5320dc2366fSVenugopal Iyer 		    handle, arg, DATALINK_CLASS_ALL,
5330dc2366fSVenugopal Iyer 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
5340dc2366fSVenugopal Iyer 	}
5350dc2366fSVenugopal Iyer }
5360dc2366fSVenugopal Iyer 
5370dc2366fSVenugopal Iyer int
5380dc2366fSVenugopal Iyer main(int argc, char *argv[])
5390dc2366fSVenugopal Iyer {
5400dc2366fSVenugopal Iyer 	dladm_status_t 		status;
5410dc2366fSVenugopal Iyer 	int			option;
5420dc2366fSVenugopal Iyer 	boolean_t		r_arg = B_FALSE;
5430dc2366fSVenugopal Iyer 	boolean_t		t_arg = B_FALSE;
5440dc2366fSVenugopal Iyer 	boolean_t		p_arg = B_FALSE;
5450dc2366fSVenugopal Iyer 	boolean_t		i_arg = B_FALSE;
5460dc2366fSVenugopal Iyer 	boolean_t		o_arg = B_FALSE;
5470dc2366fSVenugopal Iyer 	boolean_t		u_arg = B_FALSE;
5480dc2366fSVenugopal Iyer 	boolean_t		A_arg = B_FALSE;
5490dc2366fSVenugopal Iyer 	boolean_t		flow_arg = B_FALSE;
5500dc2366fSVenugopal Iyer 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5510dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
5520dc2366fSVenugopal Iyer 	char			flowname[MAXFLOWNAMELEN];
5530dc2366fSVenugopal Iyer 	uint32_t		interval = 0;
5540dc2366fSVenugopal Iyer 	char			unit = '\0';
5550dc2366fSVenugopal Iyer 	show_flow_state_t	state;
5560dc2366fSVenugopal Iyer 	char			*fields_str = NULL;
5570dc2366fSVenugopal Iyer 	char			*o_fields_str = NULL;
5580dc2366fSVenugopal Iyer 
5590dc2366fSVenugopal Iyer 	char			*total_stat_fields =
5600dc2366fSVenugopal Iyer 	    "flow,ipkts,rbytes,ierrs,opkts,obytes,oerrs";
5610dc2366fSVenugopal Iyer 	char			*rx_stat_fields =
5620dc2366fSVenugopal Iyer 	    "flow,ipkts,rbytes,ierrs";
5630dc2366fSVenugopal Iyer 	char			*tx_stat_fields =
5640dc2366fSVenugopal Iyer 	    "flow,opkts,obytes,oerrs";
5650dc2366fSVenugopal Iyer 
5660dc2366fSVenugopal Iyer 	ofmt_handle_t		ofmt;
5670dc2366fSVenugopal Iyer 	ofmt_status_t		oferr;
5680dc2366fSVenugopal Iyer 	uint_t			ofmtflags = OFMT_RIGHTJUST;
5690dc2366fSVenugopal Iyer 
5700dc2366fSVenugopal Iyer 	dladm_flow_attr_t	attr;
5710dc2366fSVenugopal Iyer 
5720dc2366fSVenugopal Iyer 	(void) setlocale(LC_ALL, "");
5730dc2366fSVenugopal Iyer #if !defined(TEXT_DOMAIN)
5740dc2366fSVenugopal Iyer #define	TEXT_DOMAIN "SYS_TEST"
5750dc2366fSVenugopal Iyer #endif
5760dc2366fSVenugopal Iyer 	(void) textdomain(TEXT_DOMAIN);
5770dc2366fSVenugopal Iyer 
5780dc2366fSVenugopal Iyer 	progname = argv[0];
5790dc2366fSVenugopal Iyer 
5800dc2366fSVenugopal Iyer 	/* Open the libdladm handle */
5810dc2366fSVenugopal Iyer 	if ((status = dladm_open(&handle)) != DLADM_STATUS_OK)
5820dc2366fSVenugopal Iyer 		die_dlerr(status, "could not open /dev/dld");
5830dc2366fSVenugopal Iyer 
5840dc2366fSVenugopal Iyer 	bzero(&state, sizeof (state));
5850dc2366fSVenugopal Iyer 
5860dc2366fSVenugopal Iyer 	opterr = 0;
587*62ef8476SYuri Pankov 	while ((option = getopt_long(argc, argv, ":rtApi:o:u:l:h",
5880dc2366fSVenugopal Iyer 	    NULL, NULL)) != -1) {
5890dc2366fSVenugopal Iyer 		switch (option) {
5900dc2366fSVenugopal Iyer 		case 'r':
5910dc2366fSVenugopal Iyer 			if (r_arg)
5920dc2366fSVenugopal Iyer 				die_optdup(option);
5930dc2366fSVenugopal Iyer 
5940dc2366fSVenugopal Iyer 			r_arg = B_TRUE;
5950dc2366fSVenugopal Iyer 			break;
5960dc2366fSVenugopal Iyer 		case 't':
5970dc2366fSVenugopal Iyer 			if (t_arg)
5980dc2366fSVenugopal Iyer 				die_optdup(option);
5990dc2366fSVenugopal Iyer 
6000dc2366fSVenugopal Iyer 			t_arg = B_TRUE;
6010dc2366fSVenugopal Iyer 			break;
6020dc2366fSVenugopal Iyer 		case 'A':
6030dc2366fSVenugopal Iyer 			if (A_arg)
6040dc2366fSVenugopal Iyer 				die_optdup(option);
6050dc2366fSVenugopal Iyer 
6060dc2366fSVenugopal Iyer 			A_arg = B_TRUE;
6070dc2366fSVenugopal Iyer 			break;
6080dc2366fSVenugopal Iyer 		case 'p':
6090dc2366fSVenugopal Iyer 			if (p_arg)
6100dc2366fSVenugopal Iyer 				die_optdup(option);
6110dc2366fSVenugopal Iyer 
6120dc2366fSVenugopal Iyer 			p_arg = B_TRUE;
6130dc2366fSVenugopal Iyer 			break;
6140dc2366fSVenugopal Iyer 		case 'i':
6150dc2366fSVenugopal Iyer 			if (i_arg)
6160dc2366fSVenugopal Iyer 				die_optdup(option);
6170dc2366fSVenugopal Iyer 
6180dc2366fSVenugopal Iyer 			i_arg = B_TRUE;
6190dc2366fSVenugopal Iyer 			if (!dladm_str2interval(optarg, &interval))
6200dc2366fSVenugopal Iyer 				die("invalid interval value '%s'", optarg);
6210dc2366fSVenugopal Iyer 			break;
6220dc2366fSVenugopal Iyer 		case 'o':
6230dc2366fSVenugopal Iyer 			o_arg = B_TRUE;
6240dc2366fSVenugopal Iyer 			o_fields_str = optarg;
6250dc2366fSVenugopal Iyer 			break;
6260dc2366fSVenugopal Iyer 		case 'u':
6270dc2366fSVenugopal Iyer 			if (u_arg)
6280dc2366fSVenugopal Iyer 				die_optdup(option);
6290dc2366fSVenugopal Iyer 
6300dc2366fSVenugopal Iyer 			u_arg = B_TRUE;
6310dc2366fSVenugopal Iyer 			if (!flowstat_unit(optarg, &unit))
6320dc2366fSVenugopal Iyer 				die("invalid unit value '%s',"
6330dc2366fSVenugopal Iyer 				    "unit must be R|K|M|G|T|P", optarg);
6340dc2366fSVenugopal Iyer 			break;
6350dc2366fSVenugopal Iyer 		case 'l':
6360dc2366fSVenugopal Iyer 			if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
6370dc2366fSVenugopal Iyer 			    >= MAXLINKNAMELEN)
6380dc2366fSVenugopal Iyer 				die("link name too long\n");
6390dc2366fSVenugopal Iyer 			if (dladm_name2info(handle, linkname, &linkid, NULL,
6400dc2366fSVenugopal Iyer 			    NULL, NULL) != DLADM_STATUS_OK)
6410dc2366fSVenugopal Iyer 				die("invalid link '%s'", linkname);
6420dc2366fSVenugopal Iyer 			break;
6430dc2366fSVenugopal Iyer 		case 'h':
6440dc2366fSVenugopal Iyer 			if (r_arg || t_arg || p_arg || o_arg || u_arg ||
645*62ef8476SYuri Pankov 			    i_arg || A_arg) {
6460dc2366fSVenugopal Iyer 				die("the option -h is not compatible with "
647*62ef8476SYuri Pankov 				    "-r, -t, -p, -o, -u, -i, -A");
6480dc2366fSVenugopal Iyer 			}
6490dc2366fSVenugopal Iyer 			do_show_history(argc, argv);
6500dc2366fSVenugopal Iyer 			return (0);
6510dc2366fSVenugopal Iyer 			break;
6520dc2366fSVenugopal Iyer 		default:
6530dc2366fSVenugopal Iyer 			die_opterr(optopt, option, usage_ermsg);
6540dc2366fSVenugopal Iyer 			break;
6550dc2366fSVenugopal Iyer 		}
6560dc2366fSVenugopal Iyer 	}
6570dc2366fSVenugopal Iyer 
6580dc2366fSVenugopal Iyer 	if (r_arg && t_arg)
6590dc2366fSVenugopal Iyer 		die("the option -t and -r are not compatible");
6600dc2366fSVenugopal Iyer 
6610dc2366fSVenugopal Iyer 	if (u_arg && p_arg)
6620dc2366fSVenugopal Iyer 		die("the option -u and -p are not compatible");
6630dc2366fSVenugopal Iyer 
6640dc2366fSVenugopal Iyer 	if (p_arg && !o_arg)
6650dc2366fSVenugopal Iyer 		die("-p requires -o");
6660dc2366fSVenugopal Iyer 
6670dc2366fSVenugopal Iyer 	if (p_arg && strcasecmp(o_fields_str, "all") == 0)
6680dc2366fSVenugopal Iyer 		die("\"-o all\" is invalid with -p");
6690dc2366fSVenugopal Iyer 
6700dc2366fSVenugopal Iyer 	if (A_arg &&
6710dc2366fSVenugopal Iyer 	    (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg))
6720dc2366fSVenugopal Iyer 		die("the option -A is not compatible with "
6730dc2366fSVenugopal Iyer 		    "-r, -t, -p, -o, -u, -i");
6740dc2366fSVenugopal Iyer 
6750dc2366fSVenugopal Iyer 	/* get flow name (optional last argument) */
6760dc2366fSVenugopal Iyer 	if (optind == (argc-1)) {
6770dc2366fSVenugopal Iyer 		if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
6780dc2366fSVenugopal Iyer 		    >= MAXFLOWNAMELEN)
6790dc2366fSVenugopal Iyer 			die("flow name too long");
6800dc2366fSVenugopal Iyer 		flow_arg = B_TRUE;
6810dc2366fSVenugopal Iyer 	} else if (optind != argc) {
6820dc2366fSVenugopal Iyer 		usage();
6830dc2366fSVenugopal Iyer 	}
6840dc2366fSVenugopal Iyer 
6850dc2366fSVenugopal Iyer 	if (flow_arg &&
6860dc2366fSVenugopal Iyer 	    dladm_flow_info(handle, flowname, &attr) != DLADM_STATUS_OK)
6870dc2366fSVenugopal Iyer 		die("invalid flow %s", flowname);
6880dc2366fSVenugopal Iyer 
6890dc2366fSVenugopal Iyer 	if (A_arg) {
6900dc2366fSVenugopal Iyer 		dump_all_flow_stats(&attr, &state, linkid, flow_arg);
6910dc2366fSVenugopal Iyer 		return (0);
6920dc2366fSVenugopal Iyer 	}
6930dc2366fSVenugopal Iyer 
6940dc2366fSVenugopal Iyer 	state.fs_unit = unit;
6950dc2366fSVenugopal Iyer 	state.fs_parsable = p_arg;
6960dc2366fSVenugopal Iyer 
6970dc2366fSVenugopal Iyer 	if (state.fs_parsable)
6980dc2366fSVenugopal Iyer 		ofmtflags |= OFMT_PARSABLE;
6990dc2366fSVenugopal Iyer 
7000dc2366fSVenugopal Iyer 	if (r_arg)
7010dc2366fSVenugopal Iyer 		fields_str = rx_stat_fields;
7020dc2366fSVenugopal Iyer 	else if (t_arg)
7030dc2366fSVenugopal Iyer 		fields_str = tx_stat_fields;
7040dc2366fSVenugopal Iyer 	else
7050dc2366fSVenugopal Iyer 		fields_str = total_stat_fields;
7060dc2366fSVenugopal Iyer 
7070dc2366fSVenugopal Iyer 	if (o_arg) {
7080dc2366fSVenugopal Iyer 		fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
7090dc2366fSVenugopal Iyer 		    fields_str : o_fields_str;
7100dc2366fSVenugopal Iyer 	}
7110dc2366fSVenugopal Iyer 
7120dc2366fSVenugopal Iyer 	oferr = ofmt_open(fields_str, flow_s_fields, ofmtflags, 0, &ofmt);
7130dc2366fSVenugopal Iyer 	flowstat_ofmt_check(oferr, state.fs_parsable, ofmt);
7140dc2366fSVenugopal Iyer 	state.fs_ofmt = ofmt;
7150dc2366fSVenugopal Iyer 
7160dc2366fSVenugopal Iyer 	for (;;) {
7170dc2366fSVenugopal Iyer 		/* Show stats for named flow */
7180dc2366fSVenugopal Iyer 		if (flow_arg)  {
7190dc2366fSVenugopal Iyer 			(void) query_flow_stats(handle, &attr, &state);
7200dc2366fSVenugopal Iyer 
7210dc2366fSVenugopal Iyer 		/* Show stats for flows on one link */
7220dc2366fSVenugopal Iyer 		} else if (linkid != DATALINK_INVALID_LINKID) {
7230dc2366fSVenugopal Iyer 			(void) dladm_walk_flow(query_flow_stats, handle, linkid,
7240dc2366fSVenugopal Iyer 			    &state, B_FALSE);
7250dc2366fSVenugopal Iyer 
7260dc2366fSVenugopal Iyer 		/* Show stats for all flows on all links */
7270dc2366fSVenugopal Iyer 		} else {
7280dc2366fSVenugopal Iyer 			(void) dladm_walk_datalink_id(query_link_flow_stats,
7290dc2366fSVenugopal Iyer 			    handle, &state, DATALINK_CLASS_ALL,
7300dc2366fSVenugopal Iyer 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
7310dc2366fSVenugopal Iyer 		}
7320dc2366fSVenugopal Iyer 
7330dc2366fSVenugopal Iyer 		if (interval == 0)
7340dc2366fSVenugopal Iyer 			break;
7350dc2366fSVenugopal Iyer 
7360dc2366fSVenugopal Iyer 		(void) fflush(stdout);
7370dc2366fSVenugopal Iyer 		cleanup_removed_flows(&state);
7380dc2366fSVenugopal Iyer 		(void) sleep(interval);
7390dc2366fSVenugopal Iyer 	}
7400dc2366fSVenugopal Iyer 	ofmt_close(ofmt);
7410dc2366fSVenugopal Iyer 
7420dc2366fSVenugopal Iyer 	dladm_close(handle);
7430dc2366fSVenugopal Iyer 	return (0);
7440dc2366fSVenugopal Iyer }
7450dc2366fSVenugopal Iyer 
7460dc2366fSVenugopal Iyer /* ARGSUSED */
7470dc2366fSVenugopal Iyer static int
7480dc2366fSVenugopal Iyer show_history_date(dladm_usage_t *history, void *arg)
7490dc2366fSVenugopal Iyer {
7500dc2366fSVenugopal Iyer 	show_history_state_t	*state = (show_history_state_t *)arg;
7510dc2366fSVenugopal Iyer 	time_t			stime;
7520dc2366fSVenugopal Iyer 	char			timebuf[20];
7530dc2366fSVenugopal Iyer 	dladm_flow_attr_t	attr;
7540dc2366fSVenugopal Iyer 	dladm_status_t		status;
7550dc2366fSVenugopal Iyer 
7560dc2366fSVenugopal Iyer 	/*
7570dc2366fSVenugopal Iyer 	 * Only show historical information for existing flows unless '-a'
7580dc2366fSVenugopal Iyer 	 * is specified.
7590dc2366fSVenugopal Iyer 	 */
7600dc2366fSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
7610dc2366fSVenugopal Iyer 	    history->du_name, &attr)) != DLADM_STATUS_OK)) {
7620dc2366fSVenugopal Iyer 		return (status);
7630dc2366fSVenugopal Iyer 	}
7640dc2366fSVenugopal Iyer 
7650dc2366fSVenugopal Iyer 	stime = history->du_stime;
7660dc2366fSVenugopal Iyer 	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
7670dc2366fSVenugopal Iyer 	    localtime(&stime));
7680dc2366fSVenugopal Iyer 	(void) printf("%s\n", timebuf);
7690dc2366fSVenugopal Iyer 
7700dc2366fSVenugopal Iyer 	return (DLADM_STATUS_OK);
7710dc2366fSVenugopal Iyer }
7720dc2366fSVenugopal Iyer 
7730dc2366fSVenugopal Iyer static int
7740dc2366fSVenugopal Iyer show_history_time(dladm_usage_t *history, void *arg)
7750dc2366fSVenugopal Iyer {
7760dc2366fSVenugopal Iyer 	show_history_state_t	*state = (show_history_state_t *)arg;
7770dc2366fSVenugopal Iyer 	char			buf[DLADM_STRSIZE];
7780dc2366fSVenugopal Iyer 	history_l_fields_buf_t 	ubuf;
7790dc2366fSVenugopal Iyer 	time_t			time;
7800dc2366fSVenugopal Iyer 	double			bw;
7810dc2366fSVenugopal Iyer 	dladm_flow_attr_t	attr;
7820dc2366fSVenugopal Iyer 	dladm_status_t		status;
7830dc2366fSVenugopal Iyer 
7840dc2366fSVenugopal Iyer 	/*
7850dc2366fSVenugopal Iyer 	 * Only show historical information for existing flows unless '-a'
7860dc2366fSVenugopal Iyer 	 * is specified.
7870dc2366fSVenugopal Iyer 	 */
7880dc2366fSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
7890dc2366fSVenugopal Iyer 	    history->du_name, &attr)) != DLADM_STATUS_OK)) {
7900dc2366fSVenugopal Iyer 		return (status);
7910dc2366fSVenugopal Iyer 	}
7920dc2366fSVenugopal Iyer 
7930dc2366fSVenugopal Iyer 	if (state->us_plot) {
7940dc2366fSVenugopal Iyer 		if (!state->us_printheader) {
7950dc2366fSVenugopal Iyer 			if (state->us_first) {
7960dc2366fSVenugopal Iyer 				(void) printf("# Time");
7970dc2366fSVenugopal Iyer 				state->us_first = B_FALSE;
7980dc2366fSVenugopal Iyer 			}
7990dc2366fSVenugopal Iyer 			(void) printf(" %s", history->du_name);
8000dc2366fSVenugopal Iyer 			if (history->du_last) {
8010dc2366fSVenugopal Iyer 				(void) printf("\n");
8020dc2366fSVenugopal Iyer 				state->us_first = B_TRUE;
8030dc2366fSVenugopal Iyer 				state->us_printheader = B_TRUE;
8040dc2366fSVenugopal Iyer 			}
8050dc2366fSVenugopal Iyer 		} else {
8060dc2366fSVenugopal Iyer 			if (state->us_first) {
8070dc2366fSVenugopal Iyer 				time = history->du_etime;
8080dc2366fSVenugopal Iyer 				(void) strftime(buf, sizeof (buf), "%T",
8090dc2366fSVenugopal Iyer 				    localtime(&time));
8100dc2366fSVenugopal Iyer 				state->us_first = B_FALSE;
8110dc2366fSVenugopal Iyer 				(void) printf("%s", buf);
8120dc2366fSVenugopal Iyer 			}
8130dc2366fSVenugopal Iyer 			bw = (double)history->du_bandwidth/1000;
8140dc2366fSVenugopal Iyer 			(void) printf(" %.2f", bw);
8150dc2366fSVenugopal Iyer 			if (history->du_last) {
8160dc2366fSVenugopal Iyer 				(void) printf("\n");
8170dc2366fSVenugopal Iyer 				state->us_first = B_TRUE;
8180dc2366fSVenugopal Iyer 			}
8190dc2366fSVenugopal Iyer 		}
8200dc2366fSVenugopal Iyer 		return (DLADM_STATUS_OK);
8210dc2366fSVenugopal Iyer 	}
8220dc2366fSVenugopal Iyer 
8230dc2366fSVenugopal Iyer 	bzero(&ubuf, sizeof (ubuf));
8240dc2366fSVenugopal Iyer 
8250dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_flow, sizeof (ubuf.history_l_flow), "%s",
8260dc2366fSVenugopal Iyer 	    history->du_name);
8270dc2366fSVenugopal Iyer 	time = history->du_stime;
8280dc2366fSVenugopal Iyer 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
8290dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_stime, sizeof (ubuf.history_l_stime),
8300dc2366fSVenugopal Iyer 	    "%s", buf);
8310dc2366fSVenugopal Iyer 	time = history->du_etime;
8320dc2366fSVenugopal Iyer 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
8330dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_etime, sizeof (ubuf.history_l_etime),
8340dc2366fSVenugopal Iyer 	    "%s", buf);
8350dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_rbytes, sizeof (ubuf.history_l_rbytes),
8360dc2366fSVenugopal Iyer 	    "%llu", history->du_rbytes);
8370dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_obytes, sizeof (ubuf.history_l_obytes),
8380dc2366fSVenugopal Iyer 	    "%llu", history->du_obytes);
8390dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_l_bandwidth,
8400dc2366fSVenugopal Iyer 	    sizeof (ubuf.history_l_bandwidth), "%s Mbps",
8410dc2366fSVenugopal Iyer 	    dladm_bw2str(history->du_bandwidth, buf));
8420dc2366fSVenugopal Iyer 
8430dc2366fSVenugopal Iyer 	ofmt_print(state->us_ofmt, (void *)&ubuf);
8440dc2366fSVenugopal Iyer 	return (DLADM_STATUS_OK);
8450dc2366fSVenugopal Iyer }
8460dc2366fSVenugopal Iyer 
8470dc2366fSVenugopal Iyer static int
8480dc2366fSVenugopal Iyer show_history_res(dladm_usage_t *history, void *arg)
8490dc2366fSVenugopal Iyer {
8500dc2366fSVenugopal Iyer 	show_history_state_t	*state = (show_history_state_t *)arg;
8510dc2366fSVenugopal Iyer 	char			buf[DLADM_STRSIZE];
8520dc2366fSVenugopal Iyer 	history_fields_buf_t	ubuf;
8530dc2366fSVenugopal Iyer 	dladm_flow_attr_t	attr;
8540dc2366fSVenugopal Iyer 	dladm_status_t		status;
8550dc2366fSVenugopal Iyer 
8560dc2366fSVenugopal Iyer 	/*
8570dc2366fSVenugopal Iyer 	 * Only show historical information for existing flows unless '-a'
8580dc2366fSVenugopal Iyer 	 * is specified.
8590dc2366fSVenugopal Iyer 	 */
8600dc2366fSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
8610dc2366fSVenugopal Iyer 	    history->du_name, &attr)) != DLADM_STATUS_OK)) {
8620dc2366fSVenugopal Iyer 		return (status);
8630dc2366fSVenugopal Iyer 	}
8640dc2366fSVenugopal Iyer 
8650dc2366fSVenugopal Iyer 	bzero(&ubuf, sizeof (ubuf));
8660dc2366fSVenugopal Iyer 
8670dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_flow, sizeof (ubuf.history_flow), "%s",
8680dc2366fSVenugopal Iyer 	    history->du_name);
8690dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_duration, sizeof (ubuf.history_duration),
8700dc2366fSVenugopal Iyer 	    "%llu", history->du_duration);
8710dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_ipackets, sizeof (ubuf.history_ipackets),
8720dc2366fSVenugopal Iyer 	    "%llu", history->du_ipackets);
8730dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_rbytes, sizeof (ubuf.history_rbytes),
8740dc2366fSVenugopal Iyer 	    "%llu", history->du_rbytes);
8750dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_opackets, sizeof (ubuf.history_opackets),
8760dc2366fSVenugopal Iyer 	    "%llu", history->du_opackets);
8770dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_obytes, sizeof (ubuf.history_obytes),
8780dc2366fSVenugopal Iyer 	    "%llu", history->du_obytes);
8790dc2366fSVenugopal Iyer 	(void) snprintf(ubuf.history_bandwidth, sizeof (ubuf.history_bandwidth),
8800dc2366fSVenugopal Iyer 	    "%s Mbps", dladm_bw2str(history->du_bandwidth, buf));
8810dc2366fSVenugopal Iyer 
8820dc2366fSVenugopal Iyer 	ofmt_print(state->us_ofmt, (void *)&ubuf);
8830dc2366fSVenugopal Iyer 
8840dc2366fSVenugopal Iyer 	return (DLADM_STATUS_OK);
8850dc2366fSVenugopal Iyer }
8860dc2366fSVenugopal Iyer 
8870dc2366fSVenugopal Iyer static boolean_t
8880dc2366fSVenugopal Iyer valid_formatspec(char *formatspec_str)
8890dc2366fSVenugopal Iyer {
8900dc2366fSVenugopal Iyer 	return (strcmp(formatspec_str, "gnuplot") == 0);
8910dc2366fSVenugopal Iyer }
8920dc2366fSVenugopal Iyer 
8930dc2366fSVenugopal Iyer /* ARGSUSED */
8940dc2366fSVenugopal Iyer static void
8950dc2366fSVenugopal Iyer do_show_history(int argc, char *argv[])
8960dc2366fSVenugopal Iyer {
8970dc2366fSVenugopal Iyer 	char			*file = NULL;
8980dc2366fSVenugopal Iyer 	int			opt;
8990dc2366fSVenugopal Iyer 	dladm_status_t		status;
9000dc2366fSVenugopal Iyer 	boolean_t		d_arg = B_FALSE;
9010dc2366fSVenugopal Iyer 	char			*stime = NULL;
9020dc2366fSVenugopal Iyer 	char			*etime = NULL;
9030dc2366fSVenugopal Iyer 	char			*resource = NULL;
9040dc2366fSVenugopal Iyer 	show_history_state_t	state;
9050dc2366fSVenugopal Iyer 	boolean_t		o_arg = B_FALSE;
9060dc2366fSVenugopal Iyer 	boolean_t		F_arg = B_FALSE;
9070dc2366fSVenugopal Iyer 	char			*fields_str = NULL;
9080dc2366fSVenugopal Iyer 	char			*formatspec_str = NULL;
9090dc2366fSVenugopal Iyer 	char			*all_fields =
9100dc2366fSVenugopal Iyer 	    "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth";
9110dc2366fSVenugopal Iyer 	char			*all_l_fields =
9120dc2366fSVenugopal Iyer 	    "flow,start,end,rbytes,obytes,bandwidth";
9130dc2366fSVenugopal Iyer 	ofmt_handle_t		ofmt;
9140dc2366fSVenugopal Iyer 	ofmt_status_t		oferr;
9150dc2366fSVenugopal Iyer 	uint_t			ofmtflags = 0;
9160dc2366fSVenugopal Iyer 
9170dc2366fSVenugopal Iyer 	bzero(&state, sizeof (show_history_state_t));
9180dc2366fSVenugopal Iyer 	state.us_parsable = B_FALSE;
9190dc2366fSVenugopal Iyer 	state.us_printheader = B_FALSE;
9200dc2366fSVenugopal Iyer 	state.us_plot = B_FALSE;
9210dc2366fSVenugopal Iyer 	state.us_first = B_TRUE;
9220dc2366fSVenugopal Iyer 
9230dc2366fSVenugopal Iyer 	while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) {
9240dc2366fSVenugopal Iyer 		switch (opt) {
9250dc2366fSVenugopal Iyer 		case 'd':
9260dc2366fSVenugopal Iyer 			d_arg = B_TRUE;
9270dc2366fSVenugopal Iyer 			break;
9280dc2366fSVenugopal Iyer 		case 'a':
9290dc2366fSVenugopal Iyer 			state.us_showall = B_TRUE;
9300dc2366fSVenugopal Iyer 			break;
9310dc2366fSVenugopal Iyer 		case 'f':
9320dc2366fSVenugopal Iyer 			file = optarg;
9330dc2366fSVenugopal Iyer 			break;
9340dc2366fSVenugopal Iyer 		case 's':
9350dc2366fSVenugopal Iyer 			stime = optarg;
9360dc2366fSVenugopal Iyer 			break;
9370dc2366fSVenugopal Iyer 		case 'e':
9380dc2366fSVenugopal Iyer 			etime = optarg;
9390dc2366fSVenugopal Iyer 			break;
9400dc2366fSVenugopal Iyer 		case 'o':
9410dc2366fSVenugopal Iyer 			o_arg = B_TRUE;
9420dc2366fSVenugopal Iyer 			fields_str = optarg;
9430dc2366fSVenugopal Iyer 			break;
9440dc2366fSVenugopal Iyer 		case 'F':
9450dc2366fSVenugopal Iyer 			state.us_plot = F_arg = B_TRUE;
9460dc2366fSVenugopal Iyer 			formatspec_str = optarg;
9470dc2366fSVenugopal Iyer 			break;
9480dc2366fSVenugopal Iyer 		default:
9490dc2366fSVenugopal Iyer 			die_opterr(optopt, opt, usage_ermsg);
9500dc2366fSVenugopal Iyer 		}
9510dc2366fSVenugopal Iyer 	}
9520dc2366fSVenugopal Iyer 
9530dc2366fSVenugopal Iyer 	if (file == NULL)
9540dc2366fSVenugopal Iyer 		die("-h requires a file");
9550dc2366fSVenugopal Iyer 
9560dc2366fSVenugopal Iyer 	if (optind == (argc-1)) {
9570dc2366fSVenugopal Iyer 		dladm_flow_attr_t	attr;
9580dc2366fSVenugopal Iyer 
9590dc2366fSVenugopal Iyer 		resource = argv[optind];
9600dc2366fSVenugopal Iyer 		if (!state.us_showall &&
9610dc2366fSVenugopal Iyer 		    dladm_flow_info(handle, resource, &attr) !=
9620dc2366fSVenugopal Iyer 		    DLADM_STATUS_OK) {
9630dc2366fSVenugopal Iyer 			die("invalid flow: '%s'", resource);
9640dc2366fSVenugopal Iyer 		}
9650dc2366fSVenugopal Iyer 	}
9660dc2366fSVenugopal Iyer 
9670dc2366fSVenugopal Iyer 	if (state.us_parsable)
9680dc2366fSVenugopal Iyer 		ofmtflags |= OFMT_PARSABLE;
9690dc2366fSVenugopal Iyer 	if (resource == NULL && stime == NULL && etime == NULL) {
9700dc2366fSVenugopal Iyer 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
9710dc2366fSVenugopal Iyer 			fields_str = all_fields;
9720dc2366fSVenugopal Iyer 		oferr = ofmt_open(fields_str, history_fields, ofmtflags,
9730dc2366fSVenugopal Iyer 		    0, &ofmt);
9740dc2366fSVenugopal Iyer 	} else {
9750dc2366fSVenugopal Iyer 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
9760dc2366fSVenugopal Iyer 			fields_str = all_l_fields;
9770dc2366fSVenugopal Iyer 		oferr = ofmt_open(fields_str, history_l_fields, ofmtflags,
9780dc2366fSVenugopal Iyer 		    0, &ofmt);
9790dc2366fSVenugopal Iyer 	}
9800dc2366fSVenugopal Iyer 
9810dc2366fSVenugopal Iyer 	flowstat_ofmt_check(oferr, state.us_parsable, ofmt);
9820dc2366fSVenugopal Iyer 	state.us_ofmt = ofmt;
9830dc2366fSVenugopal Iyer 
9840dc2366fSVenugopal Iyer 	if (F_arg && d_arg)
9850dc2366fSVenugopal Iyer 		die("incompatible -d and -F options");
9860dc2366fSVenugopal Iyer 
9870dc2366fSVenugopal Iyer 	if (F_arg && !valid_formatspec(formatspec_str))
9880dc2366fSVenugopal Iyer 		die("Format specifier %s not supported", formatspec_str);
9890dc2366fSVenugopal Iyer 
9900dc2366fSVenugopal Iyer 	if (d_arg) {
9910dc2366fSVenugopal Iyer 		/* Print log dates */
9920dc2366fSVenugopal Iyer 		status = dladm_usage_dates(show_history_date,
9930dc2366fSVenugopal Iyer 		    DLADM_LOGTYPE_FLOW, file, resource, &state);
9940dc2366fSVenugopal Iyer 	} else if (resource == NULL && stime == NULL && etime == NULL &&
9950dc2366fSVenugopal Iyer 	    !F_arg) {
9960dc2366fSVenugopal Iyer 		/* Print summary */
9970dc2366fSVenugopal Iyer 		status = dladm_usage_summary(show_history_res,
9980dc2366fSVenugopal Iyer 		    DLADM_LOGTYPE_FLOW, file, &state);
9990dc2366fSVenugopal Iyer 	} else if (resource != NULL) {
10000dc2366fSVenugopal Iyer 		/* Print log entries for named resource */
10010dc2366fSVenugopal Iyer 		status = dladm_walk_usage_res(show_history_time,
10020dc2366fSVenugopal Iyer 		    DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state);
10030dc2366fSVenugopal Iyer 	} else {
10040dc2366fSVenugopal Iyer 		/* Print time and information for each flow */
10050dc2366fSVenugopal Iyer 		status = dladm_walk_usage_time(show_history_time,
10060dc2366fSVenugopal Iyer 		    DLADM_LOGTYPE_FLOW, file, stime, etime, &state);
10070dc2366fSVenugopal Iyer 	}
10080dc2366fSVenugopal Iyer 
10090dc2366fSVenugopal Iyer 	ofmt_close(ofmt);
10100dc2366fSVenugopal Iyer 	if (status != DLADM_STATUS_OK)
10110dc2366fSVenugopal Iyer 		die_dlerr(status, "-h");
10120dc2366fSVenugopal Iyer 	dladm_close(handle);
10130dc2366fSVenugopal Iyer }
10140dc2366fSVenugopal Iyer 
10150dc2366fSVenugopal Iyer static void
10160dc2366fSVenugopal Iyer warn(const char *format, ...)
10170dc2366fSVenugopal Iyer {
10180dc2366fSVenugopal Iyer 	va_list alist;
10190dc2366fSVenugopal Iyer 
10200dc2366fSVenugopal Iyer 	format = gettext(format);
10210dc2366fSVenugopal Iyer 	(void) fprintf(stderr, "%s: warning: ", progname);
10220dc2366fSVenugopal Iyer 
10230dc2366fSVenugopal Iyer 	va_start(alist, format);
10240dc2366fSVenugopal Iyer 	(void) vfprintf(stderr, format, alist);
10250dc2366fSVenugopal Iyer 	va_end(alist);
10260dc2366fSVenugopal Iyer 
10270dc2366fSVenugopal Iyer 	(void) putc('\n', stderr);
10280dc2366fSVenugopal Iyer }
10290dc2366fSVenugopal Iyer 
10300dc2366fSVenugopal Iyer /* PRINTFLIKE1 */
10310dc2366fSVenugopal Iyer static void
10320dc2366fSVenugopal Iyer die(const char *format, ...)
10330dc2366fSVenugopal Iyer {
10340dc2366fSVenugopal Iyer 	va_list alist;
10350dc2366fSVenugopal Iyer 
10360dc2366fSVenugopal Iyer 	format = gettext(format);
10370dc2366fSVenugopal Iyer 	(void) fprintf(stderr, "%s: ", progname);
10380dc2366fSVenugopal Iyer 
10390dc2366fSVenugopal Iyer 	va_start(alist, format);
10400dc2366fSVenugopal Iyer 	(void) vfprintf(stderr, format, alist);
10410dc2366fSVenugopal Iyer 	va_end(alist);
10420dc2366fSVenugopal Iyer 
10430dc2366fSVenugopal Iyer 	(void) putc('\n', stderr);
10440dc2366fSVenugopal Iyer 
10450dc2366fSVenugopal Iyer 	/* close dladm handle if it was opened */
10460dc2366fSVenugopal Iyer 	if (handle != NULL)
10470dc2366fSVenugopal Iyer 		dladm_close(handle);
10480dc2366fSVenugopal Iyer 
10490dc2366fSVenugopal Iyer 	exit(EXIT_FAILURE);
10500dc2366fSVenugopal Iyer }
10510dc2366fSVenugopal Iyer 
10520dc2366fSVenugopal Iyer static void
10530dc2366fSVenugopal Iyer die_optdup(int opt)
10540dc2366fSVenugopal Iyer {
10550dc2366fSVenugopal Iyer 	die("the option -%c cannot be specified more than once", opt);
10560dc2366fSVenugopal Iyer }
10570dc2366fSVenugopal Iyer 
10580dc2366fSVenugopal Iyer static void
10590dc2366fSVenugopal Iyer die_opterr(int opt, int opterr, const char *usage)
10600dc2366fSVenugopal Iyer {
10610dc2366fSVenugopal Iyer 	switch (opterr) {
10620dc2366fSVenugopal Iyer 	case ':':
10630dc2366fSVenugopal Iyer 		die("option '-%c' requires a value\nusage: %s", opt,
10640dc2366fSVenugopal Iyer 		    gettext(usage));
10650dc2366fSVenugopal Iyer 		break;
10660dc2366fSVenugopal Iyer 	case '?':
10670dc2366fSVenugopal Iyer 	default:
10680dc2366fSVenugopal Iyer 		die("unrecognized option '-%c'\nusage: %s", opt,
10690dc2366fSVenugopal Iyer 		    gettext(usage));
10700dc2366fSVenugopal Iyer 		break;
10710dc2366fSVenugopal Iyer 	}
10720dc2366fSVenugopal Iyer }
10730dc2366fSVenugopal Iyer 
10740dc2366fSVenugopal Iyer /* PRINTFLIKE2 */
10750dc2366fSVenugopal Iyer static void
10760dc2366fSVenugopal Iyer die_dlerr(dladm_status_t err, const char *format, ...)
10770dc2366fSVenugopal Iyer {
10780dc2366fSVenugopal Iyer 	va_list alist;
10790dc2366fSVenugopal Iyer 	char	errmsg[DLADM_STRSIZE];
10800dc2366fSVenugopal Iyer 
10810dc2366fSVenugopal Iyer 	format = gettext(format);
10820dc2366fSVenugopal Iyer 	(void) fprintf(stderr, "%s: ", progname);
10830dc2366fSVenugopal Iyer 
10840dc2366fSVenugopal Iyer 	va_start(alist, format);
10850dc2366fSVenugopal Iyer 	(void) vfprintf(stderr, format, alist);
10860dc2366fSVenugopal Iyer 	va_end(alist);
10870dc2366fSVenugopal Iyer 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
10880dc2366fSVenugopal Iyer 
10890dc2366fSVenugopal Iyer 	/* close dladm handle if it was opened */
10900dc2366fSVenugopal Iyer 	if (handle != NULL)
10910dc2366fSVenugopal Iyer 		dladm_close(handle);
10920dc2366fSVenugopal Iyer 
10930dc2366fSVenugopal Iyer 	exit(EXIT_FAILURE);
10940dc2366fSVenugopal Iyer }
10950dc2366fSVenugopal Iyer 
10960dc2366fSVenugopal Iyer 
10970dc2366fSVenugopal Iyer /*
10980dc2366fSVenugopal Iyer  * default output callback function that, when invoked from dladm_print_output,
10990dc2366fSVenugopal Iyer  * prints string which is offset by of_arg->ofmt_id within buf.
11000dc2366fSVenugopal Iyer  */
11010dc2366fSVenugopal Iyer static boolean_t
11020dc2366fSVenugopal Iyer print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
11030dc2366fSVenugopal Iyer {
11040dc2366fSVenugopal Iyer 	char *value;
11050dc2366fSVenugopal Iyer 
11060dc2366fSVenugopal Iyer 	value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id;
11070dc2366fSVenugopal Iyer 	(void) strlcpy(buf, value, bufsize);
11080dc2366fSVenugopal Iyer 	return (B_TRUE);
11090dc2366fSVenugopal Iyer }
11100dc2366fSVenugopal Iyer 
11110dc2366fSVenugopal Iyer static void
11120dc2366fSVenugopal Iyer flowstat_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
11130dc2366fSVenugopal Iyer     ofmt_handle_t ofmt)
11140dc2366fSVenugopal Iyer {
11150dc2366fSVenugopal Iyer 	char buf[OFMT_BUFSIZE];
11160dc2366fSVenugopal Iyer 
11170dc2366fSVenugopal Iyer 	if (oferr == OFMT_SUCCESS)
11180dc2366fSVenugopal Iyer 		return;
11190dc2366fSVenugopal Iyer 	(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
11200dc2366fSVenugopal Iyer 	/*
11210dc2366fSVenugopal Iyer 	 * All errors are considered fatal in parsable mode.
11220dc2366fSVenugopal Iyer 	 * NOMEM errors are always fatal, regardless of mode.
11230dc2366fSVenugopal Iyer 	 * For other errors, we print diagnostics in human-readable
11240dc2366fSVenugopal Iyer 	 * mode and processs what we can.
11250dc2366fSVenugopal Iyer 	 */
11260dc2366fSVenugopal Iyer 	if (parsable || oferr == OFMT_ENOFIELDS) {
11270dc2366fSVenugopal Iyer 		ofmt_close(ofmt);
11280dc2366fSVenugopal Iyer 		die(buf);
11290dc2366fSVenugopal Iyer 	} else {
11300dc2366fSVenugopal Iyer 		warn(buf);
11310dc2366fSVenugopal Iyer 	}
11320dc2366fSVenugopal Iyer }
1133