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