This episode covers adding resources live: adding vCPUs and memory through the API socket without restarting, their reflection in the guest via ACPI, and VFIO device passthrough for GPUs and other devices. You'll also get to know the still-experimental vfio-user and safe practices for hotplugging in production.

With networking ready in episode 7, now we talk operational agility: the ability to change VM resources without shutting it down. In the cloud world, "restart to add RAM" is a luxury you can't always afford — especially when a production workload is serving thousands of requests.
Hotplug in Cloud Hypervisor is built on kernel mechanisms (ACPI) and operated through the API socket. In episode 8 we add vCPUs and memory live, verify them inside the guest, then cover the highest level of flexibility: device passthrough with VFIO to give physical devices directly to a VM.
To operate a running VM, enable API control at startup:
cloud-hypervisor \
--kernel kernel-vmlinux \
--disk path=os.raw \
--cpus boot=2,max=16 \
--memory size=2G,hotplug_size=12G,hotplugged_size=0 \
--api-socket /tmp/ch.sock \
--serial tty--api-socket /tmp/ch.sock opens a Unix socket as the remote control. All hotplug, snapshot, and live migration operations are done through this socket using curl (Cloud Hypervisor uses HTTP over the Unix socket).
curl --unix-socket /tmp/ch.sock http://localhost/api/v1/vm.infovm.info shows the VM's current configuration — from vCPU and memory to attached devices. It's the starting point for all runtime operations.
curl --unix-socket /tmp/ch.sock -X PUT \
-H "Content-Type: application/json" \
--data '{"desired_vcpus": 6}' \
http://localhost/api/v1/vm.resizedesired_vcpus: 6 raises the vCPU count from 2 to 6 without stopping the VM. The upper bound is the max set at startup (max=16 in the example above). To scale back down, set desired_vcpus to a smaller number.
Inside the guest, the new vCPUs appear as online CPUs after the OS processes the ACPI notification. Verify:
nproc
lscpu | grep "^CPU(s):"
cat /sys/devices/system/cpu/onlineSometimes new CPUs need to be activated explicitly (depending on distro and kernel config). If nproc hasn't changed, check whether the CPU is detected but offline:
ls /sys/devices/system/cpu/cpu6/
echo 1 | sudo tee /sys/devices/system/cpu/cpu6/onlineMemory is hotplugged through an ACPI device that can be "plugged in" to the guest. With hotplug_size=12G in the config, we have room to add:
curl --unix-socket /tmp/ch.sock -X PUT \
-H "Content-Type: application/json" \
--data '{"desired_ram": 6442450944}' \
http://localhost/api/v1/vm.resizedesired_ram: 6442450944 (6 GB) raises RAM from 2 GB to 6 GB. The number is in bytes — the same trap as the JSON config in episode 5.
Inside the guest, the additional memory appears as new memory blocks. Verify with:
free -h
grep -c "online" /sys/devices/system/memory/memory*/stateIf the total memory in free -h hasn't changed, check whether the new memory block is still offline:
echo online | sudo tee /sys/devices/system/memory/memory*/stateImportant
Memory hotplug is not always immediately visible in the guest without room for a new memory block (e.g., starting the VM with a size that isn't a multiple of the 128 MB memory block, or because the memory zone doesn't allow it). Safe practice: always start with a size that's a multiple of 128 MB and test hotplug in the lab before production.
The opposite of adding, virtio-balloon lets the host reclaim memory the guest isn't using:
curl --unix-socket /tmp/ch.sock -X PUT \
-H "Content-Type: application/json" \
--data '{"desired_size": 536870912}' \
http://localhost/api/v1/vm.resizedesired_size: 536870912 (512 MB) pressures the guest to return memory to the host. This is the basis of memory oversubscription: run many VMs on limited physical memory, then reclaim when load drops.
Sometimes virtio isn't enough — a workload needs physical devices directly: GPUs for rendering/AI, special NICs, or FPGAs. VFIO (Virtual Function I/O) lets a host PCI device be detached from the host and handed to the VM whole. The guest talks directly to the hardware, without emulation, with the help of the IOMMU.
First, detach the device from its host driver and bind it to vfio-pci:
echo 0000:01:00.0 | sudo tee /sys/bus/pci/devices/0000:01:00.0/driver/unbind
echo vfio-pci | sudo tee /sys/bus/pci/devices/0000:01:00.0/driver_override
echo 0000:01:00.0 | sudo tee /sys/bus/pci/drivers_probeThen present it to the VM with --device:
cloud-hypervisor \
--kernel kernel-vmlinux \
--disk path=os.raw \
--device path=/sys/bus/pci/devices/0000:01:00.0 \
--cpus boot=4 \
--memory size=8G--device path=... hands the vfio device to the guest. Inside the guest, the device appears as a normal PCI device with the appropriate driver.
intel_iommu=on or amd_iommu=on in the host kernel cmdline).shared=on for passthrough, because the physical device reads guest memory via DMA.ls -l /sys/kernel/iommu_groups/ | headWarning
Passthrough is a high-risk operation: one wrongly detached device can make the host lose its NIC. Always test on a lab host, and separate the host's management NIC from the device being passed through.
vfio-user is an experimental protocol that provides a virtual PCI device from another process — like VFIO, but the device is simulated in userspace, not physical hardware. This opens the door to software-defined "passthrough": a device (e.g., a virtual NVMe or GPU) runs in a separate process and is connected to the VM.
The advantages: better isolation (an error in the device process doesn't bring down the VMM) and safer memory handling. Because it's still experimental, use it carefully and watch its status on the official roadmap (episode 17).
max: adding vCPUs/memory above the limit set at startup is rejected by the API. Set max and hotplug_size from the start.CONFIG_ACPI_HOTPLUG_CPU/CONFIG_ACPI_HOTPLUG_MEMORY and that acpid is running.free in the guest.vm.info to make sure the hotplug request was actually accepted by the VMM.Tip
Combine hotplug with monitoring: add resources based on metrics (episode 20), not guesses. Automation that calls the resize API when a threshold is reached is a VM autoscaling pattern commonly used in production.
Key takeaways:
--api-socket) is the remote control for runtime operations via HTTP.desired_vcpus and desired_ram in /api/v1/vm.resize add resources live.nproc, free, and sysfs.desired_size) reclaims idle memory back to the host.shared=on.In the next episode, episode 9, we'll prepare cloud images & cloud-init — downloading Ubuntu/Fedora/Debian cloud images, converting them to raw, booting via direct or UEFI, and doing automatic bootstrap (password, SSH key, packages) with cloud-init user-data and metadata. Your VMs will be ready to use without manual interaction!