Print this page
11490 SRS ring polling disabled for VLANs
11491 Want DLS bypass for VLAN traffic
11492 add VLVF bypass to ixgbe core
2869 duplicate packets with vnics over aggrs
11489 DLS stat delete and aggr kstat can deadlock
Portions contributed by: Theo Schlossnagle <jesus@omniti.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
@@ -19,11 +19,11 @@
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright 2018 Joyent, Inc.
* Copyright 2017 RackTop Systems.
*/
/*
* - General Introduction:
@@ -863,13 +863,16 @@
* regenerated because our mac address has changed.
*/
mac_protect_update_mac_token(mcip);
/*
- * A MAC client could have one MAC address but multiple
- * VLANs. In that case update the flow entries corresponding
- * to all VLANs of the MAC client.
+ * When there are multiple VLANs sharing the same MAC address,
+ * each gets its own MAC client, except when running on sun4v
+ * vsw. In that case the mci_flent_list is used to place
+ * multiple VLAN flows on one MAC client. If we ever get rid
+ * of vsw then this code can go, but until then we need to
+ * update all flow entries.
*/
for (flent = mcip->mci_flent_list; flent != NULL;
flent = flent->fe_client_next) {
mac_flow_get_desc(flent, &flow_desc);
if (!(flent->fe_type & FLOW_PRIMARY_MAC ||
@@ -1023,11 +1026,11 @@
if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) {
i_mac_perim_exit(mip);
return (0);
}
- if (mac_find_macaddr(mip, (uint8_t *)addr) != 0) {
+ if (mac_find_macaddr(mip, (uint8_t *)addr) != NULL) {
i_mac_perim_exit(mip);
return (EBUSY);
}
map = mac_find_macaddr(mip, mip->mi_addr);
@@ -1038,13 +1041,13 @@
*/
if (mip->mi_state_flags & MIS_IS_AGGR) {
mac_capab_aggr_t aggr_cap;
/*
- * If the mac is an aggregation, other than the unicast
+ * If the MAC is an aggregation, other than the unicast
* addresses programming, aggr must be informed about this
- * primary unicst address change to change its mac address
+ * primary unicst address change to change its MAC address
* policy to be user-specified.
*/
ASSERT(map->ma_type == MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED);
VERIFY(i_mac_capab_get(mh, MAC_CAPAB_AGGR, &aggr_cap));
err = aggr_cap.mca_unicst(mip->mi_driver, addr);
@@ -1372,11 +1375,11 @@
if ((flags & MAC_OPEN_FLAGS_IS_AGGR_PORT) != 0)
mcip->mci_state_flags |= MCIS_IS_AGGR_PORT;
if (mip->mi_state_flags & MIS_IS_AGGR)
- mcip->mci_state_flags |= MCIS_IS_AGGR;
+ mcip->mci_state_flags |= MCIS_IS_AGGR_CLIENT;
if ((flags & MAC_OPEN_FLAGS_USE_DATALINK_NAME) != 0) {
datalink_id_t linkid;
ASSERT(name == NULL);
@@ -1537,11 +1540,12 @@
mcip->mci_tx_flag = 0;
kmem_cache_free(mac_client_impl_cache, mch);
}
/*
- * Set the rx bypass receive callback.
+ * Set the Rx bypass receive callback and return B_TRUE. Return
+ * B_FALSE if it's not possible to enable bypass.
*/
boolean_t
mac_rx_bypass_set(mac_client_handle_t mch, mac_direct_rx_t rx_fn, void *arg1)
{
mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
@@ -1548,15 +1552,15 @@
mac_impl_t *mip = mcip->mci_mip;
ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
/*
- * If the mac_client is a VLAN, we should not do DLS bypass and
- * instead let the packets come up via mac_rx_deliver so the vlan
- * header can be stripped.
+ * If the client has more than one VLAN then process packets
+ * through DLS. This should happen only when sun4v vsw is on
+ * the scene.
*/
- if (mcip->mci_nvids > 0)
+ if (mcip->mci_nvids > 1)
return (B_FALSE);
/*
* These are not accessed directly in the data path, and hence
* don't need any protection
@@ -1606,12 +1610,12 @@
mcip->mci_rx_arg = arg;
mac_rx_client_restart(mch);
i_mac_perim_exit(mip);
/*
- * If we're changing the rx function on the primary mac of a vnic,
- * make sure any secondary macs on the vnic are updated as well.
+ * If we're changing the Rx function on the primary MAC of a VNIC,
+ * make sure any secondary addresses on the VNIC are updated as well.
*/
if (umip != NULL) {
ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0);
mac_vnic_secondary_update(umip);
}
@@ -1785,10 +1789,18 @@
*/
MAC_RX_GRP_RELEASED(mip);
}
/* Let check if we can give this an excl group */
} else if (group == defgrp) {
+ /*
+ * If multiple clients share an
+ * address then they must stay on the
+ * default group.
+ */
+ if (mac_check_macaddr_shared(mcip->mci_unicast))
+ return (0);
+
ngrp = mac_reserve_rx_group(mcip, mac_addr,
B_TRUE);
/* Couldn't give it a group, that's fine */
if (ngrp == NULL)
return (0);
@@ -1807,10 +1819,20 @@
*/
return (0);
}
if (group == defgrp && ((mrp->mrp_nrxrings > 0) || unspec)) {
+ /*
+ * We are requesting Rx rings. Try to reserve
+ * a non-default group.
+ *
+ * If multiple clients share an address then
+ * they must stay on the default group.
+ */
+ if (mac_check_macaddr_shared(mcip->mci_unicast))
+ return (EINVAL);
+
ngrp = mac_reserve_rx_group(mcip, mac_addr, B_TRUE);
if (ngrp == NULL)
return (ENOSPC);
/* Switch to H/W */
@@ -2164,14 +2186,14 @@
flent_flags = FLOW_PRIMARY_MAC;
else
flent_flags = FLOW_VNIC_MAC;
/*
- * For the first flow we use the mac client's name - mci_name, for
- * subsequent ones we just create a name with the vid. This is
+ * For the first flow we use the MAC client's name - mci_name, for
+ * subsequent ones we just create a name with the VID. This is
* so that we can add these flows to the same flow table. This is
- * fine as the flow name (except for the one with the mac client's
+ * fine as the flow name (except for the one with the MAC client's
* name) is not visible. When the first flow is removed, we just replace
* its fdesc with another from the list, so we will still retain the
* flent with the MAC client's flow name.
*/
if (first_flow) {
@@ -2325,10 +2347,11 @@
goto done_setup;
/*
* The unicast MAC address must have been added successfully.
*/
ASSERT(mcip->mci_unicast != NULL);
+
/*
* Push down the sub-flows that were defined on this link
* hitherto. The flows are added to the active flow table
* and SRS, softrings etc. are created as needed.
*/
@@ -2336,19 +2359,27 @@
} else {
mac_address_t *map = mcip->mci_unicast;
ASSERT(!no_unicast);
/*
- * A unicast flow already exists for that MAC client,
- * this flow must be the same mac address but with
- * different VID. It has been checked by mac_addr_in_use().
+ * A unicast flow already exists for that MAC client
+ * so this flow must be the same MAC address but with
+ * a different VID. It has been checked by
+ * mac_addr_in_use().
*
- * We will use the SRS etc. from the mci_flent. Note that
- * We don't need to create kstat for this as except for
- * the fdesc, everything will be used from in the 1st flent.
+ * We will use the SRS etc. from the initial
+ * mci_flent. We don't need to create a kstat for
+ * this, as except for the fdesc, everything will be
+ * used from the first flent.
+ *
+ * The only time we should see multiple flents on the
+ * same MAC client is on the sun4v vsw. If we removed
+ * that code we should be able to remove the entire
+ * notion of multiple flents on a MAC client (this
+ * doesn't affect sub/user flows because they have
+ * their own list unrelated to mci_flent_list).
*/
-
if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) {
err = EINVAL;
goto bail;
}
@@ -2473,12 +2504,16 @@
boolean_t passive_client = B_FALSE;
mac_unicast_impl_t *muip;
boolean_t is_vnic_primary =
(flags & MAC_UNICAST_VNIC_PRIMARY);
- /* when VID is non-zero, the underlying MAC can not be VNIC */
- ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != 0)));
+ /*
+ * When the VID is non-zero the underlying MAC cannot be a
+ * VNIC. I.e., dladm create-vlan cannot take a VNIC as
+ * argument, only the primary MAC client.
+ */
+ ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != VLAN_ID_NONE)));
/*
* Can't unicast add if the client asked only for minimal datapath
* setup.
*/
@@ -2487,22 +2522,23 @@
/*
* Check for an attempted use of the current Port VLAN ID, if enabled.
* No client may use it.
*/
- if (mip->mi_pvid != 0 && vid == mip->mi_pvid)
+ if (mip->mi_pvid != VLAN_ID_NONE && vid == mip->mi_pvid)
return (EBUSY);
/*
* Check whether it's the primary client and flag it.
*/
- if (!(mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && vid == 0)
+ if (!(mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary &&
+ vid == VLAN_ID_NONE)
mcip->mci_flags |= MAC_CLIENT_FLAGS_PRIMARY;
/*
* is_vnic_primary is true when we come here as a VLAN VNIC
- * which uses the primary mac client's address but with a non-zero
+ * which uses the primary MAC client's address but with a non-zero
* VID. In this case the MAC address is not specified by an upper
* MAC client.
*/
if ((mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary &&
!is_vnic_primary) {
@@ -2550,11 +2586,11 @@
mcip->mci_flags |= MAC_CLIENT_FLAGS_VNIC_PRIMARY;
/*
* Create a handle for vid 0.
*/
- ASSERT(vid == 0);
+ ASSERT(vid == VLAN_ID_NONE);
muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP);
muip->mui_vid = vid;
*mah = (mac_unicast_handle_t)muip;
/*
* This will be used by the caller to defer setting the
@@ -2570,11 +2606,13 @@
i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_ANCHOR_VNIC, NULL)) {
return (ENXIO);
}
/*
- * If this is a VNIC/VLAN, disable softmac fast-path.
+ * If this is a VNIC/VLAN, disable softmac fast-path. This is
+ * only relevant to legacy devices which use softmac to
+ * interface with GLDv3.
*/
if (mcip->mci_state_flags & MCIS_IS_VNIC) {
err = mac_fastpath_disable((mac_handle_t)mip);
if (err != 0)
return (err);
@@ -2618,13 +2656,15 @@
*/
mac_get_resources((mac_handle_t)mip, mrp);
(void) mac_client_set_resources(mch, mrp);
} else if (mcip->mci_state_flags & MCIS_IS_VNIC) {
/*
- * This is a primary VLAN client, we don't support
- * specifying rings property for this as it inherits the
- * rings property from its MAC.
+ * This is a VLAN client sharing the address of the
+ * primary MAC client; i.e., one created via dladm
+ * create-vlan. We don't support specifying ring
+ * properties for this type of client as it inherits
+ * these from the primary MAC client.
*/
if (is_vnic_primary) {
mac_resource_props_t *vmrp;
vmrp = MCIP_RESOURCE_PROPS(mcip);
@@ -2982,18 +3022,18 @@
uint16_t mui_vid;
i_mac_perim_enter(mip);
if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) {
/*
- * Called made by the upper MAC client of a VNIC.
+ * Call made by the upper MAC client of a VNIC.
* There's nothing much to do, the unicast address will
* be removed by the VNIC driver when the VNIC is deleted,
* but let's ensure that all our transmit is done before
* the client does a mac_client_stop lest it trigger an
* assert in the driver.
*/
- ASSERT(muip->mui_vid == 0);
+ ASSERT(muip->mui_vid == VLAN_ID_NONE);
mac_tx_client_flush(mcip);
if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) {
mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY;
@@ -3053,10 +3093,11 @@
kmem_free(muip, sizeof (mac_unicast_impl_t));
i_mac_perim_exit(mip);
return (0);
}
+
/*
* Remove the VID from the list of client's VIDs.
*/
pre = mcip->mci_unicast_list;
if (muip == pre) {
@@ -3079,11 +3120,11 @@
* not associated with its own separate set of SRS and rings,
* and these constructs are still needed for the remaining
* flows.
*/
flent = mac_client_get_flow(mcip, muip);
- ASSERT(flent != NULL);
+ VERIFY3P(flent, !=, NULL);
/*
* The first one is disappearing, need to make sure
* we replace it with another from the list of
* shared clients.
@@ -3107,10 +3148,11 @@
muip->mui_vid);
}
FLOW_FINAL_REFRELE(flent);
ASSERT(!(mcip->mci_state_flags & MCIS_EXCLUSIVE));
+
/*
* Enable fastpath if this is a VNIC or a VLAN.
*/
if (mcip->mci_state_flags & MCIS_IS_VNIC)
mac_fastpath_enable((mac_handle_t)mip);
@@ -3120,11 +3162,12 @@
}
mui_vid = muip->mui_vid;
mac_client_datapath_teardown(mch, muip, flent);
- if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && mui_vid == 0) {
+ if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) &&
+ mui_vid == VLAN_ID_NONE) {
mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY;
} else {
i_mac_perim_exit(mip);
return (0);
}