mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 13:41:55 +00:00
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>
This commit is contained in:
parent
b2c8599f64
commit
1a20a9a0dd
@ -15,3 +15,4 @@ except ModuleNotFoundError as e:
|
||||
sys.exit(4)
|
||||
|
||||
from .env import *
|
||||
from .remote import Remote
|
||||
|
15
tools/testing/selftests/drivers/net/lib/py/remote.py
Normal file
15
tools/testing/selftests/drivers/net/lib/py/remote.py
Normal file
@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import os
|
||||
import importlib
|
||||
|
||||
_modules = {}
|
||||
|
||||
def Remote(kind, args, src_path):
|
||||
global _modules
|
||||
|
||||
if kind not in _modules:
|
||||
_modules[kind] = importlib.import_module("..remote_" + kind, __name__)
|
||||
|
||||
dir_path = os.path.abspath(src_path + "/../")
|
||||
return getattr(_modules[kind], "Remote")(args, dir_path)
|
21
tools/testing/selftests/drivers/net/lib/py/remote_netns.py
Normal file
21
tools/testing/selftests/drivers/net/lib/py/remote_netns.py
Normal file
@ -0,0 +1,21 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from lib.py import cmd
|
||||
|
||||
|
||||
class Remote:
|
||||
def __init__(self, name, dir_path):
|
||||
self.name = name
|
||||
self.dir_path = dir_path
|
||||
|
||||
def cmd(self, comm):
|
||||
return subprocess.Popen(["ip", "netns", "exec", self.name, "bash", "-c", comm],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
def deploy(self, what):
|
||||
if os.path.isabs(what):
|
||||
return what
|
||||
return os.path.abspath(self.dir_path + "/" + what)
|
39
tools/testing/selftests/drivers/net/lib/py/remote_ssh.py
Normal file
39
tools/testing/selftests/drivers/net/lib/py/remote_ssh.py
Normal file
@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import os
|
||||
import string
|
||||
import subprocess
|
||||
import random
|
||||
|
||||
from lib.py import cmd
|
||||
|
||||
|
||||
class Remote:
|
||||
def __init__(self, name, dir_path):
|
||||
self.name = name
|
||||
self.dir_path = dir_path
|
||||
self._tmpdir = None
|
||||
|
||||
def __del__(self):
|
||||
if self._tmpdir:
|
||||
cmd("rm -rf " + self._tmpdir, host=self)
|
||||
self._tmpdir = None
|
||||
|
||||
def cmd(self, comm):
|
||||
return subprocess.Popen(["ssh", "-q", self.name, comm],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
def _mktmp(self):
|
||||
return ''.join(random.choice(string.ascii_lowercase) for _ in range(8))
|
||||
|
||||
def deploy(self, what):
|
||||
if not self._tmpdir:
|
||||
self._tmpdir = "/tmp/" + self._mktmp()
|
||||
cmd("mkdir " + self._tmpdir, host=self)
|
||||
file_name = self._tmpdir + "/" + self._mktmp() + os.path.basename(what)
|
||||
|
||||
if not os.path.isabs(what):
|
||||
what = os.path.abspath(self.dir_path + "/" + what)
|
||||
|
||||
cmd(f"scp {what} {self.name}:{file_name}")
|
||||
return file_name
|
@ -4,10 +4,8 @@ import json as _json
|
||||
import subprocess
|
||||
|
||||
class cmd:
|
||||
def __init__(self, comm, shell=True, fail=True, ns=None, background=False):
|
||||
def __init__(self, comm, shell=True, fail=True, ns=None, background=False, host=None):
|
||||
if ns:
|
||||
if isinstance(ns, NetNS):
|
||||
ns = ns.name
|
||||
comm = f'ip netns exec {ns} ' + comm
|
||||
|
||||
self.stdout = None
|
||||
@ -15,15 +13,18 @@ class cmd:
|
||||
self.ret = None
|
||||
|
||||
self.comm = comm
|
||||
self.proc = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
if host:
|
||||
self.proc = host.cmd(comm)
|
||||
else:
|
||||
self.proc = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
if not background:
|
||||
self.process(terminate=False, fail=fail)
|
||||
|
||||
def process(self, terminate=True, fail=None):
|
||||
if terminate:
|
||||
self.proc.terminate()
|
||||
stdout, stderr = self.proc.communicate()
|
||||
stdout, stderr = self.proc.communicate(timeout=5)
|
||||
self.stdout = stdout.decode("utf-8")
|
||||
self.stderr = stderr.decode("utf-8")
|
||||
self.proc.stdout.close()
|
||||
@ -37,12 +38,12 @@ class cmd:
|
||||
(self.proc.args, stdout, stderr))
|
||||
|
||||
|
||||
def ip(args, json=None, ns=None):
|
||||
def ip(args, json=None, ns=None, host=None):
|
||||
cmd_str = "ip "
|
||||
if json:
|
||||
cmd_str += '-j '
|
||||
cmd_str += args
|
||||
cmd_obj = cmd(cmd_str, ns=ns)
|
||||
cmd_obj = cmd(cmd_str, ns=ns, host=host)
|
||||
if json:
|
||||
return _json.loads(cmd_obj.stdout)
|
||||
return cmd_obj
|
||||
|
Loading…
Reference in New Issue
Block a user