|
@@ -785,7 +785,7 @@ static int i40evf_vlan_rx_kill_vid(struct net_device *netdev,
|
|
|
**/
|
|
|
static struct
|
|
|
i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
|
|
|
- u8 *macaddr)
|
|
|
+ const u8 *macaddr)
|
|
|
{
|
|
|
struct i40evf_mac_filter *f;
|
|
|
|
|
@@ -808,7 +808,7 @@ i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
|
|
|
**/
|
|
|
static struct
|
|
|
i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
|
|
|
- u8 *macaddr)
|
|
|
+ const u8 *macaddr)
|
|
|
{
|
|
|
struct i40evf_mac_filter *f;
|
|
|
|
|
@@ -880,50 +880,64 @@ static int i40evf_set_mac(struct net_device *netdev, void *p)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * i40evf_set_rx_mode - NDO callback to set the netdev filters
|
|
|
- * @netdev: network interface device structure
|
|
|
- **/
|
|
|
-static void i40evf_set_rx_mode(struct net_device *netdev)
|
|
|
+ * i40evf_addr_sync - Callback for dev_(mc|uc)_sync to add address
|
|
|
+ * @netdev: the netdevice
|
|
|
+ * @addr: address to add
|
|
|
+ *
|
|
|
+ * Called by __dev_(mc|uc)_sync when an address needs to be added. We call
|
|
|
+ * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
|
|
|
+ */
|
|
|
+static int i40evf_addr_sync(struct net_device *netdev, const u8 *addr)
|
|
|
{
|
|
|
struct i40evf_adapter *adapter = netdev_priv(netdev);
|
|
|
- struct i40evf_mac_filter *f, *ftmp;
|
|
|
- struct netdev_hw_addr *uca;
|
|
|
- struct netdev_hw_addr *mca;
|
|
|
- struct netdev_hw_addr *ha;
|
|
|
-
|
|
|
- /* add addr if not already in the filter list */
|
|
|
- netdev_for_each_uc_addr(uca, netdev) {
|
|
|
- i40evf_add_filter(adapter, uca->addr);
|
|
|
- }
|
|
|
- netdev_for_each_mc_addr(mca, netdev) {
|
|
|
- i40evf_add_filter(adapter, mca->addr);
|
|
|
- }
|
|
|
-
|
|
|
- spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
|
|
- list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
|
|
|
- netdev_for_each_mc_addr(mca, netdev)
|
|
|
- if (ether_addr_equal(mca->addr, f->macaddr))
|
|
|
- goto bottom_of_search_loop;
|
|
|
-
|
|
|
- netdev_for_each_uc_addr(uca, netdev)
|
|
|
- if (ether_addr_equal(uca->addr, f->macaddr))
|
|
|
- goto bottom_of_search_loop;
|
|
|
+ if (i40evf_add_filter(adapter, addr))
|
|
|
+ return 0;
|
|
|
+ else
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
|
|
|
- for_each_dev_addr(netdev, ha)
|
|
|
- if (ether_addr_equal(ha->addr, f->macaddr))
|
|
|
- goto bottom_of_search_loop;
|
|
|
+/**
|
|
|
+ * i40evf_addr_unsync - Callback for dev_(mc|uc)_sync to remove address
|
|
|
+ * @netdev: the netdevice
|
|
|
+ * @addr: address to add
|
|
|
+ *
|
|
|
+ * Called by __dev_(mc|uc)_sync when an address needs to be removed. We call
|
|
|
+ * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
|
|
|
+ */
|
|
|
+static int i40evf_addr_unsync(struct net_device *netdev, const u8 *addr)
|
|
|
+{
|
|
|
+ struct i40evf_adapter *adapter = netdev_priv(netdev);
|
|
|
+ struct i40evf_mac_filter *f;
|
|
|
|
|
|
- if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr))
|
|
|
- goto bottom_of_search_loop;
|
|
|
+ /* Under some circumstances, we might receive a request to delete
|
|
|
+ * our own device address from our uc list. Because we store the
|
|
|
+ * device address in the VSI's MAC/VLAN filter list, we need to ignore
|
|
|
+ * such requests and not delete our device address from this list.
|
|
|
+ */
|
|
|
+ if (ether_addr_equal(addr, netdev->dev_addr))
|
|
|
+ return 0;
|
|
|
|
|
|
- /* f->macaddr wasn't found in uc, mc, or ha list so delete it */
|
|
|
+ f = i40evf_find_filter(adapter, addr);
|
|
|
+ if (f) {
|
|
|
f->remove = true;
|
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
|
|
|
-
|
|
|
-bottom_of_search_loop:
|
|
|
- continue;
|
|
|
}
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * i40evf_set_rx_mode - NDO callback to set the netdev filters
|
|
|
+ * @netdev: network interface device structure
|
|
|
+ **/
|
|
|
+static void i40evf_set_rx_mode(struct net_device *netdev)
|
|
|
+{
|
|
|
+ struct i40evf_adapter *adapter = netdev_priv(netdev);
|
|
|
+
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
+ __dev_uc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync);
|
|
|
+ __dev_mc_sync(netdev, i40evf_addr_sync, i40evf_addr_unsync);
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
|
|
if (netdev->flags & IFF_PROMISC &&
|
|
|
!(adapter->flags & I40EVF_FLAG_PROMISC_ON))
|
|
@@ -938,8 +952,6 @@ bottom_of_search_loop:
|
|
|
else if (!(netdev->flags & IFF_ALLMULTI) &&
|
|
|
adapter->flags & I40EVF_FLAG_ALLMULTI_ON)
|
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI;
|
|
|
-
|
|
|
- spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1041,10 +1053,15 @@ void i40evf_down(struct i40evf_adapter *adapter)
|
|
|
|
|
|
spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
|
|
+ /* clear the sync flag on all filters */
|
|
|
+ __dev_uc_unsync(adapter->netdev, NULL);
|
|
|
+ __dev_mc_unsync(adapter->netdev, NULL);
|
|
|
+
|
|
|
/* remove all MAC filters */
|
|
|
list_for_each_entry(f, &adapter->mac_filter_list, list) {
|
|
|
f->remove = true;
|
|
|
}
|
|
|
+
|
|
|
/* remove all VLAN filters */
|
|
|
list_for_each_entry(vlf, &adapter->vlan_filter_list, list) {
|
|
|
f->remove = true;
|