xref: /cloud-hypervisor/vm-migration/src/protocol.rs (revision f6cd3bd86ded632da437b6dd6077f4237d2f71fe)
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 write_to(&self, fd: &mut dyn Write) -> Result<(), MigratableError> {
194         fd.write_all(Self::as_slice(self))
195             .map_err(MigratableError::MigrateSocket)
196     }
197 }
198 
199 #[repr(C)]
200 #[derive(Clone, Default, Serialize, Deserialize)]
201 pub struct MemoryRange {
202     pub gpa: u64,
203     pub length: u64,
204 }
205 
206 #[derive(Clone, Default, Serialize, Deserialize)]
207 pub struct MemoryRangeTable {
208     data: Vec<MemoryRange>,
209 }
210 
211 impl MemoryRangeTable {
212     pub fn from_bitmap(bitmap: Vec<u64>, start_addr: u64, page_size: u64) -> Self {
213         let mut table = MemoryRangeTable::default();
214         let mut entry: Option<MemoryRange> = None;
215         for (i, block) in bitmap.iter().enumerate() {
216             for j in 0..64 {
217                 let is_page_dirty = ((block >> j) & 1u64) != 0u64;
218                 let page_offset = ((i * 64) + j) as u64 * page_size;
219                 if is_page_dirty {
220                     if let Some(entry) = &mut entry {
221                         entry.length += page_size;
222                     } else {
223                         entry = Some(MemoryRange {
224                             gpa: start_addr + page_offset,
225                             length: page_size,
226                         });
227                     }
228                 } else if let Some(entry) = entry.take() {
229                     table.push(entry);
230                 }
231             }
232         }
233         if let Some(entry) = entry.take() {
234             table.push(entry);
235         }
236 
237         table
238     }
239 
240     pub fn regions(&self) -> &[MemoryRange] {
241         &self.data
242     }
243 
244     pub fn push(&mut self, range: MemoryRange) {
245         self.data.push(range)
246     }
247 
248     pub fn read_from(fd: &mut dyn Read, length: u64) -> Result<MemoryRangeTable, MigratableError> {
249         assert!(length as usize % std::mem::size_of::<MemoryRange>() == 0);
250 
251         let mut data: Vec<MemoryRange> = Vec::new();
252         data.resize_with(
253             length as usize / (std::mem::size_of::<MemoryRange>()),
254             Default::default,
255         );
256         // SAFETY: the slice is constructed with the correct arguments
257         fd.read_exact(unsafe {
258             std::slice::from_raw_parts_mut(
259                 data.as_ptr() as *mut MemoryRange as *mut u8,
260                 length as usize,
261             )
262         })
263         .map_err(MigratableError::MigrateSocket)?;
264 
265         Ok(Self { data })
266     }
267 
268     pub fn length(&self) -> u64 {
269         (std::mem::size_of::<MemoryRange>() * self.data.len()) as u64
270     }
271 
272     pub fn write_to(&self, fd: &mut dyn Write) -> Result<(), MigratableError> {
273         // SAFETY: the slice is constructed with the correct arguments
274         fd.write_all(unsafe {
275             std::slice::from_raw_parts(self.data.as_ptr() as *const u8, self.length() as usize)
276         })
277         .map_err(MigratableError::MigrateSocket)
278     }
279 
280     pub fn is_empty(&self) -> bool {
281         self.data.is_empty()
282     }
283 
284     pub fn extend(&mut self, table: Self) {
285         self.data.extend(table.data)
286     }
287 
288     pub fn new_from_tables(tables: Vec<Self>) -> Self {
289         let mut data = Vec::new();
290         for table in tables {
291             data.extend(table.data);
292         }
293         Self { data }
294     }
295 }
296