Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

virtio_net: introduce VIRTIO_NET_HDR_F_DATA_VALID

There's no need for the guest to validate the checksum if it have been
validated by host nics. So this patch introduces a new flag -
VIRTIO_NET_HDR_F_DATA_VALID which is used to bypass the checksum
examing in guest. The backend (tap/macvtap) may set this flag when
met skbs with CHECKSUM_UNNECESSARY to save cpu utilization.

No feature negotiation is needed as old driver just ignore this flag.

Iperf shows 12%-30% performance improvement for UDP traffic. For TCP,
when gro is on no difference as it produces skb with partial
checksum. But when gro is disabled, 20% or even higher improvement
could be measured by netperf.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jason Wang and committed by
David S. Miller
10a8d94a 40d15cd0

+9
+2
drivers/net/macvtap.c
··· 508 508 vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; 509 509 vnet_hdr->csum_start = skb_checksum_start_offset(skb); 510 510 vnet_hdr->csum_offset = skb->csum_offset; 511 + } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { 512 + vnet_hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID; 511 513 } /* else everything is zero */ 512 514 513 515 return 0;
+2
drivers/net/tun.c
··· 788 788 gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; 789 789 gso.csum_start = skb_checksum_start_offset(skb); 790 790 gso.csum_offset = skb->csum_offset; 791 + } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { 792 + gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; 791 793 } /* else everything is zero */ 792 794 793 795 if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
+2
drivers/net/virtio_net.c
··· 274 274 hdr->hdr.csum_start, 275 275 hdr->hdr.csum_offset)) 276 276 goto frame_err; 277 + } else if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID) { 278 + skb->ip_summed = CHECKSUM_UNNECESSARY; 277 279 } 278 280 279 281 skb->protocol = eth_type_trans(skb, dev);
+1
include/linux/virtio_net.h
··· 63 63 * specify GSO or CSUM features, you can simply ignore the header. */ 64 64 struct virtio_net_hdr { 65 65 #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset 66 + #define VIRTIO_NET_HDR_F_DATA_VALID 2 // Csum is valid 66 67 __u8 flags; 67 68 #define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame 68 69 #define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO)
+2
net/packet/af_packet.c
··· 1685 1685 vnet_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; 1686 1686 vnet_hdr.csum_start = skb_checksum_start_offset(skb); 1687 1687 vnet_hdr.csum_offset = skb->csum_offset; 1688 + } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { 1689 + vnet_hdr.flags = VIRTIO_NET_HDR_F_DATA_VALID; 1688 1690 } /* else everything is zero */ 1689 1691 1690 1692 err = memcpy_toiovec(msg->msg_iov, (void *)&vnet_hdr,