Skip to content

Commit 8946b56

Browse files
jacob-kellerJeff Kirsher
authored andcommitted
i40evf: use __dev_[um]c_sync routines in .set_rx_mode
Similar to changes done to the PF driver in commit 6622f5c ("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 <[email protected]> Tested-by: Andrew Bowers <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 7b63435 commit 8946b56

File tree

1 file changed

+56
-39
lines changed

1 file changed

+56
-39
lines changed

drivers/net/ethernet/intel/i40evf/i40evf_main.c

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ static int i40evf_vlan_rx_kill_vid(struct net_device *netdev,
785785
**/
786786
static struct
787787
i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
788-
u8 *macaddr)
788+
const u8 *macaddr)
789789
{
790790
struct i40evf_mac_filter *f;
791791

@@ -808,7 +808,7 @@ i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
808808
**/
809809
static struct
810810
i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
811-
u8 *macaddr)
811+
const u8 *macaddr)
812812
{
813813
struct i40evf_mac_filter *f;
814814

@@ -880,50 +880,64 @@ static int i40evf_set_mac(struct net_device *netdev, void *p)
880880
}
881881

882882
/**
883-
* i40evf_set_rx_mode - NDO callback to set the netdev filters
884-
* @netdev: network interface device structure
885-
**/
886-
static void i40evf_set_rx_mode(struct net_device *netdev)
883+
* i40evf_addr_sync - Callback for dev_(mc|uc)_sync to add address
884+
* @netdev: the netdevice
885+
* @addr: address to add
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+
*/
890+
static int i40evf_addr_sync(struct net_device *netdev, const u8 *addr)
887891
{
888892
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);
903893

904-
list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
905-
netdev_for_each_mc_addr(mca, netdev)
906-
if (ether_addr_equal(mca->addr, f->macaddr))
907-
goto bottom_of_search_loop;
908-
909-
netdev_for_each_uc_addr(uca, netdev)
910-
if (ether_addr_equal(uca->addr, f->macaddr))
911-
goto bottom_of_search_loop;
894+
if (i40evf_add_filter(adapter, addr))
895+
return 0;
896+
else
897+
return -ENOMEM;
898+
}
912899

913-
for_each_dev_addr(netdev, ha)
914-
if (ether_addr_equal(ha->addr, f->macaddr))
915-
goto bottom_of_search_loop;
900+
/**
901+
* i40evf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address
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+
*/
908+
static 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;
916912

917-
if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr))
918-
goto bottom_of_search_loop;
913+
/* Under some circumstances, we might receive a request to delete
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;
919920

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) {
921923
f->remove = true;
922924
adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
923-
924-
bottom_of_search_loop:
925-
continue;
926925
}
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+
**/
933+
static 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);
927941

928942
if (netdev->flags & IFF_PROMISC &&
929943
!(adapter->flags & I40EVF_FLAG_PROMISC_ON))
@@ -938,8 +952,6 @@ static void i40evf_set_rx_mode(struct net_device *netdev)
938952
else if (!(netdev->flags & IFF_ALLMULTI) &&
939953
adapter->flags & I40EVF_FLAG_ALLMULTI_ON)
940954
adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI;
941-
942-
spin_unlock_bh(&adapter->mac_vlan_list_lock);
943955
}
944956

945957
/**
@@ -1041,10 +1053,15 @@ void i40evf_down(struct i40evf_adapter *adapter)
10411053

10421054
spin_lock_bh(&adapter->mac_vlan_list_lock);
10431055

1056+
/* clear the sync flag on all filters */
1057+
__dev_uc_unsync(adapter->netdev, NULL);
1058+
__dev_mc_unsync(adapter->netdev, NULL);
1059+
10441060
/* remove all MAC filters */
10451061
list_for_each_entry(f, &adapter->mac_filter_list, list) {
10461062
f->remove = true;
10471063
}
1064+
10481065
/* remove all VLAN filters */
10491066
list_for_each_entry(vlf, &adapter->vlan_filter_list, list) {
10501067
f->remove = true;

0 commit comments

Comments
 (0)