| From 194257f25dffea5042fa1820760e030fb93e0f07 Mon Sep 17 00:00:00 2001 |
| From: Stefan Assmann <sassmann@kpanic.de> |
| Date: Tue, 17 Dec 2019 11:29:23 +0100 |
| Subject: [PATCH] iavf: remove current MAC address filter on VF reset |
| |
| commit 9e05229190380f6b8f702da39aaeb97a0fc80dc3 upstream. |
| |
| 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> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h |
| index 272d76b733aa..4df14be14ce3 100644 |
| --- a/drivers/net/ethernet/intel/iavf/iavf.h |
| +++ b/drivers/net/ethernet/intel/iavf/iavf.h |
| @@ -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_ */ |
| diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c |
| index eeaa9125f25e..cd89cf39f984 100644 |
| --- a/drivers/net/ethernet/intel/iavf/iavf_main.c |
| +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c |
| @@ -761,9 +761,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; |
| |
| @@ -1825,9 +1824,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; |
| @@ -1941,6 +1940,16 @@ static void iavf_reset_task(struct work_struct *work) |
| |
| 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; |
| diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c |
| index e64751da0921..418890a9b551 100644 |
| --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c |
| +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c |
| @@ -1357,6 +1357,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; |
| -- |
| 2.7.4 |
| |