Thread (13 messages) 13 messages, 2 authors, 2025-06-27
STALE355d

[PATCH net 4/4] virtio-net: allow more allocated space for mergeable XDP

From: Bui Quang Minh <hidden>
Date: 2025-06-25 16:10:40
Also in: bpf, lkml, virtualization
Subsystem: networking drivers, the rest, virtio net driver · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, "Michael S. Tsirkin", Jason Wang

When the mergeable receive buffer is prefilled before XDP is set, it
does not reserve the space for XDP_PACKET_HEADROOM and skb_shared_info.
So when XDP is set and this buffer is used to receive frame, we need to
create a new buffer with reserved headroom, tailroom and copy the frame
data over. Currently, the new buffer's size is restricted to PAGE_SIZE
only. If the frame data's length + headroom + tailroom exceeds
PAGE_SIZE, the frame is dropped.

However, it seems like there is no restriction on the total size in XDP.
So we can just increase the size of new buffer to 2 * PAGE_SIZE in that
case and continue to process the frame.

In my opinion, the current drop behavior is fine and expected so this
commit is just an improvement not a bug fix.

Signed-off-by: Bui Quang Minh <redacted>
---
 drivers/net/virtio_net.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 844cb2a78be0..663cec686045 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2277,13 +2277,26 @@ static void *mergeable_xdp_get_buf(struct virtnet_info *vi,
 					      len);
 		if (!xdp_page)
 			return NULL;
+
+		*frame_sz = PAGE_SIZE;
 	} else {
+		unsigned int total_len;
+
 		xdp_room = SKB_DATA_ALIGN(XDP_PACKET_HEADROOM +
 					  sizeof(struct skb_shared_info));
-		if (*len + xdp_room > PAGE_SIZE)
+		total_len = *len + xdp_room;
+
+		/* This must never happen because len cannot exceed PAGE_SIZE */
+		if (unlikely(total_len > 2 * PAGE_SIZE))
 			return NULL;
 
-		xdp_page = alloc_page(GFP_ATOMIC);
+		if (total_len > PAGE_SIZE) {
+			xdp_page = alloc_pages(GFP_ATOMIC, 1);
+			*frame_sz = 2 * PAGE_SIZE;
+		} else {
+			xdp_page = alloc_page(GFP_ATOMIC);
+			*frame_sz = PAGE_SIZE;
+		}
 		if (!xdp_page)
 			return NULL;
 
@@ -2291,8 +2304,6 @@ static void *mergeable_xdp_get_buf(struct virtnet_info *vi,
 		       page_address(*page) + offset, *len);
 	}
 
-	*frame_sz = PAGE_SIZE;
-
 	put_page(*page);
 
 	*page = xdp_page;
-- 
2.43.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help