From: Jakub Kicinski <[email protected]>

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: Jakub Kicinski <[email protected]>
Signed-off-by: Daniel Zahka <[email protected]>
---

Notes:
    v2:
    - don't return skb->len from psp_nl_get_stats_dumpit() on success and
      EMSGSIZE

 Documentation/netlink/specs/psp.yaml | 40 +++++++++++++++
 include/net/psp/types.h              |  9 ++++
 include/uapi/linux/psp.h             | 10 ++++
 net/psp/psp-nl-gen.c                 | 19 +++++++
 net/psp/psp-nl-gen.h                 |  2 +
 net/psp/psp_nl.c                     | 74 ++++++++++++++++++++++++++++
 net/psp/psp_sock.c                   |  4 +-
 7 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/Documentation/netlink/specs/psp.yaml 
b/Documentation/netlink/specs/psp.yaml
index 944429e5c9a8..914148221384 100644
--- a/Documentation/netlink/specs/psp.yaml
+++ b/Documentation/netlink/specs/psp.yaml
@@ -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:
     -
diff --git a/include/net/psp/types.h b/include/net/psp/types.h
index 31cee64b7c86..5b0ccaac3882 100644
--- a/include/net/psp/types.h
+++ b/include/net/psp/types.h
@@ -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;
 };
 
diff --git a/include/uapi/linux/psp.h b/include/uapi/linux/psp.h
index 607c42c39ba5..31592760ad79 100644
--- a/include/uapi/linux/psp.h
+++ b/include/uapi/linux/psp.h
@@ -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)
diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c
index 9fdd6f831803..73f8b06d66f0 100644
--- a/net/psp/psp-nl-gen.c
+++ b/net/psp/psp-nl-gen.c
@@ -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[] = {
diff --git a/net/psp/psp-nl-gen.h b/net/psp/psp-nl-gen.h
index 25268ed11fb5..5bc3b5d5a53e 100644
--- a/net/psp/psp-nl-gen.h
+++ b/net/psp/psp-nl-gen.h
@@ -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,
diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c
index 8aaca62744c3..f990cccbe99c 100644
--- a/net/psp/psp_nl.c
+++ b/net/psp/psp_nl.c
@@ -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 @@ int psp_nl_tx_assoc_doit(struct sk_buff *skb, struct 
genl_info *info)
        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;
+}
diff --git a/net/psp/psp_sock.c b/net/psp/psp_sock.c
index a931d825d1cc..f785672b7df6 100644
--- a/net/psp/psp_sock.c
+++ b/net/psp/psp_sock.c
@@ -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);
 
-- 
2.47.3


Reply via email to