vmm/devices/virtio/vsock/
persist.rs1use std::fmt::Debug;
7use std::sync::Arc;
8
9use serde::{Deserialize, Serialize};
10
11use super::*;
12use crate::devices::virtio::device::{ActiveState, DeviceState};
13use crate::devices::virtio::generated::virtio_ids::{self, VIRTIO_ID_VSOCK};
14use crate::devices::virtio::persist::VirtioDeviceState;
15use crate::devices::virtio::queue::FIRECRACKER_MAX_QUEUE_SIZE;
16use crate::devices::virtio::transport::VirtioInterrupt;
17use crate::snapshot::Persist;
18use crate::vstate::memory::GuestMemoryMmap;
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct VsockState {
23 pub backend: VsockBackendState,
25 pub frontend: VsockFrontendState,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct VsockFrontendState {
32 pub cid: u64,
34 pub virtio_state: VirtioDeviceState,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub enum VsockBackendState {
40 Uds(VsockUdsState),
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct VsockUdsState {
47 pub(crate) path: String,
49}
50
51#[derive(Debug)]
53pub struct VsockConstructorArgs<B> {
54 pub mem: GuestMemoryMmap,
56 pub backend: B,
58}
59
60#[derive(Debug)]
62pub struct VsockUdsConstructorArgs {
63 pub cid: u64,
65}
66
67impl Persist<'_> for VsockUnixBackend {
68 type State = VsockBackendState;
69 type ConstructorArgs = VsockUdsConstructorArgs;
70 type Error = VsockUnixBackendError;
71
72 fn save(&self) -> Self::State {
73 VsockBackendState::Uds(VsockUdsState {
74 path: self.host_sock_path.clone(),
75 })
76 }
77
78 fn restore(
79 constructor_args: Self::ConstructorArgs,
80 state: &Self::State,
81 ) -> Result<Self, Self::Error> {
82 match state {
83 VsockBackendState::Uds(uds_state) => Ok(VsockUnixBackend::new(
84 constructor_args.cid,
85 uds_state.path.clone(),
86 )?),
87 }
88 }
89}
90
91impl<B> Persist<'_> for Vsock<B>
92where
93 B: VsockBackend + 'static + Debug,
94{
95 type State = VsockFrontendState;
96 type ConstructorArgs = VsockConstructorArgs<B>;
97 type Error = VsockError;
98
99 fn save(&self) -> Self::State {
100 VsockFrontendState {
101 cid: self.cid(),
102 virtio_state: VirtioDeviceState::from_device(self),
103 }
104 }
105
106 fn restore(
107 constructor_args: Self::ConstructorArgs,
108 state: &Self::State,
109 ) -> Result<Self, Self::Error> {
110 let queues = state
112 .virtio_state
113 .build_queues_checked(
114 &constructor_args.mem,
115 VIRTIO_ID_VSOCK,
116 defs::VSOCK_NUM_QUEUES,
117 FIRECRACKER_MAX_QUEUE_SIZE,
118 )
119 .map_err(VsockError::VirtioState)?;
120 let mut vsock = Self::with_queues(state.cid, constructor_args.backend, queues)?;
121
122 vsock.acked_features = state.virtio_state.acked_features;
123 vsock.avail_features = state.virtio_state.avail_features;
124 vsock.device_state = DeviceState::Inactive;
125 Ok(vsock)
126 }
127}
128
129#[cfg(test)]
130pub(crate) mod tests {
131 use super::device::AVAIL_FEATURES;
132 use super::*;
133 use crate::devices::virtio::device::VirtioDevice;
134 use crate::devices::virtio::test_utils::default_interrupt;
135 use crate::devices::virtio::vsock::defs::uapi;
136 use crate::devices::virtio::vsock::test_utils::{TestBackend, TestContext};
137 use crate::snapshot::Snapshot;
138 use crate::utils::byte_order;
139
140 impl Persist<'_> for TestBackend {
141 type State = VsockBackendState;
142 type ConstructorArgs = VsockUdsConstructorArgs;
143 type Error = VsockUnixBackendError;
144
145 fn save(&self) -> Self::State {
146 VsockBackendState::Uds(VsockUdsState {
147 path: "test".to_owned(),
148 })
149 }
150
151 fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result<Self, Self::Error> {
152 match state {
153 VsockBackendState::Uds(_) => Ok(TestBackend::new()),
154 }
155 }
156 }
157
158 #[test]
159 fn test_persist_uds_backend() {
160 let ctx = TestContext::new();
161 let device_features = AVAIL_FEATURES;
162 let driver_features: u64 = AVAIL_FEATURES | 1 | (1 << 32);
163 let device_pages = [
164 (device_features & 0xffff_ffff) as u32,
165 (device_features >> 32) as u32,
166 ];
167 let driver_pages = [
168 (driver_features & 0xffff_ffff) as u32,
169 (driver_features >> 32) as u32,
170 ];
171
172 let mut mem = vec![0; 4096];
174
175 let state = VsockState {
177 backend: ctx.device.backend().save(),
178 frontend: ctx.device.save(),
179 };
180
181 Snapshot::new(&state).save(&mut mem.as_mut_slice()).unwrap();
182
183 let restored_state: VsockState = Snapshot::load_without_crc_check(mem.as_slice())
184 .unwrap()
185 .data;
186 let mut restored_device = Vsock::restore(
187 VsockConstructorArgs {
188 mem: ctx.mem.clone(),
189 backend: match restored_state.backend {
190 VsockBackendState::Uds(uds_state) => {
191 assert_eq!(uds_state.path, "test".to_owned());
192 TestBackend::new()
193 }
194 },
195 },
196 &restored_state.frontend,
197 )
198 .unwrap();
199
200 assert_eq!(restored_device.device_type(), VIRTIO_ID_VSOCK);
201 assert_eq!(restored_device.avail_features_by_page(0), device_pages[0]);
202 assert_eq!(restored_device.avail_features_by_page(1), device_pages[1]);
203 assert_eq!(restored_device.avail_features_by_page(2), 0);
204
205 restored_device.ack_features_by_page(0, driver_pages[0]);
206 restored_device.ack_features_by_page(1, driver_pages[1]);
207 restored_device.ack_features_by_page(2, 0);
208 restored_device.ack_features_by_page(0, !driver_pages[0]);
209 assert_eq!(
210 restored_device.acked_features(),
211 device_features & driver_features
212 );
213
214 let mut data = [0u8; 8];
216 restored_device.read_config(0, &mut data[..4]);
217 assert_eq!(
218 u64::from(byte_order::read_le_u32(&data[..])),
219 ctx.cid & 0xffff_ffff
220 );
221 restored_device.read_config(4, &mut data[4..]);
222 assert_eq!(
223 u64::from(byte_order::read_le_u32(&data[4..])),
224 (ctx.cid >> 32) & 0xffff_ffff
225 );
226
227 let mut data = [0u8; 8];
229 restored_device.read_config(0, &mut data);
230 assert_eq!(byte_order::read_le_u64(&data), ctx.cid);
231
232 let mut data = [0u8, 1, 2, 3, 4, 5, 6, 7];
234 restored_device.read_config(2, &mut data);
235 assert_eq!(data, [0u8, 1, 2, 3, 4, 5, 6, 7]);
236 }
237}