xref: /titanic_51/usr/src/cmd/flowadm/flowadm.c (revision 63a6526d84bd7ea2c75b4b0d009fa5f51a67a22a)
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>
52da14cebeSEric Cheng 
53da14cebeSEric Cheng #define	CMD_TYPE_ANY	0xffffffff
54da14cebeSEric Cheng #define	STR_UNDEF_VAL	"--"
55da14cebeSEric Cheng 
56da14cebeSEric Cheng 
57da14cebeSEric Cheng /*
58da14cebeSEric Cheng  * data structures and routines for printing output.
59da14cebeSEric Cheng  */
60da14cebeSEric Cheng 
61da14cebeSEric Cheng typedef struct print_field_s {
62da14cebeSEric Cheng 	const char	*pf_name;
63da14cebeSEric Cheng 	const char	*pf_header;
64da14cebeSEric Cheng 	uint_t		pf_width;
65da14cebeSEric Cheng 	union {
66da14cebeSEric Cheng 		uint_t	_pf_index;
67da14cebeSEric Cheng 		size_t	_pf_offset;
68da14cebeSEric Cheng 	}_pf_un;
69da14cebeSEric Cheng #define	pf_index	_pf_un._pf_index
70da14cebeSEric Cheng #define	pf_offset	_pf_un._pf_offset;
71da14cebeSEric Cheng 	uint_t	pf_cmdtype;
72da14cebeSEric Cheng } print_field_t;
73da14cebeSEric Cheng 
74da14cebeSEric Cheng typedef struct print_state_s {
75da14cebeSEric Cheng 	print_field_t	**ps_fields;
76da14cebeSEric Cheng 	uint_t		ps_nfields;
77da14cebeSEric Cheng 	boolean_t	ps_lastfield;
78da14cebeSEric Cheng 	uint_t		ps_overflow;
79da14cebeSEric Cheng } print_state_t;
80da14cebeSEric Cheng 
81da14cebeSEric Cheng typedef struct show_usage_state_s {
82da14cebeSEric Cheng 	boolean_t	us_plot;
83da14cebeSEric Cheng 	boolean_t	us_parseable;
84da14cebeSEric Cheng 	boolean_t	us_printheader;
85da14cebeSEric Cheng 	boolean_t	us_first;
86ae6aa22aSVenugopal Iyer 	boolean_t	us_showall;
87da14cebeSEric Cheng 	print_state_t	us_print;
88da14cebeSEric Cheng } show_usage_state_t;
89da14cebeSEric Cheng 
90da14cebeSEric Cheng typedef char *(*print_callback_t)(print_field_t *, void *);
91da14cebeSEric Cheng static print_field_t **parse_output_fields(char *, print_field_t *, int,
92da14cebeSEric Cheng     uint_t, uint_t *);
93da14cebeSEric Cheng 
94da14cebeSEric Cheng static void print_header(print_state_t *);
95da14cebeSEric Cheng static void print_field(print_state_t *, print_field_t *, const char *,
96da14cebeSEric Cheng     boolean_t);
97da14cebeSEric Cheng 
98da14cebeSEric Cheng static void flowadm_print_output(print_state_t *, boolean_t,
99da14cebeSEric Cheng     print_callback_t, void *);
100da14cebeSEric Cheng 
101da14cebeSEric Cheng /*
102da14cebeSEric Cheng  * helper function that, when invoked as flowadm(print_field(pf, buf)
103da14cebeSEric Cheng  * prints string which is offset by pf->pf_offset within buf.
104da14cebeSEric Cheng  */
105da14cebeSEric Cheng static char *flowadm_print_field(print_field_t *, void *);
106da14cebeSEric Cheng 
107da14cebeSEric Cheng #define	MAX_FIELD_LEN	32
108da14cebeSEric Cheng 
109ae6aa22aSVenugopal Iyer typedef struct show_flow_state {
110ae6aa22aSVenugopal Iyer 	boolean_t		fs_firstonly;
111ae6aa22aSVenugopal Iyer 	boolean_t		fs_donefirst;
112ae6aa22aSVenugopal Iyer 	pktsum_t		fs_prevstats;
113ae6aa22aSVenugopal Iyer 	uint32_t		fs_flags;
114ae6aa22aSVenugopal Iyer 	dladm_status_t		fs_status;
115ae6aa22aSVenugopal Iyer 	print_state_t		fs_print;
116ae6aa22aSVenugopal Iyer 	const char		*fs_flow;
117ae6aa22aSVenugopal Iyer 	const char		*fs_link;
118ae6aa22aSVenugopal Iyer 	boolean_t		fs_parseable;
119ae6aa22aSVenugopal Iyer 	boolean_t		fs_printheader;
120ae6aa22aSVenugopal Iyer 	boolean_t		fs_persist;
121ae6aa22aSVenugopal Iyer 	boolean_t		fs_stats;
122ae6aa22aSVenugopal Iyer 	uint64_t		fs_mask;
123ae6aa22aSVenugopal Iyer } show_flow_state_t;
124ae6aa22aSVenugopal Iyer 
125da14cebeSEric Cheng typedef void cmdfunc_t(int, char **);
126da14cebeSEric Cheng 
127da14cebeSEric Cheng static cmdfunc_t do_add_flow, do_remove_flow, do_init_flow, do_show_flow;
128da14cebeSEric Cheng static cmdfunc_t do_show_flowprop, do_set_flowprop, do_reset_flowprop;
129da14cebeSEric Cheng static cmdfunc_t do_show_usage;
130da14cebeSEric Cheng 
131da14cebeSEric Cheng static int	show_flow(dladm_flow_attr_t *, void *);
1324ac67f02SAnurag S. Maskey static int	show_flows_onelink(dladm_handle_t, datalink_id_t, void *);
133da14cebeSEric Cheng 
134ae6aa22aSVenugopal Iyer static void	flow_stats(const char *, datalink_id_t,  uint_t, char *,
135ae6aa22aSVenugopal Iyer 		    show_flow_state_t *);
136da14cebeSEric Cheng static void	get_flow_stats(const char *, pktsum_t *);
137da14cebeSEric Cheng static int	show_flow_stats(dladm_flow_attr_t *, void *);
1384ac67f02SAnurag S. Maskey static int	show_link_flow_stats(dladm_handle_t, datalink_id_t, void *);
139da14cebeSEric Cheng 
140da14cebeSEric Cheng static int	remove_flow(dladm_flow_attr_t *, void *);
141da14cebeSEric Cheng 
142da14cebeSEric Cheng static int	show_flowprop(dladm_flow_attr_t *, void *);
143da14cebeSEric Cheng static void	show_flowprop_one_flow(void *, const char *);
1444ac67f02SAnurag S. Maskey static int	show_flowprop_onelink(dladm_handle_t, datalink_id_t, void *);
145da14cebeSEric Cheng 
146da14cebeSEric Cheng static void	die(const char *, ...);
147da14cebeSEric Cheng static void	die_optdup(int);
148da14cebeSEric Cheng static void	die_opterr(int, int);
149da14cebeSEric Cheng static void	die_dlerr(dladm_status_t, const char *, ...);
150da14cebeSEric Cheng static void	warn(const char *, ...);
151da14cebeSEric Cheng static void	warn_dlerr(dladm_status_t, const char *, ...);
152da14cebeSEric Cheng 
153da14cebeSEric Cheng typedef struct	cmd {
154da14cebeSEric Cheng 	char	*c_name;
155da14cebeSEric Cheng 	void	(*c_fn)(int, char **);
156da14cebeSEric Cheng } cmd_t;
157da14cebeSEric Cheng 
158da14cebeSEric Cheng static cmd_t	cmds[] = {
159da14cebeSEric Cheng 	{ "add-flow", do_add_flow },
160da14cebeSEric Cheng 	{ "remove-flow", do_remove_flow },
161da14cebeSEric Cheng 	{ "show-flowprop", do_show_flowprop },
162da14cebeSEric Cheng 	{ "set-flowprop", do_set_flowprop },
163da14cebeSEric Cheng 	{ "reset-flowprop", do_reset_flowprop },
164da14cebeSEric Cheng 	{ "show-flow", do_show_flow },
165da14cebeSEric Cheng 	{ "init-flow", do_init_flow },
166da14cebeSEric Cheng 	{ "show-usage", do_show_usage }
167da14cebeSEric Cheng };
168da14cebeSEric Cheng 
169da14cebeSEric Cheng static const struct option longopts[] = {
170da14cebeSEric Cheng 	{"link",		required_argument,	0, 'l'},
171da14cebeSEric Cheng 	{"parseable",		no_argument,		0, 'p'},
172da14cebeSEric Cheng 	{"statistics",		no_argument,		0, 's'},
173da14cebeSEric Cheng 	{"interval",		required_argument,	0, 'i'},
174da14cebeSEric Cheng 	{"temporary",		no_argument,		0, 't'},
175da14cebeSEric Cheng 	{"root-dir",		required_argument,	0, 'R'},
176da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
177da14cebeSEric Cheng };
178da14cebeSEric Cheng 
179da14cebeSEric Cheng static const struct option prop_longopts[] = {
180da14cebeSEric Cheng 	{"link",		required_argument,	0, 'l'},
181da14cebeSEric Cheng 	{"temporary",		no_argument,		0, 't'},
182da14cebeSEric Cheng 	{"root-dir",		required_argument,	0, 'R'},
183da14cebeSEric Cheng 	{"prop",		required_argument,	0, 'p'},
184da14cebeSEric Cheng 	{"attr",		required_argument,	0, 'a'},
185da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
186da14cebeSEric Cheng };
187da14cebeSEric Cheng 
188da14cebeSEric Cheng /*
189da14cebeSEric Cheng  * structures for 'flowadm remove-flow'
190da14cebeSEric Cheng  */
191da14cebeSEric Cheng 
192da14cebeSEric Cheng typedef struct remove_flow_state {
193da14cebeSEric Cheng 	boolean_t	fs_tempop;
194da14cebeSEric Cheng 	const char	*fs_altroot;
195da14cebeSEric Cheng 	dladm_status_t	fs_status;
196da14cebeSEric Cheng } remove_flow_state_t;
197da14cebeSEric Cheng 
198da14cebeSEric Cheng #define	PROTO_MAXSTR_LEN	7
199da14cebeSEric Cheng #define	PORT_MAXSTR_LEN		6
200da14cebeSEric Cheng #define	DSFIELD_MAXSTR_LEN	10
201da14cebeSEric Cheng 
202da14cebeSEric Cheng typedef struct flow_fields_buf_s
203da14cebeSEric Cheng {
204da000602SGirish Moodalbail 	char flow_name[MAXFLOWNAMELEN];
205da14cebeSEric Cheng 	char flow_link[MAXLINKNAMELEN];
206da14cebeSEric Cheng 	char flow_ipaddr[INET6_ADDRSTRLEN+4];
207da14cebeSEric Cheng 	char flow_proto[PROTO_MAXSTR_LEN];
208da14cebeSEric Cheng 	char flow_port[PORT_MAXSTR_LEN];
209da14cebeSEric Cheng 	char flow_dsfield[DSFIELD_MAXSTR_LEN];
210da14cebeSEric Cheng } flow_fields_buf_t;
211da14cebeSEric Cheng 
212da14cebeSEric Cheng static print_field_t flow_fields[] = {
213da14cebeSEric Cheng /* name,	header,		field width,	index,		cmdtype	*/
214da14cebeSEric Cheng {  "flow",	"FLOW",		11,
215da14cebeSEric Cheng     offsetof(flow_fields_buf_t, flow_name),	CMD_TYPE_ANY},
216da14cebeSEric Cheng {  "link",	"LINK",		11,
217da14cebeSEric Cheng     offsetof(flow_fields_buf_t, flow_link),	CMD_TYPE_ANY},
218da14cebeSEric Cheng {  "ipaddr",	"IPADDR",	30,
219da14cebeSEric Cheng     offsetof(flow_fields_buf_t, flow_ipaddr),	CMD_TYPE_ANY},
220ad091ee1SMichael Lim {  "proto",	"PROTO",	6,
221da14cebeSEric Cheng     offsetof(flow_fields_buf_t, flow_proto),	CMD_TYPE_ANY},
222da14cebeSEric Cheng {  "port",	 "PORT",	7,
223da14cebeSEric Cheng     offsetof(flow_fields_buf_t, flow_port),	CMD_TYPE_ANY},
224ad091ee1SMichael Lim {  "dsfld",	"DSFLD",	9,
225da14cebeSEric Cheng     offsetof(flow_fields_buf_t, flow_dsfield),	CMD_TYPE_ANY}}
226da14cebeSEric Cheng ;
227da14cebeSEric Cheng 
228da14cebeSEric Cheng #define	FLOW_MAX_FIELDS		(sizeof (flow_fields) / sizeof (print_field_t))
229da14cebeSEric Cheng 
230da14cebeSEric Cheng /*
231da14cebeSEric Cheng  * structures for 'flowadm show-flowprop'
232da14cebeSEric Cheng  */
233da14cebeSEric Cheng typedef enum {
234da14cebeSEric Cheng 	FLOWPROP_FLOW,
235da14cebeSEric Cheng 	FLOWPROP_PROPERTY,
236da14cebeSEric Cheng 	FLOWPROP_VALUE,
237da14cebeSEric Cheng 	FLOWPROP_DEFAULT,
238da14cebeSEric Cheng 	FLOWPROP_POSSIBLE
239da14cebeSEric Cheng } flowprop_field_index_t;
240da14cebeSEric Cheng 
241da14cebeSEric Cheng static print_field_t flowprop_fields[] = {
242da14cebeSEric Cheng /* name,	header,		fieldwidth,	index,		cmdtype */
243da14cebeSEric Cheng { "flow",	"FLOW",		12,	FLOWPROP_FLOW,		CMD_TYPE_ANY},
244da14cebeSEric Cheng { "property",	"PROPERTY",	15,	FLOWPROP_PROPERTY,	CMD_TYPE_ANY},
245da14cebeSEric Cheng { "value",	"VALUE",	14,	FLOWPROP_VALUE,		CMD_TYPE_ANY},
246da14cebeSEric Cheng { "default",	"DEFAULT",	14,	FLOWPROP_DEFAULT,	CMD_TYPE_ANY},
247da14cebeSEric Cheng { "possible",	"POSSIBLE",	20,	FLOWPROP_POSSIBLE,	CMD_TYPE_ANY}}
248da14cebeSEric Cheng ;
249da14cebeSEric Cheng #define	FLOWPROP_MAX_FIELDS					\
250da14cebeSEric Cheng 	(sizeof (flowprop_fields) / sizeof (print_field_t))
251da14cebeSEric Cheng 
252da14cebeSEric Cheng #define	MAX_PROP_LINE		512
253da14cebeSEric Cheng 
254da14cebeSEric Cheng typedef struct show_flowprop_state {
255da14cebeSEric Cheng 	const char		*fs_flow;
256da14cebeSEric Cheng 	datalink_id_t		fs_linkid;
257da14cebeSEric Cheng 	char			*fs_line;
258da14cebeSEric Cheng 	char			**fs_propvals;
259da14cebeSEric Cheng 	dladm_arg_list_t	*fs_proplist;
260da14cebeSEric Cheng 	boolean_t		fs_parseable;
261da14cebeSEric Cheng 	boolean_t		fs_persist;
262da14cebeSEric Cheng 	boolean_t		fs_header;
263da14cebeSEric Cheng 	dladm_status_t		fs_status;
264da14cebeSEric Cheng 	dladm_status_t		fs_retstatus;
265da14cebeSEric Cheng 	print_state_t		fs_print;
266da14cebeSEric Cheng } show_flowprop_state_t;
267da14cebeSEric Cheng 
268da14cebeSEric Cheng typedef struct set_flowprop_state {
269da14cebeSEric Cheng 	const char	*fs_name;
270da14cebeSEric Cheng 	boolean_t	fs_reset;
271da14cebeSEric Cheng 	boolean_t	fs_temp;
272da14cebeSEric Cheng 	dladm_status_t	fs_status;
273da14cebeSEric Cheng } set_flowprop_state_t;
274da14cebeSEric Cheng 
275da14cebeSEric Cheng typedef struct flowprop_args_s {
276da14cebeSEric Cheng 	show_flowprop_state_t	*fs_state;
277da14cebeSEric Cheng 	char			*fs_propname;
278da14cebeSEric Cheng 	char			*fs_flowname;
279da14cebeSEric Cheng } flowprop_args_t;
280ae6aa22aSVenugopal Iyer /*
281ae6aa22aSVenugopal Iyer  * structures for 'flowadm show-flow -s' (print statistics)
282ae6aa22aSVenugopal Iyer  */
283ae6aa22aSVenugopal Iyer typedef enum {
284ae6aa22aSVenugopal Iyer 	FLOW_S_FLOW,
285ae6aa22aSVenugopal Iyer 	FLOW_S_IPKTS,
286ae6aa22aSVenugopal Iyer 	FLOW_S_RBYTES,
287ae6aa22aSVenugopal Iyer 	FLOW_S_IERRORS,
288ae6aa22aSVenugopal Iyer 	FLOW_S_OPKTS,
289ae6aa22aSVenugopal Iyer 	FLOW_S_OBYTES,
290ae6aa22aSVenugopal Iyer 	FLOW_S_OERRORS
291ae6aa22aSVenugopal Iyer } flow_s_field_index_t;
292ae6aa22aSVenugopal Iyer 
293ae6aa22aSVenugopal Iyer static print_field_t flow_s_fields[] = {
294ae6aa22aSVenugopal Iyer /* name,	header,		field width,	index,		cmdtype	*/
295ae6aa22aSVenugopal Iyer { "flow",	"FLOW",			15,	FLOW_S_FLOW,	CMD_TYPE_ANY},
296ae6aa22aSVenugopal Iyer { "ipackets",	"IPACKETS",		10,	FLOW_S_IPKTS,	CMD_TYPE_ANY},
297ae6aa22aSVenugopal Iyer { "rbytes",	"RBYTES",		8,	FLOW_S_RBYTES,	CMD_TYPE_ANY},
298ae6aa22aSVenugopal Iyer { "ierrors",	"IERRORS",		10,	FLOW_S_IERRORS,	CMD_TYPE_ANY},
299ae6aa22aSVenugopal Iyer { "opackets",	"OPACKETS",		12,	FLOW_S_OPKTS,	CMD_TYPE_ANY},
300ae6aa22aSVenugopal Iyer { "obytes",	"OBYTES",		12,	FLOW_S_OBYTES,	CMD_TYPE_ANY},
301ae6aa22aSVenugopal Iyer { "oerrors",	"OERRORS",		8,	FLOW_S_OERRORS,	CMD_TYPE_ANY}}
302ae6aa22aSVenugopal Iyer ;
303ae6aa22aSVenugopal Iyer #define	FLOW_S_MAX_FIELDS \
304ae6aa22aSVenugopal Iyer 	(sizeof (flow_s_fields) / sizeof (print_field_t))
305ae6aa22aSVenugopal Iyer 
306ae6aa22aSVenugopal Iyer typedef struct flow_args_s {
307ae6aa22aSVenugopal Iyer 	char		*flow_s_flow;
308ae6aa22aSVenugopal Iyer 	pktsum_t	*flow_s_psum;
309ae6aa22aSVenugopal Iyer } flow_args_t;
310ae6aa22aSVenugopal Iyer static char *print_flow_stats(print_field_t *, void *);
311da14cebeSEric Cheng 
312da14cebeSEric Cheng /*
313ae6aa22aSVenugopal Iyer  * structures for 'flowadm show-usage'
314da14cebeSEric Cheng  */
315da14cebeSEric Cheng 
316da14cebeSEric Cheng typedef struct  usage_fields_buf_s {
317da14cebeSEric Cheng 	char	usage_flow[12];
318da14cebeSEric Cheng 	char	usage_duration[10];
319da14cebeSEric Cheng 	char	usage_ipackets[9];
320da14cebeSEric Cheng 	char	usage_rbytes[10];
321da14cebeSEric Cheng 	char	usage_opackets[9];
322da14cebeSEric Cheng 	char	usage_obytes[10];
323da14cebeSEric Cheng 	char	usage_bandwidth[14];
324da14cebeSEric Cheng } usage_fields_buf_t;
325da14cebeSEric Cheng 
326da14cebeSEric Cheng static print_field_t usage_fields[] = {
327da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
328da14cebeSEric Cheng { "flow",	"FLOW",			12,
329da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_flow),		CMD_TYPE_ANY},
330da14cebeSEric Cheng { "duration",	"DURATION",		10,
331da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_duration),	CMD_TYPE_ANY},
332da14cebeSEric Cheng { "ipackets",	"IPACKETS",		9,
333da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_ipackets),	CMD_TYPE_ANY},
334da14cebeSEric Cheng { "rbytes",	"RBYTES",		10,
335da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_rbytes),		CMD_TYPE_ANY},
336da14cebeSEric Cheng { "opackets",	"OPACKETS",		9,
337da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_opackets),	CMD_TYPE_ANY},
338da14cebeSEric Cheng { "obytes",	"OBYTES",		10,
339da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_obytes),		CMD_TYPE_ANY},
340da14cebeSEric Cheng { "bandwidth",	"BANDWIDTH",		14,
341da14cebeSEric Cheng     offsetof(usage_fields_buf_t, usage_bandwidth),	CMD_TYPE_ANY}}
342da14cebeSEric Cheng ;
343da14cebeSEric Cheng 
344da14cebeSEric Cheng #define	USAGE_MAX_FIELDS	(sizeof (usage_fields) / sizeof (print_field_t))
345da14cebeSEric Cheng 
346da14cebeSEric Cheng /*
347da14cebeSEric Cheng  * structures for 'dladm show-usage link'
348da14cebeSEric Cheng  */
349da14cebeSEric Cheng 
350da14cebeSEric Cheng typedef struct  usage_l_fields_buf_s {
351da14cebeSEric Cheng 	char	usage_l_flow[12];
352da14cebeSEric Cheng 	char	usage_l_stime[13];
353da14cebeSEric Cheng 	char	usage_l_etime[13];
354da14cebeSEric Cheng 	char	usage_l_rbytes[8];
355da14cebeSEric Cheng 	char	usage_l_obytes[8];
356da14cebeSEric Cheng 	char	usage_l_bandwidth[14];
357da14cebeSEric Cheng } usage_l_fields_buf_t;
358da14cebeSEric Cheng 
359da14cebeSEric Cheng static print_field_t usage_l_fields[] = {
360da14cebeSEric Cheng /* name,	header,		field width,	offset,	cmdtype		*/
361da14cebeSEric Cheng { "flow",	"FLOW",		12,
362da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_flow),	CMD_TYPE_ANY},
363da14cebeSEric Cheng { "start",	"START",	13,
364da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_stime),	CMD_TYPE_ANY},
365da14cebeSEric Cheng { "end",	"END",		13,
366da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_etime),	CMD_TYPE_ANY},
367da14cebeSEric Cheng { "rbytes",	"RBYTES",	8,
368da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_rbytes),	CMD_TYPE_ANY},
369da14cebeSEric Cheng { "obytes",	"OBYTES",	8,
370da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_obytes),	CMD_TYPE_ANY},
371da14cebeSEric Cheng { "bandwidth",	"BANDWIDTH",	14,
372da14cebeSEric Cheng     offsetof(usage_l_fields_buf_t, usage_l_bandwidth),	CMD_TYPE_ANY}}
373da14cebeSEric Cheng ;
374da14cebeSEric Cheng 
375da14cebeSEric Cheng #define	USAGE_L_MAX_FIELDS \
376da14cebeSEric Cheng 	(sizeof (usage_l_fields) /sizeof (print_field_t))
377da14cebeSEric Cheng 
378da14cebeSEric Cheng #define	PRI_HI		100
379da14cebeSEric Cheng #define	PRI_LO 		10
380da14cebeSEric Cheng #define	PRI_NORM	50
381da14cebeSEric Cheng 
382da14cebeSEric Cheng #define	FLOWADM_CONF	"/etc/dladm/flowadm.conf"
383da14cebeSEric Cheng #define	BLANK_LINE(s)	((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n'))
384da14cebeSEric Cheng 
385da14cebeSEric Cheng static char *progname;
386da14cebeSEric Cheng 
387da14cebeSEric Cheng boolean_t		t_arg = B_FALSE; /* changes are persistent */
388da14cebeSEric Cheng char			*altroot = NULL;
389da14cebeSEric Cheng 
3904ac67f02SAnurag S. Maskey /*
3914ac67f02SAnurag S. Maskey  * Handle to libdladm.  Opened in main() before the sub-command
3924ac67f02SAnurag S. Maskey  * specific function is called.
3934ac67f02SAnurag S. Maskey  */
3944ac67f02SAnurag S. Maskey static dladm_handle_t handle = NULL;
3954ac67f02SAnurag S. Maskey 
396da14cebeSEric Cheng static const char *attr_table[] =
397da14cebeSEric Cheng 	{"local_ip", "remote_ip", "transport", "local_port", "dsfield"};
398da14cebeSEric Cheng 
399da14cebeSEric Cheng #define	NATTR	(sizeof (attr_table)/sizeof (char *))
400da14cebeSEric Cheng 
401da14cebeSEric Cheng static void
402da14cebeSEric Cheng usage(void)
403da14cebeSEric Cheng {
404da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("usage: flowadm <subcommand>"
405da14cebeSEric Cheng 	    " <args>...\n"
4060790b6dcSAnurag S. Maskey 	    "    add-flow       [-t] -l <link> -a <attr>=<value>[,...]\n"
4070790b6dcSAnurag S. Maskey 	    "\t\t   [-p <prop>=<value>,...] <flow>\n"
4080790b6dcSAnurag S. Maskey 	    "    remove-flow    [-t] {-l <link> | <flow>}\n"
4090790b6dcSAnurag S. Maskey 	    "    show-flow      [-p] [-s [-i <interval>]] [-l <link>] "
4100790b6dcSAnurag S. Maskey 	    "[<flow>]\n\n"
4110790b6dcSAnurag S. Maskey 	    "    set-flowprop   [-t] -p <prop>=<value>[,...] <flow>\n"
4120790b6dcSAnurag S. Maskey 	    "    reset-flowprop [-t] [-p <prop>,...] <flow>\n"
4130790b6dcSAnurag S. Maskey 	    "    show-flowprop  [-cP] [-l <link>] [-p <prop>,...] "
4140790b6dcSAnurag S. Maskey 	    "[<flow>]\n\n"
415ae6aa22aSVenugopal Iyer 	    "    show-usage     [-a] [-d | -F <format>] "
4160790b6dcSAnurag S. Maskey 	    "[-s <DD/MM/YYYY,HH:MM:SS>]\n"
4170790b6dcSAnurag S. Maskey 	    "\t\t   [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<flow>]\n"));
4184ac67f02SAnurag S. Maskey 
4194ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
4204ac67f02SAnurag S. Maskey 	if (handle != NULL)
4214ac67f02SAnurag S. Maskey 		dladm_close(handle);
4224ac67f02SAnurag S. Maskey 
423da14cebeSEric Cheng 	exit(1);
424da14cebeSEric Cheng }
425da14cebeSEric Cheng 
426da14cebeSEric Cheng int
427da14cebeSEric Cheng main(int argc, char *argv[])
428da14cebeSEric Cheng {
429da14cebeSEric Cheng 	int	i, arglen, cmdlen;
430da14cebeSEric Cheng 	cmd_t	*cmdp;
4314ac67f02SAnurag S. Maskey 	dladm_status_t status;
432da14cebeSEric Cheng 
433da14cebeSEric Cheng 	(void) setlocale(LC_ALL, "");
434da14cebeSEric Cheng #if !defined(TEXT_DOMAIN)
435da14cebeSEric Cheng #define	TEXT_DOMAIN "SYS_TEST"
436da14cebeSEric Cheng #endif
437da14cebeSEric Cheng 	(void) textdomain(TEXT_DOMAIN);
438da14cebeSEric Cheng 
439da14cebeSEric Cheng 	progname = argv[0];
440da14cebeSEric Cheng 
441da14cebeSEric Cheng 	if (argc < 2)
442da14cebeSEric Cheng 		usage();
443da14cebeSEric Cheng 
444da14cebeSEric Cheng 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
445da14cebeSEric Cheng 		cmdp = &cmds[i];
446da14cebeSEric Cheng 		arglen = strlen(argv[1]);
447da14cebeSEric Cheng 		cmdlen = strlen(cmdp->c_name);
448da14cebeSEric Cheng 		if ((arglen == cmdlen) && (strncmp(argv[1], cmdp->c_name,
449da14cebeSEric Cheng 		    cmdlen) == 0)) {
4504ac67f02SAnurag S. Maskey 			/* Open the libdladm handle */
4514ac67f02SAnurag S. Maskey 			if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
4524ac67f02SAnurag S. Maskey 				die_dlerr(status,
4534ac67f02SAnurag S. Maskey 				    "could not open /dev/dld");
4544ac67f02SAnurag S. Maskey 			}
4554ac67f02SAnurag S. Maskey 
456da14cebeSEric Cheng 			cmdp->c_fn(argc - 1, &argv[1]);
4574ac67f02SAnurag S. Maskey 
4584ac67f02SAnurag S. Maskey 			dladm_close(handle);
459ad091ee1SMichael Lim 			exit(EXIT_SUCCESS);
460da14cebeSEric Cheng 		}
461da14cebeSEric Cheng 	}
462da14cebeSEric Cheng 
463da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
464da14cebeSEric Cheng 	    progname, argv[1]);
465da14cebeSEric Cheng 	usage();
466da14cebeSEric Cheng 
467da14cebeSEric Cheng 	return (0);
468da14cebeSEric Cheng }
469da14cebeSEric Cheng 
470da14cebeSEric Cheng static const char *
471da14cebeSEric Cheng match_attr(char *attr)
472da14cebeSEric Cheng {
473da14cebeSEric Cheng 	int i;
474da14cebeSEric Cheng 
475da14cebeSEric Cheng 	for (i = 0; i < NATTR; i++) {
476da14cebeSEric Cheng 		if (strlen(attr) == strlen(attr_table[i]) &&
477da14cebeSEric Cheng 		    strncmp(attr, attr_table[i], strlen(attr_table[i])) == 0) {
478da14cebeSEric Cheng 			return (attr);
479da14cebeSEric Cheng 		}
480da14cebeSEric Cheng 	}
481da14cebeSEric Cheng 	return (NULL);
482da14cebeSEric Cheng }
483da14cebeSEric Cheng 
484da14cebeSEric Cheng /* ARGSUSED */
485da14cebeSEric Cheng static void
486da14cebeSEric Cheng do_init_flow(int argc, char *argv[])
487da14cebeSEric Cheng {
488da14cebeSEric Cheng 	dladm_status_t status;
489da14cebeSEric Cheng 
4904ac67f02SAnurag S. Maskey 	status = dladm_flow_init(handle);
491da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
492da14cebeSEric Cheng 		die_dlerr(status, "flows initialization failed");
493da14cebeSEric Cheng }
494da14cebeSEric Cheng 
495da14cebeSEric Cheng /* ARGSUSED */
496da14cebeSEric Cheng static int
497da14cebeSEric Cheng show_usage_date(dladm_usage_t *usage, void *arg)
498da14cebeSEric Cheng {
499ae6aa22aSVenugopal Iyer 	show_usage_state_t	*state = (show_usage_state_t *)arg;
500da14cebeSEric Cheng 	time_t			stime;
501da14cebeSEric Cheng 	char			timebuf[20];
502ae6aa22aSVenugopal Iyer 	dladm_flow_attr_t	attr;
503ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
504ae6aa22aSVenugopal Iyer 
505ae6aa22aSVenugopal Iyer 	/*
506ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing flows unless '-a'
507ae6aa22aSVenugopal Iyer 	 * is specified.
508ae6aa22aSVenugopal Iyer 	 */
509ae6aa22aSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
510ae6aa22aSVenugopal Iyer 	    usage->du_name, &attr)) != DLADM_STATUS_OK)) {
511ae6aa22aSVenugopal Iyer 		return (status);
512ae6aa22aSVenugopal Iyer 	}
513da14cebeSEric Cheng 
514da14cebeSEric Cheng 	stime = usage->du_stime;
515da14cebeSEric Cheng 	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
516da14cebeSEric Cheng 	    localtime(&stime));
517da14cebeSEric Cheng 	(void) printf("%s\n", timebuf);
518da14cebeSEric Cheng 
519da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
520da14cebeSEric Cheng }
521da14cebeSEric Cheng 
522da14cebeSEric Cheng static int
523da14cebeSEric Cheng show_usage_time(dladm_usage_t *usage, void *arg)
524da14cebeSEric Cheng {
525da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
526da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
527da14cebeSEric Cheng 	usage_l_fields_buf_t 	ubuf;
528da14cebeSEric Cheng 	time_t			time;
529da14cebeSEric Cheng 	double			bw;
530ae6aa22aSVenugopal Iyer 	dladm_flow_attr_t	attr;
531ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
532ae6aa22aSVenugopal Iyer 
533ae6aa22aSVenugopal Iyer 	/*
534ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing flows unless '-a'
535ae6aa22aSVenugopal Iyer 	 * is specified.
536ae6aa22aSVenugopal Iyer 	 */
537ae6aa22aSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
538ae6aa22aSVenugopal Iyer 	    usage->du_name, &attr)) != DLADM_STATUS_OK)) {
539ae6aa22aSVenugopal Iyer 		return (status);
540ae6aa22aSVenugopal Iyer 	}
541da14cebeSEric Cheng 
542da14cebeSEric Cheng 	if (state->us_plot) {
543da14cebeSEric Cheng 		if (!state->us_printheader) {
544da14cebeSEric Cheng 			if (state->us_first) {
545da14cebeSEric Cheng 				(void) printf("# Time");
546da14cebeSEric Cheng 				state->us_first = B_FALSE;
547da14cebeSEric Cheng 			}
548da14cebeSEric Cheng 			(void) printf(" %s", usage->du_name);
549da14cebeSEric Cheng 			if (usage->du_last) {
550da14cebeSEric Cheng 				(void) printf("\n");
551da14cebeSEric Cheng 				state->us_first = B_TRUE;
552da14cebeSEric Cheng 				state->us_printheader = B_TRUE;
553da14cebeSEric Cheng 			}
554da14cebeSEric Cheng 		} else {
555da14cebeSEric Cheng 			if (state->us_first) {
556da14cebeSEric Cheng 				time = usage->du_etime;
557da14cebeSEric Cheng 				(void) strftime(buf, sizeof (buf), "%T",
558da14cebeSEric Cheng 				    localtime(&time));
559da14cebeSEric Cheng 				state->us_first = B_FALSE;
560da14cebeSEric Cheng 				(void) printf("%s", buf);
561da14cebeSEric Cheng 			}
562da14cebeSEric Cheng 			bw = (double)usage->du_bandwidth/1000;
563da14cebeSEric Cheng 			(void) printf(" %.2f", bw);
564da14cebeSEric Cheng 			if (usage->du_last) {
565da14cebeSEric Cheng 				(void) printf("\n");
566da14cebeSEric Cheng 				state->us_first = B_TRUE;
567da14cebeSEric Cheng 			}
568da14cebeSEric Cheng 		}
569da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
570da14cebeSEric Cheng 	}
571da14cebeSEric Cheng 
572da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
573da14cebeSEric Cheng 
574da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_flow, sizeof (ubuf.usage_l_flow), "%s",
575da14cebeSEric Cheng 	    usage->du_name);
576da14cebeSEric Cheng 	time = usage->du_stime;
577da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
578da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
579da14cebeSEric Cheng 	    buf);
580da14cebeSEric Cheng 	time = usage->du_etime;
581da14cebeSEric Cheng 	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
582da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
583da14cebeSEric Cheng 	    buf);
584da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
585da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
586da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
587da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
588da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
589da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
590da14cebeSEric Cheng 
591da14cebeSEric Cheng 	if (!state->us_parseable && !state->us_printheader) {
592da14cebeSEric Cheng 		print_header(&state->us_print);
593da14cebeSEric Cheng 		state->us_printheader = B_TRUE;
594da14cebeSEric Cheng 	}
595da14cebeSEric Cheng 
596da14cebeSEric Cheng 	flowadm_print_output(&state->us_print, state->us_parseable,
597da14cebeSEric Cheng 	    flowadm_print_field, (void *)&ubuf);
598da14cebeSEric Cheng 
599da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
600da14cebeSEric Cheng }
601da14cebeSEric Cheng 
602da14cebeSEric Cheng static int
603da14cebeSEric Cheng show_usage_res(dladm_usage_t *usage, void *arg)
604da14cebeSEric Cheng {
605da14cebeSEric Cheng 	show_usage_state_t	*state = (show_usage_state_t *)arg;
606da14cebeSEric Cheng 	char			buf[DLADM_STRSIZE];
607da14cebeSEric Cheng 	usage_fields_buf_t	ubuf;
608ae6aa22aSVenugopal Iyer 	dladm_flow_attr_t	attr;
609ae6aa22aSVenugopal Iyer 	dladm_status_t		status;
610ae6aa22aSVenugopal Iyer 
611ae6aa22aSVenugopal Iyer 	/*
612ae6aa22aSVenugopal Iyer 	 * Only show usage information for existing flows unless '-a'
613ae6aa22aSVenugopal Iyer 	 * is specified.
614ae6aa22aSVenugopal Iyer 	 */
615ae6aa22aSVenugopal Iyer 	if (!state->us_showall && ((status = dladm_flow_info(handle,
616ae6aa22aSVenugopal Iyer 	    usage->du_name, &attr)) != DLADM_STATUS_OK)) {
617ae6aa22aSVenugopal Iyer 		return (status);
618ae6aa22aSVenugopal Iyer 	}
619da14cebeSEric Cheng 
620da14cebeSEric Cheng 	bzero(&ubuf, sizeof (ubuf));
621da14cebeSEric Cheng 
622da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_flow, sizeof (ubuf.usage_flow), "%s",
623da14cebeSEric Cheng 	    usage->du_name);
624da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
625da14cebeSEric Cheng 	    "%llu", usage->du_duration);
626da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
627da14cebeSEric Cheng 	    "%llu", usage->du_ipackets);
628da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
629da14cebeSEric Cheng 	    "%llu", usage->du_rbytes);
630da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
631da14cebeSEric Cheng 	    "%llu", usage->du_opackets);
632da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
633da14cebeSEric Cheng 	    "%llu", usage->du_obytes);
634da14cebeSEric Cheng 	(void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
635da14cebeSEric Cheng 	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
636da14cebeSEric Cheng 
637da14cebeSEric Cheng 	if (!state->us_parseable && !state->us_printheader) {
638da14cebeSEric Cheng 		print_header(&state->us_print);
639da14cebeSEric Cheng 		state->us_printheader = B_TRUE;
640da14cebeSEric Cheng 	}
641da14cebeSEric Cheng 
642da14cebeSEric Cheng 	flowadm_print_output(&state->us_print, state->us_parseable,
643da14cebeSEric Cheng 	    flowadm_print_field, (void *)&ubuf);
644da14cebeSEric Cheng 
645da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
646da14cebeSEric Cheng }
647da14cebeSEric Cheng 
648da14cebeSEric Cheng static boolean_t
649da14cebeSEric Cheng valid_formatspec(char *formatspec_str)
650da14cebeSEric Cheng {
651da14cebeSEric Cheng 	if (strcmp(formatspec_str, "gnuplot") == 0)
652da14cebeSEric Cheng 		return (B_TRUE);
653da14cebeSEric Cheng 	return (B_FALSE);
654da14cebeSEric Cheng }
655da14cebeSEric Cheng 
656da14cebeSEric Cheng /* ARGSUSED */
657da14cebeSEric Cheng static void
658da14cebeSEric Cheng do_show_usage(int argc, char *argv[])
659da14cebeSEric Cheng {
660da14cebeSEric Cheng 	char			*file = NULL;
661da14cebeSEric Cheng 	int			opt;
662da14cebeSEric Cheng 	dladm_status_t		status;
663da14cebeSEric Cheng 	boolean_t		d_arg = B_FALSE;
664da14cebeSEric Cheng 	char			*stime = NULL;
665da14cebeSEric Cheng 	char			*etime = NULL;
666da14cebeSEric Cheng 	char			*resource = NULL;
667da14cebeSEric Cheng 	show_usage_state_t	state;
668da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
669da14cebeSEric Cheng 	boolean_t		F_arg = B_FALSE;
670da14cebeSEric Cheng 	char			*fields_str = NULL;
671da14cebeSEric Cheng 	char			*formatspec_str = NULL;
672da14cebeSEric Cheng 	print_field_t		**fields;
673da14cebeSEric Cheng 	uint_t			nfields;
674da14cebeSEric Cheng 	char			*all_fields =
675da14cebeSEric Cheng 	    "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth";
676da14cebeSEric Cheng 	char			*all_l_fields =
677da14cebeSEric Cheng 	    "flow,start,end,rbytes,obytes,bandwidth";
678da14cebeSEric Cheng 
679da14cebeSEric Cheng 	bzero(&state, sizeof (show_usage_state_t));
680da14cebeSEric Cheng 	state.us_parseable = B_FALSE;
681da14cebeSEric Cheng 	state.us_printheader = B_FALSE;
682da14cebeSEric Cheng 	state.us_plot = B_FALSE;
683da14cebeSEric Cheng 	state.us_first = B_TRUE;
684da14cebeSEric Cheng 
685ae6aa22aSVenugopal Iyer 	while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) {
686da14cebeSEric Cheng 		switch (opt) {
687da14cebeSEric Cheng 		case 'd':
688da14cebeSEric Cheng 			d_arg = B_TRUE;
689da14cebeSEric Cheng 			break;
690ae6aa22aSVenugopal Iyer 		case 'a':
691ae6aa22aSVenugopal Iyer 			state.us_showall = B_TRUE;
692da14cebeSEric Cheng 			break;
693da14cebeSEric Cheng 		case 'f':
694da14cebeSEric Cheng 			file = optarg;
695da14cebeSEric Cheng 			break;
696da14cebeSEric Cheng 		case 's':
697da14cebeSEric Cheng 			stime = optarg;
698da14cebeSEric Cheng 			break;
699da14cebeSEric Cheng 		case 'e':
700da14cebeSEric Cheng 			etime = optarg;
701da14cebeSEric Cheng 			break;
702da14cebeSEric Cheng 		case 'o':
703da14cebeSEric Cheng 			o_arg = B_TRUE;
704da14cebeSEric Cheng 			fields_str = optarg;
705da14cebeSEric Cheng 			break;
706da14cebeSEric Cheng 		case 'F':
707ae6aa22aSVenugopal Iyer 			state.us_plot = F_arg = B_TRUE;
708da14cebeSEric Cheng 			formatspec_str = optarg;
709da14cebeSEric Cheng 			break;
710da14cebeSEric Cheng 		default:
711da14cebeSEric Cheng 			die_opterr(optopt, opt);
712da14cebeSEric Cheng 		}
713da14cebeSEric Cheng 	}
714da14cebeSEric Cheng 
715da14cebeSEric Cheng 	if (file == NULL)
716da14cebeSEric Cheng 		die("show-usage requires a file");
717da14cebeSEric Cheng 
718da14cebeSEric Cheng 	if (optind == (argc-1)) {
719ae6aa22aSVenugopal Iyer 		dladm_flow_attr_t	attr;
720ae6aa22aSVenugopal Iyer 
721ae6aa22aSVenugopal Iyer 		if (!state.us_showall &&
722ae6aa22aSVenugopal Iyer 		    dladm_flow_info(handle, resource, &attr) !=
723ae6aa22aSVenugopal Iyer 		    DLADM_STATUS_OK) {
724ae6aa22aSVenugopal Iyer 			die("invalid flow: '%s'", resource);
725ae6aa22aSVenugopal Iyer 		}
726da14cebeSEric Cheng 		resource = argv[optind];
727da14cebeSEric Cheng 	}
728da14cebeSEric Cheng 
729da14cebeSEric Cheng 	if (resource == NULL && stime == NULL && etime == NULL) {
730da14cebeSEric Cheng 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
731da14cebeSEric Cheng 			fields_str = all_fields;
732da14cebeSEric Cheng 		fields = parse_output_fields(fields_str, usage_fields,
733da14cebeSEric Cheng 		    USAGE_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
734da14cebeSEric Cheng 	} else {
735da14cebeSEric Cheng 		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
736da14cebeSEric Cheng 			fields_str = all_l_fields;
737da14cebeSEric Cheng 		fields = parse_output_fields(fields_str, usage_l_fields,
738da14cebeSEric Cheng 		    USAGE_L_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
739da14cebeSEric Cheng 	}
740da14cebeSEric Cheng 
741da14cebeSEric Cheng 	if (fields == NULL) {
742da14cebeSEric Cheng 		die("invalid fields(s) specified");
743da14cebeSEric Cheng 		return;
744da14cebeSEric Cheng 	}
745da14cebeSEric Cheng 	state.us_print.ps_fields = fields;
746da14cebeSEric Cheng 	state.us_print.ps_nfields = nfields;
747da14cebeSEric Cheng 
748ae6aa22aSVenugopal Iyer 	if (F_arg && d_arg)
749ae6aa22aSVenugopal Iyer 		die("incompatible -d and -F options");
750da14cebeSEric Cheng 
751da14cebeSEric Cheng 	if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
752da14cebeSEric Cheng 		die("Format specifier %s not supported", formatspec_str);
753da14cebeSEric Cheng 
754da14cebeSEric Cheng 	if (d_arg) {
755da14cebeSEric Cheng 		/* Print log dates */
756da14cebeSEric Cheng 		status = dladm_usage_dates(show_usage_date,
757da14cebeSEric Cheng 		    DLADM_LOGTYPE_FLOW, file, resource, &state);
758da14cebeSEric Cheng 	} else if (resource == NULL && stime == NULL && etime == NULL &&
759ae6aa22aSVenugopal Iyer 	    !F_arg) {
760da14cebeSEric Cheng 		/* Print summary */
761da14cebeSEric Cheng 		status = dladm_usage_summary(show_usage_res,
762da14cebeSEric Cheng 		    DLADM_LOGTYPE_FLOW, file, &state);
763da14cebeSEric Cheng 	} else if (resource != NULL) {
764da14cebeSEric Cheng 		/* Print log entries for named resource */
765da14cebeSEric Cheng 		status = dladm_walk_usage_res(show_usage_time,
766da14cebeSEric Cheng 		    DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state);
767da14cebeSEric Cheng 	} else {
768da14cebeSEric Cheng 		/* Print time and information for each link */
769da14cebeSEric Cheng 		status = dladm_walk_usage_time(show_usage_time,
770da14cebeSEric Cheng 		    DLADM_LOGTYPE_FLOW, file, stime, etime, &state);
771da14cebeSEric Cheng 	}
772da14cebeSEric Cheng 
773da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
774da14cebeSEric Cheng 		die_dlerr(status, "show-usage");
775da14cebeSEric Cheng }
776da14cebeSEric Cheng 
777da14cebeSEric Cheng static void
778da14cebeSEric Cheng do_add_flow(int argc, char *argv[])
779da14cebeSEric Cheng {
780da000602SGirish Moodalbail 	char			devname[MAXLINKNAMELEN];
781da14cebeSEric Cheng 	char			*name = NULL;
782da14cebeSEric Cheng 	uint_t			index;
783da14cebeSEric Cheng 	datalink_id_t		linkid;
784da14cebeSEric Cheng 
785da14cebeSEric Cheng 	char			option;
786da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
787*63a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
788*63a6526dSMichael Lim 	char			attrstr[DLADM_STRSIZE];
789da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
790da14cebeSEric Cheng 	dladm_arg_list_t	*attrlist = NULL;
791da14cebeSEric Cheng 	dladm_status_t		status;
792da14cebeSEric Cheng 
793*63a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
794*63a6526dSMichael Lim 	bzero(attrstr, DLADM_STRSIZE);
795*63a6526dSMichael Lim 
796da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, "tR:l:a:p:",
797da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
798da14cebeSEric Cheng 		switch (option) {
799da14cebeSEric Cheng 		case 't':
800da14cebeSEric Cheng 			t_arg = B_TRUE;
801da14cebeSEric Cheng 			break;
802da14cebeSEric Cheng 		case 'R':
803da14cebeSEric Cheng 			altroot = optarg;
804da14cebeSEric Cheng 			break;
805da14cebeSEric Cheng 		case 'l':
806da14cebeSEric Cheng 			if (strlcpy(devname, optarg,
807da000602SGirish Moodalbail 			    MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
808da14cebeSEric Cheng 				die("link name too long");
809da14cebeSEric Cheng 			}
8104ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, devname, &linkid, NULL,
811da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK)
812da14cebeSEric Cheng 				die("invalid link '%s'", devname);
813da14cebeSEric Cheng 			l_arg = B_TRUE;
814da14cebeSEric Cheng 			break;
815da14cebeSEric Cheng 		case 'a':
816*63a6526dSMichael Lim 			(void) strlcat(attrstr, optarg, DLADM_STRSIZE);
817*63a6526dSMichael Lim 			if (strlcat(attrstr, ",", DLADM_STRSIZE) >=
818*63a6526dSMichael Lim 			    DLADM_STRSIZE)
819*63a6526dSMichael Lim 				die("attribute list too long '%s'", attrstr);
820da14cebeSEric Cheng 			break;
821da14cebeSEric Cheng 		case 'p':
822*63a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
823*63a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
824*63a6526dSMichael Lim 			    DLADM_STRSIZE)
825*63a6526dSMichael Lim 				die("property list too long '%s'", propstr);
826da14cebeSEric Cheng 			break;
827da14cebeSEric Cheng 		default:
828da14cebeSEric Cheng 			die_opterr(optopt, option);
829da14cebeSEric Cheng 		}
830da14cebeSEric Cheng 	}
831da14cebeSEric Cheng 	if (!l_arg) {
832da14cebeSEric Cheng 		die("link is required");
833da14cebeSEric Cheng 	}
834da14cebeSEric Cheng 
835da14cebeSEric Cheng 	opterr = 0;
836da14cebeSEric Cheng 	index = optind;
837da14cebeSEric Cheng 
838da14cebeSEric Cheng 	if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) {
839da14cebeSEric Cheng 		die("flow name is required");
840da14cebeSEric Cheng 	} else {
841da14cebeSEric Cheng 		/* get flow name; required last argument */
842da000602SGirish Moodalbail 		if (strlen(argv[index]) >= MAXFLOWNAMELEN)
843da14cebeSEric Cheng 			die("flow name too long");
844da14cebeSEric Cheng 		name = argv[index];
845da14cebeSEric Cheng 	}
846da14cebeSEric Cheng 
847*63a6526dSMichael Lim 	if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE)
848*63a6526dSMichael Lim 	    != DLADM_STATUS_OK)
849*63a6526dSMichael Lim 		die("invalid flow attribute specified");
850*63a6526dSMichael Lim 	if (dladm_parse_flow_props(propstr, &proplist, B_FALSE)
851*63a6526dSMichael Lim 	    != DLADM_STATUS_OK)
852*63a6526dSMichael Lim 		die("invalid flow property specified");
853*63a6526dSMichael Lim 
8544ac67f02SAnurag S. Maskey 	status = dladm_flow_add(handle, linkid, attrlist, proplist, name,
855da14cebeSEric Cheng 	    t_arg, altroot);
856da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
857da14cebeSEric Cheng 		die_dlerr(status, "add flow failed");
858da14cebeSEric Cheng 
859da14cebeSEric Cheng 	dladm_free_attrs(attrlist);
860da14cebeSEric Cheng 	dladm_free_props(proplist);
861da14cebeSEric Cheng }
862da14cebeSEric Cheng 
863da14cebeSEric Cheng static void
864da14cebeSEric Cheng do_remove_flow(int argc, char *argv[])
865da14cebeSEric Cheng {
866da14cebeSEric Cheng 	char			option;
867da14cebeSEric Cheng 	char			*flowname = NULL;
868da000602SGirish Moodalbail 	char			linkname[MAXLINKNAMELEN];
869da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
870da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
871da14cebeSEric Cheng 	remove_flow_state_t	state;
872da14cebeSEric Cheng 	dladm_status_t		status;
873da14cebeSEric Cheng 
874da14cebeSEric Cheng 	bzero(&state, sizeof (state));
875da14cebeSEric Cheng 
876da14cebeSEric Cheng 	opterr = 0;
877da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tR:l:",
878da14cebeSEric Cheng 	    longopts, NULL)) != -1) {
879da14cebeSEric Cheng 		switch (option) {
880da14cebeSEric Cheng 		case 't':
881da14cebeSEric Cheng 			t_arg = B_TRUE;
882da14cebeSEric Cheng 			break;
883da14cebeSEric Cheng 		case 'R':
884da14cebeSEric Cheng 			altroot = optarg;
885da14cebeSEric Cheng 			break;
886da14cebeSEric Cheng 		case 'l':
887da14cebeSEric Cheng 			if (strlcpy(linkname, optarg,
888da14cebeSEric Cheng 			    MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
889da14cebeSEric Cheng 				die("link name too long");
890da14cebeSEric Cheng 			}
8914ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, linkname, &linkid, NULL,
892da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK) {
893da14cebeSEric Cheng 				die("invalid link '%s'", linkname);
894da14cebeSEric Cheng 			}
895da14cebeSEric Cheng 			l_arg = B_TRUE;
896da14cebeSEric Cheng 			break;
897da14cebeSEric Cheng 		default:
898da14cebeSEric Cheng 			die_opterr(optopt, option);
899da14cebeSEric Cheng 			break;
900da14cebeSEric Cheng 		}
901da14cebeSEric Cheng 	}
902da14cebeSEric Cheng 
903da14cebeSEric Cheng 	/* when link not specified get flow name */
904da14cebeSEric Cheng 	if (!l_arg) {
905da14cebeSEric Cheng 		if (optind != (argc-1)) {
906da14cebeSEric Cheng 			usage();
907da14cebeSEric Cheng 		} else {
908da000602SGirish Moodalbail 			if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
909da14cebeSEric Cheng 				die("flow name too long");
910da14cebeSEric Cheng 			flowname = argv[optind];
911da14cebeSEric Cheng 		}
9124ac67f02SAnurag S. Maskey 		status = dladm_flow_remove(handle, flowname, t_arg, altroot);
913da14cebeSEric Cheng 	} else {
914da14cebeSEric Cheng 		/* if link is specified then flow name should not be there */
915da14cebeSEric Cheng 		if (optind == argc-1)
916da14cebeSEric Cheng 			usage();
917da14cebeSEric Cheng 		/* walk the link to find flows and remove them */
918da14cebeSEric Cheng 		state.fs_tempop = t_arg;
919da14cebeSEric Cheng 		state.fs_altroot = altroot;
920da14cebeSEric Cheng 		state.fs_status = DLADM_STATUS_OK;
9214ac67f02SAnurag S. Maskey 		status = dladm_walk_flow(remove_flow, handle, linkid, &state,
9224ac67f02SAnurag S. Maskey 		    B_FALSE);
923da14cebeSEric Cheng 		/*
924da14cebeSEric Cheng 		 * check if dladm_walk_flow terminated early and see if the
925da14cebeSEric Cheng 		 * walker function as any status for us
926da14cebeSEric Cheng 		 */
927da14cebeSEric Cheng 		if (status == DLADM_STATUS_OK)
928da14cebeSEric Cheng 			status = state.fs_status;
929da14cebeSEric Cheng 	}
930da14cebeSEric Cheng 
931da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
932da14cebeSEric Cheng 		die_dlerr(status, "remove flow failed");
933da14cebeSEric Cheng }
934da14cebeSEric Cheng 
935da14cebeSEric Cheng /*
936da14cebeSEric Cheng  * Walker function for removing a flow through dladm_walk_flow();
937da14cebeSEric Cheng  */
938da14cebeSEric Cheng static int
939da14cebeSEric Cheng remove_flow(dladm_flow_attr_t *attr, void *arg)
940da14cebeSEric Cheng {
941da14cebeSEric Cheng 	remove_flow_state_t	*state = (remove_flow_state_t *)arg;
942da14cebeSEric Cheng 
9434ac67f02SAnurag S. Maskey 	state->fs_status = dladm_flow_remove(handle, attr->fa_flowname,
944da14cebeSEric Cheng 	    state->fs_tempop, state->fs_altroot);
945da14cebeSEric Cheng 
946da14cebeSEric Cheng 	if (state->fs_status == DLADM_STATUS_OK)
947da14cebeSEric Cheng 		return (DLADM_WALK_CONTINUE);
948da14cebeSEric Cheng 	else
949da14cebeSEric Cheng 		return (DLADM_WALK_TERMINATE);
950da14cebeSEric Cheng }
951da14cebeSEric Cheng 
952da14cebeSEric Cheng static char *
953da14cebeSEric Cheng flowadm_print_field(print_field_t *pf, void *arg)
954da14cebeSEric Cheng {
955da14cebeSEric Cheng 	char *value;
956da14cebeSEric Cheng 
957da14cebeSEric Cheng 	value = (char *)arg + pf->pf_offset;
958da14cebeSEric Cheng 	return (value);
959da14cebeSEric Cheng }
960da14cebeSEric Cheng 
961da14cebeSEric Cheng /*ARGSUSED*/
962da14cebeSEric Cheng static dladm_status_t
963da14cebeSEric Cheng print_flow(show_flow_state_t *state, dladm_flow_attr_t *attr,
964da14cebeSEric Cheng     flow_fields_buf_t *fbuf)
965da14cebeSEric Cheng {
966da14cebeSEric Cheng 	char		link[MAXLINKNAMELEN];
967da14cebeSEric Cheng 	dladm_status_t	status;
968da14cebeSEric Cheng 
9694ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, attr->fa_linkid, NULL,
9704ac67f02SAnurag S. Maskey 	    NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
971da14cebeSEric Cheng 		return (status);
972da14cebeSEric Cheng 	}
973da14cebeSEric Cheng 
974da14cebeSEric Cheng 	(void) snprintf(fbuf->flow_name, sizeof (fbuf->flow_name),
975da14cebeSEric Cheng 	    "%s", attr->fa_flowname);
976da14cebeSEric Cheng 	(void) snprintf(fbuf->flow_link, sizeof (fbuf->flow_link),
977da14cebeSEric Cheng 	    "%s", link);
978da14cebeSEric Cheng 
979da14cebeSEric Cheng 	(void) dladm_flow_attr_ip2str(attr, fbuf->flow_ipaddr,
980da14cebeSEric Cheng 	    sizeof (fbuf->flow_ipaddr));
981da14cebeSEric Cheng 	(void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto,
982da14cebeSEric Cheng 	    sizeof (fbuf->flow_proto));
983da14cebeSEric Cheng 	(void) dladm_flow_attr_port2str(attr, fbuf->flow_port,
984da14cebeSEric Cheng 	    sizeof (fbuf->flow_port));
985da14cebeSEric Cheng 	(void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield,
986da14cebeSEric Cheng 	    sizeof (fbuf->flow_dsfield));
987da14cebeSEric Cheng 
988da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
989da14cebeSEric Cheng }
990da14cebeSEric Cheng 
991da14cebeSEric Cheng /*
992da14cebeSEric Cheng  * Walker function for showing flow attributes through dladm_walk_flow().
993da14cebeSEric Cheng  */
994da14cebeSEric Cheng static int
995da14cebeSEric Cheng show_flow(dladm_flow_attr_t *attr, void *arg)
996da14cebeSEric Cheng {
997da14cebeSEric Cheng 	show_flow_state_t	*statep = arg;
998da14cebeSEric Cheng 	dladm_status_t		status;
999da14cebeSEric Cheng 	flow_fields_buf_t	fbuf;
1000da14cebeSEric Cheng 
1001da14cebeSEric Cheng 	/*
1002da14cebeSEric Cheng 	 * first get all the flow attributes into fbuf;
1003da14cebeSEric Cheng 	 */
1004da14cebeSEric Cheng 	bzero(&fbuf, sizeof (fbuf));
1005da14cebeSEric Cheng 	status = print_flow(statep, attr, &fbuf);
1006da14cebeSEric Cheng 
1007da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1008da14cebeSEric Cheng 		goto done;
1009da14cebeSEric Cheng 
1010da14cebeSEric Cheng 	if (!statep->fs_parseable && !statep->fs_printheader) {
1011da14cebeSEric Cheng 		print_header(&statep->fs_print);
1012da14cebeSEric Cheng 		statep->fs_printheader = B_TRUE;
1013da14cebeSEric Cheng 	}
1014da14cebeSEric Cheng 
1015da14cebeSEric Cheng 	flowadm_print_output(&statep->fs_print, statep->fs_parseable,
1016da14cebeSEric Cheng 	    flowadm_print_field, (void *)&fbuf);
1017da14cebeSEric Cheng 
1018da14cebeSEric Cheng done:
1019da14cebeSEric Cheng 	statep->fs_status = status;
1020da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1021da14cebeSEric Cheng }
1022da14cebeSEric Cheng 
1023da14cebeSEric Cheng static void
1024da14cebeSEric Cheng show_one_flow(void *arg, const char *name)
1025da14cebeSEric Cheng {
1026da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
1027da14cebeSEric Cheng 
10284ac67f02SAnurag S. Maskey 	if (dladm_flow_info(handle, name, &attr) != DLADM_STATUS_OK)
1029da14cebeSEric Cheng 		die("invalid flow: '%s'", name);
1030da14cebeSEric Cheng 	else
10314ac67f02SAnurag S. Maskey 		(void) show_flow(&attr, arg);
1032da14cebeSEric Cheng }
1033da14cebeSEric Cheng 
1034da14cebeSEric Cheng /*
1035da14cebeSEric Cheng  * Wrapper of dladm_walk_flow(show_flow,...) to make it usable to
1036da14cebeSEric Cheng  * dladm_walk_datalink_id(). Used for showing flow attributes for
1037da14cebeSEric Cheng  * all flows on all links.
1038da14cebeSEric Cheng  */
1039da14cebeSEric Cheng static int
10404ac67f02SAnurag S. Maskey show_flows_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1041da14cebeSEric Cheng {
1042da14cebeSEric Cheng 	show_flow_state_t *state = arg;
1043da14cebeSEric Cheng 
10444ac67f02SAnurag S. Maskey 	(void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist);
1045da14cebeSEric Cheng 
1046da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1047da14cebeSEric Cheng }
1048da14cebeSEric Cheng 
1049da14cebeSEric Cheng static void
1050da14cebeSEric Cheng get_flow_stats(const char *flowname, pktsum_t *stats)
1051da14cebeSEric Cheng {
1052da14cebeSEric Cheng 	kstat_ctl_t	*kcp;
1053da14cebeSEric Cheng 	kstat_t		*ksp;
1054da14cebeSEric Cheng 
1055da14cebeSEric Cheng 	bzero(stats, sizeof (*stats));
1056da14cebeSEric Cheng 
1057da14cebeSEric Cheng 	if ((kcp = kstat_open()) == NULL) {
1058da14cebeSEric Cheng 		warn("kstat open operation failed");
1059da14cebeSEric Cheng 		return;
1060da14cebeSEric Cheng 	}
1061da14cebeSEric Cheng 
1062da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow");
1063da14cebeSEric Cheng 
1064da14cebeSEric Cheng 	if (ksp != NULL)
1065da14cebeSEric Cheng 		dladm_get_stats(kcp, ksp, stats);
1066da14cebeSEric Cheng 
1067da14cebeSEric Cheng 	(void) kstat_close(kcp);
1068da14cebeSEric Cheng }
1069da14cebeSEric Cheng 
1070ae6aa22aSVenugopal Iyer 
1071ae6aa22aSVenugopal Iyer static char *
1072ae6aa22aSVenugopal Iyer print_flow_stats(print_field_t *pf, void *arg)
1073ae6aa22aSVenugopal Iyer {
1074ae6aa22aSVenugopal Iyer 	flow_args_t	*fargs = arg;
1075ae6aa22aSVenugopal Iyer 	pktsum_t	*diff_stats = fargs->flow_s_psum;
1076ae6aa22aSVenugopal Iyer 	static char	buf[DLADM_STRSIZE];
1077ae6aa22aSVenugopal Iyer 
1078ae6aa22aSVenugopal Iyer 	switch (pf->pf_index) {
1079ae6aa22aSVenugopal Iyer 	case FLOW_S_FLOW:
1080ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%s", fargs->flow_s_flow);
1081ae6aa22aSVenugopal Iyer 		break;
1082ae6aa22aSVenugopal Iyer 	case FLOW_S_IPKTS:
1083ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%llu",
1084ae6aa22aSVenugopal Iyer 		    diff_stats->ipackets);
1085ae6aa22aSVenugopal Iyer 		break;
1086ae6aa22aSVenugopal Iyer 	case FLOW_S_RBYTES:
1087ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%llu",
1088ae6aa22aSVenugopal Iyer 		    diff_stats->rbytes);
1089ae6aa22aSVenugopal Iyer 		break;
1090ae6aa22aSVenugopal Iyer 	case FLOW_S_IERRORS:
1091ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%u",
1092ae6aa22aSVenugopal Iyer 		    diff_stats->ierrors);
1093ae6aa22aSVenugopal Iyer 		break;
1094ae6aa22aSVenugopal Iyer 	case FLOW_S_OPKTS:
1095ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%llu",
1096ae6aa22aSVenugopal Iyer 		    diff_stats->opackets);
1097ae6aa22aSVenugopal Iyer 		break;
1098ae6aa22aSVenugopal Iyer 	case FLOW_S_OBYTES:
1099ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%llu",
1100ae6aa22aSVenugopal Iyer 		    diff_stats->obytes);
1101ae6aa22aSVenugopal Iyer 		break;
1102ae6aa22aSVenugopal Iyer 	case FLOW_S_OERRORS:
1103ae6aa22aSVenugopal Iyer 		(void) snprintf(buf, sizeof (buf), "%u",
1104ae6aa22aSVenugopal Iyer 		    diff_stats->oerrors);
1105ae6aa22aSVenugopal Iyer 		break;
1106ae6aa22aSVenugopal Iyer 	default:
1107ae6aa22aSVenugopal Iyer 		die("invalid input");
1108ae6aa22aSVenugopal Iyer 		break;
1109ae6aa22aSVenugopal Iyer 	}
1110ae6aa22aSVenugopal Iyer 	return (buf);
1111ae6aa22aSVenugopal Iyer }
1112da14cebeSEric Cheng /* ARGSUSED */
1113da14cebeSEric Cheng static int
1114da14cebeSEric Cheng show_flow_stats(dladm_flow_attr_t *attr, void *arg)
1115da14cebeSEric Cheng {
1116da14cebeSEric Cheng 	show_flow_state_t	*state = (show_flow_state_t *)arg;
1117ae6aa22aSVenugopal Iyer 	char			*name = attr->fa_flowname;
1118da14cebeSEric Cheng 	pktsum_t		stats, diff_stats;
1119ae6aa22aSVenugopal Iyer 	flow_args_t		fargs;
1120da14cebeSEric Cheng 
1121da14cebeSEric Cheng 	if (state->fs_firstonly) {
1122da14cebeSEric Cheng 		if (state->fs_donefirst)
1123da14cebeSEric Cheng 			return (DLADM_WALK_TERMINATE);
1124da14cebeSEric Cheng 		state->fs_donefirst = B_TRUE;
1125da14cebeSEric Cheng 	} else {
1126da14cebeSEric Cheng 		bzero(&state->fs_prevstats, sizeof (state->fs_prevstats));
1127da14cebeSEric Cheng 	}
1128da14cebeSEric Cheng 
1129da14cebeSEric Cheng 	get_flow_stats(name, &stats);
1130da14cebeSEric Cheng 	dladm_stats_diff(&diff_stats, &stats, &state->fs_prevstats);
1131da14cebeSEric Cheng 
1132ae6aa22aSVenugopal Iyer 	fargs.flow_s_flow = name;
1133ae6aa22aSVenugopal Iyer 	fargs.flow_s_psum = &diff_stats;
1134ae6aa22aSVenugopal Iyer 	flowadm_print_output(&state->fs_print, state->fs_parseable,
1135ae6aa22aSVenugopal Iyer 	    print_flow_stats, &fargs);
1136da14cebeSEric Cheng 
1137da14cebeSEric Cheng 	state->fs_prevstats = stats;
1138da14cebeSEric Cheng 
1139da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1140da14cebeSEric Cheng }
1141da14cebeSEric Cheng 
1142da14cebeSEric Cheng /*
1143da14cebeSEric Cheng  * Wrapper of dladm_walk_flow(show_flow,...) to make it usable for
1144da14cebeSEric Cheng  * dladm_walk_datalink_id(). Used for showing flow stats for
1145da14cebeSEric Cheng  * all flows on all links.
1146da14cebeSEric Cheng  */
1147da14cebeSEric Cheng static int
11484ac67f02SAnurag S. Maskey show_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg)
1149da14cebeSEric Cheng {
11504ac67f02SAnurag S. Maskey 	if (dladm_walk_flow(show_flow_stats, dh, linkid, arg, B_FALSE)
1151da14cebeSEric Cheng 	    == DLADM_STATUS_OK)
1152da14cebeSEric Cheng 		return (DLADM_WALK_CONTINUE);
1153da14cebeSEric Cheng 	else
1154da14cebeSEric Cheng 		return (DLADM_WALK_TERMINATE);
1155da14cebeSEric Cheng }
1156da14cebeSEric Cheng 
1157da14cebeSEric Cheng /* ARGSUSED */
1158da14cebeSEric Cheng static void
1159ae6aa22aSVenugopal Iyer flow_stats(const char *flow, datalink_id_t linkid,  uint_t interval,
1160ae6aa22aSVenugopal Iyer     char *fields_str, show_flow_state_t *state)
1161da14cebeSEric Cheng {
1162da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
1163ae6aa22aSVenugopal Iyer 	print_field_t		**fields;
1164ae6aa22aSVenugopal Iyer 	uint_t			nfields;
1165ae6aa22aSVenugopal Iyer 
1166ae6aa22aSVenugopal Iyer 	fields = parse_output_fields(fields_str, flow_s_fields,
1167ae6aa22aSVenugopal Iyer 	    FLOW_S_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
1168ae6aa22aSVenugopal Iyer 	if (fields == NULL) {
1169ae6aa22aSVenugopal Iyer 		die("invalid field(s) specified");
1170ae6aa22aSVenugopal Iyer 		return;
1171ae6aa22aSVenugopal Iyer 	}
1172ae6aa22aSVenugopal Iyer 
1173ae6aa22aSVenugopal Iyer 	state->fs_print.ps_fields = fields;
1174ae6aa22aSVenugopal Iyer 	state->fs_print.ps_nfields = nfields;
1175da14cebeSEric Cheng 
11764ac67f02SAnurag S. Maskey 	if (flow != NULL &&
11774ac67f02SAnurag S. Maskey 	    dladm_flow_info(handle, flow, &attr) != DLADM_STATUS_OK)
1178da14cebeSEric Cheng 		die("invalid flow %s", flow);
1179da14cebeSEric Cheng 
1180da14cebeSEric Cheng 	/*
1181da14cebeSEric Cheng 	 * If an interval is specified, continuously show the stats
1182da14cebeSEric Cheng 	 * for only the first flow.
1183da14cebeSEric Cheng 	 */
1184ae6aa22aSVenugopal Iyer 	state->fs_firstonly = (interval != 0);
1185da14cebeSEric Cheng 
1186ae6aa22aSVenugopal Iyer 	if (!state->fs_parseable)
1187ae6aa22aSVenugopal Iyer 		print_header(&state->fs_print);
1188da14cebeSEric Cheng 	for (;;) {
1189ae6aa22aSVenugopal Iyer 		state->fs_donefirst = B_FALSE;
1190da14cebeSEric Cheng 
1191da14cebeSEric Cheng 		/* Show stats for named flow */
1192da14cebeSEric Cheng 		if (flow != NULL)  {
1193ae6aa22aSVenugopal Iyer 			state->fs_flow = flow;
1194ae6aa22aSVenugopal Iyer 			(void) show_flow_stats(&attr, state);
1195da14cebeSEric Cheng 
1196da14cebeSEric Cheng 		/* Show all stats on a link */
1197da14cebeSEric Cheng 		} else if (linkid != DATALINK_INVALID_LINKID) {
11984ac67f02SAnurag S. Maskey 			(void) dladm_walk_flow(show_flow_stats, handle, linkid,
1199ae6aa22aSVenugopal Iyer 			    state, B_FALSE);
1200da14cebeSEric Cheng 
1201da14cebeSEric Cheng 		/* Show all stats by datalink */
1202da14cebeSEric Cheng 		} else {
1203da14cebeSEric Cheng 			(void) dladm_walk_datalink_id(show_link_flow_stats,
1204ae6aa22aSVenugopal Iyer 			    handle, state, DATALINK_CLASS_ALL,
12054ac67f02SAnurag S. Maskey 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1206da14cebeSEric Cheng 		}
1207da14cebeSEric Cheng 
1208da14cebeSEric Cheng 		if (interval == 0)
1209da14cebeSEric Cheng 			break;
1210da14cebeSEric Cheng 
1211da14cebeSEric Cheng 		(void) sleep(interval);
1212da14cebeSEric Cheng 	}
1213da14cebeSEric Cheng }
1214da14cebeSEric Cheng 
1215da14cebeSEric Cheng static void
1216da14cebeSEric Cheng do_show_flow(int argc, char *argv[])
1217da14cebeSEric Cheng {
1218da000602SGirish Moodalbail 	char			flowname[MAXFLOWNAMELEN];
1219da000602SGirish Moodalbail 	char			linkname[MAXLINKNAMELEN];
1220da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
1221da14cebeSEric Cheng 	int			option;
1222da14cebeSEric Cheng 	boolean_t		s_arg = B_FALSE;
1223da14cebeSEric Cheng 	boolean_t		S_arg = B_FALSE;
1224da14cebeSEric Cheng 	boolean_t		i_arg = B_FALSE;
1225da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
1226da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
1227da14cebeSEric Cheng 	uint32_t		interval = 0;
1228da14cebeSEric Cheng 	show_flow_state_t	state;
1229da14cebeSEric Cheng 	char			*fields_str = NULL;
1230da14cebeSEric Cheng 	print_field_t		**fields;
1231da14cebeSEric Cheng 	uint_t			nfields;
1232da14cebeSEric Cheng 	char			*all_fields =
1233ad091ee1SMichael Lim 	    "flow,link,ipaddr,proto,port,dsfld";
1234ae6aa22aSVenugopal Iyer 	char			*allstat_fields =
1235ae6aa22aSVenugopal Iyer 	    "flow,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
1236da14cebeSEric Cheng 
1237da14cebeSEric Cheng 	bzero(&state, sizeof (state));
1238da14cebeSEric Cheng 
1239da14cebeSEric Cheng 	opterr = 0;
1240da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":pPsSi:l:o:",
1241da14cebeSEric Cheng 	    longopts, NULL)) != -1) {
1242da14cebeSEric Cheng 		switch (option) {
1243da14cebeSEric Cheng 		case 'p':
1244da14cebeSEric Cheng 			state.fs_parseable = B_TRUE;
1245da14cebeSEric Cheng 			break;
1246da14cebeSEric Cheng 		case 'P':
1247da14cebeSEric Cheng 			state.fs_persist = B_TRUE;
1248da14cebeSEric Cheng 			break;
1249da14cebeSEric Cheng 		case 's':
1250da14cebeSEric Cheng 			if (s_arg)
1251da14cebeSEric Cheng 				die_optdup(option);
1252da14cebeSEric Cheng 
1253da14cebeSEric Cheng 			s_arg = B_TRUE;
1254da14cebeSEric Cheng 			break;
1255da14cebeSEric Cheng 		case 'S':
1256da14cebeSEric Cheng 			if (S_arg)
1257da14cebeSEric Cheng 				die_optdup(option);
1258da14cebeSEric Cheng 
1259da14cebeSEric Cheng 			S_arg = B_TRUE;
1260da14cebeSEric Cheng 			break;
1261da14cebeSEric Cheng 		case 'o':
1262da14cebeSEric Cheng 			if (o_arg)
1263da14cebeSEric Cheng 				die_optdup(option);
1264da14cebeSEric Cheng 
1265da14cebeSEric Cheng 			o_arg = B_TRUE;
1266da14cebeSEric Cheng 			fields_str = optarg;
1267da14cebeSEric Cheng 			break;
1268da14cebeSEric Cheng 		case 'i':
1269da14cebeSEric Cheng 			if (i_arg)
1270da14cebeSEric Cheng 				die_optdup(option);
1271da14cebeSEric Cheng 
1272da14cebeSEric Cheng 			i_arg = B_TRUE;
1273da14cebeSEric Cheng 
1274*63a6526dSMichael Lim 			if (!dladm_str2interval(optarg, &interval))
1275*63a6526dSMichael Lim 				die("invalid interval value '%s'", optarg);
1276da14cebeSEric Cheng 			break;
1277da14cebeSEric Cheng 		case 'l':
1278da14cebeSEric Cheng 			if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
1279da14cebeSEric Cheng 			    >= MAXLINKNAMELEN)
1280da14cebeSEric Cheng 				die("link name too long\n");
12814ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, linkname, &linkid, NULL,
1282da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK)
1283da14cebeSEric Cheng 				die("invalid link '%s'", linkname);
1284da14cebeSEric Cheng 			l_arg = B_TRUE;
1285da14cebeSEric Cheng 			break;
1286da14cebeSEric Cheng 		default:
1287da14cebeSEric Cheng 			die_opterr(optopt, option);
1288da14cebeSEric Cheng 			break;
1289da14cebeSEric Cheng 		}
1290da14cebeSEric Cheng 	}
1291ad091ee1SMichael Lim 
1292da14cebeSEric Cheng 	if (i_arg && !(s_arg || S_arg))
1293da14cebeSEric Cheng 		die("the -i option can be used only with -s or -S");
1294da14cebeSEric Cheng 
1295da14cebeSEric Cheng 	if (s_arg && S_arg)
1296da14cebeSEric Cheng 		die("the -s option cannot be used with -S");
1297da14cebeSEric Cheng 
1298da14cebeSEric Cheng 	/* get flow name (optional last argument */
1299da14cebeSEric Cheng 	if (optind == (argc-1)) {
1300da000602SGirish Moodalbail 		if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
1301da000602SGirish Moodalbail 		    >= MAXFLOWNAMELEN)
1302da14cebeSEric Cheng 			die("flow name too long");
1303da14cebeSEric Cheng 		state.fs_flow = flowname;
1304da14cebeSEric Cheng 	}
1305da14cebeSEric Cheng 
1306da14cebeSEric Cheng 	if (S_arg) {
13074ac67f02SAnurag S. Maskey 		dladm_continuous(handle, linkid, state.fs_flow, interval,
13084ac67f02SAnurag S. Maskey 		    FLOW_REPORT);
1309da14cebeSEric Cheng 		return;
1310da14cebeSEric Cheng 	}
1311da14cebeSEric Cheng 
1312ae6aa22aSVenugopal Iyer 	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
1313ae6aa22aSVenugopal Iyer 		if (s_arg)
1314ae6aa22aSVenugopal Iyer 			fields_str = allstat_fields;
1315ae6aa22aSVenugopal Iyer 		else
1316da14cebeSEric Cheng 			fields_str = all_fields;
1317ae6aa22aSVenugopal Iyer 	}
1318ae6aa22aSVenugopal Iyer 
1319ae6aa22aSVenugopal Iyer 	if (s_arg) {
1320ae6aa22aSVenugopal Iyer 		flow_stats(state.fs_flow, linkid, interval, fields_str, &state);
1321ae6aa22aSVenugopal Iyer 		return;
1322ae6aa22aSVenugopal Iyer 	}
1323da14cebeSEric Cheng 
1324da14cebeSEric Cheng 	fields = parse_output_fields(fields_str, flow_fields, FLOW_MAX_FIELDS,
1325da14cebeSEric Cheng 	    CMD_TYPE_ANY, &nfields);
1326da14cebeSEric Cheng 
1327da14cebeSEric Cheng 	if (fields == NULL) {
1328da14cebeSEric Cheng 		die("invalid fields(s) specified");
1329da14cebeSEric Cheng 		return;
1330da14cebeSEric Cheng 	}
1331da14cebeSEric Cheng 
1332da14cebeSEric Cheng 	state.fs_print.ps_fields = fields;
1333da14cebeSEric Cheng 	state.fs_print.ps_nfields = nfields;
1334da14cebeSEric Cheng 
1335da14cebeSEric Cheng 	/* Show attributes of one flow */
1336da14cebeSEric Cheng 	if (state.fs_flow != NULL) {
1337da14cebeSEric Cheng 		show_one_flow(&state, state.fs_flow);
1338da14cebeSEric Cheng 
1339da14cebeSEric Cheng 	/* Show attributes of flows on one link */
1340da14cebeSEric Cheng 	} else if (l_arg) {
13414ac67f02SAnurag S. Maskey 		(void) show_flows_onelink(handle, linkid, &state);
1342da14cebeSEric Cheng 
1343da14cebeSEric Cheng 	/* Show attributes of all flows on all links */
1344da14cebeSEric Cheng 	} else {
13454ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_flows_onelink, handle,
13464ac67f02SAnurag S. Maskey 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1347da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
1348da14cebeSEric Cheng 	}
1349da14cebeSEric Cheng }
1350da14cebeSEric Cheng 
1351da14cebeSEric Cheng static dladm_status_t
1352da14cebeSEric Cheng set_flowprop_persist(const char *flow, const char *prop_name, char **prop_val,
1353da14cebeSEric Cheng     uint_t val_cnt, boolean_t reset)
1354da14cebeSEric Cheng {
1355da14cebeSEric Cheng 	dladm_status_t	status;
1356da14cebeSEric Cheng 	char		*errprop;
1357da14cebeSEric Cheng 
13584ac67f02SAnurag S. Maskey 	status = dladm_set_flowprop(handle, flow, prop_name, prop_val, val_cnt,
1359da14cebeSEric Cheng 	    DLADM_OPT_PERSIST, &errprop);
1360da14cebeSEric Cheng 
1361da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
1362da14cebeSEric Cheng 		warn_dlerr(status, "cannot persistently %s flow "
1363da14cebeSEric Cheng 		    "property '%s' on '%s'", reset? "reset": "set",
1364da14cebeSEric Cheng 		    errprop, flow);
1365da14cebeSEric Cheng 	}
1366da14cebeSEric Cheng 	return (status);
1367da14cebeSEric Cheng }
1368da14cebeSEric Cheng 
1369da14cebeSEric Cheng static void
1370da14cebeSEric Cheng set_flowprop(int argc, char **argv, boolean_t reset)
1371da14cebeSEric Cheng {
1372da14cebeSEric Cheng 	int			i, option;
1373da14cebeSEric Cheng 	char			errmsg[DLADM_STRSIZE];
1374da14cebeSEric Cheng 	const char		*flow = NULL;
1375*63a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
1376da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1377da14cebeSEric Cheng 	boolean_t		temp = B_FALSE;
1378da14cebeSEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
1379da14cebeSEric Cheng 
1380da14cebeSEric Cheng 	opterr = 0;
1381*63a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
1382*63a6526dSMichael Lim 
1383da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":p:R:t",
1384da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
1385da14cebeSEric Cheng 		switch (option) {
1386da14cebeSEric Cheng 		case 'p':
1387*63a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
1388*63a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
1389*63a6526dSMichael Lim 			    DLADM_STRSIZE)
1390*63a6526dSMichael Lim 				die("property list too long '%s'", propstr);
1391da14cebeSEric Cheng 			break;
1392da14cebeSEric Cheng 		case 't':
1393da14cebeSEric Cheng 			temp = B_TRUE;
1394da14cebeSEric Cheng 			break;
1395da14cebeSEric Cheng 		case 'R':
1396da14cebeSEric Cheng 			status = dladm_set_rootdir(optarg);
1397da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK) {
1398da14cebeSEric Cheng 				die_dlerr(status, "invalid directory "
1399da14cebeSEric Cheng 				    "specified");
1400da14cebeSEric Cheng 			}
1401da14cebeSEric Cheng 			break;
1402da14cebeSEric Cheng 		default:
1403da14cebeSEric Cheng 			die_opterr(optopt, option);
1404da14cebeSEric Cheng 			break;
1405da14cebeSEric Cheng 		}
1406da14cebeSEric Cheng 	}
1407da14cebeSEric Cheng 
1408da14cebeSEric Cheng 	if (optind == (argc - 1)) {
1409da000602SGirish Moodalbail 		if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
1410da14cebeSEric Cheng 			die("flow name too long");
1411da14cebeSEric Cheng 		flow = argv[optind];
1412da14cebeSEric Cheng 	} else if (optind != argc) {
1413da14cebeSEric Cheng 		usage();
1414da14cebeSEric Cheng 	}
1415da14cebeSEric Cheng 	if (flow == NULL)
1416da14cebeSEric Cheng 		die("flow name must be specified");
1417da14cebeSEric Cheng 
1418*63a6526dSMichael Lim 	if (dladm_parse_flow_props(propstr, &proplist, reset)
1419*63a6526dSMichael Lim 	    != DLADM_STATUS_OK)
1420*63a6526dSMichael Lim 		die("invalid flow property specified");
1421*63a6526dSMichael Lim 
1422da14cebeSEric Cheng 	if (proplist == NULL) {
1423da14cebeSEric Cheng 		char *errprop;
1424da14cebeSEric Cheng 
1425da14cebeSEric Cheng 		if (!reset)
1426da14cebeSEric Cheng 			die("flow property must be specified");
1427da14cebeSEric Cheng 
14284ac67f02SAnurag S. Maskey 		status = dladm_set_flowprop(handle, flow, NULL, NULL, 0,
1429da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE, &errprop);
1430da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
1431da14cebeSEric Cheng 			warn_dlerr(status, "cannot reset flow property '%s' "
1432da14cebeSEric Cheng 			    "on '%s'", errprop, flow);
1433da14cebeSEric Cheng 		}
1434da14cebeSEric Cheng 		if (!temp) {
1435da14cebeSEric Cheng 			dladm_status_t	s;
1436da14cebeSEric Cheng 
1437da14cebeSEric Cheng 			s = set_flowprop_persist(flow, NULL, NULL, 0, reset);
1438da14cebeSEric Cheng 			if (s != DLADM_STATUS_OK)
1439da14cebeSEric Cheng 				status = s;
1440da14cebeSEric Cheng 		}
1441da14cebeSEric Cheng 		goto done;
1442da14cebeSEric Cheng 	}
1443da14cebeSEric Cheng 
1444da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
1445da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
1446da14cebeSEric Cheng 		char		**val;
1447da14cebeSEric Cheng 		uint_t		count;
1448da14cebeSEric Cheng 		dladm_status_t	s;
1449da14cebeSEric Cheng 
1450da14cebeSEric Cheng 		if (reset) {
1451da14cebeSEric Cheng 			val = NULL;
1452da14cebeSEric Cheng 			count = 0;
1453da14cebeSEric Cheng 		} else {
1454da14cebeSEric Cheng 			val = aip->ai_val;
1455da14cebeSEric Cheng 			count = aip->ai_count;
1456da14cebeSEric Cheng 			if (count == 0) {
1457da14cebeSEric Cheng 				warn("no value specified for '%s'",
1458da14cebeSEric Cheng 				    aip->ai_name);
1459da14cebeSEric Cheng 				status = DLADM_STATUS_BADARG;
1460da14cebeSEric Cheng 				continue;
1461da14cebeSEric Cheng 			}
1462da14cebeSEric Cheng 		}
14634ac67f02SAnurag S. Maskey 		s = dladm_set_flowprop(handle, flow, aip->ai_name, val, count,
1464da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE, NULL);
1465da14cebeSEric Cheng 		if (s == DLADM_STATUS_OK) {
1466da14cebeSEric Cheng 			if (!temp) {
1467da14cebeSEric Cheng 				s = set_flowprop_persist(flow,
1468da14cebeSEric Cheng 				    aip->ai_name, val, count, reset);
1469da14cebeSEric Cheng 				if (s != DLADM_STATUS_OK)
1470da14cebeSEric Cheng 					status = s;
1471da14cebeSEric Cheng 			}
1472da14cebeSEric Cheng 			continue;
1473da14cebeSEric Cheng 		}
1474da14cebeSEric Cheng 		status = s;
1475da14cebeSEric Cheng 		switch (s) {
1476da14cebeSEric Cheng 		case DLADM_STATUS_NOTFOUND:
1477da14cebeSEric Cheng 			warn("invalid flow property '%s'", aip->ai_name);
1478da14cebeSEric Cheng 			break;
1479da14cebeSEric Cheng 		case DLADM_STATUS_BADVAL: {
1480da14cebeSEric Cheng 			int		j;
1481da14cebeSEric Cheng 			char		*ptr, *lim;
1482da14cebeSEric Cheng 			char		**propvals = NULL;
1483da14cebeSEric Cheng 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
1484da14cebeSEric Cheng 
1485da14cebeSEric Cheng 			ptr = malloc((sizeof (char *) +
1486da14cebeSEric Cheng 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
1487da14cebeSEric Cheng 			    MAX_PROP_LINE);
1488da14cebeSEric Cheng 
1489da14cebeSEric Cheng 			if (ptr == NULL)
1490da14cebeSEric Cheng 				die("insufficient memory");
1491da14cebeSEric Cheng 			propvals = (char **)(void *)ptr;
1492da14cebeSEric Cheng 
1493da14cebeSEric Cheng 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
1494da14cebeSEric Cheng 				propvals[j] = ptr + sizeof (char *) *
1495da14cebeSEric Cheng 				    DLADM_MAX_PROP_VALCNT +
1496da14cebeSEric Cheng 				    j * DLADM_PROP_VAL_MAX;
1497da14cebeSEric Cheng 			}
14984ac67f02SAnurag S. Maskey 			s = dladm_get_flowprop(handle, flow,
14994ac67f02SAnurag S. Maskey 			    DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
15004ac67f02SAnurag S. Maskey 			    &valcnt);
1501da14cebeSEric Cheng 
1502da14cebeSEric Cheng 			ptr = errmsg;
1503da14cebeSEric Cheng 			lim = ptr + DLADM_STRSIZE;
1504da14cebeSEric Cheng 			*ptr = '\0';
1505da14cebeSEric Cheng 			for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
1506da14cebeSEric Cheng 				ptr += snprintf(ptr, lim - ptr, "%s,",
1507da14cebeSEric Cheng 				    propvals[j]);
1508da14cebeSEric Cheng 				if (ptr >= lim)
1509da14cebeSEric Cheng 					break;
1510da14cebeSEric Cheng 			}
1511da14cebeSEric Cheng 			if (ptr > errmsg) {
1512da14cebeSEric Cheng 				*(ptr - 1) = '\0';
1513da14cebeSEric Cheng 				warn("flow property '%s' must be one of: %s",
1514da14cebeSEric Cheng 				    aip->ai_name, errmsg);
1515da14cebeSEric Cheng 			} else
1516da14cebeSEric Cheng 				warn("%s is an invalid value for "
1517da14cebeSEric Cheng 				    "flow property %s", *val, aip->ai_name);
1518da14cebeSEric Cheng 			free(propvals);
1519da14cebeSEric Cheng 			break;
1520da14cebeSEric Cheng 		}
1521da14cebeSEric Cheng 		default:
1522da14cebeSEric Cheng 			if (reset) {
1523da14cebeSEric Cheng 				warn_dlerr(status, "cannot reset flow property "
1524da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, flow);
1525da14cebeSEric Cheng 			} else {
1526da14cebeSEric Cheng 				warn_dlerr(status, "cannot set flow property "
1527da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, flow);
1528da14cebeSEric Cheng 			}
1529da14cebeSEric Cheng 			break;
1530da14cebeSEric Cheng 		}
1531da14cebeSEric Cheng 	}
1532da14cebeSEric Cheng done:
1533da14cebeSEric Cheng 	dladm_free_props(proplist);
15344ac67f02SAnurag S. Maskey 	if (status != DLADM_STATUS_OK) {
15354ac67f02SAnurag S. Maskey 		dladm_close(handle);
1536ad091ee1SMichael Lim 		exit(EXIT_FAILURE);
1537da14cebeSEric Cheng 	}
15384ac67f02SAnurag S. Maskey }
1539da14cebeSEric Cheng 
1540da14cebeSEric Cheng static void
1541da14cebeSEric Cheng do_set_flowprop(int argc, char **argv)
1542da14cebeSEric Cheng {
1543da14cebeSEric Cheng 	set_flowprop(argc, argv, B_FALSE);
1544da14cebeSEric Cheng }
1545da14cebeSEric Cheng 
1546da14cebeSEric Cheng static void
1547da14cebeSEric Cheng do_reset_flowprop(int argc, char **argv)
1548da14cebeSEric Cheng {
1549da14cebeSEric Cheng 	set_flowprop(argc, argv, B_TRUE);
1550da14cebeSEric Cheng }
1551da14cebeSEric Cheng 
1552da14cebeSEric Cheng static void
1553da14cebeSEric Cheng warn(const char *format, ...)
1554da14cebeSEric Cheng {
1555da14cebeSEric Cheng 	va_list alist;
1556da14cebeSEric Cheng 
1557da14cebeSEric Cheng 	format = gettext(format);
1558da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: warning: ", progname);
1559da14cebeSEric Cheng 
1560da14cebeSEric Cheng 	va_start(alist, format);
1561da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
1562da14cebeSEric Cheng 	va_end(alist);
1563da14cebeSEric Cheng 
1564da14cebeSEric Cheng 	(void) putchar('\n');
1565da14cebeSEric Cheng }
1566da14cebeSEric Cheng 
1567da14cebeSEric Cheng /* PRINTFLIKE2 */
1568da14cebeSEric Cheng static void
1569da14cebeSEric Cheng warn_dlerr(dladm_status_t err, const char *format, ...)
1570da14cebeSEric Cheng {
1571da14cebeSEric Cheng 	va_list alist;
1572da14cebeSEric Cheng 	char    errmsg[DLADM_STRSIZE];
1573da14cebeSEric Cheng 
1574da14cebeSEric Cheng 	format = gettext(format);
1575da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
1576da14cebeSEric Cheng 
1577da14cebeSEric Cheng 	va_start(alist, format);
1578da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
1579da14cebeSEric Cheng 	va_end(alist);
1580da14cebeSEric Cheng 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
1581da14cebeSEric Cheng }
1582da14cebeSEric Cheng 
1583da14cebeSEric Cheng /* PRINTFLIKE1 */
1584da14cebeSEric Cheng static void
1585da14cebeSEric Cheng die(const char *format, ...)
1586da14cebeSEric Cheng {
1587da14cebeSEric Cheng 	va_list alist;
1588da14cebeSEric Cheng 
1589da14cebeSEric Cheng 	format = gettext(format);
1590da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: ", progname);
1591da14cebeSEric Cheng 
1592da14cebeSEric Cheng 	va_start(alist, format);
1593da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
1594da14cebeSEric Cheng 	va_end(alist);
1595da14cebeSEric Cheng 
1596da14cebeSEric Cheng 	(void) putchar('\n');
15974ac67f02SAnurag S. Maskey 
15984ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
15994ac67f02SAnurag S. Maskey 	if (handle != NULL)
16004ac67f02SAnurag S. Maskey 		dladm_close(handle);
16014ac67f02SAnurag S. Maskey 
1602da14cebeSEric Cheng 	exit(EXIT_FAILURE);
1603da14cebeSEric Cheng }
1604da14cebeSEric Cheng 
1605da14cebeSEric Cheng static void
1606da14cebeSEric Cheng die_optdup(int opt)
1607da14cebeSEric Cheng {
1608da14cebeSEric Cheng 	die("the option -%c cannot be specified more than once", opt);
1609da14cebeSEric Cheng }
1610da14cebeSEric Cheng 
1611da14cebeSEric Cheng static void
1612da14cebeSEric Cheng die_opterr(int opt, int opterr)
1613da14cebeSEric Cheng {
1614da14cebeSEric Cheng 	switch (opterr) {
1615da14cebeSEric Cheng 	case ':':
1616da14cebeSEric Cheng 		die("option '-%c' requires a value", opt);
1617da14cebeSEric Cheng 		break;
1618da14cebeSEric Cheng 	case '?':
1619da14cebeSEric Cheng 	default:
1620da14cebeSEric Cheng 		die("unrecognized option '-%c'", opt);
1621da14cebeSEric Cheng 		break;
1622da14cebeSEric Cheng 	}
1623da14cebeSEric Cheng }
1624da14cebeSEric Cheng 
1625da14cebeSEric Cheng /* PRINTFLIKE2 */
1626da14cebeSEric Cheng static void
1627da14cebeSEric Cheng die_dlerr(dladm_status_t err, const char *format, ...)
1628da14cebeSEric Cheng {
1629da14cebeSEric Cheng 	va_list alist;
1630da14cebeSEric Cheng 	char	errmsg[DLADM_STRSIZE];
1631da14cebeSEric Cheng 
1632da14cebeSEric Cheng 	format = gettext(format);
1633da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: ", progname);
1634da14cebeSEric Cheng 
1635da14cebeSEric Cheng 	va_start(alist, format);
1636da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
1637da14cebeSEric Cheng 	va_end(alist);
1638da14cebeSEric Cheng 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
1639da14cebeSEric Cheng 
16404ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
16414ac67f02SAnurag S. Maskey 	if (handle != NULL)
16424ac67f02SAnurag S. Maskey 		dladm_close(handle);
16434ac67f02SAnurag S. Maskey 
1644da14cebeSEric Cheng 	exit(EXIT_FAILURE);
1645da14cebeSEric Cheng }
1646da14cebeSEric Cheng 
1647da14cebeSEric Cheng static void
1648da14cebeSEric Cheng print_flowprop(const char *flowname, show_flowprop_state_t *statep,
1649da14cebeSEric Cheng     const char *propname, dladm_prop_type_t type,
1650da14cebeSEric Cheng     const char *format, char **pptr)
1651da14cebeSEric Cheng {
1652da14cebeSEric Cheng 	int		i;
1653da14cebeSEric Cheng 	char		*ptr, *lim;
1654da14cebeSEric Cheng 	char		buf[DLADM_STRSIZE];
1655da14cebeSEric Cheng 	char		*unknown = "--", *notsup = "";
1656da14cebeSEric Cheng 	char		**propvals = statep->fs_propvals;
1657da14cebeSEric Cheng 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
1658da14cebeSEric Cheng 	dladm_status_t	status;
1659da14cebeSEric Cheng 
16604ac67f02SAnurag S. Maskey 	status = dladm_get_flowprop(handle, flowname, type, propname, propvals,
1661da14cebeSEric Cheng 	    &valcnt);
1662da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
1663da14cebeSEric Cheng 		if (status == DLADM_STATUS_TEMPONLY) {
1664da14cebeSEric Cheng 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
1665da14cebeSEric Cheng 			    statep->fs_persist) {
1666da14cebeSEric Cheng 				valcnt = 1;
1667da14cebeSEric Cheng 				propvals = &unknown;
1668da14cebeSEric Cheng 			} else {
1669da14cebeSEric Cheng 				statep->fs_status = status;
1670da14cebeSEric Cheng 				statep->fs_retstatus = status;
1671da14cebeSEric Cheng 				return;
1672da14cebeSEric Cheng 			}
1673da14cebeSEric Cheng 		} else if (status == DLADM_STATUS_NOTSUP ||
1674da14cebeSEric Cheng 		    statep->fs_persist) {
1675da14cebeSEric Cheng 			valcnt = 1;
1676da14cebeSEric Cheng 			if (type == DLADM_PROP_VAL_CURRENT)
1677da14cebeSEric Cheng 				propvals = &unknown;
1678da14cebeSEric Cheng 			else
1679da14cebeSEric Cheng 				propvals = &notsup;
1680da14cebeSEric Cheng 		} else {
1681da14cebeSEric Cheng 			if ((statep->fs_proplist != NULL) &&
1682da14cebeSEric Cheng 			    statep->fs_status == DLADM_STATUS_OK) {
1683da14cebeSEric Cheng 				warn("invalid flow property '%s'", propname);
1684da14cebeSEric Cheng 			}
1685da14cebeSEric Cheng 			statep->fs_status = status;
1686da14cebeSEric Cheng 			statep->fs_retstatus = status;
1687da14cebeSEric Cheng 			return;
1688da14cebeSEric Cheng 		}
1689da14cebeSEric Cheng 	}
1690da14cebeSEric Cheng 
1691da14cebeSEric Cheng 	statep->fs_status = DLADM_STATUS_OK;
1692da14cebeSEric Cheng 
1693da14cebeSEric Cheng 	ptr = buf;
1694da14cebeSEric Cheng 	lim = buf + DLADM_STRSIZE;
1695da14cebeSEric Cheng 	for (i = 0; i < valcnt; i++) {
1696da14cebeSEric Cheng 		if (propvals[i][0] == '\0' && !statep->fs_parseable)
1697da14cebeSEric Cheng 			ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL",");
1698da14cebeSEric Cheng 		else
1699da14cebeSEric Cheng 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
1700da14cebeSEric Cheng 		if (ptr >= lim)
1701da14cebeSEric Cheng 			break;
1702da14cebeSEric Cheng 	}
1703da14cebeSEric Cheng 	if (valcnt > 0)
1704da14cebeSEric Cheng 		buf[strlen(buf) - 1] = '\0';
1705da14cebeSEric Cheng 
1706da14cebeSEric Cheng 	lim = statep->fs_line + MAX_PROP_LINE;
1707da14cebeSEric Cheng 	if (statep->fs_parseable) {
1708da14cebeSEric Cheng 		*pptr += snprintf(*pptr, lim - *pptr,
1709da14cebeSEric Cheng 		    "%s", buf);
1710da14cebeSEric Cheng 	} else {
1711da14cebeSEric Cheng 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
1712da14cebeSEric Cheng 	}
1713da14cebeSEric Cheng }
1714da14cebeSEric Cheng 
1715da14cebeSEric Cheng static char *
1716da14cebeSEric Cheng flowprop_callback(print_field_t *pf, void *fs_arg)
1717da14cebeSEric Cheng {
1718da14cebeSEric Cheng 	flowprop_args_t		*arg = fs_arg;
1719da14cebeSEric Cheng 	char 			*propname = arg->fs_propname;
1720da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg->fs_state;
1721da14cebeSEric Cheng 	char			*ptr = statep->fs_line;
1722da14cebeSEric Cheng 	char			*lim = ptr + MAX_PROP_LINE;
1723da14cebeSEric Cheng 	char			*flowname = arg->fs_flowname;
1724da14cebeSEric Cheng 
1725da14cebeSEric Cheng 	switch (pf->pf_index) {
1726da14cebeSEric Cheng 	case FLOWPROP_FLOW:
1727da14cebeSEric Cheng 		(void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow);
1728da14cebeSEric Cheng 		break;
1729da14cebeSEric Cheng 	case FLOWPROP_PROPERTY:
1730da14cebeSEric Cheng 		(void) snprintf(ptr, lim - ptr, "%s", propname);
1731da14cebeSEric Cheng 		break;
1732da14cebeSEric Cheng 	case FLOWPROP_VALUE:
1733da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1734da14cebeSEric Cheng 		    statep->fs_persist ? DLADM_PROP_VAL_PERSISTENT :
1735da14cebeSEric Cheng 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
1736da14cebeSEric Cheng 		/*
1737da14cebeSEric Cheng 		 * If we failed to query the flow property, for example, query
1738da14cebeSEric Cheng 		 * the persistent value of a non-persistable flow property,
1739da14cebeSEric Cheng 		 * simply skip the output.
1740da14cebeSEric Cheng 		 */
1741da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1742da14cebeSEric Cheng 			goto skip;
1743da14cebeSEric Cheng 		ptr = statep->fs_line;
1744da14cebeSEric Cheng 		break;
1745da14cebeSEric Cheng 	case FLOWPROP_DEFAULT:
1746da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1747da14cebeSEric Cheng 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
1748da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1749da14cebeSEric Cheng 			goto skip;
1750da14cebeSEric Cheng 		ptr = statep->fs_line;
1751da14cebeSEric Cheng 		break;
1752da14cebeSEric Cheng 	case FLOWPROP_POSSIBLE:
1753da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1754da14cebeSEric Cheng 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
1755da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1756da14cebeSEric Cheng 			goto skip;
1757da14cebeSEric Cheng 		ptr = statep->fs_line;
1758da14cebeSEric Cheng 		break;
1759da14cebeSEric Cheng 	default:
1760da14cebeSEric Cheng 		die("invalid input");
1761da14cebeSEric Cheng 		break;
1762da14cebeSEric Cheng 	}
1763da14cebeSEric Cheng 	return (ptr);
1764da14cebeSEric Cheng skip:
1765da14cebeSEric Cheng 	if (statep->fs_status != DLADM_STATUS_OK)
1766da14cebeSEric Cheng 		return (NULL);
1767da14cebeSEric Cheng 	else
1768da14cebeSEric Cheng 		return ("");
1769da14cebeSEric Cheng }
1770da14cebeSEric Cheng 
1771da14cebeSEric Cheng static int
1772da14cebeSEric Cheng show_one_flowprop(void *arg, const char *propname)
1773da14cebeSEric Cheng {
1774da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg;
1775da14cebeSEric Cheng 	flowprop_args_t		fs_arg;
1776da14cebeSEric Cheng 
1777da14cebeSEric Cheng 	bzero(&fs_arg, sizeof (fs_arg));
1778da14cebeSEric Cheng 	fs_arg.fs_state = statep;
1779da14cebeSEric Cheng 	fs_arg.fs_propname = (char *)propname;
1780da14cebeSEric Cheng 	fs_arg.fs_flowname = (char *)statep->fs_flow;
1781da14cebeSEric Cheng 
1782da14cebeSEric Cheng 	if (statep->fs_header) {
1783da14cebeSEric Cheng 		statep->fs_header = B_FALSE;
1784da14cebeSEric Cheng 		if (!statep ->fs_parseable)
1785da14cebeSEric Cheng 			print_header(&statep->fs_print);
1786da14cebeSEric Cheng 	}
1787da14cebeSEric Cheng 	flowadm_print_output(&statep->fs_print, statep->fs_parseable,
1788da14cebeSEric Cheng 	    flowprop_callback, (void *)&fs_arg);
1789da14cebeSEric Cheng 
1790da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1791da14cebeSEric Cheng }
1792da14cebeSEric Cheng 
1793da14cebeSEric Cheng /* Walker function called by dladm_walk_flow to display flow properties */
1794da14cebeSEric Cheng static int
1795da14cebeSEric Cheng show_flowprop(dladm_flow_attr_t *attr, void *arg)
1796da14cebeSEric Cheng {
1797da14cebeSEric Cheng 	show_flowprop_one_flow(arg, attr->fa_flowname);
1798da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1799da14cebeSEric Cheng }
1800da14cebeSEric Cheng 
1801da14cebeSEric Cheng /*
1802da14cebeSEric Cheng  * Wrapper of dladm_walk_flow(show_walk_fn,...) to make it
1803da14cebeSEric Cheng  * usable to dladm_walk_datalink_id()
1804da14cebeSEric Cheng  */
1805da14cebeSEric Cheng static int
18064ac67f02SAnurag S. Maskey show_flowprop_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1807da14cebeSEric Cheng {
1808da14cebeSEric Cheng 	char	name[MAXLINKNAMELEN];
1809da14cebeSEric Cheng 
18104ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, name,
18114ac67f02SAnurag S. Maskey 	    sizeof (name)) != DLADM_STATUS_OK)
1812da14cebeSEric Cheng 		return (DLADM_WALK_TERMINATE);
1813da14cebeSEric Cheng 
18144ac67f02SAnurag S. Maskey 	(void) dladm_walk_flow(show_flowprop, dh, linkid, arg, B_FALSE);
1815da14cebeSEric Cheng 
1816da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1817da14cebeSEric Cheng }
1818da14cebeSEric Cheng 
1819da14cebeSEric Cheng static void
1820da14cebeSEric Cheng do_show_flowprop(int argc, char **argv)
1821da14cebeSEric Cheng {
1822da14cebeSEric Cheng 	int			option;
1823ad091ee1SMichael Lim 	boolean_t		o_arg = B_FALSE;
1824da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1825da14cebeSEric Cheng 	show_flowprop_state_t	state;
1826da14cebeSEric Cheng 	char			*fields_str = NULL;
1827da14cebeSEric Cheng 	print_field_t		**fields;
1828da14cebeSEric Cheng 	uint_t			nfields;
1829da14cebeSEric Cheng 	char			*all_fields =
1830da14cebeSEric Cheng 	    "flow,property,value,default,possible";
1831da14cebeSEric Cheng 
1832da14cebeSEric Cheng 	fields_str = all_fields;
1833da14cebeSEric Cheng 	opterr = 0;
1834da14cebeSEric Cheng 	state.fs_propvals = NULL;
1835da14cebeSEric Cheng 	state.fs_line = NULL;
1836da14cebeSEric Cheng 	state.fs_parseable = B_FALSE;
1837da14cebeSEric Cheng 	state.fs_persist = B_FALSE;
1838da14cebeSEric Cheng 	state.fs_header = B_TRUE;
1839da14cebeSEric Cheng 	state.fs_retstatus = DLADM_STATUS_OK;
1840da14cebeSEric Cheng 	state.fs_linkid = DATALINK_INVALID_LINKID;
1841da14cebeSEric Cheng 	state.fs_flow = NULL;
1842da14cebeSEric Cheng 
1843da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":p:cPl:o:",
1844da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
1845da14cebeSEric Cheng 		switch (option) {
1846da14cebeSEric Cheng 		case 'p':
1847da14cebeSEric Cheng 			if (dladm_parse_flow_props(optarg, &proplist, B_TRUE)
1848da14cebeSEric Cheng 			    != DLADM_STATUS_OK)
1849da14cebeSEric Cheng 				die("invalid flow properties specified");
1850da14cebeSEric Cheng 			break;
1851da14cebeSEric Cheng 		case 'c':
1852da14cebeSEric Cheng 			state.fs_parseable = B_TRUE;
1853da14cebeSEric Cheng 			break;
1854da14cebeSEric Cheng 		case 'P':
1855da14cebeSEric Cheng 			state.fs_persist = B_TRUE;
1856da14cebeSEric Cheng 			break;
1857da14cebeSEric Cheng 		case 'l':
18584ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, optarg, &state.fs_linkid,
1859da14cebeSEric Cheng 			    NULL, NULL, NULL) != DLADM_STATUS_OK)
1860da14cebeSEric Cheng 				die("invalid link '%s'", optarg);
1861da14cebeSEric Cheng 			break;
1862da14cebeSEric Cheng 		case 'o':
1863ad091ee1SMichael Lim 			o_arg = B_TRUE;
1864da14cebeSEric Cheng 			if (strcasecmp(optarg, "all") == 0)
1865da14cebeSEric Cheng 				fields_str = all_fields;
1866da14cebeSEric Cheng 			else
1867da14cebeSEric Cheng 				fields_str = optarg;
1868da14cebeSEric Cheng 			break;
1869da14cebeSEric Cheng 		default:
1870da14cebeSEric Cheng 			die_opterr(optopt, option);
1871da14cebeSEric Cheng 			break;
1872da14cebeSEric Cheng 		}
1873da14cebeSEric Cheng 	}
1874da14cebeSEric Cheng 
1875ad091ee1SMichael Lim 	if (state.fs_parseable && !o_arg)
1876ad091ee1SMichael Lim 		die("-p requires -o");
1877ad091ee1SMichael Lim 
1878ad091ee1SMichael Lim 	if (state.fs_parseable && strcasecmp(fields_str, "all") == 0)
1879ad091ee1SMichael Lim 		die("\"-o all\" is invalid with -p");
1880ad091ee1SMichael Lim 
1881da14cebeSEric Cheng 	if (optind == (argc - 1)) {
1882da000602SGirish Moodalbail 		if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
1883da14cebeSEric Cheng 			die("flow name too long");
1884da14cebeSEric Cheng 		state.fs_flow = argv[optind];
1885da14cebeSEric Cheng 	} else if (optind != argc) {
1886da14cebeSEric Cheng 		usage();
1887da14cebeSEric Cheng 	}
1888da14cebeSEric Cheng 	bzero(&state.fs_print, sizeof (print_state_t));
1889da14cebeSEric Cheng 	state.fs_proplist = proplist;
1890da14cebeSEric Cheng 	state.fs_status = DLADM_STATUS_OK;
1891da14cebeSEric Cheng 
1892da14cebeSEric Cheng 	fields = parse_output_fields(fields_str, flowprop_fields,
1893da14cebeSEric Cheng 	    FLOWPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields);
1894da14cebeSEric Cheng 
1895da14cebeSEric Cheng 	if (fields == NULL) {
1896da14cebeSEric Cheng 		die("invalid field(s) specified");
1897da14cebeSEric Cheng 		return;
1898da14cebeSEric Cheng 	}
1899da14cebeSEric Cheng 
1900da14cebeSEric Cheng 	state.fs_print.ps_fields = fields;
1901da14cebeSEric Cheng 	state.fs_print.ps_nfields = nfields;
1902da14cebeSEric Cheng 
1903da14cebeSEric Cheng 	/* Show properties for one flow */
1904da14cebeSEric Cheng 	if (state.fs_flow != NULL) {
1905da14cebeSEric Cheng 		show_flowprop_one_flow(&state, state.fs_flow);
1906da14cebeSEric Cheng 
1907da14cebeSEric Cheng 	/* Show properties for all flows on one link */
1908da14cebeSEric Cheng 	} else if (state.fs_linkid != DATALINK_INVALID_LINKID) {
19094ac67f02SAnurag S. Maskey 		(void) show_flowprop_onelink(handle, state.fs_linkid, &state);
1910da14cebeSEric Cheng 
1911da14cebeSEric Cheng 	/* Show properties for all flows on all links */
1912da14cebeSEric Cheng 	} else {
19134ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_flowprop_onelink, handle,
19144ac67f02SAnurag S. Maskey 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1915da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
1916da14cebeSEric Cheng 	}
1917da14cebeSEric Cheng 
1918da14cebeSEric Cheng 	dladm_free_props(proplist);
1919da14cebeSEric Cheng }
1920da14cebeSEric Cheng 
1921da14cebeSEric Cheng static void
1922da14cebeSEric Cheng show_flowprop_one_flow(void *arg, const char *flow)
1923da14cebeSEric Cheng {
1924da14cebeSEric Cheng 	int			i;
1925da14cebeSEric Cheng 	char			*buf;
1926da14cebeSEric Cheng 	dladm_status_t		status;
1927da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1928da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg;
1929da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
1930da14cebeSEric Cheng 	const char		*savep;
1931da14cebeSEric Cheng 
1932da14cebeSEric Cheng 	/*
1933da14cebeSEric Cheng 	 * Do not print flow props for invalid flows.
1934da14cebeSEric Cheng 	 */
19354ac67f02SAnurag S. Maskey 	if ((status = dladm_flow_info(handle, flow, &attr)) !=
19364ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK) {
1937da14cebeSEric Cheng 		die("invalid flow: '%s'", flow);
1938da14cebeSEric Cheng 	}
1939da14cebeSEric Cheng 
1940da14cebeSEric Cheng 	savep = statep->fs_flow;
1941da14cebeSEric Cheng 	statep->fs_flow = flow;
1942da14cebeSEric Cheng 
1943da14cebeSEric Cheng 	proplist = statep->fs_proplist;
1944da14cebeSEric Cheng 
1945da14cebeSEric Cheng 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX)
1946da14cebeSEric Cheng 	    * DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
1947da14cebeSEric Cheng 	if (buf == NULL)
1948da14cebeSEric Cheng 		die("insufficient memory");
1949da14cebeSEric Cheng 
1950da14cebeSEric Cheng 	statep->fs_propvals = (char **)(void *)buf;
1951da14cebeSEric Cheng 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
1952da14cebeSEric Cheng 		statep->fs_propvals[i] = buf +
1953da14cebeSEric Cheng 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1954da14cebeSEric Cheng 		    i * DLADM_PROP_VAL_MAX;
1955da14cebeSEric Cheng 	}
1956da14cebeSEric Cheng 	statep->fs_line = buf +
1957da14cebeSEric Cheng 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
1958da14cebeSEric Cheng 
1959da14cebeSEric Cheng 	/* show only specified flow properties */
1960da14cebeSEric Cheng 	if (proplist != NULL) {
1961da14cebeSEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
1962da14cebeSEric Cheng 			if (show_one_flowprop(statep,
1963da14cebeSEric Cheng 			    proplist->al_info[i].ai_name) != DLADM_STATUS_OK)
1964da14cebeSEric Cheng 				break;
1965da14cebeSEric Cheng 		}
1966da14cebeSEric Cheng 
1967da14cebeSEric Cheng 	/* show all flow properties */
1968da14cebeSEric Cheng 	} else {
1969da14cebeSEric Cheng 		status = dladm_walk_flowprop(show_one_flowprop, flow, statep);
1970da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
1971da14cebeSEric Cheng 			die_dlerr(status, "show-flowprop");
1972da14cebeSEric Cheng 	}
1973da14cebeSEric Cheng 	free(buf);
1974da14cebeSEric Cheng 	statep->fs_flow = savep;
1975da14cebeSEric Cheng }
1976da14cebeSEric Cheng 
1977da14cebeSEric Cheng typedef struct {
1978da14cebeSEric Cheng 	char	*s_buf;
1979da14cebeSEric Cheng 	char	**s_fields;	/* array of pointer to the fields in s_buf */
1980da14cebeSEric Cheng 	uint_t	s_nfields;	/* the number of fields in s_buf */
1981da14cebeSEric Cheng } split_t;
1982da14cebeSEric Cheng 
1983da14cebeSEric Cheng /*
1984da14cebeSEric Cheng  * Free the split_t structure pointed to by `sp'.
1985da14cebeSEric Cheng  */
1986da14cebeSEric Cheng static void
1987da14cebeSEric Cheng splitfree(split_t *sp)
1988da14cebeSEric Cheng {
1989da14cebeSEric Cheng 	free(sp->s_buf);
1990da14cebeSEric Cheng 	free(sp->s_fields);
1991da14cebeSEric Cheng 	free(sp);
1992da14cebeSEric Cheng }
1993da14cebeSEric Cheng 
1994da14cebeSEric Cheng /*
1995da14cebeSEric Cheng  * Split `str' into at most `maxfields' fields, each field at most `maxlen' in
1996da14cebeSEric Cheng  * length.  Return a pointer to a split_t containing the split fields, or NULL
1997da14cebeSEric Cheng  * on failure.
1998da14cebeSEric Cheng  */
1999da14cebeSEric Cheng static split_t *
2000da14cebeSEric Cheng split(const char *str, uint_t maxfields, uint_t maxlen)
2001da14cebeSEric Cheng {
2002da14cebeSEric Cheng 	char	*field, *token, *lasts = NULL;
2003da14cebeSEric Cheng 	split_t	*sp;
2004da14cebeSEric Cheng 
2005da14cebeSEric Cheng 	if (*str == '\0' || maxfields == 0 || maxlen == 0)
2006da14cebeSEric Cheng 		return (NULL);
2007da14cebeSEric Cheng 
2008da14cebeSEric Cheng 	sp = calloc(sizeof (split_t), 1);
2009da14cebeSEric Cheng 	if (sp == NULL)
2010da14cebeSEric Cheng 		return (NULL);
2011da14cebeSEric Cheng 
2012da14cebeSEric Cheng 	sp->s_buf = strdup(str);
2013da14cebeSEric Cheng 	sp->s_fields = malloc(sizeof (char *) * maxfields);
2014da14cebeSEric Cheng 	if (sp->s_buf == NULL || sp->s_fields == NULL)
2015da14cebeSEric Cheng 		goto fail;
2016da14cebeSEric Cheng 
2017da14cebeSEric Cheng 	token = sp->s_buf;
2018da14cebeSEric Cheng 	while ((field = strtok_r(token, ",", &lasts)) != NULL) {
2019da14cebeSEric Cheng 		if (sp->s_nfields == maxfields || strlen(field) > maxlen)
2020da14cebeSEric Cheng 			goto fail;
2021da14cebeSEric Cheng 		token = NULL;
2022da14cebeSEric Cheng 		sp->s_fields[sp->s_nfields++] = field;
2023da14cebeSEric Cheng 	}
2024da14cebeSEric Cheng 	return (sp);
2025da14cebeSEric Cheng fail:
2026da14cebeSEric Cheng 	splitfree(sp);
2027da14cebeSEric Cheng 	return (NULL);
2028da14cebeSEric Cheng }
2029da14cebeSEric Cheng 
2030da14cebeSEric Cheng static print_field_t **
2031da14cebeSEric Cheng parse_output_fields(char *str, print_field_t *template, int max_fields,
2032da14cebeSEric Cheng     uint_t cmdtype, uint_t *countp)
2033da14cebeSEric Cheng {
2034da14cebeSEric Cheng 	split_t		*sp;
2035da14cebeSEric Cheng 	boolean_t	good_match = B_FALSE;
2036da14cebeSEric Cheng 	uint_t		i, j;
2037da14cebeSEric Cheng 	print_field_t	**pf = NULL;
2038da14cebeSEric Cheng 
2039da14cebeSEric Cheng 	sp = split(str, max_fields, MAX_FIELD_LEN);
2040da14cebeSEric Cheng 
2041da14cebeSEric Cheng 	if (sp == NULL)
2042da14cebeSEric Cheng 		return (NULL);
2043da14cebeSEric Cheng 
2044da14cebeSEric Cheng 	pf = malloc(sp->s_nfields * sizeof (print_field_t *));
2045da14cebeSEric Cheng 	if (pf == NULL)
2046da14cebeSEric Cheng 		goto fail;
2047da14cebeSEric Cheng 
2048da14cebeSEric Cheng 	for (i = 0; i < sp->s_nfields; i++) {
2049da14cebeSEric Cheng 		for (j = 0; j < max_fields; j++) {
2050da14cebeSEric Cheng 			if (strcasecmp(sp->s_fields[i],
2051da14cebeSEric Cheng 			    template[j].pf_name) == 0) {
2052da14cebeSEric Cheng 				good_match = template[j]. pf_cmdtype & cmdtype;
2053da14cebeSEric Cheng 				break;
2054da14cebeSEric Cheng 			}
2055da14cebeSEric Cheng 		}
2056da14cebeSEric Cheng 		if (!good_match)
2057da14cebeSEric Cheng 			goto fail;
2058da14cebeSEric Cheng 
2059da14cebeSEric Cheng 		good_match = B_FALSE;
2060da14cebeSEric Cheng 		pf[i] = &template[j];
2061da14cebeSEric Cheng 	}
2062da14cebeSEric Cheng 	*countp = i;
2063da14cebeSEric Cheng 	splitfree(sp);
2064da14cebeSEric Cheng 	return (pf);
2065da14cebeSEric Cheng fail:
2066da14cebeSEric Cheng 	free(pf);
2067da14cebeSEric Cheng 	splitfree(sp);
2068da14cebeSEric Cheng 	return (NULL);
2069da14cebeSEric Cheng }
2070da14cebeSEric Cheng 
2071da14cebeSEric Cheng static void
2072da14cebeSEric Cheng flowadm_print_output(print_state_t *statep, boolean_t parseable,
2073da14cebeSEric Cheng     print_callback_t fn, void *arg)
2074da14cebeSEric Cheng {
2075da14cebeSEric Cheng 	int i;
2076da14cebeSEric Cheng 	char *value;
2077da14cebeSEric Cheng 	print_field_t **pf;
2078da14cebeSEric Cheng 
2079da14cebeSEric Cheng 	pf = statep->ps_fields;
2080da14cebeSEric Cheng 	for (i = 0; i < statep->ps_nfields; i++) {
2081da14cebeSEric Cheng 		statep->ps_lastfield = (i + 1 == statep->ps_nfields);
2082da14cebeSEric Cheng 		value = (*fn)(pf[i], arg);
2083da14cebeSEric Cheng 		if (value != NULL)
2084da14cebeSEric Cheng 			print_field(statep, pf[i], value, parseable);
2085da14cebeSEric Cheng 	}
2086da14cebeSEric Cheng 	(void) putchar('\n');
2087da14cebeSEric Cheng }
2088da14cebeSEric Cheng 
2089da14cebeSEric Cheng static void
2090da14cebeSEric Cheng print_header(print_state_t *ps)
2091da14cebeSEric Cheng {
2092da14cebeSEric Cheng 	int i;
2093da14cebeSEric Cheng 	print_field_t **pf;
2094da14cebeSEric Cheng 
2095da14cebeSEric Cheng 	pf = ps->ps_fields;
2096da14cebeSEric Cheng 	for (i = 0; i < ps->ps_nfields; i++) {
2097da14cebeSEric Cheng 		ps->ps_lastfield = (i + 1 == ps->ps_nfields);
2098da14cebeSEric Cheng 		print_field(ps, pf[i], pf[i]->pf_header, B_FALSE);
2099da14cebeSEric Cheng 	}
2100da14cebeSEric Cheng 	(void) putchar('\n');
2101da14cebeSEric Cheng }
2102da14cebeSEric Cheng 
2103da14cebeSEric Cheng static void
2104da14cebeSEric Cheng print_field(print_state_t *statep, print_field_t *pfp, const char *value,
2105da14cebeSEric Cheng     boolean_t parseable)
2106da14cebeSEric Cheng {
2107da14cebeSEric Cheng 	uint_t	width = pfp->pf_width;
2108ad091ee1SMichael Lim 	uint_t	valwidth;
2109da14cebeSEric Cheng 	uint_t	compress;
2110da14cebeSEric Cheng 
2111ad091ee1SMichael Lim 	/*
2112ad091ee1SMichael Lim 	 * Parsable fields are separated by ':'. If such a field contains
2113ad091ee1SMichael Lim 	 * a ':' or '\', this character is prefixed by a '\'.
2114ad091ee1SMichael Lim 	 */
2115da14cebeSEric Cheng 	if (parseable) {
2116ad091ee1SMichael Lim 		char	c;
2117ad091ee1SMichael Lim 
2118ad091ee1SMichael Lim 		if (statep->ps_nfields == 1) {
2119ad091ee1SMichael Lim 			(void) printf("%s", value);
2120ad091ee1SMichael Lim 			return;
2121ad091ee1SMichael Lim 		}
2122ad091ee1SMichael Lim 		while ((c = *value++) != '\0') {
2123ad091ee1SMichael Lim 			if (c == ':' || c == '\\')
2124ad091ee1SMichael Lim 				(void) putchar('\\');
2125ad091ee1SMichael Lim 			(void) putchar(c);
2126ad091ee1SMichael Lim 		}
2127ad091ee1SMichael Lim 		if (!statep->ps_lastfield)
2128ad091ee1SMichael Lim 			(void) putchar(':');
2129ad091ee1SMichael Lim 		return;
2130da14cebeSEric Cheng 	} else {
2131da14cebeSEric Cheng 		if (value[0] == '\0')
2132da14cebeSEric Cheng 			value = STR_UNDEF_VAL;
2133da14cebeSEric Cheng 		if (statep->ps_lastfield) {
2134da14cebeSEric Cheng 			(void) printf("%s", value);
2135ad091ee1SMichael Lim 			statep->ps_overflow = 0;
2136da14cebeSEric Cheng 			return;
2137da14cebeSEric Cheng 		}
2138da14cebeSEric Cheng 
2139ad091ee1SMichael Lim 		valwidth = strlen(value);
2140da14cebeSEric Cheng 		if (valwidth > width) {
2141da14cebeSEric Cheng 			statep->ps_overflow += valwidth - width;
2142da14cebeSEric Cheng 		} else if (valwidth < width && statep->ps_overflow > 0) {
2143da14cebeSEric Cheng 			compress = min(statep->ps_overflow, width - valwidth);
2144da14cebeSEric Cheng 			statep->ps_overflow -= compress;
2145da14cebeSEric Cheng 			width -= compress;
2146da14cebeSEric Cheng 		}
2147da14cebeSEric Cheng 		(void) printf("%-*s", width, value);
2148da14cebeSEric Cheng 	}
2149da14cebeSEric Cheng 
2150da14cebeSEric Cheng 	if (!statep->ps_lastfield)
2151da14cebeSEric Cheng 		(void) putchar(' ');
2152da14cebeSEric Cheng }
2153