On 2026-04-16 11:57, Laurent Vivier wrote:
udp_vu_sock_recv() currently mixes two concerns: receiving data from the socket and managing virtqueue buffers (collecting, rewinding, releasing). This makes the function harder to reason about and couples socket I/O with virtqueue state.
Move all virtqueue operations, vu_collect(), vu_init_elem(), vu_queue_rewind(), vu_set_vnethdr(), and the queue-readiness check, into udp_vu_sock_to_tap(), which is the only caller. This turns udp_vu_sock_recv() into a pure socket receive function that simply reads into the provided iov array and adjusts its length.
Signed-off-by: Laurent Vivier
Reviewed-by: David Gibson
Reviewed-by: Jon Maloy
--- udp_vu.c | 98 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 48 deletions(-)
diff --git a/udp_vu.c b/udp_vu.c index f8629af58ab5..bd9fd5abb971 100644 --- a/udp_vu.c [...] + + if (!vu_queue_enabled(vq) || !vu_queue_started(vq)) { + struct msghdr msg = { 0 }; + + debug("Got UDP packet, but RX virtqueue not usable yet"); + + for (i = 0; i < n; i++) { + if (recvmsg(s, &msg, MSG_DONTWAIT) < 0) + debug_perror("Failed to discard datagram"); + } + + return; + } + for (i = 0; i < n; i++) { + unsigned elem_cnt, elem_used;
unsigned int is standard in our code, I think. /jon
+ size_t iov_cnt; ssize_t dlen; - int iov_used;
- iov_used = udp_vu_sock_recv(c, vq, s, v6, &dlen); - if (iov_used < 0) + elem_cnt = vu_collect(vdev, vq, elem, ARRAY_SIZE(elem), + iov_vu, ARRAY_SIZE(iov_vu), &iov_cnt, + IP_MAX_MTU + ETH_HLEN + VNET_HLEN, NULL); + if (elem_cnt == 0) + break; + + assert((size_t)elem_cnt == iov_cnt); /* one iovec per element */ + + dlen = udp_vu_sock_recv(s, v6, &iov_cnt); + if (dlen < 0) { + vu_queue_rewind(vq, iov_cnt); break; + } + + elem_used = iov_cnt; /* one iovec per element */ + + /* release unused buffers */ + vu_queue_rewind(vq, elem_cnt - elem_used);
- if (iov_used > 0) { + if (iov_cnt > 0) { udp_vu_prepare(c, toside, dlen); if (*c->pcap) { - udp_vu_csum(toside, iov_used); - pcap_iov(iov_vu, iov_used, VNET_HLEN); + udp_vu_csum(toside, iov_cnt); + pcap_iov(iov_vu, iov_cnt, VNET_HLEN); } - vu_flush(vdev, vq, elem, iov_used); + vu_flush(vdev, vq, elem, iov_cnt); vu_queue_notify(vdev, vq); } }