Skip to main content

microvm_runtime/
model.rs

1use std::fmt;
2use std::path::PathBuf;
3
4use serde::Serialize;
5
6/// Current lifecycle state of a microVM.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
8#[serde(rename_all = "snake_case")]
9pub enum VmStatus {
10    /// Provisioned but not yet started.
11    Created,
12    /// Actively running.
13    Running,
14    /// Gracefully stopped; can be restarted.
15    Stopped,
16    /// Torn down; terminal state.
17    Destroyed,
18}
19
20impl fmt::Display for VmStatus {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        match self {
23            Self::Created => f.write_str("created"),
24            Self::Running => f.write_str("running"),
25            Self::Stopped => f.write_str("stopped"),
26            Self::Destroyed => f.write_str("destroyed"),
27        }
28    }
29}
30
31/// Read-only snapshot of a microVM's current state.
32#[derive(Debug, Clone, Serialize)]
33pub struct VmView {
34    /// Unique identifier for this microVM.
35    pub vm_id: String,
36    /// Current lifecycle status.
37    pub status: VmStatus,
38    /// Names of snapshots captured for this VM, in creation order.
39    pub snapshots: Vec<String>,
40}
41
42/// Per-VM configuration override. Every field is optional; `None` falls back to the
43/// provider's workspace-level default (e.g. [`FirecrackerConfig`](crate::adapters::firecracker::FirecrackerConfig)).
44///
45/// Use [`VmSpec::default`] for cold boot with workspace defaults, or set
46/// [`VmSpec::restore_from`] to restore from a snapshot instead of cold-booting.
47///
48/// To do a warm-pool handoff — a pre-restored VM that swaps its TAP and IP onto a
49/// new tenant — set [`VmSpec::restore_from`] with [`SnapshotRef::network_overrides`]
50/// populated. Firecracker 1.10+ supports this; 1.6 rejects it.
51#[derive(Debug, Clone, Default)]
52pub struct VmSpec {
53    /// Kernel image path. None = use workspace default.
54    pub kernel: Option<PathBuf>,
55    /// Rootfs image path. None = use workspace default.
56    pub rootfs: Option<PathBuf>,
57    /// Mount rootfs read-only. None = use workspace default.
58    pub rootfs_read_only: Option<bool>,
59    /// vCPU count override.
60    pub vcpu_count: Option<u8>,
61    /// Memory size in MiB override.
62    pub mem_size_mib: Option<u32>,
63    /// Kernel command-line override.
64    pub boot_args: Option<String>,
65    /// Rate limit applied to the rootfs drive.
66    pub rootfs_rate_limit: Option<RateLimiter>,
67    /// Network interfaces to attach pre-boot. Firecracker requires these to be configured
68    /// before `InstanceStart`. Empty by default — the VM has no network unless explicitly set.
69    pub network_interfaces: Vec<NetworkInterface>,
70    /// Additional drives beyond rootfs (e.g. workspace volume, sidecar, nix store).
71    /// Empty by default. Configured via `PUT /drives/<drive_id>`.
72    pub extra_drives: Vec<DriveSpec>,
73    /// Vsock device. When `Some`, configured via `PUT /vsock` before `InstanceStart`.
74    /// Required for guest↔host RPC channels (e.g. talking to a guest sidecar).
75    pub vsock: Option<VsockSpec>,
76    /// If set, the VM boots from a snapshot via `PUT /snapshot/load` instead of cold-booting.
77    /// The spec's `kernel`, `rootfs`, `vcpu_count`, `mem_size_mib`, `boot_args`,
78    /// `network_interfaces`, `extra_drives`, and `vsock` are ignored when restoring
79    /// (the snapshot encodes its own machine config). Use
80    /// [`SnapshotRef::network_overrides`] to swap network interfaces on restore.
81    pub restore_from: Option<SnapshotRef>,
82    /// Track dirty pages during execution — required to later capture diff snapshots.
83    /// None = enabled (FC's safer default for snapshot-friendly workloads).
84    pub track_dirty_pages: Option<bool>,
85}
86
87/// Additional drive beyond the rootfs.
88#[derive(Debug, Clone)]
89pub struct DriveSpec {
90    /// Identifier used by Firecracker for this drive (must be unique per VM).
91    pub drive_id: String,
92    /// Path on host to the backing file (ext4 image, or any block file).
93    pub path_on_host: PathBuf,
94    /// Mount as read-only in guest.
95    pub is_read_only: bool,
96    /// Optional bandwidth + ops rate limit.
97    pub rate_limiter: Option<RateLimiter>,
98}
99
100/// Vsock device config.
101///
102/// Firecracker's vsock implementation uses a unix socket on the host (`uds_path`) and
103/// a 32-bit Context ID (`cid`) that the guest reads to identify the channel.
104#[derive(Debug, Clone)]
105pub struct VsockSpec {
106    /// Guest context ID. Must not collide with other VMs on the same host.
107    /// Use [`crate::vsock::VsockManager`] to allocate.
108    pub cid: u32,
109    /// Host-side unix domain socket path. The parent directory MUST exist
110    /// before snapshot/load — see [`crate::vsock::VsockManager::ensure_uds_parent`].
111    pub uds_path: PathBuf,
112}
113
114/// Firecracker `RateLimiter` config, applicable to drives and network interfaces.
115///
116/// At least one of `bandwidth` / `ops` should be set; setting both is allowed.
117/// See <https://github.com/firecracker-microvm/firecracker/blob/main/docs/api_requests/patch-rate-limiter.md>.
118#[derive(Debug, Clone, Default)]
119pub struct RateLimiter {
120    /// Bandwidth token bucket (units = bytes).
121    pub bandwidth: Option<TokenBucket>,
122    /// Operations token bucket (units = IO ops).
123    pub ops: Option<TokenBucket>,
124}
125
126/// Token bucket parameters. Caller specifies `refill_time_ms`; serialization translates
127/// to Firecracker's `refill_time` (also in ms — but we keep the suffix explicit on our side
128/// to avoid the "is this seconds?" question).
129#[derive(Debug, Clone)]
130pub struct TokenBucket {
131    /// Bucket size (bytes for bandwidth, ops for ops).
132    pub size: u64,
133    /// Optional one-time burst capacity used at start. Defaults to `size` if `None`.
134    pub one_time_burst: Option<u64>,
135    /// Refill period in milliseconds.
136    pub refill_time_ms: u64,
137}
138
139/// Network interface attached to a VM.
140#[derive(Debug, Clone)]
141pub struct NetworkInterface {
142    /// Identifier used by FC for this interface (e.g. `"eth0"`).
143    pub iface_id: String,
144    /// Host-side TAP device name (e.g. `"tap-abcd1234"`).
145    pub host_dev_name: String,
146    /// Guest-visible MAC address. None = let Firecracker assign one.
147    pub guest_mac: Option<String>,
148    /// Rate limit applied to received traffic on this NIC.
149    pub rx_rate_limiter: Option<RateLimiter>,
150    /// Rate limit applied to transmitted traffic on this NIC.
151    pub tx_rate_limiter: Option<RateLimiter>,
152}
153
154/// Reference to a snapshot used to restore a VM.
155#[derive(Debug, Clone)]
156pub struct SnapshotRef {
157    /// VM the snapshot was taken from.
158    pub vm_id: String,
159    /// Snapshot name.
160    pub snapshot_id: String,
161    /// If true, transition straight to `Running` after restore (Firecracker's `resume_vm` flag).
162    /// If false, the VM is restored in Paused state and needs an explicit `start_vm`.
163    pub resume_immediately: bool,
164    /// If non-empty, replace the snapshot's recorded network interfaces with these on load.
165    /// Use this for warm-pool handoff: a pre-restored VM swaps its TAP/MAC to a new tenant
166    /// without a full re-boot. Firecracker 1.10+ required; earlier versions reject the field.
167    pub network_overrides: Vec<NetworkInterface>,
168}