]> git.baikalelectronics.ru Git - kernel.git/commitdiff
iavf: remove current MAC address filter on VF reset
authorStefan Assmann <sassmann@kpanic.de>
Tue, 17 Dec 2019 10:29:23 +0000 (11:29 +0100)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 9 Jan 2020 17:21:40 +0000 (09:21 -0800)
Currently MAC filters are not altered during a VF reset event. This may
lead to a stale filter when an administratively set MAC is forced by the
PF.

For an administratively set MAC the PF driver deletes the VFs filters,
overwrites the VFs MAC address and triggers a VF reset. However
the VF driver itself is not aware of the filter removal, which is what
the VF reset is for.
The VF reset queues all filters present in the VF driver to be re-added
to the PF filter list (including the filter for the now stale VF MAC
address) and triggers a VIRTCHNL_OP_GET_VF_RESOURCES event, which
provides the new MAC address to the VF.

When this happens i40e will complain and reject the stale MAC filter,
at least in the untrusted VF case.
i40e 0000:08:00.0: Setting MAC 3c:fa:fa:fa:fa:01 on VF 0
iavf 0000:08:02.0: Reset warning received from the PF
iavf 0000:08:02.0: Scheduling reset task
i40e 0000:08:00.0: Bring down and up the VF interface to make this change effective.
i40e 0000:08:00.0: VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation
i40e 0000:08:00.0: VF 0 failed opcode 10, retval: -1
iavf 0000:08:02.0: Failed to add MAC filter, error IAVF_ERR_NVM

To avoid re-adding the stale MAC filter it needs to be removed from the
VF driver's filter list before queuing the existing filters. Then during
the VIRTCHNL_OP_GET_VF_RESOURCES event the correct filter needs to be
added again, at which point the MAC address has been updated.

As a bonus this change makes bringing the VF down and up again
superfluous for the administratively set MAC case.

Signed-off-by: Stefan Assmann <sassmann@kpanic.de>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c

index 29de3ae96ef222d7545abead8c9004bacb312561..bd1b1ed323f4fe9e16134d31b99aad7341b5e89c 100644 (file)
@@ -415,4 +415,6 @@ void iavf_enable_channels(struct iavf_adapter *adapter);
 void iavf_disable_channels(struct iavf_adapter *adapter);
 void iavf_add_cloud_filter(struct iavf_adapter *adapter);
 void iavf_del_cloud_filter(struct iavf_adapter *adapter);
+struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
+                                       const u8 *macaddr);
 #endif /* _IAVF_H_ */
index 821987da5698ac8cf0468ac90e6f0fee460916ba..8e16be960e96b64196285916e268035cedf70449 100644 (file)
@@ -743,9 +743,8 @@ iavf_mac_filter *iavf_find_filter(struct iavf_adapter *adapter,
  *
  * Returns ptr to the filter object or NULL when no memory available.
  **/
-static struct
-iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
-                                const u8 *macaddr)
+struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
+                                       const u8 *macaddr)
 {
        struct iavf_mac_filter *f;
 
@@ -2065,9 +2064,9 @@ static void iavf_reset_task(struct work_struct *work)
        struct virtchnl_vf_resource *vfres = adapter->vf_res;
        struct net_device *netdev = adapter->netdev;
        struct iavf_hw *hw = &adapter->hw;
+       struct iavf_mac_filter *f, *ftmp;
        struct iavf_vlan_filter *vlf;
        struct iavf_cloud_filter *cf;
-       struct iavf_mac_filter *f;
        u32 reg_val;
        int i = 0, err;
        bool running;
@@ -2181,6 +2180,16 @@ continue_reset:
 
        spin_lock_bh(&adapter->mac_vlan_list_lock);
 
+       /* Delete filter for the current MAC address, it could have
+        * been changed by the PF via administratively set MAC.
+        * Will be re-added via VIRTCHNL_OP_GET_VF_RESOURCES.
+        */
+       list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
+               if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr)) {
+                       list_del(&f->list);
+                       kfree(f);
+               }
+       }
        /* re-add all MAC filters */
        list_for_each_entry(f, &adapter->mac_filter_list, list) {
                f->add = true;
index c46770eba320e6b8a05d67e566db95da1636e506..1ab9cb339acb4d195c4433d9fc0254189586cc6b 100644 (file)
@@ -1359,6 +1359,9 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                        ether_addr_copy(netdev->perm_addr,
                                        adapter->hw.mac.addr);
                }
+               spin_lock_bh(&adapter->mac_vlan_list_lock);
+               iavf_add_filter(adapter, adapter->hw.mac.addr);
+               spin_unlock_bh(&adapter->mac_vlan_list_lock);
                iavf_process_config(adapter);
                }
                break;