Skip to content

macOS support: evaluate Apple Virtualization.framework via Code-Hex/vz #4

@CMGS

Description

@CMGS

Summary

Add macOS hypervisor support to cocoon by wrapping Tart CLI as the macOS backend, alongside the existing Cloud Hypervisor backend on Linux. This enables cocoon to manage Linux and macOS VMs on Apple Silicon.

Backend Evaluation

Candidate Language Go Integration Linux Guest macOS Guest GPU Verdict
Code-Hex/vz Go Native library ✅ (arm64) PVG In-process VM — cocoon exit = VM death, needs daemon or fork wrapper
tart Swift CLI wrapper PVG Recommended — external process like CH, simplest integration
libkrun/krunvm Rust CLI only ✅ Metal No macOS guest support
Lima Go Not embeddable Full VM manager, too much overlap with cocoon

Why Tart over Code-Hex/vz

Code-Hex/vz is a native Go binding for Apple's Virtualization.framework with full PVG support (MacGraphicsDeviceConfiguration, VirtioGraphicsDeviceConfiguration). However, VF VMs are in-process Go objects — the VM dies when the process exits. This forces one of:

  • (A) cocoon becomes a long-running daemon (major architecture change)
  • (B) fork a cocoon _vm-runner subprocess per VM (reinventing tart)

Tart solves this naturally: tart run is a standalone process (like cloud-hypervisor), tracked via PID file. cocoon's existing fork + PID file + signal architecture maps 1:1.

Graphics & Remote Access

macOS guests on Apple Silicon get GPU acceleration via ParavirtualizedGraphics.framework:

  • Guest sees a Metal GPU device (PVG — not CPU software rendering)
  • Metal calls are forwarded to the host's real GPU via virtio
  • Performance is near-native

For headless remote access:

Method How Performance Recommendation
macOS Screen Sharing (VNC) Built-in, enable via launchctl Adequate for daily use Default option
Apple Remote Desktop Enhanced VNC + management Better than raw VNC Enterprise
Sunshine + Moonlight GPU-encoded H.265 streaming <10ms latency, 60fps Best for interactive use

cocoon does not need to handle display at the hypervisor layer — the VM runs Screen Sharing or Sunshine internally.

Networking

macOS has no CNI/netns. Tart uses macOS vmnet.framework:

Mode Command IP Assignment Isolation Use Case
Shared (NAT) tart run (default) macOS DHCP, 192.168.64.x Low Development
Bridged tart run --net-bridged=en0 LAN DHCP, same subnet as host None Production — VM directly reachable
Softnet tart run --net-softnet macOS DHCP High, inter-VM isolation Multi-tenant

cocoon's macOS network provider is thin:

  • Does NOT create/manage network resources (macOS vmnet handles everything)
  • Passes --net-bridged=<iface> to tart run (configurable interface)
  • Queries IP post-boot via tart ip <vm-name>
  • Delete is a no-op (macOS auto-reclaims vmnet resources)

For remote access to headless Mac hosts: use bridged mode so VMs get same-subnet IPs, directly reachable from the network.

Architecture

hypervisor/
├── hypervisor.go          # Hypervisor interface (unchanged)
├── cloudhypervisor/       # Linux backend (unchanged)
└── tart/                  # NEW: macOS backend
    ├── tart.go            # Hypervisor interface implementation
    ├── create.go          # tart clone/create
    ├── start.go           # tart run --no-graphics --net-bridged=en0 &
    │                      #   fork + PID file (same pattern as CH)
    ├── stop.go            # tart stop <name>
    ├── console.go         # tart ip → VNC connect, or SSH
    └── gc.go              # GC module

network/
├── network.go             # Network interface (unchanged)
├── cni/                   # Linux CNI (unchanged)
└── tart/                  # NEW: macOS no-op network
    └── tart.go            # Thin wrapper — delegates to macOS vmnet

images/
├── images.go              # Images interface (unchanged)
└── tart/                  # NEW: delegates to tart CLI
    └── tart.go            # tart pull/list/delete wrapper

Key design: tart backend mirrors CH backend

Aspect Cloud Hypervisor (Linux) Tart (macOS)
Process model fork cloud-hypervisor fork tart run
Process tracking PID file + /proc PID file + kill(pid, 0)
Stop API socket → SIGTERM → SIGKILL tart stop → SIGTERM
Console Unix socket / PTY VNC to guest IP
Network CNI + netns + TAP + TC redirect macOS vmnet (bridged/NAT)
Images Custom OCI pull + EROFS convert tart pull from OCI registry
Graphics N/A (serial/VNC) PVG Metal acceleration

Prerequisite changes

  1. Add HypervisorBackend field to config.Config (e.g., "cloud-hypervisor", "tart")
  2. Make cmd/core/helpers.go InitHypervisor() a factory with switch conf.HypervisorBackend
  3. Platform-aware defaults in DefaultConfig() (Linux → CH, Darwin → tart)
  4. Network interface: skip netns on macOS (tart network provider is a no-op)
  5. Existing Hypervisor interface needs no changes

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions