xref: /cloud-hypervisor/vm-migration/src/protocol.rs (revision b440cb7d2330770cd415b63544a371d4caa2db3a)
1 // Copyright © 2020 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 
6 use crate::{MigratableError, VersionMapped};
7 use serde::{Deserialize, Serialize};
8 use std::io::{Read, Write};
9 use versionize::{VersionMap, Versionize, VersionizeResult};
10 use versionize_derive::Versionize;
11 use vm_memory::ByteValued;
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 {
66     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 {
83     pub fn new(command: Command, length: u64) -> Self {
84         Self {
85             command,
86             length,
87             ..Default::default()
88         }
89     }
90 
91     pub fn start() -> Self {
92         Self::new(Command::Start, 0)
93     }
94 
95     pub fn state(length: u64) -> Self {
96         Self::new(Command::State, length)
97     }
98 
99     pub fn config(length: u64) -> Self {
100         Self::new(Command::Config, length)
101     }
102 
103     pub fn memory(length: u64) -> Self {
104         Self::new(Command::Memory, length)
105     }
106 
107     pub fn memory_fd(length: u64) -> Self {
108         Self::new(Command::MemoryFd, length)
109     }
110 
111     pub fn complete() -> Self {
112         Self::new(Command::Complete, 0)
113     }
114 
115     pub fn abandon() -> Self {
116         Self::new(Command::Abandon, 0)
117     }
118 
119     pub fn command(&self) -> Command {
120         self.command
121     }
122 
123     pub fn length(&self) -> u64 {
124         self.length
125     }
126 
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 
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 {
150     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 {
167     pub fn new(status: Status, length: u64) -> Self {
168         Self {
169             status,
170             length,
171             ..Default::default()
172         }
173     }
174 
175     pub fn ok() -> Self {
176         Self::new(Status::Ok, 0)
177     }
178 
179     pub fn error() -> Self {
180         Self::new(Status::Error, 0)
181     }
182 
183     pub fn status(&self) -> Status {
184         self.status
185     }
186 
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 
195     pub fn write_to(&self, fd: &mut dyn Write) -> Result<(), MigratableError> {
196         fd.write_all(Self::as_slice(self))
197             .map_err(MigratableError::MigrateSocket)
198     }
199 }
200 
201 #[repr(C)]
202 #[derive(Clone, Default, Serialize, Deserialize, Versionize)]
203 pub struct MemoryRange {
204     pub gpa: u64,
205     pub length: u64,
206 }
207 
208 #[derive(Clone, Default, Serialize, Deserialize, Versionize)]
209 pub struct MemoryRangeTable {
210     data: Vec<MemoryRange>,
211 }
212 
213 impl VersionMapped for MemoryRangeTable {}
214 
215 impl MemoryRangeTable {
216     pub fn from_bitmap(bitmap: Vec<u64>, start_addr: u64, page_size: u64) -> Self {
217         let mut table = MemoryRangeTable::default();
218         let mut entry: Option<MemoryRange> = None;
219         for (i, block) in bitmap.iter().enumerate() {
220             for j in 0..64 {
221                 let is_page_dirty = ((block >> j) & 1u64) != 0u64;
222                 let page_offset = ((i * 64) + j) as u64 * page_size;
223                 if is_page_dirty {
224                     if let Some(entry) = &mut entry {
225                         entry.length += page_size;
226                     } else {
227                         entry = Some(MemoryRange {
228                             gpa: start_addr + page_offset,
229                             length: page_size,
230                         });
231                     }
232                 } else if let Some(entry) = entry.take() {
233                     table.push(entry);
234                 }
235             }
236         }
237         if let Some(entry) = entry.take() {
238             table.push(entry);
239         }
240 
241         table
242     }
243 
244     pub fn regions(&self) -> &[MemoryRange] {
245         &self.data
246     }
247 
248     pub fn push(&mut self, range: MemoryRange) {
249         self.data.push(range)
250     }
251 
252     pub fn read_from(fd: &mut dyn Read, length: u64) -> Result<MemoryRangeTable, MigratableError> {
253         assert!(length as usize % std::mem::size_of::<MemoryRange>() == 0);
254 
255         let mut data: Vec<MemoryRange> = Vec::new();
256         data.resize_with(
257             length as usize / (std::mem::size_of::<MemoryRange>()),
258             Default::default,
259         );
260         fd.read_exact(unsafe {
261             std::slice::from_raw_parts_mut(
262                 data.as_ptr() as *mut MemoryRange as *mut u8,
263                 length as usize,
264             )
265         })
266         .map_err(MigratableError::MigrateSocket)?;
267 
268         Ok(Self { data })
269     }
270 
271     pub fn length(&self) -> u64 {
272         (std::mem::size_of::<MemoryRange>() * self.data.len()) as u64
273     }
274 
275     pub fn write_to(&self, fd: &mut dyn Write) -> Result<(), MigratableError> {
276         fd.write_all(unsafe {
277             std::slice::from_raw_parts(
278                 self.data.as_ptr() as *const MemoryRange as *const u8,
279                 self.length() as usize,
280             )
281         })
282         .map_err(MigratableError::MigrateSocket)
283     }
284 
285     pub fn is_empty(&self) -> bool {
286         self.data.is_empty()
287     }
288 
289     pub fn extend(&mut self, table: Self) {
290         self.data.extend(table.data)
291     }
292 
293     pub fn new_from_tables(tables: Vec<Self>) -> Self {
294         let mut data = Vec::new();
295         for table in tables {
296             data.extend(table.data);
297         }
298         Self { data }
299     }
300 }
301