Appendix A: Command-Line And Inspection Tools
The tools around a microVM fall into three groups: launchers, live inspectors, and static host inspectors. They do not all carry the same risk.
Lab boundary. Starting
firecracker,firectl, or accelerated QEMU opens/dev/kvm. The Jailer changes namespaces, cgroups, identity, mounts, and device nodes.kvm_statandperf kvmread system-wide KVM counters or tracepoints unless carefully filtered. Use those tools only on bare-metal Linux or in a disposable VM with nested virtualization. Do not attach them to an unrelated multi-tenant host. Thecpuid,lscpu,lsmod, and documented/procor/sysreads below are non-mutating, though access controls still apply.
| Tool | Answers | Important boundary |
|---|---|---|
firecracker |
How is one microVM configured and controlled? | opens KVM and device fds |
jailer |
Which host resources can Firecracker see? | privileged host mutation |
firectl |
Can a simple CLI assemble a Firecracker VM? | development wrapper, opens KVM |
qemu-system-x86_64 -M microvm |
How does QEMU expose a similar small machine? | KVM or slower TCG execution |
kvm_stat |
Which KVM events are accumulating? | debugfs and tracepoint access |
perf kvm |
Which exits occurred, when, and for how long? | perf and tracepoint access |
cpuid, lscpu |
Which CPU and hypervisor features are visible here? | reports the current host or guest view |
lsmod, /sys/module |
Which KVM modules and parameters are loaded? | presence is not usability |
firecracker
The firecracker binary owns one microVM. Its command line configures the
control plane around that VM; the HTTP API or JSON configuration describes the
machine itself.
The current command-line switches worth recognizing are:
| Switch | Purpose |
|---|---|
--api-sock <path> |
Unix socket for the HTTP API; defaults to /run/firecracker.socket |
--id <id> |
instance identifier used by logs and metrics |
--config-file <path> |
complete JSON VM configuration |
--no-api |
disable the API; requires --config-file |
--mmds-content <path> |
preload MMDS JSON from a file |
--log-path, --level, --module |
configure startup logging |
--metrics-path |
configure startup metrics output |
--seccomp-filter <path> |
load a custom compiled filter |
--no-seccomp |
disable seccomp; incompatible with --seccomp-filter |
--enable-pci |
use PCI transport for virtio devices instead of default MMIO |
--snapshot-version |
print the supported snapshot data format version |
--describe-snapshot <path> |
inspect a snapshot state's format version |
--no-api is batch mode, not merely "do not create a socket." Firecracker
loads the configuration file and starts without an active API server. The
startup-only logger and metrics flags are useful in that mode because there is
no later API call with which to configure them.
The PCI switch changes transport, not the guest device type. A virtio block device is still a virtio block device; the guest discovers its registers through PCI capabilities instead of the virtio-MMIO register page. Current developer-preview device hotplug requires this mode.
--start-time-us, --start-time-cpu-us, and --parent-cpu-time-us may appear
in a jailed process's arguments. They carry launcher timing into Firecracker's
boot metrics and are not normal operator configuration.
The API Socket
The API is HTTP/1.1 over the Unix socket. Pre-boot PUT requests configure the
boot source, machine, drives, network interfaces, entropy, balloon, memory
hotplug, pmem, vsock, MMDS, logging, and metrics. InstanceStart crosses the
state boundary after which only selected endpoints remain mutable. The exact
schema lives in Firecracker's in-tree OpenAPI document; Chapter 15 owns the
request sequence.
An API client needs filesystem permission to connect to the socket. It does
not thereby need /dev/kvm, but the already-running Firecracker process does.
Treat the socket as a privileged control interface: its caller can select host
files for guest drives and alter the VM lifecycle.
jailer
The Jailer is Firecracker's privileged launcher. Its required arguments are
--id, --exec-file, --uid, and --gid. The current optional interface
includes:
| Switch | Purpose |
|---|---|
--chroot-base-dir |
jail tree base, default /srv/jailer |
--netns <path> |
join an existing network namespace |
--new-pid-ns |
run Firecracker as the child in a new PID namespace |
--cgroup <file=value> |
repeatable cgroup setting |
--cgroup-version |
select v1 or v2; current default is v1 |
--parent-cgroup |
relative parent for the per-VM cgroup |
--resource-limit <name=value> |
set fsize or no-file limits |
--daemonize |
call setsid and redirect standard streams to /dev/null |
Arguments after -- are passed to the jailed executable. The Jailer closes
inherited fds, clears the environment, builds the jail, configures requested
cgroups and limits, changes root, drops identity, and execs Firecracker. The
exact ordering and optional namespace paths are covered in Chapter 18; avoid
inferring enabled isolation merely from the presence of the binary.
The PID file is useful evidence, but remember which PID namespace you are reading it from. A process may be PID 1 inside the optional child namespace and have a different PID on the host.
firectl
firectl is a small Go wrapper around firecracker-go-sdk. It translates one
command line into Firecracker configuration calls and connects the guest
console. Its main inputs are a kernel, root drive, optional additional drives,
vCPU and memory counts, TAP and vsock descriptions, kernel arguments, MMDS
JSON, and logging paths. Current source also contains optional Jailer settings.
Use firectl to explore a known kernel and rootfs, not as the specification of
Firecracker itself. Its defaults include an MMIO-oriented x86 kernel command
line, its feature surface trails the complete API, and the README's historical
getting-started download example still names very old Firecracker artifacts.
For an orchestrator or a reproducible production configuration, drive the
OpenAPI surface or a version-pinned SDK directly.
QEMU microvm
QEMU's x86 microvm machine is the closest stock comparison to Firecracker's
default machine. It has no PCI or ACPI, directly boots a host-supplied kernel,
and permits up to eight virtio-MMIO transports. Its optional legacy pieces are
the PIC, PIT, RTC, and ISA serial port. It has no hotplug and no live migration
across QEMU versions.
The machine properties pit, pic, rtc, isa-serial, and
x-option-roms can disable those optional pieces. auto-kernel-cmdline lets
QEMU append virtio-MMIO discovery arguments. -nodefaults and
-no-user-config remain relevant when constructing a controlled experiment,
because they suppress implicit devices and per-user configuration.
KVM acceleration and TCG answer different questions. KVM measures the
hardware-assisted path this book studies and requires /dev/kvm. TCG can run
without KVM and is useful for boot debugging, but QEMU's security policy gives
the non-virtualization TCG use case no guest-isolation guarantee. Do not compare
TCG timing with Firecracker timing as if the execution engines were equivalent.
HMP And QMP
The Human Monitor Protocol, or HMP, is QEMU's interactive console. Commands
such as info kvm, info registers, info cpus, info mtree, and the
info virtio* family expose accelerator state, CPU state, the memory map, and
virtio device or queue state. Command availability changes with QEMU builds;
help info is the live inventory.
The QEMU Machine Protocol, or QMP, is the JSON automation interface. A client
receives a greeting and must execute qmp_capabilities before normal commands.
A QMP socket is privileged: commands can add block backends, inspect VM state,
and initiate migration. Bind it to a protected local channel and let a trusted
management process own it.
kvm_stat
kvm_stat is a top-like Python tool shipped in the Linux source tree. It can
sample two providers:
- per-VM counters under KVM's debugfs directory; and
- KVM tracepoints opened through
perf_event_open(2).
It can display a curses UI, a one-shot batch, CSV, or a log. Important filters
include --pid, --guest, --fields, --debugfs, and --tracepoints.
--debugfs-include-past determines whether counters from dead VMs are included.
The counters need interpretation. A hardware VM exit need not become a
userspace return from KVM_RUN: KVM handles many exits in the kernel. An
ioeventfd notification may avoid a KVM_EXIT_MMIO return even though guest I/O
occurred. kvm_stat therefore describes KVM activity, not a direct count of
VMM event-loop iterations.
Exit names are architecture-specific. On x86, VMX reasons such as
EPT_VIOLATION and SVM reasons such as NPF describe hardware exits; names
such as MMIO, IO, and HLT in KVM_EXIT_* describe the userspace ABI.
They are related layers, not interchangeable enumerations.
perf kvm
perf kvm records and summarizes KVM trace events. Its stat family has three
useful phases:
stat recordcaptures events into a perf data file;stat reportaggregates a recording; andstat livereports a running system.
Architecture support determines which event classes are available. On x86,
the KVM statistics code can group VM exits and events such as MMIO and PIO and
report counts, total time, mean time, and time distribution. Because it uses
the perf subsystem and KVM tracepoints, permission depends on user identity,
perf_event_paranoid, capabilities, tracefs access, and kernel configuration.
Guest symbolization is a separate problem from exit accounting. It requires the correct guest kernel image and symbol files and a way to associate samples with the guest. An exit histogram can be valid even when every guest address is unresolved.
cpuid And lscpu
On x86, cpuid prints the feature leaves visible to the current CPU context.
The two first checks are:
| Feature | Leaf and bit | Meaning |
|---|---|---|
| VMX | leaf 0x1, ECX[5] |
Intel virtualization instructions are visible |
| SVM | leaf 0x80000001, ECX[2] |
AMD virtualization instructions are visible |
Visibility is not availability. Firmware may disable virtualization; a guest
may see the bit without nested virtualization being usable; permissions may
deny /dev/kvm; and KVM may reject a capability needed by a VMM.
When CPUID leaf 0x1 reports the hypervisor-present bit, leaf 0x40000000
identifies the paravirtual hypervisor interface and its maximum leaf. A KVM
guest commonly sees the KVMKVMKVM signature. That is the interface presented
to the guest, not proof that a particular userspace VMM such as Firecracker or
QEMU created it.
lscpu summarizes the same environment through kernel data. Its
Virtualization line describes a CPU extension such as VT-x or AMD-V. Its
hypervisor vendor and virtualization-type lines describe a detected guest
environment. Do not read a guest's lscpu output as an inventory of hidden
host hardware.
lsmod, /proc, And /sys
lsmod is a formatted view of /proc/modules. Typical x86 KVM hosts show the
common kvm module plus kvm_intel or kvm_amd; built-in modules need not
appear. A loaded module proves neither that firmware enabled virtualization nor
that the current user can open /dev/kvm.
Useful non-mutating paths include:
| Path | Information |
|---|---|
/sys/module/kvm*/parameters/ |
live KVM module parameters |
/sys/kernel/tracing/events/kvm/ |
available KVM tracepoints and formats |
/sys/kernel/debug/kvm/ |
KVM debugfs counters, when mounted and permitted |
/proc/<vmm-pid>/task/ |
threads and host TIDs |
/proc/<vmm-pid>/fd/ |
open KVM, TAP, eventfd, file, and socket descriptors |
/proc/<vmm-pid>/maps |
userspace mappings, including guest RAM backings |
Some module parameters are writable. Changing nested virtualization, EPT/NPT, or interrupt-virtualization settings changes host behavior and may require a module reload that disrupts every VM using it. This appendix intentionally does not provide mutation commands. Record the current values on an isolated lab host, consult the kernel parameter documentation for that exact version, and change them only as part of a host maintenance plan.