git: cbc6f7e941e4 - main - bhyve: add UNIX domain socket support to rfb
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 08 Jan 2026 16:06:07 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=cbc6f7e941e42639a0314cd121b06493cce8e0e6
commit cbc6f7e941e42639a0314cd121b06493cce8e0e6
Author: Quentin Thébault <quentin.thebault@defenso.fr>
AuthorDate: 2025-11-18 06:44:05 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-01-08 15:24:52 +0000
bhyve: add UNIX domain socket support to rfb
This commit adds support for a UNIX domain socket to bhyve's remote
framebuffer. It enables the use of the graphical console when the bhyve instance
is running in a jail with no networking, for instance. A VNC client running on
the host can then connect to the UNIX domain socket through the filesystem.
Signed-off-by: Quentin Thébault <quentin.thebault@defenso.fr>
Sponsored by: Defenso
Reviewed by: kevans, markj
MFC after: 2 weeks
Differential Revision: https://reviews.freebsd.org/D53814
---
usr.sbin/bhyve/bhyve.8 | 12 +++++++----
usr.sbin/bhyve/bhyve_config.5 | 7 ++++++-
usr.sbin/bhyve/pci_fbuf.c | 22 ++++++++++++++++++-
usr.sbin/bhyve/rfb.c | 49 +++++++++++++++++++++++++++++++------------
usr.sbin/bhyve/rfb.h | 4 +++-
5 files changed, 74 insertions(+), 20 deletions(-)
diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index d3b067509ced..496539f30885 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -891,7 +891,7 @@ to guest by VirtIO Input Interface.
.Bl -bullet
.Sm off
.It
-.Op Cm rfb= Ar ip-and-port
+.Op Cm rfb= Ar address
.Op Cm ,w= Ar width
.Op Cm ,h= Ar height
.Op Cm ,vga= Ar vgaconf
@@ -902,9 +902,9 @@ to guest by VirtIO Input Interface.
.Pp
Configuration options are defined as follows:
.Bl -tag -width 10n
-.It Cm rfb= Ns Ar ip-and-port Pq or Cm tcp= Ns Ar ip-and-port
-An IP address and a port VNC should listen on.
-There are two formats:
+.It Cm rfb= Ns Ar address Pq or Cm tcp= Ns Ar address
+A UNIX domain socket or IP address and a port VNC should listen on.
+There are three possible formats:
.Pp
.Bl -bullet -compact
.It
@@ -916,6 +916,10 @@ There are two formats:
.Sm off
.Cm \&[ Ar IPv6%zone Cm \&] Cm \&: Ar port
.Sm on
+.It
+.Sm off
+.Cm unix: Ar my/unix.sock
+.Sm on
.El
.Pp
The default is to listen on localhost IPv4 address and default VNC port 5900.
diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5
index 4ead94690d91..429ce3e38138 100644
--- a/usr.sbin/bhyve/bhyve_config.5
+++ b/usr.sbin/bhyve/bhyve_config.5
@@ -523,7 +523,7 @@ the device name.
If specified, it must be a unicast MAC address.
.El
.Ss Frame Buffer Settings
-.Bl -column "password" "[IP:]port" "127.0.0.1:5900"
+.Bl -column "password" "unix:my/unix.sock" "127.0.0.1:5900"
.It Sy Name Ta Sy Format Ta Sy Default Ta Sy Description
.It Va wait Ta bool Ta false Ta
Wait for a remote connection before starting the VM.
@@ -535,6 +535,11 @@ support scoped identifiers as described in
.Xr getaddrinfo 3 .
A bare port number may be given in which case the IPv4
localhost address is used.
+.It Va rfb Ta
+.Sm off
+.Cm unix: Ar my/unix.sock Ta Ta
+.Sm on
+Alternatively, provide a path to a UNIX domain socket.
.It Va vga Ta string Ta io Ta
VGA configuration.
More details are provided in
diff --git a/usr.sbin/bhyve/pci_fbuf.c b/usr.sbin/bhyve/pci_fbuf.c
index 1e3ec77c15b0..560c2bc839d6 100644
--- a/usr.sbin/bhyve/pci_fbuf.c
+++ b/usr.sbin/bhyve/pci_fbuf.c
@@ -28,6 +28,8 @@
#include <sys/types.h>
#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <dev/vmm/vmm_mem.h>
#include <machine/vmm.h>
@@ -94,6 +96,7 @@ struct pci_fbuf_softc {
} __packed memregs;
/* rfb server */
+ sa_family_t rfb_family;
char *rfb_host;
char *rfb_password;
int rfb_port;
@@ -252,11 +255,13 @@ pci_fbuf_parse_config(struct pci_fbuf_softc *sc, nvlist_t *nvl)
value = get_config_value_node(nvl, "tcp");
if (value != NULL) {
/*
+ * UNIX -- unix:path/to/socket.sock
* IPv4 -- host-ip:port
* IPv6 -- [host-ip%zone]:port
* XXX for now port is mandatory for IPv4.
*/
if (value[0] == '[') {
+ sc->rfb_family = AF_INET6;
cp = strchr(value + 1, ']');
if (cp == NULL || cp == value + 1) {
EPRINTLN("fbuf: Invalid IPv6 address: \"%s\"",
@@ -279,7 +284,21 @@ pci_fbuf_parse_config(struct pci_fbuf_softc *sc, nvlist_t *nvl)
value);
return (-1);
}
+ } else if (strncmp("unix:", value, 5) == 0) {
+ if (strlen(value + 5) > SUNPATHLEN) {
+ EPRINTLN(
+ "fbuf: UNIX socket path too long: \"%s\"",
+ value + 5);
+ return (-1);
+ } else if (*(value + 5) == '\0') {
+ EPRINTLN("fbuf: UNIX socket path is empty");
+ return (-1);
+ } else {
+ sc->rfb_family = AF_UNIX;
+ sc->rfb_host = strdup(value + 5);
+ }
} else {
+ sc->rfb_family = AF_UNSPEC;
cp = strchr(value, ':');
if (cp == NULL) {
sc->rfb_port = atoi(value);
@@ -433,7 +452,8 @@ pci_fbuf_init(struct pci_devinst *pi, nvlist_t *nvl)
memset((void *)sc->fb_base, 0, FB_SIZE);
- error = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait, sc->rfb_password);
+ error = rfb_init(sc->rfb_family, sc->rfb_host, sc->rfb_port,
+ sc->rfb_wait, sc->rfb_password);
done:
if (error)
free(sc);
diff --git a/usr.sbin/bhyve/rfb.c b/usr.sbin/bhyve/rfb.c
index 716e191e2fc0..aeaf8d1c0639 100644
--- a/usr.sbin/bhyve/rfb.c
+++ b/usr.sbin/bhyve/rfb.c
@@ -35,6 +35,7 @@
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
+#include <sys/un.h>
#include <arpa/inet.h>
#include <stdatomic.h>
#include <machine/cpufunc.h>
@@ -1254,13 +1255,15 @@ sse42_supported(void)
}
int
-rfb_init(const char *hostname, int port, int wait, const char *password)
+rfb_init(sa_family_t family, const char *hostname, int port, int wait,
+ const char *password)
{
int e;
char servname[6];
struct rfb_softc *rc;
struct addrinfo *ai = NULL;
struct addrinfo hints;
+ struct sockaddr_un sun;
int on = 1;
int cnt;
#ifndef WITHOUT_CAPSICUM
@@ -1301,25 +1304,42 @@ rfb_init(const char *hostname, int port, int wait, const char *password)
hostname = "[::1]";
#endif
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
-
- if ((e = getaddrinfo(hostname, servname, &hints, &ai)) != 0) {
- EPRINTLN("getaddrinfo: %s", gai_strerror(e));
- goto error;
+ if (family == AF_UNIX) {
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ if (strlcpy(sun.sun_path, hostname, sizeof(sun.sun_path)) >=
+ sizeof(sun.sun_path)) {
+ EPRINTLN("rfb: socket path too long");
+ goto error;
+ }
+ rc->sfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ } else {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = family;
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
+
+ if ((e = getaddrinfo(hostname, servname, &hints, &ai)) != 0) {
+ EPRINTLN("getaddrinfo: %s", gai_strerror(e));
+ goto error;
+ }
+ rc->sfd = socket(ai->ai_family, ai->ai_socktype, 0);
}
- rc->sfd = socket(ai->ai_family, ai->ai_socktype, 0);
if (rc->sfd < 0) {
perror("socket");
goto error;
}
+ /* No effect for UNIX domain sockets. */
setsockopt(rc->sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- if (bind(rc->sfd, ai->ai_addr, ai->ai_addrlen) < 0) {
+ if (family == AF_UNIX) {
+ unlink(hostname);
+ e = bind(rc->sfd, (struct sockaddr *)&sun, SUN_LEN(&sun));
+ } else
+ e = bind(rc->sfd, ai->ai_addr, ai->ai_addrlen);
+ if (e < 0) {
perror("bind");
goto error;
}
@@ -1355,14 +1375,17 @@ rfb_init(const char *hostname, int port, int wait, const char *password)
DPRINTF(("rfb client connected"));
}
- freeaddrinfo(ai);
+ if (family != AF_UNIX)
+ freeaddrinfo(ai);
return (0);
error:
if (rc->pixfmt_mtx)
pthread_mutex_destroy(&rc->pixfmt_mtx);
- if (ai != NULL)
+ if (ai != NULL) {
+ assert(family != AF_UNIX);
freeaddrinfo(ai);
+ }
if (rc->sfd != -1)
close(rc->sfd);
free(rc->crc);
diff --git a/usr.sbin/bhyve/rfb.h b/usr.sbin/bhyve/rfb.h
index 347ced083a22..c11d40f031af 100644
--- a/usr.sbin/bhyve/rfb.h
+++ b/usr.sbin/bhyve/rfb.h
@@ -29,9 +29,11 @@
#ifndef _RFB_H_
#define _RFB_H_
+#include <sys/socket.h>
+
#define RFB_PORT 5900
-int rfb_init(const char *hostname, int port, int wait,
+int rfb_init(sa_family_t family, const char *hostname, int port, int wait,
const char *password);
#endif /* _RFB_H_ */