Commit ecbc42ca authored by Toshiaki Makita's avatar Toshiaki Makita Committed by David S. Miller

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 9981b4fb
...@@ -586,7 +586,8 @@ static struct sk_buff *receive_small(struct net_device *dev, ...@@ -586,7 +586,8 @@ static struct sk_buff *receive_small(struct net_device *dev,
struct receive_queue *rq, struct receive_queue *rq,
void *buf, void *ctx, void *buf, void *ctx,
unsigned int len, unsigned int len,
unsigned int *xdp_xmit) unsigned int *xdp_xmit,
unsigned int *rbytes)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct bpf_prog *xdp_prog; struct bpf_prog *xdp_prog;
...@@ -601,6 +602,7 @@ static struct sk_buff *receive_small(struct net_device *dev, ...@@ -601,6 +602,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
int err; int err;
len -= vi->hdr_len; len -= vi->hdr_len;
*rbytes += len;
rcu_read_lock(); rcu_read_lock();
xdp_prog = rcu_dereference(rq->xdp_prog); xdp_prog = rcu_dereference(rq->xdp_prog);
...@@ -705,11 +707,13 @@ static struct sk_buff *receive_big(struct net_device *dev, ...@@ -705,11 +707,13 @@ static struct sk_buff *receive_big(struct net_device *dev,
struct virtnet_info *vi, struct virtnet_info *vi,
struct receive_queue *rq, struct receive_queue *rq,
void *buf, void *buf,
unsigned int len) unsigned int len,
unsigned int *rbytes)
{ {
struct page *page = buf; struct page *page = buf;
struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE); struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE);
*rbytes += len - vi->hdr_len;
if (unlikely(!skb)) if (unlikely(!skb))
goto err; goto err;
...@@ -727,7 +731,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, ...@@ -727,7 +731,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
void *buf, void *buf,
void *ctx, void *ctx,
unsigned int len, unsigned int len,
unsigned int *xdp_xmit) unsigned int *xdp_xmit,
unsigned int *rbytes)
{ {
struct virtio_net_hdr_mrg_rxbuf *hdr = buf; struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers); 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, ...@@ -740,6 +745,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
int err; int err;
head_skb = NULL; head_skb = NULL;
*rbytes += len - vi->hdr_len;
rcu_read_lock(); rcu_read_lock();
xdp_prog = rcu_dereference(rq->xdp_prog); xdp_prog = rcu_dereference(rq->xdp_prog);
...@@ -877,6 +883,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, ...@@ -877,6 +883,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
goto err_buf; goto err_buf;
} }
*rbytes += len;
page = virt_to_head_page(buf); page = virt_to_head_page(buf);
truesize = mergeable_ctx_to_truesize(ctx); truesize = mergeable_ctx_to_truesize(ctx);
...@@ -932,6 +939,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, ...@@ -932,6 +939,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
dev->stats.rx_length_errors++; dev->stats.rx_length_errors++;
break; break;
} }
*rbytes += len;
page = virt_to_head_page(buf); page = virt_to_head_page(buf);
put_page(page); put_page(page);
} }
...@@ -942,14 +950,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, ...@@ -942,14 +950,13 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
return NULL; 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, 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 net_device *dev = vi->dev;
struct sk_buff *skb; struct sk_buff *skb;
struct virtio_net_hdr_mrg_rxbuf *hdr; struct virtio_net_hdr_mrg_rxbuf *hdr;
int ret;
if (unlikely(len < vi->hdr_len + ETH_HLEN)) { if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
pr_debug("%s: short packet %i\n", dev->name, len); 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, ...@@ -961,23 +968,22 @@ static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
} else { } else {
put_page(virt_to_head_page(buf)); put_page(virt_to_head_page(buf));
} }
return 0; return;
} }
if (vi->mergeable_rx_bufs) 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) else if (vi->big_packets)
skb = receive_big(dev, vi, rq, buf, len); skb = receive_big(dev, vi, rq, buf, len, rbytes);
else 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)) if (unlikely(!skb))
return 0; return;
hdr = skb_vnet_hdr(skb); hdr = skb_vnet_hdr(skb);
ret = skb->len;
if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID) if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID)
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
...@@ -994,12 +1000,11 @@ static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq, ...@@ -994,12 +1000,11 @@ static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
ntohs(skb->protocol), skb->len, skb->pkt_type); ntohs(skb->protocol), skb->len, skb->pkt_type);
napi_gro_receive(&rq->napi, skb); napi_gro_receive(&rq->napi, skb);
return ret; return;
frame_err: frame_err:
dev->stats.rx_frame_errors++; dev->stats.rx_frame_errors++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0;
} }
/* Unlike mergeable buffers, all buffers are allocated to the /* Unlike mergeable buffers, all buffers are allocated to the
...@@ -1249,13 +1254,13 @@ static int virtnet_receive(struct receive_queue *rq, int budget, ...@@ -1249,13 +1254,13 @@ static int virtnet_receive(struct receive_queue *rq, int budget,
while (received < budget && while (received < budget &&
(buf = virtqueue_get_buf_ctx(rq->vq, &len, &ctx))) { (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++; received++;
} }
} else { } else {
while (received < budget && while (received < budget &&
(buf = virtqueue_get_buf(rq->vq, &len)) != NULL) { (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++; received++;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment