aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Keller <jacob.e.keller@intel.com>2018-01-22 12:00:38 -0500
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2018-02-13 14:40:10 -0500
commit8946b56354b71b1f75b9551aeb33f19c8d792065 (patch)
tree28d34e37906bede18a1a9c62ffeef4f5251d6f2a
parent7b63435a5035621baa4de8d15ca1b4440c3b4d12 (diff)
i40evf: use __dev_[um]c_sync routines in .set_rx_mode
Similar to changes done to the PF driver in commit 6622f5cdbaf3 ("i40e: make use of __dev_uc_sync and __dev_mc_sync"), replace our home-rolled method for updating the internal status of MAC filters with __dev_uc_sync and __dev_mc_sync. These new functions use internal state within the netdev struct in order to efficiently break the question of "which filters in this list need to be added or removed" into singular "add this filter" and "delete this filter" requests. This vastly improves our handling of .set_rx_mode especially with large number of MAC filters being added to the device, and even results in a simpler .set_rx_mode handler. Under some circumstances, such as when attached to a bridge, we may receive a request to delete our own permanent address. Prevent deletion of this address during i40evf_addr_unsync so that we don't accidentally stop receiving traffic. Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_main.c95
1 files changed, 56 insertions, 39 deletions
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index 4f07469e9769..34fd6c553879 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -785,7 +785,7 @@ static int i40evf_vlan_rx_kill_vid(struct net_device *netdev,
785 **/ 785 **/
786static struct 786static struct
787i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter, 787i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
788 u8 *macaddr) 788 const u8 *macaddr)
789{ 789{
790 struct i40evf_mac_filter *f; 790 struct i40evf_mac_filter *f;
791 791
@@ -808,7 +808,7 @@ i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
808 **/ 808 **/
809static struct 809static struct
810i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter, 810i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
811 u8 *macaddr) 811 const u8 *macaddr)
812{ 812{
813 struct i40evf_mac_filter *f; 813 struct i40evf_mac_filter *f;
814 814
@@ -880,50 +880,64 @@ static int i40evf_set_mac(struct net_device *netdev, void *p)
880} 880}
881 881
882/** 882/**
883 * i40evf_set_rx_mode - NDO callback to set the netdev filters 883 * i40evf_addr_sync - Callback for dev_(mc|uc)_sync to add address
884 * @netdev: network interface device structure 884 * @netdev: the netdevice
885 **/ 885 * @addr: address to add
886static void i40evf_set_rx_mode(struct net_device *netdev) 886 *
887 * Called by __dev_(mc|uc)_sync when an address needs to be added. We call
888 * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
889 */
890static int i40evf_addr_sync(struct net_device *netdev, const u8 *addr)
887{ 891{
888 struct i40evf_adapter *adapter = netdev_priv(netdev); 892 struct i40evf_adapter *adapter = netdev_priv(netdev);
889 struct i40evf_mac_filter *f, *ftmp;
890 struct netdev_hw_addr *uca;
891 struct netdev_hw_addr *mca;
892 struct netdev_hw_addr *ha;
893
894 /* add addr if not already in the filter list */
895 netdev_for_each_uc_addr(uca, netdev) {
896 i40evf_add_filter(adapter, uca->addr);
897 }
898 netdev_for_each_mc_addr(mca, netdev) {
899 i40evf_add_filter(adapter, mca->addr);
900 }
901
902 spin_lock_bh(&adapter->mac_vlan_list_lock);
903 893
904 list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { 894 if (i40evf_add_filter(adapter, addr))
905 netdev_for_each_mc_addr(mca, netdev) 895 return 0;
906 if (ether_addr_equal(mca->addr, f->macaddr)) 896 else
907 goto bottom_of_search_loop; 897 return -ENOMEM;
908 898}
909 netdev_for_each_uc_addr(uca, netdev)
910 if (ether_addr_equal(uca->addr, f->macaddr))
911 goto bottom_of_search_loop;
912 899
913 for_each_dev_addr(netdev, ha) 900/**
914 if (ether_addr_equal(ha->addr, f->macaddr)) 901 * i40evf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address
915 goto bottom_of_search_loop; 902 * @netdev: the netdevice
903 * @addr: address to add
904 *
905 * Called by __dev_(mc|uc)_sync when an address needs to be removed. We call
906 * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
907 */
908static int i40evf_addr_unsync(struct net_device *netdev, const u8 *addr)
909{
910 struct i40evf_adapter *adapter = netdev_priv(netdev);
911 struct i40evf_mac_filter *f;
916 912
917 if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr)) 913 /* Under some circumstances, we might receive a request to delete
918 goto bottom_of_search_loop; 914 * our own device address from our uc list. Because we store the
915 * device address in the VSI's MAC/VLAN filter list, we need to ignore
916 * such requests and not delete our device address from this list.
917 */
918 if (ether_addr_equal(addr, netdev->dev_addr))
919 return 0;
919 920
920 /* f->macaddr wasn't found in uc, mc, or ha list so delete it */ 921 f = i40evf_find_filter(adapter, addr);
922 if (f) {
921 f->remove = true; 923 f->remove = true;
922 adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; 924 adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
923
924bottom_of_search_loop:
925 continue;
926 } 925 }
926 return 0;
927}
928
929/**
930 * i40evf_set_rx_mode - NDO callback to set the netdev filters
931 * @netdev: network interface device structure
932 **/
933static void i40evf_set_rx_mode(struct net_device *netdev)
934{
935 struct i40evf_adapter *adapter = netdev_priv(netdev);
936
937 spin_lock_bh(&adapter->mac_vlan_list_lock);
938 __dev_uc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync);
939 __dev_mc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync);
940 spin_unlock_bh(&adapter->mac_vlan_list_lock);
927 941
928 if (netdev->flags & IFF_PROMISC && 942 if (netdev->flags & IFF_PROMISC &&
929 !(adapter->flags & I40EVF_FLAG_PROMISC_ON)) 943 !(adapter->flags & I40EVF_FLAG_PROMISC_ON))
@@ -938,8 +952,6 @@ bottom_of_search_loop:
938 else if (!(netdev->flags & IFF_ALLMULTI) && 952 else if (!(netdev->flags & IFF_ALLMULTI) &&
939 adapter->flags & I40EVF_FLAG_ALLMULTI_ON) 953 adapter->flags & I40EVF_FLAG_ALLMULTI_ON)
940 adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI; 954 adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI;
941
942 spin_unlock_bh(&adapter->mac_vlan_list_lock);
943} 955}
944 956
945/** 957/**
@@ -1041,10 +1053,15 @@ void i40evf_down(struct i40evf_adapter *adapter)
1041 1053
1042 spin_lock_bh(&adapter->mac_vlan_list_lock); 1054 spin_lock_bh(&adapter->mac_vlan_list_lock);
1043 1055
1056 /* clear the sync flag on all filters */
1057 __dev_uc_unsync(adapter->netdev, NULL);
1058 __dev_mc_unsync(adapter->netdev, NULL);
1059
1044 /* remove all MAC filters */ 1060 /* remove all MAC filters */
1045 list_for_each_entry(f, &adapter->mac_filter_list, list) { 1061 list_for_each_entry(f, &adapter->mac_filter_list, list) {
1046 f->remove = true; 1062 f->remove = true;
1047 } 1063 }
1064
1048 /* remove all VLAN filters */ 1065 /* remove all VLAN filters */
1049 list_for_each_entry(vlf, &adapter->vlan_filter_list, list) { 1066 list_for_each_entry(vlf, &adapter->vlan_filter_list, list) {
1050 f->remove = true; 1067 f->remove = true;