psp: report basic stats from the core

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>
This commit is contained in:
Jakub Kicinski
2025-11-05 16:26:02 -08:00
parent f73e0f46bb
commit dae4a92399
7 changed files with 157 additions and 1 deletions

View 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:
-

View 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;
};

View 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)

View 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[] = {

View 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,

View 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 @@ 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;
}

View 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);