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