Request per virtqueue statistics from the vhost library and expose them as per port OVS custom stats.
Note: - the vhost stats API is experimental at the moment, this patch is sent as a demonstrator, - we may drop maintaining rx stats in OVS itself and instead aggregate the per vq stats, this is something to investigate, - a unit test is missing, Signed-off-by: David Marchand <david.march...@redhat.com> --- lib/netdev-dpdk.c | 203 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 194 insertions(+), 9 deletions(-) diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c index 132ebb2843..3db5944977 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -532,11 +532,20 @@ struct netdev_dpdk { ); PADDED_MEMBERS(CACHE_LINE_SIZE, - /* Names of all XSTATS counters */ - struct rte_eth_xstat_name *rte_xstats_names; - int rte_xstats_names_size; - int rte_xstats_ids_size; - uint64_t *rte_xstats_ids; + union { + struct { + /* Names of all XSTATS counters */ + struct rte_eth_xstat_name *rte_xstats_names; + int rte_xstats_names_size; + int rte_xstats_ids_size; + uint64_t *rte_xstats_ids; + }; + struct { + /* Names of all vhost stats */ + struct rte_vhost_stat_name *vhost_stat_names; + int vhost_stat_size; + }; + }; ); }; @@ -552,6 +561,7 @@ static int netdev_dpdk_get_sw_custom_stats(const struct netdev *, struct netdev_custom_stats *); static void netdev_dpdk_configure_xstats(struct netdev_dpdk *dev); static void netdev_dpdk_clear_xstats(struct netdev_dpdk *dev); +static void netdev_dpdk_vhost_clear_stats(struct netdev_dpdk *dev); int netdev_dpdk_get_vid(const struct netdev_dpdk *dev); @@ -1586,6 +1596,7 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev) dev->vhost_id = NULL; rte_free(dev->vhost_rxq_enabled); + netdev_dpdk_vhost_clear_stats(dev); common_destruct(dev); ovs_mutex_unlock(&dpdk_mutex); @@ -3039,6 +3050,80 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev, return 0; } +static int +netdev_dpdk_vhost_get_custom_stats(const struct netdev *netdev, + struct netdev_custom_stats *custom_stats) +{ + netdev_dpdk_get_sw_custom_stats(netdev, custom_stats); + +#ifdef ALLOW_EXPERIMENTAL_API + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); + + ovs_mutex_lock(&dev->mutex); + + int vid = netdev_dpdk_get_vid(dev); + + if (vid >= 0 && dev->vhost_stat_size > 0) { + struct rte_vhost_stat *vhost_stats; + int stat_offset; + int sw_stats_size; + + vhost_stats = xcalloc(dev->vhost_stat_size, sizeof *vhost_stats); + + stat_offset = 0; + + for (int q = 0; q < dev->up.n_rxq; q++) { + int qid = q * VIRTIO_QNUM + VIRTIO_TXQ; + int err; + + err = rte_vhost_vring_stats_get(vid, qid, + &vhost_stats[stat_offset], + dev->vhost_stat_size + - stat_offset); + if (err < 0 || stat_offset + err > dev->vhost_stat_size) { + goto fail; + } + stat_offset += err; + } + + for (int q = 0; q < dev->up.n_txq; q++) { + int qid = q * VIRTIO_QNUM; + int err; + + err = rte_vhost_vring_stats_get(vid, qid, + &vhost_stats[stat_offset], + dev->vhost_stat_size + - stat_offset); + if (err < 0 || stat_offset + err > dev->vhost_stat_size) { + goto fail; + } + stat_offset += err; + } + + sw_stats_size = custom_stats->size; + custom_stats->size += dev->vhost_stat_size; + custom_stats->counters = xrealloc(custom_stats->counters, + custom_stats->size * + sizeof *custom_stats->counters); + + for (int i = 0; i < stat_offset; i++) { + ovs_strlcpy(custom_stats->counters[sw_stats_size + i].name, + dev->vhost_stat_names[i].name, + NETDEV_CUSTOM_STATS_NAME_SIZE); + custom_stats->counters[sw_stats_size + i].value = + vhost_stats[i].value; + } + +fail: + free(vhost_stats); + } + + ovs_mutex_unlock(&dev->mutex); +#endif + + return 0; +} + static void netdev_dpdk_convert_xstats(struct netdev_stats *stats, const struct rte_eth_xstat *xstats, @@ -5014,12 +5099,107 @@ out: return err; } +static void +netdev_dpdk_vhost_clear_stats(struct netdev_dpdk *dev) + OVS_REQUIRES(dev->mutex) +{ + free(dev->vhost_stat_names); + dev->vhost_stat_names = NULL; + dev->vhost_stat_size = 0; +}; + +static void +netdev_dpdk_vhost_configure_stats(struct netdev_dpdk *dev OVS_UNUSED) + OVS_REQUIRES(dev->mutex) +{ +#ifdef ALLOW_EXPERIMENTAL_API + struct rte_vhost_stat_name *vhost_stat_names = NULL; + int vhost_stat_size; + int stat_offset; + int vid; + + vid = netdev_dpdk_get_vid(dev); + if (vid < 0) { + goto fail; + } + + vhost_stat_size = 0; + + for (int q = 0; q < dev->up.n_rxq; q++) { + int qid = q * VIRTIO_QNUM + VIRTIO_TXQ; + int err; + + err = rte_vhost_vring_stats_get_names(vid, qid, NULL, 0); + if (err < 0) { + goto fail; + } + vhost_stat_size += err; + } + + for (int q = 0; q < dev->up.n_txq; q++) { + int qid = q * VIRTIO_QNUM; + int err; + + err = rte_vhost_vring_stats_get_names(vid, qid, NULL, 0); + if (err < 0) { + goto fail; + } + vhost_stat_size += err; + } + + vhost_stat_names = xcalloc(vhost_stat_size, sizeof *vhost_stat_names); + + stat_offset = 0; + + for (int q = 0; q < dev->up.n_rxq; q++) { + int qid = q * VIRTIO_QNUM + VIRTIO_TXQ; + int err; + + err = rte_vhost_vring_stats_get_names(vid, qid, + &vhost_stat_names[stat_offset], + vhost_stat_size - stat_offset); + if (err < 0 || stat_offset + err > vhost_stat_size) { + goto fail; + } + stat_offset += err; + } + + for (int q = 0; q < dev->up.n_txq; q++) { + int qid = q * VIRTIO_QNUM; + int err; + + err = rte_vhost_vring_stats_get_names(vid, qid, + &vhost_stat_names[stat_offset], + vhost_stat_size - stat_offset); + if (err < 0 || stat_offset + err > vhost_stat_size) { + goto fail; + } + stat_offset += err; + } + + dev->vhost_stat_names = vhost_stat_names; + vhost_stat_names = NULL; + dev->vhost_stat_size = vhost_stat_size; + +fail: + free(vhost_stat_names); +#endif +} + static int dpdk_vhost_reconfigure_helper(struct netdev_dpdk *dev) OVS_REQUIRES(dev->mutex) { - dev->up.n_txq = dev->requested_n_txq; - dev->up.n_rxq = dev->requested_n_rxq; + if (dev->up.n_rxq != dev->requested_n_rxq + || dev->up.n_txq != dev->requested_n_txq + || dev->vhost_stat_size <= 0) { + + dev->up.n_txq = dev->requested_n_txq; + dev->up.n_rxq = dev->requested_n_rxq; + + netdev_dpdk_vhost_clear_stats(dev); + netdev_dpdk_vhost_configure_stats(dev); + } /* Always keep RX queue 0 enabled for implementations that won't * report vring states. */ @@ -5090,6 +5270,11 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev *netdev) /* Register client-mode device. */ vhost_flags |= RTE_VHOST_USER_CLIENT; +#ifdef ALLOW_EXPERIMENTAL_API + /* Extended per vq statistics. */ + vhost_flags |= RTE_VHOST_USER_NET_STATS_ENABLE; +#endif + /* There is no support for multi-segments buffers. */ vhost_flags |= RTE_VHOST_USER_LINEARBUF_SUPPORT; @@ -5489,7 +5674,7 @@ static const struct netdev_class dpdk_vhost_class = { .send = netdev_dpdk_vhost_send, .get_carrier = netdev_dpdk_vhost_get_carrier, .get_stats = netdev_dpdk_vhost_get_stats, - .get_custom_stats = netdev_dpdk_get_sw_custom_stats, + .get_custom_stats = netdev_dpdk_vhost_get_custom_stats, .get_status = netdev_dpdk_vhost_user_get_status, .reconfigure = netdev_dpdk_vhost_reconfigure, .rxq_recv = netdev_dpdk_vhost_rxq_recv, @@ -5505,7 +5690,7 @@ static const struct netdev_class dpdk_vhost_client_class = { .send = netdev_dpdk_vhost_send, .get_carrier = netdev_dpdk_vhost_get_carrier, .get_stats = netdev_dpdk_vhost_get_stats, - .get_custom_stats = netdev_dpdk_get_sw_custom_stats, + .get_custom_stats = netdev_dpdk_vhost_get_custom_stats, .get_status = netdev_dpdk_vhost_user_get_status, .reconfigure = netdev_dpdk_vhost_client_reconfigure, .rxq_recv = netdev_dpdk_vhost_rxq_recv, -- 2.37.3 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev