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