Skip to content

Commit 34c9447

Browse files
committed
selftests: drv-net: define endpoint structures
JIRA: https://issues.redhat.com/browse/RHEL-57764 commit 1a20a9a Author: Jakub Kicinski <kuba@kernel.org> Date: Fri Apr 19 19:52:31 2024 -0700 selftests: drv-net: define endpoint structures Define the remote endpoint "model". To execute most meaningful device driver tests we need to be able to communicate with a remote system, and have it send traffic to the device under test. Various test environments will have different requirements. 0) "Local" netdevsim-based testing can simply use net namespaces. netdevsim supports connecting two devices now, to form a veth-like construct. 1) Similarly on hosts with multiple NICs, the NICs may be connected together with a loopback cable or internal device loopback. One interface may be placed into separate netns, and tests would proceed much like in the netdevsim case. Note that the loopback config or the moving of one interface into a netns is not expected to be part of selftest code. 2) Some systems may need to communicate with the remote endpoint via SSH. 3) Last but not least environment may have its own custom communication method. Fundamentally we only need two operations: - run a command remotely - deploy a binary (if some tool we need is built as part of kselftests) Wrap these two in a class. Use dynamic loading to load the Remote class. This will allow very easy definition of other communication methods without bothering upstream code base. Stick to the "simple" / "no unnecessary abstractions" model for referring to the remote endpoints. The host / remote object are passed as an argument to the usual cmd() or ip() invocation. For example: ip("link show", json=True, host=remote) Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://lore.kernel.org/r/20240420025237.3309296-2-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
1 parent ba9cfe0 commit 34c9447

File tree

5 files changed

+85
-8
lines changed

5 files changed

+85
-8
lines changed

tools/testing/selftests/drivers/net/lib/py/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
sys.exit(4)
1616

1717
from .env import *
18+
from .remote import Remote
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
3+
import os
4+
import importlib
5+
6+
_modules = {}
7+
8+
def Remote(kind, args, src_path):
9+
global _modules
10+
11+
if kind not in _modules:
12+
_modules[kind] = importlib.import_module("..remote_" + kind, __name__)
13+
14+
dir_path = os.path.abspath(src_path + "/../")
15+
return getattr(_modules[kind], "Remote")(args, dir_path)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
3+
import os
4+
import subprocess
5+
6+
from lib.py import cmd
7+
8+
9+
class Remote:
10+
def __init__(self, name, dir_path):
11+
self.name = name
12+
self.dir_path = dir_path
13+
14+
def cmd(self, comm):
15+
return subprocess.Popen(["ip", "netns", "exec", self.name, "bash", "-c", comm],
16+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
17+
18+
def deploy(self, what):
19+
if os.path.isabs(what):
20+
return what
21+
return os.path.abspath(self.dir_path + "/" + what)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
3+
import os
4+
import string
5+
import subprocess
6+
import random
7+
8+
from lib.py import cmd
9+
10+
11+
class Remote:
12+
def __init__(self, name, dir_path):
13+
self.name = name
14+
self.dir_path = dir_path
15+
self._tmpdir = None
16+
17+
def __del__(self):
18+
if self._tmpdir:
19+
cmd("rm -rf " + self._tmpdir, host=self)
20+
self._tmpdir = None
21+
22+
def cmd(self, comm):
23+
return subprocess.Popen(["ssh", "-q", self.name, comm],
24+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
25+
26+
def _mktmp(self):
27+
return ''.join(random.choice(string.ascii_lowercase) for _ in range(8))
28+
29+
def deploy(self, what):
30+
if not self._tmpdir:
31+
self._tmpdir = "/tmp/" + self._mktmp()
32+
cmd("mkdir " + self._tmpdir, host=self)
33+
file_name = self._tmpdir + "/" + self._mktmp() + os.path.basename(what)
34+
35+
if not os.path.isabs(what):
36+
what = os.path.abspath(self.dir_path + "/" + what)
37+
38+
cmd(f"scp {what} {self.name}:{file_name}")
39+
return file_name

tools/testing/selftests/net/lib/py/utils.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,27 @@
44
import subprocess
55

66
class cmd:
7-
def __init__(self, comm, shell=True, fail=True, ns=None, background=False):
7+
def __init__(self, comm, shell=True, fail=True, ns=None, background=False, host=None):
88
if ns:
9-
if isinstance(ns, NetNS):
10-
ns = ns.name
119
comm = f'ip netns exec {ns} ' + comm
1210

1311
self.stdout = None
1412
self.stderr = None
1513
self.ret = None
1614

1715
self.comm = comm
18-
self.proc = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE,
19-
stderr=subprocess.PIPE)
16+
if host:
17+
self.proc = host.cmd(comm)
18+
else:
19+
self.proc = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE,
20+
stderr=subprocess.PIPE)
2021
if not background:
2122
self.process(terminate=False, fail=fail)
2223

2324
def process(self, terminate=True, fail=None):
2425
if terminate:
2526
self.proc.terminate()
26-
stdout, stderr = self.proc.communicate()
27+
stdout, stderr = self.proc.communicate(timeout=5)
2728
self.stdout = stdout.decode("utf-8")
2829
self.stderr = stderr.decode("utf-8")
2930
self.proc.stdout.close()
@@ -36,12 +37,12 @@ def process(self, terminate=True, fail=None):
3637
raise Exception("Command failed: %s\n%s" % (self.proc.args, stderr))
3738

3839

39-
def ip(args, json=None, ns=None):
40+
def ip(args, json=None, ns=None, host=None):
4041
cmd_str = "ip "
4142
if json:
4243
cmd_str += '-j '
4344
cmd_str += args
44-
cmd_obj = cmd(cmd_str, ns=ns)
45+
cmd_obj = cmd(cmd_str, ns=ns, host=host)
4546
if json:
4647
return _json.loads(cmd_obj.stdout)
4748
return cmd_obj

0 commit comments

Comments
 (0)