summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/net/ynl/lib/ynl.py4
-rw-r--r--tools/testing/selftests/net/lib/py/ksft.py41
-rw-r--r--tools/testing/selftests/net/lib/py/nsim.py16
-rwxr-xr-xtools/testing/selftests/net/nl_netdev.py76
4 files changed, 121 insertions, 16 deletions
diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index 0ba5f6fb8747..a67f7b6fef92 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -995,9 +995,11 @@ class YnlFamily(SpecFamily):
rsp_msg.update(self._decode_struct(decoded.raw, op.fixed_header))
rsp.append(rsp_msg)
+ if dump:
+ return rsp
if not rsp:
return None
- if not dump and len(rsp) == 1:
+ if len(rsp) == 1:
return rsp[0]
return rsp
diff --git a/tools/testing/selftests/net/lib/py/ksft.py b/tools/testing/selftests/net/lib/py/ksft.py
index c7210525981c..3769b9197213 100644
--- a/tools/testing/selftests/net/lib/py/ksft.py
+++ b/tools/testing/selftests/net/lib/py/ksft.py
@@ -1,6 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
import builtins
+import inspect
+import time
+import traceback
from .consts import KSFT_MAIN_NAME
KSFT_RESULT = None
@@ -18,32 +21,45 @@ def ksft_pr(*objs, **kwargs):
print("#", *objs, **kwargs)
+def _fail(*args):
+ global KSFT_RESULT
+ KSFT_RESULT = False
+
+ frame = inspect.stack()[2]
+ ksft_pr("At " + frame.filename + " line " + str(frame.lineno) + ":")
+ ksft_pr(*args)
+
+
def ksft_eq(a, b, comment=""):
global KSFT_RESULT
if a != b:
- KSFT_RESULT = False
- ksft_pr("Check failed", a, "!=", b, comment)
+ _fail("Check failed", a, "!=", b, comment)
def ksft_true(a, comment=""):
- global KSFT_RESULT
if not a:
- KSFT_RESULT = False
- ksft_pr("Check failed", a, "does not eval to True", comment)
+ _fail("Check failed", a, "does not eval to True", comment)
def ksft_in(a, b, comment=""):
- global KSFT_RESULT
if a not in b:
- KSFT_RESULT = False
- ksft_pr("Check failed", a, "not in", b, comment)
+ _fail("Check failed", a, "not in", b, comment)
def ksft_ge(a, b, comment=""):
- global KSFT_RESULT
if a < b:
- KSFT_RESULT = False
- ksft_pr("Check failed", a, "<", b, comment)
+ _fail("Check failed", a, "<", b, comment)
+
+
+def ksft_busy_wait(cond, sleep=0.005, deadline=1, comment=""):
+ end = time.monotonic() + deadline
+ while True:
+ if cond():
+ return
+ if time.monotonic() > end:
+ _fail("Waiting for condition timed out", comment)
+ return
+ time.sleep(sleep)
def ktap_result(ok, cnt=1, case="", comment=""):
@@ -82,7 +98,8 @@ def ksft_run(cases, args=()):
totals['xfail'] += 1
continue
except Exception as e:
- for line in str(e).split('\n'):
+ tb = traceback.format_exc()
+ for line in tb.strip().split('\n'):
ksft_pr("Exception|", line)
ktap_result(False, cnt, case)
totals['fail'] += 1
diff --git a/tools/testing/selftests/net/lib/py/nsim.py b/tools/testing/selftests/net/lib/py/nsim.py
index 97457aca7e08..06896cdf7c18 100644
--- a/tools/testing/selftests/net/lib/py/nsim.py
+++ b/tools/testing/selftests/net/lib/py/nsim.py
@@ -28,6 +28,7 @@ class NetdevSim:
self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index)
ret = ip("-j link show dev %s" % ifname, ns=ns)
self.dev = json.loads(ret.stdout)[0]
+ self.ifindex = self.dev["ifindex"]
def dfs_write(self, path, val):
self.nsimdev.dfs_write(f'ports/{self.port_index}/' + path, val)
@@ -84,6 +85,17 @@ class NetdevSimDev:
for port_index in range(port_count):
self.nsims.append(self._make_port(port_index, ifnames[port_index]))
+ self.removed = False
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, ex_type, ex_value, ex_tb):
+ """
+ __exit__ gets called at the end of a "with" block.
+ """
+ self.remove()
+
def _make_port(self, port_index, ifname):
return NetdevSim(self, port_index, ifname, self.ns)
@@ -112,7 +124,9 @@ class NetdevSimDev:
raise Exception("netdevices did not appear within timeout")
def remove(self):
- self.ctrl_write("del_device", "%u" % (self.addr, ))
+ if not self.removed:
+ self.ctrl_write("del_device", "%u" % (self.addr, ))
+ self.removed = True
def remove_nsim(self, nsim):
self.nsims.remove(nsim)
diff --git a/tools/testing/selftests/net/nl_netdev.py b/tools/testing/selftests/net/nl_netdev.py
index 2b8b488fb419..6909b1760739 100755
--- a/tools/testing/selftests/net/nl_netdev.py
+++ b/tools/testing/selftests/net/nl_netdev.py
@@ -1,7 +1,9 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
-from lib.py import ksft_run, ksft_pr, ksft_eq, ksft_ge, NetdevFamily
+import time
+from lib.py import ksft_run, ksft_pr, ksft_eq, ksft_ge, ksft_busy_wait
+from lib.py import NetdevFamily, NetdevSimDev, ip
def empty_check(nf) -> None:
@@ -15,9 +17,79 @@ def lo_check(nf) -> None:
ksft_eq(len(lo_info['xdp-rx-metadata-features']), 0)
+def page_pool_check(nf) -> None:
+ with NetdevSimDev() as nsimdev:
+ nsim = nsimdev.nsims[0]
+
+ def up():
+ ip(f"link set dev {nsim.ifname} up")
+
+ def down():
+ ip(f"link set dev {nsim.ifname} down")
+
+ def get_pp():
+ pp_list = nf.page_pool_get({}, dump=True)
+ return [pp for pp in pp_list if pp.get("ifindex") == nsim.ifindex]
+
+ # No page pools when down
+ down()
+ ksft_eq(len(get_pp()), 0)
+
+ # Up, empty page pool appears
+ up()
+ pp_list = get_pp()
+ ksft_ge(len(pp_list), 0)
+ refs = sum([pp["inflight"] for pp in pp_list])
+ ksft_eq(refs, 0)
+
+ # Down, it disappears, again
+ down()
+ pp_list = get_pp()
+ ksft_eq(len(pp_list), 0)
+
+ # Up, allocate a page
+ up()
+ nsim.dfs_write("pp_hold", "y")
+ pp_list = nf.page_pool_get({}, dump=True)
+ refs = sum([pp["inflight"] for pp in pp_list if pp.get("ifindex") == nsim.ifindex])
+ ksft_ge(refs, 1)
+
+ # Now let's leak a page
+ down()
+ pp_list = get_pp()
+ ksft_eq(len(pp_list), 1)
+ refs = sum([pp["inflight"] for pp in pp_list])
+ ksft_eq(refs, 1)
+ attached = [pp for pp in pp_list if "detach-time" not in pp]
+ ksft_eq(len(attached), 0)
+
+ # New pp can get created, and we'll have two
+ up()
+ pp_list = get_pp()
+ attached = [pp for pp in pp_list if "detach-time" not in pp]
+ detached = [pp for pp in pp_list if "detach-time" in pp]
+ ksft_eq(len(attached), 1)
+ ksft_eq(len(detached), 1)
+
+ # Free the old page and the old pp is gone
+ nsim.dfs_write("pp_hold", "n")
+ # Freeing check is once a second so we may need to retry
+ ksft_busy_wait(lambda: len(get_pp()) == 1, deadline=2)
+
+ # And down...
+ down()
+ ksft_eq(len(get_pp()), 0)
+
+ # Last, leave the page hanging for destroy, nothing to check
+ # we're trying to exercise the orphaning path in the kernel
+ up()
+ nsim.dfs_write("pp_hold", "y")
+
+
def main() -> None:
nf = NetdevFamily()
- ksft_run([empty_check, lo_check], args=(nf, ))
+ ksft_run([empty_check, lo_check, page_pool_check],
+ args=(nf, ))
if __name__ == "__main__":