xref: /titanic_51/usr/src/lib/libdladm/common/libdlaggr.c (revision f595a68a3b8953a12aa778c2abd7642df8da8c3a)
1*f595a68aSyz147064 /*
2*f595a68aSyz147064  * CDDL HEADER START
3*f595a68aSyz147064  *
4*f595a68aSyz147064  * The contents of this file are subject to the terms of the
5*f595a68aSyz147064  * Common Development and Distribution License (the "License").
6*f595a68aSyz147064  * You may not use this file except in compliance with the License.
7*f595a68aSyz147064  *
8*f595a68aSyz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f595a68aSyz147064  * or http://www.opensolaris.org/os/licensing.
10*f595a68aSyz147064  * See the License for the specific language governing permissions
11*f595a68aSyz147064  * and limitations under the License.
12*f595a68aSyz147064  *
13*f595a68aSyz147064  * When distributing Covered Code, include this CDDL HEADER in each
14*f595a68aSyz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f595a68aSyz147064  * If applicable, add the following below this CDDL HEADER, with the
16*f595a68aSyz147064  * fields enclosed by brackets "[]" replaced with your own identifying
17*f595a68aSyz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f595a68aSyz147064  *
19*f595a68aSyz147064  * CDDL HEADER END
20*f595a68aSyz147064  */
21*f595a68aSyz147064 /*
22*f595a68aSyz147064  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*f595a68aSyz147064  * Use is subject to license terms.
24*f595a68aSyz147064  */
25*f595a68aSyz147064 
26*f595a68aSyz147064 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*f595a68aSyz147064 
28*f595a68aSyz147064 #include <stdio.h>
29*f595a68aSyz147064 #include <sys/types.h>
30*f595a68aSyz147064 #include <sys/stat.h>
31*f595a68aSyz147064 #include <string.h>
32*f595a68aSyz147064 #include <fcntl.h>
33*f595a68aSyz147064 #include <unistd.h>
34*f595a68aSyz147064 #include <stropts.h>
35*f595a68aSyz147064 #include <stdlib.h>
36*f595a68aSyz147064 #include <errno.h>
37*f595a68aSyz147064 #include <strings.h>
38*f595a68aSyz147064 #include <libintl.h>
39*f595a68aSyz147064 #include <net/if_types.h>
40*f595a68aSyz147064 #include <net/if_dl.h>
41*f595a68aSyz147064 #include <libdlaggr.h>
42*f595a68aSyz147064 #include <libdladm_impl.h>
43*f595a68aSyz147064 
44*f595a68aSyz147064 /*
45*f595a68aSyz147064  * Link Aggregation Administration Library.
46*f595a68aSyz147064  *
47*f595a68aSyz147064  * This library is used by administration tools such as dladm(1M) to
48*f595a68aSyz147064  * configure link aggregations.
49*f595a68aSyz147064  *
50*f595a68aSyz147064  * Link aggregation configuration information is saved in a text
51*f595a68aSyz147064  * file of the following format:
52*f595a68aSyz147064  *
53*f595a68aSyz147064  * <db-file>	::= <groups>*
54*f595a68aSyz147064  * <group>	::= <key> <sep> <policy> <sep> <nports> <sep> <ports> <sep>
55*f595a68aSyz147064  *		      <mac> <sep> <lacp-mode> <sep> <lacp-timer>
56*f595a68aSyz147064  * <sep>	::= ' ' | '\t'
57*f595a68aSyz147064  * <key>	::= <number>
58*f595a68aSyz147064  * <nports>	::= <number>
59*f595a68aSyz147064  * <ports>	::= <port> <m-port>*
60*f595a68aSyz147064  * <m-port>	::= ',' <port>
61*f595a68aSyz147064  * <port>	::= <devname>
62*f595a68aSyz147064  * <devname>	::= <string>
63*f595a68aSyz147064  * <port-num>	::= <number>
64*f595a68aSyz147064  * <policy>	::= <pol-level> <m-pol>*
65*f595a68aSyz147064  * <m-pol>	::= ',' <pol-level>
66*f595a68aSyz147064  * <pol-level>	::= 'L2' | 'L3' | 'L4'
67*f595a68aSyz147064  * <mac>	::= 'auto' | <mac-addr>
68*f595a68aSyz147064  * <mac-addr>	::= <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex>
69*f595a68aSyz147064  * <lacp-mode>	::= 'off' | 'active' | 'passive'
70*f595a68aSyz147064  * <lacp-timer>	::= 'short' | 'long'
71*f595a68aSyz147064  */
72*f595a68aSyz147064 
73*f595a68aSyz147064 #define	DLADM_AGGR_DEV		"/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL
74*f595a68aSyz147064 #define	DLADM_AGGR_DB		"/etc/dladm/aggregation.conf"
75*f595a68aSyz147064 #define	DLADM_AGGR_DB_TMP	"/etc/dladm/aggregation.conf.new"
76*f595a68aSyz147064 #define	DLADM_AGGR_DB_LOCK	"/tmp/aggregation.conf.lock"
77*f595a68aSyz147064 
78*f595a68aSyz147064 #define	DLADM_AGGR_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
79*f595a68aSyz147064 #define	DLADM_AGGR_DB_OWNER	15	/* "dladm" UID */
80*f595a68aSyz147064 #define	DLADM_AGGR_DB_GROUP	3	/* "sys" GID */
81*f595a68aSyz147064 
82*f595a68aSyz147064 /*
83*f595a68aSyz147064  * The largest configurable aggregation key.  Because by default the key is
84*f595a68aSyz147064  * used as the DLPI device PPA and default VLAN PPA's are calculated as
85*f595a68aSyz147064  * ((1000 * vid) + PPA), the largest key can't be > 999.
86*f595a68aSyz147064  */
87*f595a68aSyz147064 #define	DLADM_AGGR_MAX_KEY	999
88*f595a68aSyz147064 
89*f595a68aSyz147064 #define	BLANK_LINE(s)	((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n'))
90*f595a68aSyz147064 
91*f595a68aSyz147064 /* Limits on buffer size for LAIOC_INFO request */
92*f595a68aSyz147064 #define	MIN_INFO_SIZE (4*1024)
93*f595a68aSyz147064 #define	MAX_INFO_SIZE (128*1024)
94*f595a68aSyz147064 
95*f595a68aSyz147064 #define	MAXPATHLEN	1024
96*f595a68aSyz147064 
97*f595a68aSyz147064 static uchar_t	zero_mac[] = {0, 0, 0, 0, 0, 0};
98*f595a68aSyz147064 
99*f595a68aSyz147064 /* configuration database entry */
100*f595a68aSyz147064 typedef struct dladm_aggr_grp_attr_db {
101*f595a68aSyz147064 	uint32_t	lt_key;
102*f595a68aSyz147064 	uint32_t	lt_policy;
103*f595a68aSyz147064 	uint32_t	lt_nports;
104*f595a68aSyz147064 	dladm_aggr_port_attr_db_t *lt_ports;
105*f595a68aSyz147064 	boolean_t	lt_mac_fixed;
106*f595a68aSyz147064 	uchar_t		lt_mac[ETHERADDRL];
107*f595a68aSyz147064 	aggr_lacp_mode_t lt_lacp_mode;
108*f595a68aSyz147064 	aggr_lacp_timer_t lt_lacp_timer;
109*f595a68aSyz147064 } dladm_aggr_grp_attr_db_t;
110*f595a68aSyz147064 
111*f595a68aSyz147064 typedef struct dladm_aggr_up {
112*f595a68aSyz147064 	uint32_t	lu_key;
113*f595a68aSyz147064 	boolean_t	lu_found;
114*f595a68aSyz147064 	int		lu_fd;
115*f595a68aSyz147064 } dladm_aggr_up_t;
116*f595a68aSyz147064 
117*f595a68aSyz147064 typedef struct dladm_aggr_down {
118*f595a68aSyz147064 	uint32_t	ld_key;
119*f595a68aSyz147064 	boolean_t	ld_found;
120*f595a68aSyz147064 } dladm_aggr_down_t;
121*f595a68aSyz147064 
122*f595a68aSyz147064 typedef struct dladm_aggr_modify_attr {
123*f595a68aSyz147064 	uint32_t	ld_policy;
124*f595a68aSyz147064 	boolean_t	ld_mac_fixed;
125*f595a68aSyz147064 	uchar_t		ld_mac[ETHERADDRL];
126*f595a68aSyz147064 	aggr_lacp_mode_t ld_lacp_mode;
127*f595a68aSyz147064 	aggr_lacp_timer_t ld_lacp_timer;
128*f595a68aSyz147064 } dladm_aggr_modify_attr_t;
129*f595a68aSyz147064 
130*f595a68aSyz147064 typedef struct policy_s {
131*f595a68aSyz147064 	char		*pol_name;
132*f595a68aSyz147064 	uint32_t	policy;
133*f595a68aSyz147064 } policy_t;
134*f595a68aSyz147064 
135*f595a68aSyz147064 static policy_t policies[] = {
136*f595a68aSyz147064 	{"L2",		AGGR_POLICY_L2},
137*f595a68aSyz147064 	{"L3",		AGGR_POLICY_L3},
138*f595a68aSyz147064 	{"L4",		AGGR_POLICY_L4}};
139*f595a68aSyz147064 
140*f595a68aSyz147064 #define	NPOLICIES	(sizeof (policies) / sizeof (policy_t))
141*f595a68aSyz147064 
142*f595a68aSyz147064 typedef struct dladm_aggr_lacpmode_s {
143*f595a68aSyz147064 	char		*mode_str;
144*f595a68aSyz147064 	aggr_lacp_mode_t mode_id;
145*f595a68aSyz147064 } dladm_aggr_lacpmode_t;
146*f595a68aSyz147064 
147*f595a68aSyz147064 static dladm_aggr_lacpmode_t lacp_modes[] = {
148*f595a68aSyz147064 	{"off", AGGR_LACP_OFF},
149*f595a68aSyz147064 	{"active", AGGR_LACP_ACTIVE},
150*f595a68aSyz147064 	{"passive", AGGR_LACP_PASSIVE}};
151*f595a68aSyz147064 
152*f595a68aSyz147064 #define	NLACP_MODES	(sizeof (lacp_modes) / sizeof (dladm_aggr_lacpmode_t))
153*f595a68aSyz147064 
154*f595a68aSyz147064 typedef struct dladm_aggr_lacptimer_s {
155*f595a68aSyz147064 	char		*lt_str;
156*f595a68aSyz147064 	aggr_lacp_timer_t lt_id;
157*f595a68aSyz147064 } dladm_aggr_lacptimer_t;
158*f595a68aSyz147064 
159*f595a68aSyz147064 static dladm_aggr_lacptimer_t lacp_timers[] = {
160*f595a68aSyz147064 	{"short", AGGR_LACP_TIMER_SHORT},
161*f595a68aSyz147064 	{"long", AGGR_LACP_TIMER_LONG}};
162*f595a68aSyz147064 
163*f595a68aSyz147064 #define	NLACP_TIMERS	(sizeof (lacp_timers) / sizeof (dladm_aggr_lacptimer_t))
164*f595a68aSyz147064 
165*f595a68aSyz147064 typedef struct dladm_aggr_port_state {
166*f595a68aSyz147064 	char			*state_str;
167*f595a68aSyz147064 	aggr_port_state_t	state_id;
168*f595a68aSyz147064 } dladm_aggr_port_state_t;
169*f595a68aSyz147064 
170*f595a68aSyz147064 static dladm_aggr_port_state_t port_states[] = {
171*f595a68aSyz147064 	{"standby", AGGR_PORT_STATE_STANDBY },
172*f595a68aSyz147064 	{"attached", AGGR_PORT_STATE_ATTACHED }
173*f595a68aSyz147064 };
174*f595a68aSyz147064 
175*f595a68aSyz147064 #define	NPORT_STATES	\
176*f595a68aSyz147064 	(sizeof (port_states) / sizeof (dladm_aggr_port_state_t))
177*f595a68aSyz147064 
178*f595a68aSyz147064 typedef struct delete_db_state {
179*f595a68aSyz147064 	uint32_t	ds_key;
180*f595a68aSyz147064 	boolean_t	ds_found;
181*f595a68aSyz147064 } delete_db_state_t;
182*f595a68aSyz147064 
183*f595a68aSyz147064 typedef struct modify_db_state {
184*f595a68aSyz147064 	uint32_t		us_key;
185*f595a68aSyz147064 	uint32_t		us_mask;
186*f595a68aSyz147064 	dladm_aggr_modify_attr_t *us_attr_new;
187*f595a68aSyz147064 	dladm_aggr_modify_attr_t *us_attr_old;
188*f595a68aSyz147064 	boolean_t		us_found;
189*f595a68aSyz147064 } modify_db_state_t;
190*f595a68aSyz147064 
191*f595a68aSyz147064 typedef struct add_db_state {
192*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t *as_attr;
193*f595a68aSyz147064 	boolean_t	as_found;
194*f595a68aSyz147064 } add_db_state_t;
195*f595a68aSyz147064 
196*f595a68aSyz147064 static int i_dladm_aggr_fput_grp(FILE *, dladm_aggr_grp_attr_db_t *);
197*f595a68aSyz147064 
198*f595a68aSyz147064 static int
199*f595a68aSyz147064 i_dladm_aggr_strioctl(int fd, int cmd, void *ptr, int ilen)
200*f595a68aSyz147064 {
201*f595a68aSyz147064 	struct strioctl str;
202*f595a68aSyz147064 
203*f595a68aSyz147064 	str.ic_cmd = cmd;
204*f595a68aSyz147064 	str.ic_timout = 0;
205*f595a68aSyz147064 	str.ic_len = ilen;
206*f595a68aSyz147064 	str.ic_dp = ptr;
207*f595a68aSyz147064 
208*f595a68aSyz147064 	return (ioctl(fd, I_STR, &str));
209*f595a68aSyz147064 }
210*f595a68aSyz147064 
211*f595a68aSyz147064 /*
212*f595a68aSyz147064  * Open and lock the aggregation configuration file lock. The lock is
213*f595a68aSyz147064  * acquired as a reader (F_RDLCK) or writer (F_WRLCK).
214*f595a68aSyz147064  */
215*f595a68aSyz147064 static int
216*f595a68aSyz147064 i_dladm_aggr_lock_db(short type)
217*f595a68aSyz147064 {
218*f595a68aSyz147064 	int lock_fd;
219*f595a68aSyz147064 	struct flock lock;
220*f595a68aSyz147064 	int errno_save;
221*f595a68aSyz147064 
222*f595a68aSyz147064 	if ((lock_fd = open(DLADM_AGGR_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC,
223*f595a68aSyz147064 	    DLADM_AGGR_DB_PERMS)) < 0)
224*f595a68aSyz147064 		return (-1);
225*f595a68aSyz147064 
226*f595a68aSyz147064 	lock.l_type = type;
227*f595a68aSyz147064 	lock.l_whence = SEEK_SET;
228*f595a68aSyz147064 	lock.l_start = 0;
229*f595a68aSyz147064 	lock.l_len = 0;
230*f595a68aSyz147064 
231*f595a68aSyz147064 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
232*f595a68aSyz147064 		errno_save = errno;
233*f595a68aSyz147064 		(void) close(lock_fd);
234*f595a68aSyz147064 		(void) unlink(DLADM_AGGR_DB_LOCK);
235*f595a68aSyz147064 		errno = errno_save;
236*f595a68aSyz147064 		return (-1);
237*f595a68aSyz147064 	}
238*f595a68aSyz147064 	return (lock_fd);
239*f595a68aSyz147064 }
240*f595a68aSyz147064 
241*f595a68aSyz147064 /*
242*f595a68aSyz147064  * Unlock and close the specified file.
243*f595a68aSyz147064  */
244*f595a68aSyz147064 static void
245*f595a68aSyz147064 i_dladm_aggr_unlock_db(int fd)
246*f595a68aSyz147064 {
247*f595a68aSyz147064 	struct flock lock;
248*f595a68aSyz147064 
249*f595a68aSyz147064 	if (fd < 0)
250*f595a68aSyz147064 		return;
251*f595a68aSyz147064 
252*f595a68aSyz147064 	lock.l_type = F_UNLCK;
253*f595a68aSyz147064 	lock.l_whence = SEEK_SET;
254*f595a68aSyz147064 	lock.l_start = 0;
255*f595a68aSyz147064 	lock.l_len = 0;
256*f595a68aSyz147064 
257*f595a68aSyz147064 	(void) fcntl(fd, F_SETLKW, &lock);
258*f595a68aSyz147064 	(void) close(fd);
259*f595a68aSyz147064 	(void) unlink(DLADM_AGGR_DB_LOCK);
260*f595a68aSyz147064 }
261*f595a68aSyz147064 
262*f595a68aSyz147064 /*
263*f595a68aSyz147064  * Walk through the groups defined on the system and for each group <grp>,
264*f595a68aSyz147064  * invoke <fn>(<arg>, <grp>);
265*f595a68aSyz147064  * Terminate the walk if at any time <fn> returns non-NULL value
266*f595a68aSyz147064  */
267*f595a68aSyz147064 int
268*f595a68aSyz147064 dladm_aggr_walk(int (*fn)(void *, dladm_aggr_grp_attr_t *), void *arg)
269*f595a68aSyz147064 {
270*f595a68aSyz147064 	laioc_info_t *ioc;
271*f595a68aSyz147064 	laioc_info_group_t *grp;
272*f595a68aSyz147064 	laioc_info_port_t *port;
273*f595a68aSyz147064 	dladm_aggr_grp_attr_t attr;
274*f595a68aSyz147064 	int rc, i, j, bufsize, fd;
275*f595a68aSyz147064 	char *where;
276*f595a68aSyz147064 
277*f595a68aSyz147064 	if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) == -1)
278*f595a68aSyz147064 		return (-1);
279*f595a68aSyz147064 
280*f595a68aSyz147064 	bufsize = MIN_INFO_SIZE;
281*f595a68aSyz147064 	ioc = (laioc_info_t *)calloc(1, bufsize);
282*f595a68aSyz147064 	if (ioc == NULL) {
283*f595a68aSyz147064 		(void) close(fd);
284*f595a68aSyz147064 		errno = ENOMEM;
285*f595a68aSyz147064 		return (-1);
286*f595a68aSyz147064 	}
287*f595a68aSyz147064 
288*f595a68aSyz147064 tryagain:
289*f595a68aSyz147064 	rc = i_dladm_aggr_strioctl(fd, LAIOC_INFO, ioc, bufsize);
290*f595a68aSyz147064 
291*f595a68aSyz147064 	if (rc != 0) {
292*f595a68aSyz147064 		if (errno == ENOSPC) {
293*f595a68aSyz147064 			/*
294*f595a68aSyz147064 			 * The LAIOC_INFO call failed due to a short
295*f595a68aSyz147064 			 * buffer. Reallocate the buffer and try again.
296*f595a68aSyz147064 			 */
297*f595a68aSyz147064 			bufsize *= 2;
298*f595a68aSyz147064 			if (bufsize <= MAX_INFO_SIZE) {
299*f595a68aSyz147064 				ioc = (laioc_info_t *)realloc(ioc, bufsize);
300*f595a68aSyz147064 				if (ioc != NULL) {
301*f595a68aSyz147064 					bzero(ioc, sizeof (bufsize));
302*f595a68aSyz147064 					goto tryagain;
303*f595a68aSyz147064 				}
304*f595a68aSyz147064 			}
305*f595a68aSyz147064 		}
306*f595a68aSyz147064 		goto bail;
307*f595a68aSyz147064 	}
308*f595a68aSyz147064 
309*f595a68aSyz147064 	/*
310*f595a68aSyz147064 	 * Go through each group returned by the aggregation driver.
311*f595a68aSyz147064 	 */
312*f595a68aSyz147064 	where = (char *)(ioc + 1);
313*f595a68aSyz147064 	for (i = 0; i < ioc->li_ngroups; i++) {
314*f595a68aSyz147064 		/* LINTED E_BAD_PTR_CAST_ALIGN */
315*f595a68aSyz147064 		grp = (laioc_info_group_t *)where;
316*f595a68aSyz147064 
317*f595a68aSyz147064 		attr.lg_key = grp->lg_key;
318*f595a68aSyz147064 		attr.lg_nports = grp->lg_nports;
319*f595a68aSyz147064 		attr.lg_policy = grp->lg_policy;
320*f595a68aSyz147064 		attr.lg_lacp_mode = grp->lg_lacp_mode;
321*f595a68aSyz147064 		attr.lg_lacp_timer = grp->lg_lacp_timer;
322*f595a68aSyz147064 
323*f595a68aSyz147064 		bcopy(grp->lg_mac, attr.lg_mac, ETHERADDRL);
324*f595a68aSyz147064 		attr.lg_mac_fixed = grp->lg_mac_fixed;
325*f595a68aSyz147064 
326*f595a68aSyz147064 		attr.lg_ports = malloc(grp->lg_nports *
327*f595a68aSyz147064 		    sizeof (dladm_aggr_port_attr_t));
328*f595a68aSyz147064 		if (attr.lg_ports == NULL) {
329*f595a68aSyz147064 			errno = ENOMEM;
330*f595a68aSyz147064 			goto bail;
331*f595a68aSyz147064 		}
332*f595a68aSyz147064 
333*f595a68aSyz147064 		where = (char *)(grp + 1);
334*f595a68aSyz147064 
335*f595a68aSyz147064 		/*
336*f595a68aSyz147064 		 * Go through each port that is part of the group.
337*f595a68aSyz147064 		 */
338*f595a68aSyz147064 		for (j = 0; j < grp->lg_nports; j++) {
339*f595a68aSyz147064 			/* LINTED E_BAD_PTR_CAST_ALIGN */
340*f595a68aSyz147064 			port = (laioc_info_port_t *)where;
341*f595a68aSyz147064 
342*f595a68aSyz147064 			bcopy(port->lp_devname, attr.lg_ports[j].lp_devname,
343*f595a68aSyz147064 			    MAXNAMELEN + 1);
344*f595a68aSyz147064 			bcopy(port->lp_mac, attr.lg_ports[j].lp_mac,
345*f595a68aSyz147064 			    ETHERADDRL);
346*f595a68aSyz147064 			attr.lg_ports[j].lp_state = port->lp_state;
347*f595a68aSyz147064 			attr.lg_ports[j].lp_lacp_state = port->lp_lacp_state;
348*f595a68aSyz147064 
349*f595a68aSyz147064 			where = (char *)(port + 1);
350*f595a68aSyz147064 		}
351*f595a68aSyz147064 
352*f595a68aSyz147064 		rc = fn(arg, &attr);
353*f595a68aSyz147064 		free(attr.lg_ports);
354*f595a68aSyz147064 		if (rc != 0)
355*f595a68aSyz147064 			goto bail;
356*f595a68aSyz147064 	}
357*f595a68aSyz147064 
358*f595a68aSyz147064 bail:
359*f595a68aSyz147064 	free(ioc);
360*f595a68aSyz147064 	(void) close(fd);
361*f595a68aSyz147064 	return (rc);
362*f595a68aSyz147064 }
363*f595a68aSyz147064 
364*f595a68aSyz147064 /*
365*f595a68aSyz147064  * Parse one line of the link aggregation DB, and return the corresponding
366*f595a68aSyz147064  * group. Memory for the ports associated with the aggregation may be
367*f595a68aSyz147064  * allocated. It is the responsibility of the caller to free the lt_ports
368*f595a68aSyz147064  * aggregation group attribute.
369*f595a68aSyz147064  *
370*f595a68aSyz147064  * Returns -1 on parsing failure, or 0 on success.
371*f595a68aSyz147064  */
372*f595a68aSyz147064 static int
373*f595a68aSyz147064 i_dladm_aggr_parse_db(char *line, dladm_aggr_grp_attr_db_t *attr)
374*f595a68aSyz147064 {
375*f595a68aSyz147064 	char	*token;
376*f595a68aSyz147064 	int	i;
377*f595a68aSyz147064 	int	value;
378*f595a68aSyz147064 	char	*endp = NULL;
379*f595a68aSyz147064 	char	*lasts = NULL;
380*f595a68aSyz147064 
381*f595a68aSyz147064 	bzero(attr, sizeof (*attr));
382*f595a68aSyz147064 
383*f595a68aSyz147064 	/* key */
384*f595a68aSyz147064 	if ((token = strtok_r(line, " \t", &lasts)) == NULL)
385*f595a68aSyz147064 		goto failed;
386*f595a68aSyz147064 
387*f595a68aSyz147064 	errno = 0;
388*f595a68aSyz147064 	value = (int)strtol(token, &endp, 10);
389*f595a68aSyz147064 	if (errno != 0 || *endp != '\0')
390*f595a68aSyz147064 		goto failed;
391*f595a68aSyz147064 
392*f595a68aSyz147064 	attr->lt_key = value;
393*f595a68aSyz147064 
394*f595a68aSyz147064 	/* policy */
395*f595a68aSyz147064 	if ((token = strtok_r(NULL, " \t", &lasts)) == NULL ||
396*f595a68aSyz147064 	    !dladm_aggr_str2policy(token, &attr->lt_policy))
397*f595a68aSyz147064 		goto failed;
398*f595a68aSyz147064 
399*f595a68aSyz147064 	/* number of ports */
400*f595a68aSyz147064 	if ((token = strtok_r(NULL, " \t", &lasts)) == NULL)
401*f595a68aSyz147064 		return (-1);
402*f595a68aSyz147064 
403*f595a68aSyz147064 	errno = 0;
404*f595a68aSyz147064 	value = (int)strtol(token, &endp, 10);
405*f595a68aSyz147064 	if (errno != 0 || *endp != '\0')
406*f595a68aSyz147064 		goto failed;
407*f595a68aSyz147064 
408*f595a68aSyz147064 	attr->lt_nports = value;
409*f595a68aSyz147064 
410*f595a68aSyz147064 	/* ports */
411*f595a68aSyz147064 	if ((attr->lt_ports = malloc(attr->lt_nports *
412*f595a68aSyz147064 	    sizeof (dladm_aggr_port_attr_db_t))) == NULL)
413*f595a68aSyz147064 		goto failed;
414*f595a68aSyz147064 
415*f595a68aSyz147064 	for (i = 0; i < attr->lt_nports; i++) {
416*f595a68aSyz147064 		char *where, *devname;
417*f595a68aSyz147064 
418*f595a68aSyz147064 		/* port */
419*f595a68aSyz147064 		if ((token = strtok_r(NULL, ", \t\n", &lasts)) == NULL)
420*f595a68aSyz147064 			goto failed;
421*f595a68aSyz147064 
422*f595a68aSyz147064 		/*
423*f595a68aSyz147064 		 * device name: In a previous version of this file, a port
424*f595a68aSyz147064 		 * number could be specified using <devname>/<portnum>.
425*f595a68aSyz147064 		 * This syntax is unecessary and obsolete.
426*f595a68aSyz147064 		 */
427*f595a68aSyz147064 		if ((devname = strtok_r(token, "/", &where)) == NULL)
428*f595a68aSyz147064 			goto failed;
429*f595a68aSyz147064 		if (strlcpy(attr->lt_ports[i].lp_devname, devname,
430*f595a68aSyz147064 		    MAXNAMELEN) >= MAXNAMELEN)
431*f595a68aSyz147064 			goto failed;
432*f595a68aSyz147064 	}
433*f595a68aSyz147064 
434*f595a68aSyz147064 	/* unicast MAC address */
435*f595a68aSyz147064 	if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL ||
436*f595a68aSyz147064 	    !dladm_aggr_str2macaddr(token, &attr->lt_mac_fixed,
437*f595a68aSyz147064 	    attr->lt_mac))
438*f595a68aSyz147064 		goto failed;
439*f595a68aSyz147064 
440*f595a68aSyz147064 	/* LACP mode */
441*f595a68aSyz147064 	if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL ||
442*f595a68aSyz147064 	    !dladm_aggr_str2lacpmode(token, &attr->lt_lacp_mode))
443*f595a68aSyz147064 		attr->lt_lacp_mode = AGGR_LACP_OFF;
444*f595a68aSyz147064 
445*f595a68aSyz147064 	/* LACP timer */
446*f595a68aSyz147064 	if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL ||
447*f595a68aSyz147064 	    !dladm_aggr_str2lacptimer(token, &attr->lt_lacp_timer))
448*f595a68aSyz147064 		attr->lt_lacp_timer = AGGR_LACP_TIMER_SHORT;
449*f595a68aSyz147064 
450*f595a68aSyz147064 	return (0);
451*f595a68aSyz147064 
452*f595a68aSyz147064 failed:
453*f595a68aSyz147064 	free(attr->lt_ports);
454*f595a68aSyz147064 	attr->lt_ports = NULL;
455*f595a68aSyz147064 	return (-1);
456*f595a68aSyz147064 }
457*f595a68aSyz147064 
458*f595a68aSyz147064 /*
459*f595a68aSyz147064  * Walk through the groups defined in the DB and for each group <grp>,
460*f595a68aSyz147064  * invoke <fn>(<arg>, <grp>);
461*f595a68aSyz147064  */
462*f595a68aSyz147064 static dladm_status_t
463*f595a68aSyz147064 i_dladm_aggr_walk_db(dladm_status_t (*fn)(void *, dladm_aggr_grp_attr_db_t *),
464*f595a68aSyz147064     void *arg, const char *root)
465*f595a68aSyz147064 {
466*f595a68aSyz147064 	FILE *fp;
467*f595a68aSyz147064 	char line[MAXLINELEN];
468*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t attr;
469*f595a68aSyz147064 	char *db_file;
470*f595a68aSyz147064 	char db_file_buf[MAXPATHLEN];
471*f595a68aSyz147064 	int lock_fd;
472*f595a68aSyz147064 	dladm_status_t status = DLADM_STATUS_OK;
473*f595a68aSyz147064 
474*f595a68aSyz147064 	if (root == NULL) {
475*f595a68aSyz147064 		db_file = DLADM_AGGR_DB;
476*f595a68aSyz147064 	} else {
477*f595a68aSyz147064 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
478*f595a68aSyz147064 		    DLADM_AGGR_DB);
479*f595a68aSyz147064 		db_file = db_file_buf;
480*f595a68aSyz147064 	}
481*f595a68aSyz147064 
482*f595a68aSyz147064 	lock_fd = i_dladm_aggr_lock_db(F_RDLCK);
483*f595a68aSyz147064 
484*f595a68aSyz147064 	if ((fp = fopen(db_file, "r")) == NULL) {
485*f595a68aSyz147064 		status = dladm_errno2status(errno);
486*f595a68aSyz147064 		i_dladm_aggr_unlock_db(lock_fd);
487*f595a68aSyz147064 		return (status);
488*f595a68aSyz147064 	}
489*f595a68aSyz147064 
490*f595a68aSyz147064 	bzero(&attr, sizeof (attr));
491*f595a68aSyz147064 
492*f595a68aSyz147064 	while (fgets(line, MAXLINELEN, fp) != NULL) {
493*f595a68aSyz147064 		/* skip comments */
494*f595a68aSyz147064 		if (BLANK_LINE(line))
495*f595a68aSyz147064 			continue;
496*f595a68aSyz147064 
497*f595a68aSyz147064 		if (i_dladm_aggr_parse_db(line, &attr) != 0) {
498*f595a68aSyz147064 			status = DLADM_STATUS_REPOSITORYINVAL;
499*f595a68aSyz147064 			goto done;
500*f595a68aSyz147064 		}
501*f595a68aSyz147064 
502*f595a68aSyz147064 		if ((status = fn(arg, &attr)) != DLADM_STATUS_OK)
503*f595a68aSyz147064 			goto done;
504*f595a68aSyz147064 
505*f595a68aSyz147064 		free(attr.lt_ports);
506*f595a68aSyz147064 		attr.lt_ports = NULL;
507*f595a68aSyz147064 	}
508*f595a68aSyz147064 
509*f595a68aSyz147064 done:
510*f595a68aSyz147064 	free(attr.lt_ports);
511*f595a68aSyz147064 	(void) fclose(fp);
512*f595a68aSyz147064 	i_dladm_aggr_unlock_db(lock_fd);
513*f595a68aSyz147064 	return (status);
514*f595a68aSyz147064 }
515*f595a68aSyz147064 
516*f595a68aSyz147064 /*
517*f595a68aSyz147064  * Send an add or remove command to the link aggregation driver.
518*f595a68aSyz147064  */
519*f595a68aSyz147064 static dladm_status_t
520*f595a68aSyz147064 i_dladm_aggr_add_rem_sys(dladm_aggr_grp_attr_db_t *attr, int cmd)
521*f595a68aSyz147064 {
522*f595a68aSyz147064 	int i, rc, fd, len;
523*f595a68aSyz147064 	laioc_add_rem_t *iocp;
524*f595a68aSyz147064 	laioc_port_t *ports;
525*f595a68aSyz147064 	dladm_status_t status = DLADM_STATUS_OK;
526*f595a68aSyz147064 
527*f595a68aSyz147064 	len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t);
528*f595a68aSyz147064 	iocp = malloc(len);
529*f595a68aSyz147064 	if (iocp == NULL) {
530*f595a68aSyz147064 		status = DLADM_STATUS_NOMEM;
531*f595a68aSyz147064 		goto done;
532*f595a68aSyz147064 	}
533*f595a68aSyz147064 
534*f595a68aSyz147064 	iocp->la_key = attr->lt_key;
535*f595a68aSyz147064 	iocp->la_nports = attr->lt_nports;
536*f595a68aSyz147064 	ports = (laioc_port_t *)(iocp + 1);
537*f595a68aSyz147064 
538*f595a68aSyz147064 	for (i = 0; i < attr->lt_nports; i++) {
539*f595a68aSyz147064 		if (strlcpy(ports[i].lp_devname,
540*f595a68aSyz147064 		    attr->lt_ports[i].lp_devname,
541*f595a68aSyz147064 		    MAXNAMELEN) >= MAXNAMELEN) {
542*f595a68aSyz147064 			status = DLADM_STATUS_BADARG;
543*f595a68aSyz147064 			goto done;
544*f595a68aSyz147064 		}
545*f595a68aSyz147064 	}
546*f595a68aSyz147064 
547*f595a68aSyz147064 	if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) {
548*f595a68aSyz147064 		status = dladm_errno2status(errno);
549*f595a68aSyz147064 		goto done;
550*f595a68aSyz147064 	}
551*f595a68aSyz147064 
552*f595a68aSyz147064 	rc = i_dladm_aggr_strioctl(fd, cmd, iocp, len);
553*f595a68aSyz147064 	if (rc < 0) {
554*f595a68aSyz147064 		if (errno == EINVAL)
555*f595a68aSyz147064 			status = DLADM_STATUS_LINKINVAL;
556*f595a68aSyz147064 		else
557*f595a68aSyz147064 			status = dladm_errno2status(errno);
558*f595a68aSyz147064 	}
559*f595a68aSyz147064 
560*f595a68aSyz147064 	(void) close(fd);
561*f595a68aSyz147064 
562*f595a68aSyz147064 done:
563*f595a68aSyz147064 	free(iocp);
564*f595a68aSyz147064 	return (status);
565*f595a68aSyz147064 }
566*f595a68aSyz147064 
567*f595a68aSyz147064 /*
568*f595a68aSyz147064  * Send a modify command to the link aggregation driver.
569*f595a68aSyz147064  */
570*f595a68aSyz147064 static dladm_status_t
571*f595a68aSyz147064 i_dladm_aggr_modify_sys(uint32_t key, uint32_t mask,
572*f595a68aSyz147064     dladm_aggr_modify_attr_t *attr)
573*f595a68aSyz147064 {
574*f595a68aSyz147064 	int rc, fd;
575*f595a68aSyz147064 	laioc_modify_t ioc;
576*f595a68aSyz147064 	dladm_status_t status = DLADM_STATUS_OK;
577*f595a68aSyz147064 
578*f595a68aSyz147064 	ioc.lu_key = key;
579*f595a68aSyz147064 
580*f595a68aSyz147064 	ioc.lu_modify_mask = 0;
581*f595a68aSyz147064 	if (mask & DLADM_AGGR_MODIFY_POLICY)
582*f595a68aSyz147064 		ioc.lu_modify_mask |= LAIOC_MODIFY_POLICY;
583*f595a68aSyz147064 	if (mask & DLADM_AGGR_MODIFY_MAC)
584*f595a68aSyz147064 		ioc.lu_modify_mask |= LAIOC_MODIFY_MAC;
585*f595a68aSyz147064 	if (mask & DLADM_AGGR_MODIFY_LACP_MODE)
586*f595a68aSyz147064 		ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_MODE;
587*f595a68aSyz147064 	if (mask & DLADM_AGGR_MODIFY_LACP_TIMER)
588*f595a68aSyz147064 		ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_TIMER;
589*f595a68aSyz147064 
590*f595a68aSyz147064 	ioc.lu_policy = attr->ld_policy;
591*f595a68aSyz147064 	ioc.lu_mac_fixed = attr->ld_mac_fixed;
592*f595a68aSyz147064 	bcopy(attr->ld_mac, ioc.lu_mac, ETHERADDRL);
593*f595a68aSyz147064 	ioc.lu_lacp_mode = attr->ld_lacp_mode;
594*f595a68aSyz147064 	ioc.lu_lacp_timer = attr->ld_lacp_timer;
595*f595a68aSyz147064 
596*f595a68aSyz147064 	if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0)
597*f595a68aSyz147064 		return (dladm_errno2status(errno));
598*f595a68aSyz147064 
599*f595a68aSyz147064 	rc = i_dladm_aggr_strioctl(fd, LAIOC_MODIFY, &ioc, sizeof (ioc));
600*f595a68aSyz147064 	if (rc < 0) {
601*f595a68aSyz147064 		if (errno == EINVAL)
602*f595a68aSyz147064 			status = DLADM_STATUS_MACADDRINVAL;
603*f595a68aSyz147064 		else
604*f595a68aSyz147064 			status = dladm_errno2status(errno);
605*f595a68aSyz147064 	}
606*f595a68aSyz147064 
607*f595a68aSyz147064 	(void) close(fd);
608*f595a68aSyz147064 	return (status);
609*f595a68aSyz147064 }
610*f595a68aSyz147064 
611*f595a68aSyz147064 /*
612*f595a68aSyz147064  * Send a create command to the link aggregation driver.
613*f595a68aSyz147064  */
614*f595a68aSyz147064 static dladm_status_t
615*f595a68aSyz147064 i_dladm_aggr_create_sys(int fd, dladm_aggr_grp_attr_db_t *attr)
616*f595a68aSyz147064 {
617*f595a68aSyz147064 	int i, rc, len;
618*f595a68aSyz147064 	laioc_create_t *iocp;
619*f595a68aSyz147064 	laioc_port_t *ports;
620*f595a68aSyz147064 	dladm_status_t status = DLADM_STATUS_OK;
621*f595a68aSyz147064 
622*f595a68aSyz147064 	len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t);
623*f595a68aSyz147064 	iocp = malloc(len);
624*f595a68aSyz147064 	if (iocp == NULL)
625*f595a68aSyz147064 		return (DLADM_STATUS_NOMEM);
626*f595a68aSyz147064 
627*f595a68aSyz147064 	iocp->lc_key = attr->lt_key;
628*f595a68aSyz147064 	iocp->lc_nports = attr->lt_nports;
629*f595a68aSyz147064 	iocp->lc_policy = attr->lt_policy;
630*f595a68aSyz147064 	iocp->lc_lacp_mode = attr->lt_lacp_mode;
631*f595a68aSyz147064 	iocp->lc_lacp_timer = attr->lt_lacp_timer;
632*f595a68aSyz147064 
633*f595a68aSyz147064 	ports = (laioc_port_t *)(iocp + 1);
634*f595a68aSyz147064 
635*f595a68aSyz147064 	for (i = 0; i < attr->lt_nports; i++) {
636*f595a68aSyz147064 		if (strlcpy(ports[i].lp_devname,
637*f595a68aSyz147064 		    attr->lt_ports[i].lp_devname,
638*f595a68aSyz147064 		    MAXNAMELEN) >= MAXNAMELEN) {
639*f595a68aSyz147064 			free(iocp);
640*f595a68aSyz147064 			return (DLADM_STATUS_BADARG);
641*f595a68aSyz147064 		}
642*f595a68aSyz147064 	}
643*f595a68aSyz147064 
644*f595a68aSyz147064 	if (attr->lt_mac_fixed &&
645*f595a68aSyz147064 	    ((bcmp(zero_mac, attr->lt_mac, ETHERADDRL) == 0) ||
646*f595a68aSyz147064 	    (attr->lt_mac[0] & 0x01))) {
647*f595a68aSyz147064 		free(iocp);
648*f595a68aSyz147064 		return (DLADM_STATUS_MACADDRINVAL);
649*f595a68aSyz147064 	}
650*f595a68aSyz147064 
651*f595a68aSyz147064 	bcopy(attr->lt_mac, iocp->lc_mac, ETHERADDRL);
652*f595a68aSyz147064 	iocp->lc_mac_fixed = attr->lt_mac_fixed;
653*f595a68aSyz147064 
654*f595a68aSyz147064 	rc = i_dladm_aggr_strioctl(fd, LAIOC_CREATE, iocp, len);
655*f595a68aSyz147064 	if (rc < 0)
656*f595a68aSyz147064 		status = DLADM_STATUS_LINKINVAL;
657*f595a68aSyz147064 
658*f595a68aSyz147064 	free(iocp);
659*f595a68aSyz147064 	return (status);
660*f595a68aSyz147064 }
661*f595a68aSyz147064 
662*f595a68aSyz147064 /*
663*f595a68aSyz147064  * Invoked to bring up a link aggregation group.
664*f595a68aSyz147064  */
665*f595a68aSyz147064 static dladm_status_t
666*f595a68aSyz147064 i_dladm_aggr_up(void *arg, dladm_aggr_grp_attr_db_t *attr)
667*f595a68aSyz147064 {
668*f595a68aSyz147064 	dladm_aggr_up_t	*up = (dladm_aggr_up_t *)arg;
669*f595a68aSyz147064 	dladm_status_t	status;
670*f595a68aSyz147064 
671*f595a68aSyz147064 	if (up->lu_key != 0 && up->lu_key != attr->lt_key)
672*f595a68aSyz147064 		return (DLADM_STATUS_OK);
673*f595a68aSyz147064 
674*f595a68aSyz147064 	up->lu_found = B_TRUE;
675*f595a68aSyz147064 
676*f595a68aSyz147064 	status = i_dladm_aggr_create_sys(up->lu_fd, attr);
677*f595a68aSyz147064 	if (status != DLADM_STATUS_OK && up->lu_key != 0)
678*f595a68aSyz147064 		return (status);
679*f595a68aSyz147064 
680*f595a68aSyz147064 	return (DLADM_STATUS_OK);
681*f595a68aSyz147064 }
682*f595a68aSyz147064 
683*f595a68aSyz147064 /*
684*f595a68aSyz147064  * Bring up a link aggregation group or all of them if the key is zero.
685*f595a68aSyz147064  * If key is 0, walk may terminate early if any of the links fail
686*f595a68aSyz147064  */
687*f595a68aSyz147064 dladm_status_t
688*f595a68aSyz147064 dladm_aggr_up(uint32_t key, const char *root)
689*f595a68aSyz147064 {
690*f595a68aSyz147064 	dladm_aggr_up_t up;
691*f595a68aSyz147064 	dladm_status_t status;
692*f595a68aSyz147064 
693*f595a68aSyz147064 	if ((up.lu_fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0)
694*f595a68aSyz147064 		return (dladm_errno2status(errno));
695*f595a68aSyz147064 
696*f595a68aSyz147064 	up.lu_key = key;
697*f595a68aSyz147064 	up.lu_found = B_FALSE;
698*f595a68aSyz147064 
699*f595a68aSyz147064 	status = i_dladm_aggr_walk_db(i_dladm_aggr_up, &up, root);
700*f595a68aSyz147064 	if (status != DLADM_STATUS_OK) {
701*f595a68aSyz147064 		(void) close(up.lu_fd);
702*f595a68aSyz147064 		return (status);
703*f595a68aSyz147064 	}
704*f595a68aSyz147064 	(void) close(up.lu_fd);
705*f595a68aSyz147064 
706*f595a68aSyz147064 	/*
707*f595a68aSyz147064 	 * only return error if user specified key and key was
708*f595a68aSyz147064 	 * not found
709*f595a68aSyz147064 	 */
710*f595a68aSyz147064 	if (!up.lu_found && key != 0)
711*f595a68aSyz147064 		return (DLADM_STATUS_NOTFOUND);
712*f595a68aSyz147064 
713*f595a68aSyz147064 	return (DLADM_STATUS_OK);
714*f595a68aSyz147064 }
715*f595a68aSyz147064 /*
716*f595a68aSyz147064  * Send a delete command to the link aggregation driver.
717*f595a68aSyz147064  */
718*f595a68aSyz147064 static int
719*f595a68aSyz147064 i_dladm_aggr_delete_sys(int fd, dladm_aggr_grp_attr_t *attr)
720*f595a68aSyz147064 {
721*f595a68aSyz147064 	laioc_delete_t ioc;
722*f595a68aSyz147064 
723*f595a68aSyz147064 	ioc.ld_key = attr->lg_key;
724*f595a68aSyz147064 
725*f595a68aSyz147064 	return (i_dladm_aggr_strioctl(fd, LAIOC_DELETE, &ioc, sizeof (ioc)));
726*f595a68aSyz147064 }
727*f595a68aSyz147064 
728*f595a68aSyz147064 /*
729*f595a68aSyz147064  * Invoked to bring down a link aggregation group.
730*f595a68aSyz147064  */
731*f595a68aSyz147064 static int
732*f595a68aSyz147064 i_dladm_aggr_down(void *arg, dladm_aggr_grp_attr_t *attr)
733*f595a68aSyz147064 {
734*f595a68aSyz147064 	dladm_aggr_down_t *down = (dladm_aggr_down_t *)arg;
735*f595a68aSyz147064 	int fd, errno_save;
736*f595a68aSyz147064 
737*f595a68aSyz147064 	if (down->ld_key != 0 && down->ld_key != attr->lg_key)
738*f595a68aSyz147064 		return (0);
739*f595a68aSyz147064 
740*f595a68aSyz147064 	down->ld_found = B_TRUE;
741*f595a68aSyz147064 
742*f595a68aSyz147064 	if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0)
743*f595a68aSyz147064 		return (-1);
744*f595a68aSyz147064 
745*f595a68aSyz147064 	if (i_dladm_aggr_delete_sys(fd, attr) < 0 && down->ld_key != 0) {
746*f595a68aSyz147064 		errno_save = errno;
747*f595a68aSyz147064 		(void) close(fd);
748*f595a68aSyz147064 		errno = errno_save;
749*f595a68aSyz147064 		return (-1);
750*f595a68aSyz147064 	}
751*f595a68aSyz147064 
752*f595a68aSyz147064 	(void) close(fd);
753*f595a68aSyz147064 	return (0);
754*f595a68aSyz147064 }
755*f595a68aSyz147064 
756*f595a68aSyz147064 /*
757*f595a68aSyz147064  * Bring down a link aggregation group or all of them if the key is zero.
758*f595a68aSyz147064  * If key is 0, walk may terminate early if any of the links fail
759*f595a68aSyz147064  */
760*f595a68aSyz147064 dladm_status_t
761*f595a68aSyz147064 dladm_aggr_down(uint32_t key)
762*f595a68aSyz147064 {
763*f595a68aSyz147064 	dladm_aggr_down_t down;
764*f595a68aSyz147064 
765*f595a68aSyz147064 	down.ld_key = key;
766*f595a68aSyz147064 	down.ld_found = B_FALSE;
767*f595a68aSyz147064 
768*f595a68aSyz147064 	if (dladm_aggr_walk(i_dladm_aggr_down, &down) < 0)
769*f595a68aSyz147064 		return (dladm_errno2status(errno));
770*f595a68aSyz147064 
771*f595a68aSyz147064 	/*
772*f595a68aSyz147064 	 * only return error if user specified key and key was
773*f595a68aSyz147064 	 * not found
774*f595a68aSyz147064 	 */
775*f595a68aSyz147064 	if (!down.ld_found && key != 0)
776*f595a68aSyz147064 		return (DLADM_STATUS_NOTFOUND);
777*f595a68aSyz147064 
778*f595a68aSyz147064 	return (DLADM_STATUS_OK);
779*f595a68aSyz147064 }
780*f595a68aSyz147064 
781*f595a68aSyz147064 /*
782*f595a68aSyz147064  * For each group <grp> found in the DB, invokes <fn>(<grp>, <arg>).
783*f595a68aSyz147064  *
784*f595a68aSyz147064  * The following values can be returned by <fn>():
785*f595a68aSyz147064  *
786*f595a68aSyz147064  * -1: an error occured. This will cause the walk to be terminated,
787*f595a68aSyz147064  *     and the original DB file to be preserved.
788*f595a68aSyz147064  *
789*f595a68aSyz147064  *  0: success and write. The walker will write the contents of
790*f595a68aSyz147064  *     the attribute passed as argument to <fn>(), and continue walking
791*f595a68aSyz147064  *     the entries found in the DB.
792*f595a68aSyz147064  *
793*f595a68aSyz147064  *  1: skip. The walker should not write the contents of the current
794*f595a68aSyz147064  *     group attributes to the new DB, but should continue walking
795*f595a68aSyz147064  *     the entries found in the DB.
796*f595a68aSyz147064  */
797*f595a68aSyz147064 static dladm_status_t
798*f595a68aSyz147064 i_dladm_aggr_walk_rw_db(int (*fn)(void *, dladm_aggr_grp_attr_db_t *),
799*f595a68aSyz147064     void *arg, const char *root)
800*f595a68aSyz147064 {
801*f595a68aSyz147064 	FILE *fp, *nfp;
802*f595a68aSyz147064 	int nfd, fn_rc, lock_fd;
803*f595a68aSyz147064 	char line[MAXLINELEN];
804*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t attr;
805*f595a68aSyz147064 	char *db_file, *tmp_db_file;
806*f595a68aSyz147064 	char db_file_buf[MAXPATHLEN];
807*f595a68aSyz147064 	char tmp_db_file_buf[MAXPATHLEN];
808*f595a68aSyz147064 	dladm_status_t status;
809*f595a68aSyz147064 
810*f595a68aSyz147064 	if (root == NULL) {
811*f595a68aSyz147064 		db_file = DLADM_AGGR_DB;
812*f595a68aSyz147064 		tmp_db_file = DLADM_AGGR_DB_TMP;
813*f595a68aSyz147064 	} else {
814*f595a68aSyz147064 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
815*f595a68aSyz147064 		    DLADM_AGGR_DB);
816*f595a68aSyz147064 		(void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root,
817*f595a68aSyz147064 		    DLADM_AGGR_DB_TMP);
818*f595a68aSyz147064 		db_file = db_file_buf;
819*f595a68aSyz147064 		tmp_db_file = tmp_db_file_buf;
820*f595a68aSyz147064 	}
821*f595a68aSyz147064 
822*f595a68aSyz147064 	if ((lock_fd = i_dladm_aggr_lock_db(F_WRLCK)) < 0)
823*f595a68aSyz147064 		return (dladm_errno2status(errno));
824*f595a68aSyz147064 
825*f595a68aSyz147064 	if ((fp = fopen(db_file, "r")) == NULL) {
826*f595a68aSyz147064 		status = dladm_errno2status(errno);
827*f595a68aSyz147064 		i_dladm_aggr_unlock_db(lock_fd);
828*f595a68aSyz147064 		return (status);
829*f595a68aSyz147064 	}
830*f595a68aSyz147064 
831*f595a68aSyz147064 	if ((nfd = open(tmp_db_file, O_WRONLY|O_CREAT|O_TRUNC,
832*f595a68aSyz147064 	    DLADM_AGGR_DB_PERMS)) == -1) {
833*f595a68aSyz147064 		status = dladm_errno2status(errno);
834*f595a68aSyz147064 		(void) fclose(fp);
835*f595a68aSyz147064 		i_dladm_aggr_unlock_db(lock_fd);
836*f595a68aSyz147064 		return (status);
837*f595a68aSyz147064 	}
838*f595a68aSyz147064 
839*f595a68aSyz147064 	if ((nfp = fdopen(nfd, "w")) == NULL) {
840*f595a68aSyz147064 		status = dladm_errno2status(errno);
841*f595a68aSyz147064 		(void) close(nfd);
842*f595a68aSyz147064 		(void) fclose(fp);
843*f595a68aSyz147064 		(void) unlink(tmp_db_file);
844*f595a68aSyz147064 		i_dladm_aggr_unlock_db(lock_fd);
845*f595a68aSyz147064 		return (status);
846*f595a68aSyz147064 	}
847*f595a68aSyz147064 
848*f595a68aSyz147064 	attr.lt_ports = NULL;
849*f595a68aSyz147064 
850*f595a68aSyz147064 	while (fgets(line, MAXLINELEN, fp) != NULL) {
851*f595a68aSyz147064 
852*f595a68aSyz147064 		/* skip comments */
853*f595a68aSyz147064 		if (BLANK_LINE(line)) {
854*f595a68aSyz147064 			if (fputs(line, nfp) == EOF) {
855*f595a68aSyz147064 				status = dladm_errno2status(errno);
856*f595a68aSyz147064 				goto failed;
857*f595a68aSyz147064 			}
858*f595a68aSyz147064 			continue;
859*f595a68aSyz147064 		}
860*f595a68aSyz147064 
861*f595a68aSyz147064 		if (i_dladm_aggr_parse_db(line, &attr) != 0) {
862*f595a68aSyz147064 			status = DLADM_STATUS_REPOSITORYINVAL;
863*f595a68aSyz147064 			goto failed;
864*f595a68aSyz147064 		}
865*f595a68aSyz147064 
866*f595a68aSyz147064 		fn_rc = fn(arg, &attr);
867*f595a68aSyz147064 
868*f595a68aSyz147064 		switch (fn_rc) {
869*f595a68aSyz147064 		case -1:
870*f595a68aSyz147064 			/* failure, stop walking */
871*f595a68aSyz147064 			status = dladm_errno2status(errno);
872*f595a68aSyz147064 			goto failed;
873*f595a68aSyz147064 		case 0:
874*f595a68aSyz147064 			/*
875*f595a68aSyz147064 			 * Success, write group attributes, which could
876*f595a68aSyz147064 			 * have been modified by fn().
877*f595a68aSyz147064 			 */
878*f595a68aSyz147064 			if (i_dladm_aggr_fput_grp(nfp, &attr) != 0) {
879*f595a68aSyz147064 				status = dladm_errno2status(errno);
880*f595a68aSyz147064 				goto failed;
881*f595a68aSyz147064 			}
882*f595a68aSyz147064 			break;
883*f595a68aSyz147064 		case 1:
884*f595a68aSyz147064 			/* skip current group */
885*f595a68aSyz147064 			break;
886*f595a68aSyz147064 		}
887*f595a68aSyz147064 
888*f595a68aSyz147064 		free(attr.lt_ports);
889*f595a68aSyz147064 		attr.lt_ports = NULL;
890*f595a68aSyz147064 	}
891*f595a68aSyz147064 
892*f595a68aSyz147064 	if (getuid() == 0 || geteuid() == 0) {
893*f595a68aSyz147064 		if (fchmod(nfd, DLADM_AGGR_DB_PERMS) == -1) {
894*f595a68aSyz147064 			status = dladm_errno2status(errno);
895*f595a68aSyz147064 			goto failed;
896*f595a68aSyz147064 		}
897*f595a68aSyz147064 
898*f595a68aSyz147064 		if (fchown(nfd, DLADM_AGGR_DB_OWNER,
899*f595a68aSyz147064 		    DLADM_AGGR_DB_GROUP) == -1) {
900*f595a68aSyz147064 			status = dladm_errno2status(errno);
901*f595a68aSyz147064 			goto failed;
902*f595a68aSyz147064 		}
903*f595a68aSyz147064 	}
904*f595a68aSyz147064 
905*f595a68aSyz147064 	if (fflush(nfp) == EOF) {
906*f595a68aSyz147064 		status = dladm_errno2status(errno);
907*f595a68aSyz147064 		goto failed;
908*f595a68aSyz147064 	}
909*f595a68aSyz147064 
910*f595a68aSyz147064 	(void) fclose(fp);
911*f595a68aSyz147064 	(void) fclose(nfp);
912*f595a68aSyz147064 
913*f595a68aSyz147064 	if (rename(tmp_db_file, db_file) == -1) {
914*f595a68aSyz147064 		status = dladm_errno2status(errno);
915*f595a68aSyz147064 		(void) unlink(tmp_db_file);
916*f595a68aSyz147064 		i_dladm_aggr_unlock_db(lock_fd);
917*f595a68aSyz147064 		return (status);
918*f595a68aSyz147064 	}
919*f595a68aSyz147064 
920*f595a68aSyz147064 	i_dladm_aggr_unlock_db(lock_fd);
921*f595a68aSyz147064 	return (DLADM_STATUS_OK);
922*f595a68aSyz147064 
923*f595a68aSyz147064 failed:
924*f595a68aSyz147064 	free(attr.lt_ports);
925*f595a68aSyz147064 	(void) fclose(fp);
926*f595a68aSyz147064 	(void) fclose(nfp);
927*f595a68aSyz147064 	(void) unlink(tmp_db_file);
928*f595a68aSyz147064 	i_dladm_aggr_unlock_db(lock_fd);
929*f595a68aSyz147064 
930*f595a68aSyz147064 	return (status);
931*f595a68aSyz147064 }
932*f595a68aSyz147064 
933*f595a68aSyz147064 /*
934*f595a68aSyz147064  * Remove an entry from the DB.
935*f595a68aSyz147064  */
936*f595a68aSyz147064 static int
937*f595a68aSyz147064 i_dladm_aggr_del_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp)
938*f595a68aSyz147064 {
939*f595a68aSyz147064 	delete_db_state_t *state = arg;
940*f595a68aSyz147064 
941*f595a68aSyz147064 	if (grp->lt_key != state->ds_key)
942*f595a68aSyz147064 		return (0);
943*f595a68aSyz147064 
944*f595a68aSyz147064 	state->ds_found = B_TRUE;
945*f595a68aSyz147064 
946*f595a68aSyz147064 	/* don't save matching group */
947*f595a68aSyz147064 	return (1);
948*f595a68aSyz147064 }
949*f595a68aSyz147064 
950*f595a68aSyz147064 static dladm_status_t
951*f595a68aSyz147064 i_dladm_aggr_del_db(dladm_aggr_grp_attr_db_t *attr, const char *root)
952*f595a68aSyz147064 {
953*f595a68aSyz147064 	delete_db_state_t state;
954*f595a68aSyz147064 	dladm_status_t status;
955*f595a68aSyz147064 
956*f595a68aSyz147064 	state.ds_key = attr->lt_key;
957*f595a68aSyz147064 	state.ds_found = B_FALSE;
958*f595a68aSyz147064 
959*f595a68aSyz147064 	status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_del_db_fn, &state, root);
960*f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
961*f595a68aSyz147064 		return (status);
962*f595a68aSyz147064 
963*f595a68aSyz147064 	if (!state.ds_found)
964*f595a68aSyz147064 		return (DLADM_STATUS_NOTFOUND);
965*f595a68aSyz147064 
966*f595a68aSyz147064 	return (DLADM_STATUS_OK);
967*f595a68aSyz147064 }
968*f595a68aSyz147064 
969*f595a68aSyz147064 /*
970*f595a68aSyz147064  * Modify the properties of an existing group in the DB.
971*f595a68aSyz147064  */
972*f595a68aSyz147064 static int
973*f595a68aSyz147064 i_dladm_aggr_modify_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp)
974*f595a68aSyz147064 {
975*f595a68aSyz147064 	modify_db_state_t *state = arg;
976*f595a68aSyz147064 	dladm_aggr_modify_attr_t *new_attr = state->us_attr_new;
977*f595a68aSyz147064 	dladm_aggr_modify_attr_t *old_attr = state->us_attr_old;
978*f595a68aSyz147064 
979*f595a68aSyz147064 	if (grp->lt_key != state->us_key)
980*f595a68aSyz147064 		return (0);
981*f595a68aSyz147064 
982*f595a68aSyz147064 	state->us_found = B_TRUE;
983*f595a68aSyz147064 
984*f595a68aSyz147064 	if (state->us_mask & DLADM_AGGR_MODIFY_POLICY) {
985*f595a68aSyz147064 		if (old_attr != NULL)
986*f595a68aSyz147064 			old_attr->ld_policy = grp->lt_policy;
987*f595a68aSyz147064 		grp->lt_policy = new_attr->ld_policy;
988*f595a68aSyz147064 	}
989*f595a68aSyz147064 
990*f595a68aSyz147064 	if (state->us_mask & DLADM_AGGR_MODIFY_MAC) {
991*f595a68aSyz147064 		if (old_attr != NULL) {
992*f595a68aSyz147064 			old_attr->ld_mac_fixed = grp->lt_mac_fixed;
993*f595a68aSyz147064 			bcopy(grp->lt_mac, old_attr->ld_mac, ETHERADDRL);
994*f595a68aSyz147064 		}
995*f595a68aSyz147064 		grp->lt_mac_fixed = new_attr->ld_mac_fixed;
996*f595a68aSyz147064 		bcopy(new_attr->ld_mac, grp->lt_mac, ETHERADDRL);
997*f595a68aSyz147064 	}
998*f595a68aSyz147064 
999*f595a68aSyz147064 	if (state->us_mask & DLADM_AGGR_MODIFY_LACP_MODE) {
1000*f595a68aSyz147064 		if (old_attr != NULL)
1001*f595a68aSyz147064 			old_attr->ld_lacp_mode = grp->lt_lacp_mode;
1002*f595a68aSyz147064 		grp->lt_lacp_mode = new_attr->ld_lacp_mode;
1003*f595a68aSyz147064 	}
1004*f595a68aSyz147064 
1005*f595a68aSyz147064 	if (state->us_mask & DLADM_AGGR_MODIFY_LACP_TIMER) {
1006*f595a68aSyz147064 		if (old_attr != NULL)
1007*f595a68aSyz147064 			old_attr->ld_lacp_timer = grp->lt_lacp_timer;
1008*f595a68aSyz147064 		grp->lt_lacp_timer = new_attr->ld_lacp_timer;
1009*f595a68aSyz147064 	}
1010*f595a68aSyz147064 
1011*f595a68aSyz147064 	/* save modified group */
1012*f595a68aSyz147064 	return (0);
1013*f595a68aSyz147064 }
1014*f595a68aSyz147064 
1015*f595a68aSyz147064 static dladm_status_t
1016*f595a68aSyz147064 i_dladm_aggr_modify_db(uint32_t key, uint32_t mask,
1017*f595a68aSyz147064     dladm_aggr_modify_attr_t *new, dladm_aggr_modify_attr_t *old,
1018*f595a68aSyz147064     const char *root)
1019*f595a68aSyz147064 {
1020*f595a68aSyz147064 	modify_db_state_t state;
1021*f595a68aSyz147064 	dladm_status_t status;
1022*f595a68aSyz147064 
1023*f595a68aSyz147064 	state.us_key = key;
1024*f595a68aSyz147064 	state.us_mask = mask;
1025*f595a68aSyz147064 	state.us_attr_new = new;
1026*f595a68aSyz147064 	state.us_attr_old = old;
1027*f595a68aSyz147064 	state.us_found = B_FALSE;
1028*f595a68aSyz147064 
1029*f595a68aSyz147064 	if ((status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_modify_db_fn,
1030*f595a68aSyz147064 	    &state, root)) != DLADM_STATUS_OK) {
1031*f595a68aSyz147064 		return (status);
1032*f595a68aSyz147064 	}
1033*f595a68aSyz147064 
1034*f595a68aSyz147064 	if (!state.us_found)
1035*f595a68aSyz147064 		return (DLADM_STATUS_NOTFOUND);
1036*f595a68aSyz147064 
1037*f595a68aSyz147064 	return (DLADM_STATUS_OK);
1038*f595a68aSyz147064 }
1039*f595a68aSyz147064 
1040*f595a68aSyz147064 /*
1041*f595a68aSyz147064  * Add ports to an existing group in the DB.
1042*f595a68aSyz147064  */
1043*f595a68aSyz147064 static int
1044*f595a68aSyz147064 i_dladm_aggr_add_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp)
1045*f595a68aSyz147064 {
1046*f595a68aSyz147064 	add_db_state_t *state = arg;
1047*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t *attr = state->as_attr;
1048*f595a68aSyz147064 	void *ports;
1049*f595a68aSyz147064 	int i, j;
1050*f595a68aSyz147064 
1051*f595a68aSyz147064 	if (grp->lt_key != attr->lt_key)
1052*f595a68aSyz147064 		return (0);
1053*f595a68aSyz147064 
1054*f595a68aSyz147064 	state->as_found = B_TRUE;
1055*f595a68aSyz147064 
1056*f595a68aSyz147064 	/* are any of the ports to be added already members of the group? */
1057*f595a68aSyz147064 	for (i = 0; i < grp->lt_nports; i++) {
1058*f595a68aSyz147064 		for (j = 0; j < attr->lt_nports; j++) {
1059*f595a68aSyz147064 			if (strcmp(grp->lt_ports[i].lp_devname,
1060*f595a68aSyz147064 			    attr->lt_ports[j].lp_devname) == 0) {
1061*f595a68aSyz147064 				errno = EEXIST;
1062*f595a68aSyz147064 				return (-1);
1063*f595a68aSyz147064 			}
1064*f595a68aSyz147064 		}
1065*f595a68aSyz147064 	}
1066*f595a68aSyz147064 
1067*f595a68aSyz147064 	/* add groups specified by attr to grp */
1068*f595a68aSyz147064 	ports = realloc(grp->lt_ports, (grp->lt_nports +
1069*f595a68aSyz147064 	    attr->lt_nports) * sizeof (dladm_aggr_port_attr_db_t));
1070*f595a68aSyz147064 	if (ports == NULL)
1071*f595a68aSyz147064 		return (-1);
1072*f595a68aSyz147064 	grp->lt_ports = ports;
1073*f595a68aSyz147064 
1074*f595a68aSyz147064 	for (i = 0; i < attr->lt_nports; i++) {
1075*f595a68aSyz147064 		if (strlcpy(grp->lt_ports[grp->lt_nports + i].lp_devname,
1076*f595a68aSyz147064 		    attr->lt_ports[i].lp_devname, MAXNAMELEN + 1) >=
1077*f595a68aSyz147064 		    MAXNAMELEN + 1)
1078*f595a68aSyz147064 			return (-1);
1079*f595a68aSyz147064 	}
1080*f595a68aSyz147064 
1081*f595a68aSyz147064 	grp->lt_nports += attr->lt_nports;
1082*f595a68aSyz147064 
1083*f595a68aSyz147064 	/* save modified group */
1084*f595a68aSyz147064 	return (0);
1085*f595a68aSyz147064 }
1086*f595a68aSyz147064 
1087*f595a68aSyz147064 static dladm_status_t
1088*f595a68aSyz147064 i_dladm_aggr_add_db(dladm_aggr_grp_attr_db_t *attr, const char *root)
1089*f595a68aSyz147064 {
1090*f595a68aSyz147064 	add_db_state_t state;
1091*f595a68aSyz147064 	dladm_status_t status;
1092*f595a68aSyz147064 
1093*f595a68aSyz147064 	state.as_attr = attr;
1094*f595a68aSyz147064 	state.as_found = B_FALSE;
1095*f595a68aSyz147064 
1096*f595a68aSyz147064 	status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_add_db_fn, &state, root);
1097*f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1098*f595a68aSyz147064 		return (status);
1099*f595a68aSyz147064 
1100*f595a68aSyz147064 	if (!state.as_found)
1101*f595a68aSyz147064 		return (DLADM_STATUS_NOTFOUND);
1102*f595a68aSyz147064 
1103*f595a68aSyz147064 	return (DLADM_STATUS_OK);
1104*f595a68aSyz147064 }
1105*f595a68aSyz147064 
1106*f595a68aSyz147064 /*
1107*f595a68aSyz147064  * Remove ports from an existing group in the DB.
1108*f595a68aSyz147064  */
1109*f595a68aSyz147064 
1110*f595a68aSyz147064 typedef struct remove_db_state {
1111*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t *rs_attr;
1112*f595a68aSyz147064 	boolean_t	rs_found;
1113*f595a68aSyz147064 } remove_db_state_t;
1114*f595a68aSyz147064 
1115*f595a68aSyz147064 static int
1116*f595a68aSyz147064 i_dladm_aggr_remove_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp)
1117*f595a68aSyz147064 {
1118*f595a68aSyz147064 	remove_db_state_t *state = (remove_db_state_t *)arg;
1119*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t *attr = state->rs_attr;
1120*f595a68aSyz147064 	int i, j, k, nremoved;
1121*f595a68aSyz147064 	boolean_t match;
1122*f595a68aSyz147064 
1123*f595a68aSyz147064 	if (grp->lt_key != attr->lt_key)
1124*f595a68aSyz147064 		return (0);
1125*f595a68aSyz147064 
1126*f595a68aSyz147064 	state->rs_found = B_TRUE;
1127*f595a68aSyz147064 
1128*f595a68aSyz147064 	/* remove the ports specified by attr from the group */
1129*f595a68aSyz147064 	nremoved = 0;
1130*f595a68aSyz147064 	k = 0;
1131*f595a68aSyz147064 	for (i = 0; i < grp->lt_nports; i++) {
1132*f595a68aSyz147064 		match = B_FALSE;
1133*f595a68aSyz147064 		for (j = 0; j < attr->lt_nports && !match; j++) {
1134*f595a68aSyz147064 			match = (strcmp(grp->lt_ports[i].lp_devname,
1135*f595a68aSyz147064 			    attr->lt_ports[j].lp_devname) == 0);
1136*f595a68aSyz147064 		}
1137*f595a68aSyz147064 		if (match)
1138*f595a68aSyz147064 			nremoved++;
1139*f595a68aSyz147064 		else
1140*f595a68aSyz147064 			grp->lt_ports[k++] = grp->lt_ports[i];
1141*f595a68aSyz147064 	}
1142*f595a68aSyz147064 
1143*f595a68aSyz147064 	if (nremoved != attr->lt_nports) {
1144*f595a68aSyz147064 		errno = ENOENT;
1145*f595a68aSyz147064 		return (-1);
1146*f595a68aSyz147064 	}
1147*f595a68aSyz147064 
1148*f595a68aSyz147064 	grp->lt_nports -= nremoved;
1149*f595a68aSyz147064 
1150*f595a68aSyz147064 	/* save modified group */
1151*f595a68aSyz147064 	return (0);
1152*f595a68aSyz147064 }
1153*f595a68aSyz147064 
1154*f595a68aSyz147064 static dladm_status_t
1155*f595a68aSyz147064 i_dladm_aggr_remove_db(dladm_aggr_grp_attr_db_t *attr, const char *root)
1156*f595a68aSyz147064 {
1157*f595a68aSyz147064 	remove_db_state_t state;
1158*f595a68aSyz147064 	dladm_status_t status;
1159*f595a68aSyz147064 
1160*f595a68aSyz147064 	state.rs_attr = attr;
1161*f595a68aSyz147064 	state.rs_found = B_FALSE;
1162*f595a68aSyz147064 
1163*f595a68aSyz147064 	status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_remove_db_fn,
1164*f595a68aSyz147064 	    &state, root);
1165*f595a68aSyz147064 	if (status != DLADM_STATUS_OK)
1166*f595a68aSyz147064 		return (status);
1167*f595a68aSyz147064 
1168*f595a68aSyz147064 	if (!state.rs_found)
1169*f595a68aSyz147064 		return (DLADM_STATUS_NOTFOUND);
1170*f595a68aSyz147064 
1171*f595a68aSyz147064 	return (DLADM_STATUS_OK);
1172*f595a68aSyz147064 }
1173*f595a68aSyz147064 
1174*f595a68aSyz147064 /*
1175*f595a68aSyz147064  * Given a policy string, return a policy mask. Returns B_TRUE on
1176*f595a68aSyz147064  * success, or B_FALSE if an error occured during parsing.
1177*f595a68aSyz147064  */
1178*f595a68aSyz147064 boolean_t
1179*f595a68aSyz147064 dladm_aggr_str2policy(const char *str, uint32_t *policy)
1180*f595a68aSyz147064 {
1181*f595a68aSyz147064 	int i;
1182*f595a68aSyz147064 	policy_t *pol;
1183*f595a68aSyz147064 	char *token = NULL;
1184*f595a68aSyz147064 	char *lasts;
1185*f595a68aSyz147064 
1186*f595a68aSyz147064 	*policy = 0;
1187*f595a68aSyz147064 
1188*f595a68aSyz147064 	while ((token = strtok_r((token == NULL) ? (char *)str : NULL, ",",
1189*f595a68aSyz147064 	    &lasts)) != NULL) {
1190*f595a68aSyz147064 		for (i = 0; i < NPOLICIES; i++) {
1191*f595a68aSyz147064 			pol = &policies[i];
1192*f595a68aSyz147064 			if (strcasecmp(token, pol->pol_name) == 0) {
1193*f595a68aSyz147064 				*policy |= pol->policy;
1194*f595a68aSyz147064 				break;
1195*f595a68aSyz147064 			}
1196*f595a68aSyz147064 		}
1197*f595a68aSyz147064 		if (i == NPOLICIES)
1198*f595a68aSyz147064 			return (B_FALSE);
1199*f595a68aSyz147064 	}
1200*f595a68aSyz147064 
1201*f595a68aSyz147064 	return (B_TRUE);
1202*f595a68aSyz147064 }
1203*f595a68aSyz147064 
1204*f595a68aSyz147064 /*
1205*f595a68aSyz147064  * Given a policy mask, returns a printable string, or NULL if the
1206*f595a68aSyz147064  * policy mask is invalid. It is the responsibility of the caller to
1207*f595a68aSyz147064  * free the returned string after use.
1208*f595a68aSyz147064  */
1209*f595a68aSyz147064 char *
1210*f595a68aSyz147064 dladm_aggr_policy2str(uint32_t policy, char *str)
1211*f595a68aSyz147064 {
1212*f595a68aSyz147064 	int i, npolicies = 0;
1213*f595a68aSyz147064 	policy_t *pol;
1214*f595a68aSyz147064 
1215*f595a68aSyz147064 	str[0] = '\0';
1216*f595a68aSyz147064 
1217*f595a68aSyz147064 	for (i = 0; i < NPOLICIES; i++) {
1218*f595a68aSyz147064 		pol = &policies[i];
1219*f595a68aSyz147064 		if ((policy & pol->policy) != 0) {
1220*f595a68aSyz147064 			npolicies++;
1221*f595a68aSyz147064 			if (npolicies > 1)
1222*f595a68aSyz147064 				(void) strcat(str, ",");
1223*f595a68aSyz147064 			(void) strcat(str, pol->pol_name);
1224*f595a68aSyz147064 		}
1225*f595a68aSyz147064 	}
1226*f595a68aSyz147064 
1227*f595a68aSyz147064 	return (str);
1228*f595a68aSyz147064 }
1229*f595a68aSyz147064 
1230*f595a68aSyz147064 /*
1231*f595a68aSyz147064  * Given a MAC address string, return the MAC address in the mac_addr
1232*f595a68aSyz147064  * array. If the MAC address was not explicitly specified, i.e. is
1233*f595a68aSyz147064  * equal to 'auto', zero out mac-addr and set mac_fixed to B_TRUE.
1234*f595a68aSyz147064  * Return B_FALSE if a syntax error was encountered, B_FALSE otherwise.
1235*f595a68aSyz147064  */
1236*f595a68aSyz147064 boolean_t
1237*f595a68aSyz147064 dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr)
1238*f595a68aSyz147064 {
1239*f595a68aSyz147064 	uchar_t *conv_str;
1240*f595a68aSyz147064 	int mac_len;
1241*f595a68aSyz147064 
1242*f595a68aSyz147064 	*mac_fixed = (strcmp(str, "auto") != 0);
1243*f595a68aSyz147064 	if (!*mac_fixed) {
1244*f595a68aSyz147064 		bzero(mac_addr, ETHERADDRL);
1245*f595a68aSyz147064 		return (B_TRUE);
1246*f595a68aSyz147064 	}
1247*f595a68aSyz147064 
1248*f595a68aSyz147064 	conv_str = _link_aton(str, &mac_len);
1249*f595a68aSyz147064 	if (conv_str == NULL)
1250*f595a68aSyz147064 		return (B_FALSE);
1251*f595a68aSyz147064 
1252*f595a68aSyz147064 	if (mac_len != ETHERADDRL) {
1253*f595a68aSyz147064 		free(conv_str);
1254*f595a68aSyz147064 		return (B_FALSE);
1255*f595a68aSyz147064 	}
1256*f595a68aSyz147064 
1257*f595a68aSyz147064 	if ((bcmp(zero_mac, conv_str, ETHERADDRL) == 0) ||
1258*f595a68aSyz147064 	    (conv_str[0] & 0x01)) {
1259*f595a68aSyz147064 		free(conv_str);
1260*f595a68aSyz147064 		return (B_FALSE);
1261*f595a68aSyz147064 	}
1262*f595a68aSyz147064 
1263*f595a68aSyz147064 	bcopy(conv_str, mac_addr, ETHERADDRL);
1264*f595a68aSyz147064 	free(conv_str);
1265*f595a68aSyz147064 
1266*f595a68aSyz147064 	return (B_TRUE);
1267*f595a68aSyz147064 }
1268*f595a68aSyz147064 
1269*f595a68aSyz147064 /*
1270*f595a68aSyz147064  * Returns a string containing a printable representation of a MAC address.
1271*f595a68aSyz147064  */
1272*f595a68aSyz147064 const char *
1273*f595a68aSyz147064 dladm_aggr_macaddr2str(unsigned char *mac, char *buf)
1274*f595a68aSyz147064 {
1275*f595a68aSyz147064 	static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
1276*f595a68aSyz147064 
1277*f595a68aSyz147064 	if (buf == NULL)
1278*f595a68aSyz147064 		return (NULL);
1279*f595a68aSyz147064 
1280*f595a68aSyz147064 	if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
1281*f595a68aSyz147064 		return (gettext("<unknown>"));
1282*f595a68aSyz147064 	else
1283*f595a68aSyz147064 		return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
1284*f595a68aSyz147064 }
1285*f595a68aSyz147064 
1286*f595a68aSyz147064 /*
1287*f595a68aSyz147064  * Given a LACP mode string, find the corresponding LACP mode number. Returns
1288*f595a68aSyz147064  * B_TRUE if a match was found, B_FALSE otherwise.
1289*f595a68aSyz147064  */
1290*f595a68aSyz147064 boolean_t
1291*f595a68aSyz147064 dladm_aggr_str2lacpmode(const char *str, aggr_lacp_mode_t *lacp_mode)
1292*f595a68aSyz147064 {
1293*f595a68aSyz147064 	int i;
1294*f595a68aSyz147064 	dladm_aggr_lacpmode_t *mode;
1295*f595a68aSyz147064 
1296*f595a68aSyz147064 	for (i = 0; i < NLACP_MODES; i++) {
1297*f595a68aSyz147064 		mode = &lacp_modes[i];
1298*f595a68aSyz147064 		if (strncasecmp(str, mode->mode_str,
1299*f595a68aSyz147064 		    strlen(mode->mode_str)) == 0) {
1300*f595a68aSyz147064 			*lacp_mode = mode->mode_id;
1301*f595a68aSyz147064 			return (B_TRUE);
1302*f595a68aSyz147064 		}
1303*f595a68aSyz147064 	}
1304*f595a68aSyz147064 
1305*f595a68aSyz147064 	return (B_FALSE);
1306*f595a68aSyz147064 }
1307*f595a68aSyz147064 
1308*f595a68aSyz147064 /*
1309*f595a68aSyz147064  * Given a LACP mode number, returns a printable string, or NULL if the
1310*f595a68aSyz147064  * LACP mode number is invalid.
1311*f595a68aSyz147064  */
1312*f595a68aSyz147064 const char *
1313*f595a68aSyz147064 dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf)
1314*f595a68aSyz147064 {
1315*f595a68aSyz147064 	int i;
1316*f595a68aSyz147064 	dladm_aggr_lacpmode_t *mode;
1317*f595a68aSyz147064 
1318*f595a68aSyz147064 	for (i = 0; i < NLACP_MODES; i++) {
1319*f595a68aSyz147064 		mode = &lacp_modes[i];
1320*f595a68aSyz147064 		if (mode->mode_id == mode_id) {
1321*f595a68aSyz147064 			(void) snprintf(buf, DLADM_STRSIZE, "%s",
1322*f595a68aSyz147064 			    mode->mode_str);
1323*f595a68aSyz147064 			return (buf);
1324*f595a68aSyz147064 		}
1325*f595a68aSyz147064 	}
1326*f595a68aSyz147064 
1327*f595a68aSyz147064 	(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
1328*f595a68aSyz147064 	return (buf);
1329*f595a68aSyz147064 }
1330*f595a68aSyz147064 
1331*f595a68aSyz147064 /*
1332*f595a68aSyz147064  * Given a LACP timer string, find the corresponding LACP timer number. Returns
1333*f595a68aSyz147064  * B_TRUE if a match was found, B_FALSE otherwise.
1334*f595a68aSyz147064  */
1335*f595a68aSyz147064 boolean_t
1336*f595a68aSyz147064 dladm_aggr_str2lacptimer(const char *str, aggr_lacp_timer_t *lacp_timer)
1337*f595a68aSyz147064 {
1338*f595a68aSyz147064 	int i;
1339*f595a68aSyz147064 	dladm_aggr_lacptimer_t *timer;
1340*f595a68aSyz147064 
1341*f595a68aSyz147064 	for (i = 0; i < NLACP_TIMERS; i++) {
1342*f595a68aSyz147064 		timer = &lacp_timers[i];
1343*f595a68aSyz147064 		if (strncasecmp(str, timer->lt_str,
1344*f595a68aSyz147064 		    strlen(timer->lt_str)) == 0) {
1345*f595a68aSyz147064 			*lacp_timer = timer->lt_id;
1346*f595a68aSyz147064 			return (B_TRUE);
1347*f595a68aSyz147064 		}
1348*f595a68aSyz147064 	}
1349*f595a68aSyz147064 
1350*f595a68aSyz147064 	return (B_FALSE);
1351*f595a68aSyz147064 }
1352*f595a68aSyz147064 
1353*f595a68aSyz147064 /*
1354*f595a68aSyz147064  * Given a LACP timer, returns a printable string, or NULL if the
1355*f595a68aSyz147064  * LACP timer number is invalid.
1356*f595a68aSyz147064  */
1357*f595a68aSyz147064 const char *
1358*f595a68aSyz147064 dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf)
1359*f595a68aSyz147064 {
1360*f595a68aSyz147064 	int i;
1361*f595a68aSyz147064 	dladm_aggr_lacptimer_t *timer;
1362*f595a68aSyz147064 
1363*f595a68aSyz147064 	for (i = 0; i < NLACP_TIMERS; i++) {
1364*f595a68aSyz147064 		timer = &lacp_timers[i];
1365*f595a68aSyz147064 		if (timer->lt_id == timer_id) {
1366*f595a68aSyz147064 			(void) snprintf(buf, DLADM_STRSIZE, "%s",
1367*f595a68aSyz147064 			    timer->lt_str);
1368*f595a68aSyz147064 			return (buf);
1369*f595a68aSyz147064 		}
1370*f595a68aSyz147064 	}
1371*f595a68aSyz147064 
1372*f595a68aSyz147064 	(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
1373*f595a68aSyz147064 	return (buf);
1374*f595a68aSyz147064 }
1375*f595a68aSyz147064 
1376*f595a68aSyz147064 const char *
1377*f595a68aSyz147064 dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf)
1378*f595a68aSyz147064 {
1379*f595a68aSyz147064 	int			i;
1380*f595a68aSyz147064 	dladm_aggr_port_state_t	*state;
1381*f595a68aSyz147064 
1382*f595a68aSyz147064 	for (i = 0; i < NPORT_STATES; i++) {
1383*f595a68aSyz147064 		state = &port_states[i];
1384*f595a68aSyz147064 		if (state->state_id == state_id) {
1385*f595a68aSyz147064 			(void) snprintf(buf, DLADM_STRSIZE, "%s",
1386*f595a68aSyz147064 			    state->state_str);
1387*f595a68aSyz147064 			return (buf);
1388*f595a68aSyz147064 		}
1389*f595a68aSyz147064 	}
1390*f595a68aSyz147064 
1391*f595a68aSyz147064 	(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
1392*f595a68aSyz147064 	return (buf);
1393*f595a68aSyz147064 }
1394*f595a68aSyz147064 
1395*f595a68aSyz147064 #define	FPRINTF_ERR(fcall) if ((fcall) < 0) return (-1);
1396*f595a68aSyz147064 
1397*f595a68aSyz147064 /*
1398*f595a68aSyz147064  * Write the attribute of a group to the specified file. Returns 0 on
1399*f595a68aSyz147064  * success, -1 on failure.
1400*f595a68aSyz147064  */
1401*f595a68aSyz147064 static int
1402*f595a68aSyz147064 i_dladm_aggr_fput_grp(FILE *fp, dladm_aggr_grp_attr_db_t *attr)
1403*f595a68aSyz147064 {
1404*f595a68aSyz147064 	int i;
1405*f595a68aSyz147064 	char addr_str[ETHERADDRL * 3];
1406*f595a68aSyz147064 	char buf[DLADM_STRSIZE];
1407*f595a68aSyz147064 
1408*f595a68aSyz147064 	/* key, policy */
1409*f595a68aSyz147064 	FPRINTF_ERR(fprintf(fp, "%d\t%s\t", attr->lt_key,
1410*f595a68aSyz147064 	    dladm_aggr_policy2str(attr->lt_policy, buf)));
1411*f595a68aSyz147064 
1412*f595a68aSyz147064 	/* number of ports, ports */
1413*f595a68aSyz147064 	FPRINTF_ERR(fprintf(fp, "%d\t", attr->lt_nports));
1414*f595a68aSyz147064 	for (i = 0; i < attr->lt_nports; i++) {
1415*f595a68aSyz147064 		if (i > 0)
1416*f595a68aSyz147064 			FPRINTF_ERR(fprintf(fp, ","));
1417*f595a68aSyz147064 		FPRINTF_ERR(fprintf(fp, "%s", attr->lt_ports[i].lp_devname));
1418*f595a68aSyz147064 	}
1419*f595a68aSyz147064 	FPRINTF_ERR(fprintf(fp, "\t"));
1420*f595a68aSyz147064 
1421*f595a68aSyz147064 	/* MAC address */
1422*f595a68aSyz147064 	if (!attr->lt_mac_fixed) {
1423*f595a68aSyz147064 		FPRINTF_ERR(fprintf(fp, "auto"));
1424*f595a68aSyz147064 	} else {
1425*f595a68aSyz147064 		FPRINTF_ERR(fprintf(fp, "%s",
1426*f595a68aSyz147064 		    dladm_aggr_macaddr2str(attr->lt_mac, addr_str)));
1427*f595a68aSyz147064 	}
1428*f595a68aSyz147064 	FPRINTF_ERR(fprintf(fp, "\t"));
1429*f595a68aSyz147064 
1430*f595a68aSyz147064 	FPRINTF_ERR(fprintf(fp, "%s\t",
1431*f595a68aSyz147064 	    dladm_aggr_lacpmode2str(attr->lt_lacp_mode, buf)));
1432*f595a68aSyz147064 
1433*f595a68aSyz147064 	FPRINTF_ERR(fprintf(fp, "%s\n",
1434*f595a68aSyz147064 	    dladm_aggr_lacptimer2str(attr->lt_lacp_timer, buf)));
1435*f595a68aSyz147064 
1436*f595a68aSyz147064 	return (0);
1437*f595a68aSyz147064 }
1438*f595a68aSyz147064 
1439*f595a68aSyz147064 static dladm_status_t
1440*f595a68aSyz147064 i_dladm_aggr_create_db(dladm_aggr_grp_attr_db_t *attr, const char *root)
1441*f595a68aSyz147064 {
1442*f595a68aSyz147064 	FILE		*fp;
1443*f595a68aSyz147064 	char		line[MAXLINELEN];
1444*f595a68aSyz147064 	uint32_t	key;
1445*f595a68aSyz147064 	int 		lock_fd;
1446*f595a68aSyz147064 	char 		*db_file;
1447*f595a68aSyz147064 	char 		db_file_buf[MAXPATHLEN];
1448*f595a68aSyz147064 	char 		*endp = NULL;
1449*f595a68aSyz147064 	dladm_status_t	status;
1450*f595a68aSyz147064 
1451*f595a68aSyz147064 	if (root == NULL) {
1452*f595a68aSyz147064 		db_file = DLADM_AGGR_DB;
1453*f595a68aSyz147064 	} else {
1454*f595a68aSyz147064 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
1455*f595a68aSyz147064 		    DLADM_AGGR_DB);
1456*f595a68aSyz147064 		db_file = db_file_buf;
1457*f595a68aSyz147064 	}
1458*f595a68aSyz147064 
1459*f595a68aSyz147064 	if ((lock_fd = i_dladm_aggr_lock_db(F_WRLCK)) < 0)
1460*f595a68aSyz147064 		return (dladm_errno2status(errno));
1461*f595a68aSyz147064 
1462*f595a68aSyz147064 	if ((fp = fopen(db_file, "r+")) == NULL &&
1463*f595a68aSyz147064 	    (fp = fopen(db_file, "w")) == NULL) {
1464*f595a68aSyz147064 		status = dladm_errno2status(errno);
1465*f595a68aSyz147064 		i_dladm_aggr_unlock_db(lock_fd);
1466*f595a68aSyz147064 		return (status);
1467*f595a68aSyz147064 	}
1468*f595a68aSyz147064 
1469*f595a68aSyz147064 	/* look for existing group with same key */
1470*f595a68aSyz147064 	while (fgets(line, MAXLINELEN, fp) != NULL) {
1471*f595a68aSyz147064 		char *holder, *lasts;
1472*f595a68aSyz147064 
1473*f595a68aSyz147064 		/* skip comments */
1474*f595a68aSyz147064 		if (BLANK_LINE(line))
1475*f595a68aSyz147064 			continue;
1476*f595a68aSyz147064 
1477*f595a68aSyz147064 		/* ignore corrupted lines */
1478*f595a68aSyz147064 		holder = strtok_r(line, " \t", &lasts);
1479*f595a68aSyz147064 		if (holder == NULL)
1480*f595a68aSyz147064 			continue;
1481*f595a68aSyz147064 
1482*f595a68aSyz147064 		/* port number */
1483*f595a68aSyz147064 		errno = 0;
1484*f595a68aSyz147064 		key = (int)strtol(holder, &endp, 10);
1485*f595a68aSyz147064 		if (errno != 0 || *endp != '\0') {
1486*f595a68aSyz147064 			status = DLADM_STATUS_REPOSITORYINVAL;
1487*f595a68aSyz147064 			goto done;
1488*f595a68aSyz147064 		}
1489*f595a68aSyz147064 
1490*f595a68aSyz147064 		if (key == attr->lt_key) {
1491*f595a68aSyz147064 			/* group with key already exists */
1492*f595a68aSyz147064 			status = DLADM_STATUS_EXIST;
1493*f595a68aSyz147064 			goto done;
1494*f595a68aSyz147064 		}
1495*f595a68aSyz147064 	}
1496*f595a68aSyz147064 
1497*f595a68aSyz147064 	/*
1498*f595a68aSyz147064 	 * If we get here, we've verified that no existing group with
1499*f595a68aSyz147064 	 * the same key already exists. It's now time to add the
1500*f595a68aSyz147064 	 * new group to the DB.
1501*f595a68aSyz147064 	 */
1502*f595a68aSyz147064 	if (i_dladm_aggr_fput_grp(fp, attr) != 0) {
1503*f595a68aSyz147064 		status = dladm_errno2status(errno);
1504*f595a68aSyz147064 		goto done;
1505*f595a68aSyz147064 	}
1506*f595a68aSyz147064 
1507*f595a68aSyz147064 	status = DLADM_STATUS_OK;
1508*f595a68aSyz147064 
1509*f595a68aSyz147064 done:
1510*f595a68aSyz147064 	(void) fclose(fp);
1511*f595a68aSyz147064 	i_dladm_aggr_unlock_db(lock_fd);
1512*f595a68aSyz147064 	return (status);
1513*f595a68aSyz147064 }
1514*f595a68aSyz147064 
1515*f595a68aSyz147064 /*
1516*f595a68aSyz147064  * Create a new link aggregation group. Update the configuration
1517*f595a68aSyz147064  * file and bring it up.
1518*f595a68aSyz147064  */
1519*f595a68aSyz147064 dladm_status_t
1520*f595a68aSyz147064 dladm_aggr_create(uint32_t key, uint32_t nports,
1521*f595a68aSyz147064     dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed,
1522*f595a68aSyz147064     uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer,
1523*f595a68aSyz147064     boolean_t tempop, const char *root)
1524*f595a68aSyz147064 {
1525*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t attr;
1526*f595a68aSyz147064 	dladm_status_t status;
1527*f595a68aSyz147064 
1528*f595a68aSyz147064 	if (key == 0 || key > DLADM_AGGR_MAX_KEY)
1529*f595a68aSyz147064 		return (DLADM_STATUS_KEYINVAL);
1530*f595a68aSyz147064 
1531*f595a68aSyz147064 	attr.lt_key = key;
1532*f595a68aSyz147064 	attr.lt_nports = nports;
1533*f595a68aSyz147064 	attr.lt_ports = ports;
1534*f595a68aSyz147064 	attr.lt_policy = policy;
1535*f595a68aSyz147064 	attr.lt_mac_fixed = mac_addr_fixed;
1536*f595a68aSyz147064 	if (attr.lt_mac_fixed)
1537*f595a68aSyz147064 		bcopy(mac_addr, attr.lt_mac, ETHERADDRL);
1538*f595a68aSyz147064 	else
1539*f595a68aSyz147064 		bzero(attr.lt_mac, ETHERADDRL);
1540*f595a68aSyz147064 	attr.lt_lacp_mode = lacp_mode;
1541*f595a68aSyz147064 	attr.lt_lacp_timer = lacp_timer;
1542*f595a68aSyz147064 
1543*f595a68aSyz147064 	/* add the link aggregation group to the DB */
1544*f595a68aSyz147064 	if (!tempop) {
1545*f595a68aSyz147064 		status = i_dladm_aggr_create_db(&attr, root);
1546*f595a68aSyz147064 		if (status != DLADM_STATUS_OK)
1547*f595a68aSyz147064 			return (status);
1548*f595a68aSyz147064 	} else {
1549*f595a68aSyz147064 		dladm_aggr_up_t up;
1550*f595a68aSyz147064 
1551*f595a68aSyz147064 		up.lu_key = key;
1552*f595a68aSyz147064 		up.lu_found = B_FALSE;
1553*f595a68aSyz147064 		up.lu_fd = open(DLADM_AGGR_DEV, O_RDWR);
1554*f595a68aSyz147064 		if (up.lu_fd < 0)
1555*f595a68aSyz147064 			return (dladm_errno2status(errno));
1556*f595a68aSyz147064 
1557*f595a68aSyz147064 		status = i_dladm_aggr_up((void *)&up, &attr);
1558*f595a68aSyz147064 		(void) close(up.lu_fd);
1559*f595a68aSyz147064 		return (status);
1560*f595a68aSyz147064 	}
1561*f595a68aSyz147064 
1562*f595a68aSyz147064 	/* bring up the link aggregation group */
1563*f595a68aSyz147064 	status = dladm_aggr_up(key, root);
1564*f595a68aSyz147064 	/*
1565*f595a68aSyz147064 	 * If the operation fails because the aggregation already exists,
1566*f595a68aSyz147064 	 * then only update the persistent configuration repository and
1567*f595a68aSyz147064 	 * return success.
1568*f595a68aSyz147064 	 */
1569*f595a68aSyz147064 	if (status == DLADM_STATUS_EXIST)
1570*f595a68aSyz147064 		status = DLADM_STATUS_OK;
1571*f595a68aSyz147064 
1572*f595a68aSyz147064 	if (status != DLADM_STATUS_OK && !tempop)
1573*f595a68aSyz147064 		(void) i_dladm_aggr_del_db(&attr, root);
1574*f595a68aSyz147064 
1575*f595a68aSyz147064 	return (status);
1576*f595a68aSyz147064 }
1577*f595a68aSyz147064 
1578*f595a68aSyz147064 /*
1579*f595a68aSyz147064  * Modify the parameters of an existing link aggregation group. Update
1580*f595a68aSyz147064  * the configuration file and pass the changes to the kernel.
1581*f595a68aSyz147064  */
1582*f595a68aSyz147064 dladm_status_t
1583*f595a68aSyz147064 dladm_aggr_modify(uint32_t key, uint32_t modify_mask, uint32_t policy,
1584*f595a68aSyz147064     boolean_t mac_fixed, uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode,
1585*f595a68aSyz147064     aggr_lacp_timer_t lacp_timer, boolean_t tempop, const char *root)
1586*f595a68aSyz147064 {
1587*f595a68aSyz147064 	dladm_aggr_modify_attr_t new_attr, old_attr;
1588*f595a68aSyz147064 	dladm_status_t status;
1589*f595a68aSyz147064 
1590*f595a68aSyz147064 	if (key == 0)
1591*f595a68aSyz147064 		return (DLADM_STATUS_KEYINVAL);
1592*f595a68aSyz147064 
1593*f595a68aSyz147064 	if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
1594*f595a68aSyz147064 		new_attr.ld_policy = policy;
1595*f595a68aSyz147064 
1596*f595a68aSyz147064 	if (modify_mask & DLADM_AGGR_MODIFY_MAC) {
1597*f595a68aSyz147064 		new_attr.ld_mac_fixed = mac_fixed;
1598*f595a68aSyz147064 		bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL);
1599*f595a68aSyz147064 	}
1600*f595a68aSyz147064 
1601*f595a68aSyz147064 	if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
1602*f595a68aSyz147064 		new_attr.ld_lacp_mode = lacp_mode;
1603*f595a68aSyz147064 
1604*f595a68aSyz147064 	if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
1605*f595a68aSyz147064 		new_attr.ld_lacp_timer = lacp_timer;
1606*f595a68aSyz147064 
1607*f595a68aSyz147064 	/* update the DB */
1608*f595a68aSyz147064 	if (!tempop && ((status = i_dladm_aggr_modify_db(key, modify_mask,
1609*f595a68aSyz147064 	    &new_attr, &old_attr, root)) != DLADM_STATUS_OK)) {
1610*f595a68aSyz147064 		return (status);
1611*f595a68aSyz147064 	}
1612*f595a68aSyz147064 
1613*f595a68aSyz147064 	status = i_dladm_aggr_modify_sys(key, modify_mask, &new_attr);
1614*f595a68aSyz147064 	if (status != DLADM_STATUS_OK && !tempop) {
1615*f595a68aSyz147064 		(void) i_dladm_aggr_modify_db(key, modify_mask, &old_attr,
1616*f595a68aSyz147064 		    NULL, root);
1617*f595a68aSyz147064 	}
1618*f595a68aSyz147064 
1619*f595a68aSyz147064 	return (status);
1620*f595a68aSyz147064 }
1621*f595a68aSyz147064 
1622*f595a68aSyz147064 /*
1623*f595a68aSyz147064  * Delete a previously created link aggregation group.
1624*f595a68aSyz147064  */
1625*f595a68aSyz147064 dladm_status_t
1626*f595a68aSyz147064 dladm_aggr_delete(uint32_t key, boolean_t tempop, const char *root)
1627*f595a68aSyz147064 {
1628*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t db_attr;
1629*f595a68aSyz147064 	dladm_status_t status;
1630*f595a68aSyz147064 
1631*f595a68aSyz147064 	if (key == 0)
1632*f595a68aSyz147064 		return (DLADM_STATUS_KEYINVAL);
1633*f595a68aSyz147064 
1634*f595a68aSyz147064 	if (tempop) {
1635*f595a68aSyz147064 		dladm_aggr_down_t down;
1636*f595a68aSyz147064 		dladm_aggr_grp_attr_t sys_attr;
1637*f595a68aSyz147064 
1638*f595a68aSyz147064 		down.ld_key = key;
1639*f595a68aSyz147064 		down.ld_found = B_FALSE;
1640*f595a68aSyz147064 		sys_attr.lg_key = key;
1641*f595a68aSyz147064 		if (i_dladm_aggr_down((void *)&down, &sys_attr) < 0)
1642*f595a68aSyz147064 			return (dladm_errno2status(errno));
1643*f595a68aSyz147064 		else
1644*f595a68aSyz147064 			return (DLADM_STATUS_OK);
1645*f595a68aSyz147064 	} else {
1646*f595a68aSyz147064 		status = dladm_aggr_down(key);
1647*f595a68aSyz147064 
1648*f595a68aSyz147064 		/*
1649*f595a68aSyz147064 		 * Only continue to delete the configuration repository
1650*f595a68aSyz147064 		 * either if we successfully delete the active aggregation
1651*f595a68aSyz147064 		 * or if the aggregation is not found.
1652*f595a68aSyz147064 		 */
1653*f595a68aSyz147064 		if (status != DLADM_STATUS_OK &&
1654*f595a68aSyz147064 		    status != DLADM_STATUS_NOTFOUND) {
1655*f595a68aSyz147064 			return (status);
1656*f595a68aSyz147064 		}
1657*f595a68aSyz147064 	}
1658*f595a68aSyz147064 
1659*f595a68aSyz147064 	if (tempop)
1660*f595a68aSyz147064 		return (DLADM_STATUS_OK);
1661*f595a68aSyz147064 
1662*f595a68aSyz147064 	db_attr.lt_key = key;
1663*f595a68aSyz147064 	return (i_dladm_aggr_del_db(&db_attr, root));
1664*f595a68aSyz147064 }
1665*f595a68aSyz147064 
1666*f595a68aSyz147064 /*
1667*f595a68aSyz147064  * Add one or more ports to an existing link aggregation.
1668*f595a68aSyz147064  */
1669*f595a68aSyz147064 dladm_status_t
1670*f595a68aSyz147064 dladm_aggr_add(uint32_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports,
1671*f595a68aSyz147064     boolean_t tempop, const char *root)
1672*f595a68aSyz147064 {
1673*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t attr;
1674*f595a68aSyz147064 	dladm_status_t status;
1675*f595a68aSyz147064 
1676*f595a68aSyz147064 	if (key == 0)
1677*f595a68aSyz147064 		return (DLADM_STATUS_KEYINVAL);
1678*f595a68aSyz147064 
1679*f595a68aSyz147064 	bzero(&attr, sizeof (attr));
1680*f595a68aSyz147064 	attr.lt_key = key;
1681*f595a68aSyz147064 	attr.lt_nports = nports;
1682*f595a68aSyz147064 	attr.lt_ports = ports;
1683*f595a68aSyz147064 
1684*f595a68aSyz147064 	if (!tempop &&
1685*f595a68aSyz147064 	    ((status = i_dladm_aggr_add_db(&attr, root)) != DLADM_STATUS_OK)) {
1686*f595a68aSyz147064 		return (status);
1687*f595a68aSyz147064 	}
1688*f595a68aSyz147064 
1689*f595a68aSyz147064 	status = i_dladm_aggr_add_rem_sys(&attr, LAIOC_ADD);
1690*f595a68aSyz147064 	if (status != DLADM_STATUS_OK && !tempop)
1691*f595a68aSyz147064 		(void) i_dladm_aggr_remove_db(&attr, root);
1692*f595a68aSyz147064 
1693*f595a68aSyz147064 	return (status);
1694*f595a68aSyz147064 }
1695*f595a68aSyz147064 
1696*f595a68aSyz147064 /*
1697*f595a68aSyz147064  * Remove one or more ports from an existing link aggregation.
1698*f595a68aSyz147064  */
1699*f595a68aSyz147064 dladm_status_t
1700*f595a68aSyz147064 dladm_aggr_remove(uint32_t key, uint32_t nports,
1701*f595a68aSyz147064     dladm_aggr_port_attr_db_t *ports, boolean_t tempop, const char *root)
1702*f595a68aSyz147064 {
1703*f595a68aSyz147064 	dladm_aggr_grp_attr_db_t attr;
1704*f595a68aSyz147064 	dladm_status_t status;
1705*f595a68aSyz147064 
1706*f595a68aSyz147064 	if (key == 0)
1707*f595a68aSyz147064 		return (DLADM_STATUS_KEYINVAL);
1708*f595a68aSyz147064 
1709*f595a68aSyz147064 	bzero(&attr, sizeof (attr));
1710*f595a68aSyz147064 	attr.lt_key = key;
1711*f595a68aSyz147064 	attr.lt_nports = nports;
1712*f595a68aSyz147064 	attr.lt_ports = ports;
1713*f595a68aSyz147064 
1714*f595a68aSyz147064 	if (!tempop &&
1715*f595a68aSyz147064 	    ((status = i_dladm_aggr_remove_db(&attr, root)) !=
1716*f595a68aSyz147064 	    DLADM_STATUS_OK)) {
1717*f595a68aSyz147064 		return (status);
1718*f595a68aSyz147064 	}
1719*f595a68aSyz147064 
1720*f595a68aSyz147064 	status = i_dladm_aggr_add_rem_sys(&attr, LAIOC_REMOVE);
1721*f595a68aSyz147064 	if (status != DLADM_STATUS_OK && !tempop)
1722*f595a68aSyz147064 		(void) i_dladm_aggr_add_db(&attr, root);
1723*f595a68aSyz147064 
1724*f595a68aSyz147064 	return (status);
1725*f595a68aSyz147064 }
1726