@@ -1360,6 +1360,10 @@ static struct sk_buff *receive_small_xdp(struct net_device *dev,
13601360 if (unlikely (hdr -> hdr .gso_type ))
13611361 goto err_xdp ;
13621362
1363+ /* Partially checksummed packets must be dropped. */
1364+ if (unlikely (hdr -> hdr .flags & VIRTIO_NET_HDR_F_NEEDS_CSUM ))
1365+ goto err_xdp ;
1366+
13631367 buflen = SKB_DATA_ALIGN (GOOD_PACKET_LEN + headroom ) +
13641368 SKB_DATA_ALIGN (sizeof (struct skb_shared_info ));
13651369
@@ -1677,6 +1681,10 @@ static void *mergeable_xdp_get_buf(struct virtnet_info *vi,
16771681 if (unlikely (hdr -> hdr .gso_type ))
16781682 return NULL ;
16791683
1684+ /* Partially checksummed packets must be dropped. */
1685+ if (unlikely (hdr -> hdr .flags & VIRTIO_NET_HDR_F_NEEDS_CSUM ))
1686+ return NULL ;
1687+
16801688 /* Now XDP core assumes frag size is PAGE_SIZE, but buffers
16811689 * with headroom may add hole in truesize, which
16821690 * make their length exceed PAGE_SIZE. So we disabled the
@@ -1943,6 +1951,7 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
19431951 struct net_device * dev = vi -> dev ;
19441952 struct sk_buff * skb ;
19451953 struct virtio_net_common_hdr * hdr ;
1954+ u8 flags ;
19461955
19471956 if (unlikely (len < vi -> hdr_len + ETH_HLEN )) {
19481957 pr_debug ("%s: short packet %i\n" , dev -> name , len );
@@ -1951,6 +1960,15 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
19511960 return ;
19521961 }
19531962
1963+ /* 1. Save the flags early, as the XDP program might overwrite them.
1964+ * These flags ensure packets marked as VIRTIO_NET_HDR_F_DATA_VALID
1965+ * stay valid after XDP processing.
1966+ * 2. XDP doesn't work with partially checksummed packets (refer to
1967+ * virtnet_xdp_set()), so packets marked as
1968+ * VIRTIO_NET_HDR_F_NEEDS_CSUM get dropped during XDP processing.
1969+ */
1970+ flags = ((struct virtio_net_common_hdr * )buf )-> hdr .flags ;
1971+
19541972 if (vi -> mergeable_rx_bufs )
19551973 skb = receive_mergeable (dev , vi , rq , buf , ctx , len , xdp_xmit ,
19561974 stats );
@@ -1966,7 +1984,7 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
19661984 if (dev -> features & NETIF_F_RXHASH && vi -> has_rss_hash_report )
19671985 virtio_skb_set_hash (& hdr -> hash_v1_hdr , skb );
19681986
1969- if (hdr -> hdr . flags & VIRTIO_NET_HDR_F_DATA_VALID )
1987+ if (flags & VIRTIO_NET_HDR_F_DATA_VALID )
19701988 skb -> ip_summed = CHECKSUM_UNNECESSARY ;
19711989
19721990 if (virtio_net_hdr_to_skb (skb , & hdr -> hdr ,
@@ -5666,8 +5684,16 @@ static int virtnet_probe(struct virtio_device *vdev)
56665684 dev -> features |= dev -> hw_features & NETIF_F_ALL_TSO ;
56675685 /* (!csum && gso) case will be fixed by register_netdev() */
56685686 }
5669- if (virtio_has_feature (vdev , VIRTIO_NET_F_GUEST_CSUM ))
5670- dev -> features |= NETIF_F_RXCSUM ;
5687+
5688+ /* 1. With VIRTIO_NET_F_GUEST_CSUM negotiation, the driver doesn't
5689+ * need to calculate checksums for partially checksummed packets,
5690+ * as they're considered valid by the upper layer.
5691+ * 2. Without VIRTIO_NET_F_GUEST_CSUM negotiation, the driver only
5692+ * receives fully checksummed packets. The device may assist in
5693+ * validating these packets' checksums, so the driver won't have to.
5694+ */
5695+ dev -> features |= NETIF_F_RXCSUM ;
5696+
56715697 if (virtio_has_feature (vdev , VIRTIO_NET_F_GUEST_TSO4 ) ||
56725698 virtio_has_feature (vdev , VIRTIO_NET_F_GUEST_TSO6 ))
56735699 dev -> features |= NETIF_F_GRO_HW ;
0 commit comments