On Thu, Nov 18, 2021 at 1:58 PM Eli Cohen <elic@xxxxxxxxxx> wrote: > > Add support for querying virtqueue statistics. Supported statistics are: > > Received_desc - number of descriptors received for the virtqueue > completed_desc - number of descriptors completed for the virtqueue > > A new callback was added to vdpa_config_ops which provides the means for > the vdpa driver to return statistics results. > > The interface allows for reading all the supported virtqueues, including > the control virtqueue if it exists, by returning the next queue index to > query. > > Examples: > 1. Read statisitics for the virtqueue at index 1 > $ vdpa dev stats show vdpa-a index 1 > vdpa-a: > index 1 tx received_desc 21 completed_desc 21 > > 2. Read statisitics for all the virtqueues > vdpa dev stats show vdpa-a > vdpa-a: > index 0 rx received_desc 256 completed_desc 12 > index 1 tx received_desc 21 completed_desc 21 > index 2 ctrl received_desc 0 completed_desc 0 Adding Adrian and Laurent. It's quite useful but I think it's vendor specific statistics. I wonder if it's better to use "vendor" prefix in the protocol, then we use this instead: vdpa dev vendor-stats show vdpa-a Or if we want to make it standard is exposing virtio index better? qid 0 last_avail_idx X avail_idx Y last_used_idx M used_idx N Thanks > > Signed-off-by: Eli Cohen <elic@xxxxxxxxxx> > --- > drivers/vdpa/vdpa.c | 141 ++++++++++++++++++++++++++++++++++++++ > include/linux/vdpa.h | 10 +++ > include/uapi/linux/vdpa.h | 9 +++ > 3 files changed, 160 insertions(+) > > diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c > index 7332a74a4b00..54bcb140af74 100644 > --- a/drivers/vdpa/vdpa.c > +++ b/drivers/vdpa/vdpa.c > @@ -781,6 +781,87 @@ vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, > return err; > } > > +static int vdpa_fill_stats_rec(struct vdpa_device *vdev, struct sk_buff *msg, u16 *index) > +{ > + struct vdpa_vq_stats stats; > + u16 idx = *index; > + int err; > + > + err = vdev->config->get_vq_stats(vdev, index, &stats); > + if (err) > + return err; > + > + if (nla_put_u16(msg, VDPA_ATTR_DEV_QUEUE_INDEX, idx)) > + return -EMSGSIZE; > + > + if (nla_put_u16(msg, VDPA_ATTR_DEV_QUEUE_CTRL, !!stats.ctrl_vq)) > + return -EMSGSIZE; > + > + if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_RECEIVED_DESC, stats.received_desc, VDPA_ATTR_PAD)) > + return -EMSGSIZE; > + > + if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_COMPLETED_DESC, stats.completed_desc, > + VDPA_ATTR_PAD)) > + return -EMSGSIZE; > + > + return 0; > +} > + > +static int vdpa_dev_net_stats_fill(struct vdpa_device *vdev, struct sk_buff *msg, u16 index) > +{ > + int err; > + > + if (!vdev->config->get_vq_stats) > + return -EOPNOTSUPP; > + > + if (index != (u16)-1) { > + err = vdpa_fill_stats_rec(vdev, msg, &index); > + if (err) > + return err; > + } else { > + index = 0; > + do { > + err = vdpa_fill_stats_rec(vdev, msg, &index); > + } while (index != VDPA_INVAL_QUEUE_INDEX); > + } > + > + return 0; > +} > + > +static int vdpa_dev_stats_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, > + u32 seq, int flags, u16 index) > +{ > + u32 device_id; > + void *hdr; > + int err; > + > + hdr = genlmsg_put(msg, portid, seq, &vdpa_nl_family, flags, > + VDPA_CMD_DEV_STATS_GET); > + if (!hdr) > + return -EMSGSIZE; > + > + if (nla_put_string(msg, VDPA_ATTR_DEV_NAME, dev_name(&vdev->dev))) { > + err = -EMSGSIZE; > + goto undo_msg; > + } > + > + device_id = vdev->config->get_device_id(vdev); > + if (nla_put_u32(msg, VDPA_ATTR_DEV_ID, device_id)) { > + err = -EMSGSIZE; > + goto undo_msg; > + } > + > + err = vdpa_dev_net_stats_fill(vdev, msg, index); > + > + genlmsg_end(msg, hdr); > + > + return err; > + > +undo_msg: > + genlmsg_cancel(msg, hdr); > + return err; > +} > + > static int vdpa_nl_cmd_dev_config_get_doit(struct sk_buff *skb, struct genl_info *info) > { > struct vdpa_device *vdev; > @@ -862,6 +943,59 @@ vdpa_nl_cmd_dev_config_get_dumpit(struct sk_buff *msg, struct netlink_callback * > return msg->len; > } > > +static int vdpa_nl_cmd_dev_stats_get_doit(struct sk_buff *skb, > + struct genl_info *info) > +{ > + struct vdpa_device *vdev; > + struct sk_buff *msg; > + const char *devname; > + struct device *dev; > + u16 index = -1; > + int err; > + > + if (!info->attrs[VDPA_ATTR_DEV_NAME]) > + return -EINVAL; > + > + if (info->attrs[VDPA_ATTR_DEV_QUEUE_INDEX]) > + index = nla_get_u16(info->attrs[VDPA_ATTR_DEV_QUEUE_INDEX]); > + > + devname = nla_data(info->attrs[VDPA_ATTR_DEV_NAME]); > + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); > + if (!msg) > + return -ENOMEM; > + > + mutex_lock(&vdpa_dev_mutex); > + dev = bus_find_device(&vdpa_bus, NULL, devname, vdpa_name_match); > + if (!dev) { > + NL_SET_ERR_MSG_MOD(info->extack, "device not found"); > + err = -ENODEV; > + goto dev_err; > + } > + vdev = container_of(dev, struct vdpa_device, dev); > + if (!vdev->mdev) { > + NL_SET_ERR_MSG_MOD(info->extack, "unmanaged vdpa device"); > + err = -EINVAL; > + goto mdev_err; > + } > + err = vdpa_dev_stats_fill(vdev, msg, info->snd_portid, info->snd_seq, 0, index); > + if (!err) > + err = genlmsg_reply(msg, info); > + > + put_device(dev); > + mutex_unlock(&vdpa_dev_mutex); > + > + if (err) > + nlmsg_free(msg); > + > + return err; > + > +mdev_err: > + put_device(dev); > +dev_err: > + mutex_unlock(&vdpa_dev_mutex); > + return err; > +} > + > static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = { > [VDPA_ATTR_MGMTDEV_BUS_NAME] = { .type = NLA_NUL_STRING }, > [VDPA_ATTR_MGMTDEV_DEV_NAME] = { .type = NLA_STRING }, > @@ -869,6 +1003,7 @@ static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = { > [VDPA_ATTR_DEV_NET_CFG_MACADDR] = NLA_POLICY_ETH_ADDR, > /* virtio spec 1.1 section 5.1.4.1 for valid MTU range */ > [VDPA_ATTR_DEV_NET_CFG_MTU] = NLA_POLICY_MIN(NLA_U16, 68), > + [VDPA_ATTR_DEV_QUEUE_INDEX] = NLA_POLICY_RANGE(NLA_U16, 0, 32767), > }; > > static const struct genl_ops vdpa_nl_ops[] = { > @@ -902,6 +1037,12 @@ static const struct genl_ops vdpa_nl_ops[] = { > .doit = vdpa_nl_cmd_dev_config_get_doit, > .dumpit = vdpa_nl_cmd_dev_config_get_dumpit, > }, > + { > + .cmd = VDPA_CMD_DEV_STATS_GET, > + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, > + .doit = vdpa_nl_cmd_dev_stats_get_doit, > + .flags = GENL_ADMIN_PERM, > + }, > }; > > static struct genl_family vdpa_nl_family __ro_after_init = { > diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h > index c3011ccda430..1df19a87a9cb 100644 > --- a/include/linux/vdpa.h > +++ b/include/linux/vdpa.h > @@ -58,6 +58,12 @@ struct vdpa_vq_state { > }; > }; > > +struct vdpa_vq_stats { > + u64 received_desc; > + u64 completed_desc; > + bool ctrl_vq; > +}; > + > struct vdpa_mgmt_dev; > > /** > @@ -269,6 +275,8 @@ struct vdpa_config_ops { > const struct vdpa_vq_state *state); > int (*get_vq_state)(struct vdpa_device *vdev, u16 idx, > struct vdpa_vq_state *state); > + int (*get_vq_stats)(struct vdpa_device *vdev, u16 *idx, > + struct vdpa_vq_stats *stats); > struct vdpa_notification_area > (*get_vq_notification)(struct vdpa_device *vdev, u16 idx); > /* vq irq is not expected to be changed once DRIVER_OK is set */ > @@ -443,4 +451,6 @@ struct vdpa_mgmt_dev { > int vdpa_mgmtdev_register(struct vdpa_mgmt_dev *mdev); > void vdpa_mgmtdev_unregister(struct vdpa_mgmt_dev *mdev); > > +#define VDPA_INVAL_QUEUE_INDEX 0xffff > + > #endif /* _LINUX_VDPA_H */ > diff --git a/include/uapi/linux/vdpa.h b/include/uapi/linux/vdpa.h > index a252f06f9dfd..be7deeae139a 100644 > --- a/include/uapi/linux/vdpa.h > +++ b/include/uapi/linux/vdpa.h > @@ -18,11 +18,15 @@ enum vdpa_command { > VDPA_CMD_DEV_DEL, > VDPA_CMD_DEV_GET, /* can dump */ > VDPA_CMD_DEV_CONFIG_GET, /* can dump */ > + VDPA_CMD_DEV_STATS_GET, > }; > > enum vdpa_attr { > VDPA_ATTR_UNSPEC, > > + /* Pad attribute for 64b alignment */ > + VDPA_ATTR_PAD = VDPA_ATTR_UNSPEC, > + > /* bus name (optional) + dev name together make the parent device handle */ > VDPA_ATTR_MGMTDEV_BUS_NAME, /* string */ > VDPA_ATTR_MGMTDEV_DEV_NAME, /* string */ > @@ -40,6 +44,11 @@ enum vdpa_attr { > VDPA_ATTR_DEV_NET_CFG_MAX_VQP, /* u16 */ > VDPA_ATTR_DEV_NET_CFG_MTU, /* u16 */ > > + VDPA_ATTR_DEV_QUEUE_INDEX, /* u16 */ > + VDPA_ATTR_DEV_QUEUE_CTRL, /* u16 */ > + VDPA_ATTR_DEV_RECEIVED_DESC, /* u64 */ > + VDPA_ATTR_DEV_COMPLETED_DESC, /* u64 */ > + > /* new attributes must be added above here */ > VDPA_ATTR_MAX, > }; > -- > 2.33.1 > _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linuxfoundation.org/mailman/listinfo/virtualization