Project 8: An MMDS Feature Extension
The microVM Metadata Service (MMDS) is how a guest learns about itself without trusting the
host with a side channel. It is Firecracker's in-VMM answer to the EC2 Instance Metadata
Service: the operator PUTs a JSON document over the API socket, configures which guest
network interface serves it and on which link-local address, and the guest fetches it over
ordinary HTTP from inside the microVM. The twist that makes it interesting engineering is
that there is no host-side HTTP server — the request is served by dumbo, a tiny TCP/IP
stack that lives inside the VMM, intercepting packets on the configured interface and
answering them. MMDS is a small, self-contained, well-bounded subsystem that touches the
networking path, the API, a hand-rolled HTTP/TCP stack, and a security-relevant token
mechanism — which makes it an unusually good target for a scoped, mergeable feature.
This project asks you to extend MMDS: add a new metadata capability, improve the V2 (token/session) ergonomics, or add diagnostics that make MMDS behavior observable — with tests. The deliverable is a scoped feature plus integration tests, and (because MMDS is a small, evolving, contained subsystem) a realistic path to a real merged PR. It is the gentlest on-ramp in the portfolio to landing a feature — not a tool, not a study — in Firecracker proper.
Note: Read the MMDS metadata service deep dive in full and do the networking masterclass, especially Lab 3: MMDS. This brief assumes you understand the MMDS V1 vs V2 (token/session, IMDSv2-like) distinction, the
PUT /mmds/configvsPUT/PATCH/GET /mmdssplit, that the guest reaches MMDS over HTTP served by the in-VMMdumboTCP/IP stack (there is no host metadata server), and the link-local address (typically169.254.169.254) the guest queries. If those are fuzzy, do the lab first — this brief will not re-derive MMDS.
Problem & motivation
MMDS is deliberately minimal, and minimal subsystems leave well-shaped gaps that a careful contributor can fill without threatening the threat model or the device-model philosophy:
- It's a contained, evolving subsystem. MMDS has changed across releases — V1 was
deprecated in favor of the token-based V2, the config surface has been refined, the
dumbostack has been hardened. A subsystem that is small and still moving is exactly where a scoped feature has room to land, unlike the minimal device model where the bar for new surface is deliberately punishing. - V2 ergonomics have rough edges. The token/session model (get a token, then present it on every metadata request, with a configurable TTL) is more secure than V1 but more awkward to use and to debug. Clearer error responses, better token-lifecycle diagnostics, or a documented helper flow are real, low-risk improvements.
- Diagnostics are thin. When MMDS doesn't answer — wrong interface, wrong address, missing
token, malformed document, a
dumbopacket not being intercepted — the failure is opaque from both the guest and the host side. Observability into the MMDS path (what request arrived, why it was refused, which interface it was served on) is a genuine gap and a naturally mergeable contribution. - It's security-relevant but bounded. MMDS sits on the guest-facing network path and the V2 token is a security mechanism, so changes get real scrutiny — but the blast radius is contained to one subsystem, making it tractable to reason about and test fully.
The motivation is the cleanest "ship a feature" story in the portfolio: a self-contained subsystem, an evolving surface with room to add value, and a security relevance that's serious enough to be worth doing well but bounded enough to do completely.
What you'll build
Pick one direction and build it to maintainer quality with tests.
| Direction | What it is | Difficulty | Mergeability |
|---|---|---|---|
| A. A new metadata capability | A scoped extension to what MMDS can serve or how — e.g. a new response format/content negotiation, a richer query capability, a documented data-shape constraint, an IMDS-compat behavior FC lacks | Medium-Hard | Needs an issue/RFC first; scope tightly |
| B. V2 ergonomics / hardening | Clearer V2 error responses, a refined token TTL/lifecycle behavior, tighter request validation, a documented session flow with better failure messages | Medium | Good — security-positive, contained |
| C. Diagnostics / observability | MMDS-path metrics and logging: requests received, refusals and why (bad token, wrong iface, not found), token issuance/expiry counts, served-interface attribution | Medium | Best — pure addition, no contract change |
Whichever you choose, the artifact is: the feature as a minimum-diff change behind the
existing MMDS structure, unit tests for the logic (the dumbo HTTP/token handling), a
pytest integration test that drives MMDS from inside a real guest, a CHANGELOG.md entry,
and a design note stating what you did and did not change about the request/response
contract.
Tip: Direction C (diagnostics) is the recommended starting point. It's a pure addition — no change to the guest-facing request/response contract, no new attack surface, immediate value — which makes it the most likely to land and the best Phase-1 slice. You can always extend toward A or B as a stretch once the diagnostics exist (and they'll help you debug A/B).
Prerequisites
- Level 7 (the device model) and Level 3 (the API path) — MMDS spans both the network device and the API.
- The MMDS metadata service deep dive.
- The networking masterclass, especially Lab 3: MMDS and Lab 1: TAP and bridges.
- The virtio-net-and-tap deep dive — MMDS rides on the net path; you must know how packets reach the guest interface.
- The logging-and-metrics deep dive if you take Direction C — diagnostics plug into FC's existing metrics/logging.
- Working knowledge of HTTP/1.1 request handling and the link-local IMDS request shape.
Phased plan
Phase 0 — Build, map MMDS, and drive it from a guest (1–2 days)
Make MMDS concrete: configure it, query it from inside a microVM, then read how the request
flows from guest packet → dumbo → the MMDS document.
tools/devtool build --release
# MMDS and the in-VMM TCP/IP stack — read by role, never by line number:
rg -n "Mmds|MmdsVersion|V1|V2|token|session|mmds" src/vmm/src/mmds/
rg -n "dumbo|Tcp|parse_request|http|EthernetFrame|Ipv4|handle" src/vmm/src/dumbo/
# The API surface that configures and populates MMDS:
rg -n "/mmds|mmds-config|MmdsConfig|put_mmds|patch_mmds" src/firecracker/src/api_server/ src/vmm/src/vmm_config/
# How an MMDS request is dispatched on the net device path:
rg -n "mmds|ns|Mmds|is_mmds|169.254" src/vmm/src/devices/virtio/net/
Then drive it end to end. Configure V2, get a token from inside the guest, fetch metadata:
API=/tmp/fc.sock
# Pre-boot: set the document, then point MMDS at an interface as V2 (shapes — verify swagger):
curl -X PUT --unix-socket "$API" --data '{"latest":{"meta-data":{"instance-id":"i-abc"}}}' http://localhost/mmds
curl -X PUT --unix-socket "$API" --data '{"version":"V2","network_interfaces":["net1"],"ipv4_address":"169.254.169.254"}' http://localhost/mmds/config
# ... boot ... then INSIDE the guest (V2 = token first, like IMDSv2):
# TOKEN=$(curl -sX PUT "http://169.254.169.254/latest/api/token" -H "X-metadata-token-ttl-seconds: 21600")
# curl -s -H "X-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id
Anti-staleness: the MMDS module layout (
src/vmm/src/mmds/,src/vmm/src/dumbo/), the exact V2 token header names and TTL semantics, the/mmds/configbody shape, and the V1 deprecation state all move between releases. Confirm on your branch withrg/find, readdocs/mmds/(path — verify) and theswagger.yamlfor the exact bodies, and checkgit log --oneline -- src/vmm/src/mmds/ src/vmm/src/dumbo/andgh issue list --repo firecracker-microvm/firecracker --search "mmds OR metadata"for recent changes and live work you might be duplicating.
Produce capstone-work/mmds-path.md: the trace from a guest HTTP request → the net device
recognizing an MMDS-destined packet → dumbo parsing the TCP/HTTP → the token check (V2) →
the metadata lookup → the response, with file references found by rg.
Phase 1 — Reproduce the gap (the framing)
Before building, demonstrate the gap your feature fills. This makes the value concrete and gives you the "test that fails without the change."
- Direction C (diagnostics): show that today, a failed MMDS request (bad token, wrong interface, document not found) is opaque — no host-side signal of why. Capture the current (un-observable) behavior as the baseline.
- Direction B (V2 ergonomics): show a confusing or unhelpful V2 failure (e.g. a missing or expired token producing an opaque response) that your change clarifies.
- Direction A (new capability): show the capability is genuinely absent and would be used — and write the issue/RFC comment proposing it before you build, because a new guest-facing capability needs maintainer agreement.
Milestone 1: a written, reproduced statement of the gap, with the current behavior captured from a real guest.
Phase 2 — Build the feature (minimum diff, the MMDS way)
Implement behind the existing MMDS/dumbo structure. Keep the guest-facing contract stable
unless your chosen direction is a contract change (and if it is, you've already RFC'd it in
Phase 1).
- Diagnostics (C): add metrics/log points at the MMDS dispatch and refusal sites — request received, refusal reason, token issued/expired, served interface — wired into FC's existing metrics/logging. No request/response change.
- V2 ergonomics (B): improve the response/validation at the
dumboHTTP layer — clearer status/body on a bad/expired token, tighter request validation — without breaking the IMDSv2-compatible happy path. - New capability (A): add the capability behind a clear boundary, defaulting to current behavior so nothing existing changes unless explicitly used.
cargo test -p vmm mmds # the MMDS/dumbo unit tests — run them, then add yours
cargo clippy --all --all-targets --all-features -- -D warnings
Milestone 2: the feature works end to end from inside a real guest, and the existing MMDS behavior (V1 where still supported, the V2 happy path) is unchanged.
Phase 3 — Tests (the maintainer requirement)
New functionality requires an integration test — this is a hard rule, and MMDS is exactly the kind of guest-facing behavior that needs one. Drive MMDS from inside a real microVM and assert your new behavior.
# The existing MMDS integration tests are your template:
rg -n "mmds|def test_.*mmds|169.254|token" tests/integration_tests/functional/ | head
- Unit:
cargo testfor thedumboHTTP/token logic and any metadata-handling code you touched. - Integration (required): a pytest test that configures MMDS, boots, and from the guest exercises your feature — the diagnostic appearing in metrics, the clearer V2 error, or the new capability — and asserts both the new behavior and that the happy path still works.
- Negative control: the test should fail without your production change.
Phase 4 — Validation and the write-up
tools/devtool checkstyle+checkbuild --alloutput.- A
CHANGELOG.mdentry under## [Unreleased]. - A design note: what you changed, what you deliberately left alone (especially the guest-facing request/response contract and the V2 token semantics), and why.
Key code areas
| Area | Find it with |
|---|---|
| MMDS core (versions, token, document) | rg -n "Mmds|MmdsVersion|V2|token|session|ttl" src/vmm/src/mmds/ |
The dumbo in-VMM TCP/IP + HTTP stack | rg -n "dumbo|Tcp|parse_request|http|Ipv4|EthernetFrame" src/vmm/src/dumbo/ |
| MMDS dispatch on the net path | rg -n "mmds|is_mmds|ns|169.254|Mmds" src/vmm/src/devices/virtio/net/ |
The /mmds + /mmds/config API | rg -n "/mmds|MmdsConfig|mmds-config" src/firecracker/src/api_server/ src/firecracker/swagger/firecracker.yaml |
| MMDS config plumbing | rg -n "Mmds|mmds" src/vmm/src/vmm_config/ |
| Metrics/logging hooks (Direction C) | rg -n "METRICS|metric|IncMetric|SharedIncMetric|log" src/vmm/src/logger/ src/vmm/src/mmds/ |
| Existing MMDS tests | rg -n "mmds|def test_" tests/integration_tests/functional/ |
| Docs | ls docs/mmds/ (path — verify) |
Design considerations & trade-offs
- The guest-facing contract is near-permanent. The MMDS HTTP surface and the V2 token protocol are things guests depend on; a break is a downstream emergency. Diagnostics (C) are safe because they don't touch it; ergonomics (B) must preserve the IMDSv2-compatible happy path; a new capability (A) must default to current behavior. State explicitly what you kept stable.
dumbois a hand-rolled stack, and it's attack surface. Every byte of the in-VMM TCP/IP and HTTP parser is host code reachable from the guest network. Changes there get security scrutiny — keep them minimal, validate inputs, and don't add parsing surface you don't need. This is the threat model in miniature.- V2 is a security mechanism, not just ergonomics. The token/session model exists to prevent SSRF-style abuse (a confused guest process being tricked into fetching metadata). "Improving ergonomics" must not weaken that — a clearer error is good; a looser token check is a regression.
- Diagnostics must not leak. MMDS can hold sensitive data (it's metadata). A diagnostic that logs request contents or token values is a leak. Log shapes and reasons, not secrets — and say so in the design note.
- Scope is the whole game here. MMDS is mergeable because it's small. A sprawling
rewrite of
dumboor a large new capability loses that advantage. The Phase-1 slice should be the smallest change that delivers real value. - IMDS compatibility is a design anchor. MMDS deliberately mirrors EC2 IMDS so guests built for one work with the other. Any new behavior should ask "does this stay IMDS-compatible?" — divergence needs justification.
How to test & validate
- Correctness from the guest: drive MMDS from inside a real microVM (V2 token flow
included) and assert your new behavior end to end. A guest that gets the right metadata
through the right path is the proof the
dumbo/MMDS plumbing is correct. - Regression safety: the existing MMDS happy path (V2 token issue → metadata fetch, and V1 where still supported) must be unchanged — assert it in the same test.
- Unit:
cargo testfor thedumboHTTP/token and metadata-handling logic. - Integration (required): a pytest test under
tests/integration_tests/functional/modeled on the existing MMDS tests; it must fail without your change. - Security check: if you touched
dumboparsing or V2 tokens, reason about (and test) the malformed-input and bad/expired-token cases — they're the security-relevant paths.
Stretch goals
- Tie diagnostics to the boot/density harness: MMDS request latency under load is a real serverless concern; measure it.
- A V2 token-lifecycle test matrix: TTL expiry, token reuse, missing token, wrong-interface requests — turning the security-relevant edges into a thorough test suite (valuable on its own).
- A guest-side helper or documented flow for the V2 token dance, contributed to the docs — ergonomics that don't touch the protocol.
- Combine C with B: ship diagnostics first (the safe slice), then use them to drive an evidence-backed V2 ergonomics improvement.
What a strong deliverable looks like
A strong deliverable is a scoped MMDS feature — diagnostics, a V2 ergonomics/hardening
improvement, or a new capability — implemented as a minimum diff behind the existing
MMDS/dumbo structure, with unit tests and a required pytest integration test driving it
from inside a real guest, a CHANGELOG.md entry, and a design note stating exactly what stayed
stable about the guest-facing contract and the V2 token semantics.
The upstreaming path is the friendliest in the portfolio for a feature:
- Diagnostics are the safest merge. A pure-addition observability change (C) touches no
contract and adds no attack surface — the most likely brief in the portfolio to land as
written. Find the live state:
gh issue list --repo firecracker-microvm/firecracker --search "mmds OR metadata"and readdocs/mmds/. - Comment before you code for B and especially A. Anything touching the guest-facing surface or the V2 token semantics is compatibility- and security-sensitive — confirm the maintainers want it and agree on the shape before writing it.
- Bring the test. New functionality requires an integration test; a guest-driven test that exercises your feature and proves the happy path still works is exactly what gets an MMDS PR reviewed and merged.
Even if nothing lands upstream, a scoped MMDS feature with tests and a write-up is a portfolio-grade artifact: it demonstrates you can extend a guest-facing, security-relevant subsystem without breaking its contract — the core skill of a Firecracker feature contributor. A finished version at 90+ on the rubric is maintainer-grade networking/metadata work.
This is the last brief in the portfolio. You don't do all eight — you do one or two, well. Whatever you finished, present it the way the portfolio overview demands: lead with the problem and the constraint, show the before/after, show the diff is clean, state what you deliberately didn't do, and make it reproducible.
Next: return to the Capstone Project Portfolio overview to choose (or confirm) your one or two briefs, revisit the evaluation rubric to self-grade, and keep the appendix — the glossary, key types by crate, API endpoint map, and the cheat-sheets — open in a pane while you build.