Firecracker Architecture: How It Actually Works
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 48f1b9f detects 48 functional modules at
modularity Q=0.79, and the two biggest clusters are the virtio device layer
around GuestMemoryMmap (1002 symbols) and the API control plane around
ParsedRequest (675).
The map is unusually clean for a systems repo. The hubs are real domain types
(GuestMemoryMmap, ParsedRequest, VsockError, RateLimiter), the
heaviest edge runs from the API control plane into the device layer (192
calls), and the whole graph carries just 2 pairs of mutually recursive
symbols. 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.
Module map
The diagram shows the 10 largest of the 48 detected modules, with edges
weighted by how many calls cross between them. The biggest holds 1002 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; the symbol counts, hubs, and edge weights are
what the graph computed.
Where to start reading
The raw PageRank ranking on this repo is all unit converters and test
fixtures: u64_to_usize and mib_to_bytes from vmm/src/utils,
single_region_mem from the test utilities, bare new, add, and inc. A
hypervisor's most-called functions are tiny helpers, so the ranking says
little here. Start from the boot path and the module hubs instead.
build_microvm_for_bootGuestMemoryMmapParsedRequestVmmActionKvmVmVirtioDeviceCustomCpuTemplateRateLimiterMicrovmState
Key subsystems
Virtio devices and guest memory
GuestMemoryMmap is the handle to guest physical memory, and the virtio
plumbing that moves bytes through it (VirtioDevice, Queue,
VirtioInterrupt, the net device) clusters around it: 1002 symbols, the
largest module in the repo. Its heaviest inbound edge is the 192 calls from
the API control plane.
API server and VmmAction
The control plane. ParsedRequest.try_from
(src/firecracker/src/api_server/parsed_request.rs:69) turns each request on
the API socket into a VmmAction, and VmResources accumulates the machine
config before boot. 675 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. 557 symbols.
io_uring engine and bindings
The async block-IO engine: IoUringError, WrappedRequest, PendingRequest,
plus the __u32-style kernel ABI types the ring shares with Linux. 534
symbols.
Vsock device and muxer
The virtio-vsock device and its unix-socket muxer: VsockPacketTx,
VsockPacketRx, VsockConnection, MuxerRx. 507 symbols.
Balloon and block devices
Balloon, VirtioBlock, and DescriptorChain share one 504-symbol cluster.
Its hub is VirtQueue from devices/virtio/test_utils.rs, which is what a
hub looks like when the device tests drive every queue path in the cluster.
Shared infrastructure
The rest of the top 10: Seccomp BPF and device bus (457 symbols, hub
BpfInstruction), Metrics counters (438, hub SharedIncMetric), KvmVm and
memory regions (438, hub GuestRegionMmapExt), and CPU templates and CPUID
(423, hub CustomCpuTemplate).
Canonical request flow
The sequence worth reading first is the microVM build: everything between an
InstanceStart action and vcpu threads running. Allocate guest memory, create
the KVM VM and its vcpus, 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 edge out of
build_microvm_for_boot, in the order the work happens.
build_microvm_for_boot (src/vmm/src/builder.rs:143)VmResources.allocate_guest_memoryKvmVm.newKvmVm.create_vcpusDeviceManager.newload_kernelattach_block_devicesattach_net_devicesconfigure_system_for_bootKvmVm.start_vcpus
Health signals
Symvanta detected 0 dependency cycles across 48 modules (modularity Q=0.79). 2 sets of mutually recursive symbols were also detected, the largest being transport (2 symbols).
Auto-generated by Symvanta from the public repo firecracker-microvm/firecracker at commit 48f1b9f , licensed Apache-2.0 .
Machine-readable companion: data.json (module counts, subsystems, load-bearing symbols, health signals).