aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <[email protected]>2024-06-28 18:39:43 -0700
committerJakub Kicinski <[email protected]>2024-06-28 18:39:44 -0700
commitc2dd2139e0cd0a567d68f0ca7215dcfe627e7afc (patch)
treee6873d3c5d1143d082bba5e1d711d0fe2a013536
parentbf7bb7b43097d8c2b8673c5ea8a6b64a1f6090b0 (diff)
parent0759356bf5fadbd16794bec982a9af48351a02ff (diff)
Merge branch 'selftests-drv-net-add-ability-to-schedule-cleanup-with-defer'
Jakub Kicinski says: ==================== selftests: drv-net: add ability to schedule cleanup with defer() Introduce a defer / cleanup mechanism for driver selftests. More detailed info in the second patch. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
-rwxr-xr-xtools/testing/selftests/drivers/net/hw/rss_ctx.py235
-rw-r--r--tools/testing/selftests/net/lib/py/ksft.py51
-rw-r--r--tools/testing/selftests/net/lib/py/utils.py34
3 files changed, 173 insertions, 147 deletions
diff --git a/tools/testing/selftests/drivers/net/hw/rss_ctx.py b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
index 68c7d40214eb..3a804e41f7cb 100755
--- a/tools/testing/selftests/drivers/net/hw/rss_ctx.py
+++ b/tools/testing/selftests/drivers/net/hw/rss_ctx.py
@@ -8,7 +8,7 @@ from lib.py import NetDrvEpEnv
from lib.py import NetdevFamily
from lib.py import KsftSkipEx
from lib.py import rand_port
-from lib.py import ethtool, ip, GenerateTraffic, CmdExitFailure
+from lib.py import ethtool, ip, defer, GenerateTraffic, CmdExitFailure
def _rss_key_str(key):
@@ -127,64 +127,56 @@ def test_rss_context(cfg, ctx_cnt=1, create_with_cfg=None):
# Try to allocate more queues when necessary
qcnt = len(_get_rx_cnts(cfg))
- if qcnt >= 2 + 2 * ctx_cnt:
- qcnt = None
- else:
+ if qcnt < 2 + 2 * ctx_cnt:
try:
ksft_pr(f"Increasing queue count {qcnt} -> {2 + 2 * ctx_cnt}")
ethtool(f"-L {cfg.ifname} combined {2 + 2 * ctx_cnt}")
+ defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
except:
raise KsftSkipEx("Not enough queues for the test")
- ntuple = []
- ctx_id = []
ports = []
- try:
- # Use queues 0 and 1 for normal traffic
- ethtool(f"-X {cfg.ifname} equal 2")
- for i in range(ctx_cnt):
- want_cfg = f"start {2 + i * 2} equal 2"
- create_cfg = want_cfg if create_with_cfg else ""
-
- try:
- ctx_id.append(ethtool_create(cfg, "-X", f"context new {create_cfg}"))
- except CmdExitFailure:
- # try to carry on and skip at the end
- if i == 0:
- raise
- ksft_pr(f"Failed to create context {i + 1}, trying to test what we got")
- ctx_cnt = i
- break
-
- if not create_with_cfg:
- ethtool(f"-X {cfg.ifname} context {ctx_id[i]} {want_cfg}")
-
- # Sanity check the context we just created
- data = get_rss(cfg, ctx_id[i])
- 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-port {ports[i]} context {ctx_id[i]}"
- ntuple.append(ethtool_create(cfg, "-N", flow))
+ # Use queues 0 and 1 for normal traffic
+ ethtool(f"-X {cfg.ifname} equal 2")
+ defer(ethtool, f"-X {cfg.ifname} default")
- for i in range(ctx_cnt):
- cnts = _get_rx_cnts(cfg)
- GenerateTraffic(cfg, port=ports[i]).wait_pkts_and_stop(20000)
- cnts = _get_rx_cnts(cfg, prev=cnts)
+ for i in range(ctx_cnt):
+ want_cfg = f"start {2 + i * 2} equal 2"
+ create_cfg = want_cfg if create_with_cfg else ""
- ksft_lt(sum(cnts[ :2]), 10000, "traffic on main context:" + str(cnts))
- ksft_ge(sum(cnts[2+i*2:4+i*2]), 20000, f"traffic on context {i}: " + str(cnts))
- ksft_eq(sum(cnts[2:2+i*2] + cnts[4+i*2:]), 0, "traffic on other contexts: " + str(cnts))
- finally:
- for nid in ntuple:
- ethtool(f"-N {cfg.ifname} delete {nid}")
- for cid in ctx_id:
- ethtool(f"-X {cfg.ifname} context {cid} delete")
- ethtool(f"-X {cfg.ifname} default")
- if qcnt:
- ethtool(f"-L {cfg.ifname} combined {qcnt}")
+ try:
+ ctx_id = ethtool_create(cfg, "-X", f"context new {create_cfg}")
+ defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
+ except CmdExitFailure:
+ # try to carry on and skip at the end
+ if i == 0:
+ raise
+ ksft_pr(f"Failed to create context {i + 1}, trying to test what we got")
+ ctx_cnt = i
+ break
+
+ if not create_with_cfg:
+ ethtool(f"-X {cfg.ifname} context {ctx_id} {want_cfg}")
+
+ # Sanity check the context we just created
+ data = get_rss(cfg, ctx_id)
+ 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-port {ports[i]} context {ctx_id}"
+ ntuple = ethtool_create(cfg, "-N", flow)
+ defer(ethtool, f"-N {cfg.ifname} delete {ntuple}")
+
+ for i in range(ctx_cnt):
+ cnts = _get_rx_cnts(cfg)
+ GenerateTraffic(cfg, port=ports[i]).wait_pkts_and_stop(20000)
+ cnts = _get_rx_cnts(cfg, prev=cnts)
+
+ ksft_lt(sum(cnts[ :2]), 10000, "traffic on main context:" + str(cnts))
+ ksft_ge(sum(cnts[2+i*2:4+i*2]), 20000, f"traffic on context {i}: " + str(cnts))
+ ksft_eq(sum(cnts[2:2+i*2] + cnts[4+i*2:]), 0, "traffic on other contexts: " + str(cnts))
if requested_ctx_cnt != ctx_cnt:
raise KsftSkipEx(f"Tested only {ctx_cnt} contexts, wanted {requested_ctx_cnt}")
@@ -216,24 +208,23 @@ def test_rss_context_out_of_order(cfg, ctx_cnt=4):
# Try to allocate more queues when necessary
qcnt = len(_get_rx_cnts(cfg))
- if qcnt >= 2 + 2 * ctx_cnt:
- qcnt = None
- else:
+ if qcnt < 2 + 2 * ctx_cnt:
try:
ksft_pr(f"Increasing queue count {qcnt} -> {2 + 2 * ctx_cnt}")
ethtool(f"-L {cfg.ifname} combined {2 + 2 * ctx_cnt}")
+ defer(ethtool, f"-L {cfg.ifname} combined {qcnt}")
except:
raise KsftSkipEx("Not enough queues for the test")
ntuple = []
- ctx_id = []
+ ctx = []
ports = []
def remove_ctx(idx):
- ethtool(f"-N {cfg.ifname} delete {ntuple[idx]}")
+ ntuple[idx].exec()
ntuple[idx] = None
- ethtool(f"-X {cfg.ifname} context {ctx_id[idx]} delete")
- ctx_id[idx] = None
+ ctx[idx].exec()
+ ctx[idx] = None
def check_traffic():
for i in range(ctx_cnt):
@@ -241,7 +232,7 @@ def test_rss_context_out_of_order(cfg, ctx_cnt=4):
GenerateTraffic(cfg, port=ports[i]).wait_pkts_and_stop(20000)
cnts = _get_rx_cnts(cfg, prev=cnts)
- if ctx_id[i] is None:
+ if ctx[i]:
ksft_lt(sum(cnts[ :2]), 10000, "traffic on main context:" + str(cnts))
ksft_ge(sum(cnts[2+i*2:4+i*2]), 20000, f"traffic on context {i}: " + str(cnts))
ksft_eq(sum(cnts[2:2+i*2] + cnts[4+i*2:]), 0, "traffic on other contexts: " + str(cnts))
@@ -249,41 +240,32 @@ def test_rss_context_out_of_order(cfg, ctx_cnt=4):
ksft_ge(sum(cnts[ :2]), 20000, "traffic on main context:" + str(cnts))
ksft_eq(sum(cnts[2: ]), 0, "traffic on other contexts: " + str(cnts))
- try:
- # Use queues 0 and 1 for normal traffic
- ethtool(f"-X {cfg.ifname} equal 2")
-
- for i in range(ctx_cnt):
- ctx_id.append(ethtool_create(cfg, "-X", f"context new start {2 + i * 2} equal 2"))
+ # Use queues 0 and 1 for normal traffic
+ ethtool(f"-X {cfg.ifname} equal 2")
+ defer(ethtool, f"-X {cfg.ifname} default")
- ports.append(rand_port())
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {ports[i]} context {ctx_id[i]}"
- ntuple.append(ethtool_create(cfg, "-N", flow))
+ for i in range(ctx_cnt):
+ 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"))
- check_traffic()
+ ports.append(rand_port())
+ flow = f"flow-type tcp{cfg.addr_ipver} 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}"))
- # Remove middle context
- remove_ctx(ctx_cnt // 2)
- check_traffic()
+ check_traffic()
- # Remove first context
- remove_ctx(0)
- check_traffic()
+ # Remove middle context
+ remove_ctx(ctx_cnt // 2)
+ check_traffic()
- # Remove last context
- remove_ctx(-1)
- check_traffic()
+ # Remove first context
+ remove_ctx(0)
+ check_traffic()
- finally:
- for nid in ntuple:
- if nid is not None:
- ethtool(f"-N {cfg.ifname} delete {nid}")
- for cid in ctx_id:
- if cid is not None:
- ethtool(f"-X {cfg.ifname} context {cid} delete")
- ethtool(f"-X {cfg.ifname} default")
- if qcnt:
- ethtool(f"-L {cfg.ifname} combined {qcnt}")
+ # Remove last context
+ remove_ctx(-1)
+ check_traffic()
if requested_ctx_cnt != ctx_cnt:
raise KsftSkipEx(f"Tested only {ctx_cnt} contexts, wanted {requested_ctx_cnt}")
@@ -298,69 +280,58 @@ def test_rss_context_overlap(cfg, other_ctx=0):
require_ntuple(cfg)
queue_cnt = len(_get_rx_cnts(cfg))
- if queue_cnt >= 4:
- queue_cnt = None
- else:
+ if queue_cnt < 4:
try:
ksft_pr(f"Increasing queue count {queue_cnt} -> 4")
ethtool(f"-L {cfg.ifname} combined 4")
+ defer(ethtool, f"-L {cfg.ifname} combined {queue_cnt}")
except:
raise KsftSkipEx("Not enough queues for the test")
- ctx_id = None
- ntuple = None
if other_ctx == 0:
ethtool(f"-X {cfg.ifname} equal 4")
+ defer(ethtool, f"-X {cfg.ifname} default")
else:
other_ctx = ethtool_create(cfg, "-X", "context new")
ethtool(f"-X {cfg.ifname} context {other_ctx} equal 4")
+ defer(ethtool, f"-X {cfg.ifname} context {other_ctx} delete")
- try:
- ctx_id = ethtool_create(cfg, "-X", "context new")
- ethtool(f"-X {cfg.ifname} context {ctx_id} start 2 equal 2")
+ ctx_id = ethtool_create(cfg, "-X", "context new")
+ ethtool(f"-X {cfg.ifname} context {ctx_id} start 2 equal 2")
+ defer(ethtool, f"-X {cfg.ifname} context {ctx_id} delete")
- port = rand_port()
- if other_ctx:
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {port} context {other_ctx}"
- ntuple = ethtool_create(cfg, "-N", flow)
+ port = rand_port()
+ if other_ctx:
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-port {port} context {other_ctx}"
+ ntuple_id = ethtool_create(cfg, "-N", flow)
+ ntuple = defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
- # Test the main context
- cnts = _get_rx_cnts(cfg)
- GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
- cnts = _get_rx_cnts(cfg, prev=cnts)
+ # Test the main context
+ cnts = _get_rx_cnts(cfg)
+ GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
+ cnts = _get_rx_cnts(cfg, prev=cnts)
- ksft_ge(sum(cnts[ :4]), 20000, "traffic on main context: " + str(cnts))
- ksft_ge(sum(cnts[ :2]), 7000, "traffic on main context (1/2): " + str(cnts))
- ksft_ge(sum(cnts[2:4]), 7000, "traffic on main context (2/2): " + str(cnts))
- if other_ctx == 0:
- ksft_eq(sum(cnts[4: ]), 0, "traffic on other queues: " + str(cnts))
-
- # Now create a rule for context 1 and make sure traffic goes to a subset
- if other_ctx:
- ethtool(f"-N {cfg.ifname} delete {ntuple}")
- ntuple = None
- flow = f"flow-type tcp{cfg.addr_ipver} dst-port {port} context {ctx_id}"
- ntuple = ethtool_create(cfg, "-N", flow)
+ ksft_ge(sum(cnts[ :4]), 20000, "traffic on main context: " + str(cnts))
+ ksft_ge(sum(cnts[ :2]), 7000, "traffic on main context (1/2): " + str(cnts))
+ ksft_ge(sum(cnts[2:4]), 7000, "traffic on main context (2/2): " + str(cnts))
+ if other_ctx == 0:
+ ksft_eq(sum(cnts[4: ]), 0, "traffic on other queues: " + str(cnts))
- cnts = _get_rx_cnts(cfg)
- GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
- cnts = _get_rx_cnts(cfg, prev=cnts)
+ # Now create a rule for context 1 and make sure traffic goes to a subset
+ if other_ctx:
+ ntuple.exec()
+ flow = f"flow-type tcp{cfg.addr_ipver} dst-port {port} context {ctx_id}"
+ ntuple_id = ethtool_create(cfg, "-N", flow)
+ defer(ethtool, f"-N {cfg.ifname} delete {ntuple_id}")
- ksft_lt(sum(cnts[ :2]), 7000, "traffic on main context: " + str(cnts))
- ksft_ge(sum(cnts[2:4]), 20000, "traffic on extra context: " + str(cnts))
- if other_ctx == 0:
- ksft_eq(sum(cnts[4: ]), 0, "traffic on other queues: " + str(cnts))
- finally:
- if ntuple is not None:
- ethtool(f"-N {cfg.ifname} delete {ntuple}")
- if ctx_id:
- ethtool(f"-X {cfg.ifname} context {ctx_id} delete")
- if other_ctx == 0:
- ethtool(f"-X {cfg.ifname} default")
- else:
- ethtool(f"-X {cfg.ifname} context {other_ctx} delete")
- if queue_cnt:
- ethtool(f"-L {cfg.ifname} combined {queue_cnt}")
+ cnts = _get_rx_cnts(cfg)
+ GenerateTraffic(cfg, port=port).wait_pkts_and_stop(20000)
+ cnts = _get_rx_cnts(cfg, prev=cnts)
+
+ ksft_lt(sum(cnts[ :2]), 7000, "traffic on main context: " + str(cnts))
+ ksft_ge(sum(cnts[2:4]), 20000, "traffic on extra context: " + str(cnts))
+ if other_ctx == 0:
+ ksft_eq(sum(cnts[4: ]), 0, "traffic on other queues: " + str(cnts))
def test_rss_context_overlap2(cfg):
diff --git a/tools/testing/selftests/net/lib/py/ksft.py b/tools/testing/selftests/net/lib/py/ksft.py
index b6ce3f33d41e..3aaa2748a58e 100644
--- a/tools/testing/selftests/net/lib/py/ksft.py
+++ b/tools/testing/selftests/net/lib/py/ksft.py
@@ -6,6 +6,7 @@ import sys
import time
import traceback
from .consts import KSFT_MAIN_NAME
+from .utils import global_defer_queue
KSFT_RESULT = None
KSFT_RESULT_ALL = True
@@ -108,6 +109,24 @@ def ktap_result(ok, cnt=1, case="", comment=""):
print(res)
+def ksft_flush_defer():
+ global KSFT_RESULT
+
+ i = 0
+ qlen_start = len(global_defer_queue)
+ while global_defer_queue:
+ i += 1
+ entry = global_defer_queue.pop()
+ try:
+ entry.exec_only()
+ except:
+ ksft_pr(f"Exception while handling defer / cleanup (callback {i} of {qlen_start})!")
+ tb = traceback.format_exc()
+ for line in tb.strip().split('\n'):
+ ksft_pr("Defer Exception|", line)
+ KSFT_RESULT = False
+
+
def ksft_run(cases=None, globs=None, case_pfx=None, args=()):
cases = cases or []
@@ -130,29 +149,31 @@ def ksft_run(cases=None, globs=None, case_pfx=None, args=()):
for case in cases:
KSFT_RESULT = True
cnt += 1
+ comment = ""
+ cnt_key = ""
+
try:
case(*args)
except KsftSkipEx as e:
- ktap_result(True, cnt, case, comment="SKIP " + str(e))
- totals['skip'] += 1
- continue
+ comment = "SKIP " + str(e)
+ cnt_key = 'skip'
except KsftXfailEx as e:
- ktap_result(True, cnt, case, comment="XFAIL " + str(e))
- totals['xfail'] += 1
- continue
+ comment = "XFAIL " + str(e)
+ cnt_key = 'xfail'
except Exception as e:
tb = traceback.format_exc()
for line in tb.strip().split('\n'):
ksft_pr("Exception|", line)
- ktap_result(False, cnt, case)
- totals['fail'] += 1
- continue
-
- ktap_result(KSFT_RESULT, cnt, case)
- if KSFT_RESULT:
- totals['pass'] += 1
- else:
- totals['fail'] += 1
+ KSFT_RESULT = False
+ cnt_key = 'fail'
+
+ ksft_flush_defer()
+
+ if not cnt_key:
+ cnt_key = 'pass' if KSFT_RESULT else 'fail'
+
+ ktap_result(KSFT_RESULT, cnt, case, comment=comment)
+ totals[cnt_key] += 1
print(
f"# Totals: pass:{totals['pass']} fail:{totals['fail']} xfail:{totals['xfail']} xpass:0 skip:{totals['skip']} error:0"
diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py
index 405aa510aaf2..72590c3f90f1 100644
--- a/tools/testing/selftests/net/lib/py/utils.py
+++ b/tools/testing/selftests/net/lib/py/utils.py
@@ -66,6 +66,40 @@ class bkg(cmd):
return self.process(terminate=self.terminate, fail=self.check_fail)
+global_defer_queue = []
+
+
+class defer:
+ def __init__(self, func, *args, **kwargs):
+ global global_defer_queue
+
+ if not callable(func):
+ raise Exception("defer created with un-callable object, did you call the function instead of passing its name?")
+
+ self.func = func
+ self.args = args
+ self.kwargs = kwargs
+
+ self._queue = global_defer_queue
+ self._queue.append(self)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, ex_type, ex_value, ex_tb):
+ return self.exec()
+
+ def exec_only(self):
+ self.func(*self.args, **self.kwargs)
+
+ def cancel(self):
+ self._queue.remove(self)
+
+ def exec(self):
+ self.cancel()
+ self.exec_only()
+
+
def tool(name, args, json=None, ns=None, host=None):
cmd_str = name + ' '
if json: