* [PATCH net-next 1/2] selftests: net: py: Add rand_ports helper method
2026-02-24 22:46 [PATCH net-next 0/2] Add selftests helper to get N unique ports Dimitri Daskalakis
@ 2026-02-24 22:46 ` Dimitri Daskalakis
2026-02-24 22:46 ` [PATCH net-next 2/2] selftests: drv-net: rss: Generate unique ports for RSS context tests Dimitri Daskalakis
2026-02-26 4:00 ` [PATCH net-next 0/2] Add selftests helper to get N unique ports patchwork-bot+netdevbpf
2 siblings, 0 replies; 5+ messages in thread
From: Dimitri Daskalakis @ 2026-02-24 22:46 UTC (permalink / raw)
To: David S . Miller
Cc: Andrew Lunn, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Shuah Khan, Simon Horman, Willem de Bruijn, Stanislav Fomichev,
Daniel Zahka, Carolina Jubran, Gal Pressman, David Wei,
Mohsin Bashir, Nimrod Oren, Breno Leitao, Petr Machata, netdev,
linux-kselftest
Certain tests need a unique set of ports. Successive calls to the
existing rand_port method may return a duplicate port, resulting in test
flakiness. The new helper keeps sockets open while building a list of
ephemeral ports, thus the kernel enforces their uniqueness.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Dimitri Daskalakis <dimitri.daskalakis1@gmail.com>
---
.../drivers/net/hw/lib/py/__init__.py | 5 ++--
.../selftests/drivers/net/lib/py/__init__.py | 4 ++--
.../testing/selftests/net/lib/py/__init__.py | 5 ++--
tools/testing/selftests/net/lib/py/utils.py | 24 ++++++++++++++++---
4 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
index d5d247eca6b7..1971577d47e9 100644
--- a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
+++ b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
@@ -22,7 +22,8 @@ try:
NlError, RtnlFamily, DevlinkFamily, PSPFamily
from net.lib.py import CmdExitFailure
from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \
- fd_read_timeout, ip, rand_port, wait_port_listen, wait_file, tool
+ fd_read_timeout, ip, rand_port, rand_ports, wait_port_listen, \
+ wait_file, tool
from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \
ksft_setup, ksft_variants, KsftNamedVariant
@@ -36,7 +37,7 @@ try:
"NlError", "RtnlFamily", "DevlinkFamily", "PSPFamily",
"CmdExitFailure",
"bkg", "cmd", "bpftool", "bpftrace", "defer", "ethtool",
- "fd_read_timeout", "ip", "rand_port",
+ "fd_read_timeout", "ip", "rand_port", "rand_ports",
"wait_port_listen", "wait_file", "tool",
"KsftSkipEx", "KsftFailEx", "KsftXfailEx",
"ksft_disruptive", "ksft_exit", "ksft_pr", "ksft_run",
diff --git a/tools/testing/selftests/drivers/net/lib/py/__init__.py b/tools/testing/selftests/drivers/net/lib/py/__init__.py
index 8b75faa9af6d..5872d114f142 100644
--- a/tools/testing/selftests/drivers/net/lib/py/__init__.py
+++ b/tools/testing/selftests/drivers/net/lib/py/__init__.py
@@ -22,7 +22,7 @@ try:
NlError, RtnlFamily, DevlinkFamily, PSPFamily
from net.lib.py import CmdExitFailure
from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \
- fd_read_timeout, ip, rand_port, wait_port_listen, wait_file
+ fd_read_timeout, ip, rand_port, rand_ports, wait_port_listen, wait_file
from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \
ksft_setup, ksft_variants, KsftNamedVariant
@@ -34,7 +34,7 @@ try:
"NlError", "RtnlFamily", "DevlinkFamily", "PSPFamily",
"CmdExitFailure",
"bkg", "cmd", "bpftool", "bpftrace", "defer", "ethtool",
- "fd_read_timeout", "ip", "rand_port",
+ "fd_read_timeout", "ip", "rand_port", "rand_ports",
"wait_port_listen", "wait_file",
"KsftSkipEx", "KsftFailEx", "KsftXfailEx",
"ksft_disruptive", "ksft_exit", "ksft_pr", "ksft_run",
diff --git a/tools/testing/selftests/net/lib/py/__init__.py b/tools/testing/selftests/net/lib/py/__init__.py
index f528b67639de..a584e7f806a4 100644
--- a/tools/testing/selftests/net/lib/py/__init__.py
+++ b/tools/testing/selftests/net/lib/py/__init__.py
@@ -13,7 +13,8 @@ from .ksft import KsftFailEx, KsftSkipEx, KsftXfailEx, ksft_pr, ksft_eq, \
from .netns import NetNS, NetNSEnter
from .nsim import NetdevSim, NetdevSimDev
from .utils import CmdExitFailure, fd_read_timeout, cmd, bkg, defer, \
- bpftool, ip, ethtool, bpftrace, rand_port, wait_port_listen, wait_file, tool
+ bpftool, ip, ethtool, bpftrace, rand_port, rand_ports, wait_port_listen, \
+ wait_file, tool
from .ynl import NlError, YnlFamily, EthtoolFamily, NetdevFamily, RtnlFamily, RtnlAddrFamily
from .ynl import NetshaperFamily, DevlinkFamily, PSPFamily
@@ -25,7 +26,7 @@ __all__ = ["KSRC",
"ksft_run", "ksft_exit", "ksft_variants", "KsftNamedVariant",
"NetNS", "NetNSEnter",
"CmdExitFailure", "fd_read_timeout", "cmd", "bkg", "defer",
- "bpftool", "ip", "ethtool", "bpftrace", "rand_port",
+ "bpftool", "ip", "ethtool", "bpftrace", "rand_port", "rand_ports",
"wait_port_listen", "wait_file", "tool",
"NetdevSim", "NetdevSimDev",
"NetshaperFamily", "DevlinkFamily", "PSPFamily", "NlError",
diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py
index 85884f3e827b..487350fb957c 100644
--- a/tools/testing/selftests/net/lib/py/utils.py
+++ b/tools/testing/selftests/net/lib/py/utils.py
@@ -263,9 +263,27 @@ def rand_port(stype=socket.SOCK_STREAM):
"""
Get a random unprivileged port.
"""
- with socket.socket(socket.AF_INET6, stype) as s:
- s.bind(("", 0))
- return s.getsockname()[1]
+ return rand_ports(1, stype)[0]
+
+
+def rand_ports(count, stype=socket.SOCK_STREAM):
+ """
+ Get a unique set of random unprivileged ports.
+ """
+ sockets = []
+ ports = []
+
+ try:
+ for _ in range(count):
+ s = socket.socket(socket.AF_INET6, stype)
+ sockets.append(s)
+ s.bind(("", 0))
+ ports.append(s.getsockname()[1])
+ finally:
+ for s in sockets:
+ s.close()
+
+ return ports
def wait_port_listen(port, proto="tcp", ns=None, host=None, sleep=0.005, deadline=5):
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH net-next 2/2] selftests: drv-net: rss: Generate unique ports for RSS context tests
2026-02-24 22:46 [PATCH net-next 0/2] Add selftests helper to get N unique ports Dimitri Daskalakis
2026-02-24 22:46 ` [PATCH net-next 1/2] selftests: net: py: Add rand_ports helper method Dimitri Daskalakis
@ 2026-02-24 22:46 ` Dimitri Daskalakis
2026-02-26 7:23 ` [PATCH net-next 2/2] selftests: drv-net: rss: Generate unique ports for RSS context tests: manual merge Matthieu Baerts
2026-02-26 4:00 ` [PATCH net-next 0/2] Add selftests helper to get N unique ports patchwork-bot+netdevbpf
2 siblings, 1 reply; 5+ messages in thread
From: Dimitri Daskalakis @ 2026-02-24 22:46 UTC (permalink / raw)
To: David S . Miller
Cc: Andrew Lunn, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Shuah Khan, Simon Horman, Willem de Bruijn, Stanislav Fomichev,
Daniel Zahka, Carolina Jubran, Gal Pressman, David Wei,
Mohsin Bashir, Nimrod Oren, Breno Leitao, Petr Machata, netdev,
linux-kselftest
The RSS ctx tests rely on NFC rules with unique ports to steer packets
to the correct ctx. This updates the test to use the new rand_ports()
helper to guarantee the ports are unique.
Manual testing shows that generating 32 ports with the existing method
would result in at least one duplicate 4% of the time.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Dimitri Daskalakis <dimitri.daskalakis1@gmail.com>
---
| 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
--git a/tools/testing/selftests/drivers/net/hw/rss_ctx.py b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
index ed7e405682f0..cbeb3a38fdfe 100755
--- a/tools/testing/selftests/drivers/net/hw/rss_ctx.py
+++ b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
@@ -9,7 +9,7 @@ from lib.py import ksft_eq, ksft_ne, ksft_ge, ksft_in, ksft_lt, ksft_true, ksft_
from lib.py import NetDrvEpEnv
from lib.py import EthtoolFamily, NetdevFamily
from lib.py import KsftSkipEx, KsftFailEx
-from lib.py import rand_port
+from lib.py import rand_port, rand_ports
from lib.py import ethtool, ip, defer, GenerateTraffic, CmdExitFailure
@@ -452,7 +452,7 @@ def test_rss_context(cfg, ctx_cnt=1, create_with_cfg=None):
except:
raise KsftSkipEx("Not enough queues for the test")
- ports = []
+ ports = rand_ports(ctx_cnt)
# Use queues 0 and 1 for normal traffic
ethtool(f"-X {cfg.ifname} equal 2")
@@ -486,7 +486,6 @@ def test_rss_context(cfg, ctx_cnt=1, create_with_cfg=None):
ksft_eq(min(data['rss-indirection-table']), 2 + i * 2, "Unexpected context cfg: " + str(data))
ksft_eq(max(data['rss-indirection-table']), 2 + i * 2 + 1, "Unexpected context cfg: " + str(data))
- ports.append(rand_port())
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {ports[i]} context {ctx_id}"
ntuple = ethtool_create(cfg, "-N", flow)
defer(ethtool, f"-N {cfg.ifname} delete {ntuple}")
@@ -542,7 +541,7 @@ def test_rss_context_out_of_order(cfg, ctx_cnt=4):
ntuple = []
ctx = []
- ports = []
+ ports = rand_ports(ctx_cnt)
def remove_ctx(idx):
ntuple[idx].exec()
@@ -574,7 +573,6 @@ def test_rss_context_out_of_order(cfg, ctx_cnt=4):
ctx_id = ethtool_create(cfg, "-X", f"context new start {2 + i * 2} equal 2")
ctx.append(defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete"))
- ports.append(rand_port())
flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {ports[i]} context {ctx_id}"
ntuple_id = ethtool_create(cfg, "-N", flow)
ntuple.append(defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}"))
@@ -788,9 +786,10 @@ def test_rss_default_context_rule(cfg):
ethtool(f"-N {cfg.ifname} {flow_generic}")
defer(ethtool, f"-N {cfg.ifname} delete 1")
+ ports = rand_ports(2)
# Specific high-priority rule for a random port that should stay on context 0.
# Assign loc 0 so it is evaluated before the generic rule.
- port_main = rand_port()
+ port_main = ports[0]
flow_main = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port {port_main} context 0 loc 0"
ethtool(f"-N {cfg.ifname} {flow_main}")
defer(ethtool, f"-N {cfg.ifname} delete 0")
@@ -803,7 +802,7 @@ def test_rss_default_context_rule(cfg):
'empty' : (2, 3) })
# And that traffic for any other port is steered to the new context
- port_other = rand_port()
+ port_other = ports[1]
_send_traffic_check(cfg, port_other, f"context {ctx_id}",
{ 'target': (2, 3),
'noise' : (0, 1) })
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread