mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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


  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®