public inbox for netdev@vger.kernel.org 
 help / color / mirror / Atom feed
From: Edward Cree <ecree@solarflare•com>
To: David Miller <davem@davemloft•net>
Cc: <netdev@vger•kernel.org>, <linux-net-drivers@solarflare•com>
Subject: [PATCH net-next 6/9] sfc: Insert multicast filters as well as mismatch filters in promiscuous mode
Date: Tue, 21 Jul 2015 15:10:15 +0100	[thread overview]
Message-ID: <55AE52C7.7090909@solarflare.com> (raw)
In-Reply-To: <55AE5230.3040605@solarflare.com>

From: Jon Cooper <jcooper@solarflare•com>

If a function is in promiscuous mode and another function has a broadcast or
 multicast filter inserted, the function in promiscuous mode won't see that
 broadcast or multicast traffic.
Most notably this breaks broadcast, which means ARP doesn't work. Less
 show-stoppingly, a function listening on a multicast address that's also in
 promiscuous mode will not see that multicast traffic if another function is
 also listening on that multicast address.

Signed-off-by: Edward Cree <ecree@solarflare•com>
---
 drivers/net/ethernet/sfc/ef10.c | 104 ++++++++++++++++++++--------------------
 1 file changed, 53 insertions(+), 51 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 18d6388..784b46f 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -3758,7 +3758,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
 	struct netdev_hw_addr *uc;
 	struct netdev_hw_addr *mc;
 	unsigned int filter_idx;
-	int i, n, rc;
+	int i, rc;
+	bool uc_promisc = false, mc_promisc = false;
 
 	if (!efx_dev_registered(efx))
 		return;
@@ -3768,13 +3769,11 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
 
 	/* Mark old filters that may need to be removed */
 	spin_lock_bh(&efx->filter_lock);
-	n = table->dev_uc_count < 0 ? 1 : table->dev_uc_count;
-	for (i = 0; i < n; i++) {
+	for (i = 0; i < table->dev_uc_count; i++) {
 		filter_idx = table->dev_uc_list[i].id % HUNT_FILTER_TBL_ROWS;
 		table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD;
 	}
-	n = table->dev_mc_count < 0 ? 1 : table->dev_mc_count;
-	for (i = 0; i < n; i++) {
+	for (i = 0; i < table->dev_mc_count; i++) {
 		filter_idx = table->dev_mc_list[i].id % HUNT_FILTER_TBL_ROWS;
 		table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD;
 	}
@@ -3786,7 +3785,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
 	netif_addr_lock_bh(net_dev);
 	if (net_dev->flags & IFF_PROMISC ||
 	    netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) {
-		table->dev_uc_count = -1;
+		table->dev_uc_count = 0;
+		uc_promisc = true;
 	} else {
 		table->dev_uc_count = 1 + netdev_uc_count(net_dev);
 		ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr);
@@ -3796,9 +3796,11 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
 			i++;
 		}
 	}
-	if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI) ||
-	    netdev_mc_count(net_dev) >= EFX_EF10_FILTER_DEV_MC_MAX) {
-		table->dev_mc_count = -1;
+	if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */
+			>= EFX_EF10_FILTER_DEV_MC_MAX) {
+		table->dev_mc_count = 1;
+		eth_broadcast_addr(table->dev_mc_list[0].addr);
+		mc_promisc = true;
 	} else {
 		table->dev_mc_count = 1 + netdev_mc_count(net_dev);
 		eth_broadcast_addr(table->dev_mc_list[0].addr);
@@ -3807,31 +3809,32 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
 			ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
 			i++;
 		}
+		if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI))
+			mc_promisc = true;
 	}
 	netif_addr_unlock_bh(net_dev);
 
 	/* Insert/renew unicast filters */
-	if (table->dev_uc_count >= 0) {
-		for (i = 0; i < table->dev_uc_count; i++) {
-			efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
-					   EFX_FILTER_FLAG_RX_RSS,
-					   0);
-			efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
-						 table->dev_uc_list[i].addr);
-			rc = efx_ef10_filter_insert(efx, &spec, true);
-			if (rc < 0) {
-				/* Fall back to unicast-promisc */
-				while (i--)
-					efx_ef10_filter_remove_safe(
-						efx, EFX_FILTER_PRI_AUTO,
-						table->dev_uc_list[i].id);
-				table->dev_uc_count = -1;
-				break;
-			}
-			table->dev_uc_list[i].id = rc;
+	for (i = 0; i < table->dev_uc_count; i++) {
+		efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
+				   EFX_FILTER_FLAG_RX_RSS,
+				   0);
+		efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
+					 table->dev_uc_list[i].addr);
+		rc = efx_ef10_filter_insert(efx, &spec, true);
+		if (rc < 0) {
+			/* Fall back to unicast-promisc */
+			while (i--)
+				efx_ef10_filter_remove_safe(
+					efx, EFX_FILTER_PRI_AUTO,
+					table->dev_uc_list[i].id);
+			table->dev_uc_count = 0;
+			uc_promisc = true;
+			break;
 		}
+		table->dev_uc_list[i].id = rc;
 	}
-	if (table->dev_uc_count < 0) {
+	if (uc_promisc) {
 		efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
 				   EFX_FILTER_FLAG_RX_RSS,
 				   0);
@@ -3839,34 +3842,34 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
 		rc = efx_ef10_filter_insert(efx, &spec, true);
 		if (rc < 0) {
 			WARN_ON(1);
-			table->dev_uc_count = 0;
 		} else {
-			table->dev_uc_list[0].id = rc;
+			table->dev_uc_list[table->dev_uc_count++].id = rc;
 		}
 	}
 
 	/* Insert/renew multicast filters */
-	if (table->dev_mc_count >= 0) {
-		for (i = 0; i < table->dev_mc_count; i++) {
-			efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
-					   EFX_FILTER_FLAG_RX_RSS,
-					   0);
-			efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
-						 table->dev_mc_list[i].addr);
-			rc = efx_ef10_filter_insert(efx, &spec, true);
-			if (rc < 0) {
-				/* Fall back to multicast-promisc */
-				while (i--)
-					efx_ef10_filter_remove_safe(
-						efx, EFX_FILTER_PRI_AUTO,
-						table->dev_mc_list[i].id);
-				table->dev_mc_count = -1;
-				break;
-			}
-			table->dev_mc_list[i].id = rc;
+	for (i = 0; i < table->dev_mc_count; i++) {
+		efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
+				   EFX_FILTER_FLAG_RX_RSS,
+				   0);
+		efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
+					 table->dev_mc_list[i].addr);
+		rc = efx_ef10_filter_insert(efx, &spec, true);
+		if (rc < 0) {
+			/* Fall back to multicast-promisc.
+			 * Leave the broadcast filter.
+			 */
+			while (i > 1)
+				efx_ef10_filter_remove_safe(
+					efx, EFX_FILTER_PRI_AUTO,
+					table->dev_mc_list[--i].id);
+			table->dev_mc_count = i;
+			mc_promisc = true;
+			break;
 		}
+		table->dev_mc_list[i].id = rc;
 	}
-	if (table->dev_mc_count < 0) {
+	if (mc_promisc) {
 		efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
 				   EFX_FILTER_FLAG_RX_RSS,
 				   0);
@@ -3874,9 +3877,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
 		rc = efx_ef10_filter_insert(efx, &spec, true);
 		if (rc < 0) {
 			WARN_ON(1);
-			table->dev_mc_count = 0;
 		} else {
-			table->dev_mc_list[0].id = rc;
+			table->dev_mc_list[table->dev_mc_count++].id = rc;
 		}
 	}
 

  parent reply	other threads:[~2015-07-21 14:14 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-07-21 14:07 [PATCH net-next 0/9] sfc: support for cascaded multicast filtering Edward Cree
2015-07-21 14:08 ` [PATCH net-next 1/9] sfc: update MCDI protocol definitions Edward Cree
2015-07-21 14:09 ` [PATCH net-next 2/9] sfc: enable cascaded multicast filters in MCFW Edward Cree
2015-07-21 14:09 ` [PATCH net-next 3/9] sfc: cope with ENOSYS from efx_mcdi_get_workarounds() Edward Cree
2015-07-21 14:09 ` [PATCH net-next 4/9] sfc: add output flag decoding to efx_mcdi_set_workaround Edward Cree
2015-07-21 14:10 ` [PATCH net-next 5/9] sfc: warn if other functions have been reset by MCFW Edward Cree
2015-07-21 14:10 ` Edward Cree [this message]
2015-07-21 14:10 ` [PATCH net-next 7/9] sfc: re-factor efx_ef10_filter_sync_rx_mode() Edward Cree
2015-07-21 14:10 ` [PATCH net-next 8/9] sfc: support cascaded multicast filters Edward Cree
2015-07-21 14:11 ` [PATCH net-next 9/9] sfc: clean fallbacks between promisc/normal in efx_ef10_filter_sync_rx_mode Edward Cree
2015-07-22  5:21 ` [PATCH net-next 0/9] sfc: support for cascaded multicast filtering David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55AE52C7.7090909@solarflare.com \
    --to=ecree@solarflare$(echo .)com \
    --cc=davem@davemloft$(echo .)net \
    --cc=linux-net-drivers@solarflare$(echo .)com \
    --cc=netdev@vger$(echo .)kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox