xref: /aosp_15_r20/external/crosvm/third_party/vmm_vhost/src/test_backend.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
2 // SPDX-License-Identifier: Apache-2.0
3 
4 use std::fs::File;
5 
6 use crate::message::*;
7 use crate::Backend;
8 use crate::Error;
9 use crate::Result;
10 
11 pub const MAX_QUEUE_NUM: usize = 2;
12 pub const MAX_VRING_NUM: usize = 256;
13 pub const MAX_MEM_SLOTS: usize = 32;
14 pub const VIRTIO_FEATURES: u64 = 0x40000003;
15 
16 #[derive(Default)]
17 pub struct TestBackend {
18     pub owned: bool,
19     pub features_acked: bool,
20     pub acked_features: u64,
21     pub acked_protocol_features: u64,
22     pub queue_num: usize,
23     pub vring_num: [u32; MAX_QUEUE_NUM],
24     pub vring_base: [u32; MAX_QUEUE_NUM],
25     pub call_fd: [Option<File>; MAX_QUEUE_NUM],
26     pub kick_fd: [Option<File>; MAX_QUEUE_NUM],
27     pub err_fd: [Option<File>; MAX_QUEUE_NUM],
28     pub vring_started: [bool; MAX_QUEUE_NUM],
29     pub vring_enabled: [bool; MAX_QUEUE_NUM],
30     pub inflight_file: Option<File>,
31 }
32 
33 impl TestBackend {
new() -> Self34     pub fn new() -> Self {
35         TestBackend {
36             queue_num: MAX_QUEUE_NUM,
37             ..Default::default()
38         }
39     }
40 }
41 
42 impl Backend for TestBackend {
set_owner(&mut self) -> Result<()>43     fn set_owner(&mut self) -> Result<()> {
44         if self.owned {
45             return Err(Error::InvalidOperation);
46         }
47         self.owned = true;
48         Ok(())
49     }
50 
reset_owner(&mut self) -> Result<()>51     fn reset_owner(&mut self) -> Result<()> {
52         self.owned = false;
53         self.features_acked = false;
54         self.acked_features = 0;
55         self.acked_protocol_features = 0;
56         Ok(())
57     }
58 
get_features(&mut self) -> Result<u64>59     fn get_features(&mut self) -> Result<u64> {
60         Ok(VIRTIO_FEATURES)
61     }
62 
set_features(&mut self, features: u64) -> Result<()>63     fn set_features(&mut self, features: u64) -> Result<()> {
64         if !self.owned || self.features_acked {
65             return Err(Error::InvalidOperation);
66         } else if (features & !VIRTIO_FEATURES) != 0 {
67             return Err(Error::InvalidParam);
68         }
69 
70         self.acked_features = features;
71         self.features_acked = true;
72 
73         // If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated,
74         // the ring is initialized in an enabled state.
75         // If VHOST_USER_F_PROTOCOL_FEATURES has been negotiated,
76         // the ring is initialized in a disabled state. Client must not
77         // pass data to/from the backend until ring is enabled by
78         // VHOST_USER_SET_VRING_ENABLE with parameter 1, or after it has
79         // been disabled by VHOST_USER_SET_VRING_ENABLE with parameter 0.
80         let vring_enabled = self.acked_features & 1 << VHOST_USER_F_PROTOCOL_FEATURES == 0;
81         for enabled in &mut self.vring_enabled {
82             *enabled = vring_enabled;
83         }
84 
85         Ok(())
86     }
87 
set_mem_table(&mut self, _ctx: &[VhostUserMemoryRegion], _files: Vec<File>) -> Result<()>88     fn set_mem_table(&mut self, _ctx: &[VhostUserMemoryRegion], _files: Vec<File>) -> Result<()> {
89         Ok(())
90     }
91 
set_vring_num(&mut self, index: u32, num: u32) -> Result<()>92     fn set_vring_num(&mut self, index: u32, num: u32) -> Result<()> {
93         if index as usize >= self.queue_num || num == 0 || num as usize > MAX_VRING_NUM {
94             return Err(Error::InvalidParam);
95         }
96         self.vring_num[index as usize] = num;
97         Ok(())
98     }
99 
set_vring_addr( &mut self, index: u32, _flags: VhostUserVringAddrFlags, _descriptor: u64, _used: u64, _available: u64, _log: u64, ) -> Result<()>100     fn set_vring_addr(
101         &mut self,
102         index: u32,
103         _flags: VhostUserVringAddrFlags,
104         _descriptor: u64,
105         _used: u64,
106         _available: u64,
107         _log: u64,
108     ) -> Result<()> {
109         if index as usize >= self.queue_num {
110             return Err(Error::InvalidParam);
111         }
112         Ok(())
113     }
114 
set_vring_base(&mut self, index: u32, base: u32) -> Result<()>115     fn set_vring_base(&mut self, index: u32, base: u32) -> Result<()> {
116         if index as usize >= self.queue_num || base as usize >= MAX_VRING_NUM {
117             return Err(Error::InvalidParam);
118         }
119         self.vring_base[index as usize] = base;
120         Ok(())
121     }
122 
get_vring_base(&mut self, index: u32) -> Result<VhostUserVringState>123     fn get_vring_base(&mut self, index: u32) -> Result<VhostUserVringState> {
124         if index as usize >= self.queue_num {
125             return Err(Error::InvalidParam);
126         }
127         // Quotation from vhost-user spec:
128         // Client must start ring upon receiving a kick (that is, detecting
129         // that file descriptor is readable) on the descriptor specified by
130         // VHOST_USER_SET_VRING_KICK, and stop ring upon receiving
131         // VHOST_USER_GET_VRING_BASE.
132         self.vring_started[index as usize] = false;
133         Ok(VhostUserVringState::new(
134             index,
135             self.vring_base[index as usize],
136         ))
137     }
138 
set_vring_kick(&mut self, index: u8, fd: Option<File>) -> Result<()>139     fn set_vring_kick(&mut self, index: u8, fd: Option<File>) -> Result<()> {
140         if index as usize >= self.queue_num || index as usize > self.queue_num {
141             return Err(Error::InvalidParam);
142         }
143         self.kick_fd[index as usize] = fd;
144 
145         // Quotation from vhost-user spec:
146         // Client must start ring upon receiving a kick (that is, detecting
147         // that file descriptor is readable) on the descriptor specified by
148         // VHOST_USER_SET_VRING_KICK, and stop ring upon receiving
149         // VHOST_USER_GET_VRING_BASE.
150         //
151         // So we should add fd to event monitor(select, poll, epoll) here.
152         self.vring_started[index as usize] = true;
153         Ok(())
154     }
155 
set_vring_call(&mut self, index: u8, fd: Option<File>) -> Result<()>156     fn set_vring_call(&mut self, index: u8, fd: Option<File>) -> Result<()> {
157         if index as usize >= self.queue_num || index as usize > self.queue_num {
158             return Err(Error::InvalidParam);
159         }
160         self.call_fd[index as usize] = fd;
161         Ok(())
162     }
163 
set_vring_err(&mut self, index: u8, fd: Option<File>) -> Result<()>164     fn set_vring_err(&mut self, index: u8, fd: Option<File>) -> Result<()> {
165         if index as usize >= self.queue_num || index as usize > self.queue_num {
166             return Err(Error::InvalidParam);
167         }
168         self.err_fd[index as usize] = fd;
169         Ok(())
170     }
171 
get_protocol_features(&mut self) -> Result<VhostUserProtocolFeatures>172     fn get_protocol_features(&mut self) -> Result<VhostUserProtocolFeatures> {
173         Ok(VhostUserProtocolFeatures::all())
174     }
175 
set_protocol_features(&mut self, features: u64) -> Result<()>176     fn set_protocol_features(&mut self, features: u64) -> Result<()> {
177         // Note: Backend that reported VHOST_USER_F_PROTOCOL_FEATURES must
178         // support this message even before VHOST_USER_SET_FEATURES was
179         // called.
180         // What happens if the frontend calls set_features() with
181         // VHOST_USER_F_PROTOCOL_FEATURES cleared after calling this
182         // interface?
183         self.acked_protocol_features = features;
184         Ok(())
185     }
186 
get_queue_num(&mut self) -> Result<u64>187     fn get_queue_num(&mut self) -> Result<u64> {
188         Ok(MAX_QUEUE_NUM as u64)
189     }
190 
set_vring_enable(&mut self, index: u32, enable: bool) -> Result<()>191     fn set_vring_enable(&mut self, index: u32, enable: bool) -> Result<()> {
192         // This request should be handled only when VHOST_USER_F_PROTOCOL_FEATURES
193         // has been negotiated.
194         if self.acked_features & 1 << VHOST_USER_F_PROTOCOL_FEATURES == 0 {
195             return Err(Error::InvalidOperation);
196         } else if index as usize >= self.queue_num || index as usize > self.queue_num {
197             return Err(Error::InvalidParam);
198         }
199         self.vring_enabled[index as usize] = enable;
200         Ok(())
201     }
202 
get_config( &mut self, offset: u32, size: u32, _flags: VhostUserConfigFlags, ) -> Result<Vec<u8>>203     fn get_config(
204         &mut self,
205         offset: u32,
206         size: u32,
207         _flags: VhostUserConfigFlags,
208     ) -> Result<Vec<u8>> {
209         if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
210             return Err(Error::InvalidOperation);
211         } else if !(VHOST_USER_CONFIG_OFFSET..VHOST_USER_CONFIG_SIZE).contains(&offset)
212             || size > VHOST_USER_CONFIG_SIZE - VHOST_USER_CONFIG_OFFSET
213             || size + offset > VHOST_USER_CONFIG_SIZE
214         {
215             return Err(Error::InvalidParam);
216         }
217         Ok(vec![0xa5; size as usize])
218     }
219 
set_config(&mut self, offset: u32, buf: &[u8], _flags: VhostUserConfigFlags) -> Result<()>220     fn set_config(&mut self, offset: u32, buf: &[u8], _flags: VhostUserConfigFlags) -> Result<()> {
221         let size = buf.len() as u32;
222         if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
223             return Err(Error::InvalidOperation);
224         } else if !(VHOST_USER_CONFIG_OFFSET..VHOST_USER_CONFIG_SIZE).contains(&offset)
225             || size > VHOST_USER_CONFIG_SIZE - VHOST_USER_CONFIG_OFFSET
226             || size + offset > VHOST_USER_CONFIG_SIZE
227         {
228             return Err(Error::InvalidParam);
229         }
230         Ok(())
231     }
232 
get_inflight_fd( &mut self, inflight: &VhostUserInflight, ) -> Result<(VhostUserInflight, File)>233     fn get_inflight_fd(
234         &mut self,
235         inflight: &VhostUserInflight,
236     ) -> Result<(VhostUserInflight, File)> {
237         let file = tempfile::tempfile().unwrap();
238         self.inflight_file = Some(file.try_clone().unwrap());
239         Ok((
240             VhostUserInflight {
241                 mmap_size: 0x1000,
242                 mmap_offset: 0,
243                 num_queues: inflight.num_queues,
244                 queue_size: inflight.queue_size,
245                 ..Default::default()
246             },
247             file,
248         ))
249     }
250 
set_inflight_fd(&mut self, _inflight: &VhostUserInflight, _file: File) -> Result<()>251     fn set_inflight_fd(&mut self, _inflight: &VhostUserInflight, _file: File) -> Result<()> {
252         Ok(())
253     }
254 
get_max_mem_slots(&mut self) -> Result<u64>255     fn get_max_mem_slots(&mut self) -> Result<u64> {
256         Ok(MAX_MEM_SLOTS as u64)
257     }
258 
add_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion, _fd: File) -> Result<()>259     fn add_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion, _fd: File) -> Result<()> {
260         Ok(())
261     }
262 
remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> Result<()>263     fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> Result<()> {
264         Ok(())
265     }
266 
set_device_state_fd( &mut self, _transfer_direction: VhostUserTransferDirection, _migration_phase: VhostUserMigrationPhase, _fd: File, ) -> Result<Option<File>>267     fn set_device_state_fd(
268         &mut self,
269         _transfer_direction: VhostUserTransferDirection,
270         _migration_phase: VhostUserMigrationPhase,
271         _fd: File,
272     ) -> Result<Option<File>> {
273         Ok(None)
274     }
275 
check_device_state(&mut self) -> Result<()>276     fn check_device_state(&mut self) -> Result<()> {
277         Ok(())
278     }
279 
get_shared_memory_regions(&mut self) -> Result<Vec<VhostSharedMemoryRegion>>280     fn get_shared_memory_regions(&mut self) -> Result<Vec<VhostSharedMemoryRegion>> {
281         Ok(Vec::new())
282     }
283 }
284