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 09/15] net/sched: add act_psp for psp transport mode
Date: Tue, 10 Nov 2026 16:55:27 -0800 [thread overview]
Message-ID: <20261111005533.6436-10-toddfreed@meta.com> (raw)
In-Reply-To: <20261111005533.6436-1-toddfreed@meta.com>
adds tc action act_psp for psp transport mode encapsulation and
encryption.
encap attaches a psp tx association to the skb as a METADATA_PSP dst.
The packet must then be transmitted on the association's PSP device's
main netdev, which encrypts it: encap on that netdev's egress, or a
redirect there from another netdev's egress. Any other device drops it.
encap on ingress is hardware offload only, like tunnel mode: in
software, the action drops the packet. an ingress-encapped packet would
go through the stack with only its METADATA_PSP dst to keep it from
leaving in clear text, and many paths replace the dst: routing,
netfilter, bpf redirects, tc actions on the way out.
on egress, encap sets skb->decrypted, so that sk_validate_xmit_skb()
drops the packet if it loses the METADATA_PSP dst on the way. mirred
and bpf don't send such a packet back to ingress (previous patches).
Some kinds of packets are not supported and will be dropped,
- ipv4 fragments. encap inserts udp+psp between the l3 and l4 headers,
so transport mode can't carry fragments. tunnel mode psp, which a
later series adds, does support them.
- ipv6 packets with extension headers, including fragments. some
extension headers could be supported in the future.
- packets already encapsulated for a tunnel (skb->encapsulation). some
tunnel types could be supported in the future.
- packets which are too large. on transmit, packets which won't fit the
device's mtu once encapsulated are dropped (see the METADATA_PSP
patch). the traffic's mtu needs to leave room for the psp encap.
- packets with another encryption offload: already marked decrypted,
or of a psp or ktls offload socket, for which sk_validate_xmit_skb()
would apply the socket's validator instead of checking the
association. a socket can gain an offload while its packet is queued,
so sk_validate_xmit_skb() also drops a packet with a METADATA_PSP dst
whose socket has a validator.
decap removes the PSP Rx state of a packet the device decrypted. to
match packets of only one association, a rule should match the psp
header fields corresponding to the association, e.g. psp_spi / psp_ver /
psp_dev. those flower matches are added in a subsequent patch.
Signed-off-by: Todd Freed <toddfreed@meta.com>
---
MAINTAINERS | 3 +
include/net/tc_act/tc_psp.h | 23 ++
include/uapi/linux/pkt_cls.h | 1 +
include/uapi/linux/tc_act/tc_psp.h | 28 ++
net/core/dev.c | 13 +-
net/sched/Kconfig | 13 +
net/sched/Makefile | 1 +
net/sched/act_psp.c | 439 +++++++++++++++++++++++++++++
8 files changed, 519 insertions(+), 2 deletions(-)
create mode 100644 include/net/tc_act/tc_psp.h
create mode 100644 include/uapi/linux/tc_act/tc_psp.h
create mode 100644 net/sched/act_psp.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 76fb13c8730b..a8e45efd8baf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22533,8 +22533,11 @@ F: Documentation/netlink/specs/psp.yaml
F: Documentation/networking/psp.rst
F: include/net/psp/
F: include/net/psp.h
+F: include/net/tc_act/tc_psp.h
F: include/uapi/linux/psp.h
+F: include/uapi/linux/tc_act/tc_psp.h
F: net/psp/
+F: net/sched/act_psp.c
K: struct\ psp(_assoc|_dev|hdr)\b
PSTORE FILESYSTEM
diff --git a/include/net/tc_act/tc_psp.h b/include/net/tc_act/tc_psp.h
new file mode 100644
index 000000000000..8640d7685475
--- /dev/null
+++ b/include/net/tc_act/tc_psp.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NET_TC_PSP_H
+#define __NET_TC_PSP_H
+
+#include <net/act_api.h>
+#include <net/dst_metadata.h>
+#include <linux/tc_act/tc_psp.h>
+
+struct tcf_psp_params {
+ struct rcu_head rcu;
+ int action;
+ int psp_action;
+ struct metadata_dst *md;
+};
+
+struct tcf_psp {
+ struct tc_action common;
+ struct tcf_psp_params __rcu *params;
+};
+
+#define to_psp(a) ((struct tcf_psp *)a)
+
+#endif /* __NET_TC_PSP_H */
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index 28d94b11d1aa..14cff8f5da74 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -139,6 +139,7 @@ enum tca_id {
TCA_ID_MPLS,
TCA_ID_CT,
TCA_ID_GATE,
+ TCA_ID_PSP,
/* other actions go here */
__TCA_ID_MAX = 255
};
diff --git a/include/uapi/linux/tc_act/tc_psp.h b/include/uapi/linux/tc_act/tc_psp.h
new file mode 100644
index 000000000000..e58ebcae77be
--- /dev/null
+++ b/include/uapi/linux/tc_act/tc_psp.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_TC_PSP_H
+#define __LINUX_TC_PSP_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_PSP_ACT_ENCAP 1 /* attach a PSP association */
+#define TCA_PSP_ACT_DECAP 2 /* drop PSP Rx state */
+
+struct tc_psp {
+ tc_gen;
+};
+
+enum {
+ TCA_PSP_UNSPEC,
+ TCA_PSP_TM,
+ TCA_PSP_PARMS,
+ TCA_PSP_PAD,
+ TCA_PSP_ACTION, /* u32, TCA_PSP_ACT_* */
+ TCA_PSP_ASSOC_ID, /* u32, encap only: Tx association ID from
+ * the PSP netlink family (assoc-add)
+ */
+ __TCA_PSP_MAX,
+};
+
+#define TCA_PSP_MAX (__TCA_PSP_MAX - 1)
+
+#endif
diff --git a/net/core/dev.c b/net/core/dev.c
index 2cca5f0d302f..353c0409b3c0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4154,13 +4154,22 @@ static struct sk_buff *sk_validate_xmit_skb(struct sk_buff *skb,
sk_validate = NULL;
if (sk) {
if (sk_fullsock(sk))
- sk_validate = sk->sk_validate_xmit_skb;
+ sk_validate = READ_ONCE(sk->sk_validate_xmit_skb);
else if (sk_is_inet(sk) && sk->sk_state == TCP_TIME_WAIT)
sk_validate = inet_twsk(sk)->tw_validate_xmit_skb;
}
if (sk_validate) {
- skb = sk_validate(sk, dev, skb);
+ /* act_psp doesn't give an association to the packets of a
+ * socket with its own offload, but the socket can gain one
+ * while such a packet is queued
+ */
+ if (unlikely(skb_psp_md(skb))) {
+ kfree_skb_reason(skb, SKB_DROP_REASON_PSP_OUTPUT);
+ skb = NULL;
+ } else {
+ skb = sk_validate(sk, dev, skb);
+ }
} else if (unlikely(skb_psp_md(skb))) {
int psp = psp_xmit_md(skb, dev);
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 6ddff028b81a..35f9d76c4cae 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -939,6 +939,19 @@ config NET_ACT_GATE
To compile this code as a module, choose M here: the
module will be called act_gate.
+config NET_ACT_PSP
+ tristate "PSP encryption tc action"
+ depends on NET_CLS_ACT && INET_PSP
+ help
+ Say Y here to allow PSP associations, created through the PSP
+ netlink family, to be attached to packets. PSP capable devices can
+ then encrypt them on transmit. Enables transparent psp tunnels for
+ forwarded traffic.
+
+ If unsure, say N.
+ To compile this code as a module, choose M here: the
+ module will be called act_psp.
+
config NET_IFE_SKBMARK
tristate "Support to encoding decoding skb mark on IFE action"
depends on NET_ACT_IFE
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 5078ea84e6ad..9fe8cc0abfdf 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_NET_IFE_SKBTCINDEX) += act_meta_skbtcindex.o
obj-$(CONFIG_NET_ACT_TUNNEL_KEY)+= act_tunnel_key.o
obj-$(CONFIG_NET_ACT_CT) += act_ct.o
obj-$(CONFIG_NET_ACT_GATE) += act_gate.o
+obj-$(CONFIG_NET_ACT_PSP) += act_psp.o
obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o
obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o
obj-$(CONFIG_NET_SCH_HFSC) += sch_hfsc.o
diff --git a/net/sched/act_psp.c b/net/sched/act_psp.c
new file mode 100644
index 000000000000..4ff54203c9f5
--- /dev/null
+++ b/net/sched/act_psp.c
@@ -0,0 +1,439 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * tc action that attaches a PSP association to packets.
+ *
+ * encap: attach a tx association referenced by its ID, as a METADATA_PSP dst.
+ * The PSP device's netdev encrypts the packet on transmit. In
+ * software, egress only: like tunnel mode, encap on ingress is
+ * hardware offload only.
+ * decap: drop the PSP Rx state (SKB_EXT_PSP) of a decrypted packet. It
+ * takes no association. a rule which should only take the packets
+ * of one association matches its properties against psp packet header
+ * fields (flower psp_spi / psp_ver / psp_dev).
+ */
+
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/dst.h>
+#include <net/inet_timewait_sock.h>
+#include <net/ip.h>
+#include <net/netlink.h>
+#include <net/pkt_cls.h>
+#include <net/pkt_sched.h>
+#include <net/psp/functions.h>
+#include <net/tc_act/tc_psp.h>
+
+static struct tc_action_ops act_psp_ops;
+
+/* The device inserts UDP + PSP between the IP header and the transport
+ * header, so the transport header must be right by the time the packet
+ * gets there. On a forwarded packet it may not be. Transport mode doesn't
+ * support IP fragments or IPv6 extension headers.
+ */
+static bool tcf_psp_set_transport_header(struct sk_buff *skb)
+{
+ unsigned int off = skb_network_offset(skb);
+ const struct iphdr *iph;
+ unsigned int hlen, len;
+
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ if (!pskb_may_pull(skb, off + sizeof(*iph)))
+ return false;
+ iph = ip_hdr(skb);
+ if (iph->version != 4 || iph->ihl < 5 || ip_is_fragment(iph))
+ return false;
+ hlen = iph->ihl * 4;
+ len = ntohs(iph->tot_len);
+ if (!pskb_may_pull(skb, off + hlen))
+ return false;
+ break;
+ case htons(ETH_P_IPV6):
+ if (!pskb_may_pull(skb, off + sizeof(struct ipv6hdr)))
+ return false;
+ if (ipv6_hdr(skb)->version != 6 ||
+ ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr))
+ return false;
+ hlen = sizeof(struct ipv6hdr);
+ len = hlen + ntohs(ipv6_hdr(skb)->payload_len);
+ break;
+ default:
+ return false;
+ }
+
+ /* The device takes the length of the payload from the packet: it must
+ * hold the IP length, and L2 padding, e.g. of a minimum size frame,
+ * must not be encrypted as payload. A GSO skb's header doesn't always
+ * carry its length (BIG TCP).
+ */
+ if (!skb_is_gso(skb)) {
+ if (len < hlen || skb->len - off < len)
+ return false;
+ if (pskb_trim_rcsum(skb, off + len))
+ return false;
+ }
+
+ skb_set_transport_header(skb, off + hlen);
+ return true;
+}
+
+/* The socket of the packet has its own encryption offload, kTLS or PSP:
+ * sk_validate_xmit_skb() then applies the socket's validator instead of
+ * checking the association.
+ */
+static bool tcf_psp_sk_offload(const struct sk_buff *skb)
+{
+#ifdef CONFIG_SOCK_VALIDATE_XMIT
+ struct sock *sk = skb->sk;
+
+ if (!sk)
+ return false;
+ if (sk_fullsock(sk))
+ return !!READ_ONCE(sk->sk_validate_xmit_skb);
+ return sk_is_inet(sk) && sk->sk_state == TCP_TIME_WAIT &&
+ inet_twsk(sk)->tw_validate_xmit_skb;
+#else
+ return false;
+#endif
+}
+
+static int tcf_psp_drop(struct tcf_psp *p, struct sk_buff *skb,
+ enum skb_drop_reason reason)
+{
+ tcf_action_inc_drop_qstats(&p->common);
+ tcf_set_drop_reason(skb, reason);
+ return TC_ACT_SHOT;
+}
+
+static int tcf_psp_act(struct sk_buff *skb, const struct tc_action *a,
+ struct tcf_result *res)
+{
+ struct tcf_psp *p = to_psp(a);
+ struct tcf_psp_params *params;
+
+ params = rcu_dereference_bh(p->params);
+
+ tcf_lastuse_update(&p->tcf_tm);
+ tcf_action_update_bstats(&p->common, skb);
+
+ switch (params->psp_action) {
+ case TCA_PSP_ACT_ENCAP:
+ /* Encap on ingress is hardware offload only, like tunnel
+ * mode: the packet would go through the stack with nothing
+ * but its dst, which routing, netfilter or a redirect may
+ * replace, to keep it from leaving in clear text
+ */
+ if (unlikely(skb_at_tc_ingress(skb)))
+ return tcf_psp_drop(p, skb, SKB_DROP_REASON_PSP_OUTPUT);
+ /* PSP on a tunnel isn't supported: the encap would overwrite
+ * the inner headers which the device's tunnel offloads use
+ */
+ if (unlikely(skb->encapsulation))
+ return tcf_psp_drop(p, skb, SKB_DROP_REASON_PSP_OUTPUT);
+ /* Don't mix the association with another encryption
+ * offload: the packet is already marked decrypted, or its
+ * socket has an offload of its own
+ */
+ if (unlikely(skb_is_decrypted(skb) || tcf_psp_sk_offload(skb)))
+ return tcf_psp_drop(p, skb, SKB_DROP_REASON_PSP_OUTPUT);
+ if (unlikely(!tcf_psp_set_transport_header(skb)))
+ return tcf_psp_drop(p, skb, SKB_DROP_REASON_PSP_OUTPUT);
+ skb_dst_drop(skb);
+ skb_dst_set(skb, dst_clone(¶ms->md->dst));
+ /* Must be encrypted: sk_validate_xmit_skb() drops it unless
+ * it still carries the association when it is transmitted
+ */
+ skb->decrypted = 1;
+ break;
+ case TCA_PSP_ACT_DECAP:
+ /* Only a packet the device decrypted: on transmit,
+ * skb->decrypted means "device, please encrypt", which decap
+ * must not undo.
+ */
+ if (!skb_ext_find(skb, SKB_EXT_PSP))
+ break;
+ skb_ext_del(skb, SKB_EXT_PSP);
+ skb->decrypted = 0;
+ break;
+ }
+
+ return params->action;
+}
+
+static const struct nla_policy psp_policy[TCA_PSP_MAX + 1] = {
+ [TCA_PSP_PARMS] = NLA_POLICY_EXACT_LEN(sizeof(struct tc_psp)),
+ [TCA_PSP_ACTION] = NLA_POLICY_RANGE(NLA_U32, TCA_PSP_ACT_ENCAP,
+ TCA_PSP_ACT_DECAP),
+ [TCA_PSP_ASSOC_ID] = NLA_POLICY_MIN(NLA_U32, 1),
+};
+
+static void tcf_psp_release_params_rcu(struct rcu_head *head)
+{
+ struct tcf_psp_params *params = container_of(head, typeof(*params),
+ rcu);
+
+ if (params->md)
+ dst_release(¶ms->md->dst);
+ kfree(params);
+}
+
+static void tcf_psp_release_params(struct tcf_psp_params *params)
+{
+ if (params)
+ call_rcu(¶ms->rcu, tcf_psp_release_params_rcu);
+}
+
+static struct metadata_dst *
+tcf_psp_md_create(struct net *net, struct nlattr *id_attr,
+ struct netlink_ext_ack *extack)
+{
+ struct metadata_dst *md;
+ struct psp_assoc *pas;
+
+ pas = psp_assoc_get_by_id(net, nla_get_u32(id_attr));
+ if (!pas) {
+ NL_SET_ERR_MSG_ATTR(extack, id_attr,
+ "PSP association not found");
+ return ERR_PTR(-ENOENT);
+ }
+ if (!psp_assoc_is_tx(pas)) {
+ NL_SET_ERR_MSG_ATTR(extack, id_attr,
+ "encap needs a Tx association (assoc-add)");
+ psp_assoc_put(pas);
+ return ERR_PTR(-EINVAL);
+ }
+
+ md = metadata_dst_alloc(0, METADATA_PSP, GFP_KERNEL);
+ if (!md) {
+ psp_assoc_put(pas);
+ return ERR_PTR(-ENOMEM);
+ }
+ /* The dst now owns the reference on the association */
+ md->u.psp_info.pas = pas;
+
+ return md;
+}
+
+static int tcf_psp_init(struct net *net, struct nlattr *nla,
+ struct nlattr *est, struct tc_action **a,
+ struct tcf_proto *tp, u32 flags,
+ struct netlink_ext_ack *extack)
+{
+ struct tc_action_net *tn = net_generic(net, act_psp_ops.net_id);
+ bool bind = flags & TCA_ACT_FLAGS_BIND;
+ struct nlattr *tb[TCA_PSP_MAX + 1];
+ struct tcf_psp_params *params_new;
+ struct metadata_dst *md = NULL;
+ struct tcf_chain *goto_ch = NULL;
+ struct tc_psp *parm;
+ bool exists = false;
+ int ret = 0, err;
+ struct tcf_psp *p;
+ u32 psp_action;
+ u32 index;
+
+ if (!nla) {
+ NL_SET_ERR_MSG(extack, "PSP action requires attributes");
+ return -EINVAL;
+ }
+
+ err = nla_parse_nested(tb, TCA_PSP_MAX, nla, psp_policy, extack);
+ if (err < 0)
+ return err;
+
+ if (!tb[TCA_PSP_PARMS]) {
+ NL_SET_ERR_MSG(extack, "Missing PSP action parameters");
+ return -EINVAL;
+ }
+
+ parm = nla_data(tb[TCA_PSP_PARMS]);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
+ if (err < 0)
+ return err;
+ exists = err;
+ if (exists && bind)
+ return ACT_P_BOUND;
+
+ if (NL_REQ_ATTR_CHECK(extack, nla, tb, TCA_PSP_ACTION)) {
+ NL_SET_ERR_MSG(extack, "Missing PSP action, encap or decap");
+ ret = -EINVAL;
+ goto err_out;
+ }
+ psp_action = nla_get_u32(tb[TCA_PSP_ACTION]);
+
+ switch (psp_action) {
+ case TCA_PSP_ACT_ENCAP:
+ if (NL_REQ_ATTR_CHECK(extack, nla, tb, TCA_PSP_ASSOC_ID)) {
+ NL_SET_ERR_MSG(extack, "Missing PSP association ID");
+ ret = -EINVAL;
+ goto err_out;
+ }
+ md = tcf_psp_md_create(net, tb[TCA_PSP_ASSOC_ID], extack);
+ if (IS_ERR(md)) {
+ ret = PTR_ERR(md);
+ md = NULL;
+ goto err_out;
+ }
+ break;
+ case TCA_PSP_ACT_DECAP:
+ if (tb[TCA_PSP_ASSOC_ID]) {
+ NL_SET_ERR_MSG_ATTR(extack, tb[TCA_PSP_ASSOC_ID],
+ "decap takes no PSP association");
+ ret = -EINVAL;
+ goto err_out;
+ }
+ break;
+ }
+
+ if (!exists) {
+ ret = tcf_idr_create_from_flags(tn, index, est, a,
+ &act_psp_ops, bind, flags);
+ if (ret)
+ goto release_md;
+
+ ret = ACT_P_CREATED;
+ } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) {
+ NL_SET_ERR_MSG(extack, "PSP action already exists");
+ ret = -EEXIST;
+ goto release_md;
+ }
+
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
+ if (err < 0) {
+ ret = err;
+ exists = true;
+ goto release_md;
+ }
+ p = to_psp(*a);
+
+ params_new = kzalloc_obj(*params_new);
+ if (!params_new) {
+ ret = -ENOMEM;
+ exists = true;
+ goto put_chain;
+ }
+ params_new->action = parm->action;
+ params_new->psp_action = psp_action;
+ params_new->md = md;
+
+ spin_lock_bh(&p->tcf_lock);
+ goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
+ params_new = rcu_replace_pointer(p->params, params_new,
+ lockdep_is_held(&p->tcf_lock));
+ spin_unlock_bh(&p->tcf_lock);
+
+ tcf_psp_release_params(params_new);
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+
+ return ret;
+
+put_chain:
+ if (goto_ch)
+ tcf_chain_put_by_act(goto_ch);
+release_md:
+ if (md)
+ dst_release(&md->dst);
+err_out:
+ if (exists)
+ tcf_idr_release(*a, bind);
+ else
+ tcf_idr_cleanup(tn, index);
+ return ret;
+}
+
+static void tcf_psp_cleanup(struct tc_action *a)
+{
+ struct tcf_psp *p = to_psp(a);
+
+ tcf_psp_release_params(rcu_dereference_protected(p->params, 1));
+}
+
+static int tcf_psp_dump(struct sk_buff *skb, struct tc_action *a,
+ int bind, int ref)
+{
+ unsigned char *b = skb_tail_pointer(skb);
+ struct tcf_psp *p = to_psp(a);
+ struct tcf_psp_params *params;
+ struct tc_psp opt = {
+ .index = p->tcf_index,
+ .refcnt = refcount_read(&p->tcf_refcnt) - ref,
+ .bindcnt = atomic_read(&p->tcf_bindcnt) - bind,
+ };
+ struct tcf_t t;
+
+ rcu_read_lock();
+ params = rcu_dereference(p->params);
+ opt.action = params->action;
+
+ if (nla_put(skb, TCA_PSP_PARMS, sizeof(opt), &opt) ||
+ nla_put_u32(skb, TCA_PSP_ACTION, params->psp_action))
+ goto nla_put_failure;
+
+ if (params->md &&
+ nla_put_u32(skb, TCA_PSP_ASSOC_ID, params->md->u.psp_info.pas->id))
+ goto nla_put_failure;
+
+ tcf_tm_dump(&t, &p->tcf_tm);
+ if (nla_put_64bit(skb, TCA_PSP_TM, sizeof(t), &t, TCA_PSP_PAD))
+ goto nla_put_failure;
+ rcu_read_unlock();
+
+ return skb->len;
+
+nla_put_failure:
+ rcu_read_unlock();
+ nlmsg_trim(skb, b);
+ return -1;
+}
+
+static struct tc_action_ops act_psp_ops = {
+ .kind = "psp",
+ .id = TCA_ID_PSP,
+ .owner = THIS_MODULE,
+ .act = tcf_psp_act,
+ .dump = tcf_psp_dump,
+ .init = tcf_psp_init,
+ .cleanup = tcf_psp_cleanup,
+ .size = sizeof(struct tcf_psp),
+};
+MODULE_ALIAS_NET_ACT("psp");
+
+static __net_init int psp_init_net(struct net *net)
+{
+ struct tc_action_net *tn = net_generic(net, act_psp_ops.net_id);
+
+ return tc_action_net_init(net, tn, &act_psp_ops);
+}
+
+static void __net_exit psp_exit_net(struct list_head *net_list)
+{
+ tc_action_net_exit(net_list, act_psp_ops.net_id);
+}
+
+static struct pernet_operations psp_net_ops = {
+ .init = psp_init_net,
+ .exit_batch = psp_exit_net,
+ .id = &act_psp_ops.net_id,
+ .size = sizeof(struct tc_action_net),
+};
+
+static int __init psp_init_module(void)
+{
+ return tcf_register_action(&act_psp_ops, &psp_net_ops);
+}
+
+static void __exit psp_cleanup_module(void)
+{
+ tcf_unregister_action(&act_psp_ops, &psp_net_ops);
+}
+
+module_init(psp_init_module);
+module_exit(psp_cleanup_module);
+
+MODULE_DESCRIPTION("PSP encryption tc action");
+MODULE_LICENSE("GPL");
--
2.53.0-Meta
next prev parent reply other threads:[~2026-11-11 0:56 UTC|newest]
Thread overview: 39+ 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-12 0:56 ` sashiko-bot
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-12 0:56 ` sashiko-bot
2026-11-11 0:55 ` [PATCH net-next v1 03/15] psp: declare psp_assoc_set_tx() in psp.h Todd Freed
2026-11-12 0:56 ` sashiko-bot
2026-11-11 0:55 ` [PATCH net-next v1 04/15] psp: add support for socket-less psp associations Todd Freed
2026-11-11 16:49 ` Daniel Zahka
2026-11-11 18:23 ` Todd Bert Freed
2026-11-11 19:01 ` Daniel Zahka
2026-11-11 21:49 ` Todd Bert Freed
2026-11-12 0:51 ` Todd Bert Freed
2026-11-12 0:57 ` sashiko-bot
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-12 0:57 ` sashiko-bot
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-12 0:57 ` sashiko-bot
2026-11-11 0:55 ` [PATCH net-next v1 07/15] bpf: don't redirect " Todd Freed
2026-11-12 0:57 ` sashiko-bot
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 11:37 ` Daniel Zahka
2026-11-12 0:57 ` sashiko-bot
2026-11-11 0:55 ` Todd Freed [this message]
2026-11-12 0:57 ` [PATCH net-next v1 09/15] net/sched: add act_psp for psp transport mode sashiko-bot
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-12 0:57 ` sashiko-bot
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-12 0:57 ` sashiko-bot
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-12 0:57 ` sashiko-bot
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-12 0:57 ` sashiko-bot
2026-11-11 0:55 ` [PATCH net-next v1 14/15] selftests: tc-testing: add tests for the psp action Todd Freed
2026-11-12 0:57 ` sashiko-bot
2026-11-11 0:55 ` [PATCH net-next v1 15/15] Documentation: networking: psp: document socket-less associations Todd Freed
2026-11-12 0:57 ` sashiko-bot
2026-11-11 17:01 ` [PATCH net-next v1 00/15] psp: introduce " Daniel Zahka
2026-11-12 19:35 ` Todd Bert 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-10-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.