DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH] net/i40e: fix single VLAN cannot work normal
@ 2022-08-18 16:03 Kevin Liu
  2022-08-19  1:43 ` Jiale, SongX
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Kevin Liu @ 2022-08-18 16:03 UTC (permalink / raw)
  To: dev; +Cc: Yuying.Zhang, beilei.xing, stevex.yang, Kevin Liu

After disable QinQ, single VLAN can not work normal.
The reason is that QinQ is not disabled correctly.

Before configuring QinQ, need to back up and clean
MAC/VLAN filters of all ports. After configuring QinQ,
restore MAC/VLAN filters of all ports. When disable
QinQ, need to set valid_flags to 0x0008 and set first_tag
to 0x88a8.

Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
---
 doc/guides/nics/i40e.rst       |   1 -
 drivers/net/i40e/i40e_ethdev.c | 159 +++++++++++++++++++++++----------
 2 files changed, 111 insertions(+), 49 deletions(-)

diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst
index abb99406b3..15b796e67a 100644
--- a/doc/guides/nics/i40e.rst
+++ b/doc/guides/nics/i40e.rst
@@ -983,7 +983,6 @@ If FW version >= 8.4, there'll be some Vlan related issues:
 
 #. TCI input set for QinQ  is invalid.
 #. Fail to configure TPID for QinQ.
-#. Need to enable QinQ before enabling Vlan filter.
 #. Fail to strip outer Vlan.
 
 Example of getting best performance with l3fwd example
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 67d79de08d..27cfda6ff8 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -325,6 +325,7 @@ static int i40e_veb_release(struct i40e_veb *veb);
 static struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf,
 						struct i40e_vsi *vsi);
 static int i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on);
+static int i40e_vsi_config_qinq(struct i40e_vsi *vsi, int on);
 static inline int i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi,
 					     struct i40e_macvlan_filter *mv_f,
 					     int num,
@@ -3909,7 +3910,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	int qinq = dev->data->dev_conf.rxmode.offloads &
 		   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
-	u16 sw_flags = 0, valid_flags = 0;
 	int ret = 0;
 
 	if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER &&
@@ -3928,10 +3928,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 	/* 802.1ad frames ability is added in NVM API 1.7*/
 	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
 		if (qinq) {
-			if (pf->fw8_3gt) {
-				sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
-				valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
-			}
 			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
 				hw->first_tag = rte_cpu_to_le_16(tpid);
 			else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER)
@@ -3940,8 +3936,8 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
 				hw->second_tag = rte_cpu_to_le_16(tpid);
 		}
-		ret = i40e_aq_set_switch_config(hw, sw_flags,
-						valid_flags, 0, NULL);
+		ret = i40e_aq_set_switch_config(hw, 0,
+						0, 0, NULL);
 		if (ret != I40E_SUCCESS) {
 			PMD_DRV_LOG(ERR,
 				    "Set switch config failed aq_err: %d",
@@ -3993,11 +3989,15 @@ static int
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_mac_filter_info *vmac_filter[RTE_MAX_ETHPORTS];
+	struct i40e_vsi *vvsi[RTE_MAX_ETHPORTS];
 	struct i40e_mac_filter_info *mac_filter;
 	struct i40e_vsi *vsi = pf->main_vsi;
 	struct rte_eth_rxmode *rxmode;
+	int vnum[RTE_MAX_ETHPORTS];
 	struct i40e_mac_filter *f;
-	int i, num;
+	int port_num = 0;
+	int i, num, j;
 	void *temp;
 	int ret;
 
@@ -4018,50 +4018,80 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 	}
 
 	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
-		i = 0;
-		num = vsi->mac_num;
-		mac_filter = rte_zmalloc("mac_filter_info_data",
-				 num * sizeof(*mac_filter), 0);
-		if (mac_filter == NULL) {
-			PMD_DRV_LOG(ERR, "failed to allocate memory");
-			return I40E_ERR_NO_MEMORY;
-		}
-
-		/*
-		 * Outer VLAN processing is supported after firmware v8.4, kernel driver
-		 * also change the default behavior to support this feature. To align with
-		 * kernel driver, set switch config in 'i40e_vlan_tpie_set' to support for
-		 * outer VLAN processing. But it is forbidden for firmware to change the
-		 * Inner/Outer VLAN configuration while there are MAC/VLAN filters in the
-		 * switch table. Therefore, we need to clear the MAC table before setting
-		 * config, and then restore the MAC table after setting. This feature is
-		 * recommended to be used in firmware v8.6.
-		 */
-		/* Remove all existing mac */
-		RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
-			mac_filter[i] = f->mac_info;
-			ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
-			if (ret)
-				PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
-			i++;
+		/*back up and clean mac/vlan filters of all ports*/
+		for (j = 0; j < RTE_MAX_ETHPORTS; j++) {
+			/*
+			 * It is impossible to confirm whether the port is pf
+			 * only through the state field, so it is also necessary
+			 * to verify the intr_handle field.
+			 */
+			if (rte_eth_devices[j].state != RTE_ETH_DEV_UNUSED &&
+							 rte_eth_devices[j].intr_handle) {
+				struct rte_eth_dev *tmp_dev = &rte_eth_devices[j];
+				struct i40e_pf *tmp_pf =
+					I40E_DEV_PRIVATE_TO_PF(tmp_dev->data->dev_private);
+				struct i40e_vsi *tmp_vsi = tmp_pf->main_vsi;
+				i = 0;
+				num = tmp_vsi->mac_num;
+				mac_filter = rte_zmalloc("mac_filter_info_data",
+						num * sizeof(*mac_filter), 0);
+				if (mac_filter == NULL) {
+					PMD_DRV_LOG(ERR, "failed to allocate memory");
+					return I40E_ERR_NO_MEMORY;
+				}
+				/*
+				 * Outer VLAN processing is supported after firmware v8.4,
+				 * kernel driver also change the default behavior to support
+				 * this feature. To align with kernel driver, set switch
+				 * config in 'i40e_vlan_tpid_set' to support for outer VLAN
+				 * processing. But it is forbidden for firmware to change the
+				 * Inner/Outer VLAN configuration while there are MAC/VLAN
+				 * filters in the switch table. Therefore, we need to clean
+				 * MAC/VLAN filters of all ports before setting config, and
+				 * then restore the MAC table after setting. This feature is
+				 * recommended to be used in firmware v8.6.
+				 */
+				/* Remove all existing mac */
+				RTE_TAILQ_FOREACH_SAFE(f, &tmp_vsi->mac_list, next, temp) {
+					mac_filter[i] = f->mac_info;
+					ret = i40e_vsi_delete_mac(tmp_vsi, &f->mac_info.mac_addr);
+					if (ret)
+						PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
+					i++;
+				}
+				vmac_filter[j] = mac_filter;
+				vvsi[j] = tmp_vsi;
+				vnum[j] = num;
+				port_num++;
+			}
 		}
 		if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND) {
-			i40e_vsi_config_double_vlan(vsi, TRUE);
-			/* Set global registers with default ethertype. */
-			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
-					   RTE_ETHER_TYPE_VLAN);
-			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
-					   RTE_ETHER_TYPE_VLAN);
+			if (pf->fw8_3gt) {
+				i40e_vsi_config_qinq(vsi, TRUE);
+			} else {
+				i40e_vsi_config_double_vlan(vsi, TRUE);
+				/* Set global registers with default ethertype. */
+				i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
+							RTE_ETHER_TYPE_VLAN);
+				i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
+							RTE_ETHER_TYPE_VLAN);
+			}
 		} else {
-			i40e_vsi_config_double_vlan(vsi, FALSE);
-		}
-		/* Restore all mac */
-		for (i = 0; i < num; i++) {
-			ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
-			if (ret)
-				PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
+			if (pf->fw8_3gt)
+				i40e_vsi_config_qinq(vsi, FALSE);
+			else
+				i40e_vsi_config_double_vlan(vsi, FALSE);
+		}
+		/*restore mac/vlan filters of all ports*/
+		for (j = 0; j < port_num; j++) {
+			mac_filter = vmac_filter[j];
+			for (i = 0; i < vnum[j]; i++) {
+				ret = i40e_vsi_add_mac(vvsi[j], &mac_filter[i]);
+				if (ret)
+					PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
+			}
+			rte_free(mac_filter);
 		}
-		rte_free(mac_filter);
 	}
 
 	if (mask & RTE_ETH_QINQ_STRIP_MASK) {
@@ -6181,6 +6211,39 @@ i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on)
 	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
 }
 
+static int
+i40e_vsi_config_qinq(struct i40e_vsi *vsi, int on)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	u16 sw_flags = 0, valid_flags = 0;
+	int ret = 0;
+
+	ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to set port params");
+		return -1;
+	}
+
+	if (on) {
+		sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+		valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+		hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_VLAN);
+	} else {
+		valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+		hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_QINQ);
+	}
+
+	ret = i40e_aq_set_switch_config(hw, sw_flags, valid_flags, 0, NULL);
+	if (ret) {
+		PMD_DRV_LOG(ERR,
+				    "Set switch config failed aq_err: %d",
+				    hw->aq.asq_last_status);
+		return -1;
+	}
+
+	return 0;
+}
+
 static int
 i40e_update_flow_control(struct i40e_hw *hw)
 {
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH] net/i40e: fix single VLAN cannot work normal
  2022-08-18 16:03 [PATCH] net/i40e: fix single VLAN cannot work normal Kevin Liu
@ 2022-08-19  1:43 ` Jiale, SongX
  2022-09-06  2:15 ` Zhang, Yuying
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Jiale, SongX @ 2022-08-19  1:43 UTC (permalink / raw)
  To: dev; +Cc: Liu, KevinX

> -----Original Message-----
> From: Kevin Liu <kevinx.liu@intel.com>
> Sent: Friday, August 19, 2022 12:04 AM
> To: dev@dpdk.org
> Cc: Zhang, Yuying <yuying.zhang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Yang, SteveX <stevex.yang@intel.com>; Liu, KevinX
> <kevinx.liu@intel.com>
> Subject: [PATCH] net/i40e: fix single VLAN cannot work normal
> 
> After disable QinQ, single VLAN can not work normal.
> The reason is that QinQ is not disabled correctly.
> 
> Before configuring QinQ, need to back up and clean MAC/VLAN filters of all
> ports. After configuring QinQ, restore MAC/VLAN filters of all ports. When
> disable QinQ, need to set valid_flags to 0x0008 and set first_tag to 0x88a8.
> 
> Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
> ---
Tested-by: Jiale Song < songx.jiale@intel.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH] net/i40e: fix single VLAN cannot work normal
  2022-08-18 16:03 [PATCH] net/i40e: fix single VLAN cannot work normal Kevin Liu
  2022-08-19  1:43 ` Jiale, SongX
@ 2022-09-06  2:15 ` Zhang, Yuying
  2022-09-06  3:32   ` Liu, KevinX
  2022-09-06 11:40 ` [PATCH v2] " Kevin Liu
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Zhang, Yuying @ 2022-09-06  2:15 UTC (permalink / raw)
  To: Liu, KevinX, dev; +Cc: Xing, Beilei, Yang, SteveX

Hi,

> -----Original Message-----
> From: Liu, KevinX <kevinx.liu@intel.com>
> Sent: Friday, August 19, 2022 12:04 AM
> To: dev@dpdk.org
> Cc: Zhang, Yuying <yuying.zhang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Yang, SteveX <stevex.yang@intel.com>; Liu, KevinX
> <kevinx.liu@intel.com>
> Subject: [PATCH] net/i40e: fix single VLAN cannot work normal
> 
> After disable QinQ, single VLAN can not work normal.
> The reason is that QinQ is not disabled correctly.
> 
> Before configuring QinQ, need to back up and clean MAC/VLAN filters of all
> ports. After configuring QinQ, restore MAC/VLAN filters of all ports. When
> disable QinQ, need to set valid_flags to 0x0008 and set first_tag to 0x88a8.
> 
> Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
> ---
>  doc/guides/nics/i40e.rst       |   1 -
>  drivers/net/i40e/i40e_ethdev.c | 159 +++++++++++++++++++++++----------
>  2 files changed, 111 insertions(+), 49 deletions(-)
> 
> diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index
> abb99406b3..15b796e67a 100644
> --- a/doc/guides/nics/i40e.rst
> +++ b/doc/guides/nics/i40e.rst
> @@ -983,7 +983,6 @@ If FW version >= 8.4, there'll be some Vlan related issues:
> 
>  #. TCI input set for QinQ  is invalid.
>  #. Fail to configure TPID for QinQ.
> -#. Need to enable QinQ before enabling Vlan filter.
>  #. Fail to strip outer Vlan.
> 
>  Example of getting best performance with l3fwd example diff --git
> a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index
> 67d79de08d..27cfda6ff8 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
> @@ -325,6 +325,7 @@ static int i40e_veb_release(struct i40e_veb *veb);  static
> struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf,
>  						struct i40e_vsi *vsi);
>  static int i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on);
> +static int i40e_vsi_config_qinq(struct i40e_vsi *vsi, int on);
>  static inline int i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi,
>  					     struct i40e_macvlan_filter *mv_f,
>  					     int num,
> @@ -3909,7 +3910,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data-
> >dev_private);
>  	int qinq = dev->data->dev_conf.rxmode.offloads &
>  		   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
> -	u16 sw_flags = 0, valid_flags = 0;
>  	int ret = 0;
> 
>  	if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER && @@ -3928,10
> +3928,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  	/* 802.1ad frames ability is added in NVM API 1.7*/
>  	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
>  		if (qinq) {
> -			if (pf->fw8_3gt) {
> -				sw_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> -				valid_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> -			}
>  			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
>  				hw->first_tag = rte_cpu_to_le_16(tpid);
>  			else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER) @@
> -3940,8 +3936,8 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
>  				hw->second_tag = rte_cpu_to_le_16(tpid);
>  		}
> -		ret = i40e_aq_set_switch_config(hw, sw_flags,
> -						valid_flags, 0, NULL);
> +		ret = i40e_aq_set_switch_config(hw, 0,
> +						0, 0, NULL);
>  		if (ret != I40E_SUCCESS) {
>  			PMD_DRV_LOG(ERR,
>  				    "Set switch config failed aq_err: %d", @@ -
> 3993,11 +3989,15 @@ static int  i40e_vlan_offload_set(struct rte_eth_dev *dev,
> int mask)  {
>  	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data-
> >dev_private);
> +	struct i40e_mac_filter_info *vmac_filter[RTE_MAX_ETHPORTS];
> +	struct i40e_vsi *vvsi[RTE_MAX_ETHPORTS];
>  	struct i40e_mac_filter_info *mac_filter;
>  	struct i40e_vsi *vsi = pf->main_vsi;
>  	struct rte_eth_rxmode *rxmode;
> +	int vnum[RTE_MAX_ETHPORTS];
>  	struct i40e_mac_filter *f;
> -	int i, num;
> +	int port_num = 0;
> +	int i, num, j;
>  	void *temp;
>  	int ret;
> 
> @@ -4018,50 +4018,80 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int
> mask)
>  	}
> 
>  	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
> -		i = 0;
> -		num = vsi->mac_num;
> -		mac_filter = rte_zmalloc("mac_filter_info_data",
> -				 num * sizeof(*mac_filter), 0);
> -		if (mac_filter == NULL) {
> -			PMD_DRV_LOG(ERR, "failed to allocate memory");
> -			return I40E_ERR_NO_MEMORY;
> -		}
> -
> -		/*
> -		 * Outer VLAN processing is supported after firmware v8.4,
> kernel driver
> -		 * also change the default behavior to support this feature. To
> align with
> -		 * kernel driver, set switch config in 'i40e_vlan_tpie_set' to
> support for
> -		 * outer VLAN processing. But it is forbidden for firmware to
> change the
> -		 * Inner/Outer VLAN configuration while there are MAC/VLAN
> filters in the
> -		 * switch table. Therefore, we need to clear the MAC table
> before setting
> -		 * config, and then restore the MAC table after setting. This
> feature is
> -		 * recommended to be used in firmware v8.6.
> -		 */
> -		/* Remove all existing mac */
> -		RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
> -			mac_filter[i] = f->mac_info;
> -			ret = i40e_vsi_delete_mac(vsi, &f-
> >mac_info.mac_addr);
> -			if (ret)
> -				PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
> -			i++;
> +		/*back up and clean mac/vlan filters of all ports*/
> +		for (j = 0; j < RTE_MAX_ETHPORTS; j++) {
> +			/*
> +			 * It is impossible to confirm whether the port is pf
> +			 * only through the state field, so it is also necessary
> +			 * to verify the intr_handle field.
> +			 */
> +			if (rte_eth_devices[j].state != RTE_ETH_DEV_UNUSED
> &&
> +
> rte_eth_devices[j].intr_handle) {
> +				struct rte_eth_dev *tmp_dev =
> &rte_eth_devices[j];
> +				struct i40e_pf *tmp_pf =
> +					I40E_DEV_PRIVATE_TO_PF(tmp_dev-
> >data->dev_private);
> +				struct i40e_vsi *tmp_vsi = tmp_pf->main_vsi;
> +				i = 0;
> +				num = tmp_vsi->mac_num;
> +				mac_filter =
> rte_zmalloc("mac_filter_info_data",
> +						num * sizeof(*mac_filter), 0);
> +				if (mac_filter == NULL) {
> +					PMD_DRV_LOG(ERR, "failed to
> allocate memory");
> +					return I40E_ERR_NO_MEMORY;
> +				}
> +				/*
> +				 * Outer VLAN processing is supported after
> firmware v8.4,
> +				 * kernel driver also change the default
> behavior to support
> +				 * this feature. To align with kernel driver, set
> switch
> +				 * config in 'i40e_vlan_tpid_set' to support for
> outer VLAN
> +				 * processing. But it is forbidden for firmware
> to change the
> +				 * Inner/Outer VLAN configuration while there
> are MAC/VLAN
> +				 * filters in the switch table. Therefore, we
> need to clean
> +				 * MAC/VLAN filters of all ports before setting
> config, and
> +				 * then restore the MAC table after setting. This
> feature is
> +				 * recommended to be used in firmware v8.6.
> +				 */
> +				/* Remove all existing mac */
> +				RTE_TAILQ_FOREACH_SAFE(f, &tmp_vsi-
> >mac_list, next, temp) {
> +					mac_filter[i] = f->mac_info;
> +					ret = i40e_vsi_delete_mac(tmp_vsi, &f-
> >mac_info.mac_addr);
> +					if (ret)
> +						PMD_DRV_LOG(ERR, "i40e vsi
> delete mac fail.");
> +					i++;
> +				}
> +				vmac_filter[j] = mac_filter;
> +				vvsi[j] = tmp_vsi;
> +				vnum[j] = num;
> +				port_num++;
> +			}
>  		}
>  		if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND)
> {
> -			i40e_vsi_config_double_vlan(vsi, TRUE);
> -			/* Set global registers with default ethertype. */
> -			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
> -					   RTE_ETHER_TYPE_VLAN);
> -			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
> -					   RTE_ETHER_TYPE_VLAN);
> +			if (pf->fw8_3gt) {
> +				i40e_vsi_config_qinq(vsi, TRUE);
> +			} else {
> +				i40e_vsi_config_double_vlan(vsi, TRUE);
> +				/* Set global registers with default ethertype.
> */
> +				i40e_vlan_tpid_set(dev,
> RTE_ETH_VLAN_TYPE_OUTER,
> +
> 	RTE_ETHER_TYPE_VLAN);
> +				i40e_vlan_tpid_set(dev,
> RTE_ETH_VLAN_TYPE_INNER,
> +
> 	RTE_ETHER_TYPE_VLAN);
> +			}
>  		} else {
> -			i40e_vsi_config_double_vlan(vsi, FALSE);
> -		}
> -		/* Restore all mac */
> -		for (i = 0; i < num; i++) {
> -			ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
> -			if (ret)
> -				PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
> +			if (pf->fw8_3gt)
> +				i40e_vsi_config_qinq(vsi, FALSE);
> +			else
> +				i40e_vsi_config_double_vlan(vsi, FALSE);
> +		}
> +		/*restore mac/vlan filters of all ports*/
> +		for (j = 0; j < port_num; j++) {

The index here is incorrect.

> +			mac_filter = vmac_filter[j];
> +			for (i = 0; i < vnum[j]; i++) {
> +				ret = i40e_vsi_add_mac(vvsi[j], &mac_filter[i]);
> +				if (ret)
> +					PMD_DRV_LOG(ERR, "i40e vsi add mac
> fail.");
> +			}
> +			rte_free(mac_filter);
>  		}
> -		rte_free(mac_filter);
>  	}
> 
>  	if (mask & RTE_ETH_QINQ_STRIP_MASK) {
> @@ -6181,6 +6211,39 @@ i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int
> on)
>  	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);  }
> 
> +static int
> +i40e_vsi_config_qinq(struct i40e_vsi *vsi, int on) {
> +	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
> +	u16 sw_flags = 0, valid_flags = 0;
> +	int ret = 0;
> +
> +	ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
> +	if (ret != I40E_SUCCESS) {
> +		PMD_DRV_LOG(ERR, "Failed to set port params");
> +		return -1;
> +	}
> +
> +	if (on) {
> +		sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +		valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +		hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_VLAN);
> +	} else {
> +		valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +		hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_QINQ);
> +	}
> +
> +	ret = i40e_aq_set_switch_config(hw, sw_flags, valid_flags, 0, NULL);
> +	if (ret) {
> +		PMD_DRV_LOG(ERR,
> +				    "Set switch config failed aq_err: %d",
> +				    hw->aq.asq_last_status);
> +		return -1;
> +	}
> +
> +	return 0;
> +}

Qinq is double vlan, please use i40e_vsi_config_double_vlan() function for bug fixing.

> +
>  static int
>  i40e_update_flow_control(struct i40e_hw *hw)  {
> --
> 2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH] net/i40e: fix single VLAN cannot work normal
  2022-09-06  2:15 ` Zhang, Yuying
@ 2022-09-06  3:32   ` Liu, KevinX
  0 siblings, 0 replies; 9+ messages in thread
From: Liu, KevinX @ 2022-09-06  3:32 UTC (permalink / raw)
  To: Zhang, Yuying, dev; +Cc: Xing, Beilei, Yang, SteveX



> -----Original Message-----
> From: Zhang, Yuying <yuying.zhang@intel.com>
> Sent: Tuesday, September 6, 2022 10:16 AM
> To: Liu, KevinX <kevinx.liu@intel.com>; dev@dpdk.org
> Cc: Xing, Beilei <beilei.xing@intel.com>; Yang, SteveX <stevex.yang@intel.com>
> Subject: RE: [PATCH] net/i40e: fix single VLAN cannot work normal
> 
> Hi,
> 
> > -----Original Message-----
> > From: Liu, KevinX <kevinx.liu@intel.com>
> > Sent: Friday, August 19, 2022 12:04 AM
> > To: dev@dpdk.org
> > Cc: Zhang, Yuying <yuying.zhang@intel.com>; Xing, Beilei
> > <beilei.xing@intel.com>; Yang, SteveX <stevex.yang@intel.com>; Liu,
> > KevinX <kevinx.liu@intel.com>
> > Subject: [PATCH] net/i40e: fix single VLAN cannot work normal
> >
> > After disable QinQ, single VLAN can not work normal.
> > The reason is that QinQ is not disabled correctly.
> >
> > Before configuring QinQ, need to back up and clean MAC/VLAN filters of
> > all ports. After configuring QinQ, restore MAC/VLAN filters of all
> > ports. When disable QinQ, need to set valid_flags to 0x0008 and set first_tag
> to 0x88a8.
> >
> > Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
> > ---
> >  doc/guides/nics/i40e.rst       |   1 -
> >  drivers/net/i40e/i40e_ethdev.c | 159
> > +++++++++++++++++++++++----------
> >  2 files changed, 111 insertions(+), 49 deletions(-)
> >
> > diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index
> > abb99406b3..15b796e67a 100644
> > --- a/doc/guides/nics/i40e.rst
> > +++ b/doc/guides/nics/i40e.rst
> > @@ -983,7 +983,6 @@ If FW version >= 8.4, there'll be some Vlan related
> issues:
> >
> >  #. TCI input set for QinQ  is invalid.
> >  #. Fail to configure TPID for QinQ.
> > -#. Need to enable QinQ before enabling Vlan filter.
> >  #. Fail to strip outer Vlan.
> >
> >  Example of getting best performance with l3fwd example diff --git
> > a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
> > index
> > 67d79de08d..27cfda6ff8 100644
> > --- a/drivers/net/i40e/i40e_ethdev.c
> > +++ b/drivers/net/i40e/i40e_ethdev.c
> > @@ -325,6 +325,7 @@ static int i40e_veb_release(struct i40e_veb *veb);
> > static struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf,
> >  						struct i40e_vsi *vsi);
> >  static int i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on);
> > +static int i40e_vsi_config_qinq(struct i40e_vsi *vsi, int on);
> >  static inline int i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi,
> >  					     struct i40e_macvlan_filter *mv_f,
> >  					     int num,
> > @@ -3909,7 +3910,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
> >  	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data-
> > >dev_private);
> >  	int qinq = dev->data->dev_conf.rxmode.offloads &
> >  		   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
> > -	u16 sw_flags = 0, valid_flags = 0;
> >  	int ret = 0;
> >
> >  	if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER && @@ -3928,10
> > +3928,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
> >  	/* 802.1ad frames ability is added in NVM API 1.7*/
> >  	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
> >  		if (qinq) {
> > -			if (pf->fw8_3gt) {
> > -				sw_flags =
> > I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> > -				valid_flags =
> > I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> > -			}
> >  			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
> >  				hw->first_tag = rte_cpu_to_le_16(tpid);
> >  			else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER) @@
> > -3940,8 +3936,8 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
> >  			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
> >  				hw->second_tag = rte_cpu_to_le_16(tpid);
> >  		}
> > -		ret = i40e_aq_set_switch_config(hw, sw_flags,
> > -						valid_flags, 0, NULL);
> > +		ret = i40e_aq_set_switch_config(hw, 0,
> > +						0, 0, NULL);
> >  		if (ret != I40E_SUCCESS) {
> >  			PMD_DRV_LOG(ERR,
> >  				    "Set switch config failed aq_err: %d", @@ -
> > 3993,11 +3989,15 @@ static int  i40e_vlan_offload_set(struct
> > rte_eth_dev *dev, int mask)  {
> >  	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data-
> > >dev_private);
> > +	struct i40e_mac_filter_info *vmac_filter[RTE_MAX_ETHPORTS];
> > +	struct i40e_vsi *vvsi[RTE_MAX_ETHPORTS];
> >  	struct i40e_mac_filter_info *mac_filter;
> >  	struct i40e_vsi *vsi = pf->main_vsi;
> >  	struct rte_eth_rxmode *rxmode;
> > +	int vnum[RTE_MAX_ETHPORTS];
> >  	struct i40e_mac_filter *f;
> > -	int i, num;
> > +	int port_num = 0;
> > +	int i, num, j;
> >  	void *temp;
> >  	int ret;
> >
> > @@ -4018,50 +4018,80 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev,
> > int
> > mask)
> >  	}
> >
> >  	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
> > -		i = 0;
> > -		num = vsi->mac_num;
> > -		mac_filter = rte_zmalloc("mac_filter_info_data",
> > -				 num * sizeof(*mac_filter), 0);
> > -		if (mac_filter == NULL) {
> > -			PMD_DRV_LOG(ERR, "failed to allocate memory");
> > -			return I40E_ERR_NO_MEMORY;
> > -		}
> > -
> > -		/*
> > -		 * Outer VLAN processing is supported after firmware v8.4,
> > kernel driver
> > -		 * also change the default behavior to support this feature. To
> > align with
> > -		 * kernel driver, set switch config in 'i40e_vlan_tpie_set' to
> > support for
> > -		 * outer VLAN processing. But it is forbidden for firmware to
> > change the
> > -		 * Inner/Outer VLAN configuration while there are MAC/VLAN
> > filters in the
> > -		 * switch table. Therefore, we need to clear the MAC table
> > before setting
> > -		 * config, and then restore the MAC table after setting. This
> > feature is
> > -		 * recommended to be used in firmware v8.6.
> > -		 */
> > -		/* Remove all existing mac */
> > -		RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
> > -			mac_filter[i] = f->mac_info;
> > -			ret = i40e_vsi_delete_mac(vsi, &f-
> > >mac_info.mac_addr);
> > -			if (ret)
> > -				PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
> > -			i++;
> > +		/*back up and clean mac/vlan filters of all ports*/
> > +		for (j = 0; j < RTE_MAX_ETHPORTS; j++) {
> > +			/*
> > +			 * It is impossible to confirm whether the port is pf
> > +			 * only through the state field, so it is also necessary
> > +			 * to verify the intr_handle field.
> > +			 */
> > +			if (rte_eth_devices[j].state != RTE_ETH_DEV_UNUSED
> > &&
> > +
> > rte_eth_devices[j].intr_handle) {
> > +				struct rte_eth_dev *tmp_dev =
> > &rte_eth_devices[j];
> > +				struct i40e_pf *tmp_pf =
> > +					I40E_DEV_PRIVATE_TO_PF(tmp_dev-
> > >data->dev_private);
> > +				struct i40e_vsi *tmp_vsi = tmp_pf->main_vsi;
> > +				i = 0;
> > +				num = tmp_vsi->mac_num;
> > +				mac_filter =
> > rte_zmalloc("mac_filter_info_data",
> > +						num * sizeof(*mac_filter), 0);
> > +				if (mac_filter == NULL) {
> > +					PMD_DRV_LOG(ERR, "failed to
> > allocate memory");
> > +					return I40E_ERR_NO_MEMORY;
> > +				}
> > +				/*
> > +				 * Outer VLAN processing is supported after
> > firmware v8.4,
> > +				 * kernel driver also change the default
> > behavior to support
> > +				 * this feature. To align with kernel driver, set
> > switch
> > +				 * config in 'i40e_vlan_tpid_set' to support for
> > outer VLAN
> > +				 * processing. But it is forbidden for firmware
> > to change the
> > +				 * Inner/Outer VLAN configuration while there
> > are MAC/VLAN
> > +				 * filters in the switch table. Therefore, we
> > need to clean
> > +				 * MAC/VLAN filters of all ports before setting
> > config, and
> > +				 * then restore the MAC table after setting. This
> > feature is
> > +				 * recommended to be used in firmware v8.6.
> > +				 */
> > +				/* Remove all existing mac */
> > +				RTE_TAILQ_FOREACH_SAFE(f, &tmp_vsi-
> > >mac_list, next, temp) {
> > +					mac_filter[i] = f->mac_info;
> > +					ret = i40e_vsi_delete_mac(tmp_vsi, &f-
> > >mac_info.mac_addr);
> > +					if (ret)
> > +						PMD_DRV_LOG(ERR, "i40e vsi
> > delete mac fail.");
> > +					i++;
> > +				}
> > +				vmac_filter[j] = mac_filter;
> > +				vvsi[j] = tmp_vsi;
> > +				vnum[j] = num;
> > +				port_num++;
> > +			}
> >  		}
> >  		if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND)
> {
> > -			i40e_vsi_config_double_vlan(vsi, TRUE);
> > -			/* Set global registers with default ethertype. */
> > -			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
> > -					   RTE_ETHER_TYPE_VLAN);
> > -			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
> > -					   RTE_ETHER_TYPE_VLAN);
> > +			if (pf->fw8_3gt) {
> > +				i40e_vsi_config_qinq(vsi, TRUE);
> > +			} else {
> > +				i40e_vsi_config_double_vlan(vsi, TRUE);
> > +				/* Set global registers with default ethertype.
> > */
> > +				i40e_vlan_tpid_set(dev,
> > RTE_ETH_VLAN_TYPE_OUTER,
> > +
> > 	RTE_ETHER_TYPE_VLAN);
> > +				i40e_vlan_tpid_set(dev,
> > RTE_ETH_VLAN_TYPE_INNER,
> > +
> > 	RTE_ETHER_TYPE_VLAN);
> > +			}
> >  		} else {
> > -			i40e_vsi_config_double_vlan(vsi, FALSE);
> > -		}
> > -		/* Restore all mac */
> > -		for (i = 0; i < num; i++) {
> > -			ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
> > -			if (ret)
> > -				PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
> > +			if (pf->fw8_3gt)
> > +				i40e_vsi_config_qinq(vsi, FALSE);
> > +			else
> > +				i40e_vsi_config_double_vlan(vsi, FALSE);
> > +		}
> > +		/*restore mac/vlan filters of all ports*/
> > +		for (j = 0; j < port_num; j++) {
> 
> The index here is incorrect.

Thanks, I will send v2.
> 
> > +			mac_filter = vmac_filter[j];
> > +			for (i = 0; i < vnum[j]; i++) {
> > +				ret = i40e_vsi_add_mac(vvsi[j], &mac_filter[i]);
> > +				if (ret)
> > +					PMD_DRV_LOG(ERR, "i40e vsi add mac
> > fail.");
> > +			}
> > +			rte_free(mac_filter);
> >  		}
> > -		rte_free(mac_filter);
> >  	}
> >
> >  	if (mask & RTE_ETH_QINQ_STRIP_MASK) { @@ -6181,6 +6211,39 @@
> > i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int
> > on)
> >  	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
> > }
> >
> > +static int
> > +i40e_vsi_config_qinq(struct i40e_vsi *vsi, int on) {
> > +	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
> > +	u16 sw_flags = 0, valid_flags = 0;
> > +	int ret = 0;
> > +
> > +	ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
> > +	if (ret != I40E_SUCCESS) {
> > +		PMD_DRV_LOG(ERR, "Failed to set port params");
> > +		return -1;
> > +	}
> > +
> > +	if (on) {
> > +		sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> > +		valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> > +		hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_VLAN);
> > +	} else {
> > +		valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> > +		hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_QINQ);
> > +	}
> > +
> > +	ret = i40e_aq_set_switch_config(hw, sw_flags, valid_flags, 0, NULL);
> > +	if (ret) {
> > +		PMD_DRV_LOG(ERR,
> > +				    "Set switch config failed aq_err: %d",
> > +				    hw->aq.asq_last_status);
> > +		return -1;
> > +	}
> > +
> > +	return 0;
> > +}
> 
> Qinq is double vlan, please use i40e_vsi_config_double_vlan() function for bug
> fixing.

Ok, I will fix it.
> 
> > +
> >  static int
> >  i40e_update_flow_control(struct i40e_hw *hw)  {
> > --
> > 2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2] net/i40e: fix single VLAN cannot work normal
  2022-08-18 16:03 [PATCH] net/i40e: fix single VLAN cannot work normal Kevin Liu
  2022-08-19  1:43 ` Jiale, SongX
  2022-09-06  2:15 ` Zhang, Yuying
@ 2022-09-06 11:40 ` Kevin Liu
  2022-09-06 16:15 ` [PATCH v3] " Kevin Liu
  2022-09-07 15:18 ` [PATCH v4] net/i40e: fix single VLAN cannot work normally Kevin Liu
  4 siblings, 0 replies; 9+ messages in thread
From: Kevin Liu @ 2022-09-06 11:40 UTC (permalink / raw)
  To: dev; +Cc: Yuying.Zhang, beilei.xing, stevex.yang, Kevin Liu, Jiale Song

After disable QinQ, single VLAN can not work normal.
The reason is that QinQ is not disabled correctly.

Before configuring QinQ, need to back up and clean
MAC/VLAN filters of all ports. After configuring QinQ,
restore MAC/VLAN filters of all ports. When disable
QinQ, need to set valid_flags to 0x0008 and set first_tag
to 0x88a8.

Fixes: 38e9762be16a ("net/i40e: add outer VLAN processing")
Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
Tested-by: Jiale Song <songx.jiale@intel.com>
---
v2: refine code
---
 doc/guides/nics/i40e.rst       |   1 -
 drivers/net/i40e/i40e_ethdev.c | 146 ++++++++++++++++++++++-----------
 2 files changed, 100 insertions(+), 47 deletions(-)

diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst
index abb99406b3..15b796e67a 100644
--- a/doc/guides/nics/i40e.rst
+++ b/doc/guides/nics/i40e.rst
@@ -983,7 +983,6 @@ If FW version >= 8.4, there'll be some Vlan related issues:
 
 #. TCI input set for QinQ  is invalid.
 #. Fail to configure TPID for QinQ.
-#. Need to enable QinQ before enabling Vlan filter.
 #. Fail to strip outer Vlan.
 
 Example of getting best performance with l3fwd example
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 67d79de08d..6cd659a52e 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -3909,7 +3909,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	int qinq = dev->data->dev_conf.rxmode.offloads &
 		   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
-	u16 sw_flags = 0, valid_flags = 0;
 	int ret = 0;
 
 	if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER &&
@@ -3928,10 +3927,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 	/* 802.1ad frames ability is added in NVM API 1.7*/
 	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
 		if (qinq) {
-			if (pf->fw8_3gt) {
-				sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
-				valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
-			}
 			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
 				hw->first_tag = rte_cpu_to_le_16(tpid);
 			else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER)
@@ -3940,8 +3935,8 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
 				hw->second_tag = rte_cpu_to_le_16(tpid);
 		}
-		ret = i40e_aq_set_switch_config(hw, sw_flags,
-						valid_flags, 0, NULL);
+		ret = i40e_aq_set_switch_config(hw, 0,
+						0, 0, NULL);
 		if (ret != I40E_SUCCESS) {
 			PMD_DRV_LOG(ERR,
 				    "Set switch config failed aq_err: %d",
@@ -3993,11 +3988,15 @@ static int
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_mac_filter_info *vmac_filter[RTE_MAX_ETHPORTS];
+	struct i40e_vsi *vvsi[RTE_MAX_ETHPORTS];
 	struct i40e_mac_filter_info *mac_filter;
 	struct i40e_vsi *vsi = pf->main_vsi;
 	struct rte_eth_rxmode *rxmode;
+	int vnum[RTE_MAX_ETHPORTS];
 	struct i40e_mac_filter *f;
-	int i, num;
+	int port_num = 0;
+	int i, num, j;
 	void *temp;
 	int ret;
 
@@ -4018,50 +4017,75 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 	}
 
 	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
-		i = 0;
-		num = vsi->mac_num;
-		mac_filter = rte_zmalloc("mac_filter_info_data",
-				 num * sizeof(*mac_filter), 0);
-		if (mac_filter == NULL) {
-			PMD_DRV_LOG(ERR, "failed to allocate memory");
-			return I40E_ERR_NO_MEMORY;
-		}
-
-		/*
-		 * Outer VLAN processing is supported after firmware v8.4, kernel driver
-		 * also change the default behavior to support this feature. To align with
-		 * kernel driver, set switch config in 'i40e_vlan_tpie_set' to support for
-		 * outer VLAN processing. But it is forbidden for firmware to change the
-		 * Inner/Outer VLAN configuration while there are MAC/VLAN filters in the
-		 * switch table. Therefore, we need to clear the MAC table before setting
-		 * config, and then restore the MAC table after setting. This feature is
-		 * recommended to be used in firmware v8.6.
-		 */
-		/* Remove all existing mac */
-		RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
-			mac_filter[i] = f->mac_info;
-			ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
-			if (ret)
-				PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
-			i++;
+		/*back up and clean mac/vlan filters of all ports*/
+		for (j = 0; j < RTE_MAX_ETHPORTS; j++) {
+			/*
+			 * It is impossible to confirm whether the port is pf
+			 * only through the state field, so it is also necessary
+			 * to verify the intr_handle field.
+			 */
+			if (rte_eth_devices[j].state != RTE_ETH_DEV_UNUSED &&
+							 rte_eth_devices[j].intr_handle) {
+				struct rte_eth_dev *tmp_dev = &rte_eth_devices[j];
+				struct i40e_pf *tmp_pf =
+					I40E_DEV_PRIVATE_TO_PF(tmp_dev->data->dev_private);
+				struct i40e_vsi *tmp_vsi = tmp_pf->main_vsi;
+				i = 0;
+				num = tmp_vsi->mac_num;
+				mac_filter = rte_zmalloc("mac_filter_info_data",
+						num * sizeof(*mac_filter), 0);
+				if (mac_filter == NULL) {
+					PMD_DRV_LOG(ERR, "failed to allocate memory");
+					return I40E_ERR_NO_MEMORY;
+				}
+				/*
+				 * Outer VLAN processing is supported after firmware v8.4,
+				 * kernel driver also change the default behavior to support
+				 * this feature. To align with kernel driver, set switch
+				 * config in 'i40e_vlan_tpid_set' to support for outer VLAN
+				 * processing. But it is forbidden for firmware to change the
+				 * Inner/Outer VLAN configuration while there are MAC/VLAN
+				 * filters in the switch table. Therefore, we need to clean
+				 * MAC/VLAN filters of all ports before setting config, and
+				 * then restore the MAC table after setting. This feature is
+				 * recommended to be used in firmware v8.6.
+				 */
+				/* Remove all existing mac */
+				RTE_TAILQ_FOREACH_SAFE(f, &tmp_vsi->mac_list, next, temp) {
+					mac_filter[i] = f->mac_info;
+					ret = i40e_vsi_delete_mac(tmp_vsi, &f->mac_info.mac_addr);
+					if (ret)
+						PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
+					i++;
+				}
+				vmac_filter[port_num] = mac_filter;
+				vvsi[port_num] = tmp_vsi;
+				vnum[port_num] = num;
+				port_num++;
+			}
 		}
 		if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND) {
 			i40e_vsi_config_double_vlan(vsi, TRUE);
-			/* Set global registers with default ethertype. */
-			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
-					   RTE_ETHER_TYPE_VLAN);
-			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
-					   RTE_ETHER_TYPE_VLAN);
+			if (!pf->fw8_3gt) {
+				/* Set global registers with default ethertype. */
+				i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
+							RTE_ETHER_TYPE_VLAN);
+				i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
+							RTE_ETHER_TYPE_VLAN);
+			}
 		} else {
 			i40e_vsi_config_double_vlan(vsi, FALSE);
 		}
-		/* Restore all mac */
-		for (i = 0; i < num; i++) {
-			ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
-			if (ret)
-				PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
+		/*restore mac/vlan filters of all ports*/
+		for (j = 0; j < port_num; j++) {
+			mac_filter = vmac_filter[j];
+			for (i = 0; i < vnum[j]; i++) {
+				ret = i40e_vsi_add_mac(vvsi[j], &mac_filter[i]);
+				if (ret)
+					PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
+			}
+			rte_free(mac_filter);
 		}
-		rte_free(mac_filter);
 	}
 
 	if (mask & RTE_ETH_QINQ_STRIP_MASK) {
@@ -6177,8 +6201,38 @@ static int
 i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on)
 {
 	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
+	u16 sw_flags = 0, valid_flags = 0;
+	int ret = 0;
+
+	if (pf->fw8_3gt) {
+		ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to set port params");
+			return -1;
+		}
+
+		if (on) {
+			sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_VLAN);
+		} else {
+			valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_QINQ);
+		}
+
+		ret = i40e_aq_set_switch_config(hw, sw_flags, valid_flags, 0, NULL);
+		if (ret) {
+			PMD_DRV_LOG(ERR,
+						"Set switch config failed aq_err: %d",
+						hw->aq.asq_last_status);
+			return -1;
+		}
+	} else {
+		ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+	}
 
-	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+	return ret;
 }
 
 static int
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3] net/i40e: fix single VLAN cannot work normal
  2022-08-18 16:03 [PATCH] net/i40e: fix single VLAN cannot work normal Kevin Liu
                   ` (2 preceding siblings ...)
  2022-09-06 11:40 ` [PATCH v2] " Kevin Liu
@ 2022-09-06 16:15 ` Kevin Liu
  2022-09-07  6:44   ` Zhang, Yuying
  2022-09-07 15:18 ` [PATCH v4] net/i40e: fix single VLAN cannot work normally Kevin Liu
  4 siblings, 1 reply; 9+ messages in thread
From: Kevin Liu @ 2022-09-06 16:15 UTC (permalink / raw)
  To: dev; +Cc: Yuying.Zhang, beilei.xing, stevex.yang, Kevin Liu, Jiale Song

After disable QinQ, single VLAN can not work normal.
The reason is that QinQ is not disabled correctly.

Before configuring QinQ, need to back up and clean
MAC/VLAN filters of all ports. After configuring QinQ,
restore MAC/VLAN filters of all ports. When disable
QinQ, need to set valid_flags to 0x0008 and set first_tag
to 0x88a8.

Fixes: 38e9762be16a ("net/i40e: add outer VLAN processing")
Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
Tested-by: Jiale Song <songx.jiale@intel.com>
---
v2: refine code
---
v3: refine code
---
 doc/guides/nics/i40e.rst       |   1 -
 drivers/net/i40e/i40e_ethdev.c | 147 ++++++++++++++++++++++-----------
 2 files changed, 100 insertions(+), 48 deletions(-)

diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst
index abb99406b3..15b796e67a 100644
--- a/doc/guides/nics/i40e.rst
+++ b/doc/guides/nics/i40e.rst
@@ -983,7 +983,6 @@ If FW version >= 8.4, there'll be some Vlan related issues:
 
 #. TCI input set for QinQ  is invalid.
 #. Fail to configure TPID for QinQ.
-#. Need to enable QinQ before enabling Vlan filter.
 #. Fail to strip outer Vlan.
 
 Example of getting best performance with l3fwd example
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 67d79de08d..cf327ed576 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -1650,7 +1650,8 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
 	vsi = pf->main_vsi;
 
 	/* Disable double vlan by default */
-	i40e_vsi_config_double_vlan(vsi, FALSE);
+	if (!pf->fw8_3gt)
+		i40e_vsi_config_double_vlan(vsi, FALSE);
 
 	/* Disable S-TAG identification when floating_veb is disabled */
 	if (!pf->floating_veb) {
@@ -3909,7 +3910,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	int qinq = dev->data->dev_conf.rxmode.offloads &
 		   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
-	u16 sw_flags = 0, valid_flags = 0;
 	int ret = 0;
 
 	if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER &&
@@ -3928,10 +3928,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 	/* 802.1ad frames ability is added in NVM API 1.7*/
 	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
 		if (qinq) {
-			if (pf->fw8_3gt) {
-				sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
-				valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
-			}
 			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
 				hw->first_tag = rte_cpu_to_le_16(tpid);
 			else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER)
@@ -3940,8 +3936,8 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
 				hw->second_tag = rte_cpu_to_le_16(tpid);
 		}
-		ret = i40e_aq_set_switch_config(hw, sw_flags,
-						valid_flags, 0, NULL);
+		ret = i40e_aq_set_switch_config(hw, 0,
+						0, 0, NULL);
 		if (ret != I40E_SUCCESS) {
 			PMD_DRV_LOG(ERR,
 				    "Set switch config failed aq_err: %d",
@@ -3993,11 +3989,15 @@ static int
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_mac_filter_info *vmac_filter[RTE_MAX_ETHPORTS];
+	struct i40e_vsi *vvsi[RTE_MAX_ETHPORTS];
 	struct i40e_mac_filter_info *mac_filter;
 	struct i40e_vsi *vsi = pf->main_vsi;
 	struct rte_eth_rxmode *rxmode;
+	int vnum[RTE_MAX_ETHPORTS];
 	struct i40e_mac_filter *f;
-	int i, num;
+	int port_num = 0;
+	int i, num, j;
 	void *temp;
 	int ret;
 
@@ -4018,50 +4018,75 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 	}
 
 	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
-		i = 0;
-		num = vsi->mac_num;
-		mac_filter = rte_zmalloc("mac_filter_info_data",
-				 num * sizeof(*mac_filter), 0);
-		if (mac_filter == NULL) {
-			PMD_DRV_LOG(ERR, "failed to allocate memory");
-			return I40E_ERR_NO_MEMORY;
-		}
-
-		/*
-		 * Outer VLAN processing is supported after firmware v8.4, kernel driver
-		 * also change the default behavior to support this feature. To align with
-		 * kernel driver, set switch config in 'i40e_vlan_tpie_set' to support for
-		 * outer VLAN processing. But it is forbidden for firmware to change the
-		 * Inner/Outer VLAN configuration while there are MAC/VLAN filters in the
-		 * switch table. Therefore, we need to clear the MAC table before setting
-		 * config, and then restore the MAC table after setting. This feature is
-		 * recommended to be used in firmware v8.6.
-		 */
-		/* Remove all existing mac */
-		RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
-			mac_filter[i] = f->mac_info;
-			ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
-			if (ret)
-				PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
-			i++;
+		/*back up and clean mac/vlan filters of all ports*/
+		for (j = 0; j < RTE_MAX_ETHPORTS; j++) {
+			/*
+			 * It is impossible to confirm whether the port is pf
+			 * only through the state field, so it is also necessary
+			 * to verify the intr_handle field.
+			 */
+			if (rte_eth_devices[j].state != RTE_ETH_DEV_UNUSED &&
+							 rte_eth_devices[j].intr_handle) {
+				struct rte_eth_dev *tmp_dev = &rte_eth_devices[j];
+				struct i40e_pf *tmp_pf =
+					I40E_DEV_PRIVATE_TO_PF(tmp_dev->data->dev_private);
+				struct i40e_vsi *tmp_vsi = tmp_pf->main_vsi;
+				i = 0;
+				num = tmp_vsi->mac_num;
+				mac_filter = rte_zmalloc("mac_filter_info_data",
+						num * sizeof(*mac_filter), 0);
+				if (mac_filter == NULL) {
+					PMD_DRV_LOG(ERR, "failed to allocate memory");
+					return I40E_ERR_NO_MEMORY;
+				}
+				/*
+				 * Outer VLAN processing is supported after firmware v8.4,
+				 * kernel driver also change the default behavior to support
+				 * this feature. To align with kernel driver, set switch
+				 * config in 'i40e_vlan_tpid_set' to support for outer VLAN
+				 * processing. But it is forbidden for firmware to change the
+				 * Inner/Outer VLAN configuration while there are MAC/VLAN
+				 * filters in the switch table. Therefore, we need to clean
+				 * MAC/VLAN filters of all ports before setting config, and
+				 * then restore the MAC table after setting. This feature is
+				 * recommended to be used in firmware v8.6.
+				 */
+				/* Remove all existing mac */
+				RTE_TAILQ_FOREACH_SAFE(f, &tmp_vsi->mac_list, next, temp) {
+					mac_filter[i] = f->mac_info;
+					ret = i40e_vsi_delete_mac(tmp_vsi, &f->mac_info.mac_addr);
+					if (ret)
+						PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
+					i++;
+				}
+				vmac_filter[port_num] = mac_filter;
+				vvsi[port_num] = tmp_vsi;
+				vnum[port_num] = num;
+				port_num++;
+			}
 		}
 		if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND) {
 			i40e_vsi_config_double_vlan(vsi, TRUE);
-			/* Set global registers with default ethertype. */
-			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
-					   RTE_ETHER_TYPE_VLAN);
-			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
-					   RTE_ETHER_TYPE_VLAN);
+			if (!pf->fw8_3gt) {
+				/* Set global registers with default ethertype. */
+				i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
+							RTE_ETHER_TYPE_VLAN);
+				i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
+							RTE_ETHER_TYPE_VLAN);
+			}
 		} else {
 			i40e_vsi_config_double_vlan(vsi, FALSE);
 		}
-		/* Restore all mac */
-		for (i = 0; i < num; i++) {
-			ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
-			if (ret)
-				PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
+		/*restore mac/vlan filters of all ports*/
+		for (j = 0; j < port_num; j++) {
+			mac_filter = vmac_filter[j];
+			for (i = 0; i < vnum[j]; i++) {
+				ret = i40e_vsi_add_mac(vvsi[j], &mac_filter[i]);
+				if (ret)
+					PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
+			}
+			rte_free(mac_filter);
 		}
-		rte_free(mac_filter);
 	}
 
 	if (mask & RTE_ETH_QINQ_STRIP_MASK) {
@@ -6177,8 +6202,36 @@ static int
 i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on)
 {
 	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
+	u16 sw_flags = 0, valid_flags = 0;
+	int ret = 0;
+
+	ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to set port params");
+		return -1;
+	}
 
-	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+	if (pf->fw8_3gt) {
+		if (on) {
+			sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_VLAN);
+		} else {
+			valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_QINQ);
+		}
+
+		ret = i40e_aq_set_switch_config(hw, sw_flags, valid_flags, 0, NULL);
+		if (ret) {
+			PMD_DRV_LOG(ERR,
+						"Set switch config failed aq_err: %d",
+					hw->aq.asq_last_status);
+			return -1;
+		}
+	}
+
+	return ret;
 }
 
 static int
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH v3] net/i40e: fix single VLAN cannot work normal
  2022-09-06 16:15 ` [PATCH v3] " Kevin Liu
@ 2022-09-07  6:44   ` Zhang, Yuying
  0 siblings, 0 replies; 9+ messages in thread
From: Zhang, Yuying @ 2022-09-07  6:44 UTC (permalink / raw)
  To: Liu, KevinX, dev; +Cc: Xing, Beilei, Yang, SteveX, Jiale, SongX

Hi,

> -----Original Message-----
> From: Liu, KevinX <kevinx.liu@intel.com>
> Sent: Wednesday, September 7, 2022 12:15 AM
> To: dev@dpdk.org
> Cc: Zhang, Yuying <yuying.zhang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Yang, SteveX <stevex.yang@intel.com>; Liu, KevinX
> <kevinx.liu@intel.com>; Jiale, SongX <songx.jiale@intel.com>
> Subject: [PATCH v3] net/i40e: fix single VLAN cannot work normal
> 
> After disable QinQ, single VLAN can not work normal.
> The reason is that QinQ is not disabled correctly.
> 
> Before configuring QinQ, need to back up and clean MAC/VLAN filters of all
> ports. After configuring QinQ, restore MAC/VLAN filters of all ports. When
> disable QinQ, need to set valid_flags to 0x0008 and set first_tag to 0x88a8.

Please correct grammar error of commit log and change numbers to macro definition for readability.

> 
> Fixes: 38e9762be16a ("net/i40e: add outer VLAN processing")
> Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
> Tested-by: Jiale Song <songx.jiale@intel.com>

Make sure new version has been validated before adding "tested-by".

> ---
> v2: refine code
> ---
> v3: refine code
> ---
>  doc/guides/nics/i40e.rst       |   1 -
>  drivers/net/i40e/i40e_ethdev.c | 147 ++++++++++++++++++++++-----------
>  2 files changed, 100 insertions(+), 48 deletions(-)
> 
> diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index
> abb99406b3..15b796e67a 100644
> --- a/doc/guides/nics/i40e.rst
> +++ b/doc/guides/nics/i40e.rst
> @@ -983,7 +983,6 @@ If FW version >= 8.4, there'll be some Vlan related issues:
> 
>  #. TCI input set for QinQ  is invalid.
>  #. Fail to configure TPID for QinQ.
> -#. Need to enable QinQ before enabling Vlan filter.
>  #. Fail to strip outer Vlan.
> 
>  Example of getting best performance with l3fwd example diff --git
> a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index
> 67d79de08d..cf327ed576 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
> @@ -1650,7 +1650,8 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void
> *init_params __rte_unused)
>  	vsi = pf->main_vsi;
> 
>  	/* Disable double vlan by default */
> -	i40e_vsi_config_double_vlan(vsi, FALSE);
> +	if (!pf->fw8_3gt)
> +		i40e_vsi_config_double_vlan(vsi, FALSE);

Disable double vlan by default no matter the firmware is.

> 
>  	/* Disable S-TAG identification when floating_veb is disabled */
>  	if (!pf->floating_veb) {
> @@ -3909,7 +3910,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data-
> >dev_private);
>  	int qinq = dev->data->dev_conf.rxmode.offloads &
>  		   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
> -	u16 sw_flags = 0, valid_flags = 0;
>  	int ret = 0;
> 
>  	if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER && @@ -3928,10
> +3928,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  	/* 802.1ad frames ability is added in NVM API 1.7*/
>  	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
>  		if (qinq) {
> -			if (pf->fw8_3gt) {
> -				sw_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> -				valid_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> -			}
>  			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
>  				hw->first_tag = rte_cpu_to_le_16(tpid);
>  			else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER) @@
> -3940,8 +3936,8 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
>  				hw->second_tag = rte_cpu_to_le_16(tpid);
>  		}
> -		ret = i40e_aq_set_switch_config(hw, sw_flags,
> -						valid_flags, 0, NULL);
> +		ret = i40e_aq_set_switch_config(hw, 0,
> +						0, 0, NULL);
>  		if (ret != I40E_SUCCESS) {
>  			PMD_DRV_LOG(ERR,
>  				    "Set switch config failed aq_err: %d", @@ -
> 3993,11 +3989,15 @@ static int  i40e_vlan_offload_set(struct rte_eth_dev *dev,
> int mask)  {
>  	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data-
> >dev_private);
> +	struct i40e_mac_filter_info *vmac_filter[RTE_MAX_ETHPORTS];
> +	struct i40e_vsi *vvsi[RTE_MAX_ETHPORTS];
>  	struct i40e_mac_filter_info *mac_filter;
>  	struct i40e_vsi *vsi = pf->main_vsi;
>  	struct rte_eth_rxmode *rxmode;
> +	int vnum[RTE_MAX_ETHPORTS];
>  	struct i40e_mac_filter *f;
> -	int i, num;
> +	int port_num = 0;
> +	int i, num, j;
>  	void *temp;
>  	int ret;
> 
> @@ -4018,50 +4018,75 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int
> mask)
>  	}
> 
>  	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
> -		i = 0;
> -		num = vsi->mac_num;
> -		mac_filter = rte_zmalloc("mac_filter_info_data",
> -				 num * sizeof(*mac_filter), 0);
> -		if (mac_filter == NULL) {
> -			PMD_DRV_LOG(ERR, "failed to allocate memory");
> -			return I40E_ERR_NO_MEMORY;
> -		}
> -
> -		/*
> -		 * Outer VLAN processing is supported after firmware v8.4,
> kernel driver
> -		 * also change the default behavior to support this feature. To
> align with
> -		 * kernel driver, set switch config in 'i40e_vlan_tpie_set' to
> support for
> -		 * outer VLAN processing. But it is forbidden for firmware to
> change the
> -		 * Inner/Outer VLAN configuration while there are MAC/VLAN
> filters in the
> -		 * switch table. Therefore, we need to clear the MAC table
> before setting
> -		 * config, and then restore the MAC table after setting. This
> feature is
> -		 * recommended to be used in firmware v8.6.
> -		 */
> -		/* Remove all existing mac */
> -		RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
> -			mac_filter[i] = f->mac_info;
> -			ret = i40e_vsi_delete_mac(vsi, &f-
> >mac_info.mac_addr);
> -			if (ret)
> -				PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
> -			i++;
> +		/*back up and clean mac/vlan filters of all ports*/
> +		for (j = 0; j < RTE_MAX_ETHPORTS; j++) {
> +			/*
> +			 * It is impossible to confirm whether the port is pf
> +			 * only through the state field, so it is also necessary
> +			 * to verify the intr_handle field.
> +			 */
> +			if (rte_eth_devices[j].state != RTE_ETH_DEV_UNUSED
> &&
> +
> rte_eth_devices[j].intr_handle) {
> +				struct rte_eth_dev *tmp_dev =
> &rte_eth_devices[j];
> +				struct i40e_pf *tmp_pf =
> +					I40E_DEV_PRIVATE_TO_PF(tmp_dev-
> >data->dev_private);
> +				struct i40e_vsi *tmp_vsi = tmp_pf->main_vsi;
> +				i = 0;
> +				num = tmp_vsi->mac_num;
> +				mac_filter =
> rte_zmalloc("mac_filter_info_data",
> +						num * sizeof(*mac_filter), 0);
> +				if (mac_filter == NULL) {
> +					PMD_DRV_LOG(ERR, "failed to
> allocate memory");
> +					return I40E_ERR_NO_MEMORY;
> +				}
> +				/*
> +				 * Outer VLAN processing is supported after
> firmware v8.4,
> +				 * kernel driver also change the default
> behavior to support
> +				 * this feature. To align with kernel driver, set
> switch
> +				 * config in 'i40e_vlan_tpid_set' to support for
> outer VLAN
> +				 * processing. But it is forbidden for firmware
> to change the
> +				 * Inner/Outer VLAN configuration while there
> are MAC/VLAN
> +				 * filters in the switch table. Therefore, we
> need to clean
> +				 * MAC/VLAN filters of all ports before setting
> config, and
> +				 * then restore the MAC table after setting. This
> feature is
> +				 * recommended to be used in firmware v8.6.
> +				 */
> +				/* Remove all existing mac */
> +				RTE_TAILQ_FOREACH_SAFE(f, &tmp_vsi-
> >mac_list, next, temp) {
> +					mac_filter[i] = f->mac_info;
> +					ret = i40e_vsi_delete_mac(tmp_vsi, &f-
> >mac_info.mac_addr);
> +					if (ret)
> +						PMD_DRV_LOG(ERR, "i40e vsi
> delete mac fail.");
> +					i++;
> +				}
> +				vmac_filter[port_num] = mac_filter;
> +				vvsi[port_num] = tmp_vsi;
> +				vnum[port_num] = num;
> +				port_num++;
> +			}
>  		}
>  		if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND)
> {
>  			i40e_vsi_config_double_vlan(vsi, TRUE);
> -			/* Set global registers with default ethertype. */
> -			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
> -					   RTE_ETHER_TYPE_VLAN);
> -			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
> -					   RTE_ETHER_TYPE_VLAN);
> +			if (!pf->fw8_3gt) {
> +				/* Set global registers with default ethertype.
> */
> +				i40e_vlan_tpid_set(dev,
> RTE_ETH_VLAN_TYPE_OUTER,
> +
> 	RTE_ETHER_TYPE_VLAN);
> +				i40e_vlan_tpid_set(dev,
> RTE_ETH_VLAN_TYPE_INNER,
> +
> 	RTE_ETHER_TYPE_VLAN);
> +			}
>  		} else {
>  			i40e_vsi_config_double_vlan(vsi, FALSE);
>  		}
> -		/* Restore all mac */
> -		for (i = 0; i < num; i++) {
> -			ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
> -			if (ret)
> -				PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
> +		/*restore mac/vlan filters of all ports*/
> +		for (j = 0; j < port_num; j++) {
> +			mac_filter = vmac_filter[j];
> +			for (i = 0; i < vnum[j]; i++) {
> +				ret = i40e_vsi_add_mac(vvsi[j], &mac_filter[i]);
> +				if (ret)
> +					PMD_DRV_LOG(ERR, "i40e vsi add mac
> fail.");
> +			}
> +			rte_free(mac_filter);
>  		}
> -		rte_free(mac_filter);
>  	}
> 
>  	if (mask & RTE_ETH_QINQ_STRIP_MASK) {
> @@ -6177,8 +6202,36 @@ static int
>  i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on)  {
>  	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
> +	struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
> +	u16 sw_flags = 0, valid_flags = 0;
> +	int ret = 0;
> +
> +	ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
> +	if (ret != I40E_SUCCESS) {
> +		PMD_DRV_LOG(ERR, "Failed to set port params");
> +		return -1;
> +	}
> 
> -	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
> +	if (pf->fw8_3gt) {
> +		if (on) {
> +			sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +			valid_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +			hw->first_tag =
> rte_cpu_to_le_16(RTE_ETHER_TYPE_VLAN);
> +		} else {
> +			valid_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +			hw->first_tag =
> rte_cpu_to_le_16(RTE_ETHER_TYPE_QINQ);
> +		}
> +
> +		ret = i40e_aq_set_switch_config(hw, sw_flags, valid_flags, 0,
> NULL);
> +		if (ret) {
> +			PMD_DRV_LOG(ERR,
> +						"Set switch config failed
> aq_err: %d",
> +					hw->aq.asq_last_status);
> +			return -1;
> +		}
> +	}
> +
> +	return ret;
>  }
> 
>  static int
> --
> 2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v4] net/i40e: fix single VLAN cannot work normally
  2022-08-18 16:03 [PATCH] net/i40e: fix single VLAN cannot work normal Kevin Liu
                   ` (3 preceding siblings ...)
  2022-09-06 16:15 ` [PATCH v3] " Kevin Liu
@ 2022-09-07 15:18 ` Kevin Liu
  2022-09-08  2:29   ` Zhang, Yuying
  4 siblings, 1 reply; 9+ messages in thread
From: Kevin Liu @ 2022-09-07 15:18 UTC (permalink / raw)
  To: dev; +Cc: Yuying.Zhang, beilei.xing, stevex.yang, Kevin Liu

After disabling QinQ, single VLAN can not work normally.
The reason is that QinQ is not disabled correctly.

Before configuring QinQ, need to back up and clean
MAC/VLAN filters of all ports. After configuring QinQ,
restore MAC/VLAN filters of all ports. When QinQ is
disabled, need to set valid_flags to
'I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN' and set first_tag
to 'RTE_ETHER_TYPE_QINQ'.

Fixes: 38e9762be16a ("net/i40e: add outer VLAN processing")
Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
---
v2: refine code
---
v3: refine code
---
v4: refine code and commit log
---
 doc/guides/nics/i40e.rst       |   1 -
 drivers/net/i40e/i40e_ethdev.c | 156 ++++++++++++++++++++++-----------
 2 files changed, 104 insertions(+), 53 deletions(-)

diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst
index abb99406b3..15b796e67a 100644
--- a/doc/guides/nics/i40e.rst
+++ b/doc/guides/nics/i40e.rst
@@ -983,7 +983,6 @@ If FW version >= 8.4, there'll be some Vlan related issues:
 
 #. TCI input set for QinQ  is invalid.
 #. Fail to configure TPID for QinQ.
-#. Need to enable QinQ before enabling Vlan filter.
 #. Fail to strip outer Vlan.
 
 Example of getting best performance with l3fwd example
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 67d79de08d..4fb0993cc2 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -3909,7 +3909,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 	int qinq = dev->data->dev_conf.rxmode.offloads &
 		   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
-	u16 sw_flags = 0, valid_flags = 0;
 	int ret = 0;
 
 	if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER &&
@@ -3928,10 +3927,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 	/* 802.1ad frames ability is added in NVM API 1.7*/
 	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
 		if (qinq) {
-			if (pf->fw8_3gt) {
-				sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
-				valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
-			}
 			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
 				hw->first_tag = rte_cpu_to_le_16(tpid);
 			else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER)
@@ -3940,8 +3935,8 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
 			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
 				hw->second_tag = rte_cpu_to_le_16(tpid);
 		}
-		ret = i40e_aq_set_switch_config(hw, sw_flags,
-						valid_flags, 0, NULL);
+		ret = i40e_aq_set_switch_config(hw, 0,
+						0, 0, NULL);
 		if (ret != I40E_SUCCESS) {
 			PMD_DRV_LOG(ERR,
 				    "Set switch config failed aq_err: %d",
@@ -3993,13 +3988,8 @@ static int
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
 	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-	struct i40e_mac_filter_info *mac_filter;
 	struct i40e_vsi *vsi = pf->main_vsi;
 	struct rte_eth_rxmode *rxmode;
-	struct i40e_mac_filter *f;
-	int i, num;
-	void *temp;
-	int ret;
 
 	rxmode = &dev->data->dev_conf.rxmode;
 	if (mask & RTE_ETH_VLAN_FILTER_MASK) {
@@ -4018,50 +4008,18 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 	}
 
 	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
-		i = 0;
-		num = vsi->mac_num;
-		mac_filter = rte_zmalloc("mac_filter_info_data",
-				 num * sizeof(*mac_filter), 0);
-		if (mac_filter == NULL) {
-			PMD_DRV_LOG(ERR, "failed to allocate memory");
-			return I40E_ERR_NO_MEMORY;
-		}
-
-		/*
-		 * Outer VLAN processing is supported after firmware v8.4, kernel driver
-		 * also change the default behavior to support this feature. To align with
-		 * kernel driver, set switch config in 'i40e_vlan_tpie_set' to support for
-		 * outer VLAN processing. But it is forbidden for firmware to change the
-		 * Inner/Outer VLAN configuration while there are MAC/VLAN filters in the
-		 * switch table. Therefore, we need to clear the MAC table before setting
-		 * config, and then restore the MAC table after setting. This feature is
-		 * recommended to be used in firmware v8.6.
-		 */
-		/* Remove all existing mac */
-		RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
-			mac_filter[i] = f->mac_info;
-			ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
-			if (ret)
-				PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
-			i++;
-		}
 		if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND) {
 			i40e_vsi_config_double_vlan(vsi, TRUE);
-			/* Set global registers with default ethertype. */
-			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
-					   RTE_ETHER_TYPE_VLAN);
-			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
-					   RTE_ETHER_TYPE_VLAN);
+			if (!pf->fw8_3gt) {
+				/* Set global registers with default ethertype. */
+				i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
+							RTE_ETHER_TYPE_VLAN);
+				i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
+							RTE_ETHER_TYPE_VLAN);
+			}
 		} else {
 			i40e_vsi_config_double_vlan(vsi, FALSE);
 		}
-		/* Restore all mac */
-		for (i = 0; i < num; i++) {
-			ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
-			if (ret)
-				PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
-		}
-		rte_free(mac_filter);
 	}
 
 	if (mask & RTE_ETH_QINQ_STRIP_MASK) {
@@ -6176,9 +6134,103 @@ i40e_dev_init_vlan(struct rte_eth_dev *dev)
 static int
 i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on)
 {
+	struct i40e_mac_filter_info *vmac_filter[RTE_MAX_ETHPORTS];
 	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
+	struct i40e_vsi *vvsi[RTE_MAX_ETHPORTS];
+	struct i40e_mac_filter_info *mac_filter;
+	u16 sw_flags = 0, valid_flags = 0;
+	int vnum[RTE_MAX_ETHPORTS];
+	struct i40e_mac_filter *f;
+	int port_num = 0;
+	int i, num, j;
+	void *temp;
+	int ret = 0;
 
-	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+	ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to set port params");
+		return -1;
+	}
+
+	if (pf->fw8_3gt) {
+		/* back up and clean mac/vlan filters of all ports */
+		for (j = 0; j < RTE_MAX_ETHPORTS; j++) {
+			/*
+			 * It is impossible to confirm whether the port is pf
+			 * only through the state field, so it is also necessary
+			 * to verify the intr_handle field.
+			 */
+			if (rte_eth_devices[j].state != RTE_ETH_DEV_UNUSED &&
+							 rte_eth_devices[j].intr_handle) {
+				struct rte_eth_dev *tmp_dev = &rte_eth_devices[j];
+				struct i40e_pf *tmp_pf =
+					I40E_DEV_PRIVATE_TO_PF(tmp_dev->data->dev_private);
+				struct i40e_vsi *tmp_vsi = tmp_pf->main_vsi;
+				i = 0;
+				num = tmp_vsi->mac_num;
+				mac_filter = rte_zmalloc("mac_filter_info_data",
+						num * sizeof(*mac_filter), 0);
+				if (mac_filter == NULL) {
+					PMD_DRV_LOG(ERR, "failed to allocate memory");
+					return I40E_ERR_NO_MEMORY;
+				}
+				/*
+				 * Outer VLAN processing is supported after firmware v8.4,
+				 * kernel driver also change the default behavior to support
+				 * this feature. To align with kernel driver, set switch
+				 * config in 'i40e_vlan_tpid_set' to support for outer VLAN
+				 * processing. But it is forbidden for firmware to change the
+				 * Inner/Outer VLAN configuration while there are MAC/VLAN
+				 * filters in the switch table. Therefore, we need to clean
+				 * MAC/VLAN filters of all ports before setting config, and
+				 * then restore the MAC table after setting. This feature is
+				 * recommended to be used in firmware v8.6.
+				 */
+				/* Remove all existing mac */
+				RTE_TAILQ_FOREACH_SAFE(f, &tmp_vsi->mac_list, next, temp) {
+					mac_filter[i] = f->mac_info;
+					ret = i40e_vsi_delete_mac(tmp_vsi, &f->mac_info.mac_addr);
+					if (ret)
+						PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
+					i++;
+				}
+				vmac_filter[port_num] = mac_filter;
+				vvsi[port_num] = tmp_vsi;
+				vnum[port_num] = num;
+				port_num++;
+			}
+		}
+
+		if (on) {
+			sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_VLAN);
+		} else {
+			valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+			hw->first_tag = rte_cpu_to_le_16(RTE_ETHER_TYPE_QINQ);
+		}
+
+		ret = i40e_aq_set_switch_config(hw, sw_flags, valid_flags, 0, NULL);
+		if (ret) {
+			PMD_DRV_LOG(ERR,
+						"Set switch config failed aq_err: %d",
+					hw->aq.asq_last_status);
+		}
+
+		/* restore mac/vlan filters of all ports */
+		for (j = 0; j < port_num; j++) {
+			mac_filter = vmac_filter[j];
+			for (i = 0; i < vnum[j]; i++) {
+				ret = i40e_vsi_add_mac(vvsi[j], &mac_filter[i]);
+				if (ret)
+					PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
+			}
+			rte_free(mac_filter);
+		}
+	}
+
+	return ret;
 }
 
 static int
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH v4] net/i40e: fix single VLAN cannot work normally
  2022-09-07 15:18 ` [PATCH v4] net/i40e: fix single VLAN cannot work normally Kevin Liu
@ 2022-09-08  2:29   ` Zhang, Yuying
  0 siblings, 0 replies; 9+ messages in thread
From: Zhang, Yuying @ 2022-09-08  2:29 UTC (permalink / raw)
  To: Liu, KevinX, dev; +Cc: Xing, Beilei, Yang, SteveX

Hi,

> -----Original Message-----
> From: Liu, KevinX <kevinx.liu@intel.com>
> Sent: Wednesday, September 7, 2022 11:18 PM
> To: dev@dpdk.org
> Cc: Zhang, Yuying <yuying.zhang@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Yang, SteveX <stevex.yang@intel.com>; Liu, KevinX
> <kevinx.liu@intel.com>
> Subject: [PATCH v4] net/i40e: fix single VLAN cannot work normally
> 
> After disabling QinQ, single VLAN can not work normally.
> The reason is that QinQ is not disabled correctly.
> 
> Before configuring QinQ, need to back up and clean MAC/VLAN filters of all
> ports. After configuring QinQ, restore MAC/VLAN filters of all ports. When QinQ
> is disabled, need to set valid_flags to
> 'I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN' and set first_tag to
> 'RTE_ETHER_TYPE_QINQ'.
> 
> Fixes: 38e9762be16a ("net/i40e: add outer VLAN processing")
> Signed-off-by: Kevin Liu <kevinx.liu@intel.com>
> ---
> v2: refine code
> ---
> v3: refine code
> ---
> v4: refine code and commit log
> ---
>  doc/guides/nics/i40e.rst       |   1 -
>  drivers/net/i40e/i40e_ethdev.c | 156 ++++++++++++++++++++++-----------
>  2 files changed, 104 insertions(+), 53 deletions(-)
> 
> diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst index
> abb99406b3..15b796e67a 100644
> --- a/doc/guides/nics/i40e.rst
> +++ b/doc/guides/nics/i40e.rst
> @@ -983,7 +983,6 @@ If FW version >= 8.4, there'll be some Vlan related issues:
> 
>  #. TCI input set for QinQ  is invalid.
>  #. Fail to configure TPID for QinQ.
> -#. Need to enable QinQ before enabling Vlan filter.
>  #. Fail to strip outer Vlan.
> 
>  Example of getting best performance with l3fwd example diff --git
> a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index
> 67d79de08d..4fb0993cc2 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
> @@ -3909,7 +3909,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data-
> >dev_private);
>  	int qinq = dev->data->dev_conf.rxmode.offloads &
>  		   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
> -	u16 sw_flags = 0, valid_flags = 0;
>  	int ret = 0;
> 
>  	if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER && @@ -3928,10
> +3927,6 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  	/* 802.1ad frames ability is added in NVM API 1.7*/
>  	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
>  		if (qinq) {
> -			if (pf->fw8_3gt) {
> -				sw_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> -				valid_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> -			}
>  			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
>  				hw->first_tag = rte_cpu_to_le_16(tpid);
>  			else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER) @@
> -3940,8 +3935,8 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
>  			if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
>  				hw->second_tag = rte_cpu_to_le_16(tpid);
>  		}
> -		ret = i40e_aq_set_switch_config(hw, sw_flags,
> -						valid_flags, 0, NULL);
> +		ret = i40e_aq_set_switch_config(hw, 0,
> +						0, 0, NULL);
>  		if (ret != I40E_SUCCESS) {
>  			PMD_DRV_LOG(ERR,
>  				    "Set switch config failed aq_err: %d", @@ -
> 3993,13 +3988,8 @@ static int  i40e_vlan_offload_set(struct rte_eth_dev *dev,
> int mask)  {
>  	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data-
> >dev_private);
> -	struct i40e_mac_filter_info *mac_filter;
>  	struct i40e_vsi *vsi = pf->main_vsi;
>  	struct rte_eth_rxmode *rxmode;
> -	struct i40e_mac_filter *f;
> -	int i, num;
> -	void *temp;
> -	int ret;
> 
>  	rxmode = &dev->data->dev_conf.rxmode;
>  	if (mask & RTE_ETH_VLAN_FILTER_MASK) { @@ -4018,50 +4008,18
> @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
>  	}
> 
>  	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
> -		i = 0;
> -		num = vsi->mac_num;
> -		mac_filter = rte_zmalloc("mac_filter_info_data",
> -				 num * sizeof(*mac_filter), 0);
> -		if (mac_filter == NULL) {
> -			PMD_DRV_LOG(ERR, "failed to allocate memory");
> -			return I40E_ERR_NO_MEMORY;
> -		}
> -
> -		/*
> -		 * Outer VLAN processing is supported after firmware v8.4,
> kernel driver
> -		 * also change the default behavior to support this feature. To
> align with
> -		 * kernel driver, set switch config in 'i40e_vlan_tpie_set' to
> support for
> -		 * outer VLAN processing. But it is forbidden for firmware to
> change the
> -		 * Inner/Outer VLAN configuration while there are MAC/VLAN
> filters in the
> -		 * switch table. Therefore, we need to clear the MAC table
> before setting
> -		 * config, and then restore the MAC table after setting. This
> feature is
> -		 * recommended to be used in firmware v8.6.
> -		 */
> -		/* Remove all existing mac */
> -		RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
> -			mac_filter[i] = f->mac_info;
> -			ret = i40e_vsi_delete_mac(vsi, &f-
> >mac_info.mac_addr);
> -			if (ret)
> -				PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");
> -			i++;
> -		}
>  		if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND)
> {
>  			i40e_vsi_config_double_vlan(vsi, TRUE);
> -			/* Set global registers with default ethertype. */
> -			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
> -					   RTE_ETHER_TYPE_VLAN);
> -			i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
> -					   RTE_ETHER_TYPE_VLAN);
> +			if (!pf->fw8_3gt) {
> +				/* Set global registers with default ethertype.
> */
> +				i40e_vlan_tpid_set(dev,
> RTE_ETH_VLAN_TYPE_OUTER,
> +
> 	RTE_ETHER_TYPE_VLAN);
> +				i40e_vlan_tpid_set(dev,
> RTE_ETH_VLAN_TYPE_INNER,
> +
> 	RTE_ETHER_TYPE_VLAN);
> +			}
>  		} else {
>  			i40e_vsi_config_double_vlan(vsi, FALSE);
>  		}
> -		/* Restore all mac */
> -		for (i = 0; i < num; i++) {
> -			ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
> -			if (ret)
> -				PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");
> -		}
> -		rte_free(mac_filter);
>  	}
> 
>  	if (mask & RTE_ETH_QINQ_STRIP_MASK) {
> @@ -6176,9 +6134,103 @@ i40e_dev_init_vlan(struct rte_eth_dev *dev)  static
> int  i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on)  {
> +	struct i40e_mac_filter_info *vmac_filter[RTE_MAX_ETHPORTS];
>  	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
> +	struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
> +	struct i40e_vsi *vvsi[RTE_MAX_ETHPORTS];
> +	struct i40e_mac_filter_info *mac_filter;
> +	u16 sw_flags = 0, valid_flags = 0;
> +	int vnum[RTE_MAX_ETHPORTS];
> +	struct i40e_mac_filter *f;
> +	int port_num = 0;
> +	int i, num, j;
> +	void *temp;
> +	int ret = 0;
> 
> -	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
> +	ret = i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
> +	if (ret != I40E_SUCCESS) {
> +		PMD_DRV_LOG(ERR, "Failed to set port params");
> +		return -1;
> +	}
> +
> +	if (pf->fw8_3gt) {
> +		/* back up and clean mac/vlan filters of all ports */
> +		for (j = 0; j < RTE_MAX_ETHPORTS; j++) {
> +			/*
> +			 * It is impossible to confirm whether the port is pf
> +			 * only through the state field, so it is also necessary
> +			 * to verify the intr_handle field.
> +			 */
> +			if (rte_eth_devices[j].state != RTE_ETH_DEV_UNUSED
> &&
> +
> rte_eth_devices[j].intr_handle) {

Use vsi_id to check if dev is pf, not intr_handle or you can delete this validation since just main_vsi will be transfer to this function.

> +				struct rte_eth_dev *tmp_dev =
> &rte_eth_devices[j];
> +				struct i40e_pf *tmp_pf =
> +					I40E_DEV_PRIVATE_TO_PF(tmp_dev-
> >data->dev_private);
> +				struct i40e_vsi *tmp_vsi = tmp_pf->main_vsi;
> +				i = 0;
> +				num = tmp_vsi->mac_num;
> +				mac_filter =
> rte_zmalloc("mac_filter_info_data",
> +						num * sizeof(*mac_filter), 0);
> +				if (mac_filter == NULL) {
> +					PMD_DRV_LOG(ERR, "failed to
> allocate memory");
> +					return I40E_ERR_NO_MEMORY;
> +				}
> +				/*
> +				 * Outer VLAN processing is supported after
> firmware v8.4,
> +				 * kernel driver also change the default
> behavior to support
> +				 * this feature. To align with kernel driver, set
> switch
> +				 * config in 'i40e_vlan_tpid_set' to support for
> outer VLAN
> +				 * processing. But it is forbidden for firmware
> to change the
> +				 * Inner/Outer VLAN configuration while there
> are MAC/VLAN
> +				 * filters in the switch table. Therefore, we
> need to clean
> +				 * MAC/VLAN filters of all ports before setting
> config, and
> +				 * then restore the MAC table after setting. This
> feature is
> +				 * recommended to be used in firmware v8.6.
> +				 */
> +				/* Remove all existing mac */
> +				RTE_TAILQ_FOREACH_SAFE(f, &tmp_vsi-
> >mac_list, next, temp) {
> +					mac_filter[i] = f->mac_info;
> +					ret = i40e_vsi_delete_mac(tmp_vsi, &f-
> >mac_info.mac_addr);
> +					if (ret)
> +						PMD_DRV_LOG(ERR, "i40e vsi
> delete mac fail.");
> +					i++;
> +				}
> +				vmac_filter[port_num] = mac_filter;
> +				vvsi[port_num] = tmp_vsi;
> +				vnum[port_num] = num;
> +				port_num++;
> +			}
> +		}
> +
> +		if (on) {
> +			sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +			valid_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +			hw->first_tag =
> rte_cpu_to_le_16(RTE_ETHER_TYPE_VLAN);
> +		} else {
> +			valid_flags =
> I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
> +			hw->first_tag =
> rte_cpu_to_le_16(RTE_ETHER_TYPE_QINQ);
> +		}
> +
> +		ret = i40e_aq_set_switch_config(hw, sw_flags, valid_flags, 0,
> NULL);
> +		if (ret) {
> +			PMD_DRV_LOG(ERR,
> +						"Set switch config failed
> aq_err: %d",
> +					hw->aq.asq_last_status);
> +		}
> +
> +		/* restore mac/vlan filters of all ports */
> +		for (j = 0; j < port_num; j++) {
> +			mac_filter = vmac_filter[j];
> +			for (i = 0; i < vnum[j]; i++) {
> +				ret = i40e_vsi_add_mac(vvsi[j], &mac_filter[i]);
> +				if (ret)
> +					PMD_DRV_LOG(ERR, "i40e vsi add mac
> fail.");
> +			}
> +			rte_free(mac_filter);
> +		}
> +	}
> +
> +	return ret;
>  }
> 
>  static int
> --
> 2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-09-08  2:29 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-18 16:03 [PATCH] net/i40e: fix single VLAN cannot work normal Kevin Liu
2022-08-19  1:43 ` Jiale, SongX
2022-09-06  2:15 ` Zhang, Yuying
2022-09-06  3:32   ` Liu, KevinX
2022-09-06 11:40 ` [PATCH v2] " Kevin Liu
2022-09-06 16:15 ` [PATCH v3] " Kevin Liu
2022-09-07  6:44   ` Zhang, Yuying
2022-09-07 15:18 ` [PATCH v4] net/i40e: fix single VLAN cannot work normally Kevin Liu
2022-09-08  2:29   ` Zhang, Yuying

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).