From: Anurag Mandal <anurag.mandal@intel.com>
To: dev@dpdk.org
Cc: bruce.richardson@intel.com, vladimir.medvedkin@intel.com,
Anurag Mandal <anurag.mandal@intel.com>
Subject: [PATCH v3] net/iavf: add support for QinQ strip
Date: Wed, 8 Apr 2026 19:59:47 +0000 [thread overview]
Message-ID: <20260408195947.51386-1-anurag.mandal@intel.com> (raw)
In-Reply-To: <20260216103710.195777-1-anurag.mandal@intel.com>
QinQ strip with VLAN TPID 0x88a8 & 0x8100 support was absent.
This patch adds support for QinQ strip with both Outer VLAN
TPIDs 0x88a8 (802.1ad) & 0x8100 (802.1Q).
VLAN Extend should be enabled for the same and Outer VLAN
TPID should be set properly.
1. Tested QinQ stripping with TPIDs 0x88a8 as well as 0x8100.
2. Tested Double VLAN stripping i.e. QinQ (802.1ad/802.1Q) &
VLAN (802.1Q) stripping simultaneously.
3. Tested Single VLAN (802.1Q) stripping.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
V3: Rebased onto next-net-intel-for-next-net
V2: Addressed Coding Style Warnings
doc/guides/nics/intel_vf.rst | 31 ++++++++++++++
drivers/net/intel/iavf/iavf.h | 2 +
drivers/net/intel/iavf/iavf_ethdev.c | 46 +++++++++++++++++++++
drivers/net/intel/iavf/iavf_vchnl.c | 61 ++++++++++++++++++++++++++--
4 files changed, 137 insertions(+), 3 deletions(-)
diff --git a/doc/guides/nics/intel_vf.rst b/doc/guides/nics/intel_vf.rst
index 5fa2ddc9ea..dfff69b982 100644
--- a/doc/guides/nics/intel_vf.rst
+++ b/doc/guides/nics/intel_vf.rst
@@ -771,3 +771,34 @@ the VLAN header tag length will be automatically added to MTU when configuring q
As a consequence, when attempting to configure a VF port with MTU that,
together with a VLAN tag header, exceeds maximum supported MTU,
port configuration will fail if kernel driver has configured VLAN filtering on that VF.
+
+QinQ strip
+~~~~~~~~~~
+
+QinQ TPID is set as 0x8100 IEEE 802.1Q by default.
+For QinQ strip with TPID 0x88A8 IEEE 802.1ad,
+extend VLAN is enabled and VLAN outer TPID is set to 0x88A8.
+VLAN filter steps can be added before or after.
+
+To start ``testpmd``, and enable QinQ strip for TPID 0x88A8 on port 0:
+
+.. code-block:: console
+
+ ./<build_dir>/app/dpdk-testpmd -l 0-15 -- -i --forward-mode=mac
+ ...
+
+ testpmd> vlan set extend on 0
+ testpmd> vlan set outer tpid 0x88A8 0
+ testpmd> vlan set qinq_strip on 0
+
+For QinQ strip with TPID 0x8100, extend VLAN is enabled only.
+
+To start ``testpmd``, and enable QinQ strip for default TPID on port 0:
+
+.. code-block:: console
+
+ ./<build_dir>/app/dpdk-testpmd -l 0-15 -- -i --forward-mode=mac
+ ...
+
+ testpmd> vlan set extend on 0
+ testpmd> vlan set qinq_strip on 0
diff --git a/drivers/net/intel/iavf/iavf.h b/drivers/net/intel/iavf/iavf.h
index f8008d0fda..35d82b7cc0 100644
--- a/drivers/net/intel/iavf/iavf.h
+++ b/drivers/net/intel/iavf/iavf.h
@@ -292,6 +292,7 @@ struct iavf_info {
bool in_reset_recovery;
uint32_t ptp_caps;
+ uint16_t tpid; /* VLAN tag identifier */
rte_spinlock_t phc_time_aq_lock;
};
@@ -456,6 +457,7 @@ int iavf_configure_rss_key(struct iavf_adapter *adapter);
int iavf_configure_queues(struct iavf_adapter *adapter, uint16_t num_queue_pairs);
int iavf_get_supported_rxdid(struct iavf_adapter *adapter);
int iavf_config_vlan_strip_v2(struct iavf_adapter *adapter, bool enable);
+int iavf_config_outer_vlan_strip_v2(struct iavf_adapter *adapter, bool enable);
int iavf_config_vlan_insert_v2(struct iavf_adapter *adapter, bool enable);
int iavf_add_del_vlan_v2(struct iavf_adapter *adapter, uint16_t vlanid,
bool add);
diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c
index 3126d9b644..f3094fffa9 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -127,6 +127,8 @@ static int iavf_dev_add_mac_addr(struct rte_eth_dev *dev,
static void iavf_dev_del_mac_addr(struct rte_eth_dev *dev, uint32_t index);
static int iavf_dev_vlan_filter_set(struct rte_eth_dev *dev,
uint16_t vlan_id, int on);
+static int iavf_vlan_tpid_set(struct rte_eth_dev *dev,
+ enum rte_vlan_type vlan_type, uint16_t tpid);
static int iavf_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
static int iavf_dev_rss_reta_update(struct rte_eth_dev *dev,
struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -226,6 +228,7 @@ static const struct eth_dev_ops iavf_eth_dev_ops = {
.mac_addr_remove = iavf_dev_del_mac_addr,
.set_mc_addr_list = iavf_set_mc_addr_list,
.vlan_filter_set = iavf_dev_vlan_filter_set,
+ .vlan_tpid_set = iavf_vlan_tpid_set,
.vlan_offload_set = iavf_dev_vlan_offload_set,
.rx_queue_start = iavf_dev_rx_queue_start,
.rx_queue_stop = iavf_dev_rx_queue_stop,
@@ -717,6 +720,7 @@ iavf_dev_configure(struct rte_eth_dev *dev)
}
iavf_dev_init_vlan(dev);
+ vf->tpid = RTE_ETHER_TYPE_VLAN; /* VLAN TPID set to 0x8100 by default */
if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
if (iavf_init_rss(ad) != 0) {
@@ -1365,6 +1369,32 @@ iavf_dev_del_mac_addr(struct rte_eth_dev *dev, uint32_t index)
vf->mac_num--;
}
+static int
+iavf_vlan_tpid_set(struct rte_eth_dev *dev, enum rte_vlan_type vlan_type, uint16_t tpid)
+{
+ struct iavf_adapter *adapter =
+ IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
+ int qinq = dev_conf->rxmode.offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
+
+ if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER &&
+ vlan_type != RTE_ETH_VLAN_TYPE_OUTER) ||
+ (!qinq && vlan_type == RTE_ETH_VLAN_TYPE_INNER)) {
+ PMD_DRV_LOG(ERR, "Unsupported vlan type.");
+ return -EINVAL;
+ }
+
+ /* This API only fills internal iavf_info structure
+ * and does not send any signal to hardware
+ */
+ if (qinq && vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
+ vf->tpid = rte_cpu_to_le_16(tpid); /* Outer VLAN can be 0x88a8 or 0x8100 */
+ else
+ vf->tpid = RTE_ETHER_TYPE_VLAN; /* Inner VLAN 0x8100 */
+ return 0;
+}
+
static int
iavf_disable_vlan_strip_ex(struct rte_eth_dev *dev, int on)
{
@@ -1453,6 +1483,8 @@ iavf_dev_vlan_offload_set_v2(struct rte_eth_dev *dev, int mask)
struct iavf_adapter *adapter =
IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
bool enable;
+ int qinq = dev->data->dev_conf.rxmode.offloads &
+ RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
int err;
if (mask & RTE_ETH_VLAN_FILTER_MASK) {
@@ -1472,6 +1504,20 @@ iavf_dev_vlan_offload_set_v2(struct rte_eth_dev *dev, int mask)
return -EIO;
}
+ if (mask & RTE_ETH_QINQ_STRIP_MASK) {
+ if (!qinq) {
+ PMD_DRV_LOG(ERR, "VLAN-extend disabled");
+ return -ENOSYS;
+ }
+ enable = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_QINQ_STRIP);
+ err = iavf_config_outer_vlan_strip_v2(adapter, enable);
+ /* If not support, the stripping is already disabled by PF */
+ if (err == -ENOTSUP && !enable)
+ err = 0;
+ if (err)
+ return -EIO;
+ }
+
return 0;
}
diff --git a/drivers/net/intel/iavf/iavf_vchnl.c b/drivers/net/intel/iavf/iavf_vchnl.c
index 23d115298c..bae5d54553 100644
--- a/drivers/net/intel/iavf/iavf_vchnl.c
+++ b/drivers/net/intel/iavf/iavf_vchnl.c
@@ -829,6 +829,50 @@ iavf_get_supported_rxdid(struct iavf_adapter *adapter)
return 0;
}
+int
+iavf_config_outer_vlan_strip_v2(struct iavf_adapter *adapter, bool enable)
+{
+ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+ struct virtchnl_vlan_supported_caps *stripping_caps;
+ struct virtchnl_vlan_setting vlan_strip;
+ uint8_t msg_buf[IAVF_AQ_BUF_SZ] = {0};
+ struct iavf_cmd_info args;
+ uint32_t *ethertype;
+ int ret;
+
+ memset(&vlan_strip, 0, sizeof(vlan_strip));
+ stripping_caps = &vf->vlan_v2_caps.offloads.stripping_support;
+ if ((stripping_caps->outer & VIRTCHNL_VLAN_ETHERTYPE_88A8) &&
+ (stripping_caps->outer & VIRTCHNL_VLAN_TOGGLE) &&
+ vf->tpid == RTE_ETHER_TYPE_QINQ) {
+ ethertype = &vlan_strip.outer_ethertype_setting;
+ *ethertype = VIRTCHNL_VLAN_ETHERTYPE_88A8;
+ } else if ((stripping_caps->outer & VIRTCHNL_VLAN_ETHERTYPE_8100) &&
+ (stripping_caps->outer & VIRTCHNL_VLAN_TOGGLE) &&
+ vf->tpid == RTE_ETHER_TYPE_VLAN) {
+ ethertype = &vlan_strip.outer_ethertype_setting;
+ *ethertype = VIRTCHNL_VLAN_ETHERTYPE_8100;
+ } else {
+ return -ENOTSUP;
+ }
+
+ vlan_strip.vport_id = vf->vsi_res->vsi_id;
+
+ args.ops = enable ? VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 :
+ VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2;
+ args.in_args = (uint8_t *)&vlan_strip;
+ args.in_args_size = sizeof(vlan_strip);
+ args.out_buffer = msg_buf;
+ args.out_size = IAVF_AQ_BUF_SZ;
+ ret = iavf_execute_vf_cmd_safe(adapter, &args);
+ if (ret)
+ PMD_DRV_LOG(ERR, "fail to execute command %s",
+ enable ? "VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2" :
+ "VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2");
+
+ return ret;
+}
+
int
iavf_config_vlan_strip_v2(struct iavf_adapter *adapter, bool enable)
{
@@ -838,14 +882,20 @@ iavf_config_vlan_strip_v2(struct iavf_adapter *adapter, bool enable)
uint8_t msg_buf[IAVF_AQ_BUF_SZ] = {0};
struct iavf_cmd_info args;
uint32_t *ethertype;
+ int qinq = adapter->dev_data->dev_conf.rxmode.offloads &
+ RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
int ret;
stripping_caps = &vf->vlan_v2_caps.offloads.stripping_support;
- if ((stripping_caps->outer & VIRTCHNL_VLAN_ETHERTYPE_8100) &&
+ /* When VLAN extend is disabled, Single VLAN mode which is Outer VLAN
+ * When VLAN extend is enabled, QinQ mode, this API works only on
+ * Inner VLAN strip which is always 0x8100.
+ */
+ if (!qinq && (stripping_caps->outer & VIRTCHNL_VLAN_ETHERTYPE_8100) &&
(stripping_caps->outer & VIRTCHNL_VLAN_TOGGLE))
ethertype = &vlan_strip.outer_ethertype_setting;
- else if ((stripping_caps->inner & VIRTCHNL_VLAN_ETHERTYPE_8100) &&
+ else if (qinq && (stripping_caps->inner & VIRTCHNL_VLAN_ETHERTYPE_8100) &&
(stripping_caps->inner & VIRTCHNL_VLAN_TOGGLE))
ethertype = &vlan_strip.inner_ethertype_setting;
else
@@ -921,6 +971,8 @@ iavf_add_del_vlan_v2(struct iavf_adapter *adapter, uint16_t vlanid, bool add)
struct virtchnl_vlan *vlan_setting;
struct iavf_cmd_info args;
uint32_t filtering_caps;
+ int qinq = adapter->dev_data->dev_conf.rxmode.offloads &
+ RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
int err;
supported_caps = &vf->vlan_v2_caps.filtering.filtering_support;
@@ -938,7 +990,10 @@ iavf_add_del_vlan_v2(struct iavf_adapter *adapter, uint16_t vlanid, bool add)
memset(&vlan_filter, 0, sizeof(vlan_filter));
vlan_filter.vport_id = vf->vsi_res->vsi_id;
vlan_filter.num_elements = 1;
- vlan_setting->tpid = RTE_ETHER_TYPE_VLAN;
+ if (qinq && vf->tpid == RTE_ETHER_TYPE_QINQ)
+ vlan_setting->tpid = RTE_ETHER_TYPE_QINQ;
+ else
+ vlan_setting->tpid = RTE_ETHER_TYPE_VLAN;
vlan_setting->tci = vlanid;
args.ops = add ? VIRTCHNL_OP_ADD_VLAN_V2 : VIRTCHNL_OP_DEL_VLAN_V2;
--
2.34.1
next prev parent reply other threads:[~2026-04-08 19:58 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-16 10:37 [PATCH] net/iavf: add support for QinQ strip Anurag Mandal
2026-02-16 14:21 ` [PATCH v2] " Anurag Mandal
2026-04-08 19:59 ` Anurag Mandal [this message]
2026-04-09 1:05 ` [PATCH v3] " Mandal, Anurag
2026-04-09 10:19 ` [PATCH v4] " Anurag Mandal
2026-04-09 14:26 ` Mandal, Anurag
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260408195947.51386-1-anurag.mandal@intel.com \
--to=anurag.mandal@intel.com \
--cc=bruce.richardson@intel.com \
--cc=dev@dpdk.org \
--cc=vladimir.medvedkin@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox