[PATCH net-next v2 7/7] selftests: drv-net: psp: add a tx rekey drain test for SADB drivers

From: Daniel Zahka

Date: Fri Oct 09 2026 - 16:52:21 EST


Drivers that export the tx-key-count stat, should drain queued tx key
deletions in a timely manner.

Add a test that performs multiple tx rekeys on a connection and waits
to make sure tx-key-count returns to pre-rekey level.

There is a bit of noise in tx-key-count due to stale timewait sockets
from prior tests. If these sockets die between the initial and final
readings, it could only serve to cover up for a queued key deletion
that is not actually drained, so the test should not flake, but may
fail to detect an actual driver bug.

This test will likely not work if other processes on the system are
using psp on the DUT, because then the tx-key-count will be completely
unrelated to what we are doing in our tests.

Signed-off-by: Daniel Zahka <daniel.zahka@xxxxxxxxx>
---
tools/testing/selftests/drivers/net/psp.py | 38 +++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py
index af67c9e8c40f..b22891b7f5ce 100755
--- a/tools/testing/selftests/drivers/net/psp.py
+++ b/tools/testing/selftests/drivers/net/psp.py
@@ -15,7 +15,7 @@ from contextlib import contextmanager

from lib.py import defer
from lib.py import ksft_run, ksft_exit, ksft_pr
-from lib.py import ksft_true, ksft_eq, ksft_ne, ksft_gt, ksft_raises
+from lib.py import ksft_true, ksft_eq, ksft_ne, ksft_ge, ksft_gt, ksft_raises
from lib.py import ksft_not_none
from lib.py import ksft_variants, KsftNamedVariant
from lib.py import KsftSkipEx, KsftFailEx
@@ -30,6 +30,8 @@ TCP_ULP = 31

_PSP_MAX_KEY_LEN = 32
_PSP_ASSOC_MSG = f'!IB3x{_PSP_MAX_KEY_LEN}s'
+_TX_REKEY_ROUNDS = 20
+_TX_KEY_DRAIN_TIMEOUT = 5


def _get_outq(s):
@@ -202,6 +204,19 @@ def _require_version(cfg, version):
def _get_stat(cfg, key):
return cfg.pspnl.get_stats({'dev-id': cfg.psp_dev_id})[key]

+
+def _get_tx_key_count(cfg):
+ return cfg.pspnl.get_stats({'dev-id': cfg.psp_dev_id}).get('tx-key-count')
+
+
+def _wait_tx_key_drain(cfg, base):
+ cnt = _get_tx_key_count(cfg)
+ end = time.monotonic() + _TX_KEY_DRAIN_TIMEOUT
+ while cnt > base and time.monotonic() < end:
+ time.sleep(0.1)
+ cnt = _get_tx_key_count(cfg)
+ ksft_ge(base, cnt, comment="tx keys not removed from device after rekey")
+
#
# Test case boiler plate
#
@@ -730,6 +745,27 @@ def rekey_tx_basic(cfg, version):
_close_psp_conn(cfg, s)


+def rekey_tx_drain(cfg):
+ """Test that Tx rekeys do not leak keys on the device"""
+ _init_psp_dev(cfg)
+
+ if _get_tx_key_count(cfg) is None:
+ raise KsftSkipEx("Device does not track Tx keys")
+
+ s = _establish_psp_conn(cfg, 0)
+ try:
+ data_len = _psp_txrx(cfg, s, 1)
+ base = _get_tx_key_count(cfg)
+
+ for _ in range(_TX_REKEY_ROUNDS):
+ _remote_key_rotate(cfg)
+ data_len = _rekey_tx(cfg, s, data_len)
+
+ _wait_tx_key_drain(cfg, base)
+ finally:
+ _close_psp_conn(cfg, s)
+
+
@ksft_variants(_get_psp_ver_variants())
def rekey_both_sides(cfg, version):
"""Test rekeying both directions"""

--
2.52.0