]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
psp: report basic stats from the core
authorJakub Kicinski <kuba@kernel.org>
Thu, 6 Nov 2025 00:26:02 +0000 (16:26 -0800)
committerJakub Kicinski <kuba@kernel.org>
Sat, 8 Nov 2025 02:53:56 +0000 (18:53 -0800)
Track and report stats common to all psp devices from the core. A
'stale-event' is when the core marks the rx state of an active
psp_assoc as incapable of authenticating psp encapsulated data.

Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com>
Link: https://patch.msgid.link/20251106002608.1578518-2-daniel.zahka@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/netlink/specs/psp.yaml
include/net/psp/types.h
include/uapi/linux/psp.h
net/psp/psp-nl-gen.c
net/psp/psp-nl-gen.h
net/psp/psp_nl.c
net/psp/psp_sock.c

index 944429e5c9a840f0b1523aa4d4c33117567e6dc6..9141482213843f867c40d88a1c366340ec9e4ede 100644 (file)
@@ -76,6 +76,28 @@ attribute-sets:
         name: spi
         doc: Security Parameters Index (SPI) of the association.
         type: u32
+  -
+    name: stats
+    attributes:
+      -
+        name: dev-id
+        doc: PSP device ID.
+        type: u32
+        checks:
+          min: 1
+      -
+        name: key-rotations
+        type: uint
+        doc: |
+          Number of key rotations during the lifetime of the device.
+          Kernel statistic.
+      -
+        name: stale-events
+        type: uint
+        doc: |
+          Number of times a socket's Rx got shut down due to using
+          a key which went stale (fully rotated out).
+          Kernel statistic.
 
 operations:
   list:
@@ -177,6 +199,24 @@ operations:
         pre: psp-assoc-device-get-locked
         post: psp-device-unlock
 
+    -
+      name: get-stats
+      doc: Get device statistics.
+      attribute-set: stats
+      do:
+        request:
+          attributes:
+            - dev-id
+        reply: &stats-all
+          attributes:
+            - dev-id
+            - key-rotations
+            - stale-events
+        pre: psp-device-get-locked
+        post: psp-device-unlock
+      dump:
+        reply: *stats-all
+
 mcast-groups:
   list:
     -
index 31cee64b7c86aa4d73c7ec3d17cd5866a1082976..5b0ccaac38825fe98a81f3eb3c3f85ad97f057cd 100644 (file)
@@ -59,6 +59,10 @@ struct psp_dev_config {
  *                     device key
  * @stale_assocs:      associations which use a rotated out key
  *
+ * @stats:     statistics maintained by the core
+ * @stats.rotations:   See stats attr key-rotations
+ * @stats.stales:      See stats attr stale-events
+ *
  * @rcu:       RCU head for freeing the structure
  */
 struct psp_dev {
@@ -81,6 +85,11 @@ struct psp_dev {
        struct list_head prev_assocs;
        struct list_head stale_assocs;
 
+       struct {
+               unsigned long rotations;
+               unsigned long stales;
+       } stats;
+
        struct rcu_head rcu;
 };
 
index 607c42c39ba557a3758687f0d3d5f840174fd49a..31592760ad794f4568b0b9b4aa4e77fd400fc34a 100644 (file)
@@ -45,6 +45,15 @@ enum {
        PSP_A_KEYS_MAX = (__PSP_A_KEYS_MAX - 1)
 };
 
+enum {
+       PSP_A_STATS_DEV_ID = 1,
+       PSP_A_STATS_KEY_ROTATIONS,
+       PSP_A_STATS_STALE_EVENTS,
+
+       __PSP_A_STATS_MAX,
+       PSP_A_STATS_MAX = (__PSP_A_STATS_MAX - 1)
+};
+
 enum {
        PSP_CMD_DEV_GET = 1,
        PSP_CMD_DEV_ADD_NTF,
@@ -55,6 +64,7 @@ enum {
        PSP_CMD_KEY_ROTATE_NTF,
        PSP_CMD_RX_ASSOC,
        PSP_CMD_TX_ASSOC,
+       PSP_CMD_GET_STATS,
 
        __PSP_CMD_MAX,
        PSP_CMD_MAX = (__PSP_CMD_MAX - 1)
index 9fdd6f831803e6f58c7613e1d6d2c22c3f47495a..73f8b06d66f0f995068b82b95126110887ac3bc9 100644 (file)
@@ -47,6 +47,11 @@ static const struct nla_policy psp_tx_assoc_nl_policy[PSP_A_ASSOC_SOCK_FD + 1] =
        [PSP_A_ASSOC_SOCK_FD] = { .type = NLA_U32, },
 };
 
+/* PSP_CMD_GET_STATS - do */
+static const struct nla_policy psp_get_stats_nl_policy[PSP_A_STATS_DEV_ID + 1] = {
+       [PSP_A_STATS_DEV_ID] = NLA_POLICY_MIN(NLA_U32, 1),
+};
+
 /* Ops table for psp */
 static const struct genl_split_ops psp_nl_ops[] = {
        {
@@ -99,6 +104,20 @@ static const struct genl_split_ops psp_nl_ops[] = {
                .maxattr        = PSP_A_ASSOC_SOCK_FD,
                .flags          = GENL_CMD_CAP_DO,
        },
+       {
+               .cmd            = PSP_CMD_GET_STATS,
+               .pre_doit       = psp_device_get_locked,
+               .doit           = psp_nl_get_stats_doit,
+               .post_doit      = psp_device_unlock,
+               .policy         = psp_get_stats_nl_policy,
+               .maxattr        = PSP_A_STATS_DEV_ID,
+               .flags          = GENL_CMD_CAP_DO,
+       },
+       {
+               .cmd    = PSP_CMD_GET_STATS,
+               .dumpit = psp_nl_get_stats_dumpit,
+               .flags  = GENL_CMD_CAP_DUMP,
+       },
 };
 
 static const struct genl_multicast_group psp_nl_mcgrps[] = {
index 25268ed11fb56bb5259cf1e49d4fbe12e77f64e8..5bc3b5d5a53e20dd989cfe176f8c644f1df79076 100644 (file)
@@ -28,6 +28,8 @@ int psp_nl_dev_set_doit(struct sk_buff *skb, struct genl_info *info);
 int psp_nl_key_rotate_doit(struct sk_buff *skb, struct genl_info *info);
 int psp_nl_rx_assoc_doit(struct sk_buff *skb, struct genl_info *info);
 int psp_nl_tx_assoc_doit(struct sk_buff *skb, struct genl_info *info);
+int psp_nl_get_stats_doit(struct sk_buff *skb, struct genl_info *info);
+int psp_nl_get_stats_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
 
 enum {
        PSP_NLGRP_MGMT,
index 8aaca62744c3c19bc28f3afa25d0d5f5696fb3c3..f990cccbe99c172eeedce0d78d30e623b2da4cac 100644 (file)
@@ -262,6 +262,7 @@ int psp_nl_key_rotate_doit(struct sk_buff *skb, struct genl_info *info)
                     psd->generation & ~PSP_GEN_VALID_MASK);
 
        psp_assocs_key_rotated(psd);
+       psd->stats.rotations++;
 
        nlmsg_end(ntf, (struct nlmsghdr *)ntf->data);
        genlmsg_multicast_netns(&psp_nl_family, dev_net(psd->main_netdev), ntf,
@@ -503,3 +504,76 @@ err_free_msg:
        nlmsg_free(rsp);
        return err;
 }
+
+static int
+psp_nl_stats_fill(struct psp_dev *psd, struct sk_buff *rsp,
+                 const struct genl_info *info)
+{
+       void *hdr;
+
+       hdr = genlmsg_iput(rsp, info);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       if (nla_put_u32(rsp, PSP_A_STATS_DEV_ID, psd->id) ||
+           nla_put_uint(rsp, PSP_A_STATS_KEY_ROTATIONS,
+                        psd->stats.rotations) ||
+           nla_put_uint(rsp, PSP_A_STATS_STALE_EVENTS, psd->stats.stales))
+               goto err_cancel_msg;
+
+       genlmsg_end(rsp, hdr);
+       return 0;
+
+err_cancel_msg:
+       genlmsg_cancel(rsp, hdr);
+       return -EMSGSIZE;
+}
+
+int psp_nl_get_stats_doit(struct sk_buff *skb, struct genl_info *info)
+{
+       struct psp_dev *psd = info->user_ptr[0];
+       struct sk_buff *rsp;
+       int err;
+
+       rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!rsp)
+               return -ENOMEM;
+
+       err = psp_nl_stats_fill(psd, rsp, info);
+       if (err)
+               goto err_free_msg;
+
+       return genlmsg_reply(rsp, info);
+
+err_free_msg:
+       nlmsg_free(rsp);
+       return err;
+}
+
+static int
+psp_nl_stats_get_dumpit_one(struct sk_buff *rsp, struct netlink_callback *cb,
+                           struct psp_dev *psd)
+{
+       if (psp_dev_check_access(psd, sock_net(rsp->sk)))
+               return 0;
+
+       return psp_nl_stats_fill(psd, rsp, genl_info_dump(cb));
+}
+
+int psp_nl_get_stats_dumpit(struct sk_buff *rsp, struct netlink_callback *cb)
+{
+       struct psp_dev *psd;
+       int err = 0;
+
+       mutex_lock(&psp_devs_lock);
+       xa_for_each_start(&psp_devs, cb->args[0], psd, cb->args[0]) {
+               mutex_lock(&psd->lock);
+               err = psp_nl_stats_get_dumpit_one(rsp, cb, psd);
+               mutex_unlock(&psd->lock);
+               if (err)
+                       break;
+       }
+       mutex_unlock(&psp_devs_lock);
+
+       return err;
+}
index a931d825d1cc4ad50f9ba3af3e4effee6cee1a3a..f785672b7df66b603e6d94f2420d21c8c00b71da 100644 (file)
@@ -253,8 +253,10 @@ void psp_assocs_key_rotated(struct psp_dev *psd)
        /* Mark the stale associations as invalid, they will no longer
         * be able to Rx any traffic.
         */
-       list_for_each_entry_safe(pas, next, &psd->prev_assocs, assocs_list)
+       list_for_each_entry_safe(pas, next, &psd->prev_assocs, assocs_list) {
                pas->generation |= ~PSP_GEN_VALID_MASK;
+               psd->stats.stales++;
+       }
        list_splice_init(&psd->prev_assocs, &psd->stale_assocs);
        list_splice_init(&psd->active_assocs, &psd->prev_assocs);