Print this page
11493 aggr needs support for multiple pseudo rx groups
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
*** 30,72 ****
* link aggregation group. When created, aggr_grp_t objects are
* entered into the aggr_grp_hash hash table maintained by the modhash
* module. The hash key is the linkid associated with the link
* aggregation group.
*
! * A set of MAC ports are associated with each association group.
*
! * Aggr pseudo TX rings
! * --------------------
! * The underlying ports (NICs) in an aggregation can have TX rings. To
! * enhance aggr's performance, these TX rings are made available to the
! * aggr layer as pseudo TX rings. The concept of pseudo rings are not new.
! * They are already present and implemented on the RX side. It is called
! * as pseudo RX rings. The same concept is extended to the TX side where
! * each TX ring of an underlying port is reflected in aggr as a pseudo
! * TX ring. Thus each pseudo TX ring will map to a specific hardware TX
! * ring. Even in the case of a NIC that does not have a TX ring, a pseudo
! * TX ring is given to the aggregation layer.
*
* With this change, the outgoing stack depth looks much better:
*
* mac_tx() -> mac_tx_aggr_mode() -> mac_tx_soft_ring_process() ->
* mac_tx_send() -> aggr_ring_rx() -> <driver>_ring_tx()
*
! * Two new modes are introduced to mac_tx() to handle aggr pseudo TX rings:
* SRS_TX_AGGR and SRS_TX_BW_AGGR.
*
* In SRS_TX_AGGR mode, mac_tx_aggr_mode() routine is called. This routine
! * invokes an aggr function, aggr_find_tx_ring(), to find a (pseudo) TX
* ring belonging to a port on which the packet has to be sent.
* aggr_find_tx_ring() first finds the outgoing port based on L2/L3/L4
! * policy and then uses the fanout_hint passed to it to pick a TX ring from
* the selected port.
*
* In SRS_TX_BW_AGGR mode, mac_tx_bw_mode() function is called where
* bandwidth limit is applied first on the outgoing packet and the packets
* allowed to go out would call mac_tx_aggr_mode() to send the packet on a
! * particular TX ring.
*/
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/conf.h>
--- 30,102 ----
* link aggregation group. When created, aggr_grp_t objects are
* entered into the aggr_grp_hash hash table maintained by the modhash
* module. The hash key is the linkid associated with the link
* aggregation group.
*
! * Each aggregation contains a set of ports. The port is represented
! * by the aggr_port_t structure. A port consists of a single MAC
! * client which has exclusive (MCIS_EXCLUSIVE) use of the underlying
! * MAC. This client is used by the aggr to send and receive LACP
! * traffic. Each port client takes on the same MAC unicast address --
! * the address of the aggregation itself (taken from the first port by
! * default).
*
! * The MAC client that hangs off each aggr port is not your typical
! * MAC client. Not only does it have exclusive control of the MAC, but
! * it also has no Tx or Rx SRSes. An SRS is designed to queue and
! * fanout traffic among L4 protocols; but the aggr is an intermediary,
! * not a consumer. Instead of using SRSes, the aggr puts the
! * underlying hardware rings into passthru mode and ships packets up
! * via a direct call to aggr_recv_cb(). This allows aggr to enforce
! * LACP while passing all other traffic up to clients of the aggr.
*
+ * Pseudo Rx Groups and Rings
+ * --------------------------
+ *
+ * It is imperative for client performance that the aggr provide as
+ * many MAC groups as possible. In order to use the underlying HW
+ * resources, aggr creates pseudo groups to aggregate the underlying
+ * HW groups. Every HW group gets mapped to a pseudo group; and every
+ * HW ring in that group gets mapped to a pseudo ring. The pseudo
+ * group at index 0 combines all the HW groups at index 0 from each
+ * port, etc. The aggr's MAC then creates normal MAC groups and rings
+ * out of these pseudo groups and rings to present to the aggr's
+ * clients. To the clients, the aggr's groups and rings are absolutely
+ * no different than a NIC's groups or rings.
+ *
+ * Pseudo Tx Rings
+ * ---------------
+ *
+ * The underlying ports (NICs) in an aggregation can have Tx rings. To
+ * enhance aggr's performance, these Tx rings are made available to
+ * the aggr layer as pseudo Tx rings. The concept of pseudo rings are
+ * not new. They are already present and implemented on the Rx side.
+ * The same concept is extended to the Tx side where each Tx ring of
+ * an underlying port is reflected in aggr as a pseudo Tx ring. Thus
+ * each pseudo Tx ring will map to a specific hardware Tx ring. Even
+ * in the case of a NIC that does not have a Tx ring, a pseudo Tx ring
+ * is given to the aggregation layer.
+ *
* With this change, the outgoing stack depth looks much better:
*
* mac_tx() -> mac_tx_aggr_mode() -> mac_tx_soft_ring_process() ->
* mac_tx_send() -> aggr_ring_rx() -> <driver>_ring_tx()
*
! * Two new modes are introduced to mac_tx() to handle aggr pseudo Tx rings:
* SRS_TX_AGGR and SRS_TX_BW_AGGR.
*
* In SRS_TX_AGGR mode, mac_tx_aggr_mode() routine is called. This routine
! * invokes an aggr function, aggr_find_tx_ring(), to find a (pseudo) Tx
* ring belonging to a port on which the packet has to be sent.
* aggr_find_tx_ring() first finds the outgoing port based on L2/L3/L4
! * policy and then uses the fanout_hint passed to it to pick a Tx ring from
* the selected port.
*
* In SRS_TX_BW_AGGR mode, mac_tx_bw_mode() function is called where
* bandwidth limit is applied first on the outgoing packet and the packets
* allowed to go out would call mac_tx_aggr_mode() to send the packet on a
! * particular Tx ring.
*/
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/conf.h>
*** 119,129 ****
static int aggr_add_pseudo_rx_group(aggr_port_t *, aggr_pseudo_rx_group_t *);
static void aggr_rem_pseudo_rx_group(aggr_port_t *, aggr_pseudo_rx_group_t *);
static int aggr_pseudo_disable_intr(mac_intr_handle_t);
static int aggr_pseudo_enable_intr(mac_intr_handle_t);
! static int aggr_pseudo_start_ring(mac_ring_driver_t, uint64_t);
static int aggr_addmac(void *, const uint8_t *);
static int aggr_remmac(void *, const uint8_t *);
static int aggr_addvlan(mac_group_driver_t, uint16_t);
static int aggr_remvlan(mac_group_driver_t, uint16_t);
static mblk_t *aggr_rx_poll(void *, int);
--- 149,160 ----
static int aggr_add_pseudo_rx_group(aggr_port_t *, aggr_pseudo_rx_group_t *);
static void aggr_rem_pseudo_rx_group(aggr_port_t *, aggr_pseudo_rx_group_t *);
static int aggr_pseudo_disable_intr(mac_intr_handle_t);
static int aggr_pseudo_enable_intr(mac_intr_handle_t);
! static int aggr_pseudo_start_rx_ring(mac_ring_driver_t, uint64_t);
! static void aggr_pseudo_stop_rx_ring(mac_ring_driver_t);
static int aggr_addmac(void *, const uint8_t *);
static int aggr_remmac(void *, const uint8_t *);
static int aggr_addvlan(mac_group_driver_t, uint16_t);
static int aggr_remvlan(mac_group_driver_t, uint16_t);
static mblk_t *aggr_rx_poll(void *, int);
*** 364,376 ****
port->lp_state = AGGR_PORT_STATE_ATTACHED;
aggr_grp_multicst_port(port, B_TRUE);
/*
! * Set port's receive callback
*/
! mac_rx_set(port->lp_mch, aggr_recv_cb, port);
/*
* If LACP is OFF, the port can be used to send data as soon
* as its link is up and verified to be compatible with the
* aggregation.
--- 395,411 ----
port->lp_state = AGGR_PORT_STATE_ATTACHED;
aggr_grp_multicst_port(port, B_TRUE);
/*
! * The port client doesn't have an Rx SRS; instead of calling
! * mac_rx_set() we set the client's flow callback directly.
! * This datapath is used only when the port's driver doesn't
! * support MAC_CAPAB_RINGS. Drivers with ring support will
! * deliver traffic to the aggr via ring passthru.
*/
! mac_client_set_flow_cb(port->lp_mch, aggr_recv_cb, port);
/*
* If LACP is OFF, the port can be used to send data as soon
* as its link is up and verified to be compatible with the
* aggregation.
*** 396,406 ****
/* update state */
if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
return (B_FALSE);
! mac_rx_clear(port->lp_mch);
aggr_grp_multicst_port(port, B_FALSE);
if (grp->lg_lacp_mode == AGGR_LACP_OFF)
aggr_send_port_disable(port);
--- 431,441 ----
/* update state */
if (port->lp_state != AGGR_PORT_STATE_ATTACHED)
return (B_FALSE);
! mac_client_clear_flow_cb(port->lp_mch);
aggr_grp_multicst_port(port, B_FALSE);
if (grp->lg_lacp_mode == AGGR_LACP_OFF)
aggr_send_port_disable(port);
*** 535,564 ****
aggr_port_t *port, **cport;
mac_perim_handle_t mph;
zoneid_t port_zoneid = ALL_ZONES;
int err;
! /* The port must be int the same zone as the aggregation. */
if (zone_check_datalink(&port_zoneid, port_linkid) != 0)
port_zoneid = GLOBAL_ZONEID;
if (grp->lg_zoneid != port_zoneid)
return (EBUSY);
/*
! * lg_mh could be NULL when the function is called during the creation
! * of the aggregation.
*/
ASSERT(grp->lg_mh == NULL || MAC_PERIM_HELD(grp->lg_mh));
- /* create new port */
err = aggr_port_create(grp, port_linkid, force, &port);
if (err != 0)
return (err);
mac_perim_enter_by_mh(port->lp_mh, &mph);
! /* add port to list of group constituent ports */
cport = &grp->lg_ports;
while (*cport != NULL)
cport = &((*cport)->lp_next);
*cport = port;
--- 570,600 ----
aggr_port_t *port, **cport;
mac_perim_handle_t mph;
zoneid_t port_zoneid = ALL_ZONES;
int err;
! /* The port must be in the same zone as the aggregation. */
if (zone_check_datalink(&port_zoneid, port_linkid) != 0)
port_zoneid = GLOBAL_ZONEID;
if (grp->lg_zoneid != port_zoneid)
return (EBUSY);
/*
! * If we are creating the aggr, then there is no MAC handle
! * and thus no perimeter to hold. If we are adding a port to
! * an existing aggr, then the perimiter of the aggr's MAC must
! * be held.
*/
ASSERT(grp->lg_mh == NULL || MAC_PERIM_HELD(grp->lg_mh));
err = aggr_port_create(grp, port_linkid, force, &port);
if (err != 0)
return (err);
mac_perim_enter_by_mh(port->lp_mh, &mph);
! /* Add the new port to the end of the list. */
cport = &grp->lg_ports;
while (*cport != NULL)
cport = &((*cport)->lp_next);
*cport = port;
*** 636,645 ****
--- 672,682 ----
return (EIO);
ring->arr_flags |= MAC_PSEUDO_RING_INUSE;
ring->arr_hw_rh = hw_rh;
ring->arr_port = port;
+ ring->arr_grp = rx_grp;
rx_grp->arg_ring_cnt++;
/*
* The group is already registered, dynamically add a new ring to the
* mac group.
*** 646,659 ****
*/
if ((err = mac_group_add_ring(rx_grp->arg_gh, j)) != 0) {
ring->arr_flags &= ~MAC_PSEUDO_RING_INUSE;
ring->arr_hw_rh = NULL;
ring->arr_port = NULL;
rx_grp->arg_ring_cnt--;
} else {
! mac_hwring_setup(hw_rh, (mac_resource_handle_t)ring,
! mac_find_ring(rx_grp->arg_gh, j));
}
return (err);
}
/*
--- 683,701 ----
*/
if ((err = mac_group_add_ring(rx_grp->arg_gh, j)) != 0) {
ring->arr_flags &= ~MAC_PSEUDO_RING_INUSE;
ring->arr_hw_rh = NULL;
ring->arr_port = NULL;
+ ring->arr_grp = NULL;
rx_grp->arg_ring_cnt--;
} else {
! /*
! * This must run after the MAC is registered.
! */
! ASSERT3P(ring->arr_rh, !=, NULL);
! mac_hwring_set_passthru(hw_rh, (mac_rx_t)aggr_recv_cb,
! (void *)port, (mac_resource_handle_t)ring);
}
return (err);
}
/*
*** 660,674 ****
* Remove the pseudo RX ring of the given HW ring handle.
*/
static void
aggr_rem_pseudo_rx_ring(aggr_pseudo_rx_group_t *rx_grp, mac_ring_handle_t hw_rh)
{
! aggr_pseudo_rx_ring_t *ring;
! int j;
- for (j = 0; j < MAX_RINGS_PER_GROUP; j++) {
- ring = rx_grp->arg_rings + j;
if (!(ring->arr_flags & MAC_PSEUDO_RING_INUSE) ||
ring->arr_hw_rh != hw_rh) {
continue;
}
--- 702,714 ----
* Remove the pseudo RX ring of the given HW ring handle.
*/
static void
aggr_rem_pseudo_rx_ring(aggr_pseudo_rx_group_t *rx_grp, mac_ring_handle_t hw_rh)
{
! for (uint_t j = 0; j < MAX_RINGS_PER_GROUP; j++) {
! aggr_pseudo_rx_ring_t *ring = rx_grp->arg_rings + j;
if (!(ring->arr_flags & MAC_PSEUDO_RING_INUSE) ||
ring->arr_hw_rh != hw_rh) {
continue;
}
*** 675,686 ****
mac_group_rem_ring(rx_grp->arg_gh, ring->arr_rh);
ring->arr_flags &= ~MAC_PSEUDO_RING_INUSE;
ring->arr_hw_rh = NULL;
ring->arr_port = NULL;
rx_grp->arg_ring_cnt--;
! mac_hwring_teardown(hw_rh);
break;
}
}
/*
--- 715,727 ----
mac_group_rem_ring(rx_grp->arg_gh, ring->arr_rh);
ring->arr_flags &= ~MAC_PSEUDO_RING_INUSE;
ring->arr_hw_rh = NULL;
ring->arr_port = NULL;
+ ring->arr_grp = NULL;
rx_grp->arg_ring_cnt--;
! mac_hwring_clear_passthru(hw_rh);
break;
}
}
/*
*** 693,789 ****
* o Program existing VLAN filters on the pseudo group into the HW group.
*/
static int
aggr_add_pseudo_rx_group(aggr_port_t *port, aggr_pseudo_rx_group_t *rx_grp)
{
- aggr_grp_t *grp = port->lp_grp;
mac_ring_handle_t hw_rh[MAX_RINGS_PER_GROUP];
aggr_unicst_addr_t *addr, *a;
mac_perim_handle_t pmph;
aggr_vlan_t *avp;
! int hw_rh_cnt, i = 0, j;
int err = 0;
! ASSERT(MAC_PERIM_HELD(grp->lg_mh));
mac_perim_enter_by_mh(port->lp_mh, &pmph);
/*
! * This function must be called after the aggr registers its MAC
! * and its Rx group has been initialized.
*/
ASSERT(rx_grp->arg_gh != NULL);
/*
* Get the list of the underlying HW rings.
*/
! hw_rh_cnt = mac_hwrings_get(port->lp_mch,
! &port->lp_hwgh, hw_rh, MAC_RING_TYPE_RX);
- if (port->lp_hwgh != NULL) {
/*
- * Quiesce the HW ring and the MAC SRS on the ring. Note
- * that the HW ring will be restarted when the pseudo ring
- * is started. At that time all the packets will be
- * directly passed up to the pseudo Rx ring and handled
- * by MAC SRS created over the pseudo Rx ring.
- */
- mac_rx_client_quiesce(port->lp_mch);
- mac_srs_perm_quiesce(port->lp_mch, B_TRUE);
- }
-
- /*
* Add existing VLAN and unicast address filters to the port.
*/
for (avp = list_head(&rx_grp->arg_vlans); avp != NULL;
avp = list_next(&rx_grp->arg_vlans, avp)) {
! if ((err = aggr_port_addvlan(port, avp->av_vid)) != 0)
goto err;
}
for (addr = rx_grp->arg_macaddr; addr != NULL; addr = addr->aua_next) {
! if ((err = aggr_port_addmac(port, addr->aua_addr)) != 0)
goto err;
}
for (i = 0; i < hw_rh_cnt; i++) {
err = aggr_add_pseudo_rx_ring(port, rx_grp, hw_rh[i]);
if (err != 0)
goto err;
}
- port->lp_rx_grp_added = B_TRUE;
mac_perim_exit(pmph);
return (0);
err:
ASSERT(err != 0);
! for (j = 0; j < i; j++)
aggr_rem_pseudo_rx_ring(rx_grp, hw_rh[j]);
for (a = rx_grp->arg_macaddr; a != addr; a = a->aua_next)
! aggr_port_remmac(port, a->aua_addr);
if (avp != NULL)
avp = list_prev(&rx_grp->arg_vlans, avp);
for (; avp != NULL; avp = list_prev(&rx_grp->arg_vlans, avp)) {
int err2;
! if ((err2 = aggr_port_remvlan(port, avp->av_vid)) != 0) {
cmn_err(CE_WARN, "Failed to remove VLAN %u from port %s"
": errno %d.", avp->av_vid,
mac_client_name(port->lp_mch), err2);
}
}
! if (port->lp_hwgh != NULL) {
! mac_srs_perm_quiesce(port->lp_mch, B_FALSE);
! mac_rx_client_restart(port->lp_mch);
! port->lp_hwgh = NULL;
! }
!
mac_perim_exit(pmph);
return (err);
}
/*
--- 734,813 ----
* o Program existing VLAN filters on the pseudo group into the HW group.
*/
static int
aggr_add_pseudo_rx_group(aggr_port_t *port, aggr_pseudo_rx_group_t *rx_grp)
{
mac_ring_handle_t hw_rh[MAX_RINGS_PER_GROUP];
aggr_unicst_addr_t *addr, *a;
mac_perim_handle_t pmph;
aggr_vlan_t *avp;
! uint_t hw_rh_cnt, i;
int err = 0;
+ uint_t g_idx = rx_grp->arg_index;
! ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
! ASSERT3U(g_idx, <, MAX_GROUPS_PER_PORT);
mac_perim_enter_by_mh(port->lp_mh, &pmph);
/*
! * This function must be called after the aggr registers its
! * MAC and its Rx groups have been initialized.
*/
ASSERT(rx_grp->arg_gh != NULL);
/*
* Get the list of the underlying HW rings.
*/
! hw_rh_cnt = mac_hwrings_idx_get(port->lp_mh, g_idx,
! &port->lp_hwghs[g_idx], hw_rh, MAC_RING_TYPE_RX);
/*
* Add existing VLAN and unicast address filters to the port.
*/
for (avp = list_head(&rx_grp->arg_vlans); avp != NULL;
avp = list_next(&rx_grp->arg_vlans, avp)) {
! if ((err = aggr_port_addvlan(port, g_idx, avp->av_vid)) != 0)
goto err;
}
for (addr = rx_grp->arg_macaddr; addr != NULL; addr = addr->aua_next) {
! if ((err = aggr_port_addmac(port, g_idx, addr->aua_addr)) != 0)
goto err;
}
for (i = 0; i < hw_rh_cnt; i++) {
err = aggr_add_pseudo_rx_ring(port, rx_grp, hw_rh[i]);
if (err != 0)
goto err;
}
mac_perim_exit(pmph);
return (0);
err:
ASSERT(err != 0);
! for (uint_t j = 0; j < i; j++)
aggr_rem_pseudo_rx_ring(rx_grp, hw_rh[j]);
for (a = rx_grp->arg_macaddr; a != addr; a = a->aua_next)
! aggr_port_remmac(port, g_idx, a->aua_addr);
if (avp != NULL)
avp = list_prev(&rx_grp->arg_vlans, avp);
for (; avp != NULL; avp = list_prev(&rx_grp->arg_vlans, avp)) {
int err2;
! if ((err2 = aggr_port_remvlan(port, g_idx, avp->av_vid)) != 0) {
cmn_err(CE_WARN, "Failed to remove VLAN %u from port %s"
": errno %d.", avp->av_vid,
mac_client_name(port->lp_mch), err2);
}
}
! port->lp_hwghs[g_idx] = NULL;
mac_perim_exit(pmph);
return (err);
}
/*
*** 793,851 ****
* out of promisc mode.
*/
static void
aggr_rem_pseudo_rx_group(aggr_port_t *port, aggr_pseudo_rx_group_t *rx_grp)
{
- aggr_grp_t *grp = port->lp_grp;
mac_ring_handle_t hw_rh[MAX_RINGS_PER_GROUP];
aggr_unicst_addr_t *addr;
- mac_group_handle_t hwgh;
mac_perim_handle_t pmph;
! int hw_rh_cnt, i;
! ASSERT(MAC_PERIM_HELD(grp->lg_mh));
mac_perim_enter_by_mh(port->lp_mh, &pmph);
! if (!port->lp_rx_grp_added)
! goto done;
! ASSERT(rx_grp->arg_gh != NULL);
! hw_rh_cnt = mac_hwrings_get(port->lp_mch,
! &hwgh, hw_rh, MAC_RING_TYPE_RX);
!
! for (i = 0; i < hw_rh_cnt; i++)
aggr_rem_pseudo_rx_ring(rx_grp, hw_rh[i]);
for (addr = rx_grp->arg_macaddr; addr != NULL; addr = addr->aua_next)
! aggr_port_remmac(port, addr->aua_addr);
for (aggr_vlan_t *avp = list_head(&rx_grp->arg_vlans); avp != NULL;
avp = list_next(&rx_grp->arg_vlans, avp)) {
int err;
! if ((err = aggr_port_remvlan(port, avp->av_vid)) != 0) {
cmn_err(CE_WARN, "Failed to remove VLAN %u from port %s"
": errno %d.", avp->av_vid,
mac_client_name(port->lp_mch), err);
}
}
! if (port->lp_hwgh != NULL) {
! port->lp_hwgh = NULL;
!
! /*
! * First clear the permanent-quiesced flag of the RX srs then
! * restart the HW ring and the mac srs on the ring. Note that
! * the HW ring and associated SRS will soon been removed when
! * the port is removed from the aggr.
! */
! mac_srs_perm_quiesce(port->lp_mch, B_FALSE);
! mac_rx_client_restart(port->lp_mch);
! }
!
! port->lp_rx_grp_added = B_FALSE;
! done:
mac_perim_exit(pmph);
}
/*
* Add a pseudo TX ring for the given HW ring handle.
--- 817,858 ----
* out of promisc mode.
*/
static void
aggr_rem_pseudo_rx_group(aggr_port_t *port, aggr_pseudo_rx_group_t *rx_grp)
{
mac_ring_handle_t hw_rh[MAX_RINGS_PER_GROUP];
aggr_unicst_addr_t *addr;
mac_perim_handle_t pmph;
! uint_t hw_rh_cnt;
! uint_t g_idx = rx_grp->arg_index;
! ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
! ASSERT3U(g_idx, <, MAX_GROUPS_PER_PORT);
! ASSERT3P(rx_grp->arg_gh, !=, NULL);
mac_perim_enter_by_mh(port->lp_mh, &pmph);
! hw_rh_cnt = mac_hwrings_idx_get(port->lp_mh, g_idx, NULL, hw_rh,
! MAC_RING_TYPE_RX);
! for (uint_t i = 0; i < hw_rh_cnt; i++)
aggr_rem_pseudo_rx_ring(rx_grp, hw_rh[i]);
for (addr = rx_grp->arg_macaddr; addr != NULL; addr = addr->aua_next)
! aggr_port_remmac(port, g_idx, addr->aua_addr);
for (aggr_vlan_t *avp = list_head(&rx_grp->arg_vlans); avp != NULL;
avp = list_next(&rx_grp->arg_vlans, avp)) {
int err;
! if ((err = aggr_port_remvlan(port, g_idx, avp->av_vid)) != 0) {
cmn_err(CE_WARN, "Failed to remove VLAN %u from port %s"
": errno %d.", avp->av_vid,
mac_client_name(port->lp_mch), err);
}
}
! port->lp_hwghs[g_idx] = NULL;
mac_perim_exit(pmph);
}
/*
* Add a pseudo TX ring for the given HW ring handle.
*** 945,956 ****
mac_perim_enter_by_mh(port->lp_mh, &pmph);
/*
* Get the list the the underlying HW rings.
*/
! hw_rh_cnt = mac_hwrings_get(port->lp_mch,
! NULL, hw_rh, MAC_RING_TYPE_TX);
/*
* Even if the underlying NIC does not have TX rings, we
* still make a psuedo TX ring for that NIC with NULL as
* the ring handle.
--- 952,963 ----
mac_perim_enter_by_mh(port->lp_mh, &pmph);
/*
* Get the list the the underlying HW rings.
*/
! hw_rh_cnt = mac_hwrings_get(port->lp_mch, NULL, hw_rh,
! MAC_RING_TYPE_TX);
/*
* Even if the underlying NIC does not have TX rings, we
* still make a psuedo TX ring for that NIC with NULL as
* the ring handle.
*** 1052,1115 ****
aggr_pseudo_rx_ring_t *rr_ring = (aggr_pseudo_rx_ring_t *)ih;
return (mac_hwring_enable_intr(rr_ring->arr_hw_rh));
}
/*
! * Here we need to start the pseudo-ring. As MAC already ensures that the
! * underlying device is set up, all we need to do is save the ring generation.
! *
! * Note, we don't end up wanting to use the underlying mac_hwring_start/stop
! * functions here as those don't actually stop and start the ring, they just
! * quiesce the ring. Regardless of whether the aggr is logically up or not, we
! * want to make sure that we can receive traffic for LACP.
*/
static int
! aggr_pseudo_start_ring(mac_ring_driver_t arg, uint64_t mr_gen)
{
aggr_pseudo_rx_ring_t *rr_ring = (aggr_pseudo_rx_ring_t *)arg;
rr_ring->arr_gen = mr_gen;
! return (0);
}
/*
* Add one or more ports to an existing link aggregation group.
*/
int
aggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force,
laioc_port_t *ports)
{
! int rc, i, nadded = 0;
aggr_grp_t *grp = NULL;
aggr_port_t *port;
boolean_t link_state_changed = B_FALSE;
mac_perim_handle_t mph, pmph;
! /* get group corresponding to linkid */
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);
}
AGGR_GRP_REFHOLD(grp);
/*
! * Hold the perimeter so that the aggregation won't be destroyed.
*/
mac_perim_enter_by_mh(grp->lg_mh, &mph);
rw_exit(&aggr_grp_lock);
! /* add the specified ports to group */
! for (i = 0; i < nports; i++) {
! /* add port to group */
if ((rc = aggr_grp_add_port(grp, ports[i].lp_linkid,
force, &port)) != 0) {
goto bail;
}
ASSERT(port != NULL);
! nadded++;
/* check capabilities */
if (!aggr_grp_capab_check(grp, port) ||
!aggr_grp_sdu_check(grp, port) ||
!aggr_grp_margin_check(grp, port)) {
--- 1059,1150 ----
aggr_pseudo_rx_ring_t *rr_ring = (aggr_pseudo_rx_ring_t *)ih;
return (mac_hwring_enable_intr(rr_ring->arr_hw_rh));
}
/*
! * Start the pseudo ring. Since the pseudo ring is just an abstraction
! * over an actual HW ring, the real task is to start the underlying HW
! * ring.
*/
static int
! aggr_pseudo_start_rx_ring(mac_ring_driver_t arg, uint64_t mr_gen)
{
+ int err;
aggr_pseudo_rx_ring_t *rr_ring = (aggr_pseudo_rx_ring_t *)arg;
+ err = mac_hwring_start(rr_ring->arr_hw_rh);
+
+ if (err != 0)
+ return (err);
+
rr_ring->arr_gen = mr_gen;
! return (err);
}
/*
+ * Stop the pseudo ring. Since the pseudo ring is just an abstraction
+ * over an actual HW ring, the real task is to stop the underlying HW
+ * ring.
+ */
+ static void
+ aggr_pseudo_stop_rx_ring(mac_ring_driver_t arg)
+ {
+ aggr_pseudo_rx_ring_t *rr_ring = (aggr_pseudo_rx_ring_t *)arg;
+
+ /*
+ * The rings underlying the default group must stay up to
+ * continue receiving LACP traffic. We would normally never
+ * stop the default Rx rings because of the primary MAC
+ * client; but aggr's primary MAC client doesn't call
+ * mac_unicast_add() and thus mi_active is 0 when the last
+ * non-primary client is deleted.
+ */
+ if (rr_ring->arr_grp->arg_index != 0)
+ mac_hwring_stop(rr_ring->arr_hw_rh);
+ }
+
+ /*
* Add one or more ports to an existing link aggregation group.
*/
int
aggr_grp_add_ports(datalink_id_t linkid, uint_t nports, boolean_t force,
laioc_port_t *ports)
{
! int rc;
! uint_t port_added = 0;
! uint_t grp_added;
aggr_grp_t *grp = NULL;
aggr_port_t *port;
boolean_t link_state_changed = B_FALSE;
mac_perim_handle_t mph, pmph;
! /* Get the aggr corresponding to linkid. */
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);
}
AGGR_GRP_REFHOLD(grp);
/*
! * Hold the perimeter so that the aggregation can't be destroyed.
*/
mac_perim_enter_by_mh(grp->lg_mh, &mph);
rw_exit(&aggr_grp_lock);
! /* Add the specified ports to the aggr. */
! for (uint_t i = 0; i < nports; i++) {
! grp_added = 0;
!
if ((rc = aggr_grp_add_port(grp, ports[i].lp_linkid,
force, &port)) != 0) {
goto bail;
}
+
ASSERT(port != NULL);
! port_added++;
/* check capabilities */
if (!aggr_grp_capab_check(grp, port) ||
!aggr_grp_sdu_check(grp, port) ||
!aggr_grp_margin_check(grp, port)) {
*** 1122,1135 ****
* port.
*/
rc = aggr_add_pseudo_tx_group(port, &grp->lg_tx_group);
if (rc != 0)
goto bail;
! rc = aggr_add_pseudo_rx_group(port, &grp->lg_rx_group);
if (rc != 0)
goto bail;
mac_perim_enter_by_mh(port->lp_mh, &pmph);
/* set LACP mode */
aggr_port_lacp_set_mode(grp, port);
--- 1157,1177 ----
* port.
*/
rc = aggr_add_pseudo_tx_group(port, &grp->lg_tx_group);
if (rc != 0)
goto bail;
!
! for (uint_t j = 0; j < grp->lg_rx_group_count; j++) {
! rc = aggr_add_pseudo_rx_group(port,
! &grp->lg_rx_groups[j]);
!
if (rc != 0)
goto bail;
+ grp_added++;
+ }
+
mac_perim_enter_by_mh(port->lp_mh, &pmph);
/* set LACP mode */
aggr_port_lacp_set_mode(grp, port);
*** 1142,1152 ****
}
/*
* Turn on the promiscuous mode over the port when it
* is requested to be turned on to receive the
! * non-primary address over a port, or the promiscous
* mode is enabled over the aggr.
*/
if (grp->lg_promisc || port->lp_prom_addr != NULL) {
rc = aggr_port_promisc(port, B_TRUE);
if (rc != 0) {
--- 1184,1194 ----
}
/*
* Turn on the promiscuous mode over the port when it
* is requested to be turned on to receive the
! * non-primary address over a port, or the promiscuous
* mode is enabled over the aggr.
*/
if (grp->lg_promisc || port->lp_prom_addr != NULL) {
rc = aggr_port_promisc(port, B_TRUE);
if (rc != 0) {
*** 1177,1197 ****
mac_link_update(grp->lg_mh, grp->lg_link_state);
bail:
if (rc != 0) {
/* stop and remove ports that have been added */
! for (i = 0; i < nadded; i++) {
port = aggr_grp_port_lookup(grp, ports[i].lp_linkid);
ASSERT(port != NULL);
if (grp->lg_started) {
mac_perim_enter_by_mh(port->lp_mh, &pmph);
(void) aggr_port_promisc(port, B_FALSE);
aggr_port_stop(port);
mac_perim_exit(pmph);
}
aggr_rem_pseudo_tx_group(port, &grp->lg_tx_group);
! aggr_rem_pseudo_rx_group(port, &grp->lg_rx_group);
(void) aggr_grp_rem_port(grp, port, NULL, NULL);
}
}
mac_perim_exit(mph);
--- 1219,1255 ----
mac_link_update(grp->lg_mh, grp->lg_link_state);
bail:
if (rc != 0) {
/* stop and remove ports that have been added */
! for (uint_t i = 0; i < port_added; i++) {
! uint_t grp_remove;
!
port = aggr_grp_port_lookup(grp, ports[i].lp_linkid);
ASSERT(port != NULL);
+
if (grp->lg_started) {
mac_perim_enter_by_mh(port->lp_mh, &pmph);
(void) aggr_port_promisc(port, B_FALSE);
aggr_port_stop(port);
mac_perim_exit(pmph);
}
+
aggr_rem_pseudo_tx_group(port, &grp->lg_tx_group);
!
! /*
! * Only the last port could have a partial set
! * of groups added.
! */
! grp_remove = (i + 1 == port_added) ? grp_added :
! grp->lg_rx_group_count;
!
! for (uint_t j = 0; j < grp_remove; j++) {
! aggr_rem_pseudo_rx_group(port,
! &grp->lg_rx_groups[j]);
! }
!
(void) aggr_grp_rem_port(grp, port, NULL, NULL);
}
}
mac_perim_exit(mph);
*** 1349,1366 ****
grp->lg_tx_notify_thread = thread_create(NULL, 0,
aggr_tx_notify_thread, grp, 0, &p0, TS_RUN, minclsyspri);
grp->lg_tx_blocked_rings = kmem_zalloc((sizeof (mac_ring_handle_t *) *
MAX_RINGS_PER_GROUP), KM_SLEEP);
grp->lg_tx_blocked_cnt = 0;
! bzero(&grp->lg_rx_group, sizeof (aggr_pseudo_rx_group_t));
bzero(&grp->lg_tx_group, sizeof (aggr_pseudo_tx_group_t));
aggr_lacp_init_grp(grp);
- grp->lg_rx_group.arg_untagged = 0;
- list_create(&(grp->lg_rx_group.arg_vlans), sizeof (aggr_vlan_t),
- offsetof(aggr_vlan_t, av_link));
-
/* add MAC ports to group */
grp->lg_ports = NULL;
grp->lg_nports = 0;
grp->lg_nattached_ports = 0;
grp->lg_ntx_ports = 0;
--- 1407,1421 ----
grp->lg_tx_notify_thread = thread_create(NULL, 0,
aggr_tx_notify_thread, grp, 0, &p0, TS_RUN, minclsyspri);
grp->lg_tx_blocked_rings = kmem_zalloc((sizeof (mac_ring_handle_t *) *
MAX_RINGS_PER_GROUP), KM_SLEEP);
grp->lg_tx_blocked_cnt = 0;
! bzero(&grp->lg_rx_groups,
! sizeof (aggr_pseudo_rx_group_t) * MAX_GROUPS_PER_PORT);
bzero(&grp->lg_tx_group, sizeof (aggr_pseudo_tx_group_t));
aggr_lacp_init_grp(grp);
/* add MAC ports to group */
grp->lg_ports = NULL;
grp->lg_nports = 0;
grp->lg_nattached_ports = 0;
grp->lg_ntx_ports = 0;
*** 1378,1388 ****
--- 1433,1480 ----
err = aggr_grp_add_port(grp, ports[i].lp_linkid, force, &port);
if (err != 0)
goto bail;
}
+ grp->lg_rx_group_count = 1;
+
+ for (i = 0, port = grp->lg_ports; port != NULL;
+ i++, port = port->lp_next) {
+ uint_t num_rgroups;
+
+ mac_perim_enter_by_mh(port->lp_mh, &mph);
+ num_rgroups = mac_get_num_rx_groups(port->lp_mh);
+ mac_perim_exit(mph);
+
/*
+ * Utilize all the groups in a port. If some ports
+ * have less groups than others, then traffic destined
+ * for the same unicast address may be HW classified
+ * on some ports but SW classified by aggr when
+ * arriving on other ports.
+ */
+ grp->lg_rx_group_count = MAX(grp->lg_rx_group_count,
+ num_rgroups);
+ }
+
+ /*
+ * There could be cases where the hardware provides more
+ * groups than aggr can support. Make sure we never go above
+ * the max aggr can support.
+ */
+ grp->lg_rx_group_count = MIN(grp->lg_rx_group_count,
+ MAX_GROUPS_PER_PORT);
+
+ ASSERT3U(grp->lg_rx_group_count, >, 0);
+ for (i = 0; i < MAX_GROUPS_PER_PORT; i++) {
+ grp->lg_rx_groups[i].arg_index = i;
+ grp->lg_rx_groups[i].arg_untagged = 0;
+ list_create(&(grp->lg_rx_groups[i].arg_vlans),
+ sizeof (aggr_vlan_t), offsetof(aggr_vlan_t, av_link));
+ }
+
+ /*
* If no explicit MAC address was specified by the administrator,
* set it to the MAC address of the first port.
*/
grp->lg_addr_fixed = mac_fixed;
if (grp->lg_addr_fixed) {
*** 1395,1405 ****
} else {
bcopy(grp->lg_ports->lp_addr, grp->lg_addr, ETHERADDRL);
grp->lg_mac_addr_port = grp->lg_ports;
}
! /* set the initial group capabilities */
aggr_grp_capab_set(grp);
if ((mac = mac_alloc(MAC_VERSION)) == NULL) {
err = ENOMEM;
goto bail;
--- 1487,1497 ----
} else {
bcopy(grp->lg_ports->lp_addr, grp->lg_addr, ETHERADDRL);
grp->lg_mac_addr_port = grp->lg_ports;
}
! /* Set the initial group capabilities. */
aggr_grp_capab_set(grp);
if ((mac = mac_alloc(MAC_VERSION)) == NULL) {
err = ENOMEM;
goto bail;
*** 1430,1460 ****
/*
* Update the MAC address of the constituent ports.
* None of the port is attached at this time, the link state of the
* aggregation will not change.
*/
link_state_changed = aggr_grp_update_ports_mac(grp);
ASSERT(!link_state_changed);
! /* update outbound load balancing policy */
aggr_send_update_policy(grp, policy);
! /* set LACP mode */
aggr_lacp_set_mode(grp, lacp_mode, lacp_timer);
/*
* Attach each port if necessary.
*/
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
/*
! * Create the pseudo ring for each HW ring of the underlying
! * port. Note that this is done after the aggr registers the
! * mac.
*/
! VERIFY(aggr_add_pseudo_tx_group(port, &grp->lg_tx_group) == 0);
! VERIFY(aggr_add_pseudo_rx_group(port, &grp->lg_rx_group) == 0);
if (aggr_port_notify_link(grp, port))
link_state_changed = B_TRUE;
/*
* Initialize the callback functions for this port.
--- 1522,1562 ----
/*
* Update the MAC address of the constituent ports.
* None of the port is attached at this time, the link state of the
* aggregation will not change.
+ *
+ * All ports take on the primary MAC address of the aggr
+ * (lg_aggr). At this point, none of the ports are attached;
+ * thus the link state of the aggregation will not change.
*/
link_state_changed = aggr_grp_update_ports_mac(grp);
ASSERT(!link_state_changed);
! /* Update outbound load balancing policy. */
aggr_send_update_policy(grp, policy);
! /* Set LACP mode. */
aggr_lacp_set_mode(grp, lacp_mode, lacp_timer);
/*
* Attach each port if necessary.
*/
for (port = grp->lg_ports; port != NULL; port = port->lp_next) {
/*
! * Create the pseudo ring for each HW ring of the
! * underlying port. Note that this is done after the
! * aggr registers its MAC.
*/
! VERIFY3S(aggr_add_pseudo_tx_group(port, &grp->lg_tx_group),
! ==, 0);
!
! for (i = 0; i < grp->lg_rx_group_count; i++) {
! VERIFY3S(aggr_add_pseudo_rx_group(port,
! &grp->lg_rx_groups[i]), ==, 0);
! }
!
if (aggr_port_notify_link(grp, port))
link_state_changed = B_TRUE;
/*
* Initialize the callback functions for this port.
*** 1732,1742 ****
* removed ring for transmission. Once the port has been
* detached, that port will not be used and
* aggr_find_tx_ring() will not return any rings
* belonging to it.
*/
! aggr_rem_pseudo_rx_group(port, &grp->lg_rx_group);
/* remove port from group */
rc = aggr_grp_rem_port(grp, port, &mac_addr_changed,
&link_state_changed);
ASSERT(rc == 0);
--- 1834,1845 ----
* removed ring for transmission. Once the port has been
* detached, that port will not be used and
* aggr_find_tx_ring() will not return any rings
* belonging to it.
*/
! for (i = 0; i < grp->lg_rx_group_count; i++)
! aggr_rem_pseudo_rx_group(port, &grp->lg_rx_groups[i]);
/* remove port from group */
rc = aggr_grp_rem_port(grp, port, &mac_addr_changed,
&link_state_changed);
ASSERT(rc == 0);
*** 1837,1847 ****
if (grp->lg_started)
aggr_port_stop(port);
(void) aggr_grp_detach_port(grp, port);
mac_perim_exit(pmph);
aggr_rem_pseudo_tx_group(port, &grp->lg_tx_group);
! aggr_rem_pseudo_rx_group(port, &grp->lg_rx_group);
aggr_port_delete(port);
port = cport;
}
mac_perim_exit(mph);
--- 1940,1951 ----
if (grp->lg_started)
aggr_port_stop(port);
(void) aggr_grp_detach_port(grp, port);
mac_perim_exit(pmph);
aggr_rem_pseudo_tx_group(port, &grp->lg_tx_group);
! for (uint_t i = 0; i < grp->lg_rx_group_count; i++)
! aggr_rem_pseudo_rx_group(port, &grp->lg_rx_groups[i]);
aggr_port_delete(port);
port = cport;
}
mac_perim_exit(mph);
*** 1856,1866 ****
aggr_grp_port_wait(grp);
VERIFY(mac_unregister(grp->lg_mh) == 0);
grp->lg_mh = NULL;
! list_destroy(&(grp->lg_rx_group.arg_vlans));
AGGR_GRP_REFRELE(grp);
return (0);
}
--- 1960,1972 ----
aggr_grp_port_wait(grp);
VERIFY(mac_unregister(grp->lg_mh) == 0);
grp->lg_mh = NULL;
! for (uint_t i = 0; i < MAX_GROUPS_PER_PORT; i++) {
! list_destroy(&(grp->lg_rx_groups[i].arg_vlans));
! }
AGGR_GRP_REFRELE(grp);
return (0);
}
*** 2222,2242 ****
return (!grp->lg_vlan);
case MAC_CAPAB_NO_ZCOPY:
return (!grp->lg_zcopy);
case MAC_CAPAB_RINGS: {
mac_capab_rings_t *cap_rings = cap_data;
if (cap_rings->mr_type == MAC_RING_TYPE_RX) {
cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
! cap_rings->mr_rnum = grp->lg_rx_group.arg_ring_cnt;
!
! /*
! * An aggregation advertises only one (pseudo) RX
! * group, which virtualizes the main/primary group of
! * the underlying devices.
! */
! cap_rings->mr_gnum = 1;
cap_rings->mr_gaddring = NULL;
cap_rings->mr_gremring = NULL;
} else {
cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
cap_rings->mr_rnum = grp->lg_tx_group.atg_ring_cnt;
--- 2328,2346 ----
return (!grp->lg_vlan);
case MAC_CAPAB_NO_ZCOPY:
return (!grp->lg_zcopy);
case MAC_CAPAB_RINGS: {
mac_capab_rings_t *cap_rings = cap_data;
+ uint_t ring_cnt = 0;
+ for (uint_t i = 0; i < grp->lg_rx_group_count; i++)
+ ring_cnt += grp->lg_rx_groups[i].arg_ring_cnt;
+
if (cap_rings->mr_type == MAC_RING_TYPE_RX) {
cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
! cap_rings->mr_rnum = ring_cnt;
! cap_rings->mr_gnum = grp->lg_rx_group_count;
cap_rings->mr_gaddring = NULL;
cap_rings->mr_gremring = NULL;
} else {
cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
cap_rings->mr_rnum = grp->lg_tx_group.atg_ring_cnt;
*** 2271,2286 ****
static void
aggr_fill_group(void *arg, mac_ring_type_t rtype, const int index,
mac_group_info_t *infop, mac_group_handle_t gh)
{
aggr_grp_t *grp = arg;
- aggr_pseudo_rx_group_t *rx_group;
- aggr_pseudo_tx_group_t *tx_group;
- ASSERT(index == 0);
if (rtype == MAC_RING_TYPE_RX) {
! rx_group = &grp->lg_rx_group;
rx_group->arg_gh = gh;
rx_group->arg_grp = grp;
infop->mgi_driver = (mac_group_driver_t)rx_group;
infop->mgi_start = NULL;
--- 2375,2388 ----
static void
aggr_fill_group(void *arg, mac_ring_type_t rtype, const int index,
mac_group_info_t *infop, mac_group_handle_t gh)
{
aggr_grp_t *grp = arg;
if (rtype == MAC_RING_TYPE_RX) {
! aggr_pseudo_rx_group_t *rx_group = &grp->lg_rx_groups[index];
!
rx_group->arg_gh = gh;
rx_group->arg_grp = grp;
infop->mgi_driver = (mac_group_driver_t)rx_group;
infop->mgi_start = NULL;
*** 2295,2305 ****
* program and when it doesn't.
*/
infop->mgi_addvlan = aggr_addvlan;
infop->mgi_remvlan = aggr_remvlan;
} else {
! tx_group = &grp->lg_tx_group;
tx_group->atg_gh = gh;
}
}
/*
--- 2397,2409 ----
* program and when it doesn't.
*/
infop->mgi_addvlan = aggr_addvlan;
infop->mgi_remvlan = aggr_remvlan;
} else {
! aggr_pseudo_tx_group_t *tx_group = &grp->lg_tx_group;
!
! ASSERT3S(index, ==, 0);
tx_group->atg_gh = gh;
}
}
/*
*** 2311,2327 ****
{
aggr_grp_t *grp = arg;
switch (rtype) {
case MAC_RING_TYPE_RX: {
! aggr_pseudo_rx_group_t *rx_group = &grp->lg_rx_group;
aggr_pseudo_rx_ring_t *rx_ring;
mac_intr_t aggr_mac_intr;
! ASSERT(rg_index == 0);
!
! ASSERT((index >= 0) && (index < rx_group->arg_ring_cnt));
rx_ring = rx_group->arg_rings + index;
rx_ring->arr_rh = rh;
/*
* Entrypoint to enable interrupt (disable poll) and
--- 2415,2431 ----
{
aggr_grp_t *grp = arg;
switch (rtype) {
case MAC_RING_TYPE_RX: {
! aggr_pseudo_rx_group_t *rx_group;
aggr_pseudo_rx_ring_t *rx_ring;
mac_intr_t aggr_mac_intr;
! rx_group = &grp->lg_rx_groups[rg_index];
! ASSERT3S(index, >=, 0);
! ASSERT3S(index, <, rx_group->arg_ring_cnt);
rx_ring = rx_group->arg_rings + index;
rx_ring->arr_rh = rh;
/*
* Entrypoint to enable interrupt (disable poll) and
*** 2331,2342 ****
aggr_mac_intr.mi_enable = aggr_pseudo_enable_intr;
aggr_mac_intr.mi_disable = aggr_pseudo_disable_intr;
aggr_mac_intr.mi_ddi_handle = NULL;
infop->mri_driver = (mac_ring_driver_t)rx_ring;
! infop->mri_start = aggr_pseudo_start_ring;
! infop->mri_stop = NULL;
infop->mri_intr = aggr_mac_intr;
infop->mri_poll = aggr_rx_poll;
infop->mri_stat = aggr_rx_ring_stat;
--- 2435,2446 ----
aggr_mac_intr.mi_enable = aggr_pseudo_enable_intr;
aggr_mac_intr.mi_disable = aggr_pseudo_disable_intr;
aggr_mac_intr.mi_ddi_handle = NULL;
infop->mri_driver = (mac_ring_driver_t)rx_ring;
! infop->mri_start = aggr_pseudo_start_rx_ring;
! infop->mri_stop = aggr_pseudo_stop_rx_ring;
infop->mri_intr = aggr_mac_intr;
infop->mri_poll = aggr_rx_poll;
infop->mri_stat = aggr_rx_ring_stat;
*** 2419,2428 ****
--- 2523,2533 ----
aggr_unicst_addr_t *addr, **pprev;
aggr_grp_t *grp = rx_group->arg_grp;
aggr_port_t *port, *p;
mac_perim_handle_t mph;
int err = 0;
+ uint_t idx = rx_group->arg_index;
mac_perim_enter_by_mh(grp->lg_mh, &mph);
if (bcmp(mac_addr, grp->lg_addr, ETHERADDRL) == 0) {
mac_perim_exit(mph);
*** 2445,2460 ****
bcopy(mac_addr, addr->aua_addr, ETHERADDRL);
addr->aua_next = NULL;
*pprev = addr;
for (port = grp->lg_ports; port != NULL; port = port->lp_next)
! if ((err = aggr_port_addmac(port, mac_addr)) != 0)
break;
if (err != 0) {
for (p = grp->lg_ports; p != port; p = p->lp_next)
! aggr_port_remmac(p, mac_addr);
*pprev = NULL;
kmem_free(addr, sizeof (aggr_unicst_addr_t));
}
--- 2550,2565 ----
bcopy(mac_addr, addr->aua_addr, ETHERADDRL);
addr->aua_next = NULL;
*pprev = addr;
for (port = grp->lg_ports; port != NULL; port = port->lp_next)
! if ((err = aggr_port_addmac(port, idx, mac_addr)) != 0)
break;
if (err != 0) {
for (p = grp->lg_ports; p != port; p = p->lp_next)
! aggr_port_remmac(p, idx, mac_addr);
*pprev = NULL;
kmem_free(addr, sizeof (aggr_unicst_addr_t));
}
*** 2495,2505 ****
mac_perim_exit(mph);
return (EINVAL);
}
for (port = grp->lg_ports; port != NULL; port = port->lp_next)
! aggr_port_remmac(port, mac_addr);
*pprev = addr->aua_next;
kmem_free(addr, sizeof (aggr_unicst_addr_t));
mac_perim_exit(mph);
--- 2600,2610 ----
mac_perim_exit(mph);
return (EINVAL);
}
for (port = grp->lg_ports; port != NULL; port = port->lp_next)
! aggr_port_remmac(port, rx_group->arg_index, mac_addr);
*pprev = addr->aua_next;
kmem_free(addr, sizeof (aggr_unicst_addr_t));
mac_perim_exit(mph);
*** 2537,2546 ****
--- 2642,2652 ----
aggr_grp_t *aggr = rx_group->arg_grp;
aggr_port_t *port, *p;
mac_perim_handle_t mph;
int err = 0;
aggr_vlan_t *avp = NULL;
+ uint_t idx = rx_group->arg_index;
mac_perim_enter_by_mh(aggr->lg_mh, &mph);
if (vid == MAC_VLAN_UNTAGGED) {
/*
*** 2566,2576 ****
avp->av_vid = vid;
avp->av_refs = 1;
update_ports:
for (port = aggr->lg_ports; port != NULL; port = port->lp_next)
! if ((err = aggr_port_addvlan(port, vid)) != 0)
break;
if (err != 0) {
/*
* If any of these calls fail then we are in a
--- 2672,2682 ----
avp->av_vid = vid;
avp->av_refs = 1;
update_ports:
for (port = aggr->lg_ports; port != NULL; port = port->lp_next)
! if ((err = aggr_port_addvlan(port, idx, vid)) != 0)
break;
if (err != 0) {
/*
* If any of these calls fail then we are in a
*** 2579,2589 ****
* take in this scenario to rectify the situation.
*/
for (p = aggr->lg_ports; p != port; p = p->lp_next) {
int err2;
! if ((err2 = aggr_port_remvlan(p, vid)) != 0) {
cmn_err(CE_WARN, "Failed to remove VLAN %u"
" from port %s: errno %d.", vid,
mac_client_name(p->lp_mch), err2);
}
--- 2685,2695 ----
* take in this scenario to rectify the situation.
*/
for (p = aggr->lg_ports; p != port; p = p->lp_next) {
int err2;
! if ((err2 = aggr_port_remvlan(p, idx, vid)) != 0) {
cmn_err(CE_WARN, "Failed to remove VLAN %u"
" from port %s: errno %d.", vid,
mac_client_name(p->lp_mch), err2);
}
*** 2616,2625 ****
--- 2722,2732 ----
aggr_grp_t *aggr = rx_group->arg_grp;
aggr_port_t *port, *p;
mac_perim_handle_t mph;
int err = 0;
aggr_vlan_t *avp = NULL;
+ uint_t idx = rx_group->arg_index;
mac_perim_enter_by_mh(aggr->lg_mh, &mph);
/*
* See the comment in aggr_addvlan().
*** 2646,2656 ****
if (avp->av_refs > 0)
goto done;
update_ports:
for (port = aggr->lg_ports; port != NULL; port = port->lp_next)
! if ((err = aggr_port_remvlan(port, vid)) != 0)
break;
/*
* See the comment in aggr_addvlan() for justification of the
* use of VERIFY here.
--- 2753,2763 ----
if (avp->av_refs > 0)
goto done;
update_ports:
for (port = aggr->lg_ports; port != NULL; port = port->lp_next)
! if ((err = aggr_port_remvlan(port, idx, vid)) != 0)
break;
/*
* See the comment in aggr_addvlan() for justification of the
* use of VERIFY here.
*** 2657,2667 ****
*/
if (err != 0) {
for (p = aggr->lg_ports; p != port; p = p->lp_next) {
int err2;
! if ((err2 = aggr_port_addvlan(p, vid)) != 0) {
cmn_err(CE_WARN, "Failed to add VLAN %u"
" to port %s: errno %d.", vid,
mac_client_name(p->lp_mch), err2);
}
}
--- 2764,2774 ----
*/
if (err != 0) {
for (p = aggr->lg_ports; p != port; p = p->lp_next) {
int err2;
! if ((err2 = aggr_port_addvlan(p, idx, vid)) != 0) {
cmn_err(CE_WARN, "Failed to add VLAN %u"
" to port %s: errno %d.", vid,
mac_client_name(p->lp_mch), err2);
}
}