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 10/15] net/sched: flower: add psp_spi, psp_ver, and psp_dev matches
Date: Tue, 10 Nov 2026 16:55:28 -0800	[thread overview]
Message-ID: <20261111005533.6436-11-toddfreed@meta.com> (raw)
In-Reply-To: <20261111005533.6436-1-toddfreed@meta.com>

Add a flow dissector key filled from the PSP Rx state (SKB_EXT_PSP) the
device attached to a decrypted packet, and corresponding flower matches.
SPI the packet was decrypted with (psp_spi, with a mask), PSP version
(psp_ver), and the ID of the PSP device which decrypted it (psp_dev).

For example, to take the packets of one Rx association, (created with
rx-spi-alloc), and remove their PSP state so that they can be forwarded,

  tc filter add dev eth0 ingress protocol ipv6 flower
      psp_spi 0x80000001 psp_ver 0 psp_dev 1
      action psp decap

Together these matches tie a rule to one association, in a form which
hw can match on (offload comes in a follow-up series). The SPI is only
unique on its PSP device, and an association has one PSP version. This
matches the per-packet check that psp sockets have against its
association, with one exception - the generation of the device key is
not checked.

this means that a rule matching packets that correspond to an rx
association which is stale (two rotations have passed), can still match.

It is therefore important that a rule which matches a SPI should be
replaced before the device key has had two rotations. follow up work
will bring enforcement of this based on key rotation events.

Note that this only ever matches packets which were decrypted, even if
the mask is 0. So "psp_spi 0/0" matches any decrypted PSP packet.

Signed-off-by: Todd Freed <toddfreed@meta.com>
---
 Documentation/netlink/specs/tc.yaml | 14 +++++++
 include/linux/skbuff.h              |  4 ++
 include/net/flow_dissector.h        | 18 ++++++++
 include/uapi/linux/pkt_cls.h        |  5 +++
 net/core/flow_dissector.c           | 27 ++++++++++++
 net/sched/cls_flower.c              | 64 +++++++++++++++++++++++++++++
 6 files changed, 132 insertions(+)

diff --git a/Documentation/netlink/specs/tc.yaml b/Documentation/netlink/specs/tc.yaml
index b6ccc645b0e3..044938316ffd 100644
--- a/Documentation/netlink/specs/tc.yaml
+++ b/Documentation/netlink/specs/tc.yaml
@@ -2908,6 +2908,20 @@ attribute-sets:
         byte-order: big-endian
         enum: flower-key-ctrl-flags
         enum-as-flags: true
+      -
+        name: key-psp-spi
+        type: u32
+        byte-order: big-endian
+      -
+        name: key-psp-spi-mask
+        type: u32
+        byte-order: big-endian
+      -
+        name: key-psp-version
+        type: u8
+      -
+        name: key-psp-dev
+        type: u32
   -
     name: flower-key-enc-opts-attrs
     name-prefix: tca-flower-key-enc-opts-
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 73365c5de6f9..e65de3f5c136 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1660,6 +1660,10 @@ void skb_flow_dissect_hash(const struct sk_buff *skb,
 			   struct flow_dissector *flow_dissector,
 			   void *target_container);
 
+void skb_flow_dissect_psp(const struct sk_buff *skb,
+			  struct flow_dissector *flow_dissector,
+			  void *target_container);
+
 static inline __u32 skb_get_hash_net(const struct net *net, struct sk_buff *skb)
 {
 	if (!skb->l4_hash && !skb->sw_hash)
diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
index ced79dc8e856..151ae03d5ad5 100644
--- a/include/net/flow_dissector.h
+++ b/include/net/flow_dissector.h
@@ -339,6 +339,23 @@ struct flow_dissector_key_cfm {
 	u8	opcode;
 };
 
+/**
+ * struct flow_dissector_key_psp - PSP Rx state of a decrypted packet
+ * @spi: SPI of the PSP association the packet was decrypted with
+ * @dev_id: ID of the PSP device which decrypted the packet
+ * @version: PSP version (enum psp_version) the packet was decrypted with
+ * @present: packet was decrypted by a PSP device
+ *
+ * Taken from the PSP Rx state the device attached to the skb, not from the
+ * packet, which no longer carries the PSP header.
+ */
+struct flow_dissector_key_psp {
+	__be32	spi;
+	u16	dev_id;
+	u8	version;
+	u8	present;
+};
+
 #define FLOW_DIS_CFM_MDL_MASK GENMASK(7, 5)
 #define FLOW_DIS_CFM_MDL_MAX 7
 
@@ -376,6 +393,7 @@ enum flow_dissector_key_id {
 	FLOW_DISSECTOR_KEY_L2TPV3, /* struct flow_dissector_key_l2tpv3 */
 	FLOW_DISSECTOR_KEY_CFM, /* struct flow_dissector_key_cfm */
 	FLOW_DISSECTOR_KEY_IPSEC, /* struct flow_dissector_key_ipsec */
+	FLOW_DISSECTOR_KEY_PSP, /* struct flow_dissector_key_psp */
 
 	FLOW_DISSECTOR_KEY_MAX,
 };
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 14cff8f5da74..0cfa7425404b 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -561,6 +561,11 @@ enum {
 	TCA_FLOWER_KEY_ENC_FLAGS,	/* be32 */
 	TCA_FLOWER_KEY_ENC_FLAGS_MASK,	/* be32 */
 
+	TCA_FLOWER_KEY_PSP_SPI,		/* be32 */
+	TCA_FLOWER_KEY_PSP_SPI_MASK,	/* be32 */
+	TCA_FLOWER_KEY_PSP_VERSION,	/* u8, enum psp_version */
+	TCA_FLOWER_KEY_PSP_DEV,		/* u32, PSP device ID */
+
 	__TCA_FLOWER_MAX,
 };
 
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 1be6c739e3c7..95d3fa3b1568 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -28,6 +28,7 @@
 #include <linux/ptp_classify.h>
 #include <net/flow_dissector.h>
 #include <net/pkt_cls.h>
+#include <net/psp/types.h>
 #include <scsi/fc/fc_fcoe.h>
 #include <uapi/linux/batadv_packet.h>
 #include <linux/bpf.h>
@@ -511,6 +512,32 @@ void skb_flow_dissect_hash(const struct sk_buff *skb,
 }
 EXPORT_SYMBOL(skb_flow_dissect_hash);
 
+void skb_flow_dissect_psp(const struct sk_buff *skb,
+			  struct flow_dissector *flow_dissector,
+			  void *target_container)
+{
+#if IS_ENABLED(CONFIG_INET_PSP)
+	struct flow_dissector_key_psp *key;
+	struct psp_skb_ext *pse;
+
+	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PSP))
+		return;
+
+	pse = skb_ext_find(skb, SKB_EXT_PSP);
+	if (!pse)
+		return;
+
+	key = skb_flow_dissector_target(flow_dissector,
+					FLOW_DISSECTOR_KEY_PSP,
+					target_container);
+	key->spi = pse->spi;
+	key->dev_id = pse->dev_id;
+	key->version = pse->version;
+	key->present = 1;
+#endif
+}
+EXPORT_SYMBOL(skb_flow_dissect_psp);
+
 static enum flow_dissect_ret
 __skb_flow_dissect_mpls(const struct sk_buff *skb,
 			struct flow_dissector *flow_dissector,
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 23eba4a00a94..f983deab1a6d 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -81,6 +81,7 @@ struct fl_flow_key {
 	struct flow_dissector_key_l2tpv3 l2tpv3;
 	struct flow_dissector_key_ipsec ipsec;
 	struct flow_dissector_key_cfm cfm;
+	struct flow_dissector_key_psp psp;
 } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
 
 struct fl_flow_mask_range {
@@ -343,6 +344,7 @@ TC_INDIRECT_SCOPE int fl_classify(struct sk_buff *skb,
 				    ARRAY_SIZE(fl_ct_info_to_flower_map),
 				    post_ct, zone);
 		skb_flow_dissect_hash(skb, &mask->dissector, &skb_key);
+		skb_flow_dissect_psp(skb, &mask->dissector, &skb_key);
 		skb_flow_dissect(skb, &mask->dissector, &skb_key,
 				 FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP);
 
@@ -633,6 +635,11 @@ static void *fl_get(struct tcf_proto *tp, u32 handle)
 	return __fl_get(head, handle);
 }
 
+/* SKB_EXT_PSP holds the PSP device ID in 16 bits */
+static const struct netlink_range_validation fl_psp_dev_range = {
+	.max = U16_MAX,
+};
+
 static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
 	[TCA_FLOWER_UNSPEC]		= { .strict_start_type =
 						TCA_FLOWER_L2_MISS },
@@ -745,6 +752,12 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
 	[TCA_FLOWER_KEY_SPI]		= { .type = NLA_U32 },
 	[TCA_FLOWER_KEY_SPI_MASK]	= { .type = NLA_U32 },
 	[TCA_FLOWER_L2_MISS]		= NLA_POLICY_MAX(NLA_U8, 1),
+	[TCA_FLOWER_KEY_PSP_SPI]	= { .type = NLA_BE32 },
+	[TCA_FLOWER_KEY_PSP_SPI_MASK]	= { .type = NLA_BE32 },
+	/* the version field of the PSP header has 4 bits */
+	[TCA_FLOWER_KEY_PSP_VERSION]	= NLA_POLICY_MAX(NLA_U8, 15),
+	[TCA_FLOWER_KEY_PSP_DEV]	= NLA_POLICY_FULL_RANGE(NLA_U32,
+							&fl_psp_dev_range),
 	[TCA_FLOWER_KEY_CFM]		= { .type = NLA_NESTED },
 	[TCA_FLOWER_KEY_ENC_FLAGS]	= NLA_POLICY_MASK(NLA_BE32,
 							  TCA_FLOWER_KEY_ENC_FLAGS_POLICY_MASK),
@@ -2077,6 +2090,33 @@ static int fl_set_key(struct net *net, struct nlattr *tca_opts,
 			return ret;
 	}
 
+	if (tb[TCA_FLOWER_KEY_PSP_SPI_MASK] && !tb[TCA_FLOWER_KEY_PSP_SPI]) {
+		NL_SET_ERR_ATTR_MISS(extack, tca_opts, TCA_FLOWER_KEY_PSP_SPI);
+		return -EINVAL;
+	}
+	if (tb[TCA_FLOWER_KEY_PSP_SPI] || tb[TCA_FLOWER_KEY_PSP_VERSION] ||
+	    tb[TCA_FLOWER_KEY_PSP_DEV]) {
+		if (!IS_ENABLED(CONFIG_INET_PSP)) {
+			NL_SET_ERR_MSG(extack, "PSP isn't enabled");
+			return -EOPNOTSUPP;
+		}
+		fl_set_key_val(tb, &key->psp.spi, TCA_FLOWER_KEY_PSP_SPI,
+			       &mask->psp.spi, TCA_FLOWER_KEY_PSP_SPI_MASK,
+			       sizeof(key->psp.spi));
+		if (tb[TCA_FLOWER_KEY_PSP_VERSION]) {
+			key->psp.version =
+				nla_get_u8(tb[TCA_FLOWER_KEY_PSP_VERSION]);
+			mask->psp.version = 0xff;
+		}
+		if (tb[TCA_FLOWER_KEY_PSP_DEV]) {
+			key->psp.dev_id = nla_get_u32(tb[TCA_FLOWER_KEY_PSP_DEV]);
+			mask->psp.dev_id = 0xffff;
+		}
+		/* Only match packets which were actually decrypted */
+		key->psp.present = 1;
+		mask->psp.present = 0xff;
+	}
+
 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
@@ -2263,6 +2303,8 @@ static void fl_init_dissector(struct flow_dissector *dissector,
 			     FLOW_DISSECTOR_KEY_IPSEC, ipsec);
 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
 			     FLOW_DISSECTOR_KEY_CFM, cfm);
+	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
+			     FLOW_DISSECTOR_KEY_PSP, psp);
 
 	skb_flow_dissector_init(dissector, keys, cnt);
 }
@@ -3651,6 +3693,28 @@ static int fl_dump_key(struct sk_buff *skb, struct net *net,
 			    sizeof(key->ipsec.spi)))
 		goto nla_put_failure;
 
+	if (mask->psp.present &&
+	    fl_dump_key_val(skb, &key->psp.spi, TCA_FLOWER_KEY_PSP_SPI,
+			    &mask->psp.spi, TCA_FLOWER_KEY_PSP_SPI_MASK,
+			    sizeof(key->psp.spi)))
+		goto nla_put_failure;
+	/* With a 0 SPI mask and no version or device, the SPI still carries
+	 * the match on a decrypted packet: dump it with its mask
+	 */
+	if (mask->psp.present && !mask->psp.spi && !mask->psp.version &&
+	    !mask->psp.dev_id &&
+	    (nla_put(skb, TCA_FLOWER_KEY_PSP_SPI, sizeof(key->psp.spi),
+		     &key->psp.spi) ||
+	     nla_put(skb, TCA_FLOWER_KEY_PSP_SPI_MASK, sizeof(mask->psp.spi),
+		     &mask->psp.spi)))
+		goto nla_put_failure;
+	if (mask->psp.version &&
+	    nla_put_u8(skb, TCA_FLOWER_KEY_PSP_VERSION, key->psp.version))
+		goto nla_put_failure;
+	if (mask->psp.dev_id &&
+	    nla_put_u32(skb, TCA_FLOWER_KEY_PSP_DEV, key->psp.dev_id))
+		goto nla_put_failure;
+
 	if ((key->basic.ip_proto == IPPROTO_TCP ||
 	     key->basic.ip_proto == IPPROTO_UDP ||
 	     key->basic.ip_proto == IPPROTO_SCTP) &&
-- 
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 ` Todd Freed [this message]
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 ` [PATCH net-next v1 12/15] selftests: drv-net: psp: test that software encap on ingress drops Todd Freed
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-11-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®