On fast machines the tests run in quick succession so even when tests clean up after themselves the carrier may need some time to come back.
Specifically in NIPA when ping.py runs right after netpoll_basic.py the first ping command fails.
Since the context manager callbacks are now common NetDrvEpEnv gets an ip link up call as well.
Fixes: b4db9f840283 ("selftests: drivers: add scaffolding for Netlink tests in Python") Signed-off-by: Jakub Kicinski kuba@kernel.org --- CC: shuah@kernel.org CC: willemb@google.com CC: petrm@nvidia.com CC: linux-kselftest@vger.kernel.org --- .../selftests/drivers/net/lib/py/__init__.py | 2 +- .../selftests/drivers/net/lib/py/env.py | 38 +++++++++---------- tools/testing/selftests/net/lib/py/utils.py | 18 +++++++++ 3 files changed, 36 insertions(+), 22 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/lib/py/__init__.py b/tools/testing/selftests/drivers/net/lib/py/__init__.py index 8711c67ad658..a07b56a75c8a 100644 --- a/tools/testing/selftests/drivers/net/lib/py/__init__.py +++ b/tools/testing/selftests/drivers/net/lib/py/__init__.py @@ -15,7 +15,7 @@ KSFT_DIR = (Path(__file__).parent / "../../../..").resolve() NlError, RtnlFamily, DevlinkFamily from net.lib.py import CmdExitFailure from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \ - fd_read_timeout, ip, rand_port, tool, wait_port_listen + fd_read_timeout, ip, rand_port, tool, wait_port_listen, wait_file from net.lib.py import fd_read_timeout from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \ diff --git a/tools/testing/selftests/drivers/net/lib/py/env.py b/tools/testing/selftests/drivers/net/lib/py/env.py index 1b8bd648048f..1de63734ddec 100644 --- a/tools/testing/selftests/drivers/net/lib/py/env.py +++ b/tools/testing/selftests/drivers/net/lib/py/env.py @@ -4,7 +4,7 @@ import os import time from pathlib import Path from lib.py import KsftSkipEx, KsftXfailEx -from lib.py import ksft_setup +from lib.py import ksft_setup, wait_file from lib.py import cmd, ethtool, ip, CmdExitFailure from lib.py import NetNS, NetdevSimDev from .remote import Remote @@ -25,6 +25,9 @@ from .remote import Remote
self.env = self._load_env_file()
+ # Following attrs must be set be inheriting classes + self.dev = None + def _load_env_file(self): env = os.environ.copy()
@@ -48,6 +51,19 @@ from .remote import Remote env[pair[0]] = pair[1] return ksft_setup(env)
+ def __enter__(self): + ip(f"link set dev {self.dev['ifname']} up") + wait_file(f"/sys/class/net/{self.dev['ifname']}/carrier", + lambda x: x.strip() == "1") + + return self + + def __exit__(self, ex_type, ex_value, ex_tb): + """ + __exit__ gets called at the end of a "with" block. + """ + self.__del__() +
class NetDrvEnv(NetDrvEnvBase): """ @@ -72,17 +88,6 @@ from .remote import Remote self.ifname = self.dev['ifname'] self.ifindex = self.dev['ifindex']
- def __enter__(self): - ip(f"link set dev {self.dev['ifname']} up") - - return self - - def __exit__(self, ex_type, ex_value, ex_tb): - """ - __exit__ gets called at the end of a "with" block. - """ - self.__del__() - def __del__(self): if self._ns: self._ns.remove() @@ -219,15 +224,6 @@ from .remote import Remote raise Exception("Can't resolve remote interface name, multiple interfaces match") return v6[0]["ifname"] if v6 else v4[0]["ifname"]
- 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.__del__() - def __del__(self): if self._ns: self._ns.remove() diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py index f395c90fb0f1..c42bffea0d87 100644 --- a/tools/testing/selftests/net/lib/py/utils.py +++ b/tools/testing/selftests/net/lib/py/utils.py @@ -249,3 +249,21 @@ global_defer_queue = [] if time.monotonic() > end: raise Exception("Waiting for port listen timed out") time.sleep(sleep) + + +def wait_file(fname, test_fn, sleep=0.005, deadline=5, encoding='utf-8'): + """ + Wait for file contents on the local system to satisfy a condition. + test_fn() should take one argument (file contents) and return whether + condition is met. + """ + end = time.monotonic() + deadline + + with open(fname, "r", encoding=encoding) as fp: + while True: + if test_fn(fp.read()): + break + fp.seek(0) + if time.monotonic() > end: + raise TimeoutError("Wait for file contents failed", fname) + time.sleep(sleep)
On 8/9/25 12:57 AM, Jakub Kicinski wrote:
@@ -48,6 +51,19 @@ from .remote import Remote env[pair[0]] = pair[1] return ksft_setup(env)
- def __enter__(self):
ip(f"link set dev {self.dev['ifname']} up")
wait_file(f"/sys/class/net/{self.dev['ifname']}/carrier",
lambda x: x.strip() == "1")
return self
- def __exit__(self, ex_type, ex_value, ex_tb):
"""
__exit__ gets called at the end of a "with" block.
"""
self.__del__()
pylint is doing what looks like a reasonable complain to me:
tools/testing/selftests/drivers/net/lib/py/env.py:65:8: E1101: Instance of 'NetDrvEnvBase' has no '__del__' member (no-member)
/P
On Tue, 12 Aug 2025 13:12:47 +0200 Paolo Abeni wrote:
On 8/9/25 12:57 AM, Jakub Kicinski wrote:
@@ -48,6 +51,19 @@ from .remote import Remote env[pair[0]] = pair[1] return ksft_setup(env)
- def __enter__(self):
ip(f"link set dev {self.dev['ifname']} up")
wait_file(f"/sys/class/net/{self.dev['ifname']}/carrier",
lambda x: x.strip() == "1")
return self
- def __exit__(self, ex_type, ex_value, ex_tb):
"""
__exit__ gets called at the end of a "with" block.
"""
self.__del__()
pylint is doing what looks like a reasonable complain to me:
tools/testing/selftests/drivers/net/lib/py/env.py:65:8: E1101: Instance of 'NetDrvEnvBase' has no '__del__' member (no-member)
I know, it's an abstract class. The point of having an empty method is lost on me. But okay, let me obey the static analyzer overlord.
linux-kselftest-mirror@lists.linaro.org