Commit 0eff2eaa authored by Xuan Zhuo's avatar Xuan Zhuo Committed by Paolo Abeni
Browse files

virtio-net: fix incorrect flags recording in big mode



The purpose of commit 703eec1b ("virtio_net: fixing XDP for fully
checksummed packets handling") is to record the flags in advance, as
their value may be overwritten in the XDP case. However, the flags
recorded under big mode are incorrect, because in big mode, the passed
buf does not point to the rx buffer, but rather to the page of the
submitted buffer. This commit fixes this issue.

For the small mode, the commit c11a49d5 ("virtio_net: Fix mismatched
buf address when unmapping for small packets") fixed it.

Tested-by: default avatarAlyssa Ross <hi@alyssa.is>
Fixes: 703eec1b ("virtio_net: fixing XDP for fully checksummed packets handling")
Signed-off-by: default avatarXuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: default avatarJason Wang <jasowang@redhat.com>
Acked-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Link: https://patch.msgid.link/20251111090828.23186-1-xuanzhuo@linux.alibaba.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent fe82c4f8
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -2631,22 +2631,28 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
		return;
	}

	/* 1. Save the flags early, as the XDP program might overwrite them.
	/* About the flags below:
	 * 1. Save the flags early, as the XDP program might overwrite them.
	 * These flags ensure packets marked as VIRTIO_NET_HDR_F_DATA_VALID
	 * stay valid after XDP processing.
	 * 2. XDP doesn't work with partially checksummed packets (refer to
	 * virtnet_xdp_set()), so packets marked as
	 * VIRTIO_NET_HDR_F_NEEDS_CSUM get dropped during XDP processing.
	 */
	flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;

	if (vi->mergeable_rx_bufs)
	if (vi->mergeable_rx_bufs) {
		flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
		skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit,
					stats);
	else if (vi->big_packets)
	} else if (vi->big_packets) {
		void *p = page_address((struct page *)buf);

		flags = ((struct virtio_net_common_hdr *)p)->hdr.flags;
		skb = receive_big(dev, vi, rq, buf, len, stats);
	else
	} else {
		flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
		skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);
	}

	if (unlikely(!skb))
		return;