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 = 36; 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