[RFC net-next 2/4] selftests: drv-net: tso: add helpers for double tunneling GSO

From: Xu Du

Date: Mon Apr 06 2026 - 22:45:55 EST


Add helper functions to support double tunneling GSO testing. Since certain
tunnel-specific parameters (e.g., gro-hint) are not yet supported by the
standard ip-link tool, this patch adds a new helper function utilizing
the ynl-cli to handle these extended netlink attributes.

As the YNL Python module cannot be invoked across different devices or
environments directly in its current form, the helper abstracts the
YNL CLI calls to ensure proper configuration of the tunneling device
features.

Signed-off-by: Xu Du <xudu@xxxxxxxxxx>
---
.../drivers/net/hw/lib/py/__init__.py | 4 ++--
.../selftests/drivers/net/lib/py/__init__.py | 4 ++--
.../testing/selftests/net/lib/py/__init__.py | 4 ++--
tools/testing/selftests/net/lib/py/utils.py | 19 +++++++++++++++++--
4 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
index df4da5078c48..34a06e1afcb5 100644
--- a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
+++ b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py
@@ -24,7 +24,7 @@ try:
from net.lib.py import CmdExitFailure
from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \
fd_read_timeout, ip, rand_port, rand_ports, wait_port_listen, \
- wait_file, tool
+ wait_file, tool, ynlcli
from net.lib.py import bpf_map_set, bpf_map_dump, bpf_prog_map_ids
from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \
@@ -40,7 +40,7 @@ try:
"CmdExitFailure",
"bkg", "cmd", "bpftool", "bpftrace", "defer", "ethtool",
"fd_read_timeout", "ip", "rand_port", "rand_ports",
- "wait_port_listen", "wait_file", "tool",
+ "wait_port_listen", "wait_file", "tool", "ynlcli",
"bpf_map_set", "bpf_map_dump", "bpf_prog_map_ids",
"KsftSkipEx", "KsftFailEx", "KsftXfailEx",
"ksft_disruptive", "ksft_exit", "ksft_pr", "ksft_run",
diff --git a/tools/testing/selftests/drivers/net/lib/py/__init__.py b/tools/testing/selftests/drivers/net/lib/py/__init__.py
index 2b5ec0505672..a9eb1a57fcc4 100644
--- a/tools/testing/selftests/drivers/net/lib/py/__init__.py
+++ b/tools/testing/selftests/drivers/net/lib/py/__init__.py
@@ -22,7 +22,7 @@ try:
from net.lib.py import EthtoolFamily, NetdevFamily, NetshaperFamily, \
NlError, RtnlFamily, DevlinkFamily, PSPFamily, Netlink
from net.lib.py import CmdExitFailure
- from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \
+ from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, ynlcli, \
fd_read_timeout, ip, rand_port, rand_ports, wait_port_listen, wait_file
from net.lib.py import bpf_map_set, bpf_map_dump, bpf_prog_map_ids
from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
@@ -36,7 +36,7 @@ try:
"NlError", "RtnlFamily", "DevlinkFamily", "PSPFamily", "Netlink",
"CmdExitFailure",
"bkg", "cmd", "bpftool", "bpftrace", "defer", "ethtool",
- "fd_read_timeout", "ip", "rand_port", "rand_ports",
+ "fd_read_timeout", "ip", "rand_port", "rand_ports", "ynlcli",
"wait_port_listen", "wait_file",
"bpf_map_set", "bpf_map_dump", "bpf_prog_map_ids",
"KsftSkipEx", "KsftFailEx", "KsftXfailEx",
diff --git a/tools/testing/selftests/net/lib/py/__init__.py b/tools/testing/selftests/net/lib/py/__init__.py
index 7c81d86a7e97..a3337666a856 100644
--- a/tools/testing/selftests/net/lib/py/__init__.py
+++ b/tools/testing/selftests/net/lib/py/__init__.py
@@ -14,7 +14,7 @@ from .netns import NetNS, NetNSEnter
from .nsim import NetdevSim, NetdevSimDev
from .utils import CmdExitFailure, fd_read_timeout, cmd, bkg, defer, \
bpftool, ip, ethtool, bpftrace, rand_port, rand_ports, wait_port_listen, \
- wait_file, tool
+ wait_file, tool, ynlcli
from .bpf import bpf_map_set, bpf_map_dump, bpf_prog_map_ids
from .ynl import NlError, NlctrlFamily, YnlFamily, \
EthtoolFamily, NetdevFamily, RtnlFamily, RtnlAddrFamily
@@ -29,7 +29,7 @@ __all__ = ["KSRC",
"NetNS", "NetNSEnter",
"CmdExitFailure", "fd_read_timeout", "cmd", "bkg", "defer",
"bpftool", "ip", "ethtool", "bpftrace", "rand_port", "rand_ports",
- "wait_port_listen", "wait_file", "tool",
+ "wait_port_listen", "wait_file", "tool", "ynlcli",
"bpf_map_set", "bpf_map_dump", "bpf_prog_map_ids",
"NetdevSim", "NetdevSimDev",
"NetshaperFamily", "DevlinkFamily", "PSPFamily", "NlError",
diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py
index 6c44a3d2bbf7..a14a4b5dd592 100644
--- a/tools/testing/selftests/net/lib/py/utils.py
+++ b/tools/testing/selftests/net/lib/py/utils.py
@@ -8,6 +8,8 @@ import socket
import subprocess
import time

+from .consts import KSRC, KSFT_DIR
+

class CmdInitFailure(Exception):
""" Command failed to start. Only raised by bkg(). """
@@ -217,12 +219,12 @@ class defer:
self.exec_only()


-def tool(name, args, json=None, ns=None, host=None):
+def tool(name, args, json=None, ns=None, host=None, shell=None):
cmd_str = name + ' '
if json:
cmd_str += '--json '
cmd_str += args
- cmd_obj = cmd(cmd_str, ns=ns, host=host)
+ cmd_obj = cmd(cmd_str, ns=ns, host=host, shell=shell)
if json:
return _json.loads(cmd_obj.stdout)
return cmd_obj
@@ -242,6 +244,19 @@ def ethtool(args, json=None, ns=None, host=None):
return tool('ethtool', args, json=json, ns=ns, host=host)


+def ynlcli(family, args, json=None, ns=None, host=None):
+ if (KSFT_DIR / "kselftest-list.txt").exists():
+ cli = KSFT_DIR / "net/lib/ynl/pyynl/cli.py"
+ spec = KSFT_DIR / f"net/lib/specs/{family}.yaml"
+ else:
+ cli = KSRC / "tools/net/ynl/pyynl/cli.py"
+ spec = KSRC / f"Documentation/netlink/specs/{family}.yaml"
+ if not cli.exists():
+ raise FileNotFoundError(f"cli not found at {cli}")
+ args = f"--spec {spec} --no-schema {args}"
+ return tool(cli.as_posix(), args, json=json, ns=ns, host=host, shell=True)
+
+
def bpftrace(expr, json=None, ns=None, host=None, timeout=None):
"""
Run bpftrace and return map data (if json=True).
--
2.53.0