aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/ix.424
-rw-r--r--sys/dev/ixgbe/if_ix.c216
-rw-r--r--sys/dev/ixgbe/if_sriov.c222
-rw-r--r--sys/dev/ixgbe/ix_txrx.c18
-rw-r--r--sys/dev/ixgbe/ixgbe.h6
5 files changed, 392 insertions, 94 deletions
diff --git a/share/man/man4/ix.4 b/share/man/man4/ix.4
index 39ed49aa8dfc..fb1d1032c0f1 100644
--- a/share/man/man4/ix.4
+++ b/share/man/man4/ix.4
@@ -29,7 +29,7 @@
.\"
.\" * Other names and brands may be claimed as the property of others.
.\"
-.Dd November 10, 2025
+.Dd August 6, 2026
.Dt IX 4
.Os
.Sh NAME
@@ -70,6 +70,27 @@ The maximum MTU size for Jumbo Frames is 9710.
This driver version supports VLANs.
For information on enabling VLANs, see
.Xr ifconfig 8 .
+.Sh SR-IOV
+The driver-specific
+.Va vlan
+parameter in
+.Xr iovctl.conf 5
+accepts a VLAN identifier from 1 through 4095 or the keyword
+.Dq trunk ,
+which is the default.
+A numeric VLAN configures an access VF: the PF inserts the VLAN tag on
+transmit and strips it on receive.
+The stripped administrative tag is not presented to the VF network stack as
+.Dv M_VLANTAG ,
+so received packets are delivered directly through the VF interface.
+With
+.Dq trunk ,
+the VF may add and remove individual VLAN memberships; tags for VLANs
+registered by the VF are presented normally to its network stack.
+.Pp
+VLAN filtering remains enabled in the hardware while SR-IOV is active so that
+the PF can enforce VLAN ownership for each VF pool, including when hardware
+VLAN filtering has been disabled on the PF interface.
.Sh HARDWARE
The
.Nm
@@ -220,6 +241,7 @@ issue to
.Xr ng_ether 4 ,
.Xr polling 4 ,
.Xr vlan 4 ,
+.Xr iovctl.conf 5 ,
.Xr ifconfig 8 ,
.Xr sysctl 8
.Sh HISTORY
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index 6f8c453c0690..6a9bf6089a97 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -237,7 +237,6 @@ static void ixgbe_add_hw_stats(struct ixgbe_softc *);
static int ixgbe_set_flowcntl(struct ixgbe_softc *, int);
static int ixgbe_set_advertise(struct ixgbe_softc *, int);
static int ixgbe_get_default_advertise(struct ixgbe_softc *);
-static void ixgbe_setup_vlan_hw_support(if_ctx_t);
static void ixgbe_config_gpie(struct ixgbe_softc *);
static void ixgbe_config_delay_values(struct ixgbe_softc *);
@@ -2310,12 +2309,21 @@ static void
ixgbe_if_vlan_register(if_ctx_t ctx, u16 vtag)
{
struct ixgbe_softc *sc = iflib_get_softc(ctx);
- u16 index, bit;
+ bool present;
+ u16 index;
+ u32 mask;
index = (vtag >> 5) & 0x7F;
- bit = vtag & 0x1F;
- sc->shadow_vfta[index] |= (1 << bit);
- ++sc->num_vlans;
+ mask = 1U << (vtag & 0x1F);
+ present = (sc->shadow_vfta[index] & mask) != 0;
+ sc->shadow_vfta[index] |= mask;
+ if (!present)
+ ++sc->num_vlans;
+#ifdef PCI_IOV
+ if ((sc->feat_en & IXGBE_FEATURE_SRIOV) != 0 &&
+ sc->iov_vfta_valid && !sc->iov_vlan_promisc)
+ (void)ixgbe_set_vfta(&sc->hw, vtag, sc->pool, true, true);
+#endif
ixgbe_setup_vlan_hw_support(ctx);
} /* ixgbe_if_vlan_register */
@@ -2328,96 +2336,167 @@ static void
ixgbe_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
{
struct ixgbe_softc *sc = iflib_get_softc(ctx);
- u16 index, bit;
+ bool present;
+ u16 index;
+ u32 mask;
index = (vtag >> 5) & 0x7F;
- bit = vtag & 0x1F;
- sc->shadow_vfta[index] &= ~(1 << bit);
- --sc->num_vlans;
- /* Re-init to load the changes */
+ mask = 1U << (vtag & 0x1F);
+ present = (sc->shadow_vfta[index] & mask) != 0;
+ sc->shadow_vfta[index] &= ~mask;
+ if (present)
+ --sc->num_vlans;
+#ifdef PCI_IOV
+ if ((sc->feat_en & IXGBE_FEATURE_SRIOV) != 0 &&
+ sc->iov_vfta_valid && !sc->iov_vlan_promisc)
+ (void)ixgbe_set_vfta(&sc->hw, vtag, sc->pool, false, true);
+#endif
ixgbe_setup_vlan_hw_support(ctx);
} /* ixgbe_if_vlan_unregister */
+#ifdef PCI_IOV
+static bool
+ixgbe_iov_pf_owns_vlan(const struct ixgbe_softc *sc, u16 vlan)
+{
+
+ return ((sc->shadow_vfta[vlan >> 5] &
+ (1U << (vlan & 0x1f))) != 0);
+}
+
+/*
+ * start_hw clears both VFTA and VLVF. Reconstruct the shared tables from
+ * PF and VF desired state after every reset or filtering-mode transition.
+ * Allocate VF entries first so PF-only VLANs cannot exhaust VLVF.
+ */
+static void
+ixgbe_iov_vlan_rebuild(struct ixgbe_softc *sc, bool promisc)
+{
+ struct ixgbe_hw *hw;
+ struct ixgbe_vf *vf;
+ u32 vfta[IXGBE_VFTA_SIZE];
+ u32 bits, vlan, vlvf;
+ int bit, failures, i, word;
+
+ hw = &sc->hw;
+ bcopy(sc->shadow_vfta, vfta, sizeof(vfta));
+ (void)ixgbe_clear_vfta(hw);
+ failures = 0;
+ for (i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if ((vf->flags & IXGBE_VF_ACTIVE) == 0)
+ continue;
+ for (word = 0; word < IXGBE_VFTA_SIZE; word++) {
+ bits = vf->vlans[word];
+ while (bits != 0) {
+ bit = ffs(bits) - 1;
+ vlan = word * 32 + bit;
+ if (ixgbe_set_vfta(hw, vlan, vf->pool, true,
+ false) == IXGBE_SUCCESS)
+ vfta[word] |= 1U << bit;
+ else
+ failures++;
+ bits &= ~(1U << bit);
+ }
+ }
+ }
+
+ /* Add the PF to shared entries, or every entry in promiscuous mode. */
+ for (i = 1; i < IXGBE_VLVF_ENTRIES; i++) {
+ vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(i));
+ if ((vlvf & IXGBE_VLVF_VIEN) == 0)
+ continue;
+ vlan = vlvf & IXGBE_VLVF_VLANID_MASK;
+ if (promisc || ixgbe_iov_pf_owns_vlan(sc, vlan))
+ (void)ixgbe_set_vfta(hw, vlan, sc->pool, true, true);
+ vfta[vlan >> 5] |= 1U << (vlan & 0x1f);
+ }
+ if (promisc)
+ for (i = 0; i < IXGBE_VFTA_SIZE; i++)
+ vfta[i] = UINT32_MAX;
+ for (i = 0; i < IXGBE_VFTA_SIZE; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), vfta[i]);
+ if (failures != 0)
+ device_printf(sc->dev,
+ "VF VLAN restore failed for %d memberships\n", failures);
+}
+
+static void
+ixgbe_iov_vlan_sync(struct ixgbe_softc *sc, bool promisc)
+{
+
+ if (sc->iov_vfta_valid && sc->iov_vlan_promisc == promisc)
+ return;
+ ixgbe_iov_vlan_rebuild(sc, promisc);
+ sc->iov_vlan_promisc = promisc;
+ sc->iov_vfta_valid = true;
+}
+#endif
+
/************************************************************************
* ixgbe_setup_vlan_hw_support
************************************************************************/
-static void
+void
ixgbe_setup_vlan_hw_support(if_ctx_t ctx)
{
if_t ifp = iflib_get_ifp(ctx);
struct ixgbe_softc *sc = iflib_get_softc(ctx);
struct ixgbe_hw *hw = &sc->hw;
struct rx_ring *rxr;
+ bool strip;
int i;
u32 ctrl;
-
- /*
- * We get here thru init_locked, meaning
- * a soft reset, this has already cleared
- * the VFTA and other state, so if there
- * have been no vlan's registered do nothing.
- */
- if (sc->num_vlans == 0 ||
- (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) == 0) {
- /* Clear the vlan hw flag */
- for (i = 0; i < sc->num_rx_queues; i++) {
- rxr = &sc->rx_queues[i].rxr;
- /* On 82599 the VLAN enable is per/queue in RXDCTL */
- if (hw->mac.type != ixgbe_mac_82598EB) {
- ctrl = IXGBE_READ_REG(hw,
- IXGBE_RXDCTL(rxr->me));
+ strip = sc->num_vlans != 0 &&
+ (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0;
+ for (i = 0; i < sc->num_rx_queues; i++) {
+ rxr = &sc->rx_queues[i].rxr;
+ /* On 82599 and newer VLAN stripping is per receive queue. */
+ if (hw->mac.type != ixgbe_mac_82598EB) {
+ ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me));
+ if (strip)
+ ctrl |= IXGBE_RXDCTL_VME;
+ else
ctrl &= ~IXGBE_RXDCTL_VME;
- IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me),
- ctrl);
- }
- rxr->vtag_strip = false;
+ IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl);
}
- ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
- /* Enable the Filter Table if enabled */
- ctrl |= IXGBE_VLNCTRL_CFIEN;
- ctrl &= ~IXGBE_VLNCTRL_VFE;
- if (hw->mac.type == ixgbe_mac_82598EB)
+ rxr->vtag_strip = strip;
+ }
+
+ ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ if (hw->mac.type == ixgbe_mac_82598EB) {
+ if (strip)
+ ctrl |= IXGBE_VLNCTRL_VME;
+ else
ctrl &= ~IXGBE_VLNCTRL_VME;
+ }
+
+#ifdef PCI_IOV
+ if ((sc->feat_en & IXGBE_FEATURE_SRIOV) != 0) {
+ /*
+ * VFE must remain enabled to enforce per-pool VLAN ownership.
+ */
+ ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ ctrl |= IXGBE_VLNCTRL_VFE;
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
+ ixgbe_iov_vlan_sync(sc,
+ (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0);
return;
}
+#endif
- /* Setup the queues for vlans */
- if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) {
- for (i = 0; i < sc->num_rx_queues; i++) {
- rxr = &sc->rx_queues[i].rxr;
- /* On 82599 the VLAN enable is per/queue in RXDCTL */
- if (hw->mac.type != ixgbe_mac_82598EB) {
- ctrl = IXGBE_READ_REG(hw,
- IXGBE_RXDCTL(rxr->me));
- ctrl |= IXGBE_RXDCTL_VME;
- IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me),
- ctrl);
- }
- rxr->vtag_strip = true;
- }
+ if (!strip ||
+ (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0) {
+ ctrl |= IXGBE_VLNCTRL_CFIEN;
+ ctrl &= ~IXGBE_VLNCTRL_VFE;
+ IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
+ return;
}
- if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
- return;
- /*
- * A soft reset zero's out the VFTA, so
- * we need to repopulate it now.
- */
+ /* A soft reset clears VFTA, so restore the PF's desired bitmap. */
for (i = 0; i < IXGBE_VFTA_SIZE; i++)
- if (sc->shadow_vfta[i] != 0)
- IXGBE_WRITE_REG(hw, IXGBE_VFTA(i),
- sc->shadow_vfta[i]);
-
- ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
- /* Enable the Filter Table if enabled */
- if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) {
- ctrl &= ~IXGBE_VLNCTRL_CFIEN;
- ctrl |= IXGBE_VLNCTRL_VFE;
- }
- if (hw->mac.type == ixgbe_mac_82598EB)
- ctrl |= IXGBE_VLNCTRL_VME;
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), sc->shadow_vfta[i]);
+ ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ ctrl |= IXGBE_VLNCTRL_VFE;
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl);
} /* ixgbe_setup_vlan_hw_support */
@@ -3828,6 +3907,7 @@ ixgbe_if_init(if_ctx_t ctx)
ixgbe_init_hw(hw);
sc->iov_mta_valid = false;
+ sc->iov_vfta_valid = false;
ixgbe_initialize_iov(sc);
diff --git a/sys/dev/ixgbe/if_sriov.c b/sys/dev/ixgbe/if_sriov.c
index 963f4392b2fd..318e0fe70759 100644
--- a/sys/dev/ixgbe/if_sriov.c
+++ b/sys/dev/ixgbe/if_sriov.c
@@ -36,6 +36,7 @@
#ifdef PCI_IOV
+#include <sys/iov.h>
#include <sys/ktr.h>
MALLOC_DEFINE(M_IXGBE_SRIOV, "ix_sriov", "ix SR-IOV allocations");
@@ -66,6 +67,8 @@ ixgbe_define_iov_schemas(device_t dev, int *error)
IOV_SCHEMA_HASDEFAULT, false);
pci_iov_schema_add_bool(vf_schema, "allow-promisc",
IOV_SCHEMA_HASDEFAULT, false);
+ pci_iov_schema_add_vlan(vf_schema, "vlan", IOV_SCHEMA_HASDEFAULT,
+ VF_VLAN_TRUNK);
*error = pci_iov_attach(dev, pf_schema, vf_schema);
if (*error != 0) {
device_printf(dev,
@@ -249,16 +252,105 @@ ixgbe_ping_all_vfs(struct ixgbe_softc *sc)
} /* ixgbe_ping_all_vfs */
+static bool
+ixgbe_pf_owns_vlan(struct ixgbe_softc *sc, uint16_t tag)
+{
+ if_t ifp;
+
+ ifp = iflib_get_ifp(sc->ctx);
+ if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
+ return (true);
+ return ((sc->shadow_vfta[tag >> 5] &
+ (1U << (tag & 0x1f))) != 0);
+}
+
+static bool
+ixgbe_vf_owns_vlan(const struct ixgbe_vf *vf, uint16_t tag)
+{
+
+ return ((vf->vlans[tag >> 5] & (1U << (tag & 0x1f))) != 0);
+}
+
static void
-ixgbe_vf_set_default_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf,
- uint16_t tag)
+ixgbe_vf_vlan_release_pf_only(struct ixgbe_softc *sc, uint16_t tag)
{
struct ixgbe_hw *hw;
- uint32_t vmolr, vmvir;
+ uint32_t bits[2];
+ s32 slot;
+
+ hw = &sc->hw;
+ slot = ixgbe_find_vlvf_slot(hw, tag, true);
+ if (slot <= 0)
+ return;
+ bits[0] = IXGBE_READ_REG(hw, IXGBE_VLVFB(slot * 2));
+ bits[1] = IXGBE_READ_REG(hw, IXGBE_VLVFB(slot * 2 + 1));
+ bits[sc->pool / 32] &= ~(1U << (sc->pool % 32));
+ if (bits[0] != 0 || bits[1] != 0)
+ return;
+
+ /* The VFTA bit still admits this VLAN to the PF's default pool. */
+ IXGBE_WRITE_REG(hw, IXGBE_VLVF(slot), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VLVFB(slot * 2), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_VLVFB(slot * 2 + 1), 0);
+}
+
+static s32
+ixgbe_vf_vlan_hw_update(struct ixgbe_softc *sc, struct ixgbe_vf *vf,
+ uint16_t tag, bool enable)
+{
+ struct ixgbe_hw *hw;
+ s32 error;
hw = &sc->hw;
+ if (!enable &&
+ ixgbe_find_vlvf_slot(hw, tag, true) < IXGBE_SUCCESS)
+ return (IXGBE_SUCCESS);
+ /*
+ * Allocate the VLVF entry with the PF first when it also owns this
+ * VLAN. This guarantees that adding the VF cannot hide the VLAN from
+ * the PF when the shared VFTA bit becomes pool-selective.
+ */
+ if (enable && ixgbe_pf_owns_vlan(sc, tag)) {
+ error = ixgbe_set_vfta(hw, tag, sc->pool, true, false);
+ if (error != IXGBE_SUCCESS)
+ return (error);
+ }
- vf->vlan_tag = tag;
+ error = ixgbe_set_vfta(hw, tag, vf->pool, enable, false);
+ if (error != IXGBE_SUCCESS)
+ return (error);
+
+ /* Free a PF-only VLVF slot without removing the PF's VFTA bit. */
+ if (!enable && ixgbe_pf_owns_vlan(sc, tag))
+ ixgbe_vf_vlan_release_pf_only(sc, tag);
+ return (IXGBE_SUCCESS);
+}
+
+static void
+ixgbe_vf_vlan_record(struct ixgbe_vf *vf, uint16_t tag, bool enable)
+{
+ u32 mask;
+
+ mask = 1U << (tag & 0x1f);
+ if (enable) {
+ vf->vlans[tag >> 5] |= mask;
+ vf->num_vlans++;
+ } else {
+ vf->vlans[tag >> 5] &= ~mask;
+ vf->num_vlans--;
+ }
+}
+
+static void
+ixgbe_vf_configure_default_vlan(struct ixgbe_softc *sc,
+ struct ixgbe_vf *vf)
+{
+ struct ixgbe_hw *hw;
+ uint32_t vmolr, vmvir;
+ uint16_t tag;
+
+ hw = &sc->hw;
+ tag = vf->default_vlan;
vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf->pool));
@@ -286,7 +378,45 @@ ixgbe_vf_set_default_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf,
}
IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf->pool), vmolr);
IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf->pool), vmvir);
-} /* ixgbe_vf_set_default_vlan */
+} /* ixgbe_vf_configure_default_vlan */
+
+static void
+ixgbe_vf_clear_vlans(struct ixgbe_softc *sc, struct ixgbe_vf *vf,
+ bool clear_hw)
+{
+ uint32_t bits;
+ int bit, index;
+
+ for (index = 0; index < IXGBE_VFTA_SIZE; index++) {
+ bits = vf->vlans[index];
+ while (bits != 0) {
+ bit = ffs(bits) - 1;
+ if (clear_hw)
+ (void)ixgbe_vf_vlan_hw_update(sc, vf,
+ index * 32 + bit, false);
+ bits &= ~(1U << bit);
+ }
+ }
+ bzero(vf->vlans, sizeof(vf->vlans));
+ vf->num_vlans = 0;
+}
+
+static s32
+ixgbe_vf_reset_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf,
+ bool clear_hw)
+{
+ s32 error;
+
+ ixgbe_vf_clear_vlans(sc, vf, clear_hw);
+ error = IXGBE_SUCCESS;
+ if (vf->default_vlan != 0) {
+ error = ixgbe_vf_vlan_hw_update(sc, vf, vf->default_vlan, true);
+ if (error == IXGBE_SUCCESS)
+ ixgbe_vf_vlan_record(vf, vf->default_vlan, true);
+ }
+ ixgbe_vf_configure_default_vlan(sc, vf);
+ return (error);
+}
static boolean_t
ixgbe_vf_frame_size_compatible(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
@@ -338,8 +468,13 @@ static void
ixgbe_process_vf_reset(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
bool rebuild_mta;
+ s32 error;
- ixgbe_vf_set_default_vlan(sc, vf, vf->default_vlan);
+ error = ixgbe_vf_reset_vlan(sc, vf, true);
+ if (error != IXGBE_SUCCESS)
+ device_printf(sc->dev,
+ "VF %u default VLAN restore failed: %d\n",
+ vf->pool, error);
rebuild_mta = vf->num_mc_hashes != 0;
vf->num_mc_hashes = 0;
@@ -497,26 +632,37 @@ ixgbe_vf_set_mc_addr(struct ixgbe_softc *sc, struct ixgbe_vf *vf, u32 *msg)
static void
ixgbe_vf_set_vlan(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg)
{
- struct ixgbe_hw *hw;
- int enable;
+ bool enable, present;
+ s32 error;
uint16_t tag;
- hw = &sc->hw;
- enable = IXGBE_VT_MSGINFO(msg[0]);
+ enable = IXGBE_VT_MSGINFO(msg[0]) != 0;
tag = msg[1] & IXGBE_VLVF_VLANID_MASK;
- if (!(vf->flags & IXGBE_VF_CAP_VLAN)) {
+ if (!(vf->flags & IXGBE_VF_CAP_VLAN) || vf->default_vlan != 0 ||
+ (msg[1] & ~IXGBE_VLVF_VLANID_MASK) != 0) {
ixgbe_send_vf_failure(sc, vf, msg[0]);
return;
}
/* It is illegal to enable vlan tag 0. */
- if (tag == 0 && enable != 0) {
+ if (tag == 0 && enable) {
ixgbe_send_vf_failure(sc, vf, msg[0]);
return;
}
- ixgbe_set_vfta(hw, tag, vf->pool, enable, false);
+ present = ixgbe_vf_owns_vlan(vf, tag);
+ if (enable == present) {
+ ixgbe_send_vf_success(sc, vf, msg[0]);
+ return;
+ }
+
+ error = ixgbe_vf_vlan_hw_update(sc, vf, tag, enable);
+ if (error != IXGBE_SUCCESS) {
+ ixgbe_send_vf_failure(sc, vf, msg[0]);
+ return;
+ }
+ ixgbe_vf_vlan_record(vf, tag, enable);
ixgbe_send_vf_success(sc, vf, msg[0]);
} /* ixgbe_vf_set_vlan */
@@ -811,25 +957,32 @@ ixgbe_if_iov_uninit(if_ctx_t ctx)
free(sc->vfs, M_IXGBE_SRIOV);
sc->vfs = NULL;
sc->feat_en &= ~IXGBE_FEATURE_SRIOV;
+ sc->iov_vfta_valid = false;
+ sc->iov_vlan_promisc = false;
+ (void)ixgbe_clear_vfta(hw);
+ ixgbe_setup_vlan_hw_support(ctx);
} /* ixgbe_if_iov_uninit */
-static void
+static s32
ixgbe_init_vf(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
{
struct ixgbe_hw *hw;
uint32_t vf_index, pfmbimr;
+ s32 error;
hw = &sc->hw;
if (!(vf->flags & IXGBE_VF_ACTIVE))
- return;
+ return (IXGBE_SUCCESS);
vf_index = IXGBE_VF_INDEX(vf->pool);
pfmbimr = IXGBE_READ_REG(hw, IXGBE_PFMBIMR(vf_index));
pfmbimr |= IXGBE_VF_BIT(vf->pool);
IXGBE_WRITE_REG(hw, IXGBE_PFMBIMR(vf_index), pfmbimr);
- ixgbe_vf_set_default_vlan(sc, vf, vf->vlan_tag);
+ error = ixgbe_vf_reset_vlan(sc, vf, false);
+ if (error != IXGBE_SUCCESS)
+ return (error);
vf->num_mc_hashes = 0;
bzero(vf->mc_hash, sizeof(vf->mc_hash));
@@ -843,6 +996,7 @@ ixgbe_init_vf(struct ixgbe_softc *sc, struct ixgbe_vf *vf)
ixgbe_vf_enable_receive(sc, vf);
ixgbe_send_vf_msg(&sc->hw, vf, IXGBE_PF_CONTROL_MSG);
+ return (IXGBE_SUCCESS);
} /* ixgbe_init_vf */
void
@@ -900,8 +1054,11 @@ ixgbe_initialize_iov(struct ixgbe_softc *sc)
vt_ctl |= (sc->pool << IXGBE_VT_CTL_POOL_SHIFT);
IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vt_ctl);
- for (i = 0; i < sc->num_vfs; i++)
- ixgbe_init_vf(sc, &sc->vfs[i]);
+ for (i = 0; i < sc->num_vfs; i++) {
+ if (ixgbe_init_vf(sc, &sc->vfs[i]) != IXGBE_SUCCESS)
+ device_printf(sc->dev,
+ "VF %d default VLAN restore failed\n", i);
+ }
} /* ixgbe_initialize_iov */
@@ -924,6 +1081,9 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config)
struct ixgbe_softc *sc;
struct ixgbe_vf *vf;
const void *mac;
+ uint64_t configured_vlan;
+ uint16_t vlan;
+ s32 error;
sc = iflib_get_softc(ctx);
@@ -931,11 +1091,23 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config)
vfnum, sc->num_vfs));
vf = &sc->vfs[vfnum];
- vf->pool= vfnum;
+ if (vf->flags & IXGBE_VF_ACTIVE)
+ return (EBUSY);
+
+ configured_vlan = nvlist_get_number(config, "vlan");
+ if (configured_vlan > VF_VLAN_TRUNK)
+ return (EINVAL);
+ vlan = configured_vlan;
+ if (vlan == 0)
+ return (ENOTSUP);
+ if (vlan == VF_VLAN_TRUNK)
+ vlan = 0;
+
+ vf->pool = vfnum;
/* RAR[0] is used by the PF so use vfnum + 1 for VF RAR. */
vf->rar_index = vfnum + 1;
- vf->default_vlan = 0;
+ vf->default_vlan = vlan;
vf->maximum_frame_size = ETHER_MAX_LEN;
ixgbe_update_max_frame(sc, vf->maximum_frame_size);
if (nvlist_get_bool(config, "mac-anti-spoof"))
@@ -952,10 +1124,18 @@ ixgbe_if_iov_vf_add(if_ctx_t ctx, u16 vfnum, const nvlist_t *config)
* we must allow the VF to choose one.
*/
vf->flags |= IXGBE_VF_CAP_MAC;
+ if (vf->default_vlan == 0)
+ vf->flags |= IXGBE_VF_CAP_VLAN;
vf->flags |= IXGBE_VF_ACTIVE;
- ixgbe_init_vf(sc, vf);
+ error = ixgbe_init_vf(sc, vf);
+ if (error != IXGBE_SUCCESS) {
+ vf->flags &= ~IXGBE_VF_ACTIVE;
+ vf->default_vlan = 0;
+ ixgbe_vf_clear_vlans(sc, vf, true);
+ return (ENOSPC);
+ }
return (0);
} /* ixgbe_if_iov_vf_add */
diff --git a/sys/dev/ixgbe/ix_txrx.c b/sys/dev/ixgbe/ix_txrx.c
index 3dda3270a2de..c95c3fc903ef 100644
--- a/sys/dev/ixgbe/ix_txrx.c
+++ b/sys/dev/ixgbe/ix_txrx.c
@@ -403,7 +403,7 @@ ixgbe_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
struct rx_ring *rxr = &que->rxr;
union ixgbe_adv_rx_desc *rxd;
- uint16_t pkt_info, len, cidx, i;
+ uint16_t pkt_info, len, cidx, i, vid, vtag;
uint32_t ptype;
uint32_t staterr = 0;
bool eop;
@@ -463,8 +463,20 @@ ixgbe_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri)
ri->iri_rsstype = M_HASHTYPE_OPAQUE_HASH;
}
if ((rxr->vtag_strip) && (staterr & IXGBE_RXD_STAT_VP)) {
- ri->iri_vtag = le16toh(rxd->wb.upper.vlan);
- ri->iri_flags |= M_VLANTAG;
+ vtag = le16toh(rxd->wb.upper.vlan);
+ vid = EVL_VLANOFTAG(vtag);
+ /*
+ * A PF-assigned port VLAN is stripped before a VF receives the
+ * frame, but it is not one of the VLANs registered by the VF.
+ * Do not expose that administrative tag to the VF's network
+ * stack. Locally registered trunk VLANs retain M_VLANTAG.
+ */
+ if ((sc->feat_en & IXGBE_FEATURE_VF) == 0 ||
+ (sc->shadow_vfta[vid >> 5] &
+ (1U << (vid & 0x1f))) != 0) {
+ ri->iri_vtag = vtag;
+ ri->iri_flags |= M_VLANTAG;
+ }
}
ri->iri_nfrags = i;
diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h
index ae246433348e..26513a0ba965 100644
--- a/sys/dev/ixgbe/ixgbe.h
+++ b/sys/dev/ixgbe/ixgbe.h
@@ -352,9 +352,10 @@ struct ixgbe_vf {
uint32_t flags;
uint8_t ether_addr[ETHER_ADDR_LEN];
uint16_t mc_hash[IXGBE_MAX_VF_MC];
+ uint32_t vlans[IXGBE_VFTA_SIZE];
uint16_t num_mc_hashes;
+ uint16_t num_vlans;
uint16_t default_vlan;
- uint16_t vlan_tag;
uint16_t api_ver;
};
@@ -442,6 +443,8 @@ struct ixgbe_softc {
int pool;
struct ixgbe_vf *vfs;
bool iov_mta_valid;
+ bool iov_vfta_valid;
+ bool iov_vlan_promisc;
/* Bypass */
struct ixgbe_bp_data bypass;
@@ -607,6 +610,7 @@ void ixgbe_free_transmit_structures(struct ixgbe_softc *);
int ixgbe_setup_receive_structures(struct ixgbe_softc *);
void ixgbe_free_receive_structures(struct ixgbe_softc *);
int ixgbe_get_regs(SYSCTL_HANDLER_ARGS);
+void ixgbe_setup_vlan_hw_support(if_ctx_t);
void ixgbe_add_fw_logging_tunables(struct ixgbe_softc *sc,
struct sysctl_oid *parent);