Host-Guest Communication
VM sockets (vsock) provide a high-performance communication channel between host and guest, independent of networking.
What is Vsock?
Vsock is a socket family (AF_VSOCK) designed for hypervisor-guest communication:
- No IP configuration required
- Works without guest networking
- Lower latency than network sockets
- Used internally by sandbox agent
Listen Mode (Host Accepts)
The host listens for connections from the guest:
rust,no_run
let vm = capsa::vm(boot)
.vsock_listen(1024) // Host listens on port 1024
.build()
.await?;
// Get the socket for port 1024
let socket = vm.vsock_socket(1024).unwrap();
// Accept a connection from the guest
let mut stream = socket.connect().await?;
// Communicate
let mut buf = [0u8; 1024];
let n = stream.read(&mut buf).await?;
stream.write_all(b"response").await?;Inside the guest, connect to the host:
bash
# Guest connects to host (CID 2) on port 1024
socat - VSOCK-CONNECT:2:1024Connect Mode (Guest Accepts)
The guest listens and host connects:
rust,no_run
let vm = capsa::vm(boot)
.vsock_connect(1024) // Guest will listen on port 1024
.build()
.await?;
let socket = vm.vsock_socket(1024).unwrap();
// Connect to the guest
let mut stream = socket.connect().await?;
stream.write_all(b"hello guest").await?;Inside the guest, listen for connections:
bash
# Guest listens on port 1024
socat VSOCK-LISTEN:1024 -Multiple Ports
Configure multiple vsock ports:
rust,no_run
let vm = capsa::vm(boot)
.vsock_listen(1024) // RPC channel
.vsock_listen(1025) // Log streaming
.vsock_connect(2000) // Data channel
.build()
.await?;
// Access each socket
let rpc = vm.vsock_socket(1024).unwrap();
let logs = vm.vsock_socket(1025).unwrap();
let data = vm.vsock_socket(2000).unwrap();Custom Socket Path
Use a specific Unix socket path:
rust,no_run
let vm = capsa::vm(boot)
.vsock(VsockPortConfig::listen(1024, "/tmp/my-vsock.sock"))
.build()
.await?;Sandbox Agent
The sandbox agent uses vsock internally. Use vm.agent() to connect:
rust,no_run
let vm = capsa::sandbox()
.build()
.await?;
// Connect to agent
let agent = vm.agent().await?;Building Custom Protocols
Example: Simple request/response protocol over vsock:
rust,no_run
let vm = capsa::vm(boot)
.vsock_listen(1024)
.console_enabled()
.build()
.await?;
let socket = vm.vsock_socket(1024).unwrap();
// Wait for guest to connect
let stream = socket.connect().await?;
let (reader, mut writer) = tokio::io::split(stream);
let mut reader = BufReader::new(reader);
// Simple line-based protocol
let mut line = String::new();
while reader.read_line(&mut line).await? > 0 {
let response = format!("Received: {}", line.trim());
writer.write_all(response.as_bytes()).await?;
writer.write_all(b"\n").await?;
line.clear();
}Complete Example
rust,no_run
use capsa::boot::LinuxDirectBoot;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use std::time::Duration;
async fn vsock_communication() -> capsa::Result<()> {
let boot = LinuxDirectBoot::new("./kernel", "./initrd");
let vm = capsa::vm(boot)
.cpus(2)
.memory_mb(512)
.console_enabled()
.vsock_listen(1024)
.build()
.await?;
// Boot the VM and start a vsock client in the guest
let console = vm.console().await?;
console.wait_for("# ", Duration::from_secs(30)).await?;
// Start guest-side client (background)
console.write_line(r#"echo "hello from guest" | socat - VSOCK-CONNECT:2:1024 &"#).await?;
// Accept connection from guest
let socket = vm.vsock_socket(1024).unwrap();
let mut stream = socket.connect().await?;
// Read message
let mut buf = [0u8; 1024];
let n = stream.read(&mut buf).await?;
println!("Received: {}", String::from_utf8_lossy(&buf[..n]));
// Send response
stream.write_all(b"hello from host\n").await?;
vm.shutdown().await?;
Ok(())
}Next Steps
- Custom Kernels - VM configuration
- Console - Raw serial port access
- VM Pools - Pre-warmed VMs