[PATCH 4.17 323/336] virtio_net: Fix incosistent received bytes counter

From: Greg Kroah-Hartman
Date: Wed Aug 01 2018 - 14:26:00 EST


4.17-stable review patch. If anyone has any objections, please let me know.

------------------

From: Toshiaki Makita <makita.toshiaki@xxxxxxxxxxxxx>

[ Upstream commit ecbc42ca5d665e9238a4cdb595024d2e6cf87f2d ]

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: Toshiaki Makita <makita.toshiaki@xxxxxxxxxxxxx>
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/net/virtio_net.c | 41 +++++++++++++++++++++++------------------
1 file changed, 23 insertions(+), 18 deletions(-)

--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -551,7 +551,8 @@ static struct sk_buff *receive_small(str
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;
@@ -567,6 +568,7 @@ static struct sk_buff *receive_small(str
int err;

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

rcu_read_lock();
xdp_prog = rcu_dereference(rq->xdp_prog);
@@ -666,11 +668,13 @@ static struct sk_buff *receive_big(struc
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;

@@ -688,7 +692,8 @@ static struct sk_buff *receive_mergeable
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);
@@ -702,6 +707,7 @@ static struct sk_buff *receive_mergeable
int err;

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

rcu_read_lock();
xdp_prog = rcu_dereference(rq->xdp_prog);
@@ -831,6 +837,7 @@ static struct sk_buff *receive_mergeable
goto err_buf;
}

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

truesize = mergeable_ctx_to_truesize(ctx);
@@ -886,6 +893,7 @@ err_skb:
dev->stats.rx_length_errors++;
break;
}
+ *rbytes += len;
page = virt_to_head_page(buf);
put_page(page);
}
@@ -896,14 +904,13 @@ xdp_xmit:
return NULL;
}

-static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
- void *buf, unsigned int len, void **ctx,
- unsigned int *xdp_xmit)
+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 *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);
@@ -915,23 +922,22 @@ static int receive_buf(struct virtnet_in
} 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;

@@ -948,12 +954,11 @@ static int receive_buf(struct virtnet_in
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
@@ -1203,13 +1208,13 @@ static int virtnet_receive(struct receiv

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++;
}
}