net/hns3: fix VLAN filter when setting promisucous mode
authorChengchang Tang <tangchengchang@huawei.com>
Fri, 10 Apr 2020 11:09:30 +0000 (19:09 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 21 Apr 2020 11:57:07 +0000 (13:57 +0200)
Currently, when upper level application call the API function named
rte_eth_dev_set_vlan_offload to configure the hardware vlan filter
offload and call the rte_eth_promiscuous_enable API to enable
promiscuous mode based on hns3 PF device, driver can't receive the
packets with a vlan tag which has not been added by calling the API
function named rte_eth_dev_vlan_filter.

This patch fixes it by disabling the vlan filter when setting the
promiscuous mode and enabling the vlan filter again after the
promiscuous mode are disabled.

Fixes: 19a3ca4c99cf ("net/hns3: add start/stop and configure operations")
Cc: stable@dpdk.org
Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
drivers/net/hns3/hns3_ethdev.c

index bab4312..3e3a8c5 100644 (file)
@@ -607,16 +607,19 @@ hns3_vlan_offload_set(struct rte_eth_dev *dev, int mask)
        rxmode = &dev->data->dev_conf.rxmode;
        tmp_mask = (unsigned int)mask;
        if (tmp_mask & ETH_VLAN_FILTER_MASK) {
-               /* Enable or disable VLAN filter */
-               enable = rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER ?
-                   true : false;
+               /* ignore vlan filter configuration during promiscuous mode */
+               if (!dev->data->promiscuous) {
+                       /* Enable or disable VLAN filter */
+                       enable = rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER ?
+                                true : false;
 
-               ret = hns3_enable_vlan_filter(hns, enable);
-               if (ret) {
-                       rte_spinlock_unlock(&hw->lock);
-                       hns3_err(hw, "failed to %s rx filter, ret = %d",
-                                enable ? "enable" : "disable", ret);
-                       return ret;
+                       ret = hns3_enable_vlan_filter(hns, enable);
+                       if (ret) {
+                               rte_spinlock_unlock(&hw->lock);
+                               hns3_err(hw, "failed to %s rx filter, ret = %d",
+                                        enable ? "enable" : "disable", ret);
+                               return ret;
+                       }
                }
        }
 
@@ -1002,14 +1005,16 @@ hns3_restore_vlan_conf(struct hns3_adapter *hns)
        bool enable;
        int ret;
 
-       /* restore vlan filter states */
-       offloads = hw->data->dev_conf.rxmode.offloads;
-       enable = offloads & DEV_RX_OFFLOAD_VLAN_FILTER ? true : false;
-       ret = hns3_enable_vlan_filter(hns, enable);
-       if (ret) {
-               hns3_err(hw, "failed to restore vlan rx filter conf, ret = %d",
-                        ret);
-               return ret;
+       if (!hw->data->promiscuous) {
+               /* restore vlan filter states */
+               offloads = hw->data->dev_conf.rxmode.offloads;
+               enable = offloads & DEV_RX_OFFLOAD_VLAN_FILTER ? true : false;
+               ret = hns3_enable_vlan_filter(hns, enable);
+               if (ret) {
+                       hns3_err(hw, "failed to restore vlan rx filter conf, "
+                                "ret = %d", ret);
+                       return ret;
+               }
        }
 
        ret = hns3_set_vlan_rx_offload_cfg(hns, &pf->vtag_config.rx_vcfg);
@@ -3830,16 +3835,43 @@ hns3_clear_all_vfs_promisc_mode(struct hns3_hw *hw)
 static int
 hns3_dev_promiscuous_enable(struct rte_eth_dev *dev)
 {
+       bool allmulti = dev->data->all_multicast ? true : false;
        struct hns3_adapter *hns = dev->data->dev_private;
        struct hns3_hw *hw = &hns->hw;
+       uint64_t offloads;
+       int err;
        int ret;
 
        rte_spinlock_lock(&hw->lock);
        ret = hns3_set_promisc_mode(hw, true, true);
-       rte_spinlock_unlock(&hw->lock);
-       if (ret)
-               hns3_err(hw, "Failed to enable promiscuous mode, ret = %d",
+       if (ret) {
+               rte_spinlock_unlock(&hw->lock);
+               hns3_err(hw, "failed to enable promiscuous mode, ret = %d",
                         ret);
+               return ret;
+       }
+
+       /*
+        * When promiscuous mode was enabled, disable the vlan filter to let
+        * all packets coming in in the receiving direction.
+        */
+       offloads = dev->data->dev_conf.rxmode.offloads;
+       if (offloads & DEV_RX_OFFLOAD_VLAN_FILTER) {
+               ret = hns3_enable_vlan_filter(hns, false);
+               if (ret) {
+                       hns3_err(hw, "failed to enable promiscuous mode due to "
+                                    "failure to disable vlan filter, ret = %d",
+                                ret);
+                       err = hns3_set_promisc_mode(hw, false, allmulti);
+                       if (err)
+                               hns3_err(hw, "failed to restore promiscuous "
+                                        "status after disable vlan filter "
+                                        "failed during enabling promiscuous "
+                                        "mode, ret = %d", ret);
+               }
+       }
+
+       rte_spinlock_unlock(&hw->lock);
 
        return ret;
 }
@@ -3850,15 +3882,36 @@ hns3_dev_promiscuous_disable(struct rte_eth_dev *dev)
        bool allmulti = dev->data->all_multicast ? true : false;
        struct hns3_adapter *hns = dev->data->dev_private;
        struct hns3_hw *hw = &hns->hw;
+       uint64_t offloads;
+       int err;
        int ret;
 
        /* If now in all_multicast mode, must remain in all_multicast mode. */
        rte_spinlock_lock(&hw->lock);
        ret = hns3_set_promisc_mode(hw, false, allmulti);
-       rte_spinlock_unlock(&hw->lock);
-       if (ret)
-               hns3_err(hw, "Failed to disable promiscuous mode, ret = %d",
+       if (ret) {
+               rte_spinlock_unlock(&hw->lock);
+               hns3_err(hw, "failed to disable promiscuous mode, ret = %d",
                         ret);
+               return ret;
+       }
+       /* when promiscuous mode was disabled, restore the vlan filter status */
+       offloads = dev->data->dev_conf.rxmode.offloads;
+       if (offloads & DEV_RX_OFFLOAD_VLAN_FILTER) {
+               ret = hns3_enable_vlan_filter(hns, true);
+               if (ret) {
+                       hns3_err(hw, "failed to disable promiscuous mode due to"
+                                " failure to restore vlan filter, ret = %d",
+                                ret);
+                       err = hns3_set_promisc_mode(hw, true, true);
+                       if (err)
+                               hns3_err(hw, "failed to restore promiscuous "
+                                        "status after enabling vlan filter "
+                                        "failed during disabling promiscuous "
+                                        "mode, ret = %d", ret);
+               }
+       }
+       rte_spinlock_unlock(&hw->lock);
 
        return ret;
 }
@@ -3877,7 +3930,7 @@ hns3_dev_allmulticast_enable(struct rte_eth_dev *dev)
        ret = hns3_set_promisc_mode(hw, false, true);
        rte_spinlock_unlock(&hw->lock);
        if (ret)
-               hns3_err(hw, "Failed to enable allmulticast mode, ret = %d",
+               hns3_err(hw, "failed to enable allmulticast mode, ret = %d",
                         ret);
 
        return ret;
@@ -3898,7 +3951,7 @@ hns3_dev_allmulticast_disable(struct rte_eth_dev *dev)
        ret = hns3_set_promisc_mode(hw, false, false);
        rte_spinlock_unlock(&hw->lock);
        if (ret)
-               hns3_err(hw, "Failed to disable allmulticast mode, ret =  %d",
+               hns3_err(hw, "failed to disable allmulticast mode, ret = %d",
                         ret);
 
        return ret;
@@ -3909,11 +3962,21 @@ hns3_dev_promisc_restore(struct hns3_adapter *hns)
 {
        struct hns3_hw *hw = &hns->hw;
        bool allmulti = hw->data->all_multicast ? true : false;
+       int ret;
 
-       if (hw->data->promiscuous)
-               return hns3_set_promisc_mode(hw, true, true);
+       if (hw->data->promiscuous) {
+               ret = hns3_set_promisc_mode(hw, true, true);
+               if (ret)
+                       hns3_err(hw, "failed to restore promiscuous mode, "
+                                "ret = %d", ret);
+               return ret;
+       }
 
-       return hns3_set_promisc_mode(hw, false, allmulti);
+       ret = hns3_set_promisc_mode(hw, false, allmulti);
+       if (ret)
+               hns3_err(hw, "failed to restore allmulticast mode, ret = %d",
+                        ret);
+       return ret;
 }
 
 static int