xref: /cloud-hypervisor/vm-migration/src/protocol.rs (revision 7d7bfb2034001d4cb15df2ddc56d2d350c8da30f)
1 // Copyright © 2020 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 
6 use crate::{MigratableError, VersionMapped};
7 use std::io::{Read, Write};
8 use versionize::{VersionMap, Versionize, VersionizeResult};
9 use versionize_derive::Versionize;
10 use vm_memory::ByteValued;
11 
12 // Migration protocol
13 // 1: Source establishes communication with destination (file socket or TCP connection.)
14 // (The establishment is out of scope.)
15 // 2: Source -> Dest : send "start command"
16 // 3: Dest -> Source : sends "ok response" when read to accept state data
17 // 4: Source -> Dest : sends "config command" followed by config data, length
18 //                     in command is length of config data
19 // 5: Dest -> Source : sends "ok response" when ready to accept memory data
20 // 6: Source -> Dest : send "memory command" followed by table of u64 pairs (GPA, size)
21 //                     followed by the memory described in those pairs.
22 //                     !! length is size of table i.e. 16 * number of ranges !!
23 // 7: Dest -> Source : sends "ok response" when ready to accept more memory data
24 // 8..(n-4): Repeat steps 6 and 7 until source has no more memory to send
25 // (n-3): Source -> Dest : sends "state command" followed by state data, length
26 //                     in command is length of config data
27 // (n-2): Dest -> Source : sends "ok response"
28 // (n-1): Source -> Dest : send "complete command"
29 // n: Dest -> Source: sends "ok response"
30 //
31 // "Local version": (Handing FDs across socket for memory)
32 // 1: Source establishes communication with destination (file socket or TCP connection.)
33 // (The establishment is out of scope.)
34 // 2: Source -> Dest : send "start command"
35 // 3: Dest -> Source : sends "ok response" when read to accept state data
36 // 4: Source -> Dest : sends "config command" followed by config data, length
37 //                     in command is length of config data
38 // 5: Dest -> Source : sends "ok response" when ready to accept memory data
39 // 6: Source -> Dest : send "memory fd command" followed by u16 slot ID and FD for memory
40 // 7: Dest -> Source : sends "ok response" when received
41 // 8..(n-4): Repeat steps 6 and 7 until source has no more memory to send
42 // (n-3): Source -> Dest : sends "state command" followed by state data, length
43 //                     in command is length of config data
44 // (n-2): Dest -> Source : sends "ok response"
45 // (n-1): Source -> Dest : send "complete command"
46 // n: Dest -> Source: sends "ok response"
47 //
48 // The destination can at any time send an "error response" to cancel
49 // The source can at any time send an "abandon request" to cancel
50 
51 #[repr(u16)]
52 #[derive(Copy, Clone)]
53 pub enum Command {
54     Invalid,
55     Start,
56     Config,
57     State,
58     Memory,
59     Complete,
60     Abandon,
61     MemoryFd,
62 }
63 
64 impl Default for Command {
65     fn default() -> Self {
66         Self::Invalid
67     }
68 }
69 
70 #[repr(C)]
71 #[derive(Default, Copy, Clone)]
72 pub struct Request {
73     command: Command,
74     padding: [u8; 6],
75     length: u64, // Length of payload for command excluding the Request struct
76 }
77 
78 // SAFETY: Request contains a series of integers with no implicit padding
79 unsafe impl ByteValued for Request {}
80 
81 impl Request {
82     pub fn new(command: Command, length: u64) -> Self {
83         Self {
84             command,
85             length,
86             ..Default::default()
87         }
88     }
89 
90     pub fn start() -> Self {
91         Self::new(Command::Start, 0)
92     }
93 
94     pub fn state(length: u64) -> Self {
95         Self::new(Command::State, length)
96     }
97 
98     pub fn config(length: u64) -> Self {
99         Self::new(Command::Config, length)
100     }
101 
102     pub fn memory(length: u64) -> Self {
103         Self::new(Command::Memory, length)
104     }
105 
106     pub fn memory_fd(length: u64) -> Self {
107         Self::new(Command::MemoryFd, length)
108     }
109 
110     pub fn complete() -> Self {
111         Self::new(Command::Complete, 0)
112     }
113 
114     pub fn abandon() -> Self {
115         Self::new(Command::Abandon, 0)
116     }
117 
118     pub fn command(&self) -> Command {
119         self.command
120     }
121 
122     pub fn length(&self) -> u64 {
123         self.length
124     }
125 
126     pub fn read_from(fd: &mut dyn Read) -> Result<Request, MigratableError> {
127         let mut request = Request::default();
128         fd.read_exact(Self::as_mut_slice(&mut request))
129             .map_err(MigratableError::MigrateSocket)?;
130 
131         Ok(request)
132     }
133 
134     pub fn write_to(&self, fd: &mut dyn Write) -> Result<(), MigratableError> {
135         fd.write_all(Self::as_slice(self))
136             .map_err(MigratableError::MigrateSocket)
137     }
138 }
139 
140 #[repr(u16)]
141 #[derive(Copy, Clone, PartialEq)]
142 pub enum Status {
143     Invalid,
144     Ok,
145     Error,
146 }
147 
148 impl Default for Status {
149     fn default() -> Self {
150         Self::Invalid
151     }
152 }
153 
154 #[repr(C)]
155 #[derive(Default, Copy, Clone)]
156 pub struct Response {
157     status: Status,
158     padding: [u8; 6],
159     length: u64, // Length of payload for command excluding the Response struct
160 }
161 
162 // SAFETY: Response contains a series of integers with no implicit padding
163 unsafe impl ByteValued for Response {}
164 
165 impl Response {
166     pub fn new(status: Status, length: u64) -> Self {
167         Self {
168             status,
169             length,
170             ..Default::default()
171         }
172     }
173 
174     pub fn ok() -> Self {
175         Self::new(Status::Ok, 0)
176     }
177 
178     pub fn error() -> Self {
179         Self::new(Status::Error, 0)
180     }
181 
182     pub fn status(&self) -> Status {
183         self.status
184     }
185 
186     pub fn read_from(fd: &mut dyn Read) -> Result<Response, MigratableError> {
187         let mut response = Response::default();
188         fd.read_exact(Self::as_mut_slice(&mut response))
189             .map_err(MigratableError::MigrateSocket)?;
190 
191         Ok(response)
192     }
193 
194     pub fn write_to(&self, fd: &mut dyn Write) -> Result<(), MigratableError> {
195         fd.write_all(Self::as_slice(self))
196             .map_err(MigratableError::MigrateSocket)
197     }
198 }
199 
200 #[repr(C)]
201 #[derive(Clone, Default, Serialize, Deserialize, Versionize)]
202 pub struct MemoryRange {
203     pub gpa: u64,
204     pub length: u64,
205 }
206 
207 #[derive(Clone, Default, Serialize, Deserialize, Versionize)]
208 pub struct MemoryRangeTable {
209     data: Vec<MemoryRange>,
210 }
211 
212 impl VersionMapped for MemoryRangeTable {}
213 
214 impl MemoryRangeTable {
215     pub fn from_bitmap(bitmap: Vec<u64>, start_addr: u64, page_size: u64) -> Self {
216         let mut table = MemoryRangeTable::default();
217         let mut entry: Option<MemoryRange> = None;
218         for (i, block) in bitmap.iter().enumerate() {
219             for j in 0..64 {
220                 let is_page_dirty = ((block >> j) & 1u64) != 0u64;
221                 let page_offset = ((i * 64) + j) as u64 * page_size;
222                 if is_page_dirty {
223                     if let Some(entry) = &mut entry {
224                         entry.length += page_size;
225                     } else {
226                         entry = Some(MemoryRange {
227                             gpa: start_addr + page_offset,
228                             length: page_size,
229                         });
230                     }
231                 } else if let Some(entry) = entry.take() {
232                     table.push(entry);
233                 }
234             }
235         }
236         if let Some(entry) = entry.take() {
237             table.push(entry);
238         }
239 
240         table
241     }
242 
243     pub fn regions(&self) -> &[MemoryRange] {
244         &self.data
245     }
246 
247     pub fn push(&mut self, range: MemoryRange) {
248         self.data.push(range)
249     }
250 
251     pub fn read_from(fd: &mut dyn Read, length: u64) -> Result<MemoryRangeTable, MigratableError> {
252         assert!(length as usize % std::mem::size_of::<MemoryRange>() == 0);
253 
254         let mut data: Vec<MemoryRange> = Vec::new();
255         data.resize_with(
256             length as usize / (std::mem::size_of::<MemoryRange>()),
257             Default::default,
258         );
259         fd.read_exact(unsafe {
260             std::slice::from_raw_parts_mut(
261                 data.as_ptr() as *mut MemoryRange as *mut u8,
262                 length as usize,
263             )
264         })
265         .map_err(MigratableError::MigrateSocket)?;
266 
267         Ok(Self { data })
268     }
269 
270     pub fn length(&self) -> u64 {
271         (std::mem::size_of::<MemoryRange>() * self.data.len()) as u64
272     }
273 
274     pub fn write_to(&self, fd: &mut dyn Write) -> Result<(), MigratableError> {
275         fd.write_all(unsafe {
276             std::slice::from_raw_parts(
277                 self.data.as_ptr() as *const MemoryRange as *const u8,
278                 self.length() as usize,
279             )
280         })
281         .map_err(MigratableError::MigrateSocket)
282     }
283 
284     pub fn is_empty(&self) -> bool {
285         self.data.is_empty()
286     }
287 
288     pub fn extend(&mut self, table: Self) {
289         self.data.extend(table.data)
290     }
291 
292     pub fn new_from_tables(tables: Vec<Self>) -> Self {
293         let mut data = Vec::new();
294         for table in tables {
295             data.extend(table.data);
296         }
297         Self { data }
298     }
299 }
300