Architecture

Firecracker Architecture: How It Actually Works

firecracker-microvm/firecracker Apache-2.0 1 diagram
How to read this page

Symvanta parsed this repository into a code graph: every function, class, and method is a node, and every call or import between them is an edge. Everything on this page is computed from that graph at the commit shown above. The terms:

Module (or cluster)
A group of symbols that call each other far more than they call anything else. An algorithm called Louvain community detection finds these groups from the call traffic alone; nobody draws them by hand.
Modularity (the Q number)
A 0-to-1 score of how cleanly those groups separate. Higher means more call traffic stays inside its own group; scores around 0.7 and above read as clean boundaries.
Hub
The most depended-upon symbol inside one module.
Load-bearing symbols
PageRank, the algorithm Google originally used to rank web pages, run over the call graph instead: it surfaces the functions the rest of the codebase leans on hardest.
Arrows and their numbers
How many calls cross from one module into another. A heavier arrow means tighter coupling between those two parts.
Dependency cycle
File A imports B, which imports A again, sometimes through a longer loop. Cycles are not bugs, but a change inside one tends to ripple around the whole loop.
Mutually recursive symbols
Functions that call each other, usually the natural shape of parsers and tree-walking code.

Firecracker is the virtual machine monitor behind AWS Lambda and Fargate: one Rust binary that boots stripped-down microVMs on KVM, driven by a REST API over a unix socket, with its own virtio devices, seccomp filters, and a jailer. Symvanta's graph at 81b38b9 detects 46 functional modules (modularity Q=0.79), and the three biggest clusters are guest memory and the device trait built on it (886 symbols, hub GuestMemoryMmap), the virtio descriptor ring (739, hub Queue), and the VMM core the API drives (714, hub Net).

The map is clean for a systems repo. The hubs are real domain types (GuestMemoryMmap, Queue, ParsedRequest, VirtioBlock), the graph carries zero dependency cycles and just 2 pairs of mutually recursive symbols, and the heaviest edge runs from the VMM core into guest memory (210 calls). The devices sit in a ring around guest memory, which is what a VMM looks like when every device's job is moving bytes in and out of the guest. Two virtio transports coexist in that ring: the MMIO transport in devices/virtio/transport/mmio.rs, and a PCI stack of 460 symbols under vmm/src/pci whose VirtioPciDevice puts the same devices on a PCI bus.

Module map

The diagram shows the 10 largest of the 46 detected modules, with edges weighted by how many calls cross between them. The biggest holds 886 symbols and its hub is GuestMemoryMmap, the guest-physical-memory handle every virtio device keeps a clone of. Module names are checked by hand against the files their members live in and renamed where the generated label misread the cluster; the symbol counts, hubs, and edge weights are what the graph computed.

firecracker-microvm/firecracker module map: the 10 largest of 46 detected modules with call-weighted edges, generated by Symvanta
Module map of firecracker-microvm/firecracker, generated by Symvanta. Link to this diagram Open full size

Where to start reading

The raw PageRank ranking says little on this repo. Half of its top twelve are scaffolding: http_request is a helper inside the parsed-request test module (api_server/parsed_request.rs:423), single_region_mem comes from vmm/src/test_utils, default_virtio_mem, default_mem and default_vmm are per-suite defaults, and is_activated is a DummyDevice stub in the MMIO device manager. The other half are converters and bare method names: u64_to_usize, write_be_u16, host_page_size, plus new, add and setup. A hypervisor's most-called functions are tiny helpers. The list below is built from the boot path and the hub of each cluster in the diagram.

Key subsystems

Guest memory and the device trait

GuestMemoryMmap is a collection of GuestRegionMmapExt regions (vstate/memory.rs:38 and :399), and the graph clusters it with the VirtioDevice trait every device implements and the KvmVm handle they are wired against. 886 symbols, the largest module in the repo, and its heaviest outbound edge is the 136 calls into the VMM core.

Virtio queues and rate limiting

The descriptor ring in devices/virtio/queue.rs: available and used ring parsing, descriptor chain walking, and the RateLimiter token buckets that throttle block and net traffic. 739 symbols. The cluster also holds the VirtQueue fixture from devices/virtio/test_utils.rs that the device suites build rings with.

VMM core and machine configuration

The Louvain label for this cluster is the Net device, its hub, but the membership is the VMM top level: VmmError and FcExitCode in vmm/src/lib.rs, the EventManager loop, and the vmm_config structs (BootSourceConfig, RateLimiterConfig) that describe a machine before it boots. 714 symbols, and it carries the heaviest edge on the map: 210 calls into guest memory.

API server and VmmAction

The control plane. ParsedRequest (firecracker/src/api_server/parsed_request.rs:62) turns each request on the API socket into a VmmAction from rpc_interface.rs, and VmResources accumulates the machine config before boot. 646 symbols, and 196 of its calls land in the VMM core.

Device activation and vsock

DeviceState (devices/virtio/device.rs:35) is the enum every virtio device carries to say whether it is inactive or active, and the graph clusters it with the virtio-vsock packets, connections, and unix-socket muxer under devices/virtio/vsock. 642 symbols.

Dumbo MMDS network stack

InnerBytes, MacAddr, and Connection from vmm/src/dumbo: a hand-written TCP stack that serves the metadata service (MMDS) to guests directly from the VMM process, with the Mmds data store behind it. 555 symbols, and only 26 calls leave it, 14 of them into the API server that exposes MMDS.

PCI and the virtio-pci transport

Configuration space and BAR programming in vmm/src/pci, MSI-X interrupt tables in pci/msix.rs, and the VirtioPciDevice transport that puts a virtio device on the PCI bus. 460 symbols, hub PciSBDF, the segment, bus, device and function address a config access is decoded from.

io_uring engine and bindings

The async block-IO engine: the submission and completion rings in vmm/src/io_uring, IoUringError, and the bindgen kernel ABI types (io_uring_sqe, Cqe, the __u32 family) the ring shares with Linux. 459 symbols, and nearly a leaf: 8 outbound calls, 5 of them into the block device that drives it.

Block devices

The virtio-block device in devices/virtio/block/virtio, its vhost-user variant, and the cache-type and file-engine selection a block device boots with. 459 symbols, and its heaviest edge is the 133 calls into the queue cluster, which is what a block device does for a living.

Shared infrastructure

The tenth cluster in the diagram is CPU templates and CPUID (396 symbols, hub CustomCpuTemplate): the register and CPUID leaf modifiers under vmm/src/cpu_config. Just outside it sit metrics and logging (356, hub SharedIncMetric), the jailer binary (333, hub JailerError), and machine configuration around the vm-memory crate's GuestRegionMmap (282), the one hub in the top fifteen that is not defined in this repo at all.

Canonical request flow

The sequence worth reading first is the microVM build: everything between an InstanceStart action and vcpu threads running. Allocate guest memory, open KVM, create the VM and its vcpus, register the memory regions, build the device manager, load the kernel, attach the block and net devices, configure the system for boot, then start the vcpus under their seccomp filters. Every step below is a call out of build_microvm_for_boot, in the order the work happens. Three of them are compiled per architecture: the links point at the x86_64 copy, and aarch64 carries a twin of each.

  1. build_microvm_for_boot (builder.rs:143) takes the boot source, the accumulated VmResources, the event manager, and the seccomp filter map, and returns a paused Vmm.
  2. VmResources.allocate_guest_memory (resources.rs:519) turns the machine config's memory size and huge-page setting into a vector of guest regions.
  3. Kvm.new (vstate/kvm.rs:29) opens /dev/kvm and applies the capability modifiers the CPU template asked for.
  4. KvmVm.new (arch/x86_64/vm.rs:74) creates the VM file descriptor and the arch-specific interrupt state. The struct is per-arch; its shared methods come from one impl KvmVm block in vstate/vm.rs:141.
  5. KvmVm.create_vcpus (vstate/vm.rs:200) creates one Vcpu per configured vcpu, each with its own exit event fd.
  6. KvmVm.register_dram_memory_regions (vstate/vm.rs:453) hands the allocated regions to KVM as guest memory slots.
  7. DeviceManager.new (device_manager/mod.rs:233) builds the MMIO bus, the PCI bus when PCI is enabled, the serial console, and the resource allocator every later attach draws addresses from.
  8. load_kernel (arch/x86_64/mod.rs:500) reads the kernel image into guest memory and returns its entry point, then InitrdConfig::from_config places the initrd behind it.
  9. attach_block_devices (builder.rs:659) registers each configured block device on the bus and appends its root-device arguments to the kernel command line.
  10. attach_net_devices (builder.rs:691) does the same for the net devices, and attach_pmem_devices follows for persistent memory.
  11. configure_system_for_boot (arch/x86_64/mod.rs:237) applies the CPU template to every vcpu, writes the boot parameters and the device information the guest reads at startup, and seals the command line.
  12. KvmVm.start_vcpus (vstate/vm.rs:243) moves each vcpu onto its own thread, installs the vcpu seccomp filter there, and leaves the state machine paused until the API says resume.

Health signals

Symvanta detected 0 dependency cycles across 46 modules (modularity Q=0.79). 2 sets of mutually recursive symbols were also detected, the largest being transport (2 symbols). Both pairs are small and local: MmioTransport.set_device_status (transport/mmio.rs:165) loops back through the transport's own write, and the second pair sits in the virtio queue fixtures.

See your own codebase mapped like this. Free for 7 days, no credit card.

Start free trial →

Auto-generated by Symvanta from the public repo firecracker-microvm/firecracker at commit 81b38b9 , licensed Apache-2.0 .

Machine-readable companion: data.json (module counts, subsystems, load-bearing symbols, health signals).

Get this for your codebase →