Vsock / TSI

src/devices/src/virtio/vsock/ — guest↔host socket bridge with transparent impersonation

Component architecture device.rs:38

GUEST
Guest Application
socket() connect()
↓ AF_INET / AF_UNIX syscall (TSI hijacks this)
Guest vsock driver
AF_VSOCK
↓ RX queue :26 / TX virtqueues ↓
HOST
Vsock Device
virtio-vsock device 19
↓ packet channel ↓
VsockMuxer muxer.rs:99
packet routing + credits
↓ connection lookup ↓
TSI (Transparent Socket Impersonation)
↓ real OS sockets ↓
Host Network / Unix Sockets

TSI modes (tsi_features bitmask) lib.rs:2438

HIJACK_INET

bit 0

Intercepts AF_INET and AF_INET6 socket operations inside the guest kernel. connect() to a host IP:port is transparently bridged via a vsock tunnel to the actual host socket. Guest applications need zero modification.

HIJACK_UNIX

bit 1

Intercepts AF_UNIX socket operations. Guest connects to a unix socket path, TSI maps the path to a vsock port via the port map, and the muxer bridges to the real host unix socket.

// TSI port map example (inside VsockMuxer) muxer.rs:99 tsi_port_map: HashMap<GuestAddr, HostTarget> 127.0.0.1:80 → host_socket_fd (tcp) /run/foo.sock → host_unix_path (unix)

Vsock packet types mod.rs:119

OP_REQUEST (1) process:539 Connection request (SYN)

Guest initiates a connection to a host port. The muxer receives this packet, looks up the port in the TSI port map or connection table, and opens a real host socket. Responds with OP_RESPONSE on success.

OP_RESPONSE (2) process:586 Connection accepted (SYN-ACK)

Host (muxer) responds to a guest OP_REQUEST after successfully opening the host-side socket. Includes initial credit (buffer space) so data transfer can begin immediately.

OP_RST (3) mod.rs:123 Reset / abort connection

Immediately tears down a connection. Sent when an error occurs (host socket closed unexpectedly, protocol violation, unknown connection). The reaper thread periodically cleans up connections in RST state.

OP_SHUTDOWN (4) process:611 Half-close a connection

Signals that one side has finished sending (SHUT_WR) or will stop receiving (SHUT_RD). Flags field indicates which directions are shutting down. Full shutdown requires both sides to signal.

OP_RW (5) process:633 Data transfer in both directions

Carries actual payload data. Guest TX: guest driver writes data to TX virtqueue → muxer reads → forwards to host socket. Guest RX: muxer reads from host socket → builds OP_RW packet → places in RX virtqueue → guest driver delivers to application.

OP_CREDIT_UPDATE (6) process:619 Flow control — advertise buffer space

Each side advertises how many bytes the peer can send (buf_alloc - fwd_cnt). The sender must not exceed the peer's advertised credit. Prevents buffer overflow without per-packet ACKs.

OP_CREDIT_REQUEST (7) mod.rs:131 Ask peer to send credit update

Sent when a sender has run out of credit and needs to know if the peer has freed buffer space. The peer responds with OP_CREDIT_UPDATE.


Data flow examples

  1. Guest app calls connect(127.0.0.1:8080)
  2. TSI kernel hook intercepts the AF_INET syscall
  3. Guest vsock driver sends OP_REQUEST packet on TX queue
  4. Host Vsock Device dequeues TX descriptor queue.rs:452
  5. Muxer receives packet → looks up 127.0.0.1:8080 in tsi_port_map muxer.rs:539
  6. Muxer opens a real TCP socket to host port 8080
  7. Muxer sends OP_RESPONSE with credit → RX queue
  8. Guest driver delivers SYN-ACK equivalent to the app's connect() call
  9. Connection established; data flows via OP_RW packets
  1. Host socket has data ready (muxer's epoll wakes)
  2. Muxer reads up to available RX credit bytes from host socket
  3. Muxer builds OP_RW packet with data payload muxer.rs:633
  4. Vsock Device places packet into guest RX virtqueue (used ring) queue.rs:502
  5. Device signals interrupt EventFd
  6. IRQ injected into guest vCPU
  7. Guest vsock driver IRQ handler runs
  8. Driver reads descriptor from RX used ring
  9. Data is delivered to the guest application's socket buffer
  10. Guest sends OP_CREDIT_UPDATE to advertise freed buffer space
  1. Guest app calls connect("/run/dbus/system_bus_socket")
  2. TSI HIJACK_UNIX intercepts AF_UNIX syscall
  3. TSI maps path to a vsock port via unix_port_map
  4. Guest vsock driver sends OP_REQUEST to that port
  5. Muxer looks up the unix socket path for that port muxer.rs:539
  6. Muxer connects to host's /run/dbus/system_bus_socket
  7. Normal OP_RESPONSE → data flow begins
  8. Guest IPC is transparently bridged to host D-Bus socket

Muxer internals muxer.rs:99

VsockMuxer muxer.rs:99 ├─ rxq: Arc<Mutex<MuxerRxQ>> // packets queued for guest RX │ ├─ process_tx(pkt): // guest → host dispatch:703 │ match pkt.op { │ OP_REQUEST → open host socket, create connection :539 │ OP_RW → write pkt.data to host socket fd :633 │ OP_SHUTDOWN → shutdown(host_fd, direction) :611 │ OP_CREDIT_UPDATE → update peer_credit for conn :619 │ } │ └─ process_rx(): // host → guest for each readable host fd (epoll events): read data → build OP_RW packet → push to rxq if conn closed → push OP_RST
← back to Virtio Devices · Overview