diff options
Diffstat (limited to 'usr/src/lib/libdladm/common/libdlaggr.c')
-rw-r--r-- | usr/src/lib/libdladm/common/libdlaggr.c | 1923 |
1 files changed, 843 insertions, 1080 deletions
diff --git a/usr/src/lib/libdladm/common/libdlaggr.c b/usr/src/lib/libdladm/common/libdlaggr.c index 0c622fc8a2..75291d0d1d 100644 --- a/usr/src/lib/libdladm/common/libdlaggr.c +++ b/usr/src/lib/libdladm/common/libdlaggr.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -34,10 +34,13 @@ #include <stropts.h> #include <stdlib.h> #include <errno.h> +#include <assert.h> #include <strings.h> #include <libintl.h> #include <net/if_types.h> #include <net/if_dl.h> +#include <libdllink.h> +#include <libdlvlan.h> #include <libdlaggr.h> #include <libdladm_impl.h> @@ -46,78 +49,39 @@ * * This library is used by administration tools such as dladm(1M) to * configure link aggregations. - * - * Link aggregation configuration information is saved in a text - * file of the following format: - * - * <db-file> ::= <groups>* - * <group> ::= <key> <sep> <policy> <sep> <nports> <sep> <ports> <sep> - * <mac> <sep> <lacp-mode> <sep> <lacp-timer> - * <sep> ::= ' ' | '\t' - * <key> ::= <number> - * <nports> ::= <number> - * <ports> ::= <port> <m-port>* - * <m-port> ::= ',' <port> - * <port> ::= <devname> - * <devname> ::= <string> - * <port-num> ::= <number> - * <policy> ::= <pol-level> <m-pol>* - * <m-pol> ::= ',' <pol-level> - * <pol-level> ::= 'L2' | 'L3' | 'L4' - * <mac> ::= 'auto' | <mac-addr> - * <mac-addr> ::= <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex> - * <lacp-mode> ::= 'off' | 'active' | 'passive' - * <lacp-timer> ::= 'short' | 'long' */ -#define DLADM_AGGR_DEV "/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL -#define DLADM_AGGR_DB "/etc/dladm/aggregation.conf" -#define DLADM_AGGR_DB_TMP "/etc/dladm/aggregation.conf.new" -#define DLADM_AGGR_DB_LOCK "/tmp/aggregation.conf.lock" - -#define DLADM_AGGR_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH -#define DLADM_AGGR_DB_OWNER 15 /* "dladm" UID */ -#define DLADM_AGGR_DB_GROUP 3 /* "sys" GID */ - -/* - * The largest configurable aggregation key. Because by default the key is - * used as the DLPI device PPA and default VLAN PPA's are calculated as - * ((1000 * vid) + PPA), the largest key can't be > 999. - */ -#define DLADM_AGGR_MAX_KEY 999 - -#define BLANK_LINE(s) ((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n')) +#define DLADM_AGGR_DEV "/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL /* Limits on buffer size for LAIOC_INFO request */ #define MIN_INFO_SIZE (4*1024) #define MAX_INFO_SIZE (128*1024) -#define MAXPATHLEN 1024 - static uchar_t zero_mac[] = {0, 0, 0, 0, 0, 0}; +#define VALID_PORT_MAC(mac) \ + (((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) && \ + (!(mac)[0] & 0x01)) -/* configuration database entry */ -typedef struct dladm_aggr_grp_attr_db { - uint32_t lt_key; - uint32_t lt_policy; - uint32_t lt_nports; - dladm_aggr_port_attr_db_t *lt_ports; - boolean_t lt_mac_fixed; - uchar_t lt_mac[ETHERADDRL]; - aggr_lacp_mode_t lt_lacp_mode; - aggr_lacp_timer_t lt_lacp_timer; -} dladm_aggr_grp_attr_db_t; - -typedef struct dladm_aggr_up { - uint32_t lu_key; - boolean_t lu_found; - int lu_fd; -} dladm_aggr_up_t; - -typedef struct dladm_aggr_down { - uint32_t ld_key; - boolean_t ld_found; -} dladm_aggr_down_t; +#define PORT_DELIMITER '.' + +#define WRITE_PORT(portstr, portid, size) { \ + char pstr[LINKID_STR_WIDTH + 2]; \ + (void) snprintf(pstr, LINKID_STR_WIDTH + 2, "%d%c", \ + (portid), PORT_DELIMITER); \ + (void) strlcat((portstr), pstr, (size)); \ +} + +#define READ_PORT(portstr, portid, status) { \ + errno = 0; \ + (status) = DLADM_STATUS_OK; \ + (portid) = (int)strtol((portstr), &(portstr), 10); \ + if (errno != 0 || *(portstr) != PORT_DELIMITER) { \ + (status) = DLADM_STATUS_REPOSITORYINVAL; \ + } else { \ + /* Skip the delimiter. */ \ + (portstr)++; \ + } \ +} typedef struct dladm_aggr_modify_attr { uint32_t ld_policy; @@ -175,106 +139,93 @@ static dladm_aggr_port_state_t port_states[] = { #define NPORT_STATES \ (sizeof (port_states) / sizeof (dladm_aggr_port_state_t)) -typedef struct delete_db_state { - uint32_t ds_key; - boolean_t ds_found; -} delete_db_state_t; +static int +i_dladm_aggr_strioctl(int cmd, void *ptr, int ilen) +{ + int err, fd; -typedef struct modify_db_state { - uint32_t us_key; - uint32_t us_mask; - dladm_aggr_modify_attr_t *us_attr_new; - dladm_aggr_modify_attr_t *us_attr_old; - boolean_t us_found; -} modify_db_state_t; + if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) + return (-1); -typedef struct add_db_state { - dladm_aggr_grp_attr_db_t *as_attr; - boolean_t as_found; -} add_db_state_t; + err = i_dladm_ioctl(fd, cmd, ptr, ilen); + (void) close(fd); -static int i_dladm_aggr_fput_grp(FILE *, dladm_aggr_grp_attr_db_t *); + return (err); +} /* - * Open and lock the aggregation configuration file lock. The lock is - * acquired as a reader (F_RDLCK) or writer (F_WRLCK). + * Caller must free attr.lg_ports. The ptr pointer is advanced while convert + * the laioc_info_t to the dladm_aggr_grp_attr_t structure. */ static int -i_dladm_aggr_lock_db(short type) +i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp) { - int lock_fd; - struct flock lock; - int errno_save; + laioc_info_group_t *grp; + laioc_info_port_t *port; + int i; + void *where = (*ptr); - if ((lock_fd = open(DLADM_AGGR_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC, - DLADM_AGGR_DB_PERMS)) < 0) - return (-1); + grp = (laioc_info_group_t *)where; - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; + attrp->lg_linkid = grp->lg_linkid; + attrp->lg_key = grp->lg_key; + attrp->lg_nports = grp->lg_nports; + attrp->lg_policy = grp->lg_policy; + attrp->lg_lacp_mode = grp->lg_lacp_mode; + attrp->lg_lacp_timer = grp->lg_lacp_timer; + attrp->lg_force = grp->lg_force; - if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { - errno_save = errno; - (void) close(lock_fd); - (void) unlink(DLADM_AGGR_DB_LOCK); - errno = errno_save; - return (-1); + bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL); + attrp->lg_mac_fixed = grp->lg_mac_fixed; + + if ((attrp->lg_ports = malloc(grp->lg_nports * + sizeof (dladm_aggr_port_attr_t))) == NULL) { + errno = ENOMEM; + goto fail; } - return (lock_fd); -} -/* - * Unlock and close the specified file. - */ -static void -i_dladm_aggr_unlock_db(int fd) -{ - struct flock lock; + where = (grp + 1); - if (fd < 0) - return; + /* + * Go through each port that is part of the group. + */ + for (i = 0; i < grp->lg_nports; i++) { + port = (laioc_info_port_t *)where; - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; + attrp->lg_ports[i].lp_linkid = port->lp_linkid; + bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL); + attrp->lg_ports[i].lp_state = port->lp_state; + attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state; - (void) fcntl(fd, F_SETLKW, &lock); - (void) close(fd); - (void) unlink(DLADM_AGGR_DB_LOCK); + where = (port + 1); + } + *ptr = where; + return (0); +fail: + return (-1); } /* - * Walk through the groups defined on the system and for each group <grp>, - * invoke <fn>(<arg>, <grp>); - * Terminate the walk if at any time <fn> returns non-NULL value + * Get active configuration of a specific aggregation. + * Caller must free attrp->la_ports. */ -int -dladm_aggr_walk(int (*fn)(void *, dladm_aggr_grp_attr_t *), void *arg) +static dladm_status_t +i_dladm_aggr_info_active(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp) { laioc_info_t *ioc; - laioc_info_group_t *grp; - laioc_info_port_t *port; - dladm_aggr_grp_attr_t attr; - int rc, i, j, bufsize, fd; - char *where; - - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) == -1) - return (-1); + int rc, bufsize; + void *where; + dladm_status_t status = DLADM_STATUS_OK; bufsize = MIN_INFO_SIZE; ioc = (laioc_info_t *)calloc(1, bufsize); - if (ioc == NULL) { - (void) close(fd); - errno = ENOMEM; - return (-1); - } + if (ioc == NULL) + return (DLADM_STATUS_NOMEM); -tryagain: - rc = i_dladm_ioctl(fd, LAIOC_INFO, ioc, bufsize); + ioc->li_group_linkid = linkid; +tryagain: + rc = i_dladm_aggr_strioctl(LAIOC_INFO, ioc, bufsize); if (rc != 0) { if (errno == ENOSPC) { /* @@ -290,6 +241,7 @@ tryagain: } } } + status = dladm_errno2status(errno); goto bail; } @@ -297,257 +249,329 @@ tryagain: * Go through each group returned by the aggregation driver. */ where = (char *)(ioc + 1); - for (i = 0; i < ioc->li_ngroups; i++) { - /* LINTED E_BAD_PTR_CAST_ALIGN */ - grp = (laioc_info_group_t *)where; - - attr.lg_key = grp->lg_key; - attr.lg_nports = grp->lg_nports; - attr.lg_policy = grp->lg_policy; - attr.lg_lacp_mode = grp->lg_lacp_mode; - attr.lg_lacp_timer = grp->lg_lacp_timer; - - bcopy(grp->lg_mac, attr.lg_mac, ETHERADDRL); - attr.lg_mac_fixed = grp->lg_mac_fixed; - - attr.lg_ports = malloc(grp->lg_nports * - sizeof (dladm_aggr_port_attr_t)); - if (attr.lg_ports == NULL) { - errno = ENOMEM; - goto bail; - } - - where = (char *)(grp + 1); - - /* - * Go through each port that is part of the group. - */ - for (j = 0; j < grp->lg_nports; j++) { - /* LINTED E_BAD_PTR_CAST_ALIGN */ - port = (laioc_info_port_t *)where; - - bcopy(port->lp_devname, attr.lg_ports[j].lp_devname, - MAXNAMELEN + 1); - bcopy(port->lp_mac, attr.lg_ports[j].lp_mac, - ETHERADDRL); - attr.lg_ports[j].lp_state = port->lp_state; - attr.lg_ports[j].lp_lacp_state = port->lp_lacp_state; - - where = (char *)(port + 1); - } - - rc = fn(arg, &attr); - free(attr.lg_ports); - if (rc != 0) - goto bail; + if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) { + status = dladm_errno2status(errno); + goto bail; } bail: free(ioc); - (void) close(fd); - return (rc); + return (status); } /* - * Parse one line of the link aggregation DB, and return the corresponding - * group. Memory for the ports associated with the aggregation may be - * allocated. It is the responsibility of the caller to free the lt_ports - * aggregation group attribute. - * - * Returns -1 on parsing failure, or 0 on success. + * Get configuration information of a specific aggregation. + * Caller must free attrp->la_ports. */ -static int -i_dladm_aggr_parse_db(char *line, dladm_aggr_grp_attr_db_t *attr) +static dladm_status_t +i_dladm_aggr_info_persist(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp) { - char *token; - int i; - int value; - char *endp = NULL; - char *lasts = NULL; - - bzero(attr, sizeof (*attr)); + dladm_conf_t conf; + uint32_t nports, i; + char *portstr, *next; + dladm_status_t status; + uint64_t u64; + int size; + char macstr[ETHERADDRL * 3]; - /* key */ - if ((token = strtok_r(line, " \t", &lasts)) == NULL) - goto failed; + attrp->lg_linkid = linkid; + if ((status = dladm_read_conf(linkid, &conf)) != DLADM_STATUS_OK) + return (status); - errno = 0; - value = (int)strtol(token, &endp, 10); - if (errno != 0 || *endp != '\0') - goto failed; + status = dladm_get_conf_field(conf, FKEY, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_key = (uint16_t)u64; - attr->lt_key = value; + status = dladm_get_conf_field(conf, FPOLICY, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_policy = (uint32_t)u64; - /* policy */ - if ((token = strtok_r(NULL, " \t", &lasts)) == NULL || - !dladm_aggr_str2policy(token, &attr->lt_policy)) - goto failed; + status = dladm_get_conf_field(conf, FFIXMACADDR, &attrp->lg_mac_fixed, + sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + goto done; - /* number of ports */ - if ((token = strtok_r(NULL, " \t", &lasts)) == NULL) - return (-1); + if (attrp->lg_mac_fixed) { + boolean_t fixed; - errno = 0; - value = (int)strtol(token, &endp, 10); - if (errno != 0 || *endp != '\0') - goto failed; + if ((status = dladm_get_conf_field(conf, FMACADDR, macstr, + sizeof (macstr))) != DLADM_STATUS_OK) { + goto done; + } + if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) { + status = DLADM_STATUS_REPOSITORYINVAL; + goto done; + } + } - attr->lt_nports = value; + status = dladm_get_conf_field(conf, FFORCE, &attrp->lg_force, + sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + goto done; - /* ports */ - if ((attr->lt_ports = malloc(attr->lt_nports * - sizeof (dladm_aggr_port_attr_db_t))) == NULL) - goto failed; + status = dladm_get_conf_field(conf, FLACPMODE, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64; - for (i = 0; i < attr->lt_nports; i++) { - char *where, *devname; + status = dladm_get_conf_field(conf, FLACPTIMER, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64; - /* port */ - if ((token = strtok_r(NULL, ", \t\n", &lasts)) == NULL) - goto failed; + status = dladm_get_conf_field(conf, FNPORTS, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + nports = (uint32_t)u64; + attrp->lg_nports = nports; - /* - * device name: In a previous version of this file, a port - * number could be specified using <devname>/<portnum>. - * This syntax is unecessary and obsolete. - */ - if ((devname = strtok_r(token, "/", &where)) == NULL) - goto failed; - if (strlcpy(attr->lt_ports[i].lp_devname, devname, - MAXNAMELEN) >= MAXNAMELEN) - goto failed; + size = nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - /* unicast MAC address */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2macaddr(token, &attr->lt_mac_fixed, - attr->lt_mac)) - goto failed; + status = dladm_get_conf_field(conf, FPORTS, portstr, size); + if (status != DLADM_STATUS_OK) { + free(portstr); + goto done; + } - /* LACP mode */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2lacpmode(token, &attr->lt_lacp_mode)) - attr->lt_lacp_mode = AGGR_LACP_OFF; + if ((attrp->lg_ports = malloc(nports * + sizeof (dladm_aggr_port_attr_t))) == NULL) { + free(portstr); + status = DLADM_STATUS_NOMEM; + goto done; + } - /* LACP timer */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2lacptimer(token, &attr->lt_lacp_timer)) - attr->lt_lacp_timer = AGGR_LACP_TIMER_SHORT; + for (next = portstr, i = 0; i < nports; i++) { + READ_PORT(next, attrp->lg_ports[i].lp_linkid, status); + if (status != DLADM_STATUS_OK) { + free(portstr); + free(attrp->lg_ports); + goto done; + } + } + free(portstr); - return (0); +done: + dladm_destroy_conf(conf); + return (status); +} -failed: - free(attr->lt_ports); - attr->lt_ports = NULL; - return (-1); +dladm_status_t +dladm_aggr_info(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp, + uint32_t flags) +{ + assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); + if (flags == DLADM_OPT_ACTIVE) + return (i_dladm_aggr_info_active(linkid, attrp)); + else + return (i_dladm_aggr_info_persist(linkid, attrp)); } /* - * Walk through the groups defined in the DB and for each group <grp>, - * invoke <fn>(<arg>, <grp>); + * Add or remove one or more ports to/from an existing link aggregation. */ static dladm_status_t -i_dladm_aggr_walk_db(dladm_status_t (*fn)(void *, dladm_aggr_grp_attr_db_t *), - void *arg, const char *root) +i_dladm_aggr_add_rmv(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd) { - FILE *fp; - char line[MAXLINELEN]; - dladm_aggr_grp_attr_db_t attr; - char *db_file; - char db_file_buf[MAXPATHLEN]; - int lock_fd; + char *orig_portstr = NULL, *portstr = NULL; + laioc_add_rem_t *iocp; + laioc_port_t *ioc_ports; + uint32_t orig_nports, result_nports, len, i, j; + dladm_conf_t conf; + datalink_class_t class; dladm_status_t status = DLADM_STATUS_OK; + int size; + uint64_t u64; + uint32_t media; - if (root == NULL) { - db_file = DLADM_AGGR_DB; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - db_file = db_file_buf; - } - - lock_fd = i_dladm_aggr_lock_db(F_RDLCK); + if (nports == 0) + return (DLADM_STATUS_BADARG); - if ((fp = fopen(db_file, "r")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); + /* + * Sanity check - aggregations can only be created over Ethernet + * physical links. + */ + for (i = 0; i < nports; i++) { + if ((dladm_datalink_id2info(ports[i].lp_linkid, NULL, + &class, &media, NULL, 0) != DLADM_STATUS_OK) || + (class != DATALINK_CLASS_PHYS) || (media != DL_ETHER)) { + return (DLADM_STATUS_BADARG); + } } - bzero(&attr, sizeof (attr)); + /* + * First, update the persistent configuration if requested. We only + * need to update the FPORTS and FNPORTS fields of this aggregation. + * Note that FPORTS is a list of port linkids separated by + * PORT_DELIMITER ('.'). + */ + if (flags & DLADM_OPT_PERSIST) { + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); - while (fgets(line, MAXLINELEN, fp) != NULL) { - /* skip comments */ - if (BLANK_LINE(line)) - continue; + /* + * Get the original configuration of FNPORTS and FPORTS. + */ + status = dladm_get_conf_field(conf, FNPORTS, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto destroyconf; + orig_nports = (uint32_t)u64; - if (i_dladm_aggr_parse_db(line, &attr) != 0) { - status = DLADM_STATUS_REPOSITORYINVAL; - goto done; + /* + * At least one port needs to be in the aggregation. + */ + if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) { + status = DLADM_STATUS_BADARG; + goto destroyconf; } - if ((status = fn(arg, &attr)) != DLADM_STATUS_OK) - goto done; + size = orig_nports * (LINKID_STR_WIDTH + 1) + 1; + if ((orig_portstr = calloc(1, size)) == NULL) { + status = dladm_errno2status(errno); + goto destroyconf; + } - free(attr.lt_ports); - attr.lt_ports = NULL; - } + status = dladm_get_conf_field(conf, FPORTS, orig_portstr, size); + if (status != DLADM_STATUS_OK) + goto destroyconf; -done: - free(attr.lt_ports); - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); - return (status); -} + result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports : + orig_nports; -/* - * Send an add or remove command to the link aggregation driver. - */ -static dladm_status_t -i_dladm_aggr_add_rem_sys(dladm_aggr_grp_attr_db_t *attr, int cmd) -{ - int i, rc, fd, len; - laioc_add_rem_t *iocp; - laioc_port_t *ports; - dladm_status_t status = DLADM_STATUS_OK; + size = result_nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = dladm_errno2status(errno); + goto destroyconf; + } - len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t); - iocp = malloc(len); - if (iocp == NULL) { - status = DLADM_STATUS_NOMEM; - goto done; - } + /* + * get the new configuration and set to result_nports and + * portstr. + */ + if (cmd == LAIOC_ADD) { + (void) strlcpy(portstr, orig_portstr, size); + for (i = 0; i < nports; i++) + WRITE_PORT(portstr, ports[i].lp_linkid, size); + } else { + char *next; + datalink_id_t portid; + uint32_t remove = 0; + + for (next = orig_portstr, j = 0; j < orig_nports; j++) { + /* + * Read the portids from the old configuration + * one by one. + */ + READ_PORT(next, portid, status); + if (status != DLADM_STATUS_OK) { + free(portstr); + goto destroyconf; + } + + /* + * See whether this port is in the removal + * list. If not, copy to the new config. + */ + for (i = 0; i < nports; i++) { + if (ports[i].lp_linkid == portid) + break; + } + if (i == nports) { + WRITE_PORT(portstr, portid, size); + } else { + remove++; + } + } + if (remove != nports) { + status = DLADM_STATUS_LINKINVAL; + free(portstr); + goto destroyconf; + } + result_nports -= nports; + } + + u64 = result_nports; + if ((status = dladm_set_conf_field(conf, FNPORTS, + DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) { + free(portstr); + goto destroyconf; + } - iocp->la_key = attr->lt_key; - iocp->la_nports = attr->lt_nports; - ports = (laioc_port_t *)(iocp + 1); + status = dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, + portstr); + free(portstr); + if (status != DLADM_STATUS_OK) + goto destroyconf; - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(ports[i].lp_devname, - attr->lt_ports[i].lp_devname, - MAXNAMELEN) >= MAXNAMELEN) { - status = DLADM_STATUS_BADARG; - goto done; + /* + * Write the new configuration to the persistent repository. + */ + status = dladm_write_conf(conf); + +destroyconf: + dladm_destroy_conf(conf); + if (status != DLADM_STATUS_OK) { + free(orig_portstr); + return (status); } } - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) { - status = dladm_errno2status(errno); + /* + * If the caller only requested to update the persistent + * configuration, we are done. + */ + if (!(flags & DLADM_OPT_ACTIVE)) goto done; - } - rc = i_dladm_ioctl(fd, cmd, iocp, len); - if (rc < 0) { - if (errno == EINVAL) - status = DLADM_STATUS_LINKINVAL; - else - status = dladm_errno2status(errno); + /* + * Update the active configuration. + */ + len = sizeof (*iocp) + nports * sizeof (laioc_port_t); + if ((iocp = malloc(len)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - (void) close(fd); + iocp->la_linkid = linkid; + iocp->la_nports = nports; + if (cmd == LAIOC_ADD) + iocp->la_force = (flags & DLADM_OPT_FORCE); + + ioc_ports = (laioc_port_t *)(iocp + 1); + for (i = 0; i < nports; i++) + ioc_ports[i].lp_linkid = ports[i].lp_linkid; + + if (i_dladm_aggr_strioctl(cmd, iocp, len) < 0) + status = dladm_errno2status(errno); done: free(iocp); + + /* + * If the active configuration update fails, restore the old + * persistent configuration if we've changed that. + */ + if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { + if (dladm_read_conf(linkid, &conf) == DLADM_STATUS_OK) { + u64 = orig_nports; + if ((dladm_set_conf_field(conf, FNPORTS, + DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) && + (dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, + orig_portstr) == DLADM_STATUS_OK)) { + (void) dladm_write_conf(conf); + } + (void) dladm_destroy_conf(conf); + } + } + free(orig_portstr); return (status); } @@ -555,14 +579,12 @@ done: * Send a modify command to the link aggregation driver. */ static dladm_status_t -i_dladm_aggr_modify_sys(uint32_t key, uint32_t mask, +i_dladm_aggr_modify_sys(datalink_id_t linkid, uint32_t mask, dladm_aggr_modify_attr_t *attr) { - int rc, fd; laioc_modify_t ioc; - dladm_status_t status = DLADM_STATUS_OK; - ioc.lu_key = key; + ioc.lu_linkid = linkid; ioc.lu_modify_mask = 0; if (mask & DLADM_AGGR_MODIFY_POLICY) @@ -580,68 +602,60 @@ i_dladm_aggr_modify_sys(uint32_t key, uint32_t mask, ioc.lu_lacp_mode = attr->ld_lacp_mode; ioc.lu_lacp_timer = attr->ld_lacp_timer; - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); - - rc = i_dladm_ioctl(fd, LAIOC_MODIFY, &ioc, sizeof (ioc)); - if (rc < 0) { + if (i_dladm_aggr_strioctl(LAIOC_MODIFY, &ioc, sizeof (ioc)) < 0) { if (errno == EINVAL) - status = DLADM_STATUS_MACADDRINVAL; + return (DLADM_STATUS_MACADDRINVAL); else - status = dladm_errno2status(errno); + return (dladm_errno2status(errno)); + } else { + return (DLADM_STATUS_OK); } - - (void) close(fd); - return (status); } /* * Send a create command to the link aggregation driver. */ static dladm_status_t -i_dladm_aggr_create_sys(int fd, dladm_aggr_grp_attr_db_t *attr) +i_dladm_aggr_create_sys(datalink_id_t linkid, uint16_t key, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t policy, + boolean_t mac_addr_fixed, const uchar_t *mac_addr, + aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force) { int i, rc, len; - laioc_create_t *iocp; - laioc_port_t *ports; + laioc_create_t *iocp = NULL; + laioc_port_t *ioc_ports; dladm_status_t status = DLADM_STATUS_OK; - len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t); + len = sizeof (*iocp) + nports * sizeof (laioc_port_t); iocp = malloc(len); if (iocp == NULL) return (DLADM_STATUS_NOMEM); - iocp->lc_key = attr->lt_key; - iocp->lc_nports = attr->lt_nports; - iocp->lc_policy = attr->lt_policy; - iocp->lc_lacp_mode = attr->lt_lacp_mode; - iocp->lc_lacp_timer = attr->lt_lacp_timer; - - ports = (laioc_port_t *)(iocp + 1); + iocp->lc_key = key; + iocp->lc_linkid = linkid; + iocp->lc_nports = nports; + iocp->lc_policy = policy; + iocp->lc_lacp_mode = lacp_mode; + iocp->lc_lacp_timer = lacp_timer; + ioc_ports = (laioc_port_t *)(iocp + 1); + iocp->lc_force = force; - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(ports[i].lp_devname, - attr->lt_ports[i].lp_devname, - MAXNAMELEN) >= MAXNAMELEN) { - free(iocp); - return (DLADM_STATUS_BADARG); - } - } + for (i = 0; i < nports; i++) + ioc_ports[i].lp_linkid = ports[i].lp_linkid; - if (attr->lt_mac_fixed && - ((bcmp(zero_mac, attr->lt_mac, ETHERADDRL) == 0) || - (attr->lt_mac[0] & 0x01))) { - free(iocp); - return (DLADM_STATUS_MACADDRINVAL); + if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) { + status = DLADM_STATUS_MACADDRINVAL; + goto done; } - bcopy(attr->lt_mac, iocp->lc_mac, ETHERADDRL); - iocp->lc_mac_fixed = attr->lt_mac_fixed; + bcopy(mac_addr, iocp->lc_mac, ETHERADDRL); + iocp->lc_mac_fixed = mac_addr_fixed; - rc = i_dladm_ioctl(fd, LAIOC_CREATE, iocp, len); + rc = i_dladm_aggr_strioctl(LAIOC_CREATE, iocp, len); if (rc < 0) - status = DLADM_STATUS_LINKINVAL; + status = dladm_errno2status(errno); +done: free(iocp); return (status); } @@ -649,518 +663,109 @@ i_dladm_aggr_create_sys(int fd, dladm_aggr_grp_attr_db_t *attr) /* * Invoked to bring up a link aggregation group. */ -static dladm_status_t -i_dladm_aggr_up(void *arg, dladm_aggr_grp_attr_db_t *attr) -{ - dladm_aggr_up_t *up = (dladm_aggr_up_t *)arg; - dladm_status_t status; - - if (up->lu_key != 0 && up->lu_key != attr->lt_key) - return (DLADM_STATUS_OK); - - up->lu_found = B_TRUE; - - status = i_dladm_aggr_create_sys(up->lu_fd, attr); - if (status != DLADM_STATUS_OK && up->lu_key != 0) - return (status); - - return (DLADM_STATUS_OK); -} - -/* - * Bring up a link aggregation group or all of them if the key is zero. - * If key is 0, walk may terminate early if any of the links fail - */ -dladm_status_t -dladm_aggr_up(uint32_t key, const char *root) +static int +i_dladm_aggr_up(datalink_id_t linkid, void *arg) { - dladm_aggr_up_t up; + dladm_status_t *statusp = (dladm_status_t *)arg; + dladm_aggr_grp_attr_t attr; + dladm_aggr_port_attr_db_t *ports = NULL; + uint16_t key = 0; + int i, j; dladm_status_t status; - if ((up.lu_fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); - - up.lu_key = key; - up.lu_found = B_FALSE; - - status = i_dladm_aggr_walk_db(i_dladm_aggr_up, &up, root); + status = dladm_aggr_info(linkid, &attr, DLADM_OPT_PERSIST); if (status != DLADM_STATUS_OK) { - (void) close(up.lu_fd); - return (status); + *statusp = status; + return (DLADM_WALK_CONTINUE); } - (void) close(up.lu_fd); - - /* - * only return error if user specified key and key was - * not found - */ - if (!up.lu_found && key != 0) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} -/* - * Send a delete command to the link aggregation driver. - */ -static int -i_dladm_aggr_delete_sys(int fd, dladm_aggr_grp_attr_t *attr) -{ - laioc_delete_t ioc; - - ioc.ld_key = attr->lg_key; - - return (i_dladm_ioctl(fd, LAIOC_DELETE, &ioc, sizeof (ioc))); -} - -/* - * Invoked to bring down a link aggregation group. - */ -static int -i_dladm_aggr_down(void *arg, dladm_aggr_grp_attr_t *attr) -{ - dladm_aggr_down_t *down = (dladm_aggr_down_t *)arg; - int fd, errno_save; - - if (down->ld_key != 0 && down->ld_key != attr->lg_key) - return (0); - down->ld_found = B_TRUE; - - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (-1); + if (attr.lg_key <= AGGR_MAX_KEY) + key = attr.lg_key; - if (i_dladm_aggr_delete_sys(fd, attr) < 0 && down->ld_key != 0) { - errno_save = errno; - (void) close(fd); - errno = errno_save; - return (-1); + ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t)); + if (ports == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - (void) close(fd); - return (0); -} - -/* - * Bring down a link aggregation group or all of them if the key is zero. - * If key is 0, walk may terminate early if any of the links fail - */ -dladm_status_t -dladm_aggr_down(uint32_t key) -{ - dladm_aggr_down_t down; - - down.ld_key = key; - down.ld_found = B_FALSE; - - if (dladm_aggr_walk(i_dladm_aggr_down, &down) < 0) - return (dladm_errno2status(errno)); - /* - * only return error if user specified key and key was - * not found + * Validate (and purge) each physical link associated with this + * aggregation, if the specific hardware has been removed during + * the system shutdown. */ - if (!down.ld_found && key != 0) - return (DLADM_STATUS_NOTFOUND); + for (i = 0, j = 0; i < attr.lg_nports; i++) { + datalink_id_t portid = attr.lg_ports[i].lp_linkid; + uint32_t flags; + dladm_status_t s; - return (DLADM_STATUS_OK); -} - -/* - * For each group <grp> found in the DB, invokes <fn>(<grp>, <arg>). - * - * The following values can be returned by <fn>(): - * - * -1: an error occured. This will cause the walk to be terminated, - * and the original DB file to be preserved. - * - * 0: success and write. The walker will write the contents of - * the attribute passed as argument to <fn>(), and continue walking - * the entries found in the DB. - * - * 1: skip. The walker should not write the contents of the current - * group attributes to the new DB, but should continue walking - * the entries found in the DB. - */ -static dladm_status_t -i_dladm_aggr_walk_rw_db(int (*fn)(void *, dladm_aggr_grp_attr_db_t *), - void *arg, const char *root) -{ - FILE *fp, *nfp; - int nfd, fn_rc, lock_fd; - char line[MAXLINELEN]; - dladm_aggr_grp_attr_db_t attr; - char *db_file, *tmp_db_file; - char db_file_buf[MAXPATHLEN]; - char tmp_db_file_buf[MAXPATHLEN]; - dladm_status_t status; - - if (root == NULL) { - db_file = DLADM_AGGR_DB; - tmp_db_file = DLADM_AGGR_DB_TMP; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - (void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB_TMP); - db_file = db_file_buf; - tmp_db_file = tmp_db_file_buf; - } - - if ((lock_fd = i_dladm_aggr_lock_db(F_WRLCK)) < 0) - return (dladm_errno2status(errno)); - - if ((fp = fopen(db_file, "r")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - if ((nfd = open(tmp_db_file, O_WRONLY|O_CREAT|O_TRUNC, - DLADM_AGGR_DB_PERMS)) == -1) { - status = dladm_errno2status(errno); - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - if ((nfp = fdopen(nfd, "w")) == NULL) { - status = dladm_errno2status(errno); - (void) close(nfd); - (void) fclose(fp); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - attr.lt_ports = NULL; - - while (fgets(line, MAXLINELEN, fp) != NULL) { - - /* skip comments */ - if (BLANK_LINE(line)) { - if (fputs(line, nfp) == EOF) { - status = dladm_errno2status(errno); - goto failed; - } + s = dladm_datalink_id2info(portid, &flags, NULL, NULL, NULL, 0); + if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) continue; - } - - if (i_dladm_aggr_parse_db(line, &attr) != 0) { - status = DLADM_STATUS_REPOSITORYINVAL; - goto failed; - } - - fn_rc = fn(arg, &attr); - - switch (fn_rc) { - case -1: - /* failure, stop walking */ - status = dladm_errno2status(errno); - goto failed; - case 0: - /* - * Success, write group attributes, which could - * have been modified by fn(). - */ - if (i_dladm_aggr_fput_grp(nfp, &attr) != 0) { - status = dladm_errno2status(errno); - goto failed; - } - break; - case 1: - /* skip current group */ - break; - } - - free(attr.lt_ports); - attr.lt_ports = NULL; - } - - if (getuid() == 0 || geteuid() == 0) { - if (fchmod(nfd, DLADM_AGGR_DB_PERMS) == -1) { - status = dladm_errno2status(errno); - goto failed; - } - - if (fchown(nfd, DLADM_AGGR_DB_OWNER, - DLADM_AGGR_DB_GROUP) == -1) { - status = dladm_errno2status(errno); - goto failed; - } - } - - if (fflush(nfp) == EOF) { - status = dladm_errno2status(errno); - goto failed; - } - - (void) fclose(fp); - (void) fclose(nfp); - - if (rename(tmp_db_file, db_file) == -1) { - status = dladm_errno2status(errno); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - i_dladm_aggr_unlock_db(lock_fd); - return (DLADM_STATUS_OK); - -failed: - free(attr.lt_ports); - (void) fclose(fp); - (void) fclose(nfp); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - - return (status); -} - -/* - * Remove an entry from the DB. - */ -static int -i_dladm_aggr_del_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - delete_db_state_t *state = arg; - - if (grp->lt_key != state->ds_key) - return (0); - - state->ds_found = B_TRUE; - - /* don't save matching group */ - return (1); -} - -static dladm_status_t -i_dladm_aggr_del_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - delete_db_state_t state; - dladm_status_t status; - - state.ds_key = attr->lt_key; - state.ds_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_del_db_fn, &state, root); - if (status != DLADM_STATUS_OK) - return (status); - - if (!state.ds_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} - -/* - * Modify the properties of an existing group in the DB. - */ -static int -i_dladm_aggr_modify_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - modify_db_state_t *state = arg; - dladm_aggr_modify_attr_t *new_attr = state->us_attr_new; - dladm_aggr_modify_attr_t *old_attr = state->us_attr_old; - - if (grp->lt_key != state->us_key) - return (0); - - state->us_found = B_TRUE; - - if (state->us_mask & DLADM_AGGR_MODIFY_POLICY) { - if (old_attr != NULL) - old_attr->ld_policy = grp->lt_policy; - grp->lt_policy = new_attr->ld_policy; + ports[j++].lp_linkid = portid; } - if (state->us_mask & DLADM_AGGR_MODIFY_MAC) { - if (old_attr != NULL) { - old_attr->ld_mac_fixed = grp->lt_mac_fixed; - bcopy(grp->lt_mac, old_attr->ld_mac, ETHERADDRL); - } - grp->lt_mac_fixed = new_attr->ld_mac_fixed; - bcopy(new_attr->ld_mac, grp->lt_mac, ETHERADDRL); + if (j == 0) { + /* + * All of the physical links are removed. + */ + status = DLADM_STATUS_BADARG; + goto done; } - if (state->us_mask & DLADM_AGGR_MODIFY_LACP_MODE) { - if (old_attr != NULL) - old_attr->ld_lacp_mode = grp->lt_lacp_mode; - grp->lt_lacp_mode = new_attr->ld_lacp_mode; + /* + * Create active aggregation. + */ + if ((status = i_dladm_aggr_create_sys(linkid, + key, j, ports, attr.lg_policy, attr.lg_mac_fixed, + (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode, + attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) { + goto done; } - if (state->us_mask & DLADM_AGGR_MODIFY_LACP_TIMER) { - if (old_attr != NULL) - old_attr->ld_lacp_timer = grp->lt_lacp_timer; - grp->lt_lacp_timer = new_attr->ld_lacp_timer; + if ((status = dladm_up_datalink_id(linkid)) != DLADM_STATUS_OK) { + laioc_delete_t ioc; + ioc.ld_linkid = linkid; + (void) i_dladm_aggr_strioctl(LAIOC_DELETE, &ioc, sizeof (ioc)); + goto done; } - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_modify_db(uint32_t key, uint32_t mask, - dladm_aggr_modify_attr_t *new, dladm_aggr_modify_attr_t *old, - const char *root) -{ - modify_db_state_t state; - dladm_status_t status; - - state.us_key = key; - state.us_mask = mask; - state.us_attr_new = new; - state.us_attr_old = old; - state.us_found = B_FALSE; - - if ((status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_modify_db_fn, - &state, root)) != DLADM_STATUS_OK) { - return (status); - } + /* + * Reset the active linkprop of this specific link. + */ + (void) dladm_init_linkprop(linkid); - if (!state.us_found) - return (DLADM_STATUS_NOTFOUND); +done: + free(attr.lg_ports); + free(ports); - return (DLADM_STATUS_OK); + *statusp = status; + return (DLADM_WALK_CONTINUE); } /* - * Add ports to an existing group in the DB. + * Bring up one aggregation, or all persistent aggregations. In the latter + * case, the walk may terminate early if bringup of an aggregation fails. */ -static int -i_dladm_aggr_add_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - add_db_state_t *state = arg; - dladm_aggr_grp_attr_db_t *attr = state->as_attr; - void *ports; - int i, j; - - if (grp->lt_key != attr->lt_key) - return (0); - - state->as_found = B_TRUE; - - /* are any of the ports to be added already members of the group? */ - for (i = 0; i < grp->lt_nports; i++) { - for (j = 0; j < attr->lt_nports; j++) { - if (strcmp(grp->lt_ports[i].lp_devname, - attr->lt_ports[j].lp_devname) == 0) { - errno = EEXIST; - return (-1); - } - } - } - - /* add groups specified by attr to grp */ - ports = realloc(grp->lt_ports, (grp->lt_nports + - attr->lt_nports) * sizeof (dladm_aggr_port_attr_db_t)); - if (ports == NULL) - return (-1); - grp->lt_ports = ports; - - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(grp->lt_ports[grp->lt_nports + i].lp_devname, - attr->lt_ports[i].lp_devname, MAXNAMELEN + 1) >= - MAXNAMELEN + 1) - return (-1); - } - - grp->lt_nports += attr->lt_nports; - - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_add_db(dladm_aggr_grp_attr_db_t *attr, const char *root) +dladm_status_t +dladm_aggr_up(datalink_id_t linkid) { - add_db_state_t state; dladm_status_t status; - state.as_attr = attr; - state.as_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_add_db_fn, &state, root); - if (status != DLADM_STATUS_OK) + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_aggr_up, &status, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + return (DLADM_STATUS_OK); + } else { + (void) i_dladm_aggr_up(linkid, &status); return (status); - - if (!state.as_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} - -/* - * Remove ports from an existing group in the DB. - */ - -typedef struct remove_db_state { - dladm_aggr_grp_attr_db_t *rs_attr; - boolean_t rs_found; -} remove_db_state_t; - -static int -i_dladm_aggr_remove_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - remove_db_state_t *state = (remove_db_state_t *)arg; - dladm_aggr_grp_attr_db_t *attr = state->rs_attr; - int i, j, k, nremoved; - boolean_t match; - - if (grp->lt_key != attr->lt_key) - return (0); - - state->rs_found = B_TRUE; - - /* remove the ports specified by attr from the group */ - nremoved = 0; - k = 0; - for (i = 0; i < grp->lt_nports; i++) { - match = B_FALSE; - for (j = 0; j < attr->lt_nports && !match; j++) { - match = (strcmp(grp->lt_ports[i].lp_devname, - attr->lt_ports[j].lp_devname) == 0); - } - if (match) - nremoved++; - else - grp->lt_ports[k++] = grp->lt_ports[i]; - } - - if (nremoved != attr->lt_nports) { - errno = ENOENT; - return (-1); } - - grp->lt_nports -= nremoved; - - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_remove_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - remove_db_state_t state; - dladm_status_t status; - - state.rs_attr = attr; - state.rs_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_remove_db_fn, - &state, root); - if (status != DLADM_STATUS_OK) - return (status); - - if (!state.rs_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); } /* * Given a policy string, return a policy mask. Returns B_TRUE on - * success, or B_FALSE if an error occured during parsing. + * success, or B_FALSE if an error occurred during parsing. */ boolean_t dladm_aggr_str2policy(const char *str, uint32_t *policy) @@ -1199,6 +804,9 @@ dladm_aggr_policy2str(uint32_t policy, char *str) int i, npolicies = 0; policy_t *pol; + if (str == NULL) + return (NULL); + str[0] = '\0'; for (i = 0; i < NPOLICIES; i++) { @@ -1206,8 +814,8 @@ dladm_aggr_policy2str(uint32_t policy, char *str) if ((policy & pol->policy) != 0) { npolicies++; if (npolicies > 1) - (void) strcat(str, ","); - (void) strcat(str, pol->pol_name); + (void) strlcat(str, ",", DLADM_STRSIZE); + (void) strlcat(str, pol->pol_name, DLADM_STRSIZE); } } @@ -1257,7 +865,7 @@ dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr) * Returns a string containing a printable representation of a MAC address. */ const char * -dladm_aggr_macaddr2str(unsigned char *mac, char *buf) +dladm_aggr_macaddr2str(const unsigned char *mac, char *buf) { static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; @@ -1265,9 +873,11 @@ dladm_aggr_macaddr2str(unsigned char *mac, char *buf) return (NULL); if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) - return (gettext("<unknown>")); + (void) strlcpy(buf, "unknown", DLADM_STRSIZE); else return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); + + return (buf); } /* @@ -1302,6 +912,9 @@ dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf) int i; dladm_aggr_lacpmode_t *mode; + if (buf == NULL) + return (NULL); + for (i = 0; i < NLACP_MODES; i++) { mode = &lacp_modes[i]; if (mode->mode_id == mode_id) { @@ -1347,6 +960,9 @@ dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf) int i; dladm_aggr_lacptimer_t *timer; + if (buf == NULL) + return (NULL); + for (i = 0; i < NLACP_TIMERS; i++) { timer = &lacp_timers[i]; if (timer->lt_id == timer_id) { @@ -1364,7 +980,10 @@ const char * dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) { int i; - dladm_aggr_port_state_t *state; + dladm_aggr_port_state_t *state; + + if (buf == NULL) + return (NULL); for (i = 0; i < NPORT_STATES; i++) { state = &port_states[i]; @@ -1379,123 +998,94 @@ dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) return (buf); } -#define FPRINTF_ERR(fcall) if ((fcall) < 0) return (-1); - -/* - * Write the attribute of a group to the specified file. Returns 0 on - * success, -1 on failure. - */ -static int -i_dladm_aggr_fput_grp(FILE *fp, dladm_aggr_grp_attr_db_t *attr) +static dladm_status_t +dladm_aggr_persist_aggr_conf(const char *link, datalink_id_t linkid, + uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, + uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr, + aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, + boolean_t force) { - int i; - char addr_str[ETHERADDRL * 3]; - char buf[DLADM_STRSIZE]; - - /* key, policy */ - FPRINTF_ERR(fprintf(fp, "%d\t%s\t", attr->lt_key, - dladm_aggr_policy2str(attr->lt_policy, buf))); - - /* number of ports, ports */ - FPRINTF_ERR(fprintf(fp, "%d\t", attr->lt_nports)); - for (i = 0; i < attr->lt_nports; i++) { - if (i > 0) - FPRINTF_ERR(fprintf(fp, ",")); - FPRINTF_ERR(fprintf(fp, "%s", attr->lt_ports[i].lp_devname)); - } - FPRINTF_ERR(fprintf(fp, "\t")); + dladm_conf_t conf = DLADM_INVALID_CONF; + char *portstr = NULL; + char macstr[ETHERADDRL * 3]; + dladm_status_t status; + int i, size; + uint64_t u64; - /* MAC address */ - if (!attr->lt_mac_fixed) { - FPRINTF_ERR(fprintf(fp, "auto")); - } else { - FPRINTF_ERR(fprintf(fp, "%s", - dladm_aggr_macaddr2str(attr->lt_mac, addr_str))); + if ((status = dladm_create_conf(link, linkid, DATALINK_CLASS_AGGR, + DL_ETHER, &conf)) != DLADM_STATUS_OK) { + return (status); } - FPRINTF_ERR(fprintf(fp, "\t")); - - FPRINTF_ERR(fprintf(fp, "%s\t", - dladm_aggr_lacpmode2str(attr->lt_lacp_mode, buf))); - - FPRINTF_ERR(fprintf(fp, "%s\n", - dladm_aggr_lacptimer2str(attr->lt_lacp_timer, buf))); - return (0); -} + u64 = key; + status = dladm_set_conf_field(conf, FKEY, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; -static dladm_status_t -i_dladm_aggr_create_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - FILE *fp; - char line[MAXLINELEN]; - uint32_t key; - int lock_fd; - char *db_file; - char db_file_buf[MAXPATHLEN]; - char *endp = NULL; - dladm_status_t status; + u64 = nports; + status = dladm_set_conf_field(conf, FNPORTS, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; - if (root == NULL) { - db_file = DLADM_AGGR_DB; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - db_file = db_file_buf; + size = nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - if ((lock_fd = i_dladm_aggr_lock_db(F_WRLCK)) < 0) - return (dladm_errno2status(errno)); + for (i = 0; i < nports; i++) + WRITE_PORT(portstr, ports[i].lp_linkid, size); + status = dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, portstr); + free(portstr); - if ((fp = fopen(db_file, "r+")) == NULL && - (fp = fopen(db_file, "w")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - /* look for existing group with same key */ - while (fgets(line, MAXLINELEN, fp) != NULL) { - char *holder, *lasts; + if (status != DLADM_STATUS_OK) + goto done; - /* skip comments */ - if (BLANK_LINE(line)) - continue; + u64 = policy; + status = dladm_set_conf_field(conf, FPOLICY, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; - /* ignore corrupted lines */ - holder = strtok_r(line, " \t", &lasts); - if (holder == NULL) - continue; + status = dladm_set_conf_field(conf, FFIXMACADDR, DLADM_TYPE_BOOLEAN, + &mac_addr_fixed); + if (status != DLADM_STATUS_OK) + goto done; - /* port number */ - errno = 0; - key = (int)strtol(holder, &endp, 10); - if (errno != 0 || *endp != '\0') { - status = DLADM_STATUS_REPOSITORYINVAL; + if (mac_addr_fixed) { + if (!VALID_PORT_MAC(mac_addr)) { + status = DLADM_STATUS_MACADDRINVAL; goto done; } - if (key == attr->lt_key) { - /* group with key already exists */ - status = DLADM_STATUS_EXIST; + (void) dladm_aggr_macaddr2str(mac_addr, macstr); + status = dladm_set_conf_field(conf, FMACADDR, DLADM_TYPE_STR, + macstr); + if (status != DLADM_STATUS_OK) goto done; - } } - /* - * If we get here, we've verified that no existing group with - * the same key already exists. It's now time to add the - * new group to the DB. - */ - if (i_dladm_aggr_fput_grp(fp, attr) != 0) { - status = dladm_errno2status(errno); + status = dladm_set_conf_field(conf, FFORCE, DLADM_TYPE_BOOLEAN, &force); + if (status != DLADM_STATUS_OK) goto done; - } - status = DLADM_STATUS_OK; + u64 = lacp_mode; + status = dladm_set_conf_field(conf, FLACPMODE, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; + + u64 = lacp_timer; + status = dladm_set_conf_field(conf, FLACPTIMER, DLADM_TYPE_UINT64, + &u64); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * Commit the link aggregation configuration. + */ + status = dladm_write_conf(conf); done: - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); + dladm_destroy_conf(conf); return (status); } @@ -1504,60 +1094,168 @@ done: * file and bring it up. */ dladm_status_t -dladm_aggr_create(uint32_t key, uint32_t nports, +dladm_aggr_create(const char *name, uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed, - uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, - boolean_t tempop, const char *root) + const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, + aggr_lacp_timer_t lacp_timer, uint32_t flags) { - dladm_aggr_grp_attr_db_t attr; + datalink_id_t linkid = DATALINK_INVALID_LINKID; + uint32_t media; + uint32_t i; + datalink_class_t class; dladm_status_t status; + boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE; - if (key == 0 || key > DLADM_AGGR_MAX_KEY) + if (key != 0 && key > AGGR_MAX_KEY) return (DLADM_STATUS_KEYINVAL); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; - attr.lt_policy = policy; - attr.lt_mac_fixed = mac_addr_fixed; - if (attr.lt_mac_fixed) - bcopy(mac_addr, attr.lt_mac, ETHERADDRL); - else - bzero(attr.lt_mac, ETHERADDRL); - attr.lt_lacp_mode = lacp_mode; - attr.lt_lacp_timer = lacp_timer; + if (nports == 0) + return (DLADM_STATUS_BADARG); - /* add the link aggregation group to the DB */ - if (!tempop) { - status = i_dladm_aggr_create_db(&attr, root); + for (i = 0; i < nports; i++) { + if ((dladm_datalink_id2info(ports[i].lp_linkid, NULL, + &class, &media, NULL, 0) != DLADM_STATUS_OK) || + (class != DATALINK_CLASS_PHYS) && (media != DL_ETHER)) { + return (DLADM_STATUS_BADARG); + } + } + + flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); + if ((status = dladm_create_datalink_id(name, DATALINK_CLASS_AGGR, + DL_ETHER, flags, &linkid)) != DLADM_STATUS_OK) { + goto fail; + } + + if ((flags & DLADM_OPT_PERSIST) && + (status = dladm_aggr_persist_aggr_conf(name, linkid, key, nports, + ports, policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, + force)) != DLADM_STATUS_OK) { + goto fail; + } + + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_OK); + + status = i_dladm_aggr_create_sys(linkid, key, nports, ports, policy, + mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force); + + if (status != DLADM_STATUS_OK) { + if (flags & DLADM_OPT_PERSIST) + (void) dladm_remove_conf(linkid); + goto fail; + } + + return (DLADM_STATUS_OK); + +fail: + if (linkid != DATALINK_INVALID_LINKID) + (void) dladm_destroy_datalink_id(linkid, flags); + + return (status); +} + +static dladm_status_t +i_dladm_aggr_get_aggr_attr(dladm_conf_t conf, uint32_t mask, + dladm_aggr_modify_attr_t *attrp) +{ + dladm_status_t status = DLADM_STATUS_OK; + char macstr[ETHERADDRL * 3]; + uint64_t u64; + + if (mask & DLADM_AGGR_MODIFY_POLICY) { + status = dladm_get_conf_field(conf, FPOLICY, &u64, + sizeof (u64)); if (status != DLADM_STATUS_OK) return (status); - } else { - dladm_aggr_up_t up; + attrp->ld_policy = (uint32_t)u64; + } - up.lu_key = key; - up.lu_found = B_FALSE; - up.lu_fd = open(DLADM_AGGR_DEV, O_RDWR); - if (up.lu_fd < 0) - return (dladm_errno2status(errno)); + if (mask & DLADM_AGGR_MODIFY_MAC) { + status = dladm_get_conf_field(conf, FFIXMACADDR, + &attrp->ld_mac_fixed, sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + return (status); - status = i_dladm_aggr_up((void *)&up, &attr); - (void) close(up.lu_fd); - return (status); + if (attrp->ld_mac_fixed) { + boolean_t fixed; + + status = dladm_get_conf_field(conf, FMACADDR, + macstr, sizeof (macstr)); + if (status != DLADM_STATUS_OK) + return (status); + + if (!dladm_aggr_str2macaddr(macstr, &fixed, + attrp->ld_mac)) { + return (DLADM_STATUS_REPOSITORYINVAL); + } + } } - /* bring up the link aggregation group */ - status = dladm_aggr_up(key, root); - /* - * If the operation fails because the aggregation already exists, - * then only update the persistent configuration repository and - * return success. - */ - if (status == DLADM_STATUS_EXIST) - status = DLADM_STATUS_OK; + if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { + status = dladm_get_conf_field(conf, FLACPMODE, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + return (status); + attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64; + } + + if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { + status = dladm_get_conf_field(conf, FLACPTIMER, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + return (status); + attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64; + } + + return (status); +} + +static dladm_status_t +i_dladm_aggr_set_aggr_attr(dladm_conf_t conf, uint32_t mask, + dladm_aggr_modify_attr_t *attrp) +{ + dladm_status_t status = DLADM_STATUS_OK; + char macstr[ETHERADDRL * 3]; + uint64_t u64; + + if (mask & DLADM_AGGR_MODIFY_POLICY) { + u64 = attrp->ld_policy; + status = dladm_set_conf_field(conf, FPOLICY, DLADM_TYPE_UINT64, + &u64); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (mask & DLADM_AGGR_MODIFY_MAC) { + status = dladm_set_conf_field(conf, FFIXMACADDR, + DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed); + if (status != DLADM_STATUS_OK) + return (status); + + if (attrp->ld_mac_fixed) { + (void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr); + status = dladm_set_conf_field(conf, FMACADDR, + DLADM_TYPE_STR, macstr); + if (status != DLADM_STATUS_OK) + return (status); + } + } + + if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { + u64 = attrp->ld_lacp_mode; + status = dladm_set_conf_field(conf, FLACPMODE, + DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + return (status); + } - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_del_db(&attr, root); + if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { + u64 = attrp->ld_lacp_timer; + status = dladm_set_conf_field(conf, FLACPTIMER, + DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + return (status); + } return (status); } @@ -1567,146 +1265,211 @@ dladm_aggr_create(uint32_t key, uint32_t nports, * the configuration file and pass the changes to the kernel. */ dladm_status_t -dladm_aggr_modify(uint32_t key, uint32_t modify_mask, uint32_t policy, - boolean_t mac_fixed, uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, - aggr_lacp_timer_t lacp_timer, boolean_t tempop, const char *root) +dladm_aggr_modify(datalink_id_t linkid, uint32_t modify_mask, uint32_t policy, + boolean_t mac_fixed, const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, + aggr_lacp_timer_t lacp_timer, uint32_t flags) { dladm_aggr_modify_attr_t new_attr, old_attr; + dladm_conf_t conf; dladm_status_t status; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); + new_attr.ld_policy = policy; + new_attr.ld_mac_fixed = mac_fixed; + new_attr.ld_lacp_mode = lacp_mode; + new_attr.ld_lacp_timer = lacp_timer; + bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); - if (modify_mask & DLADM_AGGR_MODIFY_POLICY) - new_attr.ld_policy = policy; + if (flags & DLADM_OPT_PERSIST) { + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); - if (modify_mask & DLADM_AGGR_MODIFY_MAC) { - new_attr.ld_mac_fixed = mac_fixed; - bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); - } + if ((status = i_dladm_aggr_get_aggr_attr(conf, modify_mask, + &old_attr)) != DLADM_STATUS_OK) { + goto done; + } - if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) - new_attr.ld_lacp_mode = lacp_mode; + if ((status = i_dladm_aggr_set_aggr_attr(conf, modify_mask, + &new_attr)) != DLADM_STATUS_OK) { + goto done; + } - if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) - new_attr.ld_lacp_timer = lacp_timer; + status = dladm_write_conf(conf); - /* update the DB */ - if (!tempop && ((status = i_dladm_aggr_modify_db(key, modify_mask, - &new_attr, &old_attr, root)) != DLADM_STATUS_OK)) { - return (status); +done: + dladm_destroy_conf(conf); + if (status != DLADM_STATUS_OK) + return (status); } - status = i_dladm_aggr_modify_sys(key, modify_mask, &new_attr); - if (status != DLADM_STATUS_OK && !tempop) { - (void) i_dladm_aggr_modify_db(key, modify_mask, &old_attr, - NULL, root); + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_OK); + + status = i_dladm_aggr_modify_sys(linkid, modify_mask, &new_attr); + if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { + if (dladm_read_conf(linkid, &conf) == DLADM_STATUS_OK) { + if (i_dladm_aggr_set_aggr_attr(conf, modify_mask, + &old_attr) == DLADM_STATUS_OK) { + (void) dladm_write_conf(conf); + } + dladm_destroy_conf(conf); + } } return (status); } +typedef struct aggr_held_arg_s { + datalink_id_t aggrid; + boolean_t isheld; +} aggr_held_arg_t; + +static int +i_dladm_aggr_is_held(datalink_id_t linkid, void *arg) +{ + aggr_held_arg_t *aggr_held_arg = arg; + dladm_vlan_attr_t dva; + + if (dladm_vlan_info(linkid, &dva, DLADM_OPT_PERSIST) != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + if (dva.dv_linkid == aggr_held_arg->aggrid) { + /* + * This VLAN is created over the given aggregation. + */ + aggr_held_arg->isheld = B_TRUE; + return (DLADM_WALK_TERMINATE); + } + return (DLADM_WALK_CONTINUE); +} + /* - * Delete a previously created link aggregation group. + * Delete a previously created link aggregation group. Either the name "aggr" + * or the "key" is specified. */ dladm_status_t -dladm_aggr_delete(uint32_t key, boolean_t tempop, const char *root) +dladm_aggr_delete(datalink_id_t linkid, uint32_t flags) { - dladm_aggr_grp_attr_db_t db_attr; + laioc_delete_t ioc; + datalink_class_t class; dladm_status_t status; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); - - if (tempop) { - dladm_aggr_down_t down; - dladm_aggr_grp_attr_t sys_attr; + if ((dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0) != + DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) { + return (DLADM_STATUS_BADARG); + } - down.ld_key = key; - down.ld_found = B_FALSE; - sys_attr.lg_key = key; - if (i_dladm_aggr_down((void *)&down, &sys_attr) < 0) - return (dladm_errno2status(errno)); - else - return (DLADM_STATUS_OK); - } else { - status = dladm_aggr_down(key); + if (flags & DLADM_OPT_ACTIVE) { + ioc.ld_linkid = linkid; + if ((i_dladm_aggr_strioctl(LAIOC_DELETE, &ioc, + sizeof (ioc)) < 0) && + ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { + status = dladm_errno2status(errno); + return (status); + } /* - * Only continue to delete the configuration repository - * either if we successfully delete the active aggregation - * or if the aggregation is not found. + * Delete ACTIVE linkprop first. */ - if (status != DLADM_STATUS_OK && - status != DLADM_STATUS_NOTFOUND) { - return (status); - } + (void) dladm_set_linkprop(linkid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); } - if (tempop) - return (DLADM_STATUS_OK); + /* + * If we reach here, it means that the active aggregation has already + * been deleted, and there is no active VLANs holding this aggregation. + * Now we see whether there is any persistent VLANs holding this + * aggregation. If so, we fail the operation. + */ + if (flags & DLADM_OPT_PERSIST) { + aggr_held_arg_t arg; + + arg.aggrid = linkid; + arg.isheld = B_FALSE; + + (void) dladm_walk_datalink_id(i_dladm_aggr_is_held, + &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + if (arg.isheld) + return (DLADM_STATUS_LINKBUSY); + + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); + (void) dladm_remove_conf(linkid); + } - db_attr.lt_key = key; - return (i_dladm_aggr_del_db(&db_attr, root)); + return (DLADM_STATUS_OK); } /* * Add one or more ports to an existing link aggregation. */ dladm_status_t -dladm_aggr_add(uint32_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, - boolean_t tempop, const char *root) +dladm_aggr_add(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags) { - dladm_aggr_grp_attr_db_t attr; - dladm_status_t status; - - if (key == 0) - return (DLADM_STATUS_KEYINVAL); - - bzero(&attr, sizeof (attr)); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; - - if (!tempop && - ((status = i_dladm_aggr_add_db(&attr, root)) != DLADM_STATUS_OK)) { - return (status); - } - - status = i_dladm_aggr_add_rem_sys(&attr, LAIOC_ADD); - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_remove_db(&attr, root); - - return (status); + return (i_dladm_aggr_add_rmv(linkid, nports, ports, flags, LAIOC_ADD)); } /* * Remove one or more ports from an existing link aggregation. */ dladm_status_t -dladm_aggr_remove(uint32_t key, uint32_t nports, - dladm_aggr_port_attr_db_t *ports, boolean_t tempop, const char *root) +dladm_aggr_remove(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags) +{ + return (i_dladm_aggr_add_rmv(linkid, nports, ports, flags, + LAIOC_REMOVE)); +} + +typedef struct i_walk_key_state_s { + uint16_t key; + datalink_id_t linkid; + boolean_t found; +} i_walk_key_state_t; + +static int +i_dladm_walk_key2linkid(datalink_id_t linkid, void *arg) { - dladm_aggr_grp_attr_db_t attr; + dladm_conf_t conf; + uint16_t key; dladm_status_t status; + i_walk_key_state_t *statep = (i_walk_key_state_t *)arg; + uint64_t u64; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); + if (dladm_read_conf(linkid, &conf) != 0) + return (DLADM_WALK_CONTINUE); - bzero(&attr, sizeof (attr)); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; + status = dladm_get_conf_field(conf, FKEY, &u64, sizeof (u64)); + key = (uint16_t)u64; + dladm_destroy_conf(conf); - if (!tempop && - ((status = i_dladm_aggr_remove_db(&attr, root)) != - DLADM_STATUS_OK)) { - return (status); + if ((status == DLADM_STATUS_OK) && (key == statep->key)) { + statep->found = B_TRUE; + statep->linkid = linkid; + return (DLADM_WALK_TERMINATE); } - status = i_dladm_aggr_add_rem_sys(&attr, LAIOC_REMOVE); - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_add_db(&attr, root); + return (DLADM_WALK_CONTINUE); +} - return (status); +dladm_status_t +dladm_key2linkid(uint16_t key, datalink_id_t *linkidp, uint32_t flags) +{ + i_walk_key_state_t state; + + if (key > AGGR_MAX_KEY) + return (DLADM_STATUS_NOTFOUND); + + state.found = B_FALSE; + state.key = key; + + (void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, &state, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); + if (state.found == B_TRUE) { + *linkidp = state.linkid; + return (DLADM_STATUS_OK); + } else { + return (DLADM_STATUS_NOTFOUND); + } } |