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