Skip to content

feat: wire host balloon controls#873

Draft
enricoschaaf wants to merge 1 commit into
superradcompany:mainfrom
enricoschaaf:enrico/sandbox-balloon-control
Draft

feat: wire host balloon controls#873
enricoschaaf wants to merge 1 commit into
superradcompany:mainfrom
enricoschaaf:enrico/sandbox-balloon-control

Conversation

@enricoschaaf

@enricoschaaf enricoschaaf commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Wires host-driven memory balloon configuration through microsandbox and stacks it on the libkrun support in superradcompany/libkrun#59.

This adds app-level fields for the guest-visible boot target, the minimum guest-visible target, and the host Unix control socket, then carries those values through sandbox spawning into msb_krun::VmBuilder::balloon(...).

Technical implementation

  • Extends SandboxConfig with three optional fields:
    • balloon_initial_mib: guest-visible memory at boot;
    • balloon_min_mib: minimum guest-visible memory allowed at runtime;
    • balloon_control_socket: Unix socket path used by the host to submit runtime memory targets.
  • Adds SandboxBuilder::balloon(initial, min, control_socket) as the fluent API. The builder stores guest-visible MiB values instead of reclaimed pages so callers do not need to know the virtio-balloon representation.
  • Adds builder validation so balloon settings cannot exceed the configured memory ceiling and the minimum cannot exceed the initial target.
  • Updates the host spawn argument renderer to emit --balloon-initial-mib, --balloon-min-mib, and --balloon-control-socket only when the corresponding config values are present.
  • Extends the internal msb sandbox clap args with matching fields and passes them into microsandbox_runtime::vm::VmConfig.
  • Extends runtime VmConfig and its Debug output with the balloon fields.
  • In build_vm(), enables msb_krun::VmBuilder::balloon(...) whenever any balloon field is set. Missing initial defaults to the configured memory ceiling, and missing min defaults to 0, leaving the lower-level libkrun validation and max-page clamping as the final enforcement layer.
  • Updates the msb_krun dependency requirements to 0.1.15 and temporarily patches msb_krun to the enricoschaaf/msb-libkrun branch used by feat: add host-driven balloon controls libkrun#59. The lockfile resolves all internal msb_krun* crates from that same branch so microsandbox compiles against the new API before a crates.io release exists.

Dependency and firmware notes

  • This PR depends on feat: add host-driven balloon controls libkrun#59.
  • I did not open a libkrunfw PR. I checked the target firmware configs and they already carry the relevant virtio-balloon / compaction support, with memory hotplug enabled on the architectures where those options exist.
  • Once msb_krun 0.1.15 is published, the [patch.crates-io] entry can be removed and the dependency can resolve from crates.io normally.

Validation

  • cargo check -p microsandbox-runtime -p microsandbox-cli -p microsandbox
  • cargo test -p microsandbox balloon

Caviats

Main caveats in the current PRs:

  • No encrypted guest support. tee builds reject ballooning. The C API returns EOPNOTSUPP; the Rust builder returns a config error.

  • Guest cooperation is required. This only changes the virtio-balloon target. The guest kernel must have and load a working virtio-balloon driver. If the guest ignores the device or cannot reclaim memory, the host request may not take effect.

  • It is best-effort, not a hard memory cap. The VM still has the configured memory_mib ceiling. Ballooning asks the guest to give pages back; it does not resize the guest physical address space or enforce a cgroup-like limit.

  • Runtime targets are clamped, not rejected. If the control socket receives a target above the ceiling, it effectively becomes the ceiling. If it receives a target below min_mib, it clamps to min_mib. The response is OK <pages>, not the effective MiB target.

  • Dangerous default when partially configured. In microsandbox runtime, setting only one balloon field enables ballooning. If only the socket is set, initial defaults to the full memory ceiling and min defaults to 0, meaning the controller can request reclaiming essentially all guest memory.

  • The control socket is very simple. It accepts one decimal MiB target per connection. No auth, no structured protocol, no status query, no actual-memory reporting. Access control is only filesystem permissions on the socket path.

  • Socket bind failure does not fail VM startup. The listener is spawned after the VMM is built. If the parent directory does not exist, bind fails, or stale socket removal fails, it logs but the VM continues.

  • A stuck socket client can block control. The listener handles connections serially and uses read_line; a client that connects and never sends a newline/EOF can block later resize commands.

  • No cleanup lifecycle for the socket. The code removes a stale socket before binding, but does not explicitly unlink the socket on VM exit.

  • No SDK/top-level CLI exposure yet. The internal msb sandbox process accepts the flags, and Rust config/builder fields exist, but I did not wire public msb run/create flags or update Node/Python/Go SDK APIs.

  • Metrics still use the ceiling. Existing memory-limit metrics/reservation are based on memory_mib, not the current balloon target.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant