Virtio-Block2 Prototype (with Protobuf)¶
This prototype extends virtio-block with structured guest-to-VMM communication using Protocol Buffers. The guest sends typed messages over the serial port, enabling machine-readable progress reporting and error handling.
Goals¶
- Structured messaging: Replace plain text serial output with protobuf
- Type-safe communication: Use enum-based message types with typed payloads
- Machine-readable output: VMM can parse and act on structured messages
- no_std compatibility: Protobuf encoding works in bare-metal guest
Changes from Virtio-Block¶
| Aspect | virtio-block | virtio-block2 |
|---|---|---|
| Serial output | Plain text strings | Framed protobuf messages |
| Progress reporting | "Progress: 100/500" | ProgressMessage |
| Error messages | "Read error at sector 5" | ErrorMessage |
| VMM decoding | String matching | Type-safe protobuf decode |
Architecture¶
flowchart TB
src[("Source file")]
dst[("Dest file")]
subgraph vmm["VMM"]
kvm["KVM VM + vCPU"]
indev["Input device (read-only)"]
outdev["Output device (write)"]
mem["Guest memory (8MB)"]
decoder["Protobuf decoder"]
end
kvm -- "owns" --> mem
src --> indev --> mem
mem --> outdev --> dst
mem -- "serial port (0x3f8)" --> decoder
Protocol Messages¶
Messages are framed with a 2-byte little-endian length prefix:
Message Types¶
| Type | Level | Purpose |
|---|---|---|
| InitMessage | Info | Device initialization stages (probe, features, queue) |
| CapacityMessage | Info | Device capacity in sectors and bytes |
| ProgressMessage | Progress | Copy progress (current/total, percent) |
| ErrorMessage | Error | I/O errors with operation, device, sector, status |
| CompleteMessage | Complete | Operation completion with count and success flag |
Example Output¶
[INFO] init stage=probe device=input address=0x10000000
[INFO] init stage=features device=input address=0x100000020
[INFO] init stage=queue device=input address=0x100
[INFO] capacity device=input sectors=50 bytes=25600
[INFO] init stage=probe device=output address=0x10001000
[INFO] init stage=features device=output address=0x100000000
[INFO] init stage=queue device=output address=0x100
[INFO] capacity device=output sectors=50 bytes=25600
[PROGRESS] progress op=copy 1/50 (2%)
[PROGRESS] progress op=copy 11/50 (22%)
[PROGRESS] progress op=copy 21/50 (42%)
[PROGRESS] progress op=copy 31/50 (62%)
[PROGRESS] progress op=copy 41/50 (82%)
[PROGRESS] progress op=copy 50/50 (100%)
[COMPLETE] complete op=copy count=50 success=true
Guest Protocol Integration¶
Guest Side (no_std)¶
use guest_protocol::{init_message, progress_message, encode_framed};
// Create a progress message
let msg = progress_message("copy", current, total, percent);
// Encode with length prefix
let mut buf = [0u8; 128];
if let Some(len) = encode_framed(&msg, &mut buf) {
for &byte in &buf[..len] {
serial_write(byte);
}
}
VMM Side (std)¶
use guest_protocol::{decode_framed, guest_};
struct SerialDecoder {
buffer: Vec<u8>,
}
impl SerialDecoder {
fn add_byte(&mut self, byte: u8) -> Option<guest_::GuestMessage> {
self.buffer.push(byte);
// Check for complete message
if let Some((msg, consumed)) = decode_framed(&self.buffer) {
self.buffer.drain(..consumed);
return Some(msg);
}
None
}
}
Dependencies¶
Guest (no_std)¶
guest-protocol: Protobuf encoding (no_std compatible)heapless: Fixed-capacity containers for strings
VMM (std)¶
guest-protocol(withstdfeature): Protobuf decodingkvm-ioctls,kvm-bindings: KVM interfacevm-memory: Guest memory managementclap: CLI argument parsing
Performance¶
The protobuf messaging adds overhead compared to plain text:
| Test | virtio-block | virtio-block2 |
|---|---|---|
| 10M sectors (4.8GB) | ~5 min | ~7 min |
The overhead comes from: - Protobuf encoding in guest (heapless Vec allocation) - Per-byte serial transmission of framed messages - Protobuf decoding in VMM
For production use, consider batching messages or using a more efficient transport (virtio-console, shared memory).