Volt VMM (Neutron Stardust): source-available under AGPSL v5.0

KVM-based microVMM for the Volt platform:
- Sub-second VM boot times
- Minimal memory footprint
- Landlock LSM + seccomp security
- Virtio device support
- Custom kernel management

Copyright (c) Armored Gates LLC. All rights reserved.
Licensed under AGPSL v5.0
This commit is contained in:
Karl Clinger
2026-03-21 01:04:35 -05:00
commit 40ed108dd5
143 changed files with 50300 additions and 0 deletions

View File

@@ -0,0 +1,344 @@
//! Integration tests for Volt VM boot
//!
//! These tests verify that VMs boot correctly and measure boot times.
//! Run with: cargo test --test boot_test -- --ignored
//!
//! Requirements:
//! - KVM access (/dev/kvm readable/writable)
//! - Built kernel in kernels/vmlinux
//! - Built rootfs in images/alpine-rootfs.ext4
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};
/// Get the project root directory
fn project_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.to_path_buf()
}
/// Check if KVM is available
fn kvm_available() -> bool {
std::path::Path::new("/dev/kvm").exists()
&& std::fs::metadata("/dev/kvm")
.map(|m| !m.permissions().readonly())
.unwrap_or(false)
}
/// Get path to the Volt binary
fn volt-vmm_binary() -> PathBuf {
let release = project_root().join("target/release/volt-vmm");
if release.exists() {
release
} else {
project_root().join("target/debug/volt-vmm")
}
}
/// Get path to the test kernel
fn test_kernel() -> PathBuf {
project_root().join("kernels/vmlinux")
}
/// Get path to the test rootfs
fn test_rootfs() -> PathBuf {
let ext4 = project_root().join("images/alpine-rootfs.ext4");
if ext4.exists() {
ext4
} else {
project_root().join("images/alpine-rootfs.squashfs")
}
}
/// Spawn a VM and return the child process
fn spawn_vm(memory_mb: u32, cpus: u32) -> std::io::Result<Child> {
let binary = volt-vmm_binary();
let kernel = test_kernel();
let rootfs = test_rootfs();
Command::new(&binary)
.arg("--kernel")
.arg(&kernel)
.arg("--rootfs")
.arg(&rootfs)
.arg("--memory")
.arg(memory_mb.to_string())
.arg("--cpus")
.arg(cpus.to_string())
.arg("--cmdline")
.arg("console=ttyS0 reboot=k panic=1 nomodules quiet")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
/// Wait for a specific string in VM output
fn wait_for_output(
child: &mut Child,
pattern: &str,
timeout: Duration,
) -> Result<Duration, String> {
let start = Instant::now();
let stdout = child.stdout.take().ok_or("No stdout")?;
let reader = BufReader::new(stdout);
let (tx, rx) = mpsc::channel();
let pattern = pattern.to_string();
// Spawn reader thread
thread::spawn(move || {
for line in reader.lines() {
if let Ok(line) = line {
if line.contains(&pattern) {
let _ = tx.send(Instant::now());
break;
}
}
}
});
// Wait for pattern or timeout
match rx.recv_timeout(timeout) {
Ok(found_time) => Ok(found_time.duration_since(start)),
Err(_) => Err(format!("Timeout waiting for '{}'", pattern)),
}
}
// ============================================================================
// Tests
// ============================================================================
#[test]
#[ignore = "requires KVM and built assets"]
fn test_vm_boots() {
if !kvm_available() {
eprintln!("Skipping: KVM not available");
return;
}
let binary = volt-vmm_binary();
if !binary.exists() {
eprintln!("Skipping: Volt binary not found at {:?}", binary);
return;
}
let kernel = test_kernel();
if !kernel.exists() {
eprintln!("Skipping: Kernel not found at {:?}", kernel);
return;
}
let rootfs = test_rootfs();
if !rootfs.exists() {
eprintln!("Skipping: Rootfs not found at {:?}", rootfs);
return;
}
println!("Starting VM...");
let mut child = spawn_vm(128, 1).expect("Failed to spawn VM");
// Wait for boot message
let result = wait_for_output(&mut child, "Volt microVM booted", Duration::from_secs(30));
// Clean up
let _ = child.kill();
match result {
Ok(boot_time) => {
println!("✓ VM booted successfully in {:?}", boot_time);
assert!(boot_time < Duration::from_secs(10), "Boot took too long");
}
Err(e) => {
panic!("VM boot failed: {}", e);
}
}
}
#[test]
#[ignore = "requires KVM and built assets"]
fn test_boot_time_under_500ms() {
if !kvm_available() {
eprintln!("Skipping: KVM not available");
return;
}
let binary = volt-vmm_binary();
let kernel = test_kernel();
let rootfs = test_rootfs();
if !binary.exists() || !kernel.exists() || !rootfs.exists() {
eprintln!("Skipping: Required assets not found");
return;
}
// Run multiple times and average
let mut boot_times = Vec::new();
let iterations = 3;
for i in 0..iterations {
println!("Boot test iteration {}/{}", i + 1, iterations);
let mut child = spawn_vm(128, 1).expect("Failed to spawn VM");
// Look for kernel boot message or shell prompt
let result = wait_for_output(&mut child, "Booting", Duration::from_secs(5));
let _ = child.kill();
if let Ok(duration) = result {
boot_times.push(duration);
}
}
if boot_times.is_empty() {
eprintln!("No successful boots recorded");
return;
}
let avg_boot: Duration =
boot_times.iter().sum::<Duration>() / boot_times.len() as u32;
println!("Average boot time: {:?} ({} samples)", avg_boot, boot_times.len());
// Target: <500ms to first kernel output
// This is aggressive but achievable with PVH boot
if avg_boot < Duration::from_millis(500) {
println!("✓ Boot time target met: {:?} < 500ms", avg_boot);
} else {
println!("⚠ Boot time target missed: {:?} >= 500ms", avg_boot);
// Don't fail yet - this is aspirational
}
}
#[test]
#[ignore = "requires KVM and built assets"]
fn test_multiple_vcpus() {
if !kvm_available() {
return;
}
let binary = volt-vmm_binary();
let kernel = test_kernel();
let rootfs = test_rootfs();
if !binary.exists() || !kernel.exists() || !rootfs.exists() {
return;
}
// Test with 2 and 4 vCPUs
for cpus in [2, 4] {
println!("Testing with {} vCPUs...", cpus);
let mut child = spawn_vm(256, cpus).expect("Failed to spawn VM");
let result = wait_for_output(
&mut child,
"Volt microVM booted",
Duration::from_secs(30),
);
let _ = child.kill();
assert!(result.is_ok(), "Failed to boot with {} vCPUs", cpus);
println!("{} vCPUs: booted in {:?}", cpus, result.unwrap());
}
}
#[test]
#[ignore = "requires KVM and built assets"]
fn test_memory_sizes() {
if !kvm_available() {
return;
}
let binary = volt-vmm_binary();
let kernel = test_kernel();
let rootfs = test_rootfs();
if !binary.exists() || !kernel.exists() || !rootfs.exists() {
return;
}
// Test various memory sizes
for mem_mb in [64, 128, 256, 512] {
println!("Testing with {}MB memory...", mem_mb);
let mut child = spawn_vm(mem_mb, 1).expect("Failed to spawn VM");
let result = wait_for_output(
&mut child,
"Volt microVM booted",
Duration::from_secs(30),
);
let _ = child.kill();
assert!(result.is_ok(), "Failed to boot with {}MB", mem_mb);
println!("{}MB: booted in {:?}", mem_mb, result.unwrap());
}
}
// ============================================================================
// Benchmarks (manual, run with --nocapture)
// ============================================================================
#[test]
#[ignore = "benchmark - run manually"]
fn bench_cold_boot() {
if !kvm_available() {
return;
}
println!("\n=== Cold Boot Benchmark ===\n");
let iterations = 10;
let mut times = Vec::with_capacity(iterations);
for i in 0..iterations {
// Clear caches (would need root)
// let _ = Command::new("sync").status();
// let _ = std::fs::write("/proc/sys/vm/drop_caches", "3");
let start = Instant::now();
let mut child = spawn_vm(128, 1).expect("Failed to spawn");
let result = wait_for_output(
&mut child,
"Volt microVM booted",
Duration::from_secs(30),
);
let _ = child.kill();
if let Ok(_) = result {
let elapsed = start.elapsed();
times.push(elapsed);
println!(" Run {:2}: {:?}", i + 1, elapsed);
}
}
if times.is_empty() {
println!("No successful runs");
return;
}
times.sort();
let sum: Duration = times.iter().sum();
let avg = sum / times.len() as u32;
let min = times.first().unwrap();
let max = times.last().unwrap();
let median = &times[times.len() / 2];
println!("\nResults ({} runs):", times.len());
println!(" Min: {:?}", min);
println!(" Max: {:?}", max);
println!(" Avg: {:?}", avg);
println!(" Median: {:?}", median);
}

3
tests/integration/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
//! Integration tests for Volt
mod boot_test;