git: d3bdfa583044 - main - bhyve: Use a non-blocking read in slirp_recv()

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 07 Jan 2025 14:34:54 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=d3bdfa583044dbfb76ef777939b86bb68baebee7

commit d3bdfa583044dbfb76ef777939b86bb68baebee7
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-01-07 14:33:06 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-01-07 14:33:06 +0000

    bhyve: Use a non-blocking read in slirp_recv()
    
    When using the slirp backend with the e1000 frontend, I otherwise get
    hangs in readv(), caused by the e1000 emulation not checking whether
    bytes are available before trying to read them.  In particular, that
    device model expects the recv callback to return 0 if no bytes are
    available, and with slirp it would end up blocking forever.  The virtio
    device model uses the peek_recvlen to check first, so I didn't notice
    the problem when implementing the slirp backend.
    
    Make the slirp backend more flexible to accommodate e1000.
    
    MFC after:      1 month
    Differential Revision:  https://reviews.freebsd.org/D48164
---
 usr.sbin/bhyve/net_backend_slirp.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/usr.sbin/bhyve/net_backend_slirp.c b/usr.sbin/bhyve/net_backend_slirp.c
index 5ae33801387c..d070d2cdfdb6 100644
--- a/usr.sbin/bhyve/net_backend_slirp.c
+++ b/usr.sbin/bhyve/net_backend_slirp.c
@@ -609,11 +609,22 @@ static ssize_t
 slirp_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
 {
 	struct slirp_priv *priv = NET_BE_PRIV(be);
+	struct msghdr hdr;
 	ssize_t n;
 
-	n = readv(priv->pipe[0], iov, iovcnt);
-	if (n < 0)
+	hdr.msg_name = NULL;
+	hdr.msg_namelen = 0;
+	hdr.msg_iov = __DECONST(struct iovec *, iov);
+	hdr.msg_iovlen = iovcnt;
+	hdr.msg_control = NULL;
+	hdr.msg_controllen = 0;
+	hdr.msg_flags = 0;
+	n = recvmsg(priv->pipe[0], &hdr, MSG_DONTWAIT);
+	if (n < 0) {
+		if (errno == EWOULDBLOCK)
+			return (0);
 		return (-1);
+	}
 	assert(n <= SLIRP_MTU);
 	return (n);
 }