Skip to content

Commit e0a93b7

Browse files
committed
doc: adapt snapshot versioning docs and CHANGELOG
Adapt documentation around snapshot versions format and compatibility to remove mentions of Versionize and the effects its usage had to snapshot compatibility. Also, add a CHANGELOG entry regarding the new strategy for snapshot versioning. Signed-off-by: Babis Chalios <[email protected]>
1 parent fb4c972 commit e0a93b7

File tree

5 files changed

+56
-148
lines changed

5 files changed

+56
-148
lines changed

CHANGELOG.md

+11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@
4242
Removed support for creating Firecracker snapshots targeting older versions
4343
of Firecracker. With this change, running 'firecracker --version' will not
4444
print the supported snapshot versions.
45+
- [#4230](https://github.com./firecracker-microvm/firecracker/pull/4230):
46+
Changed microVM snapshot format version strategy. Firecracker snapshot format
47+
now has a version that follows semantic versioning and is independent of
48+
Firecracker version. The current version of the snapshot format is v1.0.0.
49+
From now on, the Firecracker binary will define the snapshot format version
50+
it supports and it will only be able to load snapshots with format that is
51+
backwards compatible with that version, according to semantic versioning.
52+
Users can pass the `--snapshot-version` flag to the Firecracker binary to see
53+
its supported snapshot version format. This change renders all previous
54+
Firecracker snapshots (up to Firecracker version v1.5.0) incompatible with
55+
the current Firecracker version.
4556

4657
### Deprecated
4758

docs/images/version_graph.png

-24.3 KB
Binary file not shown.

docs/images/versionize.png

-47.1 KB
Binary file not shown.

docs/snapshotting/snapshot-support.md

+7-48
Original file line numberDiff line numberDiff line change
@@ -174,41 +174,13 @@ The snapshot functionality is still in developer preview due to the following:
174174

175175
## Snapshot versioning
176176

177-
The Firecracker snapshotting implementation offers support for snapshot versioning
178-
(`cross-version snapshots`) in the following contexts:
179-
180-
- Saving snapshots at older versions
181-
182-
**DEPRECATED**: This feature is deprecated starting with version 1.5.0. It
183-
will be removed in a subsequent release. After dropping support, Firecracker
184-
will be able to create snapshots only for the version supported by the
185-
Firecracker binary that launched the microVM and not for older versions.
186-
187-
This refers to being able to create a snapshot with any version in the
188-
`[N, N + o]` interval, while running Firecracker version `N+o`.
189-
190-
The possibility to save snapshots at older versions might not be offered by
191-
all Firecracker releases. Depending on the features that it introduces, a new
192-
Firecracker release `v` might drop the possibility to save snapshots at any
193-
versions older than `v`.
194-
195-
For example Firecracker v1.0 and v1.1 adds support for some additional virtio
196-
features (e.g. notification suppression). These features lead the guest
197-
drivers to behave in a very specific way and as a consequence the Firecracker
198-
devices have to respond accordingly. As a result, the snapshots that are
199-
created while these features are in use will not be backwards compatible with
200-
previous versions of Firecracker since the devices that come with these older
201-
versions do not behave in a way that’s compatible with the snapshotted guest
202-
drivers.
203-
204-
The list of versions that break snapshot backwards compatibility: `1.0`, `1.1`
205-
- Loading snapshots from older versions (being able to load a snapshot created
206-
by any Firecracker version in the `[N, N + o]` interval, in a Firecracker
207-
version `N+o`).
208-
209-
The design supports an unlimited number of versions, the value of `o` (maximum number
210-
of older versions that we can restore from / save a snapshot to, from the current
211-
version) will be defined later.
177+
The microVM state snapshot file uses a data format that follows semantic
178+
versioning. Each Firecracker binary supports a fixed version of the snapshot
179+
data format. When creating the snapshots it will use the supported data format
180+
version. When loading snapshots, Firecracker will check that the snapshot
181+
version is compatible with the version it supports. More information about the
182+
snapshot data format and details about snapshot data format versions can be
183+
found at [versioning](./versioning.md).
212184

213185
## Snapshot API
214186

@@ -293,7 +265,6 @@ curl --unix-socket /tmp/firecracker.socket -i \
293265
"snapshot_type": "Full",
294266
"snapshot_path": "./snapshot_file",
295267
"mem_file_path": "./mem_file",
296-
"version": "1.0.0"
297268
}'
298269
```
299270

@@ -322,24 +293,13 @@ the snapshot. If they exist, the files will be truncated and overwritten.
322293
- If diff snapshots were enabled, the snapshot creation resets then the
323294
dirtied page bitmap and marks all pages clean (from a diff snapshot point
324295
of view).
325-
- If a `version` is specified, the new snapshot is saved at that version,
326-
otherwise it will be saved at the latest snapshot version of the running
327-
Firecracker. The version is only used for the microVM state file as it
328-
contains internal state structures for device emulation, vCPUs and others
329-
that can change their format from a Firecracker version to another.
330-
Versioning is not required for the block and memory files.
331296

332297
- _on failure_: no side-effects.
333298

334299
**Notes**:
335300

336301
- The separate block device file components of the snapshot have to be handled
337302
by the user.
338-
- If specified, `version` must match the firecracker version that introduced a
339-
snapshot version, which may differ from the running Firecracker version. For
340-
example, if you are running on `1.1.2` and want to target version `1.0.4`, you
341-
should specify `1.0.0`. Not specifying `version` uses the latest snapshot
342-
version available to that version.
343303

344304
#### Creating diff snapshots
345305

@@ -357,7 +317,6 @@ curl --unix-socket /tmp/firecracker.socket -i \
357317
"snapshot_type": "Diff",
358318
"snapshot_path": "./snapshot_file",
359319
"mem_file_path": "./mem_file",
360-
"version": "1.0.0"
361320
}'
362321
```
363322

docs/snapshotting/versioning.md

+38-100
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,18 @@
11
# Firecracker snapshot versioning
22

3-
This document describes how Firecracker persists its state across multiple
4-
versions, diving deep into the snapshot format, encoding, compatibility and
3+
This document describes how Firecracker persists microVM state into Firecracker
4+
snapshots. It describes the snapshot format, encoding, compatibility and
55
limitations.
66

77
## Introduction
88

9-
The design behind the snapshot implementation enables version tolerant save
10-
and restore across multiple Firecracker versions which we call a version space.
11-
For example, one can pause a microVM, save it to disk with Firecracker version
12-
**0.23.0** and later load it in Firecracker version **0.24.0**. It also works
13-
in reverse: Firecracker version **0.23.0** loads what **0.24.0** saves.
14-
15-
Below is an example graph showing backward and forward snapshot compatibility.
16-
This is the general picture, but keep in mind that when adding new features
17-
some version translations would not be possible.
18-
19-
![Version graph](
20-
../images/version_graph.png?raw=true
21-
"Version graph")
22-
23-
A non-exhaustive list of how cross-version snapshot support can be used:
24-
25-
Example scenario #1 - load snapshot from older version:
26-
27-
* Start Firecracker v0.23 → Boot microVM → *Workload starts* → Pause →
28-
CreateSnapshot(snap) → kill microVM
29-
* Start Firecracker v0.24 → LoadSnapshot → Resume → *Workload continues*
30-
31-
Example scenario #2 - load snapshot in older version:
32-
33-
* Start Firecracker v0.24 → Boot microVM → *Workload starts* → Pause →
34-
CreateSnapshot(snap, “0.23”) → kill microVM
35-
* Start Firecracker v0.23 → LoadSnapshot(snap) → Resume → *Workload continues*
36-
37-
Example scenario #3 - load snapshot in older version:
38-
39-
* Start Firecracker v0.24 → LoadSnapshot(older_snap) → Resume →
40-
*Workload continues* → Pause → CreateSnapshot(snap, “0.23”) → kill microVM
41-
* Start Firecracker v0.23 → LoadSnapshot(snap) → Resume → *Workload continues*
9+
Firecracker uses the serde crate [1] along with the bincode [2] format to
10+
serialize its state into Firecracker snapshots. Firecracker snapshots have
11+
versions that are independent of Firecracker versions. Each Firecracker version
12+
declares support for a specific snapshot data format version. When creating a
13+
snapshot, Firecracker will use the supported snapshot format version. When
14+
loading a snapshot, Firecracker will check that format of the snapshot file is
15+
compatible with the snapshot version Firecracker supports.
4216

4317
## Overview
4418

@@ -61,59 +35,37 @@ emulation, KVM and vCPUs) with 2 exceptions - serial emulation and vsock backend
6135

6236
While we continuously improve and extend Firecracker's features by adding new
6337
capabilities, devices or enhancements, the microVM state file may change both
64-
structurally and semantically with each new release. The state file includes
65-
versioning information and each Firecracker release implements distinct
66-
save/restore logic for the supported version space.
38+
structurally and semantically with each new release.
6739

6840
## MicroVM state file format
6941

70-
A microVM state file is further split into four different fields:
42+
A Firecracker snapshot has the following format:
7143

72-
| Field | Bits| Description |
73-
|----|----|----|
74-
| magic_id | 64 | Firecracker snapshot, architecture (x86_64/aarch64) and storage version. |
75-
| version | 16 | The snapshot version number internally mapped 1:1 to a specific Firecracker version. |
44+
| Field | Bits | Description |
45+
|-------|------|-------------|
46+
| magic_id | 64 | Firecracker snapshot and architecture (x86_64/aarch64). |
47+
| version | M | The snapshot data format version (`MAJOR.MINOR.PATCH`) |
7648
| state | N | Bincode blob containing the microVM state. |
77-
| crc| 64 | Optional CRC64 sum of magic_id, version and state fields. |
78-
79-
**Note**: the last 16 bits of `magic_id` encode the storage version which specifies
80-
the encoding used for the `version` and `state` fields. The current
81-
implementation sets this field to 1, which identifies it as a [Serde bincode](https://github.com./servo/bincode)
82-
compatible encoder/decoder.
83-
84-
### Version tolerant ser/de
85-
86-
Firecracker reads and writes the `state` blob of the snapshot by using per
87-
version, separate serialization and deserialization logic. This logic is mostly
88-
autogenerated by a Rust procedural macro based on `struct` and `enum`
89-
annotations. Basically, one can say that these structures support versioning.
90-
The versioning logic is generated by parsing a structure's history log (encoded
91-
using Rust annotations) and emitting Rust code.
92-
93-
Versioned serialization and deserialization is divided into two translation layers:
94-
95-
* field translator,
96-
* semantic translator.
97-
98-
The _field translator_ implements the logic to convert between different
99-
versions of the same Rust POD structure: it can deserialize or serialize from
100-
source version to target.
101-
The translation is done field by field - the common fields are copied from
102-
source to target, and the fields that are unique to the target are
103-
(de)serialized with their default values.
104-
105-
The _semantic translator_ is only concerned with translating the semantics of
106-
the serialized/deserialized fields.
107-
108-
The _field translator_ is generated automatically through a procedural macro,
109-
and the _semantic translation methods_ have to be annotated in the structure
110-
by the user.
111-
112-
This block diagram illustrates the concept:
113-
114-
![Versionize](
115-
../images/versionize.png?raw=true
116-
"Versionize layers")
49+
| crc | 64 | Optional CRC64 sum of magic_id, version and state fields. |
50+
51+
The snapshot format has its own version encoded in the snapshot file itself
52+
after the snapshot's `magic_id`. The snapshot format version is independent of
53+
the Firecracker version and it follows semantic versioning, i.e.
54+
`MAJOR.MINOR.PATCH`. That means that backwards incompatible changes in the data
55+
format will cause `MAJOR` version number bump, whereas backwards compatible
56+
changes will cause a `MINOR` version number bump.
57+
58+
For example, that means that a Firecracker binary that supports snapshot data
59+
format `x.y.z` will be able to load all snapshot files with version `x.Y.z`
60+
where `Y <= y`.
61+
62+
Currently, Firecracker uses the [Serde bincode
63+
encoder](https://github.com./servo/bincode) for serializing the microVM state.
64+
The encoding format that bincode uses does not allow backwards compatible
65+
changes in the state, so essentially every change in the microVM state
66+
description will result in bump of the format's `MAJOR` version. If the needs
67+
arises, we will look into alternative formats that allow more flexibility with
68+
regards to backwards compatibility.
11769

11870
## VM state encoding
11971

@@ -132,10 +84,6 @@ Key benefits of using *bincode*:
13284

13385
The current implementation relies on the [Serde bincode encoder](https://github.com./servo/bincode).
13486

135-
Versionize is compatible to Serde with bincode backend: structures serialized
136-
with versionize at a specific version can be deserialized with Serde. Also
137-
structures serialized with serde can be deserialized with versionize.
138-
13987
## Snapshot compatibility
14088

14189
### Host kernel
@@ -195,18 +143,8 @@ specifically, the MSRs corresponding to the guest exposed features.
195143

196144
## Implementation
197145

198-
To enable Firecracker cross version snapshots we have designed and built two
199-
crates:
200-
201-
* [versionize](https://crates.io/crates/versionize) - defines the `Versionize`
202-
trait, implements serialization of primitive types and provides a helper
203-
class to map Firecracker versions to individual structure versions.
204-
* [versionize_derive](https://crates.io/crates/versionize_derive) - exports
205-
a procedural macro that consumes structures and enums and their annotations
206-
to produce an implementation of the `Versionize` trait.
207-
208-
The microVM state file format is implemented in the [snapshot crate](../../src/snapshot/src/lib.rs)
209-
in the Firecracker repository.
210-
All Firecracker devices implement the [Persist](../../src/snapshot/src/persist.rs)
146+
The microVM state file format is implemented in the [snapshot
147+
crate](../../src/snapshot/src/lib.rs) in the Firecracker repository. All
148+
Firecracker devices implement the [Persist](../../src/snapshot/src/persist.rs)
211149
trait which exposes an interface that enables creating from and saving to the
212150
microVM state.

0 commit comments

Comments
 (0)