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