Skip to content

Commit ab8b1f7

Browse files
Daniel Pieczkodavem330
authored andcommitted
sfc: support cascaded multicast filters
If the workaround to support cascaded multicast filters ("workaround_26807") is enabled, the broadcast filter and individual multicast filters are not inserted when in promiscuous or allmulti mode. There is a race while inserting and removing filters when entering and leaving promiscuous mode. When changing promiscuous state with cascaded multicast filters, the old multicast filters are removed before inserting the new filters to avoid duplicating packets; this can lead to dropped packets until all filters have been inserted. The efx_nic:mc_promisc flag is added to record the presence of a multicast promiscuous filter; this gives a simple way to tell if the promiscuous state is changing. Signed-off-by: Edward Cree <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 822b96f commit ab8b1f7

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

drivers/net/ethernet/sfc/ef10.c

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3792,26 +3792,42 @@ static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc)
37923792
static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc)
37933793
{
37943794
struct efx_ef10_filter_table *table = efx->filter_state;
3795+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
37953796
struct net_device *net_dev = efx->net_dev;
37963797
struct netdev_hw_addr *mc;
3797-
unsigned int i;
3798+
unsigned int i, addr_count;
37983799

3799-
if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */
3800-
>= EFX_EF10_FILTER_DEV_MC_MAX) {
3801-
table->dev_mc_count = 1;
3802-
eth_broadcast_addr(table->dev_mc_list[0].addr);
3800+
if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI))
38033801
*promisc = true;
3802+
3803+
if (nic_data->workaround_26807) {
3804+
if (*promisc) {
3805+
table->dev_mc_count = 0;
3806+
return;
3807+
}
3808+
addr_count = netdev_mc_count(net_dev);
38043809
} else {
3805-
table->dev_mc_count = 1 + netdev_mc_count(net_dev);
3806-
eth_broadcast_addr(table->dev_mc_list[0].addr);
3807-
i = 1;
3808-
netdev_for_each_mc_addr(mc, net_dev) {
3809-
ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
3810-
i++;
3810+
/* Allow room for broadcast and promiscuous */
3811+
addr_count = netdev_mc_count(net_dev) + 2;
3812+
}
3813+
3814+
if (addr_count >= EFX_EF10_FILTER_DEV_MC_MAX) {
3815+
if (nic_data->workaround_26807) {
3816+
table->dev_mc_count = 0;
3817+
} else {
3818+
table->dev_mc_count = 1;
3819+
eth_broadcast_addr(table->dev_mc_list[0].addr);
38113820
}
3821+
*promisc = true;
3822+
return;
3823+
}
38123824

3813-
if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI))
3814-
*promisc = true;
3825+
table->dev_mc_count = 1 + netdev_mc_count(net_dev);
3826+
eth_broadcast_addr(table->dev_mc_list[0].addr);
3827+
i = 1;
3828+
netdev_for_each_mc_addr(mc, net_dev) {
3829+
ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
3830+
i++;
38153831
}
38163832
}
38173833

@@ -3846,7 +3862,11 @@ static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
38463862
* filter for multicast
38473863
*/
38483864
while (i--) {
3849-
if (multicast && i == 1)
3865+
struct efx_ef10_nic_data *nic_data =
3866+
efx->nic_data;
3867+
3868+
if (multicast && i == 1 &&
3869+
!nic_data->workaround_26807)
38503870
break;
38513871

38523872
efx_ef10_filter_remove_safe(
@@ -3974,6 +3994,7 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx)
39743994
static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
39753995
{
39763996
struct efx_ef10_filter_table *table = efx->filter_state;
3997+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
39773998
struct net_device *net_dev = efx->net_dev;
39783999
bool uc_promisc = false, mc_promisc = false;
39794000

@@ -3995,9 +4016,16 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
39954016

39964017
/* Insert/renew filters */
39974018
efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc);
4019+
4020+
/* If changing promiscuous state with cascaded multicast filters, remove
4021+
* old filters first, so that packets are dropped rather than duplicated
4022+
*/
4023+
if (nic_data->workaround_26807 && efx->mc_promisc != mc_promisc)
4024+
efx_ef10_filter_remove_old(efx);
39984025
efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc);
39994026

40004027
efx_ef10_filter_remove_old(efx);
4028+
efx->mc_promisc = mc_promisc;
40014029
}
40024030

40034031
static int efx_ef10_set_mac_address(struct efx_nic *efx)

drivers/net/ethernet/sfc/net_driver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,7 @@ struct vfdi_status;
925925
* @stats_lock: Statistics update lock. Must be held when calling
926926
* efx_nic_type::{update,start,stop}_stats.
927927
* @n_rx_noskb_drops: Count of RX packets dropped due to failure to allocate an skb
928+
* @mc_promisc: Whether in multicast promiscuous mode when last changed
928929
*
929930
* This is stored in the private area of the &struct net_device.
930931
*/
@@ -1072,6 +1073,7 @@ struct efx_nic {
10721073
int last_irq_cpu;
10731074
spinlock_t stats_lock;
10741075
atomic_t n_rx_noskb_drops;
1076+
bool mc_promisc;
10751077
};
10761078

10771079
static inline int efx_dev_registered(struct efx_nic *efx)

0 commit comments

Comments
 (0)