From: Todd Freed <toddfreed@meta.com>
To: <netdev@vger.kernel.org>, <toddfreed@meta.com>
Cc: "David S. Miller" <davem@davemloft.net>,
"Andrew Lunn" <andrew+netdev@lunn.ch>,
"Björn Töpel" <bjorn@kernel.org>,
bpf@vger.kernel.org, "Daniel Borkmann" <daniel@iogearbox.net>,
"Daniel Zahka" <daniel.zahka@gmail.com>,
"Donald Hunter" <donald.hunter@gmail.com>,
"Eric Dumazet" <edumazet@kernel.org>,
"Jakub Kicinski" <kuba@kernel.org>,
"Jamal Hadi Salim" <jhs@mojatatu.com>,
"Jiri Pirko" <jiri@resnulli.us>,
"John Fastabend" <john.fastabend@gmail.com>,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-rdma@vger.kernel.org,
"Martin KaFai Lau" <martin.lau@linux.dev>,
"Paolo Abeni" <pabeni@redhat.com>,
"Saeed Mahameed" <saeedm@nvidia.com>,
"Simon Horman" <horms@kernel.org>,
"Tariq Toukan" <tariqt@nvidia.com>,
"Wei Wang" <weiwan@google.com>,
"Willem de Bruijn" <willemdebruijn.kernel@gmail.com>
Subject: [PATCH net-next v1 12/15] selftests: drv-net: psp: test that software encap on ingress drops
Date: Tue, 10 Nov 2026 16:55:30 -0800 [thread overview]
Message-ID: <20261111005533.6436-13-toddfreed@meta.com> (raw)
In-Reply-To: <20261111005533.6436-1-toddfreed@meta.com>
encap on ingress is hardware offload only. In software, the packet is
dropped.
Verify it on traffic of a client behind a veth, with encap on the veth's
ingress: forwarded, the packets must not reach the remote in clear text,
and to a local address, they must not reach the local socket.
data_tc_encap_routed routed packets are dropped by encap, IPv4 and
IPv6
data_tc_encap_local so are packets to a local address
Signed-off-by: Todd Freed <toddfreed@meta.com>
---
tools/testing/selftests/drivers/net/config | 2 +
tools/testing/selftests/drivers/net/psp.py | 159 ++++++++++++++++++++-
2 files changed, 159 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/config b/tools/testing/selftests/drivers/net/config
index baf1c9d0dd13..b39de6e64263 100644
--- a/tools/testing/selftests/drivers/net/config
+++ b/tools/testing/selftests/drivers/net/config
@@ -5,6 +5,7 @@ CONFIG_DUMMY=m
CONFIG_INET_PSP=y
CONFIG_IPV6=y
CONFIG_MACSEC=m
+CONFIG_NET_ACT_GACT=m
CONFIG_NET_ACT_MIRRED=m
CONFIG_NET_ACT_PSP=m
CONFIG_NET_ACT_SKBEDIT=m
@@ -25,5 +26,6 @@ CONFIG_NET_SCH_PRIO=m
CONFIG_PPP=y
CONFIG_PPPOE=y
CONFIG_TLS=y
+CONFIG_VETH=m
CONFIG_VLAN_8021Q=m
CONFIG_XDP_SOCKETS=y
diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py
index fb7544410051..f7613fcd2fbf 100755
--- a/tools/testing/selftests/drivers/net/psp.py
+++ b/tools/testing/selftests/drivers/net/psp.py
@@ -22,7 +22,7 @@ from lib.py import ksft_variants, KsftNamedVariant
from lib.py import KsftSkipEx, KsftFailEx
from lib.py import NetDrvEpEnv, NetDrvContEnv
from lib.py import Netlink, NlError, PSPFamily, RtnlFamily
-from lib.py import NetNSEnter
+from lib.py import NetNS, NetNSEnter
from lib.py import bkg, rand_port, wait_port_listen
from lib.py import cmd, ip, tc
@@ -1242,6 +1242,160 @@ def data_tc_encap_ingress(cfg):
del_flt.exec()
+def _tc_act_stats(dev, pref, host=None):
+ """ Stats of the first action of the ingress filter @pref of @dev """
+ filters = tc(f"-s filter show dev {dev} ingress pref {pref}",
+ json=True, host=host)
+ for flt in filters:
+ for act in flt.get("options", {}).get("actions", []):
+ return act["stats"]
+ raise KsftFailEx(f"no action on the {dev} pref {pref} filter")
+
+
+def _tc_act_pkts(dev, pref, host=None):
+ """ Packets of the first action of the ingress filter @pref of @dev """
+ return _tc_act_stats(dev, pref, host)["packets"]
+
+
+def _fwd_client(cfg, ipver):
+ """
+ Set up a client in a netns behind veth psp-fwd0, and forward its
+ traffic: only from psp-fwd0, the host's own forwarding settings stay as
+ they are. Return a UDP socket of the client.
+ """
+ ns = NetNS()
+ defer(ns.__del__)
+ ip(f"link add psp-fwd0 type veth peer name psp-fwd1 netns {ns.name}")
+ defer(ip, "link del psp-fwd0")
+ if ipver == "4":
+ fwd = "/proc/sys/net/ipv4/conf/psp-fwd0/forwarding"
+ local, client, plen = "198.51.100.1", "198.51.100.2", 24
+ else:
+ fwd = "/proc/sys/net/ipv6/conf/psp-fwd0/force_forwarding"
+ local, client, plen = "2001:db8:fe::1", "2001:db8:fe::2", 64
+ if not os.path.exists(fwd):
+ raise KsftSkipEx(f"{fwd} not supported")
+ # Goes away with the device
+ with open(fwd, "w", encoding="utf-8") as fp:
+ fp.write("1")
+ # IPv6 may be disabled on new devices
+ if cmd(f"ip addr add {local}/{plen} dev psp-fwd0 nodad",
+ fail=False).ret:
+ raise KsftSkipEx(f"can't add {local} to a new device")
+ ip("link set psp-fwd0 up")
+ ip(f"-n {ns.name} addr add {client}/{plen} dev psp-fwd1 nodad")
+ ip(f"-n {ns.name} link set psp-fwd1 up")
+ ip(f"-n {ns.name} route add default via {local}")
+
+ family = socket.AF_INET if ipver == "4" else socket.AF_INET6
+ with NetNSEnter(ns.name):
+ s = socket.socket(family, socket.SOCK_DGRAM)
+ defer(s.close)
+ return s
+
+
+def _remote_filter(cfg, pref, proto, match):
+ """
+ Add a flower filter on the remote's ingress, to count what gets there.
+ In software only: drivers refresh the counters of offloaded filters
+ periodically, and these counts must be exact.
+ """
+ _tc_clsact(cfg.remote_ifname, host=cfg.remote)
+ tc(f"filter add dev {cfg.remote_ifname} ingress pref {pref} handle 1 "
+ f"protocol {proto} flower skip_hw {match}", host=cfg.remote)
+ defer(tc, f"filter del dev {cfg.remote_ifname} ingress pref {pref} "
+ f"handle 1 protocol {proto} flower", host=cfg.remote)
+
+
+def _tc_encap_ingress(proto, port, tx):
+ """ psp encap on psp-fwd0's ingress, which software drops """
+ _tc_clsact("psp-fwd0")
+ tc(f"filter add dev psp-fwd0 ingress pref 10 protocol {proto} "
+ f"flower ip_proto udp dst_port {port} "
+ f"action psp encap assoc {tx['id']}")
+
+
+@ksft_variants(_get_ip_variants())
+def data_tc_encap_routed(cfg, ipver):
+ """ Test software encap on ingress drops routed packets """
+ cfg.require_ipver(ipver)
+ _init_psp_dev(cfg)
+ _require_tc_psp(cfg)
+
+ proto = _tc_proto(ipver)
+ _, tx = _sockless_assocs(cfg)
+ s = _fwd_client(cfg, ipver)
+
+ port = rand_port(socket.SOCK_DGRAM)
+ _remote_filter(cfg, 10, proto,
+ f"ip_proto udp dst_port {port} action drop")
+
+ def remote_pkts():
+ return _tc_act_pkts(cfg.remote_ifname, 10, host=cfg.remote)
+
+ def send(n):
+ for _ in range(n):
+ s.sendto(b'0123456789', (cfg.remote_addr_v[ipver], port))
+ time.sleep(0.01)
+ time.sleep(0.2)
+
+ # Without encap the packets are forwarded to the remote, unless
+ # something else, e.g. a FORWARD policy, stops them
+ send(10)
+ sent = remote_pkts()
+ if not sent:
+ raise KsftSkipEx("forwarded packets don't reach the remote")
+
+ # Encap on ingress is hardware offload only: in software the action
+ # drops the packets. They must not reach the remote in clear text.
+ _tc_encap_ingress(proto, port, tx)
+ send(10)
+ ksft_eq(_tc_act_pkts("psp-fwd0", 10), 10)
+ ksft_eq(_tc_act_stats("psp-fwd0", 10)["drops"], 10,
+ comment="dropped by encap")
+ ksft_eq(remote_pkts(), sent)
+
+
+@ksft_variants(_get_ip_variants())
+def data_tc_encap_local(cfg, ipver):
+ """ Test software encap on ingress drops packets to a local address """
+ cfg.require_ipver(ipver)
+ _init_psp_dev(cfg)
+ _require_tc_psp(cfg)
+
+ _, tx = _sockless_assocs(cfg)
+ s = _fwd_client(cfg, ipver)
+ fam = "inet" if ipver == "4" else "inet6"
+ addrs = ip("addr show dev psp-fwd0", json=True)[0]["addr_info"]
+ local = [a["local"] for a in addrs
+ if a["family"] == fam and a["scope"] == "global"][0]
+
+ family = socket.AF_INET if ipver == "4" else socket.AF_INET6
+ with socket.socket(family, socket.SOCK_DGRAM) as srv:
+ srv.bind((local, 0))
+ srv.settimeout(0.5)
+ port = srv.getsockname()[1]
+
+ # Without encap the packets are delivered, unless something
+ # else, e.g. an INPUT policy, stops them
+ s.sendto(b'clear', (local, port))
+ try:
+ got = srv.recv(64)
+ except socket.timeout as e:
+ raise KsftSkipEx("the client's packets aren't delivered") from e
+ ksft_eq(got, b'clear')
+
+ # Encap on ingress is hardware offload only: in software the
+ # action drops the packets, rather than let them be received
+ _tc_encap_ingress(_tc_proto(ipver), port, tx)
+ s.sendto(b'encap', (local, port))
+ with ksft_raises(socket.timeout):
+ srv.recv(64)
+ ksft_eq(_tc_act_pkts("psp-fwd0", 10), 1)
+ ksft_eq(_tc_act_stats("psp-fwd0", 10)["drops"], 1,
+ comment="dropped by encap")
+
+
def removal_device_tc(cfg):
""" Test removing a PSD with tc actions holding its assocs """
cfg.require_nsim()
@@ -1760,7 +1914,8 @@ def main() -> None:
cfg.comm_port),
timeout=1)
- cases = [data_basic_send, data_mss_adjust, data_tc_basic_send]
+ cases = [data_basic_send, data_mss_adjust, data_tc_basic_send,
+ data_tc_encap_routed, data_tc_encap_local]
if has_cont:
cases += [
--
2.53.0-Meta
next prev parent reply other threads:[~2026-11-11 0:56 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 0:55 [PATCH net-next v1 00/15] psp: introduce socket-less associations Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 01/15] psp: get netns from net_device instead of sock Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 02/15] psp: take the psp nexthdr from the packet on encap Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 03/15] psp: declare psp_assoc_set_tx() in psp.h Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 04/15] psp: add support for socket-less psp associations Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 05/15] net: add METADATA_PSP dst to carry a psp association on an skb Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 06/15] net/sched: act_mirred: don't send decrypted skbs from egress to ingress Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 07/15] bpf: don't redirect " Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 08/15] psp: only give time-wait sockets of psp connections a validator Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 09/15] net/sched: add act_psp for psp transport mode Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 10/15] net/sched: flower: add psp_spi, psp_ver, and psp_dev matches Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 11/15] selftests: drv-net: psp: test socket-less associations and the tc psp action Todd Freed
2026-11-11 0:55 ` Todd Freed [this message]
2026-11-11 0:55 ` [PATCH net-next v1 13/15] selftests: tc-testing: run dependsOn probes outside the test namespace Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 14/15] selftests: tc-testing: add tests for the psp action Todd Freed
2026-11-11 0:55 ` [PATCH net-next v1 15/15] Documentation: networking: psp: document socket-less associations Todd Freed
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=20261111005533.6436-13-toddfreed@meta.com \
--to=toddfreed@meta.com \
--cc=andrew+netdev@lunn.ch \
--cc=bjorn@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel.zahka@gmail.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=donald.hunter@gmail.com \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=jhs@mojatatu.com \
--cc=jiri@resnulli.us \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=saeedm@nvidia.com \
--cc=tariqt@nvidia.com \
--cc=weiwan@google.com \
--cc=willemdebruijn.kernel@gmail.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
all inboxes | Powered by JetHome®