Blob Blame History Raw
From: Shannon Nelson <snelson@pensando.io>
Date: Wed, 25 Aug 2021 18:24:50 -0700
Subject: ionic: handle mac filter overflow
Patch-mainline: v5.15-rc1
Git-commit: a0c007b3f6455641c5ba7fb5c474401d82387121
References: jsc#SLE-19282

Make sure we go into PROMISC mode when we have too many
filters by specifically counting the filters that successfully
get saved to the firmware.

The device advertises max_ucast_filters and max_mcast_filters,
but really only has max_ucast_filters slots available for
uc and mc filters combined.

Signed-off-by: Shannon Nelson <snelson@pensando.io>
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
 drivers/net/ethernet/pensando/ionic/ionic_lif.c |   40 +++++++++++++++++-------
 1 file changed, 29 insertions(+), 11 deletions(-)

--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1256,6 +1256,8 @@ int ionic_lif_addr_add(struct ionic_lif
 			.match = cpu_to_le16(IONIC_RX_FILTER_MATCH_MAC),
 		},
 	};
+	int nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
+	bool mc = is_multicast_ether_addr(addr);
 	struct ionic_rx_filter *f;
 	int err = 0;
 
@@ -1282,7 +1284,13 @@ int ionic_lif_addr_add(struct ionic_lif
 
 	netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);
 
-	err = ionic_adminq_post_wait(lif, &ctx);
+	/* Don't bother with the write to FW if we know there's no room,
+	 * we can try again on the next sync attempt.
+	 */
+	if ((lif->nucast + lif->nmcast) >= nfilters)
+		err = -ENOSPC;
+	else
+		err = ionic_adminq_post_wait(lif, &ctx);
 
 	spin_lock_bh(&lif->rx_filters.lock);
 	if (err && err != -EEXIST) {
@@ -1292,9 +1300,18 @@ int ionic_lif_addr_add(struct ionic_lif
 			f->state = IONIC_FILTER_STATE_NEW;
 
 		spin_unlock_bh(&lif->rx_filters.lock);
-		return err;
+
+		if (err == -ENOSPC)
+			return 0;
+		else
+			return err;
 	}
 
+	if (mc)
+		lif->nmcast++;
+	else
+		lif->nucast++;
+
 	f = ionic_rx_filter_by_addr(lif, addr);
 	if (f && f->state == IONIC_FILTER_STATE_OLD) {
 		/* Someone requested a delete while we were adding
@@ -1340,6 +1357,12 @@ int ionic_lif_addr_del(struct ionic_lif
 	state = f->state;
 	ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
 	ionic_rx_filter_free(lif, f);
+
+	if (is_multicast_ether_addr(addr) && lif->nmcast)
+		lif->nmcast--;
+	else if (!is_multicast_ether_addr(addr) && lif->nucast)
+		lif->nucast--;
+
 	spin_unlock_bh(&lif->rx_filters.lock);
 
 	if (state != IONIC_FILTER_STATE_NEW) {
@@ -1392,21 +1415,16 @@ void ionic_lif_rx_mode(struct ionic_lif
 	 *       to see if we can disable NIC PROMISC
 	 */
 	nfilters = le32_to_cpu(lif->identity->eth.max_ucast_filters);
-	if (netdev_uc_count(netdev) + 1 > nfilters) {
+	if ((lif->nucast + lif->nmcast) >= nfilters) {
 		rx_mode |= IONIC_RX_MODE_F_PROMISC;
+		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
 		lif->uc_overflow = true;
+		lif->mc_overflow = true;
 	} else if (lif->uc_overflow) {
 		lif->uc_overflow = false;
+		lif->mc_overflow = false;
 		if (!(nd_flags & IFF_PROMISC))
 			rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
-	}
-
-	nfilters = le32_to_cpu(lif->identity->eth.max_mcast_filters);
-	if (netdev_mc_count(netdev) > nfilters) {
-		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
-		lif->mc_overflow = true;
-	} else if (lif->mc_overflow) {
-		lif->mc_overflow = false;
 		if (!(nd_flags & IFF_ALLMULTI))
 			rx_mode &= ~IONIC_RX_MODE_F_ALLMULTI;
 	}