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