* [PATCH net v4 1/3] bnxt_en: Fix RSS context delete logic
2026-02-19 18:53 [PATCH net v4 0/3] bnxt_en: Fix RSS context and ntuple filter issues Michael Chan
@ 2026-02-19 18:53 ` Michael Chan
2026-02-19 18:53 ` [PATCH net v4 2/3] bnxt_en: Fix deleting of Ntuple filters Michael Chan
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Michael Chan @ 2026-02-19 18:53 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi,
andrew.gospodarek, horms, Jakub Kicinski
From: Pavan Chebbi <pavan.chebbi@broadcom.com>
We need to free the corresponding RSS context VNIC
in FW everytime an RSS context is deleted in driver.
Commit 667ac333dbb7 added a check to delete the VNIC
in FW only when netif_running() is true to help delete
RSS contexts with interface down.
Having that condition will make the driver leak VNICs
in FW whenever close() happens with active RSS contexts.
On the subsequent open(), as part of RSS context restoration,
we will end up trying to create extra VNICs for which we
did not make any reservation. FW can fail this request,
thereby making us lose active RSS contexts.
Suppose an RSS context is deleted already and we try to
process a delete request again, then the HWRM functions
will check for validity of the request and they simply
return if the resource is already freed. So, even for
delete-when-down cases, netif_running() check is not
necessary.
Remove the netif_running() condition check when deleting
an RSS context.
Reported-by: Jakub Kicinski <kicinski@meta.com>
Fixes: 667ac333dbb7 ("eth: bnxt: allow deleting RSS contexts when the device is down")
Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index fb45e1dd1dd7..7768d9753e2d 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -10889,12 +10889,10 @@ void bnxt_del_one_rss_ctx(struct bnxt *bp, struct bnxt_rss_ctx *rss_ctx,
struct bnxt_ntuple_filter *ntp_fltr;
int i;
- if (netif_running(bp->dev)) {
- bnxt_hwrm_vnic_free_one(bp, &rss_ctx->vnic);
- for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) {
- if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID)
- bnxt_hwrm_vnic_ctx_free_one(bp, vnic, i);
- }
+ bnxt_hwrm_vnic_free_one(bp, &rss_ctx->vnic);
+ for (i = 0; i < BNXT_MAX_CTX_PER_VNIC; i++) {
+ if (vnic->fw_rss_cos_lb_ctx[i] != INVALID_HW_RING_ID)
+ bnxt_hwrm_vnic_ctx_free_one(bp, vnic, i);
}
if (!all)
return;
--
2.51.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH net v4 3/3] selftests: drv-net: rss_ctx: test RSS contexts persist after ifdown/up
2026-02-19 18:53 [PATCH net v4 0/3] bnxt_en: Fix RSS context and ntuple filter issues Michael Chan
2026-02-19 18:53 ` [PATCH net v4 1/3] bnxt_en: Fix RSS context delete logic Michael Chan
2026-02-19 18:53 ` [PATCH net v4 2/3] bnxt_en: Fix deleting of Ntuple filters Michael Chan
@ 2026-02-19 18:53 ` Michael Chan
2026-02-21 0:40 ` [PATCH net v4 0/3] bnxt_en: Fix RSS context and ntuple filter issues patchwork-bot+netdevbpf
3 siblings, 0 replies; 5+ messages in thread
From: Michael Chan @ 2026-02-19 18:53 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi,
andrew.gospodarek, horms
From: Pavan Chebbi <pavan.chebbi@broadcom.com>
Add a test to verify that RSS contexts persist across interface
down/up along with their associated Ntuple filters. Another test
that creates contexts/rules keeping interface down and test their
persistence is also added.
Tested on bnxt_en:
TAP version 13
1..1
# timeout set to 0
# selftests: drivers/net/hw: rss_ctx.py
# TAP version 13
# 1..2
# ok 1 rss_ctx.test_rss_context_persist_create_and_ifdown
# ok 2 rss_ctx.test_rss_context_persist_ifdown_and_create # SKIP Create context not supported with interface down
# # Totals: pass:1 fail:0 xfail:0 xpass:0 skip:1 error:0
Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
v3: More improvements suggested by Jakub:
1. Used defer() and exec() for the if up
2. Wait for carrier before trying the ping to start traffic tests
3. Replace manual subprocess.run() ping loop with cmd()
4. Fixed all ruff and pylint warnings in the newly added code
v2: Many improvements suggested by Jakub:
https://lore.kernel.org/netdev/20260206052930.1882740-5-michael.chan@broadcom.com/
1. simplified the tests to have only 2 contexts, use one of the contexts
to test ntuple filters' persistence also
2. used @ksft_disruptive for the test
3. used netlink API to get rss contexts
v1: https://lore.kernel.org/netdev/20260129061646.1417185-5-michael.chan@broadcom.com/
---
| 100 +++++++++++++++++-
1 file changed, 98 insertions(+), 2 deletions(-)
--git a/tools/testing/selftests/drivers/net/hw/rss_ctx.py b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
index ed7e405682f0..b9b7527c2c6b 100755
--- a/tools/testing/selftests/drivers/net/hw/rss_ctx.py
+++ b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
@@ -4,13 +4,15 @@
import datetime
import random
import re
+import time
from lib.py import ksft_run, ksft_pr, ksft_exit
from lib.py import ksft_eq, ksft_ne, ksft_ge, ksft_in, ksft_lt, ksft_true, ksft_raises
from lib.py import NetDrvEpEnv
from lib.py import EthtoolFamily, NetdevFamily
from lib.py import KsftSkipEx, KsftFailEx
+from lib.py import ksft_disruptive
from lib.py import rand_port
-from lib.py import ethtool, ip, defer, GenerateTraffic, CmdExitFailure
+from lib.py import cmd, ethtool, ip, defer, GenerateTraffic, CmdExitFailure, wait_file
def _rss_key_str(key):
@@ -809,6 +811,98 @@ def test_rss_default_context_rule(cfg):
'noise' : (0, 1) })
+@ksft_disruptive
+def test_rss_context_persist_ifupdown(cfg, pre_down=False):
+ """
+ Test that RSS contexts and their associated ntuple filters persist across
+ an interface down/up cycle.
+
+ """
+
+ require_ntuple(cfg)
+
+ qcnt = len(_get_rx_cnts(cfg))
+ if qcnt < 6:
+ try:
+ ethtool(f"-L {cfg.ifname} combined 6")
+ defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
+ except Exception as exc:
+ raise KsftSkipEx("Not enough queues for the test") from exc
+
+ ethtool(f"-X {cfg.ifname} equal 2")
+ defer(ethtool, f"-X {cfg.ifname} default")
+
+ ifup = defer(ip, f"link set dev {cfg.ifname} up")
+ if pre_down:
+ ip(f"link set dev {cfg.ifname} down")
+
+ try:
+ ctx1_id = ethtool_create(cfg, "-X", "context new start 2 equal 2")
+ defer(ethtool, f"-X {cfg.ifname} context {ctx1_id} delete")
+ except CmdExitFailure as exc:
+ raise KsftSkipEx("Create context not supported with interface down") from exc
+
+ ctx2_id = ethtool_create(cfg, "-X", "context new start 4 equal 2")
+ defer(ethtool, f"-X {cfg.ifname} context {ctx2_id} delete")
+
+ port_ctx2 = rand_port()
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port_ctx2} context {ctx2_id}"
+ ntuple_id = ethtool_create(cfg, "-N", flow)
+ defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
+
+ if not pre_down:
+ ip(f"link set dev {cfg.ifname} down")
+ ifup.exec()
+
+ wait_file(f"/sys/class/net/{cfg.ifname}/carrier",
+ lambda x: x.strip() == "1", deadline=20)
+
+ remote_addr = cfg.remote_addr_v[cfg.addr_ipver]
+ for _ in range(10):
+ if cmd(f"ping -c 1 -W 1 {remote_addr}", fail=False).ret == 0:
+ break
+ time.sleep(1)
+ else:
+ raise KsftSkipEx("Cannot reach remote host after interface up")
+
+ ctxs = cfg.ethnl.rss_get({'header': {'dev-name': cfg.ifname}}, dump=True)
+
+ data1 = [c for c in ctxs if c.get('context') == ctx1_id]
+ ksft_eq(len(data1), 1, f"Context {ctx1_id} should persist after ifup")
+
+ data2 = [c for c in ctxs if c.get('context') == ctx2_id]
+ ksft_eq(len(data2), 1, f"Context {ctx2_id} should persist after ifup")
+
+ _ntuple_rule_check(cfg, ntuple_id, ctx2_id)
+
+ cnts = _get_rx_cnts(cfg)
+ GenerateTraffic(cfg).wait_pkts_and_stop(20000)
+ cnts = _get_rx_cnts(cfg, prev=cnts)
+
+ main_traffic = sum(cnts[0:2])
+ ksft_ge(main_traffic, 18000, f"Main context traffic distribution: {cnts}")
+ ksft_lt(sum(cnts[2:6]), 500, f"Other context queues should be mostly empty: {cnts}")
+
+ _send_traffic_check(cfg, port_ctx2, f"context {ctx2_id}",
+ {'target': (4, 5),
+ 'noise': (0, 1),
+ 'empty': (2, 3)})
+
+
+def test_rss_context_persist_create_and_ifdown(cfg):
+ """
+ Create RSS contexts then cycle the interface down and up.
+ """
+ test_rss_context_persist_ifupdown(cfg, pre_down=False)
+
+
+def test_rss_context_persist_ifdown_and_create(cfg):
+ """
+ Bring interface down first, then create RSS contexts and bring up.
+ """
+ test_rss_context_persist_ifupdown(cfg, pre_down=True)
+
+
def main() -> None:
with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
cfg.context_cnt = None
@@ -823,7 +917,9 @@ def main() -> None:
test_rss_context_out_of_order, test_rss_context4_create_with_cfg,
test_flow_add_context_missing,
test_delete_rss_context_busy, test_rss_ntuple_addition,
- test_rss_default_context_rule],
+ test_rss_default_context_rule,
+ test_rss_context_persist_create_and_ifdown,
+ test_rss_context_persist_ifdown_and_create],
args=(cfg, ))
ksft_exit()
--
2.51.0
^ permalink raw reply related [flat|nested] 5+ messages in thread