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:
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:
-
* 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 {
struct list_head prev_assocs;
struct list_head stale_assocs;
+ struct {
+ unsigned long rotations;
+ unsigned long stales;
+ } stats;
+
struct rcu_head rcu;
};
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,
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)
[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[] = {
{
.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[] = {
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,
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,
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;
+}
/* 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);