Home | History | Annotate | Download | only in common
      1      0     stevel /*
      2      0     stevel  * CDDL HEADER START
      3      0     stevel  *
      4      0     stevel  * The contents of this file are subject to the terms of the
      5   2311        seb  * Common Development and Distribution License (the "License").
      6   2311        seb  * You may not use this file except in compliance with the License.
      7      0     stevel  *
      8      0     stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0     stevel  * or http://www.opensolaris.org/os/licensing.
     10      0     stevel  * See the License for the specific language governing permissions
     11      0     stevel  * and limitations under the License.
     12      0     stevel  *
     13      0     stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0     stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0     stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0     stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0     stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0     stevel  *
     19      0     stevel  * CDDL HEADER END
     20      0     stevel  */
     21      0     stevel /*
     22   9815      Rishi  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0     stevel  * Use is subject to license terms.
     24      0     stevel  */
     25      0     stevel 
     26      0     stevel #include <stdio.h>
     27      0     stevel #include <sys/types.h>
     28      0     stevel #include <sys/stat.h>
     29      0     stevel #include <string.h>
     30      0     stevel #include <fcntl.h>
     31      0     stevel #include <unistd.h>
     32      0     stevel #include <stropts.h>
     33      0     stevel #include <stdlib.h>
     34      0     stevel #include <errno.h>
     35   5895   yz147064 #include <assert.h>
     36      0     stevel #include <strings.h>
     37      0     stevel #include <libintl.h>
     38      0     stevel #include <net/if_types.h>
     39      0     stevel #include <net/if_dl.h>
     40   8275       Eric #include <sys/dld.h>
     41   5895   yz147064 #include <libdllink.h>
     42   5895   yz147064 #include <libdlvlan.h>
     43   3871   yz147064 #include <libdlaggr.h>
     44   3871   yz147064 #include <libdladm_impl.h>
     45      0     stevel 
     46      0     stevel /*
     47      0     stevel  * Link Aggregation Administration Library.
     48      0     stevel  *
     49      0     stevel  * This library is used by administration tools such as dladm(1M) to
     50      0     stevel  * configure link aggregations.
     51      0     stevel  */
     52      0     stevel 
     53      0     stevel /* Limits on buffer size for LAIOC_INFO request */
     54      0     stevel #define	MIN_INFO_SIZE (4*1024)
     55      0     stevel #define	MAX_INFO_SIZE (128*1024)
     56      0     stevel 
     57   5895   yz147064 static uchar_t	zero_mac[] = {0, 0, 0, 0, 0, 0};
     58   5895   yz147064 #define	VALID_PORT_MAC(mac)						\
     59   5895   yz147064 	(((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) &&	\
     60   5895   yz147064 	(!(mac)[0] & 0x01))
     61      0     stevel 
     62  10616  Sebastien #define	PORT_DELIMITER	":"
     63      0     stevel 
     64   3871   yz147064 typedef struct dladm_aggr_modify_attr {
     65      0     stevel 	uint32_t	ld_policy;
     66      0     stevel 	boolean_t	ld_mac_fixed;
     67      0     stevel 	uchar_t		ld_mac[ETHERADDRL];
     68      0     stevel 	aggr_lacp_mode_t ld_lacp_mode;
     69      0     stevel 	aggr_lacp_timer_t ld_lacp_timer;
     70   3871   yz147064 } dladm_aggr_modify_attr_t;
     71      0     stevel 
     72      0     stevel typedef struct policy_s {
     73      0     stevel 	char		*pol_name;
     74      0     stevel 	uint32_t	policy;
     75      0     stevel } policy_t;
     76      0     stevel 
     77      0     stevel static policy_t policies[] = {
     78      0     stevel 	{"L2",		AGGR_POLICY_L2},
     79      0     stevel 	{"L3",		AGGR_POLICY_L3},
     80      0     stevel 	{"L4",		AGGR_POLICY_L4}};
     81      0     stevel 
     82      0     stevel #define	NPOLICIES	(sizeof (policies) / sizeof (policy_t))
     83      0     stevel 
     84   3871   yz147064 typedef struct dladm_aggr_lacpmode_s {
     85      0     stevel 	char		*mode_str;
     86      0     stevel 	aggr_lacp_mode_t mode_id;
     87   3871   yz147064 } dladm_aggr_lacpmode_t;
     88      0     stevel 
     89   3871   yz147064 static dladm_aggr_lacpmode_t lacp_modes[] = {
     90      0     stevel 	{"off", AGGR_LACP_OFF},
     91      0     stevel 	{"active", AGGR_LACP_ACTIVE},
     92      0     stevel 	{"passive", AGGR_LACP_PASSIVE}};
     93      0     stevel 
     94   3871   yz147064 #define	NLACP_MODES	(sizeof (lacp_modes) / sizeof (dladm_aggr_lacpmode_t))
     95      0     stevel 
     96   3871   yz147064 typedef struct dladm_aggr_lacptimer_s {
     97      0     stevel 	char		*lt_str;
     98      0     stevel 	aggr_lacp_timer_t lt_id;
     99   3871   yz147064 } dladm_aggr_lacptimer_t;
    100      0     stevel 
    101   3871   yz147064 static dladm_aggr_lacptimer_t lacp_timers[] = {
    102      0     stevel 	{"short", AGGR_LACP_TIMER_SHORT},
    103      0     stevel 	{"long", AGGR_LACP_TIMER_LONG}};
    104      0     stevel 
    105   3871   yz147064 #define	NLACP_TIMERS	(sizeof (lacp_timers) / sizeof (dladm_aggr_lacptimer_t))
    106   3871   yz147064 
    107   3871   yz147064 typedef struct dladm_aggr_port_state {
    108   3871   yz147064 	char			*state_str;
    109   3871   yz147064 	aggr_port_state_t	state_id;
    110   3871   yz147064 } dladm_aggr_port_state_t;
    111   3871   yz147064 
    112   3871   yz147064 static dladm_aggr_port_state_t port_states[] = {
    113   3871   yz147064 	{"standby", AGGR_PORT_STATE_STANDBY },
    114   3871   yz147064 	{"attached", AGGR_PORT_STATE_ATTACHED }
    115   3871   yz147064 };
    116   3871   yz147064 
    117   3871   yz147064 #define	NPORT_STATES	\
    118   3871   yz147064 	(sizeof (port_states) / sizeof (dladm_aggr_port_state_t))
    119  10616  Sebastien 
    120  10616  Sebastien static dladm_status_t
    121  10616  Sebastien write_port(dladm_handle_t handle, char *portstr, datalink_id_t portid,
    122  10616  Sebastien     size_t portstrsize)
    123  10616  Sebastien {
    124  10616  Sebastien 	char		pname[MAXLINKNAMELEN + 1];
    125  10616  Sebastien 	dladm_status_t	status;
    126  10616  Sebastien 
    127  10616  Sebastien 	if ((status = dladm_datalink_id2info(handle, portid, NULL, NULL, NULL,
    128  10616  Sebastien 	    pname, sizeof (pname))) != DLADM_STATUS_OK)
    129  10616  Sebastien 		return (status);
    130  10616  Sebastien 	(void) strlcat(pname, PORT_DELIMITER, sizeof (pname));
    131  10616  Sebastien 	if (strlcat(portstr, pname, portstrsize) >= portstrsize)
    132  10616  Sebastien 		status = DLADM_STATUS_TOOSMALL;
    133  10616  Sebastien 	return (status);
    134  10616  Sebastien }
    135  10616  Sebastien 
    136  10616  Sebastien static dladm_status_t
    137  10616  Sebastien read_port(dladm_handle_t handle, char **portstr, datalink_id_t *portid)
    138  10616  Sebastien {
    139  10616  Sebastien 	dladm_status_t	status;
    140  10616  Sebastien 	char		*pname;
    141  10616  Sebastien 
    142  10616  Sebastien 	if ((pname = strtok(*portstr, PORT_DELIMITER)) == NULL)
    143  10616  Sebastien 		return (DLADM_STATUS_REPOSITORYINVAL);
    144  10616  Sebastien 	*portstr += (strlen(pname) + 1);
    145  10616  Sebastien 	status = dladm_name2info(handle, pname, portid, NULL, NULL, NULL);
    146  10616  Sebastien 	return (status);
    147  10616  Sebastien }
    148      0     stevel 
    149   5895   yz147064 static int
    150   8453     Anurag i_dladm_aggr_ioctl(dladm_handle_t handle, int cmd, void *ptr)
    151   5895   yz147064 {
    152   8453     Anurag 	return (ioctl(dladm_dld_fd(handle), cmd, ptr));
    153      0     stevel }
    154      0     stevel 
    155      0     stevel /*
    156   5895   yz147064  * Caller must free attr.lg_ports. The ptr pointer is advanced while convert
    157   5895   yz147064  * the laioc_info_t to the dladm_aggr_grp_attr_t structure.
    158      0     stevel  */
    159   5895   yz147064 static int
    160   5895   yz147064 i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp)
    161      0     stevel {
    162   5895   yz147064 	laioc_info_group_t	*grp;
    163   5895   yz147064 	laioc_info_port_t	*port;
    164   5895   yz147064 	int			i;
    165   5895   yz147064 	void			*where = (*ptr);
    166      0     stevel 
    167   5895   yz147064 	grp = (laioc_info_group_t *)where;
    168      0     stevel 
    169   5895   yz147064 	attrp->lg_linkid = grp->lg_linkid;
    170   5895   yz147064 	attrp->lg_key = grp->lg_key;
    171   5895   yz147064 	attrp->lg_nports = grp->lg_nports;
    172   5895   yz147064 	attrp->lg_policy = grp->lg_policy;
    173   5895   yz147064 	attrp->lg_lacp_mode = grp->lg_lacp_mode;
    174   5895   yz147064 	attrp->lg_lacp_timer = grp->lg_lacp_timer;
    175   5895   yz147064 	attrp->lg_force = grp->lg_force;
    176      0     stevel 
    177   5895   yz147064 	bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL);
    178   5895   yz147064 	attrp->lg_mac_fixed = grp->lg_mac_fixed;
    179   5895   yz147064 
    180   5895   yz147064 	if ((attrp->lg_ports = malloc(grp->lg_nports *
    181   5895   yz147064 	    sizeof (dladm_aggr_port_attr_t))) == NULL) {
    182   5895   yz147064 		errno = ENOMEM;
    183   5895   yz147064 		goto fail;
    184   5895   yz147064 	}
    185   5895   yz147064 
    186   5895   yz147064 	where = (grp + 1);
    187   5895   yz147064 
    188   5895   yz147064 	/*
    189   5895   yz147064 	 * Go through each port that is part of the group.
    190   5895   yz147064 	 */
    191   5895   yz147064 	for (i = 0; i < grp->lg_nports; i++) {
    192   5895   yz147064 		port = (laioc_info_port_t *)where;
    193   5895   yz147064 
    194   5895   yz147064 		attrp->lg_ports[i].lp_linkid = port->lp_linkid;
    195   5895   yz147064 		bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL);
    196   5895   yz147064 		attrp->lg_ports[i].lp_state = port->lp_state;
    197   5895   yz147064 		attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state;
    198   5895   yz147064 
    199   5895   yz147064 		where = (port + 1);
    200   5895   yz147064 	}
    201   5895   yz147064 	*ptr = where;
    202   5895   yz147064 	return (0);
    203   5895   yz147064 fail:
    204   5895   yz147064 	return (-1);
    205      0     stevel }
    206      0     stevel 
    207      0     stevel /*
    208   5895   yz147064  * Get active configuration of a specific aggregation.
    209   5895   yz147064  * Caller must free attrp->la_ports.
    210      0     stevel  */
    211   5895   yz147064 static dladm_status_t
    212   8453     Anurag i_dladm_aggr_info_active(dladm_handle_t handle, datalink_id_t linkid,
    213   8453     Anurag     dladm_aggr_grp_attr_t *attrp)
    214      0     stevel {
    215      0     stevel 	laioc_info_t *ioc;
    216   7408  Sebastien 	int bufsize;
    217   5895   yz147064 	void *where;
    218   5895   yz147064 	dladm_status_t status = DLADM_STATUS_OK;
    219      0     stevel 
    220      0     stevel 	bufsize = MIN_INFO_SIZE;
    221      0     stevel 	ioc = (laioc_info_t *)calloc(1, bufsize);
    222   5895   yz147064 	if (ioc == NULL)
    223   5895   yz147064 		return (DLADM_STATUS_NOMEM);
    224   5895   yz147064 
    225   5895   yz147064 	ioc->li_group_linkid = linkid;
    226      0     stevel 
    227      0     stevel tryagain:
    228   7408  Sebastien 	ioc->li_bufsize = bufsize;
    229   8453     Anurag 	if (i_dladm_aggr_ioctl(handle, LAIOC_INFO, ioc) != 0) {
    230      0     stevel 		if (errno == ENOSPC) {
    231      0     stevel 			/*
    232      0     stevel 			 * The LAIOC_INFO call failed due to a short
    233      0     stevel 			 * buffer. Reallocate the buffer and try again.
    234      0     stevel 			 */
    235      0     stevel 			bufsize *= 2;
    236      0     stevel 			if (bufsize <= MAX_INFO_SIZE) {
    237      0     stevel 				ioc = (laioc_info_t *)realloc(ioc, bufsize);
    238      0     stevel 				if (ioc != NULL) {
    239      0     stevel 					bzero(ioc, sizeof (bufsize));
    240      0     stevel 					goto tryagain;
    241      0     stevel 				}
    242      0     stevel 			}
    243      0     stevel 		}
    244   5895   yz147064 		status = dladm_errno2status(errno);
    245      0     stevel 		goto bail;
    246      0     stevel 	}
    247      0     stevel 
    248      0     stevel 	/*
    249      0     stevel 	 * Go through each group returned by the aggregation driver.
    250      0     stevel 	 */
    251      0     stevel 	where = (char *)(ioc + 1);
    252   5895   yz147064 	if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) {
    253   5895   yz147064 		status = dladm_errno2status(errno);
    254   5895   yz147064 		goto bail;
    255      0     stevel 	}
    256      0     stevel 
    257      0     stevel bail:
    258      0     stevel 	free(ioc);
    259   3871   yz147064 	return (status);
    260      0     stevel }
    261      0     stevel 
    262      0     stevel /*
    263   5895   yz147064  * Get configuration information of a specific aggregation.
    264   5895   yz147064  * Caller must free attrp->la_ports.
    265      0     stevel  */
    266   3871   yz147064 static dladm_status_t
    267   8453     Anurag i_dladm_aggr_info_persist(dladm_handle_t handle, datalink_id_t linkid,
    268   8453     Anurag     dladm_aggr_grp_attr_t *attrp)
    269      0     stevel {
    270   5895   yz147064 	dladm_conf_t	conf;
    271   5895   yz147064 	uint32_t	nports, i;
    272  10616  Sebastien 	char		*portstr = NULL, *next;
    273   5895   yz147064 	dladm_status_t	status;
    274   5895   yz147064 	uint64_t	u64;
    275   5895   yz147064 	int		size;
    276   5895   yz147064 	char		macstr[ETHERADDRL * 3];
    277      0     stevel 
    278   5895   yz147064 	attrp->lg_linkid = linkid;
    279   8453     Anurag 	if ((status = dladm_read_conf(handle, linkid, &conf)) !=
    280   8453     Anurag 	    DLADM_STATUS_OK)
    281   5895   yz147064 		return (status);
    282   5895   yz147064 
    283   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64));
    284   5895   yz147064 	if (status != DLADM_STATUS_OK)
    285   5895   yz147064 		goto done;
    286   5895   yz147064 	attrp->lg_key = (uint16_t)u64;
    287   5895   yz147064 
    288   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FPOLICY, &u64,
    289   8453     Anurag 	    sizeof (u64));
    290   5895   yz147064 	if (status != DLADM_STATUS_OK)
    291   5895   yz147064 		goto done;
    292   5895   yz147064 	attrp->lg_policy = (uint32_t)u64;
    293   5895   yz147064 
    294   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FFIXMACADDR,
    295   8453     Anurag 	    &attrp->lg_mac_fixed, sizeof (boolean_t));
    296   5895   yz147064 	if (status != DLADM_STATUS_OK)
    297   5895   yz147064 		goto done;
    298   5895   yz147064 
    299   5895   yz147064 	if (attrp->lg_mac_fixed) {
    300   5895   yz147064 		boolean_t fixed;
    301   5895   yz147064 
    302   8453     Anurag 		if ((status = dladm_get_conf_field(handle, conf, FMACADDR,
    303   8453     Anurag 		    macstr, sizeof (macstr))) != DLADM_STATUS_OK) {
    304   5895   yz147064 			goto done;
    305   5895   yz147064 		}
    306   5895   yz147064 		if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) {
    307   5895   yz147064 			status = DLADM_STATUS_REPOSITORYINVAL;
    308   5895   yz147064 			goto done;
    309   5895   yz147064 		}
    310   5895   yz147064 	}
    311   5895   yz147064 
    312   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FFORCE, &attrp->lg_force,
    313   5895   yz147064 	    sizeof (boolean_t));
    314   5895   yz147064 	if (status != DLADM_STATUS_OK)
    315   5895   yz147064 		goto done;
    316   5895   yz147064 
    317   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64,
    318   8453     Anurag 	    sizeof (u64));
    319   5895   yz147064 	if (status != DLADM_STATUS_OK)
    320   5895   yz147064 		goto done;
    321   5895   yz147064 	attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64;
    322   5895   yz147064 
    323   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64,
    324   8453     Anurag 	    sizeof (u64));
    325   5895   yz147064 	if (status != DLADM_STATUS_OK)
    326   5895   yz147064 		goto done;
    327   5895   yz147064 	attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64;
    328   5895   yz147064 
    329   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FNPORTS, &u64,
    330   8453     Anurag 	    sizeof (u64));
    331   5895   yz147064 	if (status != DLADM_STATUS_OK)
    332   5895   yz147064 		goto done;
    333   5895   yz147064 	nports = (uint32_t)u64;
    334   5895   yz147064 	attrp->lg_nports = nports;
    335   5895   yz147064 
    336  10616  Sebastien 	size = nports * (MAXLINKNAMELEN + 1) + 1;
    337   5895   yz147064 	if ((portstr = calloc(1, size)) == NULL) {
    338   3871   yz147064 		status = DLADM_STATUS_NOMEM;
    339   3871   yz147064 		goto done;
    340   3871   yz147064 	}
    341      0     stevel 
    342   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FPORTS, portstr, size);
    343  10616  Sebastien 	if (status != DLADM_STATUS_OK)
    344   5895   yz147064 		goto done;
    345      0     stevel 
    346   5895   yz147064 	if ((attrp->lg_ports = malloc(nports *
    347   5895   yz147064 	    sizeof (dladm_aggr_port_attr_t))) == NULL) {
    348   5895   yz147064 		status = DLADM_STATUS_NOMEM;
    349   5895   yz147064 		goto done;
    350   5895   yz147064 	}
    351   5895   yz147064 
    352   5895   yz147064 	for (next = portstr, i = 0; i < nports; i++) {
    353  10616  Sebastien 		if ((status = read_port(handle, &next,
    354  10616  Sebastien 		    &attrp->lg_ports[i].lp_linkid)) != DLADM_STATUS_OK)
    355   5895   yz147064 			free(attrp->lg_ports);
    356      0     stevel 	}
    357      0     stevel 
    358   5895   yz147064 done:
    359  10616  Sebastien 	free(portstr);
    360   8453     Anurag 	dladm_destroy_conf(handle, conf);
    361   5895   yz147064 	return (status);
    362   5895   yz147064 }
    363   5895   yz147064 
    364   5895   yz147064 dladm_status_t
    365   8453     Anurag dladm_aggr_info(dladm_handle_t handle, datalink_id_t linkid,
    366   8453     Anurag     dladm_aggr_grp_attr_t *attrp, uint32_t flags)
    367   5895   yz147064 {
    368   5895   yz147064 	assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST);
    369   5895   yz147064 	if (flags == DLADM_OPT_ACTIVE)
    370   8453     Anurag 		return (i_dladm_aggr_info_active(handle, linkid, attrp));
    371   5895   yz147064 	else
    372   8453     Anurag 		return (i_dladm_aggr_info_persist(handle, linkid, attrp));
    373   5895   yz147064 }
    374   5895   yz147064 
    375   5895   yz147064 /*
    376   5895   yz147064  * Add or remove one or more ports to/from an existing link aggregation.
    377   5895   yz147064  */
    378   5895   yz147064 static dladm_status_t
    379   8453     Anurag i_dladm_aggr_add_rmv(dladm_handle_t handle, datalink_id_t linkid,
    380   8453     Anurag     uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd)
    381   5895   yz147064 {
    382   5895   yz147064 	char *orig_portstr = NULL, *portstr = NULL;
    383   6077   yz147064 	laioc_add_rem_t *iocp = NULL;
    384   5895   yz147064 	laioc_port_t *ioc_ports;
    385   5895   yz147064 	uint32_t orig_nports, result_nports, len, i, j;
    386   5895   yz147064 	dladm_conf_t conf;
    387   5895   yz147064 	datalink_class_t class;
    388   5895   yz147064 	dladm_status_t status = DLADM_STATUS_OK;
    389   5895   yz147064 	int size;
    390   5895   yz147064 	uint64_t u64;
    391   5895   yz147064 	uint32_t media;
    392   5895   yz147064 
    393   5895   yz147064 	if (nports == 0)
    394   5895   yz147064 		return (DLADM_STATUS_BADARG);
    395   5895   yz147064 
    396   5895   yz147064 	/*
    397   5895   yz147064 	 * Sanity check - aggregations can only be created over Ethernet
    398   9815      Rishi 	 * physical links and simnets.
    399   5895   yz147064 	 */
    400   5895   yz147064 	for (i = 0; i < nports; i++) {
    401   8453     Anurag 		if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL,
    402   5895   yz147064 		    &class, &media, NULL, 0) != DLADM_STATUS_OK) ||
    403   9815      Rishi 		    !((class == DATALINK_CLASS_PHYS) ||
    404   9815      Rishi 		    (class == DATALINK_CLASS_SIMNET)) || (media != DL_ETHER)) {
    405   5895   yz147064 			return (DLADM_STATUS_BADARG);
    406   5895   yz147064 		}
    407   5895   yz147064 	}
    408   5895   yz147064 
    409   5895   yz147064 	/*
    410   5895   yz147064 	 * First, update the persistent configuration if requested.  We only
    411   5895   yz147064 	 * need to update the FPORTS and FNPORTS fields of this aggregation.
    412   5895   yz147064 	 * Note that FPORTS is a list of port linkids separated by
    413  10616  Sebastien 	 * PORT_DELIMITER (':').
    414   5895   yz147064 	 */
    415   5895   yz147064 	if (flags & DLADM_OPT_PERSIST) {
    416   8453     Anurag 		status = dladm_read_conf(handle, linkid, &conf);
    417   5895   yz147064 		if (status != DLADM_STATUS_OK)
    418   5895   yz147064 			return (status);
    419   5895   yz147064 
    420   5895   yz147064 		/*
    421   5895   yz147064 		 * Get the original configuration of FNPORTS and FPORTS.
    422   5895   yz147064 		 */
    423   8453     Anurag 		status = dladm_get_conf_field(handle, conf, FNPORTS, &u64,
    424   5895   yz147064 		    sizeof (u64));
    425   5895   yz147064 		if (status != DLADM_STATUS_OK)
    426   5895   yz147064 			goto destroyconf;
    427   5895   yz147064 		orig_nports = (uint32_t)u64;
    428   5895   yz147064 
    429   5895   yz147064 		/*
    430   5895   yz147064 		 * At least one port needs to be in the aggregation.
    431   5895   yz147064 		 */
    432   5895   yz147064 		if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) {
    433   5895   yz147064 			status = DLADM_STATUS_BADARG;
    434   5895   yz147064 			goto destroyconf;
    435   5895   yz147064 		}
    436   5895   yz147064 
    437  10616  Sebastien 		size = orig_nports * (MAXLINKNAMELEN + 1) + 1;
    438   5895   yz147064 		if ((orig_portstr = calloc(1, size)) == NULL) {
    439   5895   yz147064 			status = dladm_errno2status(errno);
    440   5895   yz147064 			goto destroyconf;
    441   5895   yz147064 		}
    442   5895   yz147064 
    443   8453     Anurag 		status = dladm_get_conf_field(handle, conf, FPORTS,
    444   8453     Anurag 		    orig_portstr, size);
    445   5895   yz147064 		if (status != DLADM_STATUS_OK)
    446   5895   yz147064 			goto destroyconf;
    447   5895   yz147064 
    448   5895   yz147064 		result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports :
    449   5895   yz147064 		    orig_nports;
    450   5895   yz147064 
    451  10616  Sebastien 		size = result_nports * (MAXLINKNAMELEN + 1) + 1;
    452   5895   yz147064 		if ((portstr = calloc(1, size)) == NULL) {
    453   5895   yz147064 			status = dladm_errno2status(errno);
    454   5895   yz147064 			goto destroyconf;
    455   5895   yz147064 		}
    456   5895   yz147064 
    457   5895   yz147064 		/*
    458   5895   yz147064 		 * get the new configuration and set to result_nports and
    459   5895   yz147064 		 * portstr.
    460   5895   yz147064 		 */
    461   5895   yz147064 		if (cmd == LAIOC_ADD) {
    462   5895   yz147064 			(void) strlcpy(portstr, orig_portstr, size);
    463  10616  Sebastien 			for (i = 0; i < nports; i++) {
    464  10616  Sebastien 				status = write_port(handle, portstr,
    465  10616  Sebastien 				    ports[i].lp_linkid, size);
    466  10616  Sebastien 				if (status != DLADM_STATUS_OK) {
    467  10616  Sebastien 					free(portstr);
    468  10616  Sebastien 					goto destroyconf;
    469  10616  Sebastien 				}
    470  10616  Sebastien 			}
    471   5895   yz147064 		} else {
    472   5895   yz147064 			char *next;
    473   5895   yz147064 			datalink_id_t portid;
    474   5895   yz147064 			uint32_t remove = 0;
    475   5895   yz147064 
    476   5895   yz147064 			for (next = orig_portstr, j = 0; j < orig_nports; j++) {
    477   5895   yz147064 				/*
    478   5895   yz147064 				 * Read the portids from the old configuration
    479   5895   yz147064 				 * one by one.
    480   5895   yz147064 				 */
    481  10616  Sebastien 				status = read_port(handle, &next, &portid);
    482   5895   yz147064 				if (status != DLADM_STATUS_OK) {
    483   5895   yz147064 					free(portstr);
    484   5895   yz147064 					goto destroyconf;
    485   5895   yz147064 				}
    486   5895   yz147064 
    487   5895   yz147064 				/*
    488   5895   yz147064 				 * See whether this port is in the removal
    489   5895   yz147064 				 * list.  If not, copy to the new config.
    490   5895   yz147064 				 */
    491   5895   yz147064 				for (i = 0; i < nports; i++) {
    492   5895   yz147064 					if (ports[i].lp_linkid == portid)
    493   5895   yz147064 						break;
    494   5895   yz147064 				}
    495   5895   yz147064 				if (i == nports) {
    496  10616  Sebastien 					status = write_port(handle, portstr,
    497  10616  Sebastien 					    portid, size);
    498  10616  Sebastien 					if (status != DLADM_STATUS_OK) {
    499  10616  Sebastien 						free(portstr);
    500  10616  Sebastien 						goto destroyconf;
    501  10616  Sebastien 					}
    502   5895   yz147064 				} else {
    503   5895   yz147064 					remove++;
    504   5895   yz147064 				}
    505   5895   yz147064 			}
    506   5895   yz147064 			if (remove != nports) {
    507   5895   yz147064 				status = DLADM_STATUS_LINKINVAL;
    508   5895   yz147064 				free(portstr);
    509   5895   yz147064 				goto destroyconf;
    510   5895   yz147064 			}
    511   5895   yz147064 			result_nports -= nports;
    512   5895   yz147064 		}
    513   5895   yz147064 
    514   5895   yz147064 		u64 = result_nports;
    515   8453     Anurag 		if ((status = dladm_set_conf_field(handle, conf, FNPORTS,
    516   5895   yz147064 		    DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) {
    517   5895   yz147064 			free(portstr);
    518   5895   yz147064 			goto destroyconf;
    519   5895   yz147064 		}
    520   5895   yz147064 
    521   8453     Anurag 		status = dladm_set_conf_field(handle, conf, FPORTS,
    522   8453     Anurag 		    DLADM_TYPE_STR, portstr);
    523   5895   yz147064 		free(portstr);
    524   5895   yz147064 		if (status != DLADM_STATUS_OK)
    525   5895   yz147064 			goto destroyconf;
    526   5895   yz147064 
    527   5895   yz147064 		/*
    528   5895   yz147064 		 * Write the new configuration to the persistent repository.
    529   5895   yz147064 		 */
    530   8453     Anurag 		status = dladm_write_conf(handle, conf);
    531   5895   yz147064 
    532   5895   yz147064 destroyconf:
    533   8453     Anurag 		dladm_destroy_conf(handle, conf);
    534   5895   yz147064 		if (status != DLADM_STATUS_OK) {
    535   5895   yz147064 			free(orig_portstr);
    536   5895   yz147064 			return (status);
    537   5895   yz147064 		}
    538   5895   yz147064 	}
    539   5895   yz147064 
    540   5895   yz147064 	/*
    541   5895   yz147064 	 * If the caller only requested to update the persistent
    542   5895   yz147064 	 * configuration, we are done.
    543   5895   yz147064 	 */
    544   5895   yz147064 	if (!(flags & DLADM_OPT_ACTIVE))
    545   5895   yz147064 		goto done;
    546   5895   yz147064 
    547   5895   yz147064 	/*
    548   5895   yz147064 	 * Update the active configuration.
    549   5895   yz147064 	 */
    550   5895   yz147064 	len = sizeof (*iocp) + nports * sizeof (laioc_port_t);
    551   5895   yz147064 	if ((iocp = malloc(len)) == NULL) {
    552   5895   yz147064 		status = DLADM_STATUS_NOMEM;
    553   3871   yz147064 		goto done;
    554      0     stevel 	}
    555      0     stevel 
    556   5895   yz147064 	iocp->la_linkid = linkid;
    557   5895   yz147064 	iocp->la_nports = nports;
    558   5895   yz147064 	if (cmd == LAIOC_ADD)
    559   5895   yz147064 		iocp->la_force = (flags & DLADM_OPT_FORCE);
    560      0     stevel 
    561   5895   yz147064 	ioc_ports = (laioc_port_t *)(iocp + 1);
    562   5895   yz147064 	for (i = 0; i < nports; i++)
    563   5895   yz147064 		ioc_ports[i].lp_linkid = ports[i].lp_linkid;
    564   5895   yz147064 
    565   8453     Anurag 	if (i_dladm_aggr_ioctl(handle, cmd, iocp) < 0)
    566   5895   yz147064 		status = dladm_errno2status(errno);
    567      0     stevel 
    568   3871   yz147064 done:
    569    269   ericheng 	free(iocp);
    570   5895   yz147064 
    571   5895   yz147064 	/*
    572   5895   yz147064 	 * If the active configuration update fails, restore the old
    573   5895   yz147064 	 * persistent configuration if we've changed that.
    574   5895   yz147064 	 */
    575   5895   yz147064 	if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) {
    576   8453     Anurag 		if (dladm_read_conf(handle, linkid, &conf) == DLADM_STATUS_OK) {
    577   5895   yz147064 			u64 = orig_nports;
    578   8453     Anurag 			if ((dladm_set_conf_field(handle, conf, FNPORTS,
    579   5895   yz147064 			    DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) &&
    580   8453     Anurag 			    (dladm_set_conf_field(handle, conf, FPORTS,
    581   8453     Anurag 			    DLADM_TYPE_STR, orig_portstr) == DLADM_STATUS_OK)) {
    582   8453     Anurag 				(void) dladm_write_conf(handle, conf);
    583   5895   yz147064 			}
    584   8453     Anurag 			(void) dladm_destroy_conf(handle, conf);
    585   5895   yz147064 		}
    586   5895   yz147064 	}
    587   5895   yz147064 	free(orig_portstr);
    588   3871   yz147064 	return (status);
    589      0     stevel }
    590      0     stevel 
    591      0     stevel /*
    592      0     stevel  * Send a modify command to the link aggregation driver.
    593      0     stevel  */
    594   3871   yz147064 static dladm_status_t
    595   8453     Anurag i_dladm_aggr_modify_sys(dladm_handle_t handle, datalink_id_t linkid,
    596   8453     Anurag     uint32_t mask, dladm_aggr_modify_attr_t *attr)
    597      0     stevel {
    598      0     stevel 	laioc_modify_t ioc;
    599      0     stevel 
    600   5895   yz147064 	ioc.lu_linkid = linkid;
    601      0     stevel 
    602      0     stevel 	ioc.lu_modify_mask = 0;
    603   3871   yz147064 	if (mask & DLADM_AGGR_MODIFY_POLICY)
    604      0     stevel 		ioc.lu_modify_mask |= LAIOC_MODIFY_POLICY;
    605   3871   yz147064 	if (mask & DLADM_AGGR_MODIFY_MAC)
    606      0     stevel 		ioc.lu_modify_mask |= LAIOC_MODIFY_MAC;
    607   3871   yz147064 	if (mask & DLADM_AGGR_MODIFY_LACP_MODE)
    608      0     stevel 		ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_MODE;
    609   3871   yz147064 	if (mask & DLADM_AGGR_MODIFY_LACP_TIMER)
    610      0     stevel 		ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_TIMER;
    611      0     stevel 
    612      0     stevel 	ioc.lu_policy = attr->ld_policy;
    613      0     stevel 	ioc.lu_mac_fixed = attr->ld_mac_fixed;
    614      0     stevel 	bcopy(attr->ld_mac, ioc.lu_mac, ETHERADDRL);
    615      0     stevel 	ioc.lu_lacp_mode = attr->ld_lacp_mode;
    616      0     stevel 	ioc.lu_lacp_timer = attr->ld_lacp_timer;
    617      0     stevel 
    618   8453     Anurag 	if (i_dladm_aggr_ioctl(handle, LAIOC_MODIFY, &ioc) < 0) {
    619   3871   yz147064 		if (errno == EINVAL)
    620   5895   yz147064 			return (DLADM_STATUS_MACADDRINVAL);
    621   3871   yz147064 		else
    622   5895   yz147064 			return (dladm_errno2status(errno));
    623   5895   yz147064 	} else {
    624   5895   yz147064 		return (DLADM_STATUS_OK);
    625      0     stevel 	}
    626      0     stevel }
    627      0     stevel 
    628      0     stevel /*
    629      0     stevel  * Send a create command to the link aggregation driver.
    630      0     stevel  */
    631   3871   yz147064 static dladm_status_t
    632   8453     Anurag i_dladm_aggr_create_sys(dladm_handle_t handle, datalink_id_t linkid,
    633   8453     Anurag     uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports,
    634   8453     Anurag     uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr,
    635   5895   yz147064     aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force)
    636      0     stevel {
    637   7408  Sebastien 	int i, len;
    638   5895   yz147064 	laioc_create_t *iocp = NULL;
    639   5895   yz147064 	laioc_port_t *ioc_ports;
    640   3871   yz147064 	dladm_status_t status = DLADM_STATUS_OK;
    641      0     stevel 
    642   5895   yz147064 	len = sizeof (*iocp) + nports * sizeof (laioc_port_t);
    643    269   ericheng 	iocp = malloc(len);
    644    269   ericheng 	if (iocp == NULL)
    645   3871   yz147064 		return (DLADM_STATUS_NOMEM);
    646      0     stevel 
    647   5895   yz147064 	iocp->lc_key = key;
    648   5895   yz147064 	iocp->lc_linkid = linkid;
    649   5895   yz147064 	iocp->lc_nports = nports;
    650   5895   yz147064 	iocp->lc_policy = policy;
    651   5895   yz147064 	iocp->lc_lacp_mode = lacp_mode;
    652   5895   yz147064 	iocp->lc_lacp_timer = lacp_timer;
    653   5895   yz147064 	ioc_ports = (laioc_port_t *)(iocp + 1);
    654   5895   yz147064 	iocp->lc_force = force;
    655    269   ericheng 
    656   5895   yz147064 	for (i = 0; i < nports; i++)
    657   5895   yz147064 		ioc_ports[i].lp_linkid = ports[i].lp_linkid;
    658      0     stevel 
    659   5895   yz147064 	if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) {
    660   5895   yz147064 		status = DLADM_STATUS_MACADDRINVAL;
    661   5895   yz147064 		goto done;
    662      0     stevel 	}
    663      0     stevel 
    664   5895   yz147064 	bcopy(mac_addr, iocp->lc_mac, ETHERADDRL);
    665   5895   yz147064 	iocp->lc_mac_fixed = mac_addr_fixed;
    666      0     stevel 
    667   8453     Anurag 	if (i_dladm_aggr_ioctl(handle, LAIOC_CREATE, iocp) < 0)
    668   5895   yz147064 		status = dladm_errno2status(errno);
    669      0     stevel 
    670   5895   yz147064 done:
    671    269   ericheng 	free(iocp);
    672   3871   yz147064 	return (status);
    673      0     stevel }
    674      0     stevel 
    675      0     stevel /*
    676      0     stevel  * Invoked to bring up a link aggregation group.
    677      0     stevel  */
    678   5895   yz147064 static int
    679   8453     Anurag i_dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
    680      0     stevel {
    681   5895   yz147064 	dladm_status_t *statusp = (dladm_status_t *)arg;
    682   5895   yz147064 	dladm_aggr_grp_attr_t attr;
    683   5895   yz147064 	dladm_aggr_port_attr_db_t *ports = NULL;
    684   5895   yz147064 	uint16_t key = 0;
    685   5895   yz147064 	int i, j;
    686   5895   yz147064 	dladm_status_t status;
    687      0     stevel 
    688   8453     Anurag 	status = dladm_aggr_info(handle, linkid, &attr, DLADM_OPT_PERSIST);
    689   5895   yz147064 	if (status != DLADM_STATUS_OK) {
    690   5895   yz147064 		*statusp = status;
    691   5895   yz147064 		return (DLADM_WALK_CONTINUE);
    692   5895   yz147064 	}
    693      0     stevel 
    694   5895   yz147064 	if (attr.lg_key <= AGGR_MAX_KEY)
    695   5895   yz147064 		key = attr.lg_key;
    696      0     stevel 
    697   5895   yz147064 	ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t));
    698   5895   yz147064 	if (ports == NULL) {
    699   5895   yz147064 		status = DLADM_STATUS_NOMEM;
    700   5895   yz147064 		goto done;
    701   5895   yz147064 	}
    702      0     stevel 
    703   5895   yz147064 	/*
    704   5895   yz147064 	 * Validate (and purge) each physical link associated with this
    705   5895   yz147064 	 * aggregation, if the specific hardware has been removed during
    706   5895   yz147064 	 * the system shutdown.
    707   5895   yz147064 	 */
    708   5895   yz147064 	for (i = 0, j = 0; i < attr.lg_nports; i++) {
    709   5895   yz147064 		datalink_id_t	portid = attr.lg_ports[i].lp_linkid;
    710   5895   yz147064 		uint32_t	flags;
    711   5895   yz147064 		dladm_status_t	s;
    712   5895   yz147064 
    713   8453     Anurag 		s = dladm_datalink_id2info(handle, portid, &flags, NULL, NULL,
    714   8453     Anurag 		    NULL, 0);
    715   5895   yz147064 		if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE))
    716   5895   yz147064 			continue;
    717   5895   yz147064 
    718   5895   yz147064 		ports[j++].lp_linkid = portid;
    719   5895   yz147064 	}
    720   5895   yz147064 
    721   5895   yz147064 	if (j == 0) {
    722   5895   yz147064 		/*
    723   5895   yz147064 		 * All of the physical links are removed.
    724   5895   yz147064 		 */
    725   5895   yz147064 		status = DLADM_STATUS_BADARG;
    726   5895   yz147064 		goto done;
    727   5895   yz147064 	}
    728   5895   yz147064 
    729   5895   yz147064 	/*
    730   5895   yz147064 	 * Create active aggregation.
    731   5895   yz147064 	 */
    732   8453     Anurag 	if ((status = i_dladm_aggr_create_sys(handle, linkid,
    733   5895   yz147064 	    key, j, ports, attr.lg_policy, attr.lg_mac_fixed,
    734   5895   yz147064 	    (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode,
    735   5895   yz147064 	    attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) {
    736   5895   yz147064 		goto done;
    737   5895   yz147064 	}
    738   5895   yz147064 
    739   8453     Anurag 	if ((status = dladm_up_datalink_id(handle, linkid)) !=
    740   8453     Anurag 	    DLADM_STATUS_OK) {
    741   5895   yz147064 		laioc_delete_t ioc;
    742  10616  Sebastien 
    743   5895   yz147064 		ioc.ld_linkid = linkid;
    744   8453     Anurag 		(void) i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc);
    745   5895   yz147064 	}
    746   5895   yz147064 done:
    747   5895   yz147064 	free(attr.lg_ports);
    748   5895   yz147064 	free(ports);
    749   5895   yz147064 
    750   5895   yz147064 	*statusp = status;
    751   5895   yz147064 	return (DLADM_WALK_CONTINUE);
    752      0     stevel }
    753      0     stevel 
    754      0     stevel /*
    755   5895   yz147064  * Bring up one aggregation, or all persistent aggregations.  In the latter
    756   5895   yz147064  * case, the walk may terminate early if bringup of an aggregation fails.
    757      0     stevel  */
    758   3871   yz147064 dladm_status_t
    759   8453     Anurag dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid)
    760      0     stevel {
    761   3871   yz147064 	dladm_status_t status;
    762      0     stevel 
    763   5895   yz147064 	if (linkid == DATALINK_ALL_LINKID) {
    764   8453     Anurag 		(void) dladm_walk_datalink_id(i_dladm_aggr_up, handle, &status,
    765   5895   yz147064 		    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
    766   5895   yz147064 		    DLADM_OPT_PERSIST);
    767   5895   yz147064 		return (DLADM_STATUS_OK);
    768   5895   yz147064 	} else {
    769   8453     Anurag 		(void) i_dladm_aggr_up(handle, linkid, &status);
    770   3871   yz147064 		return (status);
    771      0     stevel 	}
    772      0     stevel }
    773      0     stevel 
    774      0     stevel /*
    775      0     stevel  * Given a policy string, return a policy mask. Returns B_TRUE on
    776   5895   yz147064  * success, or B_FALSE if an error occurred during parsing.
    777      0     stevel  */
    778      0     stevel boolean_t
    779   3871   yz147064 dladm_aggr_str2policy(const char *str, uint32_t *policy)
    780      0     stevel {
    781      0     stevel 	int i;
    782      0     stevel 	policy_t *pol;
    783      0     stevel 	char *token = NULL;
    784      0     stevel 	char *lasts;
    785      0     stevel 
    786      0     stevel 	*policy = 0;
    787      0     stevel 
    788      0     stevel 	while ((token = strtok_r((token == NULL) ? (char *)str : NULL, ",",
    789      0     stevel 	    &lasts)) != NULL) {
    790      0     stevel 		for (i = 0; i < NPOLICIES; i++) {
    791      0     stevel 			pol = &policies[i];
    792      0     stevel 			if (strcasecmp(token, pol->pol_name) == 0) {
    793      0     stevel 				*policy |= pol->policy;
    794      0     stevel 				break;
    795      0     stevel 			}
    796      0     stevel 		}
    797      0     stevel 		if (i == NPOLICIES)
    798      0     stevel 			return (B_FALSE);
    799      0     stevel 	}
    800      0     stevel 
    801      0     stevel 	return (B_TRUE);
    802      0     stevel }
    803      0     stevel 
    804      0     stevel /*
    805      0     stevel  * Given a policy mask, returns a printable string, or NULL if the
    806      0     stevel  * policy mask is invalid. It is the responsibility of the caller to
    807      0     stevel  * free the returned string after use.
    808      0     stevel  */
    809      0     stevel char *
    810   3871   yz147064 dladm_aggr_policy2str(uint32_t policy, char *str)
    811      0     stevel {
    812      0     stevel 	int i, npolicies = 0;
    813      0     stevel 	policy_t *pol;
    814      0     stevel 
    815   5895   yz147064 	if (str == NULL)
    816   5895   yz147064 		return (NULL);
    817   5895   yz147064 
    818      0     stevel 	str[0] = '\0';
    819      0     stevel 
    820      0     stevel 	for (i = 0; i < NPOLICIES; i++) {
    821      0     stevel 		pol = &policies[i];
    822      0     stevel 		if ((policy & pol->policy) != 0) {
    823      0     stevel 			npolicies++;
    824      0     stevel 			if (npolicies > 1)
    825   5895   yz147064 				(void) strlcat(str, ",", DLADM_STRSIZE);
    826   5895   yz147064 			(void) strlcat(str, pol->pol_name, DLADM_STRSIZE);
    827      0     stevel 		}
    828      0     stevel 	}
    829      0     stevel 
    830      0     stevel 	return (str);
    831      0     stevel }
    832      0     stevel 
    833      0     stevel /*
    834      0     stevel  * Given a MAC address string, return the MAC address in the mac_addr
    835      0     stevel  * array. If the MAC address was not explicitly specified, i.e. is
    836      0     stevel  * equal to 'auto', zero out mac-addr and set mac_fixed to B_TRUE.
    837      0     stevel  * Return B_FALSE if a syntax error was encountered, B_FALSE otherwise.
    838      0     stevel  */
    839      0     stevel boolean_t
    840   3871   yz147064 dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr)
    841      0     stevel {
    842      0     stevel 	uchar_t *conv_str;
    843      0     stevel 	int mac_len;
    844      0     stevel 
    845      0     stevel 	*mac_fixed = (strcmp(str, "auto") != 0);
    846      0     stevel 	if (!*mac_fixed) {
    847      0     stevel 		bzero(mac_addr, ETHERADDRL);
    848      0     stevel 		return (B_TRUE);
    849      0     stevel 	}
    850      0     stevel 
    851      0     stevel 	conv_str = _link_aton(str, &mac_len);
    852      0     stevel 	if (conv_str == NULL)
    853      0     stevel 		return (B_FALSE);
    854      0     stevel 
    855      0     stevel 	if (mac_len != ETHERADDRL) {
    856      0     stevel 		free(conv_str);
    857      0     stevel 		return (B_FALSE);
    858      0     stevel 	}
    859      0     stevel 
    860    449   ericheng 	if ((bcmp(zero_mac, conv_str, ETHERADDRL) == 0) ||
    861    449   ericheng 	    (conv_str[0] & 0x01)) {
    862    449   ericheng 		free(conv_str);
    863    449   ericheng 		return (B_FALSE);
    864    449   ericheng 	}
    865    449   ericheng 
    866      0     stevel 	bcopy(conv_str, mac_addr, ETHERADDRL);
    867      0     stevel 	free(conv_str);
    868      0     stevel 
    869      0     stevel 	return (B_TRUE);
    870      0     stevel }
    871      0     stevel 
    872      0     stevel /*
    873      0     stevel  * Returns a string containing a printable representation of a MAC address.
    874      0     stevel  */
    875      0     stevel const char *
    876   5895   yz147064 dladm_aggr_macaddr2str(const unsigned char *mac, char *buf)
    877      0     stevel {
    878      0     stevel 	static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
    879      0     stevel 
    880      0     stevel 	if (buf == NULL)
    881      0     stevel 		return (NULL);
    882      0     stevel 
    883      0     stevel 	if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
    884   5895   yz147064 		(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
    885      0     stevel 	else
    886      0     stevel 		return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
    887   5895   yz147064 
    888   5895   yz147064 	return (buf);
    889      0     stevel }
    890      0     stevel 
    891      0     stevel /*
    892      0     stevel  * Given a LACP mode string, find the corresponding LACP mode number. Returns
    893      0     stevel  * B_TRUE if a match was found, B_FALSE otherwise.
    894      0     stevel  */
    895      0     stevel boolean_t
    896   3871   yz147064 dladm_aggr_str2lacpmode(const char *str, aggr_lacp_mode_t *lacp_mode)
    897      0     stevel {
    898      0     stevel 	int i;
    899   3871   yz147064 	dladm_aggr_lacpmode_t *mode;
    900      0     stevel 
    901      0     stevel 	for (i = 0; i < NLACP_MODES; i++) {
    902      0     stevel 		mode = &lacp_modes[i];
    903      0     stevel 		if (strncasecmp(str, mode->mode_str,
    904      0     stevel 		    strlen(mode->mode_str)) == 0) {
    905      0     stevel 			*lacp_mode = mode->mode_id;
    906      0     stevel 			return (B_TRUE);
    907      0     stevel 		}
    908      0     stevel 	}
    909      0     stevel 
    910      0     stevel 	return (B_FALSE);
    911      0     stevel }
    912      0     stevel 
    913      0     stevel /*
    914      0     stevel  * Given a LACP mode number, returns a printable string, or NULL if the
    915      0     stevel  * LACP mode number is invalid.
    916      0     stevel  */
    917      0     stevel const char *
    918   3871   yz147064 dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf)
    919      0     stevel {
    920      0     stevel 	int i;
    921   3871   yz147064 	dladm_aggr_lacpmode_t *mode;
    922   5895   yz147064 
    923   5895   yz147064 	if (buf == NULL)
    924   5895   yz147064 		return (NULL);
    925      0     stevel 
    926      0     stevel 	for (i = 0; i < NLACP_MODES; i++) {
    927      0     stevel 		mode = &lacp_modes[i];
    928   3871   yz147064 		if (mode->mode_id == mode_id) {
    929   3871   yz147064 			(void) snprintf(buf, DLADM_STRSIZE, "%s",
    930   3871   yz147064 			    mode->mode_str);
    931   3871   yz147064 			return (buf);
    932   3871   yz147064 		}
    933      0     stevel 	}
    934      0     stevel 
    935   3871   yz147064 	(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
    936   3871   yz147064 	return (buf);
    937      0     stevel }
    938      0     stevel 
    939      0     stevel /*
    940      0     stevel  * Given a LACP timer string, find the corresponding LACP timer number. Returns
    941      0     stevel  * B_TRUE if a match was found, B_FALSE otherwise.
    942      0     stevel  */
    943      0     stevel boolean_t
    944   3871   yz147064 dladm_aggr_str2lacptimer(const char *str, aggr_lacp_timer_t *lacp_timer)
    945      0     stevel {
    946      0     stevel 	int i;
    947   3871   yz147064 	dladm_aggr_lacptimer_t *timer;
    948      0     stevel 
    949      0     stevel 	for (i = 0; i < NLACP_TIMERS; i++) {
    950      0     stevel 		timer = &lacp_timers[i];
    951      0     stevel 		if (strncasecmp(str, timer->lt_str,
    952      0     stevel 		    strlen(timer->lt_str)) == 0) {
    953      0     stevel 			*lacp_timer = timer->lt_id;
    954      0     stevel 			return (B_TRUE);
    955      0     stevel 		}
    956      0     stevel 	}
    957      0     stevel 
    958      0     stevel 	return (B_FALSE);
    959      0     stevel }
    960      0     stevel 
    961      0     stevel /*
    962      0     stevel  * Given a LACP timer, returns a printable string, or NULL if the
    963      0     stevel  * LACP timer number is invalid.
    964      0     stevel  */
    965      0     stevel const char *
    966   3871   yz147064 dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf)
    967      0     stevel {
    968      0     stevel 	int i;
    969   3871   yz147064 	dladm_aggr_lacptimer_t *timer;
    970      0     stevel 
    971   5895   yz147064 	if (buf == NULL)
    972   5895   yz147064 		return (NULL);
    973   5895   yz147064 
    974      0     stevel 	for (i = 0; i < NLACP_TIMERS; i++) {
    975      0     stevel 		timer = &lacp_timers[i];
    976   3871   yz147064 		if (timer->lt_id == timer_id) {
    977   3871   yz147064 			(void) snprintf(buf, DLADM_STRSIZE, "%s",
    978   3871   yz147064 			    timer->lt_str);
    979   3871   yz147064 			return (buf);
    980   3871   yz147064 		}
    981      0     stevel 	}
    982      0     stevel 
    983   3871   yz147064 	(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
    984   3871   yz147064 	return (buf);
    985   3871   yz147064 }
    986   3871   yz147064 
    987   3871   yz147064 const char *
    988   3871   yz147064 dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf)
    989   3871   yz147064 {
    990   3871   yz147064 	int			i;
    991   5895   yz147064 	dladm_aggr_port_state_t *state;
    992   5895   yz147064 
    993   5895   yz147064 	if (buf == NULL)
    994   5895   yz147064 		return (NULL);
    995   3871   yz147064 
    996   3871   yz147064 	for (i = 0; i < NPORT_STATES; i++) {
    997   3871   yz147064 		state = &port_states[i];
    998   3871   yz147064 		if (state->state_id == state_id) {
    999   3871   yz147064 			(void) snprintf(buf, DLADM_STRSIZE, "%s",
   1000   3871   yz147064 			    state->state_str);
   1001   3871   yz147064 			return (buf);
   1002   3871   yz147064 		}
   1003   3871   yz147064 	}
   1004   3871   yz147064 
   1005   3871   yz147064 	(void) strlcpy(buf, "unknown", DLADM_STRSIZE);
   1006   3871   yz147064 	return (buf);
   1007      0     stevel }
   1008      0     stevel 
   1009   5895   yz147064 static dladm_status_t
   1010   8453     Anurag dladm_aggr_persist_aggr_conf(dladm_handle_t handle, const char *link,
   1011   8453     Anurag     datalink_id_t linkid, uint16_t key, uint32_t nports,
   1012   8453     Anurag     dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed,
   1013   8453     Anurag     const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode,
   1014   8453     Anurag     aggr_lacp_timer_t lacp_timer, boolean_t force)
   1015   5895   yz147064 {
   1016   5895   yz147064 	dladm_conf_t conf = DLADM_INVALID_CONF;
   1017   5895   yz147064 	char *portstr = NULL;
   1018   5895   yz147064 	char macstr[ETHERADDRL * 3];
   1019   5895   yz147064 	dladm_status_t status;
   1020   5895   yz147064 	int i, size;
   1021   5895   yz147064 	uint64_t u64;
   1022      0     stevel 
   1023   8453     Anurag 	if ((status = dladm_create_conf(handle, link, linkid,
   1024   8453     Anurag 	    DATALINK_CLASS_AGGR, DL_ETHER, &conf)) != DLADM_STATUS_OK) {
   1025   3871   yz147064 		return (status);
   1026      0     stevel 	}
   1027      0     stevel 
   1028   5895   yz147064 	u64 = key;
   1029   8453     Anurag 	status = dladm_set_conf_field(handle, conf, FKEY, DLADM_TYPE_UINT64,
   1030   8453     Anurag 	    &u64);
   1031   5895   yz147064 	if (status != DLADM_STATUS_OK)
   1032   5895   yz147064 		goto done;
   1033      0     stevel 
   1034   5895   yz147064 	u64 = nports;
   1035   8453     Anurag 	status = dladm_set_conf_field(handle, conf, FNPORTS, DLADM_TYPE_UINT64,
   1036   8453     Anurag 	    &u64);
   1037   5895   yz147064 	if (status != DLADM_STATUS_OK)
   1038   5895   yz147064 		goto done;
   1039      0     stevel 
   1040  10616  Sebastien 	size = nports * MAXLINKNAMELEN + 1;
   1041   5895   yz147064 	if ((portstr = calloc(1, size)) == NULL) {
   1042   5895   yz147064 		status = DLADM_STATUS_NOMEM;
   1043   5895   yz147064 		goto done;
   1044   5895   yz147064 	}
   1045      0     stevel 
   1046  10616  Sebastien 	for (i = 0; i < nports; i++) {
   1047  10616  Sebastien 		status = write_port(handle, portstr, ports[i].lp_linkid, size);
   1048  10616  Sebastien 		if (status != DLADM_STATUS_OK) {
   1049  10616  Sebastien 			free(portstr);
   1050  10616  Sebastien 			goto done;
   1051  10616  Sebastien 		}
   1052  10616  Sebastien 	}
   1053   8453     Anurag 	status = dladm_set_conf_field(handle, conf, FPORTS, DLADM_TYPE_STR,
   1054   8453     Anurag 	    portstr);
   1055   5895   yz147064 	free(portstr);
   1056   5895   yz147064 
   1057   5895   yz147064 	if (status != DLADM_STATUS_OK)
   1058   5895   yz147064 		goto done;
   1059   5895   yz147064 
   1060   5895   yz147064 	u64 = policy;
   1061   8453     Anurag 	status = dladm_set_conf_field(handle, conf, FPOLICY, DLADM_TYPE_UINT64,
   1062   8453     Anurag 	    &u64);
   1063   5895   yz147064 	if (status != DLADM_STATUS_OK)
   1064   5895   yz147064 		goto done;
   1065   5895   yz147064 
   1066   8453     Anurag 	status = dladm_set_conf_field(handle, conf, FFIXMACADDR,
   1067   8453     Anurag 	    DLADM_TYPE_BOOLEAN, &mac_addr_fixed);
   1068   5895   yz147064 	if (status != DLADM_STATUS_OK)
   1069   5895   yz147064 		goto done;
   1070   5895   yz147064 
   1071   5895   yz147064 	if (mac_addr_fixed) {
   1072   5895   yz147064 		if (!VALID_PORT_MAC(mac_addr)) {
   1073   5895   yz147064 			status = DLADM_STATUS_MACADDRINVAL;
   1074   3871   yz147064 			goto done;
   1075      0     stevel 		}
   1076      0     stevel 
   1077   5895   yz147064 		(void) dladm_aggr_macaddr2str(mac_addr, macstr);
   1078   8453     Anurag 		status = dladm_set_conf_field(handle, conf, FMACADDR,
   1079   8453     Anurag 		    DLADM_TYPE_STR, macstr);
   1080   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1081   3871   yz147064 			goto done;
   1082      0     stevel 	}
   1083      0     stevel 
   1084   8453     Anurag 	status = dladm_set_conf_field(handle, conf, FFORCE, DLADM_TYPE_BOOLEAN,
   1085   8453     Anurag 	    &force);
   1086   5895   yz147064 	if (status != DLADM_STATUS_OK)
   1087   5895   yz147064 		goto done;
   1088   5895   yz147064 
   1089   5895   yz147064 	u64 = lacp_mode;
   1090   8453     Anurag 	status = dladm_set_conf_field(handle, conf, FLACPMODE,
   1091   8453     Anurag 	    DLADM_TYPE_UINT64, &u64);
   1092   5895   yz147064 	if (status != DLADM_STATUS_OK)
   1093   5895   yz147064 		goto done;
   1094   5895   yz147064 
   1095   5895   yz147064 	u64 = lacp_timer;
   1096   8453     Anurag 	status = dladm_set_conf_field(handle, conf, FLACPTIMER,
   1097   8453     Anurag 	    DLADM_TYPE_UINT64, &u64);
   1098   5895   yz147064 	if (status != DLADM_STATUS_OK)
   1099   5895   yz147064 		goto done;
   1100   5895   yz147064 
   1101      0     stevel 	/*
   1102   5895   yz147064 	 * Commit the link aggregation configuration.
   1103      0     stevel 	 */
   1104   8453     Anurag 	status = dladm_write_conf(handle, conf);
   1105      0     stevel 
   1106   3871   yz147064 done:
   1107   8453     Anurag 	dladm_destroy_conf(handle, conf);
   1108   3871   yz147064 	return (status);
   1109      0     stevel }
   1110      0     stevel 
   1111      0     stevel /*
   1112      0     stevel  * Create a new link aggregation group. Update the configuration
   1113      0     stevel  * file and bring it up.
   1114      0     stevel  */
   1115   3871   yz147064 dladm_status_t
   1116   8453     Anurag dladm_aggr_create(dladm_handle_t handle, const char *name, uint16_t key,
   1117   8453     Anurag     uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t policy,
   1118   8453     Anurag     boolean_t mac_addr_fixed, const uchar_t *mac_addr,
   1119   8453     Anurag     aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, uint32_t flags)
   1120      0     stevel {
   1121   5895   yz147064 	datalink_id_t linkid = DATALINK_INVALID_LINKID;
   1122   5895   yz147064 	uint32_t media;
   1123   5895   yz147064 	uint32_t i;
   1124   5895   yz147064 	datalink_class_t class;
   1125   3871   yz147064 	dladm_status_t status;
   1126   5895   yz147064 	boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE;
   1127      0     stevel 
   1128   5895   yz147064 	if (key != 0 && key > AGGR_MAX_KEY)
   1129   3871   yz147064 		return (DLADM_STATUS_KEYINVAL);
   1130      0     stevel 
   1131   5895   yz147064 	if (nports == 0)
   1132   5895   yz147064 		return (DLADM_STATUS_BADARG);
   1133      0     stevel 
   1134   5895   yz147064 	for (i = 0; i < nports; i++) {
   1135   8453     Anurag 		if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL,
   1136   5895   yz147064 		    &class, &media, NULL, 0) != DLADM_STATUS_OK) ||
   1137   9815      Rishi 		    !((class == DATALINK_CLASS_PHYS || class ==
   1138   9815      Rishi 		    DATALINK_CLASS_SIMNET) && (media == DL_ETHER))) {
   1139   5895   yz147064 			return (DLADM_STATUS_BADARG);
   1140   5895   yz147064 		}
   1141   5895   yz147064 	}
   1142   5895   yz147064 
   1143   5895   yz147064 	flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
   1144   8453     Anurag 	if ((status = dladm_create_datalink_id(handle, name,
   1145   8453     Anurag 	    DATALINK_CLASS_AGGR, DL_ETHER, flags, &linkid)) !=
   1146   8453     Anurag 	    DLADM_STATUS_OK) {
   1147   5895   yz147064 		goto fail;
   1148   5895   yz147064 	}
   1149   5895   yz147064 
   1150   5895   yz147064 	if ((flags & DLADM_OPT_PERSIST) &&
   1151   8453     Anurag 	    (status = dladm_aggr_persist_aggr_conf(handle, name, linkid, key,
   1152   8453     Anurag 	    nports, ports, policy, mac_addr_fixed, mac_addr, lacp_mode,
   1153   8453     Anurag 	    lacp_timer, force)) != DLADM_STATUS_OK) {
   1154   5895   yz147064 		goto fail;
   1155   5895   yz147064 	}
   1156   5895   yz147064 
   1157   5895   yz147064 	if (!(flags & DLADM_OPT_ACTIVE))
   1158   5895   yz147064 		return (DLADM_STATUS_OK);
   1159   5895   yz147064 
   1160   8453     Anurag 	status = i_dladm_aggr_create_sys(handle, linkid, key, nports, ports,
   1161   8453     Anurag 	    policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force);
   1162   5895   yz147064 
   1163   5895   yz147064 	if (status != DLADM_STATUS_OK) {
   1164   5895   yz147064 		if (flags & DLADM_OPT_PERSIST)
   1165   8453     Anurag 			(void) dladm_remove_conf(handle, linkid);
   1166   5895   yz147064 		goto fail;
   1167   5895   yz147064 	}
   1168   5895   yz147064 
   1169   5895   yz147064 	return (DLADM_STATUS_OK);
   1170   5895   yz147064 
   1171   5895   yz147064 fail:
   1172   5895   yz147064 	if (linkid != DATALINK_INVALID_LINKID)
   1173   8453     Anurag 		(void) dladm_destroy_datalink_id(handle, linkid, flags);
   1174   5895   yz147064 
   1175   5895   yz147064 	return (status);
   1176   5895   yz147064 }
   1177   5895   yz147064 
   1178   5895   yz147064 static dladm_status_t
   1179   8453     Anurag i_dladm_aggr_get_aggr_attr(dladm_handle_t handle, dladm_conf_t conf,
   1180   8453     Anurag     uint32_t mask, dladm_aggr_modify_attr_t *attrp)
   1181   5895   yz147064 {
   1182   5895   yz147064 	dladm_status_t status = DLADM_STATUS_OK;
   1183   5895   yz147064 	char macstr[ETHERADDRL * 3];
   1184   5895   yz147064 	uint64_t u64;
   1185   5895   yz147064 
   1186   5895   yz147064 	if (mask & DLADM_AGGR_MODIFY_POLICY) {
   1187   8453     Anurag 		status = dladm_get_conf_field(handle, conf, FPOLICY, &u64,
   1188   5895   yz147064 		    sizeof (u64));
   1189   3871   yz147064 		if (status != DLADM_STATUS_OK)
   1190   3871   yz147064 			return (status);
   1191   5895   yz147064 		attrp->ld_policy = (uint32_t)u64;
   1192      0     stevel 	}
   1193      0     stevel 
   1194   5895   yz147064 	if (mask & DLADM_AGGR_MODIFY_MAC) {
   1195   8453     Anurag 		status = dladm_get_conf_field(handle, conf, FFIXMACADDR,
   1196   5895   yz147064 		    &attrp->ld_mac_fixed, sizeof (boolean_t));
   1197   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1198   5895   yz147064 			return (status);
   1199      0     stevel 
   1200   5895   yz147064 		if (attrp->ld_mac_fixed) {
   1201   5895   yz147064 			boolean_t fixed;
   1202   5895   yz147064 
   1203   8453     Anurag 			status = dladm_get_conf_field(handle, conf, FMACADDR,
   1204   5895   yz147064 			    macstr, sizeof (macstr));
   1205   5895   yz147064 			if (status != DLADM_STATUS_OK)
   1206   5895   yz147064 				return (status);
   1207   5895   yz147064 
   1208   5895   yz147064 			if (!dladm_aggr_str2macaddr(macstr, &fixed,
   1209   5895   yz147064 			    attrp->ld_mac)) {
   1210   5895   yz147064 				return (DLADM_STATUS_REPOSITORYINVAL);
   1211   5895   yz147064 			}
   1212   5895   yz147064 		}
   1213   5895   yz147064 	}
   1214   5895   yz147064 
   1215   5895   yz147064 	if (mask & DLADM_AGGR_MODIFY_LACP_MODE) {
   1216   8453     Anurag 		status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64,
   1217   5895   yz147064 		    sizeof (u64));
   1218   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1219   5895   yz147064 			return (status);
   1220   5895   yz147064 		attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64;
   1221   5895   yz147064 	}
   1222   5895   yz147064 
   1223   5895   yz147064 	if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) {
   1224   8453     Anurag 		status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64,
   1225   5895   yz147064 		    sizeof (u64));
   1226   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1227   5895   yz147064 			return (status);
   1228   5895   yz147064 		attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64;
   1229   5895   yz147064 	}
   1230   5895   yz147064 
   1231   5895   yz147064 	return (status);
   1232   5895   yz147064 }
   1233   5895   yz147064 
   1234   5895   yz147064 static dladm_status_t
   1235   8453     Anurag i_dladm_aggr_set_aggr_attr(dladm_handle_t handle, dladm_conf_t conf,
   1236   8453     Anurag     uint32_t mask, dladm_aggr_modify_attr_t *attrp)
   1237   5895   yz147064 {
   1238   5895   yz147064 	dladm_status_t status = DLADM_STATUS_OK;
   1239   5895   yz147064 	char macstr[ETHERADDRL * 3];
   1240   5895   yz147064 	uint64_t u64;
   1241   5895   yz147064 
   1242   5895   yz147064 	if (mask & DLADM_AGGR_MODIFY_POLICY) {
   1243   5895   yz147064 		u64 = attrp->ld_policy;
   1244   8453     Anurag 		status = dladm_set_conf_field(handle, conf, FPOLICY,
   1245   8453     Anurag 		    DLADM_TYPE_UINT64, &u64);
   1246   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1247   5895   yz147064 			return (status);
   1248   5895   yz147064 	}
   1249   5895   yz147064 
   1250   5895   yz147064 	if (mask & DLADM_AGGR_MODIFY_MAC) {
   1251   8453     Anurag 		status = dladm_set_conf_field(handle, conf, FFIXMACADDR,
   1252   5895   yz147064 		    DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed);
   1253   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1254   5895   yz147064 			return (status);
   1255   5895   yz147064 
   1256   5895   yz147064 		if (attrp->ld_mac_fixed) {
   1257   5895   yz147064 			(void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr);
   1258   8453     Anurag 			status = dladm_set_conf_field(handle, conf, FMACADDR,
   1259   5895   yz147064 			    DLADM_TYPE_STR, macstr);
   1260   5895   yz147064 			if (status != DLADM_STATUS_OK)
   1261   5895   yz147064 				return (status);
   1262   5895   yz147064 		}
   1263   5895   yz147064 	}
   1264   5895   yz147064 
   1265   5895   yz147064 	if (mask & DLADM_AGGR_MODIFY_LACP_MODE) {
   1266   5895   yz147064 		u64 = attrp->ld_lacp_mode;
   1267   8453     Anurag 		status = dladm_set_conf_field(handle, conf, FLACPMODE,
   1268   5895   yz147064 		    DLADM_TYPE_UINT64, &u64);
   1269   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1270   5895   yz147064 			return (status);
   1271   5895   yz147064 	}
   1272   5895   yz147064 
   1273   5895   yz147064 	if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) {
   1274   5895   yz147064 		u64 = attrp->ld_lacp_timer;
   1275   8453     Anurag 		status = dladm_set_conf_field(handle, conf, FLACPTIMER,
   1276   5895   yz147064 		    DLADM_TYPE_UINT64, &u64);
   1277   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1278   5895   yz147064 			return (status);
   1279   5895   yz147064 	}
   1280   3871   yz147064 
   1281   3871   yz147064 	return (status);
   1282      0     stevel }
   1283      0     stevel 
   1284      0     stevel /*
   1285      0     stevel  * Modify the parameters of an existing link aggregation group. Update
   1286      0     stevel  * the configuration file and pass the changes to the kernel.
   1287      0     stevel  */
   1288   3871   yz147064 dladm_status_t
   1289   8453     Anurag dladm_aggr_modify(dladm_handle_t handle, datalink_id_t linkid,
   1290   8453     Anurag     uint32_t modify_mask, uint32_t policy, boolean_t mac_fixed,
   1291   8453     Anurag     const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode,
   1292   5895   yz147064     aggr_lacp_timer_t lacp_timer, uint32_t flags)
   1293      0     stevel {
   1294   3871   yz147064 	dladm_aggr_modify_attr_t new_attr, old_attr;
   1295   5895   yz147064 	dladm_conf_t conf;
   1296   3871   yz147064 	dladm_status_t status;
   1297      0     stevel 
   1298   5895   yz147064 	new_attr.ld_policy = policy;
   1299   5895   yz147064 	new_attr.ld_mac_fixed = mac_fixed;
   1300   5895   yz147064 	new_attr.ld_lacp_mode = lacp_mode;
   1301   5895   yz147064 	new_attr.ld_lacp_timer = lacp_timer;
   1302   5895   yz147064 	bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL);
   1303      0     stevel 
   1304   5895   yz147064 	if (flags & DLADM_OPT_PERSIST) {
   1305   8453     Anurag 		status = dladm_read_conf(handle, linkid, &conf);
   1306   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1307   5895   yz147064 			return (status);
   1308      0     stevel 
   1309   8453     Anurag 		if ((status = i_dladm_aggr_get_aggr_attr(handle, conf,
   1310   8453     Anurag 		    modify_mask, &old_attr)) != DLADM_STATUS_OK) {
   1311   5895   yz147064 			goto done;
   1312   5895   yz147064 		}
   1313   5895   yz147064 
   1314   8453     Anurag 		if ((status = i_dladm_aggr_set_aggr_attr(handle, conf,
   1315   8453     Anurag 		    modify_mask, &new_attr)) != DLADM_STATUS_OK) {
   1316   5895   yz147064 			goto done;
   1317   5895   yz147064 		}
   1318   5895   yz147064 
   1319   8453     Anurag 		status = dladm_write_conf(handle, conf);
   1320   5895   yz147064 
   1321   5895   yz147064 done:
   1322   8453     Anurag 		dladm_destroy_conf(handle, conf);
   1323   5895   yz147064 		if (status != DLADM_STATUS_OK)
   1324   5895   yz147064 			return (status);
   1325      0     stevel 	}
   1326      0     stevel 
   1327   5895   yz147064 	if (!(flags & DLADM_OPT_ACTIVE))
   1328   5895   yz147064 		return (DLADM_STATUS_OK);
   1329      0     stevel 
   1330   8453     Anurag 	status = i_dladm_aggr_modify_sys(handle, linkid, modify_mask,
   1331   8453     Anurag 	    &new_attr);
   1332   5895   yz147064 	if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) {
   1333   8453     Anurag 		if (dladm_read_conf(handle, linkid, &conf) == DLADM_STATUS_OK) {
   1334   8453     Anurag 			if (i_dladm_aggr_set_aggr_attr(handle, conf,
   1335   8453     Anurag 			    modify_mask, &old_attr) == DLADM_STATUS_OK) {
   1336   8453     Anurag 				(void) dladm_write_conf(handle, conf);
   1337   5895   yz147064 			}
   1338   8453     Anurag 			dladm_destroy_conf(handle, conf);
   1339   5895   yz147064 		}
   1340      0     stevel 	}
   1341      0     stevel 
   1342   3871   yz147064 	return (status);
   1343      0     stevel }
   1344      0     stevel 
   1345   5895   yz147064 typedef struct aggr_held_arg_s {
   1346   5895   yz147064 	datalink_id_t	aggrid;
   1347   5895   yz147064 	boolean_t	isheld;
   1348   5895   yz147064 } aggr_held_arg_t;
   1349   5895   yz147064 
   1350   5895   yz147064 static int
   1351   8453     Anurag i_dladm_aggr_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg)
   1352   5895   yz147064 {
   1353   5895   yz147064 	aggr_held_arg_t		*aggr_held_arg = arg;
   1354   5895   yz147064 	dladm_vlan_attr_t	dva;
   1355   5895   yz147064 
   1356   8453     Anurag 	if (dladm_vlan_info(handle, linkid, &dva, DLADM_OPT_PERSIST) !=
   1357   8453     Anurag 	    DLADM_STATUS_OK)
   1358   5895   yz147064 		return (DLADM_WALK_CONTINUE);
   1359   5895   yz147064 
   1360   5895   yz147064 	if (dva.dv_linkid == aggr_held_arg->aggrid) {
   1361   5895   yz147064 		/*
   1362   5895   yz147064 		 * This VLAN is created over the given aggregation.
   1363   5895   yz147064 		 */
   1364   5895   yz147064 		aggr_held_arg->isheld = B_TRUE;
   1365   5895   yz147064 		return (DLADM_WALK_TERMINATE);
   1366   5895   yz147064 	}
   1367   5895   yz147064 	return (DLADM_WALK_CONTINUE);
   1368   5895   yz147064 }
   1369   5895   yz147064 
   1370      0     stevel /*
   1371   5895   yz147064  * Delete a previously created link aggregation group. Either the name "aggr"
   1372   5895   yz147064  * or the "key" is specified.
   1373      0     stevel  */
   1374   3871   yz147064 dladm_status_t
   1375   8453     Anurag dladm_aggr_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
   1376      0     stevel {
   1377   5895   yz147064 	laioc_delete_t ioc;
   1378   5895   yz147064 	datalink_class_t class;
   1379   3871   yz147064 	dladm_status_t status;
   1380      0     stevel 
   1381   8453     Anurag 	if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL,
   1382   8453     Anurag 	    0) != DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) {
   1383   5895   yz147064 		return (DLADM_STATUS_BADARG);
   1384   5895   yz147064 	}
   1385      0     stevel 
   1386   5895   yz147064 	if (flags & DLADM_OPT_ACTIVE) {
   1387   5895   yz147064 		ioc.ld_linkid = linkid;
   1388   8453     Anurag 		if ((i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc) < 0) &&
   1389   5895   yz147064 		    ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) {
   1390   5895   yz147064 			status = dladm_errno2status(errno);
   1391   5895   yz147064 			return (status);
   1392   5895   yz147064 		}
   1393   3871   yz147064 
   1394   3871   yz147064 		/*
   1395   5895   yz147064 		 * Delete ACTIVE linkprop first.
   1396   3871   yz147064 		 */
   1397   8453     Anurag 		(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
   1398   5895   yz147064 		    DLADM_OPT_ACTIVE);
   1399   8453     Anurag 		(void) dladm_destroy_datalink_id(handle, linkid,
   1400   8453     Anurag 		    DLADM_OPT_ACTIVE);
   1401      0     stevel 	}
   1402      0     stevel 
   1403   5895   yz147064 	/*
   1404   5895   yz147064 	 * If we reach here, it means that the active aggregation has already
   1405   5895   yz147064 	 * been deleted, and there is no active VLANs holding this aggregation.
   1406   5895   yz147064 	 * Now we see whether there is any persistent VLANs holding this
   1407   5895   yz147064 	 * aggregation. If so, we fail the operation.
   1408   5895   yz147064 	 */
   1409   5895   yz147064 	if (flags & DLADM_OPT_PERSIST) {
   1410   5895   yz147064 		aggr_held_arg_t arg;
   1411   3871   yz147064 
   1412   5895   yz147064 		arg.aggrid = linkid;
   1413   5895   yz147064 		arg.isheld = B_FALSE;
   1414   5895   yz147064 
   1415   8453     Anurag 		(void) dladm_walk_datalink_id(i_dladm_aggr_is_held, handle,
   1416   5895   yz147064 		    &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE,
   1417   5895   yz147064 		    DLADM_OPT_PERSIST);
   1418   5895   yz147064 		if (arg.isheld)
   1419   5895   yz147064 			return (DLADM_STATUS_LINKBUSY);
   1420   5895   yz147064 
   1421  10616  Sebastien 		(void) dladm_remove_conf(handle, linkid);
   1422   8453     Anurag 		(void) dladm_destroy_datalink_id(handle, linkid,
   1423   8453     Anurag 		    DLADM_OPT_PERSIST);
   1424   5895   yz147064 	}
   1425   5895   yz147064 
   1426   5895   yz147064 	return (DLADM_STATUS_OK);
   1427      0     stevel }
   1428      0     stevel 
   1429      0     stevel /*
   1430      0     stevel  * Add one or more ports to an existing link aggregation.
   1431      0     stevel  */
   1432   3871   yz147064 dladm_status_t
   1433   8453     Anurag dladm_aggr_add(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports,
   1434   5895   yz147064     dladm_aggr_port_attr_db_t *ports, uint32_t flags)
   1435      0     stevel {
   1436   8453     Anurag 	return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags,
   1437   8453     Anurag 	    LAIOC_ADD));
   1438      0     stevel }
   1439      0     stevel 
   1440      0     stevel /*
   1441      0     stevel  * Remove one or more ports from an existing link aggregation.
   1442      0     stevel  */
   1443   3871   yz147064 dladm_status_t
   1444   8453     Anurag dladm_aggr_remove(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports,
   1445   5895   yz147064     dladm_aggr_port_attr_db_t *ports, uint32_t flags)
   1446      0     stevel {
   1447   8453     Anurag 	return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags,
   1448   5895   yz147064 	    LAIOC_REMOVE));
   1449   5895   yz147064 }
   1450   5895   yz147064 
   1451   5895   yz147064 typedef struct i_walk_key_state_s {
   1452   5895   yz147064 	uint16_t key;
   1453   5895   yz147064 	datalink_id_t linkid;
   1454   5895   yz147064 	boolean_t found;
   1455   5895   yz147064 } i_walk_key_state_t;
   1456   5895   yz147064 
   1457   5895   yz147064 static int
   1458   8453     Anurag i_dladm_walk_key2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg)
   1459   5895   yz147064 {
   1460   5895   yz147064 	dladm_conf_t conf;
   1461   5895   yz147064 	uint16_t key;
   1462   3871   yz147064 	dladm_status_t status;
   1463   5895   yz147064 	i_walk_key_state_t *statep = (i_walk_key_state_t *)arg;
   1464   5895   yz147064 	uint64_t u64;
   1465      0     stevel 
   1466   8453     Anurag 	if (dladm_read_conf(handle, linkid, &conf) != 0)
   1467   5895   yz147064 		return (DLADM_WALK_CONTINUE);
   1468      0     stevel 
   1469   8453     Anurag 	status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64));
   1470   5895   yz147064 	key = (uint16_t)u64;
   1471   8453     Anurag 	dladm_destroy_conf(handle, conf);
   1472      0     stevel 
   1473   5895   yz147064 	if ((status == DLADM_STATUS_OK) && (key == statep->key)) {
   1474   5895   yz147064 		statep->found = B_TRUE;
   1475   5895   yz147064 		statep->linkid = linkid;
   1476   5895   yz147064 		return (DLADM_WALK_TERMINATE);
   1477      0     stevel 	}
   1478      0     stevel 
   1479   5895   yz147064 	return (DLADM_WALK_CONTINUE);
   1480   5895   yz147064 }
   1481      0     stevel 
   1482   5895   yz147064 dladm_status_t
   1483   8453     Anurag dladm_key2linkid(dladm_handle_t handle, uint16_t key, datalink_id_t *linkidp,
   1484   8453     Anurag     uint32_t flags)
   1485   5895   yz147064 {
   1486   5895   yz147064 	i_walk_key_state_t state;
   1487   5895   yz147064 
   1488   5895   yz147064 	if (key > AGGR_MAX_KEY)
   1489   5895   yz147064 		return (DLADM_STATUS_NOTFOUND);
   1490   5895   yz147064 
   1491   5895   yz147064 	state.found = B_FALSE;
   1492   5895   yz147064 	state.key = key;
   1493   5895   yz147064 
   1494   8453     Anurag 	(void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, handle, &state,
   1495   5895   yz147064 	    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
   1496   5895   yz147064 	if (state.found == B_TRUE) {
   1497   5895   yz147064 		*linkidp = state.linkid;
   1498   5895   yz147064 		return (DLADM_STATUS_OK);
   1499   5895   yz147064 	} else {
   1500   5895   yz147064 		return (DLADM_STATUS_NOTFOUND);
   1501   5895   yz147064 	}
   1502      0     stevel }
   1503