xref: /titanic_53/usr/src/cmd/dladm/dladm.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <locale.h>
31*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
34*7c478bd9Sstevel@tonic-gate #include <string.h>
35*7c478bd9Sstevel@tonic-gate #include <stropts.h>
36*7c478bd9Sstevel@tonic-gate #include <errno.h>
37*7c478bd9Sstevel@tonic-gate #include <kstat.h>
38*7c478bd9Sstevel@tonic-gate #include <strings.h>
39*7c478bd9Sstevel@tonic-gate #include <getopt.h>
40*7c478bd9Sstevel@tonic-gate #include <unistd.h>
41*7c478bd9Sstevel@tonic-gate #include <libintl.h>
42*7c478bd9Sstevel@tonic-gate #include <libdlpi.h>
43*7c478bd9Sstevel@tonic-gate #include <libdladm.h>
44*7c478bd9Sstevel@tonic-gate #include <liblaadm.h>
45*7c478bd9Sstevel@tonic-gate #include <libmacadm.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #define	AGGR_DRIVER	"aggr"
48*7c478bd9Sstevel@tonic-gate #define	AGGR_DEV	"aggr0"
49*7c478bd9Sstevel@tonic-gate #define	MAXPORT		256
50*7c478bd9Sstevel@tonic-gate #define	DUMP_LACP_FORMAT	"    %-9s %-8s %-7s %-12s "	\
51*7c478bd9Sstevel@tonic-gate 	"%-5s %-4s %-4s %-9s %-7s\n"
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate typedef struct pktsum_s {
54*7c478bd9Sstevel@tonic-gate 	uint64_t	ipackets;
55*7c478bd9Sstevel@tonic-gate 	uint64_t	opackets;
56*7c478bd9Sstevel@tonic-gate 	uint64_t	rbytes;
57*7c478bd9Sstevel@tonic-gate 	uint64_t	obytes;
58*7c478bd9Sstevel@tonic-gate 	uint32_t	ierrors;
59*7c478bd9Sstevel@tonic-gate 	uint32_t	oerrors;
60*7c478bd9Sstevel@tonic-gate } pktsum_t;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate typedef struct show_link_state {
63*7c478bd9Sstevel@tonic-gate 	boolean_t	ls_firstonly;
64*7c478bd9Sstevel@tonic-gate 	boolean_t	ls_donefirst;
65*7c478bd9Sstevel@tonic-gate 	boolean_t	ls_stats;
66*7c478bd9Sstevel@tonic-gate 	pktsum_t	ls_prevstats;
67*7c478bd9Sstevel@tonic-gate 	boolean_t	ls_parseable;
68*7c478bd9Sstevel@tonic-gate } show_link_state_t;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate typedef struct show_grp_state {
71*7c478bd9Sstevel@tonic-gate 	uint32_t	gs_key;
72*7c478bd9Sstevel@tonic-gate 	boolean_t	gs_lacp;
73*7c478bd9Sstevel@tonic-gate 	boolean_t	gs_found;
74*7c478bd9Sstevel@tonic-gate 	boolean_t	gs_stats;
75*7c478bd9Sstevel@tonic-gate 	boolean_t	gs_firstonly;
76*7c478bd9Sstevel@tonic-gate 	pktsum_t	gs_prevstats[MAXPORT];
77*7c478bd9Sstevel@tonic-gate 	boolean_t	gs_parseable;
78*7c478bd9Sstevel@tonic-gate } show_grp_state_t;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate typedef struct show_mac_state {
81*7c478bd9Sstevel@tonic-gate 	boolean_t	ms_firstonly;
82*7c478bd9Sstevel@tonic-gate 	boolean_t	ms_donefirst;
83*7c478bd9Sstevel@tonic-gate 	pktsum_t	ms_prevstats;
84*7c478bd9Sstevel@tonic-gate 	boolean_t	ms_parseable;
85*7c478bd9Sstevel@tonic-gate } show_mac_state_t;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate typedef struct port_state {
88*7c478bd9Sstevel@tonic-gate 	char			*state_name;
89*7c478bd9Sstevel@tonic-gate 	aggr_port_state_t	state_num;
90*7c478bd9Sstevel@tonic-gate } port_state_t;
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate static port_state_t port_states[] = {
93*7c478bd9Sstevel@tonic-gate 	{"standby", AGGR_PORT_STATE_STANDBY },
94*7c478bd9Sstevel@tonic-gate 	{"attached", AGGR_PORT_STATE_ATTACHED }
95*7c478bd9Sstevel@tonic-gate };
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate #define	NPORTSTATES	(sizeof (port_states) / sizeof (port_state_t))
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate static void	do_create_vlan(int, char **);
100*7c478bd9Sstevel@tonic-gate static void	do_delete_vlan(int, char **);
101*7c478bd9Sstevel@tonic-gate static void	do_show_link(int, char **);
102*7c478bd9Sstevel@tonic-gate static void	do_up_link(int, char **);
103*7c478bd9Sstevel@tonic-gate static void	do_init_link(int, char **);
104*7c478bd9Sstevel@tonic-gate static void	do_create_aggr(int, char **);
105*7c478bd9Sstevel@tonic-gate static void	do_delete_aggr(int, char **);
106*7c478bd9Sstevel@tonic-gate static void	do_add_aggr(int, char **);
107*7c478bd9Sstevel@tonic-gate static void	do_remove_aggr(int, char **);
108*7c478bd9Sstevel@tonic-gate static void	do_modify_aggr(int, char **);
109*7c478bd9Sstevel@tonic-gate static void	do_show_aggr(int, char **);
110*7c478bd9Sstevel@tonic-gate static void	do_up_aggr(int, char **);
111*7c478bd9Sstevel@tonic-gate static void	do_down_aggr(int, char **);
112*7c478bd9Sstevel@tonic-gate static void	do_show_dev(int, char **);
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate static void	link_stats(const char *, uint32_t);
115*7c478bd9Sstevel@tonic-gate static void	aggr_stats(uint16_t, uint32_t);
116*7c478bd9Sstevel@tonic-gate static void	dev_stats(const char *dev, uint32_t);
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate static void	get_mac_stats(const char *, uint_t, pktsum_t *);
119*7c478bd9Sstevel@tonic-gate static void	get_link_stats(const char *, pktsum_t *);
120*7c478bd9Sstevel@tonic-gate static uint64_t	mac_ifspeed(const char *, uint_t);
121*7c478bd9Sstevel@tonic-gate static char	*mac_link_state(const char *, uint_t);
122*7c478bd9Sstevel@tonic-gate static char	*mac_link_duplex(const char *, uint_t);
123*7c478bd9Sstevel@tonic-gate static void	stats_total(pktsum_t *, pktsum_t *, pktsum_t *);
124*7c478bd9Sstevel@tonic-gate static void	stats_diff(pktsum_t *, pktsum_t *, pktsum_t *);
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate typedef struct	cmd {
127*7c478bd9Sstevel@tonic-gate 	char	*c_name;
128*7c478bd9Sstevel@tonic-gate 	void	(*c_fn)(int, char **);
129*7c478bd9Sstevel@tonic-gate } cmd_t;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate static cmd_t	cmds[] = {
132*7c478bd9Sstevel@tonic-gate 	{ "create-vlan", do_create_vlan },
133*7c478bd9Sstevel@tonic-gate 	{ "delete-vlan", do_delete_vlan },
134*7c478bd9Sstevel@tonic-gate 	{ "show-link", do_show_link },
135*7c478bd9Sstevel@tonic-gate 	{ "up-link", do_up_link },
136*7c478bd9Sstevel@tonic-gate 	{ "init-link", do_init_link },
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	{ "create-aggr", do_create_aggr },
139*7c478bd9Sstevel@tonic-gate 	{ "delete-aggr", do_delete_aggr },
140*7c478bd9Sstevel@tonic-gate 	{ "add-aggr", do_add_aggr },
141*7c478bd9Sstevel@tonic-gate 	{ "remove-aggr", do_remove_aggr },
142*7c478bd9Sstevel@tonic-gate 	{ "modify-aggr", do_modify_aggr },
143*7c478bd9Sstevel@tonic-gate 	{ "show-aggr", do_show_aggr },
144*7c478bd9Sstevel@tonic-gate 	{ "up-aggr", do_up_aggr },
145*7c478bd9Sstevel@tonic-gate 	{ "down-aggr", do_down_aggr },
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	{ "show-dev", do_show_dev }
148*7c478bd9Sstevel@tonic-gate };
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate static const struct option longopts[] = {
151*7c478bd9Sstevel@tonic-gate 	{"vlan-id",	required_argument,	0, 'v'},
152*7c478bd9Sstevel@tonic-gate 	{"dev",		required_argument,	0, 'd'},
153*7c478bd9Sstevel@tonic-gate 	{"policy",	required_argument,	0, 'P'},
154*7c478bd9Sstevel@tonic-gate 	{"lacp-mode",	required_argument,	0, 'l'},
155*7c478bd9Sstevel@tonic-gate 	{"lacp-timer",	required_argument,	0, 'T'},
156*7c478bd9Sstevel@tonic-gate 	{"unicast",	required_argument,	0, 'u'},
157*7c478bd9Sstevel@tonic-gate 	{"statistics",	no_argument,		0, 's'},
158*7c478bd9Sstevel@tonic-gate 	{"interval",	required_argument,	0, 'i'},
159*7c478bd9Sstevel@tonic-gate 	{"lacp",	no_argument,		0, 'L'},
160*7c478bd9Sstevel@tonic-gate 	{"temporary",	no_argument,		0, 't'},
161*7c478bd9Sstevel@tonic-gate 	{"root-dir",	required_argument,	0, 'r'},
162*7c478bd9Sstevel@tonic-gate 	{"parseable",	no_argument,		0, 'p'},
163*7c478bd9Sstevel@tonic-gate 	{ 0, 0, 0, 0 }
164*7c478bd9Sstevel@tonic-gate };
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate static char *progname;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate #define	PRINT_ERR_DIAG(s, diag, func) {					\
169*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(s), progname, strerror(errno));	\
170*7c478bd9Sstevel@tonic-gate 	if (diag != 0)							\
171*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, " (%s)", func(diag));		\
172*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");					\
173*7c478bd9Sstevel@tonic-gate }
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate static void
176*7c478bd9Sstevel@tonic-gate usage(void)
177*7c478bd9Sstevel@tonic-gate {
178*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
179*7c478bd9Sstevel@tonic-gate 	    "usage: dladm create-vlan [-t] [-R <root-dir>] -v <vlan> -d <dev>\n"
180*7c478bd9Sstevel@tonic-gate 	    "             delete-vlan [-t] [-R <root-dir>] -v <vlan> -d <dev>\n"
181*7c478bd9Sstevel@tonic-gate 	    "             create-aggr [-t] [-R <root-dir>] [-P <policy>]\n"
182*7c478bd9Sstevel@tonic-gate 	    "                    [-l <mode>] [-T <time>]\n"
183*7c478bd9Sstevel@tonic-gate 	    "                    [-u <address>] -d <dev> ... <key>\n"
184*7c478bd9Sstevel@tonic-gate 	    "             delete-aggr [-t] [-R <root-dir>] <key>\n"
185*7c478bd9Sstevel@tonic-gate 	    "             add-aggr    [-t] [-R <root-dir>] -d <dev> ... <key>\n"
186*7c478bd9Sstevel@tonic-gate 	    "             remove-aggr [-t] [-R <root-dir>] -d <dev> ... <key>\n"
187*7c478bd9Sstevel@tonic-gate 	    "             modify-aggr [-t] [-R <root-dir>] [-P <policy>]\n"
188*7c478bd9Sstevel@tonic-gate 	    "                    [-l <mode>] [-T <time>] [-u <address>] <key>\n"
189*7c478bd9Sstevel@tonic-gate 	    "             show-aggr [-L] [-s] [-i <interval>] [-p] [<key>]\n"
190*7c478bd9Sstevel@tonic-gate 	    "             show-dev [-s] [-i <interval>] [-p] [<dev>]\n"
191*7c478bd9Sstevel@tonic-gate 	    "             show-link [-s] [-i <interval>] [-p] [<name>]\n"));
192*7c478bd9Sstevel@tonic-gate 	exit(1);
193*7c478bd9Sstevel@tonic-gate }
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate int
196*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
197*7c478bd9Sstevel@tonic-gate {
198*7c478bd9Sstevel@tonic-gate 	int	i;
199*7c478bd9Sstevel@tonic-gate 	cmd_t	*cmdp;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
202*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
203*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
204*7c478bd9Sstevel@tonic-gate #endif
205*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	progname = argv[0];
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	if (argc < 2)
210*7c478bd9Sstevel@tonic-gate 		usage();
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
213*7c478bd9Sstevel@tonic-gate 		cmdp = &cmds[i];
214*7c478bd9Sstevel@tonic-gate 		if (strcmp(argv[1], cmdp->c_name) == 0) {
215*7c478bd9Sstevel@tonic-gate 			cmdp->c_fn(argc - 1, &argv[1]);
216*7c478bd9Sstevel@tonic-gate 			exit(0);
217*7c478bd9Sstevel@tonic-gate 		}
218*7c478bd9Sstevel@tonic-gate 	}
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
221*7c478bd9Sstevel@tonic-gate 	    progname, argv[1]);
222*7c478bd9Sstevel@tonic-gate 	usage();
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	return (0);
225*7c478bd9Sstevel@tonic-gate }
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate static void
228*7c478bd9Sstevel@tonic-gate do_create_vlan(int argc, char *argv[])
229*7c478bd9Sstevel@tonic-gate {
230*7c478bd9Sstevel@tonic-gate 	char		name[MAXNAMELEN];
231*7c478bd9Sstevel@tonic-gate 	char		driver[MAXNAMELEN];
232*7c478bd9Sstevel@tonic-gate 	int		instance;
233*7c478bd9Sstevel@tonic-gate 	dladm_attr_t	dlattr;
234*7c478bd9Sstevel@tonic-gate 	int		value;
235*7c478bd9Sstevel@tonic-gate 	char		option;
236*7c478bd9Sstevel@tonic-gate 	boolean_t	v_arg = B_FALSE;
237*7c478bd9Sstevel@tonic-gate 	boolean_t	d_arg = B_FALSE;
238*7c478bd9Sstevel@tonic-gate 	boolean_t	t_arg = B_FALSE;
239*7c478bd9Sstevel@tonic-gate 	char		*altroot = NULL;
240*7c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
241*7c478bd9Sstevel@tonic-gate 	dladm_diag_t	diag = 0;
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	bzero(&dlattr, sizeof (dladm_attr_t));
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	opterr = 0;
246*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":d:R:tv:", longopts,
247*7c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
248*7c478bd9Sstevel@tonic-gate 		switch (option) {
249*7c478bd9Sstevel@tonic-gate 		case 'v':
250*7c478bd9Sstevel@tonic-gate 			if (v_arg) {
251*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("%s: the option "
252*7c478bd9Sstevel@tonic-gate 				    "-v cannot be specified more than once\n"),
253*7c478bd9Sstevel@tonic-gate 				    progname);
254*7c478bd9Sstevel@tonic-gate 				usage();
255*7c478bd9Sstevel@tonic-gate 			}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 			v_arg = B_TRUE;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 			errno = 0;
260*7c478bd9Sstevel@tonic-gate 			value = (int)strtol(optarg, &endp, 10);
261*7c478bd9Sstevel@tonic-gate 			if (errno != 0 || value < 1 || value > 4094 ||
262*7c478bd9Sstevel@tonic-gate 			    *endp != '\0') {
263*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
264*7c478bd9Sstevel@tonic-gate 				    gettext("%s: illegal VLAN identifier"
265*7c478bd9Sstevel@tonic-gate 				    " '%d'\n"), progname, value);
266*7c478bd9Sstevel@tonic-gate 				exit(1);
267*7c478bd9Sstevel@tonic-gate 			}
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 			dlattr.da_vid = (uint16_t)value;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 			break;
272*7c478bd9Sstevel@tonic-gate 		case 'd':
273*7c478bd9Sstevel@tonic-gate 			if (d_arg) {
274*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
275*7c478bd9Sstevel@tonic-gate 				    "%s: the option -d cannot be specified "
276*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
277*7c478bd9Sstevel@tonic-gate 				usage();
278*7c478bd9Sstevel@tonic-gate 			}
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 			d_arg = B_TRUE;
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 			if (strlcpy(dlattr.da_dev, optarg, MAXNAMELEN) >=
283*7c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) {
284*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
285*7c478bd9Sstevel@tonic-gate 				    gettext("%s: device name too long\n"),
286*7c478bd9Sstevel@tonic-gate 				    progname);
287*7c478bd9Sstevel@tonic-gate 				exit(1);
288*7c478bd9Sstevel@tonic-gate 			}
289*7c478bd9Sstevel@tonic-gate 			break;
290*7c478bd9Sstevel@tonic-gate 		case 't':
291*7c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
292*7c478bd9Sstevel@tonic-gate 			break;
293*7c478bd9Sstevel@tonic-gate 		case 'R':
294*7c478bd9Sstevel@tonic-gate 			altroot = optarg;
295*7c478bd9Sstevel@tonic-gate 			break;
296*7c478bd9Sstevel@tonic-gate 		case ':':
297*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
298*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
299*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
300*7c478bd9Sstevel@tonic-gate 			exit(1);
301*7c478bd9Sstevel@tonic-gate 			break;
302*7c478bd9Sstevel@tonic-gate 		case '?':
303*7c478bd9Sstevel@tonic-gate 		default:
304*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
305*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
306*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
307*7c478bd9Sstevel@tonic-gate 			exit(1);
308*7c478bd9Sstevel@tonic-gate 			break;
309*7c478bd9Sstevel@tonic-gate 		}
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	if (optind != argc) {
313*7c478bd9Sstevel@tonic-gate 		usage();
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	if (dlattr.da_dev[0] == '\0') {
317*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
318*7c478bd9Sstevel@tonic-gate 		    gettext("%s: no device specified\n"),
319*7c478bd9Sstevel@tonic-gate 		    progname);
320*7c478bd9Sstevel@tonic-gate 		exit(1);
321*7c478bd9Sstevel@tonic-gate 	}
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	if (dlattr.da_vid == 0) {
324*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
325*7c478bd9Sstevel@tonic-gate 		    gettext("%s: no VLAN ID specified\n"),
326*7c478bd9Sstevel@tonic-gate 		    progname);
327*7c478bd9Sstevel@tonic-gate 		exit(1);
328*7c478bd9Sstevel@tonic-gate 	}
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	if (dlpi_if_parse(dlattr.da_dev, driver, &instance) < 0 ||
331*7c478bd9Sstevel@tonic-gate 	    instance < 0) {
332*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
333*7c478bd9Sstevel@tonic-gate 		    gettext("%s: badly formatted device '%s'\n"),
334*7c478bd9Sstevel@tonic-gate 		    progname, dlattr.da_dev);
335*7c478bd9Sstevel@tonic-gate 		exit(1);
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXNAMELEN, "%s%d", driver,
339*7c478bd9Sstevel@tonic-gate 	    (dlattr.da_vid * 1000) + instance);
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	/*
342*7c478bd9Sstevel@tonic-gate 	 * For aggregations, the da_dev is always AGGR_DEV, and the
343*7c478bd9Sstevel@tonic-gate 	 * aggregation key (the instance integer extracted above by
344*7c478bd9Sstevel@tonic-gate 	 * dlpi_if_parse) is da_port.
345*7c478bd9Sstevel@tonic-gate 	 */
346*7c478bd9Sstevel@tonic-gate 	if (strcmp(driver, AGGR_DRIVER) == 0) {
347*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(dlattr.da_dev, AGGR_DEV, MAXNAMELEN);
348*7c478bd9Sstevel@tonic-gate 		dlattr.da_port = instance;
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	if (dladm_link(name, &dlattr, (t_arg ? DLADM_LINK_TEMP : 0),
352*7c478bd9Sstevel@tonic-gate 	    altroot, &diag) < 0) {
353*7c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: link operation failed: %s", diag,
354*7c478bd9Sstevel@tonic-gate 		    dladm_diag);
355*7c478bd9Sstevel@tonic-gate 		exit(1);
356*7c478bd9Sstevel@tonic-gate 	}
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	if (dladm_sync() < 0) {
359*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
360*7c478bd9Sstevel@tonic-gate 		    gettext("%s: sync operation failed"),
361*7c478bd9Sstevel@tonic-gate 		    progname);
362*7c478bd9Sstevel@tonic-gate 		perror(" ");
363*7c478bd9Sstevel@tonic-gate 		exit(1);
364*7c478bd9Sstevel@tonic-gate 	}
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate static void
368*7c478bd9Sstevel@tonic-gate do_delete_vlan(int argc, char *argv[])
369*7c478bd9Sstevel@tonic-gate {
370*7c478bd9Sstevel@tonic-gate 	char		option;
371*7c478bd9Sstevel@tonic-gate 	boolean_t	t_arg = B_FALSE;
372*7c478bd9Sstevel@tonic-gate 	boolean_t	v_arg = B_FALSE;
373*7c478bd9Sstevel@tonic-gate 	boolean_t	d_arg = B_FALSE;
374*7c478bd9Sstevel@tonic-gate 	char		device[MAXNAMELEN];
375*7c478bd9Sstevel@tonic-gate 	char		name[MAXNAMELEN];
376*7c478bd9Sstevel@tonic-gate 	char		driver[MAXNAMELEN];
377*7c478bd9Sstevel@tonic-gate 	int		instance;
378*7c478bd9Sstevel@tonic-gate 	int		vid;
379*7c478bd9Sstevel@tonic-gate 	char		*altroot = NULL;
380*7c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
381*7c478bd9Sstevel@tonic-gate 	dladm_diag_t	diag = 0;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	opterr = 0;
384*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":R:td:v:", longopts,
385*7c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
386*7c478bd9Sstevel@tonic-gate 		switch (option) {
387*7c478bd9Sstevel@tonic-gate 		case 'v':
388*7c478bd9Sstevel@tonic-gate 			if (v_arg) {
389*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("%s: the option "
390*7c478bd9Sstevel@tonic-gate 				    "-v cannot be specified more than once\n"),
391*7c478bd9Sstevel@tonic-gate 				    progname);
392*7c478bd9Sstevel@tonic-gate 				usage();
393*7c478bd9Sstevel@tonic-gate 			}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 			v_arg = B_TRUE;
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 			errno = 0;
398*7c478bd9Sstevel@tonic-gate 			vid = (int)strtol(optarg, &endp, 10);
399*7c478bd9Sstevel@tonic-gate 			if (errno != 0 || vid < 1 || vid > 4094 ||
400*7c478bd9Sstevel@tonic-gate 			    *endp != '\0') {
401*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
402*7c478bd9Sstevel@tonic-gate 				    gettext("%s: illegal VLAN identifier"
403*7c478bd9Sstevel@tonic-gate 				    " '%d'\n"), progname, vid);
404*7c478bd9Sstevel@tonic-gate 				exit(1);
405*7c478bd9Sstevel@tonic-gate 			}
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 			break;
408*7c478bd9Sstevel@tonic-gate 		case 'd':
409*7c478bd9Sstevel@tonic-gate 			if (d_arg) {
410*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
411*7c478bd9Sstevel@tonic-gate 				    "%s: the option -d cannot be specified "
412*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
413*7c478bd9Sstevel@tonic-gate 				usage();
414*7c478bd9Sstevel@tonic-gate 			}
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 			d_arg = B_TRUE;
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 			if (strlcpy(device, optarg, MAXNAMELEN) >=
419*7c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) {
420*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
421*7c478bd9Sstevel@tonic-gate 				    gettext("%s: device name too long\n"),
422*7c478bd9Sstevel@tonic-gate 				    progname);
423*7c478bd9Sstevel@tonic-gate 				exit(1);
424*7c478bd9Sstevel@tonic-gate 			}
425*7c478bd9Sstevel@tonic-gate 			break;
426*7c478bd9Sstevel@tonic-gate 		case 't':
427*7c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
428*7c478bd9Sstevel@tonic-gate 			break;
429*7c478bd9Sstevel@tonic-gate 		case 'R':
430*7c478bd9Sstevel@tonic-gate 			altroot = optarg;
431*7c478bd9Sstevel@tonic-gate 			break;
432*7c478bd9Sstevel@tonic-gate 		case ':':
433*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
434*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
435*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
436*7c478bd9Sstevel@tonic-gate 			exit(1);
437*7c478bd9Sstevel@tonic-gate 			break;
438*7c478bd9Sstevel@tonic-gate 		case '?':
439*7c478bd9Sstevel@tonic-gate 		default:
440*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
441*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
442*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
443*7c478bd9Sstevel@tonic-gate 			exit(1);
444*7c478bd9Sstevel@tonic-gate 			break;
445*7c478bd9Sstevel@tonic-gate 		}
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	if (optind != argc)
449*7c478bd9Sstevel@tonic-gate 		usage();
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	if (d_arg == B_FALSE) {
452*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
453*7c478bd9Sstevel@tonic-gate 		    gettext("%s: no device specified\n"),
454*7c478bd9Sstevel@tonic-gate 		    progname);
455*7c478bd9Sstevel@tonic-gate 		exit(1);
456*7c478bd9Sstevel@tonic-gate 	}
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	if (v_arg == B_FALSE) {
459*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
460*7c478bd9Sstevel@tonic-gate 		    gettext("%s: no VLAN ID specified\n"),
461*7c478bd9Sstevel@tonic-gate 		    progname);
462*7c478bd9Sstevel@tonic-gate 		exit(1);
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	if (dlpi_if_parse(device, driver, &instance) < 0 ||
466*7c478bd9Sstevel@tonic-gate 	    instance < 0) {
467*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
468*7c478bd9Sstevel@tonic-gate 		    gettext("%s: badly formatted device '%s'\n"),
469*7c478bd9Sstevel@tonic-gate 		    progname, device);
470*7c478bd9Sstevel@tonic-gate 		exit(1);
471*7c478bd9Sstevel@tonic-gate 	}
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXNAMELEN, "%s%d", driver,
474*7c478bd9Sstevel@tonic-gate 	    (vid * 1000) + instance);
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	if (dladm_unlink(name, t_arg, altroot, &diag) < 0) {
477*7c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: unlink operation failed: %s", diag,
478*7c478bd9Sstevel@tonic-gate 		    dladm_diag);
479*7c478bd9Sstevel@tonic-gate 		exit(1);
480*7c478bd9Sstevel@tonic-gate 	}
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	if (dladm_sync() < 0) {
483*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
484*7c478bd9Sstevel@tonic-gate 		    gettext("%s: sync operation failed"),
485*7c478bd9Sstevel@tonic-gate 		    progname);
486*7c478bd9Sstevel@tonic-gate 		perror(" ");
487*7c478bd9Sstevel@tonic-gate 		exit(1);
488*7c478bd9Sstevel@tonic-gate 	}
489*7c478bd9Sstevel@tonic-gate }
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate static void
492*7c478bd9Sstevel@tonic-gate do_create_aggr(int argc, char *argv[])
493*7c478bd9Sstevel@tonic-gate {
494*7c478bd9Sstevel@tonic-gate 	char			option;
495*7c478bd9Sstevel@tonic-gate 	uint16_t		key;
496*7c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
497*7c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
498*7c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
499*7c478bd9Sstevel@tonic-gate 	laadm_port_attr_db_t	port[MAXPORT];
500*7c478bd9Sstevel@tonic-gate 	uint_t			nport = 0;
501*7c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
502*7c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
503*7c478bd9Sstevel@tonic-gate 	boolean_t		P_arg = B_FALSE;
504*7c478bd9Sstevel@tonic-gate 	boolean_t		l_arg = B_FALSE;
505*7c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
506*7c478bd9Sstevel@tonic-gate 	boolean_t		u_arg = B_FALSE;
507*7c478bd9Sstevel@tonic-gate 	boolean_t		T_arg = B_FALSE;
508*7c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
509*7c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
510*7c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	opterr = 0;
513*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":d:l:P:R:tu:T:",
514*7c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
515*7c478bd9Sstevel@tonic-gate 		switch (option) {
516*7c478bd9Sstevel@tonic-gate 		case 'd':
517*7c478bd9Sstevel@tonic-gate 			if (nport >= MAXPORT) {
518*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
519*7c478bd9Sstevel@tonic-gate 				    gettext("%s: too many <dev> arguments\n"),
520*7c478bd9Sstevel@tonic-gate 				    progname);
521*7c478bd9Sstevel@tonic-gate 				exit(1);
522*7c478bd9Sstevel@tonic-gate 			}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 			if (strlcpy(port[nport].lp_devname, optarg,
525*7c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) >= MAXNAMELEN) {
526*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
527*7c478bd9Sstevel@tonic-gate 				    gettext("%s: device name too long\n"),
528*7c478bd9Sstevel@tonic-gate 				    progname);
529*7c478bd9Sstevel@tonic-gate 				exit(1);
530*7c478bd9Sstevel@tonic-gate 			}
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 			port[nport].lp_port = 0;
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 			nport++;
535*7c478bd9Sstevel@tonic-gate 			break;
536*7c478bd9Sstevel@tonic-gate 		case 'P':
537*7c478bd9Sstevel@tonic-gate 			if (P_arg) {
538*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
539*7c478bd9Sstevel@tonic-gate 				    "%s: the option -P cannot be specified "
540*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
541*7c478bd9Sstevel@tonic-gate 				usage();
542*7c478bd9Sstevel@tonic-gate 			}
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 			P_arg = B_TRUE;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_policy(optarg, &policy)) {
547*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
548*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid policy '%s'\n"),
549*7c478bd9Sstevel@tonic-gate 				    progname, optarg);
550*7c478bd9Sstevel@tonic-gate 				exit(1);
551*7c478bd9Sstevel@tonic-gate 			}
552*7c478bd9Sstevel@tonic-gate 			break;
553*7c478bd9Sstevel@tonic-gate 		case 'u':
554*7c478bd9Sstevel@tonic-gate 			if (u_arg) {
555*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
556*7c478bd9Sstevel@tonic-gate 				    "%s: the option -u cannot be specified "
557*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
558*7c478bd9Sstevel@tonic-gate 				usage();
559*7c478bd9Sstevel@tonic-gate 			}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 			u_arg = B_TRUE;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed,
564*7c478bd9Sstevel@tonic-gate 			    mac_addr)) {
565*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
566*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid MAC address '%s'\n"),
567*7c478bd9Sstevel@tonic-gate 				    progname, optarg);
568*7c478bd9Sstevel@tonic-gate 				exit(1);
569*7c478bd9Sstevel@tonic-gate 			}
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 			break;
572*7c478bd9Sstevel@tonic-gate 		case 'l':
573*7c478bd9Sstevel@tonic-gate 			if (l_arg) {
574*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
575*7c478bd9Sstevel@tonic-gate 				    "%s: the option -l cannot be specified "
576*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
577*7c478bd9Sstevel@tonic-gate 				usage();
578*7c478bd9Sstevel@tonic-gate 			}
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 			l_arg = B_TRUE;
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) {
583*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
584*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid LACP mode '%s'\n"),
585*7c478bd9Sstevel@tonic-gate 				    progname, optarg);
586*7c478bd9Sstevel@tonic-gate 				exit(1);
587*7c478bd9Sstevel@tonic-gate 			}
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 			break;
590*7c478bd9Sstevel@tonic-gate 		case 'T':
591*7c478bd9Sstevel@tonic-gate 			if (T_arg) {
592*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
593*7c478bd9Sstevel@tonic-gate 				    "%s: the option -T cannot be specified "
594*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
595*7c478bd9Sstevel@tonic-gate 				usage();
596*7c478bd9Sstevel@tonic-gate 			}
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 			T_arg = B_TRUE;
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) {
601*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
602*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid LACP timer value"
603*7c478bd9Sstevel@tonic-gate 				    " '%s'\n"),
604*7c478bd9Sstevel@tonic-gate 				    progname, optarg);
605*7c478bd9Sstevel@tonic-gate 				exit(1);
606*7c478bd9Sstevel@tonic-gate 			}
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 			break;
609*7c478bd9Sstevel@tonic-gate 		case 't':
610*7c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
611*7c478bd9Sstevel@tonic-gate 			break;
612*7c478bd9Sstevel@tonic-gate 		case 'R':
613*7c478bd9Sstevel@tonic-gate 			altroot = optarg;
614*7c478bd9Sstevel@tonic-gate 			break;
615*7c478bd9Sstevel@tonic-gate 		case ':':
616*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
617*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
618*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
619*7c478bd9Sstevel@tonic-gate 			exit(1);
620*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
621*7c478bd9Sstevel@tonic-gate 		case '?':
622*7c478bd9Sstevel@tonic-gate 		default:
623*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
624*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
625*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
626*7c478bd9Sstevel@tonic-gate 			exit(1);
627*7c478bd9Sstevel@tonic-gate 		}
628*7c478bd9Sstevel@tonic-gate 	}
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	if (nport == 0)
631*7c478bd9Sstevel@tonic-gate 		usage();
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
634*7c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
635*7c478bd9Sstevel@tonic-gate 		usage();
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	errno = 0;
638*7c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
639*7c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
640*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
641*7c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
642*7c478bd9Sstevel@tonic-gate 		    progname, key);
643*7c478bd9Sstevel@tonic-gate 		exit(1);
644*7c478bd9Sstevel@tonic-gate 	}
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	if (laadm_create(key, nport, port, policy, mac_addr_fixed,
647*7c478bd9Sstevel@tonic-gate 	    mac_addr, lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) {
648*7c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: create operation failed: %s", diag,
649*7c478bd9Sstevel@tonic-gate 		    laadm_diag);
650*7c478bd9Sstevel@tonic-gate 		exit(1);
651*7c478bd9Sstevel@tonic-gate 	}
652*7c478bd9Sstevel@tonic-gate }
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate static void
655*7c478bd9Sstevel@tonic-gate do_delete_aggr(int argc, char *argv[])
656*7c478bd9Sstevel@tonic-gate {
657*7c478bd9Sstevel@tonic-gate 	uint16_t		key;
658*7c478bd9Sstevel@tonic-gate 	char			option;
659*7c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
660*7c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
661*7c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
662*7c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	opterr = 0;
665*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":R:t", longopts,
666*7c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
667*7c478bd9Sstevel@tonic-gate 		switch (option) {
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 		case 't':
670*7c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
671*7c478bd9Sstevel@tonic-gate 			break;
672*7c478bd9Sstevel@tonic-gate 		case 'R':
673*7c478bd9Sstevel@tonic-gate 			altroot = optarg;
674*7c478bd9Sstevel@tonic-gate 			break;
675*7c478bd9Sstevel@tonic-gate 		case ':':
676*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
677*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
678*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
679*7c478bd9Sstevel@tonic-gate 			exit(1);
680*7c478bd9Sstevel@tonic-gate 			break;
681*7c478bd9Sstevel@tonic-gate 		case '?':
682*7c478bd9Sstevel@tonic-gate 		default:
683*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
684*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
685*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
686*7c478bd9Sstevel@tonic-gate 			exit(1);
687*7c478bd9Sstevel@tonic-gate 			break;
688*7c478bd9Sstevel@tonic-gate 		}
689*7c478bd9Sstevel@tonic-gate 	}
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
692*7c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
693*7c478bd9Sstevel@tonic-gate 		usage();
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	errno = 0;
696*7c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
697*7c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
698*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
699*7c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
700*7c478bd9Sstevel@tonic-gate 		    progname, key);
701*7c478bd9Sstevel@tonic-gate 		exit(1);
702*7c478bd9Sstevel@tonic-gate 	}
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 	if (laadm_delete(key, t_arg, altroot, &diag) < 0) {
705*7c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: delete operation failed: %s", diag,
706*7c478bd9Sstevel@tonic-gate 		    laadm_diag);
707*7c478bd9Sstevel@tonic-gate 		exit(1);
708*7c478bd9Sstevel@tonic-gate 	}
709*7c478bd9Sstevel@tonic-gate }
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate static void
712*7c478bd9Sstevel@tonic-gate do_add_aggr(int argc, char *argv[])
713*7c478bd9Sstevel@tonic-gate {
714*7c478bd9Sstevel@tonic-gate 	char			option;
715*7c478bd9Sstevel@tonic-gate 	uint16_t		key;
716*7c478bd9Sstevel@tonic-gate 	laadm_port_attr_db_t	port[MAXPORT];
717*7c478bd9Sstevel@tonic-gate 	uint_t			nport = 0;
718*7c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
719*7c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
720*7c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
721*7c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	opterr = 0;
724*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":d:R:t", longopts,
725*7c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
726*7c478bd9Sstevel@tonic-gate 		switch (option) {
727*7c478bd9Sstevel@tonic-gate 		case 'd':
728*7c478bd9Sstevel@tonic-gate 			if (nport >= MAXPORT) {
729*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
730*7c478bd9Sstevel@tonic-gate 				    gettext("%s: too many <dev> arguments\n"),
731*7c478bd9Sstevel@tonic-gate 				    progname);
732*7c478bd9Sstevel@tonic-gate 				exit(1);
733*7c478bd9Sstevel@tonic-gate 			}
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 			if (strlcpy(port[nport].lp_devname, optarg,
736*7c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) >= MAXNAMELEN) {
737*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
738*7c478bd9Sstevel@tonic-gate 				    gettext("%s: device name too long\n"),
739*7c478bd9Sstevel@tonic-gate 				    progname);
740*7c478bd9Sstevel@tonic-gate 				exit(1);
741*7c478bd9Sstevel@tonic-gate 			}
742*7c478bd9Sstevel@tonic-gate 			port[nport].lp_port = 0;
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 			nport++;
745*7c478bd9Sstevel@tonic-gate 			break;
746*7c478bd9Sstevel@tonic-gate 		case 't':
747*7c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
748*7c478bd9Sstevel@tonic-gate 			break;
749*7c478bd9Sstevel@tonic-gate 		case 'R':
750*7c478bd9Sstevel@tonic-gate 			altroot = optarg;
751*7c478bd9Sstevel@tonic-gate 			break;
752*7c478bd9Sstevel@tonic-gate 		case ':':
753*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
754*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
755*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
756*7c478bd9Sstevel@tonic-gate 			exit(1);
757*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
758*7c478bd9Sstevel@tonic-gate 		case '?':
759*7c478bd9Sstevel@tonic-gate 		default:
760*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
761*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
762*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
763*7c478bd9Sstevel@tonic-gate 			exit(1);
764*7c478bd9Sstevel@tonic-gate 		}
765*7c478bd9Sstevel@tonic-gate 	}
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 	if (nport == 0)
768*7c478bd9Sstevel@tonic-gate 		usage();
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
771*7c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
772*7c478bd9Sstevel@tonic-gate 		usage();
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	errno = 0;
775*7c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
776*7c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
777*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
778*7c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
779*7c478bd9Sstevel@tonic-gate 		    progname, key);
780*7c478bd9Sstevel@tonic-gate 		exit(1);
781*7c478bd9Sstevel@tonic-gate 	}
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	if (laadm_add(key, nport, port, t_arg, altroot, &diag) < 0) {
784*7c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: add operation failed: %s", diag,
785*7c478bd9Sstevel@tonic-gate 		    laadm_diag);
786*7c478bd9Sstevel@tonic-gate 		exit(1);
787*7c478bd9Sstevel@tonic-gate 	}
788*7c478bd9Sstevel@tonic-gate }
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate static void
791*7c478bd9Sstevel@tonic-gate do_remove_aggr(int argc, char *argv[])
792*7c478bd9Sstevel@tonic-gate {
793*7c478bd9Sstevel@tonic-gate 	char			option;
794*7c478bd9Sstevel@tonic-gate 	uint16_t		key;
795*7c478bd9Sstevel@tonic-gate 	laadm_port_attr_db_t	port[MAXPORT];
796*7c478bd9Sstevel@tonic-gate 	uint_t			nport = 0;
797*7c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
798*7c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
799*7c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
800*7c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	opterr = 0;
803*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":d:R:t",
804*7c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
805*7c478bd9Sstevel@tonic-gate 		switch (option) {
806*7c478bd9Sstevel@tonic-gate 		case 'd':
807*7c478bd9Sstevel@tonic-gate 			if (nport >= MAXPORT) {
808*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
809*7c478bd9Sstevel@tonic-gate 				    gettext("%s: too many <dev> arguments\n"),
810*7c478bd9Sstevel@tonic-gate 				    progname);
811*7c478bd9Sstevel@tonic-gate 				exit(1);
812*7c478bd9Sstevel@tonic-gate 			}
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 			if (strlcpy(port[nport].lp_devname, optarg,
815*7c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) >= MAXNAMELEN) {
816*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
817*7c478bd9Sstevel@tonic-gate 				    gettext("%s: device name too long\n"),
818*7c478bd9Sstevel@tonic-gate 				    progname);
819*7c478bd9Sstevel@tonic-gate 				exit(1);
820*7c478bd9Sstevel@tonic-gate 			}
821*7c478bd9Sstevel@tonic-gate 			port[nport].lp_port = 0;
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 			nport++;
824*7c478bd9Sstevel@tonic-gate 			break;
825*7c478bd9Sstevel@tonic-gate 		case 't':
826*7c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
827*7c478bd9Sstevel@tonic-gate 			break;
828*7c478bd9Sstevel@tonic-gate 		case 'R':
829*7c478bd9Sstevel@tonic-gate 			altroot = optarg;
830*7c478bd9Sstevel@tonic-gate 			break;
831*7c478bd9Sstevel@tonic-gate 		case ':':
832*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
833*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
834*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
835*7c478bd9Sstevel@tonic-gate 			exit(1);
836*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
837*7c478bd9Sstevel@tonic-gate 		case '?':
838*7c478bd9Sstevel@tonic-gate 		default:
839*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
840*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
841*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
842*7c478bd9Sstevel@tonic-gate 			exit(1);
843*7c478bd9Sstevel@tonic-gate 		}
844*7c478bd9Sstevel@tonic-gate 	}
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 	if (nport == 0)
847*7c478bd9Sstevel@tonic-gate 		usage();
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
850*7c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
851*7c478bd9Sstevel@tonic-gate 		usage();
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	errno = 0;
854*7c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
855*7c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
856*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
857*7c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
858*7c478bd9Sstevel@tonic-gate 		    progname, key);
859*7c478bd9Sstevel@tonic-gate 		exit(1);
860*7c478bd9Sstevel@tonic-gate 	}
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 	if (laadm_remove(key, nport, port, t_arg, altroot, &diag) < 0) {
863*7c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: remove operation failed: %s", diag,
864*7c478bd9Sstevel@tonic-gate 		    laadm_diag);
865*7c478bd9Sstevel@tonic-gate 		exit(1);
866*7c478bd9Sstevel@tonic-gate 	}
867*7c478bd9Sstevel@tonic-gate }
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate static void
870*7c478bd9Sstevel@tonic-gate do_modify_aggr(int argc, char *argv[])
871*7c478bd9Sstevel@tonic-gate {
872*7c478bd9Sstevel@tonic-gate 	char			option;
873*7c478bd9Sstevel@tonic-gate 	uint16_t		key;
874*7c478bd9Sstevel@tonic-gate 	uint32_t		policy = AGGR_POLICY_L4;
875*7c478bd9Sstevel@tonic-gate 	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
876*7c478bd9Sstevel@tonic-gate 	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
877*7c478bd9Sstevel@tonic-gate 	uint8_t			mac_addr[ETHERADDRL];
878*7c478bd9Sstevel@tonic-gate 	boolean_t		mac_addr_fixed = B_FALSE;
879*7c478bd9Sstevel@tonic-gate 	uint8_t			modify_mask = 0;
880*7c478bd9Sstevel@tonic-gate 	boolean_t		t_arg = B_FALSE;
881*7c478bd9Sstevel@tonic-gate 	char			*altroot = NULL;
882*7c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
883*7c478bd9Sstevel@tonic-gate 	laadm_diag_t		diag = 0;
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	opterr = 0;
886*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":l:P:R:tu:T:", longopts,
887*7c478bd9Sstevel@tonic-gate 	    NULL)) != -1) {
888*7c478bd9Sstevel@tonic-gate 		switch (option) {
889*7c478bd9Sstevel@tonic-gate 		case 'P':
890*7c478bd9Sstevel@tonic-gate 			if (modify_mask & LAADM_MODIFY_POLICY) {
891*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
892*7c478bd9Sstevel@tonic-gate 				    "%s: the option -P cannot be specified "
893*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
894*7c478bd9Sstevel@tonic-gate 				usage();
895*7c478bd9Sstevel@tonic-gate 			}
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 			modify_mask |= LAADM_MODIFY_POLICY;
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_policy(optarg, &policy)) {
900*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
901*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid policy '%s'\n"),
902*7c478bd9Sstevel@tonic-gate 				    progname, optarg);
903*7c478bd9Sstevel@tonic-gate 				exit(1);
904*7c478bd9Sstevel@tonic-gate 			}
905*7c478bd9Sstevel@tonic-gate 			break;
906*7c478bd9Sstevel@tonic-gate 		case 'u':
907*7c478bd9Sstevel@tonic-gate 			if (modify_mask & LAADM_MODIFY_MAC) {
908*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
909*7c478bd9Sstevel@tonic-gate 				    "%s: the option -u cannot be specified "
910*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
911*7c478bd9Sstevel@tonic-gate 				usage();
912*7c478bd9Sstevel@tonic-gate 			}
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 			modify_mask |= LAADM_MODIFY_MAC;
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_mac_addr(optarg, &mac_addr_fixed,
917*7c478bd9Sstevel@tonic-gate 			    mac_addr)) {
918*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
919*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid MAC address '%s'\n"),
920*7c478bd9Sstevel@tonic-gate 				    progname, optarg);
921*7c478bd9Sstevel@tonic-gate 				exit(1);
922*7c478bd9Sstevel@tonic-gate 			}
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 			break;
925*7c478bd9Sstevel@tonic-gate 		case 'l':
926*7c478bd9Sstevel@tonic-gate 			if (modify_mask & LAADM_MODIFY_LACP_MODE) {
927*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
928*7c478bd9Sstevel@tonic-gate 				    "%s: the option -l cannot be specified "
929*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
930*7c478bd9Sstevel@tonic-gate 				usage();
931*7c478bd9Sstevel@tonic-gate 			}
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 			modify_mask |= LAADM_MODIFY_LACP_MODE;
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_lacp_mode(optarg, &lacp_mode)) {
936*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
937*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid LACP mode '%s'\n"),
938*7c478bd9Sstevel@tonic-gate 				    progname, optarg);
939*7c478bd9Sstevel@tonic-gate 				exit(1);
940*7c478bd9Sstevel@tonic-gate 			}
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 			break;
943*7c478bd9Sstevel@tonic-gate 		case 'T':
944*7c478bd9Sstevel@tonic-gate 			if (modify_mask & LAADM_MODIFY_LACP_TIMER) {
945*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
946*7c478bd9Sstevel@tonic-gate 				    "%s: the option -T cannot be specified "
947*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
948*7c478bd9Sstevel@tonic-gate 				usage();
949*7c478bd9Sstevel@tonic-gate 			}
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 			modify_mask |= LAADM_MODIFY_LACP_TIMER;
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 			if (!laadm_str_to_lacp_timer(optarg, &lacp_timer)) {
954*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
955*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid LACP timer value"
956*7c478bd9Sstevel@tonic-gate 				    " '%s'\n"),
957*7c478bd9Sstevel@tonic-gate 				    progname, optarg);
958*7c478bd9Sstevel@tonic-gate 				exit(1);
959*7c478bd9Sstevel@tonic-gate 			}
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 			break;
962*7c478bd9Sstevel@tonic-gate 		case 't':
963*7c478bd9Sstevel@tonic-gate 			t_arg = B_TRUE;
964*7c478bd9Sstevel@tonic-gate 			break;
965*7c478bd9Sstevel@tonic-gate 		case 'R':
966*7c478bd9Sstevel@tonic-gate 			altroot = optarg;
967*7c478bd9Sstevel@tonic-gate 			break;
968*7c478bd9Sstevel@tonic-gate 		case ':':
969*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
970*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
971*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
972*7c478bd9Sstevel@tonic-gate 			exit(1);
973*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
974*7c478bd9Sstevel@tonic-gate 		case '?':
975*7c478bd9Sstevel@tonic-gate 		default:
976*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
977*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
978*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
979*7c478bd9Sstevel@tonic-gate 			exit(1);
980*7c478bd9Sstevel@tonic-gate 		}
981*7c478bd9Sstevel@tonic-gate 	}
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	if (modify_mask == 0) {
984*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: at least one of the "
985*7c478bd9Sstevel@tonic-gate 		    "-PulT options must be specified\n"), progname);
986*7c478bd9Sstevel@tonic-gate 		usage();
987*7c478bd9Sstevel@tonic-gate 	}
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 	/* get key value (required last argument) */
990*7c478bd9Sstevel@tonic-gate 	if (optind != (argc-1))
991*7c478bd9Sstevel@tonic-gate 		usage();
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 	errno = 0;
994*7c478bd9Sstevel@tonic-gate 	key = (int)strtol(argv[optind], &endp, 10);
995*7c478bd9Sstevel@tonic-gate 	if (errno != 0 || key < 1 || *endp != '\0') {
996*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
997*7c478bd9Sstevel@tonic-gate 		    gettext("%s: illegal key value '%d'\n"),
998*7c478bd9Sstevel@tonic-gate 		    progname, key);
999*7c478bd9Sstevel@tonic-gate 		exit(1);
1000*7c478bd9Sstevel@tonic-gate 	}
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	if (laadm_modify(key, modify_mask, policy, mac_addr_fixed, mac_addr,
1004*7c478bd9Sstevel@tonic-gate 	    lacp_mode, lacp_timer, t_arg, altroot, &diag) < 0) {
1005*7c478bd9Sstevel@tonic-gate 		PRINT_ERR_DIAG("%s: modify operation failed: %s", diag,
1006*7c478bd9Sstevel@tonic-gate 		    laadm_diag);
1007*7c478bd9Sstevel@tonic-gate 		exit(1);
1008*7c478bd9Sstevel@tonic-gate 	}
1009*7c478bd9Sstevel@tonic-gate }
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate static void
1012*7c478bd9Sstevel@tonic-gate do_up_link(int argc, char *argv[])
1013*7c478bd9Sstevel@tonic-gate {
1014*7c478bd9Sstevel@tonic-gate 	char		*name = NULL;
1015*7c478bd9Sstevel@tonic-gate 	dladm_diag_t	diag = 0;
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 	/* get link name (optional last argument) */
1018*7c478bd9Sstevel@tonic-gate 	if (argc == 2)
1019*7c478bd9Sstevel@tonic-gate 		name = argv[1];
1020*7c478bd9Sstevel@tonic-gate 	else if (argc > 2)
1021*7c478bd9Sstevel@tonic-gate 		usage();
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	if (dladm_up(name, &diag) < 0) {
1024*7c478bd9Sstevel@tonic-gate 		if (name != NULL) {
1025*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1026*7c478bd9Sstevel@tonic-gate 			    gettext("%s: could not bring up link '%s' : %s"),
1027*7c478bd9Sstevel@tonic-gate 			    progname, name, strerror(errno));
1028*7c478bd9Sstevel@tonic-gate 			if (diag != 0)
1029*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, " (%s)",
1030*7c478bd9Sstevel@tonic-gate 				    dladm_diag(diag));
1031*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
1032*7c478bd9Sstevel@tonic-gate 		} else {
1033*7c478bd9Sstevel@tonic-gate 			PRINT_ERR_DIAG("%s: could not bring links up: %s",
1034*7c478bd9Sstevel@tonic-gate 			    diag, dladm_diag);
1035*7c478bd9Sstevel@tonic-gate 		}
1036*7c478bd9Sstevel@tonic-gate 		exit(1);
1037*7c478bd9Sstevel@tonic-gate 	}
1038*7c478bd9Sstevel@tonic-gate }
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate static void
1041*7c478bd9Sstevel@tonic-gate do_up_aggr(int argc, char *argv[])
1042*7c478bd9Sstevel@tonic-gate {
1043*7c478bd9Sstevel@tonic-gate 	uint16_t	key = 0;
1044*7c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
1045*7c478bd9Sstevel@tonic-gate 	laadm_diag_t	diag = 0;
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 	/* get aggregation key (optional last argument) */
1048*7c478bd9Sstevel@tonic-gate 	if (argc == 2) {
1049*7c478bd9Sstevel@tonic-gate 		errno = 0;
1050*7c478bd9Sstevel@tonic-gate 		key = (int)strtol(argv[1], &endp, 10);
1051*7c478bd9Sstevel@tonic-gate 		if (errno != 0 || key < 1 || *endp != '\0') {
1052*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1053*7c478bd9Sstevel@tonic-gate 			    gettext("%s: illegal key value '%d'\n"),
1054*7c478bd9Sstevel@tonic-gate 			    progname, key);
1055*7c478bd9Sstevel@tonic-gate 			exit(1);
1056*7c478bd9Sstevel@tonic-gate 		}
1057*7c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
1058*7c478bd9Sstevel@tonic-gate 		usage();
1059*7c478bd9Sstevel@tonic-gate 	}
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	if (laadm_up(key, NULL, &diag) < 0) {
1062*7c478bd9Sstevel@tonic-gate 		if (key != 0) {
1063*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1064*7c478bd9Sstevel@tonic-gate 			    gettext("%s: could not bring up aggregation"
1065*7c478bd9Sstevel@tonic-gate 			    " '%u' : %s"), progname, key, strerror(errno));
1066*7c478bd9Sstevel@tonic-gate 			if (diag != 0)
1067*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, " (%s)",
1068*7c478bd9Sstevel@tonic-gate 				    laadm_diag(diag));
1069*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
1070*7c478bd9Sstevel@tonic-gate 		} else {
1071*7c478bd9Sstevel@tonic-gate 			PRINT_ERR_DIAG(
1072*7c478bd9Sstevel@tonic-gate 			    "%s: could not bring aggregations up: %s",
1073*7c478bd9Sstevel@tonic-gate 			    diag, laadm_diag);
1074*7c478bd9Sstevel@tonic-gate 		}
1075*7c478bd9Sstevel@tonic-gate 		exit(1);
1076*7c478bd9Sstevel@tonic-gate 	}
1077*7c478bd9Sstevel@tonic-gate }
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate static void
1080*7c478bd9Sstevel@tonic-gate do_down_aggr(int argc, char *argv[])
1081*7c478bd9Sstevel@tonic-gate {
1082*7c478bd9Sstevel@tonic-gate 	uint16_t	key = 0;
1083*7c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	/* get aggregation key (optional last argument) */
1086*7c478bd9Sstevel@tonic-gate 	if (argc == 2) {
1087*7c478bd9Sstevel@tonic-gate 		errno = 0;
1088*7c478bd9Sstevel@tonic-gate 		key = (int)strtol(argv[1], &endp, 10);
1089*7c478bd9Sstevel@tonic-gate 		if (errno != 0 || key < 1 || *endp != '\0') {
1090*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1091*7c478bd9Sstevel@tonic-gate 			    gettext("%s: illegal key value '%d'\n"),
1092*7c478bd9Sstevel@tonic-gate 			    progname, key);
1093*7c478bd9Sstevel@tonic-gate 			exit(1);
1094*7c478bd9Sstevel@tonic-gate 		}
1095*7c478bd9Sstevel@tonic-gate 	} else if (argc > 2) {
1096*7c478bd9Sstevel@tonic-gate 		usage();
1097*7c478bd9Sstevel@tonic-gate 	}
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	if (laadm_down(key) < 0) {
1100*7c478bd9Sstevel@tonic-gate 		if (key != 0) {
1101*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1102*7c478bd9Sstevel@tonic-gate 			    gettext("%s: could not bring aggregation"
1103*7c478bd9Sstevel@tonic-gate 			    " down '%u' : %s"),
1104*7c478bd9Sstevel@tonic-gate 			    progname, key, strerror(errno));
1105*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "\n");
1106*7c478bd9Sstevel@tonic-gate 		} else {
1107*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1108*7c478bd9Sstevel@tonic-gate 			    gettext("%s: could not bring aggregations"
1109*7c478bd9Sstevel@tonic-gate 			    " down: %s"), progname, strerror(errno));
1110*7c478bd9Sstevel@tonic-gate 		}
1111*7c478bd9Sstevel@tonic-gate 		exit(1);
1112*7c478bd9Sstevel@tonic-gate 	}
1113*7c478bd9Sstevel@tonic-gate }
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate static void
1116*7c478bd9Sstevel@tonic-gate create(void *arg, const char *dev, uint_t port)
1117*7c478bd9Sstevel@tonic-gate {
1118*7c478bd9Sstevel@tonic-gate 	dladm_attr_t	dlattr;
1119*7c478bd9Sstevel@tonic-gate 	dladm_diag_t	diag;
1120*7c478bd9Sstevel@tonic-gate 	int		flags;
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	if (port != 0)
1123*7c478bd9Sstevel@tonic-gate 		return;
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 	if (strlcpy(dlattr.da_dev, dev, MAXNAMELEN) >= MAXNAMELEN) {
1126*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1127*7c478bd9Sstevel@tonic-gate 		    gettext("%s: device name too long\n"),
1128*7c478bd9Sstevel@tonic-gate 		    progname);
1129*7c478bd9Sstevel@tonic-gate 		exit(1);
1130*7c478bd9Sstevel@tonic-gate 	}
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	dlattr.da_port = 0;
1133*7c478bd9Sstevel@tonic-gate 	dlattr.da_vid = 0;
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	flags = DLADM_LINK_FORCED;
1136*7c478bd9Sstevel@tonic-gate 	if (arg != NULL)
1137*7c478bd9Sstevel@tonic-gate 		flags |= DLADM_LINK_TEMP;
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 	(void) dladm_link(dlattr.da_dev, &dlattr, flags, NULL, &diag);
1140*7c478bd9Sstevel@tonic-gate }
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1143*7c478bd9Sstevel@tonic-gate static void
1144*7c478bd9Sstevel@tonic-gate do_init_link(int argc, char *argv[])
1145*7c478bd9Sstevel@tonic-gate {
1146*7c478bd9Sstevel@tonic-gate 	if (argc != 1 && strcmp(argv[1], "-t") != 0)
1147*7c478bd9Sstevel@tonic-gate 		usage();
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 	(void) macadm_walk(create, (void *)(argc > 1), B_FALSE);
1150*7c478bd9Sstevel@tonic-gate }
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate #define	TYPE_WIDTH	10
1153*7c478bd9Sstevel@tonic-gate #define	MAC_WIDTH	23
1154*7c478bd9Sstevel@tonic-gate #define	MTU_WIDTH	11
1155*7c478bd9Sstevel@tonic-gate #define	STATE_WIDTH	15
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1158*7c478bd9Sstevel@tonic-gate static void
1159*7c478bd9Sstevel@tonic-gate show_link(void *arg, const char *name)
1160*7c478bd9Sstevel@tonic-gate {
1161*7c478bd9Sstevel@tonic-gate 	dladm_attr_t	dlattr;
1162*7c478bd9Sstevel@tonic-gate 	char		type[TYPE_WIDTH];
1163*7c478bd9Sstevel@tonic-gate 	int		fd;
1164*7c478bd9Sstevel@tonic-gate 	dlpi_if_attr_t	dia;
1165*7c478bd9Sstevel@tonic-gate 	dl_info_ack_t	dlia;
1166*7c478bd9Sstevel@tonic-gate 	t_uscalar_t	dl_max_sdu;
1167*7c478bd9Sstevel@tonic-gate 	show_link_state_t *state = (show_link_state_t *)arg;
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 	if ((fd = dlpi_if_open(name, &dia, B_FALSE)) != -1 &&
1170*7c478bd9Sstevel@tonic-gate 	    dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL,
1171*7c478bd9Sstevel@tonic-gate 	    NULL, NULL) != -1) {
1172*7c478bd9Sstevel@tonic-gate 		(void) dlpi_close(fd);
1173*7c478bd9Sstevel@tonic-gate 		dl_max_sdu = dlia.dl_max_sdu;
1174*7c478bd9Sstevel@tonic-gate 	} else {
1175*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1176*7c478bd9Sstevel@tonic-gate 		    gettext("%s: invalid device '%s'\n"),
1177*7c478bd9Sstevel@tonic-gate 		    progname, name);
1178*7c478bd9Sstevel@tonic-gate 		exit(1);
1179*7c478bd9Sstevel@tonic-gate 	}
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 	if (dladm_info(name, &dlattr) < 0) {
1182*7c478bd9Sstevel@tonic-gate 		if (!state->ls_parseable) {
1183*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("%-9s\ttype: legacy"
1184*7c478bd9Sstevel@tonic-gate 			    "\tmtu: %d\tdevice: %s\n"),
1185*7c478bd9Sstevel@tonic-gate 			    name, (int)dl_max_sdu, name);
1186*7c478bd9Sstevel@tonic-gate 		} else {
1187*7c478bd9Sstevel@tonic-gate 			(void) printf("%s type=legacy mtu=%d device=%s\n",
1188*7c478bd9Sstevel@tonic-gate 			    name, (int)dl_max_sdu, name);
1189*7c478bd9Sstevel@tonic-gate 		}
1190*7c478bd9Sstevel@tonic-gate 	} else {
1191*7c478bd9Sstevel@tonic-gate 		if (dlattr.da_vid != 0) {
1192*7c478bd9Sstevel@tonic-gate 			(void) snprintf(type, TYPE_WIDTH,
1193*7c478bd9Sstevel@tonic-gate 			    state->ls_parseable ? "vlan %u" :
1194*7c478bd9Sstevel@tonic-gate 			    gettext("vlan %u"), dlattr.da_vid);
1195*7c478bd9Sstevel@tonic-gate 		} else {
1196*7c478bd9Sstevel@tonic-gate 			(void) snprintf(type, TYPE_WIDTH,
1197*7c478bd9Sstevel@tonic-gate 			    state->ls_parseable ? "non-vlan" :
1198*7c478bd9Sstevel@tonic-gate 			    gettext("non-vlan"));
1199*7c478bd9Sstevel@tonic-gate 		}
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate 		if (strcmp(dlattr.da_dev, AGGR_DEV) == 0) {
1202*7c478bd9Sstevel@tonic-gate 			if (!state->ls_parseable) {
1203*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("%-9s\ttype: %s"
1204*7c478bd9Sstevel@tonic-gate 				    "\tmtu: %d\taggregation: key %u\n"),
1205*7c478bd9Sstevel@tonic-gate 				    name, type, (int)dl_max_sdu,
1206*7c478bd9Sstevel@tonic-gate 				    dlattr.da_port);
1207*7c478bd9Sstevel@tonic-gate 			} else {
1208*7c478bd9Sstevel@tonic-gate 				(void) printf("%s type=%s mtu=%d key=%u\n",
1209*7c478bd9Sstevel@tonic-gate 				    name, type, (int)dl_max_sdu,
1210*7c478bd9Sstevel@tonic-gate 				    dlattr.da_port);
1211*7c478bd9Sstevel@tonic-gate 			}
1212*7c478bd9Sstevel@tonic-gate 		} else {
1213*7c478bd9Sstevel@tonic-gate 			if (!state->ls_parseable) {
1214*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("%-9s\ttype: %s"
1215*7c478bd9Sstevel@tonic-gate 				    "\tmtu: %d\tdevice: %s\n"),
1216*7c478bd9Sstevel@tonic-gate 				    name, type, (int)dl_max_sdu,
1217*7c478bd9Sstevel@tonic-gate 				    dlattr.da_dev);
1218*7c478bd9Sstevel@tonic-gate 			} else {
1219*7c478bd9Sstevel@tonic-gate 				(void) printf("%s type=%s mtu=%d device=%s\n",
1220*7c478bd9Sstevel@tonic-gate 				    name, type, (int)dl_max_sdu, dlattr.da_dev);
1221*7c478bd9Sstevel@tonic-gate 			}
1222*7c478bd9Sstevel@tonic-gate 		}
1223*7c478bd9Sstevel@tonic-gate 	}
1224*7c478bd9Sstevel@tonic-gate }
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate static void
1227*7c478bd9Sstevel@tonic-gate show_link_stats(void *arg, const char *name)
1228*7c478bd9Sstevel@tonic-gate {
1229*7c478bd9Sstevel@tonic-gate 	show_link_state_t *state = (show_link_state_t *)arg;
1230*7c478bd9Sstevel@tonic-gate 	pktsum_t stats, diff_stats;
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	if (state->ls_firstonly) {
1233*7c478bd9Sstevel@tonic-gate 		if (state->ls_donefirst)
1234*7c478bd9Sstevel@tonic-gate 			return;
1235*7c478bd9Sstevel@tonic-gate 		state->ls_donefirst = B_TRUE;
1236*7c478bd9Sstevel@tonic-gate 	} else {
1237*7c478bd9Sstevel@tonic-gate 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
1238*7c478bd9Sstevel@tonic-gate 	}
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	get_link_stats(name, &stats);
1241*7c478bd9Sstevel@tonic-gate 	stats_diff(&diff_stats, &stats, &state->ls_prevstats);
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	(void) printf("%s", name);
1244*7c478bd9Sstevel@tonic-gate 	(void) printf("\t\t%-10llu", diff_stats.ipackets);
1245*7c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.rbytes);
1246*7c478bd9Sstevel@tonic-gate 	(void) printf("%-8u", diff_stats.ierrors);
1247*7c478bd9Sstevel@tonic-gate 	(void) printf("%-10llu", diff_stats.opackets);
1248*7c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.obytes);
1249*7c478bd9Sstevel@tonic-gate 	(void) printf("%-8u\n", diff_stats.oerrors);
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 	state->ls_prevstats = stats;
1252*7c478bd9Sstevel@tonic-gate }
1253*7c478bd9Sstevel@tonic-gate 
1254*7c478bd9Sstevel@tonic-gate static void
1255*7c478bd9Sstevel@tonic-gate dump_grp(laadm_grp_attr_sys_t	*grp, boolean_t parseable)
1256*7c478bd9Sstevel@tonic-gate {
1257*7c478bd9Sstevel@tonic-gate 	char policy_str[LAADM_POLICY_STR_LEN];
1258*7c478bd9Sstevel@tonic-gate 	char addr_str[ETHERADDRL * 3];
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 	if (!parseable) {
1261*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("key: %d (0x%04x)"),
1262*7c478bd9Sstevel@tonic-gate 		    grp->lg_key, grp->lg_key);
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tpolicy: %s"),
1265*7c478bd9Sstevel@tonic-gate 		    laadm_policy_to_str(grp->lg_policy, policy_str));
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\taddress: %s (%s)\n"),
1268*7c478bd9Sstevel@tonic-gate 		    laadm_mac_addr_to_str(grp->lg_mac, addr_str),
1269*7c478bd9Sstevel@tonic-gate 		    (grp->lg_mac_fixed) ? gettext("fixed") : gettext("auto"));
1270*7c478bd9Sstevel@tonic-gate 	} else {
1271*7c478bd9Sstevel@tonic-gate 		(void) printf("aggr key=%d", grp->lg_key);
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate 		(void) printf(" policy=%s",
1274*7c478bd9Sstevel@tonic-gate 		    laadm_policy_to_str(grp->lg_policy, policy_str));
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 		(void) printf(" address=%s",
1277*7c478bd9Sstevel@tonic-gate 		    laadm_mac_addr_to_str(grp->lg_mac, addr_str));
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 		(void) printf(" address-type=%s\n",
1280*7c478bd9Sstevel@tonic-gate 		    (grp->lg_mac_fixed) ? "fixed" : "auto");
1281*7c478bd9Sstevel@tonic-gate 	}
1282*7c478bd9Sstevel@tonic-gate }
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate static void
1285*7c478bd9Sstevel@tonic-gate dump_grp_lacp(laadm_grp_attr_sys_t *grp, boolean_t parseable)
1286*7c478bd9Sstevel@tonic-gate {
1287*7c478bd9Sstevel@tonic-gate 	const char *lacp_mode_str = laadm_lacp_mode_to_str(grp->lg_lacp_mode);
1288*7c478bd9Sstevel@tonic-gate 	const char *lacp_timer_str =
1289*7c478bd9Sstevel@tonic-gate 	    laadm_lacp_timer_to_str(grp->lg_lacp_timer);
1290*7c478bd9Sstevel@tonic-gate 
1291*7c478bd9Sstevel@tonic-gate 	if (!parseable) {
1292*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\t\tLACP mode: %s"), lacp_mode_str);
1293*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tLACP timer: %s\n"), lacp_timer_str);
1294*7c478bd9Sstevel@tonic-gate 	} else {
1295*7c478bd9Sstevel@tonic-gate 		(void) printf(" lacp-mode=%s", lacp_mode_str);
1296*7c478bd9Sstevel@tonic-gate 		(void) printf(" lacp-timer=%s\n", lacp_timer_str);
1297*7c478bd9Sstevel@tonic-gate 	}
1298*7c478bd9Sstevel@tonic-gate }
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate static void
1301*7c478bd9Sstevel@tonic-gate dump_grp_stats(laadm_grp_attr_sys_t *grp)
1302*7c478bd9Sstevel@tonic-gate {
1303*7c478bd9Sstevel@tonic-gate 	(void) printf("key: %d", grp->lg_key);
1304*7c478bd9Sstevel@tonic-gate 	(void) printf("\tipackets  rbytes      opackets	 obytes		 ");
1305*7c478bd9Sstevel@tonic-gate 	(void) printf("%%ipkts	%%opkts\n");
1306*7c478bd9Sstevel@tonic-gate }
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate static void
1309*7c478bd9Sstevel@tonic-gate dump_ports_lacp_head(void)
1310*7c478bd9Sstevel@tonic-gate {
1311*7c478bd9Sstevel@tonic-gate 	(void) printf(DUMP_LACP_FORMAT, gettext("device"), gettext("activity"),
1312*7c478bd9Sstevel@tonic-gate 	    gettext("timeout"), gettext("aggregatable"), gettext("sync"),
1313*7c478bd9Sstevel@tonic-gate 	    gettext("coll"), gettext("dist"), gettext("defaulted"),
1314*7c478bd9Sstevel@tonic-gate 	    gettext("expired"));
1315*7c478bd9Sstevel@tonic-gate }
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate static void
1318*7c478bd9Sstevel@tonic-gate dump_ports_head(void)
1319*7c478bd9Sstevel@tonic-gate {
1320*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("	   device\taddress\t\t	speed\t\tduplex\tlink\t"
1321*7c478bd9Sstevel@tonic-gate 	    "state\n"));
1322*7c478bd9Sstevel@tonic-gate }
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate static char *
1325*7c478bd9Sstevel@tonic-gate port_state_to_str(aggr_port_state_t state_num)
1326*7c478bd9Sstevel@tonic-gate {
1327*7c478bd9Sstevel@tonic-gate 	int			i;
1328*7c478bd9Sstevel@tonic-gate 	port_state_t		*state;
1329*7c478bd9Sstevel@tonic-gate 
1330*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NPORTSTATES; i++) {
1331*7c478bd9Sstevel@tonic-gate 		state = &port_states[i];
1332*7c478bd9Sstevel@tonic-gate 		if (state->state_num == state_num)
1333*7c478bd9Sstevel@tonic-gate 			return (state->state_name);
1334*7c478bd9Sstevel@tonic-gate 	}
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 	return ("unknown");
1337*7c478bd9Sstevel@tonic-gate }
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate static void
1340*7c478bd9Sstevel@tonic-gate dump_port(laadm_port_attr_sys_t *port, boolean_t parseable)
1341*7c478bd9Sstevel@tonic-gate {
1342*7c478bd9Sstevel@tonic-gate 	char *dev = port->lp_devname;
1343*7c478bd9Sstevel@tonic-gate 	uint_t portnum = port->lp_port;
1344*7c478bd9Sstevel@tonic-gate 	char buf[ETHERADDRL * 3];
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	if (!parseable) {
1347*7c478bd9Sstevel@tonic-gate 		(void) printf("	   %-9s\t%s", dev, laadm_mac_addr_to_str(
1348*7c478bd9Sstevel@tonic-gate 		    port->lp_mac, buf));
1349*7c478bd9Sstevel@tonic-gate 		(void) printf("\t  %-5u Mbps", (int)(mac_ifspeed(dev, portnum) /
1350*7c478bd9Sstevel@tonic-gate 		    1000000ull));
1351*7c478bd9Sstevel@tonic-gate 		(void) printf("\t%s", mac_link_duplex(dev, portnum));
1352*7c478bd9Sstevel@tonic-gate 		(void) printf("\t%s", mac_link_state(dev, portnum));
1353*7c478bd9Sstevel@tonic-gate 		(void) printf("\t%s\n", port_state_to_str(port->lp_state));
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	} else {
1356*7c478bd9Sstevel@tonic-gate 		(void) printf(" device=%s address=%s", dev,
1357*7c478bd9Sstevel@tonic-gate 		    laadm_mac_addr_to_str(port->lp_mac, buf));
1358*7c478bd9Sstevel@tonic-gate 		(void) printf(" speed=%u", (int)(mac_ifspeed(dev, portnum) /
1359*7c478bd9Sstevel@tonic-gate 		    1000000ull));
1360*7c478bd9Sstevel@tonic-gate 		(void) printf(" duplex=%s", mac_link_duplex(dev, portnum));
1361*7c478bd9Sstevel@tonic-gate 		(void) printf(" link=%s", mac_link_state(dev, portnum));
1362*7c478bd9Sstevel@tonic-gate 		(void) printf(" port=%s", port_state_to_str(port->lp_state));
1363*7c478bd9Sstevel@tonic-gate 	}
1364*7c478bd9Sstevel@tonic-gate }
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate static void
1367*7c478bd9Sstevel@tonic-gate dump_port_lacp(laadm_port_attr_sys_t *port)
1368*7c478bd9Sstevel@tonic-gate {
1369*7c478bd9Sstevel@tonic-gate 	aggr_lacp_state_t *state = &port->lp_lacp_state;
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 	(void) printf(DUMP_LACP_FORMAT,
1372*7c478bd9Sstevel@tonic-gate 	    port->lp_devname, state->bit.activity ? "active" : "passive",
1373*7c478bd9Sstevel@tonic-gate 	    state->bit.timeout ? "short" : "long",
1374*7c478bd9Sstevel@tonic-gate 	    state->bit.aggregation ? "yes" : "no",
1375*7c478bd9Sstevel@tonic-gate 	    state->bit.sync ? "yes" : "no",
1376*7c478bd9Sstevel@tonic-gate 	    state->bit.collecting ? "yes" : "no",
1377*7c478bd9Sstevel@tonic-gate 	    state->bit.distributing ? "yes" : "no",
1378*7c478bd9Sstevel@tonic-gate 	    state->bit.defaulted ? "yes" : "no",
1379*7c478bd9Sstevel@tonic-gate 	    state->bit.expired ? "yes" : "no");
1380*7c478bd9Sstevel@tonic-gate }
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate static void
1383*7c478bd9Sstevel@tonic-gate dump_port_stat(int index, show_grp_state_t *state, pktsum_t *port_stats,
1384*7c478bd9Sstevel@tonic-gate     pktsum_t *tot_stats)
1385*7c478bd9Sstevel@tonic-gate {
1386*7c478bd9Sstevel@tonic-gate 	pktsum_t	diff_stats;
1387*7c478bd9Sstevel@tonic-gate 	pktsum_t	*old_stats = &state->gs_prevstats[index];
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate 	stats_diff(&diff_stats, port_stats, old_stats);
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate 	(void) printf("\t%-10llu", diff_stats.ipackets);
1392*7c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.rbytes);
1393*7c478bd9Sstevel@tonic-gate 	(void) printf("%-10llu", diff_stats.opackets);
1394*7c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.obytes);
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 	if (tot_stats->ipackets == 0)
1397*7c478bd9Sstevel@tonic-gate 		(void) printf("\t-");
1398*7c478bd9Sstevel@tonic-gate 	else
1399*7c478bd9Sstevel@tonic-gate 		(void) printf("\t%-6.1f", (double)diff_stats.ipackets/
1400*7c478bd9Sstevel@tonic-gate 		    (double)tot_stats->ipackets * 100);
1401*7c478bd9Sstevel@tonic-gate 
1402*7c478bd9Sstevel@tonic-gate 	if (tot_stats->opackets == 0)
1403*7c478bd9Sstevel@tonic-gate 		(void) printf("\t-");
1404*7c478bd9Sstevel@tonic-gate 	else
1405*7c478bd9Sstevel@tonic-gate 		(void) printf("\t%-6.1f", (double)diff_stats.opackets/
1406*7c478bd9Sstevel@tonic-gate 		    (double)tot_stats->opackets * 100);
1407*7c478bd9Sstevel@tonic-gate 
1408*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
1409*7c478bd9Sstevel@tonic-gate 
1410*7c478bd9Sstevel@tonic-gate 	*old_stats = *port_stats;
1411*7c478bd9Sstevel@tonic-gate }
1412*7c478bd9Sstevel@tonic-gate 
1413*7c478bd9Sstevel@tonic-gate static int
1414*7c478bd9Sstevel@tonic-gate show_key(void *arg, laadm_grp_attr_sys_t *grp)
1415*7c478bd9Sstevel@tonic-gate {
1416*7c478bd9Sstevel@tonic-gate 	show_grp_state_t	*state = (show_grp_state_t *)arg;
1417*7c478bd9Sstevel@tonic-gate 	int			i;
1418*7c478bd9Sstevel@tonic-gate 	pktsum_t		pktsumtot, port_stat;
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate 	if (state->gs_key != 0 && state->gs_key != grp->lg_key)
1421*7c478bd9Sstevel@tonic-gate 		return (0);
1422*7c478bd9Sstevel@tonic-gate 	if (state->gs_firstonly) {
1423*7c478bd9Sstevel@tonic-gate 		if (state->gs_found)
1424*7c478bd9Sstevel@tonic-gate 			return (0);
1425*7c478bd9Sstevel@tonic-gate 	} else {
1426*7c478bd9Sstevel@tonic-gate 		bzero(&state->gs_prevstats, sizeof (state->gs_prevstats));
1427*7c478bd9Sstevel@tonic-gate 	}
1428*7c478bd9Sstevel@tonic-gate 
1429*7c478bd9Sstevel@tonic-gate 	state->gs_found = B_TRUE;
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate 	if (state->gs_stats) {
1432*7c478bd9Sstevel@tonic-gate 		/* show statistics */
1433*7c478bd9Sstevel@tonic-gate 		dump_grp_stats(grp);
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 		/* sum the ports statistics */
1436*7c478bd9Sstevel@tonic-gate 		bzero(&pktsumtot, sizeof (pktsumtot));
1437*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < grp->lg_nports; i++) {
1438*7c478bd9Sstevel@tonic-gate 			get_mac_stats(grp->lg_ports[i].lp_devname,
1439*7c478bd9Sstevel@tonic-gate 			    grp->lg_ports[i].lp_port, &port_stat);
1440*7c478bd9Sstevel@tonic-gate 			stats_total(&pktsumtot, &port_stat,
1441*7c478bd9Sstevel@tonic-gate 			    &state->gs_prevstats[i]);
1442*7c478bd9Sstevel@tonic-gate 		}
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate 		(void) printf("	   Total");
1445*7c478bd9Sstevel@tonic-gate 		(void) printf("\t%-10llu", pktsumtot.ipackets);
1446*7c478bd9Sstevel@tonic-gate 		(void) printf("%-12llu", pktsumtot.rbytes);
1447*7c478bd9Sstevel@tonic-gate 		(void) printf("%-10llu", pktsumtot.opackets);
1448*7c478bd9Sstevel@tonic-gate 		(void) printf("%-12llu\n", pktsumtot.obytes);
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < grp->lg_nports; i++) {
1451*7c478bd9Sstevel@tonic-gate 			get_mac_stats(grp->lg_ports[i].lp_devname,
1452*7c478bd9Sstevel@tonic-gate 			    grp->lg_ports[i].lp_port, &port_stat);
1453*7c478bd9Sstevel@tonic-gate 			(void) printf("	   %s", grp->lg_ports[i].lp_devname);
1454*7c478bd9Sstevel@tonic-gate 			dump_port_stat(i, state, &port_stat, &pktsumtot);
1455*7c478bd9Sstevel@tonic-gate 		}
1456*7c478bd9Sstevel@tonic-gate 	} else if (state->gs_lacp) {
1457*7c478bd9Sstevel@tonic-gate 		/* show LACP info */
1458*7c478bd9Sstevel@tonic-gate 		dump_grp(grp, state->gs_parseable);
1459*7c478bd9Sstevel@tonic-gate 		dump_grp_lacp(grp, state->gs_parseable);
1460*7c478bd9Sstevel@tonic-gate 		dump_ports_lacp_head();
1461*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < grp->lg_nports; i++)
1462*7c478bd9Sstevel@tonic-gate 			dump_port_lacp(&grp->lg_ports[i]);
1463*7c478bd9Sstevel@tonic-gate 	} else {
1464*7c478bd9Sstevel@tonic-gate 		dump_grp(grp, state->gs_parseable);
1465*7c478bd9Sstevel@tonic-gate 		if (!state->gs_parseable)
1466*7c478bd9Sstevel@tonic-gate 			dump_ports_head();
1467*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < grp->lg_nports; i++) {
1468*7c478bd9Sstevel@tonic-gate 			if (state->gs_parseable)
1469*7c478bd9Sstevel@tonic-gate 				(void) printf("dev key=%d", grp->lg_key);
1470*7c478bd9Sstevel@tonic-gate 			dump_port(&grp->lg_ports[i], state->gs_parseable);
1471*7c478bd9Sstevel@tonic-gate 			if (state->gs_parseable)
1472*7c478bd9Sstevel@tonic-gate 				(void) printf("\n");
1473*7c478bd9Sstevel@tonic-gate 		}
1474*7c478bd9Sstevel@tonic-gate 	}
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 	return (0);
1477*7c478bd9Sstevel@tonic-gate }
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate static int
1480*7c478bd9Sstevel@tonic-gate kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
1481*7c478bd9Sstevel@tonic-gate {
1482*7c478bd9Sstevel@tonic-gate 	kstat_named_t	*knp;
1483*7c478bd9Sstevel@tonic-gate 
1484*7c478bd9Sstevel@tonic-gate 	if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
1485*7c478bd9Sstevel@tonic-gate 		return (-1);
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate 	if (knp->data_type != type)
1488*7c478bd9Sstevel@tonic-gate 		return (-1);
1489*7c478bd9Sstevel@tonic-gate 
1490*7c478bd9Sstevel@tonic-gate 	switch (type) {
1491*7c478bd9Sstevel@tonic-gate 	case KSTAT_DATA_UINT64:
1492*7c478bd9Sstevel@tonic-gate 		*(uint64_t *)buf = knp->value.ui64;
1493*7c478bd9Sstevel@tonic-gate 		break;
1494*7c478bd9Sstevel@tonic-gate 	case KSTAT_DATA_UINT32:
1495*7c478bd9Sstevel@tonic-gate 		*(uint32_t *)buf = knp->value.ui32;
1496*7c478bd9Sstevel@tonic-gate 		break;
1497*7c478bd9Sstevel@tonic-gate 	default:
1498*7c478bd9Sstevel@tonic-gate 		return (-1);
1499*7c478bd9Sstevel@tonic-gate 	}
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate 	return (0);
1502*7c478bd9Sstevel@tonic-gate }
1503*7c478bd9Sstevel@tonic-gate 
1504*7c478bd9Sstevel@tonic-gate static void
1505*7c478bd9Sstevel@tonic-gate show_dev(void *arg, const char *dev, uint_t port)
1506*7c478bd9Sstevel@tonic-gate {
1507*7c478bd9Sstevel@tonic-gate 	show_mac_state_t	*state = (show_mac_state_t *)arg;
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate 	/* aggregations are already managed by a set of subcommands */
1510*7c478bd9Sstevel@tonic-gate 	if (strcmp(dev, AGGR_DEV) == 0)
1511*7c478bd9Sstevel@tonic-gate 		return;
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate 	(void) printf("%s", dev);
1514*7c478bd9Sstevel@tonic-gate 	if (port != 0)
1515*7c478bd9Sstevel@tonic-gate 		(void) printf("/%d", port);
1516*7c478bd9Sstevel@tonic-gate 
1517*7c478bd9Sstevel@tonic-gate 	if (!state->ms_parseable) {
1518*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\t\tlink: %s"),
1519*7c478bd9Sstevel@tonic-gate 		    mac_link_state(dev, port));
1520*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tspeed: %-5u Mbps"),
1521*7c478bd9Sstevel@tonic-gate 		    (unsigned int)(mac_ifspeed(dev, port) / 1000000ull));
1522*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("\tduplex: %s\n"),
1523*7c478bd9Sstevel@tonic-gate 		    mac_link_duplex(dev, port));
1524*7c478bd9Sstevel@tonic-gate 	} else {
1525*7c478bd9Sstevel@tonic-gate 		(void) printf(" link=%s", mac_link_state(dev, port));
1526*7c478bd9Sstevel@tonic-gate 		(void) printf(" speed=%u",
1527*7c478bd9Sstevel@tonic-gate 		    (unsigned int)(mac_ifspeed(dev, port) / 1000000ull));
1528*7c478bd9Sstevel@tonic-gate 		(void) printf(" duplex=%s\n", mac_link_duplex(dev, port));
1529*7c478bd9Sstevel@tonic-gate 	}
1530*7c478bd9Sstevel@tonic-gate }
1531*7c478bd9Sstevel@tonic-gate 
1532*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1533*7c478bd9Sstevel@tonic-gate static void
1534*7c478bd9Sstevel@tonic-gate show_dev_stats(void *arg, const char *dev, uint_t port)
1535*7c478bd9Sstevel@tonic-gate {
1536*7c478bd9Sstevel@tonic-gate 	show_mac_state_t *state = (show_mac_state_t *)arg;
1537*7c478bd9Sstevel@tonic-gate 	pktsum_t stats, diff_stats;
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate 	/* aggregations are already managed by a set of subcommands */
1540*7c478bd9Sstevel@tonic-gate 	if (strcmp(dev, AGGR_DEV) == 0)
1541*7c478bd9Sstevel@tonic-gate 		return;
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 	if (state->ms_firstonly) {
1544*7c478bd9Sstevel@tonic-gate 		if (state->ms_donefirst)
1545*7c478bd9Sstevel@tonic-gate 			return;
1546*7c478bd9Sstevel@tonic-gate 		state->ms_donefirst = B_TRUE;
1547*7c478bd9Sstevel@tonic-gate 	} else {
1548*7c478bd9Sstevel@tonic-gate 		bzero(&state->ms_prevstats, sizeof (state->ms_prevstats));
1549*7c478bd9Sstevel@tonic-gate 	}
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate 	get_mac_stats(dev, port, &stats);
1552*7c478bd9Sstevel@tonic-gate 	stats_diff(&diff_stats, &stats, &state->ms_prevstats);
1553*7c478bd9Sstevel@tonic-gate 
1554*7c478bd9Sstevel@tonic-gate 	(void) printf("%s", dev);
1555*7c478bd9Sstevel@tonic-gate 	if (port != 0)
1556*7c478bd9Sstevel@tonic-gate 		(void) printf("/%d", port);
1557*7c478bd9Sstevel@tonic-gate 	(void) printf("\t\t%-10llu", diff_stats.ipackets);
1558*7c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.rbytes);
1559*7c478bd9Sstevel@tonic-gate 	(void) printf("%-8u", diff_stats.ierrors);
1560*7c478bd9Sstevel@tonic-gate 	(void) printf("%-10llu", diff_stats.opackets);
1561*7c478bd9Sstevel@tonic-gate 	(void) printf("%-12llu", diff_stats.obytes);
1562*7c478bd9Sstevel@tonic-gate 	(void) printf("%-8u\n", diff_stats.oerrors);
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate 	state->ms_prevstats = stats;
1565*7c478bd9Sstevel@tonic-gate }
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate static void
1568*7c478bd9Sstevel@tonic-gate do_show_link(int argc, char *argv[])
1569*7c478bd9Sstevel@tonic-gate {
1570*7c478bd9Sstevel@tonic-gate 	char		*name = NULL;
1571*7c478bd9Sstevel@tonic-gate 	int		option;
1572*7c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
1573*7c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
1574*7c478bd9Sstevel@tonic-gate 	uint32_t	interval = 0;
1575*7c478bd9Sstevel@tonic-gate 	show_link_state_t state;
1576*7c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
1577*7c478bd9Sstevel@tonic-gate 
1578*7c478bd9Sstevel@tonic-gate 	state.ls_stats = B_FALSE;
1579*7c478bd9Sstevel@tonic-gate 	state.ls_parseable = B_FALSE;
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate 	opterr = 0;
1582*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":psi:",
1583*7c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
1584*7c478bd9Sstevel@tonic-gate 		switch (option) {
1585*7c478bd9Sstevel@tonic-gate 		case 'p':
1586*7c478bd9Sstevel@tonic-gate 			state.ls_parseable = B_TRUE;
1587*7c478bd9Sstevel@tonic-gate 			break;
1588*7c478bd9Sstevel@tonic-gate 		case 's':
1589*7c478bd9Sstevel@tonic-gate 			if (s_arg) {
1590*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1591*7c478bd9Sstevel@tonic-gate 				    "%s: the option -s cannot be specified "
1592*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
1593*7c478bd9Sstevel@tonic-gate 				usage();
1594*7c478bd9Sstevel@tonic-gate 			}
1595*7c478bd9Sstevel@tonic-gate 
1596*7c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
1597*7c478bd9Sstevel@tonic-gate 			break;
1598*7c478bd9Sstevel@tonic-gate 		case 'i':
1599*7c478bd9Sstevel@tonic-gate 			if (i_arg) {
1600*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1601*7c478bd9Sstevel@tonic-gate 				    "%s: the option -i cannot be specified "
1602*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
1603*7c478bd9Sstevel@tonic-gate 				usage();
1604*7c478bd9Sstevel@tonic-gate 			}
1605*7c478bd9Sstevel@tonic-gate 
1606*7c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
1607*7c478bd9Sstevel@tonic-gate 
1608*7c478bd9Sstevel@tonic-gate 			errno = 0;
1609*7c478bd9Sstevel@tonic-gate 			interval = (int)strtol(optarg, &endp, 10);
1610*7c478bd9Sstevel@tonic-gate 			if (errno != 0 || interval == 0 || *endp != '\0') {
1611*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1612*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid interval value"
1613*7c478bd9Sstevel@tonic-gate 				    " '%d'\n"),
1614*7c478bd9Sstevel@tonic-gate 				    progname, interval);
1615*7c478bd9Sstevel@tonic-gate 				exit(1);
1616*7c478bd9Sstevel@tonic-gate 			}
1617*7c478bd9Sstevel@tonic-gate 			break;
1618*7c478bd9Sstevel@tonic-gate 		case ':':
1619*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1620*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
1621*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
1622*7c478bd9Sstevel@tonic-gate 			exit(1);
1623*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1624*7c478bd9Sstevel@tonic-gate 		case '?':
1625*7c478bd9Sstevel@tonic-gate 		default:
1626*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1627*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
1628*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
1629*7c478bd9Sstevel@tonic-gate 			exit(1);
1630*7c478bd9Sstevel@tonic-gate 		}
1631*7c478bd9Sstevel@tonic-gate 	}
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate 	if (i_arg && !s_arg) {
1634*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: the option -i "
1635*7c478bd9Sstevel@tonic-gate 		    "can be used only with -s\n"), progname);
1636*7c478bd9Sstevel@tonic-gate 		usage();
1637*7c478bd9Sstevel@tonic-gate 	}
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate 	/* get link name (optional last argument) */
1641*7c478bd9Sstevel@tonic-gate 	if (optind == (argc-1))
1642*7c478bd9Sstevel@tonic-gate 		name = argv[optind];
1643*7c478bd9Sstevel@tonic-gate 	else if (optind != argc)
1644*7c478bd9Sstevel@tonic-gate 		usage();
1645*7c478bd9Sstevel@tonic-gate 
1646*7c478bd9Sstevel@tonic-gate 	if (s_arg) {
1647*7c478bd9Sstevel@tonic-gate 		link_stats(name, interval);
1648*7c478bd9Sstevel@tonic-gate 		return;
1649*7c478bd9Sstevel@tonic-gate 	}
1650*7c478bd9Sstevel@tonic-gate 
1651*7c478bd9Sstevel@tonic-gate 	if (name == NULL)
1652*7c478bd9Sstevel@tonic-gate 		(void) dladm_walk(show_link, &state);
1653*7c478bd9Sstevel@tonic-gate 	else
1654*7c478bd9Sstevel@tonic-gate 		show_link(&state, name);
1655*7c478bd9Sstevel@tonic-gate }
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate static void
1658*7c478bd9Sstevel@tonic-gate do_show_aggr(int argc, char *argv[])
1659*7c478bd9Sstevel@tonic-gate {
1660*7c478bd9Sstevel@tonic-gate 	int			option;
1661*7c478bd9Sstevel@tonic-gate 	uint16_t		key = 0;
1662*7c478bd9Sstevel@tonic-gate 	boolean_t		L_arg = B_FALSE;
1663*7c478bd9Sstevel@tonic-gate 	boolean_t		s_arg = B_FALSE;
1664*7c478bd9Sstevel@tonic-gate 	boolean_t		i_arg = B_FALSE;
1665*7c478bd9Sstevel@tonic-gate 	show_grp_state_t	state;
1666*7c478bd9Sstevel@tonic-gate 	uint32_t		interval = 0;
1667*7c478bd9Sstevel@tonic-gate 	char			*endp = NULL;
1668*7c478bd9Sstevel@tonic-gate 
1669*7c478bd9Sstevel@tonic-gate 	state.gs_stats = B_FALSE;
1670*7c478bd9Sstevel@tonic-gate 	state.gs_lacp = B_FALSE;
1671*7c478bd9Sstevel@tonic-gate 	state.gs_parseable = B_FALSE;
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate 	opterr = 0;
1674*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":Lpsi:",
1675*7c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
1676*7c478bd9Sstevel@tonic-gate 		switch (option) {
1677*7c478bd9Sstevel@tonic-gate 		case 'L':
1678*7c478bd9Sstevel@tonic-gate 			if (L_arg) {
1679*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1680*7c478bd9Sstevel@tonic-gate 				    "%s: the option -L cannot be specified "
1681*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
1682*7c478bd9Sstevel@tonic-gate 				usage();
1683*7c478bd9Sstevel@tonic-gate 			}
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate 			if (s_arg || i_arg) {
1686*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1687*7c478bd9Sstevel@tonic-gate 				    "%s: the option -L cannot be used with "
1688*7c478bd9Sstevel@tonic-gate 				    "any of -is\n"), progname);
1689*7c478bd9Sstevel@tonic-gate 				usage();
1690*7c478bd9Sstevel@tonic-gate 			}
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 			L_arg = B_TRUE;
1693*7c478bd9Sstevel@tonic-gate 
1694*7c478bd9Sstevel@tonic-gate 			state.gs_lacp = B_TRUE;
1695*7c478bd9Sstevel@tonic-gate 			break;
1696*7c478bd9Sstevel@tonic-gate 		case 'p':
1697*7c478bd9Sstevel@tonic-gate 			state.gs_parseable = B_TRUE;
1698*7c478bd9Sstevel@tonic-gate 			break;
1699*7c478bd9Sstevel@tonic-gate 		case 's':
1700*7c478bd9Sstevel@tonic-gate 			if (s_arg) {
1701*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1702*7c478bd9Sstevel@tonic-gate 				    "%s: the option -s cannot be specified "
1703*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
1704*7c478bd9Sstevel@tonic-gate 				usage();
1705*7c478bd9Sstevel@tonic-gate 			}
1706*7c478bd9Sstevel@tonic-gate 
1707*7c478bd9Sstevel@tonic-gate 			if (L_arg) {
1708*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1709*7c478bd9Sstevel@tonic-gate 				    "%s: the option -L cannot be used "
1710*7c478bd9Sstevel@tonic-gate 				    "with -k\n"), progname);
1711*7c478bd9Sstevel@tonic-gate 				usage();
1712*7c478bd9Sstevel@tonic-gate 			}
1713*7c478bd9Sstevel@tonic-gate 
1714*7c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
1715*7c478bd9Sstevel@tonic-gate 			break;
1716*7c478bd9Sstevel@tonic-gate 		case 'i':
1717*7c478bd9Sstevel@tonic-gate 			if (i_arg) {
1718*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1719*7c478bd9Sstevel@tonic-gate 				    "%s: the option -i cannot be specified "
1720*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
1721*7c478bd9Sstevel@tonic-gate 				usage();
1722*7c478bd9Sstevel@tonic-gate 			}
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate 			if (L_arg) {
1725*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1726*7c478bd9Sstevel@tonic-gate 				    "%s: the option -i cannot be used "
1727*7c478bd9Sstevel@tonic-gate 				    "with -L\n"), progname);
1728*7c478bd9Sstevel@tonic-gate 				usage();
1729*7c478bd9Sstevel@tonic-gate 			}
1730*7c478bd9Sstevel@tonic-gate 
1731*7c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
1732*7c478bd9Sstevel@tonic-gate 
1733*7c478bd9Sstevel@tonic-gate 			errno = 0;
1734*7c478bd9Sstevel@tonic-gate 			interval = (int)strtol(optarg, &endp, 10);
1735*7c478bd9Sstevel@tonic-gate 			if (errno != 0 || interval == 0 || *endp != '\0') {
1736*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1737*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid interval value"
1738*7c478bd9Sstevel@tonic-gate 				    " '%d'\n"),
1739*7c478bd9Sstevel@tonic-gate 				    progname, interval);
1740*7c478bd9Sstevel@tonic-gate 				exit(1);
1741*7c478bd9Sstevel@tonic-gate 			}
1742*7c478bd9Sstevel@tonic-gate 			break;
1743*7c478bd9Sstevel@tonic-gate 		case ':':
1744*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1745*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
1746*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
1747*7c478bd9Sstevel@tonic-gate 			exit(1);
1748*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1749*7c478bd9Sstevel@tonic-gate 		case '?':
1750*7c478bd9Sstevel@tonic-gate 		default:
1751*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1752*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
1753*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
1754*7c478bd9Sstevel@tonic-gate 			exit(1);
1755*7c478bd9Sstevel@tonic-gate 		}
1756*7c478bd9Sstevel@tonic-gate 	}
1757*7c478bd9Sstevel@tonic-gate 
1758*7c478bd9Sstevel@tonic-gate 	if (i_arg && !s_arg) {
1759*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: the option -i "
1760*7c478bd9Sstevel@tonic-gate 		    "can be used only with -s\n"), progname);
1761*7c478bd9Sstevel@tonic-gate 		usage();
1762*7c478bd9Sstevel@tonic-gate 	}
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate 	/* get aggregation key (optional last argument) */
1765*7c478bd9Sstevel@tonic-gate 	if (optind == (argc-1)) {
1766*7c478bd9Sstevel@tonic-gate 		errno = 0;
1767*7c478bd9Sstevel@tonic-gate 		key = (int)strtol(argv[optind], &endp, 10);
1768*7c478bd9Sstevel@tonic-gate 		if (errno != 0 || key < 1 || *endp != '\0') {
1769*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1770*7c478bd9Sstevel@tonic-gate 			    gettext("%s: illegal key value '%d'\n"),
1771*7c478bd9Sstevel@tonic-gate 			    progname, key);
1772*7c478bd9Sstevel@tonic-gate 			exit(1);
1773*7c478bd9Sstevel@tonic-gate 		}
1774*7c478bd9Sstevel@tonic-gate 	} else if (optind != argc) {
1775*7c478bd9Sstevel@tonic-gate 		usage();
1776*7c478bd9Sstevel@tonic-gate 	}
1777*7c478bd9Sstevel@tonic-gate 
1778*7c478bd9Sstevel@tonic-gate 	if (s_arg) {
1779*7c478bd9Sstevel@tonic-gate 		aggr_stats(key, interval);
1780*7c478bd9Sstevel@tonic-gate 		return;
1781*7c478bd9Sstevel@tonic-gate 	}
1782*7c478bd9Sstevel@tonic-gate 
1783*7c478bd9Sstevel@tonic-gate 	state.gs_key = key;
1784*7c478bd9Sstevel@tonic-gate 	state.gs_found = B_FALSE;
1785*7c478bd9Sstevel@tonic-gate 
1786*7c478bd9Sstevel@tonic-gate 	(void) laadm_walk_sys(show_key, &state);
1787*7c478bd9Sstevel@tonic-gate 
1788*7c478bd9Sstevel@tonic-gate 	if (key != 0 && !state.gs_found) {
1789*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1790*7c478bd9Sstevel@tonic-gate 		    gettext("%s: non-existent aggregation key '%u'\n"),
1791*7c478bd9Sstevel@tonic-gate 		    progname, key);
1792*7c478bd9Sstevel@tonic-gate 		exit(1);
1793*7c478bd9Sstevel@tonic-gate 	}
1794*7c478bd9Sstevel@tonic-gate }
1795*7c478bd9Sstevel@tonic-gate 
1796*7c478bd9Sstevel@tonic-gate static void
1797*7c478bd9Sstevel@tonic-gate do_show_dev(int argc, char *argv[])
1798*7c478bd9Sstevel@tonic-gate {
1799*7c478bd9Sstevel@tonic-gate 	int		option;
1800*7c478bd9Sstevel@tonic-gate 	char		*dev = NULL;
1801*7c478bd9Sstevel@tonic-gate 	boolean_t	s_arg = B_FALSE;
1802*7c478bd9Sstevel@tonic-gate 	boolean_t	i_arg = B_FALSE;
1803*7c478bd9Sstevel@tonic-gate 	uint32_t	interval = 0;
1804*7c478bd9Sstevel@tonic-gate 	show_mac_state_t state;
1805*7c478bd9Sstevel@tonic-gate 	char		*endp = NULL;
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate 	state.ms_parseable = B_FALSE;
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 	opterr = 0;
1810*7c478bd9Sstevel@tonic-gate 	while ((option = getopt_long(argc, argv, ":psi:",
1811*7c478bd9Sstevel@tonic-gate 	    longopts, NULL)) != -1) {
1812*7c478bd9Sstevel@tonic-gate 		switch (option) {
1813*7c478bd9Sstevel@tonic-gate 		case 'p':
1814*7c478bd9Sstevel@tonic-gate 			state.ms_parseable = B_TRUE;
1815*7c478bd9Sstevel@tonic-gate 			break;
1816*7c478bd9Sstevel@tonic-gate 		case 's':
1817*7c478bd9Sstevel@tonic-gate 			if (s_arg) {
1818*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1819*7c478bd9Sstevel@tonic-gate 				    "%s: the option -s cannot be specified "
1820*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
1821*7c478bd9Sstevel@tonic-gate 				usage();
1822*7c478bd9Sstevel@tonic-gate 			}
1823*7c478bd9Sstevel@tonic-gate 
1824*7c478bd9Sstevel@tonic-gate 			s_arg = B_TRUE;
1825*7c478bd9Sstevel@tonic-gate 			break;
1826*7c478bd9Sstevel@tonic-gate 		case 'i':
1827*7c478bd9Sstevel@tonic-gate 			if (i_arg) {
1828*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1829*7c478bd9Sstevel@tonic-gate 				    "%s: the option -i cannot be specified "
1830*7c478bd9Sstevel@tonic-gate 				    "more than once\n"), progname);
1831*7c478bd9Sstevel@tonic-gate 				usage();
1832*7c478bd9Sstevel@tonic-gate 			}
1833*7c478bd9Sstevel@tonic-gate 
1834*7c478bd9Sstevel@tonic-gate 			i_arg = B_TRUE;
1835*7c478bd9Sstevel@tonic-gate 
1836*7c478bd9Sstevel@tonic-gate 			errno = 0;
1837*7c478bd9Sstevel@tonic-gate 			interval = (int)strtol(optarg, &endp, 10);
1838*7c478bd9Sstevel@tonic-gate 			if (errno != 0 || interval == 0 || *endp != '\0') {
1839*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1840*7c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid interval value"
1841*7c478bd9Sstevel@tonic-gate 				    " '%d'\n"),
1842*7c478bd9Sstevel@tonic-gate 				    progname, interval);
1843*7c478bd9Sstevel@tonic-gate 				exit(1);
1844*7c478bd9Sstevel@tonic-gate 			}
1845*7c478bd9Sstevel@tonic-gate 			break;
1846*7c478bd9Sstevel@tonic-gate 		case ':':
1847*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1848*7c478bd9Sstevel@tonic-gate 			    gettext("%s: option requires a value '-%c'\n"),
1849*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
1850*7c478bd9Sstevel@tonic-gate 			exit(1);
1851*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
1852*7c478bd9Sstevel@tonic-gate 		case '?':
1853*7c478bd9Sstevel@tonic-gate 		default:
1854*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1855*7c478bd9Sstevel@tonic-gate 			    gettext("%s: unrecognized option '-%c'\n"),
1856*7c478bd9Sstevel@tonic-gate 			    progname, optopt);
1857*7c478bd9Sstevel@tonic-gate 			exit(1);
1858*7c478bd9Sstevel@tonic-gate 		}
1859*7c478bd9Sstevel@tonic-gate 	}
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate 	if (i_arg && !s_arg) {
1862*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: the option -i "
1863*7c478bd9Sstevel@tonic-gate 		    "can be used only with -s\n"), progname);
1864*7c478bd9Sstevel@tonic-gate 		usage();
1865*7c478bd9Sstevel@tonic-gate 	}
1866*7c478bd9Sstevel@tonic-gate 
1867*7c478bd9Sstevel@tonic-gate 	/* get dev name (optional last argument) */
1868*7c478bd9Sstevel@tonic-gate 	if (optind == (argc-1))
1869*7c478bd9Sstevel@tonic-gate 		dev = argv[optind];
1870*7c478bd9Sstevel@tonic-gate 	else if (optind != argc)
1871*7c478bd9Sstevel@tonic-gate 		usage();
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate 	if ((dev != NULL) && (strcmp(dev, AGGR_DEV) == 0)) {
1874*7c478bd9Sstevel@tonic-gate 		/* aggregations are already managed by a set of subcommands */
1875*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1876*7c478bd9Sstevel@tonic-gate 		    gettext("%s: non-existant device '%s'\n"),
1877*7c478bd9Sstevel@tonic-gate 		    progname, dev);
1878*7c478bd9Sstevel@tonic-gate 		exit(1);
1879*7c478bd9Sstevel@tonic-gate 	}
1880*7c478bd9Sstevel@tonic-gate 
1881*7c478bd9Sstevel@tonic-gate 	if (s_arg) {
1882*7c478bd9Sstevel@tonic-gate 		dev_stats(dev, interval);
1883*7c478bd9Sstevel@tonic-gate 		return;
1884*7c478bd9Sstevel@tonic-gate 	}
1885*7c478bd9Sstevel@tonic-gate 
1886*7c478bd9Sstevel@tonic-gate 	if (dev == NULL)
1887*7c478bd9Sstevel@tonic-gate 		(void) macadm_walk(show_dev, &state, B_TRUE);
1888*7c478bd9Sstevel@tonic-gate 	else
1889*7c478bd9Sstevel@tonic-gate 		show_dev(&state, dev, 0);
1890*7c478bd9Sstevel@tonic-gate }
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1893*7c478bd9Sstevel@tonic-gate static void
1894*7c478bd9Sstevel@tonic-gate link_stats(const char *link, uint32_t interval)
1895*7c478bd9Sstevel@tonic-gate {
1896*7c478bd9Sstevel@tonic-gate 	show_link_state_t state;
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate 	if (link != NULL) {
1899*7c478bd9Sstevel@tonic-gate 		dlpi_if_attr_t dia;
1900*7c478bd9Sstevel@tonic-gate 		int fd;
1901*7c478bd9Sstevel@tonic-gate 
1902*7c478bd9Sstevel@tonic-gate 		if ((fd = dlpi_if_open(link, &dia, B_FALSE)) != -1) {
1903*7c478bd9Sstevel@tonic-gate 			(void) dlpi_close(fd);
1904*7c478bd9Sstevel@tonic-gate 		} else {
1905*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1906*7c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid device '%s'\n"),
1907*7c478bd9Sstevel@tonic-gate 			    progname, link);
1908*7c478bd9Sstevel@tonic-gate 			exit(1);
1909*7c478bd9Sstevel@tonic-gate 		}
1910*7c478bd9Sstevel@tonic-gate 	}
1911*7c478bd9Sstevel@tonic-gate 
1912*7c478bd9Sstevel@tonic-gate 	bzero(&state, sizeof (state));
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 	/*
1915*7c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
1916*7c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
1917*7c478bd9Sstevel@tonic-gate 	 */
1918*7c478bd9Sstevel@tonic-gate 	state.ls_firstonly = (interval != 0);
1919*7c478bd9Sstevel@tonic-gate 
1920*7c478bd9Sstevel@tonic-gate 	for (;;) {
1921*7c478bd9Sstevel@tonic-gate 		(void) printf("\t\tipackets  rbytes	 ierrors ");
1922*7c478bd9Sstevel@tonic-gate 		(void) printf("opackets	 obytes	     oerrors\n");
1923*7c478bd9Sstevel@tonic-gate 
1924*7c478bd9Sstevel@tonic-gate 		state.ls_donefirst = B_FALSE;
1925*7c478bd9Sstevel@tonic-gate 		if (link == NULL)
1926*7c478bd9Sstevel@tonic-gate 			(void) dladm_walk(show_link_stats, &state);
1927*7c478bd9Sstevel@tonic-gate 		else
1928*7c478bd9Sstevel@tonic-gate 			show_link_stats(&state, link);
1929*7c478bd9Sstevel@tonic-gate 
1930*7c478bd9Sstevel@tonic-gate 		if (interval == 0)
1931*7c478bd9Sstevel@tonic-gate 			break;
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
1934*7c478bd9Sstevel@tonic-gate 	}
1935*7c478bd9Sstevel@tonic-gate 
1936*7c478bd9Sstevel@tonic-gate }
1937*7c478bd9Sstevel@tonic-gate 
1938*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1939*7c478bd9Sstevel@tonic-gate static void
1940*7c478bd9Sstevel@tonic-gate aggr_stats(uint16_t key, uint32_t interval)
1941*7c478bd9Sstevel@tonic-gate {
1942*7c478bd9Sstevel@tonic-gate 	show_grp_state_t state;
1943*7c478bd9Sstevel@tonic-gate 
1944*7c478bd9Sstevel@tonic-gate 	bzero(&state, sizeof (state));
1945*7c478bd9Sstevel@tonic-gate 	state.gs_stats = B_TRUE;
1946*7c478bd9Sstevel@tonic-gate 	state.gs_key = key;
1947*7c478bd9Sstevel@tonic-gate 
1948*7c478bd9Sstevel@tonic-gate 	/*
1949*7c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
1950*7c478bd9Sstevel@tonic-gate 	 * only for the first group.
1951*7c478bd9Sstevel@tonic-gate 	 */
1952*7c478bd9Sstevel@tonic-gate 	state.gs_firstonly = (interval != 0);
1953*7c478bd9Sstevel@tonic-gate 
1954*7c478bd9Sstevel@tonic-gate 	for (;;) {
1955*7c478bd9Sstevel@tonic-gate 		state.gs_found = B_FALSE;
1956*7c478bd9Sstevel@tonic-gate 		(void) laadm_walk_sys(show_key, &state);
1957*7c478bd9Sstevel@tonic-gate 		if (state.gs_key != 0 && !state.gs_found) {
1958*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1959*7c478bd9Sstevel@tonic-gate 			    gettext("%s: non-existent aggregation key '%u'\n"),
1960*7c478bd9Sstevel@tonic-gate 			    progname, key);
1961*7c478bd9Sstevel@tonic-gate 			exit(1);
1962*7c478bd9Sstevel@tonic-gate 		}
1963*7c478bd9Sstevel@tonic-gate 
1964*7c478bd9Sstevel@tonic-gate 		if (interval == 0)
1965*7c478bd9Sstevel@tonic-gate 			break;
1966*7c478bd9Sstevel@tonic-gate 
1967*7c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
1968*7c478bd9Sstevel@tonic-gate 	}
1969*7c478bd9Sstevel@tonic-gate }
1970*7c478bd9Sstevel@tonic-gate 
1971*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1972*7c478bd9Sstevel@tonic-gate static void
1973*7c478bd9Sstevel@tonic-gate dev_stats(const char *dev, uint32_t interval)
1974*7c478bd9Sstevel@tonic-gate {
1975*7c478bd9Sstevel@tonic-gate 	show_mac_state_t state;
1976*7c478bd9Sstevel@tonic-gate 
1977*7c478bd9Sstevel@tonic-gate 	bzero(&state, sizeof (state));
1978*7c478bd9Sstevel@tonic-gate 
1979*7c478bd9Sstevel@tonic-gate 	/*
1980*7c478bd9Sstevel@tonic-gate 	 * If an interval is specified, continuously show the stats
1981*7c478bd9Sstevel@tonic-gate 	 * only for the first MAC port.
1982*7c478bd9Sstevel@tonic-gate 	 */
1983*7c478bd9Sstevel@tonic-gate 	state.ms_firstonly = (interval != 0);
1984*7c478bd9Sstevel@tonic-gate 
1985*7c478bd9Sstevel@tonic-gate 	for (;;) {
1986*7c478bd9Sstevel@tonic-gate 
1987*7c478bd9Sstevel@tonic-gate 		(void) printf("\t\tipackets  rbytes	 ierrors ");
1988*7c478bd9Sstevel@tonic-gate 		(void) printf("opackets	 obytes	     oerrors\n");
1989*7c478bd9Sstevel@tonic-gate 
1990*7c478bd9Sstevel@tonic-gate 		state.ms_donefirst = B_FALSE;
1991*7c478bd9Sstevel@tonic-gate 		if (dev == NULL) {
1992*7c478bd9Sstevel@tonic-gate 			(void) macadm_walk(show_dev_stats, &state, B_TRUE);
1993*7c478bd9Sstevel@tonic-gate 		} else {
1994*7c478bd9Sstevel@tonic-gate 			show_dev_stats(&state, dev, 0);
1995*7c478bd9Sstevel@tonic-gate 		}
1996*7c478bd9Sstevel@tonic-gate 
1997*7c478bd9Sstevel@tonic-gate 		if (interval == 0)
1998*7c478bd9Sstevel@tonic-gate 			break;
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate 		(void) sleep(interval);
2001*7c478bd9Sstevel@tonic-gate 	}
2002*7c478bd9Sstevel@tonic-gate }
2003*7c478bd9Sstevel@tonic-gate 
2004*7c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */
2005*7c478bd9Sstevel@tonic-gate static void
2006*7c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
2007*7c478bd9Sstevel@tonic-gate {
2008*7c478bd9Sstevel@tonic-gate 	s1->ipackets += (s2->ipackets - s3->ipackets);
2009*7c478bd9Sstevel@tonic-gate 	s1->opackets += (s2->opackets - s3->opackets);
2010*7c478bd9Sstevel@tonic-gate 	s1->rbytes += (s2->rbytes - s3->rbytes);
2011*7c478bd9Sstevel@tonic-gate 	s1->obytes += (s2->obytes - s3->obytes);
2012*7c478bd9Sstevel@tonic-gate 	s1->ierrors += (s2->ierrors - s3->ierrors);
2013*7c478bd9Sstevel@tonic-gate 	s1->oerrors += (s2->oerrors - s3->oerrors);
2014*7c478bd9Sstevel@tonic-gate }
2015*7c478bd9Sstevel@tonic-gate 
2016*7c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */
2017*7c478bd9Sstevel@tonic-gate static void
2018*7c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
2019*7c478bd9Sstevel@tonic-gate {
2020*7c478bd9Sstevel@tonic-gate 	s1->ipackets = s2->ipackets - s3->ipackets;
2021*7c478bd9Sstevel@tonic-gate 	s1->opackets = s2->opackets - s3->opackets;
2022*7c478bd9Sstevel@tonic-gate 	s1->rbytes = s2->rbytes - s3->rbytes;
2023*7c478bd9Sstevel@tonic-gate 	s1->obytes = s2->obytes - s3->obytes;
2024*7c478bd9Sstevel@tonic-gate 	s1->ierrors = s2->ierrors - s3->ierrors;
2025*7c478bd9Sstevel@tonic-gate 	s1->oerrors = s2->oerrors - s3->oerrors;
2026*7c478bd9Sstevel@tonic-gate }
2027*7c478bd9Sstevel@tonic-gate 
2028*7c478bd9Sstevel@tonic-gate static void
2029*7c478bd9Sstevel@tonic-gate get_stats(char *module, int instance, char *name, pktsum_t *stats)
2030*7c478bd9Sstevel@tonic-gate {
2031*7c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
2032*7c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
2033*7c478bd9Sstevel@tonic-gate 
2034*7c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
2035*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2036*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat open operation failed\n"),
2037*7c478bd9Sstevel@tonic-gate 		    progname);
2038*7c478bd9Sstevel@tonic-gate 		return;
2039*7c478bd9Sstevel@tonic-gate 	}
2040*7c478bd9Sstevel@tonic-gate 
2041*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kcp, module, instance, name)) == NULL) {
2042*7c478bd9Sstevel@tonic-gate 		/*
2043*7c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
2044*7c478bd9Sstevel@tonic-gate 		 * driver was already detached.
2045*7c478bd9Sstevel@tonic-gate 		 */
2046*7c478bd9Sstevel@tonic-gate 		(void) kstat_close(kcp);
2047*7c478bd9Sstevel@tonic-gate 		return;
2048*7c478bd9Sstevel@tonic-gate 	}
2049*7c478bd9Sstevel@tonic-gate 
2050*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1)
2051*7c478bd9Sstevel@tonic-gate 		goto bail;
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
2054*7c478bd9Sstevel@tonic-gate 	    &stats->ipackets) < 0)
2055*7c478bd9Sstevel@tonic-gate 		goto bail;
2056*7c478bd9Sstevel@tonic-gate 
2057*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
2058*7c478bd9Sstevel@tonic-gate 	    &stats->opackets) < 0)
2059*7c478bd9Sstevel@tonic-gate 		goto bail;
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
2062*7c478bd9Sstevel@tonic-gate 	    &stats->rbytes) < 0)
2063*7c478bd9Sstevel@tonic-gate 		goto bail;
2064*7c478bd9Sstevel@tonic-gate 
2065*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
2066*7c478bd9Sstevel@tonic-gate 	    &stats->obytes) < 0)
2067*7c478bd9Sstevel@tonic-gate 		goto bail;
2068*7c478bd9Sstevel@tonic-gate 
2069*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
2070*7c478bd9Sstevel@tonic-gate 	    &stats->ierrors) < 0)
2071*7c478bd9Sstevel@tonic-gate 		goto bail;
2072*7c478bd9Sstevel@tonic-gate 
2073*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
2074*7c478bd9Sstevel@tonic-gate 	    &stats->oerrors) < 0)
2075*7c478bd9Sstevel@tonic-gate 		goto bail;
2076*7c478bd9Sstevel@tonic-gate 
2077*7c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
2078*7c478bd9Sstevel@tonic-gate 	return;
2079*7c478bd9Sstevel@tonic-gate 
2080*7c478bd9Sstevel@tonic-gate bail:
2081*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
2082*7c478bd9Sstevel@tonic-gate 	    gettext("%s: kstat operation failed\n"),
2083*7c478bd9Sstevel@tonic-gate 	    progname);
2084*7c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
2085*7c478bd9Sstevel@tonic-gate }
2086*7c478bd9Sstevel@tonic-gate 
2087*7c478bd9Sstevel@tonic-gate static void
2088*7c478bd9Sstevel@tonic-gate get_mac_stats(const char *dev, uint_t port, pktsum_t *stats)
2089*7c478bd9Sstevel@tonic-gate {
2090*7c478bd9Sstevel@tonic-gate 	char			name[MAXNAMELEN];
2091*7c478bd9Sstevel@tonic-gate 
2092*7c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
2093*7c478bd9Sstevel@tonic-gate 
2094*7c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXNAMELEN - 1, "%s/%u", dev, port);
2095*7c478bd9Sstevel@tonic-gate 	get_stats((char *)dev, 0, name, stats);
2096*7c478bd9Sstevel@tonic-gate }
2097*7c478bd9Sstevel@tonic-gate 
2098*7c478bd9Sstevel@tonic-gate static void
2099*7c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats)
2100*7c478bd9Sstevel@tonic-gate {
2101*7c478bd9Sstevel@tonic-gate 	bzero(stats, sizeof (*stats));
2102*7c478bd9Sstevel@tonic-gate 	get_stats(NULL, -1, (char *)link, stats);
2103*7c478bd9Sstevel@tonic-gate }
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate static uint64_t
2106*7c478bd9Sstevel@tonic-gate mac_ifspeed(const char *dev, uint_t port)
2107*7c478bd9Sstevel@tonic-gate {
2108*7c478bd9Sstevel@tonic-gate 	char		name[MAXNAMELEN];
2109*7c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
2110*7c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
2111*7c478bd9Sstevel@tonic-gate 	uint64_t	ifspeed = 0;
2112*7c478bd9Sstevel@tonic-gate 
2113*7c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
2114*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2115*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat open operation failed\n"),
2116*7c478bd9Sstevel@tonic-gate 		    progname);
2117*7c478bd9Sstevel@tonic-gate 		return (0);
2118*7c478bd9Sstevel@tonic-gate 	}
2119*7c478bd9Sstevel@tonic-gate 
2120*7c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXNAMELEN - 1, "%s/%u", dev, port);
2121*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kcp, (char *)dev, 0, name)) == NULL) {
2122*7c478bd9Sstevel@tonic-gate 		/*
2123*7c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
2124*7c478bd9Sstevel@tonic-gate 		 * driver was already detached.
2125*7c478bd9Sstevel@tonic-gate 		 */
2126*7c478bd9Sstevel@tonic-gate 		goto bail;
2127*7c478bd9Sstevel@tonic-gate 	}
2128*7c478bd9Sstevel@tonic-gate 
2129*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
2130*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2131*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat read failed\n"),
2132*7c478bd9Sstevel@tonic-gate 		    progname);
2133*7c478bd9Sstevel@tonic-gate 		goto bail;
2134*7c478bd9Sstevel@tonic-gate 	}
2135*7c478bd9Sstevel@tonic-gate 
2136*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64, &ifspeed) < 0) {
2137*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2138*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat value failed\n"),
2139*7c478bd9Sstevel@tonic-gate 		    progname);
2140*7c478bd9Sstevel@tonic-gate 		goto bail;
2141*7c478bd9Sstevel@tonic-gate 	}
2142*7c478bd9Sstevel@tonic-gate 
2143*7c478bd9Sstevel@tonic-gate bail:
2144*7c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
2145*7c478bd9Sstevel@tonic-gate 	return (ifspeed);
2146*7c478bd9Sstevel@tonic-gate }
2147*7c478bd9Sstevel@tonic-gate 
2148*7c478bd9Sstevel@tonic-gate static char *
2149*7c478bd9Sstevel@tonic-gate mac_link_state(const char *dev, uint_t port)
2150*7c478bd9Sstevel@tonic-gate {
2151*7c478bd9Sstevel@tonic-gate 	char		name[MAXNAMELEN];
2152*7c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
2153*7c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
2154*7c478bd9Sstevel@tonic-gate 	link_state_t	link_state;
2155*7c478bd9Sstevel@tonic-gate 	char		*state_str = "unknown";
2156*7c478bd9Sstevel@tonic-gate 
2157*7c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
2158*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2159*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat open operation failed\n"),
2160*7c478bd9Sstevel@tonic-gate 		    progname);
2161*7c478bd9Sstevel@tonic-gate 		return (state_str);
2162*7c478bd9Sstevel@tonic-gate 	}
2163*7c478bd9Sstevel@tonic-gate 
2164*7c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXNAMELEN - 1, "%s/%u", dev, port);
2165*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kcp, (char *)dev, 0, name)) == NULL) {
2166*7c478bd9Sstevel@tonic-gate 		/*
2167*7c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
2168*7c478bd9Sstevel@tonic-gate 		 * driver was already detached.
2169*7c478bd9Sstevel@tonic-gate 		 */
2170*7c478bd9Sstevel@tonic-gate 		goto bail;
2171*7c478bd9Sstevel@tonic-gate 	}
2172*7c478bd9Sstevel@tonic-gate 
2173*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
2174*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2175*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat read failed\n"),
2176*7c478bd9Sstevel@tonic-gate 		    progname);
2177*7c478bd9Sstevel@tonic-gate 		goto bail;
2178*7c478bd9Sstevel@tonic-gate 	}
2179*7c478bd9Sstevel@tonic-gate 
2180*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "link_state", KSTAT_DATA_UINT32,
2181*7c478bd9Sstevel@tonic-gate 	    &link_state) < 0) {
2182*7c478bd9Sstevel@tonic-gate 		goto bail;
2183*7c478bd9Sstevel@tonic-gate 	}
2184*7c478bd9Sstevel@tonic-gate 
2185*7c478bd9Sstevel@tonic-gate 	switch (link_state) {
2186*7c478bd9Sstevel@tonic-gate 	case LINK_STATE_UP:
2187*7c478bd9Sstevel@tonic-gate 		state_str = "up";
2188*7c478bd9Sstevel@tonic-gate 		break;
2189*7c478bd9Sstevel@tonic-gate 	case LINK_STATE_DOWN:
2190*7c478bd9Sstevel@tonic-gate 		state_str = "down";
2191*7c478bd9Sstevel@tonic-gate 		break;
2192*7c478bd9Sstevel@tonic-gate 	default:
2193*7c478bd9Sstevel@tonic-gate 		break;
2194*7c478bd9Sstevel@tonic-gate 	}
2195*7c478bd9Sstevel@tonic-gate 
2196*7c478bd9Sstevel@tonic-gate bail:
2197*7c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
2198*7c478bd9Sstevel@tonic-gate 	return (state_str);
2199*7c478bd9Sstevel@tonic-gate }
2200*7c478bd9Sstevel@tonic-gate 
2201*7c478bd9Sstevel@tonic-gate 
2202*7c478bd9Sstevel@tonic-gate static char *
2203*7c478bd9Sstevel@tonic-gate mac_link_duplex(const char *dev, uint_t port)
2204*7c478bd9Sstevel@tonic-gate {
2205*7c478bd9Sstevel@tonic-gate 	char		name[MAXNAMELEN];
2206*7c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kcp;
2207*7c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
2208*7c478bd9Sstevel@tonic-gate 	link_duplex_t	link_duplex;
2209*7c478bd9Sstevel@tonic-gate 	char		*duplex_str = "unknown";
2210*7c478bd9Sstevel@tonic-gate 
2211*7c478bd9Sstevel@tonic-gate 	if ((kcp = kstat_open()) == NULL) {
2212*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2213*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat open operation failed\n"),
2214*7c478bd9Sstevel@tonic-gate 		    progname);
2215*7c478bd9Sstevel@tonic-gate 		return (duplex_str);
2216*7c478bd9Sstevel@tonic-gate 	}
2217*7c478bd9Sstevel@tonic-gate 
2218*7c478bd9Sstevel@tonic-gate 	(void) snprintf(name, MAXNAMELEN - 1, "%s/%u", dev, port);
2219*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kcp, (char *)dev, 0, name)) == NULL) {
2220*7c478bd9Sstevel@tonic-gate 		/*
2221*7c478bd9Sstevel@tonic-gate 		 * The kstat query could fail if the underlying MAC
2222*7c478bd9Sstevel@tonic-gate 		 * driver was already detached.
2223*7c478bd9Sstevel@tonic-gate 		 */
2224*7c478bd9Sstevel@tonic-gate 		goto bail;
2225*7c478bd9Sstevel@tonic-gate 	}
2226*7c478bd9Sstevel@tonic-gate 
2227*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kcp, ksp, NULL) == -1) {
2228*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2229*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat read failed\n"),
2230*7c478bd9Sstevel@tonic-gate 		    progname);
2231*7c478bd9Sstevel@tonic-gate 		goto bail;
2232*7c478bd9Sstevel@tonic-gate 	}
2233*7c478bd9Sstevel@tonic-gate 
2234*7c478bd9Sstevel@tonic-gate 	if (kstat_value(ksp, "link_duplex", KSTAT_DATA_UINT32,
2235*7c478bd9Sstevel@tonic-gate 	    &link_duplex) < 0) {
2236*7c478bd9Sstevel@tonic-gate 		goto bail;
2237*7c478bd9Sstevel@tonic-gate 	}
2238*7c478bd9Sstevel@tonic-gate 	switch (link_duplex) {
2239*7c478bd9Sstevel@tonic-gate 	case LINK_DUPLEX_FULL:
2240*7c478bd9Sstevel@tonic-gate 		duplex_str = "full";
2241*7c478bd9Sstevel@tonic-gate 		break;
2242*7c478bd9Sstevel@tonic-gate 	case LINK_DUPLEX_HALF:
2243*7c478bd9Sstevel@tonic-gate 		duplex_str = "half";
2244*7c478bd9Sstevel@tonic-gate 		break;
2245*7c478bd9Sstevel@tonic-gate 	default:
2246*7c478bd9Sstevel@tonic-gate 		break;
2247*7c478bd9Sstevel@tonic-gate 	}
2248*7c478bd9Sstevel@tonic-gate 
2249*7c478bd9Sstevel@tonic-gate bail:
2250*7c478bd9Sstevel@tonic-gate 	(void) kstat_close(kcp);
2251*7c478bd9Sstevel@tonic-gate 	return (duplex_str);
2252*7c478bd9Sstevel@tonic-gate }
2253