bhyve sandbox substrate

The jail backend is the default sandbox substrate; bhyve is the second substrate for the hardware-isolated path. Session A built the pool-control plane and the guest image; this appendix is the substrate-verification receipt. Pool warm → checkout → SSH-resume → return → drain all gate-pass on honor.

Pieces

Lifecycle (hot path)

  1. warm copies the template image per-entry, patches /etc/coppice-instance via mdconfig+mount inside a lockf-guarded critical section (parallel warm would race devfs otherwise), starts bhyve (-H -A -P, needed for SIGSTOP/SIGCONT semantics), polls SSH, then kill -STOPs the bhyve process.
  2. checkout picks the first available entry, flips it to in-use, and kill -CONTs. SSH on the guest answers within ~150 ms on honor — dominated by TCP-probe latency plus sshd wake-up.
  3. return destroys the in-use VM and respawns a fresh one from the template (v1 policy; per-entry ZFS snapshots are a future optimization).
  4. drain tears every entry down, removes /vms/bhyve-pool/<id>.img, and deletes the state file. list afterwards is empty.

Smoke-rig receipt

benchmarks/rigs/bhyve-sandbox-pool-smoke.sh drives the full lifecycle. Sample transcript on honor 2026-04-23:

smoke: warm wall time: 15s
smoke: checkout: id=pool-0 ip=10.77.0.50 pid=22149
smoke: checkout → ssh-ready: 147 ms
smoke: python3 1+1 = 2
smoke: checkout #2 (while #1 still in-use): id=pool-1 (!= pool-0, concurrency-safe)
smoke: return: pool-0 back to available
smoke: drain python-bhyve
template        pool_size       warm_s  checkout_ms     py_result
python-bhyve    2               15      147             2
smoke: ALL GATES PASSED

Full sample at benchmarks/rigs/bhyve-sandbox-pool-smoke.sample.txt.

Numbers, honestly

Gotchas we hit

What this does not cover