xref: /titanic_51/usr/src/cmd/flowadm/flowadm.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
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 /*
22*0dc2366fSVenugopal Iyer  * Copyright 2010 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 <strings.h>
35da14cebeSEric Cheng #include <getopt.h>
36da14cebeSEric Cheng #include <unistd.h>
37da14cebeSEric Cheng #include <priv.h>
38da14cebeSEric Cheng #include <netdb.h>
39da14cebeSEric Cheng #include <libintl.h>
40da14cebeSEric Cheng #include <libdlflow.h>
41da14cebeSEric Cheng #include <libdllink.h>
42da14cebeSEric Cheng #include <libdlstat.h>
43da14cebeSEric Cheng #include <sys/types.h>
44da14cebeSEric Cheng #include <sys/socket.h>
45da14cebeSEric Cheng #include <netinet/in.h>
46da14cebeSEric Cheng #include <arpa/inet.h>
47da14cebeSEric Cheng #include <sys/ethernet.h>
48da14cebeSEric Cheng #include <inet/ip.h>
49da14cebeSEric Cheng #include <inet/ip6.h>
50da14cebeSEric Cheng #include <stddef.h>
518002d411SSowmini Varadhan #include <ofmt.h>
52da14cebeSEric Cheng 
53ae6aa22aSVenugopal Iyer typedef struct show_flow_state {
54ae6aa22aSVenugopal Iyer 	dladm_status_t		fs_status;
558002d411SSowmini Varadhan 	ofmt_handle_t		fs_ofmt;
56ae6aa22aSVenugopal Iyer 	const char		*fs_flow;
578002d411SSowmini Varadhan 	boolean_t		fs_parsable;
58ae6aa22aSVenugopal Iyer 	boolean_t		fs_persist;
59ae6aa22aSVenugopal Iyer } show_flow_state_t;
60ae6aa22aSVenugopal Iyer 
61da14cebeSEric Cheng typedef void cmdfunc_t(int, char **);
62da14cebeSEric Cheng 
63da14cebeSEric Cheng static cmdfunc_t do_add_flow, do_remove_flow, do_init_flow, do_show_flow;
64da14cebeSEric Cheng static cmdfunc_t do_show_flowprop, do_set_flowprop, do_reset_flowprop;
65da14cebeSEric Cheng 
66c3affd82SMichael Lim static int	show_flow(dladm_handle_t, dladm_flow_attr_t *, void *);
674ac67f02SAnurag S. Maskey static int	show_flows_onelink(dladm_handle_t, datalink_id_t, void *);
68da14cebeSEric Cheng 
69c3affd82SMichael Lim static int	remove_flow(dladm_handle_t, dladm_flow_attr_t *, void *);
70da14cebeSEric Cheng 
71c3affd82SMichael Lim static int	show_flowprop(dladm_handle_t, dladm_flow_attr_t *, void *);
72da14cebeSEric Cheng static void	show_flowprop_one_flow(void *, const char *);
734ac67f02SAnurag S. Maskey static int	show_flowprop_onelink(dladm_handle_t, datalink_id_t, void *);
74da14cebeSEric Cheng 
75da14cebeSEric Cheng static void	die(const char *, ...);
76da14cebeSEric Cheng static void	die_optdup(int);
77da14cebeSEric Cheng static void	die_opterr(int, int);
78da14cebeSEric Cheng static void	die_dlerr(dladm_status_t, const char *, ...);
79da14cebeSEric Cheng static void	warn(const char *, ...);
80da14cebeSEric Cheng static void	warn_dlerr(dladm_status_t, const char *, ...);
81da14cebeSEric Cheng 
828002d411SSowmini Varadhan /* callback functions for printing output */
83*0dc2366fSVenugopal Iyer static ofmt_cb_t print_flowprop_cb, print_default_cb;
848002d411SSowmini Varadhan static void flowadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
858002d411SSowmini Varadhan 
86da14cebeSEric Cheng typedef struct	cmd {
87da14cebeSEric Cheng 	char	*c_name;
88da14cebeSEric Cheng 	void	(*c_fn)(int, char **);
89da14cebeSEric Cheng } cmd_t;
90da14cebeSEric Cheng 
91da14cebeSEric Cheng static cmd_t	cmds[] = {
92da14cebeSEric Cheng 	{ "add-flow", do_add_flow },
93da14cebeSEric Cheng 	{ "remove-flow", do_remove_flow },
94da14cebeSEric Cheng 	{ "show-flowprop", do_show_flowprop },
95da14cebeSEric Cheng 	{ "set-flowprop", do_set_flowprop },
96da14cebeSEric Cheng 	{ "reset-flowprop", do_reset_flowprop },
97da14cebeSEric Cheng 	{ "show-flow", do_show_flow },
98da14cebeSEric Cheng 	{ "init-flow", do_init_flow },
99da14cebeSEric Cheng };
100da14cebeSEric Cheng 
101da14cebeSEric Cheng static const struct option longopts[] = {
102da14cebeSEric Cheng 	{"link",		required_argument,	0, 'l'},
1038002d411SSowmini Varadhan 	{"parsable",		no_argument,		0, 'p'},
104da14cebeSEric Cheng 	{"parseable",		no_argument,		0, 'p'},
105da14cebeSEric Cheng 	{"temporary",		no_argument,		0, 't'},
106da14cebeSEric Cheng 	{"root-dir",		required_argument,	0, 'R'},
107da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
108da14cebeSEric Cheng };
109da14cebeSEric Cheng 
110da14cebeSEric Cheng static const struct option prop_longopts[] = {
111da14cebeSEric Cheng 	{"link",		required_argument,	0, 'l'},
112da14cebeSEric Cheng 	{"temporary",		no_argument,		0, 't'},
113da14cebeSEric Cheng 	{"root-dir",		required_argument,	0, 'R'},
114da14cebeSEric Cheng 	{"prop",		required_argument,	0, 'p'},
115da14cebeSEric Cheng 	{"attr",		required_argument,	0, 'a'},
116da14cebeSEric Cheng 	{ 0, 0, 0, 0 }
117da14cebeSEric Cheng };
118da14cebeSEric Cheng 
119da14cebeSEric Cheng /*
120da14cebeSEric Cheng  * structures for 'flowadm remove-flow'
121da14cebeSEric Cheng  */
122da14cebeSEric Cheng typedef struct remove_flow_state {
123da14cebeSEric Cheng 	boolean_t	fs_tempop;
124da14cebeSEric Cheng 	const char	*fs_altroot;
125da14cebeSEric Cheng 	dladm_status_t	fs_status;
126da14cebeSEric Cheng } remove_flow_state_t;
127da14cebeSEric Cheng 
128da14cebeSEric Cheng #define	PROTO_MAXSTR_LEN	7
129da14cebeSEric Cheng #define	PORT_MAXSTR_LEN		6
130da14cebeSEric Cheng #define	DSFIELD_MAXSTR_LEN	10
1318002d411SSowmini Varadhan #define	NULL_OFMT		{NULL, 0, 0, NULL}
132da14cebeSEric Cheng 
133da14cebeSEric Cheng typedef struct flow_fields_buf_s
134da14cebeSEric Cheng {
135da000602SGirish Moodalbail 	char flow_name[MAXFLOWNAMELEN];
136da14cebeSEric Cheng 	char flow_link[MAXLINKNAMELEN];
137da14cebeSEric Cheng 	char flow_ipaddr[INET6_ADDRSTRLEN+4];
138da14cebeSEric Cheng 	char flow_proto[PROTO_MAXSTR_LEN];
13925ec3e3dSEric Cheng 	char flow_lport[PORT_MAXSTR_LEN];
14025ec3e3dSEric Cheng 	char flow_rport[PORT_MAXSTR_LEN];
141da14cebeSEric Cheng 	char flow_dsfield[DSFIELD_MAXSTR_LEN];
142da14cebeSEric Cheng } flow_fields_buf_t;
143da14cebeSEric Cheng 
1448002d411SSowmini Varadhan static ofmt_field_t flow_fields[] = {
1458002d411SSowmini Varadhan /* name,	field width,	index */
1468002d411SSowmini Varadhan {  "FLOW",	12,
1478002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_name), print_default_cb},
1488002d411SSowmini Varadhan {  "LINK",	12,
1498002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_link), print_default_cb},
15025ec3e3dSEric Cheng {  "IPADDR",	25,
1518002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb},
1528002d411SSowmini Varadhan {  "PROTO",	7,
1538002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_proto), print_default_cb},
15425ec3e3dSEric Cheng {  "LPORT",	8,
15525ec3e3dSEric Cheng 	offsetof(flow_fields_buf_t, flow_lport), print_default_cb},
15625ec3e3dSEric Cheng {  "RPORT",	8,
15725ec3e3dSEric Cheng 	offsetof(flow_fields_buf_t, flow_rport), print_default_cb},
1588002d411SSowmini Varadhan {  "DSFLD",	10,
1598002d411SSowmini Varadhan 	offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb},
1608002d411SSowmini Varadhan NULL_OFMT}
161da14cebeSEric Cheng ;
162da14cebeSEric Cheng 
163da14cebeSEric Cheng /*
164da14cebeSEric Cheng  * structures for 'flowadm show-flowprop'
165da14cebeSEric Cheng  */
166da14cebeSEric Cheng typedef enum {
167da14cebeSEric Cheng 	FLOWPROP_FLOW,
168da14cebeSEric Cheng 	FLOWPROP_PROPERTY,
169da14cebeSEric Cheng 	FLOWPROP_VALUE,
170da14cebeSEric Cheng 	FLOWPROP_DEFAULT,
171da14cebeSEric Cheng 	FLOWPROP_POSSIBLE
172da14cebeSEric Cheng } flowprop_field_index_t;
173da14cebeSEric Cheng 
1748002d411SSowmini Varadhan static ofmt_field_t flowprop_fields[] = {
1758002d411SSowmini Varadhan /* name,	fieldwidth,	index, 		callback */
1768002d411SSowmini Varadhan { "FLOW",	13,	FLOWPROP_FLOW,		print_flowprop_cb},
1778002d411SSowmini Varadhan { "PROPERTY",	16,	FLOWPROP_PROPERTY,	print_flowprop_cb},
1788002d411SSowmini Varadhan { "VALUE",	15,	FLOWPROP_VALUE,		print_flowprop_cb},
1798002d411SSowmini Varadhan { "DEFAULT",	15,	FLOWPROP_DEFAULT,	print_flowprop_cb},
1808002d411SSowmini Varadhan { "POSSIBLE",	21,	FLOWPROP_POSSIBLE,	print_flowprop_cb},
1818002d411SSowmini Varadhan NULL_OFMT}
182da14cebeSEric Cheng ;
183da14cebeSEric Cheng 
184da14cebeSEric Cheng #define	MAX_PROP_LINE		512
185da14cebeSEric Cheng 
186da14cebeSEric Cheng typedef struct show_flowprop_state {
187da14cebeSEric Cheng 	const char		*fs_flow;
188da14cebeSEric Cheng 	datalink_id_t		fs_linkid;
189da14cebeSEric Cheng 	char			*fs_line;
190da14cebeSEric Cheng 	char			**fs_propvals;
191da14cebeSEric Cheng 	dladm_arg_list_t	*fs_proplist;
1928002d411SSowmini Varadhan 	boolean_t		fs_parsable;
193da14cebeSEric Cheng 	boolean_t		fs_persist;
194da14cebeSEric Cheng 	boolean_t		fs_header;
195da14cebeSEric Cheng 	dladm_status_t		fs_status;
196da14cebeSEric Cheng 	dladm_status_t		fs_retstatus;
1978002d411SSowmini Varadhan 	ofmt_handle_t		fs_ofmt;
198da14cebeSEric Cheng } show_flowprop_state_t;
199da14cebeSEric Cheng 
200da14cebeSEric Cheng typedef struct set_flowprop_state {
201da14cebeSEric Cheng 	const char	*fs_name;
202da14cebeSEric Cheng 	boolean_t	fs_reset;
203da14cebeSEric Cheng 	boolean_t	fs_temp;
204da14cebeSEric Cheng 	dladm_status_t	fs_status;
205da14cebeSEric Cheng } set_flowprop_state_t;
206da14cebeSEric Cheng 
207da14cebeSEric Cheng typedef struct flowprop_args_s {
208da14cebeSEric Cheng 	show_flowprop_state_t	*fs_state;
209da14cebeSEric Cheng 	char			*fs_propname;
210da14cebeSEric Cheng 	char			*fs_flowname;
211da14cebeSEric Cheng } flowprop_args_t;
212da14cebeSEric Cheng 
213da14cebeSEric Cheng static char *progname;
214da14cebeSEric Cheng 
215da14cebeSEric Cheng boolean_t		t_arg = B_FALSE; /* changes are persistent */
216da14cebeSEric Cheng char			*altroot = NULL;
217da14cebeSEric Cheng 
2184ac67f02SAnurag S. Maskey /*
2194ac67f02SAnurag S. Maskey  * Handle to libdladm.  Opened in main() before the sub-command
2204ac67f02SAnurag S. Maskey  * specific function is called.
2214ac67f02SAnurag S. Maskey  */
2224ac67f02SAnurag S. Maskey static dladm_handle_t handle = NULL;
2234ac67f02SAnurag S. Maskey 
224da14cebeSEric Cheng static const char *attr_table[] =
22525ec3e3dSEric Cheng 	{"local_ip", "remote_ip", "transport", "local_port", "remote_port",
22625ec3e3dSEric Cheng 	    "dsfield"};
227da14cebeSEric Cheng 
228da14cebeSEric Cheng #define	NATTR	(sizeof (attr_table)/sizeof (char *))
229da14cebeSEric Cheng 
230da14cebeSEric Cheng static void
231da14cebeSEric Cheng usage(void)
232da14cebeSEric Cheng {
233da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("usage: flowadm <subcommand>"
234da14cebeSEric Cheng 	    " <args>...\n"
2350790b6dcSAnurag S. Maskey 	    "    add-flow       [-t] -l <link> -a <attr>=<value>[,...]\n"
2360790b6dcSAnurag S. Maskey 	    "\t\t   [-p <prop>=<value>,...] <flow>\n"
2370790b6dcSAnurag S. Maskey 	    "    remove-flow    [-t] {-l <link> | <flow>}\n"
238*0dc2366fSVenugopal Iyer 	    "    show-flow      [-p] [-l <link>] "
2390790b6dcSAnurag S. Maskey 	    "[<flow>]\n\n"
2400790b6dcSAnurag S. Maskey 	    "    set-flowprop   [-t] -p <prop>=<value>[,...] <flow>\n"
2410790b6dcSAnurag S. Maskey 	    "    reset-flowprop [-t] [-p <prop>,...] <flow>\n"
2420790b6dcSAnurag S. Maskey 	    "    show-flowprop  [-cP] [-l <link>] [-p <prop>,...] "
243*0dc2366fSVenugopal Iyer 	    "[<flow>]\n"));
2444ac67f02SAnurag S. Maskey 
2454ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
2464ac67f02SAnurag S. Maskey 	if (handle != NULL)
2474ac67f02SAnurag S. Maskey 		dladm_close(handle);
2484ac67f02SAnurag S. Maskey 
249da14cebeSEric Cheng 	exit(1);
250da14cebeSEric Cheng }
251da14cebeSEric Cheng 
252da14cebeSEric Cheng int
253da14cebeSEric Cheng main(int argc, char *argv[])
254da14cebeSEric Cheng {
255da14cebeSEric Cheng 	int	i, arglen, cmdlen;
256da14cebeSEric Cheng 	cmd_t	*cmdp;
2574ac67f02SAnurag S. Maskey 	dladm_status_t status;
258da14cebeSEric Cheng 
259da14cebeSEric Cheng 	(void) setlocale(LC_ALL, "");
260da14cebeSEric Cheng #if !defined(TEXT_DOMAIN)
261da14cebeSEric Cheng #define	TEXT_DOMAIN "SYS_TEST"
262da14cebeSEric Cheng #endif
263da14cebeSEric Cheng 	(void) textdomain(TEXT_DOMAIN);
264da14cebeSEric Cheng 
265da14cebeSEric Cheng 	progname = argv[0];
266da14cebeSEric Cheng 
267da14cebeSEric Cheng 	if (argc < 2)
268da14cebeSEric Cheng 		usage();
269da14cebeSEric Cheng 
270da14cebeSEric Cheng 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
271da14cebeSEric Cheng 		cmdp = &cmds[i];
272da14cebeSEric Cheng 		arglen = strlen(argv[1]);
273da14cebeSEric Cheng 		cmdlen = strlen(cmdp->c_name);
274da14cebeSEric Cheng 		if ((arglen == cmdlen) && (strncmp(argv[1], cmdp->c_name,
275da14cebeSEric Cheng 		    cmdlen) == 0)) {
2764ac67f02SAnurag S. Maskey 			/* Open the libdladm handle */
2774ac67f02SAnurag S. Maskey 			if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
2784ac67f02SAnurag S. Maskey 				die_dlerr(status,
2794ac67f02SAnurag S. Maskey 				    "could not open /dev/dld");
2804ac67f02SAnurag S. Maskey 			}
2814ac67f02SAnurag S. Maskey 
282da14cebeSEric Cheng 			cmdp->c_fn(argc - 1, &argv[1]);
2834ac67f02SAnurag S. Maskey 
2844ac67f02SAnurag S. Maskey 			dladm_close(handle);
285ad091ee1SMichael Lim 			exit(EXIT_SUCCESS);
286da14cebeSEric Cheng 		}
287da14cebeSEric Cheng 	}
288da14cebeSEric Cheng 
289da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
290da14cebeSEric Cheng 	    progname, argv[1]);
291da14cebeSEric Cheng 	usage();
292da14cebeSEric Cheng 
293da14cebeSEric Cheng 	return (0);
294da14cebeSEric Cheng }
295da14cebeSEric Cheng 
296da14cebeSEric Cheng static const char *
297da14cebeSEric Cheng match_attr(char *attr)
298da14cebeSEric Cheng {
299da14cebeSEric Cheng 	int i;
300da14cebeSEric Cheng 
301da14cebeSEric Cheng 	for (i = 0; i < NATTR; i++) {
302da14cebeSEric Cheng 		if (strlen(attr) == strlen(attr_table[i]) &&
303da14cebeSEric Cheng 		    strncmp(attr, attr_table[i], strlen(attr_table[i])) == 0) {
304da14cebeSEric Cheng 			return (attr);
305da14cebeSEric Cheng 		}
306da14cebeSEric Cheng 	}
307da14cebeSEric Cheng 	return (NULL);
308da14cebeSEric Cheng }
309da14cebeSEric Cheng 
310da14cebeSEric Cheng /* ARGSUSED */
311da14cebeSEric Cheng static void
312da14cebeSEric Cheng do_init_flow(int argc, char *argv[])
313da14cebeSEric Cheng {
314da14cebeSEric Cheng 	dladm_status_t status;
315da14cebeSEric Cheng 
3164ac67f02SAnurag S. Maskey 	status = dladm_flow_init(handle);
317da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
318da14cebeSEric Cheng 		die_dlerr(status, "flows initialization failed");
319da14cebeSEric Cheng }
320da14cebeSEric Cheng 
321da14cebeSEric Cheng static void
322da14cebeSEric Cheng do_add_flow(int argc, char *argv[])
323da14cebeSEric Cheng {
324da000602SGirish Moodalbail 	char			devname[MAXLINKNAMELEN];
325da14cebeSEric Cheng 	char			*name = NULL;
326da14cebeSEric Cheng 	uint_t			index;
327da14cebeSEric Cheng 	datalink_id_t		linkid;
328da14cebeSEric Cheng 
329da14cebeSEric Cheng 	char			option;
330da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
33163a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
33263a6526dSMichael Lim 	char			attrstr[DLADM_STRSIZE];
333da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
334da14cebeSEric Cheng 	dladm_arg_list_t	*attrlist = NULL;
335da14cebeSEric Cheng 	dladm_status_t		status;
336da14cebeSEric Cheng 
33763a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
33863a6526dSMichael Lim 	bzero(attrstr, DLADM_STRSIZE);
33963a6526dSMichael Lim 
340da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, "tR:l:a:p:",
341da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
342da14cebeSEric Cheng 		switch (option) {
343da14cebeSEric Cheng 		case 't':
344da14cebeSEric Cheng 			t_arg = B_TRUE;
345da14cebeSEric Cheng 			break;
346da14cebeSEric Cheng 		case 'R':
347da14cebeSEric Cheng 			altroot = optarg;
348da14cebeSEric Cheng 			break;
349da14cebeSEric Cheng 		case 'l':
350da14cebeSEric Cheng 			if (strlcpy(devname, optarg,
351da000602SGirish Moodalbail 			    MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
352da14cebeSEric Cheng 				die("link name too long");
353da14cebeSEric Cheng 			}
3544ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, devname, &linkid, NULL,
355da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK)
356da14cebeSEric Cheng 				die("invalid link '%s'", devname);
357da14cebeSEric Cheng 			l_arg = B_TRUE;
358da14cebeSEric Cheng 			break;
359da14cebeSEric Cheng 		case 'a':
36063a6526dSMichael Lim 			(void) strlcat(attrstr, optarg, DLADM_STRSIZE);
36163a6526dSMichael Lim 			if (strlcat(attrstr, ",", DLADM_STRSIZE) >=
36263a6526dSMichael Lim 			    DLADM_STRSIZE)
36363a6526dSMichael Lim 				die("attribute list too long '%s'", attrstr);
364da14cebeSEric Cheng 			break;
365da14cebeSEric Cheng 		case 'p':
36663a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
36763a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
36863a6526dSMichael Lim 			    DLADM_STRSIZE)
36963a6526dSMichael Lim 				die("property list too long '%s'", propstr);
370da14cebeSEric Cheng 			break;
371da14cebeSEric Cheng 		default:
372da14cebeSEric Cheng 			die_opterr(optopt, option);
373da14cebeSEric Cheng 		}
374da14cebeSEric Cheng 	}
375da14cebeSEric Cheng 	if (!l_arg) {
376da14cebeSEric Cheng 		die("link is required");
377da14cebeSEric Cheng 	}
378da14cebeSEric Cheng 
379da14cebeSEric Cheng 	opterr = 0;
380da14cebeSEric Cheng 	index = optind;
381da14cebeSEric Cheng 
382da14cebeSEric Cheng 	if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) {
383da14cebeSEric Cheng 		die("flow name is required");
384da14cebeSEric Cheng 	} else {
385da14cebeSEric Cheng 		/* get flow name; required last argument */
386da000602SGirish Moodalbail 		if (strlen(argv[index]) >= MAXFLOWNAMELEN)
387da14cebeSEric Cheng 			die("flow name too long");
388da14cebeSEric Cheng 		name = argv[index];
389da14cebeSEric Cheng 	}
390da14cebeSEric Cheng 
39163a6526dSMichael Lim 	if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE)
39263a6526dSMichael Lim 	    != DLADM_STATUS_OK)
39363a6526dSMichael Lim 		die("invalid flow attribute specified");
39463a6526dSMichael Lim 	if (dladm_parse_flow_props(propstr, &proplist, B_FALSE)
39563a6526dSMichael Lim 	    != DLADM_STATUS_OK)
39663a6526dSMichael Lim 		die("invalid flow property specified");
39763a6526dSMichael Lim 
3984ac67f02SAnurag S. Maskey 	status = dladm_flow_add(handle, linkid, attrlist, proplist, name,
399da14cebeSEric Cheng 	    t_arg, altroot);
400da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
401da14cebeSEric Cheng 		die_dlerr(status, "add flow failed");
402da14cebeSEric Cheng 
403da14cebeSEric Cheng 	dladm_free_attrs(attrlist);
404da14cebeSEric Cheng 	dladm_free_props(proplist);
405da14cebeSEric Cheng }
406da14cebeSEric Cheng 
407da14cebeSEric Cheng static void
408da14cebeSEric Cheng do_remove_flow(int argc, char *argv[])
409da14cebeSEric Cheng {
410da14cebeSEric Cheng 	char			option;
411da14cebeSEric Cheng 	char			*flowname = NULL;
412da000602SGirish Moodalbail 	char			linkname[MAXLINKNAMELEN];
413da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
414da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
415da14cebeSEric Cheng 	remove_flow_state_t	state;
416da14cebeSEric Cheng 	dladm_status_t		status;
417da14cebeSEric Cheng 
418da14cebeSEric Cheng 	bzero(&state, sizeof (state));
419da14cebeSEric Cheng 
420da14cebeSEric Cheng 	opterr = 0;
421da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":tR:l:",
422da14cebeSEric Cheng 	    longopts, NULL)) != -1) {
423da14cebeSEric Cheng 		switch (option) {
424da14cebeSEric Cheng 		case 't':
425da14cebeSEric Cheng 			t_arg = B_TRUE;
426da14cebeSEric Cheng 			break;
427da14cebeSEric Cheng 		case 'R':
428da14cebeSEric Cheng 			altroot = optarg;
429da14cebeSEric Cheng 			break;
430da14cebeSEric Cheng 		case 'l':
431da14cebeSEric Cheng 			if (strlcpy(linkname, optarg,
432da14cebeSEric Cheng 			    MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
433da14cebeSEric Cheng 				die("link name too long");
434da14cebeSEric Cheng 			}
4354ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, linkname, &linkid, NULL,
436da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK) {
437da14cebeSEric Cheng 				die("invalid link '%s'", linkname);
438da14cebeSEric Cheng 			}
439da14cebeSEric Cheng 			l_arg = B_TRUE;
440da14cebeSEric Cheng 			break;
441da14cebeSEric Cheng 		default:
442da14cebeSEric Cheng 			die_opterr(optopt, option);
443da14cebeSEric Cheng 			break;
444da14cebeSEric Cheng 		}
445da14cebeSEric Cheng 	}
446da14cebeSEric Cheng 
447da14cebeSEric Cheng 	/* when link not specified get flow name */
448da14cebeSEric Cheng 	if (!l_arg) {
449da14cebeSEric Cheng 		if (optind != (argc-1)) {
450da14cebeSEric Cheng 			usage();
451da14cebeSEric Cheng 		} else {
452da000602SGirish Moodalbail 			if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
453da14cebeSEric Cheng 				die("flow name too long");
454da14cebeSEric Cheng 			flowname = argv[optind];
455da14cebeSEric Cheng 		}
4564ac67f02SAnurag S. Maskey 		status = dladm_flow_remove(handle, flowname, t_arg, altroot);
457da14cebeSEric Cheng 	} else {
458da14cebeSEric Cheng 		/* if link is specified then flow name should not be there */
459da14cebeSEric Cheng 		if (optind == argc-1)
460da14cebeSEric Cheng 			usage();
461da14cebeSEric Cheng 		/* walk the link to find flows and remove them */
462da14cebeSEric Cheng 		state.fs_tempop = t_arg;
463da14cebeSEric Cheng 		state.fs_altroot = altroot;
464da14cebeSEric Cheng 		state.fs_status = DLADM_STATUS_OK;
4654ac67f02SAnurag S. Maskey 		status = dladm_walk_flow(remove_flow, handle, linkid, &state,
4664ac67f02SAnurag S. Maskey 		    B_FALSE);
467da14cebeSEric Cheng 		/*
468da14cebeSEric Cheng 		 * check if dladm_walk_flow terminated early and see if the
469da14cebeSEric Cheng 		 * walker function as any status for us
470da14cebeSEric Cheng 		 */
471da14cebeSEric Cheng 		if (status == DLADM_STATUS_OK)
472da14cebeSEric Cheng 			status = state.fs_status;
473da14cebeSEric Cheng 	}
474da14cebeSEric Cheng 
475da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
476da14cebeSEric Cheng 		die_dlerr(status, "remove flow failed");
477da14cebeSEric Cheng }
478da14cebeSEric Cheng 
479da14cebeSEric Cheng /*
480da14cebeSEric Cheng  * Walker function for removing a flow through dladm_walk_flow();
481da14cebeSEric Cheng  */
482c3affd82SMichael Lim /*ARGSUSED*/
483da14cebeSEric Cheng static int
484c3affd82SMichael Lim remove_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
485da14cebeSEric Cheng {
486da14cebeSEric Cheng 	remove_flow_state_t	*state = (remove_flow_state_t *)arg;
487da14cebeSEric Cheng 
4884ac67f02SAnurag S. Maskey 	state->fs_status = dladm_flow_remove(handle, attr->fa_flowname,
489da14cebeSEric Cheng 	    state->fs_tempop, state->fs_altroot);
490da14cebeSEric Cheng 
491da14cebeSEric Cheng 	if (state->fs_status == DLADM_STATUS_OK)
492da14cebeSEric Cheng 		return (DLADM_WALK_CONTINUE);
493da14cebeSEric Cheng 	else
494da14cebeSEric Cheng 		return (DLADM_WALK_TERMINATE);
495da14cebeSEric Cheng }
496da14cebeSEric Cheng 
497da14cebeSEric Cheng /*ARGSUSED*/
498da14cebeSEric Cheng static dladm_status_t
499da14cebeSEric Cheng print_flow(show_flow_state_t *state, dladm_flow_attr_t *attr,
500da14cebeSEric Cheng     flow_fields_buf_t *fbuf)
501da14cebeSEric Cheng {
502da14cebeSEric Cheng 	char		link[MAXLINKNAMELEN];
503da14cebeSEric Cheng 	dladm_status_t	status;
504da14cebeSEric Cheng 
5054ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, attr->fa_linkid, NULL,
5064ac67f02SAnurag S. Maskey 	    NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
507da14cebeSEric Cheng 		return (status);
508da14cebeSEric Cheng 	}
509da14cebeSEric Cheng 
510da14cebeSEric Cheng 	(void) snprintf(fbuf->flow_name, sizeof (fbuf->flow_name),
511da14cebeSEric Cheng 	    "%s", attr->fa_flowname);
512da14cebeSEric Cheng 	(void) snprintf(fbuf->flow_link, sizeof (fbuf->flow_link),
513da14cebeSEric Cheng 	    "%s", link);
514da14cebeSEric Cheng 
515da14cebeSEric Cheng 	(void) dladm_flow_attr_ip2str(attr, fbuf->flow_ipaddr,
516da14cebeSEric Cheng 	    sizeof (fbuf->flow_ipaddr));
517da14cebeSEric Cheng 	(void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto,
518da14cebeSEric Cheng 	    sizeof (fbuf->flow_proto));
51925ec3e3dSEric Cheng 	if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL) != 0) {
52025ec3e3dSEric Cheng 		(void) dladm_flow_attr_port2str(attr, fbuf->flow_lport,
52125ec3e3dSEric Cheng 		    sizeof (fbuf->flow_lport));
52225ec3e3dSEric Cheng 	}
52325ec3e3dSEric Cheng 	if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE) != 0) {
52425ec3e3dSEric Cheng 		(void) dladm_flow_attr_port2str(attr, fbuf->flow_rport,
52525ec3e3dSEric Cheng 		    sizeof (fbuf->flow_rport));
52625ec3e3dSEric Cheng 	}
527da14cebeSEric Cheng 	(void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield,
528da14cebeSEric Cheng 	    sizeof (fbuf->flow_dsfield));
529da14cebeSEric Cheng 
530da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
531da14cebeSEric Cheng }
532da14cebeSEric Cheng 
533da14cebeSEric Cheng /*
534da14cebeSEric Cheng  * Walker function for showing flow attributes through dladm_walk_flow().
535da14cebeSEric Cheng  */
536c3affd82SMichael Lim /*ARGSUSED*/
537da14cebeSEric Cheng static int
538c3affd82SMichael Lim show_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
539da14cebeSEric Cheng {
540da14cebeSEric Cheng 	show_flow_state_t	*statep = arg;
541da14cebeSEric Cheng 	dladm_status_t		status;
542da14cebeSEric Cheng 	flow_fields_buf_t	fbuf;
543da14cebeSEric Cheng 
544da14cebeSEric Cheng 	/*
545da14cebeSEric Cheng 	 * first get all the flow attributes into fbuf;
546da14cebeSEric Cheng 	 */
547da14cebeSEric Cheng 	bzero(&fbuf, sizeof (fbuf));
548da14cebeSEric Cheng 	status = print_flow(statep, attr, &fbuf);
549da14cebeSEric Cheng 
550da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
551da14cebeSEric Cheng 		goto done;
552da14cebeSEric Cheng 
5538002d411SSowmini Varadhan 	ofmt_print(statep->fs_ofmt, (void *)&fbuf);
554da14cebeSEric Cheng 
555da14cebeSEric Cheng done:
556da14cebeSEric Cheng 	statep->fs_status = status;
557da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
558da14cebeSEric Cheng }
559da14cebeSEric Cheng 
560da14cebeSEric Cheng static void
561da14cebeSEric Cheng show_one_flow(void *arg, const char *name)
562da14cebeSEric Cheng {
563da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
564da14cebeSEric Cheng 
5654ac67f02SAnurag S. Maskey 	if (dladm_flow_info(handle, name, &attr) != DLADM_STATUS_OK)
566da14cebeSEric Cheng 		die("invalid flow: '%s'", name);
567da14cebeSEric Cheng 	else
568c3affd82SMichael Lim 		(void) show_flow(handle, &attr, arg);
569da14cebeSEric Cheng }
570da14cebeSEric Cheng 
571da14cebeSEric Cheng /*
572da14cebeSEric Cheng  * Wrapper of dladm_walk_flow(show_flow,...) to make it usable to
573da14cebeSEric Cheng  * dladm_walk_datalink_id(). Used for showing flow attributes for
574da14cebeSEric Cheng  * all flows on all links.
575da14cebeSEric Cheng  */
576da14cebeSEric Cheng static int
5774ac67f02SAnurag S. Maskey show_flows_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg)
578da14cebeSEric Cheng {
579da14cebeSEric Cheng 	show_flow_state_t *state = arg;
580da14cebeSEric Cheng 
5814ac67f02SAnurag S. Maskey 	(void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist);
582da14cebeSEric Cheng 
583da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
584da14cebeSEric Cheng }
585da14cebeSEric Cheng 
586da14cebeSEric Cheng static void
587da14cebeSEric Cheng do_show_flow(int argc, char *argv[])
588da14cebeSEric Cheng {
589da000602SGirish Moodalbail 	char			flowname[MAXFLOWNAMELEN];
590da000602SGirish Moodalbail 	char			linkname[MAXLINKNAMELEN];
591da14cebeSEric Cheng 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
592da14cebeSEric Cheng 	int			option;
593da14cebeSEric Cheng 	boolean_t		l_arg = B_FALSE;
594da14cebeSEric Cheng 	boolean_t		o_arg = B_FALSE;
595da14cebeSEric Cheng 	show_flow_state_t	state;
596da14cebeSEric Cheng 	char			*fields_str = NULL;
5978002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
5988002d411SSowmini Varadhan 	ofmt_status_t		oferr;
5998002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
600da14cebeSEric Cheng 
601da14cebeSEric Cheng 	bzero(&state, sizeof (state));
602da14cebeSEric Cheng 
603da14cebeSEric Cheng 	opterr = 0;
604*0dc2366fSVenugopal Iyer 	while ((option = getopt_long(argc, argv, ":pPl:o:",
605da14cebeSEric Cheng 	    longopts, NULL)) != -1) {
606da14cebeSEric Cheng 		switch (option) {
607da14cebeSEric Cheng 		case 'p':
6088002d411SSowmini Varadhan 			state.fs_parsable = B_TRUE;
6098002d411SSowmini Varadhan 			ofmtflags |= OFMT_PARSABLE;
610da14cebeSEric Cheng 			break;
611da14cebeSEric Cheng 		case 'P':
612da14cebeSEric Cheng 			state.fs_persist = B_TRUE;
613da14cebeSEric Cheng 			break;
614da14cebeSEric Cheng 		case 'o':
615da14cebeSEric Cheng 			if (o_arg)
616da14cebeSEric Cheng 				die_optdup(option);
617da14cebeSEric Cheng 
618da14cebeSEric Cheng 			o_arg = B_TRUE;
619da14cebeSEric Cheng 			fields_str = optarg;
620da14cebeSEric Cheng 			break;
621da14cebeSEric Cheng 		case 'l':
622da14cebeSEric Cheng 			if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
623da14cebeSEric Cheng 			    >= MAXLINKNAMELEN)
624da14cebeSEric Cheng 				die("link name too long\n");
6254ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, linkname, &linkid, NULL,
626da14cebeSEric Cheng 			    NULL, NULL) != DLADM_STATUS_OK)
627da14cebeSEric Cheng 				die("invalid link '%s'", linkname);
628da14cebeSEric Cheng 			l_arg = B_TRUE;
629da14cebeSEric Cheng 			break;
630da14cebeSEric Cheng 		default:
631da14cebeSEric Cheng 			die_opterr(optopt, option);
632da14cebeSEric Cheng 			break;
633da14cebeSEric Cheng 		}
634da14cebeSEric Cheng 	}
635da14cebeSEric Cheng 
636da14cebeSEric Cheng 	/* get flow name (optional last argument */
637da14cebeSEric Cheng 	if (optind == (argc-1)) {
638da000602SGirish Moodalbail 		if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
639da000602SGirish Moodalbail 		    >= MAXFLOWNAMELEN)
640da14cebeSEric Cheng 			die("flow name too long");
641da14cebeSEric Cheng 		state.fs_flow = flowname;
642da14cebeSEric Cheng 	}
643da14cebeSEric Cheng 
6448002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, flow_fields, ofmtflags, 0, &ofmt);
6458002d411SSowmini Varadhan 	flowadm_ofmt_check(oferr, state.fs_parsable, ofmt);
6468002d411SSowmini Varadhan 	state.fs_ofmt = ofmt;
647da14cebeSEric Cheng 
648da14cebeSEric Cheng 	/* Show attributes of one flow */
649da14cebeSEric Cheng 	if (state.fs_flow != NULL) {
650da14cebeSEric Cheng 		show_one_flow(&state, state.fs_flow);
651da14cebeSEric Cheng 
652da14cebeSEric Cheng 	/* Show attributes of flows on one link */
653da14cebeSEric Cheng 	} else if (l_arg) {
6544ac67f02SAnurag S. Maskey 		(void) show_flows_onelink(handle, linkid, &state);
655da14cebeSEric Cheng 
656da14cebeSEric Cheng 	/* Show attributes of all flows on all links */
657da14cebeSEric Cheng 	} else {
6584ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_flows_onelink, handle,
6594ac67f02SAnurag S. Maskey 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
660da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
661da14cebeSEric Cheng 	}
6628002d411SSowmini Varadhan 	ofmt_close(ofmt);
663da14cebeSEric Cheng }
664da14cebeSEric Cheng 
665da14cebeSEric Cheng static dladm_status_t
666da14cebeSEric Cheng set_flowprop_persist(const char *flow, const char *prop_name, char **prop_val,
667da14cebeSEric Cheng     uint_t val_cnt, boolean_t reset)
668da14cebeSEric Cheng {
669da14cebeSEric Cheng 	dladm_status_t	status;
670da14cebeSEric Cheng 	char		*errprop;
671da14cebeSEric Cheng 
6724ac67f02SAnurag S. Maskey 	status = dladm_set_flowprop(handle, flow, prop_name, prop_val, val_cnt,
673da14cebeSEric Cheng 	    DLADM_OPT_PERSIST, &errprop);
674da14cebeSEric Cheng 
675da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
676da14cebeSEric Cheng 		warn_dlerr(status, "cannot persistently %s flow "
677da14cebeSEric Cheng 		    "property '%s' on '%s'", reset? "reset": "set",
678da14cebeSEric Cheng 		    errprop, flow);
679da14cebeSEric Cheng 	}
680da14cebeSEric Cheng 	return (status);
681da14cebeSEric Cheng }
682da14cebeSEric Cheng 
683da14cebeSEric Cheng static void
684da14cebeSEric Cheng set_flowprop(int argc, char **argv, boolean_t reset)
685da14cebeSEric Cheng {
686da14cebeSEric Cheng 	int			i, option;
687da14cebeSEric Cheng 	char			errmsg[DLADM_STRSIZE];
688da14cebeSEric Cheng 	const char		*flow = NULL;
68963a6526dSMichael Lim 	char			propstr[DLADM_STRSIZE];
690da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
691da14cebeSEric Cheng 	boolean_t		temp = B_FALSE;
692da14cebeSEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
693da14cebeSEric Cheng 
694da14cebeSEric Cheng 	opterr = 0;
69563a6526dSMichael Lim 	bzero(propstr, DLADM_STRSIZE);
69663a6526dSMichael Lim 
697da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":p:R:t",
698da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
699da14cebeSEric Cheng 		switch (option) {
700da14cebeSEric Cheng 		case 'p':
70163a6526dSMichael Lim 			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
70263a6526dSMichael Lim 			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
70363a6526dSMichael Lim 			    DLADM_STRSIZE)
70463a6526dSMichael Lim 				die("property list too long '%s'", propstr);
705da14cebeSEric Cheng 			break;
706da14cebeSEric Cheng 		case 't':
707da14cebeSEric Cheng 			temp = B_TRUE;
708da14cebeSEric Cheng 			break;
709da14cebeSEric Cheng 		case 'R':
710da14cebeSEric Cheng 			status = dladm_set_rootdir(optarg);
711da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK) {
712da14cebeSEric Cheng 				die_dlerr(status, "invalid directory "
713da14cebeSEric Cheng 				    "specified");
714da14cebeSEric Cheng 			}
715da14cebeSEric Cheng 			break;
716da14cebeSEric Cheng 		default:
717da14cebeSEric Cheng 			die_opterr(optopt, option);
718da14cebeSEric Cheng 			break;
719da14cebeSEric Cheng 		}
720da14cebeSEric Cheng 	}
721da14cebeSEric Cheng 
722da14cebeSEric Cheng 	if (optind == (argc - 1)) {
723da000602SGirish Moodalbail 		if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
724da14cebeSEric Cheng 			die("flow name too long");
725da14cebeSEric Cheng 		flow = argv[optind];
726da14cebeSEric Cheng 	} else if (optind != argc) {
727da14cebeSEric Cheng 		usage();
728da14cebeSEric Cheng 	}
729da14cebeSEric Cheng 	if (flow == NULL)
730da14cebeSEric Cheng 		die("flow name must be specified");
731da14cebeSEric Cheng 
73263a6526dSMichael Lim 	if (dladm_parse_flow_props(propstr, &proplist, reset)
73363a6526dSMichael Lim 	    != DLADM_STATUS_OK)
73463a6526dSMichael Lim 		die("invalid flow property specified");
73563a6526dSMichael Lim 
736da14cebeSEric Cheng 	if (proplist == NULL) {
737da14cebeSEric Cheng 		char *errprop;
738da14cebeSEric Cheng 
739da14cebeSEric Cheng 		if (!reset)
740da14cebeSEric Cheng 			die("flow property must be specified");
741da14cebeSEric Cheng 
7424ac67f02SAnurag S. Maskey 		status = dladm_set_flowprop(handle, flow, NULL, NULL, 0,
743da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE, &errprop);
744da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK) {
745da14cebeSEric Cheng 			warn_dlerr(status, "cannot reset flow property '%s' "
746da14cebeSEric Cheng 			    "on '%s'", errprop, flow);
747da14cebeSEric Cheng 		}
748da14cebeSEric Cheng 		if (!temp) {
749da14cebeSEric Cheng 			dladm_status_t	s;
750da14cebeSEric Cheng 
751da14cebeSEric Cheng 			s = set_flowprop_persist(flow, NULL, NULL, 0, reset);
752da14cebeSEric Cheng 			if (s != DLADM_STATUS_OK)
753da14cebeSEric Cheng 				status = s;
754da14cebeSEric Cheng 		}
755da14cebeSEric Cheng 		goto done;
756da14cebeSEric Cheng 	}
757da14cebeSEric Cheng 
758da14cebeSEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
759da14cebeSEric Cheng 		dladm_arg_info_t	*aip = &proplist->al_info[i];
760da14cebeSEric Cheng 		char		**val;
761da14cebeSEric Cheng 		uint_t		count;
762da14cebeSEric Cheng 		dladm_status_t	s;
763da14cebeSEric Cheng 
764da14cebeSEric Cheng 		if (reset) {
765da14cebeSEric Cheng 			val = NULL;
766da14cebeSEric Cheng 			count = 0;
767da14cebeSEric Cheng 		} else {
768da14cebeSEric Cheng 			val = aip->ai_val;
769da14cebeSEric Cheng 			count = aip->ai_count;
770da14cebeSEric Cheng 			if (count == 0) {
771da14cebeSEric Cheng 				warn("no value specified for '%s'",
772da14cebeSEric Cheng 				    aip->ai_name);
773da14cebeSEric Cheng 				status = DLADM_STATUS_BADARG;
774da14cebeSEric Cheng 				continue;
775da14cebeSEric Cheng 			}
776da14cebeSEric Cheng 		}
7774ac67f02SAnurag S. Maskey 		s = dladm_set_flowprop(handle, flow, aip->ai_name, val, count,
778da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE, NULL);
779da14cebeSEric Cheng 		if (s == DLADM_STATUS_OK) {
780da14cebeSEric Cheng 			if (!temp) {
781da14cebeSEric Cheng 				s = set_flowprop_persist(flow,
782da14cebeSEric Cheng 				    aip->ai_name, val, count, reset);
783da14cebeSEric Cheng 				if (s != DLADM_STATUS_OK)
784da14cebeSEric Cheng 					status = s;
785da14cebeSEric Cheng 			}
786da14cebeSEric Cheng 			continue;
787da14cebeSEric Cheng 		}
788da14cebeSEric Cheng 		status = s;
789da14cebeSEric Cheng 		switch (s) {
790da14cebeSEric Cheng 		case DLADM_STATUS_NOTFOUND:
791da14cebeSEric Cheng 			warn("invalid flow property '%s'", aip->ai_name);
792da14cebeSEric Cheng 			break;
793da14cebeSEric Cheng 		case DLADM_STATUS_BADVAL: {
794da14cebeSEric Cheng 			int		j;
795da14cebeSEric Cheng 			char		*ptr, *lim;
796da14cebeSEric Cheng 			char		**propvals = NULL;
797da14cebeSEric Cheng 			uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
798da14cebeSEric Cheng 
799da14cebeSEric Cheng 			ptr = malloc((sizeof (char *) +
800da14cebeSEric Cheng 			    DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
801da14cebeSEric Cheng 			    MAX_PROP_LINE);
802da14cebeSEric Cheng 
803da14cebeSEric Cheng 			if (ptr == NULL)
804da14cebeSEric Cheng 				die("insufficient memory");
805da14cebeSEric Cheng 			propvals = (char **)(void *)ptr;
806da14cebeSEric Cheng 
807da14cebeSEric Cheng 			for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
808da14cebeSEric Cheng 				propvals[j] = ptr + sizeof (char *) *
809da14cebeSEric Cheng 				    DLADM_MAX_PROP_VALCNT +
810da14cebeSEric Cheng 				    j * DLADM_PROP_VAL_MAX;
811da14cebeSEric Cheng 			}
8124ac67f02SAnurag S. Maskey 			s = dladm_get_flowprop(handle, flow,
8134ac67f02SAnurag S. Maskey 			    DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
8144ac67f02SAnurag S. Maskey 			    &valcnt);
815da14cebeSEric Cheng 
816da14cebeSEric Cheng 			ptr = errmsg;
817da14cebeSEric Cheng 			lim = ptr + DLADM_STRSIZE;
818da14cebeSEric Cheng 			*ptr = '\0';
819da14cebeSEric Cheng 			for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
820da14cebeSEric Cheng 				ptr += snprintf(ptr, lim - ptr, "%s,",
821da14cebeSEric Cheng 				    propvals[j]);
822da14cebeSEric Cheng 				if (ptr >= lim)
823da14cebeSEric Cheng 					break;
824da14cebeSEric Cheng 			}
825da14cebeSEric Cheng 			if (ptr > errmsg) {
826da14cebeSEric Cheng 				*(ptr - 1) = '\0';
827da14cebeSEric Cheng 				warn("flow property '%s' must be one of: %s",
828da14cebeSEric Cheng 				    aip->ai_name, errmsg);
829da14cebeSEric Cheng 			} else
830da14cebeSEric Cheng 				warn("%s is an invalid value for "
831da14cebeSEric Cheng 				    "flow property %s", *val, aip->ai_name);
832da14cebeSEric Cheng 			free(propvals);
833da14cebeSEric Cheng 			break;
834da14cebeSEric Cheng 		}
835da14cebeSEric Cheng 		default:
836da14cebeSEric Cheng 			if (reset) {
837da14cebeSEric Cheng 				warn_dlerr(status, "cannot reset flow property "
838da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, flow);
839da14cebeSEric Cheng 			} else {
840da14cebeSEric Cheng 				warn_dlerr(status, "cannot set flow property "
841da14cebeSEric Cheng 				    "'%s' on '%s'", aip->ai_name, flow);
842da14cebeSEric Cheng 			}
843da14cebeSEric Cheng 			break;
844da14cebeSEric Cheng 		}
845da14cebeSEric Cheng 	}
846da14cebeSEric Cheng done:
847da14cebeSEric Cheng 	dladm_free_props(proplist);
8484ac67f02SAnurag S. Maskey 	if (status != DLADM_STATUS_OK) {
8494ac67f02SAnurag S. Maskey 		dladm_close(handle);
850ad091ee1SMichael Lim 		exit(EXIT_FAILURE);
851da14cebeSEric Cheng 	}
8524ac67f02SAnurag S. Maskey }
853da14cebeSEric Cheng 
854da14cebeSEric Cheng static void
855da14cebeSEric Cheng do_set_flowprop(int argc, char **argv)
856da14cebeSEric Cheng {
857da14cebeSEric Cheng 	set_flowprop(argc, argv, B_FALSE);
858da14cebeSEric Cheng }
859da14cebeSEric Cheng 
860da14cebeSEric Cheng static void
861da14cebeSEric Cheng do_reset_flowprop(int argc, char **argv)
862da14cebeSEric Cheng {
863da14cebeSEric Cheng 	set_flowprop(argc, argv, B_TRUE);
864da14cebeSEric Cheng }
865da14cebeSEric Cheng 
866da14cebeSEric Cheng static void
867da14cebeSEric Cheng warn(const char *format, ...)
868da14cebeSEric Cheng {
869da14cebeSEric Cheng 	va_list alist;
870da14cebeSEric Cheng 
871da14cebeSEric Cheng 	format = gettext(format);
872da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: warning: ", progname);
873da14cebeSEric Cheng 
874da14cebeSEric Cheng 	va_start(alist, format);
875da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
876da14cebeSEric Cheng 	va_end(alist);
877da14cebeSEric Cheng 
878*0dc2366fSVenugopal Iyer 	(void) putc('\n', stderr);
879da14cebeSEric Cheng }
880da14cebeSEric Cheng 
881da14cebeSEric Cheng /* PRINTFLIKE2 */
882da14cebeSEric Cheng static void
883da14cebeSEric Cheng warn_dlerr(dladm_status_t err, const char *format, ...)
884da14cebeSEric Cheng {
885da14cebeSEric Cheng 	va_list alist;
886da14cebeSEric Cheng 	char    errmsg[DLADM_STRSIZE];
887da14cebeSEric Cheng 
888da14cebeSEric Cheng 	format = gettext(format);
889da14cebeSEric Cheng 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
890da14cebeSEric Cheng 
891da14cebeSEric Cheng 	va_start(alist, format);
892da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
893da14cebeSEric Cheng 	va_end(alist);
894da14cebeSEric Cheng 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
895da14cebeSEric Cheng }
896da14cebeSEric Cheng 
897da14cebeSEric Cheng /* PRINTFLIKE1 */
898da14cebeSEric Cheng static void
899da14cebeSEric Cheng die(const char *format, ...)
900da14cebeSEric Cheng {
901da14cebeSEric Cheng 	va_list alist;
902da14cebeSEric Cheng 
903da14cebeSEric Cheng 	format = gettext(format);
904da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: ", progname);
905da14cebeSEric Cheng 
906da14cebeSEric Cheng 	va_start(alist, format);
907da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
908da14cebeSEric Cheng 	va_end(alist);
909da14cebeSEric Cheng 
910*0dc2366fSVenugopal Iyer 	(void) putc('\n', stderr);
9114ac67f02SAnurag S. Maskey 
9124ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
9134ac67f02SAnurag S. Maskey 	if (handle != NULL)
9144ac67f02SAnurag S. Maskey 		dladm_close(handle);
9154ac67f02SAnurag S. Maskey 
916da14cebeSEric Cheng 	exit(EXIT_FAILURE);
917da14cebeSEric Cheng }
918da14cebeSEric Cheng 
919da14cebeSEric Cheng static void
920da14cebeSEric Cheng die_optdup(int opt)
921da14cebeSEric Cheng {
922da14cebeSEric Cheng 	die("the option -%c cannot be specified more than once", opt);
923da14cebeSEric Cheng }
924da14cebeSEric Cheng 
925da14cebeSEric Cheng static void
926da14cebeSEric Cheng die_opterr(int opt, int opterr)
927da14cebeSEric Cheng {
928da14cebeSEric Cheng 	switch (opterr) {
929da14cebeSEric Cheng 	case ':':
930da14cebeSEric Cheng 		die("option '-%c' requires a value", opt);
931da14cebeSEric Cheng 		break;
932da14cebeSEric Cheng 	case '?':
933da14cebeSEric Cheng 	default:
934da14cebeSEric Cheng 		die("unrecognized option '-%c'", opt);
935da14cebeSEric Cheng 		break;
936da14cebeSEric Cheng 	}
937da14cebeSEric Cheng }
938da14cebeSEric Cheng 
939da14cebeSEric Cheng /* PRINTFLIKE2 */
940da14cebeSEric Cheng static void
941da14cebeSEric Cheng die_dlerr(dladm_status_t err, const char *format, ...)
942da14cebeSEric Cheng {
943da14cebeSEric Cheng 	va_list alist;
944da14cebeSEric Cheng 	char	errmsg[DLADM_STRSIZE];
945da14cebeSEric Cheng 
946da14cebeSEric Cheng 	format = gettext(format);
947da14cebeSEric Cheng 	(void) fprintf(stderr, "%s: ", progname);
948da14cebeSEric Cheng 
949da14cebeSEric Cheng 	va_start(alist, format);
950da14cebeSEric Cheng 	(void) vfprintf(stderr, format, alist);
951da14cebeSEric Cheng 	va_end(alist);
952da14cebeSEric Cheng 	(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
953da14cebeSEric Cheng 
9544ac67f02SAnurag S. Maskey 	/* close dladm handle if it was opened */
9554ac67f02SAnurag S. Maskey 	if (handle != NULL)
9564ac67f02SAnurag S. Maskey 		dladm_close(handle);
9574ac67f02SAnurag S. Maskey 
958da14cebeSEric Cheng 	exit(EXIT_FAILURE);
959da14cebeSEric Cheng }
960da14cebeSEric Cheng 
961da14cebeSEric Cheng static void
962da14cebeSEric Cheng print_flowprop(const char *flowname, show_flowprop_state_t *statep,
963da14cebeSEric Cheng     const char *propname, dladm_prop_type_t type,
964da14cebeSEric Cheng     const char *format, char **pptr)
965da14cebeSEric Cheng {
966da14cebeSEric Cheng 	int		i;
967da14cebeSEric Cheng 	char		*ptr, *lim;
968da14cebeSEric Cheng 	char		buf[DLADM_STRSIZE];
969da14cebeSEric Cheng 	char		*unknown = "--", *notsup = "";
970da14cebeSEric Cheng 	char		**propvals = statep->fs_propvals;
971da14cebeSEric Cheng 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
972da14cebeSEric Cheng 	dladm_status_t	status;
973da14cebeSEric Cheng 
9744ac67f02SAnurag S. Maskey 	status = dladm_get_flowprop(handle, flowname, type, propname, propvals,
975da14cebeSEric Cheng 	    &valcnt);
976da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK) {
977da14cebeSEric Cheng 		if (status == DLADM_STATUS_TEMPONLY) {
978da14cebeSEric Cheng 			if (type == DLADM_PROP_VAL_MODIFIABLE &&
979da14cebeSEric Cheng 			    statep->fs_persist) {
980da14cebeSEric Cheng 				valcnt = 1;
981da14cebeSEric Cheng 				propvals = &unknown;
982da14cebeSEric Cheng 			} else {
983da14cebeSEric Cheng 				statep->fs_status = status;
984da14cebeSEric Cheng 				statep->fs_retstatus = status;
985da14cebeSEric Cheng 				return;
986da14cebeSEric Cheng 			}
987da14cebeSEric Cheng 		} else if (status == DLADM_STATUS_NOTSUP ||
988da14cebeSEric Cheng 		    statep->fs_persist) {
989da14cebeSEric Cheng 			valcnt = 1;
990da14cebeSEric Cheng 			if (type == DLADM_PROP_VAL_CURRENT)
991da14cebeSEric Cheng 				propvals = &unknown;
992da14cebeSEric Cheng 			else
993da14cebeSEric Cheng 				propvals = &notsup;
994da14cebeSEric Cheng 		} else {
995da14cebeSEric Cheng 			if ((statep->fs_proplist != NULL) &&
996da14cebeSEric Cheng 			    statep->fs_status == DLADM_STATUS_OK) {
997da14cebeSEric Cheng 				warn("invalid flow property '%s'", propname);
998da14cebeSEric Cheng 			}
999da14cebeSEric Cheng 			statep->fs_status = status;
1000da14cebeSEric Cheng 			statep->fs_retstatus = status;
1001da14cebeSEric Cheng 			return;
1002da14cebeSEric Cheng 		}
1003da14cebeSEric Cheng 	}
1004da14cebeSEric Cheng 
1005da14cebeSEric Cheng 	statep->fs_status = DLADM_STATUS_OK;
1006da14cebeSEric Cheng 
1007da14cebeSEric Cheng 	ptr = buf;
1008da14cebeSEric Cheng 	lim = buf + DLADM_STRSIZE;
1009da14cebeSEric Cheng 	for (i = 0; i < valcnt; i++) {
10108002d411SSowmini Varadhan 		if (propvals[i][0] == '\0' && !statep->fs_parsable)
10118002d411SSowmini Varadhan 			ptr += snprintf(ptr, lim - ptr, "--,");
1012da14cebeSEric Cheng 		else
1013da14cebeSEric Cheng 			ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
1014da14cebeSEric Cheng 		if (ptr >= lim)
1015da14cebeSEric Cheng 			break;
1016da14cebeSEric Cheng 	}
1017da14cebeSEric Cheng 	if (valcnt > 0)
1018da14cebeSEric Cheng 		buf[strlen(buf) - 1] = '\0';
1019da14cebeSEric Cheng 
1020da14cebeSEric Cheng 	lim = statep->fs_line + MAX_PROP_LINE;
10218002d411SSowmini Varadhan 	if (statep->fs_parsable) {
1022da14cebeSEric Cheng 		*pptr += snprintf(*pptr, lim - *pptr,
1023da14cebeSEric Cheng 		    "%s", buf);
1024da14cebeSEric Cheng 	} else {
1025da14cebeSEric Cheng 		*pptr += snprintf(*pptr, lim - *pptr, format, buf);
1026da14cebeSEric Cheng 	}
1027da14cebeSEric Cheng }
1028da14cebeSEric Cheng 
10298002d411SSowmini Varadhan static boolean_t
10308002d411SSowmini Varadhan print_flowprop_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1031da14cebeSEric Cheng {
10328002d411SSowmini Varadhan 	flowprop_args_t		*arg = of_arg->ofmt_cbarg;
1033da14cebeSEric Cheng 	char 			*propname = arg->fs_propname;
1034da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg->fs_state;
1035da14cebeSEric Cheng 	char			*ptr = statep->fs_line;
1036da14cebeSEric Cheng 	char			*lim = ptr + MAX_PROP_LINE;
1037da14cebeSEric Cheng 	char			*flowname = arg->fs_flowname;
1038da14cebeSEric Cheng 
10398002d411SSowmini Varadhan 	switch (of_arg->ofmt_id) {
1040da14cebeSEric Cheng 	case FLOWPROP_FLOW:
1041da14cebeSEric Cheng 		(void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow);
1042da14cebeSEric Cheng 		break;
1043da14cebeSEric Cheng 	case FLOWPROP_PROPERTY:
1044da14cebeSEric Cheng 		(void) snprintf(ptr, lim - ptr, "%s", propname);
1045da14cebeSEric Cheng 		break;
1046da14cebeSEric Cheng 	case FLOWPROP_VALUE:
1047da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1048da14cebeSEric Cheng 		    statep->fs_persist ? DLADM_PROP_VAL_PERSISTENT :
1049da14cebeSEric Cheng 		    DLADM_PROP_VAL_CURRENT, "%s", &ptr);
1050da14cebeSEric Cheng 		/*
1051da14cebeSEric Cheng 		 * If we failed to query the flow property, for example, query
1052da14cebeSEric Cheng 		 * the persistent value of a non-persistable flow property,
1053da14cebeSEric Cheng 		 * simply skip the output.
1054da14cebeSEric Cheng 		 */
1055da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1056da14cebeSEric Cheng 			goto skip;
1057da14cebeSEric Cheng 		ptr = statep->fs_line;
1058da14cebeSEric Cheng 		break;
1059da14cebeSEric Cheng 	case FLOWPROP_DEFAULT:
1060da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1061da14cebeSEric Cheng 		    DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
1062da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1063da14cebeSEric Cheng 			goto skip;
1064da14cebeSEric Cheng 		ptr = statep->fs_line;
1065da14cebeSEric Cheng 		break;
1066da14cebeSEric Cheng 	case FLOWPROP_POSSIBLE:
1067da14cebeSEric Cheng 		print_flowprop(flowname, statep, propname,
1068da14cebeSEric Cheng 		    DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
1069da14cebeSEric Cheng 		if (statep->fs_status != DLADM_STATUS_OK)
1070da14cebeSEric Cheng 			goto skip;
1071da14cebeSEric Cheng 		ptr = statep->fs_line;
1072da14cebeSEric Cheng 		break;
1073da14cebeSEric Cheng 	default:
1074da14cebeSEric Cheng 		die("invalid input");
1075da14cebeSEric Cheng 		break;
1076da14cebeSEric Cheng 	}
10778002d411SSowmini Varadhan 	(void) strlcpy(buf, ptr, bufsize);
10788002d411SSowmini Varadhan 	return (B_TRUE);
1079da14cebeSEric Cheng skip:
10808002d411SSowmini Varadhan 	buf[0] = '\0';
10818002d411SSowmini Varadhan 	return ((statep->fs_status == DLADM_STATUS_OK) ?
10828002d411SSowmini Varadhan 	    B_TRUE : B_FALSE);
1083da14cebeSEric Cheng }
1084da14cebeSEric Cheng 
1085da14cebeSEric Cheng static int
1086da14cebeSEric Cheng show_one_flowprop(void *arg, const char *propname)
1087da14cebeSEric Cheng {
1088da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg;
1089da14cebeSEric Cheng 	flowprop_args_t		fs_arg;
1090da14cebeSEric Cheng 
1091da14cebeSEric Cheng 	bzero(&fs_arg, sizeof (fs_arg));
1092da14cebeSEric Cheng 	fs_arg.fs_state = statep;
1093da14cebeSEric Cheng 	fs_arg.fs_propname = (char *)propname;
1094da14cebeSEric Cheng 	fs_arg.fs_flowname = (char *)statep->fs_flow;
1095da14cebeSEric Cheng 
10968002d411SSowmini Varadhan 	ofmt_print(statep->fs_ofmt, (void *)&fs_arg);
1097da14cebeSEric Cheng 
1098da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1099da14cebeSEric Cheng }
1100da14cebeSEric Cheng 
1101c3affd82SMichael Lim /*ARGSUSED*/
1102da14cebeSEric Cheng /* Walker function called by dladm_walk_flow to display flow properties */
1103da14cebeSEric Cheng static int
1104c3affd82SMichael Lim show_flowprop(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
1105da14cebeSEric Cheng {
1106da14cebeSEric Cheng 	show_flowprop_one_flow(arg, attr->fa_flowname);
1107da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1108da14cebeSEric Cheng }
1109da14cebeSEric Cheng 
1110da14cebeSEric Cheng /*
1111da14cebeSEric Cheng  * Wrapper of dladm_walk_flow(show_walk_fn,...) to make it
1112da14cebeSEric Cheng  * usable to dladm_walk_datalink_id()
1113da14cebeSEric Cheng  */
1114da14cebeSEric Cheng static int
11154ac67f02SAnurag S. Maskey show_flowprop_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1116da14cebeSEric Cheng {
1117da14cebeSEric Cheng 	char	name[MAXLINKNAMELEN];
1118da14cebeSEric Cheng 
11194ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, name,
11204ac67f02SAnurag S. Maskey 	    sizeof (name)) != DLADM_STATUS_OK)
1121da14cebeSEric Cheng 		return (DLADM_WALK_TERMINATE);
1122da14cebeSEric Cheng 
11234ac67f02SAnurag S. Maskey 	(void) dladm_walk_flow(show_flowprop, dh, linkid, arg, B_FALSE);
1124da14cebeSEric Cheng 
1125da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
1126da14cebeSEric Cheng }
1127da14cebeSEric Cheng 
1128da14cebeSEric Cheng static void
1129da14cebeSEric Cheng do_show_flowprop(int argc, char **argv)
1130da14cebeSEric Cheng {
1131da14cebeSEric Cheng 	int			option;
1132da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1133da14cebeSEric Cheng 	show_flowprop_state_t	state;
1134da14cebeSEric Cheng 	char			*fields_str = NULL;
11358002d411SSowmini Varadhan 	ofmt_handle_t		ofmt;
11368002d411SSowmini Varadhan 	ofmt_status_t		oferr;
11378002d411SSowmini Varadhan 	uint_t			ofmtflags = 0;
1138da14cebeSEric Cheng 
1139da14cebeSEric Cheng 	opterr = 0;
1140da14cebeSEric Cheng 	state.fs_propvals = NULL;
1141da14cebeSEric Cheng 	state.fs_line = NULL;
11428002d411SSowmini Varadhan 	state.fs_parsable = B_FALSE;
1143da14cebeSEric Cheng 	state.fs_persist = B_FALSE;
1144da14cebeSEric Cheng 	state.fs_header = B_TRUE;
1145da14cebeSEric Cheng 	state.fs_retstatus = DLADM_STATUS_OK;
1146da14cebeSEric Cheng 	state.fs_linkid = DATALINK_INVALID_LINKID;
1147da14cebeSEric Cheng 	state.fs_flow = NULL;
1148da14cebeSEric Cheng 
1149da14cebeSEric Cheng 	while ((option = getopt_long(argc, argv, ":p:cPl:o:",
1150da14cebeSEric Cheng 	    prop_longopts, NULL)) != -1) {
1151da14cebeSEric Cheng 		switch (option) {
1152da14cebeSEric Cheng 		case 'p':
1153da14cebeSEric Cheng 			if (dladm_parse_flow_props(optarg, &proplist, B_TRUE)
1154da14cebeSEric Cheng 			    != DLADM_STATUS_OK)
1155da14cebeSEric Cheng 				die("invalid flow properties specified");
1156da14cebeSEric Cheng 			break;
1157da14cebeSEric Cheng 		case 'c':
11588002d411SSowmini Varadhan 			state.fs_parsable = B_TRUE;
11598002d411SSowmini Varadhan 			ofmtflags |= OFMT_PARSABLE;
1160da14cebeSEric Cheng 			break;
1161da14cebeSEric Cheng 		case 'P':
1162da14cebeSEric Cheng 			state.fs_persist = B_TRUE;
1163da14cebeSEric Cheng 			break;
1164da14cebeSEric Cheng 		case 'l':
11654ac67f02SAnurag S. Maskey 			if (dladm_name2info(handle, optarg, &state.fs_linkid,
1166da14cebeSEric Cheng 			    NULL, NULL, NULL) != DLADM_STATUS_OK)
1167da14cebeSEric Cheng 				die("invalid link '%s'", optarg);
1168da14cebeSEric Cheng 			break;
1169da14cebeSEric Cheng 		case 'o':
1170da14cebeSEric Cheng 			fields_str = optarg;
1171da14cebeSEric Cheng 			break;
1172da14cebeSEric Cheng 		default:
1173da14cebeSEric Cheng 			die_opterr(optopt, option);
1174da14cebeSEric Cheng 			break;
1175da14cebeSEric Cheng 		}
1176da14cebeSEric Cheng 	}
1177da14cebeSEric Cheng 
1178da14cebeSEric Cheng 	if (optind == (argc - 1)) {
1179da000602SGirish Moodalbail 		if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
1180da14cebeSEric Cheng 			die("flow name too long");
1181da14cebeSEric Cheng 		state.fs_flow = argv[optind];
1182da14cebeSEric Cheng 	} else if (optind != argc) {
1183da14cebeSEric Cheng 		usage();
1184da14cebeSEric Cheng 	}
1185da14cebeSEric Cheng 	state.fs_proplist = proplist;
1186da14cebeSEric Cheng 	state.fs_status = DLADM_STATUS_OK;
1187da14cebeSEric Cheng 
11888002d411SSowmini Varadhan 	oferr = ofmt_open(fields_str, flowprop_fields, ofmtflags, 0, &ofmt);
11898002d411SSowmini Varadhan 	flowadm_ofmt_check(oferr, state.fs_parsable, ofmt);
11908002d411SSowmini Varadhan 	state.fs_ofmt = ofmt;
1191da14cebeSEric Cheng 
1192da14cebeSEric Cheng 	/* Show properties for one flow */
1193da14cebeSEric Cheng 	if (state.fs_flow != NULL) {
1194da14cebeSEric Cheng 		show_flowprop_one_flow(&state, state.fs_flow);
1195da14cebeSEric Cheng 
1196da14cebeSEric Cheng 	/* Show properties for all flows on one link */
1197da14cebeSEric Cheng 	} else if (state.fs_linkid != DATALINK_INVALID_LINKID) {
11984ac67f02SAnurag S. Maskey 		(void) show_flowprop_onelink(handle, state.fs_linkid, &state);
1199da14cebeSEric Cheng 
1200da14cebeSEric Cheng 	/* Show properties for all flows on all links */
1201da14cebeSEric Cheng 	} else {
12024ac67f02SAnurag S. Maskey 		(void) dladm_walk_datalink_id(show_flowprop_onelink, handle,
12034ac67f02SAnurag S. Maskey 		    &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1204da14cebeSEric Cheng 		    DLADM_OPT_ACTIVE);
1205da14cebeSEric Cheng 	}
1206da14cebeSEric Cheng 
1207da14cebeSEric Cheng 	dladm_free_props(proplist);
12088002d411SSowmini Varadhan 	ofmt_close(ofmt);
1209da14cebeSEric Cheng }
1210da14cebeSEric Cheng 
1211da14cebeSEric Cheng static void
1212da14cebeSEric Cheng show_flowprop_one_flow(void *arg, const char *flow)
1213da14cebeSEric Cheng {
1214da14cebeSEric Cheng 	int			i;
1215da14cebeSEric Cheng 	char			*buf;
1216da14cebeSEric Cheng 	dladm_status_t		status;
1217da14cebeSEric Cheng 	dladm_arg_list_t	*proplist = NULL;
1218da14cebeSEric Cheng 	show_flowprop_state_t	*statep = arg;
1219da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
1220da14cebeSEric Cheng 	const char		*savep;
1221da14cebeSEric Cheng 
1222da14cebeSEric Cheng 	/*
1223da14cebeSEric Cheng 	 * Do not print flow props for invalid flows.
1224da14cebeSEric Cheng 	 */
12254ac67f02SAnurag S. Maskey 	if ((status = dladm_flow_info(handle, flow, &attr)) !=
12264ac67f02SAnurag S. Maskey 	    DLADM_STATUS_OK) {
1227da14cebeSEric Cheng 		die("invalid flow: '%s'", flow);
1228da14cebeSEric Cheng 	}
1229da14cebeSEric Cheng 
1230da14cebeSEric Cheng 	savep = statep->fs_flow;
1231da14cebeSEric Cheng 	statep->fs_flow = flow;
1232da14cebeSEric Cheng 
1233da14cebeSEric Cheng 	proplist = statep->fs_proplist;
1234da14cebeSEric Cheng 
1235da14cebeSEric Cheng 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX)
1236da14cebeSEric Cheng 	    * DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
1237da14cebeSEric Cheng 	if (buf == NULL)
1238da14cebeSEric Cheng 		die("insufficient memory");
1239da14cebeSEric Cheng 
1240da14cebeSEric Cheng 	statep->fs_propvals = (char **)(void *)buf;
1241da14cebeSEric Cheng 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
1242da14cebeSEric Cheng 		statep->fs_propvals[i] = buf +
1243da14cebeSEric Cheng 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1244da14cebeSEric Cheng 		    i * DLADM_PROP_VAL_MAX;
1245da14cebeSEric Cheng 	}
1246da14cebeSEric Cheng 	statep->fs_line = buf +
1247da14cebeSEric Cheng 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
1248da14cebeSEric Cheng 
1249da14cebeSEric Cheng 	/* show only specified flow properties */
1250da14cebeSEric Cheng 	if (proplist != NULL) {
1251da14cebeSEric Cheng 		for (i = 0; i < proplist->al_count; i++) {
1252da14cebeSEric Cheng 			if (show_one_flowprop(statep,
1253da14cebeSEric Cheng 			    proplist->al_info[i].ai_name) != DLADM_STATUS_OK)
1254da14cebeSEric Cheng 				break;
1255da14cebeSEric Cheng 		}
1256da14cebeSEric Cheng 
1257da14cebeSEric Cheng 	/* show all flow properties */
1258da14cebeSEric Cheng 	} else {
1259da14cebeSEric Cheng 		status = dladm_walk_flowprop(show_one_flowprop, flow, statep);
1260da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
1261da14cebeSEric Cheng 			die_dlerr(status, "show-flowprop");
1262da14cebeSEric Cheng 	}
1263da14cebeSEric Cheng 	free(buf);
1264da14cebeSEric Cheng 	statep->fs_flow = savep;
1265da14cebeSEric Cheng }
1266da14cebeSEric Cheng 
1267da14cebeSEric Cheng /*
12688002d411SSowmini Varadhan  * default output callback function that, when invoked from dladm_print_output,
12698002d411SSowmini Varadhan  * prints string which is offset by of_arg->ofmt_id within buf.
1270da14cebeSEric Cheng  */
12718002d411SSowmini Varadhan static boolean_t
12728002d411SSowmini Varadhan print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1273da14cebeSEric Cheng {
1274da14cebeSEric Cheng 	char *value;
1275da14cebeSEric Cheng 
12768002d411SSowmini Varadhan 	value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id;
12778002d411SSowmini Varadhan 	(void) strlcpy(buf, value, bufsize);
12788002d411SSowmini Varadhan 	return (B_TRUE);
1279da14cebeSEric Cheng }
1280da14cebeSEric Cheng 
1281da14cebeSEric Cheng static void
12828002d411SSowmini Varadhan flowadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
12838002d411SSowmini Varadhan     ofmt_handle_t ofmt)
1284da14cebeSEric Cheng {
12858002d411SSowmini Varadhan 	char buf[OFMT_BUFSIZE];
1286da14cebeSEric Cheng 
12878002d411SSowmini Varadhan 	if (oferr == OFMT_SUCCESS)
12888002d411SSowmini Varadhan 		return;
12898002d411SSowmini Varadhan 	(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
1290ad091ee1SMichael Lim 	/*
12918002d411SSowmini Varadhan 	 * All errors are considered fatal in parsable mode.
12928002d411SSowmini Varadhan 	 * NOMEM errors are always fatal, regardless of mode.
12938002d411SSowmini Varadhan 	 * For other errors, we print diagnostics in human-readable
12948002d411SSowmini Varadhan 	 * mode and processs what we can.
1295ad091ee1SMichael Lim 	 */
12968002d411SSowmini Varadhan 	if (parsable || oferr == OFMT_ENOFIELDS) {
12978002d411SSowmini Varadhan 		ofmt_close(ofmt);
12988002d411SSowmini Varadhan 		die(buf);
1299da14cebeSEric Cheng 	} else {
13008002d411SSowmini Varadhan 		warn(buf);
1301da14cebeSEric Cheng 	}
1302da14cebeSEric Cheng }
1303