[PATCH v4] net/iavf: add support for QinQ strip
Mandal, Anurag
anurag.mandal at intel.com
Tue May 5 11:18:52 CEST 2026
Hi All,
Gentle reminder for review & ack.
Thank you.
Regards,
Anurag M
> -----Original Message-----
> From: Mandal, Anurag <anurag.mandal at intel.com>
> Sent: 09 April 2026 15:50
> To: dev at dpdk.org
> Cc: Richardson, Bruce <bruce.richardson at intel.com>; Medvedkin, Vladimir
> <vladimir.medvedkin at intel.com>; Mandal, Anurag
> <anurag.mandal at intel.com>
> Subject: [PATCH v4] net/iavf: add support for QinQ strip
>
> 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 at intel.com>
> ---
> V4: Addressed ai-code-review suggestions
> 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 | 50 +++++++++++++++++++++++
> drivers/net/intel/iavf/iavf_vchnl.c | 61 ++++++++++++++++++++++++++--
> 4 files changed, 141 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..6a77dacf59 100644
> --- a/drivers/net/intel/iavf/iavf.h
> +++ b/drivers/net/intel/iavf/iavf.h
> @@ -387,6 +387,7 @@ struct iavf_adapter {
> uint16_t fdir_ref_cnt;
> struct iavf_devargs devargs;
> bool mac_primary_set;
> + uint16_t tpid; /* VLAN tag identifier */
> };
>
> /* IAVF_DEV_PRIVATE_TO */
> @@ -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..5da2cd43c2 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,
> @@ -1365,6 +1368,36 @@ 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 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_OUTER) {
> + PMD_DRV_LOG(ERR, "Unsupported vlan type.");
> + return -EINVAL;
> + } else if (!qinq) {
> + PMD_DRV_LOG(ERR, "VLAN-extend disabled.");
> + return -ENOSYS;
> + } else if (tpid != RTE_ETHER_TYPE_VLAN &&
> + tpid != RTE_ETHER_TYPE_QINQ) {
> + PMD_DRV_LOG(ERR, "tpid supported 0x8100/0x88A8");
> + return -ENOTSUP;
> + }
> +
> + /* This API only fills internal iavf_adapter structure
> + * and does not send any signal to hardware.
> + * Inner VLAN always 0x8100, so not set explicitly.
> + */
> + if (qinq && vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
> + adapter->tpid = tpid; /* Outer VLAN can be 0x88a8 or 0x8100
> */
> +
> + return 0;
> +}
> +
> static int
> iavf_disable_vlan_strip_ex(struct rte_eth_dev *dev, int on) { @@ -1453,6
> +1486,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 +1507,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;
> }
>
> @@ -2812,6 +2861,7 @@ iavf_dev_init(struct rte_eth_dev *eth_dev)
> adapter->dev_data = eth_dev->data;
> adapter->stopped = 1;
> adapter->mac_primary_set = false;
> + adapter->tpid = RTE_ETHER_TYPE_VLAN; /* VLAN TPID set to 0x8100
> by
> +default */
>
> if (iavf_dev_event_handler_init())
> goto init_vf_err;
> diff --git a/drivers/net/intel/iavf/iavf_vchnl.c
> b/drivers/net/intel/iavf/iavf_vchnl.c
> index 23d115298c..c2f340db81 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) &&
> + adapter->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) &&
> + adapter->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 && adapter->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
More information about the dev
mailing list