aggr_grp.c revision 195993116a964de43c0be7ac387506d62dc7e201
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * CDDL HEADER START
70025d765b044c6d8594bb965a2247a61e991a99johnny *
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 *
70025d765b044c6d8594bb965a2247a61e991a99johnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
70025d765b044c6d8594bb965a2247a61e991a99johnny * or http://www.opensolaris.org/os/licensing.
70025d765b044c6d8594bb965a2247a61e991a99johnny * See the License for the specific language governing permissions
70025d765b044c6d8594bb965a2247a61e991a99johnny * and limitations under the License.
70025d765b044c6d8594bb965a2247a61e991a99johnny *
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 *
70025d765b044c6d8594bb965a2247a61e991a99johnny * CDDL HEADER END
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
fc256490629fe68815f7e0f23cf9b3545720cfacJason Beloro * Use is subject to license terms.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny#pragma ident "%Z%%M% %I% %E% SMI"
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * IEEE 802.3ad Link Aggregation -- Link Aggregation Groups.
70025d765b044c6d8594bb965a2247a61e991a99johnny *
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 *
70025d765b044c6d8594bb965a2247a61e991a99johnny * A set of MAC ports are associated with each association group.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet#include <sys/types.h>
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet#include <sys/sysmacros.h>
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet#include <sys/conf.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/cmn_err.h>
c333dd99c762d509c7eb6cce222221958e23b4c8dm#include <sys/list.h>
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae#include <sys/ksynch.h>
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae#include <sys/kmem.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/stream.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/modctl.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/ddi.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/sunddi.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/atomic.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/stat.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/modhash.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/id_space.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/strsun.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/dlpi.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/dls.h>
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg#include <sys/vlan.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/aggr.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny#include <sys/aggr_impl.h>
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int aggr_m_start(void *);
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic void aggr_m_stop(void *);
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int aggr_m_promisc(void *, boolean_t);
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int aggr_m_multicst(void *, boolean_t, const uint8_t *);
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int aggr_m_unicst(void *, const uint8_t *);
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int aggr_m_stat(void *, uint_t, uint64_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 *,
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae boolean_t *);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaestatic void aggr_grp_capab_set(aggr_grp_t *);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaestatic boolean_t aggr_grp_capab_check(aggr_grp_t *, aggr_port_t *);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaestatic uint_t aggr_grp_max_sdu(aggr_grp_t *);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaestatic uint32_t aggr_grp_max_margin(aggr_grp_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,
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae const uint8_t *addrp);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic kmem_cache_t *aggr_grp_cache;
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic mod_hash_t *aggr_grp_hash;
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic krwlock_t aggr_grp_lock;
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic uint_t aggr_grp_cnt;
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic id_space_t *key_ids;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny#define GRP_HASHSZ 64
70025d765b044c6d8594bb965a2247a61e991a99johnny#define GRP_HASH_KEY(linkid) ((mod_hash_key_t)(uintptr_t)linkid)
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic uchar_t aggr_zero_mac[] = {0, 0, 0, 0, 0, 0};
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny#define AGGR_M_CALLBACK_FLAGS (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB)
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic mac_callbacks_t aggr_m_callbacks = {
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_M_CALLBACK_FLAGS,
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_m_stat,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_start,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_stop,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_promisc,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_multicst,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_unicst,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_tx,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_resources,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_ioctl,
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_m_capab_get
269473047d747f7815af570197e4ef7322d3632cEvan Yan};
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanaggr_grp_constructor(void *buf, void *arg, int kmflag)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_t *grp = buf;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny bzero(grp, sizeof (*grp));
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_init(&grp->lg_lock, NULL, RW_DRIVER, NULL);
70025d765b044c6d8594bb965a2247a61e991a99johnny mutex_init(&grp->aggr.gl_lock, NULL, MUTEX_DEFAULT, NULL);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_link_state = LINK_STATE_UNKNOWN;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny return (0);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*ARGSUSED*/
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic void
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_destructor(void *buf, void *arg)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_t *grp = buf;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp->lg_tx_ports != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(grp->lg_tx_ports,
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_tx_ports_size * sizeof (aggr_port_t *));
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny mutex_destroy(&grp->aggr.gl_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_destroy(&grp->lg_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnyvoid
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_init(void)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_cache = kmem_cache_create("aggr_grp_cache",
70025d765b044c6d8594bb965a2247a61e991a99johnny sizeof (aggr_grp_t), 0, aggr_grp_constructor,
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_destructor, NULL, NULL, NULL, 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_hash = mod_hash_create_idhash("aggr_grp_hash",
70025d765b044c6d8594bb965a2247a61e991a99johnny GRP_HASHSZ, mod_hash_null_valdtor);
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_init(&aggr_grp_lock, NULL, RW_DEFAULT, NULL);
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_cnt = 0;
247980bee8b0de250570942681f1567bd54ad984anish
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
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.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
193974072f41a843678abf5f61979c748687e66bSherry Moore key_ids = id_space_create("aggr_key_ids", AGGR_MAX_KEY + 1, UINT16_MAX);
193974072f41a843678abf5f61979c748687e66bSherry Moore ASSERT(key_ids != NULL);
193974072f41a843678abf5f61979c748687e66bSherry Moore}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnyvoid
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_fini(void)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny id_space_destroy(key_ids);
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_destroy(&aggr_grp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny mod_hash_destroy_idhash(aggr_grp_hash);
70025d765b044c6d8594bb965a2247a61e991a99johnny kmem_cache_destroy(aggr_grp_cache);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnyuint_t
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_count(void)
337fc9e235877b459e389f54daf9833bbc645439anish{
7a23d1009aa28ea040052630547929b9c5eb6ab4anish uint_t count;
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak rw_enter(&aggr_grp_lock, RW_READER);
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg count = aggr_grp_cnt;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases rw_exit(&aggr_grp_lock);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases return (count);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Attach a port to a link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnny *
70025d765b044c6d8594bb965a2247a61e991a99johnny * A port is attached to a link aggregation group once its speed
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and link state have been verified.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
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().
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnnyboolean_t
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_attach_port(aggr_grp_t *grp, aggr_port_t *port)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t link_state_changed = B_FALSE;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(AGGR_LACP_LOCK_HELD(grp));
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(RW_WRITE_HELD(&grp->lg_lock));
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(RW_WRITE_HELD(&port->lp_lock));
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (port->lp_state == AGGR_PORT_STATE_ATTACHED)
70025d765b044c6d8594bb965a2247a61e991a99johnny return (B_FALSE);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Validate the MAC port link speed and update the group
70025d765b044c6d8594bb965a2247a61e991a99johnny * link speed if needed.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (port->lp_ifspeed == 0 ||
70025d765b044c6d8594bb965a2247a61e991a99johnny port->lp_link_state != LINK_STATE_UP ||
70025d765b044c6d8594bb965a2247a61e991a99johnny port->lp_link_duplex != LINK_DUPLEX_FULL) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Can't attach a MAC port with unknown link speed,
70025d765b044c6d8594bb965a2247a61e991a99johnny * down link, or not in full duplex mode.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny return (B_FALSE);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp->lg_ifspeed == 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * The group inherits the speed of the first link being
70025d765b044c6d8594bb965a2247a61e991a99johnny * attached.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_ifspeed = port->lp_ifspeed;
70025d765b044c6d8594bb965a2247a61e991a99johnny link_state_changed = B_TRUE;
70025d765b044c6d8594bb965a2247a61e991a99johnny } else if (grp->lg_ifspeed != port->lp_ifspeed) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
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 */
70025d765b044c6d8594bb965a2247a61e991a99johnny return (B_FALSE);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_nattached_ports++;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Update the group link state.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (grp->lg_link_state != LINK_STATE_UP) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan grp->lg_link_state = LINK_STATE_UP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan grp->lg_link_duplex = LINK_DUPLEX_FULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan link_state_changed = B_TRUE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_grp_multicst_port(port, B_TRUE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Update port's state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan port->lp_state = AGGR_PORT_STATE_ATTACHED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Set port's receive callback
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan port->lp_mrh = mac_rx_add(port->lp_mh, aggr_recv_cb, (void *)port);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 *
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.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (grp->lg_lacp_mode == AGGR_LACP_OFF)
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_send_port_enable(port);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_lacp_port_attached(port);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny return (link_state_changed);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanboolean_t
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_detach_port(aggr_grp_t *grp, aggr_port_t *port)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases{
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases boolean_t link_state_changed = B_FALSE;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases ASSERT(RW_WRITE_HELD(&grp->lg_lock));
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases ASSERT(RW_WRITE_HELD(&port->lp_lock));
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf ASSERT(AGGR_LACP_LOCK_HELD(grp));
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases /* update state */
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases return (B_FALSE);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases mac_rx_remove(port->lp_mh, port->lp_mrh, B_FALSE);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases port->lp_state = AGGR_PORT_STATE_STANDBY;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases aggr_grp_multicst_port(port, B_FALSE);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases if (grp->lg_lacp_mode == AGGR_LACP_OFF)
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases aggr_send_port_disable(port);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases else
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases aggr_lacp_port_detached(port);
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_nattached_ports--;
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp->lg_nattached_ports == 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /* the last attached MAC port of the group is being detached */
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_ifspeed = 0;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_link_state = LINK_STATE_DOWN;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_link_duplex = LINK_DUPLEX_UNKNOWN;
70025d765b044c6d8594bb965a2247a61e991a99johnny link_state_changed = B_TRUE;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny return (link_state_changed);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
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 *
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.
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetboolean_t
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaeaggr_grp_update_ports_mac(aggr_grp_t *grp)
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae{
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae aggr_port_t *cport;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae boolean_t link_state_changed = B_FALSE;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(RW_WRITE_HELD(&grp->lg_lock));
70025d765b044c6d8594bb965a2247a61e991a99johnny
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (grp->lg_closing)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (link_state_changed);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny for (cport = grp->lg_ports; cport != NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cport = cport->lp_next) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_enter(&cport->lp_lock, RW_WRITER);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (aggr_port_unicst(cport, grp->lg_addr) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (aggr_grp_detach_port(grp, cport))
269473047d747f7815af570197e4ef7322d3632cEvan Yan link_state_changed = B_TRUE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (aggr_grp_attach_port(grp, cport))
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet link_state_changed = B_TRUE;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet }
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_exit(&cport->lp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf return (link_state_changed);
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf}
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
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.
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf */
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaevoid
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{
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf ASSERT(AGGR_LACP_LOCK_HELD(grp));
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf ASSERT(RW_WRITE_HELD(&grp->lg_lock));
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf ASSERT(RW_WRITE_HELD(&port->lp_lock));
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf ASSERT(mac_addr_changedp != NULL);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases ASSERT(link_state_changedp != NULL);
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases *mac_addr_changedp = B_FALSE;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases *link_state_changedp = B_FALSE;
cb7ea99db394f3bd5f4a6c6bf58c8c52df3508f0Jimmy Vetayases
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf if (grp->lg_addr_fixed) {
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf /*
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * The group is using a fixed MAC address or an automatic
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * MAC address has not been set.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny return;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg }
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if (grp->lg_mac_addr_port == port) {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /*
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * The MAC address of the port was assigned to the group
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * MAC address. Update the group MAC address.
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg bcopy(port->lp_addr, grp->lg_addr, ETHERADDRL);
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg *mac_addr_changedp = B_TRUE;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg } else {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /*
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * Update the actual port MAC address to the MAC address
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg * of the group.
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if (aggr_port_unicst(port, grp->lg_addr) != 0) {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg *link_state_changedp = aggr_grp_detach_port(grp, port);
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg } else {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /*
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 */
70025d765b044c6d8594bb965a2247a61e991a99johnny *link_state_changedp = aggr_grp_attach_port(grp, port);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Add a port to a link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_add_port(aggr_grp_t *grp, datalink_id_t linkid, boolean_t force,
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_port_t **pp)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_port_t *port, **cport;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet int err;
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick ASSERT(AGGR_LACP_LOCK_HELD(grp));
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(RW_WRITE_HELD(&grp->lg_lock));
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* create new port */
70025d765b044c6d8594bb965a2247a61e991a99johnny err = aggr_port_create(linkid, force, &port);
70025d765b044c6d8594bb965a2247a61e991a99johnny if (err != 0)
70025d765b044c6d8594bb965a2247a61e991a99johnny return (err);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_enter(&port->lp_lock, RW_WRITER);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* add port to list of group constituent ports */
70025d765b044c6d8594bb965a2247a61e991a99johnny cport = &grp->lg_ports;
70025d765b044c6d8594bb965a2247a61e991a99johnny while (*cport != NULL)
70025d765b044c6d8594bb965a2247a61e991a99johnny cport = &((*cport)->lp_next);
70025d765b044c6d8594bb965a2247a61e991a99johnny *cport = port;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
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 */
70025d765b044c6d8594bb965a2247a61e991a99johnny port->lp_grp = grp;
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_GRP_REFHOLD(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_nports++;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_lacp_init_port(port);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Initialize the callback functions for this port. Note that this
70025d765b044c6d8594bb965a2247a61e991a99johnny * can only be done after the lp_grp field is set.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_port_init_callbacks(port);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&port->lp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (pp != NULL)
70025d765b044c6d8594bb965a2247a61e991a99johnny *pp = port;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny return (0);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Add one or more ports to an existing link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnnyint
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force,
70025d765b044c6d8594bb965a2247a61e991a99johnny laioc_port_t *ports)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny int rc, i, nadded = 0;
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_t *grp = NULL;
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_port_t *port;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t link_state_changed = B_FALSE;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* get group corresponding to linkid */
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_enter(&aggr_grp_lock, RW_READER);
70025d765b044c6d8594bb965a2247a61e991a99johnny if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
70025d765b044c6d8594bb965a2247a61e991a99johnny (mod_hash_val_t *)&grp) != 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&aggr_grp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny return (ENOENT);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_GRP_REFHOLD(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&aggr_grp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_LACP_LOCK(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_enter(&grp->lg_lock, RW_WRITER);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* add the specified ports to group */
70025d765b044c6d8594bb965a2247a61e991a99johnny for (i = 0; i < nports; i++) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /* add port to group */
70025d765b044c6d8594bb965a2247a61e991a99johnny if ((rc = aggr_grp_add_port(grp, ports[i].lp_linkid,
70025d765b044c6d8594bb965a2247a61e991a99johnny force, &port)) != 0) {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg goto bail;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg }
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg ASSERT(port != NULL);
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg nadded++;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* check capabilities */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if (!aggr_grp_capab_check(grp, port) ||
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg !aggr_grp_sdu_check(grp, port) ||
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet !aggr_grp_margin_check(grp, port)) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rc = ENOTSUP;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet goto bail;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet }
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* start port if group has already been started */
247980bee8b0de250570942681f1567bd54ad984anish if (grp->lg_started) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_enter(&port->lp_lock, RW_WRITER);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rc = aggr_port_start(port);
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur if (rc != 0) {
247980bee8b0de250570942681f1567bd54ad984anish rw_exit(&port->lp_lock);
649d4cce0c8ba57f2c399df82be95a0395cfeef2anish goto bail;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* set port promiscuous mode */
70025d765b044c6d8594bb965a2247a61e991a99johnny rc = aggr_port_promisc(port, grp->lg_promisc);
70025d765b044c6d8594bb965a2247a61e991a99johnny if (rc != 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&port->lp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny goto bail;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&port->lp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Attach each port if necessary.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (aggr_port_notify_link(grp, port, B_FALSE))
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet link_state_changed = B_TRUE;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet }
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* update the MAC address of the constituent ports */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (aggr_grp_update_ports_mac(grp))
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet link_state_changed = B_TRUE;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (link_state_changed)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet mac_link_update(grp->lg_mh, grp->lg_link_state);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnybail:
70025d765b044c6d8594bb965a2247a61e991a99johnny if (rc != 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /* stop and remove ports that have been added */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet for (i = 0; i < nadded && !grp->lg_closing; i++) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet port = aggr_grp_port_lookup(grp, ports[i].lp_linkid);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet ASSERT(port != NULL);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (grp->lg_started) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_enter(&port->lp_lock, RW_WRITER);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet aggr_port_stop(port);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_exit(&port->lp_lock);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet }
70025d765b044c6d8594bb965a2247a61e991a99johnny (void) aggr_grp_rem_port(grp, port, NULL, NULL);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&grp->lg_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_LACP_UNLOCK(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny if (rc == 0 && !grp->lg_closing)
70025d765b044c6d8594bb965a2247a61e991a99johnny mac_resource_update(grp->lg_mh);
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_GRP_REFRELE(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny return (rc);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet}
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet/*
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet * Update properties of an existing link aggregation group.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet */
70025d765b044c6d8594bb965a2247a61e991a99johnnyint
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{
70025d765b044c6d8594bb965a2247a61e991a99johnny int rc = 0;
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_t *grp = NULL;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t mac_addr_changed = B_FALSE;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t link_state_changed = B_FALSE;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp_arg == NULL) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /* get group corresponding to linkid */
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_enter(&aggr_grp_lock, RW_READER);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
649d4cce0c8ba57f2c399df82be95a0395cfeef2anish (mod_hash_val_t *)&grp) != 0) {
49fbdd30212f016ddd49c4b5c997b0b827ff0962Erwin T Tsaur rc = ENOENT;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg goto bail;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg }
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg AGGR_LACP_LOCK(grp);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_enter(&grp->lg_lock, RW_WRITER);
247980bee8b0de250570942681f1567bd54ad984anish } else {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg grp = grp_arg;
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick ASSERT(AGGR_LACP_LOCK_HELD(grp));
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick ASSERT(RW_WRITE_HELD(&grp->lg_lock));
649d4cce0c8ba57f2c399df82be95a0395cfeef2anish }
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg ASSERT(RW_WRITE_HELD(&grp->lg_lock) || RW_READ_HELD(&grp->lg_lock));
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick AGGR_GRP_REFHOLD(grp);
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg
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 (mac_addr[0] & 0x01))) {
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick rc = EINVAL;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg goto bail;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg }
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* update policy if requested */
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick if (update_mask & AGGR_MODIFY_POLICY)
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg aggr_send_update_policy(grp, policy);
70025d765b044c6d8594bb965a2247a61e991a99johnny
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* update unicast MAC address if requested */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if (update_mask & AGGR_MODIFY_MAC) {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if (mac_fixed) {
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick /* user-supplied MAC address */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg grp->lg_mac_addr_port = NULL;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg if (bcmp(mac_addr, grp->lg_addr, ETHERADDRL) != 0) {
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick bcopy(mac_addr, grp->lg_addr, ETHERADDRL);
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg mac_addr_changed = B_TRUE;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg }
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg } else if (grp->lg_addr_fixed) {
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg /* switch from user-supplied to automatic */
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg aggr_port_t *port = grp->lg_ports;
14f1dfe8cc1a1f86b7a23d406ca317c05ce87cd6Seth Goldberg
5c59319b8761ccd4b952eec8d5caecf298024607Dan Mick rw_enter(&port->lp_lock, RW_WRITER);
70025d765b044c6d8594bb965a2247a61e991a99johnny bcopy(port->lp_addr, grp->lg_addr, ETHERADDRL);
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_mac_addr_port = port;
70025d765b044c6d8594bb965a2247a61e991a99johnny mac_addr_changed = B_TRUE;
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&port->lp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_addr_fixed = mac_fixed;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (mac_addr_changed)
70025d765b044c6d8594bb965a2247a61e991a99johnny link_state_changed = aggr_grp_update_ports_mac(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (update_mask & AGGR_MODIFY_LACP_MODE)
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_lacp_update_mode(grp, lacp_mode);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if ((update_mask & AGGR_MODIFY_LACP_TIMER) && !grp->lg_closing)
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_lacp_update_timer(grp, lacp_timer);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnnybail:
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp != NULL && !grp->lg_closing) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
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 */
70025d765b044c6d8594bb965a2247a61e991a99johnny if ((grp_arg == NULL) && mac_addr_changed)
70025d765b044c6d8594bb965a2247a61e991a99johnny mac_unicst_update(grp->lg_mh, grp->lg_addr);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (link_state_changed)
70025d765b044c6d8594bb965a2247a61e991a99johnny mac_link_update(grp->lg_mh, grp->lg_link_state);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp_arg == NULL) {
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp != NULL) {
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&grp->lg_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_LACP_UNLOCK(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&aggr_grp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp != NULL)
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_GRP_REFRELE(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny return (rc);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Create a new link aggregation group upon request from administrator.
70025d765b044c6d8594bb965a2247a61e991a99johnny * Returns 0 on success, an errno on failure.
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreetint
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{
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet aggr_grp_t *grp = NULL;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet aggr_port_t *port;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet mac_register_t *mac;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet boolean_t link_state_changed;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet int err;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet int i;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* need at least one port */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (nports == 0)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet return (EINVAL);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_enter(&aggr_grp_lock, RW_WRITER);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* does a group with the same linkid already exist? */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet err = mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (mod_hash_val_t *)&grp);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (err == 0) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_exit(&aggr_grp_lock);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet return (EEXIST);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet }
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
70025d765b044c6d8594bb965a2247a61e991a99johnny grp = kmem_cache_alloc(aggr_grp_cache, KM_SLEEP);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_LACP_LOCK(grp);
649d4cce0c8ba57f2c399df82be95a0395cfeef2anish rw_enter(&grp->lg_lock, RW_WRITER);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_refs = 1;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_closing = B_FALSE;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_force = force;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_linkid = linkid;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_ifspeed = 0;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_link_state = LINK_STATE_UNKNOWN;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_link_duplex = LINK_DUPLEX_UNKNOWN;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_started = B_FALSE;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae grp->lg_promisc = B_FALSE;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae aggr_lacp_init_grp(grp);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae /* add MAC ports to group */
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_ports = NULL;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_nports = 0;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_nattached_ports = 0;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_ntx_ports = 0;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * If key is not specified by the user, allocate the key.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny if ((key == 0) && ((key = (uint32_t)id_alloc(key_ids)) == 0)) {
70025d765b044c6d8594bb965a2247a61e991a99johnny err = ENOMEM;
70025d765b044c6d8594bb965a2247a61e991a99johnny goto bail;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_key = key;
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_mcst_list = NULL;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny for (i = 0; i < nports; i++) {
70025d765b044c6d8594bb965a2247a61e991a99johnny err = aggr_grp_add_port(grp, ports[i].lp_linkid, force, NULL);
70025d765b044c6d8594bb965a2247a61e991a99johnny if (err != 0)
70025d765b044c6d8594bb965a2247a61e991a99johnny goto bail;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * If no explicit MAC address was specified by the administrator,
70025d765b044c6d8594bb965a2247a61e991a99johnny * set it to the MAC address of the first port.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_addr_fixed = mac_fixed;
70025d765b044c6d8594bb965a2247a61e991a99johnny if (grp->lg_addr_fixed) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /* validate specified address */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (bcmp(aggr_zero_mac, mac_addr, ETHERADDRL) == 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny err = EINVAL;
70025d765b044c6d8594bb965a2247a61e991a99johnny goto bail;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny bcopy(mac_addr, grp->lg_addr, ETHERADDRL);
70025d765b044c6d8594bb965a2247a61e991a99johnny } else {
70025d765b044c6d8594bb965a2247a61e991a99johnny bcopy(grp->lg_ports->lp_addr, grp->lg_addr, ETHERADDRL);
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_mac_addr_port = grp->lg_ports;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
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 */
70025d765b044c6d8594bb965a2247a61e991a99johnny link_state_changed = aggr_grp_update_ports_mac(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(!link_state_changed);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* update outbound load balancing policy */
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_send_update_policy(grp, policy);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* set the initial group capabilities */
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_capab_set(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny if ((mac = mac_alloc(MAC_VERSION)) == NULL) {
70025d765b044c6d8594bb965a2247a61e991a99johnny err = ENOMEM;
70025d765b044c6d8594bb965a2247a61e991a99johnny goto bail;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
70025d765b044c6d8594bb965a2247a61e991a99johnny mac->m_driver = grp;
70025d765b044c6d8594bb965a2247a61e991a99johnny mac->m_dip = aggr_dip;
70025d765b044c6d8594bb965a2247a61e991a99johnny mac->m_instance = grp->lg_key > AGGR_MAX_KEY ? (uint_t)-1 : grp->lg_key;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet mac->m_src_addr = grp->lg_addr;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet mac->m_callbacks = &aggr_m_callbacks;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet mac->m_min_sdu = 0;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet mac->m_max_sdu = grp->lg_max_sdu = aggr_grp_max_sdu(grp);
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf mac->m_margin = aggr_grp_max_margin(grp);
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf err = mac_register(mac, &grp->lg_mh);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae mac_free(mac);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae if (err != 0)
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae goto bail;
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae if ((err = dls_devnet_create(grp->lg_mh, grp->lg_linkid)) != 0) {
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae (void) mac_unregister(grp->lg_mh);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae goto bail;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae }
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf /* set LACP mode */
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf aggr_lacp_set_mode(grp, lacp_mode, lacp_timer);
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf /*
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf * Attach each port if necessary.
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf */
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf if (aggr_port_notify_link(grp, port, B_FALSE))
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf link_state_changed = B_TRUE;
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf }
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae if (link_state_changed)
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf mac_link_update(grp->lg_mh, grp->lg_link_state);
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae /* add new group to hash table */
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae err = mod_hash_insert(aggr_grp_hash, GRP_HASH_KEY(linkid),
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae (mod_hash_val_t)grp);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae ASSERT(err == 0);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae aggr_grp_cnt++;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae rw_exit(&grp->lg_lock);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae AGGR_LACP_UNLOCK(grp);
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf rw_exit(&aggr_grp_lock);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae return (0);
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyfbail:
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf if (grp != NULL) {
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae aggr_port_t *cport;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
2df1fe9ca32bb227b9158c67f5c00b54c20b10fdrandyf grp->lg_closing = B_TRUE;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny port = grp->lg_ports;
70025d765b044c6d8594bb965a2247a61e991a99johnny while (port != NULL) {
70025d765b044c6d8594bb965a2247a61e991a99johnny cport = port->lp_next;
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_port_delete(port);
70025d765b044c6d8594bb965a2247a61e991a99johnny port = cport;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&grp->lg_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_LACP_UNLOCK(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_GRP_REFRELE(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&aggr_grp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny return (err);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Return a pointer to the member of a group with specified linkid.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic aggr_port_t *
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_port_lookup(aggr_grp_t *grp, datalink_id_t linkid)
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae{
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae aggr_port_t *port;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
337fc9e235877b459e389f54daf9833bbc645439anish ASSERT(RW_WRITE_HELD(&grp->lg_lock) || RW_READ_HELD(&grp->lg_lock));
70025d765b044c6d8594bb965a2247a61e991a99johnny
7a23d1009aa28ea040052630547929b9c5eb6ab4anish for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
7a23d1009aa28ea040052630547929b9c5eb6ab4anish if (port->lp_linkid == linkid)
7a23d1009aa28ea040052630547929b9c5eb6ab4anish break;
7a23d1009aa28ea040052630547929b9c5eb6ab4anish }
7a23d1009aa28ea040052630547929b9c5eb6ab4anish
7a23d1009aa28ea040052630547929b9c5eb6ab4anish return (port);
7a23d1009aa28ea040052630547929b9c5eb6ab4anish}
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny/*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Stop, detach and remove a port from a link aggregation group.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnnystatic int
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_rem_port(aggr_grp_t *grp, aggr_port_t *port,
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t *mac_addr_changedp, boolean_t *link_state_changedp)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny int rc = 0;
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_port_t **pport;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t mac_addr_changed = B_FALSE;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t link_state_changed = B_FALSE;
70025d765b044c6d8594bb965a2247a61e991a99johnny uint64_t val;
70025d765b044c6d8594bb965a2247a61e991a99johnny uint_t i;
70025d765b044c6d8594bb965a2247a61e991a99johnny uint_t stat;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(AGGR_LACP_LOCK_HELD(grp));
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(RW_WRITE_HELD(&grp->lg_lock));
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(grp->lg_nports > 1);
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(!grp->lg_closing);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* unlink port */
70025d765b044c6d8594bb965a2247a61e991a99johnny for (pport = &grp->lg_ports; *pport != port;
70025d765b044c6d8594bb965a2247a61e991a99johnny pport = &(*pport)->lp_next) {
70025d765b044c6d8594bb965a2247a61e991a99johnny if (*pport == NULL) {
70025d765b044c6d8594bb965a2247a61e991a99johnny rc = ENOENT;
70025d765b044c6d8594bb965a2247a61e991a99johnny goto done;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny *pport = port->lp_next;
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny atomic_add_32(&port->lp_closing, 1);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_enter(&port->lp_lock, RW_WRITER);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
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 */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (!grp->lg_addr_fixed && grp->lg_mac_addr_port == port) {
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
70025d765b044c6d8594bb965a2247a61e991a99johnny * Set the MAC address of the group to the
70025d765b044c6d8594bb965a2247a61e991a99johnny * MAC address of its first port.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
70025d765b044c6d8594bb965a2247a61e991a99johnny bcopy(grp->lg_ports->lp_addr, grp->lg_addr, ETHERADDRL);
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_mac_addr_port = grp->lg_ports;
70025d765b044c6d8594bb965a2247a61e991a99johnny mac_addr_changed = B_TRUE;
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny link_state_changed = aggr_grp_detach_port(grp, port);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /*
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 */
70025d765b044c6d8594bb965a2247a61e991a99johnny for (i = 0; i < MAC_NSTAT && !grp->lg_closing; i++) {
70025d765b044c6d8594bb965a2247a61e991a99johnny stat = i + MAC_STAT_MIN;
70025d765b044c6d8594bb965a2247a61e991a99johnny if (!MAC_STAT_ISACOUNTER(stat))
70025d765b044c6d8594bb965a2247a61e991a99johnny continue;
70025d765b044c6d8594bb965a2247a61e991a99johnny val = aggr_port_stat(port, stat);
70025d765b044c6d8594bb965a2247a61e991a99johnny val -= port->lp_stat[i];
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae grp->lg_stat[i] += val;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae }
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae for (i = 0; i < ETHER_NSTAT && !grp->lg_closing; i++) {
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae stat = i + MACTYPE_STAT_MIN;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae if (!ETHER_STAT_ISACOUNTER(stat))
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae continue;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae val = aggr_port_stat(port, stat);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae val -= port->lp_ether_stat[i];
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_ether_stat[i] += val;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae }
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
70025d765b044c6d8594bb965a2247a61e991a99johnny grp->lg_nports--;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae rw_exit(&port->lp_lock);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
337fc9e235877b459e389f54daf9833bbc645439anish aggr_port_delete(port);
337fc9e235877b459e389f54daf9833bbc645439anish
a2de976fd11ced5331ebe7c3a8ffbaf11f5427cfPavel Potoplyak /*
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.
70025d765b044c6d8594bb965a2247a61e991a99johnny */
c0da627439dfb642fb41ab7d78406fc69d2c64b2Zhi-Jun Robin Fu if (mac_addr_changed && aggr_grp_update_ports_mac(grp))
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae link_state_changed = B_TRUE;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaedone:
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae if (mac_addr_changedp != NULL)
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae *mac_addr_changedp = mac_addr_changed;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae if (link_state_changedp != NULL)
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae *link_state_changedp = link_state_changed;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae return (rc);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae}
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
fc256490629fe68815f7e0f23cf9b3545720cfacJason Beloro/*
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae * Remove one or more ports from an existing link aggregation group.
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae */
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnaeint
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_rem_ports(datalink_id_t linkid, uint_t nports, laioc_port_t *ports)
70025d765b044c6d8594bb965a2247a61e991a99johnny{
70025d765b044c6d8594bb965a2247a61e991a99johnny int rc = 0, i;
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_t *grp = NULL;
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_port_t *port;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t mac_addr_update = B_FALSE, mac_addr_changed;
70025d765b044c6d8594bb965a2247a61e991a99johnny boolean_t link_state_update = B_FALSE, link_state_changed;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
70025d765b044c6d8594bb965a2247a61e991a99johnny /* get group corresponding to linkid */
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_enter(&aggr_grp_lock, RW_READER);
70025d765b044c6d8594bb965a2247a61e991a99johnny if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
70025d765b044c6d8594bb965a2247a61e991a99johnny (mod_hash_val_t *)&grp) != 0) {
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&aggr_grp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny return (ENOENT);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_GRP_REFHOLD(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_exit(&aggr_grp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_LACP_LOCK(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny rw_enter(&grp->lg_lock, RW_WRITER);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny /* we need to keep at least one port per group */
70025d765b044c6d8594bb965a2247a61e991a99johnny if (nports >= grp->lg_nports) {
70025d765b044c6d8594bb965a2247a61e991a99johnny rc = EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto bail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
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 rc = ENOENT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto bail;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* remove the specified ports from group */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = 0; i < nports && !grp->lg_closing; i++) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* lookup port */
269473047d747f7815af570197e4ef7322d3632cEvan Yan port = aggr_grp_port_lookup(grp, ports[i].lp_linkid);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(port != NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* stop port if group has already been started */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (grp->lg_started) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_enter(&port->lp_lock, RW_WRITER);
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_port_stop(port);
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_exit(&port->lp_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* remove port from group */
269473047d747f7815af570197e4ef7322d3632cEvan Yan rc = aggr_grp_rem_port(grp, port, &mac_addr_changed,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &link_state_changed);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(rc == 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mac_addr_update = mac_addr_update || mac_addr_changed;
269473047d747f7815af570197e4ef7322d3632cEvan Yan link_state_update = link_state_update || link_state_changed;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanbail:
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_exit(&grp->lg_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan AGGR_LACP_UNLOCK(grp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!grp->lg_closing) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (mac_addr_update)
269473047d747f7815af570197e4ef7322d3632cEvan Yan mac_unicst_update(grp->lg_mh, grp->lg_addr);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (link_state_update)
269473047d747f7815af570197e4ef7322d3632cEvan Yan mac_link_update(grp->lg_mh, grp->lg_link_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rc == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan mac_resource_update(grp->lg_mh);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan AGGR_GRP_REFRELE(grp);
70025d765b044c6d8594bb965a2247a61e991a99johnny
70025d765b044c6d8594bb965a2247a61e991a99johnny return (rc);
70025d765b044c6d8594bb965a2247a61e991a99johnny}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
70025d765b044c6d8594bb965a2247a61e991a99johnnyint
70025d765b044c6d8594bb965a2247a61e991a99johnnyaggr_grp_delete(datalink_id_t linkid)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
70025d765b044c6d8594bb965a2247a61e991a99johnny aggr_grp_t *grp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan aggr_port_t *port, *cport;
70025d765b044c6d8594bb965a2247a61e991a99johnny lg_mcst_addr_t *mcst, *mcst_nextp;
70025d765b044c6d8594bb965a2247a61e991a99johnny datalink_id_t tmpid;
70025d765b044c6d8594bb965a2247a61e991a99johnny mod_hash_val_t val;
70025d765b044c6d8594bb965a2247a61e991a99johnny int err;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae rw_enter(&aggr_grp_lock, RW_WRITER);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
269473047d747f7815af570197e4ef7322d3632cEvan Yan (mod_hash_val_t *)&grp) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_exit(&aggr_grp_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ENOENT);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((err = dls_devnet_destroy(grp->lg_mh, &tmpid)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_exit(&aggr_grp_lock);
70025d765b044c6d8594bb965a2247a61e991a99johnny return (err);
70025d765b044c6d8594bb965a2247a61e991a99johnny }
70025d765b044c6d8594bb965a2247a61e991a99johnny ASSERT(linkid == tmpid);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
70025d765b044c6d8594bb965a2247a61e991a99johnny AGGR_LACP_LOCK(grp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_enter(&grp->lg_lock, RW_WRITER);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
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 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan grp->lg_closing = B_TRUE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((err = mac_disable(grp->lg_mh)) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan grp->lg_closing = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_exit(&grp->lg_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan AGGR_LACP_UNLOCK(grp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) dls_devnet_create(grp->lg_mh, linkid);
269473047d747f7815af570197e4ef7322d3632cEvan Yan rw_exit(&aggr_grp_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (err);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Free the list of multicast addresses.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (mcst = grp->lg_mcst_list; mcst != NULL; mcst = mcst_nextp) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan mcst_nextp = mcst->lg_mcst_nextp;
70025d765b044c6d8594bb965a2247a61e991a99johnny kmem_free(mcst, sizeof (lg_mcst_addr_t));
247980bee8b0de250570942681f1567bd54ad984anish }
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet grp->lg_mcst_list = NULL;
247980bee8b0de250570942681f1567bd54ad984anish
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet /* detach and free MAC ports associated with group */
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet port = grp->lg_ports;
247980bee8b0de250570942681f1567bd54ad984anish while (port != NULL) {
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet cport = port->lp_next;
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_enter(&port->lp_lock, RW_WRITER);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet if (grp->lg_started)
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet aggr_port_stop(port);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet (void) aggr_grp_detach_port(grp, port);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_exit(&port->lp_lock);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet aggr_port_delete(port);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet port = cport;
247980bee8b0de250570942681f1567bd54ad984anish }
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet VERIFY(mac_unregister(grp->lg_mh) == 0);
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet
00d0963faf2e861a4aef6b1bf28f99a5b2b20755dilpreet rw_exit(&grp->lg_lock);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae AGGR_LACP_UNLOCK(grp);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae (void) mod_hash_remove(aggr_grp_hash, GRP_HASH_KEY(linkid), &val);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae ASSERT(grp == (aggr_grp_t *)val);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae ASSERT(aggr_grp_cnt > 0);
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae aggr_grp_cnt--;
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae
eae2e508a8e70b1ec407b10bd068c080651bbe5ckrishnae rw_exit(&aggr_grp_lock);
247980bee8b0de250570942681f1567bd54ad984anish AGGR_GRP_REFRELE(grp);
return (0);
}
void
aggr_grp_free(aggr_grp_t *grp)
{
ASSERT(grp->lg_refs == 0);
if (grp->lg_key > AGGR_MAX_KEY) {
id_free(key_ids, grp->lg_key);
grp->lg_key = 0;
}
kmem_cache_free(aggr_grp_cache, grp);
}
int
aggr_grp_info(datalink_id_t linkid, void *fn_arg,
aggr_grp_info_new_grp_fn_t new_grp_fn,
aggr_grp_info_new_port_fn_t new_port_fn)
{
aggr_grp_t *grp;
aggr_port_t *port;
int rc = 0;
rw_enter(&aggr_grp_lock, RW_READER);
if (mod_hash_find(aggr_grp_hash, GRP_HASH_KEY(linkid),
(mod_hash_val_t *)&grp) != 0) {
rw_exit(&aggr_grp_lock);
return (ENOENT);
}
rw_enter(&grp->lg_lock, RW_READER);
rc = new_grp_fn(fn_arg, grp->lg_linkid,
(grp->lg_key > AGGR_MAX_KEY) ? 0 : grp->lg_key, grp->lg_addr,
grp->lg_addr_fixed, grp->lg_force, grp->lg_tx_policy,
grp->lg_nports, grp->lg_lacp_mode, grp->aggr.PeriodicTimer);
if (rc != 0)
goto bail;
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
rw_enter(&port->lp_lock, RW_READER);
rc = new_port_fn(fn_arg, port->lp_linkid, port->lp_addr,
port->lp_state, &port->lp_lacp.ActorOperPortState);
rw_exit(&port->lp_lock);
if (rc != 0)
goto bail;
}
bail:
rw_exit(&grp->lg_lock);
rw_exit(&aggr_grp_lock);
return (rc);
}
static void
aggr_m_resources(void *arg)
{
aggr_grp_t *grp = arg;
aggr_port_t *port;
/* Call each port's m_resources function */
for (port = grp->lg_ports; port != NULL; port = port->lp_next)
mac_resources(port->lp_mh);
}
/*ARGSUSED*/
static void
aggr_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
{
miocnak(q, mp, 0, ENOTSUP);
}
static int
aggr_grp_stat(aggr_grp_t *grp, uint_t stat, uint64_t *val)
{
aggr_port_t *port;
uint_t stat_index;
/* We only aggregate counter statistics. */
if (IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat) ||
IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat)) {
return (ENOTSUP);
}
/*
* Counter statistics for a group are computed by aggregating the
* counters of the members MACs while they were aggregated, plus
* the residual counter of the group itself, which is updated each
* time a MAC is removed from the group.
*/
*val = 0;
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
/* actual port statistic */
*val += aggr_port_stat(port, stat);
/*
* minus the port stat when it was added, plus any residual
* amount for the group.
*/
if (IS_MAC_STAT(stat)) {
stat_index = stat - MAC_STAT_MIN;
*val -= port->lp_stat[stat_index];
*val += grp->lg_stat[stat_index];
} else if (IS_MACTYPE_STAT(stat)) {
stat_index = stat - MACTYPE_STAT_MIN;
*val -= port->lp_ether_stat[stat_index];
*val += grp->lg_ether_stat[stat_index];
}
}
return (0);
}
static int
aggr_m_stat(void *arg, uint_t stat, uint64_t *val)
{
aggr_grp_t *grp = arg;
int rval = 0;
rw_enter(&grp->lg_lock, RW_READER);
switch (stat) {
case MAC_STAT_IFSPEED:
*val = grp->lg_ifspeed;
break;
case ETHER_STAT_LINK_DUPLEX:
*val = grp->lg_link_duplex;
break;
default:
/*
* For all other statistics, we return the aggregated stat
* from the underlying ports. aggr_grp_stat() will set
* rval appropriately if the statistic isn't a counter.
*/
rval = aggr_grp_stat(grp, stat, val);
}
rw_exit(&grp->lg_lock);
return (rval);
}
static int
aggr_m_start(void *arg)
{
aggr_grp_t *grp = arg;
aggr_port_t *port;
AGGR_LACP_LOCK(grp);
rw_enter(&grp->lg_lock, RW_WRITER);
/*
* Attempts to start all configured members of the group.
* Group members will be attached when their link-up notification
* is received.
*/
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
rw_enter(&port->lp_lock, RW_WRITER);
if (aggr_port_start(port) != 0) {
rw_exit(&port->lp_lock);
continue;
}
/* set port promiscuous mode */
if (aggr_port_promisc(port, grp->lg_promisc) != 0)
aggr_port_stop(port);
rw_exit(&port->lp_lock);
}
grp->lg_started = B_TRUE;
rw_exit(&grp->lg_lock);
AGGR_LACP_UNLOCK(grp);
return (0);
}
static void
aggr_m_stop(void *arg)
{
aggr_grp_t *grp = arg;
aggr_port_t *port;
rw_enter(&grp->lg_lock, RW_WRITER);
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
rw_enter(&port->lp_lock, RW_WRITER);
aggr_port_stop(port);
rw_exit(&port->lp_lock);
}
grp->lg_started = B_FALSE;
rw_exit(&grp->lg_lock);
}
static int
aggr_m_promisc(void *arg, boolean_t on)
{
aggr_grp_t *grp = arg;
aggr_port_t *port;
boolean_t link_state_changed = B_FALSE;
AGGR_LACP_LOCK(grp);
rw_enter(&grp->lg_lock, RW_WRITER);
AGGR_GRP_REFHOLD(grp);
ASSERT(!grp->lg_closing);
if (on == grp->lg_promisc)
goto bail;
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
rw_enter(&port->lp_lock, RW_WRITER);
AGGR_PORT_REFHOLD(port);
if (port->lp_started) {
if (aggr_port_promisc(port, on) != 0) {
if (aggr_grp_detach_port(grp, port))
link_state_changed = B_TRUE;
} else {
/*
* If a port was detached because of a previous
* failure changing the promiscuity, the port
* is reattached when it successfully changes
* the promiscuity now, and this might cause
* the link state of the aggregation to change.
*/
if (aggr_grp_attach_port(grp, port))
link_state_changed = B_TRUE;
}
}
rw_exit(&port->lp_lock);
AGGR_PORT_REFRELE(port);
}
grp->lg_promisc = on;
if (link_state_changed)
mac_link_update(grp->lg_mh, grp->lg_link_state);
bail:
rw_exit(&grp->lg_lock);
AGGR_LACP_UNLOCK(grp);
AGGR_GRP_REFRELE(grp);
return (0);
}
/*
* Initialize the capabilities that are advertised for the group
* according to the capabilities of the constituent ports.
*/
static boolean_t
aggr_m_capab_get(void *arg, mac_capab_t cap, void *cap_data)
{
aggr_grp_t *grp = arg;
switch (cap) {
case MAC_CAPAB_HCKSUM: {
uint32_t *hcksum_txflags = cap_data;
*hcksum_txflags = grp->lg_hcksum_txflags;
break;
}
case MAC_CAPAB_POLL:
/*
* There's nothing for us to fill in, we simply return
* B_TRUE or B_FALSE to represent the group's support
* status for this capability.
*/
return (grp->lg_gldv3_polling);
case MAC_CAPAB_NO_NATIVEVLAN:
return (!grp->lg_vlan);
case MAC_CAPAB_NO_ZCOPY:
return (!grp->lg_zcopy);
default:
return (B_FALSE);
}
return (B_TRUE);
}
static int
aggr_grp_multicst(aggr_grp_t *grp, boolean_t add, const uint8_t *addrp)
{
lg_mcst_addr_t *mcst, **ppmcst;
ASSERT(RW_WRITE_HELD(&grp->lg_lock));
for (ppmcst = &(grp->lg_mcst_list); (mcst = *ppmcst) != NULL;
ppmcst = &(mcst->lg_mcst_nextp)) {
if (bcmp(mcst->lg_mcst_addr, addrp, MAXMACADDRLEN) == 0)
break;
}
if (add) {
if (mcst != NULL)
return (0);
mcst = kmem_zalloc(sizeof (lg_mcst_addr_t), KM_NOSLEEP);
if (mcst == NULL)
return (ENOMEM);
bcopy(addrp, mcst->lg_mcst_addr, MAXMACADDRLEN);
*ppmcst = mcst;
} else {
if (mcst == NULL)
return (ENOENT);
*ppmcst = mcst->lg_mcst_nextp;
kmem_free(mcst, sizeof (lg_mcst_addr_t));
}
return (0);
}
/*
* Add or remove the multicast addresses that are defined for the group
* to or from the specified port.
* This function is called before stopping a port, before a port
* is detached from a group, and when attaching a port to a group.
*/
void
aggr_grp_multicst_port(aggr_port_t *port, boolean_t add)
{
aggr_grp_t *grp = port->lp_grp;
lg_mcst_addr_t *mcst;
ASSERT(RW_WRITE_HELD(&port->lp_lock));
ASSERT(RW_WRITE_HELD(&grp->lg_lock) || RW_READ_HELD(&grp->lg_lock));
if (!port->lp_started)
return;
for (mcst = grp->lg_mcst_list; mcst != NULL;
mcst = mcst->lg_mcst_nextp)
(void) aggr_port_multicst(port, add, mcst->lg_mcst_addr);
}
static int
aggr_m_multicst(void *arg, boolean_t add, const uint8_t *addrp)
{
aggr_grp_t *grp = arg;
aggr_port_t *port = NULL;
int err = 0, cerr;
rw_enter(&grp->lg_lock, RW_WRITER);
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
continue;
cerr = aggr_port_multicst(port, add, addrp);
if (cerr == 0)
(void) aggr_grp_multicst(grp, add, addrp);
if (cerr != 0 && err == 0)
err = cerr;
}
rw_exit(&grp->lg_lock);
return (err);
}
static int
aggr_m_unicst(void *arg, const uint8_t *macaddr)
{
aggr_grp_t *grp = arg;
int rc;
AGGR_LACP_LOCK(grp);
rw_enter(&grp->lg_lock, RW_WRITER);
rc = aggr_grp_modify(0, grp, AGGR_MODIFY_MAC, 0, B_TRUE, macaddr,
0, 0);
rw_exit(&grp->lg_lock);
AGGR_LACP_UNLOCK(grp);
return (rc);
}
/*
* Initialize the capabilities that are advertised for the group
* according to the capabilities of the constituent ports.
*/
static void
aggr_grp_capab_set(aggr_grp_t *grp)
{
uint32_t cksum;
aggr_port_t *port;
ASSERT(RW_WRITE_HELD(&grp->lg_lock));
ASSERT(grp->lg_ports != NULL);
grp->lg_hcksum_txflags = (uint32_t)-1;
grp->lg_gldv3_polling = B_TRUE;
grp->lg_zcopy = B_TRUE;
grp->lg_vlan = B_TRUE;
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
if (!mac_capab_get(port->lp_mh, MAC_CAPAB_HCKSUM, &cksum))
cksum = 0;
grp->lg_hcksum_txflags &= cksum;
grp->lg_vlan &=
!mac_capab_get(port->lp_mh, MAC_CAPAB_NO_NATIVEVLAN, NULL);
grp->lg_zcopy &=
!mac_capab_get(port->lp_mh, MAC_CAPAB_NO_ZCOPY, NULL);
grp->lg_gldv3_polling &=
mac_capab_get(port->lp_mh, MAC_CAPAB_POLL, NULL);
}
}
/*
* Checks whether the capabilities of the port being added are compatible
* with the current capabilities of the aggregation.
*/
static boolean_t
aggr_grp_capab_check(aggr_grp_t *grp, aggr_port_t *port)
{
uint32_t hcksum_txflags;
ASSERT(grp->lg_ports != NULL);
if (((!mac_capab_get(port->lp_mh, MAC_CAPAB_NO_NATIVEVLAN, NULL)) &
grp->lg_vlan) != grp->lg_vlan) {
return (B_FALSE);
}
if (((!mac_capab_get(port->lp_mh, MAC_CAPAB_NO_ZCOPY, NULL)) &
grp->lg_zcopy) != grp->lg_zcopy) {
return (B_FALSE);
}
if (!mac_capab_get(port->lp_mh, MAC_CAPAB_HCKSUM, &hcksum_txflags)) {
if (grp->lg_hcksum_txflags != 0)
return (B_FALSE);
} else if ((hcksum_txflags & grp->lg_hcksum_txflags) !=
grp->lg_hcksum_txflags) {
return (B_FALSE);
}
if (mac_capab_get(port->lp_mh, MAC_CAPAB_POLL, NULL) !=
grp->lg_gldv3_polling) {
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Returns the maximum SDU according to the SDU of the constituent ports.
*/
static uint_t
aggr_grp_max_sdu(aggr_grp_t *grp)
{
uint_t max_sdu = (uint_t)-1;
aggr_port_t *port;
ASSERT(RW_WRITE_HELD(&grp->lg_lock));
ASSERT(grp->lg_ports != NULL);
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
uint_t port_sdu_max;
mac_sdu_get(port->lp_mh, NULL, &port_sdu_max);
if (max_sdu > port_sdu_max)
max_sdu = port_sdu_max;
}
return (max_sdu);
}
/*
* Checks if the maximum SDU of the specified port is compatible
* with the maximum SDU of the specified aggregation group, returns
* B_TRUE if it is, B_FALSE otherwise.
*/
static boolean_t
aggr_grp_sdu_check(aggr_grp_t *grp, aggr_port_t *port)
{
uint_t port_sdu_max;
mac_sdu_get(port->lp_mh, NULL, &port_sdu_max);
return (port_sdu_max >= grp->lg_max_sdu);
}
/*
* Returns the maximum margin according to the margin of the constituent ports.
*/
static uint32_t
aggr_grp_max_margin(aggr_grp_t *grp)
{
uint32_t margin = UINT32_MAX;
aggr_port_t *port;
ASSERT(RW_WRITE_HELD(&grp->lg_lock));
ASSERT(grp->lg_ports != NULL);
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
if (margin > port->lp_margin)
margin = port->lp_margin;
}
grp->lg_margin = margin;
return (margin);
}
/*
* Checks if the maximum margin of the specified port is compatible
* with the maximum margin of the specified aggregation group, returns
* B_TRUE if it is, B_FALSE otherwise.
*/
static boolean_t
aggr_grp_margin_check(aggr_grp_t *grp, aggr_port_t *port)
{
if (port->lp_margin >= grp->lg_margin)
return (B_TRUE);
/*
* See whether the current margin value is allowed to be changed to
* the new value.
*/
if (!mac_margin_update(grp->lg_mh, port->lp_margin))
return (B_FALSE);
grp->lg_margin = port->lp_margin;
return (B_TRUE);
}