aggr_grp.c revision 195993116a964de43c0be7ac387506d62dc7e201
70025d765b044c6d8594bb965a2247a61e991a99johnny * CDDL HEADER START
70025d765b044c6d8594bb965a2247a61e991a99johnny * The contents of this file are subject to the terms of the
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Common Development and Distribution License (the "License").
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * You may not use this file except in compliance with the License.
70025d765b044c6d8594bb965a2247a61e991a99johnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
70025d765b044c6d8594bb965a2247a61e991a99johnny * See the License for the specific language governing permissions
70025d765b044c6d8594bb965a2247a61e991a99johnny * and limitations under the License.
70025d765b044c6d8594bb965a2247a61e991a99johnny * When distributing Covered Code, include this CDDL HEADER in each
70025d765b044c6d8594bb965a2247a61e991a99johnny * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
70025d765b044c6d8594bb965a2247a61e991a99johnny * If applicable, add the following below this CDDL HEADER, with the
70025d765b044c6d8594bb965a2247a61e991a99johnny * fields enclosed by brackets "[]" replaced with your own identifying
70025d765b044c6d8594bb965a2247a61e991a99johnny * information: Portions Copyright [yyyy] [name of copyright owner]
70025d765b044c6d8594bb965a2247a61e991a99johnny * CDDL HEADER END
70025d765b044c6d8594bb965a2247a61e991a99johnny * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
fc256490629fe68815f7e0f23cf9b3545720cfacJason Beloro * Use is subject to license terms.
70025d765b044c6d8594bb965a2247a61e991a99johnny#pragma ident "%Z%%M% %I% %E% SMI"
70025d765b044c6d8594bb965a2247a61e991a99johnny * IEEE 802.3ad Link Aggregation -- Link Aggregation Groups.
70025d765b044c6d8594bb965a2247a61e991a99johnny * An instance of the structure aggr_grp_t is allocated for each
70025d765b044c6d8594bb965a2247a61e991a99johnny * link aggregation group. When created, aggr_grp_t objects are
269473047d747f7815af570197e4ef7322d3632cEvan Yan * entered into the aggr_grp_hash hash table maintained by the modhash
70025d765b044c6d8594bb965a2247a61e991a99johnny * module. The hash key is the linkid associated with the link
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnny * A set of MAC ports are associated with each association group.
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int aggr_m_start(void *);
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic void aggr_m_stop(void *);
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int aggr_m_multicst(void *, boolean_t, const uint8_t *);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetstatic void aggr_m_resources(void *);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetstatic void aggr_m_ioctl(void *, queue_t *, mblk_t *);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetstatic boolean_t aggr_m_capab_get(void *, mac_capab_t, void *);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetstatic aggr_port_t *aggr_grp_port_lookup(aggr_grp_t *, datalink_id_t);
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int aggr_grp_rem_port(aggr_grp_t *, aggr_port_t *, boolean_t *,
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaestatic boolean_t aggr_grp_capab_check(aggr_grp_t *, aggr_port_t *);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaestatic boolean_t aggr_grp_sdu_check(aggr_grp_t *, aggr_port_t *);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaestatic boolean_t aggr_grp_margin_check(aggr_grp_t *, aggr_port_t *);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaestatic int aggr_grp_multicst(aggr_grp_t *grp, boolean_t add,
70025d765b044c6d8594bb965a2247a61e991a99johnny#define GRP_HASH_KEY(linkid) ((mod_hash_key_t)(uintptr_t)linkid)
70025d765b044c6d8594bb965a2247a61e991a99johnny#define AGGR_M_CALLBACK_FLAGS (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB)
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanaggr_grp_constructor(void *buf, void *arg, int kmflag)
70025d765b044c6d8594bb965a2247a61e991a99johnny mutex_init(&grp->aggr.gl_lock, NULL, MUTEX_DEFAULT, NULL);
70025d765b044c6d8594bb965a2247a61e991a99johnny return (0);
70025d765b044c6d8594bb965a2247a61e991a99johnny/*ARGSUSED*/
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_hash = mod_hash_create_idhash("aggr_grp_hash",
70025d765b044c6d8594bb965a2247a61e991a99johnny * Allocate an id space to manage key values (when key is not
70025d765b044c6d8594bb965a2247a61e991a99johnny * specified). The range of the id space will be from
70025d765b044c6d8594bb965a2247a61e991a99johnny * (AGGR_MAX_KEY + 1) to UINT16_MAX, because the LACP protocol
70025d765b044c6d8594bb965a2247a61e991a99johnny * uses a 16-bit key.
193974072f41a843678abf5f61979c748687e66bSherry Moore key_ids = id_space_create("aggr_key_ids", AGGR_MAX_KEY + 1, UINT16_MAX);
70025d765b044c6d8594bb965a2247a61e991a99johnny * Attach a port to a link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnny * A port is attached to a link aggregation group once its speed
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and link state have been verified.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Returns B_TRUE if the group link state or speed has changed. If
70025d765b044c6d8594bb965a2247a61e991a99johnny * it's the case, the caller must notify the MAC layer via a call
70025d765b044c6d8594bb965a2247a61e991a99johnny * to mac_link().
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_attach_port(aggr_grp_t *grp, aggr_port_t *port)
70025d765b044c6d8594bb965a2247a61e991a99johnny * Validate the MAC port link speed and update the group
70025d765b044c6d8594bb965a2247a61e991a99johnny * link speed if needed.
70025d765b044c6d8594bb965a2247a61e991a99johnny * Can't attach a MAC port with unknown link speed,
70025d765b044c6d8594bb965a2247a61e991a99johnny * down link, or not in full duplex mode.
70025d765b044c6d8594bb965a2247a61e991a99johnny * The group inherits the speed of the first link being
70025d765b044c6d8594bb965a2247a61e991a99johnny * attached.
70025d765b044c6d8594bb965a2247a61e991a99johnny * The link speed of the MAC port must be the same as
70025d765b044c6d8594bb965a2247a61e991a99johnny * the group link speed, as per 802.3ad. Since it is
70025d765b044c6d8594bb965a2247a61e991a99johnny * not, the attach is cancelled.
70025d765b044c6d8594bb965a2247a61e991a99johnny * Update the group link state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Update port's state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Set port's receive callback
269473047d747f7815af570197e4ef7322d3632cEvan Yan port->lp_mrh = mac_rx_add(port->lp_mh, aggr_recv_cb, (void *)port);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If LACP is OFF, the port can be used to send data as soon
269473047d747f7815af570197e4ef7322d3632cEvan Yan * as its link is up and verified to be compatible with the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * aggregation.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If LACP is active or passive, notify the LACP subsystem, which
269473047d747f7815af570197e4ef7322d3632cEvan Yan * will enable sending on the port following the LACP protocol.
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_detach_port(aggr_grp_t *grp, aggr_port_t *port)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases /* update state */
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases mac_rx_remove(port->lp_mh, port->lp_mrh, B_FALSE);
70025d765b044c6d8594bb965a2247a61e991a99johnny /* the last attached MAC port of the group is being detached */
70025d765b044c6d8594bb965a2247a61e991a99johnny * Update the MAC addresses of the constituent ports of the specified
269473047d747f7815af570197e4ef7322d3632cEvan Yan * group. This function is invoked:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * - after creating a new aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnny * - after adding new ports to an aggregation group.
7a364d25fde47aa82704b12b5251bf7fac37f02eschwartz * - after removing a port from a group when the MAC address of
269473047d747f7815af570197e4ef7322d3632cEvan Yan * that port was used for the MAC address of the group.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * - after the MAC address of a port changed when the MAC address
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * of that port was used for the MAC address of the group.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Return true if the link state of the aggregation changed, for example
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * as a result of a failure changing the MAC address of one of the
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * constituent ports.
70025d765b044c6d8594bb965a2247a61e991a99johnny * If a port was detached because of a previous
70025d765b044c6d8594bb965a2247a61e991a99johnny * failure changing the MAC address, the port is
70025d765b044c6d8594bb965a2247a61e991a99johnny * reattached when it successfully changes the MAC
70025d765b044c6d8594bb965a2247a61e991a99johnny * address now, and this might cause the link state
70025d765b044c6d8594bb965a2247a61e991a99johnny * of the aggregation to change.
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * Invoked when the MAC address of a port has changed. If the port's
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * MAC address was used for the group MAC address, set mac_addr_changedp
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * to B_TRUE to indicate to the caller that it should send a MAC_NOTE_UNICST
269473047d747f7815af570197e4ef7322d3632cEvan Yan * notification. If the link state changes due to detach/attach of
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the constituent port, set link_state_changedp to B_TRUE to indicate
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * to the caller that it should send a MAC_NOTE_LINK notification. In both
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * cases, it is the responsibility of the caller to invoke notification
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * functions after releasing the the port lock.
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaeaggr_grp_port_mac_changed(aggr_grp_t *grp, aggr_port_t *port,
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae boolean_t *mac_addr_changedp, boolean_t *link_state_changedp)
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * The group is using a fixed MAC address or an automatic
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * MAC address has not been set.
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * The MAC address of the port was assigned to the group
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * MAC address. Update the group MAC address.
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg bcopy(port->lp_addr, grp->lg_addr, ETHERADDRL);
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * Update the actual port MAC address to the MAC address
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * of the group.
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if (aggr_port_unicst(port, grp->lg_addr) != 0) {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg *link_state_changedp = aggr_grp_detach_port(grp, port);
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * If a port was detached because of a previous
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * failure changing the MAC address, the port is
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * reattached when it successfully changes the MAC
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * address now, and this might cause the link state
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * of the aggregation to change.
70025d765b044c6d8594bb965a2247a61e991a99johnny *link_state_changedp = aggr_grp_attach_port(grp, port);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Add a port to a link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_add_port(aggr_grp_t *grp, datalink_id_t linkid, boolean_t force,
70025d765b044c6d8594bb965a2247a61e991a99johnny /* create new port */
70025d765b044c6d8594bb965a2247a61e991a99johnny /* add port to list of group constituent ports */
70025d765b044c6d8594bb965a2247a61e991a99johnny * Back reference to the group it is member of. A port always
70025d765b044c6d8594bb965a2247a61e991a99johnny * holds a reference to its group to ensure that the back
70025d765b044c6d8594bb965a2247a61e991a99johnny * reference is always valid.
70025d765b044c6d8594bb965a2247a61e991a99johnny * Initialize the callback functions for this port. Note that this
70025d765b044c6d8594bb965a2247a61e991a99johnny * can only be done after the lp_grp field is set.
70025d765b044c6d8594bb965a2247a61e991a99johnny return (0);
70025d765b044c6d8594bb965a2247a61e991a99johnny * Add one or more ports to an existing link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force,
70025d765b044c6d8594bb965a2247a61e991a99johnny /* get group corresponding to linkid */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
70025d765b044c6d8594bb965a2247a61e991a99johnny /* add the specified ports to group */
70025d765b044c6d8594bb965a2247a61e991a99johnny for (i = 0; i < nports; i++) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /* add port to group */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* check capabilities */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* start port if group has already been started */
70025d765b044c6d8594bb965a2247a61e991a99johnny /* set port promiscuous mode */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (rc != 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny * Attach each port if necessary.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* update the MAC address of the constituent ports */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (rc != 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /* stop and remove ports that have been added */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet port = aggr_grp_port_lookup(grp, ports[i].lp_linkid);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Update properties of an existing link aggregation group.
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldbergaggr_grp_modify(datalink_id_t linkid, aggr_grp_t *grp_arg, uint8_t update_mask,
70025d765b044c6d8594bb965a2247a61e991a99johnny uint32_t policy, boolean_t mac_fixed, const uchar_t *mac_addr,
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer)
70025d765b044c6d8594bb965a2247a61e991a99johnny /* get group corresponding to linkid */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg ASSERT(RW_WRITE_HELD(&grp->lg_lock) || RW_READ_HELD(&grp->lg_lock));
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* validate fixed address if specified */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if ((update_mask & AGGR_MODIFY_MAC) && mac_fixed &&
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg ((bcmp(aggr_zero_mac, mac_addr, ETHERADDRL) == 0) ||
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* update policy if requested */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* update unicast MAC address if requested */
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick /* user-supplied MAC address */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if (bcmp(mac_addr, grp->lg_addr, ETHERADDRL) != 0) {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* switch from user-supplied to automatic */
70025d765b044c6d8594bb965a2247a61e991a99johnny if ((update_mask & AGGR_MODIFY_LACP_TIMER) && !grp->lg_closing)
70025d765b044c6d8594bb965a2247a61e991a99johnny * If grp_arg is non-NULL, this function is called from
70025d765b044c6d8594bb965a2247a61e991a99johnny * mac_unicst_set(), and the MAC_NOTE_UNICST notification
70025d765b044c6d8594bb965a2247a61e991a99johnny * will be sent there.
70025d765b044c6d8594bb965a2247a61e991a99johnny * Create a new link aggregation group upon request from administrator.
70025d765b044c6d8594bb965a2247a61e991a99johnny * Returns 0 on success, an errno on failure.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetaggr_grp_create(datalink_id_t linkid, uint32_t key, uint_t nports,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet laioc_port_t *ports, uint32_t policy, boolean_t mac_fixed, boolean_t force,
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* need at least one port */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* does a group with the same linkid already exist? */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet err = mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (err == 0) {
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae /* add MAC ports to group */
70025d765b044c6d8594bb965a2247a61e991a99johnny * If key is not specified by the user, allocate the key.
70025d765b044c6d8594bb965a2247a61e991a99johnny if ((key == 0) && ((key = (uint32_t)id_alloc(key_ids)) == 0)) {
70025d765b044c6d8594bb965a2247a61e991a99johnny for (i = 0; i < nports; i++) {
70025d765b044c6d8594bb965a2247a61e991a99johnny err = aggr_grp_add_port(grp, ports[i].lp_linkid, force, NULL);
70025d765b044c6d8594bb965a2247a61e991a99johnny * If no explicit MAC address was specified by the administrator,
70025d765b044c6d8594bb965a2247a61e991a99johnny * set it to the MAC address of the first port.
70025d765b044c6d8594bb965a2247a61e991a99johnny /* validate specified address */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (bcmp(aggr_zero_mac, mac_addr, ETHERADDRL) == 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny bcopy(grp->lg_ports->lp_addr, grp->lg_addr, ETHERADDRL);
70025d765b044c6d8594bb965a2247a61e991a99johnny * Update the MAC address of the constituent ports.
70025d765b044c6d8594bb965a2247a61e991a99johnny * None of the port is attached at this time, the link state of the
70025d765b044c6d8594bb965a2247a61e991a99johnny * aggregation will not change.
70025d765b044c6d8594bb965a2247a61e991a99johnny /* update outbound load balancing policy */
70025d765b044c6d8594bb965a2247a61e991a99johnny /* set the initial group capabilities */
70025d765b044c6d8594bb965a2247a61e991a99johnny mac->m_instance = grp->lg_key > AGGR_MAX_KEY ? (uint_t)-1 : grp->lg_key;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet mac->m_max_sdu = grp->lg_max_sdu = aggr_grp_max_sdu(grp);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae if ((err = dls_devnet_create(grp->lg_mh, grp->lg_linkid)) != 0) {
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf /* set LACP mode */
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * Attach each port if necessary.
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae /* add new group to hash table */
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae err = mod_hash_insert(aggr_grp_hash, GRP_HASH_KEY(linkid),
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae return (0);
70025d765b044c6d8594bb965a2247a61e991a99johnny * Return a pointer to the member of a group with specified linkid.
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_port_lookup(aggr_grp_t *grp, datalink_id_t linkid)
337fc9e235877b459e389f54daf9833bbc645439anish ASSERT(RW_WRITE_HELD(&grp->lg_lock) || RW_READ_HELD(&grp->lg_lock));
7a23d1009aa28ea040052630547929b9c5eb6ab4anish for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
70025d765b044c6d8594bb965a2247a61e991a99johnny * Stop, detach and remove a port from a link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t *mac_addr_changedp, boolean_t *link_state_changedp)
70025d765b044c6d8594bb965a2247a61e991a99johnny /* unlink port */
70025d765b044c6d8594bb965a2247a61e991a99johnny * If the MAC address of the port being removed was assigned
70025d765b044c6d8594bb965a2247a61e991a99johnny * to the group, update the group MAC address
70025d765b044c6d8594bb965a2247a61e991a99johnny * using the MAC address of a different port.
70025d765b044c6d8594bb965a2247a61e991a99johnny if (!grp->lg_addr_fixed && grp->lg_mac_addr_port == port) {
70025d765b044c6d8594bb965a2247a61e991a99johnny * Set the MAC address of the group to the
70025d765b044c6d8594bb965a2247a61e991a99johnny * MAC address of its first port.
70025d765b044c6d8594bb965a2247a61e991a99johnny bcopy(grp->lg_ports->lp_addr, grp->lg_addr, ETHERADDRL);
70025d765b044c6d8594bb965a2247a61e991a99johnny link_state_changed = aggr_grp_detach_port(grp, port);
70025d765b044c6d8594bb965a2247a61e991a99johnny * Add the counter statistics of the ports while it was aggregated
70025d765b044c6d8594bb965a2247a61e991a99johnny * to the group's residual statistics. This is done by obtaining
70025d765b044c6d8594bb965a2247a61e991a99johnny * the current counter from the underlying MAC then subtracting the
70025d765b044c6d8594bb965a2247a61e991a99johnny * value of the counter at the moment it was added to the
70025d765b044c6d8594bb965a2247a61e991a99johnny * aggregation.
70025d765b044c6d8594bb965a2247a61e991a99johnny for (i = 0; i < MAC_NSTAT && !grp->lg_closing; i++) {
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae for (i = 0; i < ETHER_NSTAT && !grp->lg_closing; i++) {
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak * If the group MAC address has changed, update the MAC address of
337fc9e235877b459e389f54daf9833bbc645439anish * the remaining constituent ports according to the new MAC
337fc9e235877b459e389f54daf9833bbc645439anish * address of the group.
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (mac_addr_changed && aggr_grp_update_ports_mac(grp))
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * Remove one or more ports from an existing link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_rem_ports(datalink_id_t linkid, uint_t nports, laioc_port_t *ports)
70025d765b044c6d8594bb965a2247a61e991a99johnny int rc = 0, i;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t mac_addr_update = B_FALSE, mac_addr_changed;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t link_state_update = B_FALSE, link_state_changed;
70025d765b044c6d8594bb965a2247a61e991a99johnny /* get group corresponding to linkid */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
70025d765b044c6d8594bb965a2247a61e991a99johnny /* we need to keep at least one port per group */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* first verify that all the groups are valid */
70025d765b044c6d8594bb965a2247a61e991a99johnny for (i = 0; i < nports; i++) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (aggr_grp_port_lookup(grp, ports[i].lp_linkid) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* port not found */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* remove the specified ports from group */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* lookup port */
269473047d747f7815af570197e4ef7322d3632cEvan Yan port = aggr_grp_port_lookup(grp, ports[i].lp_linkid);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* stop port if group has already been started */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* remove port from group */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rc = aggr_grp_rem_port(grp, port, &mac_addr_changed,
269473047d747f7815af570197e4ef7322d3632cEvan Yan mac_addr_update = mac_addr_update || mac_addr_changed;
269473047d747f7815af570197e4ef7322d3632cEvan Yan link_state_update = link_state_update || link_state_changed;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note that dls_devnet_destroy() must be called before lg_lock is
269473047d747f7815af570197e4ef7322d3632cEvan Yan * held. Otherwise, it will deadlock if another thread is in
70025d765b044c6d8594bb965a2247a61e991a99johnny * aggr_m_stat() and thus has a kstat_hold() on the kstats that
269473047d747f7815af570197e4ef7322d3632cEvan Yan * dls_devnet_destroy() needs to delete.
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((err = dls_devnet_destroy(grp->lg_mh, &tmpid)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unregister from the MAC service module. Since this can
269473047d747f7815af570197e4ef7322d3632cEvan Yan * fail if a client hasn't closed the MAC port, we gracefully
269473047d747f7815af570197e4ef7322d3632cEvan Yan * fail the operation.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Free the list of multicast addresses.
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (mcst = grp->lg_mcst_list; mcst != NULL; mcst = mcst_nextp) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* detach and free MAC ports associated with group */
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae (void) mod_hash_remove(aggr_grp_hash, GRP_HASH_KEY(linkid), &val);
int rc = 0;
return (ENOENT);
if (rc != 0)
goto bail;
if (rc != 0)
goto bail;
bail:
return (rc);
return (ENOTSUP);
*val = 0;
int rval = 0;
switch (stat) {
case MAC_STAT_IFSPEED:
case ETHER_STAT_LINK_DUPLEX:
return (rval);
goto bail;
if (link_state_changed)
bail:
static boolean_t
switch (cap) {
case MAC_CAPAB_HCKSUM: {
case MAC_CAPAB_POLL:
case MAC_CAPAB_NO_NATIVEVLAN:
case MAC_CAPAB_NO_ZCOPY:
return (B_FALSE);
return (B_TRUE);
if (add) {
return (ENOMEM);
return (ENOENT);
if (cerr == 0)
return (err);
int rc;
return (rc);
cksum = 0;
static boolean_t
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
static uint_t
return (max_sdu);
static boolean_t
static uint32_t
return (margin);
static boolean_t
return (B_TRUE);
return (B_FALSE);
return (B_TRUE);