Blob Blame History Raw
From: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Date: Mon, 23 Jul 2018 23:36:08 +0900
Subject: virtio_net: Add XDP related stats
Patch-mainline: v4.19-rc1
Git-commit: 5b8f3c8d30a6176c6be35c6ac75e22b0a60a3c43
References: bsc#1109837

Add counters below:
* Tx
 - xdp_tx: frames sent by ndo_xdp_xmit or XDP_TX.
 - xdp_tx_drops: dropped frames out of xdp_tx ones.
* Rx
 - xdp_packets: frames went through xdp program.
 - xdp_tx: XDP_TX frames.
 - xdp_redirects: XDP_REDIRECT frames.
 - xdp_drops: any dropped frames out of xdp_packets ones.

Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
 drivers/net/virtio_net.c |   71 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 59 insertions(+), 12 deletions(-)

--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -82,12 +82,18 @@ struct virtnet_sq_stats {
 	struct u64_stats_sync syncp;
 	u64 packets;
 	u64 bytes;
+	u64 xdp_tx;
+	u64 xdp_tx_drops;
 };
 
 struct virtnet_rq_stat_items {
 	u64 packets;
 	u64 bytes;
 	u64 drops;
+	u64 xdp_packets;
+	u64 xdp_tx;
+	u64 xdp_redirects;
+	u64 xdp_drops;
 };
 
 struct virtnet_rq_stats {
@@ -97,20 +103,30 @@ struct virtnet_rq_stats {
 
 struct virtnet_rx_stats {
 	struct virtnet_rq_stat_items rx;
+	struct {
+		unsigned int xdp_tx;
+		unsigned int xdp_tx_drops;
+	} tx;
 };
 
 #define VIRTNET_SQ_STAT(m)	offsetof(struct virtnet_sq_stats, m)
 #define VIRTNET_RQ_STAT(m)	offsetof(struct virtnet_rq_stat_items, m)
 
 static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = {
-	{ "packets",	VIRTNET_SQ_STAT(packets) },
-	{ "bytes",	VIRTNET_SQ_STAT(bytes) },
+	{ "packets",		VIRTNET_SQ_STAT(packets) },
+	{ "bytes",		VIRTNET_SQ_STAT(bytes) },
+	{ "xdp_tx",		VIRTNET_SQ_STAT(xdp_tx) },
+	{ "xdp_tx_drops",	VIRTNET_SQ_STAT(xdp_tx_drops) },
 };
 
 static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
-	{ "packets",	VIRTNET_RQ_STAT(packets) },
-	{ "bytes",	VIRTNET_RQ_STAT(bytes) },
-	{ "drops",	VIRTNET_RQ_STAT(drops) },
+	{ "packets",		VIRTNET_RQ_STAT(packets) },
+	{ "bytes",		VIRTNET_RQ_STAT(bytes) },
+	{ "drops",		VIRTNET_RQ_STAT(drops) },
+	{ "xdp_packets",	VIRTNET_RQ_STAT(xdp_packets) },
+	{ "xdp_tx",		VIRTNET_RQ_STAT(xdp_tx) },
+	{ "xdp_redirects",	VIRTNET_RQ_STAT(xdp_redirects) },
+	{ "xdp_drops",		VIRTNET_RQ_STAT(xdp_drops) },
 };
 
 #define VIRTNET_SQ_STATS_LEN	ARRAY_SIZE(virtnet_sq_stats_desc)
@@ -491,20 +507,26 @@ static int virtnet_xdp_xmit(struct net_d
 	struct send_queue *sq;
 	unsigned int len;
 	int drops = 0;
-	int err;
+	int ret, err;
 	int i;
 
-	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
-		return -EINVAL;
-
 	sq = virtnet_xdp_sq(vi);
 
+	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) {
+		ret = -EINVAL;
+		drops = n;
+		goto out;
+	}
+
 	/* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this
 	 * indicate XDP resources have been successfully allocated.
 	 */
 	xdp_prog = rcu_dereference(rq->xdp_prog);
-	if (!xdp_prog)
-		return -ENXIO;
+	if (!xdp_prog) {
+		ret = -ENXIO;
+		drops = n;
+		goto out;
+	}
 
 	/* Free up any pending old buffers before queueing new ones. */
 	while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL)
@@ -519,11 +541,17 @@ static int virtnet_xdp_xmit(struct net_d
 			drops++;
 		}
 	}
+	ret = n - drops;
 
 	if (flags & XDP_XMIT_FLUSH)
 		virtqueue_kick(sq->vq);
+out:
+	u64_stats_update_begin(&sq->stats.syncp);
+	sq->stats.xdp_tx += n;
+	sq->stats.xdp_tx_drops += drops;
+	u64_stats_update_end(&sq->stats.syncp);
 
-	return n - drops;
+	return ret;
 }
 
 static unsigned int virtnet_get_headroom(struct virtnet_info *vi)
@@ -658,6 +686,7 @@ static struct sk_buff *receive_small(str
 		xdp.rxq = &rq->xdp_rxq;
 		orig_data = xdp.data;
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
+		stats->rx.xdp_packets++;
 
 		switch (act) {
 		case XDP_PASS:
@@ -666,11 +695,14 @@ static struct sk_buff *receive_small(str
 			len = xdp.data_end - xdp.data;
 			break;
 		case XDP_TX:
+			stats->rx.xdp_tx++;
 			xdpf = convert_to_xdp_frame(&xdp);
 			if (unlikely(!xdpf))
 				goto err_xdp;
+			stats->tx.xdp_tx++;
 			err = __virtnet_xdp_tx_xmit(vi, xdpf);
 			if (unlikely(err)) {
+				stats->tx.xdp_tx_drops++;
 				trace_xdp_exception(vi->dev, xdp_prog, act);
 				goto err_xdp;
 			}
@@ -678,6 +710,7 @@ static struct sk_buff *receive_small(str
 			rcu_read_unlock();
 			goto xdp_xmit;
 		case XDP_REDIRECT:
+			stats->rx.xdp_redirects++;
 			err = xdp_do_redirect(dev, &xdp, xdp_prog);
 			if (err)
 				goto err_xdp;
@@ -711,6 +744,7 @@ err:
 
 err_xdp:
 	rcu_read_unlock();
+	stats->rx.xdp_drops++;
 	stats->rx.drops++;
 	put_page(page);
 xdp_xmit:
@@ -808,6 +842,7 @@ static struct sk_buff *receive_mergeable
 		xdp.rxq = &rq->xdp_rxq;
 
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
+		stats->rx.xdp_packets++;
 
 		switch (act) {
 		case XDP_PASS:
@@ -832,11 +867,14 @@ static struct sk_buff *receive_mergeable
 			}
 			break;
 		case XDP_TX:
+			stats->rx.xdp_tx++;
 			xdpf = convert_to_xdp_frame(&xdp);
 			if (unlikely(!xdpf))
 				goto err_xdp;
+			stats->tx.xdp_tx++;
 			err = __virtnet_xdp_tx_xmit(vi, xdpf);
 			if (unlikely(err)) {
+				stats->tx.xdp_tx_drops++;
 				trace_xdp_exception(vi->dev, xdp_prog, act);
 				if (unlikely(xdp_page != page))
 					put_page(xdp_page);
@@ -848,6 +886,7 @@ static struct sk_buff *receive_mergeable
 			rcu_read_unlock();
 			goto xdp_xmit;
 		case XDP_REDIRECT:
+			stats->rx.xdp_redirects++;
 			err = xdp_do_redirect(dev, &xdp, xdp_prog);
 			if (err) {
 				if (unlikely(xdp_page != page))
@@ -943,6 +982,7 @@ static struct sk_buff *receive_mergeable
 
 err_xdp:
 	rcu_read_unlock();
+	stats->rx.xdp_drops++;
 err_skb:
 	put_page(page);
 	while (num_buf-- > 1) {
@@ -1263,6 +1303,7 @@ static int virtnet_receive(struct receiv
 {
 	struct virtnet_info *vi = rq->vq->vdev->priv;
 	struct virtnet_rx_stats stats = {};
+	struct send_queue *sq;
 	unsigned int len;
 	void *buf;
 	int i;
@@ -1298,6 +1339,12 @@ static int virtnet_receive(struct receiv
 	}
 	u64_stats_update_end(&rq->stats.syncp);
 
+	sq = virtnet_xdp_sq(vi);
+	u64_stats_update_begin(&sq->stats.syncp);
+	sq->stats.xdp_tx += stats.tx.xdp_tx;
+	sq->stats.xdp_tx_drops += stats.tx.xdp_tx_drops;
+	u64_stats_update_end(&sq->stats.syncp);
+
 	return stats.rx.packets;
 }