Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
5c9d239
docs(plans): smoltcp passt-pattern port — spec + Phase 0 plan
dpsoft Apr 27, 2026
8d63aaa
test(network): scaffold network_baseline pins with frame helpers
dpsoft Apr 27, 2026
bc9eefb
test(network): address review — restore reserved constants, alias IpA…
dpsoft Apr 27, 2026
21134d8
test(network): pin TCP handshake SYN-ACK emission
dpsoft Apr 27, 2026
1226986
test(network): pin TCP guest↔host data round-trip
dpsoft Apr 27, 2026
5838586
test(network): BROKEN_ON_PURPOSE pin — 256 KB to_host cliff
dpsoft Apr 28, 2026
6cc850c
test(network): hoist inline `use` statements to module scope
dpsoft Apr 28, 2026
a5b9128
test(network): pin TCP rate limit, concurrent cap, deny list
dpsoft Apr 28, 2026
cf59b33
test(network): pin ARP reply behavior for gateway and subnet
dpsoft Apr 28, 2026
3dc5309
test(network): pin DNS resolution and cache xid-rewrite
dpsoft Apr 28, 2026
40c0f7e
test(network): fix build_udp_frame payload_len double-count
dpsoft Apr 28, 2026
279af3b
test(network): BROKEN_ON_PURPOSE pin — UDP non-DNS dropped
dpsoft Apr 28, 2026
4d96ad7
test(network): BROKEN_ON_PURPOSE pin — ICMP echo dropped
dpsoft Apr 28, 2026
41c8382
bench(network): divan microbenches for SLIRP hot paths
dpsoft Apr 28, 2026
499ee35
bench(network): parametric NAT-walk scaling at 1/100/1000 flows
dpsoft Apr 28, 2026
7cca766
bench(network): DNS cache hit and miss paths
dpsoft Apr 28, 2026
7868bb2
ci(bench): include network microbenches in regression gate
dpsoft Apr 28, 2026
e1ed1e2
bench(network): voidbox-network-bench binary scaffold
dpsoft Apr 28, 2026
df898d6
bench(network): TCP throughput via busybox nc
dpsoft Apr 28, 2026
68136d1
bench(network): TCP RR/CRR latency p50/p99
dpsoft Apr 28, 2026
594190b
bench(network): UDP DNS qps and JSON report output
dpsoft Apr 28, 2026
3143e1f
docs(plans): rename SmoltcpBackend → SlirpBackend in spec + Phase 0 plan
dpsoft Apr 28, 2026
b7e426c
feat(network): introduce NetworkBackend trait
dpsoft Apr 28, 2026
046d57d
refactor(slirp): add drain_to_guest wrapper for trait fit
dpsoft Apr 28, 2026
5095d6d
refactor(slirp): move poll body into drain_to_guest, drop alloc
dpsoft Apr 28, 2026
66f007f
feat(slirp): impl NetworkBackend for SlirpStack
dpsoft Apr 28, 2026
dbe5208
refactor(virtio_net): hold dyn NetworkBackend, reuse rx buffer
dpsoft Apr 28, 2026
bf3cd6a
refactor(network): rename SlirpStack to SlirpBackend
dpsoft Apr 28, 2026
028707c
docs(plans): add Phase 1 plan (ICMP echo via SOCK_DGRAM IPPROTO_ICMP)
dpsoft Apr 28, 2026
fa48f05
feat(slirp): add IcmpEchoEntry + IPPROTO_ICMP socket helper
dpsoft Apr 28, 2026
3d2ec08
refactor(slirp): hoist FromRawFd to module scope, drop redundant use …
dpsoft Apr 28, 2026
c5112c9
feat(slirp): forward guest ICMP echo via SOCK_DGRAM IPPROTO_ICMP
dpsoft Apr 28, 2026
5180bda
feat(slirp): relay ICMP echo replies back to guest
dpsoft Apr 28, 2026
195038f
feat(slirp): warn-once + fallback when unprivileged ICMP forbidden
dpsoft Apr 28, 2026
f9330da
test(network): flip ICMP pin — assert echo reply (was BROKEN_ON_PURPOSE)
dpsoft Apr 28, 2026
8572122
bench(network): populate ICMP RR latency p50
dpsoft Apr 29, 2026
77dfc67
fix(scripts): revert setuid busybox in test image (Phase 1.6 regression)
dpsoft Apr 29, 2026
83f7dcb
docs(plans): add Phase 2 plan (generalize UDP via per-flow connected …
dpsoft Apr 29, 2026
4d46c5f
feat(slirp): add UdpFlowEntry + per-flow connected socket helper
dpsoft Apr 29, 2026
0aff7df
feat(slirp): forward non-DNS UDP via per-flow connected sockets
dpsoft Apr 29, 2026
cd41b8f
ci(bench): add strict voidbox-network-bench step (no continue-on-error)
dpsoft Apr 29, 2026
b117c13
feat(slirp): relay UDP flow replies back to guest
dpsoft Apr 29, 2026
cced8ad
feat(slirp): UDP flow idle reap (60s)
dpsoft Apr 29, 2026
b79e07f
test(network): full RTT for UDP pin (was BROKEN_ON_PURPOSE one-way)
dpsoft Apr 29, 2026
0758df1
bench(network): document DNS qps busybox-nc bottleneck (set null + WARN)
dpsoft Apr 29, 2026
0d0ab20
fix(startup-bench): require userspace vsock backend for snapshot capture
dpsoft Apr 29, 2026
c26d44c
docs(plans): add Phase 3 plan (TCP relay rewrite via MSG_PEEK + seque…
dpsoft Apr 29, 2026
ecc624a
docs(plans): lock observability as a hard non-negotiable invariant
dpsoft Apr 29, 2026
1882c33
refactor(slirp): add bytes_in_flight to TcpNatEntry (no behavior change)
dpsoft Apr 29, 2026
e143f7a
refactor(slirp): add recv_peek helper using libc::recv MSG_PEEK
dpsoft Apr 29, 2026
bc1708a
refactor(slirp): peek-based host→guest TCP relay (drops to_guest depe…
dpsoft Apr 29, 2026
ee9f8da
refactor(slirp): ACK-driven consume from kernel socket
dpsoft Apr 29, 2026
4a41f57
refactor(slirp): drop to_host buffer + 256KB cliff, use TCP backpressure
dpsoft Apr 29, 2026
03a1f59
refactor(slirp): drop to_guest/to_host/pending_ack fields and dead he…
dpsoft Apr 29, 2026
ae94859
test(network): flip 256KB cliff pin — assert >1MB throughput succeeds
dpsoft Apr 29, 2026
5fe4316
bench(network): tcp_bulk_throughput_1mb — measures post-Phase-3 backp…
dpsoft Apr 29, 2026
4471c91
bench(network): --bulk-mb mode to measure post-Phase-3 backpressure
dpsoft Apr 29, 2026
120ad73
docs(plans): add Phase 4 plan (unified flow table refactor)
dpsoft Apr 29, 2026
827135e
refactor(slirp): define FlowKey + FlowEntry enums (no callers yet)
dpsoft Apr 29, 2026
f5a2d11
fix(ci): non-Linux stubs for benches/network.rs + voidbox-network-bench
dpsoft Apr 30, 2026
ee353c5
docs(plans): add three Phase 4 benches (mixed flows, per-protocol, ta…
dpsoft Apr 30, 2026
93523ba
refactor(slirp): add flow_table field on SlirpBackend (parallel to ex…
dpsoft Apr 30, 2026
e94998c
refactor(slirp): migrate ICMP path to flow_table
dpsoft Apr 30, 2026
29206d1
refactor(slirp): migrate UDP path to flow_table
dpsoft Apr 30, 2026
9c3fac9
refactor(slirp): migrate TCP path to flow_table
dpsoft Apr 30, 2026
7cad565
refactor(slirp): update Phase 4 doc header for unified flow table
dpsoft Apr 30, 2026
f53de94
bench(network): poll_with_n_mixed_flows — mixed TCP/UDP/ICMP at scale
dpsoft Apr 30, 2026
ae9195b
bench(network): process_udp_frame + process_icmp_echo_request
dpsoft Apr 30, 2026
01ea90a
bench(network): add flow_table_insert_remove synthetic microbench
dpsoft Apr 30, 2026
8566451
docs(plans): add Phase 5 plan (stateless NAT + port forwarding)
dpsoft Apr 30, 2026
81ba8ca
feat(network): add nat.rs with stateless translate_outbound (no calle…
dpsoft Apr 30, 2026
aad628b
refactor(slirp): add nat::Rules field on SlirpBackend (parallel to de…
dpsoft Apr 30, 2026
4d622d2
refactor(slirp): TCP path uses nat::translate_outbound
dpsoft Apr 30, 2026
dbb641c
refactor(slirp): UDP path uses nat::translate_outbound, drop deny_lis…
dpsoft Apr 30, 2026
1c27145
refactor(slirp): plumb port_forwards from NetworkConfig into nat::Rules
dpsoft Apr 30, 2026
7e8d5ce
test(network): pin nat::translate_outbound (loopback, external, deny)
dpsoft Apr 30, 2026
d31a3ec
bench(network): nat_translate_outbound_hot_path — Phase 5 baseline
dpsoft Apr 30, 2026
4baaa9a
feat(slirp): TcpNatState::SynSent + handle inbound SYN-ACK
dpsoft Apr 30, 2026
a464fc1
bench(network): tcp_inbound_syn_ack_transition — Phase 5.5b.1 microbench
dpsoft Apr 30, 2026
9b077d2
feat(slirp): add synthesize_inbound_syn helper for port-forwarding
dpsoft Apr 30, 2026
473971f
bench(network): synthesize_inbound_syn pure-compute (Phase 5.5b.2.b)
dpsoft Apr 30, 2026
b2fbf58
feat(slirp): port-forward listener thread implementation (not wired yet)
dpsoft Apr 30, 2026
efbf5a9
feat(slirp): wire spawn_port_forward_listeners from with_security
dpsoft Apr 30, 2026
423fba2
test(network): tcp_port_forward_inbound — Phase 5.5b e2e contract
dpsoft Apr 30, 2026
aa60b8a
bench(network): port_forward_accept_latency — Phase 5.5b wall-clock b…
dpsoft Apr 30, 2026
5a02b14
chore(bench): add scripts/bench-compare.sh — phase comparison report
dpsoft Apr 30, 2026
9cab10e
test(network): icmp_echo_returns_reply — probe + assert, no silent skip
dpsoft Apr 30, 2026
bb64525
fix(network-bench): skip failed iterations + drop guest-ping ICMP path
dpsoft Apr 30, 2026
6a892c0
bench(network): migrate from deprecated .poll() to drain_to_guest()
dpsoft Apr 30, 2026
163bed3
chore(bench): bench-compare.sh — fall back without bench-helpers feature
dpsoft Apr 30, 2026
e6de98a
fix(network-bench): bound accept-thread lifetimes with deadlines
dpsoft Apr 30, 2026
47868f0
docs: Phase 6 overview plan — TCP lifecycle + async connect + windows…
dpsoft Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 85 additions & 15 deletions .github/workflows/startup-bench.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
name: Startup Bench

# Two layers, both run in this workflow:
# Three layers, all run in this workflow:
#
# 1. **Divan micro-bench** — `cargo bench --bench startup`. Pure-compute
# hot paths (Message::serialize/deserialize, kernel_cmdline,
# getrandom). No KVM, no nested virt, no L2 boot — same wall-clock
# cost on every Linux runner. Cheap regression gate.
# 1. **Divan micro-bench (startup)** — `cargo bench --bench startup`.
# Pure-compute hot paths (Message::serialize/deserialize,
# kernel_cmdline, getrandom). No KVM, no nested virt, no L2 boot —
# same wall-clock cost on every Linux runner. Cheap regression gate.
#
# 2. **Wall-clock harness** — `voidbox-startup-bench --iters 20
# 2. **Divan micro-bench (network)** — `cargo bench --bench network`.
# SLIRP hot paths (process_syn, poll_idle, process_arp_request,
# poll_with_n_flows, dns_cache_hit, dns_cache_miss). Also pure
# compute, no nested virt — stable regression gate for the network
# stack without requiring KVM or a real VM boot.
#
# 3. **Wall-clock harness** — `voidbox-startup-bench --iters 20
# --breakdown`. Boots a real KVM VM through the slim kernel + test
# initramfs and measures cold-boot + warm-restore p50/p95/p99 end
# to end. Informational only on this runner: the GitHub-hosted
Expand Down Expand Up @@ -161,14 +167,37 @@ jobs:
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

- name: Run wall-clock harness (informational)
# No threshold gate — Azure nested-virt is slower than the
# bare-metal targets the verify-skill thresholds were tuned for.
# `continue-on-error` keeps the workflow green even if the
# harness fails outright (e.g. missing /dev/vhost-vsock on a
# future runner image change). The artifact preserves the log
# either way.
continue-on-error: true
- name: Run network divan micro-bench (regression gate)
# Same regression-detection role as the startup divan step, but
# for SLIRP hot paths: process_syn, poll_idle, process_arp_request,
# poll_with_n_flows, dns_cache_hit, dns_cache_miss. Pure compute,
# no nested virt — stable across CI hosts. Output captured for
# artifact + step summary.
run: |
cargo bench --bench network 2>&1 | tee target/tmp/divan-network.log

{
echo
echo "## Divan network micro-bench (cargo bench --bench network)"
echo
echo '```'
grep -E 'fastest|median|slowest|^[a-z_]+\.' target/tmp/divan-network.log \
|| tail -40 target/tmp/divan-network.log
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

- name: Run wall-clock harness (strict)
# NO `continue-on-error` — was previously silently masking the
# vhost/userspace vsock backend mismatch on warm restore (root
# cause: `capture_snapshot` was building a Sandbox without
# `.enable_snapshots(true)` so vhost-vsock was selected, but
# `from_snapshot` always restores into userspace vsock; vring
# state lives in the kernel's vhost-vsock module and isn't part
# of our snapshot, so the restored userspace device couldn't
# accept connections and every host connect timed out).
# Threshold gate stays informal — Azure nested-virt is slower
# than the bare-metal Fedora 43 / KVM targets the verify-skill
# thresholds were tuned for, but the harness MUST exit 0.
env:
ITERS: ${{ inputs.iters || '20' }}
VOID_BOX_KERNEL: ${{ github.workspace }}/target/vmlinux-slim-x86_64
Expand All @@ -194,10 +223,51 @@ jobs:
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

- name: Build voidbox-network-bench (release)
# Network wall-clock harness: boots one VM with `network(true)`,
# measures TCP throughput, RR/CRR latency, UDP DNS qps, and ICMP
# RR latency. Mirror the startup harness build step.
run: cargo build --release --bin voidbox-network-bench

- name: Run voidbox-network-bench (network wall-clock harness)
# NO `continue-on-error` here — unlike the startup-bench warm
# phase, this harness has well-defined failure modes that we
# want to surface in CI. A regression like the setuid-busybox
# bug fixed at 77dfc67 (Phase 1.6 → ECONNRESET on every
# connect for `network(true)` VMs) would otherwise hide behind
# `continue-on-error`. If this step is genuinely flaky on the
# runner image, fix the runner image — don't mask the signal.
env:
VOID_BOX_KERNEL: ${{ github.workspace }}/target/vmlinux-slim-x86_64
VOID_BOX_INITRAMFS: /tmp/void-box-test-rootfs.cpio.gz
run: |
if [ ! -e /dev/vhost-vsock ]; then
echo "::warning::/dev/vhost-vsock not available; skipping voidbox-network-bench"
exit 0
fi
ls -la "$VOID_BOX_KERNEL" "$VOID_BOX_INITRAMFS"
./target/release/voidbox-network-bench --iterations 3 \
--output target/tmp/network-bench.json 2>&1 \
| tee target/tmp/network-bench.log

{
echo
echo "## Network wall-clock harness (voidbox-network-bench --iterations 3)"
echo
echo "Metric names mirror passt's published table (passt.top/passt) so a"
echo "future side-by-side comparison run on the same host is plug-compatible."
echo
echo '```json'
cat target/tmp/network-bench.json
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload bench logs
if: always()
uses: actions/upload-artifact@v4
with:
name: startup-bench-${{ github.run_id }}
path: target/tmp/*.log
path: |
target/tmp/*.log
target/tmp/*.json
retention-days: 30
16 changes: 16 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ divan = "0.1"
default = []
# Enable full OpenTelemetry integration (OTLP export, trace context propagation)
opentelemetry = ["dep:opentelemetry", "dep:opentelemetry_sdk", "dep:opentelemetry-otlp"]
# Expose internal SlirpBackend helpers (insert_synthetic_synsent_entry, etc.)
# for use in benches/. Never enable in production builds.
bench-helpers = []

[[bin]]
name = "voidbox"
Expand Down Expand Up @@ -170,11 +173,20 @@ path = "tests/oci_integration.rs"
name = "observe_codex"
path = "tests/observe_codex.rs"

[[test]]
name = "network_baseline"
path = "tests/network_baseline.rs"

[[bench]]
name = "startup"
path = "benches/startup.rs"
harness = false

[[bench]]
name = "network"
path = "benches/network.rs"
harness = false

[[bin]]
name = "voidbox-startup-bench"
path = "src/bin/voidbox-startup-bench/main.rs"
Expand All @@ -183,6 +195,10 @@ path = "src/bin/voidbox-startup-bench/main.rs"
name = "voidbox-rpc-bench"
path = "src/bin/voidbox-rpc-bench/main.rs"

[[bin]]
name = "voidbox-network-bench"
path = "src/bin/voidbox-network-bench/main.rs"

[workspace]
members = ["guest-agent", "void-box-protocol", "claudio", "voidbox-oci", "void-message", "void-mcp"]

Expand Down
Loading
Loading