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 = 26; 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 complete migration for migratable component: {0}")] 58 CompleteMigration(#[source] anyhow::Error), 59 } 60 61 /// A Pausable component can be paused and resumed. 62 pub trait Pausable { 63 /// Pause the component. 64 fn pause(&mut self) -> std::result::Result<(), MigratableError> { 65 Ok(()) 66 } 67 68 /// Resume the component. 69 fn resume(&mut self) -> std::result::Result<(), MigratableError> { 70 Ok(()) 71 } 72 } 73 74 /// A Snapshottable component snapshot section. 75 /// Migratable component can split their migration snapshot into 76 /// separate sections. 77 /// Splitting a component migration data into different sections 78 /// allows for easier and forward compatible extensions. 79 #[derive(Clone, Default, Deserialize, Serialize)] 80 pub struct SnapshotDataSection { 81 /// The section id. 82 pub id: String, 83 84 /// The section serialized snapshot. 85 pub snapshot: Vec<u8>, 86 } 87 88 impl SnapshotDataSection { 89 /// Generate the state data from the snapshot data 90 pub fn to_state<'a, T>(&'a self) -> Result<T, MigratableError> 91 where 92 T: Deserialize<'a>, 93 { 94 serde_json::from_slice(&self.snapshot).map_err(|e| { 95 MigratableError::Restore(anyhow!("Error deserialising: {} {}", self.id, e)) 96 }) 97 } 98 99 /// Generate versioned state 100 pub fn to_versioned_state<T>(&self) -> Result<T, MigratableError> 101 where 102 T: Versionize + VersionMapped, 103 { 104 T::deserialize( 105 &mut self.snapshot.as_slice(), 106 &T::version_map(), 107 VMM_VERSION, 108 ) 109 .map_err(|e| MigratableError::Restore(anyhow!("Error deserialising: {} {}", self.id, e))) 110 } 111 112 /// Create from state that can be serialized 113 pub fn new_from_state<T>(id: &str, state: &T) -> Result<Self, MigratableError> 114 where 115 T: Serialize, 116 { 117 let snapshot = serde_json::to_vec(state) 118 .map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {} {}", id, e)))?; 119 120 let snapshot_data = SnapshotDataSection { 121 id: format!("{}-section", id), 122 snapshot, 123 }; 124 125 Ok(snapshot_data) 126 } 127 128 /// Create from versioned state 129 pub fn new_from_versioned_state<T>(id: &str, state: &T) -> Result<Self, MigratableError> 130 where 131 T: Versionize + VersionMapped, 132 { 133 let mut snapshot = Vec::new(); 134 state 135 .serialize(&mut snapshot, &T::version_map(), VMM_VERSION) 136 .map_err(|e| MigratableError::Snapshot(anyhow!("Error serialising: {} {}", id, e)))?; 137 138 let snapshot_data = SnapshotDataSection { 139 id: format!("{}-section", id), 140 snapshot, 141 }; 142 143 Ok(snapshot_data) 144 } 145 } 146 147 /// A Snapshottable component's snapshot is a tree of snapshots, where leafs 148 /// contain the snapshot data. Nodes of this tree track all their children 149 /// through the snapshots field, which is basically their sub-components. 150 /// Leaves will typically have an empty snapshots map, while nodes usually 151 /// carry an empty snapshot_data. 152 /// 153 /// For example, a device manager snapshot is the composition of all its 154 /// devices snapshots. The device manager Snapshot would have no snapshot_data 155 /// but one Snapshot child per tracked device. Then each device's Snapshot 156 /// would carry an empty snapshots map but a map of SnapshotDataSection, i.e. 157 /// the actual device snapshot data. 158 #[derive(Clone, Default, Deserialize, Serialize)] 159 pub struct Snapshot { 160 /// The Snapshottable component id. 161 pub id: String, 162 163 /// The Snapshottable component snapshots. 164 pub snapshots: std::collections::BTreeMap<String, Box<Snapshot>>, 165 166 /// The Snapshottable component's snapshot data. 167 /// A map of snapshot sections, indexed by the section ids. 168 pub snapshot_data: std::collections::HashMap<String, SnapshotDataSection>, 169 } 170 171 impl Snapshot { 172 /// Create an empty Snapshot. 173 pub fn new(id: &str) -> Self { 174 Snapshot { 175 id: id.to_string(), 176 ..Default::default() 177 } 178 } 179 180 /// Create from state that can be serialized 181 pub fn new_from_state<T>(id: &str, state: &T) -> Result<Self, MigratableError> 182 where 183 T: Serialize, 184 { 185 let mut snapshot_data = Snapshot::new(id); 186 snapshot_data.add_data_section(SnapshotDataSection::new_from_state(id, state)?); 187 188 Ok(snapshot_data) 189 } 190 191 /// Create from versioned state 192 pub fn new_from_versioned_state<T>(id: &str, state: &T) -> Result<Self, MigratableError> 193 where 194 T: Versionize + VersionMapped, 195 { 196 let mut snapshot_data = Snapshot::new(id); 197 snapshot_data.add_data_section(SnapshotDataSection::new_from_versioned_state(id, state)?); 198 199 Ok(snapshot_data) 200 } 201 202 /// Add a sub-component's Snapshot to the Snapshot. 203 pub fn add_snapshot(&mut self, snapshot: Snapshot) { 204 self.snapshots 205 .insert(snapshot.id.clone(), Box::new(snapshot)); 206 } 207 208 /// Add a SnapshotDatasection to the component snapshot data. 209 pub fn add_data_section(&mut self, section: SnapshotDataSection) { 210 self.snapshot_data.insert(section.id.clone(), section); 211 } 212 213 /// Generate the state data from the snapshot 214 pub fn to_state<'a, T>(&'a self, id: &str) -> Result<T, MigratableError> 215 where 216 T: Deserialize<'a>, 217 { 218 self.snapshot_data 219 .get(&format!("{}-section", id)) 220 .ok_or_else(|| MigratableError::Restore(anyhow!("Missing section for {}", id)))? 221 .to_state() 222 } 223 224 /// Generate versioned state 225 pub fn to_versioned_state<T>(&self, id: &str) -> Result<T, MigratableError> 226 where 227 T: Versionize + VersionMapped, 228 { 229 self.snapshot_data 230 .get(&format!("{}-section", id)) 231 .ok_or_else(|| MigratableError::Restore(anyhow!("Missing section for {}", id)))? 232 .to_versioned_state() 233 } 234 } 235 236 /// A snapshottable component can be snapshotted. 237 pub trait Snapshottable: Pausable { 238 /// The snapshottable component id. 239 fn id(&self) -> String { 240 String::new() 241 } 242 243 /// Take a component snapshot. 244 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 245 Ok(Snapshot::new("")) 246 } 247 248 /// Restore a component from its snapshot. 249 fn restore(&mut self, _snapshot: Snapshot) -> std::result::Result<(), MigratableError> { 250 Ok(()) 251 } 252 } 253 254 /// A transportable component can be sent or receive to a specific URL. 255 /// 256 /// This trait is meant to be used for component that have custom 257 /// transport handlers. 258 pub trait Transportable: Pausable + Snapshottable { 259 /// Send a component snapshot. 260 /// 261 /// # Arguments 262 /// 263 /// * `snapshot` - The migratable component snapshot to send. 264 /// * `destination_url` - The destination URL to send the snapshot to. This 265 /// could be an HTTP endpoint, a TCP address or a local file. 266 fn send( 267 &self, 268 _snapshot: &Snapshot, 269 _destination_url: &str, 270 ) -> std::result::Result<(), MigratableError> { 271 Ok(()) 272 } 273 274 /// Receive a component snapshot. 275 /// 276 /// # Arguments 277 /// 278 /// * `source_url` - The source URL to fetch the snapshot from. This could be an HTTP 279 /// endpoint, a TCP address or a local file. 280 fn recv(&self, _source_url: &str) -> std::result::Result<Snapshot, MigratableError> { 281 Ok(Snapshot::new("")) 282 } 283 } 284 285 /// Trait to be implemented by any component (device, CPU, RAM, etc) that 286 /// can be migrated. 287 /// All migratable components are paused before being snapshotted, and then 288 /// eventually resumed. Thus any Migratable component must be both Pausable 289 /// and Snapshottable. 290 /// Moreover a migratable component can be transported to a remote or local 291 /// destination and thus must be Transportable. 292 pub trait Migratable: Send + Pausable + Snapshottable + Transportable { 293 fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> { 294 Ok(()) 295 } 296 297 fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> { 298 Ok(()) 299 } 300 301 fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> { 302 Ok(MemoryRangeTable::default()) 303 } 304 305 fn start_migration(&mut self) -> std::result::Result<(), MigratableError> { 306 Ok(()) 307 } 308 309 fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> { 310 Ok(()) 311 } 312 } 313