Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d9d60fd authored by Toshiaki Makita's avatar Toshiaki Makita Committed by David S. Miller
Browse files

virtio_net: Fix incosistent received bytes counter



When received packets are dropped in virtio_net driver, received packets
counter is incremented but bytes counter is not.
As a result, for instance if we drop all packets by XDP, only received
is counted and bytes stays 0, which looks inconsistent.
IMHO received packets/bytes should be counted if packets are produced by
the hypervisor, like what common NICs on physical machines are doing.
So fix the bytes counter.

Signed-off-by: default avatarToshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 19725496
Loading
Loading
Loading
Loading
+23 −18
Original line number Diff line number Diff line
@@ -586,7 +586,8 @@ static struct sk_buff *receive_small(struct net_device *dev,
				     struct receive_queue *rq,
				     void *buf, void *ctx,
				     unsigned int len,
				     unsigned int *xdp_xmit)
				     unsigned int *xdp_xmit,
				     unsigned int *rbytes)
{
	struct sk_buff *skb;
	struct bpf_prog *xdp_prog;
@@ -601,6 +602,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
	int err;

	len -= vi->hdr_len;
	*rbytes += len;

	rcu_read_lock();
	xdp_prog = rcu_dereference(rq->xdp_prog);
@@ -705,11 +707,13 @@ static struct sk_buff *receive_big(struct net_device *dev,
				   struct virtnet_info *vi,
				   struct receive_queue *rq,
				   void *buf,
				   unsigned int len)
				   unsigned int len,
				   unsigned int *rbytes)
{
	struct page *page = buf;
	struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE);

	*rbytes += len - vi->hdr_len;
	if (unlikely(!skb))
		goto err;

@@ -727,7 +731,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
					 void *buf,
					 void *ctx,
					 unsigned int len,
					 unsigned int *xdp_xmit)
					 unsigned int *xdp_xmit,
					 unsigned int *rbytes)
{
	struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
	u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
@@ -740,6 +745,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
	int err;

	head_skb = NULL;
	*rbytes += len - vi->hdr_len;

	rcu_read_lock();
	xdp_prog = rcu_dereference(rq->xdp_prog);
@@ -877,6 +883,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
			goto err_buf;
		}

		*rbytes += len;
		page = virt_to_head_page(buf);

		truesize = mergeable_ctx_to_truesize(ctx);
@@ -932,6 +939,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
			dev->stats.rx_length_errors++;
			break;
		}
		*rbytes += len;
		page = virt_to_head_page(buf);
		put_page(page);
	}
@@ -942,14 +950,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
	return NULL;
}

static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
			void *buf, unsigned int len, void **ctx,
		       unsigned int *xdp_xmit)
			unsigned int *xdp_xmit, unsigned int *rbytes)
{
	struct net_device *dev = vi->dev;
	struct sk_buff *skb;
	struct virtio_net_hdr_mrg_rxbuf *hdr;
	int ret;

	if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
		pr_debug("%s: short packet %i\n", dev->name, len);
@@ -961,23 +968,22 @@ static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
		} else {
			put_page(virt_to_head_page(buf));
		}
		return 0;
		return;
	}

	if (vi->mergeable_rx_bufs)
		skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit);
		skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit,
					rbytes);
	else if (vi->big_packets)
		skb = receive_big(dev, vi, rq, buf, len);
		skb = receive_big(dev, vi, rq, buf, len, rbytes);
	else
		skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit);
		skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, rbytes);

	if (unlikely(!skb))
		return 0;
		return;

	hdr = skb_vnet_hdr(skb);

	ret = skb->len;

	if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
		skb->ip_summed = CHECKSUM_UNNECESSARY;

@@ -994,12 +1000,11 @@ static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
		 ntohs(skb->protocol), skb->len, skb->pkt_type);

	napi_gro_receive(&rq->napi, skb);
	return ret;
	return;

frame_err:
	dev->stats.rx_frame_errors++;
	dev_kfree_skb(skb);
	return 0;
}

/* Unlike mergeable buffers, all buffers are allocated to the
@@ -1249,13 +1254,13 @@ static int virtnet_receive(struct receive_queue *rq, int budget,

		while (received < budget &&
		       (buf = virtqueue_get_buf_ctx(rq->vq, &len, &ctx))) {
			bytes += receive_buf(vi, rq, buf, len, ctx, xdp_xmit);
			receive_buf(vi, rq, buf, len, ctx, xdp_xmit, &bytes);
			received++;
		}
	} else {
		while (received < budget &&
		       (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
			bytes += receive_buf(vi, rq, buf, len, NULL, xdp_xmit);
			receive_buf(vi, rq, buf, len, NULL, xdp_xmit, &bytes);
			received++;
		}
	}