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