Page MenuHomeFreeBSD

D43514.id135322.diff
No OneTemporary

D43514.id135322.diff

diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -573,6 +573,9 @@
process.
.It Ar /dev/xxx
Use the host TTY device for serial port I/O.
+.It Ar tcp:ip:port
+Use the tcp server for serial port I/O.
+It will start a tcp server and wait for connection.
.El
.Pp
TPM device backends:
@@ -1065,7 +1068,7 @@
.Ed
.Pp
Run a UEFI virtual machine with a display resolution of 800 by 600 pixels
-that can be accessed via VNC at: 0.0.0.0:5900.
+that can be accessed via VNC at: 0.0.0.0:5900 or via raw tcp at: 0.0.0.0:1234
.Bd -literal -offset indent
bhyve -c 2 -m 4G -w -H \\
-s 0,hostbridge \\
@@ -1074,13 +1077,13 @@
-s 5,virtio-net,tap0 \\
-s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait \\
-s 30,xhci,tablet \\
- -s 31,lpc -l com1,stdio \\
+ -s 31,lpc -l com1,tcp=0.0.0.0:1234 \\
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \\
uefivm
.Ed
.Pp
Run a UEFI virtual machine with a VNC display that is bound to all IPv6
-addresses on port 5900.
+addresses on port 5900 and a TCP serial I/O bound to port 1234.
.Bd -literal -offset indent
bhyve -c 2 -m 4G -w -H \\
-s 0,hostbridge \\
@@ -1088,7 +1091,7 @@
-s 5,virtio-net,tap0 \\
-s 29,fbuf,tcp=[::]:5900,w=800,h=600 \\
-s 30,xhci,tablet \\
- -s 31,lpc -l com1,stdio \\
+ -s 31,lpc -l com1,tcp=[::]:1234 \\
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \\
uefivm
.Ed
diff --git a/usr.sbin/bhyve/uart_emul.c b/usr.sbin/bhyve/uart_emul.c
--- a/usr.sbin/bhyve/uart_emul.c
+++ b/usr.sbin/bhyve/uart_emul.c
@@ -28,7 +28,11 @@
*/
#include <sys/types.h>
+#include <sys/socket.h>
#include <dev/ic/ns16550.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
#ifndef WITHOUT_CAPSICUM
#include <sys/capsicum.h>
#include <capsicum_helpers.h>
@@ -104,6 +108,7 @@
struct ttyfd {
bool opened;
+ bool connect_based;
int rfd; /* fd for reading */
int wfd; /* fd for writing, may be == rfd */
};
@@ -134,6 +139,7 @@
};
static void uart_drain(int fd, enum ev_type ev, void *arg);
+static void uart_tcp_disconnect(struct uart_softc *sc);
static void
ttyclose(void)
@@ -160,21 +166,23 @@
}
static int
-ttyread(struct ttyfd *tf)
+ttyread(struct ttyfd *tf, unsigned char *ret)
{
unsigned char rb;
+ int sz;
- if (read(tf->rfd, &rb, 1) == 1)
- return (rb);
- else
- return (-1);
+ sz = read(tf->rfd, &rb, 1);
+ if (ret != NULL)
+ *ret = rb;
+
+ return sz;
}
-static void
+static int
ttywrite(struct ttyfd *tf, unsigned char wb)
{
- (void)write(tf->wfd, &wb, 1);
+ return write(tf->wfd, &wb, 1);
}
static void
@@ -374,7 +382,8 @@
uart_drain(int fd, enum ev_type ev, void *arg)
{
struct uart_softc *sc;
- int ch;
+ int len;
+ unsigned char ch;
sc = arg;
@@ -389,15 +398,26 @@
pthread_mutex_lock(&sc->mtx);
if ((sc->mcr & MCR_LOOPBACK) != 0) {
- (void) ttyread(&sc->tty);
+ if (ttyread(&sc->tty, NULL) == 0 && sc->tty.connect_based)
+ uart_tcp_disconnect(sc);
} else {
- while (rxfifo_available(sc) &&
- ((ch = ttyread(&sc->tty)) != -1)) {
- rxfifo_putchar(sc, ch);
+ while (rxfifo_available(sc)) {
+ len = ttyread(&sc->tty, &ch);
+
+ if (len <= 0) {
+ if (len == 0 && sc->tty.connect_based) {
+ uart_tcp_disconnect(sc);
+ goto clear;
+ }
+ break;
+ } else {
+ rxfifo_putchar(sc, ch);
+ }
}
uart_toggle_intr(sc);
}
+clear:
pthread_mutex_unlock(&sc->mtx);
}
@@ -430,7 +450,9 @@
if (rxfifo_putchar(sc, value) != 0)
sc->lsr |= LSR_OE;
} else if (sc->tty.opened) {
- ttywrite(&sc->tty, value);
+ if (ttywrite(&sc->tty, value) == -1 &&
+ sc->tty.connect_based)
+ uart_tcp_disconnect(sc);
} /* else drop on floor */
sc->thre_int_pending = true;
break;
@@ -705,6 +727,119 @@
return (0);
}
+static void
+uart_tcp_listener(int fd, enum ev_type type __unused, void *arg)
+{
+ const static char tcp_error_msg[] = "Socket already connected\n";
+ struct uart_softc *sc = (struct uart_softc *)arg;
+ struct sockaddr_in dst_addr;
+ socklen_t len = sizeof(dst_addr);
+ int conn_fd;
+
+ conn_fd = accept(fd, (struct sockaddr *)&dst_addr, &len);
+ if (conn_fd == -1) {
+ errx(EX_OSERR, "Unable to accept the connection");
+ return;
+ }
+
+ if (fcntl(conn_fd, F_SETFL, O_NONBLOCK) != 0) {
+ errx(EX_OSERR, "Unable to set nonblocking mode to connection");
+ return;
+ }
+
+ pthread_mutex_lock(&sc->mtx);
+
+ if (sc->tty.opened) {
+ send(conn_fd, tcp_error_msg, sizeof(tcp_error_msg), 0);
+ close(conn_fd);
+ } else {
+ sc->tty.rfd = sc->tty.wfd = conn_fd;
+ sc->tty.opened = true;
+ uart_opentty(sc);
+ }
+
+ pthread_mutex_unlock(&sc->mtx);
+}
+
+static void
+uart_tcp_disconnect(struct uart_softc *sc)
+{
+ mevent_delete_close(sc->mev);
+ sc->mev = NULL;
+
+ sc->tty.opened = false;
+ sc->tty.rfd = sc->tty.wfd = -1;
+}
+
+// Listen to address and add to kqueue.
+// If connected (e.g. tcp_handler is triggered), we replace the handler to the
+// connected handler
+static int
+uart_tcp_backend(struct uart_softc *sc, const char *path)
+{
+#ifndef WITHOUT_CAPSICUM
+ cap_rights_t rights;
+ cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
+#endif
+ int bind_fd;
+ char addr[256], port[6];
+ int domain;
+ struct addrinfo hints, *src_addr;
+
+ if (sscanf(path, "tcp=[%255[^]]]:%5s", addr, port) == 2) {
+ domain = AF_INET6;
+ } else if (sscanf(path, "tcp=%255[^:]:%5s", addr, port) == 2) {
+ domain = AF_INET;
+ } else {
+ errx(EX_CONFIG, "Invalid number of parameter");
+ return (-1);
+ }
+
+ bind_fd = socket(domain, SOCK_STREAM, 0);
+ if (bind_fd < 0)
+ return (-1);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = domain;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
+
+ if (getaddrinfo(addr, port, &hints, &src_addr) != 0) {
+ errx(EX_CONFIG, "Invalid address %s:%s", addr, port);
+ return -1;
+ }
+
+ if (bind(bind_fd, src_addr->ai_addr, src_addr->ai_addrlen) == -1) {
+ errx(EX_OSERR,
+ "Unable to bind to address %s:%s. Maybe the address is used?",
+ addr, port);
+ return (-1);
+ }
+
+ if (fcntl(bind_fd, F_SETFL, O_NONBLOCK) == -1)
+ return (-1);
+
+ if (listen(bind_fd, 1) == -1)
+ errx(EX_OSERR, "Unable to listen to address %s:%s", addr, port);
+
+ if (mevent_add(bind_fd, EVF_READ, uart_tcp_listener, (void *)sc) ==
+ NULL)
+ return (-1);
+
+#ifndef WITHOUT_CAPSICUM
+ cap_rights_init(&rights, CAP_EVENT, CAP_ACCEPT, CAP_RECV, CAP_SEND,
+ CAP_FCNTL, CAP_IOCTL);
+ if (caph_rights_limit(bind_fd, &rights) == -1)
+ errx(EX_OSERR, "Unable to apply rights for sandbox");
+ if (caph_ioctls_limit(bind_fd, cmds, nitems(cmds)) == -1)
+ errx(EX_OSERR, "Unable to apply ioctls for sandbox");
+ if (caph_fcntls_limit(bind_fd, CAP_FCNTL_SETFL) == -1)
+ errx(EX_OSERR, "Unable to apply fcntls for sandbox");
+#endif
+
+ return (0);
+}
+
int
uart_set_backend(struct uart_softc *sc, const char *device)
{
@@ -715,9 +850,12 @@
if (strcmp("stdio", device) == 0)
retval = uart_stdio_backend(sc);
- else
+ else if (strncmp("tcp", device, 3) == 0) {
+ retval = uart_tcp_backend(sc, device);
+ sc->tty.connect_based = true;
+ } else
retval = uart_tty_backend(sc, device);
- if (retval == 0)
+ if (retval == 0 && !sc->tty.connect_based)
uart_opentty(sc);
return (retval);

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 19, 1:30 AM (12 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23903738
Default Alt Text
D43514.id135322.diff (7 KB)

Event Timeline