xref: /cloud-hypervisor/vm-migration/src/lib.rs (revision 30ee2c129d7cf5cf9511a5115bcbcf71909ee824)
11b1a2175SSamuel Ortiz // Copyright © 2019 Intel Corporation
21b1a2175SSamuel Ortiz //
31b1a2175SSamuel Ortiz // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
41b1a2175SSamuel Ortiz //
51b1a2175SSamuel Ortiz 
66f5d4702SRob Bradford use anyhow::anyhow;
76f5d4702SRob Bradford use serde::{Deserialize, Serialize};
81b1a2175SSamuel Ortiz use thiserror::Error;
91b1a2175SSamuel Ortiz 
1088a9f799SRob Bradford use crate::protocol::MemoryRangeTable;
1188a9f799SRob Bradford 
12aa98589bSRob Bradford pub mod protocol;
13aa98589bSRob Bradford 
141b1a2175SSamuel Ortiz #[derive(Error, Debug)]
151b1a2175SSamuel Ortiz pub enum MigratableError {
16*30ee2c12SPhilipp Schuster     #[error("Failed to pause migratable component")]
171b1a2175SSamuel Ortiz     Pause(#[source] anyhow::Error),
181b1a2175SSamuel Ortiz 
19*30ee2c12SPhilipp Schuster     #[error("Failed to resume migratable component")]
201b1a2175SSamuel Ortiz     Resume(#[source] anyhow::Error),
211b1a2175SSamuel Ortiz 
22*30ee2c12SPhilipp Schuster     #[error("Failed to snapshot migratable component")]
231b1a2175SSamuel Ortiz     Snapshot(#[source] anyhow::Error),
241b1a2175SSamuel Ortiz 
25*30ee2c12SPhilipp Schuster     #[error("Failed to restore migratable component")]
261b1a2175SSamuel Ortiz     Restore(#[source] anyhow::Error),
271b1a2175SSamuel Ortiz 
28*30ee2c12SPhilipp Schuster     #[error("Failed to send migratable component snapshot")]
291b1a2175SSamuel Ortiz     MigrateSend(#[source] anyhow::Error),
301b1a2175SSamuel Ortiz 
31*30ee2c12SPhilipp Schuster     #[error("Failed to receive migratable component snapshot")]
321b1a2175SSamuel Ortiz     MigrateReceive(#[source] anyhow::Error),
33aa98589bSRob Bradford 
34*30ee2c12SPhilipp Schuster     #[error("Socket error")]
35aa98589bSRob Bradford     MigrateSocket(#[source] std::io::Error),
36c1b96204SSebastien Boeuf 
37*30ee2c12SPhilipp Schuster     #[error("Failed to start migration for migratable component")]
381c3f8236SSebastien Boeuf     StartDirtyLog(#[source] anyhow::Error),
39c1b96204SSebastien Boeuf 
40*30ee2c12SPhilipp Schuster     #[error("Failed to stop migration for migratable component")]
411c3f8236SSebastien Boeuf     StopDirtyLog(#[source] anyhow::Error),
42c1b96204SSebastien Boeuf 
43*30ee2c12SPhilipp Schuster     #[error("Failed to retrieve dirty ranges for migratable component")]
441c3f8236SSebastien Boeuf     DirtyLog(#[source] anyhow::Error),
45f65538b0SSebastien Boeuf 
46*30ee2c12SPhilipp Schuster     #[error("Failed to start migration for migratable component")]
47a9ccb20eSSebastien Boeuf     StartMigration(#[source] anyhow::Error),
48a9ccb20eSSebastien Boeuf 
49*30ee2c12SPhilipp Schuster     #[error("Failed to complete migration for migratable component")]
50f65538b0SSebastien Boeuf     CompleteMigration(#[source] anyhow::Error),
5105968f5cSPhilipp Schuster 
52*30ee2c12SPhilipp Schuster     #[error("Failed to release a disk lock before the migration")]
5305968f5cSPhilipp Schuster     UnlockError(#[source] anyhow::Error),
541b1a2175SSamuel Ortiz }
551b1a2175SSamuel Ortiz 
561b1a2175SSamuel Ortiz /// A Pausable component can be paused and resumed.
571b1a2175SSamuel Ortiz pub trait Pausable {
581b1a2175SSamuel Ortiz     /// Pause the component.
pause(&mut self) -> std::result::Result<(), MigratableError>591b1a2175SSamuel Ortiz     fn pause(&mut self) -> std::result::Result<(), MigratableError> {
601b1a2175SSamuel Ortiz         Ok(())
611b1a2175SSamuel Ortiz     }
621b1a2175SSamuel Ortiz 
631b1a2175SSamuel Ortiz     /// Resume the component.
resume(&mut self) -> std::result::Result<(), MigratableError>641b1a2175SSamuel Ortiz     fn resume(&mut self) -> std::result::Result<(), MigratableError> {
651b1a2175SSamuel Ortiz         Ok(())
661b1a2175SSamuel Ortiz     }
671b1a2175SSamuel Ortiz }
681b1a2175SSamuel Ortiz 
691b1a2175SSamuel Ortiz /// A Snapshottable component snapshot section.
7060c8a72eSBo Chen ///
711b1a2175SSamuel Ortiz /// Migratable component can split their migration snapshot into
721b1a2175SSamuel Ortiz /// separate sections.
731b1a2175SSamuel Ortiz /// Splitting a component migration data into different sections
741b1a2175SSamuel Ortiz /// allows for easier and forward compatible extensions.
751b1a2175SSamuel Ortiz #[derive(Clone, Default, Deserialize, Serialize)]
7610ab87d6SRob Bradford pub struct SnapshotData {
7710ab87d6SRob Bradford     state: String,
7810ab87d6SRob Bradford }
791b1a2175SSamuel Ortiz 
804517b76aSSebastien Boeuf impl SnapshotData {
8108c4e503SRob Bradford     /// Generate the state data from the snapshot data
to_state<'a, T>(&'a self) -> Result<T, MigratableError> where T: Deserialize<'a>,8208c4e503SRob Bradford     pub fn to_state<'a, T>(&'a self) -> Result<T, MigratableError>
8308c4e503SRob Bradford     where
8408c4e503SRob Bradford         T: Deserialize<'a>,
8508c4e503SRob Bradford     {
8610ab87d6SRob Bradford         serde_json::from_str(&self.state)
875b3bcfa2SSebastien Boeuf             .map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {}", e)))
88bbda0871SRob Bradford     }
89bbda0871SRob Bradford 
9008c4e503SRob Bradford     /// Create from state that can be serialized
new_from_state<T>(state: &T) -> Result<Self, MigratableError> where T: Serialize,915b3bcfa2SSebastien Boeuf     pub fn new_from_state<T>(state: &T) -> Result<Self, MigratableError>
9208c4e503SRob Bradford     where
9308c4e503SRob Bradford         T: Serialize,
9408c4e503SRob Bradford     {
9510ab87d6SRob Bradford         let state = serde_json::to_string(state)
965b3bcfa2SSebastien Boeuf             .map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {}", e)))?;
9708c4e503SRob Bradford 
9810ab87d6SRob Bradford         Ok(SnapshotData { state })
99bbda0871SRob Bradford     }
10008c4e503SRob Bradford }
10108c4e503SRob Bradford 
10260c8a72eSBo Chen /// Data structure to describe snapshot data
10360c8a72eSBo Chen ///
10412b72ba3SPhilipp Schuster /// A Snapshottable component's snapshot is a tree of snapshots, where leaves
1051b1a2175SSamuel Ortiz /// contain the snapshot data. Nodes of this tree track all their children
1061b1a2175SSamuel Ortiz /// through the snapshots field, which is basically their sub-components.
1071b1a2175SSamuel Ortiz /// Leaves will typically have an empty snapshots map, while nodes usually
1081b1a2175SSamuel Ortiz /// carry an empty snapshot_data.
1091b1a2175SSamuel Ortiz ///
1101b1a2175SSamuel Ortiz /// For example, a device manager snapshot is the composition of all its
1111b1a2175SSamuel Ortiz /// devices snapshots. The device manager Snapshot would have no snapshot_data
1121b1a2175SSamuel Ortiz /// but one Snapshot child per tracked device. Then each device's Snapshot
1134517b76aSSebastien Boeuf /// would carry an empty snapshots map but a map of SnapshotData, i.e.
1141b1a2175SSamuel Ortiz /// the actual device snapshot data.
1151b1a2175SSamuel Ortiz #[derive(Clone, Default, Deserialize, Serialize)]
1161b1a2175SSamuel Ortiz pub struct Snapshot {
1171b1a2175SSamuel Ortiz     /// The Snapshottable component snapshots.
1181d104331SSebastien Boeuf     pub snapshots: std::collections::BTreeMap<String, Snapshot>,
1191b1a2175SSamuel Ortiz 
1201b1a2175SSamuel Ortiz     /// The Snapshottable component's snapshot data.
1211b1a2175SSamuel Ortiz     /// A map of snapshot sections, indexed by the section ids.
1224517b76aSSebastien Boeuf     pub snapshot_data: Option<SnapshotData>,
1231b1a2175SSamuel Ortiz }
1241b1a2175SSamuel Ortiz 
1251b1a2175SSamuel Ortiz impl Snapshot {
from_data(data: SnapshotData) -> Self1263931b99dSSebastien Boeuf     pub fn from_data(data: SnapshotData) -> Self {
1273931b99dSSebastien Boeuf         Snapshot {
1283931b99dSSebastien Boeuf             snapshot_data: Some(data),
1293931b99dSSebastien Boeuf             ..Default::default()
1303931b99dSSebastien Boeuf         }
1313931b99dSSebastien Boeuf     }
1323931b99dSSebastien Boeuf 
1336f5d4702SRob Bradford     /// Create from state that can be serialized
new_from_state<T>(state: &T) -> Result<Self, MigratableError> where T: Serialize,134748018acSSebastien Boeuf     pub fn new_from_state<T>(state: &T) -> Result<Self, MigratableError>
1356f5d4702SRob Bradford     where
1366f5d4702SRob Bradford         T: Serialize,
1376f5d4702SRob Bradford     {
1383931b99dSSebastien Boeuf         Ok(Snapshot::from_data(SnapshotData::new_from_state(state)?))
1396f5d4702SRob Bradford     }
1406f5d4702SRob Bradford 
1411b1a2175SSamuel Ortiz     /// Add a sub-component's Snapshot to the Snapshot.
add_snapshot(&mut self, id: String, snapshot: Snapshot)142748018acSSebastien Boeuf     pub fn add_snapshot(&mut self, id: String, snapshot: Snapshot) {
143748018acSSebastien Boeuf         self.snapshots.insert(id, snapshot);
1441b1a2175SSamuel Ortiz     }
1451b1a2175SSamuel Ortiz 
1466f5d4702SRob Bradford     /// Generate the state data from the snapshot
to_state<'a, T>(&'a self) -> Result<T, MigratableError> where T: Deserialize<'a>,1475b3bcfa2SSebastien Boeuf     pub fn to_state<'a, T>(&'a self) -> Result<T, MigratableError>
1486f5d4702SRob Bradford     where
1496f5d4702SRob Bradford         T: Deserialize<'a>,
1506f5d4702SRob Bradford     {
15108c4e503SRob Bradford         self.snapshot_data
1525b3bcfa2SSebastien Boeuf             .as_ref()
1535b3bcfa2SSebastien Boeuf             .ok_or_else(|| MigratableError::Restore(anyhow!("Missing snapshot data")))?
15408c4e503SRob Bradford             .to_state()
1556f5d4702SRob Bradford     }
1561b1a2175SSamuel Ortiz }
1571b1a2175SSamuel Ortiz 
snapshot_from_id(snapshot: Option<&Snapshot>, id: &str) -> Option<Snapshot>1581f0e5eb6SSebastien Boeuf pub fn snapshot_from_id(snapshot: Option<&Snapshot>, id: &str) -> Option<Snapshot> {
1591d104331SSebastien Boeuf     snapshot.and_then(|s| s.snapshots.get(id).cloned())
1601f0e5eb6SSebastien Boeuf }
1611f0e5eb6SSebastien Boeuf 
state_from_id<'a, T>(s: Option<&'a Snapshot>, id: &str) -> Result<Option<T>, MigratableError> where T: Deserialize<'a>,16210ab87d6SRob Bradford pub fn state_from_id<'a, T>(s: Option<&'a Snapshot>, id: &str) -> Result<Option<T>, MigratableError>
1631f0e5eb6SSebastien Boeuf where
16410ab87d6SRob Bradford     T: Deserialize<'a>,
1651f0e5eb6SSebastien Boeuf {
16610ab87d6SRob Bradford     if let Some(s) = s.as_ref() {
16710ab87d6SRob Bradford         s.snapshots.get(id).map(|s| s.to_state()).transpose()
16810ab87d6SRob Bradford     } else {
16910ab87d6SRob Bradford         Ok(None)
17010ab87d6SRob Bradford     }
1711f0e5eb6SSebastien Boeuf }
1721f0e5eb6SSebastien Boeuf 
1731b1a2175SSamuel Ortiz /// A snapshottable component can be snapshotted.
1741b1a2175SSamuel Ortiz pub trait Snapshottable: Pausable {
1751b1a2175SSamuel Ortiz     /// The snapshottable component id.
id(&self) -> String1761b1a2175SSamuel Ortiz     fn id(&self) -> String {
1771b1a2175SSamuel Ortiz         String::new()
1781b1a2175SSamuel Ortiz     }
1791b1a2175SSamuel Ortiz 
1801b1a2175SSamuel Ortiz     /// Take a component snapshot.
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>181871138d5SSebastien Boeuf     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
182748018acSSebastien Boeuf         Ok(Snapshot::default())
1831b1a2175SSamuel Ortiz     }
1841b1a2175SSamuel Ortiz }
1851b1a2175SSamuel Ortiz 
1861b1a2175SSamuel Ortiz /// A transportable component can be sent or receive to a specific URL.
1871b1a2175SSamuel Ortiz ///
1881b1a2175SSamuel Ortiz /// This trait is meant to be used for component that have custom
1891b1a2175SSamuel Ortiz /// transport handlers.
1901b1a2175SSamuel Ortiz pub trait Transportable: Pausable + Snapshottable {
1911b1a2175SSamuel Ortiz     /// Send a component snapshot.
1921b1a2175SSamuel Ortiz     ///
1931b1a2175SSamuel Ortiz     /// # Arguments
1941b1a2175SSamuel Ortiz     ///
1951b1a2175SSamuel Ortiz     /// * `snapshot` - The migratable component snapshot to send.
1961b1a2175SSamuel Ortiz     /// * `destination_url` - The destination URL to send the snapshot to. This
1971b1a2175SSamuel Ortiz     ///   could be an HTTP endpoint, a TCP address or a local file.
send( &self, _snapshot: &Snapshot, _destination_url: &str, ) -> std::result::Result<(), MigratableError>1981b1a2175SSamuel Ortiz     fn send(
1991b1a2175SSamuel Ortiz         &self,
2001b1a2175SSamuel Ortiz         _snapshot: &Snapshot,
2011b1a2175SSamuel Ortiz         _destination_url: &str,
2021b1a2175SSamuel Ortiz     ) -> std::result::Result<(), MigratableError> {
2031b1a2175SSamuel Ortiz         Ok(())
2041b1a2175SSamuel Ortiz     }
2051b1a2175SSamuel Ortiz 
2061b1a2175SSamuel Ortiz     /// Receive a component snapshot.
2071b1a2175SSamuel Ortiz     ///
2081b1a2175SSamuel Ortiz     /// # Arguments
2091b1a2175SSamuel Ortiz     ///
2101b1a2175SSamuel Ortiz     /// * `source_url` - The source URL to fetch the snapshot from. This could be an HTTP
2111b1a2175SSamuel Ortiz     ///   endpoint, a TCP address or a local file.
recv(&self, _source_url: &str) -> std::result::Result<Snapshot, MigratableError>2121b1a2175SSamuel Ortiz     fn recv(&self, _source_url: &str) -> std::result::Result<Snapshot, MigratableError> {
213748018acSSebastien Boeuf         Ok(Snapshot::default())
2141b1a2175SSamuel Ortiz     }
2151b1a2175SSamuel Ortiz }
2161b1a2175SSamuel Ortiz 
21760c8a72eSBo Chen /// Trait to define shared behaviors of components that can be migrated
21860c8a72eSBo Chen ///
21960c8a72eSBo Chen /// Examples are device, CPU, RAM, etc.
2201b1a2175SSamuel Ortiz /// All migratable components are paused before being snapshotted, and then
2211b1a2175SSamuel Ortiz /// eventually resumed. Thus any Migratable component must be both Pausable
2221b1a2175SSamuel Ortiz /// and Snapshottable.
2231b1a2175SSamuel Ortiz /// Moreover a migratable component can be transported to a remote or local
2241b1a2175SSamuel Ortiz /// destination and thus must be Transportable.
225c1b96204SSebastien Boeuf pub trait Migratable: Send + Pausable + Snapshottable + Transportable {
start_dirty_log(&mut self) -> std::result::Result<(), MigratableError>226c1b96204SSebastien Boeuf     fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
227c1b96204SSebastien Boeuf         Ok(())
228c1b96204SSebastien Boeuf     }
229c1b96204SSebastien Boeuf 
stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError>230c1b96204SSebastien Boeuf     fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
231c1b96204SSebastien Boeuf         Ok(())
232c1b96204SSebastien Boeuf     }
233c1b96204SSebastien Boeuf 
dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError>234c1b96204SSebastien Boeuf     fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> {
235c1b96204SSebastien Boeuf         Ok(MemoryRangeTable::default())
236c1b96204SSebastien Boeuf     }
237f65538b0SSebastien Boeuf 
start_migration(&mut self) -> std::result::Result<(), MigratableError>238a45e458cSlizhaoxin1     fn start_migration(&mut self) -> std::result::Result<(), MigratableError> {
239a45e458cSlizhaoxin1         Ok(())
240a45e458cSlizhaoxin1     }
241a45e458cSlizhaoxin1 
complete_migration(&mut self) -> std::result::Result<(), MigratableError>242f65538b0SSebastien Boeuf     fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
243f65538b0SSebastien Boeuf         Ok(())
244f65538b0SSebastien Boeuf     }
245c1b96204SSebastien Boeuf }
246