xref: /cloud-hypervisor/vm-migration/src/lib.rs (revision adb318f4cd0079246b3cb07e01c4e978330445d2)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
4 //
5 
6 use crate::protocol::MemoryRangeTable;
7 use anyhow::anyhow;
8 use serde::{Deserialize, Serialize};
9 use thiserror::Error;
10 use versionize::{VersionMap, Versionize};
11 
12 pub mod protocol;
13 
14 /// Global VMM version for versioning
15 const MAJOR_VERSION: u16 = 38;
16 const MINOR_VERSION: u16 = 0;
17 const VMM_VERSION: u16 = MAJOR_VERSION << 12 | MINOR_VERSION & 0b1111;
18 
19 pub trait VersionMapped {
20     fn version_map() -> VersionMap {
21         VersionMap::new()
22     }
23 }
24 
25 #[derive(Error, Debug)]
26 pub enum MigratableError {
27     #[error("Failed to pause migratable component: {0}")]
28     Pause(#[source] anyhow::Error),
29 
30     #[error("Failed to resume migratable component: {0}")]
31     Resume(#[source] anyhow::Error),
32 
33     #[error("Failed to snapshot migratable component: {0}")]
34     Snapshot(#[source] anyhow::Error),
35 
36     #[error("Failed to restore migratable component: {0}")]
37     Restore(#[source] anyhow::Error),
38 
39     #[error("Failed to send migratable component snapshot: {0}")]
40     MigrateSend(#[source] anyhow::Error),
41 
42     #[error("Failed to receive migratable component snapshot: {0}")]
43     MigrateReceive(#[source] anyhow::Error),
44 
45     #[error("Socket error: {0}")]
46     MigrateSocket(#[source] std::io::Error),
47 
48     #[error("Failed to start migration for migratable component: {0}")]
49     StartDirtyLog(#[source] anyhow::Error),
50 
51     #[error("Failed to stop migration for migratable component: {0}")]
52     StopDirtyLog(#[source] anyhow::Error),
53 
54     #[error("Failed to retrieve dirty ranges for migratable component: {0}")]
55     DirtyLog(#[source] anyhow::Error),
56 
57     #[error("Failed to start migration for migratable component: {0}")]
58     StartMigration(#[source] anyhow::Error),
59 
60     #[error("Failed to complete migration for migratable component: {0}")]
61     CompleteMigration(#[source] anyhow::Error),
62 }
63 
64 /// A Pausable component can be paused and resumed.
65 pub trait Pausable {
66     /// Pause the component.
67     fn pause(&mut self) -> std::result::Result<(), MigratableError> {
68         Ok(())
69     }
70 
71     /// Resume the component.
72     fn resume(&mut self) -> std::result::Result<(), MigratableError> {
73         Ok(())
74     }
75 }
76 
77 /// A Snapshottable component snapshot section.
78 /// Migratable component can split their migration snapshot into
79 /// separate sections.
80 /// Splitting a component migration data into different sections
81 /// allows for easier and forward compatible extensions.
82 #[derive(Clone, Default, Deserialize, Serialize)]
83 pub struct SnapshotData(pub Vec<u8>);
84 
85 impl SnapshotData {
86     /// Generate the state data from the snapshot data
87     pub fn to_state<'a, T>(&'a self) -> Result<T, MigratableError>
88     where
89         T: Deserialize<'a>,
90     {
91         serde_json::from_slice(&self.0)
92             .map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {}", e)))
93     }
94 
95     /// Generate versioned state
96     pub fn to_versioned_state<T>(&self) -> Result<T, MigratableError>
97     where
98         T: Versionize + VersionMapped,
99     {
100         T::deserialize(&mut self.0.as_slice(), &T::version_map(), VMM_VERSION)
101             .map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {}", e)))
102     }
103 
104     /// Create from state that can be serialized
105     pub fn new_from_state<T>(state: &T) -> Result<Self, MigratableError>
106     where
107         T: Serialize,
108     {
109         let data = serde_json::to_vec(state)
110             .map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {}", e)))?;
111 
112         Ok(SnapshotData(data))
113     }
114 
115     /// Create from versioned state
116     pub fn new_from_versioned_state<T>(state: &T) -> Result<Self, MigratableError>
117     where
118         T: Versionize + VersionMapped,
119     {
120         let mut data = Vec::new();
121         state
122             .serialize(&mut data, &T::version_map(), VMM_VERSION)
123             .map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {}", e)))?;
124 
125         Ok(SnapshotData(data))
126     }
127 }
128 
129 /// A Snapshottable component's snapshot is a tree of snapshots, where leafs
130 /// contain the snapshot data. Nodes of this tree track all their children
131 /// through the snapshots field, which is basically their sub-components.
132 /// Leaves will typically have an empty snapshots map, while nodes usually
133 /// carry an empty snapshot_data.
134 ///
135 /// For example, a device manager snapshot is the composition of all its
136 /// devices snapshots. The device manager Snapshot would have no snapshot_data
137 /// but one Snapshot child per tracked device. Then each device's Snapshot
138 /// would carry an empty snapshots map but a map of SnapshotData, i.e.
139 /// the actual device snapshot data.
140 #[derive(Clone, Default, Deserialize, Serialize)]
141 pub struct Snapshot {
142     /// The Snapshottable component snapshots.
143     pub snapshots: std::collections::BTreeMap<String, Snapshot>,
144 
145     /// The Snapshottable component's snapshot data.
146     /// A map of snapshot sections, indexed by the section ids.
147     pub snapshot_data: Option<SnapshotData>,
148 }
149 
150 impl Snapshot {
151     pub fn from_data(data: SnapshotData) -> Self {
152         Snapshot {
153             snapshot_data: Some(data),
154             ..Default::default()
155         }
156     }
157 
158     /// Create from state that can be serialized
159     pub fn new_from_state<T>(state: &T) -> Result<Self, MigratableError>
160     where
161         T: Serialize,
162     {
163         Ok(Snapshot::from_data(SnapshotData::new_from_state(state)?))
164     }
165 
166     /// Create from versioned state
167     pub fn new_from_versioned_state<T>(state: &T) -> Result<Self, MigratableError>
168     where
169         T: Versionize + VersionMapped,
170     {
171         Ok(Snapshot::from_data(SnapshotData::new_from_versioned_state(
172             state,
173         )?))
174     }
175 
176     /// Add a sub-component's Snapshot to the Snapshot.
177     pub fn add_snapshot(&mut self, id: String, snapshot: Snapshot) {
178         self.snapshots.insert(id, snapshot);
179     }
180 
181     /// Generate the state data from the snapshot
182     pub fn to_state<'a, T>(&'a self) -> Result<T, MigratableError>
183     where
184         T: Deserialize<'a>,
185     {
186         self.snapshot_data
187             .as_ref()
188             .ok_or_else(|| MigratableError::Restore(anyhow!("Missing snapshot data")))?
189             .to_state()
190     }
191 
192     /// Generate versioned state
193     pub fn to_versioned_state<T>(&self) -> Result<T, MigratableError>
194     where
195         T: Versionize + VersionMapped,
196     {
197         self.snapshot_data
198             .as_ref()
199             .ok_or_else(|| MigratableError::Restore(anyhow!("Missing snapshot data")))?
200             .to_versioned_state()
201     }
202 }
203 
204 pub fn snapshot_from_id(snapshot: Option<&Snapshot>, id: &str) -> Option<Snapshot> {
205     snapshot.and_then(|s| s.snapshots.get(id).cloned())
206 }
207 
208 pub fn versioned_state_from_id<T>(
209     snapshot: Option<&Snapshot>,
210     id: &str,
211 ) -> Result<Option<T>, MigratableError>
212 where
213     T: Versionize + VersionMapped,
214 {
215     snapshot
216         .and_then(|s| s.snapshots.get(id).cloned())
217         .map(|s| s.to_versioned_state())
218         .transpose()
219 }
220 
221 /// A snapshottable component can be snapshotted.
222 pub trait Snapshottable: Pausable {
223     /// The snapshottable component id.
224     fn id(&self) -> String {
225         String::new()
226     }
227 
228     /// Take a component snapshot.
229     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
230         Ok(Snapshot::default())
231     }
232 }
233 
234 /// A transportable component can be sent or receive to a specific URL.
235 ///
236 /// This trait is meant to be used for component that have custom
237 /// transport handlers.
238 pub trait Transportable: Pausable + Snapshottable {
239     /// Send a component snapshot.
240     ///
241     /// # Arguments
242     ///
243     /// * `snapshot` - The migratable component snapshot to send.
244     /// * `destination_url` - The destination URL to send the snapshot to. This
245     ///                       could be an HTTP endpoint, a TCP address or a local file.
246     fn send(
247         &self,
248         _snapshot: &Snapshot,
249         _destination_url: &str,
250     ) -> std::result::Result<(), MigratableError> {
251         Ok(())
252     }
253 
254     /// Receive a component snapshot.
255     ///
256     /// # Arguments
257     ///
258     /// * `source_url` - The source URL to fetch the snapshot from. This could be an HTTP
259     ///                  endpoint, a TCP address or a local file.
260     fn recv(&self, _source_url: &str) -> std::result::Result<Snapshot, MigratableError> {
261         Ok(Snapshot::default())
262     }
263 }
264 
265 /// Trait to be implemented by any component (device, CPU, RAM, etc) that
266 /// can be migrated.
267 /// All migratable components are paused before being snapshotted, and then
268 /// eventually resumed. Thus any Migratable component must be both Pausable
269 /// and Snapshottable.
270 /// Moreover a migratable component can be transported to a remote or local
271 /// destination and thus must be Transportable.
272 pub trait Migratable: Send + Pausable + Snapshottable + Transportable {
273     fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
274         Ok(())
275     }
276 
277     fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
278         Ok(())
279     }
280 
281     fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> {
282         Ok(MemoryRangeTable::default())
283     }
284 
285     fn start_migration(&mut self) -> std::result::Result<(), MigratableError> {
286         Ok(())
287     }
288 
289     fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
290         Ok(())
291     }
292 }
293