Skip to content

Commit 4959aeb

Browse files
GavinLi-NVmstsirkin
authored andcommitted
virtio-net: use mtu size as buffer length for big packets
Currently add_recvbuf_big() allocates MAX_SKB_FRAGS segments for big packets even when GUEST_* offloads are not present on the device. However, if guest GSO is not supported, it would be sufficient to allocate segments to cover just up the MTU size and no further. Allocating the maximum amount of segments results in a large waste of buffer space in the queue, which limits the number of packets that can be buffered and can result in reduced performance. Therefore, if guest GSO is not supported, use the MTU to calculate the optimal amount of segments required. Below is the iperf TCP test results over a Mellanox NIC, using vDPA for 1 VQ, queue size 1024, before and after the change, with the iperf server running over the virtio-net interface. MTU(Bytes)/Bandwidth (Gbit/s) Before After 1500 22.5 22.4 9000 12.8 25.9 And result of queue size 256. MTU(Bytes)/Bandwidth (Gbit/s) Before After 9000 2.15 11.9 With this patch no degradation is observed with multiple below tests and feature bit combinations. Results are summarized below for q depth of 1024. Interface MTU is 1500 if MTU feature is disabled. MTU is set to 9000 in other tests. Features/ Bandwidth (Gbit/s) Before After mtu off 20.1 20.2 mtu/indirect on 17.4 17.3 mtu/indirect/packed on 17.2 17.2 Signed-off-by: Gavin Li <gavinl@nvidia.com> Reviewed-by: Gavi Teitz <gavi@nvidia.com> Reviewed-by: Parav Pandit <parav@nvidia.com> Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Reviewed-by: Si-Wei Liu <si-wei.liu@oracle.com> Message-Id: <20220914144911.56422-3-gavinl@nvidia.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Acked-by: Jason Wang <jasowang@redhat.com>
1 parent 46cd26f commit 4959aeb

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

drivers/net/virtio_net.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ struct virtnet_info {
225225
/* I like... big packets and I cannot lie! */
226226
bool big_packets;
227227

228+
/* number of sg entries allocated for big packets */
229+
unsigned int big_packets_num_skbfrags;
230+
228231
/* Host will merge rx buffers for big packets (shake it! shake it!) */
229232
bool mergeable_rx_bufs;
230233

@@ -1331,10 +1334,10 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
13311334
char *p;
13321335
int i, err, offset;
13331336

1334-
sg_init_table(rq->sg, MAX_SKB_FRAGS + 2);
1337+
sg_init_table(rq->sg, vi->big_packets_num_skbfrags + 2);
13351338

1336-
/* page in rq->sg[MAX_SKB_FRAGS + 1] is list tail */
1337-
for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {
1339+
/* page in rq->sg[vi->big_packets_num_skbfrags + 1] is list tail */
1340+
for (i = vi->big_packets_num_skbfrags + 1; i > 1; --i) {
13381341
first = get_a_page(rq, gfp);
13391342
if (!first) {
13401343
if (list)
@@ -1365,7 +1368,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
13651368

13661369
/* chain first in list head */
13671370
first->private = (unsigned long)list;
1368-
err = virtqueue_add_inbuf(rq->vq, rq->sg, MAX_SKB_FRAGS + 2,
1371+
err = virtqueue_add_inbuf(rq->vq, rq->sg, vi->big_packets_num_skbfrags + 2,
13691372
first, gfp);
13701373
if (err < 0)
13711374
give_pages(rq, first);
@@ -3690,13 +3693,27 @@ static bool virtnet_check_guest_gso(const struct virtnet_info *vi)
36903693
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO);
36913694
}
36923695

3696+
static void virtnet_set_big_packets(struct virtnet_info *vi, const int mtu)
3697+
{
3698+
bool guest_gso = virtnet_check_guest_gso(vi);
3699+
3700+
/* If device can receive ANY guest GSO packets, regardless of mtu,
3701+
* allocate packets of maximum size, otherwise limit it to only
3702+
* mtu size worth only.
3703+
*/
3704+
if (mtu > ETH_DATA_LEN || guest_gso) {
3705+
vi->big_packets = true;
3706+
vi->big_packets_num_skbfrags = guest_gso ? MAX_SKB_FRAGS : DIV_ROUND_UP(mtu, PAGE_SIZE);
3707+
}
3708+
}
3709+
36933710
static int virtnet_probe(struct virtio_device *vdev)
36943711
{
36953712
int i, err = -ENOMEM;
36963713
struct net_device *dev;
36973714
struct virtnet_info *vi;
36983715
u16 max_queue_pairs;
3699-
int mtu;
3716+
int mtu = 0;
37003717

37013718
/* Find if host supports multiqueue/rss virtio_net device */
37023719
max_queue_pairs = 1;
@@ -3784,10 +3801,6 @@ static int virtnet_probe(struct virtio_device *vdev)
37843801
INIT_WORK(&vi->config_work, virtnet_config_changed_work);
37853802
spin_lock_init(&vi->refill_lock);
37863803

3787-
/* If we can receive ANY GSO packets, we must allocate large ones. */
3788-
if (virtnet_check_guest_gso(vi))
3789-
vi->big_packets = true;
3790-
37913804
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
37923805
vi->mergeable_rx_bufs = true;
37933806

@@ -3853,12 +3866,10 @@ static int virtnet_probe(struct virtio_device *vdev)
38533866

38543867
dev->mtu = mtu;
38553868
dev->max_mtu = mtu;
3856-
3857-
/* TODO: size buffers correctly in this case. */
3858-
if (dev->mtu > ETH_DATA_LEN)
3859-
vi->big_packets = true;
38603869
}
38613870

3871+
virtnet_set_big_packets(vi, mtu);
3872+
38623873
if (vi->any_header_sg)
38633874
dev->needed_headroom = vi->hdr_len;
38643875

0 commit comments

Comments
 (0)