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