This enables a subset of the functionality provided by QEMU's user
networking implementation. In particular, it uses net/libslirp, the
same library as QEMU.
libslirp is permissively licensed but has some dependencies which make
it impractical to bring into the base system (glib in particular). I
thus opted to make bhyve dlopen the libslirp.so, which can be installed
via pkg. The library header is imported into bhyve.
The slirp backend takes a "hostfwd" which is identical to QEMU's
hostfwd. When configured, bhyve opens a host socket and listens for
connections, which get forwarded to the guest. For instance,
"hostfwd=tcp::1234-:22" allows one to ssh into the guest by ssh'ing to
port 1234 on the host, e.g., via 127.0.0.1. I didn't try to hook up
guestfwd support since I don't personally have a use-case for it yet,
and I think it won't interact nicely with the capsicum sandbox.
The data path is kind of complicated because there's quite a lot of
callbacks involved. When the backend receives a packet to be sent to
the guest, libslirp calls slirp_cb_send_packet(), which puts the packet
into a socket buffer, to be read by the mevent thread in slirp_recv().
Packets transmitted by the guest are handed to slirp_send(), which calls
slirp_input() to perform library processing.
We use a dedicated thread to handle events; the slirp interface is
really designed for a thread which calls poll(), so it was cleaner to
add a new event loop rather than try to translate between pollfds and
mevent. This loop polls for incoming connection requests and handles
libslirp timeout events (retransmits, etc.). A mutex is used to
serialize calls into libslirp after initialization is done.