git: 90b9a77ebeb8 - main - bhyve: support MTU configuration for SLIRP net backend

From: Roman Bogorodskiy <novel_at_FreeBSD.org>
Date: Thu, 08 Jan 2026 17:09:32 UTC
The branch main has been updated by novel:

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

commit 90b9a77ebeb8019fbd22b3cf992370cd9b0004a2
Author:     Roman Bogorodskiy <novel@FreeBSD.org>
AuthorDate: 2025-12-08 17:37:09 +0000
Commit:     Roman Bogorodskiy <novel@FreeBSD.org>
CommitDate: 2026-01-08 17:01:13 +0000

    bhyve: support MTU configuration for SLIRP net backend
    
    Support configuring MTU for the SLIRP net backend, for example:
    
      -s 1:0,virtio-net,slirp,mtu=2048,open
    
    Update the manual page accordingly.  While here, also document
    MAC address configuration.
    
    Reviewed by:    markj
    Approved by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 month
    Differential Revision:  https://reviews.freebsd.org/D54133
---
 usr.sbin/bhyve/bhyve.8              |  4 +++-
 usr.sbin/bhyve/net_backend_slirp.c  | 35 ++++++++++++++++++++++++++++++-----
 usr.sbin/bhyve/slirp/slirp-helper.c | 22 ++++++++++++++--------
 3 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index 496539f30885..4c73a119b1ed 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd December 26, 2025
+.Dd January 5, 2026
 .Dt BHYVE 8
 .Os
 .Sh NAME
@@ -542,6 +542,8 @@ considered unconnected.
 .Cm slirp
 .Op Cm \&,open
 .Op Cm \&,hostfwd= Ar proto : Ar hostaddr : Ar hostport - Ar guestaddr : Ar guestport
+.Op Cm \&,mac= Ar xx:xx:xx:xx:xx:xx
+.Op Cm \&,mtu= Ar N
 .Xc
 .El
 .Sm on
diff --git a/usr.sbin/bhyve/net_backend_slirp.c b/usr.sbin/bhyve/net_backend_slirp.c
index f2b483c5e314..6084ca31966d 100644
--- a/usr.sbin/bhyve/net_backend_slirp.c
+++ b/usr.sbin/bhyve/net_backend_slirp.c
@@ -62,15 +62,18 @@
 #include "config.h"
 #include "debug.h"
 #include "mevent.h"
+#include "net_utils.h"
 #include "net_backends.h"
 #include "net_backends_priv.h"
 
-#define	SLIRP_MTU	2048
+#define	DEFAULT_MTU	2048
 
 struct slirp_priv {
 	int s;
 	pid_t helper;
 	struct mevent *mevp;
+	size_t mtu;
+	uint8_t *buf;
 };
 
 extern char **environ;
@@ -86,6 +89,8 @@ slirp_init(struct net_backend *be, const char *devname __unused,
 	const char **argv;
 	char sockname[32];
 	int error, s[2];
+	const char *mtu_value;
+	size_t mtu;
 
 	if (socketpair(PF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK, 0, s) != 0) {
 		EPRINTLN("socketpair");
@@ -124,6 +129,25 @@ slirp_init(struct net_backend *be, const char *devname __unused,
 		EPRINTLN("nvlist_clone");
 		goto err;
 	}
+
+	mtu_value = get_config_value_node(config, "mtu");
+	if (mtu_value != NULL) {
+		if (net_parsemtu(mtu_value, &mtu)) {
+		    	EPRINTLN("Could not parse MTU");
+		    	goto err;
+		}
+	} else {
+		mtu = DEFAULT_MTU;
+	}
+	nvlist_add_number(config, "mtui", mtu);
+
+	priv->mtu = mtu;
+	priv->buf = malloc(mtu);
+	if (priv->buf == NULL) {
+		EPRINTLN("Could not allocate buffer");
+		goto err;
+	}
+
 	nvlist_add_string(config, "vmname", get_config_value("name"));
 	error = nvlist_send(s[0], config);
 	nvlist_destroy(config);
@@ -146,6 +170,7 @@ slirp_init(struct net_backend *be, const char *devname __unused,
 	return (0);
 
 err:
+	free(priv->buf);
 	(void)close(s[0]);
 	(void)close(s[1]);
 	return (-1);
@@ -168,6 +193,8 @@ slirp_cleanup(struct net_backend *be)
 {
 	struct slirp_priv *priv = NET_BE_PRIV(be);
 
+	free(priv->buf);
+
 	if (priv->helper > 0) {
 		int status;
 
@@ -184,17 +211,15 @@ static ssize_t
 slirp_peek_recvlen(struct net_backend *be)
 {
 	struct slirp_priv *priv = NET_BE_PRIV(be);
-	uint8_t buf[SLIRP_MTU];
 	ssize_t n;
 
 	/*
 	 * Copying into the buffer is totally unnecessary, but we don't
 	 * implement MSG_TRUNC for SEQPACKET sockets.
 	 */
-	n = recv(priv->s, buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT);
+	n = recv(priv->s, priv->buf, priv->mtu, MSG_PEEK | MSG_DONTWAIT);
 	if (n < 0)
 		return (errno == EWOULDBLOCK ? 0 : -1);
-	assert((size_t)n <= SLIRP_MTU);
 	return (n);
 }
 
@@ -218,7 +243,7 @@ slirp_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
 			return (0);
 		return (-1);
 	}
-	assert(n <= SLIRP_MTU);
+	assert((size_t)n <= priv->mtu);
 	return (n);
 }
 
diff --git a/usr.sbin/bhyve/slirp/slirp-helper.c b/usr.sbin/bhyve/slirp/slirp-helper.c
index 9fb9784662fe..36192c590eb1 100644
--- a/usr.sbin/bhyve/slirp/slirp-helper.c
+++ b/usr.sbin/bhyve/slirp/slirp-helper.c
@@ -38,8 +38,6 @@
 #include "config.h"
 #include "libslirp.h"
 
-#define	SLIRP_MTU	2048
-
 struct slirp_priv {
 	Slirp *slirp;		/* libslirp handle */
 	int sock;		/* data and control socket */
@@ -47,6 +45,8 @@ struct slirp_priv {
 	struct pollfd *pollfds;
 	size_t npollfds;
 	size_t lastpollfd;
+	size_t mtu;
+	uint8_t *buf;
 };
 
 typedef int (*slirp_add_hostxfwd_p_t)(Slirp *,
@@ -104,7 +104,7 @@ slirp_cb_send_packet(const void *buf, size_t len, void *param)
 
 	priv = param;
 
-	assert(len <= SLIRP_MTU);
+	assert(len <= priv->mtu);
 	n = send(priv->sock, buf, len, MSG_EOR);
 	if (n < 0) {
 		warn("slirp_cb_send_packet: send");
@@ -289,16 +289,14 @@ slirp_pollfd_loop(struct slirp_priv *priv)
 			ssize_t n;
 
 			do {
-				uint8_t buf[SLIRP_MTU];
-
-				n = recv(priv->sock, buf, sizeof(buf),
+				n = recv(priv->sock, priv->buf, priv->mtu,
 				    MSG_DONTWAIT);
 				if (n < 0) {
 					if (errno == EWOULDBLOCK)
 						break;
 					err(1, "recv");
 				}
-				slirp_input_p(priv->slirp, buf, (int)n);
+				slirp_input_p(priv->slirp, priv->buf, (int)n);
 			} while (n >= 0);
 		}
 	}
@@ -464,6 +462,7 @@ main(int argc, char **argv)
 	const char *hostfwd, *vmname;
 	int ch, fd, sd;
 	bool restricted;
+	size_t mtu;
 
 	sd = -1;
 	while ((ch = getopt(argc, argv, "S:")) != -1) {
@@ -514,6 +513,13 @@ main(int argc, char **argv)
 	config = nvlist_recv(sd, 0);
 	if (config == NULL)
 		err(1, "nvlist_recv");
+
+	mtu = nvlist_get_number(config, "mtui");
+	priv.mtu = mtu;
+	priv.buf = malloc(mtu);
+	if (priv.buf == NULL)
+		err(1, "malloc");
+
 	vmname = get_config_value_node(config, "vmname");
 	if (vmname != NULL)
 		setproctitle("%s", vmname);
@@ -521,7 +527,7 @@ main(int argc, char **argv)
 
 	slirpconfig = (SlirpConfig){
 		.version = 4,
-		.if_mtu = SLIRP_MTU,
+		.if_mtu = mtu,
 		.restricted = restricted,
 		.in_enabled = true,
 		.vnetwork.s_addr = htonl(0x0a000200),	/* 10.0.2.0/24 */