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