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: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
19725496da
commit
7d9d60fd4a
@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@ err_skb:
|
|||||||
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 @@ xdp_xmit:
|
|||||||
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,
|
|||||||
} 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,
|
|||||||
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,
|
|||||||
|
|
||||||
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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user