13871Syz147064 /*
23871Syz147064 * CDDL HEADER START
33871Syz147064 *
43871Syz147064 * The contents of this file are subject to the terms of the
53871Syz147064 * Common Development and Distribution License (the "License").
63871Syz147064 * You may not use this file except in compliance with the License.
73871Syz147064 *
83871Syz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93871Syz147064 * or http://www.opensolaris.org/os/licensing.
103871Syz147064 * See the License for the specific language governing permissions
113871Syz147064 * and limitations under the License.
123871Syz147064 *
133871Syz147064 * When distributing Covered Code, include this CDDL HEADER in each
143871Syz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153871Syz147064 * If applicable, add the following below this CDDL HEADER, with the
163871Syz147064 * fields enclosed by brackets "[]" replaced with your own identifying
173871Syz147064 * information: Portions Copyright [yyyy] [name of copyright owner]
183871Syz147064 *
193871Syz147064 * CDDL HEADER END
203871Syz147064 */
213871Syz147064 /*
22*12824SCathy.Zhou@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
233871Syz147064 */
243871Syz147064
253871Syz147064 #include <stdio.h>
263871Syz147064 #include <sys/types.h>
273871Syz147064 #include <sys/stat.h>
283871Syz147064 #include <string.h>
293871Syz147064 #include <fcntl.h>
303871Syz147064 #include <unistd.h>
313871Syz147064 #include <stropts.h>
323871Syz147064 #include <stdlib.h>
333871Syz147064 #include <errno.h>
345895Syz147064 #include <assert.h>
353871Syz147064 #include <strings.h>
363871Syz147064 #include <libintl.h>
373871Syz147064 #include <net/if_types.h>
383871Syz147064 #include <net/if_dl.h>
398275SEric Cheng #include <sys/dld.h>
405895Syz147064 #include <libdllink.h>
415895Syz147064 #include <libdlvlan.h>
423871Syz147064 #include <libdlaggr.h>
433871Syz147064 #include <libdladm_impl.h>
443871Syz147064
453871Syz147064 /*
463871Syz147064 * Link Aggregation Administration Library.
473871Syz147064 *
483871Syz147064 * This library is used by administration tools such as dladm(1M) to
493871Syz147064 * configure link aggregations.
503871Syz147064 */
513871Syz147064
523871Syz147064 /* Limits on buffer size for LAIOC_INFO request */
533871Syz147064 #define MIN_INFO_SIZE (4*1024)
543871Syz147064 #define MAX_INFO_SIZE (128*1024)
553871Syz147064
565895Syz147064 static uchar_t zero_mac[] = {0, 0, 0, 0, 0, 0};
575895Syz147064 #define VALID_PORT_MAC(mac) \
585895Syz147064 (((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) && \
5911878SVenu.Iyer@Sun.COM (!((mac)[0] & 0x01)))
603871Syz147064
6110616SSebastien.Roy@Sun.COM #define PORT_DELIMITER ":"
623871Syz147064
633871Syz147064 typedef struct dladm_aggr_modify_attr {
643871Syz147064 uint32_t ld_policy;
653871Syz147064 boolean_t ld_mac_fixed;
663871Syz147064 uchar_t ld_mac[ETHERADDRL];
673871Syz147064 aggr_lacp_mode_t ld_lacp_mode;
683871Syz147064 aggr_lacp_timer_t ld_lacp_timer;
693871Syz147064 } dladm_aggr_modify_attr_t;
703871Syz147064
713871Syz147064 typedef struct policy_s {
723871Syz147064 char *pol_name;
733871Syz147064 uint32_t policy;
743871Syz147064 } policy_t;
753871Syz147064
763871Syz147064 static policy_t policies[] = {
773871Syz147064 {"L2", AGGR_POLICY_L2},
783871Syz147064 {"L3", AGGR_POLICY_L3},
793871Syz147064 {"L4", AGGR_POLICY_L4}};
803871Syz147064
813871Syz147064 #define NPOLICIES (sizeof (policies) / sizeof (policy_t))
823871Syz147064
833871Syz147064 typedef struct dladm_aggr_lacpmode_s {
843871Syz147064 char *mode_str;
853871Syz147064 aggr_lacp_mode_t mode_id;
863871Syz147064 } dladm_aggr_lacpmode_t;
873871Syz147064
883871Syz147064 static dladm_aggr_lacpmode_t lacp_modes[] = {
893871Syz147064 {"off", AGGR_LACP_OFF},
903871Syz147064 {"active", AGGR_LACP_ACTIVE},
913871Syz147064 {"passive", AGGR_LACP_PASSIVE}};
923871Syz147064
933871Syz147064 #define NLACP_MODES (sizeof (lacp_modes) / sizeof (dladm_aggr_lacpmode_t))
943871Syz147064
953871Syz147064 typedef struct dladm_aggr_lacptimer_s {
963871Syz147064 char *lt_str;
973871Syz147064 aggr_lacp_timer_t lt_id;
983871Syz147064 } dladm_aggr_lacptimer_t;
993871Syz147064
1003871Syz147064 static dladm_aggr_lacptimer_t lacp_timers[] = {
1013871Syz147064 {"short", AGGR_LACP_TIMER_SHORT},
1023871Syz147064 {"long", AGGR_LACP_TIMER_LONG}};
1033871Syz147064
1043871Syz147064 #define NLACP_TIMERS (sizeof (lacp_timers) / sizeof (dladm_aggr_lacptimer_t))
1053871Syz147064
1063871Syz147064 typedef struct dladm_aggr_port_state {
1073871Syz147064 char *state_str;
1083871Syz147064 aggr_port_state_t state_id;
1093871Syz147064 } dladm_aggr_port_state_t;
1103871Syz147064
1113871Syz147064 static dladm_aggr_port_state_t port_states[] = {
1123871Syz147064 {"standby", AGGR_PORT_STATE_STANDBY },
1133871Syz147064 {"attached", AGGR_PORT_STATE_ATTACHED }
1143871Syz147064 };
1153871Syz147064
1163871Syz147064 #define NPORT_STATES \
1173871Syz147064 (sizeof (port_states) / sizeof (dladm_aggr_port_state_t))
1183871Syz147064
11910616SSebastien.Roy@Sun.COM static dladm_status_t
write_port(dladm_handle_t handle,char * portstr,datalink_id_t portid,size_t portstrsize)12010616SSebastien.Roy@Sun.COM write_port(dladm_handle_t handle, char *portstr, datalink_id_t portid,
12110616SSebastien.Roy@Sun.COM size_t portstrsize)
12210616SSebastien.Roy@Sun.COM {
12310616SSebastien.Roy@Sun.COM char pname[MAXLINKNAMELEN + 1];
12410616SSebastien.Roy@Sun.COM dladm_status_t status;
12510616SSebastien.Roy@Sun.COM
12610616SSebastien.Roy@Sun.COM if ((status = dladm_datalink_id2info(handle, portid, NULL, NULL, NULL,
12710616SSebastien.Roy@Sun.COM pname, sizeof (pname))) != DLADM_STATUS_OK)
12810616SSebastien.Roy@Sun.COM return (status);
12910616SSebastien.Roy@Sun.COM (void) strlcat(pname, PORT_DELIMITER, sizeof (pname));
13010616SSebastien.Roy@Sun.COM if (strlcat(portstr, pname, portstrsize) >= portstrsize)
13110616SSebastien.Roy@Sun.COM status = DLADM_STATUS_TOOSMALL;
13210616SSebastien.Roy@Sun.COM return (status);
13310616SSebastien.Roy@Sun.COM }
13410616SSebastien.Roy@Sun.COM
13510616SSebastien.Roy@Sun.COM static dladm_status_t
read_port(dladm_handle_t handle,char ** portstr,datalink_id_t * portid)13610616SSebastien.Roy@Sun.COM read_port(dladm_handle_t handle, char **portstr, datalink_id_t *portid)
13710616SSebastien.Roy@Sun.COM {
13810616SSebastien.Roy@Sun.COM dladm_status_t status;
13910616SSebastien.Roy@Sun.COM char *pname;
14010616SSebastien.Roy@Sun.COM
14110616SSebastien.Roy@Sun.COM if ((pname = strtok(*portstr, PORT_DELIMITER)) == NULL)
14210616SSebastien.Roy@Sun.COM return (DLADM_STATUS_REPOSITORYINVAL);
14310616SSebastien.Roy@Sun.COM *portstr += (strlen(pname) + 1);
14410616SSebastien.Roy@Sun.COM status = dladm_name2info(handle, pname, portid, NULL, NULL, NULL);
14510616SSebastien.Roy@Sun.COM return (status);
14610616SSebastien.Roy@Sun.COM }
14710616SSebastien.Roy@Sun.COM
1485895Syz147064 static int
i_dladm_aggr_ioctl(dladm_handle_t handle,int cmd,void * ptr)1498453SAnurag.Maskey@Sun.COM i_dladm_aggr_ioctl(dladm_handle_t handle, int cmd, void *ptr)
1505895Syz147064 {
1518453SAnurag.Maskey@Sun.COM return (ioctl(dladm_dld_fd(handle), cmd, ptr));
1523871Syz147064 }
1533871Syz147064
1543871Syz147064 /*
1555895Syz147064 * Caller must free attr.lg_ports. The ptr pointer is advanced while convert
1565895Syz147064 * the laioc_info_t to the dladm_aggr_grp_attr_t structure.
1573871Syz147064 */
1585895Syz147064 static int
i_dladm_aggr_iocp2grpattr(void ** ptr,dladm_aggr_grp_attr_t * attrp)1595895Syz147064 i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp)
1603871Syz147064 {
1615895Syz147064 laioc_info_group_t *grp;
1625895Syz147064 laioc_info_port_t *port;
1635895Syz147064 int i;
1645895Syz147064 void *where = (*ptr);
1655895Syz147064
1665895Syz147064 grp = (laioc_info_group_t *)where;
1675895Syz147064
1685895Syz147064 attrp->lg_linkid = grp->lg_linkid;
1695895Syz147064 attrp->lg_key = grp->lg_key;
1705895Syz147064 attrp->lg_nports = grp->lg_nports;
1715895Syz147064 attrp->lg_policy = grp->lg_policy;
1725895Syz147064 attrp->lg_lacp_mode = grp->lg_lacp_mode;
1735895Syz147064 attrp->lg_lacp_timer = grp->lg_lacp_timer;
1745895Syz147064 attrp->lg_force = grp->lg_force;
1755895Syz147064
1765895Syz147064 bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL);
1775895Syz147064 attrp->lg_mac_fixed = grp->lg_mac_fixed;
1783871Syz147064
1795895Syz147064 if ((attrp->lg_ports = malloc(grp->lg_nports *
1805895Syz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) {
1815895Syz147064 errno = ENOMEM;
1825895Syz147064 goto fail;
1835895Syz147064 }
1845895Syz147064
1855895Syz147064 where = (grp + 1);
1863871Syz147064
1875895Syz147064 /*
1885895Syz147064 * Go through each port that is part of the group.
1895895Syz147064 */
1905895Syz147064 for (i = 0; i < grp->lg_nports; i++) {
1915895Syz147064 port = (laioc_info_port_t *)where;
1923871Syz147064
1935895Syz147064 attrp->lg_ports[i].lp_linkid = port->lp_linkid;
1945895Syz147064 bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL);
1955895Syz147064 attrp->lg_ports[i].lp_state = port->lp_state;
1965895Syz147064 attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state;
1975895Syz147064
1985895Syz147064 where = (port + 1);
1995895Syz147064 }
2005895Syz147064 *ptr = where;
2015895Syz147064 return (0);
2025895Syz147064 fail:
2035895Syz147064 return (-1);
2043871Syz147064 }
2053871Syz147064
2063871Syz147064 /*
2075895Syz147064 * Get active configuration of a specific aggregation.
2085895Syz147064 * Caller must free attrp->la_ports.
2093871Syz147064 */
2105895Syz147064 static dladm_status_t
i_dladm_aggr_info_active(dladm_handle_t handle,datalink_id_t linkid,dladm_aggr_grp_attr_t * attrp)2118453SAnurag.Maskey@Sun.COM i_dladm_aggr_info_active(dladm_handle_t handle, datalink_id_t linkid,
2128453SAnurag.Maskey@Sun.COM dladm_aggr_grp_attr_t *attrp)
2133871Syz147064 {
2143871Syz147064 laioc_info_t *ioc;
2157408SSebastien.Roy@Sun.COM int bufsize;
2165895Syz147064 void *where;
2175895Syz147064 dladm_status_t status = DLADM_STATUS_OK;
2183871Syz147064
2193871Syz147064 bufsize = MIN_INFO_SIZE;
2203871Syz147064 ioc = (laioc_info_t *)calloc(1, bufsize);
2215895Syz147064 if (ioc == NULL)
2225895Syz147064 return (DLADM_STATUS_NOMEM);
2235895Syz147064
2245895Syz147064 ioc->li_group_linkid = linkid;
2253871Syz147064
2263871Syz147064 tryagain:
2277408SSebastien.Roy@Sun.COM ioc->li_bufsize = bufsize;
2288453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_ioctl(handle, LAIOC_INFO, ioc) != 0) {
2293871Syz147064 if (errno == ENOSPC) {
2303871Syz147064 /*
2313871Syz147064 * The LAIOC_INFO call failed due to a short
2323871Syz147064 * buffer. Reallocate the buffer and try again.
2333871Syz147064 */
2343871Syz147064 bufsize *= 2;
2353871Syz147064 if (bufsize <= MAX_INFO_SIZE) {
2363871Syz147064 ioc = (laioc_info_t *)realloc(ioc, bufsize);
2373871Syz147064 if (ioc != NULL) {
2383871Syz147064 bzero(ioc, sizeof (bufsize));
2393871Syz147064 goto tryagain;
2403871Syz147064 }
2413871Syz147064 }
2423871Syz147064 }
2435895Syz147064 status = dladm_errno2status(errno);
2443871Syz147064 goto bail;
2453871Syz147064 }
2463871Syz147064
2473871Syz147064 /*
2483871Syz147064 * Go through each group returned by the aggregation driver.
2493871Syz147064 */
2503871Syz147064 where = (char *)(ioc + 1);
2515895Syz147064 if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) {
2525895Syz147064 status = dladm_errno2status(errno);
2535895Syz147064 goto bail;
2543871Syz147064 }
2553871Syz147064
2563871Syz147064 bail:
2573871Syz147064 free(ioc);
2583871Syz147064 return (status);
2593871Syz147064 }
2603871Syz147064
2613871Syz147064 /*
2625895Syz147064 * Get configuration information of a specific aggregation.
2635895Syz147064 * Caller must free attrp->la_ports.
2643871Syz147064 */
2653871Syz147064 static dladm_status_t
i_dladm_aggr_info_persist(dladm_handle_t handle,datalink_id_t linkid,dladm_aggr_grp_attr_t * attrp)2668453SAnurag.Maskey@Sun.COM i_dladm_aggr_info_persist(dladm_handle_t handle, datalink_id_t linkid,
2678453SAnurag.Maskey@Sun.COM dladm_aggr_grp_attr_t *attrp)
2683871Syz147064 {
2695895Syz147064 dladm_conf_t conf;
2705895Syz147064 uint32_t nports, i;
27110616SSebastien.Roy@Sun.COM char *portstr = NULL, *next;
2725895Syz147064 dladm_status_t status;
2735895Syz147064 uint64_t u64;
2745895Syz147064 int size;
2755895Syz147064 char macstr[ETHERADDRL * 3];
2765895Syz147064
2775895Syz147064 attrp->lg_linkid = linkid;
278*12824SCathy.Zhou@Sun.COM if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
2798453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK)
2805895Syz147064 return (status);
2815895Syz147064
2828453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64));
2835895Syz147064 if (status != DLADM_STATUS_OK)
2845895Syz147064 goto done;
2855895Syz147064 attrp->lg_key = (uint16_t)u64;
2865895Syz147064
2878453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FPOLICY, &u64,
2888453SAnurag.Maskey@Sun.COM sizeof (u64));
2895895Syz147064 if (status != DLADM_STATUS_OK)
2905895Syz147064 goto done;
2915895Syz147064 attrp->lg_policy = (uint32_t)u64;
2925895Syz147064
2938453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FFIXMACADDR,
2948453SAnurag.Maskey@Sun.COM &attrp->lg_mac_fixed, sizeof (boolean_t));
2955895Syz147064 if (status != DLADM_STATUS_OK)
2965895Syz147064 goto done;
2975895Syz147064
2985895Syz147064 if (attrp->lg_mac_fixed) {
2995895Syz147064 boolean_t fixed;
3003871Syz147064
3018453SAnurag.Maskey@Sun.COM if ((status = dladm_get_conf_field(handle, conf, FMACADDR,
3028453SAnurag.Maskey@Sun.COM macstr, sizeof (macstr))) != DLADM_STATUS_OK) {
3035895Syz147064 goto done;
3045895Syz147064 }
3055895Syz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) {
3065895Syz147064 status = DLADM_STATUS_REPOSITORYINVAL;
3075895Syz147064 goto done;
3085895Syz147064 }
3095895Syz147064 }
3105895Syz147064
3118453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FFORCE, &attrp->lg_force,
3125895Syz147064 sizeof (boolean_t));
3135895Syz147064 if (status != DLADM_STATUS_OK)
3145895Syz147064 goto done;
3155895Syz147064
3168453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64,
3178453SAnurag.Maskey@Sun.COM sizeof (u64));
3185895Syz147064 if (status != DLADM_STATUS_OK)
3195895Syz147064 goto done;
3205895Syz147064 attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64;
3215895Syz147064
3228453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64,
3238453SAnurag.Maskey@Sun.COM sizeof (u64));
3245895Syz147064 if (status != DLADM_STATUS_OK)
3255895Syz147064 goto done;
3265895Syz147064 attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64;
3275895Syz147064
3288453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FNPORTS, &u64,
3298453SAnurag.Maskey@Sun.COM sizeof (u64));
3305895Syz147064 if (status != DLADM_STATUS_OK)
3315895Syz147064 goto done;
3325895Syz147064 nports = (uint32_t)u64;
3335895Syz147064 attrp->lg_nports = nports;
3345895Syz147064
33510616SSebastien.Roy@Sun.COM size = nports * (MAXLINKNAMELEN + 1) + 1;
3365895Syz147064 if ((portstr = calloc(1, size)) == NULL) {
3375895Syz147064 status = DLADM_STATUS_NOMEM;
3385895Syz147064 goto done;
3395895Syz147064 }
3405895Syz147064
3418453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FPORTS, portstr, size);
34210616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK)
3435895Syz147064 goto done;
3445895Syz147064
3455895Syz147064 if ((attrp->lg_ports = malloc(nports *
3465895Syz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) {
3473871Syz147064 status = DLADM_STATUS_NOMEM;
3483871Syz147064 goto done;
3493871Syz147064 }
3503871Syz147064
3515895Syz147064 for (next = portstr, i = 0; i < nports; i++) {
35210616SSebastien.Roy@Sun.COM if ((status = read_port(handle, &next,
35310616SSebastien.Roy@Sun.COM &attrp->lg_ports[i].lp_linkid)) != DLADM_STATUS_OK)
3545895Syz147064 free(attrp->lg_ports);
3555895Syz147064 }
3565895Syz147064
3575895Syz147064 done:
35810616SSebastien.Roy@Sun.COM free(portstr);
3598453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
3605895Syz147064 return (status);
3615895Syz147064 }
3625895Syz147064
3635895Syz147064 dladm_status_t
dladm_aggr_info(dladm_handle_t handle,datalink_id_t linkid,dladm_aggr_grp_attr_t * attrp,uint32_t flags)3648453SAnurag.Maskey@Sun.COM dladm_aggr_info(dladm_handle_t handle, datalink_id_t linkid,
3658453SAnurag.Maskey@Sun.COM dladm_aggr_grp_attr_t *attrp, uint32_t flags)
3665895Syz147064 {
3675895Syz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST);
3685895Syz147064 if (flags == DLADM_OPT_ACTIVE)
3698453SAnurag.Maskey@Sun.COM return (i_dladm_aggr_info_active(handle, linkid, attrp));
3705895Syz147064 else
3718453SAnurag.Maskey@Sun.COM return (i_dladm_aggr_info_persist(handle, linkid, attrp));
3725895Syz147064 }
3733871Syz147064
3745895Syz147064 /*
3755895Syz147064 * Add or remove one or more ports to/from an existing link aggregation.
3765895Syz147064 */
3775895Syz147064 static dladm_status_t
i_dladm_aggr_add_rmv(dladm_handle_t handle,datalink_id_t linkid,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t flags,int cmd)3788453SAnurag.Maskey@Sun.COM i_dladm_aggr_add_rmv(dladm_handle_t handle, datalink_id_t linkid,
3798453SAnurag.Maskey@Sun.COM uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd)
3805895Syz147064 {
3815895Syz147064 char *orig_portstr = NULL, *portstr = NULL;
3826077Syz147064 laioc_add_rem_t *iocp = NULL;
3835895Syz147064 laioc_port_t *ioc_ports;
3845895Syz147064 uint32_t orig_nports, result_nports, len, i, j;
3855895Syz147064 dladm_conf_t conf;
3865895Syz147064 datalink_class_t class;
3875895Syz147064 dladm_status_t status = DLADM_STATUS_OK;
3885895Syz147064 int size;
3895895Syz147064 uint64_t u64;
3905895Syz147064 uint32_t media;
3915895Syz147064
3925895Syz147064 if (nports == 0)
3935895Syz147064 return (DLADM_STATUS_BADARG);
3945895Syz147064
3955895Syz147064 /*
3965895Syz147064 * Sanity check - aggregations can only be created over Ethernet
3979815SRishi.Srivatsavai@Sun.COM * physical links and simnets.
3985895Syz147064 */
3995895Syz147064 for (i = 0; i < nports; i++) {
4008453SAnurag.Maskey@Sun.COM if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL,
4015895Syz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) ||
4029815SRishi.Srivatsavai@Sun.COM !((class == DATALINK_CLASS_PHYS) ||
4039815SRishi.Srivatsavai@Sun.COM (class == DATALINK_CLASS_SIMNET)) || (media != DL_ETHER)) {
4045895Syz147064 return (DLADM_STATUS_BADARG);
4053871Syz147064 }
4063871Syz147064 }
4073871Syz147064
4085895Syz147064 /*
4095895Syz147064 * First, update the persistent configuration if requested. We only
4105895Syz147064 * need to update the FPORTS and FNPORTS fields of this aggregation.
4115895Syz147064 * Note that FPORTS is a list of port linkids separated by
41210616SSebastien.Roy@Sun.COM * PORT_DELIMITER (':').
4135895Syz147064 */
4145895Syz147064 if (flags & DLADM_OPT_PERSIST) {
415*12824SCathy.Zhou@Sun.COM status = dladm_open_conf(handle, linkid, &conf);
4165895Syz147064 if (status != DLADM_STATUS_OK)
4175895Syz147064 return (status);
4185895Syz147064
4195895Syz147064 /*
4205895Syz147064 * Get the original configuration of FNPORTS and FPORTS.
4215895Syz147064 */
4228453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FNPORTS, &u64,
4235895Syz147064 sizeof (u64));
4245895Syz147064 if (status != DLADM_STATUS_OK)
4255895Syz147064 goto destroyconf;
4265895Syz147064 orig_nports = (uint32_t)u64;
4275895Syz147064
4285895Syz147064 /*
4295895Syz147064 * At least one port needs to be in the aggregation.
4305895Syz147064 */
4315895Syz147064 if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) {
4325895Syz147064 status = DLADM_STATUS_BADARG;
4335895Syz147064 goto destroyconf;
4345895Syz147064 }
4355895Syz147064
43610616SSebastien.Roy@Sun.COM size = orig_nports * (MAXLINKNAMELEN + 1) + 1;
4375895Syz147064 if ((orig_portstr = calloc(1, size)) == NULL) {
4385895Syz147064 status = dladm_errno2status(errno);
4395895Syz147064 goto destroyconf;
4405895Syz147064 }
4415895Syz147064
4428453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FPORTS,
4438453SAnurag.Maskey@Sun.COM orig_portstr, size);
4445895Syz147064 if (status != DLADM_STATUS_OK)
4455895Syz147064 goto destroyconf;
4465895Syz147064
4475895Syz147064 result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports :
4485895Syz147064 orig_nports;
4495895Syz147064
45010616SSebastien.Roy@Sun.COM size = result_nports * (MAXLINKNAMELEN + 1) + 1;
4515895Syz147064 if ((portstr = calloc(1, size)) == NULL) {
4525895Syz147064 status = dladm_errno2status(errno);
4535895Syz147064 goto destroyconf;
4545895Syz147064 }
4555895Syz147064
4565895Syz147064 /*
4575895Syz147064 * get the new configuration and set to result_nports and
4585895Syz147064 * portstr.
4595895Syz147064 */
4605895Syz147064 if (cmd == LAIOC_ADD) {
4615895Syz147064 (void) strlcpy(portstr, orig_portstr, size);
46210616SSebastien.Roy@Sun.COM for (i = 0; i < nports; i++) {
46310616SSebastien.Roy@Sun.COM status = write_port(handle, portstr,
46410616SSebastien.Roy@Sun.COM ports[i].lp_linkid, size);
46510616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) {
46610616SSebastien.Roy@Sun.COM free(portstr);
46710616SSebastien.Roy@Sun.COM goto destroyconf;
46810616SSebastien.Roy@Sun.COM }
46910616SSebastien.Roy@Sun.COM }
4705895Syz147064 } else {
4715895Syz147064 char *next;
4725895Syz147064 datalink_id_t portid;
4735895Syz147064 uint32_t remove = 0;
4745895Syz147064
4755895Syz147064 for (next = orig_portstr, j = 0; j < orig_nports; j++) {
4765895Syz147064 /*
4775895Syz147064 * Read the portids from the old configuration
4785895Syz147064 * one by one.
4795895Syz147064 */
48010616SSebastien.Roy@Sun.COM status = read_port(handle, &next, &portid);
4815895Syz147064 if (status != DLADM_STATUS_OK) {
4825895Syz147064 free(portstr);
4835895Syz147064 goto destroyconf;
4845895Syz147064 }
4855895Syz147064
4865895Syz147064 /*
4875895Syz147064 * See whether this port is in the removal
4885895Syz147064 * list. If not, copy to the new config.
4895895Syz147064 */
4905895Syz147064 for (i = 0; i < nports; i++) {
4915895Syz147064 if (ports[i].lp_linkid == portid)
4925895Syz147064 break;
4935895Syz147064 }
4945895Syz147064 if (i == nports) {
49510616SSebastien.Roy@Sun.COM status = write_port(handle, portstr,
49610616SSebastien.Roy@Sun.COM portid, size);
49710616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) {
49810616SSebastien.Roy@Sun.COM free(portstr);
49910616SSebastien.Roy@Sun.COM goto destroyconf;
50010616SSebastien.Roy@Sun.COM }
5015895Syz147064 } else {
5025895Syz147064 remove++;
5035895Syz147064 }
5045895Syz147064 }
5055895Syz147064 if (remove != nports) {
5065895Syz147064 status = DLADM_STATUS_LINKINVAL;
5075895Syz147064 free(portstr);
5085895Syz147064 goto destroyconf;
5095895Syz147064 }
5105895Syz147064 result_nports -= nports;
5115895Syz147064 }
5125895Syz147064
5135895Syz147064 u64 = result_nports;
5148453SAnurag.Maskey@Sun.COM if ((status = dladm_set_conf_field(handle, conf, FNPORTS,
5155895Syz147064 DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) {
5165895Syz147064 free(portstr);
5175895Syz147064 goto destroyconf;
5185895Syz147064 }
5195895Syz147064
5208453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FPORTS,
5218453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, portstr);
5225895Syz147064 free(portstr);
5235895Syz147064 if (status != DLADM_STATUS_OK)
5245895Syz147064 goto destroyconf;
5255895Syz147064
5265895Syz147064 /*
5275895Syz147064 * Write the new configuration to the persistent repository.
5285895Syz147064 */
5298453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf);
5305895Syz147064
5315895Syz147064 destroyconf:
5328453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
5335895Syz147064 if (status != DLADM_STATUS_OK) {
5345895Syz147064 free(orig_portstr);
5355895Syz147064 return (status);
5365895Syz147064 }
5375895Syz147064 }
5385895Syz147064
5395895Syz147064 /*
5405895Syz147064 * If the caller only requested to update the persistent
5415895Syz147064 * configuration, we are done.
5425895Syz147064 */
5435895Syz147064 if (!(flags & DLADM_OPT_ACTIVE))
5445895Syz147064 goto done;
5455895Syz147064
5465895Syz147064 /*
5475895Syz147064 * Update the active configuration.
5485895Syz147064 */
5495895Syz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t);
5505895Syz147064 if ((iocp = malloc(len)) == NULL) {
5515895Syz147064 status = DLADM_STATUS_NOMEM;
5523871Syz147064 goto done;
5533871Syz147064 }
5543871Syz147064
5555895Syz147064 iocp->la_linkid = linkid;
5565895Syz147064 iocp->la_nports = nports;
5575895Syz147064 if (cmd == LAIOC_ADD)
5585895Syz147064 iocp->la_force = (flags & DLADM_OPT_FORCE);
5593871Syz147064
5605895Syz147064 ioc_ports = (laioc_port_t *)(iocp + 1);
5615895Syz147064 for (i = 0; i < nports; i++)
5625895Syz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid;
5635895Syz147064
5648453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_ioctl(handle, cmd, iocp) < 0)
5655895Syz147064 status = dladm_errno2status(errno);
5663871Syz147064
5673871Syz147064 done:
5683871Syz147064 free(iocp);
5695895Syz147064
5705895Syz147064 /*
5715895Syz147064 * If the active configuration update fails, restore the old
5725895Syz147064 * persistent configuration if we've changed that.
5735895Syz147064 */
5745895Syz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) {
575*12824SCathy.Zhou@Sun.COM if (dladm_open_conf(handle, linkid, &conf) == DLADM_STATUS_OK) {
5765895Syz147064 u64 = orig_nports;
5778453SAnurag.Maskey@Sun.COM if ((dladm_set_conf_field(handle, conf, FNPORTS,
5785895Syz147064 DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) &&
5798453SAnurag.Maskey@Sun.COM (dladm_set_conf_field(handle, conf, FPORTS,
5808453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, orig_portstr) == DLADM_STATUS_OK)) {
5818453SAnurag.Maskey@Sun.COM (void) dladm_write_conf(handle, conf);
5825895Syz147064 }
5838453SAnurag.Maskey@Sun.COM (void) dladm_destroy_conf(handle, conf);
5845895Syz147064 }
5855895Syz147064 }
5865895Syz147064 free(orig_portstr);
5873871Syz147064 return (status);
5883871Syz147064 }
5893871Syz147064
5903871Syz147064 /*
5913871Syz147064 * Send a modify command to the link aggregation driver.
5923871Syz147064 */
5933871Syz147064 static dladm_status_t
i_dladm_aggr_modify_sys(dladm_handle_t handle,datalink_id_t linkid,uint32_t mask,dladm_aggr_modify_attr_t * attr)5948453SAnurag.Maskey@Sun.COM i_dladm_aggr_modify_sys(dladm_handle_t handle, datalink_id_t linkid,
5958453SAnurag.Maskey@Sun.COM uint32_t mask, dladm_aggr_modify_attr_t *attr)
5963871Syz147064 {
5973871Syz147064 laioc_modify_t ioc;
5983871Syz147064
5995895Syz147064 ioc.lu_linkid = linkid;
6003871Syz147064
6013871Syz147064 ioc.lu_modify_mask = 0;
6023871Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY)
6033871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_POLICY;
6043871Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC)
6053871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_MAC;
6063871Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE)
6073871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_MODE;
6083871Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER)
6093871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_TIMER;
6103871Syz147064
6113871Syz147064 ioc.lu_policy = attr->ld_policy;
6123871Syz147064 ioc.lu_mac_fixed = attr->ld_mac_fixed;
6133871Syz147064 bcopy(attr->ld_mac, ioc.lu_mac, ETHERADDRL);
6143871Syz147064 ioc.lu_lacp_mode = attr->ld_lacp_mode;
6153871Syz147064 ioc.lu_lacp_timer = attr->ld_lacp_timer;
6163871Syz147064
6178453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_ioctl(handle, LAIOC_MODIFY, &ioc) < 0) {
6183871Syz147064 if (errno == EINVAL)
6195895Syz147064 return (DLADM_STATUS_MACADDRINVAL);
6203871Syz147064 else
6215895Syz147064 return (dladm_errno2status(errno));
6225895Syz147064 } else {
6235895Syz147064 return (DLADM_STATUS_OK);
6243871Syz147064 }
6253871Syz147064 }
6263871Syz147064
6273871Syz147064 /*
6283871Syz147064 * Send a create command to the link aggregation driver.
6293871Syz147064 */
6303871Syz147064 static dladm_status_t
i_dladm_aggr_create_sys(dladm_handle_t handle,datalink_id_t linkid,uint16_t key,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t policy,boolean_t mac_addr_fixed,const uchar_t * mac_addr,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer,boolean_t force)6318453SAnurag.Maskey@Sun.COM i_dladm_aggr_create_sys(dladm_handle_t handle, datalink_id_t linkid,
6328453SAnurag.Maskey@Sun.COM uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports,
6338453SAnurag.Maskey@Sun.COM uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr,
6345895Syz147064 aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force)
6353871Syz147064 {
6367408SSebastien.Roy@Sun.COM int i, len;
6375895Syz147064 laioc_create_t *iocp = NULL;
6385895Syz147064 laioc_port_t *ioc_ports;
6393871Syz147064 dladm_status_t status = DLADM_STATUS_OK;
6403871Syz147064
6415895Syz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t);
6423871Syz147064 iocp = malloc(len);
6433871Syz147064 if (iocp == NULL)
6443871Syz147064 return (DLADM_STATUS_NOMEM);
6453871Syz147064
6465895Syz147064 iocp->lc_key = key;
6475895Syz147064 iocp->lc_linkid = linkid;
6485895Syz147064 iocp->lc_nports = nports;
6495895Syz147064 iocp->lc_policy = policy;
6505895Syz147064 iocp->lc_lacp_mode = lacp_mode;
6515895Syz147064 iocp->lc_lacp_timer = lacp_timer;
6525895Syz147064 ioc_ports = (laioc_port_t *)(iocp + 1);
6535895Syz147064 iocp->lc_force = force;
6543871Syz147064
6555895Syz147064 for (i = 0; i < nports; i++)
6565895Syz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid;
6575895Syz147064
6585895Syz147064 if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) {
6595895Syz147064 status = DLADM_STATUS_MACADDRINVAL;
6605895Syz147064 goto done;
6613871Syz147064 }
6623871Syz147064
6635895Syz147064 bcopy(mac_addr, iocp->lc_mac, ETHERADDRL);
6645895Syz147064 iocp->lc_mac_fixed = mac_addr_fixed;
6653871Syz147064
6668453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_ioctl(handle, LAIOC_CREATE, iocp) < 0)
6675895Syz147064 status = dladm_errno2status(errno);
6683871Syz147064
6695895Syz147064 done:
6703871Syz147064 free(iocp);
6713871Syz147064 return (status);
6723871Syz147064 }
6733871Syz147064
6743871Syz147064 /*
6753871Syz147064 * Invoked to bring up a link aggregation group.
6763871Syz147064 */
6775895Syz147064 static int
i_dladm_aggr_up(dladm_handle_t handle,datalink_id_t linkid,void * arg)6788453SAnurag.Maskey@Sun.COM i_dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
6793871Syz147064 {
6805895Syz147064 dladm_status_t *statusp = (dladm_status_t *)arg;
6815895Syz147064 dladm_aggr_grp_attr_t attr;
6825895Syz147064 dladm_aggr_port_attr_db_t *ports = NULL;
6835895Syz147064 uint16_t key = 0;
6845895Syz147064 int i, j;
6853871Syz147064 dladm_status_t status;
6863871Syz147064
6878453SAnurag.Maskey@Sun.COM status = dladm_aggr_info(handle, linkid, &attr, DLADM_OPT_PERSIST);
6885895Syz147064 if (status != DLADM_STATUS_OK) {
6895895Syz147064 *statusp = status;
6905895Syz147064 return (DLADM_WALK_CONTINUE);
6915895Syz147064 }
6923871Syz147064
6935895Syz147064 if (attr.lg_key <= AGGR_MAX_KEY)
6945895Syz147064 key = attr.lg_key;
6955895Syz147064
6965895Syz147064 ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t));
6975895Syz147064 if (ports == NULL) {
6985895Syz147064 status = DLADM_STATUS_NOMEM;
6995895Syz147064 goto done;
7003871Syz147064 }
7013871Syz147064
7023871Syz147064 /*
7035895Syz147064 * Validate (and purge) each physical link associated with this
7045895Syz147064 * aggregation, if the specific hardware has been removed during
7055895Syz147064 * the system shutdown.
7063871Syz147064 */
7075895Syz147064 for (i = 0, j = 0; i < attr.lg_nports; i++) {
7085895Syz147064 datalink_id_t portid = attr.lg_ports[i].lp_linkid;
7095895Syz147064 uint32_t flags;
7105895Syz147064 dladm_status_t s;
7113871Syz147064
7128453SAnurag.Maskey@Sun.COM s = dladm_datalink_id2info(handle, portid, &flags, NULL, NULL,
7138453SAnurag.Maskey@Sun.COM NULL, 0);
7145895Syz147064 if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE))
7155895Syz147064 continue;
7165895Syz147064
7175895Syz147064 ports[j++].lp_linkid = portid;
7185895Syz147064 }
7193871Syz147064
7205895Syz147064 if (j == 0) {
7215895Syz147064 /*
7225895Syz147064 * All of the physical links are removed.
7235895Syz147064 */
7245895Syz147064 status = DLADM_STATUS_BADARG;
7255895Syz147064 goto done;
7263871Syz147064 }
7273871Syz147064
7285895Syz147064 /*
7295895Syz147064 * Create active aggregation.
7305895Syz147064 */
7318453SAnurag.Maskey@Sun.COM if ((status = i_dladm_aggr_create_sys(handle, linkid,
7325895Syz147064 key, j, ports, attr.lg_policy, attr.lg_mac_fixed,
7335895Syz147064 (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode,
7345895Syz147064 attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) {
7355895Syz147064 goto done;
7365895Syz147064 }
7373871Syz147064
7388453SAnurag.Maskey@Sun.COM if ((status = dladm_up_datalink_id(handle, linkid)) !=
7398453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) {
7405895Syz147064 laioc_delete_t ioc;
74110616SSebastien.Roy@Sun.COM
7425895Syz147064 ioc.ld_linkid = linkid;
7438453SAnurag.Maskey@Sun.COM (void) i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc);
7445895Syz147064 }
7455895Syz147064 done:
7465895Syz147064 free(attr.lg_ports);
7475895Syz147064 free(ports);
7485895Syz147064
7495895Syz147064 *statusp = status;
7505895Syz147064 return (DLADM_WALK_CONTINUE);
7513871Syz147064 }
7523871Syz147064
7533871Syz147064 /*
7545895Syz147064 * Bring up one aggregation, or all persistent aggregations. In the latter
7555895Syz147064 * case, the walk may terminate early if bringup of an aggregation fails.
7563871Syz147064 */
7575895Syz147064 dladm_status_t
dladm_aggr_up(dladm_handle_t handle,datalink_id_t linkid)7588453SAnurag.Maskey@Sun.COM dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid)
7593871Syz147064 {
7603871Syz147064 dladm_status_t status;
7613871Syz147064
7625895Syz147064 if (linkid == DATALINK_ALL_LINKID) {
7638453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_aggr_up, handle, &status,
7645895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
7655895Syz147064 DLADM_OPT_PERSIST);
7665895Syz147064 return (DLADM_STATUS_OK);
7675895Syz147064 } else {
7688453SAnurag.Maskey@Sun.COM (void) i_dladm_aggr_up(handle, linkid, &status);
7693871Syz147064 return (status);
7703871Syz147064 }
7713871Syz147064 }
7723871Syz147064
7733871Syz147064 /*
7743871Syz147064 * Given a policy string, return a policy mask. Returns B_TRUE on
7755895Syz147064 * success, or B_FALSE if an error occurred during parsing.
7763871Syz147064 */
7773871Syz147064 boolean_t
dladm_aggr_str2policy(const char * str,uint32_t * policy)7783871Syz147064 dladm_aggr_str2policy(const char *str, uint32_t *policy)
7793871Syz147064 {
7803871Syz147064 int i;
7813871Syz147064 policy_t *pol;
7823871Syz147064 char *token = NULL;
7833871Syz147064 char *lasts;
7843871Syz147064
7853871Syz147064 *policy = 0;
7863871Syz147064
7873871Syz147064 while ((token = strtok_r((token == NULL) ? (char *)str : NULL, ",",
7883871Syz147064 &lasts)) != NULL) {
7893871Syz147064 for (i = 0; i < NPOLICIES; i++) {
7903871Syz147064 pol = &policies[i];
7913871Syz147064 if (strcasecmp(token, pol->pol_name) == 0) {
7923871Syz147064 *policy |= pol->policy;
7933871Syz147064 break;
7943871Syz147064 }
7953871Syz147064 }
7963871Syz147064 if (i == NPOLICIES)
7973871Syz147064 return (B_FALSE);
7983871Syz147064 }
7993871Syz147064
8003871Syz147064 return (B_TRUE);
8013871Syz147064 }
8023871Syz147064
8033871Syz147064 /*
8043871Syz147064 * Given a policy mask, returns a printable string, or NULL if the
8053871Syz147064 * policy mask is invalid. It is the responsibility of the caller to
8063871Syz147064 * free the returned string after use.
8073871Syz147064 */
8083871Syz147064 char *
dladm_aggr_policy2str(uint32_t policy,char * str)8093871Syz147064 dladm_aggr_policy2str(uint32_t policy, char *str)
8103871Syz147064 {
8113871Syz147064 int i, npolicies = 0;
8123871Syz147064 policy_t *pol;
8133871Syz147064
8145895Syz147064 if (str == NULL)
8155895Syz147064 return (NULL);
8165895Syz147064
8173871Syz147064 str[0] = '\0';
8183871Syz147064
8193871Syz147064 for (i = 0; i < NPOLICIES; i++) {
8203871Syz147064 pol = &policies[i];
8213871Syz147064 if ((policy & pol->policy) != 0) {
8223871Syz147064 npolicies++;
8233871Syz147064 if (npolicies > 1)
8245895Syz147064 (void) strlcat(str, ",", DLADM_STRSIZE);
8255895Syz147064 (void) strlcat(str, pol->pol_name, DLADM_STRSIZE);
8263871Syz147064 }
8273871Syz147064 }
8283871Syz147064
8293871Syz147064 return (str);
8303871Syz147064 }
8313871Syz147064
8323871Syz147064 /*
8333871Syz147064 * Given a MAC address string, return the MAC address in the mac_addr
8343871Syz147064 * array. If the MAC address was not explicitly specified, i.e. is
8353871Syz147064 * equal to 'auto', zero out mac-addr and set mac_fixed to B_TRUE.
8363871Syz147064 * Return B_FALSE if a syntax error was encountered, B_FALSE otherwise.
8373871Syz147064 */
8383871Syz147064 boolean_t
dladm_aggr_str2macaddr(const char * str,boolean_t * mac_fixed,uchar_t * mac_addr)8393871Syz147064 dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr)
8403871Syz147064 {
8413871Syz147064 uchar_t *conv_str;
8423871Syz147064 int mac_len;
8433871Syz147064
8443871Syz147064 *mac_fixed = (strcmp(str, "auto") != 0);
8453871Syz147064 if (!*mac_fixed) {
8463871Syz147064 bzero(mac_addr, ETHERADDRL);
8473871Syz147064 return (B_TRUE);
8483871Syz147064 }
8493871Syz147064
8503871Syz147064 conv_str = _link_aton(str, &mac_len);
8513871Syz147064 if (conv_str == NULL)
8523871Syz147064 return (B_FALSE);
8533871Syz147064
8543871Syz147064 if (mac_len != ETHERADDRL) {
8553871Syz147064 free(conv_str);
8563871Syz147064 return (B_FALSE);
8573871Syz147064 }
8583871Syz147064
8593871Syz147064 if ((bcmp(zero_mac, conv_str, ETHERADDRL) == 0) ||
8603871Syz147064 (conv_str[0] & 0x01)) {
8613871Syz147064 free(conv_str);
8623871Syz147064 return (B_FALSE);
8633871Syz147064 }
8643871Syz147064
8653871Syz147064 bcopy(conv_str, mac_addr, ETHERADDRL);
8663871Syz147064 free(conv_str);
8673871Syz147064
8683871Syz147064 return (B_TRUE);
8693871Syz147064 }
8703871Syz147064
8713871Syz147064 /*
8723871Syz147064 * Returns a string containing a printable representation of a MAC address.
8733871Syz147064 */
8743871Syz147064 const char *
dladm_aggr_macaddr2str(const unsigned char * mac,char * buf)8755895Syz147064 dladm_aggr_macaddr2str(const unsigned char *mac, char *buf)
8763871Syz147064 {
8773871Syz147064 static char unknown_mac[] = {0, 0, 0, 0, 0, 0};
8783871Syz147064
8793871Syz147064 if (buf == NULL)
8803871Syz147064 return (NULL);
8813871Syz147064
8823871Syz147064 if (bcmp(unknown_mac, mac, ETHERADDRL) == 0)
8835895Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
8843871Syz147064 else
8853871Syz147064 return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER));
8865895Syz147064
8875895Syz147064 return (buf);
8883871Syz147064 }
8893871Syz147064
8903871Syz147064 /*
8913871Syz147064 * Given a LACP mode string, find the corresponding LACP mode number. Returns
8923871Syz147064 * B_TRUE if a match was found, B_FALSE otherwise.
8933871Syz147064 */
8943871Syz147064 boolean_t
dladm_aggr_str2lacpmode(const char * str,aggr_lacp_mode_t * lacp_mode)8953871Syz147064 dladm_aggr_str2lacpmode(const char *str, aggr_lacp_mode_t *lacp_mode)
8963871Syz147064 {
8973871Syz147064 int i;
8983871Syz147064 dladm_aggr_lacpmode_t *mode;
8993871Syz147064
9003871Syz147064 for (i = 0; i < NLACP_MODES; i++) {
9013871Syz147064 mode = &lacp_modes[i];
9023871Syz147064 if (strncasecmp(str, mode->mode_str,
9033871Syz147064 strlen(mode->mode_str)) == 0) {
9043871Syz147064 *lacp_mode = mode->mode_id;
9053871Syz147064 return (B_TRUE);
9063871Syz147064 }
9073871Syz147064 }
9083871Syz147064
9093871Syz147064 return (B_FALSE);
9103871Syz147064 }
9113871Syz147064
9123871Syz147064 /*
9133871Syz147064 * Given a LACP mode number, returns a printable string, or NULL if the
9143871Syz147064 * LACP mode number is invalid.
9153871Syz147064 */
9163871Syz147064 const char *
dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id,char * buf)9173871Syz147064 dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf)
9183871Syz147064 {
9193871Syz147064 int i;
9203871Syz147064 dladm_aggr_lacpmode_t *mode;
9213871Syz147064
9225895Syz147064 if (buf == NULL)
9235895Syz147064 return (NULL);
9245895Syz147064
9253871Syz147064 for (i = 0; i < NLACP_MODES; i++) {
9263871Syz147064 mode = &lacp_modes[i];
9273871Syz147064 if (mode->mode_id == mode_id) {
9283871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s",
9293871Syz147064 mode->mode_str);
9303871Syz147064 return (buf);
9313871Syz147064 }
9323871Syz147064 }
9333871Syz147064
9343871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
9353871Syz147064 return (buf);
9363871Syz147064 }
9373871Syz147064
9383871Syz147064 /*
9393871Syz147064 * Given a LACP timer string, find the corresponding LACP timer number. Returns
9403871Syz147064 * B_TRUE if a match was found, B_FALSE otherwise.
9413871Syz147064 */
9423871Syz147064 boolean_t
dladm_aggr_str2lacptimer(const char * str,aggr_lacp_timer_t * lacp_timer)9433871Syz147064 dladm_aggr_str2lacptimer(const char *str, aggr_lacp_timer_t *lacp_timer)
9443871Syz147064 {
9453871Syz147064 int i;
9463871Syz147064 dladm_aggr_lacptimer_t *timer;
9473871Syz147064
9483871Syz147064 for (i = 0; i < NLACP_TIMERS; i++) {
9493871Syz147064 timer = &lacp_timers[i];
9503871Syz147064 if (strncasecmp(str, timer->lt_str,
9513871Syz147064 strlen(timer->lt_str)) == 0) {
9523871Syz147064 *lacp_timer = timer->lt_id;
9533871Syz147064 return (B_TRUE);
9543871Syz147064 }
9553871Syz147064 }
9563871Syz147064
9573871Syz147064 return (B_FALSE);
9583871Syz147064 }
9593871Syz147064
9603871Syz147064 /*
9613871Syz147064 * Given a LACP timer, returns a printable string, or NULL if the
9623871Syz147064 * LACP timer number is invalid.
9633871Syz147064 */
9643871Syz147064 const char *
dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id,char * buf)9653871Syz147064 dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf)
9663871Syz147064 {
9673871Syz147064 int i;
9683871Syz147064 dladm_aggr_lacptimer_t *timer;
9693871Syz147064
9705895Syz147064 if (buf == NULL)
9715895Syz147064 return (NULL);
9725895Syz147064
9733871Syz147064 for (i = 0; i < NLACP_TIMERS; i++) {
9743871Syz147064 timer = &lacp_timers[i];
9753871Syz147064 if (timer->lt_id == timer_id) {
9763871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s",
9773871Syz147064 timer->lt_str);
9783871Syz147064 return (buf);
9793871Syz147064 }
9803871Syz147064 }
9813871Syz147064
9823871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
9833871Syz147064 return (buf);
9843871Syz147064 }
9853871Syz147064
9863871Syz147064 const char *
dladm_aggr_portstate2str(aggr_port_state_t state_id,char * buf)9873871Syz147064 dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf)
9883871Syz147064 {
9893871Syz147064 int i;
9905895Syz147064 dladm_aggr_port_state_t *state;
9915895Syz147064
9925895Syz147064 if (buf == NULL)
9935895Syz147064 return (NULL);
9943871Syz147064
9953871Syz147064 for (i = 0; i < NPORT_STATES; i++) {
9963871Syz147064 state = &port_states[i];
9973871Syz147064 if (state->state_id == state_id) {
9983871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s",
9993871Syz147064 state->state_str);
10003871Syz147064 return (buf);
10013871Syz147064 }
10023871Syz147064 }
10033871Syz147064
10043871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE);
10053871Syz147064 return (buf);
10063871Syz147064 }
10073871Syz147064
10085895Syz147064 static dladm_status_t
dladm_aggr_persist_aggr_conf(dladm_handle_t handle,const char * link,datalink_id_t linkid,uint16_t key,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t policy,boolean_t mac_addr_fixed,const uchar_t * mac_addr,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer,boolean_t force)10098453SAnurag.Maskey@Sun.COM dladm_aggr_persist_aggr_conf(dladm_handle_t handle, const char *link,
10108453SAnurag.Maskey@Sun.COM datalink_id_t linkid, uint16_t key, uint32_t nports,
10118453SAnurag.Maskey@Sun.COM dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed,
10128453SAnurag.Maskey@Sun.COM const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode,
10138453SAnurag.Maskey@Sun.COM aggr_lacp_timer_t lacp_timer, boolean_t force)
10143871Syz147064 {
1015*12824SCathy.Zhou@Sun.COM dladm_conf_t conf;
10165895Syz147064 char *portstr = NULL;
10175895Syz147064 char macstr[ETHERADDRL * 3];
10185895Syz147064 dladm_status_t status;
10195895Syz147064 int i, size;
10205895Syz147064 uint64_t u64;
10213871Syz147064
10228453SAnurag.Maskey@Sun.COM if ((status = dladm_create_conf(handle, link, linkid,
10238453SAnurag.Maskey@Sun.COM DATALINK_CLASS_AGGR, DL_ETHER, &conf)) != DLADM_STATUS_OK) {
10243871Syz147064 return (status);
10253871Syz147064 }
10263871Syz147064
10275895Syz147064 u64 = key;
10288453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FKEY, DLADM_TYPE_UINT64,
10298453SAnurag.Maskey@Sun.COM &u64);
10305895Syz147064 if (status != DLADM_STATUS_OK)
10315895Syz147064 goto done;
10323871Syz147064
10335895Syz147064 u64 = nports;
10348453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FNPORTS, DLADM_TYPE_UINT64,
10358453SAnurag.Maskey@Sun.COM &u64);
10365895Syz147064 if (status != DLADM_STATUS_OK)
10375895Syz147064 goto done;
10385895Syz147064
103910616SSebastien.Roy@Sun.COM size = nports * MAXLINKNAMELEN + 1;
10405895Syz147064 if ((portstr = calloc(1, size)) == NULL) {
10415895Syz147064 status = DLADM_STATUS_NOMEM;
10425895Syz147064 goto done;
10435895Syz147064 }
10443871Syz147064
104510616SSebastien.Roy@Sun.COM for (i = 0; i < nports; i++) {
104610616SSebastien.Roy@Sun.COM status = write_port(handle, portstr, ports[i].lp_linkid, size);
104710616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) {
104810616SSebastien.Roy@Sun.COM free(portstr);
104910616SSebastien.Roy@Sun.COM goto done;
105010616SSebastien.Roy@Sun.COM }
105110616SSebastien.Roy@Sun.COM }
10528453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FPORTS, DLADM_TYPE_STR,
10538453SAnurag.Maskey@Sun.COM portstr);
10545895Syz147064 free(portstr);
10555895Syz147064
10565895Syz147064 if (status != DLADM_STATUS_OK)
10575895Syz147064 goto done;
10583871Syz147064
10595895Syz147064 u64 = policy;
10608453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FPOLICY, DLADM_TYPE_UINT64,
10618453SAnurag.Maskey@Sun.COM &u64);
10625895Syz147064 if (status != DLADM_STATUS_OK)
10635895Syz147064 goto done;
10645895Syz147064
10658453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FFIXMACADDR,
10668453SAnurag.Maskey@Sun.COM DLADM_TYPE_BOOLEAN, &mac_addr_fixed);
10675895Syz147064 if (status != DLADM_STATUS_OK)
10685895Syz147064 goto done;
10695895Syz147064
10705895Syz147064 if (mac_addr_fixed) {
10715895Syz147064 if (!VALID_PORT_MAC(mac_addr)) {
10725895Syz147064 status = DLADM_STATUS_MACADDRINVAL;
10733871Syz147064 goto done;
10743871Syz147064 }
10753871Syz147064
10765895Syz147064 (void) dladm_aggr_macaddr2str(mac_addr, macstr);
10778453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMACADDR,
10788453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, macstr);
10795895Syz147064 if (status != DLADM_STATUS_OK)
10803871Syz147064 goto done;
10813871Syz147064 }
10823871Syz147064
10838453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FFORCE, DLADM_TYPE_BOOLEAN,
10848453SAnurag.Maskey@Sun.COM &force);
10855895Syz147064 if (status != DLADM_STATUS_OK)
10865895Syz147064 goto done;
10875895Syz147064
10885895Syz147064 u64 = lacp_mode;
10898453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLACPMODE,
10908453SAnurag.Maskey@Sun.COM DLADM_TYPE_UINT64, &u64);
10915895Syz147064 if (status != DLADM_STATUS_OK)
10925895Syz147064 goto done;
10935895Syz147064
10945895Syz147064 u64 = lacp_timer;
10958453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLACPTIMER,
10968453SAnurag.Maskey@Sun.COM DLADM_TYPE_UINT64, &u64);
10975895Syz147064 if (status != DLADM_STATUS_OK)
10985895Syz147064 goto done;
10995895Syz147064
11003871Syz147064 /*
11015895Syz147064 * Commit the link aggregation configuration.
11023871Syz147064 */
11038453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf);
11043871Syz147064
11053871Syz147064 done:
11068453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
11073871Syz147064 return (status);
11083871Syz147064 }
11093871Syz147064
11103871Syz147064 /*
11113871Syz147064 * Create a new link aggregation group. Update the configuration
11123871Syz147064 * file and bring it up.
11133871Syz147064 */
11143871Syz147064 dladm_status_t
dladm_aggr_create(dladm_handle_t handle,const char * name,uint16_t key,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t policy,boolean_t mac_addr_fixed,const uchar_t * mac_addr,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer,uint32_t flags)11158453SAnurag.Maskey@Sun.COM dladm_aggr_create(dladm_handle_t handle, const char *name, uint16_t key,
11168453SAnurag.Maskey@Sun.COM uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t policy,
11178453SAnurag.Maskey@Sun.COM boolean_t mac_addr_fixed, const uchar_t *mac_addr,
11188453SAnurag.Maskey@Sun.COM aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, uint32_t flags)
11193871Syz147064 {
11205895Syz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID;
11215895Syz147064 uint32_t media;
11225895Syz147064 uint32_t i;
11235895Syz147064 datalink_class_t class;
11243871Syz147064 dladm_status_t status;
11255895Syz147064 boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE;
11263871Syz147064
11275895Syz147064 if (key != 0 && key > AGGR_MAX_KEY)
11283871Syz147064 return (DLADM_STATUS_KEYINVAL);
11293871Syz147064
11305895Syz147064 if (nports == 0)
11315895Syz147064 return (DLADM_STATUS_BADARG);
11325895Syz147064
11335895Syz147064 for (i = 0; i < nports; i++) {
11348453SAnurag.Maskey@Sun.COM if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL,
11355895Syz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) ||
11369815SRishi.Srivatsavai@Sun.COM !((class == DATALINK_CLASS_PHYS || class ==
11379815SRishi.Srivatsavai@Sun.COM DATALINK_CLASS_SIMNET) && (media == DL_ETHER))) {
11385895Syz147064 return (DLADM_STATUS_BADARG);
11395895Syz147064 }
11405895Syz147064 }
11415895Syz147064
11425895Syz147064 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
11438453SAnurag.Maskey@Sun.COM if ((status = dladm_create_datalink_id(handle, name,
11448453SAnurag.Maskey@Sun.COM DATALINK_CLASS_AGGR, DL_ETHER, flags, &linkid)) !=
11458453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) {
11465895Syz147064 goto fail;
11475895Syz147064 }
11485895Syz147064
11495895Syz147064 if ((flags & DLADM_OPT_PERSIST) &&
11508453SAnurag.Maskey@Sun.COM (status = dladm_aggr_persist_aggr_conf(handle, name, linkid, key,
11518453SAnurag.Maskey@Sun.COM nports, ports, policy, mac_addr_fixed, mac_addr, lacp_mode,
11528453SAnurag.Maskey@Sun.COM lacp_timer, force)) != DLADM_STATUS_OK) {
11535895Syz147064 goto fail;
11545895Syz147064 }
11555895Syz147064
11565895Syz147064 if (!(flags & DLADM_OPT_ACTIVE))
11575895Syz147064 return (DLADM_STATUS_OK);
11585895Syz147064
11598453SAnurag.Maskey@Sun.COM status = i_dladm_aggr_create_sys(handle, linkid, key, nports, ports,
11608453SAnurag.Maskey@Sun.COM policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force);
11613871Syz147064
11625895Syz147064 if (status != DLADM_STATUS_OK) {
11635895Syz147064 if (flags & DLADM_OPT_PERSIST)
11648453SAnurag.Maskey@Sun.COM (void) dladm_remove_conf(handle, linkid);
11655895Syz147064 goto fail;
11665895Syz147064 }
11675895Syz147064
11685895Syz147064 return (DLADM_STATUS_OK);
11695895Syz147064
11705895Syz147064 fail:
11715895Syz147064 if (linkid != DATALINK_INVALID_LINKID)
11728453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, flags);
11735895Syz147064
11745895Syz147064 return (status);
11755895Syz147064 }
11765895Syz147064
11775895Syz147064 static dladm_status_t
i_dladm_aggr_get_aggr_attr(dladm_handle_t handle,dladm_conf_t conf,uint32_t mask,dladm_aggr_modify_attr_t * attrp)11788453SAnurag.Maskey@Sun.COM i_dladm_aggr_get_aggr_attr(dladm_handle_t handle, dladm_conf_t conf,
11798453SAnurag.Maskey@Sun.COM uint32_t mask, dladm_aggr_modify_attr_t *attrp)
11805895Syz147064 {
11815895Syz147064 dladm_status_t status = DLADM_STATUS_OK;
11825895Syz147064 char macstr[ETHERADDRL * 3];
11835895Syz147064 uint64_t u64;
11845895Syz147064
11855895Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) {
11868453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FPOLICY, &u64,
11875895Syz147064 sizeof (u64));
11885895Syz147064 if (status != DLADM_STATUS_OK)
11895895Syz147064 return (status);
11905895Syz147064 attrp->ld_policy = (uint32_t)u64;
11915895Syz147064 }
11925895Syz147064
11935895Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC) {
11948453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FFIXMACADDR,
11955895Syz147064 &attrp->ld_mac_fixed, sizeof (boolean_t));
11963871Syz147064 if (status != DLADM_STATUS_OK)
11973871Syz147064 return (status);
11985895Syz147064
11995895Syz147064 if (attrp->ld_mac_fixed) {
12005895Syz147064 boolean_t fixed;
12015895Syz147064
12028453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMACADDR,
12035895Syz147064 macstr, sizeof (macstr));
12045895Syz147064 if (status != DLADM_STATUS_OK)
12055895Syz147064 return (status);
12063871Syz147064
12075895Syz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed,
12085895Syz147064 attrp->ld_mac)) {
12095895Syz147064 return (DLADM_STATUS_REPOSITORYINVAL);
12105895Syz147064 }
12115895Syz147064 }
12125895Syz147064 }
12133871Syz147064
12145895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) {
12158453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64,
12165895Syz147064 sizeof (u64));
12175895Syz147064 if (status != DLADM_STATUS_OK)
12185895Syz147064 return (status);
12195895Syz147064 attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64;
12205895Syz147064 }
12215895Syz147064
12225895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) {
12238453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64,
12245895Syz147064 sizeof (u64));
12255895Syz147064 if (status != DLADM_STATUS_OK)
12265895Syz147064 return (status);
12275895Syz147064 attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64;
12283871Syz147064 }
12293871Syz147064
12305895Syz147064 return (status);
12315895Syz147064 }
12325895Syz147064
12335895Syz147064 static dladm_status_t
i_dladm_aggr_set_aggr_attr(dladm_handle_t handle,dladm_conf_t conf,uint32_t mask,dladm_aggr_modify_attr_t * attrp)12348453SAnurag.Maskey@Sun.COM i_dladm_aggr_set_aggr_attr(dladm_handle_t handle, dladm_conf_t conf,
12358453SAnurag.Maskey@Sun.COM uint32_t mask, dladm_aggr_modify_attr_t *attrp)
12365895Syz147064 {
12375895Syz147064 dladm_status_t status = DLADM_STATUS_OK;
12385895Syz147064 char macstr[ETHERADDRL * 3];
12395895Syz147064 uint64_t u64;
12405895Syz147064
12415895Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) {
12425895Syz147064 u64 = attrp->ld_policy;
12438453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FPOLICY,
12448453SAnurag.Maskey@Sun.COM DLADM_TYPE_UINT64, &u64);
12455895Syz147064 if (status != DLADM_STATUS_OK)
12465895Syz147064 return (status);
12475895Syz147064 }
12485895Syz147064
12495895Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC) {
12508453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FFIXMACADDR,
12515895Syz147064 DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed);
12525895Syz147064 if (status != DLADM_STATUS_OK)
12535895Syz147064 return (status);
12543871Syz147064
12555895Syz147064 if (attrp->ld_mac_fixed) {
12565895Syz147064 (void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr);
12578453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMACADDR,
12585895Syz147064 DLADM_TYPE_STR, macstr);
12595895Syz147064 if (status != DLADM_STATUS_OK)
12605895Syz147064 return (status);
12615895Syz147064 }
12625895Syz147064 }
12635895Syz147064
12645895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) {
12655895Syz147064 u64 = attrp->ld_lacp_mode;
12668453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLACPMODE,
12675895Syz147064 DLADM_TYPE_UINT64, &u64);
12685895Syz147064 if (status != DLADM_STATUS_OK)
12695895Syz147064 return (status);
12705895Syz147064 }
12715895Syz147064
12725895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) {
12735895Syz147064 u64 = attrp->ld_lacp_timer;
12748453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLACPTIMER,
12755895Syz147064 DLADM_TYPE_UINT64, &u64);
12765895Syz147064 if (status != DLADM_STATUS_OK)
12775895Syz147064 return (status);
12785895Syz147064 }
12793871Syz147064
12803871Syz147064 return (status);
12813871Syz147064 }
12823871Syz147064
12833871Syz147064 /*
12843871Syz147064 * Modify the parameters of an existing link aggregation group. Update
12853871Syz147064 * the configuration file and pass the changes to the kernel.
12863871Syz147064 */
12873871Syz147064 dladm_status_t
dladm_aggr_modify(dladm_handle_t handle,datalink_id_t linkid,uint32_t modify_mask,uint32_t policy,boolean_t mac_fixed,const uchar_t * mac_addr,aggr_lacp_mode_t lacp_mode,aggr_lacp_timer_t lacp_timer,uint32_t flags)12888453SAnurag.Maskey@Sun.COM dladm_aggr_modify(dladm_handle_t handle, datalink_id_t linkid,
12898453SAnurag.Maskey@Sun.COM uint32_t modify_mask, uint32_t policy, boolean_t mac_fixed,
12908453SAnurag.Maskey@Sun.COM const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode,
12915895Syz147064 aggr_lacp_timer_t lacp_timer, uint32_t flags)
12923871Syz147064 {
12933871Syz147064 dladm_aggr_modify_attr_t new_attr, old_attr;
12945895Syz147064 dladm_conf_t conf;
12953871Syz147064 dladm_status_t status;
12963871Syz147064
12975895Syz147064 new_attr.ld_policy = policy;
12985895Syz147064 new_attr.ld_mac_fixed = mac_fixed;
12995895Syz147064 new_attr.ld_lacp_mode = lacp_mode;
13005895Syz147064 new_attr.ld_lacp_timer = lacp_timer;
13015895Syz147064 bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL);
13025895Syz147064
13035895Syz147064 if (flags & DLADM_OPT_PERSIST) {
1304*12824SCathy.Zhou@Sun.COM status = dladm_open_conf(handle, linkid, &conf);
13055895Syz147064 if (status != DLADM_STATUS_OK)
13065895Syz147064 return (status);
13073871Syz147064
13088453SAnurag.Maskey@Sun.COM if ((status = i_dladm_aggr_get_aggr_attr(handle, conf,
13098453SAnurag.Maskey@Sun.COM modify_mask, &old_attr)) != DLADM_STATUS_OK) {
13105895Syz147064 goto done;
13115895Syz147064 }
13123871Syz147064
13138453SAnurag.Maskey@Sun.COM if ((status = i_dladm_aggr_set_aggr_attr(handle, conf,
13148453SAnurag.Maskey@Sun.COM modify_mask, &new_attr)) != DLADM_STATUS_OK) {
13155895Syz147064 goto done;
13165895Syz147064 }
13175895Syz147064
13188453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf);
13195895Syz147064
13205895Syz147064 done:
13218453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
13225895Syz147064 if (status != DLADM_STATUS_OK)
13235895Syz147064 return (status);
13243871Syz147064 }
13253871Syz147064
13265895Syz147064 if (!(flags & DLADM_OPT_ACTIVE))
13275895Syz147064 return (DLADM_STATUS_OK);
13283871Syz147064
13298453SAnurag.Maskey@Sun.COM status = i_dladm_aggr_modify_sys(handle, linkid, modify_mask,
13308453SAnurag.Maskey@Sun.COM &new_attr);
13315895Syz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) {
1332*12824SCathy.Zhou@Sun.COM if (dladm_open_conf(handle, linkid, &conf) == DLADM_STATUS_OK) {
13338453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_set_aggr_attr(handle, conf,
13348453SAnurag.Maskey@Sun.COM modify_mask, &old_attr) == DLADM_STATUS_OK) {
13358453SAnurag.Maskey@Sun.COM (void) dladm_write_conf(handle, conf);
13365895Syz147064 }
13378453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
13385895Syz147064 }
13393871Syz147064 }
13403871Syz147064
13413871Syz147064 return (status);
13423871Syz147064 }
13433871Syz147064
13445895Syz147064 typedef struct aggr_held_arg_s {
13455895Syz147064 datalink_id_t aggrid;
13465895Syz147064 boolean_t isheld;
13475895Syz147064 } aggr_held_arg_t;
13485895Syz147064
13495895Syz147064 static int
i_dladm_aggr_is_held(dladm_handle_t handle,datalink_id_t linkid,void * arg)13508453SAnurag.Maskey@Sun.COM i_dladm_aggr_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg)
13515895Syz147064 {
13525895Syz147064 aggr_held_arg_t *aggr_held_arg = arg;
13535895Syz147064 dladm_vlan_attr_t dva;
13545895Syz147064
13558453SAnurag.Maskey@Sun.COM if (dladm_vlan_info(handle, linkid, &dva, DLADM_OPT_PERSIST) !=
13568453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK)
13575895Syz147064 return (DLADM_WALK_CONTINUE);
13585895Syz147064
13595895Syz147064 if (dva.dv_linkid == aggr_held_arg->aggrid) {
13605895Syz147064 /*
13615895Syz147064 * This VLAN is created over the given aggregation.
13625895Syz147064 */
13635895Syz147064 aggr_held_arg->isheld = B_TRUE;
13645895Syz147064 return (DLADM_WALK_TERMINATE);
13655895Syz147064 }
13665895Syz147064 return (DLADM_WALK_CONTINUE);
13675895Syz147064 }
13685895Syz147064
13693871Syz147064 /*
13705895Syz147064 * Delete a previously created link aggregation group. Either the name "aggr"
13715895Syz147064 * or the "key" is specified.
13723871Syz147064 */
13733871Syz147064 dladm_status_t
dladm_aggr_delete(dladm_handle_t handle,datalink_id_t linkid,uint32_t flags)13748453SAnurag.Maskey@Sun.COM dladm_aggr_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
13753871Syz147064 {
13765895Syz147064 laioc_delete_t ioc;
13775895Syz147064 datalink_class_t class;
13783871Syz147064 dladm_status_t status;
13793871Syz147064
13808453SAnurag.Maskey@Sun.COM if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL,
13818453SAnurag.Maskey@Sun.COM 0) != DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) {
13825895Syz147064 return (DLADM_STATUS_BADARG);
13835895Syz147064 }
13843871Syz147064
13855895Syz147064 if (flags & DLADM_OPT_ACTIVE) {
13865895Syz147064 ioc.ld_linkid = linkid;
13878453SAnurag.Maskey@Sun.COM if ((i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc) < 0) &&
13885895Syz147064 ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) {
13895895Syz147064 status = dladm_errno2status(errno);
13905895Syz147064 return (status);
13915895Syz147064 }
13923871Syz147064
13933871Syz147064 /*
13945895Syz147064 * Delete ACTIVE linkprop first.
13953871Syz147064 */
13968453SAnurag.Maskey@Sun.COM (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
13975895Syz147064 DLADM_OPT_ACTIVE);
13988453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid,
13998453SAnurag.Maskey@Sun.COM DLADM_OPT_ACTIVE);
14003871Syz147064 }
14013871Syz147064
14025895Syz147064 /*
14035895Syz147064 * If we reach here, it means that the active aggregation has already
14045895Syz147064 * been deleted, and there is no active VLANs holding this aggregation.
14055895Syz147064 * Now we see whether there is any persistent VLANs holding this
14065895Syz147064 * aggregation. If so, we fail the operation.
14075895Syz147064 */
14085895Syz147064 if (flags & DLADM_OPT_PERSIST) {
14095895Syz147064 aggr_held_arg_t arg;
14105895Syz147064
14115895Syz147064 arg.aggrid = linkid;
14125895Syz147064 arg.isheld = B_FALSE;
14133871Syz147064
14148453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_aggr_is_held, handle,
14155895Syz147064 &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE,
14165895Syz147064 DLADM_OPT_PERSIST);
14175895Syz147064 if (arg.isheld)
14185895Syz147064 return (DLADM_STATUS_LINKBUSY);
14195895Syz147064
142010616SSebastien.Roy@Sun.COM (void) dladm_remove_conf(handle, linkid);
14218453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid,
14228453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST);
14235895Syz147064 }
14245895Syz147064
14255895Syz147064 return (DLADM_STATUS_OK);
14263871Syz147064 }
14273871Syz147064
14283871Syz147064 /*
14293871Syz147064 * Add one or more ports to an existing link aggregation.
14303871Syz147064 */
14313871Syz147064 dladm_status_t
dladm_aggr_add(dladm_handle_t handle,datalink_id_t linkid,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t flags)14328453SAnurag.Maskey@Sun.COM dladm_aggr_add(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports,
14335895Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags)
14343871Syz147064 {
14358453SAnurag.Maskey@Sun.COM return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags,
14368453SAnurag.Maskey@Sun.COM LAIOC_ADD));
14373871Syz147064 }
14383871Syz147064
14393871Syz147064 /*
14403871Syz147064 * Remove one or more ports from an existing link aggregation.
14413871Syz147064 */
14423871Syz147064 dladm_status_t
dladm_aggr_remove(dladm_handle_t handle,datalink_id_t linkid,uint32_t nports,dladm_aggr_port_attr_db_t * ports,uint32_t flags)14438453SAnurag.Maskey@Sun.COM dladm_aggr_remove(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports,
14445895Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags)
14453871Syz147064 {
14468453SAnurag.Maskey@Sun.COM return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags,
14475895Syz147064 LAIOC_REMOVE));
14485895Syz147064 }
14493871Syz147064
14505895Syz147064 typedef struct i_walk_key_state_s {
14515895Syz147064 uint16_t key;
14525895Syz147064 datalink_id_t linkid;
14535895Syz147064 boolean_t found;
14545895Syz147064 } i_walk_key_state_t;
14553871Syz147064
14565895Syz147064 static int
i_dladm_walk_key2linkid(dladm_handle_t handle,datalink_id_t linkid,void * arg)14578453SAnurag.Maskey@Sun.COM i_dladm_walk_key2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg)
14585895Syz147064 {
14595895Syz147064 dladm_conf_t conf;
14605895Syz147064 uint16_t key;
14615895Syz147064 dladm_status_t status;
14625895Syz147064 i_walk_key_state_t *statep = (i_walk_key_state_t *)arg;
14635895Syz147064 uint64_t u64;
14643871Syz147064
1465*12824SCathy.Zhou@Sun.COM if (dladm_getsnap_conf(handle, linkid, &conf) != DLADM_STATUS_OK)
14665895Syz147064 return (DLADM_WALK_CONTINUE);
14675895Syz147064
14688453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64));
14695895Syz147064 key = (uint16_t)u64;
14708453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf);
14715895Syz147064
14725895Syz147064 if ((status == DLADM_STATUS_OK) && (key == statep->key)) {
14735895Syz147064 statep->found = B_TRUE;
14745895Syz147064 statep->linkid = linkid;
14755895Syz147064 return (DLADM_WALK_TERMINATE);
14763871Syz147064 }
14773871Syz147064
14785895Syz147064 return (DLADM_WALK_CONTINUE);
14795895Syz147064 }
14805895Syz147064
14815895Syz147064 dladm_status_t
dladm_key2linkid(dladm_handle_t handle,uint16_t key,datalink_id_t * linkidp,uint32_t flags)14828453SAnurag.Maskey@Sun.COM dladm_key2linkid(dladm_handle_t handle, uint16_t key, datalink_id_t *linkidp,
14838453SAnurag.Maskey@Sun.COM uint32_t flags)
14845895Syz147064 {
14855895Syz147064 i_walk_key_state_t state;
14865895Syz147064
14875895Syz147064 if (key > AGGR_MAX_KEY)
14885895Syz147064 return (DLADM_STATUS_NOTFOUND);
14893871Syz147064
14905895Syz147064 state.found = B_FALSE;
14915895Syz147064 state.key = key;
14925895Syz147064
14938453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, handle, &state,
14945895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
14955895Syz147064 if (state.found == B_TRUE) {
14965895Syz147064 *linkidp = state.linkid;
14975895Syz147064 return (DLADM_STATUS_OK);
14985895Syz147064 } else {
14995895Syz147064 return (DLADM_STATUS_NOTFOUND);
15005895Syz147064 }
15013871Syz147064 }
1502