[PATCH net-next 1/3] psp: add crypt-offset and spi-threshold get/set attributes

Akhilesh Samineni
2026-04-06T22:23:32Z

crypt-offset (Crypt Offset)
----------------------------------
The crypt-offset attribute specifies the byte offset within a packet
from which encryption begins. This is a per-device attribute that
allows a portion of the packet header to remain in plaintext while
the rest of the payload is encrypted. This is useful in scenarios
where intermediate nodes need to inspect or process a fixed-size
header before the encrypted payload.

The default value is 0, meaning encryption starts from the beginning
of the payload following the PSP header.

spi-threshold (SPI Threshold)
------------------------------
The SPI (Security Parameter Index) is a 32-bit per-device identifier
used to distinguish security associations. As SPI values are allocated
monotonically, a threshold is needed to trigger timely SPI rotation
before the space is exhausted.

The spi-threshold attribute allows userspace to configure the value at
which an SPI rotation should be initiated. The default is set to
PSP_SPI_THRESHOLD_DEFAULT (~90% of 0x7FFFFFFF), providing a comfortable
margin to perform rotation without racing to exhaustion.

NOTE: A follow-up series will add notification support to alert
subscribed users when the configured spi-threshold is reached, enabling
timely SPI rotation.

Signed-off-by: Akhilesh Samineni <akhilesh.samineni@broadcom.com>
Reviewed-by: Kiran Kella <kiran.kella@broadcom.com>
Reviewed-by: Ajit Kumar Khaparde <ajit.khaparde@broadcom.com>
---
Documentation/netlink/specs/psp.yaml | 13 +++++++++++++
include/net/psp/types.h | 7 +++++++
include/uapi/linux/psp.h | 2 ++
net/psp/psp-nl-gen.c | 6 ++++--
net/psp/psp_main.c | 3 +++
net/psp/psp_nl.c | 27 +++++++++++++++++++++++----
6 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/Documentation/netlink/specs/psp.yaml b/Documentation/netlink/specs/psp.yaml
index f3a57782d2cf..b22869be91cf 100644
--- a/Documentation/netlink/specs/psp.yaml
+++ b/Documentation/netlink/specs/psp.yaml
@@ -38,6 +38,15 @@ attribute-sets:
type: u32
enum: version
enum-as-flags: true
+ -
+ name: crypt-offset
+ doc: The offset from the end of the PSP header to the start of the encrypted payload.
+ type: u8
+ -
+ name: spi-threshold
+ doc: Threshold for the SPI to trigger notification to the user for appropriate rotate action.
+ type: u32
+
-
name: assoc
attributes:
@@ -170,6 +179,8 @@ operations:
- ifindex
- psp-versions-cap
- psp-versions-ena
+ - crypt-offset
+ - spi-threshold
pre: psp-device-get-locked
post: psp-device-unlock
dump:
@@ -193,6 +204,8 @@ operations:
attributes:
- id
- psp-versions-ena
+ - crypt-offset
+ - spi-threshold
reply:
attributes: []
pre: psp-device-get-locked
diff --git a/include/net/psp/types.h b/include/net/psp/types.h
index 25a9096d4e7d..875f7822557f 100644
--- a/include/net/psp/types.h
+++ b/include/net/psp/types.h
@@ -25,6 +25,9 @@ struct psphdr {
#define PSP_SPI_KEY_ID GENMASK(30, 0)
#define PSP_SPI_KEY_PHASE BIT(31)

+/* Default SPI threshold: ~90% of max SPI (0x7FFFFFFF) to allow rotation before exhaustion */
+#define PSP_SPI_THRESHOLD_DEFAULT 0x73333333
+
#define PSPHDR_CRYPT_OFFSET GENMASK(5, 0)

#define PSPHDR_VERFL_SAMPLE BIT(7)
@@ -38,9 +41,13 @@ struct psphdr {
/**
* struct psp_dev_config - PSP device configuration
* @versions: PSP versions enabled on the device
+ * @crypt_offset: crypto offset configured on the device
+ * @spi_threshold: SPI threshold value on the device
*/
struct psp_dev_config {
u32 versions;
+ u8 crypt_offset;
+ u32 spi_threshold;
};

/**
diff --git a/include/uapi/linux/psp.h b/include/uapi/linux/psp.h
index a3a336488dc3..bb390159dc72 100644
--- a/include/uapi/linux/psp.h
+++ b/include/uapi/linux/psp.h
@@ -22,6 +22,8 @@ enum {
PSP_A_DEV_IFINDEX,
PSP_A_DEV_PSP_VERSIONS_CAP,
PSP_A_DEV_PSP_VERSIONS_ENA,
+ PSP_A_DEV_CRYPT_OFFSET,
+ PSP_A_DEV_SPI_THRESHOLD,

__PSP_A_DEV_MAX,
PSP_A_DEV_MAX = (__PSP_A_DEV_MAX - 1)
diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c
index 22a48d0fa378..e50b8b80955c 100644
--- a/net/psp/psp-nl-gen.c
+++ b/net/psp/psp-nl-gen.c
@@ -23,9 +23,11 @@ static const struct nla_policy psp_dev_get_nl_policy[PSP_A_DEV_ID + 1] = {
};

/* PSP_CMD_DEV_SET - do */
-static const struct nla_policy psp_dev_set_nl_policy[PSP_A_DEV_PSP_VERSIONS_ENA + 1] = {
+static const struct nla_policy psp_dev_set_nl_policy[PSP_A_DEV_SPI_THRESHOLD + 1] = {
[PSP_A_DEV_ID] = NLA_POLICY_MIN(NLA_U32, 1),
[PSP_A_DEV_PSP_VERSIONS_ENA] = NLA_POLICY_MASK(NLA_U32, 0xf),
+ [PSP_A_DEV_CRYPT_OFFSET] = { .type = NLA_U8, },
+ [PSP_A_DEV_SPI_THRESHOLD] = { .type = NLA_U32, },
};

/* PSP_CMD_KEY_ROTATE - do */
@@ -75,7 +77,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
.doit = psp_nl_dev_set_doit,
.post_doit = psp_device_unlock,
.policy = psp_dev_set_nl_policy,
- .maxattr = PSP_A_DEV_PSP_VERSIONS_ENA,
+ .maxattr = PSP_A_DEV_SPI_THRESHOLD,
.flags = GENL_CMD_CAP_DO,
},
{
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 9508b6c38003..536ee44db09d 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -79,6 +79,9 @@ psp_dev_create(struct net_device *netdev,
INIT_LIST_HEAD(&psd->stale_assocs);
refcount_set(&psd->refcnt, 1);

+ /* ~90% of 0x7FFFFFFF; allows SPI rotation well before space is exhausted */
+ psd->config.spi_threshold = PSP_SPI_THRESHOLD_DEFAULT;
+
mutex_lock(&psp_devs_lock);
err = xa_alloc_cyclic(&psp_devs, &psd->id, psd, xa_limit_16b,
&last_id, GFP_KERNEL);
diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c
index 6afd7707ec12..fbb77460a24b 100644
--- a/net/psp/psp_nl.c
+++ b/net/psp/psp_nl.c
@@ -101,7 +101,9 @@ psp_nl_dev_fill(struct psp_dev *psd, struct sk_buff *rsp,
if (nla_put_u32(rsp, PSP_A_DEV_ID, psd->id) ||
nla_put_u32(rsp, PSP_A_DEV_IFINDEX, psd->main_netdev->ifindex) ||
nla_put_u32(rsp, PSP_A_DEV_PSP_VERSIONS_CAP, psd->caps->versions) ||
- nla_put_u32(rsp, PSP_A_DEV_PSP_VERSIONS_ENA, psd->config.versions))
+ nla_put_u32(rsp, PSP_A_DEV_PSP_VERSIONS_ENA, psd->config.versions) ||
+ nla_put_u8(rsp, PSP_A_DEV_CRYPT_OFFSET, psd->config.crypt_offset) ||
+ nla_put_u32(rsp, PSP_A_DEV_SPI_THRESHOLD, psd->config.spi_threshold))
goto err_cancel_msg;

genlmsg_end(rsp, hdr);
@@ -193,6 +195,13 @@ int psp_nl_dev_set_doit(struct sk_buff *skb, struct genl_info *info)

memcpy(&new_config, &psd->config, sizeof(new_config));

+ if (!info->attrs[PSP_A_DEV_PSP_VERSIONS_ENA] &&
+ !info->attrs[PSP_A_DEV_CRYPT_OFFSET] &&
+ !info->attrs[PSP_A_DEV_SPI_THRESHOLD]) {
+ NL_SET_ERR_MSG(info->extack, "No settings present");
+ return -EINVAL;
+ }
+
if (info->attrs[PSP_A_DEV_PSP_VERSIONS_ENA]) {
new_config.versions =
nla_get_u32(info->attrs[PSP_A_DEV_PSP_VERSIONS_ENA]);
@@ -200,9 +209,19 @@ int psp_nl_dev_set_doit(struct sk_buff *skb, struct genl_info *info)
NL_SET_ERR_MSG(info->extack, "Requested PSP versions not supported by the device");
return -EINVAL;
}
- } else {
- NL_SET_ERR_MSG(info->extack, "No settings present");
- return -EINVAL;
+ }
+
+ if (info->attrs[PSP_A_DEV_CRYPT_OFFSET])
+ new_config.crypt_offset =
+ nla_get_u8(info->attrs[PSP_A_DEV_CRYPT_OFFSET]);
+
+ if (info->attrs[PSP_A_DEV_SPI_THRESHOLD]) {
+ new_config.spi_threshold =
+ nla_get_u32(info->attrs[PSP_A_DEV_SPI_THRESHOLD]);
+ if (new_config.spi_threshold & PSP_SPI_KEY_PHASE) {
+ NL_SET_ERR_MSG(info->extack, "SPI threshold must not have bit 31 set");
+ return -EINVAL;
+ }
}

rsp = psp_nl_reply_new(info);
--
2.45.4