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*5895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 233871Syz147064 * Use is subject to license terms. 243871Syz147064 */ 253871Syz147064 263871Syz147064 #pragma ident "%Z%%M% %I% %E% SMI" 273871Syz147064 283871Syz147064 #include <stdio.h> 293871Syz147064 #include <sys/types.h> 303871Syz147064 #include <sys/stat.h> 313871Syz147064 #include <string.h> 323871Syz147064 #include <fcntl.h> 333871Syz147064 #include <unistd.h> 343871Syz147064 #include <stropts.h> 353871Syz147064 #include <stdlib.h> 363871Syz147064 #include <errno.h> 37*5895Syz147064 #include <assert.h> 383871Syz147064 #include <strings.h> 393871Syz147064 #include <libintl.h> 403871Syz147064 #include <net/if_types.h> 413871Syz147064 #include <net/if_dl.h> 42*5895Syz147064 #include <libdllink.h> 43*5895Syz147064 #include <libdlvlan.h> 443871Syz147064 #include <libdlaggr.h> 453871Syz147064 #include <libdladm_impl.h> 463871Syz147064 473871Syz147064 /* 483871Syz147064 * Link Aggregation Administration Library. 493871Syz147064 * 503871Syz147064 * This library is used by administration tools such as dladm(1M) to 513871Syz147064 * configure link aggregations. 523871Syz147064 */ 533871Syz147064 54*5895Syz147064 #define DLADM_AGGR_DEV "/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL 553871Syz147064 563871Syz147064 /* Limits on buffer size for LAIOC_INFO request */ 573871Syz147064 #define MIN_INFO_SIZE (4*1024) 583871Syz147064 #define MAX_INFO_SIZE (128*1024) 593871Syz147064 60*5895Syz147064 static uchar_t zero_mac[] = {0, 0, 0, 0, 0, 0}; 61*5895Syz147064 #define VALID_PORT_MAC(mac) \ 62*5895Syz147064 (((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) && \ 63*5895Syz147064 (!(mac)[0] & 0x01)) 643871Syz147064 65*5895Syz147064 #define PORT_DELIMITER '.' 663871Syz147064 67*5895Syz147064 #define WRITE_PORT(portstr, portid, size) { \ 68*5895Syz147064 char pstr[LINKID_STR_WIDTH + 2]; \ 69*5895Syz147064 (void) snprintf(pstr, LINKID_STR_WIDTH + 2, "%d%c", \ 70*5895Syz147064 (portid), PORT_DELIMITER); \ 71*5895Syz147064 (void) strlcat((portstr), pstr, (size)); \ 72*5895Syz147064 } 733871Syz147064 74*5895Syz147064 #define READ_PORT(portstr, portid, status) { \ 75*5895Syz147064 errno = 0; \ 76*5895Syz147064 (status) = DLADM_STATUS_OK; \ 77*5895Syz147064 (portid) = (int)strtol((portstr), &(portstr), 10); \ 78*5895Syz147064 if (errno != 0 || *(portstr) != PORT_DELIMITER) { \ 79*5895Syz147064 (status) = DLADM_STATUS_REPOSITORYINVAL; \ 80*5895Syz147064 } else { \ 81*5895Syz147064 /* Skip the delimiter. */ \ 82*5895Syz147064 (portstr)++; \ 83*5895Syz147064 } \ 84*5895Syz147064 } 853871Syz147064 863871Syz147064 typedef struct dladm_aggr_modify_attr { 873871Syz147064 uint32_t ld_policy; 883871Syz147064 boolean_t ld_mac_fixed; 893871Syz147064 uchar_t ld_mac[ETHERADDRL]; 903871Syz147064 aggr_lacp_mode_t ld_lacp_mode; 913871Syz147064 aggr_lacp_timer_t ld_lacp_timer; 923871Syz147064 } dladm_aggr_modify_attr_t; 933871Syz147064 943871Syz147064 typedef struct policy_s { 953871Syz147064 char *pol_name; 963871Syz147064 uint32_t policy; 973871Syz147064 } policy_t; 983871Syz147064 993871Syz147064 static policy_t policies[] = { 1003871Syz147064 {"L2", AGGR_POLICY_L2}, 1013871Syz147064 {"L3", AGGR_POLICY_L3}, 1023871Syz147064 {"L4", AGGR_POLICY_L4}}; 1033871Syz147064 1043871Syz147064 #define NPOLICIES (sizeof (policies) / sizeof (policy_t)) 1053871Syz147064 1063871Syz147064 typedef struct dladm_aggr_lacpmode_s { 1073871Syz147064 char *mode_str; 1083871Syz147064 aggr_lacp_mode_t mode_id; 1093871Syz147064 } dladm_aggr_lacpmode_t; 1103871Syz147064 1113871Syz147064 static dladm_aggr_lacpmode_t lacp_modes[] = { 1123871Syz147064 {"off", AGGR_LACP_OFF}, 1133871Syz147064 {"active", AGGR_LACP_ACTIVE}, 1143871Syz147064 {"passive", AGGR_LACP_PASSIVE}}; 1153871Syz147064 1163871Syz147064 #define NLACP_MODES (sizeof (lacp_modes) / sizeof (dladm_aggr_lacpmode_t)) 1173871Syz147064 1183871Syz147064 typedef struct dladm_aggr_lacptimer_s { 1193871Syz147064 char *lt_str; 1203871Syz147064 aggr_lacp_timer_t lt_id; 1213871Syz147064 } dladm_aggr_lacptimer_t; 1223871Syz147064 1233871Syz147064 static dladm_aggr_lacptimer_t lacp_timers[] = { 1243871Syz147064 {"short", AGGR_LACP_TIMER_SHORT}, 1253871Syz147064 {"long", AGGR_LACP_TIMER_LONG}}; 1263871Syz147064 1273871Syz147064 #define NLACP_TIMERS (sizeof (lacp_timers) / sizeof (dladm_aggr_lacptimer_t)) 1283871Syz147064 1293871Syz147064 typedef struct dladm_aggr_port_state { 1303871Syz147064 char *state_str; 1313871Syz147064 aggr_port_state_t state_id; 1323871Syz147064 } dladm_aggr_port_state_t; 1333871Syz147064 1343871Syz147064 static dladm_aggr_port_state_t port_states[] = { 1353871Syz147064 {"standby", AGGR_PORT_STATE_STANDBY }, 1363871Syz147064 {"attached", AGGR_PORT_STATE_ATTACHED } 1373871Syz147064 }; 1383871Syz147064 1393871Syz147064 #define NPORT_STATES \ 1403871Syz147064 (sizeof (port_states) / sizeof (dladm_aggr_port_state_t)) 1413871Syz147064 142*5895Syz147064 static int 143*5895Syz147064 i_dladm_aggr_strioctl(int cmd, void *ptr, int ilen) 144*5895Syz147064 { 145*5895Syz147064 int err, fd; 1463871Syz147064 147*5895Syz147064 if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) 1483871Syz147064 return (-1); 1493871Syz147064 150*5895Syz147064 err = i_dladm_ioctl(fd, cmd, ptr, ilen); 151*5895Syz147064 (void) close(fd); 1523871Syz147064 153*5895Syz147064 return (err); 1543871Syz147064 } 1553871Syz147064 1563871Syz147064 /* 157*5895Syz147064 * Caller must free attr.lg_ports. The ptr pointer is advanced while convert 158*5895Syz147064 * the laioc_info_t to the dladm_aggr_grp_attr_t structure. 1593871Syz147064 */ 160*5895Syz147064 static int 161*5895Syz147064 i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp) 1623871Syz147064 { 163*5895Syz147064 laioc_info_group_t *grp; 164*5895Syz147064 laioc_info_port_t *port; 165*5895Syz147064 int i; 166*5895Syz147064 void *where = (*ptr); 167*5895Syz147064 168*5895Syz147064 grp = (laioc_info_group_t *)where; 169*5895Syz147064 170*5895Syz147064 attrp->lg_linkid = grp->lg_linkid; 171*5895Syz147064 attrp->lg_key = grp->lg_key; 172*5895Syz147064 attrp->lg_nports = grp->lg_nports; 173*5895Syz147064 attrp->lg_policy = grp->lg_policy; 174*5895Syz147064 attrp->lg_lacp_mode = grp->lg_lacp_mode; 175*5895Syz147064 attrp->lg_lacp_timer = grp->lg_lacp_timer; 176*5895Syz147064 attrp->lg_force = grp->lg_force; 177*5895Syz147064 178*5895Syz147064 bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL); 179*5895Syz147064 attrp->lg_mac_fixed = grp->lg_mac_fixed; 1803871Syz147064 181*5895Syz147064 if ((attrp->lg_ports = malloc(grp->lg_nports * 182*5895Syz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) { 183*5895Syz147064 errno = ENOMEM; 184*5895Syz147064 goto fail; 185*5895Syz147064 } 186*5895Syz147064 187*5895Syz147064 where = (grp + 1); 1883871Syz147064 189*5895Syz147064 /* 190*5895Syz147064 * Go through each port that is part of the group. 191*5895Syz147064 */ 192*5895Syz147064 for (i = 0; i < grp->lg_nports; i++) { 193*5895Syz147064 port = (laioc_info_port_t *)where; 1943871Syz147064 195*5895Syz147064 attrp->lg_ports[i].lp_linkid = port->lp_linkid; 196*5895Syz147064 bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL); 197*5895Syz147064 attrp->lg_ports[i].lp_state = port->lp_state; 198*5895Syz147064 attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state; 199*5895Syz147064 200*5895Syz147064 where = (port + 1); 201*5895Syz147064 } 202*5895Syz147064 *ptr = where; 203*5895Syz147064 return (0); 204*5895Syz147064 fail: 205*5895Syz147064 return (-1); 2063871Syz147064 } 2073871Syz147064 2083871Syz147064 /* 209*5895Syz147064 * Get active configuration of a specific aggregation. 210*5895Syz147064 * Caller must free attrp->la_ports. 2113871Syz147064 */ 212*5895Syz147064 static dladm_status_t 213*5895Syz147064 i_dladm_aggr_info_active(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp) 2143871Syz147064 { 2153871Syz147064 laioc_info_t *ioc; 216*5895Syz147064 int rc, bufsize; 217*5895Syz147064 void *where; 218*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 2193871Syz147064 2203871Syz147064 bufsize = MIN_INFO_SIZE; 2213871Syz147064 ioc = (laioc_info_t *)calloc(1, bufsize); 222*5895Syz147064 if (ioc == NULL) 223*5895Syz147064 return (DLADM_STATUS_NOMEM); 224*5895Syz147064 225*5895Syz147064 ioc->li_group_linkid = linkid; 2263871Syz147064 2273871Syz147064 tryagain: 228*5895Syz147064 rc = i_dladm_aggr_strioctl(LAIOC_INFO, ioc, bufsize); 2293871Syz147064 if (rc != 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 } 244*5895Syz147064 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); 252*5895Syz147064 if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) { 253*5895Syz147064 status = dladm_errno2status(errno); 254*5895Syz147064 goto bail; 2553871Syz147064 } 2563871Syz147064 2573871Syz147064 bail: 2583871Syz147064 free(ioc); 2593871Syz147064 return (status); 2603871Syz147064 } 2613871Syz147064 2623871Syz147064 /* 263*5895Syz147064 * Get configuration information of a specific aggregation. 264*5895Syz147064 * Caller must free attrp->la_ports. 2653871Syz147064 */ 2663871Syz147064 static dladm_status_t 267*5895Syz147064 i_dladm_aggr_info_persist(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp) 2683871Syz147064 { 269*5895Syz147064 dladm_conf_t conf; 270*5895Syz147064 uint32_t nports, i; 271*5895Syz147064 char *portstr, *next; 272*5895Syz147064 dladm_status_t status; 273*5895Syz147064 uint64_t u64; 274*5895Syz147064 int size; 275*5895Syz147064 char macstr[ETHERADDRL * 3]; 276*5895Syz147064 277*5895Syz147064 attrp->lg_linkid = linkid; 278*5895Syz147064 if ((status = dladm_read_conf(linkid, &conf)) != DLADM_STATUS_OK) 279*5895Syz147064 return (status); 280*5895Syz147064 281*5895Syz147064 status = dladm_get_conf_field(conf, FKEY, &u64, sizeof (u64)); 282*5895Syz147064 if (status != DLADM_STATUS_OK) 283*5895Syz147064 goto done; 284*5895Syz147064 attrp->lg_key = (uint16_t)u64; 285*5895Syz147064 286*5895Syz147064 status = dladm_get_conf_field(conf, FPOLICY, &u64, sizeof (u64)); 287*5895Syz147064 if (status != DLADM_STATUS_OK) 288*5895Syz147064 goto done; 289*5895Syz147064 attrp->lg_policy = (uint32_t)u64; 290*5895Syz147064 291*5895Syz147064 status = dladm_get_conf_field(conf, FFIXMACADDR, &attrp->lg_mac_fixed, 292*5895Syz147064 sizeof (boolean_t)); 293*5895Syz147064 if (status != DLADM_STATUS_OK) 294*5895Syz147064 goto done; 295*5895Syz147064 296*5895Syz147064 if (attrp->lg_mac_fixed) { 297*5895Syz147064 boolean_t fixed; 2983871Syz147064 299*5895Syz147064 if ((status = dladm_get_conf_field(conf, FMACADDR, macstr, 300*5895Syz147064 sizeof (macstr))) != DLADM_STATUS_OK) { 301*5895Syz147064 goto done; 302*5895Syz147064 } 303*5895Syz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) { 304*5895Syz147064 status = DLADM_STATUS_REPOSITORYINVAL; 305*5895Syz147064 goto done; 306*5895Syz147064 } 307*5895Syz147064 } 308*5895Syz147064 309*5895Syz147064 status = dladm_get_conf_field(conf, FFORCE, &attrp->lg_force, 310*5895Syz147064 sizeof (boolean_t)); 311*5895Syz147064 if (status != DLADM_STATUS_OK) 312*5895Syz147064 goto done; 313*5895Syz147064 314*5895Syz147064 status = dladm_get_conf_field(conf, FLACPMODE, &u64, sizeof (u64)); 315*5895Syz147064 if (status != DLADM_STATUS_OK) 316*5895Syz147064 goto done; 317*5895Syz147064 attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64; 318*5895Syz147064 319*5895Syz147064 status = dladm_get_conf_field(conf, FLACPTIMER, &u64, sizeof (u64)); 320*5895Syz147064 if (status != DLADM_STATUS_OK) 321*5895Syz147064 goto done; 322*5895Syz147064 attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64; 323*5895Syz147064 324*5895Syz147064 status = dladm_get_conf_field(conf, FNPORTS, &u64, sizeof (u64)); 325*5895Syz147064 if (status != DLADM_STATUS_OK) 326*5895Syz147064 goto done; 327*5895Syz147064 nports = (uint32_t)u64; 328*5895Syz147064 attrp->lg_nports = nports; 329*5895Syz147064 330*5895Syz147064 size = nports * (LINKID_STR_WIDTH + 1) + 1; 331*5895Syz147064 if ((portstr = calloc(1, size)) == NULL) { 332*5895Syz147064 status = DLADM_STATUS_NOMEM; 333*5895Syz147064 goto done; 334*5895Syz147064 } 335*5895Syz147064 336*5895Syz147064 status = dladm_get_conf_field(conf, FPORTS, portstr, size); 337*5895Syz147064 if (status != DLADM_STATUS_OK) { 338*5895Syz147064 free(portstr); 339*5895Syz147064 goto done; 340*5895Syz147064 } 341*5895Syz147064 342*5895Syz147064 if ((attrp->lg_ports = malloc(nports * 343*5895Syz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) { 344*5895Syz147064 free(portstr); 3453871Syz147064 status = DLADM_STATUS_NOMEM; 3463871Syz147064 goto done; 3473871Syz147064 } 3483871Syz147064 349*5895Syz147064 for (next = portstr, i = 0; i < nports; i++) { 350*5895Syz147064 READ_PORT(next, attrp->lg_ports[i].lp_linkid, status); 351*5895Syz147064 if (status != DLADM_STATUS_OK) { 352*5895Syz147064 free(portstr); 353*5895Syz147064 free(attrp->lg_ports); 354*5895Syz147064 goto done; 355*5895Syz147064 } 356*5895Syz147064 } 357*5895Syz147064 free(portstr); 358*5895Syz147064 359*5895Syz147064 done: 360*5895Syz147064 dladm_destroy_conf(conf); 361*5895Syz147064 return (status); 362*5895Syz147064 } 363*5895Syz147064 364*5895Syz147064 dladm_status_t 365*5895Syz147064 dladm_aggr_info(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp, 366*5895Syz147064 uint32_t flags) 367*5895Syz147064 { 368*5895Syz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 369*5895Syz147064 if (flags == DLADM_OPT_ACTIVE) 370*5895Syz147064 return (i_dladm_aggr_info_active(linkid, attrp)); 371*5895Syz147064 else 372*5895Syz147064 return (i_dladm_aggr_info_persist(linkid, attrp)); 373*5895Syz147064 } 3743871Syz147064 375*5895Syz147064 /* 376*5895Syz147064 * Add or remove one or more ports to/from an existing link aggregation. 377*5895Syz147064 */ 378*5895Syz147064 static dladm_status_t 379*5895Syz147064 i_dladm_aggr_add_rmv(datalink_id_t linkid, uint32_t nports, 380*5895Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd) 381*5895Syz147064 { 382*5895Syz147064 char *orig_portstr = NULL, *portstr = NULL; 383*5895Syz147064 laioc_add_rem_t *iocp; 384*5895Syz147064 laioc_port_t *ioc_ports; 385*5895Syz147064 uint32_t orig_nports, result_nports, len, i, j; 386*5895Syz147064 dladm_conf_t conf; 387*5895Syz147064 datalink_class_t class; 388*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 389*5895Syz147064 int size; 390*5895Syz147064 uint64_t u64; 391*5895Syz147064 uint32_t media; 392*5895Syz147064 393*5895Syz147064 if (nports == 0) 394*5895Syz147064 return (DLADM_STATUS_BADARG); 395*5895Syz147064 396*5895Syz147064 /* 397*5895Syz147064 * Sanity check - aggregations can only be created over Ethernet 398*5895Syz147064 * physical links. 399*5895Syz147064 */ 400*5895Syz147064 for (i = 0; i < nports; i++) { 401*5895Syz147064 if ((dladm_datalink_id2info(ports[i].lp_linkid, NULL, 402*5895Syz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) || 403*5895Syz147064 (class != DATALINK_CLASS_PHYS) || (media != DL_ETHER)) { 404*5895Syz147064 return (DLADM_STATUS_BADARG); 4053871Syz147064 } 4063871Syz147064 } 4073871Syz147064 408*5895Syz147064 /* 409*5895Syz147064 * First, update the persistent configuration if requested. We only 410*5895Syz147064 * need to update the FPORTS and FNPORTS fields of this aggregation. 411*5895Syz147064 * Note that FPORTS is a list of port linkids separated by 412*5895Syz147064 * PORT_DELIMITER ('.'). 413*5895Syz147064 */ 414*5895Syz147064 if (flags & DLADM_OPT_PERSIST) { 415*5895Syz147064 status = dladm_read_conf(linkid, &conf); 416*5895Syz147064 if (status != DLADM_STATUS_OK) 417*5895Syz147064 return (status); 418*5895Syz147064 419*5895Syz147064 /* 420*5895Syz147064 * Get the original configuration of FNPORTS and FPORTS. 421*5895Syz147064 */ 422*5895Syz147064 status = dladm_get_conf_field(conf, FNPORTS, &u64, 423*5895Syz147064 sizeof (u64)); 424*5895Syz147064 if (status != DLADM_STATUS_OK) 425*5895Syz147064 goto destroyconf; 426*5895Syz147064 orig_nports = (uint32_t)u64; 427*5895Syz147064 428*5895Syz147064 /* 429*5895Syz147064 * At least one port needs to be in the aggregation. 430*5895Syz147064 */ 431*5895Syz147064 if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) { 432*5895Syz147064 status = DLADM_STATUS_BADARG; 433*5895Syz147064 goto destroyconf; 434*5895Syz147064 } 435*5895Syz147064 436*5895Syz147064 size = orig_nports * (LINKID_STR_WIDTH + 1) + 1; 437*5895Syz147064 if ((orig_portstr = calloc(1, size)) == NULL) { 438*5895Syz147064 status = dladm_errno2status(errno); 439*5895Syz147064 goto destroyconf; 440*5895Syz147064 } 441*5895Syz147064 442*5895Syz147064 status = dladm_get_conf_field(conf, FPORTS, orig_portstr, size); 443*5895Syz147064 if (status != DLADM_STATUS_OK) 444*5895Syz147064 goto destroyconf; 445*5895Syz147064 446*5895Syz147064 result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports : 447*5895Syz147064 orig_nports; 448*5895Syz147064 449*5895Syz147064 size = result_nports * (LINKID_STR_WIDTH + 1) + 1; 450*5895Syz147064 if ((portstr = calloc(1, size)) == NULL) { 451*5895Syz147064 status = dladm_errno2status(errno); 452*5895Syz147064 goto destroyconf; 453*5895Syz147064 } 454*5895Syz147064 455*5895Syz147064 /* 456*5895Syz147064 * get the new configuration and set to result_nports and 457*5895Syz147064 * portstr. 458*5895Syz147064 */ 459*5895Syz147064 if (cmd == LAIOC_ADD) { 460*5895Syz147064 (void) strlcpy(portstr, orig_portstr, size); 461*5895Syz147064 for (i = 0; i < nports; i++) 462*5895Syz147064 WRITE_PORT(portstr, ports[i].lp_linkid, size); 463*5895Syz147064 } else { 464*5895Syz147064 char *next; 465*5895Syz147064 datalink_id_t portid; 466*5895Syz147064 uint32_t remove = 0; 467*5895Syz147064 468*5895Syz147064 for (next = orig_portstr, j = 0; j < orig_nports; j++) { 469*5895Syz147064 /* 470*5895Syz147064 * Read the portids from the old configuration 471*5895Syz147064 * one by one. 472*5895Syz147064 */ 473*5895Syz147064 READ_PORT(next, portid, status); 474*5895Syz147064 if (status != DLADM_STATUS_OK) { 475*5895Syz147064 free(portstr); 476*5895Syz147064 goto destroyconf; 477*5895Syz147064 } 478*5895Syz147064 479*5895Syz147064 /* 480*5895Syz147064 * See whether this port is in the removal 481*5895Syz147064 * list. If not, copy to the new config. 482*5895Syz147064 */ 483*5895Syz147064 for (i = 0; i < nports; i++) { 484*5895Syz147064 if (ports[i].lp_linkid == portid) 485*5895Syz147064 break; 486*5895Syz147064 } 487*5895Syz147064 if (i == nports) { 488*5895Syz147064 WRITE_PORT(portstr, portid, size); 489*5895Syz147064 } else { 490*5895Syz147064 remove++; 491*5895Syz147064 } 492*5895Syz147064 } 493*5895Syz147064 if (remove != nports) { 494*5895Syz147064 status = DLADM_STATUS_LINKINVAL; 495*5895Syz147064 free(portstr); 496*5895Syz147064 goto destroyconf; 497*5895Syz147064 } 498*5895Syz147064 result_nports -= nports; 499*5895Syz147064 } 500*5895Syz147064 501*5895Syz147064 u64 = result_nports; 502*5895Syz147064 if ((status = dladm_set_conf_field(conf, FNPORTS, 503*5895Syz147064 DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) { 504*5895Syz147064 free(portstr); 505*5895Syz147064 goto destroyconf; 506*5895Syz147064 } 507*5895Syz147064 508*5895Syz147064 status = dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, 509*5895Syz147064 portstr); 510*5895Syz147064 free(portstr); 511*5895Syz147064 if (status != DLADM_STATUS_OK) 512*5895Syz147064 goto destroyconf; 513*5895Syz147064 514*5895Syz147064 /* 515*5895Syz147064 * Write the new configuration to the persistent repository. 516*5895Syz147064 */ 517*5895Syz147064 status = dladm_write_conf(conf); 518*5895Syz147064 519*5895Syz147064 destroyconf: 520*5895Syz147064 dladm_destroy_conf(conf); 521*5895Syz147064 if (status != DLADM_STATUS_OK) { 522*5895Syz147064 free(orig_portstr); 523*5895Syz147064 return (status); 524*5895Syz147064 } 525*5895Syz147064 } 526*5895Syz147064 527*5895Syz147064 /* 528*5895Syz147064 * If the caller only requested to update the persistent 529*5895Syz147064 * configuration, we are done. 530*5895Syz147064 */ 531*5895Syz147064 if (!(flags & DLADM_OPT_ACTIVE)) 532*5895Syz147064 goto done; 533*5895Syz147064 534*5895Syz147064 /* 535*5895Syz147064 * Update the active configuration. 536*5895Syz147064 */ 537*5895Syz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t); 538*5895Syz147064 if ((iocp = malloc(len)) == NULL) { 539*5895Syz147064 status = DLADM_STATUS_NOMEM; 5403871Syz147064 goto done; 5413871Syz147064 } 5423871Syz147064 543*5895Syz147064 iocp->la_linkid = linkid; 544*5895Syz147064 iocp->la_nports = nports; 545*5895Syz147064 if (cmd == LAIOC_ADD) 546*5895Syz147064 iocp->la_force = (flags & DLADM_OPT_FORCE); 5473871Syz147064 548*5895Syz147064 ioc_ports = (laioc_port_t *)(iocp + 1); 549*5895Syz147064 for (i = 0; i < nports; i++) 550*5895Syz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid; 551*5895Syz147064 552*5895Syz147064 if (i_dladm_aggr_strioctl(cmd, iocp, len) < 0) 553*5895Syz147064 status = dladm_errno2status(errno); 5543871Syz147064 5553871Syz147064 done: 5563871Syz147064 free(iocp); 557*5895Syz147064 558*5895Syz147064 /* 559*5895Syz147064 * If the active configuration update fails, restore the old 560*5895Syz147064 * persistent configuration if we've changed that. 561*5895Syz147064 */ 562*5895Syz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { 563*5895Syz147064 if (dladm_read_conf(linkid, &conf) == DLADM_STATUS_OK) { 564*5895Syz147064 u64 = orig_nports; 565*5895Syz147064 if ((dladm_set_conf_field(conf, FNPORTS, 566*5895Syz147064 DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) && 567*5895Syz147064 (dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, 568*5895Syz147064 orig_portstr) == DLADM_STATUS_OK)) { 569*5895Syz147064 (void) dladm_write_conf(conf); 570*5895Syz147064 } 571*5895Syz147064 (void) dladm_destroy_conf(conf); 572*5895Syz147064 } 573*5895Syz147064 } 574*5895Syz147064 free(orig_portstr); 5753871Syz147064 return (status); 5763871Syz147064 } 5773871Syz147064 5783871Syz147064 /* 5793871Syz147064 * Send a modify command to the link aggregation driver. 5803871Syz147064 */ 5813871Syz147064 static dladm_status_t 582*5895Syz147064 i_dladm_aggr_modify_sys(datalink_id_t linkid, uint32_t mask, 5833871Syz147064 dladm_aggr_modify_attr_t *attr) 5843871Syz147064 { 5853871Syz147064 laioc_modify_t ioc; 5863871Syz147064 587*5895Syz147064 ioc.lu_linkid = linkid; 5883871Syz147064 5893871Syz147064 ioc.lu_modify_mask = 0; 5903871Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) 5913871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_POLICY; 5923871Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC) 5933871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_MAC; 5943871Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) 5953871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_MODE; 5963871Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) 5973871Syz147064 ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_TIMER; 5983871Syz147064 5993871Syz147064 ioc.lu_policy = attr->ld_policy; 6003871Syz147064 ioc.lu_mac_fixed = attr->ld_mac_fixed; 6013871Syz147064 bcopy(attr->ld_mac, ioc.lu_mac, ETHERADDRL); 6023871Syz147064 ioc.lu_lacp_mode = attr->ld_lacp_mode; 6033871Syz147064 ioc.lu_lacp_timer = attr->ld_lacp_timer; 6043871Syz147064 605*5895Syz147064 if (i_dladm_aggr_strioctl(LAIOC_MODIFY, &ioc, sizeof (ioc)) < 0) { 6063871Syz147064 if (errno == EINVAL) 607*5895Syz147064 return (DLADM_STATUS_MACADDRINVAL); 6083871Syz147064 else 609*5895Syz147064 return (dladm_errno2status(errno)); 610*5895Syz147064 } else { 611*5895Syz147064 return (DLADM_STATUS_OK); 6123871Syz147064 } 6133871Syz147064 } 6143871Syz147064 6153871Syz147064 /* 6163871Syz147064 * Send a create command to the link aggregation driver. 6173871Syz147064 */ 6183871Syz147064 static dladm_status_t 619*5895Syz147064 i_dladm_aggr_create_sys(datalink_id_t linkid, uint16_t key, uint32_t nports, 620*5895Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t policy, 621*5895Syz147064 boolean_t mac_addr_fixed, const uchar_t *mac_addr, 622*5895Syz147064 aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force) 6233871Syz147064 { 6243871Syz147064 int i, rc, len; 625*5895Syz147064 laioc_create_t *iocp = NULL; 626*5895Syz147064 laioc_port_t *ioc_ports; 6273871Syz147064 dladm_status_t status = DLADM_STATUS_OK; 6283871Syz147064 629*5895Syz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t); 6303871Syz147064 iocp = malloc(len); 6313871Syz147064 if (iocp == NULL) 6323871Syz147064 return (DLADM_STATUS_NOMEM); 6333871Syz147064 634*5895Syz147064 iocp->lc_key = key; 635*5895Syz147064 iocp->lc_linkid = linkid; 636*5895Syz147064 iocp->lc_nports = nports; 637*5895Syz147064 iocp->lc_policy = policy; 638*5895Syz147064 iocp->lc_lacp_mode = lacp_mode; 639*5895Syz147064 iocp->lc_lacp_timer = lacp_timer; 640*5895Syz147064 ioc_ports = (laioc_port_t *)(iocp + 1); 641*5895Syz147064 iocp->lc_force = force; 6423871Syz147064 643*5895Syz147064 for (i = 0; i < nports; i++) 644*5895Syz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid; 645*5895Syz147064 646*5895Syz147064 if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) { 647*5895Syz147064 status = DLADM_STATUS_MACADDRINVAL; 648*5895Syz147064 goto done; 6493871Syz147064 } 6503871Syz147064 651*5895Syz147064 bcopy(mac_addr, iocp->lc_mac, ETHERADDRL); 652*5895Syz147064 iocp->lc_mac_fixed = mac_addr_fixed; 6533871Syz147064 654*5895Syz147064 rc = i_dladm_aggr_strioctl(LAIOC_CREATE, iocp, len); 655*5895Syz147064 if (rc < 0) 656*5895Syz147064 status = dladm_errno2status(errno); 6573871Syz147064 658*5895Syz147064 done: 6593871Syz147064 free(iocp); 6603871Syz147064 return (status); 6613871Syz147064 } 6623871Syz147064 6633871Syz147064 /* 6643871Syz147064 * Invoked to bring up a link aggregation group. 6653871Syz147064 */ 666*5895Syz147064 static int 667*5895Syz147064 i_dladm_aggr_up(datalink_id_t linkid, void *arg) 6683871Syz147064 { 669*5895Syz147064 dladm_status_t *statusp = (dladm_status_t *)arg; 670*5895Syz147064 dladm_aggr_grp_attr_t attr; 671*5895Syz147064 dladm_aggr_port_attr_db_t *ports = NULL; 672*5895Syz147064 uint16_t key = 0; 673*5895Syz147064 int i, j; 6743871Syz147064 dladm_status_t status; 6753871Syz147064 676*5895Syz147064 status = dladm_aggr_info(linkid, &attr, DLADM_OPT_PERSIST); 677*5895Syz147064 if (status != DLADM_STATUS_OK) { 678*5895Syz147064 *statusp = status; 679*5895Syz147064 return (DLADM_WALK_CONTINUE); 680*5895Syz147064 } 6813871Syz147064 682*5895Syz147064 if (attr.lg_key <= AGGR_MAX_KEY) 683*5895Syz147064 key = attr.lg_key; 684*5895Syz147064 685*5895Syz147064 ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t)); 686*5895Syz147064 if (ports == NULL) { 687*5895Syz147064 status = DLADM_STATUS_NOMEM; 688*5895Syz147064 goto done; 6893871Syz147064 } 6903871Syz147064 6913871Syz147064 /* 692*5895Syz147064 * Validate (and purge) each physical link associated with this 693*5895Syz147064 * aggregation, if the specific hardware has been removed during 694*5895Syz147064 * the system shutdown. 6953871Syz147064 */ 696*5895Syz147064 for (i = 0, j = 0; i < attr.lg_nports; i++) { 697*5895Syz147064 datalink_id_t portid = attr.lg_ports[i].lp_linkid; 698*5895Syz147064 uint32_t flags; 699*5895Syz147064 dladm_status_t s; 7003871Syz147064 701*5895Syz147064 s = dladm_datalink_id2info(portid, &flags, NULL, NULL, NULL, 0); 702*5895Syz147064 if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) 703*5895Syz147064 continue; 704*5895Syz147064 705*5895Syz147064 ports[j++].lp_linkid = portid; 706*5895Syz147064 } 7073871Syz147064 708*5895Syz147064 if (j == 0) { 709*5895Syz147064 /* 710*5895Syz147064 * All of the physical links are removed. 711*5895Syz147064 */ 712*5895Syz147064 status = DLADM_STATUS_BADARG; 713*5895Syz147064 goto done; 7143871Syz147064 } 7153871Syz147064 716*5895Syz147064 /* 717*5895Syz147064 * Create active aggregation. 718*5895Syz147064 */ 719*5895Syz147064 if ((status = i_dladm_aggr_create_sys(linkid, 720*5895Syz147064 key, j, ports, attr.lg_policy, attr.lg_mac_fixed, 721*5895Syz147064 (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode, 722*5895Syz147064 attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) { 723*5895Syz147064 goto done; 724*5895Syz147064 } 7253871Syz147064 726*5895Syz147064 if ((status = dladm_up_datalink_id(linkid)) != DLADM_STATUS_OK) { 727*5895Syz147064 laioc_delete_t ioc; 728*5895Syz147064 ioc.ld_linkid = linkid; 729*5895Syz147064 (void) i_dladm_aggr_strioctl(LAIOC_DELETE, &ioc, sizeof (ioc)); 730*5895Syz147064 goto done; 731*5895Syz147064 } 7323871Syz147064 7333871Syz147064 /* 734*5895Syz147064 * Reset the active linkprop of this specific link. 7353871Syz147064 */ 736*5895Syz147064 (void) dladm_init_linkprop(linkid); 7373871Syz147064 738*5895Syz147064 done: 739*5895Syz147064 free(attr.lg_ports); 740*5895Syz147064 free(ports); 741*5895Syz147064 742*5895Syz147064 *statusp = status; 743*5895Syz147064 return (DLADM_WALK_CONTINUE); 7443871Syz147064 } 7453871Syz147064 7463871Syz147064 /* 747*5895Syz147064 * Bring up one aggregation, or all persistent aggregations. In the latter 748*5895Syz147064 * case, the walk may terminate early if bringup of an aggregation fails. 7493871Syz147064 */ 750*5895Syz147064 dladm_status_t 751*5895Syz147064 dladm_aggr_up(datalink_id_t linkid) 7523871Syz147064 { 7533871Syz147064 dladm_status_t status; 7543871Syz147064 755*5895Syz147064 if (linkid == DATALINK_ALL_LINKID) { 756*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_aggr_up, &status, 757*5895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 758*5895Syz147064 DLADM_OPT_PERSIST); 759*5895Syz147064 return (DLADM_STATUS_OK); 760*5895Syz147064 } else { 761*5895Syz147064 (void) i_dladm_aggr_up(linkid, &status); 7623871Syz147064 return (status); 7633871Syz147064 } 7643871Syz147064 } 7653871Syz147064 7663871Syz147064 /* 7673871Syz147064 * Given a policy string, return a policy mask. Returns B_TRUE on 768*5895Syz147064 * success, or B_FALSE if an error occurred during parsing. 7693871Syz147064 */ 7703871Syz147064 boolean_t 7713871Syz147064 dladm_aggr_str2policy(const char *str, uint32_t *policy) 7723871Syz147064 { 7733871Syz147064 int i; 7743871Syz147064 policy_t *pol; 7753871Syz147064 char *token = NULL; 7763871Syz147064 char *lasts; 7773871Syz147064 7783871Syz147064 *policy = 0; 7793871Syz147064 7803871Syz147064 while ((token = strtok_r((token == NULL) ? (char *)str : NULL, ",", 7813871Syz147064 &lasts)) != NULL) { 7823871Syz147064 for (i = 0; i < NPOLICIES; i++) { 7833871Syz147064 pol = &policies[i]; 7843871Syz147064 if (strcasecmp(token, pol->pol_name) == 0) { 7853871Syz147064 *policy |= pol->policy; 7863871Syz147064 break; 7873871Syz147064 } 7883871Syz147064 } 7893871Syz147064 if (i == NPOLICIES) 7903871Syz147064 return (B_FALSE); 7913871Syz147064 } 7923871Syz147064 7933871Syz147064 return (B_TRUE); 7943871Syz147064 } 7953871Syz147064 7963871Syz147064 /* 7973871Syz147064 * Given a policy mask, returns a printable string, or NULL if the 7983871Syz147064 * policy mask is invalid. It is the responsibility of the caller to 7993871Syz147064 * free the returned string after use. 8003871Syz147064 */ 8013871Syz147064 char * 8023871Syz147064 dladm_aggr_policy2str(uint32_t policy, char *str) 8033871Syz147064 { 8043871Syz147064 int i, npolicies = 0; 8053871Syz147064 policy_t *pol; 8063871Syz147064 807*5895Syz147064 if (str == NULL) 808*5895Syz147064 return (NULL); 809*5895Syz147064 8103871Syz147064 str[0] = '\0'; 8113871Syz147064 8123871Syz147064 for (i = 0; i < NPOLICIES; i++) { 8133871Syz147064 pol = &policies[i]; 8143871Syz147064 if ((policy & pol->policy) != 0) { 8153871Syz147064 npolicies++; 8163871Syz147064 if (npolicies > 1) 817*5895Syz147064 (void) strlcat(str, ",", DLADM_STRSIZE); 818*5895Syz147064 (void) strlcat(str, pol->pol_name, DLADM_STRSIZE); 8193871Syz147064 } 8203871Syz147064 } 8213871Syz147064 8223871Syz147064 return (str); 8233871Syz147064 } 8243871Syz147064 8253871Syz147064 /* 8263871Syz147064 * Given a MAC address string, return the MAC address in the mac_addr 8273871Syz147064 * array. If the MAC address was not explicitly specified, i.e. is 8283871Syz147064 * equal to 'auto', zero out mac-addr and set mac_fixed to B_TRUE. 8293871Syz147064 * Return B_FALSE if a syntax error was encountered, B_FALSE otherwise. 8303871Syz147064 */ 8313871Syz147064 boolean_t 8323871Syz147064 dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr) 8333871Syz147064 { 8343871Syz147064 uchar_t *conv_str; 8353871Syz147064 int mac_len; 8363871Syz147064 8373871Syz147064 *mac_fixed = (strcmp(str, "auto") != 0); 8383871Syz147064 if (!*mac_fixed) { 8393871Syz147064 bzero(mac_addr, ETHERADDRL); 8403871Syz147064 return (B_TRUE); 8413871Syz147064 } 8423871Syz147064 8433871Syz147064 conv_str = _link_aton(str, &mac_len); 8443871Syz147064 if (conv_str == NULL) 8453871Syz147064 return (B_FALSE); 8463871Syz147064 8473871Syz147064 if (mac_len != ETHERADDRL) { 8483871Syz147064 free(conv_str); 8493871Syz147064 return (B_FALSE); 8503871Syz147064 } 8513871Syz147064 8523871Syz147064 if ((bcmp(zero_mac, conv_str, ETHERADDRL) == 0) || 8533871Syz147064 (conv_str[0] & 0x01)) { 8543871Syz147064 free(conv_str); 8553871Syz147064 return (B_FALSE); 8563871Syz147064 } 8573871Syz147064 8583871Syz147064 bcopy(conv_str, mac_addr, ETHERADDRL); 8593871Syz147064 free(conv_str); 8603871Syz147064 8613871Syz147064 return (B_TRUE); 8623871Syz147064 } 8633871Syz147064 8643871Syz147064 /* 8653871Syz147064 * Returns a string containing a printable representation of a MAC address. 8663871Syz147064 */ 8673871Syz147064 const char * 868*5895Syz147064 dladm_aggr_macaddr2str(const unsigned char *mac, char *buf) 8693871Syz147064 { 8703871Syz147064 static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; 8713871Syz147064 8723871Syz147064 if (buf == NULL) 8733871Syz147064 return (NULL); 8743871Syz147064 8753871Syz147064 if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) 876*5895Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 8773871Syz147064 else 8783871Syz147064 return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); 879*5895Syz147064 880*5895Syz147064 return (buf); 8813871Syz147064 } 8823871Syz147064 8833871Syz147064 /* 8843871Syz147064 * Given a LACP mode string, find the corresponding LACP mode number. Returns 8853871Syz147064 * B_TRUE if a match was found, B_FALSE otherwise. 8863871Syz147064 */ 8873871Syz147064 boolean_t 8883871Syz147064 dladm_aggr_str2lacpmode(const char *str, aggr_lacp_mode_t *lacp_mode) 8893871Syz147064 { 8903871Syz147064 int i; 8913871Syz147064 dladm_aggr_lacpmode_t *mode; 8923871Syz147064 8933871Syz147064 for (i = 0; i < NLACP_MODES; i++) { 8943871Syz147064 mode = &lacp_modes[i]; 8953871Syz147064 if (strncasecmp(str, mode->mode_str, 8963871Syz147064 strlen(mode->mode_str)) == 0) { 8973871Syz147064 *lacp_mode = mode->mode_id; 8983871Syz147064 return (B_TRUE); 8993871Syz147064 } 9003871Syz147064 } 9013871Syz147064 9023871Syz147064 return (B_FALSE); 9033871Syz147064 } 9043871Syz147064 9053871Syz147064 /* 9063871Syz147064 * Given a LACP mode number, returns a printable string, or NULL if the 9073871Syz147064 * LACP mode number is invalid. 9083871Syz147064 */ 9093871Syz147064 const char * 9103871Syz147064 dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf) 9113871Syz147064 { 9123871Syz147064 int i; 9133871Syz147064 dladm_aggr_lacpmode_t *mode; 9143871Syz147064 915*5895Syz147064 if (buf == NULL) 916*5895Syz147064 return (NULL); 917*5895Syz147064 9183871Syz147064 for (i = 0; i < NLACP_MODES; i++) { 9193871Syz147064 mode = &lacp_modes[i]; 9203871Syz147064 if (mode->mode_id == mode_id) { 9213871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 9223871Syz147064 mode->mode_str); 9233871Syz147064 return (buf); 9243871Syz147064 } 9253871Syz147064 } 9263871Syz147064 9273871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 9283871Syz147064 return (buf); 9293871Syz147064 } 9303871Syz147064 9313871Syz147064 /* 9323871Syz147064 * Given a LACP timer string, find the corresponding LACP timer number. Returns 9333871Syz147064 * B_TRUE if a match was found, B_FALSE otherwise. 9343871Syz147064 */ 9353871Syz147064 boolean_t 9363871Syz147064 dladm_aggr_str2lacptimer(const char *str, aggr_lacp_timer_t *lacp_timer) 9373871Syz147064 { 9383871Syz147064 int i; 9393871Syz147064 dladm_aggr_lacptimer_t *timer; 9403871Syz147064 9413871Syz147064 for (i = 0; i < NLACP_TIMERS; i++) { 9423871Syz147064 timer = &lacp_timers[i]; 9433871Syz147064 if (strncasecmp(str, timer->lt_str, 9443871Syz147064 strlen(timer->lt_str)) == 0) { 9453871Syz147064 *lacp_timer = timer->lt_id; 9463871Syz147064 return (B_TRUE); 9473871Syz147064 } 9483871Syz147064 } 9493871Syz147064 9503871Syz147064 return (B_FALSE); 9513871Syz147064 } 9523871Syz147064 9533871Syz147064 /* 9543871Syz147064 * Given a LACP timer, returns a printable string, or NULL if the 9553871Syz147064 * LACP timer number is invalid. 9563871Syz147064 */ 9573871Syz147064 const char * 9583871Syz147064 dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf) 9593871Syz147064 { 9603871Syz147064 int i; 9613871Syz147064 dladm_aggr_lacptimer_t *timer; 9623871Syz147064 963*5895Syz147064 if (buf == NULL) 964*5895Syz147064 return (NULL); 965*5895Syz147064 9663871Syz147064 for (i = 0; i < NLACP_TIMERS; i++) { 9673871Syz147064 timer = &lacp_timers[i]; 9683871Syz147064 if (timer->lt_id == timer_id) { 9693871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 9703871Syz147064 timer->lt_str); 9713871Syz147064 return (buf); 9723871Syz147064 } 9733871Syz147064 } 9743871Syz147064 9753871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 9763871Syz147064 return (buf); 9773871Syz147064 } 9783871Syz147064 9793871Syz147064 const char * 9803871Syz147064 dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) 9813871Syz147064 { 9823871Syz147064 int i; 983*5895Syz147064 dladm_aggr_port_state_t *state; 984*5895Syz147064 985*5895Syz147064 if (buf == NULL) 986*5895Syz147064 return (NULL); 9873871Syz147064 9883871Syz147064 for (i = 0; i < NPORT_STATES; i++) { 9893871Syz147064 state = &port_states[i]; 9903871Syz147064 if (state->state_id == state_id) { 9913871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 9923871Syz147064 state->state_str); 9933871Syz147064 return (buf); 9943871Syz147064 } 9953871Syz147064 } 9963871Syz147064 9973871Syz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 9983871Syz147064 return (buf); 9993871Syz147064 } 10003871Syz147064 1001*5895Syz147064 static dladm_status_t 1002*5895Syz147064 dladm_aggr_persist_aggr_conf(const char *link, datalink_id_t linkid, 1003*5895Syz147064 uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, 1004*5895Syz147064 uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr, 1005*5895Syz147064 aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, 1006*5895Syz147064 boolean_t force) 10073871Syz147064 { 1008*5895Syz147064 dladm_conf_t conf = DLADM_INVALID_CONF; 1009*5895Syz147064 char *portstr = NULL; 1010*5895Syz147064 char macstr[ETHERADDRL * 3]; 1011*5895Syz147064 dladm_status_t status; 1012*5895Syz147064 int i, size; 1013*5895Syz147064 uint64_t u64; 10143871Syz147064 1015*5895Syz147064 if ((status = dladm_create_conf(link, linkid, DATALINK_CLASS_AGGR, 1016*5895Syz147064 DL_ETHER, &conf)) != DLADM_STATUS_OK) { 10173871Syz147064 return (status); 10183871Syz147064 } 10193871Syz147064 1020*5895Syz147064 u64 = key; 1021*5895Syz147064 status = dladm_set_conf_field(conf, FKEY, DLADM_TYPE_UINT64, &u64); 1022*5895Syz147064 if (status != DLADM_STATUS_OK) 1023*5895Syz147064 goto done; 10243871Syz147064 1025*5895Syz147064 u64 = nports; 1026*5895Syz147064 status = dladm_set_conf_field(conf, FNPORTS, DLADM_TYPE_UINT64, &u64); 1027*5895Syz147064 if (status != DLADM_STATUS_OK) 1028*5895Syz147064 goto done; 1029*5895Syz147064 1030*5895Syz147064 size = nports * (LINKID_STR_WIDTH + 1) + 1; 1031*5895Syz147064 if ((portstr = calloc(1, size)) == NULL) { 1032*5895Syz147064 status = DLADM_STATUS_NOMEM; 1033*5895Syz147064 goto done; 1034*5895Syz147064 } 10353871Syz147064 1036*5895Syz147064 for (i = 0; i < nports; i++) 1037*5895Syz147064 WRITE_PORT(portstr, ports[i].lp_linkid, size); 1038*5895Syz147064 status = dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, portstr); 1039*5895Syz147064 free(portstr); 1040*5895Syz147064 1041*5895Syz147064 if (status != DLADM_STATUS_OK) 1042*5895Syz147064 goto done; 10433871Syz147064 1044*5895Syz147064 u64 = policy; 1045*5895Syz147064 status = dladm_set_conf_field(conf, FPOLICY, DLADM_TYPE_UINT64, &u64); 1046*5895Syz147064 if (status != DLADM_STATUS_OK) 1047*5895Syz147064 goto done; 1048*5895Syz147064 1049*5895Syz147064 status = dladm_set_conf_field(conf, FFIXMACADDR, DLADM_TYPE_BOOLEAN, 1050*5895Syz147064 &mac_addr_fixed); 1051*5895Syz147064 if (status != DLADM_STATUS_OK) 1052*5895Syz147064 goto done; 1053*5895Syz147064 1054*5895Syz147064 if (mac_addr_fixed) { 1055*5895Syz147064 if (!VALID_PORT_MAC(mac_addr)) { 1056*5895Syz147064 status = DLADM_STATUS_MACADDRINVAL; 10573871Syz147064 goto done; 10583871Syz147064 } 10593871Syz147064 1060*5895Syz147064 (void) dladm_aggr_macaddr2str(mac_addr, macstr); 1061*5895Syz147064 status = dladm_set_conf_field(conf, FMACADDR, DLADM_TYPE_STR, 1062*5895Syz147064 macstr); 1063*5895Syz147064 if (status != DLADM_STATUS_OK) 10643871Syz147064 goto done; 10653871Syz147064 } 10663871Syz147064 1067*5895Syz147064 status = dladm_set_conf_field(conf, FFORCE, DLADM_TYPE_BOOLEAN, &force); 1068*5895Syz147064 if (status != DLADM_STATUS_OK) 1069*5895Syz147064 goto done; 1070*5895Syz147064 1071*5895Syz147064 u64 = lacp_mode; 1072*5895Syz147064 status = dladm_set_conf_field(conf, FLACPMODE, DLADM_TYPE_UINT64, &u64); 1073*5895Syz147064 if (status != DLADM_STATUS_OK) 1074*5895Syz147064 goto done; 1075*5895Syz147064 1076*5895Syz147064 u64 = lacp_timer; 1077*5895Syz147064 status = dladm_set_conf_field(conf, FLACPTIMER, DLADM_TYPE_UINT64, 1078*5895Syz147064 &u64); 1079*5895Syz147064 if (status != DLADM_STATUS_OK) 1080*5895Syz147064 goto done; 1081*5895Syz147064 10823871Syz147064 /* 1083*5895Syz147064 * Commit the link aggregation configuration. 10843871Syz147064 */ 1085*5895Syz147064 status = dladm_write_conf(conf); 10863871Syz147064 10873871Syz147064 done: 1088*5895Syz147064 dladm_destroy_conf(conf); 10893871Syz147064 return (status); 10903871Syz147064 } 10913871Syz147064 10923871Syz147064 /* 10933871Syz147064 * Create a new link aggregation group. Update the configuration 10943871Syz147064 * file and bring it up. 10953871Syz147064 */ 10963871Syz147064 dladm_status_t 1097*5895Syz147064 dladm_aggr_create(const char *name, uint16_t key, uint32_t nports, 10983871Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed, 1099*5895Syz147064 const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, 1100*5895Syz147064 aggr_lacp_timer_t lacp_timer, uint32_t flags) 11013871Syz147064 { 1102*5895Syz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 1103*5895Syz147064 uint32_t media; 1104*5895Syz147064 uint32_t i; 1105*5895Syz147064 datalink_class_t class; 11063871Syz147064 dladm_status_t status; 1107*5895Syz147064 boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE; 11083871Syz147064 1109*5895Syz147064 if (key != 0 && key > AGGR_MAX_KEY) 11103871Syz147064 return (DLADM_STATUS_KEYINVAL); 11113871Syz147064 1112*5895Syz147064 if (nports == 0) 1113*5895Syz147064 return (DLADM_STATUS_BADARG); 1114*5895Syz147064 1115*5895Syz147064 for (i = 0; i < nports; i++) { 1116*5895Syz147064 if ((dladm_datalink_id2info(ports[i].lp_linkid, NULL, 1117*5895Syz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) || 1118*5895Syz147064 (class != DATALINK_CLASS_PHYS) && (media != DL_ETHER)) { 1119*5895Syz147064 return (DLADM_STATUS_BADARG); 1120*5895Syz147064 } 1121*5895Syz147064 } 1122*5895Syz147064 1123*5895Syz147064 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1124*5895Syz147064 if ((status = dladm_create_datalink_id(name, DATALINK_CLASS_AGGR, 1125*5895Syz147064 DL_ETHER, flags, &linkid)) != DLADM_STATUS_OK) { 1126*5895Syz147064 goto fail; 1127*5895Syz147064 } 1128*5895Syz147064 1129*5895Syz147064 if ((flags & DLADM_OPT_PERSIST) && 1130*5895Syz147064 (status = dladm_aggr_persist_aggr_conf(name, linkid, key, nports, 1131*5895Syz147064 ports, policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, 1132*5895Syz147064 force)) != DLADM_STATUS_OK) { 1133*5895Syz147064 goto fail; 1134*5895Syz147064 } 1135*5895Syz147064 1136*5895Syz147064 if (!(flags & DLADM_OPT_ACTIVE)) 1137*5895Syz147064 return (DLADM_STATUS_OK); 1138*5895Syz147064 1139*5895Syz147064 status = i_dladm_aggr_create_sys(linkid, key, nports, ports, policy, 1140*5895Syz147064 mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force); 11413871Syz147064 1142*5895Syz147064 if (status != DLADM_STATUS_OK) { 1143*5895Syz147064 if (flags & DLADM_OPT_PERSIST) 1144*5895Syz147064 (void) dladm_remove_conf(linkid); 1145*5895Syz147064 goto fail; 1146*5895Syz147064 } 1147*5895Syz147064 1148*5895Syz147064 return (DLADM_STATUS_OK); 1149*5895Syz147064 1150*5895Syz147064 fail: 1151*5895Syz147064 if (linkid != DATALINK_INVALID_LINKID) 1152*5895Syz147064 (void) dladm_destroy_datalink_id(linkid, flags); 1153*5895Syz147064 1154*5895Syz147064 return (status); 1155*5895Syz147064 } 1156*5895Syz147064 1157*5895Syz147064 static dladm_status_t 1158*5895Syz147064 i_dladm_aggr_get_aggr_attr(dladm_conf_t conf, uint32_t mask, 1159*5895Syz147064 dladm_aggr_modify_attr_t *attrp) 1160*5895Syz147064 { 1161*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 1162*5895Syz147064 char macstr[ETHERADDRL * 3]; 1163*5895Syz147064 uint64_t u64; 1164*5895Syz147064 1165*5895Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) { 1166*5895Syz147064 status = dladm_get_conf_field(conf, FPOLICY, &u64, 1167*5895Syz147064 sizeof (u64)); 1168*5895Syz147064 if (status != DLADM_STATUS_OK) 1169*5895Syz147064 return (status); 1170*5895Syz147064 attrp->ld_policy = (uint32_t)u64; 1171*5895Syz147064 } 1172*5895Syz147064 1173*5895Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC) { 1174*5895Syz147064 status = dladm_get_conf_field(conf, FFIXMACADDR, 1175*5895Syz147064 &attrp->ld_mac_fixed, sizeof (boolean_t)); 11763871Syz147064 if (status != DLADM_STATUS_OK) 11773871Syz147064 return (status); 1178*5895Syz147064 1179*5895Syz147064 if (attrp->ld_mac_fixed) { 1180*5895Syz147064 boolean_t fixed; 1181*5895Syz147064 1182*5895Syz147064 status = dladm_get_conf_field(conf, FMACADDR, 1183*5895Syz147064 macstr, sizeof (macstr)); 1184*5895Syz147064 if (status != DLADM_STATUS_OK) 1185*5895Syz147064 return (status); 11863871Syz147064 1187*5895Syz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed, 1188*5895Syz147064 attrp->ld_mac)) { 1189*5895Syz147064 return (DLADM_STATUS_REPOSITORYINVAL); 1190*5895Syz147064 } 1191*5895Syz147064 } 1192*5895Syz147064 } 11933871Syz147064 1194*5895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { 1195*5895Syz147064 status = dladm_get_conf_field(conf, FLACPMODE, &u64, 1196*5895Syz147064 sizeof (u64)); 1197*5895Syz147064 if (status != DLADM_STATUS_OK) 1198*5895Syz147064 return (status); 1199*5895Syz147064 attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64; 1200*5895Syz147064 } 1201*5895Syz147064 1202*5895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { 1203*5895Syz147064 status = dladm_get_conf_field(conf, FLACPTIMER, &u64, 1204*5895Syz147064 sizeof (u64)); 1205*5895Syz147064 if (status != DLADM_STATUS_OK) 1206*5895Syz147064 return (status); 1207*5895Syz147064 attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64; 12083871Syz147064 } 12093871Syz147064 1210*5895Syz147064 return (status); 1211*5895Syz147064 } 1212*5895Syz147064 1213*5895Syz147064 static dladm_status_t 1214*5895Syz147064 i_dladm_aggr_set_aggr_attr(dladm_conf_t conf, uint32_t mask, 1215*5895Syz147064 dladm_aggr_modify_attr_t *attrp) 1216*5895Syz147064 { 1217*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 1218*5895Syz147064 char macstr[ETHERADDRL * 3]; 1219*5895Syz147064 uint64_t u64; 1220*5895Syz147064 1221*5895Syz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) { 1222*5895Syz147064 u64 = attrp->ld_policy; 1223*5895Syz147064 status = dladm_set_conf_field(conf, FPOLICY, DLADM_TYPE_UINT64, 1224*5895Syz147064 &u64); 1225*5895Syz147064 if (status != DLADM_STATUS_OK) 1226*5895Syz147064 return (status); 1227*5895Syz147064 } 1228*5895Syz147064 1229*5895Syz147064 if (mask & DLADM_AGGR_MODIFY_MAC) { 1230*5895Syz147064 status = dladm_set_conf_field(conf, FFIXMACADDR, 1231*5895Syz147064 DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed); 1232*5895Syz147064 if (status != DLADM_STATUS_OK) 1233*5895Syz147064 return (status); 12343871Syz147064 1235*5895Syz147064 if (attrp->ld_mac_fixed) { 1236*5895Syz147064 (void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr); 1237*5895Syz147064 status = dladm_set_conf_field(conf, FMACADDR, 1238*5895Syz147064 DLADM_TYPE_STR, macstr); 1239*5895Syz147064 if (status != DLADM_STATUS_OK) 1240*5895Syz147064 return (status); 1241*5895Syz147064 } 1242*5895Syz147064 } 1243*5895Syz147064 1244*5895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { 1245*5895Syz147064 u64 = attrp->ld_lacp_mode; 1246*5895Syz147064 status = dladm_set_conf_field(conf, FLACPMODE, 1247*5895Syz147064 DLADM_TYPE_UINT64, &u64); 1248*5895Syz147064 if (status != DLADM_STATUS_OK) 1249*5895Syz147064 return (status); 1250*5895Syz147064 } 1251*5895Syz147064 1252*5895Syz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { 1253*5895Syz147064 u64 = attrp->ld_lacp_timer; 1254*5895Syz147064 status = dladm_set_conf_field(conf, FLACPTIMER, 1255*5895Syz147064 DLADM_TYPE_UINT64, &u64); 1256*5895Syz147064 if (status != DLADM_STATUS_OK) 1257*5895Syz147064 return (status); 1258*5895Syz147064 } 12593871Syz147064 12603871Syz147064 return (status); 12613871Syz147064 } 12623871Syz147064 12633871Syz147064 /* 12643871Syz147064 * Modify the parameters of an existing link aggregation group. Update 12653871Syz147064 * the configuration file and pass the changes to the kernel. 12663871Syz147064 */ 12673871Syz147064 dladm_status_t 1268*5895Syz147064 dladm_aggr_modify(datalink_id_t linkid, uint32_t modify_mask, uint32_t policy, 1269*5895Syz147064 boolean_t mac_fixed, const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, 1270*5895Syz147064 aggr_lacp_timer_t lacp_timer, uint32_t flags) 12713871Syz147064 { 12723871Syz147064 dladm_aggr_modify_attr_t new_attr, old_attr; 1273*5895Syz147064 dladm_conf_t conf; 12743871Syz147064 dladm_status_t status; 12753871Syz147064 1276*5895Syz147064 new_attr.ld_policy = policy; 1277*5895Syz147064 new_attr.ld_mac_fixed = mac_fixed; 1278*5895Syz147064 new_attr.ld_lacp_mode = lacp_mode; 1279*5895Syz147064 new_attr.ld_lacp_timer = lacp_timer; 1280*5895Syz147064 bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); 1281*5895Syz147064 1282*5895Syz147064 if (flags & DLADM_OPT_PERSIST) { 1283*5895Syz147064 status = dladm_read_conf(linkid, &conf); 1284*5895Syz147064 if (status != DLADM_STATUS_OK) 1285*5895Syz147064 return (status); 12863871Syz147064 1287*5895Syz147064 if ((status = i_dladm_aggr_get_aggr_attr(conf, modify_mask, 1288*5895Syz147064 &old_attr)) != DLADM_STATUS_OK) { 1289*5895Syz147064 goto done; 1290*5895Syz147064 } 12913871Syz147064 1292*5895Syz147064 if ((status = i_dladm_aggr_set_aggr_attr(conf, modify_mask, 1293*5895Syz147064 &new_attr)) != DLADM_STATUS_OK) { 1294*5895Syz147064 goto done; 1295*5895Syz147064 } 1296*5895Syz147064 1297*5895Syz147064 status = dladm_write_conf(conf); 1298*5895Syz147064 1299*5895Syz147064 done: 1300*5895Syz147064 dladm_destroy_conf(conf); 1301*5895Syz147064 if (status != DLADM_STATUS_OK) 1302*5895Syz147064 return (status); 13033871Syz147064 } 13043871Syz147064 1305*5895Syz147064 if (!(flags & DLADM_OPT_ACTIVE)) 1306*5895Syz147064 return (DLADM_STATUS_OK); 13073871Syz147064 1308*5895Syz147064 status = i_dladm_aggr_modify_sys(linkid, modify_mask, &new_attr); 1309*5895Syz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { 1310*5895Syz147064 if (dladm_read_conf(linkid, &conf) == DLADM_STATUS_OK) { 1311*5895Syz147064 if (i_dladm_aggr_set_aggr_attr(conf, modify_mask, 1312*5895Syz147064 &old_attr) == DLADM_STATUS_OK) { 1313*5895Syz147064 (void) dladm_write_conf(conf); 1314*5895Syz147064 } 1315*5895Syz147064 dladm_destroy_conf(conf); 1316*5895Syz147064 } 13173871Syz147064 } 13183871Syz147064 13193871Syz147064 return (status); 13203871Syz147064 } 13213871Syz147064 1322*5895Syz147064 typedef struct aggr_held_arg_s { 1323*5895Syz147064 datalink_id_t aggrid; 1324*5895Syz147064 boolean_t isheld; 1325*5895Syz147064 } aggr_held_arg_t; 1326*5895Syz147064 1327*5895Syz147064 static int 1328*5895Syz147064 i_dladm_aggr_is_held(datalink_id_t linkid, void *arg) 1329*5895Syz147064 { 1330*5895Syz147064 aggr_held_arg_t *aggr_held_arg = arg; 1331*5895Syz147064 dladm_vlan_attr_t dva; 1332*5895Syz147064 1333*5895Syz147064 if (dladm_vlan_info(linkid, &dva, DLADM_OPT_PERSIST) != DLADM_STATUS_OK) 1334*5895Syz147064 return (DLADM_WALK_CONTINUE); 1335*5895Syz147064 1336*5895Syz147064 if (dva.dv_linkid == aggr_held_arg->aggrid) { 1337*5895Syz147064 /* 1338*5895Syz147064 * This VLAN is created over the given aggregation. 1339*5895Syz147064 */ 1340*5895Syz147064 aggr_held_arg->isheld = B_TRUE; 1341*5895Syz147064 return (DLADM_WALK_TERMINATE); 1342*5895Syz147064 } 1343*5895Syz147064 return (DLADM_WALK_CONTINUE); 1344*5895Syz147064 } 1345*5895Syz147064 13463871Syz147064 /* 1347*5895Syz147064 * Delete a previously created link aggregation group. Either the name "aggr" 1348*5895Syz147064 * or the "key" is specified. 13493871Syz147064 */ 13503871Syz147064 dladm_status_t 1351*5895Syz147064 dladm_aggr_delete(datalink_id_t linkid, uint32_t flags) 13523871Syz147064 { 1353*5895Syz147064 laioc_delete_t ioc; 1354*5895Syz147064 datalink_class_t class; 13553871Syz147064 dladm_status_t status; 13563871Syz147064 1357*5895Syz147064 if ((dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0) != 1358*5895Syz147064 DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) { 1359*5895Syz147064 return (DLADM_STATUS_BADARG); 1360*5895Syz147064 } 13613871Syz147064 1362*5895Syz147064 if (flags & DLADM_OPT_ACTIVE) { 1363*5895Syz147064 ioc.ld_linkid = linkid; 1364*5895Syz147064 if ((i_dladm_aggr_strioctl(LAIOC_DELETE, &ioc, 1365*5895Syz147064 sizeof (ioc)) < 0) && 1366*5895Syz147064 ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { 1367*5895Syz147064 status = dladm_errno2status(errno); 1368*5895Syz147064 return (status); 1369*5895Syz147064 } 13703871Syz147064 13713871Syz147064 /* 1372*5895Syz147064 * Delete ACTIVE linkprop first. 13733871Syz147064 */ 1374*5895Syz147064 (void) dladm_set_linkprop(linkid, NULL, NULL, 0, 1375*5895Syz147064 DLADM_OPT_ACTIVE); 1376*5895Syz147064 (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); 13773871Syz147064 } 13783871Syz147064 1379*5895Syz147064 /* 1380*5895Syz147064 * If we reach here, it means that the active aggregation has already 1381*5895Syz147064 * been deleted, and there is no active VLANs holding this aggregation. 1382*5895Syz147064 * Now we see whether there is any persistent VLANs holding this 1383*5895Syz147064 * aggregation. If so, we fail the operation. 1384*5895Syz147064 */ 1385*5895Syz147064 if (flags & DLADM_OPT_PERSIST) { 1386*5895Syz147064 aggr_held_arg_t arg; 1387*5895Syz147064 1388*5895Syz147064 arg.aggrid = linkid; 1389*5895Syz147064 arg.isheld = B_FALSE; 13903871Syz147064 1391*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_aggr_is_held, 1392*5895Syz147064 &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 1393*5895Syz147064 DLADM_OPT_PERSIST); 1394*5895Syz147064 if (arg.isheld) 1395*5895Syz147064 return (DLADM_STATUS_LINKBUSY); 1396*5895Syz147064 1397*5895Syz147064 (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); 1398*5895Syz147064 (void) dladm_remove_conf(linkid); 1399*5895Syz147064 } 1400*5895Syz147064 1401*5895Syz147064 return (DLADM_STATUS_OK); 14023871Syz147064 } 14033871Syz147064 14043871Syz147064 /* 14053871Syz147064 * Add one or more ports to an existing link aggregation. 14063871Syz147064 */ 14073871Syz147064 dladm_status_t 1408*5895Syz147064 dladm_aggr_add(datalink_id_t linkid, uint32_t nports, 1409*5895Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags) 14103871Syz147064 { 1411*5895Syz147064 return (i_dladm_aggr_add_rmv(linkid, nports, ports, flags, LAIOC_ADD)); 14123871Syz147064 } 14133871Syz147064 14143871Syz147064 /* 14153871Syz147064 * Remove one or more ports from an existing link aggregation. 14163871Syz147064 */ 14173871Syz147064 dladm_status_t 1418*5895Syz147064 dladm_aggr_remove(datalink_id_t linkid, uint32_t nports, 1419*5895Syz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags) 14203871Syz147064 { 1421*5895Syz147064 return (i_dladm_aggr_add_rmv(linkid, nports, ports, flags, 1422*5895Syz147064 LAIOC_REMOVE)); 1423*5895Syz147064 } 14243871Syz147064 1425*5895Syz147064 typedef struct i_walk_key_state_s { 1426*5895Syz147064 uint16_t key; 1427*5895Syz147064 datalink_id_t linkid; 1428*5895Syz147064 boolean_t found; 1429*5895Syz147064 } i_walk_key_state_t; 14303871Syz147064 1431*5895Syz147064 static int 1432*5895Syz147064 i_dladm_walk_key2linkid(datalink_id_t linkid, void *arg) 1433*5895Syz147064 { 1434*5895Syz147064 dladm_conf_t conf; 1435*5895Syz147064 uint16_t key; 1436*5895Syz147064 dladm_status_t status; 1437*5895Syz147064 i_walk_key_state_t *statep = (i_walk_key_state_t *)arg; 1438*5895Syz147064 uint64_t u64; 14393871Syz147064 1440*5895Syz147064 if (dladm_read_conf(linkid, &conf) != 0) 1441*5895Syz147064 return (DLADM_WALK_CONTINUE); 1442*5895Syz147064 1443*5895Syz147064 status = dladm_get_conf_field(conf, FKEY, &u64, sizeof (u64)); 1444*5895Syz147064 key = (uint16_t)u64; 1445*5895Syz147064 dladm_destroy_conf(conf); 1446*5895Syz147064 1447*5895Syz147064 if ((status == DLADM_STATUS_OK) && (key == statep->key)) { 1448*5895Syz147064 statep->found = B_TRUE; 1449*5895Syz147064 statep->linkid = linkid; 1450*5895Syz147064 return (DLADM_WALK_TERMINATE); 14513871Syz147064 } 14523871Syz147064 1453*5895Syz147064 return (DLADM_WALK_CONTINUE); 1454*5895Syz147064 } 1455*5895Syz147064 1456*5895Syz147064 dladm_status_t 1457*5895Syz147064 dladm_key2linkid(uint16_t key, datalink_id_t *linkidp, uint32_t flags) 1458*5895Syz147064 { 1459*5895Syz147064 i_walk_key_state_t state; 1460*5895Syz147064 1461*5895Syz147064 if (key > AGGR_MAX_KEY) 1462*5895Syz147064 return (DLADM_STATUS_NOTFOUND); 14633871Syz147064 1464*5895Syz147064 state.found = B_FALSE; 1465*5895Syz147064 state.key = key; 1466*5895Syz147064 1467*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, &state, 1468*5895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 1469*5895Syz147064 if (state.found == B_TRUE) { 1470*5895Syz147064 *linkidp = state.linkid; 1471*5895Syz147064 return (DLADM_STATUS_OK); 1472*5895Syz147064 } else { 1473*5895Syz147064 return (DLADM_STATUS_NOTFOUND); 1474*5895Syz147064 } 14753871Syz147064 } 1476