Skip to content

Commit e7428e9

Browse files
mstsirkindavem330
authored andcommitted
virtio-net: put virtio net header inline with data
For small packets we can simplify xmit processing by linearizing buffers with the header: most packets seem to have enough head room we can use for this purpose. Since existing hypervisors require that header is the first s/g element, we need a feature bit for this. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 10eccb4 commit e7428e9

File tree

2 files changed

+37
-9
lines changed

2 files changed

+37
-9
lines changed

drivers/net/virtio_net.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ struct virtnet_info {
106106
/* Has control virtqueue */
107107
bool has_cvq;
108108

109+
/* Host can handle any s/g split between our header and packet data */
110+
bool any_header_sg;
111+
109112
/* enable config space updates */
110113
bool config_enable;
111114

@@ -669,12 +672,28 @@ static void free_old_xmit_skbs(struct send_queue *sq)
669672

670673
static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
671674
{
672-
struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
675+
struct skb_vnet_hdr *hdr;
673676
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
674677
struct virtnet_info *vi = sq->vq->vdev->priv;
675678
unsigned num_sg;
679+
unsigned hdr_len;
680+
bool can_push;
676681

677682
pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
683+
if (vi->mergeable_rx_bufs)
684+
hdr_len = sizeof hdr->mhdr;
685+
else
686+
hdr_len = sizeof hdr->hdr;
687+
688+
can_push = vi->any_header_sg &&
689+
!((unsigned long)skb->data & (__alignof__(*hdr) - 1)) &&
690+
!skb_header_cloned(skb) && skb_headroom(skb) >= hdr_len;
691+
/* Even if we can, don't push here yet as this would skew
692+
* csum_start offset below. */
693+
if (can_push)
694+
hdr = (struct skb_vnet_hdr *)(skb->data - hdr_len);
695+
else
696+
hdr = skb_vnet_hdr(skb);
678697

679698
if (skb->ip_summed == CHECKSUM_PARTIAL) {
680699
hdr->hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
@@ -703,15 +722,18 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
703722
hdr->hdr.gso_size = hdr->hdr.hdr_len = 0;
704723
}
705724

706-
hdr->mhdr.num_buffers = 0;
707-
708-
/* Encode metadata header at front. */
709725
if (vi->mergeable_rx_bufs)
710-
sg_set_buf(sq->sg, &hdr->mhdr, sizeof hdr->mhdr);
711-
else
712-
sg_set_buf(sq->sg, &hdr->hdr, sizeof hdr->hdr);
726+
hdr->mhdr.num_buffers = 0;
713727

714-
num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
728+
if (can_push) {
729+
__skb_push(skb, hdr_len);
730+
num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len);
731+
/* Pull header back to avoid skew in tx bytes calculations. */
732+
__skb_pull(skb, hdr_len);
733+
} else {
734+
sg_set_buf(sq->sg, hdr, hdr_len);
735+
num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
736+
}
715737
return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC);
716738
}
717739

@@ -1552,6 +1574,9 @@ static int virtnet_probe(struct virtio_device *vdev)
15521574
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
15531575
vi->mergeable_rx_bufs = true;
15541576

1577+
if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT))
1578+
vi->any_header_sg = true;
1579+
15551580
if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
15561581
vi->has_cvq = true;
15571582

@@ -1727,6 +1752,7 @@ static unsigned int features[] = {
17271752
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
17281753
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
17291754
VIRTIO_NET_F_CTRL_MAC_ADDR,
1755+
VIRTIO_F_ANY_LAYOUT,
17301756
};
17311757

17321758
static struct virtio_driver virtio_net_driver = {

include/uapi/linux/virtio_net.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ struct virtio_net_config {
7070
__u16 max_virtqueue_pairs;
7171
} __attribute__((packed));
7272

73-
/* This is the first element of the scatter-gather list. If you don't
73+
/* This header comes first in the scatter-gather list.
74+
* If VIRTIO_F_ANY_LAYOUT is not negotiated, it must
75+
* be the first element of the scatter-gather list. If you don't
7476
* specify GSO or CSUM features, you can simply ignore the header. */
7577
struct virtio_net_hdr {
7678
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset

0 commit comments

Comments
 (0)