1 // Copyright (C) 2019-2021 Alibaba Cloud. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause 3 // 4 // Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 // 6 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 7 // Use of this source code is governed by a BSD-style license that can be 8 // found in the LICENSE-BSD-Google file. 9 10 //! Common traits and structs for vhost-user backend drivers. 11 12 use base::{RawDescriptor, INVALID_DESCRIPTOR}; 13 use std::cell::RefCell; 14 use std::sync::RwLock; 15 16 use base::Event; 17 18 use super::Result; 19 20 /// Maximum number of memory regions supported. 21 pub const VHOST_MAX_MEMORY_REGIONS: usize = 255; 22 23 /// Vring configuration data. 24 pub struct VringConfigData { 25 /// Maximum queue size supported by the driver. 26 pub queue_max_size: u16, 27 /// Actual queue size negotiated by the driver. 28 pub queue_size: u16, 29 /// Bitmask of vring flags. 30 pub flags: u32, 31 /// Descriptor table address. 32 pub desc_table_addr: u64, 33 /// Used ring buffer address. 34 pub used_ring_addr: u64, 35 /// Available ring buffer address. 36 pub avail_ring_addr: u64, 37 /// Optional address for logging. 38 pub log_addr: Option<u64>, 39 } 40 41 impl VringConfigData { 42 /// Check whether the log (flag, address) pair is valid. is_log_addr_valid(&self) -> bool43 pub fn is_log_addr_valid(&self) -> bool { 44 if self.flags & 0x1 != 0 && self.log_addr.is_none() { 45 return false; 46 } 47 48 true 49 } 50 51 /// Get the log address, default to zero if not available. get_log_addr(&self) -> u6452 pub fn get_log_addr(&self) -> u64 { 53 if self.flags & 0x1 != 0 && self.log_addr.is_some() { 54 self.log_addr.unwrap() 55 } else { 56 0 57 } 58 } 59 } 60 61 /// Memory region configuration data. 62 #[derive(Clone, Copy)] 63 pub struct VhostUserMemoryRegionInfo { 64 /// Guest physical address of the memory region. 65 pub guest_phys_addr: u64, 66 /// Size of the memory region. 67 pub memory_size: u64, 68 /// Virtual address in the current process. 69 pub userspace_addr: u64, 70 /// Optional offset where region starts in the mapped memory. 71 pub mmap_offset: u64, 72 /// Optional file descriptor for mmap. 73 pub mmap_handle: RawDescriptor, 74 } 75 76 // We cannot derive default because windows Handle does not implement a default. 77 impl Default for VhostUserMemoryRegionInfo { default() -> Self78 fn default() -> Self { 79 VhostUserMemoryRegionInfo { 80 guest_phys_addr: u64::default(), 81 memory_size: u64::default(), 82 userspace_addr: u64::default(), 83 mmap_offset: u64::default(), 84 mmap_handle: INVALID_DESCRIPTOR, 85 } 86 } 87 } 88 89 /// An interface for setting up vhost-based backend drivers with interior mutability. 90 /// 91 /// Vhost devices are subset of virtio devices, which improve virtio device's performance by 92 /// delegating data plane operations to dedicated IO service processes. Vhost devices use the 93 /// same virtqueue layout as virtio devices to allow vhost devices to be mapped directly to 94 /// virtio devices. 95 /// 96 /// The purpose of vhost is to implement a subset of a virtio device's functionality outside the 97 /// VMM process. Typically fast paths for IO operations are delegated to the dedicated IO service 98 /// processes, and slow path for device configuration are still handled by the VMM process. It may 99 /// also be used to control access permissions of virtio backend devices. 100 pub trait VhostBackend: std::marker::Sized { 101 /// Get a bitmask of supported virtio/vhost features. get_features(&self) -> Result<u64>102 fn get_features(&self) -> Result<u64>; 103 104 /// Inform the vhost subsystem which features to enable. 105 /// This should be a subset of supported features from get_features(). 106 /// 107 /// # Arguments 108 /// * `features` - Bitmask of features to set. set_features(&self, features: u64) -> Result<()>109 fn set_features(&self, features: u64) -> Result<()>; 110 111 /// Set the current process as the owner of the vhost backend. 112 /// This must be run before any other vhost commands. set_owner(&self) -> Result<()>113 fn set_owner(&self) -> Result<()>; 114 115 /// Used to be sent to request disabling all rings 116 /// This is no longer used. reset_owner(&self) -> Result<()>117 fn reset_owner(&self) -> Result<()>; 118 119 /// Set the guest memory mappings for vhost to use. set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>120 fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>; 121 122 /// Set base address for page modification logging. set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()>123 fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()>; 124 125 /// Specify an event file descriptor to signal on log write. set_log_fd(&self, fd: RawDescriptor) -> Result<()>126 fn set_log_fd(&self, fd: RawDescriptor) -> Result<()>; 127 128 /// Set the number of descriptors in the vring. 129 /// 130 /// # Arguments 131 /// * `queue_index` - Index of the queue to set descriptor count for. 132 /// * `num` - Number of descriptors in the queue. set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>133 fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>; 134 135 /// Set the addresses for a given vring. 136 /// 137 /// # Arguments 138 /// * `queue_index` - Index of the queue to set addresses for. 139 /// * `config_data` - Configuration data for a vring. set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>140 fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>; 141 142 /// Set the first index to look for available descriptors. 143 /// 144 /// # Arguments 145 /// * `queue_index` - Index of the queue to modify. 146 /// * `num` - Index where available descriptors start. set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>147 fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>; 148 149 /// Get the available vring base offset. get_vring_base(&self, queue_index: usize) -> Result<u32>150 fn get_vring_base(&self, queue_index: usize) -> Result<u32>; 151 152 /// Set the event to trigger when buffers have been used by the host. 153 /// 154 /// # Arguments 155 /// * `queue_index` - Index of the queue to modify. 156 /// * `event` - Event to trigger. set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>157 fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>; 158 159 /// Set the event that will be signaled by the guest when buffers are 160 /// available for the host to process. 161 /// 162 /// # Arguments 163 /// * `queue_index` - Index of the queue to modify. 164 /// * `event` - Event that will be signaled from guest. set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>165 fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>; 166 167 /// Set the event that will be signaled by the guest when error happens. 168 /// 169 /// # Arguments 170 /// * `queue_index` - Index of the queue to modify. 171 /// * `event` - Event that will be signaled from guest. set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>172 fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>; 173 } 174 175 /// An interface for setting up vhost-based backend drivers. 176 /// 177 /// Vhost devices are subset of virtio devices, which improve virtio device's performance by 178 /// delegating data plane operations to dedicated IO service processes. Vhost devices use the 179 /// same virtqueue layout as virtio devices to allow vhost devices to be mapped directly to 180 /// virtio devices. 181 /// 182 /// The purpose of vhost is to implement a subset of a virtio device's functionality outside the 183 /// VMM process. Typically fast paths for IO operations are delegated to the dedicated IO service 184 /// processes, and slow path for device configuration are still handled by the VMM process. It may 185 /// also be used to control access permissions of virtio backend devices. 186 pub trait VhostBackendMut: std::marker::Sized { 187 /// Get a bitmask of supported virtio/vhost features. get_features(&mut self) -> Result<u64>188 fn get_features(&mut self) -> Result<u64>; 189 190 /// Inform the vhost subsystem which features to enable. 191 /// This should be a subset of supported features from get_features(). 192 /// 193 /// # Arguments 194 /// * `features` - Bitmask of features to set. set_features(&mut self, features: u64) -> Result<()>195 fn set_features(&mut self, features: u64) -> Result<()>; 196 197 /// Set the current process as the owner of the vhost backend. 198 /// This must be run before any other vhost commands. set_owner(&mut self) -> Result<()>199 fn set_owner(&mut self) -> Result<()>; 200 201 /// Used to be sent to request disabling all rings 202 /// This is no longer used. reset_owner(&mut self) -> Result<()>203 fn reset_owner(&mut self) -> Result<()>; 204 205 /// Set the guest memory mappings for vhost to use. set_mem_table(&mut self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>206 fn set_mem_table(&mut self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>; 207 208 /// Set base address for page modification logging. set_log_base(&mut self, base: u64, fd: Option<RawDescriptor>) -> Result<()>209 fn set_log_base(&mut self, base: u64, fd: Option<RawDescriptor>) -> Result<()>; 210 211 /// Specify an event file descriptor to signal on log write. set_log_fd(&mut self, fd: RawDescriptor) -> Result<()>212 fn set_log_fd(&mut self, fd: RawDescriptor) -> Result<()>; 213 214 /// Set the number of descriptors in the vring. 215 /// 216 /// # Arguments 217 /// * `queue_index` - Index of the queue to set descriptor count for. 218 /// * `num` - Number of descriptors in the queue. set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()>219 fn set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()>; 220 221 /// Set the addresses for a given vring. 222 /// 223 /// # Arguments 224 /// * `queue_index` - Index of the queue to set addresses for. 225 /// * `config_data` - Configuration data for a vring. set_vring_addr(&mut self, queue_index: usize, config_data: &VringConfigData) -> Result<()>226 fn set_vring_addr(&mut self, queue_index: usize, config_data: &VringConfigData) -> Result<()>; 227 228 /// Set the first index to look for available descriptors. 229 /// 230 /// # Arguments 231 /// * `queue_index` - Index of the queue to modify. 232 /// * `num` - Index where available descriptors start. set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()>233 fn set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()>; 234 235 /// Get the available vring base offset. get_vring_base(&mut self, queue_index: usize) -> Result<u32>236 fn get_vring_base(&mut self, queue_index: usize) -> Result<u32>; 237 238 /// Set the event to trigger when buffers have been used by the host. 239 /// 240 /// # Arguments 241 /// * `queue_index` - Index of the queue to modify. 242 /// * `event` - Event to trigger. set_vring_call(&mut self, queue_index: usize, event: &Event) -> Result<()>243 fn set_vring_call(&mut self, queue_index: usize, event: &Event) -> Result<()>; 244 245 /// Set the event that will be signaled by the guest when buffers are 246 /// available for the host to process. 247 /// 248 /// # Arguments 249 /// * `queue_index` - Index of the queue to modify. 250 /// * `event` - Event that will be signaled from guest. set_vring_kick(&mut self, queue_index: usize, event: &Event) -> Result<()>251 fn set_vring_kick(&mut self, queue_index: usize, event: &Event) -> Result<()>; 252 253 /// Set the event that will be signaled by the guest when error happens. 254 /// 255 /// # Arguments 256 /// * `queue_index` - Index of the queue to modify. 257 /// * `event` - Event that will be signaled from guest. set_vring_err(&mut self, queue_index: usize, event: &Event) -> Result<()>258 fn set_vring_err(&mut self, queue_index: usize, event: &Event) -> Result<()>; 259 } 260 261 impl<T: VhostBackendMut> VhostBackend for RwLock<T> { get_features(&self) -> Result<u64>262 fn get_features(&self) -> Result<u64> { 263 self.write().unwrap().get_features() 264 } 265 set_features(&self, features: u64) -> Result<()>266 fn set_features(&self, features: u64) -> Result<()> { 267 self.write().unwrap().set_features(features) 268 } 269 set_owner(&self) -> Result<()>270 fn set_owner(&self) -> Result<()> { 271 self.write().unwrap().set_owner() 272 } 273 reset_owner(&self) -> Result<()>274 fn reset_owner(&self) -> Result<()> { 275 self.write().unwrap().reset_owner() 276 } 277 set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>278 fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> { 279 self.write().unwrap().set_mem_table(regions) 280 } 281 set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()>282 fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()> { 283 self.write().unwrap().set_log_base(base, fd) 284 } 285 set_log_fd(&self, fd: RawDescriptor) -> Result<()>286 fn set_log_fd(&self, fd: RawDescriptor) -> Result<()> { 287 self.write().unwrap().set_log_fd(fd) 288 } 289 set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>290 fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> { 291 self.write().unwrap().set_vring_num(queue_index, num) 292 } 293 set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>294 fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> { 295 self.write() 296 .unwrap() 297 .set_vring_addr(queue_index, config_data) 298 } 299 set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>300 fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> { 301 self.write().unwrap().set_vring_base(queue_index, base) 302 } 303 get_vring_base(&self, queue_index: usize) -> Result<u32>304 fn get_vring_base(&self, queue_index: usize) -> Result<u32> { 305 self.write().unwrap().get_vring_base(queue_index) 306 } 307 set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>308 fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> { 309 self.write().unwrap().set_vring_call(queue_index, event) 310 } 311 set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>312 fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> { 313 self.write().unwrap().set_vring_kick(queue_index, event) 314 } 315 set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>316 fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> { 317 self.write().unwrap().set_vring_err(queue_index, event) 318 } 319 } 320 321 impl<T: VhostBackendMut> VhostBackend for RefCell<T> { get_features(&self) -> Result<u64>322 fn get_features(&self) -> Result<u64> { 323 self.borrow_mut().get_features() 324 } 325 set_features(&self, features: u64) -> Result<()>326 fn set_features(&self, features: u64) -> Result<()> { 327 self.borrow_mut().set_features(features) 328 } 329 set_owner(&self) -> Result<()>330 fn set_owner(&self) -> Result<()> { 331 self.borrow_mut().set_owner() 332 } 333 reset_owner(&self) -> Result<()>334 fn reset_owner(&self) -> Result<()> { 335 self.borrow_mut().reset_owner() 336 } 337 set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()>338 fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> { 339 self.borrow_mut().set_mem_table(regions) 340 } 341 set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()>342 fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()> { 343 self.borrow_mut().set_log_base(base, fd) 344 } 345 set_log_fd(&self, fd: RawDescriptor) -> Result<()>346 fn set_log_fd(&self, fd: RawDescriptor) -> Result<()> { 347 self.borrow_mut().set_log_fd(fd) 348 } 349 set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>350 fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> { 351 self.borrow_mut().set_vring_num(queue_index, num) 352 } 353 set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()>354 fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> { 355 self.borrow_mut().set_vring_addr(queue_index, config_data) 356 } 357 set_vring_base(&self, queue_index: usize, base: u16) -> Result<()>358 fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> { 359 self.borrow_mut().set_vring_base(queue_index, base) 360 } 361 get_vring_base(&self, queue_index: usize) -> Result<u32>362 fn get_vring_base(&self, queue_index: usize) -> Result<u32> { 363 self.borrow_mut().get_vring_base(queue_index) 364 } 365 set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>366 fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> { 367 self.borrow_mut().set_vring_call(queue_index, event) 368 } 369 set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>370 fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> { 371 self.borrow_mut().set_vring_kick(queue_index, event) 372 } 373 set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>374 fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> { 375 self.borrow_mut().set_vring_err(queue_index, event) 376 } 377 } 378 #[cfg(test)] 379 mod tests { 380 use super::*; 381 382 struct MockBackend {} 383 384 impl VhostBackendMut for MockBackend { get_features(&mut self) -> Result<u64>385 fn get_features(&mut self) -> Result<u64> { 386 Ok(0x1) 387 } 388 set_features(&mut self, features: u64) -> Result<()>389 fn set_features(&mut self, features: u64) -> Result<()> { 390 assert_eq!(features, 0x1); 391 Ok(()) 392 } 393 set_owner(&mut self) -> Result<()>394 fn set_owner(&mut self) -> Result<()> { 395 Ok(()) 396 } 397 reset_owner(&mut self) -> Result<()>398 fn reset_owner(&mut self) -> Result<()> { 399 Ok(()) 400 } 401 set_mem_table(&mut self, _regions: &[VhostUserMemoryRegionInfo]) -> Result<()>402 fn set_mem_table(&mut self, _regions: &[VhostUserMemoryRegionInfo]) -> Result<()> { 403 Ok(()) 404 } 405 set_log_base(&mut self, base: u64, fd: Option<RawDescriptor>) -> Result<()>406 fn set_log_base(&mut self, base: u64, fd: Option<RawDescriptor>) -> Result<()> { 407 assert_eq!(base, 0x100); 408 #[allow(clippy::unnecessary_cast)] 409 let rd = 100 as RawDescriptor; 410 assert_eq!(fd, Some(rd)); 411 Ok(()) 412 } 413 set_log_fd(&mut self, fd: RawDescriptor) -> Result<()>414 fn set_log_fd(&mut self, fd: RawDescriptor) -> Result<()> { 415 #[allow(clippy::unnecessary_cast)] 416 let rd = 100 as RawDescriptor; 417 assert_eq!(fd, rd); 418 Ok(()) 419 } 420 set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()>421 fn set_vring_num(&mut self, queue_index: usize, num: u16) -> Result<()> { 422 assert_eq!(queue_index, 1); 423 assert_eq!(num, 256); 424 Ok(()) 425 } 426 set_vring_addr( &mut self, queue_index: usize, _config_data: &VringConfigData, ) -> Result<()>427 fn set_vring_addr( 428 &mut self, 429 queue_index: usize, 430 _config_data: &VringConfigData, 431 ) -> Result<()> { 432 assert_eq!(queue_index, 1); 433 Ok(()) 434 } 435 set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()>436 fn set_vring_base(&mut self, queue_index: usize, base: u16) -> Result<()> { 437 assert_eq!(queue_index, 1); 438 assert_eq!(base, 2); 439 Ok(()) 440 } 441 get_vring_base(&mut self, queue_index: usize) -> Result<u32>442 fn get_vring_base(&mut self, queue_index: usize) -> Result<u32> { 443 assert_eq!(queue_index, 1); 444 Ok(2) 445 } 446 set_vring_call(&mut self, queue_index: usize, _event: &Event) -> Result<()>447 fn set_vring_call(&mut self, queue_index: usize, _event: &Event) -> Result<()> { 448 assert_eq!(queue_index, 1); 449 Ok(()) 450 } 451 set_vring_kick(&mut self, queue_index: usize, _event: &Event) -> Result<()>452 fn set_vring_kick(&mut self, queue_index: usize, _event: &Event) -> Result<()> { 453 assert_eq!(queue_index, 1); 454 Ok(()) 455 } 456 set_vring_err(&mut self, queue_index: usize, _event: &Event) -> Result<()>457 fn set_vring_err(&mut self, queue_index: usize, _event: &Event) -> Result<()> { 458 assert_eq!(queue_index, 1); 459 Ok(()) 460 } 461 } 462 463 #[test] test_vring_backend_mut()464 fn test_vring_backend_mut() { 465 let b = RwLock::new(MockBackend {}); 466 467 assert_eq!(b.get_features().unwrap(), 0x1); 468 b.set_features(0x1).unwrap(); 469 b.set_owner().unwrap(); 470 b.reset_owner().unwrap(); 471 b.set_mem_table(&[]).unwrap(); 472 473 #[allow(clippy::unnecessary_cast)] 474 let rd = 100 as RawDescriptor; 475 b.set_log_base(0x100, Some(rd)).unwrap(); 476 b.set_log_fd(rd).unwrap(); 477 b.set_vring_num(1, 256).unwrap(); 478 479 let config = VringConfigData { 480 queue_max_size: 0x1000, 481 queue_size: 0x2000, 482 flags: 0x0, 483 desc_table_addr: 0x4000, 484 used_ring_addr: 0x5000, 485 avail_ring_addr: 0x6000, 486 log_addr: None, 487 }; 488 b.set_vring_addr(1, &config).unwrap(); 489 490 b.set_vring_base(1, 2).unwrap(); 491 assert_eq!(b.get_vring_base(1).unwrap(), 2); 492 493 let event = Event::new().unwrap(); 494 b.set_vring_call(1, &event).unwrap(); 495 b.set_vring_kick(1, &event).unwrap(); 496 b.set_vring_err(1, &event).unwrap(); 497 } 498 499 #[test] test_vring_config_data()500 fn test_vring_config_data() { 501 let mut config = VringConfigData { 502 queue_max_size: 0x1000, 503 queue_size: 0x2000, 504 flags: 0x0, 505 desc_table_addr: 0x4000, 506 used_ring_addr: 0x5000, 507 avail_ring_addr: 0x6000, 508 log_addr: None, 509 }; 510 511 assert!(config.is_log_addr_valid()); 512 assert_eq!(config.get_log_addr(), 0); 513 514 config.flags = 0x1; 515 assert!(!config.is_log_addr_valid()); 516 assert_eq!(config.get_log_addr(), 0); 517 518 config.log_addr = Some(0x7000); 519 assert!(config.is_log_addr_valid()); 520 assert_eq!(config.get_log_addr(), 0x7000); 521 522 config.flags = 0x0; 523 assert!(config.is_log_addr_valid()); 524 assert_eq!(config.get_log_addr(), 0); 525 } 526 } 527