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 /* 229815SRishi.Srivatsavai@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233871Syz147064 * Use is subject to license terms. 243871Syz147064 */ 253871Syz147064 263871Syz147064 #include <stdio.h> 273871Syz147064 #include <sys/types.h> 283871Syz147064 #include <sys/stat.h> 293871Syz147064 #include <string.h> 303871Syz147064 #include <fcntl.h> 313871Syz147064 #include <unistd.h> 323871Syz147064 #include <stropts.h> 333871Syz147064 #include <stdlib.h> 343871Syz147064 #include <errno.h> 355895Syz147064 #include <assert.h> 363871Syz147064 #include <strings.h> 373871Syz147064 #include <libintl.h> 383871Syz147064 #include <net/if_types.h> 393871Syz147064 #include <net/if_dl.h> 408275SEric Cheng #include <sys/dld.h> 415895Syz147064 #include <libdllink.h> 425895Syz147064 #include <libdlvlan.h> 433871Syz147064 #include <libdlaggr.h> 443871Syz147064 #include <libdladm_impl.h> 453871Syz147064 463871Syz147064 /* 473871Syz147064 * Link Aggregation Administration Library. 483871Syz147064 * 493871Syz147064 * This library is used by administration tools such as dladm(1M) to 503871Syz147064 * configure link aggregations. 513871Syz147064 */ 523871Syz147064 533871Syz147064 /* Limits on buffer size for LAIOC_INFO request */ 543871Syz147064 #define MIN_INFO_SIZE (4*1024) 553871Syz147064 #define MAX_INFO_SIZE (128*1024) 563871Syz147064 575895Syz147064 static uchar_t zero_mac[] = {0, 0, 0, 0, 0, 0}; 585895Syz147064 #define VALID_PORT_MAC(mac) \ 595895Syz147064 (((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) && \ 605895Syz147064 (!(mac)[0] & 0x01)) 613871Syz147064 62*10616SSebastien.Roy@Sun.COM #define PORT_DELIMITER ":" 633871Syz147064 643871Syz147064 typedef struct dladm_aggr_modify_attr { 653871Syz147064 uint32_t ld_policy; 663871Syz147064 boolean_t ld_mac_fixed; 673871Syz147064 uchar_t ld_mac[ETHERADDRL]; 683871Syz147064 aggr_lacp_mode_t ld_lacp_mode; 693871Syz147064 aggr_lacp_timer_t ld_lacp_timer; 703871Syz147064 } dladm_aggr_modify_attr_t; 713871Syz147064 723871Syz147064 typedef struct policy_s { 733871Syz147064 char *pol_name; 743871Syz147064 uint32_t policy; 753871Syz147064 } policy_t; 763871Syz147064 773871Syz147064 static policy_t policies[] = { 783871Syz147064 {"L2", AGGR_POLICY_L2}, 793871Syz147064 {"L3", AGGR_POLICY_L3}, 803871Syz147064 {"L4", AGGR_POLICY_L4}}; 813871Syz147064 823871Syz147064 #define NPOLICIES (sizeof (policies) / sizeof (policy_t)) 833871Syz147064 843871Syz147064 typedef struct dladm_aggr_lacpmode_s { 853871Syz147064 char *mode_str; 863871Syz147064 aggr_lacp_mode_t mode_id; 873871Syz147064 } dladm_aggr_lacpmode_t; 883871Syz147064 893871Syz147064 static dladm_aggr_lacpmode_t lacp_modes[] = { 903871Syz147064 {"off", AGGR_LACP_OFF}, 913871Syz147064 {"active", AGGR_LACP_ACTIVE}, 923871Syz147064 {"passive", AGGR_LACP_PASSIVE}}; 933871Syz147064 943871Syz147064 #define NLACP_MODES (sizeof (lacp_modes) / sizeof (dladm_aggr_lacpmode_t)) 953871Syz147064 963871Syz147064 typedef struct dladm_aggr_lacptimer_s { 973871Syz147064 char *lt_str; 983871Syz147064 aggr_lacp_timer_t lt_id; 993871Syz147064 } dladm_aggr_lacptimer_t; 1003871Syz147064 1013871Syz147064 static dladm_aggr_lacptimer_t lacp_timers[] = { 1023871Syz147064 {"short", AGGR_LACP_TIMER_SHORT}, 1033871Syz147064 {"long", AGGR_LACP_TIMER_LONG}}; 1043871Syz147064 1053871Syz147064 #define NLACP_TIMERS (sizeof (lacp_timers) / sizeof (dladm_aggr_lacptimer_t)) 1063871Syz147064 1073871Syz147064 typedef struct dladm_aggr_port_state { 1083871Syz147064 char *state_str; 1093871Syz147064 aggr_port_state_t state_id; 1103871Syz147064 } dladm_aggr_port_state_t; 1113871Syz147064 1123871Syz147064 static dladm_aggr_port_state_t port_states[] = { 1133871Syz147064 {"standby", AGGR_PORT_STATE_STANDBY }, 1143871Syz147064 {"attached", AGGR_PORT_STATE_ATTACHED } 1153871Syz147064 }; 1163871Syz147064 1173871Syz147064 #define NPORT_STATES \ 1183871Syz147064 (sizeof (port_states) / sizeof (dladm_aggr_port_state_t)) 1193871Syz147064 120*10616SSebastien.Roy@Sun.COM static dladm_status_t 121*10616SSebastien.Roy@Sun.COM write_port(dladm_handle_t handle, char *portstr, datalink_id_t portid, 122*10616SSebastien.Roy@Sun.COM size_t portstrsize) 123*10616SSebastien.Roy@Sun.COM { 124*10616SSebastien.Roy@Sun.COM char pname[MAXLINKNAMELEN + 1]; 125*10616SSebastien.Roy@Sun.COM dladm_status_t status; 126*10616SSebastien.Roy@Sun.COM 127*10616SSebastien.Roy@Sun.COM if ((status = dladm_datalink_id2info(handle, portid, NULL, NULL, NULL, 128*10616SSebastien.Roy@Sun.COM pname, sizeof (pname))) != DLADM_STATUS_OK) 129*10616SSebastien.Roy@Sun.COM return (status); 130*10616SSebastien.Roy@Sun.COM (void) strlcat(pname, PORT_DELIMITER, sizeof (pname)); 131*10616SSebastien.Roy@Sun.COM if (strlcat(portstr, pname, portstrsize) >= portstrsize) 132*10616SSebastien.Roy@Sun.COM status = DLADM_STATUS_TOOSMALL; 133*10616SSebastien.Roy@Sun.COM return (status); 134*10616SSebastien.Roy@Sun.COM } 135*10616SSebastien.Roy@Sun.COM 136*10616SSebastien.Roy@Sun.COM static dladm_status_t 137*10616SSebastien.Roy@Sun.COM read_port(dladm_handle_t handle, char **portstr, datalink_id_t *portid) 138*10616SSebastien.Roy@Sun.COM { 139*10616SSebastien.Roy@Sun.COM dladm_status_t status; 140*10616SSebastien.Roy@Sun.COM char *pname; 141*10616SSebastien.Roy@Sun.COM 142*10616SSebastien.Roy@Sun.COM if ((pname = strtok(*portstr, PORT_DELIMITER)) == NULL) 143*10616SSebastien.Roy@Sun.COM return (DLADM_STATUS_REPOSITORYINVAL); 144*10616SSebastien.Roy@Sun.COM *portstr += (strlen(pname) + 1); 145*10616SSebastien.Roy@Sun.COM status = dladm_name2info(handle, pname, portid, NULL, NULL, NULL); 146*10616SSebastien.Roy@Sun.COM return (status); 147*10616SSebastien.Roy@Sun.COM } 148*10616SSebastien.Roy@Sun.COM 1495895Syz147064 static int 1508453SAnurag.Maskey@Sun.COM i_dladm_aggr_ioctl(dladm_handle_t handle, int cmd, void *ptr) 1515895Syz147064 { 1528453SAnurag.Maskey@Sun.COM return (ioctl(dladm_dld_fd(handle), cmd, ptr)); 1533871Syz147064 } 1543871Syz147064 1553871Syz147064 /* 1565895Syz147064 * Caller must free attr.lg_ports. The ptr pointer is advanced while convert 1575895Syz147064 * the laioc_info_t to the dladm_aggr_grp_attr_t structure. 1583871Syz147064 */ 1595895Syz147064 static int 1605895Syz147064 i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp) 1613871Syz147064 { 1625895Syz147064 laioc_info_group_t *grp; 1635895Syz147064 laioc_info_port_t *port; 1645895Syz147064 int i; 1655895Syz147064 void *where = (*ptr); 1665895Syz147064 1675895Syz147064 grp = (laioc_info_group_t *)where; 1685895Syz147064 1695895Syz147064 attrp->lg_linkid = grp->lg_linkid; 1705895Syz147064 attrp->lg_key = grp->lg_key; 1715895Syz147064 attrp->lg_nports = grp->lg_nports; 1725895Syz147064 attrp->lg_policy = grp->lg_policy; 1735895Syz147064 attrp->lg_lacp_mode = grp->lg_lacp_mode; 1745895Syz147064 attrp->lg_lacp_timer = grp->lg_lacp_timer; 1755895Syz147064 attrp->lg_force = grp->lg_force; 1765895Syz147064 1775895Syz147064 bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL); 1785895Syz147064 attrp->lg_mac_fixed = grp->lg_mac_fixed; 1793871Syz147064 1805895Syz147064 if ((attrp->lg_ports = malloc(grp->lg_nports * 1815895Syz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) { 1825895Syz147064 errno = ENOMEM; 1835895Syz147064 goto fail; 1845895Syz147064 } 1855895Syz147064 1865895Syz147064 where = (grp + 1); 1873871Syz147064 1885895Syz147064 /* 1895895Syz147064 * Go through each port that is part of the group. 1905895Syz147064 */ 1915895Syz147064 for (i = 0; i < grp->lg_nports; i++) { 1925895Syz147064 port = (laioc_info_port_t *)where; 1933871Syz147064 1945895Syz147064 attrp->lg_ports[i].lp_linkid = port->lp_linkid; 1955895Syz147064 bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL); 1965895Syz147064 attrp->lg_ports[i].lp_state = port->lp_state; 1975895Syz147064 attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state; 1985895Syz147064 1995895Syz147064 where = (port + 1); 2005895Syz147064 } 2015895Syz147064 *ptr = where; 2025895Syz147064 return (0); 2035895Syz147064 fail: 2045895Syz147064 return (-1); 2053871Syz147064 } 2063871Syz147064 2073871Syz147064 /* 2085895Syz147064 * Get active configuration of a specific aggregation. 2095895Syz147064 * Caller must free attrp->la_ports. 2103871Syz147064 */ 2115895Syz147064 static dladm_status_t 2128453SAnurag.Maskey@Sun.COM i_dladm_aggr_info_active(dladm_handle_t handle, datalink_id_t linkid, 2138453SAnurag.Maskey@Sun.COM dladm_aggr_grp_attr_t *attrp) 2143871Syz147064 { 2153871Syz147064 laioc_info_t *ioc; 2167408SSebastien.Roy@Sun.COM int bufsize; 2175895Syz147064 void *where; 2185895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 2193871Syz147064 2203871Syz147064 bufsize = MIN_INFO_SIZE; 2213871Syz147064 ioc = (laioc_info_t *)calloc(1, bufsize); 2225895Syz147064 if (ioc == NULL) 2235895Syz147064 return (DLADM_STATUS_NOMEM); 2245895Syz147064 2255895Syz147064 ioc->li_group_linkid = linkid; 2263871Syz147064 2273871Syz147064 tryagain: 2287408SSebastien.Roy@Sun.COM ioc->li_bufsize = bufsize; 2298453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_ioctl(handle, LAIOC_INFO, ioc) != 0) { 2303871Syz147064 if (errno == ENOSPC) { 2313871Syz147064 /* 2323871Syz147064 * The LAIOC_INFO call failed due to a short 2333871Syz147064 * buffer. Reallocate the buffer and try again. 2343871Syz147064 */ 2353871Syz147064 bufsize *= 2; 2363871Syz147064 if (bufsize <= MAX_INFO_SIZE) { 2373871Syz147064 ioc = (laioc_info_t *)realloc(ioc, bufsize); 2383871Syz147064 if (ioc != NULL) { 2393871Syz147064 bzero(ioc, sizeof (bufsize)); 2403871Syz147064 goto tryagain; 2413871Syz147064 } 2423871Syz147064 } 2433871Syz147064 } 2445895Syz147064 status = dladm_errno2status(errno); 2453871Syz147064 goto bail; 2463871Syz147064 } 2473871Syz147064 2483871Syz147064 /* 2493871Syz147064 * Go through each group returned by the aggregation driver. 2503871Syz147064 */ 2513871Syz147064 where = (char *)(ioc + 1); 2525895Syz147064 if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) { 2535895Syz147064 status = dladm_errno2status(errno); 2545895Syz147064 goto bail; 2553871Syz147064 } 2563871Syz147064 2573871Syz147064 bail: 2583871Syz147064 free(ioc); 2593871Syz147064 return (status); 2603871Syz147064 } 2613871Syz147064 2623871Syz147064 /* 2635895Syz147064 * Get configuration information of a specific aggregation. 2645895Syz147064 * Caller must free attrp->la_ports. 2653871Syz147064 */ 2663871Syz147064 static dladm_status_t 2678453SAnurag.Maskey@Sun.COM i_dladm_aggr_info_persist(dladm_handle_t handle, datalink_id_t linkid, 2688453SAnurag.Maskey@Sun.COM dladm_aggr_grp_attr_t *attrp) 2693871Syz147064 { 2705895Syz147064 dladm_conf_t conf; 2715895Syz147064 uint32_t nports, i; 272*10616SSebastien.Roy@Sun.COM char *portstr = NULL, *next; 2735895Syz147064 dladm_status_t status; 2745895Syz147064 uint64_t u64; 2755895Syz147064 int size; 2765895Syz147064 char macstr[ETHERADDRL * 3]; 2775895Syz147064 2785895Syz147064 attrp->lg_linkid = linkid; 2798453SAnurag.Maskey@Sun.COM if ((status = dladm_read_conf(handle, linkid, &conf)) != 2808453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) 2815895Syz147064 return (status); 2825895Syz147064 2838453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64)); 2845895Syz147064 if (status != DLADM_STATUS_OK) 2855895Syz147064 goto done; 2865895Syz147064 attrp->lg_key = (uint16_t)u64; 2875895Syz147064 2888453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FPOLICY, &u64, 2898453SAnurag.Maskey@Sun.COM sizeof (u64)); 2905895Syz147064 if (status != DLADM_STATUS_OK) 2915895Syz147064 goto done; 2925895Syz147064 attrp->lg_policy = (uint32_t)u64; 2935895Syz147064 2948453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FFIXMACADDR, 2958453SAnurag.Maskey@Sun.COM &attrp->lg_mac_fixed, sizeof (boolean_t)); 2965895Syz147064 if (status != DLADM_STATUS_OK) 2975895Syz147064 goto done; 2985895Syz147064 2995895Syz147064 if (attrp->lg_mac_fixed) { 3005895Syz147064 boolean_t fixed; 3013871Syz147064 3028453SAnurag.Maskey@Sun.COM if ((status = dladm_get_conf_field(handle, conf, FMACADDR, 3038453SAnurag.Maskey@Sun.COM macstr, sizeof (macstr))) != DLADM_STATUS_OK) { 3045895Syz147064 goto done; 3055895Syz147064 } 3065895Syz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) { 3075895Syz147064 status = DLADM_STATUS_REPOSITORYINVAL; 3085895Syz147064 goto done; 3095895Syz147064 } 3105895Syz147064 } 3115895Syz147064 3128453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FFORCE, &attrp->lg_force, 3135895Syz147064 sizeof (boolean_t)); 3145895Syz147064 if (status != DLADM_STATUS_OK) 3155895Syz147064 goto done; 3165895Syz147064 3178453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64, 3188453SAnurag.Maskey@Sun.COM sizeof (u64)); 3195895Syz147064 if (status != DLADM_STATUS_OK) 3205895Syz147064 goto done; 3215895Syz147064 attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64; 3225895Syz147064 3238453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64, 3248453SAnurag.Maskey@Sun.COM sizeof (u64)); 3255895Syz147064 if (status != DLADM_STATUS_OK) 3265895Syz147064 goto done; 3275895Syz147064 attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64; 3285895Syz147064 3298453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FNPORTS, &u64, 3308453SAnurag.Maskey@Sun.COM sizeof (u64)); 3315895Syz147064 if (status != DLADM_STATUS_OK) 3325895Syz147064 goto done; 3335895Syz147064 nports = (uint32_t)u64; 3345895Syz147064 attrp->lg_nports = nports; 3355895Syz147064 336*10616SSebastien.Roy@Sun.COM size = nports * (MAXLINKNAMELEN + 1) + 1; 3375895Syz147064 if ((portstr = calloc(1, size)) == NULL) { 3385895Syz147064 status = DLADM_STATUS_NOMEM; 3395895Syz147064 goto done; 3405895Syz147064 } 3415895Syz147064 3428453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FPORTS, portstr, size); 343*10616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) 3445895Syz147064 goto done; 3455895Syz147064 3465895Syz147064 if ((attrp->lg_ports = malloc(nports * 3475895Syz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) { 3483871Syz147064 status = DLADM_STATUS_NOMEM; 3493871Syz147064 goto done; 3503871Syz147064 } 3513871Syz147064 3525895Syz147064 for (next = portstr, i = 0; i < nports; i++) { 353*10616SSebastien.Roy@Sun.COM if ((status = read_port(handle, &next, 354*10616SSebastien.Roy@Sun.COM &attrp->lg_ports[i].lp_linkid)) != DLADM_STATUS_OK) 3555895Syz147064 free(attrp->lg_ports); 3565895Syz147064 } 3575895Syz147064 3585895Syz147064 done: 359*10616SSebastien.Roy@Sun.COM free(portstr); 3608453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 3615895Syz147064 return (status); 3625895Syz147064 } 3635895Syz147064 3645895Syz147064 dladm_status_t 3658453SAnurag.Maskey@Sun.COM dladm_aggr_info(dladm_handle_t handle, datalink_id_t linkid, 3668453SAnurag.Maskey@Sun.COM dladm_aggr_grp_attr_t *attrp, uint32_t flags) 3675895Syz147064 { 3685895Syz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 3695895Syz147064 if (flags == DLADM_OPT_ACTIVE) 3708453SAnurag.Maskey@Sun.COM return (i_dladm_aggr_info_active(handle, linkid, attrp)); 3715895Syz147064 else 3728453SAnurag.Maskey@Sun.COM return (i_dladm_aggr_info_persist(handle, linkid, attrp)); 3735895Syz147064 } 3743871Syz147064 3755895Syz147064 /* 3765895Syz147064 * Add or remove one or more ports to/from an existing link aggregation. 3775895Syz147064 */ 3785895Syz147064 static dladm_status_t 3798453SAnurag.Maskey@Sun.COM i_dladm_aggr_add_rmv(dladm_handle_t handle, datalink_id_t linkid, 3808453SAnurag.Maskey@Sun.COM uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd) 3815895Syz147064 { 3825895Syz147064 char *orig_portstr = NULL, *portstr = NULL; 3836077Syz147064 laioc_add_rem_t *iocp = NULL; 3845895Syz147064 laioc_port_t *ioc_ports; 3855895Syz147064 uint32_t orig_nports, result_nports, len, i, j; 3865895Syz147064 dladm_conf_t conf; 3875895Syz147064 datalink_class_t class; 3885895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 3895895Syz147064 int size; 3905895Syz147064 uint64_t u64; 3915895Syz147064 uint32_t media; 3925895Syz147064 3935895Syz147064 if (nports == 0) 3945895Syz147064 return (DLADM_STATUS_BADARG); 3955895Syz147064 3965895Syz147064 /* 3975895Syz147064 * Sanity check - aggregations can only be created over Ethernet 3989815SRishi.Srivatsavai@Sun.COM * physical links and simnets. 3995895Syz147064 */ 4005895Syz147064 for (i = 0; i < nports; i++) { 4018453SAnurag.Maskey@Sun.COM if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL, 4025895Syz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) || 4039815SRishi.Srivatsavai@Sun.COM !((class == DATALINK_CLASS_PHYS) || 4049815SRishi.Srivatsavai@Sun.COM (class == DATALINK_CLASS_SIMNET)) || (media != DL_ETHER)) { 4055895Syz147064 return (DLADM_STATUS_BADARG); 4063871Syz147064 } 4073871Syz147064 } 4083871Syz147064 4095895Syz147064 /* 4105895Syz147064 * First, update the persistent configuration if requested. We only 4115895Syz147064 * need to update the FPORTS and FNPORTS fields of this aggregation. 4125895Syz147064 * Note that FPORTS is a list of port linkids separated by 413*10616SSebastien.Roy@Sun.COM * PORT_DELIMITER (':'). 4145895Syz147064 */ 4155895Syz147064 if (flags & DLADM_OPT_PERSIST) { 4168453SAnurag.Maskey@Sun.COM status = dladm_read_conf(handle, linkid, &conf); 4175895Syz147064 if (status != DLADM_STATUS_OK) 4185895Syz147064 return (status); 4195895Syz147064 4205895Syz147064 /* 4215895Syz147064 * Get the original configuration of FNPORTS and FPORTS. 4225895Syz147064 */ 4238453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FNPORTS, &u64, 4245895Syz147064 sizeof (u64)); 4255895Syz147064 if (status != DLADM_STATUS_OK) 4265895Syz147064 goto destroyconf; 4275895Syz147064 orig_nports = (uint32_t)u64; 4285895Syz147064 4295895Syz147064 /* 4305895Syz147064 * At least one port needs to be in the aggregation. 4315895Syz147064 */ 4325895Syz147064 if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) { 4335895Syz147064 status = DLADM_STATUS_BADARG; 4345895Syz147064 goto destroyconf; 4355895Syz147064 } 4365895Syz147064 437*10616SSebastien.Roy@Sun.COM size = orig_nports * (MAXLINKNAMELEN + 1) + 1; 4385895Syz147064 if ((orig_portstr = calloc(1, size)) == NULL) { 4395895Syz147064 status = dladm_errno2status(errno); 4405895Syz147064 goto destroyconf; 4415895Syz147064 } 4425895Syz147064 4438453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FPORTS, 4448453SAnurag.Maskey@Sun.COM orig_portstr, size); 4455895Syz147064 if (status != DLADM_STATUS_OK) 4465895Syz147064 goto destroyconf; 4475895Syz147064 4485895Syz147064 result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports : 4495895Syz147064 orig_nports; 4505895Syz147064 451*10616SSebastien.Roy@Sun.COM size = result_nports * (MAXLINKNAMELEN + 1) + 1; 4525895Syz147064 if ((portstr = calloc(1, size)) == NULL) { 4535895Syz147064 status = dladm_errno2status(errno); 4545895Syz147064 goto destroyconf; 4555895Syz147064 } 4565895Syz147064 4575895Syz147064 /* 4585895Syz147064 * get the new configuration and set to result_nports and 4595895Syz147064 * portstr. 4605895Syz147064 */ 4615895Syz147064 if (cmd == LAIOC_ADD) { 4625895Syz147064 (void) strlcpy(portstr, orig_portstr, size); 463*10616SSebastien.Roy@Sun.COM for (i = 0; i < nports; i++) { 464*10616SSebastien.Roy@Sun.COM status = write_port(handle, portstr, 465*10616SSebastien.Roy@Sun.COM ports[i].lp_linkid, size); 466*10616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) { 467*10616SSebastien.Roy@Sun.COM free(portstr); 468*10616SSebastien.Roy@Sun.COM goto destroyconf; 469*10616SSebastien.Roy@Sun.COM } 470*10616SSebastien.Roy@Sun.COM } 4715895Syz147064 } else { 4725895Syz147064 char *next; 4735895Syz147064 datalink_id_t portid; 4745895Syz147064 uint32_t remove = 0; 4755895Syz147064 4765895Syz147064 for (next = orig_portstr, j = 0; j < orig_nports; j++) { 4775895Syz147064 /* 4785895Syz147064 * Read the portids from the old configuration 4795895Syz147064 * one by one. 4805895Syz147064 */ 481*10616SSebastien.Roy@Sun.COM status = read_port(handle, &next, &portid); 4825895Syz147064 if (status != DLADM_STATUS_OK) { 4835895Syz147064 free(portstr); 4845895Syz147064 goto destroyconf; 4855895Syz147064 } 4865895Syz147064 4875895Syz147064 /* 4885895Syz147064 * See whether this port is in the removal 4895895Syz147064 * list. If not, copy to the new config. 4905895Syz147064 */ 4915895Syz147064 for (i = 0; i < nports; i++) { 4925895Syz147064 if (ports[i].lp_linkid == portid) 4935895Syz147064 break; 4945895Syz147064 } 4955895Syz147064 if (i == nports) { 496*10616SSebastien.Roy@Sun.COM status = write_port(handle, portstr, 497*10616SSebastien.Roy@Sun.COM portid, size); 498*10616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) { 499*10616SSebastien.Roy@Sun.COM free(portstr); 500*10616SSebastien.Roy@Sun.COM goto destroyconf; 501*10616SSebastien.Roy@Sun.COM } 5025895Syz147064 } else { 5035895Syz147064 remove++; 5045895Syz147064 } 5055895Syz147064 } 5065895Syz147064 if (remove != nports) { 5075895Syz147064 status = DLADM_STATUS_LINKINVAL; 5085895Syz147064 free(portstr); 5095895Syz147064 goto destroyconf; 5105895Syz147064 } 5115895Syz147064 result_nports -= nports; 5125895Syz147064 } 5135895Syz147064 5145895Syz147064 u64 = result_nports; 5158453SAnurag.Maskey@Sun.COM if ((status = dladm_set_conf_field(handle, conf, FNPORTS, 5165895Syz147064 DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) { 5175895Syz147064 free(portstr); 5185895Syz147064 goto destroyconf; 5195895Syz147064 } 5205895Syz147064 5218453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FPORTS, 5228453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, portstr); 5235895Syz147064 free(portstr); 5245895Syz147064 if (status != DLADM_STATUS_OK) 5255895Syz147064 goto destroyconf; 5265895Syz147064 5275895Syz147064 /* 5285895Syz147064 * Write the new configuration to the persistent repository. 5295895Syz147064 */ 5308453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf); 5315895Syz147064 5325895Syz147064 destroyconf: 5338453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 5345895Syz147064 if (status != DLADM_STATUS_OK) { 5355895Syz147064 free(orig_portstr); 5365895Syz147064 return (status); 5375895Syz147064 } 5385895Syz147064 } 5395895Syz147064 5405895Syz147064 /* 5415895Syz147064 * If the caller only requested to update the persistent 5425895Syz147064 * configuration, we are done. 5435895Syz147064 */ 5445895Syz147064 if (!(flags & DLADM_OPT_ACTIVE)) 5455895Syz147064 goto done; 5465895Syz147064 5475895Syz147064 /* 5485895Syz147064 * Update the active configuration. 5495895Syz147064 */ 5505895Syz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t); 5515895Syz147064 if ((iocp = malloc(len)) == NULL) { 5525895Syz147064 status = DLADM_STATUS_NOMEM; 5533871Syz147064 goto done; 5543871Syz147064 } 5553871Syz147064 5565895Syz147064 iocp->la_linkid = linkid; 5575895Syz147064 iocp->la_nports = nports; 5585895Syz147064 if (cmd == LAIOC_ADD) 5595895Syz147064 iocp->la_force = (flags & DLADM_OPT_FORCE); 5603871Syz147064 5615895Syz147064 ioc_ports = (laioc_port_t *)(iocp + 1); 5625895Syz147064 for (i = 0; i < nports; i++) 5635895Syz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid; 5645895Syz147064 5658453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_ioctl(handle, cmd, iocp) < 0) 5665895Syz147064 status = dladm_errno2status(errno); 5673871Syz147064 5683871Syz147064 done: 5693871Syz147064 free(iocp); 5705895Syz147064 5715895Syz147064 /* 5725895Syz147064 * If the active configuration update fails, restore the old 5735895Syz147064 * persistent configuration if we've changed that. 5745895Syz147064 */ 5755895Syz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { 5768453SAnurag.Maskey@Sun.COM if (dladm_read_conf(handle, linkid, &conf) == DLADM_STATUS_OK) { 5775895Syz147064 u64 = orig_nports; 5788453SAnurag.Maskey@Sun.COM if ((dladm_set_conf_field(handle, conf, FNPORTS, 5795895Syz147064 DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) && 5808453SAnurag.Maskey@Sun.COM (dladm_set_conf_field(handle, conf, FPORTS, 5818453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, orig_portstr) == DLADM_STATUS_OK)) { 5828453SAnurag.Maskey@Sun.COM (void) dladm_write_conf(handle, conf); 5835895Syz147064 } 5848453SAnurag.Maskey@Sun.COM (void) dladm_destroy_conf(handle, conf); 5855895Syz147064 } 5865895Syz147064 } 5875895Syz147064 free(orig_portstr); 5883871Syz147064 return (status); 5893871Syz147064 } 5903871Syz147064 5913871Syz147064 /* 5923871Syz147064 * Send a modify command to the link aggregation driver. 5933871Syz147064 */ 5943871Syz147064 static dladm_status_t 5958453SAnurag.Maskey@Sun.COM i_dladm_aggr_modify_sys(dladm_handle_t handle, datalink_id_t linkid, 5968453SAnurag.Maskey@Sun.COM uint32_t mask, dladm_aggr_modify_attr_t *attr) 5973871Syz147064 { 5983871Syz147064 laioc_modify_t ioc; 5993871Syz147064 6005895Syz147064 ioc.lu_linkid = linkid; 6013871Syz147064 6023871Syz147064 ioc.lu_modify_mask = 0; 6033871Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) 6043871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_POLICY; 6053871Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC) 6063871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_MAC; 6073871Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) 6083871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_MODE; 6093871Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) 6103871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_TIMER; 6113871Syz147064 6123871Syz147064 ioc.lu_policy = attr->ld_policy; 6133871Syz147064 ioc.lu_mac_fixed = attr->ld_mac_fixed; 6143871Syz147064 bcopy(attr->ld_mac, ioc.lu_mac, ETHERADDRL); 6153871Syz147064 ioc.lu_lacp_mode = attr->ld_lacp_mode; 6163871Syz147064 ioc.lu_lacp_timer = attr->ld_lacp_timer; 6173871Syz147064 6188453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_ioctl(handle, LAIOC_MODIFY, &ioc) < 0) { 6193871Syz147064 if (errno == EINVAL) 6205895Syz147064 return (DLADM_STATUS_MACADDRINVAL); 6213871Syz147064 else 6225895Syz147064 return (dladm_errno2status(errno)); 6235895Syz147064 } else { 6245895Syz147064 return (DLADM_STATUS_OK); 6253871Syz147064 } 6263871Syz147064 } 6273871Syz147064 6283871Syz147064 /* 6293871Syz147064 * Send a create command to the link aggregation driver. 6303871Syz147064 */ 6313871Syz147064 static dladm_status_t 6328453SAnurag.Maskey@Sun.COM i_dladm_aggr_create_sys(dladm_handle_t handle, datalink_id_t linkid, 6338453SAnurag.Maskey@Sun.COM uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, 6348453SAnurag.Maskey@Sun.COM uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr, 6355895Syz147064 aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force) 6363871Syz147064 { 6377408SSebastien.Roy@Sun.COM int i, len; 6385895Syz147064 laioc_create_t *iocp = NULL; 6395895Syz147064 laioc_port_t *ioc_ports; 6403871Syz147064 dladm_status_t status = DLADM_STATUS_OK; 6413871Syz147064 6425895Syz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t); 6433871Syz147064 iocp = malloc(len); 6443871Syz147064 if (iocp == NULL) 6453871Syz147064 return (DLADM_STATUS_NOMEM); 6463871Syz147064 6475895Syz147064 iocp->lc_key = key; 6485895Syz147064 iocp->lc_linkid = linkid; 6495895Syz147064 iocp->lc_nports = nports; 6505895Syz147064 iocp->lc_policy = policy; 6515895Syz147064 iocp->lc_lacp_mode = lacp_mode; 6525895Syz147064 iocp->lc_lacp_timer = lacp_timer; 6535895Syz147064 ioc_ports = (laioc_port_t *)(iocp + 1); 6545895Syz147064 iocp->lc_force = force; 6553871Syz147064 6565895Syz147064 for (i = 0; i < nports; i++) 6575895Syz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid; 6585895Syz147064 6595895Syz147064 if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) { 6605895Syz147064 status = DLADM_STATUS_MACADDRINVAL; 6615895Syz147064 goto done; 6623871Syz147064 } 6633871Syz147064 6645895Syz147064 bcopy(mac_addr, iocp->lc_mac, ETHERADDRL); 6655895Syz147064 iocp->lc_mac_fixed = mac_addr_fixed; 6663871Syz147064 6678453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_ioctl(handle, LAIOC_CREATE, iocp) < 0) 6685895Syz147064 status = dladm_errno2status(errno); 6693871Syz147064 6705895Syz147064 done: 6713871Syz147064 free(iocp); 6723871Syz147064 return (status); 6733871Syz147064 } 6743871Syz147064 6753871Syz147064 /* 6763871Syz147064 * Invoked to bring up a link aggregation group. 6773871Syz147064 */ 6785895Syz147064 static int 6798453SAnurag.Maskey@Sun.COM i_dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) 6803871Syz147064 { 6815895Syz147064 dladm_status_t *statusp = (dladm_status_t *)arg; 6825895Syz147064 dladm_aggr_grp_attr_t attr; 6835895Syz147064 dladm_aggr_port_attr_db_t *ports = NULL; 6845895Syz147064 uint16_t key = 0; 6855895Syz147064 int i, j; 6863871Syz147064 dladm_status_t status; 6873871Syz147064 6888453SAnurag.Maskey@Sun.COM status = dladm_aggr_info(handle, linkid, &attr, DLADM_OPT_PERSIST); 6895895Syz147064 if (status != DLADM_STATUS_OK) { 6905895Syz147064 *statusp = status; 6915895Syz147064 return (DLADM_WALK_CONTINUE); 6925895Syz147064 } 6933871Syz147064 6945895Syz147064 if (attr.lg_key <= AGGR_MAX_KEY) 6955895Syz147064 key = attr.lg_key; 6965895Syz147064 6975895Syz147064 ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t)); 6985895Syz147064 if (ports == NULL) { 6995895Syz147064 status = DLADM_STATUS_NOMEM; 7005895Syz147064 goto done; 7013871Syz147064 } 7023871Syz147064 7033871Syz147064 /* 7045895Syz147064 * Validate (and purge) each physical link associated with this 7055895Syz147064 * aggregation, if the specific hardware has been removed during 7065895Syz147064 * the system shutdown. 7073871Syz147064 */ 7085895Syz147064 for (i = 0, j = 0; i < attr.lg_nports; i++) { 7095895Syz147064 datalink_id_t portid = attr.lg_ports[i].lp_linkid; 7105895Syz147064 uint32_t flags; 7115895Syz147064 dladm_status_t s; 7123871Syz147064 7138453SAnurag.Maskey@Sun.COM s = dladm_datalink_id2info(handle, portid, &flags, NULL, NULL, 7148453SAnurag.Maskey@Sun.COM NULL, 0); 7155895Syz147064 if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) 7165895Syz147064 continue; 7175895Syz147064 7185895Syz147064 ports[j++].lp_linkid = portid; 7195895Syz147064 } 7203871Syz147064 7215895Syz147064 if (j == 0) { 7225895Syz147064 /* 7235895Syz147064 * All of the physical links are removed. 7245895Syz147064 */ 7255895Syz147064 status = DLADM_STATUS_BADARG; 7265895Syz147064 goto done; 7273871Syz147064 } 7283871Syz147064 7295895Syz147064 /* 7305895Syz147064 * Create active aggregation. 7315895Syz147064 */ 7328453SAnurag.Maskey@Sun.COM if ((status = i_dladm_aggr_create_sys(handle, linkid, 7335895Syz147064 key, j, ports, attr.lg_policy, attr.lg_mac_fixed, 7345895Syz147064 (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode, 7355895Syz147064 attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) { 7365895Syz147064 goto done; 7375895Syz147064 } 7383871Syz147064 7398453SAnurag.Maskey@Sun.COM if ((status = dladm_up_datalink_id(handle, linkid)) != 7408453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) { 7415895Syz147064 laioc_delete_t ioc; 742*10616SSebastien.Roy@Sun.COM 7435895Syz147064 ioc.ld_linkid = linkid; 7448453SAnurag.Maskey@Sun.COM (void) i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc); 7455895Syz147064 } 7465895Syz147064 done: 7475895Syz147064 free(attr.lg_ports); 7485895Syz147064 free(ports); 7495895Syz147064 7505895Syz147064 *statusp = status; 7515895Syz147064 return (DLADM_WALK_CONTINUE); 7523871Syz147064 } 7533871Syz147064 7543871Syz147064 /* 7555895Syz147064 * Bring up one aggregation, or all persistent aggregations. In the latter 7565895Syz147064 * case, the walk may terminate early if bringup of an aggregation fails. 7573871Syz147064 */ 7585895Syz147064 dladm_status_t 7598453SAnurag.Maskey@Sun.COM dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid) 7603871Syz147064 { 7613871Syz147064 dladm_status_t status; 7623871Syz147064 7635895Syz147064 if (linkid == DATALINK_ALL_LINKID) { 7648453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_aggr_up, handle, &status, 7655895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 7665895Syz147064 DLADM_OPT_PERSIST); 7675895Syz147064 return (DLADM_STATUS_OK); 7685895Syz147064 } else { 7698453SAnurag.Maskey@Sun.COM (void) i_dladm_aggr_up(handle, linkid, &status); 7703871Syz147064 return (status); 7713871Syz147064 } 7723871Syz147064 } 7733871Syz147064 7743871Syz147064 /* 7753871Syz147064 * Given a policy string, return a policy mask. Returns B_TRUE on 7765895Syz147064 * success, or B_FALSE if an error occurred during parsing. 7773871Syz147064 */ 7783871Syz147064 boolean_t 7793871Syz147064 dladm_aggr_str2policy(const char *str, uint32_t *policy) 7803871Syz147064 { 7813871Syz147064 int i; 7823871Syz147064 policy_t *pol; 7833871Syz147064 char *token = NULL; 7843871Syz147064 char *lasts; 7853871Syz147064 7863871Syz147064 *policy = 0; 7873871Syz147064 7883871Syz147064 while ((token = strtok_r((token == NULL) ? (char *)str : NULL, ",", 7893871Syz147064 &lasts)) != NULL) { 7903871Syz147064 for (i = 0; i < NPOLICIES; i++) { 7913871Syz147064 pol = &policies[i]; 7923871Syz147064 if (strcasecmp(token, pol->pol_name) == 0) { 7933871Syz147064 *policy |= pol->policy; 7943871Syz147064 break; 7953871Syz147064 } 7963871Syz147064 } 7973871Syz147064 if (i == NPOLICIES) 7983871Syz147064 return (B_FALSE); 7993871Syz147064 } 8003871Syz147064 8013871Syz147064 return (B_TRUE); 8023871Syz147064 } 8033871Syz147064 8043871Syz147064 /* 8053871Syz147064 * Given a policy mask, returns a printable string, or NULL if the 8063871Syz147064 * policy mask is invalid. It is the responsibility of the caller to 8073871Syz147064 * free the returned string after use. 8083871Syz147064 */ 8093871Syz147064 char * 8103871Syz147064 dladm_aggr_policy2str(uint32_t policy, char *str) 8113871Syz147064 { 8123871Syz147064 int i, npolicies = 0; 8133871Syz147064 policy_t *pol; 8143871Syz147064 8155895Syz147064 if (str == NULL) 8165895Syz147064 return (NULL); 8175895Syz147064 8183871Syz147064 str[0] = '\0'; 8193871Syz147064 8203871Syz147064 for (i = 0; i < NPOLICIES; i++) { 8213871Syz147064 pol = &policies[i]; 8223871Syz147064 if ((policy & pol->policy) != 0) { 8233871Syz147064 npolicies++; 8243871Syz147064 if (npolicies > 1) 8255895Syz147064 (void) strlcat(str, ",", DLADM_STRSIZE); 8265895Syz147064 (void) strlcat(str, pol->pol_name, DLADM_STRSIZE); 8273871Syz147064 } 8283871Syz147064 } 8293871Syz147064 8303871Syz147064 return (str); 8313871Syz147064 } 8323871Syz147064 8333871Syz147064 /* 8343871Syz147064 * Given a MAC address string, return the MAC address in the mac_addr 8353871Syz147064 * array. If the MAC address was not explicitly specified, i.e. is 8363871Syz147064 * equal to 'auto', zero out mac-addr and set mac_fixed to B_TRUE. 8373871Syz147064 * Return B_FALSE if a syntax error was encountered, B_FALSE otherwise. 8383871Syz147064 */ 8393871Syz147064 boolean_t 8403871Syz147064 dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr) 8413871Syz147064 { 8423871Syz147064 uchar_t *conv_str; 8433871Syz147064 int mac_len; 8443871Syz147064 8453871Syz147064 *mac_fixed = (strcmp(str, "auto") != 0); 8463871Syz147064 if (!*mac_fixed) { 8473871Syz147064 bzero(mac_addr, ETHERADDRL); 8483871Syz147064 return (B_TRUE); 8493871Syz147064 } 8503871Syz147064 8513871Syz147064 conv_str = _link_aton(str, &mac_len); 8523871Syz147064 if (conv_str == NULL) 8533871Syz147064 return (B_FALSE); 8543871Syz147064 8553871Syz147064 if (mac_len != ETHERADDRL) { 8563871Syz147064 free(conv_str); 8573871Syz147064 return (B_FALSE); 8583871Syz147064 } 8593871Syz147064 8603871Syz147064 if ((bcmp(zero_mac, conv_str, ETHERADDRL) == 0) || 8613871Syz147064 (conv_str[0] & 0x01)) { 8623871Syz147064 free(conv_str); 8633871Syz147064 return (B_FALSE); 8643871Syz147064 } 8653871Syz147064 8663871Syz147064 bcopy(conv_str, mac_addr, ETHERADDRL); 8673871Syz147064 free(conv_str); 8683871Syz147064 8693871Syz147064 return (B_TRUE); 8703871Syz147064 } 8713871Syz147064 8723871Syz147064 /* 8733871Syz147064 * Returns a string containing a printable representation of a MAC address. 8743871Syz147064 */ 8753871Syz147064 const char * 8765895Syz147064 dladm_aggr_macaddr2str(const unsigned char *mac, char *buf) 8773871Syz147064 { 8783871Syz147064 static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; 8793871Syz147064 8803871Syz147064 if (buf == NULL) 8813871Syz147064 return (NULL); 8823871Syz147064 8833871Syz147064 if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) 8845895Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 8853871Syz147064 else 8863871Syz147064 return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); 8875895Syz147064 8885895Syz147064 return (buf); 8893871Syz147064 } 8903871Syz147064 8913871Syz147064 /* 8923871Syz147064 * Given a LACP mode string, find the corresponding LACP mode number. Returns 8933871Syz147064 * B_TRUE if a match was found, B_FALSE otherwise. 8943871Syz147064 */ 8953871Syz147064 boolean_t 8963871Syz147064 dladm_aggr_str2lacpmode(const char *str, aggr_lacp_mode_t *lacp_mode) 8973871Syz147064 { 8983871Syz147064 int i; 8993871Syz147064 dladm_aggr_lacpmode_t *mode; 9003871Syz147064 9013871Syz147064 for (i = 0; i < NLACP_MODES; i++) { 9023871Syz147064 mode = &lacp_modes[i]; 9033871Syz147064 if (strncasecmp(str, mode->mode_str, 9043871Syz147064 strlen(mode->mode_str)) == 0) { 9053871Syz147064 *lacp_mode = mode->mode_id; 9063871Syz147064 return (B_TRUE); 9073871Syz147064 } 9083871Syz147064 } 9093871Syz147064 9103871Syz147064 return (B_FALSE); 9113871Syz147064 } 9123871Syz147064 9133871Syz147064 /* 9143871Syz147064 * Given a LACP mode number, returns a printable string, or NULL if the 9153871Syz147064 * LACP mode number is invalid. 9163871Syz147064 */ 9173871Syz147064 const char * 9183871Syz147064 dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf) 9193871Syz147064 { 9203871Syz147064 int i; 9213871Syz147064 dladm_aggr_lacpmode_t *mode; 9223871Syz147064 9235895Syz147064 if (buf == NULL) 9245895Syz147064 return (NULL); 9255895Syz147064 9263871Syz147064 for (i = 0; i < NLACP_MODES; i++) { 9273871Syz147064 mode = &lacp_modes[i]; 9283871Syz147064 if (mode->mode_id == mode_id) { 9293871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 9303871Syz147064 mode->mode_str); 9313871Syz147064 return (buf); 9323871Syz147064 } 9333871Syz147064 } 9343871Syz147064 9353871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 9363871Syz147064 return (buf); 9373871Syz147064 } 9383871Syz147064 9393871Syz147064 /* 9403871Syz147064 * Given a LACP timer string, find the corresponding LACP timer number. Returns 9413871Syz147064 * B_TRUE if a match was found, B_FALSE otherwise. 9423871Syz147064 */ 9433871Syz147064 boolean_t 9443871Syz147064 dladm_aggr_str2lacptimer(const char *str, aggr_lacp_timer_t *lacp_timer) 9453871Syz147064 { 9463871Syz147064 int i; 9473871Syz147064 dladm_aggr_lacptimer_t *timer; 9483871Syz147064 9493871Syz147064 for (i = 0; i < NLACP_TIMERS; i++) { 9503871Syz147064 timer = &lacp_timers[i]; 9513871Syz147064 if (strncasecmp(str, timer->lt_str, 9523871Syz147064 strlen(timer->lt_str)) == 0) { 9533871Syz147064 *lacp_timer = timer->lt_id; 9543871Syz147064 return (B_TRUE); 9553871Syz147064 } 9563871Syz147064 } 9573871Syz147064 9583871Syz147064 return (B_FALSE); 9593871Syz147064 } 9603871Syz147064 9613871Syz147064 /* 9623871Syz147064 * Given a LACP timer, returns a printable string, or NULL if the 9633871Syz147064 * LACP timer number is invalid. 9643871Syz147064 */ 9653871Syz147064 const char * 9663871Syz147064 dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf) 9673871Syz147064 { 9683871Syz147064 int i; 9693871Syz147064 dladm_aggr_lacptimer_t *timer; 9703871Syz147064 9715895Syz147064 if (buf == NULL) 9725895Syz147064 return (NULL); 9735895Syz147064 9743871Syz147064 for (i = 0; i < NLACP_TIMERS; i++) { 9753871Syz147064 timer = &lacp_timers[i]; 9763871Syz147064 if (timer->lt_id == timer_id) { 9773871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 9783871Syz147064 timer->lt_str); 9793871Syz147064 return (buf); 9803871Syz147064 } 9813871Syz147064 } 9823871Syz147064 9833871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 9843871Syz147064 return (buf); 9853871Syz147064 } 9863871Syz147064 9873871Syz147064 const char * 9883871Syz147064 dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) 9893871Syz147064 { 9903871Syz147064 int i; 9915895Syz147064 dladm_aggr_port_state_t *state; 9925895Syz147064 9935895Syz147064 if (buf == NULL) 9945895Syz147064 return (NULL); 9953871Syz147064 9963871Syz147064 for (i = 0; i < NPORT_STATES; i++) { 9973871Syz147064 state = &port_states[i]; 9983871Syz147064 if (state->state_id == state_id) { 9993871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 10003871Syz147064 state->state_str); 10013871Syz147064 return (buf); 10023871Syz147064 } 10033871Syz147064 } 10043871Syz147064 10053871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 10063871Syz147064 return (buf); 10073871Syz147064 } 10083871Syz147064 10095895Syz147064 static dladm_status_t 10108453SAnurag.Maskey@Sun.COM dladm_aggr_persist_aggr_conf(dladm_handle_t handle, const char *link, 10118453SAnurag.Maskey@Sun.COM datalink_id_t linkid, uint16_t key, uint32_t nports, 10128453SAnurag.Maskey@Sun.COM dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed, 10138453SAnurag.Maskey@Sun.COM const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, 10148453SAnurag.Maskey@Sun.COM aggr_lacp_timer_t lacp_timer, boolean_t force) 10153871Syz147064 { 10165895Syz147064 dladm_conf_t conf = DLADM_INVALID_CONF; 10175895Syz147064 char *portstr = NULL; 10185895Syz147064 char macstr[ETHERADDRL * 3]; 10195895Syz147064 dladm_status_t status; 10205895Syz147064 int i, size; 10215895Syz147064 uint64_t u64; 10223871Syz147064 10238453SAnurag.Maskey@Sun.COM if ((status = dladm_create_conf(handle, link, linkid, 10248453SAnurag.Maskey@Sun.COM DATALINK_CLASS_AGGR, DL_ETHER, &conf)) != DLADM_STATUS_OK) { 10253871Syz147064 return (status); 10263871Syz147064 } 10273871Syz147064 10285895Syz147064 u64 = key; 10298453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FKEY, DLADM_TYPE_UINT64, 10308453SAnurag.Maskey@Sun.COM &u64); 10315895Syz147064 if (status != DLADM_STATUS_OK) 10325895Syz147064 goto done; 10333871Syz147064 10345895Syz147064 u64 = nports; 10358453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FNPORTS, DLADM_TYPE_UINT64, 10368453SAnurag.Maskey@Sun.COM &u64); 10375895Syz147064 if (status != DLADM_STATUS_OK) 10385895Syz147064 goto done; 10395895Syz147064 1040*10616SSebastien.Roy@Sun.COM size = nports * MAXLINKNAMELEN + 1; 10415895Syz147064 if ((portstr = calloc(1, size)) == NULL) { 10425895Syz147064 status = DLADM_STATUS_NOMEM; 10435895Syz147064 goto done; 10445895Syz147064 } 10453871Syz147064 1046*10616SSebastien.Roy@Sun.COM for (i = 0; i < nports; i++) { 1047*10616SSebastien.Roy@Sun.COM status = write_port(handle, portstr, ports[i].lp_linkid, size); 1048*10616SSebastien.Roy@Sun.COM if (status != DLADM_STATUS_OK) { 1049*10616SSebastien.Roy@Sun.COM free(portstr); 1050*10616SSebastien.Roy@Sun.COM goto done; 1051*10616SSebastien.Roy@Sun.COM } 1052*10616SSebastien.Roy@Sun.COM } 10538453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FPORTS, DLADM_TYPE_STR, 10548453SAnurag.Maskey@Sun.COM portstr); 10555895Syz147064 free(portstr); 10565895Syz147064 10575895Syz147064 if (status != DLADM_STATUS_OK) 10585895Syz147064 goto done; 10593871Syz147064 10605895Syz147064 u64 = policy; 10618453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FPOLICY, DLADM_TYPE_UINT64, 10628453SAnurag.Maskey@Sun.COM &u64); 10635895Syz147064 if (status != DLADM_STATUS_OK) 10645895Syz147064 goto done; 10655895Syz147064 10668453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FFIXMACADDR, 10678453SAnurag.Maskey@Sun.COM DLADM_TYPE_BOOLEAN, &mac_addr_fixed); 10685895Syz147064 if (status != DLADM_STATUS_OK) 10695895Syz147064 goto done; 10705895Syz147064 10715895Syz147064 if (mac_addr_fixed) { 10725895Syz147064 if (!VALID_PORT_MAC(mac_addr)) { 10735895Syz147064 status = DLADM_STATUS_MACADDRINVAL; 10743871Syz147064 goto done; 10753871Syz147064 } 10763871Syz147064 10775895Syz147064 (void) dladm_aggr_macaddr2str(mac_addr, macstr); 10788453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMACADDR, 10798453SAnurag.Maskey@Sun.COM DLADM_TYPE_STR, macstr); 10805895Syz147064 if (status != DLADM_STATUS_OK) 10813871Syz147064 goto done; 10823871Syz147064 } 10833871Syz147064 10848453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FFORCE, DLADM_TYPE_BOOLEAN, 10858453SAnurag.Maskey@Sun.COM &force); 10865895Syz147064 if (status != DLADM_STATUS_OK) 10875895Syz147064 goto done; 10885895Syz147064 10895895Syz147064 u64 = lacp_mode; 10908453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLACPMODE, 10918453SAnurag.Maskey@Sun.COM DLADM_TYPE_UINT64, &u64); 10925895Syz147064 if (status != DLADM_STATUS_OK) 10935895Syz147064 goto done; 10945895Syz147064 10955895Syz147064 u64 = lacp_timer; 10968453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLACPTIMER, 10978453SAnurag.Maskey@Sun.COM DLADM_TYPE_UINT64, &u64); 10985895Syz147064 if (status != DLADM_STATUS_OK) 10995895Syz147064 goto done; 11005895Syz147064 11013871Syz147064 /* 11025895Syz147064 * Commit the link aggregation configuration. 11033871Syz147064 */ 11048453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf); 11053871Syz147064 11063871Syz147064 done: 11078453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 11083871Syz147064 return (status); 11093871Syz147064 } 11103871Syz147064 11113871Syz147064 /* 11123871Syz147064 * Create a new link aggregation group. Update the configuration 11133871Syz147064 * file and bring it up. 11143871Syz147064 */ 11153871Syz147064 dladm_status_t 11168453SAnurag.Maskey@Sun.COM dladm_aggr_create(dladm_handle_t handle, const char *name, uint16_t key, 11178453SAnurag.Maskey@Sun.COM uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t policy, 11188453SAnurag.Maskey@Sun.COM boolean_t mac_addr_fixed, const uchar_t *mac_addr, 11198453SAnurag.Maskey@Sun.COM aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, uint32_t flags) 11203871Syz147064 { 11215895Syz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 11225895Syz147064 uint32_t media; 11235895Syz147064 uint32_t i; 11245895Syz147064 datalink_class_t class; 11253871Syz147064 dladm_status_t status; 11265895Syz147064 boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE; 11273871Syz147064 11285895Syz147064 if (key != 0 && key > AGGR_MAX_KEY) 11293871Syz147064 return (DLADM_STATUS_KEYINVAL); 11303871Syz147064 11315895Syz147064 if (nports == 0) 11325895Syz147064 return (DLADM_STATUS_BADARG); 11335895Syz147064 11345895Syz147064 for (i = 0; i < nports; i++) { 11358453SAnurag.Maskey@Sun.COM if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL, 11365895Syz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) || 11379815SRishi.Srivatsavai@Sun.COM !((class == DATALINK_CLASS_PHYS || class == 11389815SRishi.Srivatsavai@Sun.COM DATALINK_CLASS_SIMNET) && (media == DL_ETHER))) { 11395895Syz147064 return (DLADM_STATUS_BADARG); 11405895Syz147064 } 11415895Syz147064 } 11425895Syz147064 11435895Syz147064 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 11448453SAnurag.Maskey@Sun.COM if ((status = dladm_create_datalink_id(handle, name, 11458453SAnurag.Maskey@Sun.COM DATALINK_CLASS_AGGR, DL_ETHER, flags, &linkid)) != 11468453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) { 11475895Syz147064 goto fail; 11485895Syz147064 } 11495895Syz147064 11505895Syz147064 if ((flags & DLADM_OPT_PERSIST) && 11518453SAnurag.Maskey@Sun.COM (status = dladm_aggr_persist_aggr_conf(handle, name, linkid, key, 11528453SAnurag.Maskey@Sun.COM nports, ports, policy, mac_addr_fixed, mac_addr, lacp_mode, 11538453SAnurag.Maskey@Sun.COM lacp_timer, force)) != DLADM_STATUS_OK) { 11545895Syz147064 goto fail; 11555895Syz147064 } 11565895Syz147064 11575895Syz147064 if (!(flags & DLADM_OPT_ACTIVE)) 11585895Syz147064 return (DLADM_STATUS_OK); 11595895Syz147064 11608453SAnurag.Maskey@Sun.COM status = i_dladm_aggr_create_sys(handle, linkid, key, nports, ports, 11618453SAnurag.Maskey@Sun.COM policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force); 11623871Syz147064 11635895Syz147064 if (status != DLADM_STATUS_OK) { 11645895Syz147064 if (flags & DLADM_OPT_PERSIST) 11658453SAnurag.Maskey@Sun.COM (void) dladm_remove_conf(handle, linkid); 11665895Syz147064 goto fail; 11675895Syz147064 } 11685895Syz147064 11695895Syz147064 return (DLADM_STATUS_OK); 11705895Syz147064 11715895Syz147064 fail: 11725895Syz147064 if (linkid != DATALINK_INVALID_LINKID) 11738453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, flags); 11745895Syz147064 11755895Syz147064 return (status); 11765895Syz147064 } 11775895Syz147064 11785895Syz147064 static dladm_status_t 11798453SAnurag.Maskey@Sun.COM i_dladm_aggr_get_aggr_attr(dladm_handle_t handle, dladm_conf_t conf, 11808453SAnurag.Maskey@Sun.COM uint32_t mask, dladm_aggr_modify_attr_t *attrp) 11815895Syz147064 { 11825895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 11835895Syz147064 char macstr[ETHERADDRL * 3]; 11845895Syz147064 uint64_t u64; 11855895Syz147064 11865895Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) { 11878453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FPOLICY, &u64, 11885895Syz147064 sizeof (u64)); 11895895Syz147064 if (status != DLADM_STATUS_OK) 11905895Syz147064 return (status); 11915895Syz147064 attrp->ld_policy = (uint32_t)u64; 11925895Syz147064 } 11935895Syz147064 11945895Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC) { 11958453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FFIXMACADDR, 11965895Syz147064 &attrp->ld_mac_fixed, sizeof (boolean_t)); 11973871Syz147064 if (status != DLADM_STATUS_OK) 11983871Syz147064 return (status); 11995895Syz147064 12005895Syz147064 if (attrp->ld_mac_fixed) { 12015895Syz147064 boolean_t fixed; 12025895Syz147064 12038453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FMACADDR, 12045895Syz147064 macstr, sizeof (macstr)); 12055895Syz147064 if (status != DLADM_STATUS_OK) 12065895Syz147064 return (status); 12073871Syz147064 12085895Syz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed, 12095895Syz147064 attrp->ld_mac)) { 12105895Syz147064 return (DLADM_STATUS_REPOSITORYINVAL); 12115895Syz147064 } 12125895Syz147064 } 12135895Syz147064 } 12143871Syz147064 12155895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { 12168453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64, 12175895Syz147064 sizeof (u64)); 12185895Syz147064 if (status != DLADM_STATUS_OK) 12195895Syz147064 return (status); 12205895Syz147064 attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64; 12215895Syz147064 } 12225895Syz147064 12235895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { 12248453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64, 12255895Syz147064 sizeof (u64)); 12265895Syz147064 if (status != DLADM_STATUS_OK) 12275895Syz147064 return (status); 12285895Syz147064 attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64; 12293871Syz147064 } 12303871Syz147064 12315895Syz147064 return (status); 12325895Syz147064 } 12335895Syz147064 12345895Syz147064 static dladm_status_t 12358453SAnurag.Maskey@Sun.COM i_dladm_aggr_set_aggr_attr(dladm_handle_t handle, dladm_conf_t conf, 12368453SAnurag.Maskey@Sun.COM uint32_t mask, dladm_aggr_modify_attr_t *attrp) 12375895Syz147064 { 12385895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 12395895Syz147064 char macstr[ETHERADDRL * 3]; 12405895Syz147064 uint64_t u64; 12415895Syz147064 12425895Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) { 12435895Syz147064 u64 = attrp->ld_policy; 12448453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FPOLICY, 12458453SAnurag.Maskey@Sun.COM DLADM_TYPE_UINT64, &u64); 12465895Syz147064 if (status != DLADM_STATUS_OK) 12475895Syz147064 return (status); 12485895Syz147064 } 12495895Syz147064 12505895Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC) { 12518453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FFIXMACADDR, 12525895Syz147064 DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed); 12535895Syz147064 if (status != DLADM_STATUS_OK) 12545895Syz147064 return (status); 12553871Syz147064 12565895Syz147064 if (attrp->ld_mac_fixed) { 12575895Syz147064 (void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr); 12588453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FMACADDR, 12595895Syz147064 DLADM_TYPE_STR, macstr); 12605895Syz147064 if (status != DLADM_STATUS_OK) 12615895Syz147064 return (status); 12625895Syz147064 } 12635895Syz147064 } 12645895Syz147064 12655895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { 12665895Syz147064 u64 = attrp->ld_lacp_mode; 12678453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLACPMODE, 12685895Syz147064 DLADM_TYPE_UINT64, &u64); 12695895Syz147064 if (status != DLADM_STATUS_OK) 12705895Syz147064 return (status); 12715895Syz147064 } 12725895Syz147064 12735895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { 12745895Syz147064 u64 = attrp->ld_lacp_timer; 12758453SAnurag.Maskey@Sun.COM status = dladm_set_conf_field(handle, conf, FLACPTIMER, 12765895Syz147064 DLADM_TYPE_UINT64, &u64); 12775895Syz147064 if (status != DLADM_STATUS_OK) 12785895Syz147064 return (status); 12795895Syz147064 } 12803871Syz147064 12813871Syz147064 return (status); 12823871Syz147064 } 12833871Syz147064 12843871Syz147064 /* 12853871Syz147064 * Modify the parameters of an existing link aggregation group. Update 12863871Syz147064 * the configuration file and pass the changes to the kernel. 12873871Syz147064 */ 12883871Syz147064 dladm_status_t 12898453SAnurag.Maskey@Sun.COM dladm_aggr_modify(dladm_handle_t handle, datalink_id_t linkid, 12908453SAnurag.Maskey@Sun.COM uint32_t modify_mask, uint32_t policy, boolean_t mac_fixed, 12918453SAnurag.Maskey@Sun.COM const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, 12925895Syz147064 aggr_lacp_timer_t lacp_timer, uint32_t flags) 12933871Syz147064 { 12943871Syz147064 dladm_aggr_modify_attr_t new_attr, old_attr; 12955895Syz147064 dladm_conf_t conf; 12963871Syz147064 dladm_status_t status; 12973871Syz147064 12985895Syz147064 new_attr.ld_policy = policy; 12995895Syz147064 new_attr.ld_mac_fixed = mac_fixed; 13005895Syz147064 new_attr.ld_lacp_mode = lacp_mode; 13015895Syz147064 new_attr.ld_lacp_timer = lacp_timer; 13025895Syz147064 bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); 13035895Syz147064 13045895Syz147064 if (flags & DLADM_OPT_PERSIST) { 13058453SAnurag.Maskey@Sun.COM status = dladm_read_conf(handle, linkid, &conf); 13065895Syz147064 if (status != DLADM_STATUS_OK) 13075895Syz147064 return (status); 13083871Syz147064 13098453SAnurag.Maskey@Sun.COM if ((status = i_dladm_aggr_get_aggr_attr(handle, conf, 13108453SAnurag.Maskey@Sun.COM modify_mask, &old_attr)) != DLADM_STATUS_OK) { 13115895Syz147064 goto done; 13125895Syz147064 } 13133871Syz147064 13148453SAnurag.Maskey@Sun.COM if ((status = i_dladm_aggr_set_aggr_attr(handle, conf, 13158453SAnurag.Maskey@Sun.COM modify_mask, &new_attr)) != DLADM_STATUS_OK) { 13165895Syz147064 goto done; 13175895Syz147064 } 13185895Syz147064 13198453SAnurag.Maskey@Sun.COM status = dladm_write_conf(handle, conf); 13205895Syz147064 13215895Syz147064 done: 13228453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 13235895Syz147064 if (status != DLADM_STATUS_OK) 13245895Syz147064 return (status); 13253871Syz147064 } 13263871Syz147064 13275895Syz147064 if (!(flags & DLADM_OPT_ACTIVE)) 13285895Syz147064 return (DLADM_STATUS_OK); 13293871Syz147064 13308453SAnurag.Maskey@Sun.COM status = i_dladm_aggr_modify_sys(handle, linkid, modify_mask, 13318453SAnurag.Maskey@Sun.COM &new_attr); 13325895Syz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { 13338453SAnurag.Maskey@Sun.COM if (dladm_read_conf(handle, linkid, &conf) == DLADM_STATUS_OK) { 13348453SAnurag.Maskey@Sun.COM if (i_dladm_aggr_set_aggr_attr(handle, conf, 13358453SAnurag.Maskey@Sun.COM modify_mask, &old_attr) == DLADM_STATUS_OK) { 13368453SAnurag.Maskey@Sun.COM (void) dladm_write_conf(handle, conf); 13375895Syz147064 } 13388453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 13395895Syz147064 } 13403871Syz147064 } 13413871Syz147064 13423871Syz147064 return (status); 13433871Syz147064 } 13443871Syz147064 13455895Syz147064 typedef struct aggr_held_arg_s { 13465895Syz147064 datalink_id_t aggrid; 13475895Syz147064 boolean_t isheld; 13485895Syz147064 } aggr_held_arg_t; 13495895Syz147064 13505895Syz147064 static int 13518453SAnurag.Maskey@Sun.COM i_dladm_aggr_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg) 13525895Syz147064 { 13535895Syz147064 aggr_held_arg_t *aggr_held_arg = arg; 13545895Syz147064 dladm_vlan_attr_t dva; 13555895Syz147064 13568453SAnurag.Maskey@Sun.COM if (dladm_vlan_info(handle, linkid, &dva, DLADM_OPT_PERSIST) != 13578453SAnurag.Maskey@Sun.COM DLADM_STATUS_OK) 13585895Syz147064 return (DLADM_WALK_CONTINUE); 13595895Syz147064 13605895Syz147064 if (dva.dv_linkid == aggr_held_arg->aggrid) { 13615895Syz147064 /* 13625895Syz147064 * This VLAN is created over the given aggregation. 13635895Syz147064 */ 13645895Syz147064 aggr_held_arg->isheld = B_TRUE; 13655895Syz147064 return (DLADM_WALK_TERMINATE); 13665895Syz147064 } 13675895Syz147064 return (DLADM_WALK_CONTINUE); 13685895Syz147064 } 13695895Syz147064 13703871Syz147064 /* 13715895Syz147064 * Delete a previously created link aggregation group. Either the name "aggr" 13725895Syz147064 * or the "key" is specified. 13733871Syz147064 */ 13743871Syz147064 dladm_status_t 13758453SAnurag.Maskey@Sun.COM dladm_aggr_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 13763871Syz147064 { 13775895Syz147064 laioc_delete_t ioc; 13785895Syz147064 datalink_class_t class; 13793871Syz147064 dladm_status_t status; 13803871Syz147064 13818453SAnurag.Maskey@Sun.COM if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 13828453SAnurag.Maskey@Sun.COM 0) != DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) { 13835895Syz147064 return (DLADM_STATUS_BADARG); 13845895Syz147064 } 13853871Syz147064 13865895Syz147064 if (flags & DLADM_OPT_ACTIVE) { 13875895Syz147064 ioc.ld_linkid = linkid; 13888453SAnurag.Maskey@Sun.COM if ((i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc) < 0) && 13895895Syz147064 ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { 13905895Syz147064 status = dladm_errno2status(errno); 13915895Syz147064 return (status); 13925895Syz147064 } 13933871Syz147064 13943871Syz147064 /* 13955895Syz147064 * Delete ACTIVE linkprop first. 13963871Syz147064 */ 13978453SAnurag.Maskey@Sun.COM (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 13985895Syz147064 DLADM_OPT_ACTIVE); 13998453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, 14008453SAnurag.Maskey@Sun.COM DLADM_OPT_ACTIVE); 14013871Syz147064 } 14023871Syz147064 14035895Syz147064 /* 14045895Syz147064 * If we reach here, it means that the active aggregation has already 14055895Syz147064 * been deleted, and there is no active VLANs holding this aggregation. 14065895Syz147064 * Now we see whether there is any persistent VLANs holding this 14075895Syz147064 * aggregation. If so, we fail the operation. 14085895Syz147064 */ 14095895Syz147064 if (flags & DLADM_OPT_PERSIST) { 14105895Syz147064 aggr_held_arg_t arg; 14115895Syz147064 14125895Syz147064 arg.aggrid = linkid; 14135895Syz147064 arg.isheld = B_FALSE; 14143871Syz147064 14158453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_aggr_is_held, handle, 14165895Syz147064 &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 14175895Syz147064 DLADM_OPT_PERSIST); 14185895Syz147064 if (arg.isheld) 14195895Syz147064 return (DLADM_STATUS_LINKBUSY); 14205895Syz147064 1421*10616SSebastien.Roy@Sun.COM (void) dladm_remove_conf(handle, linkid); 14228453SAnurag.Maskey@Sun.COM (void) dladm_destroy_datalink_id(handle, linkid, 14238453SAnurag.Maskey@Sun.COM DLADM_OPT_PERSIST); 14245895Syz147064 } 14255895Syz147064 14265895Syz147064 return (DLADM_STATUS_OK); 14273871Syz147064 } 14283871Syz147064 14293871Syz147064 /* 14303871Syz147064 * Add one or more ports to an existing link aggregation. 14313871Syz147064 */ 14323871Syz147064 dladm_status_t 14338453SAnurag.Maskey@Sun.COM dladm_aggr_add(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports, 14345895Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags) 14353871Syz147064 { 14368453SAnurag.Maskey@Sun.COM return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags, 14378453SAnurag.Maskey@Sun.COM LAIOC_ADD)); 14383871Syz147064 } 14393871Syz147064 14403871Syz147064 /* 14413871Syz147064 * Remove one or more ports from an existing link aggregation. 14423871Syz147064 */ 14433871Syz147064 dladm_status_t 14448453SAnurag.Maskey@Sun.COM dladm_aggr_remove(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports, 14455895Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags) 14463871Syz147064 { 14478453SAnurag.Maskey@Sun.COM return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags, 14485895Syz147064 LAIOC_REMOVE)); 14495895Syz147064 } 14503871Syz147064 14515895Syz147064 typedef struct i_walk_key_state_s { 14525895Syz147064 uint16_t key; 14535895Syz147064 datalink_id_t linkid; 14545895Syz147064 boolean_t found; 14555895Syz147064 } i_walk_key_state_t; 14563871Syz147064 14575895Syz147064 static int 14588453SAnurag.Maskey@Sun.COM i_dladm_walk_key2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg) 14595895Syz147064 { 14605895Syz147064 dladm_conf_t conf; 14615895Syz147064 uint16_t key; 14625895Syz147064 dladm_status_t status; 14635895Syz147064 i_walk_key_state_t *statep = (i_walk_key_state_t *)arg; 14645895Syz147064 uint64_t u64; 14653871Syz147064 14668453SAnurag.Maskey@Sun.COM if (dladm_read_conf(handle, linkid, &conf) != 0) 14675895Syz147064 return (DLADM_WALK_CONTINUE); 14685895Syz147064 14698453SAnurag.Maskey@Sun.COM status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64)); 14705895Syz147064 key = (uint16_t)u64; 14718453SAnurag.Maskey@Sun.COM dladm_destroy_conf(handle, conf); 14725895Syz147064 14735895Syz147064 if ((status == DLADM_STATUS_OK) && (key == statep->key)) { 14745895Syz147064 statep->found = B_TRUE; 14755895Syz147064 statep->linkid = linkid; 14765895Syz147064 return (DLADM_WALK_TERMINATE); 14773871Syz147064 } 14783871Syz147064 14795895Syz147064 return (DLADM_WALK_CONTINUE); 14805895Syz147064 } 14815895Syz147064 14825895Syz147064 dladm_status_t 14838453SAnurag.Maskey@Sun.COM dladm_key2linkid(dladm_handle_t handle, uint16_t key, datalink_id_t *linkidp, 14848453SAnurag.Maskey@Sun.COM uint32_t flags) 14855895Syz147064 { 14865895Syz147064 i_walk_key_state_t state; 14875895Syz147064 14885895Syz147064 if (key > AGGR_MAX_KEY) 14895895Syz147064 return (DLADM_STATUS_NOTFOUND); 14903871Syz147064 14915895Syz147064 state.found = B_FALSE; 14925895Syz147064 state.key = key; 14935895Syz147064 14948453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, handle, &state, 14955895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 14965895Syz147064 if (state.found == B_TRUE) { 14975895Syz147064 *linkidp = state.linkid; 14985895Syz147064 return (DLADM_STATUS_OK); 14995895Syz147064 } else { 15005895Syz147064 return (DLADM_STATUS_NOTFOUND); 15015895Syz147064 } 15023871Syz147064 } 1503