Add xstats() functions and statistic strings to virtio PMD. Signed-off-by: Harry van Haaren <harry.van.haaren at intel.com> --- drivers/net/virtio/virtio_ethdev.c | 98 +++++++++++++++++++++++++++++++++++++- drivers/net/virtio/virtio_rxtx.c | 32 +++++++++++++ drivers/net/virtio/virtqueue.h | 4 ++ 3 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 12fcc23..fe5afb9 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -80,7 +80,10 @@ static int virtio_dev_link_update(struct rte_eth_dev *dev, static void virtio_set_hwaddr(struct virtio_hw *hw); static void virtio_get_hwaddr(struct virtio_hw *hw); -static void virtio_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats); +static void virtio_dev_stats_get(struct rte_eth_dev *dev, + struct rte_eth_stats *stats); +static int virtio_dev_xstats_get(struct rte_eth_dev *dev, + struct rte_eth_xstats *xstats, unsigned n); static void virtio_dev_stats_reset(struct rte_eth_dev *dev); static void virtio_dev_free_mbufs(struct rte_eth_dev *dev); static int virtio_vlan_filter_set(struct rte_eth_dev *dev, @@ -109,6 +112,31 @@ static const struct rte_pci_id pci_id_virtio_map[] = { { .vendor_id = 0, /* sentinel */ }, }; +struct rte_virtio_xstats_name_off { + char name[RTE_ETH_XSTATS_NAME_SIZE]; + unsigned offset; +}; + +/* [rt]x_qX_ is prepended to the name string here */ +static const struct rte_virtio_xstats_name_off rte_virtio_q_stat_strings[] = { + {"good_packets", offsetof(struct virtqueue, packets)}, + {"good_bytes", offsetof(struct virtqueue, bytes)}, + {"errors", offsetof(struct virtqueue, errors)}, + {"multicast_packets", offsetof(struct virtqueue, multicast)}, + {"broadcast_packets", offsetof(struct virtqueue, broadcast)}, + {"undersize_packets", offsetof(struct virtqueue, size_bins[0])}, + {"size_64_packets", offsetof(struct virtqueue, size_bins[1])}, + {"size_65_127_packets", offsetof(struct virtqueue, size_bins[2])}, + {"size_128_255_packets", offsetof(struct virtqueue, size_bins[3])}, + {"size_256_511_packets", offsetof(struct virtqueue, size_bins[4])}, + {"size_512_1023_packets", offsetof(struct virtqueue, size_bins[5])}, + {"size_1024_1517_packets", offsetof(struct virtqueue, size_bins[6])}, + {"size_1518_max_packets", offsetof(struct virtqueue, size_bins[7])}, +}; + +#define VIRTIO_NB_Q_XSTATS (sizeof(rte_virtio_q_stat_strings) / \ + sizeof(rte_virtio_q_stat_strings[0])) + static int virtio_send_command(struct virtqueue *vq, struct virtio_pmd_ctrl *ctrl, int *dlen, int pkt_num) @@ -568,7 +596,9 @@ static const struct eth_dev_ops virtio_eth_dev_ops = { .dev_infos_get = virtio_dev_info_get, .stats_get = virtio_dev_stats_get, + .xstats_get = virtio_dev_xstats_get, .stats_reset = virtio_dev_stats_reset, + .xstats_reset = virtio_dev_stats_reset, .link_update = virtio_dev_link_update, .rx_queue_setup = virtio_dev_rx_queue_setup, .rx_queue_release = virtio_dev_rx_queue_release, @@ -623,7 +653,7 @@ virtio_dev_atomic_write_link_status(struct rte_eth_dev *dev, } static void -virtio_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) +virtio_update_stats(struct rte_eth_dev *dev, struct rte_eth_stats *stats) { unsigned i; @@ -660,6 +690,64 @@ virtio_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) stats->rx_nombuf = dev->data->rx_mbuf_alloc_failed; } +static int +virtio_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats, + unsigned n) +{ + unsigned i; + unsigned count = 0; + + unsigned nstats = dev->data->nb_tx_queues * VIRTIO_NB_Q_XSTATS + + dev->data->nb_rx_queues * VIRTIO_NB_Q_XSTATS; + + if (n < nstats) + return nstats; + + for (i = 0; i < dev->data->nb_rx_queues; i++) { + struct virtqueue *rxvq = dev->data->rx_queues[i]; + + if (rxvq == NULL) + continue; + + unsigned t; + + for (t = 0; t < VIRTIO_NB_Q_XSTATS; t++) { + snprintf(xstats[count].name, sizeof(xstats[count].name), + "rx_q%u_%s", i, + rte_virtio_q_stat_strings[t].name); + xstats[count].value = *(uint64_t *)(((char *)rxvq) + + rte_virtio_q_stat_strings[t].offset); + count++; + } + } + + for (i = 0; i < dev->data->nb_tx_queues; i++) { + struct virtqueue *txvq = dev->data->tx_queues[i]; + + if (txvq == NULL) + continue; + + unsigned t; + + for (t = 0; t < VIRTIO_NB_Q_XSTATS; t++) { + snprintf(xstats[count].name, sizeof(xstats[count].name), + "tx_q%u_%s", i, + rte_virtio_q_stat_strings[t].name); + xstats[count].value = *(uint64_t *)(((char *)txvq) + + rte_virtio_q_stat_strings[t].offset); + count++; + } + } + + return count; +} + +static void +virtio_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) +{ + virtio_update_stats(dev, stats); +} + static void virtio_dev_stats_reset(struct rte_eth_dev *dev) { @@ -673,6 +761,9 @@ virtio_dev_stats_reset(struct rte_eth_dev *dev) txvq->packets = 0; txvq->bytes = 0; txvq->errors = 0; + txvq->multicast = 0; + txvq->broadcast = 0; + memset(txvq->size_bins, 0, sizeof(txvq->size_bins[0]) * 8); } for (i = 0; i < dev->data->nb_rx_queues; i++) { @@ -683,6 +774,9 @@ virtio_dev_stats_reset(struct rte_eth_dev *dev) rxvq->packets = 0; rxvq->bytes = 0; rxvq->errors = 0; + rxvq->multicast = 0; + rxvq->broadcast = 0; + memset(rxvq->size_bins, 0, sizeof(rxvq->size_bins[0]) * 8); } dev->data->rx_mbuf_alloc_failed = 0; diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index d35c5f9..7590485 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -482,6 +482,34 @@ virtio_discard_rxbuf(struct virtqueue *vq, struct rte_mbuf *m) } } +static void +virtio_update_packet_stats(struct virtqueue *vq, struct rte_mbuf *mbuf) +{ + uint32_t s = mbuf->pkt_len; + struct ether_addr *ea; + + if (s == 64) { + vq->size_bins[1]++; + } else if (s > 64 && s < 1024) { + uint32_t bin; + + /* count zeros, and offset into correct bin */ + bin = (sizeof(s) * 8) - __builtin_clz(s) - 5; + vq->size_bins[bin]++; + } else { + if (s < 64) + vq->size_bins[0]++; + else if (s < 1519) + vq->size_bins[6]++; + else if (s >= 1519) + vq->size_bins[7]++; + } + + ea = rte_pktmbuf_mtod(mbuf, struct ether_addr *); + vq->multicast += is_multicast_ether_addr(ea); + vq->broadcast += is_broadcast_ether_addr(ea); +} + #define VIRTIO_MBUF_BURST_SZ 64 #define DESC_PER_CACHELINE (RTE_CACHE_LINE_SIZE / sizeof(struct vring_desc)) uint16_t @@ -543,7 +571,9 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) VIRTIO_DUMP_PACKET(rxm, rxm->data_len); rx_pkts[nb_rx++] = rxm; + rxvq->bytes += rx_pkts[nb_rx - 1]->pkt_len; + virtio_update_packet_stats(rxvq, rxm); } rxvq->packets += nb_rx; @@ -706,6 +736,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, rx_pkts[nb_rx]->data_len); rxvq->bytes += rx_pkts[nb_rx]->pkt_len; + virtio_update_packet_stats(rxvq, rx_pkts[nb_rx]); nb_rx++; } @@ -806,6 +837,7 @@ virtio_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) } nb_tx++; txvq->bytes += txm->pkt_len; + virtio_update_packet_stats(txvq, txm); } else { PMD_TX_LOG(ERR, "No free tx descriptors to transmit"); break; diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h index 7789411..9032e6d 100644 --- a/drivers/net/virtio/virtqueue.h +++ b/drivers/net/virtio/virtqueue.h @@ -194,6 +194,10 @@ struct virtqueue { uint64_t packets; uint64_t bytes; uint64_t errors; + uint64_t multicast; + uint64_t broadcast; + /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */ + uint64_t size_bins[8]; struct vq_desc_extra { void *cookie; -- 1.9.1