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