xref: /titanic_51/usr/src/cmd/flowadm/flowadm.c (revision 25ec3e3dd27cc1038c10efa18ed08f064eab5fbe)
1da14cebeSEric Cheng /*
2da14cebeSEric Cheng  * CDDL HEADER START
3da14cebeSEric Cheng  *
4da14cebeSEric Cheng  * The contents of this file are subject to the terms of the
5da14cebeSEric Cheng  * Common Development and Distribution License (the "License").
6da14cebeSEric Cheng  * You may not use this file except in compliance with the License.
7da14cebeSEric Cheng  *
8da14cebeSEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da14cebeSEric Cheng  * or http://www.opensolaris.org/os/licensing.
10da14cebeSEric Cheng  * See the License for the specific language governing permissions
11da14cebeSEric Cheng  * and limitations under the License.
12da14cebeSEric Cheng  *
13da14cebeSEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
14da14cebeSEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da14cebeSEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
16da14cebeSEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
17da14cebeSEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
18da14cebeSEric Cheng  *
19da14cebeSEric Cheng  * CDDL HEADER END
20da14cebeSEric Cheng  */
21da14cebeSEric Cheng /*
22da000602SGirish Moodalbail  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da14cebeSEric Cheng  * Use is subject to license terms.
24da14cebeSEric Cheng  */
25da14cebeSEric Cheng 
26da14cebeSEric Cheng #include <stdio.h>
27da14cebeSEric Cheng #include <locale.h>
28da14cebeSEric Cheng #include <stdarg.h>
29da14cebeSEric Cheng #include <stdlib.h>
30da14cebeSEric Cheng #include <fcntl.h>
31da14cebeSEric Cheng #include <string.h>
32da14cebeSEric Cheng #include <stropts.h>
33da14cebeSEric Cheng #include <errno.h>
34da14cebeSEric Cheng #include <kstat.h>
35da14cebeSEric Cheng #include <strings.h>
36da14cebeSEric Cheng #include <getopt.h>
37da14cebeSEric Cheng #include <unistd.h>
38da14cebeSEric Cheng #include <priv.h>
39da14cebeSEric Cheng #include <netdb.h>
40da14cebeSEric Cheng #include <libintl.h>
41da14cebeSEric Cheng #include <libdlflow.h>
42da14cebeSEric Cheng #include <libdllink.h>
43da14cebeSEric Cheng #include <libdlstat.h>
44da14cebeSEric Cheng #include <sys/types.h>
45da14cebeSEric Cheng #include <sys/socket.h>
46da14cebeSEric Cheng #include <netinet/in.h>
47da14cebeSEric Cheng #include <arpa/inet.h>
48da14cebeSEric Cheng #include <sys/ethernet.h>
49da14cebeSEric Cheng #include <inet/ip.h>
50da14cebeSEric Cheng #include <inet/ip6.h>
51da14cebeSEric Cheng #include <stddef.h>
528002d411SSowmini Varadhan #include <ofmt.h>
53da14cebeSEric Cheng 
54da14cebeSEric Cheng typedef struct show_usage_state_s {
55da14cebeSEric Cheng 	boolean_t	us_plot;
568002d411SSowmini Varadhan 	boolean_t	us_parsable;
57da14cebeSEric Cheng 	boolean_t	us_printheader;
58da14cebeSEric Cheng 	boolean_t	us_first;
59ae6aa22aSVenugopal Iyer 	boolean_t	us_showall;
608002d411SSowmini Varadhan 	ofmt_handle_t	us_ofmt;
61da14cebeSEric Cheng } show_usage_state_t;
62da14cebeSEric Cheng 
63ae6aa22aSVenugopal Iyer typedef struct show_flow_state {
64ae6aa22aSVenugopal Iyer 	boolean_t		fs_firstonly;
65ae6aa22aSVenugopal Iyer 	boolean_t		fs_donefirst;
66ae6aa22aSVenugopal Iyer 	pktsum_t		fs_prevstats;
67ae6aa22aSVenugopal Iyer 	uint32_t		fs_flags;
68ae6aa22aSVenugopal Iyer 	dladm_status_t		fs_status;
698002d411SSowmini Varadhan 	ofmt_handle_t		fs_ofmt;
70ae6aa22aSVenugopal Iyer 	const char		*fs_flow;
71ae6aa22aSVenugopal Iyer 	const char		*fs_link;
728002d411SSowmini Varadhan 	boolean_t		fs_parsable;
73ae6aa22aSVenugopal Iyer 	boolean_t		fs_persist;
74ae6aa22aSVenugopal Iyer 	boolean_t		fs_stats;
75ae6aa22aSVenugopal Iyer 	uint64_t		fs_mask;
76ae6aa22aSVenugopal Iyer } show_flow_state_t;
77ae6aa22aSVenugopal Iyer 
78da14cebeSEric Cheng typedef void cmdfunc_t(int, char **);
79da14cebeSEric Cheng 
80da14cebeSEric Cheng static cmdfunc_t do_add_flow, do_remove_flow, do_init_flow, do_show_flow;
81da14cebeSEric Cheng static cmdfunc_t do_show_flowprop, do_set_flowprop, do_reset_flowprop;
82da14cebeSEric Cheng static cmdfunc_t do_show_usage;
83da14cebeSEric Cheng 
84c3affd82SMichael Lim static int	show_flow(dladm_handle_t, dladm_flow_attr_t *, void *);
854ac67f02SAnurag S. Maskey static int	show_flows_onelink(dladm_handle_t, datalink_id_t, void *);
86da14cebeSEric Cheng 
87ae6aa22aSVenugopal Iyer static void	flow_stats(const char *, datalink_id_t,  uint_t, char *,
88ae6aa22aSVenugopal Iyer 		    show_flow_state_t *);
89da14cebeSEric Cheng static void	get_flow_stats(const char *, pktsum_t *);
90c3affd82SMichael Lim static int	show_flow_stats(dladm_handle_t, dladm_flow_attr_t *, void *);
914ac67f02SAnurag S. Maskey static int	show_link_flow_stats(dladm_handle_t, datalink_id_t, void *);
92da14cebeSEric Cheng 
93c3affd82SMichael Lim static int	remove_flow(dladm_handle_t, dladm_flow_attr_t *, void *);
94da14cebeSEric Cheng 
95c3affd82SMichael Lim static int	show_flowprop(dladm_handle_t, dladm_flow_attr_t *, void *);
96da14cebeSEric Cheng static void	show_flowprop_one_flow(void *, const char *);
974ac67f02SAnurag S. Maskey static int	show_flowprop_onelink(dladm_handle_t, datalink_id_t, void *);
98da14cebeSEric Cheng 
99da14cebeSEric Cheng static void	die(const char *, ...);
100da14cebeSEric Cheng static void	die_optdup(int);
101da14cebeSEric Cheng static void	die_opterr(int, int);
102da14cebeSEric Cheng static void	die_dlerr(dladm_status_t, const char *, ...);
103da14cebeSEric Cheng static void	warn(const char *, ...);
104da14cebeSEric Cheng static void	warn_dlerr(dladm_status_t, const char *, ...);
105da14cebeSEric Cheng 
1068002d411SSowmini Varadhan /* callback functions for printing output */
1078002d411SSowmini Varadhan static ofmt_cb_t print_flowprop_cb, print_default_cb, print_flow_stats_cb;
1088002d411SSowmini Varadhan static void flowadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
1098002d411SSowmini Varadhan 
110da14cebeSEric Cheng typedef struct	cmd {
111da14cebeSEric Cheng 	char	*c_name;
112da14cebeSEric Cheng 	void	(*c_fn)(int, char **);
113da14cebeSEric Cheng } cmd_t;
114da14cebeSEric Cheng 
115da14cebeSEric Cheng static cmd_t	cmds[] = {
116da14cebeSEric Cheng 	{ "add-flow", do_add_flow },
117da14cebeSEric Cheng 	{ "remove-flow", do_remove_flow },
118da14cebeSEric Cheng 	{ "show-flowprop", do_show_flowprop },
119da14cebeSEric Cheng 	{ "set-flowprop", do_set_flowprop },
120da14cebeSEric Cheng 	{ "reset-flowprop", do_reset_flowprop },
121da14cebeSEric Cheng 	{ "show-flow", do_show_flow },
122da14cebeSEric Cheng 	{ "init-flow", do_init_flow },
123da14cebeSEric Cheng 	{ "show-usage", do_show_usage }
124da14cebeSEric Cheng };
125da14cebeSEric Cheng 
126da14cebeSEric Cheng static const struct option longopts[] = {
127da14cebeSEric Cheng 	{"link",		required_argument,	0, 'l'},
1288002d411SSowmini Varadhan 	{"parsable",		no_argument,		0, 'p'},
129da14cebeSEric Cheng 	{"parseable",		no_argument,		0, 'p'},
130da14cebeSEric Cheng 	{"statistics",		no_argument,		0, 's'},
131da14cebeSEric Cheng 	{"interval",		required_argument,	0, 'i'},
132da14cebeSEric Cheng 	{"temporary",		no_argument,		0, 't'},
133da14cebeSEric Cheng 	{"root-dir",		required_argument,	0, 'R'},
134da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
135da14cebeSEric Cheng };
136da14cebeSEric Cheng 
137da14cebeSEric Cheng static const struct option prop_longopts[] = {
138da14cebeSEric Cheng 	{"link",		required_argument,	0, 'l'},
139da14cebeSEric Cheng 	{"temporary",		no_argument,		0, 't'},
140da14cebeSEric Cheng 	{"root-dir",		required_argument,	0, 'R'},
141da14cebeSEric Cheng 	{"prop",		required_argument,	0, 'p'},
142da14cebeSEric Cheng 	{"attr",		required_argument,	0, 'a'},
143da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
144da14cebeSEric Cheng };
145da14cebeSEric Cheng 
146da14cebeSEric Cheng /*
147da14cebeSEric Cheng  * structures for 'flowadm remove-flow'
148da14cebeSEric Cheng  */
149da14cebeSEric Cheng typedef struct remove_flow_state {
150da14cebeSEric Cheng 	boolean_t	fs_tempop;
151da14cebeSEric Cheng 	const char	*fs_altroot;
152da14cebeSEric Cheng 	dladm_status_t	fs_status;
153da14cebeSEric Cheng } remove_flow_state_t;
154da14cebeSEric Cheng 
155da14cebeSEric Cheng #define	PROTO_MAXSTR_LEN	7
156da14cebeSEric Cheng #define	PORT_MAXSTR_LEN		6
157da14cebeSEric Cheng #define	DSFIELD_MAXSTR_LEN	10
1588002d411SSowmini Varadhan #define	NULL_OFMT		{NULL, 0, 0, NULL}
159da14cebeSEric Cheng 
160da14cebeSEric Cheng typedef struct flow_fields_buf_s
161da14cebeSEric Cheng {
162da000602SGirish Moodalbail 	char flow_name[MAXFLOWNAMELEN];
163da14cebeSEric Cheng 	char flow_link[MAXLINKNAMELEN];
164da14cebeSEric Cheng 	char flow_ipaddr[INET6_ADDRSTRLEN+4];
165da14cebeSEric Cheng 	char flow_proto[PROTO_MAXSTR_LEN];
166*25ec3e3dSEric Cheng 	char flow_lport[PORT_MAXSTR_LEN];
167*25ec3e3dSEric Cheng 	char flow_rport[PORT_MAXSTR_LEN];
168da14cebeSEric Cheng 	char flow_dsfield[DSFIELD_MAXSTR_LEN];
169da14cebeSEric Cheng } flow_fields_buf_t;
170da14cebeSEric Cheng 
1718002d411SSowmini Varadhan static ofmt_field_t flow_fields[] = {
1728002d411SSowmini Varadhan /* name,	field width,	index */
1738002d411SSowmini Varadhan {  "FLOW",	12,
1748002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_name), print_default_cb},
1758002d411SSowmini Varadhan {  "LINK",	12,
1768002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_link), print_default_cb},
177*25ec3e3dSEric Cheng {  "IPADDR",	25,
1788002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb},
1798002d411SSowmini Varadhan {  "PROTO",	7,
1808002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_proto), print_default_cb},
181*25ec3e3dSEric Cheng {  "LPORT",	8,
182*25ec3e3dSEric Cheng 	offsetof(flow_fields_buf_t, flow_lport), print_default_cb},
183*25ec3e3dSEric Cheng {  "RPORT",	8,
184*25ec3e3dSEric Cheng 	offsetof(flow_fields_buf_t, flow_rport), print_default_cb},
1858002d411SSowmini Varadhan {  "DSFLD",	10,
1868002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb},
1878002d411SSowmini Varadhan NULL_OFMT}
188da14cebeSEric Cheng ;
189da14cebeSEric Cheng 
190da14cebeSEric Cheng /*
191da14cebeSEric Cheng  * structures for 'flowadm show-flowprop'
192da14cebeSEric Cheng  */
193da14cebeSEric Cheng typedef enum {
194da14cebeSEric Cheng 	FLOWPROP_FLOW,
195da14cebeSEric Cheng 	FLOWPROP_PROPERTY,
196da14cebeSEric Cheng 	FLOWPROP_VALUE,
197da14cebeSEric Cheng 	FLOWPROP_DEFAULT,
198da14cebeSEric Cheng 	FLOWPROP_POSSIBLE
199da14cebeSEric Cheng } flowprop_field_index_t;
200da14cebeSEric Cheng 
2018002d411SSowmini Varadhan static ofmt_field_t flowprop_fields[] = {
2028002d411SSowmini Varadhan /* name,	fieldwidth,	index, 		callback */
2038002d411SSowmini Varadhan { "FLOW",	13,	FLOWPROP_FLOW,		print_flowprop_cb},
2048002d411SSowmini Varadhan { "PROPERTY",	16,	FLOWPROP_PROPERTY,	print_flowprop_cb},
2058002d411SSowmini Varadhan { "VALUE",	15,	FLOWPROP_VALUE,		print_flowprop_cb},
2068002d411SSowmini Varadhan { "DEFAULT",	15,	FLOWPROP_DEFAULT,	print_flowprop_cb},
2078002d411SSowmini Varadhan { "POSSIBLE",	21,	FLOWPROP_POSSIBLE,	print_flowprop_cb},
2088002d411SSowmini Varadhan NULL_OFMT}
209da14cebeSEric Cheng ;
210da14cebeSEric Cheng 
211da14cebeSEric Cheng #define	MAX_PROP_LINE		512
212da14cebeSEric Cheng 
213da14cebeSEric Cheng typedef struct show_flowprop_state {
214da14cebeSEric Cheng 	const char		*fs_flow;
215da14cebeSEric Cheng 	datalink_id_t		fs_linkid;
216da14cebeSEric Cheng 	char			*fs_line;
217da14cebeSEric Cheng 	char			**fs_propvals;
218da14cebeSEric Cheng 	dladm_arg_list_t	*fs_proplist;
2198002d411SSowmini Varadhan 	boolean_t		fs_parsable;
220da14cebeSEric Cheng 	boolean_t		fs_persist;
221da14cebeSEric Cheng 	boolean_t		fs_header;
222da14cebeSEric Cheng 	dladm_status_t		fs_status;
223da14cebeSEric Cheng 	dladm_status_t		fs_retstatus;
2248002d411SSowmini Varadhan 	ofmt_handle_t		fs_ofmt;
225da14cebeSEric Cheng } show_flowprop_state_t;
226da14cebeSEric Cheng 
227da14cebeSEric Cheng typedef struct set_flowprop_state {
228da14cebeSEric Cheng 	const char	*fs_name;
229da14cebeSEric Cheng 	boolean_t	fs_reset;
230da14cebeSEric Cheng 	boolean_t	fs_temp;
231da14cebeSEric Cheng 	dladm_status_t	fs_status;
232da14cebeSEric Cheng } set_flowprop_state_t;
233da14cebeSEric Cheng 
234da14cebeSEric Cheng typedef struct flowprop_args_s {
235da14cebeSEric Cheng 	show_flowprop_state_t	*fs_state;
236da14cebeSEric Cheng 	char			*fs_propname;
237da14cebeSEric Cheng 	char			*fs_flowname;
238da14cebeSEric Cheng } flowprop_args_t;
239ae6aa22aSVenugopal Iyer /*
240ae6aa22aSVenugopal Iyer  * structures for 'flowadm show-flow -s' (print statistics)
241ae6aa22aSVenugopal Iyer  */
242ae6aa22aSVenugopal Iyer typedef enum {
243ae6aa22aSVenugopal Iyer 	FLOW_S_FLOW,
244ae6aa22aSVenugopal Iyer 	FLOW_S_IPKTS,
245ae6aa22aSVenugopal Iyer 	FLOW_S_RBYTES,
246ae6aa22aSVenugopal Iyer 	FLOW_S_IERRORS,
247ae6aa22aSVenugopal Iyer 	FLOW_S_OPKTS,
248ae6aa22aSVenugopal Iyer 	FLOW_S_OBYTES,
249ae6aa22aSVenugopal Iyer 	FLOW_S_OERRORS
250ae6aa22aSVenugopal Iyer } flow_s_field_index_t;
251ae6aa22aSVenugopal Iyer 
2528002d411SSowmini Varadhan static ofmt_field_t flow_s_fields[] = {
2538002d411SSowmini Varadhan /* name,	field width,	index,		callback */
2548002d411SSowmini Varadhan { "FLOW",	15,	FLOW_S_FLOW,	print_flow_stats_cb},
2558002d411SSowmini Varadhan { "IPACKETS",	10,	FLOW_S_IPKTS,	print_flow_stats_cb},
2568002d411SSowmini Varadhan { "RBYTES",	8,	FLOW_S_RBYTES,	print_flow_stats_cb},
2578002d411SSowmini Varadhan { "IERRORS",	10,	FLOW_S_IERRORS,	print_flow_stats_cb},
2588002d411SSowmini Varadhan { "OPACKETS",	12,	FLOW_S_OPKTS,	print_flow_stats_cb},
2598002d411SSowmini Varadhan { "OBYTES",	12,	FLOW_S_OBYTES,	print_flow_stats_cb},
2608002d411SSowmini Varadhan { "OERRORS",	8,	FLOW_S_OERRORS,	print_flow_stats_cb},
2618002d411SSowmini Varadhan NULL_OFMT}
262ae6aa22aSVenugopal Iyer ;
263ae6aa22aSVenugopal Iyer 
264ae6aa22aSVenugopal Iyer typedef struct flow_args_s {
265ae6aa22aSVenugopal Iyer 	char		*flow_s_flow;
266ae6aa22aSVenugopal Iyer 	pktsum_t	*flow_s_psum;
267ae6aa22aSVenugopal Iyer } flow_args_t;
268da14cebeSEric Cheng 
269da14cebeSEric Cheng /*
270ae6aa22aSVenugopal Iyer  * structures for 'flowadm show-usage'
271da14cebeSEric Cheng  */
272da14cebeSEric Cheng typedef struct  usage_fields_buf_s {
273da14cebeSEric Cheng 	char	usage_flow[12];
274da14cebeSEric Cheng 	char	usage_duration[10];
275da14cebeSEric Cheng 	char	usage_ipackets[9];
276da14cebeSEric Cheng 	char	usage_rbytes[10];
277da14cebeSEric Cheng 	char	usage_opackets[9];
278da14cebeSEric Cheng 	char	usage_obytes[10];
279da14cebeSEric Cheng 	char	usage_bandwidth[14];
280da14cebeSEric Cheng } usage_fields_buf_t;
281da14cebeSEric Cheng 
2828002d411SSowmini Varadhan static ofmt_field_t usage_fields[] = {
2838002d411SSowmini Varadhan /* name,	field width,	offset */
2848002d411SSowmini Varadhan { "FLOW",	13,
2858002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_flow), print_default_cb},
2868002d411SSowmini Varadhan { "DURATION",	11,
2878002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_duration), print_default_cb},
2888002d411SSowmini Varadhan { "IPACKETS",	10,
2898002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb},
2908002d411SSowmini Varadhan { "RBYTES",	11,
2918002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb},
2928002d411SSowmini Varadhan { "OPACKETS",	10,
2938002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_opackets), print_default_cb},
2948002d411SSowmini Varadhan { "OBYTES",	11,
2958002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_obytes), print_default_cb},
2968002d411SSowmini Varadhan { "BANDWIDTH",	15,
2978002d411SSowmini Varadhan 	offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb},
2988002d411SSowmini Varadhan NULL_OFMT}
299da14cebeSEric Cheng ;
300da14cebeSEric Cheng 
301da14cebeSEric Cheng /*
302da14cebeSEric Cheng  * structures for 'dladm show-usage link'
303da14cebeSEric Cheng  */
304da14cebeSEric Cheng 
305da14cebeSEric Cheng typedef struct  usage_l_fields_buf_s {
306da14cebeSEric Cheng 	char	usage_l_flow[12];
307da14cebeSEric Cheng 	char	usage_l_stime[13];
308da14cebeSEric Cheng 	char	usage_l_etime[13];
309da14cebeSEric Cheng 	char	usage_l_rbytes[8];
310da14cebeSEric Cheng 	char	usage_l_obytes[8];
311da14cebeSEric Cheng 	char	usage_l_bandwidth[14];
312da14cebeSEric Cheng } usage_l_fields_buf_t;
313da14cebeSEric Cheng 
3148002d411SSowmini Varadhan static ofmt_field_t usage_l_fields[] = {
3158002d411SSowmini Varadhan /* name,	field width,	offset */
3168002d411SSowmini Varadhan { "FLOW",	13,
3178002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_flow), print_default_cb},
3188002d411SSowmini Varadhan { "START",	14,
3198002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb},
3208002d411SSowmini Varadhan { "END",	14,
3218002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb},
3228002d411SSowmini Varadhan { "RBYTES",	9,
3238002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb},
3248002d411SSowmini Varadhan { "OBYTES",	9,
3258002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb},
3268002d411SSowmini Varadhan { "BANDWIDTH",	15,
3278002d411SSowmini Varadhan 	offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb},
3288002d411SSowmini Varadhan NULL_OFMT}
329da14cebeSEric Cheng ;
330da14cebeSEric Cheng 
331da14cebeSEric Cheng #define	PRI_HI		100
332da14cebeSEric Cheng #define	PRI_LO 		10
333da14cebeSEric Cheng #define	PRI_NORM	50
334da14cebeSEric Cheng 
335da14cebeSEric Cheng #define	FLOWADM_CONF	"/etc/dladm/flowadm.conf"
336da14cebeSEric Cheng #define	BLANK_LINE(s)	((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n'))
337da14cebeSEric Cheng 
338da14cebeSEric Cheng static char *progname;
339da14cebeSEric Cheng 
340da14cebeSEric Cheng boolean_t		t_arg = B_FALSE; /* changes are persistent */
341da14cebeSEric Cheng char			*altroot = NULL;
342da14cebeSEric Cheng 
3434ac67f02SAnurag S. Maskey /*
3444ac67f02SAnurag S. Maskey  * Handle to libdladm.  Opened in main() before the sub-command
3454ac67f02SAnurag S. Maskey  * specific function is called.
3464ac67f02SAnurag S. Maskey  */
3474ac67f02SAnurag S. Maskey static dladm_handle_t handle = NULL;
3484ac67f02SAnurag S. Maskey 
349da14cebeSEric Cheng static const char *attr_table[] =
350*25ec3e3dSEric Cheng 	{"local_ip", "remote_ip", "transport", "local_port", "remote_port",
351*25ec3e3dSEric Cheng 	    "dsfield"};
352da14cebeSEric Cheng 
353da14cebeSEric Cheng #define	NATTR	(sizeof (attr_table)/sizeof (char *))
354da14cebeSEric Cheng 
355da14cebeSEric Cheng static void
356da14cebeSEric Cheng usage(void)
357da14cebeSEric Cheng {
358da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("usage: flowadm <subcommand>"
359da14cebeSEric Cheng 	    " <args>...\n"
3600790b6dcSAnurag S. Maskey 	    "    add-flow       [-t] -l <link> -a <attr>=<value>[,...]\n"
3610790b6dcSAnurag S. Maskey 	    "\t\t   [-p <prop>=<value>,...] <flow>\n"
3620790b6dcSAnurag S. Maskey 	    "    remove-flow    [-t] {-l <link> | <flow>}\n"
3630790b6dcSAnurag S. Maskey 	    "    show-flow      [-p] [-s [-i <interval>]] [-l <link>] "
3640790b6dcSAnurag S. Maskey 	    "[<flow>]\n\n"
3650790b6dcSAnurag S. Maskey 	    "    set-flowprop   [-t] -p <prop>=<value>[,...] <flow>\n"
3660790b6dcSAnurag S. Maskey 	    "    reset-flowprop [-t] [-p <prop>,...] <flow>\n"
3670790b6dcSAnurag S. Maskey 	    "    show-flowprop  [-cP] [-l <link>] [-p <prop>,...] "
3680790b6dcSAnurag S. Maskey 	    "[<flow>]\n\n"
369ae6aa22aSVenugopal Iyer 	    "    show-usage     [-a] [-d | -F <format>] "
3700790b6dcSAnurag S. Maskey 	    "[-s <DD/MM/YYYY,HH:MM:SS>]\n"
3710790b6dcSAnurag S. Maskey 	    "\t\t   [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<flow>]\n"));
3724ac67f02SAnurag S. Maskey 
3734ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
3744ac67f02SAnurag S. Maskey 	if (handle != NULL)
3754ac67f02SAnurag S. Maskey 		dladm_close(handle);
3764ac67f02SAnurag S. Maskey 
377da14cebeSEric Cheng 	exit(1);
378da14cebeSEric Cheng }
379da14cebeSEric Cheng 
380da14cebeSEric Cheng int
381da14cebeSEric Cheng main(int argc, char *argv[])
382da14cebeSEric Cheng {
383da14cebeSEric Cheng 	int	i, arglen, cmdlen;
384da14cebeSEric Cheng 	cmd_t	*cmdp;
3854ac67f02SAnurag S. Maskey 	dladm_status_t status;
386da14cebeSEric Cheng 
387da14cebeSEric Cheng 	(void) setlocale(LC_ALL, "");
388da14cebeSEric Cheng #if !defined(TEXT_DOMAIN)
389da14cebeSEric Cheng #define	TEXT_DOMAIN "SYS_TEST"
390da14cebeSEric Cheng #endif
391da14cebeSEric Cheng 	(void) textdomain(TEXT_DOMAIN);
392da14cebeSEric Cheng 
393da14cebeSEric Cheng 	progname = argv[0];
394da14cebeSEric Cheng 
395da14cebeSEric Cheng 	if (argc < 2)
396da14cebeSEric Cheng 		usage();
397da14cebeSEric Cheng 
398da14cebeSEric Cheng 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
399da14cebeSEric Cheng 		cmdp = &cmds[i];
400da14cebeSEric Cheng 		arglen = strlen(argv[1]);
401da14cebeSEric Cheng 		cmdlen = strlen(cmdp->c_name);
402da14cebeSEric Cheng 		if ((arglen == cmdlen) && (strncmp(argv[1], cmdp->c_name,
403da14cebeSEric Cheng 		    cmdlen) == 0)) {
4044ac67f02SAnurag S. Maskey 			/* Open the libdladm handle */
4054ac67f02SAnurag S. Maskey 			if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
4064ac67f02SAnurag S. Maskey 				die_dlerr(status,
4074ac67f02SAnurag S. Maskey 				    "could not open /dev/dld");
4084ac67f02SAnurag S. Maskey 			}
4094ac67f02SAnurag S. Maskey 
410da14cebeSEric Cheng 			cmdp->c_fn(argc - 1, &argv[1]);
4114ac67f02SAnurag S. Maskey 
4124ac67f02SAnurag S. Maskey 			dladm_close(handle);
413ad091ee1SMichael Lim 			exit(EXIT_SUCCESS);
414da14cebeSEric Cheng 		}
415da14cebeSEric Cheng 	}
416da14cebeSEric Cheng 
417da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
418da14cebeSEric Cheng 	    progname, argv[1]);
419da14cebeSEric Cheng 	usage();
420da14cebeSEric Cheng 
421da14cebeSEric Cheng 	return (0);
422da14cebeSEric Cheng }
423da14cebeSEric Cheng 
424da14cebeSEric Cheng static const char *
425da14cebeSEric Cheng match_attr(char *attr)
426da14cebeSEric Cheng {
427da14cebeSEric Cheng 	int i;
428da14cebeSEric Cheng 
429da14cebeSEric Cheng 	for (i = 0; i < NATTR; i++) {
430da14cebeSEric Cheng 		if (strlen(attr) == strlen(attr_table[i]) &&
431da14cebeSEric Cheng 		    strncmp(attr, attr_table[i], strlen(attr_table[i])) == 0) {
432da14cebeSEric Cheng 			return (attr);
433da14cebeSEric Cheng 		}
434da14cebeSEric Cheng 	}
435da14cebeSEric Cheng 	return (NULL);
436da14cebeSEric Cheng }
437da14cebeSEric Cheng 
438da14cebeSEric Cheng /* ARGSUSED */
439da14cebeSEric Cheng static void
440da14cebeSEric Cheng do_init_flow(int argc, char *argv[])
441da14cebeSEric Cheng {
442da14cebeSEric Cheng 	dladm_status_t status;
443da14cebeSEric Cheng 
4444ac67f02SAnurag S. Maskey 	status = dladm_flow_init(handle);
445da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
446da14cebeSEric Cheng 		die_dlerr(status, "flows initialization failed");
447da14cebeSEric Cheng }
448da14cebeSEric Cheng 
449da14cebeSEric Cheng /* ARGSUSED */
450da14cebeSEric Cheng static int
451da14cebeSEric Cheng show_usage_date(dladm_usage_t *usage, void *arg)
452da14cebeSEric Cheng {
453ae6aa22aSVenugopal Iyer 	show_usage_state_t	*state = (show_usage_state_t *)arg;
454da14cebeSEric Cheng 	time_t			stime;
455da14cebeSEric Cheng 	char			timebuf[20];
456ae6aa22aSVenugopal Iyer 	dladm_flow_attr_t	attr;
457ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
458ae6aa22aSVenugopal Iyer 
459ae6aa22aSVenugopal Iyer 	/*
460ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing flows unless '-a'
461ae6aa22aSVenugopal Iyer 	 * is specified.
462ae6aa22aSVenugopal Iyer 	 */
463ae6aa22aSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
464ae6aa22aSVenugopal Iyer 	    usage->du_name, &attr)) != DLADM_STATUS_OK)) {
465ae6aa22aSVenugopal Iyer 		return (status);
466ae6aa22aSVenugopal Iyer 	}
467da14cebeSEric Cheng 
468da14cebeSEric Cheng 	stime = usage->du_stime;
469da14cebeSEric Cheng 	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
470da14cebeSEric Cheng 	    localtime(&stime));
471da14cebeSEric Cheng 	(void) printf("%s\n", timebuf);
472da14cebeSEric Cheng 
473da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
474da14cebeSEric Cheng }
475da14cebeSEric Cheng 
476da14cebeSEric Cheng static int
477da14cebeSEric Cheng show_usage_time(dladm_usage_t *usage, void *arg)
478da14cebeSEric Cheng {
479da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
480da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
481da14cebeSEric Cheng 	usage_l_fields_buf_t 	ubuf;
482da14cebeSEric Cheng 	time_t			time;
483da14cebeSEric Cheng 	double			bw;
484ae6aa22aSVenugopal Iyer 	dladm_flow_attr_t	attr;
485ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
486ae6aa22aSVenugopal Iyer 
487ae6aa22aSVenugopal Iyer 	/*
488ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing flows unless '-a'
489ae6aa22aSVenugopal Iyer 	 * is specified.
490ae6aa22aSVenugopal Iyer 	 */
491ae6aa22aSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
492ae6aa22aSVenugopal Iyer 	    usage->du_name, &attr)) != DLADM_STATUS_OK)) {
493ae6aa22aSVenugopal Iyer 		return (status);
494ae6aa22aSVenugopal Iyer 	}
495da14cebeSEric Cheng 
496da14cebeSEric Cheng 	if (state->us_plot) {
497da14cebeSEric Cheng 		if (!state->us_printheader) {
498da14cebeSEric Cheng 			if (state->us_first) {
499da14cebeSEric Cheng 				(void) printf("# Time");
500da14cebeSEric Cheng 				state->us_first = B_FALSE;
501da14cebeSEric Cheng 			}
502da14cebeSEric Cheng 			(void) printf(" %s", usage->du_name);
503da14cebeSEric Cheng 			if (usage->du_last) {
504da14cebeSEric Cheng 				(void) printf("\n");
505da14cebeSEric Cheng 				state->us_first = B_TRUE;
506da14cebeSEric Cheng 				state->us_printheader = B_TRUE;
507da14cebeSEric Cheng 			}
508da14cebeSEric Cheng 		} else {
509da14cebeSEric Cheng 			if (state->us_first) {
510da14cebeSEric Cheng 				time = usage->du_etime;
511da14cebeSEric Cheng 				(void) strftime(buf, sizeof (buf), "%T",
512da14cebeSEric Cheng 				    localtime(&time));
513da14cebeSEric Cheng 				state->us_first = B_FALSE;
514da14cebeSEric Cheng 				(void) printf("%s", buf);
515da14cebeSEric Cheng 			}
516da14cebeSEric Cheng 			bw = (double)usage->du_bandwidth/1000;
517da14cebeSEric Cheng 			(void) printf(" %.2f", bw);
518da14cebeSEric Cheng 			if (usage->du_last) {
519da14cebeSEric Cheng 				(void) printf("\n");
520da14cebeSEric Cheng 				state->us_first = B_TRUE;
521da14cebeSEric Cheng 			}
522da14cebeSEric Cheng 		}
523da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
524da14cebeSEric Cheng 	}
525da14cebeSEric Cheng 
526da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
527da14cebeSEric Cheng 
528da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_flow, sizeof (ubuf.usage_l_flow), "%s",
529da14cebeSEric Cheng 	    usage->du_name);
530da14cebeSEric Cheng 	time = usage->du_stime;
531da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
532da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
533da14cebeSEric Cheng 	    buf);
534da14cebeSEric Cheng 	time = usage->du_etime;
535da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
536da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
537da14cebeSEric Cheng 	    buf);
538da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
539da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
540da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
541da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
542da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
543da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
544da14cebeSEric Cheng 
5458002d411SSowmini Varadhan 	ofmt_print(state->us_ofmt, (void *)&ubuf);
546da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
547da14cebeSEric Cheng }
548da14cebeSEric Cheng 
549da14cebeSEric Cheng static int
550da14cebeSEric Cheng show_usage_res(dladm_usage_t *usage, void *arg)
551da14cebeSEric Cheng {
552da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
553da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
554da14cebeSEric Cheng 	usage_fields_buf_t	ubuf;
555ae6aa22aSVenugopal Iyer 	dladm_flow_attr_t	attr;
556ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
557ae6aa22aSVenugopal Iyer 
558ae6aa22aSVenugopal Iyer 	/*
559ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing flows unless '-a'
560ae6aa22aSVenugopal Iyer 	 * is specified.
561ae6aa22aSVenugopal Iyer 	 */
562ae6aa22aSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
563ae6aa22aSVenugopal Iyer 	    usage->du_name, &attr)) != DLADM_STATUS_OK)) {
564ae6aa22aSVenugopal Iyer 		return (status);
565ae6aa22aSVenugopal Iyer 	}
566da14cebeSEric Cheng 
567da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
568da14cebeSEric Cheng 
569da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_flow, sizeof (ubuf.usage_flow), "%s",
570da14cebeSEric Cheng 	    usage->du_name);
571da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
572da14cebeSEric Cheng 	    "%llu", usage->du_duration);
573da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
574da14cebeSEric Cheng 	    "%llu", usage->du_ipackets);
575da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
576da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
577da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
578da14cebeSEric Cheng 	    "%llu", usage->du_opackets);
579da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
580da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
581da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
582da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
583da14cebeSEric Cheng 
5848002d411SSowmini Varadhan 	ofmt_print(state->us_ofmt, (void *)&ubuf);
585da14cebeSEric Cheng 
586da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
587da14cebeSEric Cheng }
588da14cebeSEric Cheng 
589da14cebeSEric Cheng static boolean_t
590da14cebeSEric Cheng valid_formatspec(char *formatspec_str)
591da14cebeSEric Cheng {
592da14cebeSEric Cheng 	if (strcmp(formatspec_str, "gnuplot") == 0)
593da14cebeSEric Cheng 		return (B_TRUE);
594da14cebeSEric Cheng 	return (B_FALSE);
595da14cebeSEric Cheng }
596da14cebeSEric Cheng 
597da14cebeSEric Cheng /* ARGSUSED */
598da14cebeSEric Cheng static void
599da14cebeSEric Cheng do_show_usage(int argc, char *argv[])
600da14cebeSEric Cheng {
601da14cebeSEric Cheng 	char			*file = NULL;
602da14cebeSEric Cheng 	int			opt;
603da14cebeSEric Cheng 	dladm_status_t		status;
604da14cebeSEric Cheng 	boolean_t		d_arg = B_FALSE;
605da14cebeSEric Cheng 	char			*stime = NULL;
606da14cebeSEric Cheng 	char			*etime = NULL;
607da14cebeSEric Cheng 	char			*resource = NULL;
608da14cebeSEric Cheng 	show_usage_state_t	state;
609da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
610da14cebeSEric Cheng 	boolean_t		F_arg = B_FALSE;
611da14cebeSEric Cheng 	char			*fields_str = NULL;
612da14cebeSEric Cheng 	char			*formatspec_str = NULL;
613da14cebeSEric Cheng 	char			*all_fields =
614da14cebeSEric Cheng 	    "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth";
615da14cebeSEric Cheng 	char			*all_l_fields =
616da14cebeSEric Cheng 	    "flow,start,end,rbytes,obytes,bandwidth";
6178002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
6188002d411SSowmini Varadhan 	ofmt_status_t		oferr;
6198002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
620da14cebeSEric Cheng 
621da14cebeSEric Cheng 	bzero(&state, sizeof (show_usage_state_t));
6228002d411SSowmini Varadhan 	state.us_parsable = B_FALSE;
623da14cebeSEric Cheng 	state.us_printheader = B_FALSE;
624da14cebeSEric Cheng 	state.us_plot = B_FALSE;
625da14cebeSEric Cheng 	state.us_first = B_TRUE;
626da14cebeSEric Cheng 
627ae6aa22aSVenugopal Iyer 	while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) {
628da14cebeSEric Cheng 		switch (opt) {
629da14cebeSEric Cheng 		case 'd':
630da14cebeSEric Cheng 			d_arg = B_TRUE;
631da14cebeSEric Cheng 			break;
632ae6aa22aSVenugopal Iyer 		case 'a':
633ae6aa22aSVenugopal Iyer 			state.us_showall = B_TRUE;
634da14cebeSEric Cheng 			break;
635da14cebeSEric Cheng 		case 'f':
636da14cebeSEric Cheng 			file = optarg;
637da14cebeSEric Cheng 			break;
638da14cebeSEric Cheng 		case 's':
639da14cebeSEric Cheng 			stime = optarg;
640da14cebeSEric Cheng 			break;
641da14cebeSEric Cheng 		case 'e':
642da14cebeSEric Cheng 			etime = optarg;
643da14cebeSEric Cheng 			break;
644da14cebeSEric Cheng 		case 'o':
645da14cebeSEric Cheng 			o_arg = B_TRUE;
646da14cebeSEric Cheng 			fields_str = optarg;
647da14cebeSEric Cheng 			break;
648da14cebeSEric Cheng 		case 'F':
649ae6aa22aSVenugopal Iyer 			state.us_plot = F_arg = B_TRUE;
650da14cebeSEric Cheng 			formatspec_str = optarg;
651da14cebeSEric Cheng 			break;
652da14cebeSEric Cheng 		default:
653da14cebeSEric Cheng 			die_opterr(optopt, opt);
654da14cebeSEric Cheng 		}
655da14cebeSEric Cheng 	}
656da14cebeSEric Cheng 
657da14cebeSEric Cheng 	if (file == NULL)
658da14cebeSEric Cheng 		die("show-usage requires a file");
659da14cebeSEric Cheng 
660da14cebeSEric Cheng 	if (optind == (argc-1)) {
661ae6aa22aSVenugopal Iyer 		dladm_flow_attr_t	attr;
662ae6aa22aSVenugopal Iyer 
663ae6aa22aSVenugopal Iyer 		if (!state.us_showall &&
664ae6aa22aSVenugopal Iyer 		    dladm_flow_info(handle, resource, &attr) !=
665ae6aa22aSVenugopal Iyer 		    DLADM_STATUS_OK) {
666ae6aa22aSVenugopal Iyer 			die("invalid flow: '%s'", resource);
667ae6aa22aSVenugopal Iyer 		}
668da14cebeSEric Cheng 		resource = argv[optind];
669da14cebeSEric Cheng 	}
670da14cebeSEric Cheng 
6718002d411SSowmini Varadhan 	if (state.us_parsable)
6728002d411SSowmini Varadhan 		ofmtflags |= OFMT_PARSABLE;
673da14cebeSEric Cheng 	if (resource == NULL && stime == NULL && etime == NULL) {
674da14cebeSEric Cheng 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
675da14cebeSEric Cheng 			fields_str = all_fields;
6768002d411SSowmini Varadhan 		oferr = ofmt_open(fields_str, usage_fields, ofmtflags,
6778002d411SSowmini Varadhan 		    0, &ofmt);
678da14cebeSEric Cheng 	} else {
679da14cebeSEric Cheng 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
680da14cebeSEric Cheng 			fields_str = all_l_fields;
6818002d411SSowmini Varadhan 		oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags,
6828002d411SSowmini Varadhan 		    0, &ofmt);
683da14cebeSEric Cheng 	}
684da14cebeSEric Cheng 
6858002d411SSowmini Varadhan 	flowadm_ofmt_check(oferr, state.us_parsable, ofmt);
6868002d411SSowmini Varadhan 	state.us_ofmt = ofmt;
687da14cebeSEric Cheng 
688ae6aa22aSVenugopal Iyer 	if (F_arg && d_arg)
689ae6aa22aSVenugopal Iyer 		die("incompatible -d and -F options");
690da14cebeSEric Cheng 
691da14cebeSEric Cheng 	if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
692da14cebeSEric Cheng 		die("Format specifier %s not supported", formatspec_str);
693da14cebeSEric Cheng 
694da14cebeSEric Cheng 	if (d_arg) {
695da14cebeSEric Cheng 		/* Print log dates */
696da14cebeSEric Cheng 		status = dladm_usage_dates(show_usage_date,
697da14cebeSEric Cheng 		    DLADM_LOGTYPE_FLOW, file, resource, &state);
698da14cebeSEric Cheng 	} else if (resource == NULL && stime == NULL && etime == NULL &&
699ae6aa22aSVenugopal Iyer 	    !F_arg) {
700da14cebeSEric Cheng 		/* Print summary */
701da14cebeSEric Cheng 		status = dladm_usage_summary(show_usage_res,
702da14cebeSEric Cheng 		    DLADM_LOGTYPE_FLOW, file, &state);
703da14cebeSEric Cheng 	} else if (resource != NULL) {
704da14cebeSEric Cheng 		/* Print log entries for named resource */
705da14cebeSEric Cheng 		status = dladm_walk_usage_res(show_usage_time,
706da14cebeSEric Cheng 		    DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state);
707da14cebeSEric Cheng 	} else {
708da14cebeSEric Cheng 		/* Print time and information for each link */
709da14cebeSEric Cheng 		status = dladm_walk_usage_time(show_usage_time,
710da14cebeSEric Cheng 		    DLADM_LOGTYPE_FLOW, file, stime, etime, &state);
711da14cebeSEric Cheng 	}
712da14cebeSEric Cheng 
7138002d411SSowmini Varadhan 	ofmt_close(ofmt);
714da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
715da14cebeSEric Cheng 		die_dlerr(status, "show-usage");
716da14cebeSEric Cheng }
717da14cebeSEric Cheng 
718da14cebeSEric Cheng static void
719da14cebeSEric Cheng do_add_flow(int argc, char *argv[])
720da14cebeSEric Cheng {
721da000602SGirish Moodalbail 	char			devname[MAXLINKNAMELEN];
722da14cebeSEric Cheng 	char			*name = NULL;
723da14cebeSEric Cheng 	uint_t			index;
724da14cebeSEric Cheng 	datalink_id_t		linkid;
725da14cebeSEric Cheng 
726da14cebeSEric Cheng 	char			option;
727da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
72863a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
72963a6526dSMichael Lim 	char			attrstr[DLADM_STRSIZE];
730da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
731da14cebeSEric Cheng 	dladm_arg_list_t	*attrlist = NULL;
732da14cebeSEric Cheng 	dladm_status_t		status;
733da14cebeSEric Cheng 
73463a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
73563a6526dSMichael Lim 	bzero(attrstr, DLADM_STRSIZE);
73663a6526dSMichael Lim 
737da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, "tR:l:a:p:",
738da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
739da14cebeSEric Cheng 		switch (option) {
740da14cebeSEric Cheng 		case 't':
741da14cebeSEric Cheng 			t_arg = B_TRUE;
742da14cebeSEric Cheng 			break;
743da14cebeSEric Cheng 		case 'R':
744da14cebeSEric Cheng 			altroot = optarg;
745da14cebeSEric Cheng 			break;
746da14cebeSEric Cheng 		case 'l':
747da14cebeSEric Cheng 			if (strlcpy(devname, optarg,
748da000602SGirish Moodalbail 			    MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
749da14cebeSEric Cheng 				die("link name too long");
750da14cebeSEric Cheng 			}
7514ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, devname, &linkid, NULL,
752da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK)
753da14cebeSEric Cheng 				die("invalid link '%s'", devname);
754da14cebeSEric Cheng 			l_arg = B_TRUE;
755da14cebeSEric Cheng 			break;
756da14cebeSEric Cheng 		case 'a':
75763a6526dSMichael Lim 			(void) strlcat(attrstr, optarg, DLADM_STRSIZE);
75863a6526dSMichael Lim 			if (strlcat(attrstr, ",", DLADM_STRSIZE) >=
75963a6526dSMichael Lim 			    DLADM_STRSIZE)
76063a6526dSMichael Lim 				die("attribute list too long '%s'", attrstr);
761da14cebeSEric Cheng 			break;
762da14cebeSEric Cheng 		case 'p':
76363a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
76463a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
76563a6526dSMichael Lim 			    DLADM_STRSIZE)
76663a6526dSMichael Lim 				die("property list too long '%s'", propstr);
767da14cebeSEric Cheng 			break;
768da14cebeSEric Cheng 		default:
769da14cebeSEric Cheng 			die_opterr(optopt, option);
770da14cebeSEric Cheng 		}
771da14cebeSEric Cheng 	}
772da14cebeSEric Cheng 	if (!l_arg) {
773da14cebeSEric Cheng 		die("link is required");
774da14cebeSEric Cheng 	}
775da14cebeSEric Cheng 
776da14cebeSEric Cheng 	opterr = 0;
777da14cebeSEric Cheng 	index = optind;
778da14cebeSEric Cheng 
779da14cebeSEric Cheng 	if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) {
780da14cebeSEric Cheng 		die("flow name is required");
781da14cebeSEric Cheng 	} else {
782da14cebeSEric Cheng 		/* get flow name; required last argument */
783da000602SGirish Moodalbail 		if (strlen(argv[index]) >= MAXFLOWNAMELEN)
784da14cebeSEric Cheng 			die("flow name too long");
785da14cebeSEric Cheng 		name = argv[index];
786da14cebeSEric Cheng 	}
787da14cebeSEric Cheng 
78863a6526dSMichael Lim 	if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE)
78963a6526dSMichael Lim 	    != DLADM_STATUS_OK)
79063a6526dSMichael Lim 		die("invalid flow attribute specified");
79163a6526dSMichael Lim 	if (dladm_parse_flow_props(propstr, &proplist, B_FALSE)
79263a6526dSMichael Lim 	    != DLADM_STATUS_OK)
79363a6526dSMichael Lim 		die("invalid flow property specified");
79463a6526dSMichael Lim 
7954ac67f02SAnurag S. Maskey 	status = dladm_flow_add(handle, linkid, attrlist, proplist, name,
796da14cebeSEric Cheng 	    t_arg, altroot);
797da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
798da14cebeSEric Cheng 		die_dlerr(status, "add flow failed");
799da14cebeSEric Cheng 
800da14cebeSEric Cheng 	dladm_free_attrs(attrlist);
801da14cebeSEric Cheng 	dladm_free_props(proplist);
802da14cebeSEric Cheng }
803da14cebeSEric Cheng 
804da14cebeSEric Cheng static void
805da14cebeSEric Cheng do_remove_flow(int argc, char *argv[])
806da14cebeSEric Cheng {
807da14cebeSEric Cheng 	char			option;
808da14cebeSEric Cheng 	char			*flowname = NULL;
809da000602SGirish Moodalbail 	char			linkname[MAXLINKNAMELEN];
810da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
811da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
812da14cebeSEric Cheng 	remove_flow_state_t	state;
813da14cebeSEric Cheng 	dladm_status_t		status;
814da14cebeSEric Cheng 
815da14cebeSEric Cheng 	bzero(&state, sizeof (state));
816da14cebeSEric Cheng 
817da14cebeSEric Cheng 	opterr = 0;
818da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tR:l:",
819da14cebeSEric Cheng 	    longopts, NULL)) != -1) {
820da14cebeSEric Cheng 		switch (option) {
821da14cebeSEric Cheng 		case 't':
822da14cebeSEric Cheng 			t_arg = B_TRUE;
823da14cebeSEric Cheng 			break;
824da14cebeSEric Cheng 		case 'R':
825da14cebeSEric Cheng 			altroot = optarg;
826da14cebeSEric Cheng 			break;
827da14cebeSEric Cheng 		case 'l':
828da14cebeSEric Cheng 			if (strlcpy(linkname, optarg,
829da14cebeSEric Cheng 			    MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
830da14cebeSEric Cheng 				die("link name too long");
831da14cebeSEric Cheng 			}
8324ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, linkname, &linkid, NULL,
833da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK) {
834da14cebeSEric Cheng 				die("invalid link '%s'", linkname);
835da14cebeSEric Cheng 			}
836da14cebeSEric Cheng 			l_arg = B_TRUE;
837da14cebeSEric Cheng 			break;
838da14cebeSEric Cheng 		default:
839da14cebeSEric Cheng 			die_opterr(optopt, option);
840da14cebeSEric Cheng 			break;
841da14cebeSEric Cheng 		}
842da14cebeSEric Cheng 	}
843da14cebeSEric Cheng 
844da14cebeSEric Cheng 	/* when link not specified get flow name */
845da14cebeSEric Cheng 	if (!l_arg) {
846da14cebeSEric Cheng 		if (optind != (argc-1)) {
847da14cebeSEric Cheng 			usage();
848da14cebeSEric Cheng 		} else {
849da000602SGirish Moodalbail 			if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
850da14cebeSEric Cheng 				die("flow name too long");
851da14cebeSEric Cheng 			flowname = argv[optind];
852da14cebeSEric Cheng 		}
8534ac67f02SAnurag S. Maskey 		status = dladm_flow_remove(handle, flowname, t_arg, altroot);
854da14cebeSEric Cheng 	} else {
855da14cebeSEric Cheng 		/* if link is specified then flow name should not be there */
856da14cebeSEric Cheng 		if (optind == argc-1)
857da14cebeSEric Cheng 			usage();
858da14cebeSEric Cheng 		/* walk the link to find flows and remove them */
859da14cebeSEric Cheng 		state.fs_tempop = t_arg;
860da14cebeSEric Cheng 		state.fs_altroot = altroot;
861da14cebeSEric Cheng 		state.fs_status = DLADM_STATUS_OK;
8624ac67f02SAnurag S. Maskey 		status = dladm_walk_flow(remove_flow, handle, linkid, &state,
8634ac67f02SAnurag S. Maskey 		    B_FALSE);
864da14cebeSEric Cheng 		/*
865da14cebeSEric Cheng 		 * check if dladm_walk_flow terminated early and see if the
866da14cebeSEric Cheng 		 * walker function as any status for us
867da14cebeSEric Cheng 		 */
868da14cebeSEric Cheng 		if (status == DLADM_STATUS_OK)
869da14cebeSEric Cheng 			status = state.fs_status;
870da14cebeSEric Cheng 	}
871da14cebeSEric Cheng 
872da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
873da14cebeSEric Cheng 		die_dlerr(status, "remove flow failed");
874da14cebeSEric Cheng }
875da14cebeSEric Cheng 
876da14cebeSEric Cheng /*
877da14cebeSEric Cheng  * Walker function for removing a flow through dladm_walk_flow();
878da14cebeSEric Cheng  */
879c3affd82SMichael Lim /*ARGSUSED*/
880da14cebeSEric Cheng static int
881c3affd82SMichael Lim remove_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
882da14cebeSEric Cheng {
883da14cebeSEric Cheng 	remove_flow_state_t	*state = (remove_flow_state_t *)arg;
884da14cebeSEric Cheng 
8854ac67f02SAnurag S. Maskey 	state->fs_status = dladm_flow_remove(handle, attr->fa_flowname,
886da14cebeSEric Cheng 	    state->fs_tempop, state->fs_altroot);
887da14cebeSEric Cheng 
888da14cebeSEric Cheng 	if (state->fs_status == DLADM_STATUS_OK)
889da14cebeSEric Cheng 		return (DLADM_WALK_CONTINUE);
890da14cebeSEric Cheng 	else
891da14cebeSEric Cheng 		return (DLADM_WALK_TERMINATE);
892da14cebeSEric Cheng }
893da14cebeSEric Cheng 
894da14cebeSEric Cheng /*ARGSUSED*/
895da14cebeSEric Cheng static dladm_status_t
896da14cebeSEric Cheng print_flow(show_flow_state_t *state, dladm_flow_attr_t *attr,
897da14cebeSEric Cheng     flow_fields_buf_t *fbuf)
898da14cebeSEric Cheng {
899da14cebeSEric Cheng 	char		link[MAXLINKNAMELEN];
900da14cebeSEric Cheng 	dladm_status_t	status;
901da14cebeSEric Cheng 
9024ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, attr->fa_linkid, NULL,
9034ac67f02SAnurag S. Maskey 	    NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
904da14cebeSEric Cheng 		return (status);
905da14cebeSEric Cheng 	}
906da14cebeSEric Cheng 
907da14cebeSEric Cheng 	(void) snprintf(fbuf->flow_name, sizeof (fbuf->flow_name),
908da14cebeSEric Cheng 	    "%s", attr->fa_flowname);
909da14cebeSEric Cheng 	(void) snprintf(fbuf->flow_link, sizeof (fbuf->flow_link),
910da14cebeSEric Cheng 	    "%s", link);
911da14cebeSEric Cheng 
912da14cebeSEric Cheng 	(void) dladm_flow_attr_ip2str(attr, fbuf->flow_ipaddr,
913da14cebeSEric Cheng 	    sizeof (fbuf->flow_ipaddr));
914da14cebeSEric Cheng 	(void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto,
915da14cebeSEric Cheng 	    sizeof (fbuf->flow_proto));
916*25ec3e3dSEric Cheng 	if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL) != 0) {
917*25ec3e3dSEric Cheng 		(void) dladm_flow_attr_port2str(attr, fbuf->flow_lport,
918*25ec3e3dSEric Cheng 		    sizeof (fbuf->flow_lport));
919*25ec3e3dSEric Cheng 	}
920*25ec3e3dSEric Cheng 	if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE) != 0) {
921*25ec3e3dSEric Cheng 		(void) dladm_flow_attr_port2str(attr, fbuf->flow_rport,
922*25ec3e3dSEric Cheng 		    sizeof (fbuf->flow_rport));
923*25ec3e3dSEric Cheng 	}
924da14cebeSEric Cheng 	(void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield,
925da14cebeSEric Cheng 	    sizeof (fbuf->flow_dsfield));
926da14cebeSEric Cheng 
927da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
928da14cebeSEric Cheng }
929da14cebeSEric Cheng 
930da14cebeSEric Cheng /*
931da14cebeSEric Cheng  * Walker function for showing flow attributes through dladm_walk_flow().
932da14cebeSEric Cheng  */
933c3affd82SMichael Lim /*ARGSUSED*/
934da14cebeSEric Cheng static int
935c3affd82SMichael Lim show_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
936da14cebeSEric Cheng {
937da14cebeSEric Cheng 	show_flow_state_t	*statep = arg;
938da14cebeSEric Cheng 	dladm_status_t		status;
939da14cebeSEric Cheng 	flow_fields_buf_t	fbuf;
940da14cebeSEric Cheng 
941da14cebeSEric Cheng 	/*
942da14cebeSEric Cheng 	 * first get all the flow attributes into fbuf;
943da14cebeSEric Cheng 	 */
944da14cebeSEric Cheng 	bzero(&fbuf, sizeof (fbuf));
945da14cebeSEric Cheng 	status = print_flow(statep, attr, &fbuf);
946da14cebeSEric Cheng 
947da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
948da14cebeSEric Cheng 		goto done;
949da14cebeSEric Cheng 
9508002d411SSowmini Varadhan 	ofmt_print(statep->fs_ofmt, (void *)&fbuf);
951da14cebeSEric Cheng 
952da14cebeSEric Cheng done:
953da14cebeSEric Cheng 	statep->fs_status = status;
954da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
955da14cebeSEric Cheng }
956da14cebeSEric Cheng 
957da14cebeSEric Cheng static void
958da14cebeSEric Cheng show_one_flow(void *arg, const char *name)
959da14cebeSEric Cheng {
960da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
961da14cebeSEric Cheng 
9624ac67f02SAnurag S. Maskey 	if (dladm_flow_info(handle, name, &attr) != DLADM_STATUS_OK)
963da14cebeSEric Cheng 		die("invalid flow: '%s'", name);
964da14cebeSEric Cheng 	else
965c3affd82SMichael Lim 		(void) show_flow(handle, &attr, arg);
966da14cebeSEric Cheng }
967da14cebeSEric Cheng 
968da14cebeSEric Cheng /*
969da14cebeSEric Cheng  * Wrapper of dladm_walk_flow(show_flow,...) to make it usable to
970da14cebeSEric Cheng  * dladm_walk_datalink_id(). Used for showing flow attributes for
971da14cebeSEric Cheng  * all flows on all links.
972da14cebeSEric Cheng  */
973da14cebeSEric Cheng static int
9744ac67f02SAnurag S. Maskey show_flows_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg)
975da14cebeSEric Cheng {
976da14cebeSEric Cheng 	show_flow_state_t *state = arg;
977da14cebeSEric Cheng 
9784ac67f02SAnurag S. Maskey 	(void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist);
979da14cebeSEric Cheng 
980da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
981da14cebeSEric Cheng }
982da14cebeSEric Cheng 
983da14cebeSEric Cheng static void
984da14cebeSEric Cheng get_flow_stats(const char *flowname, pktsum_t *stats)
985da14cebeSEric Cheng {
986da14cebeSEric Cheng 	kstat_ctl_t	*kcp;
987da14cebeSEric Cheng 	kstat_t		*ksp;
988da14cebeSEric Cheng 
989da14cebeSEric Cheng 	bzero(stats, sizeof (*stats));
990da14cebeSEric Cheng 
991da14cebeSEric Cheng 	if ((kcp = kstat_open()) == NULL) {
992da14cebeSEric Cheng 		warn("kstat open operation failed");
993da14cebeSEric Cheng 		return;
994da14cebeSEric Cheng 	}
995da14cebeSEric Cheng 
996da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow");
997da14cebeSEric Cheng 
998da14cebeSEric Cheng 	if (ksp != NULL)
999da14cebeSEric Cheng 		dladm_get_stats(kcp, ksp, stats);
1000da14cebeSEric Cheng 
1001da14cebeSEric Cheng 	(void) kstat_close(kcp);
1002da14cebeSEric Cheng }
1003da14cebeSEric Cheng 
10048002d411SSowmini Varadhan static boolean_t
10058002d411SSowmini Varadhan print_flow_stats_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1006ae6aa22aSVenugopal Iyer {
10078002d411SSowmini Varadhan 	flow_args_t	*fargs = of_arg->ofmt_cbarg;
1008ae6aa22aSVenugopal Iyer 	pktsum_t	*diff_stats = fargs->flow_s_psum;
1009ae6aa22aSVenugopal Iyer 
10108002d411SSowmini Varadhan 	switch (of_arg->ofmt_id) {
1011ae6aa22aSVenugopal Iyer 	case FLOW_S_FLOW:
10128002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%s", fargs->flow_s_flow);
1013ae6aa22aSVenugopal Iyer 		break;
1014ae6aa22aSVenugopal Iyer 	case FLOW_S_IPKTS:
10158002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%llu",
1016ae6aa22aSVenugopal Iyer 		    diff_stats->ipackets);
1017ae6aa22aSVenugopal Iyer 		break;
1018ae6aa22aSVenugopal Iyer 	case FLOW_S_RBYTES:
10198002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%llu",
1020ae6aa22aSVenugopal Iyer 		    diff_stats->rbytes);
1021ae6aa22aSVenugopal Iyer 		break;
1022ae6aa22aSVenugopal Iyer 	case FLOW_S_IERRORS:
10238002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%u",
1024ae6aa22aSVenugopal Iyer 		    diff_stats->ierrors);
1025ae6aa22aSVenugopal Iyer 		break;
1026ae6aa22aSVenugopal Iyer 	case FLOW_S_OPKTS:
10278002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%llu",
1028ae6aa22aSVenugopal Iyer 		    diff_stats->opackets);
1029ae6aa22aSVenugopal Iyer 		break;
1030ae6aa22aSVenugopal Iyer 	case FLOW_S_OBYTES:
10318002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%llu",
1032ae6aa22aSVenugopal Iyer 		    diff_stats->obytes);
1033ae6aa22aSVenugopal Iyer 		break;
1034ae6aa22aSVenugopal Iyer 	case FLOW_S_OERRORS:
10358002d411SSowmini Varadhan 		(void) snprintf(buf, bufsize, "%u",
1036ae6aa22aSVenugopal Iyer 		    diff_stats->oerrors);
1037ae6aa22aSVenugopal Iyer 		break;
1038ae6aa22aSVenugopal Iyer 	default:
1039ae6aa22aSVenugopal Iyer 		die("invalid input");
1040ae6aa22aSVenugopal Iyer 		break;
1041ae6aa22aSVenugopal Iyer 	}
10428002d411SSowmini Varadhan 	return (B_TRUE);
1043ae6aa22aSVenugopal Iyer }
10448002d411SSowmini Varadhan 
1045da14cebeSEric Cheng /* ARGSUSED */
1046da14cebeSEric Cheng static int
1047c3affd82SMichael Lim show_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
1048da14cebeSEric Cheng {
1049da14cebeSEric Cheng 	show_flow_state_t	*state = (show_flow_state_t *)arg;
1050ae6aa22aSVenugopal Iyer 	char			*name = attr->fa_flowname;
1051da14cebeSEric Cheng 	pktsum_t		stats, diff_stats;
1052ae6aa22aSVenugopal Iyer 	flow_args_t		fargs;
1053da14cebeSEric Cheng 
1054da14cebeSEric Cheng 	if (state->fs_firstonly) {
1055da14cebeSEric Cheng 		if (state->fs_donefirst)
1056da14cebeSEric Cheng 			return (DLADM_WALK_TERMINATE);
1057da14cebeSEric Cheng 		state->fs_donefirst = B_TRUE;
1058da14cebeSEric Cheng 	} else {
1059da14cebeSEric Cheng 		bzero(&state->fs_prevstats, sizeof (state->fs_prevstats));
1060da14cebeSEric Cheng 	}
1061da14cebeSEric Cheng 
1062da14cebeSEric Cheng 	get_flow_stats(name, &stats);
1063da14cebeSEric Cheng 	dladm_stats_diff(&diff_stats, &stats, &state->fs_prevstats);
1064da14cebeSEric Cheng 
1065ae6aa22aSVenugopal Iyer 	fargs.flow_s_flow = name;
1066ae6aa22aSVenugopal Iyer 	fargs.flow_s_psum = &diff_stats;
10678002d411SSowmini Varadhan 	ofmt_print(state->fs_ofmt, (void *)&fargs);
1068da14cebeSEric Cheng 	state->fs_prevstats = stats;
1069da14cebeSEric Cheng 
1070da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1071da14cebeSEric Cheng }
1072da14cebeSEric Cheng 
1073da14cebeSEric Cheng /*
1074da14cebeSEric Cheng  * Wrapper of dladm_walk_flow(show_flow,...) to make it usable for
1075da14cebeSEric Cheng  * dladm_walk_datalink_id(). Used for showing flow stats for
1076da14cebeSEric Cheng  * all flows on all links.
1077da14cebeSEric Cheng  */
1078da14cebeSEric Cheng static int
10794ac67f02SAnurag S. Maskey show_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg)
1080da14cebeSEric Cheng {
10814ac67f02SAnurag S. Maskey 	if (dladm_walk_flow(show_flow_stats, dh, linkid, arg, B_FALSE)
1082da14cebeSEric Cheng 	    == DLADM_STATUS_OK)
1083da14cebeSEric Cheng 		return (DLADM_WALK_CONTINUE);
1084da14cebeSEric Cheng 	else
1085da14cebeSEric Cheng 		return (DLADM_WALK_TERMINATE);
1086da14cebeSEric Cheng }
1087da14cebeSEric Cheng 
1088da14cebeSEric Cheng /* ARGSUSED */
1089da14cebeSEric Cheng static void
1090ae6aa22aSVenugopal Iyer flow_stats(const char *flow, datalink_id_t linkid,  uint_t interval,
1091ae6aa22aSVenugopal Iyer     char *fields_str, show_flow_state_t *state)
1092da14cebeSEric Cheng {
1093da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
10948002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
10958002d411SSowmini Varadhan 	ofmt_status_t		oferr;
10968002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
1097ae6aa22aSVenugopal Iyer 
10988002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, flow_s_fields, ofmtflags, 0, &ofmt);
10998002d411SSowmini Varadhan 	flowadm_ofmt_check(oferr, state->fs_parsable, ofmt);
11008002d411SSowmini Varadhan 	state->fs_ofmt = ofmt;
1101da14cebeSEric Cheng 
11024ac67f02SAnurag S. Maskey 	if (flow != NULL &&
11034ac67f02SAnurag S. Maskey 	    dladm_flow_info(handle, flow, &attr) != DLADM_STATUS_OK)
1104da14cebeSEric Cheng 		die("invalid flow %s", flow);
1105da14cebeSEric Cheng 
1106da14cebeSEric Cheng 	/*
1107da14cebeSEric Cheng 	 * If an interval is specified, continuously show the stats
1108da14cebeSEric Cheng 	 * for only the first flow.
1109da14cebeSEric Cheng 	 */
1110ae6aa22aSVenugopal Iyer 	state->fs_firstonly = (interval != 0);
1111da14cebeSEric Cheng 
1112da14cebeSEric Cheng 	for (;;) {
1113ae6aa22aSVenugopal Iyer 		state->fs_donefirst = B_FALSE;
1114da14cebeSEric Cheng 
1115da14cebeSEric Cheng 		/* Show stats for named flow */
1116da14cebeSEric Cheng 		if (flow != NULL)  {
1117ae6aa22aSVenugopal Iyer 			state->fs_flow = flow;
1118c3affd82SMichael Lim 			(void) show_flow_stats(handle, &attr, state);
1119da14cebeSEric Cheng 
1120da14cebeSEric Cheng 		/* Show all stats on a link */
1121da14cebeSEric Cheng 		} else if (linkid != DATALINK_INVALID_LINKID) {
11224ac67f02SAnurag S. Maskey 			(void) dladm_walk_flow(show_flow_stats, handle, linkid,
1123ae6aa22aSVenugopal Iyer 			    state, B_FALSE);
1124da14cebeSEric Cheng 
1125da14cebeSEric Cheng 		/* Show all stats by datalink */
1126da14cebeSEric Cheng 		} else {
1127da14cebeSEric Cheng 			(void) dladm_walk_datalink_id(show_link_flow_stats,
1128ae6aa22aSVenugopal Iyer 			    handle, state, DATALINK_CLASS_ALL,
11294ac67f02SAnurag S. Maskey 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1130da14cebeSEric Cheng 		}
1131da14cebeSEric Cheng 
1132da14cebeSEric Cheng 		if (interval == 0)
1133da14cebeSEric Cheng 			break;
1134da14cebeSEric Cheng 
1135c3affd82SMichael Lim 		(void) fflush(stdout);
1136da14cebeSEric Cheng 		(void) sleep(interval);
1137da14cebeSEric Cheng 	}
11388002d411SSowmini Varadhan 	ofmt_close(ofmt);
1139da14cebeSEric Cheng }
1140da14cebeSEric Cheng 
1141da14cebeSEric Cheng static void
1142da14cebeSEric Cheng do_show_flow(int argc, char *argv[])
1143da14cebeSEric Cheng {
1144da000602SGirish Moodalbail 	char			flowname[MAXFLOWNAMELEN];
1145da000602SGirish Moodalbail 	char			linkname[MAXLINKNAMELEN];
1146da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
1147da14cebeSEric Cheng 	int			option;
1148da14cebeSEric Cheng 	boolean_t		s_arg = B_FALSE;
1149da14cebeSEric Cheng 	boolean_t		S_arg = B_FALSE;
1150da14cebeSEric Cheng 	boolean_t		i_arg = B_FALSE;
1151da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
1152da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
1153da14cebeSEric Cheng 	uint32_t		interval = 0;
1154da14cebeSEric Cheng 	show_flow_state_t	state;
1155da14cebeSEric Cheng 	char			*fields_str = NULL;
11568002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
11578002d411SSowmini Varadhan 	ofmt_status_t		oferr;
11588002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
1159da14cebeSEric Cheng 
1160da14cebeSEric Cheng 	bzero(&state, sizeof (state));
1161da14cebeSEric Cheng 
1162da14cebeSEric Cheng 	opterr = 0;
1163da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPsSi:l:o:",
1164da14cebeSEric Cheng 	    longopts, NULL)) != -1) {
1165da14cebeSEric Cheng 		switch (option) {
1166da14cebeSEric Cheng 		case 'p':
11678002d411SSowmini Varadhan 			state.fs_parsable = B_TRUE;
11688002d411SSowmini Varadhan 			ofmtflags |= OFMT_PARSABLE;
1169da14cebeSEric Cheng 			break;
1170da14cebeSEric Cheng 		case 'P':
1171da14cebeSEric Cheng 			state.fs_persist = B_TRUE;
1172da14cebeSEric Cheng 			break;
1173da14cebeSEric Cheng 		case 's':
1174da14cebeSEric Cheng 			if (s_arg)
1175da14cebeSEric Cheng 				die_optdup(option);
1176da14cebeSEric Cheng 
1177da14cebeSEric Cheng 			s_arg = B_TRUE;
1178da14cebeSEric Cheng 			break;
1179da14cebeSEric Cheng 		case 'S':
1180da14cebeSEric Cheng 			if (S_arg)
1181da14cebeSEric Cheng 				die_optdup(option);
1182da14cebeSEric Cheng 
1183da14cebeSEric Cheng 			S_arg = B_TRUE;
1184da14cebeSEric Cheng 			break;
1185da14cebeSEric Cheng 		case 'o':
1186da14cebeSEric Cheng 			if (o_arg)
1187da14cebeSEric Cheng 				die_optdup(option);
1188da14cebeSEric Cheng 
1189da14cebeSEric Cheng 			o_arg = B_TRUE;
1190da14cebeSEric Cheng 			fields_str = optarg;
1191da14cebeSEric Cheng 			break;
1192da14cebeSEric Cheng 		case 'i':
1193da14cebeSEric Cheng 			if (i_arg)
1194da14cebeSEric Cheng 				die_optdup(option);
1195da14cebeSEric Cheng 
1196da14cebeSEric Cheng 			i_arg = B_TRUE;
1197da14cebeSEric Cheng 
119863a6526dSMichael Lim 			if (!dladm_str2interval(optarg, &interval))
119963a6526dSMichael Lim 				die("invalid interval value '%s'", optarg);
1200da14cebeSEric Cheng 			break;
1201da14cebeSEric Cheng 		case 'l':
1202da14cebeSEric Cheng 			if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
1203da14cebeSEric Cheng 			    >= MAXLINKNAMELEN)
1204da14cebeSEric Cheng 				die("link name too long\n");
12054ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, linkname, &linkid, NULL,
1206da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK)
1207da14cebeSEric Cheng 				die("invalid link '%s'", linkname);
1208da14cebeSEric Cheng 			l_arg = B_TRUE;
1209da14cebeSEric Cheng 			break;
1210da14cebeSEric Cheng 		default:
1211da14cebeSEric Cheng 			die_opterr(optopt, option);
1212da14cebeSEric Cheng 			break;
1213da14cebeSEric Cheng 		}
1214da14cebeSEric Cheng 	}
1215da14cebeSEric Cheng 	if (i_arg && !(s_arg || S_arg))
1216da14cebeSEric Cheng 		die("the -i option can be used only with -s or -S");
1217da14cebeSEric Cheng 
1218da14cebeSEric Cheng 	if (s_arg && S_arg)
1219da14cebeSEric Cheng 		die("the -s option cannot be used with -S");
1220da14cebeSEric Cheng 
1221da14cebeSEric Cheng 	/* get flow name (optional last argument */
1222da14cebeSEric Cheng 	if (optind == (argc-1)) {
1223da000602SGirish Moodalbail 		if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
1224da000602SGirish Moodalbail 		    >= MAXFLOWNAMELEN)
1225da14cebeSEric Cheng 			die("flow name too long");
1226da14cebeSEric Cheng 		state.fs_flow = flowname;
1227da14cebeSEric Cheng 	}
1228da14cebeSEric Cheng 
1229da14cebeSEric Cheng 	if (S_arg) {
12304ac67f02SAnurag S. Maskey 		dladm_continuous(handle, linkid, state.fs_flow, interval,
12314ac67f02SAnurag S. Maskey 		    FLOW_REPORT);
1232da14cebeSEric Cheng 		return;
1233da14cebeSEric Cheng 	}
1234da14cebeSEric Cheng 
1235ae6aa22aSVenugopal Iyer 	if (s_arg) {
1236ae6aa22aSVenugopal Iyer 		flow_stats(state.fs_flow, linkid, interval, fields_str, &state);
1237ae6aa22aSVenugopal Iyer 		return;
1238ae6aa22aSVenugopal Iyer 	}
1239da14cebeSEric Cheng 
12408002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, flow_fields, ofmtflags, 0, &ofmt);
12418002d411SSowmini Varadhan 	flowadm_ofmt_check(oferr, state.fs_parsable, ofmt);
12428002d411SSowmini Varadhan 	state.fs_ofmt = ofmt;
1243da14cebeSEric Cheng 
1244da14cebeSEric Cheng 	/* Show attributes of one flow */
1245da14cebeSEric Cheng 	if (state.fs_flow != NULL) {
1246da14cebeSEric Cheng 		show_one_flow(&state, state.fs_flow);
1247da14cebeSEric Cheng 
1248da14cebeSEric Cheng 	/* Show attributes of flows on one link */
1249da14cebeSEric Cheng 	} else if (l_arg) {
12504ac67f02SAnurag S. Maskey 		(void) show_flows_onelink(handle, linkid, &state);
1251da14cebeSEric Cheng 
1252da14cebeSEric Cheng 	/* Show attributes of all flows on all links */
1253da14cebeSEric Cheng 	} else {
12544ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_flows_onelink, handle,
12554ac67f02SAnurag S. Maskey 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1256da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
1257da14cebeSEric Cheng 	}
12588002d411SSowmini Varadhan 	ofmt_close(ofmt);
1259da14cebeSEric Cheng }
1260da14cebeSEric Cheng 
1261da14cebeSEric Cheng static dladm_status_t
1262da14cebeSEric Cheng set_flowprop_persist(const char *flow, const char *prop_name, char **prop_val,
1263da14cebeSEric Cheng     uint_t val_cnt, boolean_t reset)
1264da14cebeSEric Cheng {
1265da14cebeSEric Cheng 	dladm_status_t	status;
1266da14cebeSEric Cheng 	char		*errprop;
1267da14cebeSEric Cheng 
12684ac67f02SAnurag S. Maskey 	status = dladm_set_flowprop(handle, flow, prop_name, prop_val, val_cnt,
1269da14cebeSEric Cheng 	    DLADM_OPT_PERSIST, &errprop);
1270da14cebeSEric Cheng 
1271da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
1272da14cebeSEric Cheng 		warn_dlerr(status, "cannot persistently %s flow "
1273da14cebeSEric Cheng 		    "property '%s' on '%s'", reset? "reset": "set",
1274da14cebeSEric Cheng 		    errprop, flow);
1275da14cebeSEric Cheng 	}
1276da14cebeSEric Cheng 	return (status);
1277da14cebeSEric Cheng }
1278da14cebeSEric Cheng 
1279da14cebeSEric Cheng static void
1280da14cebeSEric Cheng set_flowprop(int argc, char **argv, boolean_t reset)
1281da14cebeSEric Cheng {
1282da14cebeSEric Cheng 	int			i, option;
1283da14cebeSEric Cheng 	char			errmsg[DLADM_STRSIZE];
1284da14cebeSEric Cheng 	const char		*flow = NULL;
128563a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
1286da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1287da14cebeSEric Cheng 	boolean_t		temp = B_FALSE;
1288da14cebeSEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
1289da14cebeSEric Cheng 
1290da14cebeSEric Cheng 	opterr = 0;
129163a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
129263a6526dSMichael Lim 
1293da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":p:R:t",
1294da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
1295da14cebeSEric Cheng 		switch (option) {
1296da14cebeSEric Cheng 		case 'p':
129763a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
129863a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
129963a6526dSMichael Lim 			    DLADM_STRSIZE)
130063a6526dSMichael Lim 				die("property list too long '%s'", propstr);
1301da14cebeSEric Cheng 			break;
1302da14cebeSEric Cheng 		case 't':
1303da14cebeSEric Cheng 			temp = B_TRUE;
1304da14cebeSEric Cheng 			break;
1305da14cebeSEric Cheng 		case 'R':
1306da14cebeSEric Cheng 			status = dladm_set_rootdir(optarg);
1307da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK) {
1308da14cebeSEric Cheng 				die_dlerr(status, "invalid directory "
1309da14cebeSEric Cheng 				    "specified");
1310da14cebeSEric Cheng 			}
1311da14cebeSEric Cheng 			break;
1312da14cebeSEric Cheng 		default:
1313da14cebeSEric Cheng 			die_opterr(optopt, option);
1314da14cebeSEric Cheng 			break;
1315da14cebeSEric Cheng 		}
1316da14cebeSEric Cheng 	}
1317da14cebeSEric Cheng 
1318da14cebeSEric Cheng 	if (optind == (argc - 1)) {
1319da000602SGirish Moodalbail 		if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
1320da14cebeSEric Cheng 			die("flow name too long");
1321da14cebeSEric Cheng 		flow = argv[optind];
1322da14cebeSEric Cheng 	} else if (optind != argc) {
1323da14cebeSEric Cheng 		usage();
1324da14cebeSEric Cheng 	}
1325da14cebeSEric Cheng 	if (flow == NULL)
1326da14cebeSEric Cheng 		die("flow name must be specified");
1327da14cebeSEric Cheng 
132863a6526dSMichael Lim 	if (dladm_parse_flow_props(propstr, &proplist, reset)
132963a6526dSMichael Lim 	    != DLADM_STATUS_OK)
133063a6526dSMichael Lim 		die("invalid flow property specified");
133163a6526dSMichael Lim 
1332da14cebeSEric Cheng 	if (proplist == NULL) {
1333da14cebeSEric Cheng 		char *errprop;
1334da14cebeSEric Cheng 
1335da14cebeSEric Cheng 		if (!reset)
1336da14cebeSEric Cheng 			die("flow property must be specified");
1337da14cebeSEric Cheng 
13384ac67f02SAnurag S. Maskey 		status = dladm_set_flowprop(handle, flow, NULL, NULL, 0,
1339da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE, &errprop);
1340da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
1341da14cebeSEric Cheng 			warn_dlerr(status, "cannot reset flow property '%s' "
1342da14cebeSEric Cheng 			    "on '%s'", errprop, flow);
1343da14cebeSEric Cheng 		}
1344da14cebeSEric Cheng 		if (!temp) {
1345da14cebeSEric Cheng 			dladm_status_t	s;
1346da14cebeSEric Cheng 
1347da14cebeSEric Cheng 			s = set_flowprop_persist(flow, NULL, NULL, 0, reset);
1348da14cebeSEric Cheng 			if (s != DLADM_STATUS_OK)
1349da14cebeSEric Cheng 				status = s;
1350da14cebeSEric Cheng 		}
1351da14cebeSEric Cheng 		goto done;
1352da14cebeSEric Cheng 	}
1353da14cebeSEric Cheng 
1354da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
1355da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
1356da14cebeSEric Cheng 		char		**val;
1357da14cebeSEric Cheng 		uint_t		count;
1358da14cebeSEric Cheng 		dladm_status_t	s;
1359da14cebeSEric Cheng 
1360da14cebeSEric Cheng 		if (reset) {
1361da14cebeSEric Cheng 			val = NULL;
1362da14cebeSEric Cheng 			count = 0;
1363da14cebeSEric Cheng 		} else {
1364da14cebeSEric Cheng 			val = aip->ai_val;
1365da14cebeSEric Cheng 			count = aip->ai_count;
1366da14cebeSEric Cheng 			if (count == 0) {
1367da14cebeSEric Cheng 				warn("no value specified for '%s'",
1368da14cebeSEric Cheng 				    aip->ai_name);
1369da14cebeSEric Cheng 				status = DLADM_STATUS_BADARG;
1370da14cebeSEric Cheng 				continue;
1371da14cebeSEric Cheng 			}
1372da14cebeSEric Cheng 		}
13734ac67f02SAnurag S. Maskey 		s = dladm_set_flowprop(handle, flow, aip->ai_name, val, count,
1374da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE, NULL);
1375da14cebeSEric Cheng 		if (s == DLADM_STATUS_OK) {
1376da14cebeSEric Cheng 			if (!temp) {
1377da14cebeSEric Cheng 				s = set_flowprop_persist(flow,
1378da14cebeSEric Cheng 				    aip->ai_name, val, count, reset);
1379da14cebeSEric Cheng 				if (s != DLADM_STATUS_OK)
1380da14cebeSEric Cheng 					status = s;
1381da14cebeSEric Cheng 			}
1382da14cebeSEric Cheng 			continue;
1383da14cebeSEric Cheng 		}
1384da14cebeSEric Cheng 		status = s;
1385da14cebeSEric Cheng 		switch (s) {
1386da14cebeSEric Cheng 		case DLADM_STATUS_NOTFOUND:
1387da14cebeSEric Cheng 			warn("invalid flow property '%s'", aip->ai_name);
1388da14cebeSEric Cheng 			break;
1389da14cebeSEric Cheng 		case DLADM_STATUS_BADVAL: {
1390da14cebeSEric Cheng 			int		j;
1391da14cebeSEric Cheng 			char		*ptr, *lim;
1392da14cebeSEric Cheng 			char		**propvals = NULL;
1393da14cebeSEric Cheng 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
1394da14cebeSEric Cheng 
1395da14cebeSEric Cheng 			ptr = malloc((sizeof (char *) +
1396da14cebeSEric Cheng 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
1397da14cebeSEric Cheng 			    MAX_PROP_LINE);
1398da14cebeSEric Cheng 
1399da14cebeSEric Cheng 			if (ptr == NULL)
1400da14cebeSEric Cheng 				die("insufficient memory");
1401da14cebeSEric Cheng 			propvals = (char **)(void *)ptr;
1402da14cebeSEric Cheng 
1403da14cebeSEric Cheng 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
1404da14cebeSEric Cheng 				propvals[j] = ptr + sizeof (char *) *
1405da14cebeSEric Cheng 				    DLADM_MAX_PROP_VALCNT +
1406da14cebeSEric Cheng 				    j * DLADM_PROP_VAL_MAX;
1407da14cebeSEric Cheng 			}
14084ac67f02SAnurag S. Maskey 			s = dladm_get_flowprop(handle, flow,
14094ac67f02SAnurag S. Maskey 			    DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
14104ac67f02SAnurag S. Maskey 			    &valcnt);
1411da14cebeSEric Cheng 
1412da14cebeSEric Cheng 			ptr = errmsg;
1413da14cebeSEric Cheng 			lim = ptr + DLADM_STRSIZE;
1414da14cebeSEric Cheng 			*ptr = '\0';
1415da14cebeSEric Cheng 			for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
1416da14cebeSEric Cheng 				ptr += snprintf(ptr, lim - ptr, "%s,",
1417da14cebeSEric Cheng 				    propvals[j]);
1418da14cebeSEric Cheng 				if (ptr >= lim)
1419da14cebeSEric Cheng 					break;
1420da14cebeSEric Cheng 			}
1421da14cebeSEric Cheng 			if (ptr > errmsg) {
1422da14cebeSEric Cheng 				*(ptr - 1) = '\0';
1423da14cebeSEric Cheng 				warn("flow property '%s' must be one of: %s",
1424da14cebeSEric Cheng 				    aip->ai_name, errmsg);
1425da14cebeSEric Cheng 			} else
1426da14cebeSEric Cheng 				warn("%s is an invalid value for "
1427da14cebeSEric Cheng 				    "flow property %s", *val, aip->ai_name);
1428da14cebeSEric Cheng 			free(propvals);
1429da14cebeSEric Cheng 			break;
1430da14cebeSEric Cheng 		}
1431da14cebeSEric Cheng 		default:
1432da14cebeSEric Cheng 			if (reset) {
1433da14cebeSEric Cheng 				warn_dlerr(status, "cannot reset flow property "
1434da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, flow);
1435da14cebeSEric Cheng 			} else {
1436da14cebeSEric Cheng 				warn_dlerr(status, "cannot set flow property "
1437da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, flow);
1438da14cebeSEric Cheng 			}
1439da14cebeSEric Cheng 			break;
1440da14cebeSEric Cheng 		}
1441da14cebeSEric Cheng 	}
1442da14cebeSEric Cheng done:
1443da14cebeSEric Cheng 	dladm_free_props(proplist);
14444ac67f02SAnurag S. Maskey 	if (status != DLADM_STATUS_OK) {
14454ac67f02SAnurag S. Maskey 		dladm_close(handle);
1446ad091ee1SMichael Lim 		exit(EXIT_FAILURE);
1447da14cebeSEric Cheng 	}
14484ac67f02SAnurag S. Maskey }
1449da14cebeSEric Cheng 
1450da14cebeSEric Cheng static void
1451da14cebeSEric Cheng do_set_flowprop(int argc, char **argv)
1452da14cebeSEric Cheng {
1453da14cebeSEric Cheng 	set_flowprop(argc, argv, B_FALSE);
1454da14cebeSEric Cheng }
1455da14cebeSEric Cheng 
1456da14cebeSEric Cheng static void
1457da14cebeSEric Cheng do_reset_flowprop(int argc, char **argv)
1458da14cebeSEric Cheng {
1459da14cebeSEric Cheng 	set_flowprop(argc, argv, B_TRUE);
1460da14cebeSEric Cheng }
1461da14cebeSEric Cheng 
1462da14cebeSEric Cheng static void
1463da14cebeSEric Cheng warn(const char *format, ...)
1464da14cebeSEric Cheng {
1465da14cebeSEric Cheng 	va_list alist;
1466da14cebeSEric Cheng 
1467da14cebeSEric Cheng 	format = gettext(format);
1468da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: warning: ", progname);
1469da14cebeSEric Cheng 
1470da14cebeSEric Cheng 	va_start(alist, format);
1471da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
1472da14cebeSEric Cheng 	va_end(alist);
1473da14cebeSEric Cheng 
1474da14cebeSEric Cheng 	(void) putchar('\n');
1475da14cebeSEric Cheng }
1476da14cebeSEric Cheng 
1477da14cebeSEric Cheng /* PRINTFLIKE2 */
1478da14cebeSEric Cheng static void
1479da14cebeSEric Cheng warn_dlerr(dladm_status_t err, const char *format, ...)
1480da14cebeSEric Cheng {
1481da14cebeSEric Cheng 	va_list alist;
1482da14cebeSEric Cheng 	char    errmsg[DLADM_STRSIZE];
1483da14cebeSEric Cheng 
1484da14cebeSEric Cheng 	format = gettext(format);
1485da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
1486da14cebeSEric Cheng 
1487da14cebeSEric Cheng 	va_start(alist, format);
1488da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
1489da14cebeSEric Cheng 	va_end(alist);
1490da14cebeSEric Cheng 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
1491da14cebeSEric Cheng }
1492da14cebeSEric Cheng 
1493da14cebeSEric Cheng /* PRINTFLIKE1 */
1494da14cebeSEric Cheng static void
1495da14cebeSEric Cheng die(const char *format, ...)
1496da14cebeSEric Cheng {
1497da14cebeSEric Cheng 	va_list alist;
1498da14cebeSEric Cheng 
1499da14cebeSEric Cheng 	format = gettext(format);
1500da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: ", progname);
1501da14cebeSEric Cheng 
1502da14cebeSEric Cheng 	va_start(alist, format);
1503da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
1504da14cebeSEric Cheng 	va_end(alist);
1505da14cebeSEric Cheng 
1506da14cebeSEric Cheng 	(void) putchar('\n');
15074ac67f02SAnurag S. Maskey 
15084ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
15094ac67f02SAnurag S. Maskey 	if (handle != NULL)
15104ac67f02SAnurag S. Maskey 		dladm_close(handle);
15114ac67f02SAnurag S. Maskey 
1512da14cebeSEric Cheng 	exit(EXIT_FAILURE);
1513da14cebeSEric Cheng }
1514da14cebeSEric Cheng 
1515da14cebeSEric Cheng static void
1516da14cebeSEric Cheng die_optdup(int opt)
1517da14cebeSEric Cheng {
1518da14cebeSEric Cheng 	die("the option -%c cannot be specified more than once", opt);
1519da14cebeSEric Cheng }
1520da14cebeSEric Cheng 
1521da14cebeSEric Cheng static void
1522da14cebeSEric Cheng die_opterr(int opt, int opterr)
1523da14cebeSEric Cheng {
1524da14cebeSEric Cheng 	switch (opterr) {
1525da14cebeSEric Cheng 	case ':':
1526da14cebeSEric Cheng 		die("option '-%c' requires a value", opt);
1527da14cebeSEric Cheng 		break;
1528da14cebeSEric Cheng 	case '?':
1529da14cebeSEric Cheng 	default:
1530da14cebeSEric Cheng 		die("unrecognized option '-%c'", opt);
1531da14cebeSEric Cheng 		break;
1532da14cebeSEric Cheng 	}
1533da14cebeSEric Cheng }
1534da14cebeSEric Cheng 
1535da14cebeSEric Cheng /* PRINTFLIKE2 */
1536da14cebeSEric Cheng static void
1537da14cebeSEric Cheng die_dlerr(dladm_status_t err, const char *format, ...)
1538da14cebeSEric Cheng {
1539da14cebeSEric Cheng 	va_list alist;
1540da14cebeSEric Cheng 	char	errmsg[DLADM_STRSIZE];
1541da14cebeSEric Cheng 
1542da14cebeSEric Cheng 	format = gettext(format);
1543da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: ", progname);
1544da14cebeSEric Cheng 
1545da14cebeSEric Cheng 	va_start(alist, format);
1546da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
1547da14cebeSEric Cheng 	va_end(alist);
1548da14cebeSEric Cheng 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
1549da14cebeSEric Cheng 
15504ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
15514ac67f02SAnurag S. Maskey 	if (handle != NULL)
15524ac67f02SAnurag S. Maskey 		dladm_close(handle);
15534ac67f02SAnurag S. Maskey 
1554da14cebeSEric Cheng 	exit(EXIT_FAILURE);
1555da14cebeSEric Cheng }
1556da14cebeSEric Cheng 
1557da14cebeSEric Cheng static void
1558da14cebeSEric Cheng print_flowprop(const char *flowname, show_flowprop_state_t *statep,
1559da14cebeSEric Cheng     const char *propname, dladm_prop_type_t type,
1560da14cebeSEric Cheng     const char *format, char **pptr)
1561da14cebeSEric Cheng {
1562da14cebeSEric Cheng 	int		i;
1563da14cebeSEric Cheng 	char		*ptr, *lim;
1564da14cebeSEric Cheng 	char		buf[DLADM_STRSIZE];
1565da14cebeSEric Cheng 	char		*unknown = "--", *notsup = "";
1566da14cebeSEric Cheng 	char		**propvals = statep->fs_propvals;
1567da14cebeSEric Cheng 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
1568da14cebeSEric Cheng 	dladm_status_t	status;
1569da14cebeSEric Cheng 
15704ac67f02SAnurag S. Maskey 	status = dladm_get_flowprop(handle, flowname, type, propname, propvals,
1571da14cebeSEric Cheng 	    &valcnt);
1572da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
1573da14cebeSEric Cheng 		if (status == DLADM_STATUS_TEMPONLY) {
1574da14cebeSEric Cheng 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
1575da14cebeSEric Cheng 			    statep->fs_persist) {
1576da14cebeSEric Cheng 				valcnt = 1;
1577da14cebeSEric Cheng 				propvals = &unknown;
1578da14cebeSEric Cheng 			} else {
1579da14cebeSEric Cheng 				statep->fs_status = status;
1580da14cebeSEric Cheng 				statep->fs_retstatus = status;
1581da14cebeSEric Cheng 				return;
1582da14cebeSEric Cheng 			}
1583da14cebeSEric Cheng 		} else if (status == DLADM_STATUS_NOTSUP ||
1584da14cebeSEric Cheng 		    statep->fs_persist) {
1585da14cebeSEric Cheng 			valcnt = 1;
1586da14cebeSEric Cheng 			if (type == DLADM_PROP_VAL_CURRENT)
1587da14cebeSEric Cheng 				propvals = &unknown;
1588da14cebeSEric Cheng 			else
1589da14cebeSEric Cheng 				propvals = &notsup;
1590da14cebeSEric Cheng 		} else {
1591da14cebeSEric Cheng 			if ((statep->fs_proplist != NULL) &&
1592da14cebeSEric Cheng 			    statep->fs_status == DLADM_STATUS_OK) {
1593da14cebeSEric Cheng 				warn("invalid flow property '%s'", propname);
1594da14cebeSEric Cheng 			}
1595da14cebeSEric Cheng 			statep->fs_status = status;
1596da14cebeSEric Cheng 			statep->fs_retstatus = status;
1597da14cebeSEric Cheng 			return;
1598da14cebeSEric Cheng 		}
1599da14cebeSEric Cheng 	}
1600da14cebeSEric Cheng 
1601da14cebeSEric Cheng 	statep->fs_status = DLADM_STATUS_OK;
1602da14cebeSEric Cheng 
1603da14cebeSEric Cheng 	ptr = buf;
1604da14cebeSEric Cheng 	lim = buf + DLADM_STRSIZE;
1605da14cebeSEric Cheng 	for (i = 0; i < valcnt; i++) {
16068002d411SSowmini Varadhan 		if (propvals[i][0] == '\0' && !statep->fs_parsable)
16078002d411SSowmini Varadhan 			ptr += snprintf(ptr, lim - ptr, "--,");
1608da14cebeSEric Cheng 		else
1609da14cebeSEric Cheng 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
1610da14cebeSEric Cheng 		if (ptr >= lim)
1611da14cebeSEric Cheng 			break;
1612da14cebeSEric Cheng 	}
1613da14cebeSEric Cheng 	if (valcnt > 0)
1614da14cebeSEric Cheng 		buf[strlen(buf) - 1] = '\0';
1615da14cebeSEric Cheng 
1616da14cebeSEric Cheng 	lim = statep->fs_line + MAX_PROP_LINE;
16178002d411SSowmini Varadhan 	if (statep->fs_parsable) {
1618da14cebeSEric Cheng 		*pptr += snprintf(*pptr, lim - *pptr,
1619da14cebeSEric Cheng 		    "%s", buf);
1620da14cebeSEric Cheng 	} else {
1621da14cebeSEric Cheng 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
1622da14cebeSEric Cheng 	}
1623da14cebeSEric Cheng }
1624da14cebeSEric Cheng 
16258002d411SSowmini Varadhan static boolean_t
16268002d411SSowmini Varadhan print_flowprop_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1627da14cebeSEric Cheng {
16288002d411SSowmini Varadhan 	flowprop_args_t		*arg = of_arg->ofmt_cbarg;
1629da14cebeSEric Cheng 	char 			*propname = arg->fs_propname;
1630da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg->fs_state;
1631da14cebeSEric Cheng 	char			*ptr = statep->fs_line;
1632da14cebeSEric Cheng 	char			*lim = ptr + MAX_PROP_LINE;
1633da14cebeSEric Cheng 	char			*flowname = arg->fs_flowname;
1634da14cebeSEric Cheng 
16358002d411SSowmini Varadhan 	switch (of_arg->ofmt_id) {
1636da14cebeSEric Cheng 	case FLOWPROP_FLOW:
1637da14cebeSEric Cheng 		(void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow);
1638da14cebeSEric Cheng 		break;
1639da14cebeSEric Cheng 	case FLOWPROP_PROPERTY:
1640da14cebeSEric Cheng 		(void) snprintf(ptr, lim - ptr, "%s", propname);
1641da14cebeSEric Cheng 		break;
1642da14cebeSEric Cheng 	case FLOWPROP_VALUE:
1643da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1644da14cebeSEric Cheng 		    statep->fs_persist ? DLADM_PROP_VAL_PERSISTENT :
1645da14cebeSEric Cheng 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
1646da14cebeSEric Cheng 		/*
1647da14cebeSEric Cheng 		 * If we failed to query the flow property, for example, query
1648da14cebeSEric Cheng 		 * the persistent value of a non-persistable flow property,
1649da14cebeSEric Cheng 		 * simply skip the output.
1650da14cebeSEric Cheng 		 */
1651da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1652da14cebeSEric Cheng 			goto skip;
1653da14cebeSEric Cheng 		ptr = statep->fs_line;
1654da14cebeSEric Cheng 		break;
1655da14cebeSEric Cheng 	case FLOWPROP_DEFAULT:
1656da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1657da14cebeSEric Cheng 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
1658da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1659da14cebeSEric Cheng 			goto skip;
1660da14cebeSEric Cheng 		ptr = statep->fs_line;
1661da14cebeSEric Cheng 		break;
1662da14cebeSEric Cheng 	case FLOWPROP_POSSIBLE:
1663da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1664da14cebeSEric Cheng 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
1665da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1666da14cebeSEric Cheng 			goto skip;
1667da14cebeSEric Cheng 		ptr = statep->fs_line;
1668da14cebeSEric Cheng 		break;
1669da14cebeSEric Cheng 	default:
1670da14cebeSEric Cheng 		die("invalid input");
1671da14cebeSEric Cheng 		break;
1672da14cebeSEric Cheng 	}
16738002d411SSowmini Varadhan 	(void) strlcpy(buf, ptr, bufsize);
16748002d411SSowmini Varadhan 	return (B_TRUE);
1675da14cebeSEric Cheng skip:
16768002d411SSowmini Varadhan 	buf[0] = '\0';
16778002d411SSowmini Varadhan 	return ((statep->fs_status == DLADM_STATUS_OK) ?
16788002d411SSowmini Varadhan 	    B_TRUE : B_FALSE);
1679da14cebeSEric Cheng }
1680da14cebeSEric Cheng 
1681da14cebeSEric Cheng static int
1682da14cebeSEric Cheng show_one_flowprop(void *arg, const char *propname)
1683da14cebeSEric Cheng {
1684da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg;
1685da14cebeSEric Cheng 	flowprop_args_t		fs_arg;
1686da14cebeSEric Cheng 
1687da14cebeSEric Cheng 	bzero(&fs_arg, sizeof (fs_arg));
1688da14cebeSEric Cheng 	fs_arg.fs_state = statep;
1689da14cebeSEric Cheng 	fs_arg.fs_propname = (char *)propname;
1690da14cebeSEric Cheng 	fs_arg.fs_flowname = (char *)statep->fs_flow;
1691da14cebeSEric Cheng 
16928002d411SSowmini Varadhan 	ofmt_print(statep->fs_ofmt, (void *)&fs_arg);
1693da14cebeSEric Cheng 
1694da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1695da14cebeSEric Cheng }
1696da14cebeSEric Cheng 
1697c3affd82SMichael Lim /*ARGSUSED*/
1698da14cebeSEric Cheng /* Walker function called by dladm_walk_flow to display flow properties */
1699da14cebeSEric Cheng static int
1700c3affd82SMichael Lim show_flowprop(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
1701da14cebeSEric Cheng {
1702da14cebeSEric Cheng 	show_flowprop_one_flow(arg, attr->fa_flowname);
1703da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1704da14cebeSEric Cheng }
1705da14cebeSEric Cheng 
1706da14cebeSEric Cheng /*
1707da14cebeSEric Cheng  * Wrapper of dladm_walk_flow(show_walk_fn,...) to make it
1708da14cebeSEric Cheng  * usable to dladm_walk_datalink_id()
1709da14cebeSEric Cheng  */
1710da14cebeSEric Cheng static int
17114ac67f02SAnurag S. Maskey show_flowprop_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1712da14cebeSEric Cheng {
1713da14cebeSEric Cheng 	char	name[MAXLINKNAMELEN];
1714da14cebeSEric Cheng 
17154ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, name,
17164ac67f02SAnurag S. Maskey 	    sizeof (name)) != DLADM_STATUS_OK)
1717da14cebeSEric Cheng 		return (DLADM_WALK_TERMINATE);
1718da14cebeSEric Cheng 
17194ac67f02SAnurag S. Maskey 	(void) dladm_walk_flow(show_flowprop, dh, linkid, arg, B_FALSE);
1720da14cebeSEric Cheng 
1721da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1722da14cebeSEric Cheng }
1723da14cebeSEric Cheng 
1724da14cebeSEric Cheng static void
1725da14cebeSEric Cheng do_show_flowprop(int argc, char **argv)
1726da14cebeSEric Cheng {
1727da14cebeSEric Cheng 	int			option;
1728da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1729da14cebeSEric Cheng 	show_flowprop_state_t	state;
1730da14cebeSEric Cheng 	char			*fields_str = NULL;
17318002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
17328002d411SSowmini Varadhan 	ofmt_status_t		oferr;
17338002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
1734da14cebeSEric Cheng 
1735da14cebeSEric Cheng 	opterr = 0;
1736da14cebeSEric Cheng 	state.fs_propvals = NULL;
1737da14cebeSEric Cheng 	state.fs_line = NULL;
17388002d411SSowmini Varadhan 	state.fs_parsable = B_FALSE;
1739da14cebeSEric Cheng 	state.fs_persist = B_FALSE;
1740da14cebeSEric Cheng 	state.fs_header = B_TRUE;
1741da14cebeSEric Cheng 	state.fs_retstatus = DLADM_STATUS_OK;
1742da14cebeSEric Cheng 	state.fs_linkid = DATALINK_INVALID_LINKID;
1743da14cebeSEric Cheng 	state.fs_flow = NULL;
1744da14cebeSEric Cheng 
1745da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":p:cPl:o:",
1746da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
1747da14cebeSEric Cheng 		switch (option) {
1748da14cebeSEric Cheng 		case 'p':
1749da14cebeSEric Cheng 			if (dladm_parse_flow_props(optarg, &proplist, B_TRUE)
1750da14cebeSEric Cheng 			    != DLADM_STATUS_OK)
1751da14cebeSEric Cheng 				die("invalid flow properties specified");
1752da14cebeSEric Cheng 			break;
1753da14cebeSEric Cheng 		case 'c':
17548002d411SSowmini Varadhan 			state.fs_parsable = B_TRUE;
17558002d411SSowmini Varadhan 			ofmtflags |= OFMT_PARSABLE;
1756da14cebeSEric Cheng 			break;
1757da14cebeSEric Cheng 		case 'P':
1758da14cebeSEric Cheng 			state.fs_persist = B_TRUE;
1759da14cebeSEric Cheng 			break;
1760da14cebeSEric Cheng 		case 'l':
17614ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, optarg, &state.fs_linkid,
1762da14cebeSEric Cheng 			    NULL, NULL, NULL) != DLADM_STATUS_OK)
1763da14cebeSEric Cheng 				die("invalid link '%s'", optarg);
1764da14cebeSEric Cheng 			break;
1765da14cebeSEric Cheng 		case 'o':
1766da14cebeSEric Cheng 			fields_str = optarg;
1767da14cebeSEric Cheng 			break;
1768da14cebeSEric Cheng 		default:
1769da14cebeSEric Cheng 			die_opterr(optopt, option);
1770da14cebeSEric Cheng 			break;
1771da14cebeSEric Cheng 		}
1772da14cebeSEric Cheng 	}
1773da14cebeSEric Cheng 
1774da14cebeSEric Cheng 	if (optind == (argc - 1)) {
1775da000602SGirish Moodalbail 		if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
1776da14cebeSEric Cheng 			die("flow name too long");
1777da14cebeSEric Cheng 		state.fs_flow = argv[optind];
1778da14cebeSEric Cheng 	} else if (optind != argc) {
1779da14cebeSEric Cheng 		usage();
1780da14cebeSEric Cheng 	}
1781da14cebeSEric Cheng 	state.fs_proplist = proplist;
1782da14cebeSEric Cheng 	state.fs_status = DLADM_STATUS_OK;
1783da14cebeSEric Cheng 
17848002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, flowprop_fields, ofmtflags, 0, &ofmt);
17858002d411SSowmini Varadhan 	flowadm_ofmt_check(oferr, state.fs_parsable, ofmt);
17868002d411SSowmini Varadhan 	state.fs_ofmt = ofmt;
1787da14cebeSEric Cheng 
1788da14cebeSEric Cheng 	/* Show properties for one flow */
1789da14cebeSEric Cheng 	if (state.fs_flow != NULL) {
1790da14cebeSEric Cheng 		show_flowprop_one_flow(&state, state.fs_flow);
1791da14cebeSEric Cheng 
1792da14cebeSEric Cheng 	/* Show properties for all flows on one link */
1793da14cebeSEric Cheng 	} else if (state.fs_linkid != DATALINK_INVALID_LINKID) {
17944ac67f02SAnurag S. Maskey 		(void) show_flowprop_onelink(handle, state.fs_linkid, &state);
1795da14cebeSEric Cheng 
1796da14cebeSEric Cheng 	/* Show properties for all flows on all links */
1797da14cebeSEric Cheng 	} else {
17984ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_flowprop_onelink, handle,
17994ac67f02SAnurag S. Maskey 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1800da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
1801da14cebeSEric Cheng 	}
1802da14cebeSEric Cheng 
1803da14cebeSEric Cheng 	dladm_free_props(proplist);
18048002d411SSowmini Varadhan 	ofmt_close(ofmt);
1805da14cebeSEric Cheng }
1806da14cebeSEric Cheng 
1807da14cebeSEric Cheng static void
1808da14cebeSEric Cheng show_flowprop_one_flow(void *arg, const char *flow)
1809da14cebeSEric Cheng {
1810da14cebeSEric Cheng 	int			i;
1811da14cebeSEric Cheng 	char			*buf;
1812da14cebeSEric Cheng 	dladm_status_t		status;
1813da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1814da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg;
1815da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
1816da14cebeSEric Cheng 	const char		*savep;
1817da14cebeSEric Cheng 
1818da14cebeSEric Cheng 	/*
1819da14cebeSEric Cheng 	 * Do not print flow props for invalid flows.
1820da14cebeSEric Cheng 	 */
18214ac67f02SAnurag S. Maskey 	if ((status = dladm_flow_info(handle, flow, &attr)) !=
18224ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK) {
1823da14cebeSEric Cheng 		die("invalid flow: '%s'", flow);
1824da14cebeSEric Cheng 	}
1825da14cebeSEric Cheng 
1826da14cebeSEric Cheng 	savep = statep->fs_flow;
1827da14cebeSEric Cheng 	statep->fs_flow = flow;
1828da14cebeSEric Cheng 
1829da14cebeSEric Cheng 	proplist = statep->fs_proplist;
1830da14cebeSEric Cheng 
1831da14cebeSEric Cheng 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX)
1832da14cebeSEric Cheng 	    * DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
1833da14cebeSEric Cheng 	if (buf == NULL)
1834da14cebeSEric Cheng 		die("insufficient memory");
1835da14cebeSEric Cheng 
1836da14cebeSEric Cheng 	statep->fs_propvals = (char **)(void *)buf;
1837da14cebeSEric Cheng 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
1838da14cebeSEric Cheng 		statep->fs_propvals[i] = buf +
1839da14cebeSEric Cheng 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1840da14cebeSEric Cheng 		    i * DLADM_PROP_VAL_MAX;
1841da14cebeSEric Cheng 	}
1842da14cebeSEric Cheng 	statep->fs_line = buf +
1843da14cebeSEric Cheng 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
1844da14cebeSEric Cheng 
1845da14cebeSEric Cheng 	/* show only specified flow properties */
1846da14cebeSEric Cheng 	if (proplist != NULL) {
1847da14cebeSEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
1848da14cebeSEric Cheng 			if (show_one_flowprop(statep,
1849da14cebeSEric Cheng 			    proplist->al_info[i].ai_name) != DLADM_STATUS_OK)
1850da14cebeSEric Cheng 				break;
1851da14cebeSEric Cheng 		}
1852da14cebeSEric Cheng 
1853da14cebeSEric Cheng 	/* show all flow properties */
1854da14cebeSEric Cheng 	} else {
1855da14cebeSEric Cheng 		status = dladm_walk_flowprop(show_one_flowprop, flow, statep);
1856da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
1857da14cebeSEric Cheng 			die_dlerr(status, "show-flowprop");
1858da14cebeSEric Cheng 	}
1859da14cebeSEric Cheng 	free(buf);
1860da14cebeSEric Cheng 	statep->fs_flow = savep;
1861da14cebeSEric Cheng }
1862da14cebeSEric Cheng 
1863da14cebeSEric Cheng /*
18648002d411SSowmini Varadhan  * default output callback function that, when invoked from dladm_print_output,
18658002d411SSowmini Varadhan  * prints string which is offset by of_arg->ofmt_id within buf.
1866da14cebeSEric Cheng  */
18678002d411SSowmini Varadhan static boolean_t
18688002d411SSowmini Varadhan print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1869da14cebeSEric Cheng {
1870da14cebeSEric Cheng 	char *value;
1871da14cebeSEric Cheng 
18728002d411SSowmini Varadhan 	value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id;
18738002d411SSowmini Varadhan 	(void) strlcpy(buf, value, bufsize);
18748002d411SSowmini Varadhan 	return (B_TRUE);
1875da14cebeSEric Cheng }
1876da14cebeSEric Cheng 
1877da14cebeSEric Cheng static void
18788002d411SSowmini Varadhan flowadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
18798002d411SSowmini Varadhan     ofmt_handle_t ofmt)
1880da14cebeSEric Cheng {
18818002d411SSowmini Varadhan 	char buf[OFMT_BUFSIZE];
1882da14cebeSEric Cheng 
18838002d411SSowmini Varadhan 	if (oferr == OFMT_SUCCESS)
18848002d411SSowmini Varadhan 		return;
18858002d411SSowmini Varadhan 	(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
1886ad091ee1SMichael Lim 	/*
18878002d411SSowmini Varadhan 	 * All errors are considered fatal in parsable mode.
18888002d411SSowmini Varadhan 	 * NOMEM errors are always fatal, regardless of mode.
18898002d411SSowmini Varadhan 	 * For other errors, we print diagnostics in human-readable
18908002d411SSowmini Varadhan 	 * mode and processs what we can.
1891ad091ee1SMichael Lim 	 */
18928002d411SSowmini Varadhan 	if (parsable || oferr == OFMT_ENOFIELDS) {
18938002d411SSowmini Varadhan 		ofmt_close(ofmt);
18948002d411SSowmini Varadhan 		die(buf);
1895da14cebeSEric Cheng 	} else {
18968002d411SSowmini Varadhan 		warn(buf);
1897da14cebeSEric Cheng 	}
1898da14cebeSEric Cheng }
1899