1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2311 seb * Common Development and Distribution License (the "License"). 6 2311 seb * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 9815 Rishi * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <stdio.h> 27 0 stevel #include <sys/types.h> 28 0 stevel #include <sys/stat.h> 29 0 stevel #include <string.h> 30 0 stevel #include <fcntl.h> 31 0 stevel #include <unistd.h> 32 0 stevel #include <stropts.h> 33 0 stevel #include <stdlib.h> 34 0 stevel #include <errno.h> 35 5895 yz147064 #include <assert.h> 36 0 stevel #include <strings.h> 37 0 stevel #include <libintl.h> 38 0 stevel #include <net/if_types.h> 39 0 stevel #include <net/if_dl.h> 40 8275 Eric #include <sys/dld.h> 41 5895 yz147064 #include <libdllink.h> 42 5895 yz147064 #include <libdlvlan.h> 43 3871 yz147064 #include <libdlaggr.h> 44 3871 yz147064 #include <libdladm_impl.h> 45 0 stevel 46 0 stevel /* 47 0 stevel * Link Aggregation Administration Library. 48 0 stevel * 49 0 stevel * This library is used by administration tools such as dladm(1M) to 50 0 stevel * configure link aggregations. 51 0 stevel */ 52 0 stevel 53 0 stevel /* Limits on buffer size for LAIOC_INFO request */ 54 0 stevel #define MIN_INFO_SIZE (4*1024) 55 0 stevel #define MAX_INFO_SIZE (128*1024) 56 0 stevel 57 5895 yz147064 static uchar_t zero_mac[] = {0, 0, 0, 0, 0, 0}; 58 5895 yz147064 #define VALID_PORT_MAC(mac) \ 59 5895 yz147064 (((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) && \ 60 5895 yz147064 (!(mac)[0] & 0x01)) 61 0 stevel 62 10616 Sebastien #define PORT_DELIMITER ":" 63 0 stevel 64 3871 yz147064 typedef struct dladm_aggr_modify_attr { 65 0 stevel uint32_t ld_policy; 66 0 stevel boolean_t ld_mac_fixed; 67 0 stevel uchar_t ld_mac[ETHERADDRL]; 68 0 stevel aggr_lacp_mode_t ld_lacp_mode; 69 0 stevel aggr_lacp_timer_t ld_lacp_timer; 70 3871 yz147064 } dladm_aggr_modify_attr_t; 71 0 stevel 72 0 stevel typedef struct policy_s { 73 0 stevel char *pol_name; 74 0 stevel uint32_t policy; 75 0 stevel } policy_t; 76 0 stevel 77 0 stevel static policy_t policies[] = { 78 0 stevel {"L2", AGGR_POLICY_L2}, 79 0 stevel {"L3", AGGR_POLICY_L3}, 80 0 stevel {"L4", AGGR_POLICY_L4}}; 81 0 stevel 82 0 stevel #define NPOLICIES (sizeof (policies) / sizeof (policy_t)) 83 0 stevel 84 3871 yz147064 typedef struct dladm_aggr_lacpmode_s { 85 0 stevel char *mode_str; 86 0 stevel aggr_lacp_mode_t mode_id; 87 3871 yz147064 } dladm_aggr_lacpmode_t; 88 0 stevel 89 3871 yz147064 static dladm_aggr_lacpmode_t lacp_modes[] = { 90 0 stevel {"off", AGGR_LACP_OFF}, 91 0 stevel {"active", AGGR_LACP_ACTIVE}, 92 0 stevel {"passive", AGGR_LACP_PASSIVE}}; 93 0 stevel 94 3871 yz147064 #define NLACP_MODES (sizeof (lacp_modes) / sizeof (dladm_aggr_lacpmode_t)) 95 0 stevel 96 3871 yz147064 typedef struct dladm_aggr_lacptimer_s { 97 0 stevel char *lt_str; 98 0 stevel aggr_lacp_timer_t lt_id; 99 3871 yz147064 } dladm_aggr_lacptimer_t; 100 0 stevel 101 3871 yz147064 static dladm_aggr_lacptimer_t lacp_timers[] = { 102 0 stevel {"short", AGGR_LACP_TIMER_SHORT}, 103 0 stevel {"long", AGGR_LACP_TIMER_LONG}}; 104 0 stevel 105 3871 yz147064 #define NLACP_TIMERS (sizeof (lacp_timers) / sizeof (dladm_aggr_lacptimer_t)) 106 3871 yz147064 107 3871 yz147064 typedef struct dladm_aggr_port_state { 108 3871 yz147064 char *state_str; 109 3871 yz147064 aggr_port_state_t state_id; 110 3871 yz147064 } dladm_aggr_port_state_t; 111 3871 yz147064 112 3871 yz147064 static dladm_aggr_port_state_t port_states[] = { 113 3871 yz147064 {"standby", AGGR_PORT_STATE_STANDBY }, 114 3871 yz147064 {"attached", AGGR_PORT_STATE_ATTACHED } 115 3871 yz147064 }; 116 3871 yz147064 117 3871 yz147064 #define NPORT_STATES \ 118 3871 yz147064 (sizeof (port_states) / sizeof (dladm_aggr_port_state_t)) 119 10616 Sebastien 120 10616 Sebastien static dladm_status_t 121 10616 Sebastien write_port(dladm_handle_t handle, char *portstr, datalink_id_t portid, 122 10616 Sebastien size_t portstrsize) 123 10616 Sebastien { 124 10616 Sebastien char pname[MAXLINKNAMELEN + 1]; 125 10616 Sebastien dladm_status_t status; 126 10616 Sebastien 127 10616 Sebastien if ((status = dladm_datalink_id2info(handle, portid, NULL, NULL, NULL, 128 10616 Sebastien pname, sizeof (pname))) != DLADM_STATUS_OK) 129 10616 Sebastien return (status); 130 10616 Sebastien (void) strlcat(pname, PORT_DELIMITER, sizeof (pname)); 131 10616 Sebastien if (strlcat(portstr, pname, portstrsize) >= portstrsize) 132 10616 Sebastien status = DLADM_STATUS_TOOSMALL; 133 10616 Sebastien return (status); 134 10616 Sebastien } 135 10616 Sebastien 136 10616 Sebastien static dladm_status_t 137 10616 Sebastien read_port(dladm_handle_t handle, char **portstr, datalink_id_t *portid) 138 10616 Sebastien { 139 10616 Sebastien dladm_status_t status; 140 10616 Sebastien char *pname; 141 10616 Sebastien 142 10616 Sebastien if ((pname = strtok(*portstr, PORT_DELIMITER)) == NULL) 143 10616 Sebastien return (DLADM_STATUS_REPOSITORYINVAL); 144 10616 Sebastien *portstr += (strlen(pname) + 1); 145 10616 Sebastien status = dladm_name2info(handle, pname, portid, NULL, NULL, NULL); 146 10616 Sebastien return (status); 147 10616 Sebastien } 148 0 stevel 149 5895 yz147064 static int 150 8453 Anurag i_dladm_aggr_ioctl(dladm_handle_t handle, int cmd, void *ptr) 151 5895 yz147064 { 152 8453 Anurag return (ioctl(dladm_dld_fd(handle), cmd, ptr)); 153 0 stevel } 154 0 stevel 155 0 stevel /* 156 5895 yz147064 * Caller must free attr.lg_ports. The ptr pointer is advanced while convert 157 5895 yz147064 * the laioc_info_t to the dladm_aggr_grp_attr_t structure. 158 0 stevel */ 159 5895 yz147064 static int 160 5895 yz147064 i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp) 161 0 stevel { 162 5895 yz147064 laioc_info_group_t *grp; 163 5895 yz147064 laioc_info_port_t *port; 164 5895 yz147064 int i; 165 5895 yz147064 void *where = (*ptr); 166 0 stevel 167 5895 yz147064 grp = (laioc_info_group_t *)where; 168 0 stevel 169 5895 yz147064 attrp->lg_linkid = grp->lg_linkid; 170 5895 yz147064 attrp->lg_key = grp->lg_key; 171 5895 yz147064 attrp->lg_nports = grp->lg_nports; 172 5895 yz147064 attrp->lg_policy = grp->lg_policy; 173 5895 yz147064 attrp->lg_lacp_mode = grp->lg_lacp_mode; 174 5895 yz147064 attrp->lg_lacp_timer = grp->lg_lacp_timer; 175 5895 yz147064 attrp->lg_force = grp->lg_force; 176 0 stevel 177 5895 yz147064 bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL); 178 5895 yz147064 attrp->lg_mac_fixed = grp->lg_mac_fixed; 179 5895 yz147064 180 5895 yz147064 if ((attrp->lg_ports = malloc(grp->lg_nports * 181 5895 yz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) { 182 5895 yz147064 errno = ENOMEM; 183 5895 yz147064 goto fail; 184 5895 yz147064 } 185 5895 yz147064 186 5895 yz147064 where = (grp + 1); 187 5895 yz147064 188 5895 yz147064 /* 189 5895 yz147064 * Go through each port that is part of the group. 190 5895 yz147064 */ 191 5895 yz147064 for (i = 0; i < grp->lg_nports; i++) { 192 5895 yz147064 port = (laioc_info_port_t *)where; 193 5895 yz147064 194 5895 yz147064 attrp->lg_ports[i].lp_linkid = port->lp_linkid; 195 5895 yz147064 bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL); 196 5895 yz147064 attrp->lg_ports[i].lp_state = port->lp_state; 197 5895 yz147064 attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state; 198 5895 yz147064 199 5895 yz147064 where = (port + 1); 200 5895 yz147064 } 201 5895 yz147064 *ptr = where; 202 5895 yz147064 return (0); 203 5895 yz147064 fail: 204 5895 yz147064 return (-1); 205 0 stevel } 206 0 stevel 207 0 stevel /* 208 5895 yz147064 * Get active configuration of a specific aggregation. 209 5895 yz147064 * Caller must free attrp->la_ports. 210 0 stevel */ 211 5895 yz147064 static dladm_status_t 212 8453 Anurag i_dladm_aggr_info_active(dladm_handle_t handle, datalink_id_t linkid, 213 8453 Anurag dladm_aggr_grp_attr_t *attrp) 214 0 stevel { 215 0 stevel laioc_info_t *ioc; 216 7408 Sebastien int bufsize; 217 5895 yz147064 void *where; 218 5895 yz147064 dladm_status_t status = DLADM_STATUS_OK; 219 0 stevel 220 0 stevel bufsize = MIN_INFO_SIZE; 221 0 stevel ioc = (laioc_info_t *)calloc(1, bufsize); 222 5895 yz147064 if (ioc == NULL) 223 5895 yz147064 return (DLADM_STATUS_NOMEM); 224 5895 yz147064 225 5895 yz147064 ioc->li_group_linkid = linkid; 226 0 stevel 227 0 stevel tryagain: 228 7408 Sebastien ioc->li_bufsize = bufsize; 229 8453 Anurag if (i_dladm_aggr_ioctl(handle, LAIOC_INFO, ioc) != 0) { 230 0 stevel if (errno == ENOSPC) { 231 0 stevel /* 232 0 stevel * The LAIOC_INFO call failed due to a short 233 0 stevel * buffer. Reallocate the buffer and try again. 234 0 stevel */ 235 0 stevel bufsize *= 2; 236 0 stevel if (bufsize <= MAX_INFO_SIZE) { 237 0 stevel ioc = (laioc_info_t *)realloc(ioc, bufsize); 238 0 stevel if (ioc != NULL) { 239 0 stevel bzero(ioc, sizeof (bufsize)); 240 0 stevel goto tryagain; 241 0 stevel } 242 0 stevel } 243 0 stevel } 244 5895 yz147064 status = dladm_errno2status(errno); 245 0 stevel goto bail; 246 0 stevel } 247 0 stevel 248 0 stevel /* 249 0 stevel * Go through each group returned by the aggregation driver. 250 0 stevel */ 251 0 stevel where = (char *)(ioc + 1); 252 5895 yz147064 if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) { 253 5895 yz147064 status = dladm_errno2status(errno); 254 5895 yz147064 goto bail; 255 0 stevel } 256 0 stevel 257 0 stevel bail: 258 0 stevel free(ioc); 259 3871 yz147064 return (status); 260 0 stevel } 261 0 stevel 262 0 stevel /* 263 5895 yz147064 * Get configuration information of a specific aggregation. 264 5895 yz147064 * Caller must free attrp->la_ports. 265 0 stevel */ 266 3871 yz147064 static dladm_status_t 267 8453 Anurag i_dladm_aggr_info_persist(dladm_handle_t handle, datalink_id_t linkid, 268 8453 Anurag dladm_aggr_grp_attr_t *attrp) 269 0 stevel { 270 5895 yz147064 dladm_conf_t conf; 271 5895 yz147064 uint32_t nports, i; 272 10616 Sebastien char *portstr = NULL, *next; 273 5895 yz147064 dladm_status_t status; 274 5895 yz147064 uint64_t u64; 275 5895 yz147064 int size; 276 5895 yz147064 char macstr[ETHERADDRL * 3]; 277 0 stevel 278 5895 yz147064 attrp->lg_linkid = linkid; 279 8453 Anurag if ((status = dladm_read_conf(handle, linkid, &conf)) != 280 8453 Anurag DLADM_STATUS_OK) 281 5895 yz147064 return (status); 282 5895 yz147064 283 8453 Anurag status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64)); 284 5895 yz147064 if (status != DLADM_STATUS_OK) 285 5895 yz147064 goto done; 286 5895 yz147064 attrp->lg_key = (uint16_t)u64; 287 5895 yz147064 288 8453 Anurag status = dladm_get_conf_field(handle, conf, FPOLICY, &u64, 289 8453 Anurag sizeof (u64)); 290 5895 yz147064 if (status != DLADM_STATUS_OK) 291 5895 yz147064 goto done; 292 5895 yz147064 attrp->lg_policy = (uint32_t)u64; 293 5895 yz147064 294 8453 Anurag status = dladm_get_conf_field(handle, conf, FFIXMACADDR, 295 8453 Anurag &attrp->lg_mac_fixed, sizeof (boolean_t)); 296 5895 yz147064 if (status != DLADM_STATUS_OK) 297 5895 yz147064 goto done; 298 5895 yz147064 299 5895 yz147064 if (attrp->lg_mac_fixed) { 300 5895 yz147064 boolean_t fixed; 301 5895 yz147064 302 8453 Anurag if ((status = dladm_get_conf_field(handle, conf, FMACADDR, 303 8453 Anurag macstr, sizeof (macstr))) != DLADM_STATUS_OK) { 304 5895 yz147064 goto done; 305 5895 yz147064 } 306 5895 yz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) { 307 5895 yz147064 status = DLADM_STATUS_REPOSITORYINVAL; 308 5895 yz147064 goto done; 309 5895 yz147064 } 310 5895 yz147064 } 311 5895 yz147064 312 8453 Anurag status = dladm_get_conf_field(handle, conf, FFORCE, &attrp->lg_force, 313 5895 yz147064 sizeof (boolean_t)); 314 5895 yz147064 if (status != DLADM_STATUS_OK) 315 5895 yz147064 goto done; 316 5895 yz147064 317 8453 Anurag status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64, 318 8453 Anurag sizeof (u64)); 319 5895 yz147064 if (status != DLADM_STATUS_OK) 320 5895 yz147064 goto done; 321 5895 yz147064 attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64; 322 5895 yz147064 323 8453 Anurag status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64, 324 8453 Anurag sizeof (u64)); 325 5895 yz147064 if (status != DLADM_STATUS_OK) 326 5895 yz147064 goto done; 327 5895 yz147064 attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64; 328 5895 yz147064 329 8453 Anurag status = dladm_get_conf_field(handle, conf, FNPORTS, &u64, 330 8453 Anurag sizeof (u64)); 331 5895 yz147064 if (status != DLADM_STATUS_OK) 332 5895 yz147064 goto done; 333 5895 yz147064 nports = (uint32_t)u64; 334 5895 yz147064 attrp->lg_nports = nports; 335 5895 yz147064 336 10616 Sebastien size = nports * (MAXLINKNAMELEN + 1) + 1; 337 5895 yz147064 if ((portstr = calloc(1, size)) == NULL) { 338 3871 yz147064 status = DLADM_STATUS_NOMEM; 339 3871 yz147064 goto done; 340 3871 yz147064 } 341 0 stevel 342 8453 Anurag status = dladm_get_conf_field(handle, conf, FPORTS, portstr, size); 343 10616 Sebastien if (status != DLADM_STATUS_OK) 344 5895 yz147064 goto done; 345 0 stevel 346 5895 yz147064 if ((attrp->lg_ports = malloc(nports * 347 5895 yz147064 sizeof (dladm_aggr_port_attr_t))) == NULL) { 348 5895 yz147064 status = DLADM_STATUS_NOMEM; 349 5895 yz147064 goto done; 350 5895 yz147064 } 351 5895 yz147064 352 5895 yz147064 for (next = portstr, i = 0; i < nports; i++) { 353 10616 Sebastien if ((status = read_port(handle, &next, 354 10616 Sebastien &attrp->lg_ports[i].lp_linkid)) != DLADM_STATUS_OK) 355 5895 yz147064 free(attrp->lg_ports); 356 0 stevel } 357 0 stevel 358 5895 yz147064 done: 359 10616 Sebastien free(portstr); 360 8453 Anurag dladm_destroy_conf(handle, conf); 361 5895 yz147064 return (status); 362 5895 yz147064 } 363 5895 yz147064 364 5895 yz147064 dladm_status_t 365 8453 Anurag dladm_aggr_info(dladm_handle_t handle, datalink_id_t linkid, 366 8453 Anurag dladm_aggr_grp_attr_t *attrp, uint32_t flags) 367 5895 yz147064 { 368 5895 yz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 369 5895 yz147064 if (flags == DLADM_OPT_ACTIVE) 370 8453 Anurag return (i_dladm_aggr_info_active(handle, linkid, attrp)); 371 5895 yz147064 else 372 8453 Anurag return (i_dladm_aggr_info_persist(handle, linkid, attrp)); 373 5895 yz147064 } 374 5895 yz147064 375 5895 yz147064 /* 376 5895 yz147064 * Add or remove one or more ports to/from an existing link aggregation. 377 5895 yz147064 */ 378 5895 yz147064 static dladm_status_t 379 8453 Anurag i_dladm_aggr_add_rmv(dladm_handle_t handle, datalink_id_t linkid, 380 8453 Anurag uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd) 381 5895 yz147064 { 382 5895 yz147064 char *orig_portstr = NULL, *portstr = NULL; 383 6077 yz147064 laioc_add_rem_t *iocp = NULL; 384 5895 yz147064 laioc_port_t *ioc_ports; 385 5895 yz147064 uint32_t orig_nports, result_nports, len, i, j; 386 5895 yz147064 dladm_conf_t conf; 387 5895 yz147064 datalink_class_t class; 388 5895 yz147064 dladm_status_t status = DLADM_STATUS_OK; 389 5895 yz147064 int size; 390 5895 yz147064 uint64_t u64; 391 5895 yz147064 uint32_t media; 392 5895 yz147064 393 5895 yz147064 if (nports == 0) 394 5895 yz147064 return (DLADM_STATUS_BADARG); 395 5895 yz147064 396 5895 yz147064 /* 397 5895 yz147064 * Sanity check - aggregations can only be created over Ethernet 398 9815 Rishi * physical links and simnets. 399 5895 yz147064 */ 400 5895 yz147064 for (i = 0; i < nports; i++) { 401 8453 Anurag if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL, 402 5895 yz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) || 403 9815 Rishi !((class == DATALINK_CLASS_PHYS) || 404 9815 Rishi (class == DATALINK_CLASS_SIMNET)) || (media != DL_ETHER)) { 405 5895 yz147064 return (DLADM_STATUS_BADARG); 406 5895 yz147064 } 407 5895 yz147064 } 408 5895 yz147064 409 5895 yz147064 /* 410 5895 yz147064 * First, update the persistent configuration if requested. We only 411 5895 yz147064 * need to update the FPORTS and FNPORTS fields of this aggregation. 412 5895 yz147064 * Note that FPORTS is a list of port linkids separated by 413 10616 Sebastien * PORT_DELIMITER (':'). 414 5895 yz147064 */ 415 5895 yz147064 if (flags & DLADM_OPT_PERSIST) { 416 8453 Anurag status = dladm_read_conf(handle, linkid, &conf); 417 5895 yz147064 if (status != DLADM_STATUS_OK) 418 5895 yz147064 return (status); 419 5895 yz147064 420 5895 yz147064 /* 421 5895 yz147064 * Get the original configuration of FNPORTS and FPORTS. 422 5895 yz147064 */ 423 8453 Anurag status = dladm_get_conf_field(handle, conf, FNPORTS, &u64, 424 5895 yz147064 sizeof (u64)); 425 5895 yz147064 if (status != DLADM_STATUS_OK) 426 5895 yz147064 goto destroyconf; 427 5895 yz147064 orig_nports = (uint32_t)u64; 428 5895 yz147064 429 5895 yz147064 /* 430 5895 yz147064 * At least one port needs to be in the aggregation. 431 5895 yz147064 */ 432 5895 yz147064 if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) { 433 5895 yz147064 status = DLADM_STATUS_BADARG; 434 5895 yz147064 goto destroyconf; 435 5895 yz147064 } 436 5895 yz147064 437 10616 Sebastien size = orig_nports * (MAXLINKNAMELEN + 1) + 1; 438 5895 yz147064 if ((orig_portstr = calloc(1, size)) == NULL) { 439 5895 yz147064 status = dladm_errno2status(errno); 440 5895 yz147064 goto destroyconf; 441 5895 yz147064 } 442 5895 yz147064 443 8453 Anurag status = dladm_get_conf_field(handle, conf, FPORTS, 444 8453 Anurag orig_portstr, size); 445 5895 yz147064 if (status != DLADM_STATUS_OK) 446 5895 yz147064 goto destroyconf; 447 5895 yz147064 448 5895 yz147064 result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports : 449 5895 yz147064 orig_nports; 450 5895 yz147064 451 10616 Sebastien size = result_nports * (MAXLINKNAMELEN + 1) + 1; 452 5895 yz147064 if ((portstr = calloc(1, size)) == NULL) { 453 5895 yz147064 status = dladm_errno2status(errno); 454 5895 yz147064 goto destroyconf; 455 5895 yz147064 } 456 5895 yz147064 457 5895 yz147064 /* 458 5895 yz147064 * get the new configuration and set to result_nports and 459 5895 yz147064 * portstr. 460 5895 yz147064 */ 461 5895 yz147064 if (cmd == LAIOC_ADD) { 462 5895 yz147064 (void) strlcpy(portstr, orig_portstr, size); 463 10616 Sebastien for (i = 0; i < nports; i++) { 464 10616 Sebastien status = write_port(handle, portstr, 465 10616 Sebastien ports[i].lp_linkid, size); 466 10616 Sebastien if (status != DLADM_STATUS_OK) { 467 10616 Sebastien free(portstr); 468 10616 Sebastien goto destroyconf; 469 10616 Sebastien } 470 10616 Sebastien } 471 5895 yz147064 } else { 472 5895 yz147064 char *next; 473 5895 yz147064 datalink_id_t portid; 474 5895 yz147064 uint32_t remove = 0; 475 5895 yz147064 476 5895 yz147064 for (next = orig_portstr, j = 0; j < orig_nports; j++) { 477 5895 yz147064 /* 478 5895 yz147064 * Read the portids from the old configuration 479 5895 yz147064 * one by one. 480 5895 yz147064 */ 481 10616 Sebastien status = read_port(handle, &next, &portid); 482 5895 yz147064 if (status != DLADM_STATUS_OK) { 483 5895 yz147064 free(portstr); 484 5895 yz147064 goto destroyconf; 485 5895 yz147064 } 486 5895 yz147064 487 5895 yz147064 /* 488 5895 yz147064 * See whether this port is in the removal 489 5895 yz147064 * list. If not, copy to the new config. 490 5895 yz147064 */ 491 5895 yz147064 for (i = 0; i < nports; i++) { 492 5895 yz147064 if (ports[i].lp_linkid == portid) 493 5895 yz147064 break; 494 5895 yz147064 } 495 5895 yz147064 if (i == nports) { 496 10616 Sebastien status = write_port(handle, portstr, 497 10616 Sebastien portid, size); 498 10616 Sebastien if (status != DLADM_STATUS_OK) { 499 10616 Sebastien free(portstr); 500 10616 Sebastien goto destroyconf; 501 10616 Sebastien } 502 5895 yz147064 } else { 503 5895 yz147064 remove++; 504 5895 yz147064 } 505 5895 yz147064 } 506 5895 yz147064 if (remove != nports) { 507 5895 yz147064 status = DLADM_STATUS_LINKINVAL; 508 5895 yz147064 free(portstr); 509 5895 yz147064 goto destroyconf; 510 5895 yz147064 } 511 5895 yz147064 result_nports -= nports; 512 5895 yz147064 } 513 5895 yz147064 514 5895 yz147064 u64 = result_nports; 515 8453 Anurag if ((status = dladm_set_conf_field(handle, conf, FNPORTS, 516 5895 yz147064 DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) { 517 5895 yz147064 free(portstr); 518 5895 yz147064 goto destroyconf; 519 5895 yz147064 } 520 5895 yz147064 521 8453 Anurag status = dladm_set_conf_field(handle, conf, FPORTS, 522 8453 Anurag DLADM_TYPE_STR, portstr); 523 5895 yz147064 free(portstr); 524 5895 yz147064 if (status != DLADM_STATUS_OK) 525 5895 yz147064 goto destroyconf; 526 5895 yz147064 527 5895 yz147064 /* 528 5895 yz147064 * Write the new configuration to the persistent repository. 529 5895 yz147064 */ 530 8453 Anurag status = dladm_write_conf(handle, conf); 531 5895 yz147064 532 5895 yz147064 destroyconf: 533 8453 Anurag dladm_destroy_conf(handle, conf); 534 5895 yz147064 if (status != DLADM_STATUS_OK) { 535 5895 yz147064 free(orig_portstr); 536 5895 yz147064 return (status); 537 5895 yz147064 } 538 5895 yz147064 } 539 5895 yz147064 540 5895 yz147064 /* 541 5895 yz147064 * If the caller only requested to update the persistent 542 5895 yz147064 * configuration, we are done. 543 5895 yz147064 */ 544 5895 yz147064 if (!(flags & DLADM_OPT_ACTIVE)) 545 5895 yz147064 goto done; 546 5895 yz147064 547 5895 yz147064 /* 548 5895 yz147064 * Update the active configuration. 549 5895 yz147064 */ 550 5895 yz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t); 551 5895 yz147064 if ((iocp = malloc(len)) == NULL) { 552 5895 yz147064 status = DLADM_STATUS_NOMEM; 553 3871 yz147064 goto done; 554 0 stevel } 555 0 stevel 556 5895 yz147064 iocp->la_linkid = linkid; 557 5895 yz147064 iocp->la_nports = nports; 558 5895 yz147064 if (cmd == LAIOC_ADD) 559 5895 yz147064 iocp->la_force = (flags & DLADM_OPT_FORCE); 560 0 stevel 561 5895 yz147064 ioc_ports = (laioc_port_t *)(iocp + 1); 562 5895 yz147064 for (i = 0; i < nports; i++) 563 5895 yz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid; 564 5895 yz147064 565 8453 Anurag if (i_dladm_aggr_ioctl(handle, cmd, iocp) < 0) 566 5895 yz147064 status = dladm_errno2status(errno); 567 0 stevel 568 3871 yz147064 done: 569 269 ericheng free(iocp); 570 5895 yz147064 571 5895 yz147064 /* 572 5895 yz147064 * If the active configuration update fails, restore the old 573 5895 yz147064 * persistent configuration if we've changed that. 574 5895 yz147064 */ 575 5895 yz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { 576 8453 Anurag if (dladm_read_conf(handle, linkid, &conf) == DLADM_STATUS_OK) { 577 5895 yz147064 u64 = orig_nports; 578 8453 Anurag if ((dladm_set_conf_field(handle, conf, FNPORTS, 579 5895 yz147064 DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) && 580 8453 Anurag (dladm_set_conf_field(handle, conf, FPORTS, 581 8453 Anurag DLADM_TYPE_STR, orig_portstr) == DLADM_STATUS_OK)) { 582 8453 Anurag (void) dladm_write_conf(handle, conf); 583 5895 yz147064 } 584 8453 Anurag (void) dladm_destroy_conf(handle, conf); 585 5895 yz147064 } 586 5895 yz147064 } 587 5895 yz147064 free(orig_portstr); 588 3871 yz147064 return (status); 589 0 stevel } 590 0 stevel 591 0 stevel /* 592 0 stevel * Send a modify command to the link aggregation driver. 593 0 stevel */ 594 3871 yz147064 static dladm_status_t 595 8453 Anurag i_dladm_aggr_modify_sys(dladm_handle_t handle, datalink_id_t linkid, 596 8453 Anurag uint32_t mask, dladm_aggr_modify_attr_t *attr) 597 0 stevel { 598 0 stevel laioc_modify_t ioc; 599 0 stevel 600 5895 yz147064 ioc.lu_linkid = linkid; 601 0 stevel 602 0 stevel ioc.lu_modify_mask = 0; 603 3871 yz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) 604 0 stevel ioc.lu_modify_mask |= LAIOC_MODIFY_POLICY; 605 3871 yz147064 if (mask & DLADM_AGGR_MODIFY_MAC) 606 0 stevel ioc.lu_modify_mask |= LAIOC_MODIFY_MAC; 607 3871 yz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) 608 0 stevel ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_MODE; 609 3871 yz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) 610 0 stevel ioc.lu_modify_mask |= LAIOC_MODIFY_LACP_TIMER; 611 0 stevel 612 0 stevel ioc.lu_policy = attr->ld_policy; 613 0 stevel ioc.lu_mac_fixed = attr->ld_mac_fixed; 614 0 stevel bcopy(attr->ld_mac, ioc.lu_mac, ETHERADDRL); 615 0 stevel ioc.lu_lacp_mode = attr->ld_lacp_mode; 616 0 stevel ioc.lu_lacp_timer = attr->ld_lacp_timer; 617 0 stevel 618 8453 Anurag if (i_dladm_aggr_ioctl(handle, LAIOC_MODIFY, &ioc) < 0) { 619 3871 yz147064 if (errno == EINVAL) 620 5895 yz147064 return (DLADM_STATUS_MACADDRINVAL); 621 3871 yz147064 else 622 5895 yz147064 return (dladm_errno2status(errno)); 623 5895 yz147064 } else { 624 5895 yz147064 return (DLADM_STATUS_OK); 625 0 stevel } 626 0 stevel } 627 0 stevel 628 0 stevel /* 629 0 stevel * Send a create command to the link aggregation driver. 630 0 stevel */ 631 3871 yz147064 static dladm_status_t 632 8453 Anurag i_dladm_aggr_create_sys(dladm_handle_t handle, datalink_id_t linkid, 633 8453 Anurag uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, 634 8453 Anurag uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr, 635 5895 yz147064 aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force) 636 0 stevel { 637 7408 Sebastien int i, len; 638 5895 yz147064 laioc_create_t *iocp = NULL; 639 5895 yz147064 laioc_port_t *ioc_ports; 640 3871 yz147064 dladm_status_t status = DLADM_STATUS_OK; 641 0 stevel 642 5895 yz147064 len = sizeof (*iocp) + nports * sizeof (laioc_port_t); 643 269 ericheng iocp = malloc(len); 644 269 ericheng if (iocp == NULL) 645 3871 yz147064 return (DLADM_STATUS_NOMEM); 646 0 stevel 647 5895 yz147064 iocp->lc_key = key; 648 5895 yz147064 iocp->lc_linkid = linkid; 649 5895 yz147064 iocp->lc_nports = nports; 650 5895 yz147064 iocp->lc_policy = policy; 651 5895 yz147064 iocp->lc_lacp_mode = lacp_mode; 652 5895 yz147064 iocp->lc_lacp_timer = lacp_timer; 653 5895 yz147064 ioc_ports = (laioc_port_t *)(iocp + 1); 654 5895 yz147064 iocp->lc_force = force; 655 269 ericheng 656 5895 yz147064 for (i = 0; i < nports; i++) 657 5895 yz147064 ioc_ports[i].lp_linkid = ports[i].lp_linkid; 658 0 stevel 659 5895 yz147064 if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) { 660 5895 yz147064 status = DLADM_STATUS_MACADDRINVAL; 661 5895 yz147064 goto done; 662 0 stevel } 663 0 stevel 664 5895 yz147064 bcopy(mac_addr, iocp->lc_mac, ETHERADDRL); 665 5895 yz147064 iocp->lc_mac_fixed = mac_addr_fixed; 666 0 stevel 667 8453 Anurag if (i_dladm_aggr_ioctl(handle, LAIOC_CREATE, iocp) < 0) 668 5895 yz147064 status = dladm_errno2status(errno); 669 0 stevel 670 5895 yz147064 done: 671 269 ericheng free(iocp); 672 3871 yz147064 return (status); 673 0 stevel } 674 0 stevel 675 0 stevel /* 676 0 stevel * Invoked to bring up a link aggregation group. 677 0 stevel */ 678 5895 yz147064 static int 679 8453 Anurag i_dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) 680 0 stevel { 681 5895 yz147064 dladm_status_t *statusp = (dladm_status_t *)arg; 682 5895 yz147064 dladm_aggr_grp_attr_t attr; 683 5895 yz147064 dladm_aggr_port_attr_db_t *ports = NULL; 684 5895 yz147064 uint16_t key = 0; 685 5895 yz147064 int i, j; 686 5895 yz147064 dladm_status_t status; 687 0 stevel 688 8453 Anurag status = dladm_aggr_info(handle, linkid, &attr, DLADM_OPT_PERSIST); 689 5895 yz147064 if (status != DLADM_STATUS_OK) { 690 5895 yz147064 *statusp = status; 691 5895 yz147064 return (DLADM_WALK_CONTINUE); 692 5895 yz147064 } 693 0 stevel 694 5895 yz147064 if (attr.lg_key <= AGGR_MAX_KEY) 695 5895 yz147064 key = attr.lg_key; 696 0 stevel 697 5895 yz147064 ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t)); 698 5895 yz147064 if (ports == NULL) { 699 5895 yz147064 status = DLADM_STATUS_NOMEM; 700 5895 yz147064 goto done; 701 5895 yz147064 } 702 0 stevel 703 5895 yz147064 /* 704 5895 yz147064 * Validate (and purge) each physical link associated with this 705 5895 yz147064 * aggregation, if the specific hardware has been removed during 706 5895 yz147064 * the system shutdown. 707 5895 yz147064 */ 708 5895 yz147064 for (i = 0, j = 0; i < attr.lg_nports; i++) { 709 5895 yz147064 datalink_id_t portid = attr.lg_ports[i].lp_linkid; 710 5895 yz147064 uint32_t flags; 711 5895 yz147064 dladm_status_t s; 712 5895 yz147064 713 8453 Anurag s = dladm_datalink_id2info(handle, portid, &flags, NULL, NULL, 714 8453 Anurag NULL, 0); 715 5895 yz147064 if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) 716 5895 yz147064 continue; 717 5895 yz147064 718 5895 yz147064 ports[j++].lp_linkid = portid; 719 5895 yz147064 } 720 5895 yz147064 721 5895 yz147064 if (j == 0) { 722 5895 yz147064 /* 723 5895 yz147064 * All of the physical links are removed. 724 5895 yz147064 */ 725 5895 yz147064 status = DLADM_STATUS_BADARG; 726 5895 yz147064 goto done; 727 5895 yz147064 } 728 5895 yz147064 729 5895 yz147064 /* 730 5895 yz147064 * Create active aggregation. 731 5895 yz147064 */ 732 8453 Anurag if ((status = i_dladm_aggr_create_sys(handle, linkid, 733 5895 yz147064 key, j, ports, attr.lg_policy, attr.lg_mac_fixed, 734 5895 yz147064 (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode, 735 5895 yz147064 attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) { 736 5895 yz147064 goto done; 737 5895 yz147064 } 738 5895 yz147064 739 8453 Anurag if ((status = dladm_up_datalink_id(handle, linkid)) != 740 8453 Anurag DLADM_STATUS_OK) { 741 5895 yz147064 laioc_delete_t ioc; 742 10616 Sebastien 743 5895 yz147064 ioc.ld_linkid = linkid; 744 8453 Anurag (void) i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc); 745 5895 yz147064 } 746 5895 yz147064 done: 747 5895 yz147064 free(attr.lg_ports); 748 5895 yz147064 free(ports); 749 5895 yz147064 750 5895 yz147064 *statusp = status; 751 5895 yz147064 return (DLADM_WALK_CONTINUE); 752 0 stevel } 753 0 stevel 754 0 stevel /* 755 5895 yz147064 * Bring up one aggregation, or all persistent aggregations. In the latter 756 5895 yz147064 * case, the walk may terminate early if bringup of an aggregation fails. 757 0 stevel */ 758 3871 yz147064 dladm_status_t 759 8453 Anurag dladm_aggr_up(dladm_handle_t handle, datalink_id_t linkid) 760 0 stevel { 761 3871 yz147064 dladm_status_t status; 762 0 stevel 763 5895 yz147064 if (linkid == DATALINK_ALL_LINKID) { 764 8453 Anurag (void) dladm_walk_datalink_id(i_dladm_aggr_up, handle, &status, 765 5895 yz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 766 5895 yz147064 DLADM_OPT_PERSIST); 767 5895 yz147064 return (DLADM_STATUS_OK); 768 5895 yz147064 } else { 769 8453 Anurag (void) i_dladm_aggr_up(handle, linkid, &status); 770 3871 yz147064 return (status); 771 0 stevel } 772 0 stevel } 773 0 stevel 774 0 stevel /* 775 0 stevel * Given a policy string, return a policy mask. Returns B_TRUE on 776 5895 yz147064 * success, or B_FALSE if an error occurred during parsing. 777 0 stevel */ 778 0 stevel boolean_t 779 3871 yz147064 dladm_aggr_str2policy(const char *str, uint32_t *policy) 780 0 stevel { 781 0 stevel int i; 782 0 stevel policy_t *pol; 783 0 stevel char *token = NULL; 784 0 stevel char *lasts; 785 0 stevel 786 0 stevel *policy = 0; 787 0 stevel 788 0 stevel while ((token = strtok_r((token == NULL) ? (char *)str : NULL, ",", 789 0 stevel &lasts)) != NULL) { 790 0 stevel for (i = 0; i < NPOLICIES; i++) { 791 0 stevel pol = &policies[i]; 792 0 stevel if (strcasecmp(token, pol->pol_name) == 0) { 793 0 stevel *policy |= pol->policy; 794 0 stevel break; 795 0 stevel } 796 0 stevel } 797 0 stevel if (i == NPOLICIES) 798 0 stevel return (B_FALSE); 799 0 stevel } 800 0 stevel 801 0 stevel return (B_TRUE); 802 0 stevel } 803 0 stevel 804 0 stevel /* 805 0 stevel * Given a policy mask, returns a printable string, or NULL if the 806 0 stevel * policy mask is invalid. It is the responsibility of the caller to 807 0 stevel * free the returned string after use. 808 0 stevel */ 809 0 stevel char * 810 3871 yz147064 dladm_aggr_policy2str(uint32_t policy, char *str) 811 0 stevel { 812 0 stevel int i, npolicies = 0; 813 0 stevel policy_t *pol; 814 0 stevel 815 5895 yz147064 if (str == NULL) 816 5895 yz147064 return (NULL); 817 5895 yz147064 818 0 stevel str[0] = '\0'; 819 0 stevel 820 0 stevel for (i = 0; i < NPOLICIES; i++) { 821 0 stevel pol = &policies[i]; 822 0 stevel if ((policy & pol->policy) != 0) { 823 0 stevel npolicies++; 824 0 stevel if (npolicies > 1) 825 5895 yz147064 (void) strlcat(str, ",", DLADM_STRSIZE); 826 5895 yz147064 (void) strlcat(str, pol->pol_name, DLADM_STRSIZE); 827 0 stevel } 828 0 stevel } 829 0 stevel 830 0 stevel return (str); 831 0 stevel } 832 0 stevel 833 0 stevel /* 834 0 stevel * Given a MAC address string, return the MAC address in the mac_addr 835 0 stevel * array. If the MAC address was not explicitly specified, i.e. is 836 0 stevel * equal to 'auto', zero out mac-addr and set mac_fixed to B_TRUE. 837 0 stevel * Return B_FALSE if a syntax error was encountered, B_FALSE otherwise. 838 0 stevel */ 839 0 stevel boolean_t 840 3871 yz147064 dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr) 841 0 stevel { 842 0 stevel uchar_t *conv_str; 843 0 stevel int mac_len; 844 0 stevel 845 0 stevel *mac_fixed = (strcmp(str, "auto") != 0); 846 0 stevel if (!*mac_fixed) { 847 0 stevel bzero(mac_addr, ETHERADDRL); 848 0 stevel return (B_TRUE); 849 0 stevel } 850 0 stevel 851 0 stevel conv_str = _link_aton(str, &mac_len); 852 0 stevel if (conv_str == NULL) 853 0 stevel return (B_FALSE); 854 0 stevel 855 0 stevel if (mac_len != ETHERADDRL) { 856 0 stevel free(conv_str); 857 0 stevel return (B_FALSE); 858 0 stevel } 859 0 stevel 860 449 ericheng if ((bcmp(zero_mac, conv_str, ETHERADDRL) == 0) || 861 449 ericheng (conv_str[0] & 0x01)) { 862 449 ericheng free(conv_str); 863 449 ericheng return (B_FALSE); 864 449 ericheng } 865 449 ericheng 866 0 stevel bcopy(conv_str, mac_addr, ETHERADDRL); 867 0 stevel free(conv_str); 868 0 stevel 869 0 stevel return (B_TRUE); 870 0 stevel } 871 0 stevel 872 0 stevel /* 873 0 stevel * Returns a string containing a printable representation of a MAC address. 874 0 stevel */ 875 0 stevel const char * 876 5895 yz147064 dladm_aggr_macaddr2str(const unsigned char *mac, char *buf) 877 0 stevel { 878 0 stevel static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; 879 0 stevel 880 0 stevel if (buf == NULL) 881 0 stevel return (NULL); 882 0 stevel 883 0 stevel if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) 884 5895 yz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 885 0 stevel else 886 0 stevel return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); 887 5895 yz147064 888 5895 yz147064 return (buf); 889 0 stevel } 890 0 stevel 891 0 stevel /* 892 0 stevel * Given a LACP mode string, find the corresponding LACP mode number. Returns 893 0 stevel * B_TRUE if a match was found, B_FALSE otherwise. 894 0 stevel */ 895 0 stevel boolean_t 896 3871 yz147064 dladm_aggr_str2lacpmode(const char *str, aggr_lacp_mode_t *lacp_mode) 897 0 stevel { 898 0 stevel int i; 899 3871 yz147064 dladm_aggr_lacpmode_t *mode; 900 0 stevel 901 0 stevel for (i = 0; i < NLACP_MODES; i++) { 902 0 stevel mode = &lacp_modes[i]; 903 0 stevel if (strncasecmp(str, mode->mode_str, 904 0 stevel strlen(mode->mode_str)) == 0) { 905 0 stevel *lacp_mode = mode->mode_id; 906 0 stevel return (B_TRUE); 907 0 stevel } 908 0 stevel } 909 0 stevel 910 0 stevel return (B_FALSE); 911 0 stevel } 912 0 stevel 913 0 stevel /* 914 0 stevel * Given a LACP mode number, returns a printable string, or NULL if the 915 0 stevel * LACP mode number is invalid. 916 0 stevel */ 917 0 stevel const char * 918 3871 yz147064 dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf) 919 0 stevel { 920 0 stevel int i; 921 3871 yz147064 dladm_aggr_lacpmode_t *mode; 922 5895 yz147064 923 5895 yz147064 if (buf == NULL) 924 5895 yz147064 return (NULL); 925 0 stevel 926 0 stevel for (i = 0; i < NLACP_MODES; i++) { 927 0 stevel mode = &lacp_modes[i]; 928 3871 yz147064 if (mode->mode_id == mode_id) { 929 3871 yz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 930 3871 yz147064 mode->mode_str); 931 3871 yz147064 return (buf); 932 3871 yz147064 } 933 0 stevel } 934 0 stevel 935 3871 yz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 936 3871 yz147064 return (buf); 937 0 stevel } 938 0 stevel 939 0 stevel /* 940 0 stevel * Given a LACP timer string, find the corresponding LACP timer number. Returns 941 0 stevel * B_TRUE if a match was found, B_FALSE otherwise. 942 0 stevel */ 943 0 stevel boolean_t 944 3871 yz147064 dladm_aggr_str2lacptimer(const char *str, aggr_lacp_timer_t *lacp_timer) 945 0 stevel { 946 0 stevel int i; 947 3871 yz147064 dladm_aggr_lacptimer_t *timer; 948 0 stevel 949 0 stevel for (i = 0; i < NLACP_TIMERS; i++) { 950 0 stevel timer = &lacp_timers[i]; 951 0 stevel if (strncasecmp(str, timer->lt_str, 952 0 stevel strlen(timer->lt_str)) == 0) { 953 0 stevel *lacp_timer = timer->lt_id; 954 0 stevel return (B_TRUE); 955 0 stevel } 956 0 stevel } 957 0 stevel 958 0 stevel return (B_FALSE); 959 0 stevel } 960 0 stevel 961 0 stevel /* 962 0 stevel * Given a LACP timer, returns a printable string, or NULL if the 963 0 stevel * LACP timer number is invalid. 964 0 stevel */ 965 0 stevel const char * 966 3871 yz147064 dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf) 967 0 stevel { 968 0 stevel int i; 969 3871 yz147064 dladm_aggr_lacptimer_t *timer; 970 0 stevel 971 5895 yz147064 if (buf == NULL) 972 5895 yz147064 return (NULL); 973 5895 yz147064 974 0 stevel for (i = 0; i < NLACP_TIMERS; i++) { 975 0 stevel timer = &lacp_timers[i]; 976 3871 yz147064 if (timer->lt_id == timer_id) { 977 3871 yz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 978 3871 yz147064 timer->lt_str); 979 3871 yz147064 return (buf); 980 3871 yz147064 } 981 0 stevel } 982 0 stevel 983 3871 yz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 984 3871 yz147064 return (buf); 985 3871 yz147064 } 986 3871 yz147064 987 3871 yz147064 const char * 988 3871 yz147064 dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) 989 3871 yz147064 { 990 3871 yz147064 int i; 991 5895 yz147064 dladm_aggr_port_state_t *state; 992 5895 yz147064 993 5895 yz147064 if (buf == NULL) 994 5895 yz147064 return (NULL); 995 3871 yz147064 996 3871 yz147064 for (i = 0; i < NPORT_STATES; i++) { 997 3871 yz147064 state = &port_states[i]; 998 3871 yz147064 if (state->state_id == state_id) { 999 3871 yz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", 1000 3871 yz147064 state->state_str); 1001 3871 yz147064 return (buf); 1002 3871 yz147064 } 1003 3871 yz147064 } 1004 3871 yz147064 1005 3871 yz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 1006 3871 yz147064 return (buf); 1007 0 stevel } 1008 0 stevel 1009 5895 yz147064 static dladm_status_t 1010 8453 Anurag dladm_aggr_persist_aggr_conf(dladm_handle_t handle, const char *link, 1011 8453 Anurag datalink_id_t linkid, uint16_t key, uint32_t nports, 1012 8453 Anurag dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed, 1013 8453 Anurag const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, 1014 8453 Anurag aggr_lacp_timer_t lacp_timer, boolean_t force) 1015 5895 yz147064 { 1016 5895 yz147064 dladm_conf_t conf = DLADM_INVALID_CONF; 1017 5895 yz147064 char *portstr = NULL; 1018 5895 yz147064 char macstr[ETHERADDRL * 3]; 1019 5895 yz147064 dladm_status_t status; 1020 5895 yz147064 int i, size; 1021 5895 yz147064 uint64_t u64; 1022 0 stevel 1023 8453 Anurag if ((status = dladm_create_conf(handle, link, linkid, 1024 8453 Anurag DATALINK_CLASS_AGGR, DL_ETHER, &conf)) != DLADM_STATUS_OK) { 1025 3871 yz147064 return (status); 1026 0 stevel } 1027 0 stevel 1028 5895 yz147064 u64 = key; 1029 8453 Anurag status = dladm_set_conf_field(handle, conf, FKEY, DLADM_TYPE_UINT64, 1030 8453 Anurag &u64); 1031 5895 yz147064 if (status != DLADM_STATUS_OK) 1032 5895 yz147064 goto done; 1033 0 stevel 1034 5895 yz147064 u64 = nports; 1035 8453 Anurag status = dladm_set_conf_field(handle, conf, FNPORTS, DLADM_TYPE_UINT64, 1036 8453 Anurag &u64); 1037 5895 yz147064 if (status != DLADM_STATUS_OK) 1038 5895 yz147064 goto done; 1039 0 stevel 1040 10616 Sebastien size = nports * MAXLINKNAMELEN + 1; 1041 5895 yz147064 if ((portstr = calloc(1, size)) == NULL) { 1042 5895 yz147064 status = DLADM_STATUS_NOMEM; 1043 5895 yz147064 goto done; 1044 5895 yz147064 } 1045 0 stevel 1046 10616 Sebastien for (i = 0; i < nports; i++) { 1047 10616 Sebastien status = write_port(handle, portstr, ports[i].lp_linkid, size); 1048 10616 Sebastien if (status != DLADM_STATUS_OK) { 1049 10616 Sebastien free(portstr); 1050 10616 Sebastien goto done; 1051 10616 Sebastien } 1052 10616 Sebastien } 1053 8453 Anurag status = dladm_set_conf_field(handle, conf, FPORTS, DLADM_TYPE_STR, 1054 8453 Anurag portstr); 1055 5895 yz147064 free(portstr); 1056 5895 yz147064 1057 5895 yz147064 if (status != DLADM_STATUS_OK) 1058 5895 yz147064 goto done; 1059 5895 yz147064 1060 5895 yz147064 u64 = policy; 1061 8453 Anurag status = dladm_set_conf_field(handle, conf, FPOLICY, DLADM_TYPE_UINT64, 1062 8453 Anurag &u64); 1063 5895 yz147064 if (status != DLADM_STATUS_OK) 1064 5895 yz147064 goto done; 1065 5895 yz147064 1066 8453 Anurag status = dladm_set_conf_field(handle, conf, FFIXMACADDR, 1067 8453 Anurag DLADM_TYPE_BOOLEAN, &mac_addr_fixed); 1068 5895 yz147064 if (status != DLADM_STATUS_OK) 1069 5895 yz147064 goto done; 1070 5895 yz147064 1071 5895 yz147064 if (mac_addr_fixed) { 1072 5895 yz147064 if (!VALID_PORT_MAC(mac_addr)) { 1073 5895 yz147064 status = DLADM_STATUS_MACADDRINVAL; 1074 3871 yz147064 goto done; 1075 0 stevel } 1076 0 stevel 1077 5895 yz147064 (void) dladm_aggr_macaddr2str(mac_addr, macstr); 1078 8453 Anurag status = dladm_set_conf_field(handle, conf, FMACADDR, 1079 8453 Anurag DLADM_TYPE_STR, macstr); 1080 5895 yz147064 if (status != DLADM_STATUS_OK) 1081 3871 yz147064 goto done; 1082 0 stevel } 1083 0 stevel 1084 8453 Anurag status = dladm_set_conf_field(handle, conf, FFORCE, DLADM_TYPE_BOOLEAN, 1085 8453 Anurag &force); 1086 5895 yz147064 if (status != DLADM_STATUS_OK) 1087 5895 yz147064 goto done; 1088 5895 yz147064 1089 5895 yz147064 u64 = lacp_mode; 1090 8453 Anurag status = dladm_set_conf_field(handle, conf, FLACPMODE, 1091 8453 Anurag DLADM_TYPE_UINT64, &u64); 1092 5895 yz147064 if (status != DLADM_STATUS_OK) 1093 5895 yz147064 goto done; 1094 5895 yz147064 1095 5895 yz147064 u64 = lacp_timer; 1096 8453 Anurag status = dladm_set_conf_field(handle, conf, FLACPTIMER, 1097 8453 Anurag DLADM_TYPE_UINT64, &u64); 1098 5895 yz147064 if (status != DLADM_STATUS_OK) 1099 5895 yz147064 goto done; 1100 5895 yz147064 1101 0 stevel /* 1102 5895 yz147064 * Commit the link aggregation configuration. 1103 0 stevel */ 1104 8453 Anurag status = dladm_write_conf(handle, conf); 1105 0 stevel 1106 3871 yz147064 done: 1107 8453 Anurag dladm_destroy_conf(handle, conf); 1108 3871 yz147064 return (status); 1109 0 stevel } 1110 0 stevel 1111 0 stevel /* 1112 0 stevel * Create a new link aggregation group. Update the configuration 1113 0 stevel * file and bring it up. 1114 0 stevel */ 1115 3871 yz147064 dladm_status_t 1116 8453 Anurag dladm_aggr_create(dladm_handle_t handle, const char *name, uint16_t key, 1117 8453 Anurag uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t policy, 1118 8453 Anurag boolean_t mac_addr_fixed, const uchar_t *mac_addr, 1119 8453 Anurag aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, uint32_t flags) 1120 0 stevel { 1121 5895 yz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 1122 5895 yz147064 uint32_t media; 1123 5895 yz147064 uint32_t i; 1124 5895 yz147064 datalink_class_t class; 1125 3871 yz147064 dladm_status_t status; 1126 5895 yz147064 boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE; 1127 0 stevel 1128 5895 yz147064 if (key != 0 && key > AGGR_MAX_KEY) 1129 3871 yz147064 return (DLADM_STATUS_KEYINVAL); 1130 0 stevel 1131 5895 yz147064 if (nports == 0) 1132 5895 yz147064 return (DLADM_STATUS_BADARG); 1133 0 stevel 1134 5895 yz147064 for (i = 0; i < nports; i++) { 1135 8453 Anurag if ((dladm_datalink_id2info(handle, ports[i].lp_linkid, NULL, 1136 5895 yz147064 &class, &media, NULL, 0) != DLADM_STATUS_OK) || 1137 9815 Rishi !((class == DATALINK_CLASS_PHYS || class == 1138 9815 Rishi DATALINK_CLASS_SIMNET) && (media == DL_ETHER))) { 1139 5895 yz147064 return (DLADM_STATUS_BADARG); 1140 5895 yz147064 } 1141 5895 yz147064 } 1142 5895 yz147064 1143 5895 yz147064 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1144 8453 Anurag if ((status = dladm_create_datalink_id(handle, name, 1145 8453 Anurag DATALINK_CLASS_AGGR, DL_ETHER, flags, &linkid)) != 1146 8453 Anurag DLADM_STATUS_OK) { 1147 5895 yz147064 goto fail; 1148 5895 yz147064 } 1149 5895 yz147064 1150 5895 yz147064 if ((flags & DLADM_OPT_PERSIST) && 1151 8453 Anurag (status = dladm_aggr_persist_aggr_conf(handle, name, linkid, key, 1152 8453 Anurag nports, ports, policy, mac_addr_fixed, mac_addr, lacp_mode, 1153 8453 Anurag lacp_timer, force)) != DLADM_STATUS_OK) { 1154 5895 yz147064 goto fail; 1155 5895 yz147064 } 1156 5895 yz147064 1157 5895 yz147064 if (!(flags & DLADM_OPT_ACTIVE)) 1158 5895 yz147064 return (DLADM_STATUS_OK); 1159 5895 yz147064 1160 8453 Anurag status = i_dladm_aggr_create_sys(handle, linkid, key, nports, ports, 1161 8453 Anurag policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force); 1162 5895 yz147064 1163 5895 yz147064 if (status != DLADM_STATUS_OK) { 1164 5895 yz147064 if (flags & DLADM_OPT_PERSIST) 1165 8453 Anurag (void) dladm_remove_conf(handle, linkid); 1166 5895 yz147064 goto fail; 1167 5895 yz147064 } 1168 5895 yz147064 1169 5895 yz147064 return (DLADM_STATUS_OK); 1170 5895 yz147064 1171 5895 yz147064 fail: 1172 5895 yz147064 if (linkid != DATALINK_INVALID_LINKID) 1173 8453 Anurag (void) dladm_destroy_datalink_id(handle, linkid, flags); 1174 5895 yz147064 1175 5895 yz147064 return (status); 1176 5895 yz147064 } 1177 5895 yz147064 1178 5895 yz147064 static dladm_status_t 1179 8453 Anurag i_dladm_aggr_get_aggr_attr(dladm_handle_t handle, dladm_conf_t conf, 1180 8453 Anurag uint32_t mask, dladm_aggr_modify_attr_t *attrp) 1181 5895 yz147064 { 1182 5895 yz147064 dladm_status_t status = DLADM_STATUS_OK; 1183 5895 yz147064 char macstr[ETHERADDRL * 3]; 1184 5895 yz147064 uint64_t u64; 1185 5895 yz147064 1186 5895 yz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) { 1187 8453 Anurag status = dladm_get_conf_field(handle, conf, FPOLICY, &u64, 1188 5895 yz147064 sizeof (u64)); 1189 3871 yz147064 if (status != DLADM_STATUS_OK) 1190 3871 yz147064 return (status); 1191 5895 yz147064 attrp->ld_policy = (uint32_t)u64; 1192 0 stevel } 1193 0 stevel 1194 5895 yz147064 if (mask & DLADM_AGGR_MODIFY_MAC) { 1195 8453 Anurag status = dladm_get_conf_field(handle, conf, FFIXMACADDR, 1196 5895 yz147064 &attrp->ld_mac_fixed, sizeof (boolean_t)); 1197 5895 yz147064 if (status != DLADM_STATUS_OK) 1198 5895 yz147064 return (status); 1199 0 stevel 1200 5895 yz147064 if (attrp->ld_mac_fixed) { 1201 5895 yz147064 boolean_t fixed; 1202 5895 yz147064 1203 8453 Anurag status = dladm_get_conf_field(handle, conf, FMACADDR, 1204 5895 yz147064 macstr, sizeof (macstr)); 1205 5895 yz147064 if (status != DLADM_STATUS_OK) 1206 5895 yz147064 return (status); 1207 5895 yz147064 1208 5895 yz147064 if (!dladm_aggr_str2macaddr(macstr, &fixed, 1209 5895 yz147064 attrp->ld_mac)) { 1210 5895 yz147064 return (DLADM_STATUS_REPOSITORYINVAL); 1211 5895 yz147064 } 1212 5895 yz147064 } 1213 5895 yz147064 } 1214 5895 yz147064 1215 5895 yz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { 1216 8453 Anurag status = dladm_get_conf_field(handle, conf, FLACPMODE, &u64, 1217 5895 yz147064 sizeof (u64)); 1218 5895 yz147064 if (status != DLADM_STATUS_OK) 1219 5895 yz147064 return (status); 1220 5895 yz147064 attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64; 1221 5895 yz147064 } 1222 5895 yz147064 1223 5895 yz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { 1224 8453 Anurag status = dladm_get_conf_field(handle, conf, FLACPTIMER, &u64, 1225 5895 yz147064 sizeof (u64)); 1226 5895 yz147064 if (status != DLADM_STATUS_OK) 1227 5895 yz147064 return (status); 1228 5895 yz147064 attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64; 1229 5895 yz147064 } 1230 5895 yz147064 1231 5895 yz147064 return (status); 1232 5895 yz147064 } 1233 5895 yz147064 1234 5895 yz147064 static dladm_status_t 1235 8453 Anurag i_dladm_aggr_set_aggr_attr(dladm_handle_t handle, dladm_conf_t conf, 1236 8453 Anurag uint32_t mask, dladm_aggr_modify_attr_t *attrp) 1237 5895 yz147064 { 1238 5895 yz147064 dladm_status_t status = DLADM_STATUS_OK; 1239 5895 yz147064 char macstr[ETHERADDRL * 3]; 1240 5895 yz147064 uint64_t u64; 1241 5895 yz147064 1242 5895 yz147064 if (mask & DLADM_AGGR_MODIFY_POLICY) { 1243 5895 yz147064 u64 = attrp->ld_policy; 1244 8453 Anurag status = dladm_set_conf_field(handle, conf, FPOLICY, 1245 8453 Anurag DLADM_TYPE_UINT64, &u64); 1246 5895 yz147064 if (status != DLADM_STATUS_OK) 1247 5895 yz147064 return (status); 1248 5895 yz147064 } 1249 5895 yz147064 1250 5895 yz147064 if (mask & DLADM_AGGR_MODIFY_MAC) { 1251 8453 Anurag status = dladm_set_conf_field(handle, conf, FFIXMACADDR, 1252 5895 yz147064 DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed); 1253 5895 yz147064 if (status != DLADM_STATUS_OK) 1254 5895 yz147064 return (status); 1255 5895 yz147064 1256 5895 yz147064 if (attrp->ld_mac_fixed) { 1257 5895 yz147064 (void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr); 1258 8453 Anurag status = dladm_set_conf_field(handle, conf, FMACADDR, 1259 5895 yz147064 DLADM_TYPE_STR, macstr); 1260 5895 yz147064 if (status != DLADM_STATUS_OK) 1261 5895 yz147064 return (status); 1262 5895 yz147064 } 1263 5895 yz147064 } 1264 5895 yz147064 1265 5895 yz147064 if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { 1266 5895 yz147064 u64 = attrp->ld_lacp_mode; 1267 8453 Anurag status = dladm_set_conf_field(handle, conf, FLACPMODE, 1268 5895 yz147064 DLADM_TYPE_UINT64, &u64); 1269 5895 yz147064 if (status != DLADM_STATUS_OK) 1270 5895 yz147064 return (status); 1271 5895 yz147064 } 1272 5895 yz147064 1273 5895 yz147064 if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { 1274 5895 yz147064 u64 = attrp->ld_lacp_timer; 1275 8453 Anurag status = dladm_set_conf_field(handle, conf, FLACPTIMER, 1276 5895 yz147064 DLADM_TYPE_UINT64, &u64); 1277 5895 yz147064 if (status != DLADM_STATUS_OK) 1278 5895 yz147064 return (status); 1279 5895 yz147064 } 1280 3871 yz147064 1281 3871 yz147064 return (status); 1282 0 stevel } 1283 0 stevel 1284 0 stevel /* 1285 0 stevel * Modify the parameters of an existing link aggregation group. Update 1286 0 stevel * the configuration file and pass the changes to the kernel. 1287 0 stevel */ 1288 3871 yz147064 dladm_status_t 1289 8453 Anurag dladm_aggr_modify(dladm_handle_t handle, datalink_id_t linkid, 1290 8453 Anurag uint32_t modify_mask, uint32_t policy, boolean_t mac_fixed, 1291 8453 Anurag const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, 1292 5895 yz147064 aggr_lacp_timer_t lacp_timer, uint32_t flags) 1293 0 stevel { 1294 3871 yz147064 dladm_aggr_modify_attr_t new_attr, old_attr; 1295 5895 yz147064 dladm_conf_t conf; 1296 3871 yz147064 dladm_status_t status; 1297 0 stevel 1298 5895 yz147064 new_attr.ld_policy = policy; 1299 5895 yz147064 new_attr.ld_mac_fixed = mac_fixed; 1300 5895 yz147064 new_attr.ld_lacp_mode = lacp_mode; 1301 5895 yz147064 new_attr.ld_lacp_timer = lacp_timer; 1302 5895 yz147064 bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); 1303 0 stevel 1304 5895 yz147064 if (flags & DLADM_OPT_PERSIST) { 1305 8453 Anurag status = dladm_read_conf(handle, linkid, &conf); 1306 5895 yz147064 if (status != DLADM_STATUS_OK) 1307 5895 yz147064 return (status); 1308 0 stevel 1309 8453 Anurag if ((status = i_dladm_aggr_get_aggr_attr(handle, conf, 1310 8453 Anurag modify_mask, &old_attr)) != DLADM_STATUS_OK) { 1311 5895 yz147064 goto done; 1312 5895 yz147064 } 1313 5895 yz147064 1314 8453 Anurag if ((status = i_dladm_aggr_set_aggr_attr(handle, conf, 1315 8453 Anurag modify_mask, &new_attr)) != DLADM_STATUS_OK) { 1316 5895 yz147064 goto done; 1317 5895 yz147064 } 1318 5895 yz147064 1319 8453 Anurag status = dladm_write_conf(handle, conf); 1320 5895 yz147064 1321 5895 yz147064 done: 1322 8453 Anurag dladm_destroy_conf(handle, conf); 1323 5895 yz147064 if (status != DLADM_STATUS_OK) 1324 5895 yz147064 return (status); 1325 0 stevel } 1326 0 stevel 1327 5895 yz147064 if (!(flags & DLADM_OPT_ACTIVE)) 1328 5895 yz147064 return (DLADM_STATUS_OK); 1329 0 stevel 1330 8453 Anurag status = i_dladm_aggr_modify_sys(handle, linkid, modify_mask, 1331 8453 Anurag &new_attr); 1332 5895 yz147064 if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { 1333 8453 Anurag if (dladm_read_conf(handle, linkid, &conf) == DLADM_STATUS_OK) { 1334 8453 Anurag if (i_dladm_aggr_set_aggr_attr(handle, conf, 1335 8453 Anurag modify_mask, &old_attr) == DLADM_STATUS_OK) { 1336 8453 Anurag (void) dladm_write_conf(handle, conf); 1337 5895 yz147064 } 1338 8453 Anurag dladm_destroy_conf(handle, conf); 1339 5895 yz147064 } 1340 0 stevel } 1341 0 stevel 1342 3871 yz147064 return (status); 1343 0 stevel } 1344 0 stevel 1345 5895 yz147064 typedef struct aggr_held_arg_s { 1346 5895 yz147064 datalink_id_t aggrid; 1347 5895 yz147064 boolean_t isheld; 1348 5895 yz147064 } aggr_held_arg_t; 1349 5895 yz147064 1350 5895 yz147064 static int 1351 8453 Anurag i_dladm_aggr_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1352 5895 yz147064 { 1353 5895 yz147064 aggr_held_arg_t *aggr_held_arg = arg; 1354 5895 yz147064 dladm_vlan_attr_t dva; 1355 5895 yz147064 1356 8453 Anurag if (dladm_vlan_info(handle, linkid, &dva, DLADM_OPT_PERSIST) != 1357 8453 Anurag DLADM_STATUS_OK) 1358 5895 yz147064 return (DLADM_WALK_CONTINUE); 1359 5895 yz147064 1360 5895 yz147064 if (dva.dv_linkid == aggr_held_arg->aggrid) { 1361 5895 yz147064 /* 1362 5895 yz147064 * This VLAN is created over the given aggregation. 1363 5895 yz147064 */ 1364 5895 yz147064 aggr_held_arg->isheld = B_TRUE; 1365 5895 yz147064 return (DLADM_WALK_TERMINATE); 1366 5895 yz147064 } 1367 5895 yz147064 return (DLADM_WALK_CONTINUE); 1368 5895 yz147064 } 1369 5895 yz147064 1370 0 stevel /* 1371 5895 yz147064 * Delete a previously created link aggregation group. Either the name "aggr" 1372 5895 yz147064 * or the "key" is specified. 1373 0 stevel */ 1374 3871 yz147064 dladm_status_t 1375 8453 Anurag dladm_aggr_delete(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags) 1376 0 stevel { 1377 5895 yz147064 laioc_delete_t ioc; 1378 5895 yz147064 datalink_class_t class; 1379 3871 yz147064 dladm_status_t status; 1380 0 stevel 1381 8453 Anurag if ((dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, NULL, 1382 8453 Anurag 0) != DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) { 1383 5895 yz147064 return (DLADM_STATUS_BADARG); 1384 5895 yz147064 } 1385 0 stevel 1386 5895 yz147064 if (flags & DLADM_OPT_ACTIVE) { 1387 5895 yz147064 ioc.ld_linkid = linkid; 1388 8453 Anurag if ((i_dladm_aggr_ioctl(handle, LAIOC_DELETE, &ioc) < 0) && 1389 5895 yz147064 ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { 1390 5895 yz147064 status = dladm_errno2status(errno); 1391 5895 yz147064 return (status); 1392 5895 yz147064 } 1393 3871 yz147064 1394 3871 yz147064 /* 1395 5895 yz147064 * Delete ACTIVE linkprop first. 1396 3871 yz147064 */ 1397 8453 Anurag (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 1398 5895 yz147064 DLADM_OPT_ACTIVE); 1399 8453 Anurag (void) dladm_destroy_datalink_id(handle, linkid, 1400 8453 Anurag DLADM_OPT_ACTIVE); 1401 0 stevel } 1402 0 stevel 1403 5895 yz147064 /* 1404 5895 yz147064 * If we reach here, it means that the active aggregation has already 1405 5895 yz147064 * been deleted, and there is no active VLANs holding this aggregation. 1406 5895 yz147064 * Now we see whether there is any persistent VLANs holding this 1407 5895 yz147064 * aggregation. If so, we fail the operation. 1408 5895 yz147064 */ 1409 5895 yz147064 if (flags & DLADM_OPT_PERSIST) { 1410 5895 yz147064 aggr_held_arg_t arg; 1411 3871 yz147064 1412 5895 yz147064 arg.aggrid = linkid; 1413 5895 yz147064 arg.isheld = B_FALSE; 1414 5895 yz147064 1415 8453 Anurag (void) dladm_walk_datalink_id(i_dladm_aggr_is_held, handle, 1416 5895 yz147064 &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 1417 5895 yz147064 DLADM_OPT_PERSIST); 1418 5895 yz147064 if (arg.isheld) 1419 5895 yz147064 return (DLADM_STATUS_LINKBUSY); 1420 5895 yz147064 1421 10616 Sebastien (void) dladm_remove_conf(handle, linkid); 1422 8453 Anurag (void) dladm_destroy_datalink_id(handle, linkid, 1423 8453 Anurag DLADM_OPT_PERSIST); 1424 5895 yz147064 } 1425 5895 yz147064 1426 5895 yz147064 return (DLADM_STATUS_OK); 1427 0 stevel } 1428 0 stevel 1429 0 stevel /* 1430 0 stevel * Add one or more ports to an existing link aggregation. 1431 0 stevel */ 1432 3871 yz147064 dladm_status_t 1433 8453 Anurag dladm_aggr_add(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports, 1434 5895 yz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags) 1435 0 stevel { 1436 8453 Anurag return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags, 1437 8453 Anurag LAIOC_ADD)); 1438 0 stevel } 1439 0 stevel 1440 0 stevel /* 1441 0 stevel * Remove one or more ports from an existing link aggregation. 1442 0 stevel */ 1443 3871 yz147064 dladm_status_t 1444 8453 Anurag dladm_aggr_remove(dladm_handle_t handle, datalink_id_t linkid, uint32_t nports, 1445 5895 yz147064 dladm_aggr_port_attr_db_t *ports, uint32_t flags) 1446 0 stevel { 1447 8453 Anurag return (i_dladm_aggr_add_rmv(handle, linkid, nports, ports, flags, 1448 5895 yz147064 LAIOC_REMOVE)); 1449 5895 yz147064 } 1450 5895 yz147064 1451 5895 yz147064 typedef struct i_walk_key_state_s { 1452 5895 yz147064 uint16_t key; 1453 5895 yz147064 datalink_id_t linkid; 1454 5895 yz147064 boolean_t found; 1455 5895 yz147064 } i_walk_key_state_t; 1456 5895 yz147064 1457 5895 yz147064 static int 1458 8453 Anurag i_dladm_walk_key2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1459 5895 yz147064 { 1460 5895 yz147064 dladm_conf_t conf; 1461 5895 yz147064 uint16_t key; 1462 3871 yz147064 dladm_status_t status; 1463 5895 yz147064 i_walk_key_state_t *statep = (i_walk_key_state_t *)arg; 1464 5895 yz147064 uint64_t u64; 1465 0 stevel 1466 8453 Anurag if (dladm_read_conf(handle, linkid, &conf) != 0) 1467 5895 yz147064 return (DLADM_WALK_CONTINUE); 1468 0 stevel 1469 8453 Anurag status = dladm_get_conf_field(handle, conf, FKEY, &u64, sizeof (u64)); 1470 5895 yz147064 key = (uint16_t)u64; 1471 8453 Anurag dladm_destroy_conf(handle, conf); 1472 0 stevel 1473 5895 yz147064 if ((status == DLADM_STATUS_OK) && (key == statep->key)) { 1474 5895 yz147064 statep->found = B_TRUE; 1475 5895 yz147064 statep->linkid = linkid; 1476 5895 yz147064 return (DLADM_WALK_TERMINATE); 1477 0 stevel } 1478 0 stevel 1479 5895 yz147064 return (DLADM_WALK_CONTINUE); 1480 5895 yz147064 } 1481 0 stevel 1482 5895 yz147064 dladm_status_t 1483 8453 Anurag dladm_key2linkid(dladm_handle_t handle, uint16_t key, datalink_id_t *linkidp, 1484 8453 Anurag uint32_t flags) 1485 5895 yz147064 { 1486 5895 yz147064 i_walk_key_state_t state; 1487 5895 yz147064 1488 5895 yz147064 if (key > AGGR_MAX_KEY) 1489 5895 yz147064 return (DLADM_STATUS_NOTFOUND); 1490 5895 yz147064 1491 5895 yz147064 state.found = B_FALSE; 1492 5895 yz147064 state.key = key; 1493 5895 yz147064 1494 8453 Anurag (void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, handle, &state, 1495 5895 yz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 1496 5895 yz147064 if (state.found == B_TRUE) { 1497 5895 yz147064 *linkidp = state.linkid; 1498 5895 yz147064 return (DLADM_STATUS_OK); 1499 5895 yz147064 } else { 1500 5895 yz147064 return (DLADM_STATUS_NOTFOUND); 1501 5895 yz147064 } 1502 0 stevel } 1503