From: Jakub Kicinski <kuba@kernel.org>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com,
shuah@kernel.org, petrm@nvidia.com,
linux-kselftest@vger.kernel.org, willemb@google.com,
Jakub Kicinski <kuba@kernel.org>
Subject: [PATCH net-next 1/5] selftests: drv-net: define endpoint structures
Date: Fri, 12 Apr 2024 16:37:01 -0700 [thread overview]
Message-ID: <20240412233705.1066444-2-kuba@kernel.org> (raw)
In-Reply-To: <20240412233705.1066444-1-kuba@kernel.org>
Define the 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 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 Endpoint
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 endpoints. The host / endpoint object are passed
as an argument to the usual cmd() or ip() invocation. For example:
ip("link show", json=True, host=endpoint)
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
.../selftests/drivers/net/lib/py/__init__.py | 1 +
.../selftests/drivers/net/lib/py/endpoint.py | 13 +++++++
.../selftests/drivers/net/lib/py/ep_netns.py | 15 ++++++++
.../selftests/drivers/net/lib/py/ep_ssh.py | 34 +++++++++++++++++++
tools/testing/selftests/net/lib/py/utils.py | 19 ++++++-----
5 files changed, 73 insertions(+), 9 deletions(-)
create mode 100644 tools/testing/selftests/drivers/net/lib/py/endpoint.py
create mode 100644 tools/testing/selftests/drivers/net/lib/py/ep_netns.py
create mode 100644 tools/testing/selftests/drivers/net/lib/py/ep_ssh.py
diff --git a/tools/testing/selftests/drivers/net/lib/py/__init__.py b/tools/testing/selftests/drivers/net/lib/py/__init__.py
index 4653dffcd962..0d71ec83135b 100644
--- a/tools/testing/selftests/drivers/net/lib/py/__init__.py
+++ b/tools/testing/selftests/drivers/net/lib/py/__init__.py
@@ -15,3 +15,4 @@ KSFT_DIR = (Path(__file__).parent / "../../../..").resolve()
sys.exit(4)
from .env import *
+from .endpoint import Endpoint
diff --git a/tools/testing/selftests/drivers/net/lib/py/endpoint.py b/tools/testing/selftests/drivers/net/lib/py/endpoint.py
new file mode 100644
index 000000000000..9272fdc47a06
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/lib/py/endpoint.py
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+
+import importlib
+
+_modules = {}
+
+def Endpoint(ep_type, ep_args):
+ global _modules
+
+ if ep_type not in _modules:
+ _modules[ep_type] = importlib.import_module("..ep_" + ep_type, __name__)
+
+ return getattr(_modules[ep_type], "Endpoint")(ep_args)
diff --git a/tools/testing/selftests/drivers/net/lib/py/ep_netns.py b/tools/testing/selftests/drivers/net/lib/py/ep_netns.py
new file mode 100644
index 000000000000..f5c588bb31f0
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/lib/py/ep_netns.py
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+
+from lib.py import cmd
+
+
+class Endpoint:
+ def __init__(self, name):
+ self.name = name
+
+ def cmd(self, *args):
+ c = cmd(*args, ns=self.name)
+ return c.stdout, c.stderr, c.ret
+
+ def deploy(self, what):
+ return what
diff --git a/tools/testing/selftests/drivers/net/lib/py/ep_ssh.py b/tools/testing/selftests/drivers/net/lib/py/ep_ssh.py
new file mode 100644
index 000000000000..620df0dd8c07
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/lib/py/ep_ssh.py
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+
+import os
+import shlex
+import string
+import random
+
+from lib.py import cmd
+
+
+class Endpoint:
+ def __init__(self, name):
+ self.name = name
+ self._tmpdir = None
+
+ def __del__(self):
+ if self._tmpdir:
+ self.cmd("rm -rf " + self._tmpdir)
+ self._tmpdir = None
+
+ def cmd(self, comm, *args):
+ c = cmd("ssh " + self.name + " " + shlex.quote(comm), *args)
+ return c.stdout, c.stderr, c.ret
+
+ 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()
+ self.cmd("mkdir " + self._tmpdir)
+ file_name = self._tmpdir + "/" + self._mktmp() + os.path.basename(what)
+ cmd(f"scp {what} {self.name}:{file_name}")
+ return file_name
diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py
index f0d425731fd4..eff50ddd9a9d 100644
--- a/tools/testing/selftests/net/lib/py/utils.py
+++ b/tools/testing/selftests/net/lib/py/utils.py
@@ -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,10 +13,13 @@ import subprocess
self.ret = None
self.comm = comm
- self.proc = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- if not background:
- self.process(terminate=False, fail=fail)
+ if host:
+ self.stdout, self.stderr, self.ret = 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:
@@ -36,12 +37,12 @@ import subprocess
raise Exception("Command failed: %s\n%s" % (self.proc.args, 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
--
2.44.0
next prev parent reply other threads:[~2024-04-12 23:37 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-12 23:37 [PATCH net-next 0/5] selftests: drv-net: support testing with a remote system Jakub Kicinski
2024-04-12 23:37 ` Jakub Kicinski [this message]
2024-04-14 17:04 ` [PATCH net-next 1/5] selftests: drv-net: define endpoint structures Willem de Bruijn
2024-04-15 14:16 ` Jakub Kicinski
2024-04-15 15:23 ` Willem de Bruijn
2024-04-15 19:39 ` Petr Machata
2024-04-15 8:57 ` Paolo Abeni
2024-04-15 14:19 ` Jakub Kicinski
2024-04-15 16:02 ` Paolo Abeni
2024-04-15 16:11 ` Paolo Abeni
2024-04-12 23:37 ` [PATCH net-next 2/5] selftests: drv-net: add stdout to the command failed exception Jakub Kicinski
2024-04-12 23:37 ` [PATCH net-next 3/5] selftests: drv-net: factor out parsing of the env Jakub Kicinski
2024-04-12 23:37 ` [PATCH net-next 4/5] selftests: drv-net: construct environment for running tests which require an endpoint Jakub Kicinski
2024-04-14 16:45 ` Willem de Bruijn
2024-04-15 14:31 ` Jakub Kicinski
2024-04-15 15:28 ` Willem de Bruijn
2024-04-15 17:36 ` Jakub Kicinski
2024-04-15 9:28 ` Paolo Abeni
2024-04-12 23:37 ` [PATCH net-next 5/5] selftests: drv-net: add a trivial ping test Jakub Kicinski
2024-04-15 9:31 ` Paolo Abeni
2024-04-15 14:33 ` Jakub Kicinski
2024-04-15 16:09 ` Paolo Abeni
2024-04-15 15:30 ` [PATCH net-next 0/5] selftests: drv-net: support testing with a remote system Willem de Bruijn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240412233705.1066444-2-kuba@kernel.org \
--to=kuba@kernel.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=petrm@nvidia.com \
--cc=shuah@kernel.org \
--cc=willemb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).