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

virtio_net: fixing XDP for fully checksummed packets handling

The XDP program can't correctly handle partially checksummed
packets, but works fine with fully checksummed packets. If the
device has already validated fully checksummed packets, then
the driver doesn't need to re-validate them, saving CPU resources.

Additionally, the driver does not drop all partially checksummed
packets when VIRTIO_NET_F_GUEST_CSUM is not negotiated. This is
not a bug, as the driver has always done this.

Fixes: 436c9453a1ac ("virtio-net: keep vnet header zeroed after processing XDP")
Signed-off-by: Heng Qi <hengqi@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Heng Qi and committed by
David S. Miller
703eec1b 604141c0

+19 -1
+19 -1
drivers/net/virtio_net.c
··· 1360 1360 if (unlikely(hdr->hdr.gso_type)) 1361 1361 goto err_xdp; 1362 1362 1363 + /* Partially checksummed packets must be dropped. */ 1364 + if (unlikely(hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) 1365 + goto err_xdp; 1366 + 1363 1367 buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + 1364 1368 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 1365 1369 ··· 1681 1677 if (unlikely(hdr->hdr.gso_type)) 1682 1678 return NULL; 1683 1679 1680 + /* Partially checksummed packets must be dropped. */ 1681 + if (unlikely(hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) 1682 + return NULL; 1683 + 1684 1684 /* Now XDP core assumes frag size is PAGE_SIZE, but buffers 1685 1685 * with headroom may add hole in truesize, which 1686 1686 * make their length exceed PAGE_SIZE. So we disabled the ··· 1951 1943 struct net_device *dev = vi->dev; 1952 1944 struct sk_buff *skb; 1953 1945 struct virtio_net_common_hdr *hdr; 1946 + u8 flags; 1954 1947 1955 1948 if (unlikely(len < vi->hdr_len + ETH_HLEN)) { 1956 1949 pr_debug("%s: short packet %i\n", dev->name, len); ··· 1959 1950 virtnet_rq_free_buf(vi, rq, buf); 1960 1951 return; 1961 1952 } 1953 + 1954 + /* 1. Save the flags early, as the XDP program might overwrite them. 1955 + * These flags ensure packets marked as VIRTIO_NET_HDR_F_DATA_VALID 1956 + * stay valid after XDP processing. 1957 + * 2. XDP doesn't work with partially checksummed packets (refer to 1958 + * virtnet_xdp_set()), so packets marked as 1959 + * VIRTIO_NET_HDR_F_NEEDS_CSUM get dropped during XDP processing. 1960 + */ 1961 + flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags; 1962 1962 1963 1963 if (vi->mergeable_rx_bufs) 1964 1964 skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit, ··· 1984 1966 if (dev->features & NETIF_F_RXHASH && vi->has_rss_hash_report) 1985 1967 virtio_skb_set_hash(&hdr->hash_v1_hdr, skb); 1986 1968 1987 - if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID) 1969 + if (flags & VIRTIO_NET_HDR_F_DATA_VALID) 1988 1970 skb->ip_summed = CHECKSUM_UNNECESSARY; 1989 1971 1990 1972 if (virtio_net_hdr_to_skb(skb, &hdr->hdr,