1 // Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 //! Define communication messages for the vhost-user protocol. 5 //! 6 //! For message definition, please refer to the [vhost-user spec](https://github.com/qemu/qemu/blob/f7526eece29cd2e36a63b6703508b24453095eb8/docs/interop/vhost-user.txt). 7 8 #![allow(dead_code)] 9 #![allow(non_camel_case_types)] 10 11 use std::fmt::Debug; 12 use std::marker::PhantomData; 13 14 use crate::VringConfigData; 15 16 /// The vhost-user specification uses a field of u32 to store message length. 17 /// On the other hand, preallocated buffers are needed to receive messages from the Unix domain 18 /// socket. To preallocating a 4GB buffer for each vhost-user message is really just an overhead. 19 /// Among all defined vhost-user messages, only the VhostUserConfig and VhostUserMemory has variable 20 /// message size. For the VhostUserConfig, a maximum size of 4K is enough because the user 21 /// configuration space for virtio devices is (4K - 0x100) bytes at most. For the VhostUserMemory, 22 /// 4K should be enough too because it can support 255 memory regions at most. 23 pub const MAX_MSG_SIZE: usize = 0x1000; 24 25 /// The VhostUserMemory message has variable message size and variable number of attached file 26 /// descriptors. Each user memory region entry in the message payload occupies 32 bytes, 27 /// so setting maximum number of attached file descriptors based on the maximum message size. 28 /// But rust only implements Default and AsMut traits for arrays with 0 - 32 entries, so further 29 /// reduce the maximum number... 30 // pub const MAX_ATTACHED_FD_ENTRIES: usize = (MAX_MSG_SIZE - 8) / 32; 31 pub const MAX_ATTACHED_FD_ENTRIES: usize = 32; 32 33 /// Starting position (inclusion) of the device configuration space in virtio devices. 34 pub const VHOST_USER_CONFIG_OFFSET: u32 = 0x100; 35 36 /// Ending position (exclusion) of the device configuration space in virtio devices. 37 pub const VHOST_USER_CONFIG_SIZE: u32 = 0x1000; 38 39 /// Maximum number of vrings supported. 40 pub const VHOST_USER_MAX_VRINGS: u64 = 0x8000u64; 41 42 pub(super) trait Req: 43 Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Into<u32> 44 { is_valid(&self) -> bool45 fn is_valid(&self) -> bool; 46 } 47 48 /// Type of requests sending from masters to slaves. 49 #[repr(u32)] 50 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 51 pub enum MasterReq { 52 /// Null operation. 53 NOOP = 0, 54 /// Get from the underlying vhost implementation the features bit mask. 55 GET_FEATURES = 1, 56 /// Enable features in the underlying vhost implementation using a bit mask. 57 SET_FEATURES = 2, 58 /// Set the current Master as an owner of the session. 59 SET_OWNER = 3, 60 /// No longer used. 61 RESET_OWNER = 4, 62 /// Set the memory map regions on the slave so it can translate the vring addresses. 63 SET_MEM_TABLE = 5, 64 /// Set logging shared memory space. 65 SET_LOG_BASE = 6, 66 /// Set the logging file descriptor, which is passed as ancillary data. 67 SET_LOG_FD = 7, 68 /// Set the size of the queue. 69 SET_VRING_NUM = 8, 70 /// Set the addresses of the different aspects of the vring. 71 SET_VRING_ADDR = 9, 72 /// Set the base offset in the available vring. 73 SET_VRING_BASE = 10, 74 /// Get the available vring base offset. 75 GET_VRING_BASE = 11, 76 /// Set the event file descriptor for adding buffers to the vring. 77 SET_VRING_KICK = 12, 78 /// Set the event file descriptor to signal when buffers are used. 79 SET_VRING_CALL = 13, 80 /// Set the event file descriptor to signal when error occurs. 81 SET_VRING_ERR = 14, 82 /// Get the protocol feature bit mask from the underlying vhost implementation. 83 GET_PROTOCOL_FEATURES = 15, 84 /// Enable protocol features in the underlying vhost implementation. 85 SET_PROTOCOL_FEATURES = 16, 86 /// Query how many queues the backend supports. 87 GET_QUEUE_NUM = 17, 88 /// Signal slave to enable or disable corresponding vring. 89 SET_VRING_ENABLE = 18, 90 /// Ask vhost user backend to broadcast a fake RARP to notify the migration is terminated 91 /// for guest that does not support GUEST_ANNOUNCE. 92 SEND_RARP = 19, 93 /// Set host MTU value exposed to the guest. 94 NET_SET_MTU = 20, 95 /// Set the socket file descriptor for slave initiated requests. 96 SET_SLAVE_REQ_FD = 21, 97 /// Send IOTLB messages with struct vhost_iotlb_msg as payload. 98 IOTLB_MSG = 22, 99 /// Set the endianness of a VQ for legacy devices. 100 SET_VRING_ENDIAN = 23, 101 /// Fetch the contents of the virtio device configuration space. 102 GET_CONFIG = 24, 103 /// Change the contents of the virtio device configuration space. 104 SET_CONFIG = 25, 105 /// Create a session for crypto operation. 106 CREATE_CRYPTO_SESSION = 26, 107 /// Close a session for crypto operation. 108 CLOSE_CRYPTO_SESSION = 27, 109 /// Advise slave that a migration with postcopy enabled is underway. 110 POSTCOPY_ADVISE = 28, 111 /// Advise slave that a transition to postcopy mode has happened. 112 POSTCOPY_LISTEN = 29, 113 /// Advise that postcopy migration has now completed. 114 POSTCOPY_END = 30, 115 /// Get a shared buffer from slave. 116 GET_INFLIGHT_FD = 31, 117 /// Send the shared inflight buffer back to slave. 118 SET_INFLIGHT_FD = 32, 119 /// Sets the GPU protocol socket file descriptor. 120 GPU_SET_SOCKET = 33, 121 /// Ask the vhost user backend to disable all rings and reset all internal 122 /// device state to the initial state. 123 RESET_DEVICE = 34, 124 /// Indicate that a buffer was added to the vring instead of signalling it 125 /// using the vring’s kick file descriptor. 126 VRING_KICK = 35, 127 /// Return a u64 payload containing the maximum number of memory slots. 128 GET_MAX_MEM_SLOTS = 36, 129 /// Update the memory tables by adding the region described. 130 ADD_MEM_REG = 37, 131 /// Update the memory tables by removing the region described. 132 REM_MEM_REG = 38, 133 /// Notify the backend with updated device status as defined in the VIRTIO 134 /// specification. 135 SET_STATUS = 39, 136 /// Query the backend for its device status as defined in the VIRTIO 137 /// specification. 138 GET_STATUS = 40, 139 /// Upper bound of valid commands. 140 MAX_CMD = 41, 141 } 142 143 impl Into<u32> for MasterReq { into(self) -> u32144 fn into(self) -> u32 { 145 self as u32 146 } 147 } 148 149 impl Req for MasterReq { is_valid(&self) -> bool150 fn is_valid(&self) -> bool { 151 (*self > MasterReq::NOOP) && (*self < MasterReq::MAX_CMD) 152 } 153 } 154 155 /// Type of requests sending from slaves to masters. 156 #[repr(u32)] 157 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 158 pub enum SlaveReq { 159 /// Null operation. 160 NOOP = 0, 161 /// Send IOTLB messages with struct vhost_iotlb_msg as payload. 162 IOTLB_MSG = 1, 163 /// Notify that the virtio device's configuration space has changed. 164 CONFIG_CHANGE_MSG = 2, 165 /// Set host notifier for a specified queue. 166 VRING_HOST_NOTIFIER_MSG = 3, 167 /// Indicate that a buffer was used from the vring. 168 VRING_CALL = 4, 169 /// Indicate that an error occurred on the specific vring. 170 VRING_ERR = 5, 171 /// Virtio-fs draft: map file content into the window. 172 FS_MAP = 6, 173 /// Virtio-fs draft: unmap file content from the window. 174 FS_UNMAP = 7, 175 /// Virtio-fs draft: sync file content. 176 FS_SYNC = 8, 177 /// Virtio-fs draft: perform a read/write from an fd directly to GPA. 178 FS_IO = 9, 179 /// Upper bound of valid commands. 180 MAX_CMD = 10, 181 } 182 183 impl Into<u32> for SlaveReq { into(self) -> u32184 fn into(self) -> u32 { 185 self as u32 186 } 187 } 188 189 impl Req for SlaveReq { is_valid(&self) -> bool190 fn is_valid(&self) -> bool { 191 (*self > SlaveReq::NOOP) && (*self < SlaveReq::MAX_CMD) 192 } 193 } 194 195 /// Vhost message Validator. 196 pub trait VhostUserMsgValidator { 197 /// Validate message syntax only. 198 /// It doesn't validate message semantics such as protocol version number and dependency 199 /// on feature flags etc. is_valid(&self) -> bool200 fn is_valid(&self) -> bool { 201 true 202 } 203 } 204 205 // Bit mask for common message flags. 206 bitflags! { 207 /// Common message flags for vhost-user requests and replies. 208 pub struct VhostUserHeaderFlag: u32 { 209 /// Bits[0..2] is message version number. 210 const VERSION = 0x3; 211 /// Mark message as reply. 212 const REPLY = 0x4; 213 /// Sender anticipates a reply message from the peer. 214 const NEED_REPLY = 0x8; 215 /// All valid bits. 216 const ALL_FLAGS = 0xc; 217 /// All reserved bits. 218 const RESERVED_BITS = !0xf; 219 } 220 } 221 222 /// Common message header for vhost-user requests and replies. 223 /// A vhost-user message consists of 3 header fields and an optional payload. All numbers are in the 224 /// machine native byte order. 225 #[allow(safe_packed_borrows)] 226 #[repr(packed)] 227 #[derive(Debug, Clone, Copy, PartialEq)] 228 pub(super) struct VhostUserMsgHeader<R: Req> { 229 request: u32, 230 flags: u32, 231 size: u32, 232 _r: PhantomData<R>, 233 } 234 235 impl<R: Req> VhostUserMsgHeader<R> { 236 /// Create a new instance of `VhostUserMsgHeader`. new(request: R, flags: u32, size: u32) -> Self237 pub fn new(request: R, flags: u32, size: u32) -> Self { 238 // Default to protocol version 1 239 let fl = (flags & VhostUserHeaderFlag::ALL_FLAGS.bits()) | 0x1; 240 VhostUserMsgHeader { 241 request: request.into(), 242 flags: fl, 243 size, 244 _r: PhantomData, 245 } 246 } 247 248 /// Get message type. get_code(&self) -> R249 pub fn get_code(&self) -> R { 250 // It's safe because R is marked as repr(u32). 251 unsafe { std::mem::transmute_copy::<u32, R>(&self.request) } 252 } 253 254 /// Set message type. set_code(&mut self, request: R)255 pub fn set_code(&mut self, request: R) { 256 self.request = request.into(); 257 } 258 259 /// Get message version number. get_version(&self) -> u32260 pub fn get_version(&self) -> u32 { 261 self.flags & 0x3 262 } 263 264 /// Set message version number. set_version(&mut self, ver: u32)265 pub fn set_version(&mut self, ver: u32) { 266 self.flags &= !0x3; 267 self.flags |= ver & 0x3; 268 } 269 270 /// Check whether it's a reply message. is_reply(&self) -> bool271 pub fn is_reply(&self) -> bool { 272 (self.flags & VhostUserHeaderFlag::REPLY.bits()) != 0 273 } 274 275 /// Mark message as reply. set_reply(&mut self, is_reply: bool)276 pub fn set_reply(&mut self, is_reply: bool) { 277 if is_reply { 278 self.flags |= VhostUserHeaderFlag::REPLY.bits(); 279 } else { 280 self.flags &= !VhostUserHeaderFlag::REPLY.bits(); 281 } 282 } 283 284 /// Check whether reply for this message is requested. is_need_reply(&self) -> bool285 pub fn is_need_reply(&self) -> bool { 286 (self.flags & VhostUserHeaderFlag::NEED_REPLY.bits()) != 0 287 } 288 289 /// Mark that reply for this message is needed. set_need_reply(&mut self, need_reply: bool)290 pub fn set_need_reply(&mut self, need_reply: bool) { 291 if need_reply { 292 self.flags |= VhostUserHeaderFlag::NEED_REPLY.bits(); 293 } else { 294 self.flags &= !VhostUserHeaderFlag::NEED_REPLY.bits(); 295 } 296 } 297 298 /// Check whether it's the reply message for the request `req`. is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool299 pub fn is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool { 300 self.is_reply() && !req.is_reply() && self.get_code() == req.get_code() 301 } 302 303 /// Get message size. get_size(&self) -> u32304 pub fn get_size(&self) -> u32 { 305 self.size 306 } 307 308 /// Set message size. set_size(&mut self, size: u32)309 pub fn set_size(&mut self, size: u32) { 310 self.size = size; 311 } 312 } 313 314 impl<R: Req> Default for VhostUserMsgHeader<R> { default() -> Self315 fn default() -> Self { 316 VhostUserMsgHeader { 317 request: 0, 318 flags: 0x1, 319 size: 0, 320 _r: PhantomData, 321 } 322 } 323 } 324 325 impl<T: Req> VhostUserMsgValidator for VhostUserMsgHeader<T> { 326 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool327 fn is_valid(&self) -> bool { 328 if !self.get_code().is_valid() { 329 return false; 330 } else if self.size as usize > MAX_MSG_SIZE { 331 return false; 332 } else if self.get_version() != 0x1 { 333 return false; 334 } else if (self.flags & VhostUserHeaderFlag::RESERVED_BITS.bits()) != 0 { 335 return false; 336 } 337 true 338 } 339 } 340 341 // Bit mask for transport specific flags in VirtIO feature set defined by vhost-user. 342 bitflags! { 343 /// Transport specific flags in VirtIO feature set defined by vhost-user. 344 pub struct VhostUserVirtioFeatures: u64 { 345 /// Feature flag for the protocol feature. 346 const PROTOCOL_FEATURES = 0x4000_0000; 347 } 348 } 349 350 // Bit mask for vhost-user protocol feature flags. 351 bitflags! { 352 /// Vhost-user protocol feature flags. 353 pub struct VhostUserProtocolFeatures: u64 { 354 /// Support multiple queues. 355 const MQ = 0x0000_0001; 356 /// Support logging through shared memory fd. 357 const LOG_SHMFD = 0x0000_0002; 358 /// Support broadcasting fake RARP packet. 359 const RARP = 0x0000_0004; 360 /// Support sending reply messages for requests with NEED_REPLY flag set. 361 const REPLY_ACK = 0x0000_0008; 362 /// Support setting MTU for virtio-net devices. 363 const MTU = 0x0000_0010; 364 /// Allow the slave to send requests to the master by an optional communication channel. 365 const SLAVE_REQ = 0x0000_0020; 366 /// Support setting slave endian by SET_VRING_ENDIAN. 367 const CROSS_ENDIAN = 0x0000_0040; 368 /// Support crypto operations. 369 const CRYPTO_SESSION = 0x0000_0080; 370 /// Support sending userfault_fd from slaves to masters. 371 const PAGEFAULT = 0x0000_0100; 372 /// Support Virtio device configuration. 373 const CONFIG = 0x0000_0200; 374 /// Allow the slave to send fds (at most 8 descriptors in each message) to the master. 375 const SLAVE_SEND_FD = 0x0000_0400; 376 /// Allow the slave to register a host notifier. 377 const HOST_NOTIFIER = 0x0000_0800; 378 /// Support inflight shmfd. 379 const INFLIGHT_SHMFD = 0x0000_1000; 380 /// Support resetting the device. 381 const RESET_DEVICE = 0x0000_2000; 382 /// Support inband notifications. 383 const INBAND_NOTIFICATIONS = 0x0000_4000; 384 /// Support configuring memory slots. 385 const CONFIGURE_MEM_SLOTS = 0x0000_8000; 386 /// Support reporting status. 387 const STATUS = 0x0001_0000; 388 } 389 } 390 391 /// A generic message to encapsulate a 64-bit value. 392 #[repr(packed)] 393 #[derive(Default)] 394 pub struct VhostUserU64 { 395 /// The encapsulated 64-bit common value. 396 pub value: u64, 397 } 398 399 impl VhostUserU64 { 400 /// Create a new instance. new(value: u64) -> Self401 pub fn new(value: u64) -> Self { 402 VhostUserU64 { value } 403 } 404 } 405 406 impl VhostUserMsgValidator for VhostUserU64 {} 407 408 /// Memory region descriptor for the SET_MEM_TABLE request. 409 #[repr(packed)] 410 #[derive(Default)] 411 pub struct VhostUserMemory { 412 /// Number of memory regions in the payload. 413 pub num_regions: u32, 414 /// Padding for alignment. 415 pub padding1: u32, 416 } 417 418 impl VhostUserMemory { 419 /// Create a new instance. new(cnt: u32) -> Self420 pub fn new(cnt: u32) -> Self { 421 VhostUserMemory { 422 num_regions: cnt, 423 padding1: 0, 424 } 425 } 426 } 427 428 impl VhostUserMsgValidator for VhostUserMemory { 429 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool430 fn is_valid(&self) -> bool { 431 if self.padding1 != 0 { 432 return false; 433 } else if self.num_regions == 0 || self.num_regions > MAX_ATTACHED_FD_ENTRIES as u32 { 434 return false; 435 } 436 true 437 } 438 } 439 440 /// Memory region descriptors as payload for the SET_MEM_TABLE request. 441 #[repr(packed)] 442 #[derive(Default, Clone, Copy)] 443 pub struct VhostUserMemoryRegion { 444 /// Guest physical address of the memory region. 445 pub guest_phys_addr: u64, 446 /// Size of the memory region. 447 pub memory_size: u64, 448 /// Virtual address in the current process. 449 pub user_addr: u64, 450 /// Offset where region starts in the mapped memory. 451 pub mmap_offset: u64, 452 } 453 454 impl VhostUserMemoryRegion { 455 /// Create a new instance. new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self456 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self { 457 VhostUserMemoryRegion { 458 guest_phys_addr, 459 memory_size, 460 user_addr, 461 mmap_offset, 462 } 463 } 464 } 465 466 impl VhostUserMsgValidator for VhostUserMemoryRegion { is_valid(&self) -> bool467 fn is_valid(&self) -> bool { 468 if self.memory_size == 0 469 || self.guest_phys_addr.checked_add(self.memory_size).is_none() 470 || self.user_addr.checked_add(self.memory_size).is_none() 471 || self.mmap_offset.checked_add(self.memory_size).is_none() 472 { 473 return false; 474 } 475 true 476 } 477 } 478 479 /// Payload of the VhostUserMemory message. 480 pub type VhostUserMemoryPayload = Vec<VhostUserMemoryRegion>; 481 482 /// Single memory region descriptor as payload for ADD_MEM_REG and REM_MEM_REG 483 /// requests. 484 #[repr(C)] 485 #[derive(Default, Clone, Copy)] 486 pub struct VhostUserSingleMemoryRegion { 487 /// Padding for correct alignment 488 padding: u64, 489 /// Guest physical address of the memory region. 490 pub guest_phys_addr: u64, 491 /// Size of the memory region. 492 pub memory_size: u64, 493 /// Virtual address in the current process. 494 pub user_addr: u64, 495 /// Offset where region starts in the mapped memory. 496 pub mmap_offset: u64, 497 } 498 499 impl VhostUserSingleMemoryRegion { 500 /// Create a new instance. new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self501 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self { 502 VhostUserSingleMemoryRegion { 503 padding: 0, 504 guest_phys_addr, 505 memory_size, 506 user_addr, 507 mmap_offset, 508 } 509 } 510 } 511 512 impl VhostUserMsgValidator for VhostUserSingleMemoryRegion { is_valid(&self) -> bool513 fn is_valid(&self) -> bool { 514 if self.memory_size == 0 515 || self.guest_phys_addr.checked_add(self.memory_size).is_none() 516 || self.user_addr.checked_add(self.memory_size).is_none() 517 || self.mmap_offset.checked_add(self.memory_size).is_none() 518 { 519 return false; 520 } 521 true 522 } 523 } 524 525 /// Vring state descriptor. 526 #[repr(packed)] 527 #[derive(Default)] 528 pub struct VhostUserVringState { 529 /// Vring index. 530 pub index: u32, 531 /// A common 32bit value to encapsulate vring state etc. 532 pub num: u32, 533 } 534 535 impl VhostUserVringState { 536 /// Create a new instance. new(index: u32, num: u32) -> Self537 pub fn new(index: u32, num: u32) -> Self { 538 VhostUserVringState { index, num } 539 } 540 } 541 542 impl VhostUserMsgValidator for VhostUserVringState {} 543 544 // Bit mask for vring address flags. 545 bitflags! { 546 /// Flags for vring address. 547 pub struct VhostUserVringAddrFlags: u32 { 548 /// Support log of vring operations. 549 /// Modifications to "used" vring should be logged. 550 const VHOST_VRING_F_LOG = 0x1; 551 } 552 } 553 554 /// Vring address descriptor. 555 #[repr(packed)] 556 #[derive(Default)] 557 pub struct VhostUserVringAddr { 558 /// Vring index. 559 pub index: u32, 560 /// Vring flags defined by VhostUserVringAddrFlags. 561 pub flags: u32, 562 /// Ring address of the vring descriptor table. 563 pub descriptor: u64, 564 /// Ring address of the vring used ring. 565 pub used: u64, 566 /// Ring address of the vring available ring. 567 pub available: u64, 568 /// Guest address for logging. 569 pub log: u64, 570 } 571 572 impl VhostUserVringAddr { 573 /// Create a new instance. new( index: u32, flags: VhostUserVringAddrFlags, descriptor: u64, used: u64, available: u64, log: u64, ) -> Self574 pub fn new( 575 index: u32, 576 flags: VhostUserVringAddrFlags, 577 descriptor: u64, 578 used: u64, 579 available: u64, 580 log: u64, 581 ) -> Self { 582 VhostUserVringAddr { 583 index, 584 flags: flags.bits(), 585 descriptor, 586 used, 587 available, 588 log, 589 } 590 } 591 592 /// Create a new instance from `VringConfigData`. 593 #[cfg_attr(feature = "cargo-clippy", allow(clippy::identity_conversion))] from_config_data(index: u32, config_data: &VringConfigData) -> Self594 pub fn from_config_data(index: u32, config_data: &VringConfigData) -> Self { 595 let log_addr = config_data.log_addr.unwrap_or(0); 596 VhostUserVringAddr { 597 index, 598 flags: config_data.flags, 599 descriptor: config_data.desc_table_addr, 600 used: config_data.used_ring_addr, 601 available: config_data.avail_ring_addr, 602 log: log_addr, 603 } 604 } 605 } 606 607 impl VhostUserMsgValidator for VhostUserVringAddr { 608 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool609 fn is_valid(&self) -> bool { 610 if (self.flags & !VhostUserVringAddrFlags::all().bits()) != 0 { 611 return false; 612 } else if self.descriptor & 0xf != 0 { 613 return false; 614 } else if self.available & 0x1 != 0 { 615 return false; 616 } else if self.used & 0x3 != 0 { 617 return false; 618 } 619 true 620 } 621 } 622 623 // Bit mask for the vhost-user device configuration message. 624 bitflags! { 625 /// Flags for the device configuration message. 626 pub struct VhostUserConfigFlags: u32 { 627 /// Vhost master messages used for writeable fields. 628 const WRITABLE = 0x1; 629 /// Vhost master messages used for live migration. 630 const LIVE_MIGRATION = 0x2; 631 } 632 } 633 634 /// Message to read/write device configuration space. 635 #[repr(packed)] 636 #[derive(Default)] 637 pub struct VhostUserConfig { 638 /// Offset of virtio device's configuration space. 639 pub offset: u32, 640 /// Configuration space access size in bytes. 641 pub size: u32, 642 /// Flags for the device configuration operation. 643 pub flags: u32, 644 } 645 646 impl VhostUserConfig { 647 /// Create a new instance. new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self648 pub fn new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self { 649 VhostUserConfig { 650 offset, 651 size, 652 flags: flags.bits(), 653 } 654 } 655 } 656 657 impl VhostUserMsgValidator for VhostUserConfig { 658 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool659 fn is_valid(&self) -> bool { 660 if (self.flags & !VhostUserConfigFlags::all().bits()) != 0 { 661 return false; 662 } else if self.offset < 0x100 { 663 return false; 664 } else if self.size == 0 665 || self.size > VHOST_USER_CONFIG_SIZE 666 || self.size + self.offset > VHOST_USER_CONFIG_SIZE 667 { 668 return false; 669 } 670 true 671 } 672 } 673 674 /// Payload for the VhostUserConfig message. 675 pub type VhostUserConfigPayload = Vec<u8>; 676 677 /* 678 * TODO: support dirty log, live migration and IOTLB operations. 679 #[repr(packed)] 680 pub struct VhostUserVringArea { 681 pub index: u32, 682 pub flags: u32, 683 pub size: u64, 684 pub offset: u64, 685 } 686 687 #[repr(packed)] 688 pub struct VhostUserLog { 689 pub size: u64, 690 pub offset: u64, 691 } 692 693 #[repr(packed)] 694 pub struct VhostUserIotlb { 695 pub iova: u64, 696 pub size: u64, 697 pub user_addr: u64, 698 pub permission: u8, 699 pub optype: u8, 700 } 701 */ 702 703 // Bit mask for flags in virtio-fs slave messages 704 bitflags! { 705 #[derive(Default)] 706 /// Flags for virtio-fs slave messages. 707 pub struct VhostUserFSSlaveMsgFlags: u64 { 708 /// Empty permission. 709 const EMPTY = 0x0; 710 /// Read permission. 711 const MAP_R = 0x1; 712 /// Write permission. 713 const MAP_W = 0x2; 714 } 715 } 716 717 /// Max entries in one virtio-fs slave request. 718 pub const VHOST_USER_FS_SLAVE_ENTRIES: usize = 8; 719 720 /// Slave request message to update the MMIO window. 721 #[repr(packed)] 722 #[derive(Default)] 723 pub struct VhostUserFSSlaveMsg { 724 /// File offset. 725 pub fd_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES], 726 /// Offset into the DAX window. 727 pub cache_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES], 728 /// Size of region to map. 729 pub len: [u64; VHOST_USER_FS_SLAVE_ENTRIES], 730 /// Flags for the mmap operation 731 pub flags: [VhostUserFSSlaveMsgFlags; VHOST_USER_FS_SLAVE_ENTRIES], 732 } 733 734 impl VhostUserMsgValidator for VhostUserFSSlaveMsg { is_valid(&self) -> bool735 fn is_valid(&self) -> bool { 736 for i in 0..VHOST_USER_FS_SLAVE_ENTRIES { 737 if ({ self.flags[i] }.bits() & !VhostUserFSSlaveMsgFlags::all().bits()) != 0 738 || self.fd_offset[i].checked_add(self.len[i]).is_none() 739 || self.cache_offset[i].checked_add(self.len[i]).is_none() 740 { 741 return false; 742 } 743 } 744 true 745 } 746 } 747 748 #[cfg(test)] 749 mod tests { 750 use super::*; 751 use std::mem; 752 753 #[test] check_master_request_code()754 fn check_master_request_code() { 755 let code = MasterReq::NOOP; 756 assert!(!code.is_valid()); 757 let code = MasterReq::MAX_CMD; 758 assert!(!code.is_valid()); 759 assert!(code > MasterReq::NOOP); 760 let code = MasterReq::GET_FEATURES; 761 assert!(code.is_valid()); 762 assert_eq!(code, code.clone()); 763 let code: MasterReq = unsafe { std::mem::transmute::<u32, MasterReq>(10000u32) }; 764 assert!(!code.is_valid()); 765 } 766 767 #[test] check_slave_request_code()768 fn check_slave_request_code() { 769 let code = SlaveReq::NOOP; 770 assert!(!code.is_valid()); 771 let code = SlaveReq::MAX_CMD; 772 assert!(!code.is_valid()); 773 assert!(code > SlaveReq::NOOP); 774 let code = SlaveReq::CONFIG_CHANGE_MSG; 775 assert!(code.is_valid()); 776 assert_eq!(code, code.clone()); 777 let code: SlaveReq = unsafe { std::mem::transmute::<u32, SlaveReq>(10000u32) }; 778 assert!(!code.is_valid()); 779 } 780 781 #[test] msg_header_ops()782 fn msg_header_ops() { 783 let mut hdr = VhostUserMsgHeader::new(MasterReq::GET_FEATURES, 0, 0x100); 784 assert_eq!(hdr.get_code(), MasterReq::GET_FEATURES); 785 hdr.set_code(MasterReq::SET_FEATURES); 786 assert_eq!(hdr.get_code(), MasterReq::SET_FEATURES); 787 788 assert_eq!(hdr.get_version(), 0x1); 789 790 assert_eq!(hdr.is_reply(), false); 791 hdr.set_reply(true); 792 assert_eq!(hdr.is_reply(), true); 793 hdr.set_reply(false); 794 795 assert_eq!(hdr.is_need_reply(), false); 796 hdr.set_need_reply(true); 797 assert_eq!(hdr.is_need_reply(), true); 798 hdr.set_need_reply(false); 799 800 assert_eq!(hdr.get_size(), 0x100); 801 hdr.set_size(0x200); 802 assert_eq!(hdr.get_size(), 0x200); 803 804 assert_eq!(hdr.is_need_reply(), false); 805 assert_eq!(hdr.is_reply(), false); 806 assert_eq!(hdr.get_version(), 0x1); 807 808 // Check message length 809 assert!(hdr.is_valid()); 810 hdr.set_size(0x2000); 811 assert!(!hdr.is_valid()); 812 hdr.set_size(0x100); 813 assert_eq!(hdr.get_size(), 0x100); 814 assert!(hdr.is_valid()); 815 hdr.set_size((MAX_MSG_SIZE - mem::size_of::<VhostUserMsgHeader<MasterReq>>()) as u32); 816 assert!(hdr.is_valid()); 817 hdr.set_size(0x0); 818 assert!(hdr.is_valid()); 819 820 // Check version 821 hdr.set_version(0x0); 822 assert!(!hdr.is_valid()); 823 hdr.set_version(0x2); 824 assert!(!hdr.is_valid()); 825 hdr.set_version(0x1); 826 assert!(hdr.is_valid()); 827 828 assert_eq!(hdr, hdr.clone()); 829 } 830 831 #[test] test_vhost_user_message_u64()832 fn test_vhost_user_message_u64() { 833 let val = VhostUserU64::default(); 834 let val1 = VhostUserU64::new(0); 835 836 let a = val.value; 837 let b = val1.value; 838 assert_eq!(a, b); 839 let a = VhostUserU64::new(1).value; 840 assert_eq!(a, 1); 841 } 842 843 #[test] check_user_memory()844 fn check_user_memory() { 845 let mut msg = VhostUserMemory::new(1); 846 assert!(msg.is_valid()); 847 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32; 848 assert!(msg.is_valid()); 849 850 msg.num_regions += 1; 851 assert!(!msg.is_valid()); 852 msg.num_regions = 0xFFFFFFFF; 853 assert!(!msg.is_valid()); 854 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32; 855 msg.padding1 = 1; 856 assert!(!msg.is_valid()); 857 } 858 859 #[test] check_user_memory_region()860 fn check_user_memory_region() { 861 let mut msg = VhostUserMemoryRegion { 862 guest_phys_addr: 0, 863 memory_size: 0x1000, 864 user_addr: 0, 865 mmap_offset: 0, 866 }; 867 assert!(msg.is_valid()); 868 msg.guest_phys_addr = 0xFFFFFFFFFFFFEFFF; 869 assert!(msg.is_valid()); 870 msg.guest_phys_addr = 0xFFFFFFFFFFFFF000; 871 assert!(!msg.is_valid()); 872 msg.guest_phys_addr = 0xFFFFFFFFFFFF0000; 873 msg.memory_size = 0; 874 assert!(!msg.is_valid()); 875 let a = msg.guest_phys_addr; 876 let b = msg.guest_phys_addr; 877 assert_eq!(a, b); 878 879 let msg = VhostUserMemoryRegion::default(); 880 let a = msg.guest_phys_addr; 881 assert_eq!(a, 0); 882 let a = msg.memory_size; 883 assert_eq!(a, 0); 884 let a = msg.user_addr; 885 assert_eq!(a, 0); 886 let a = msg.mmap_offset; 887 assert_eq!(a, 0); 888 } 889 890 #[test] test_vhost_user_state()891 fn test_vhost_user_state() { 892 let state = VhostUserVringState::new(5, 8); 893 894 let a = state.index; 895 assert_eq!(a, 5); 896 let a = state.num; 897 assert_eq!(a, 8); 898 assert_eq!(state.is_valid(), true); 899 900 let state = VhostUserVringState::default(); 901 let a = state.index; 902 assert_eq!(a, 0); 903 let a = state.num; 904 assert_eq!(a, 0); 905 assert_eq!(state.is_valid(), true); 906 } 907 908 #[test] test_vhost_user_addr()909 fn test_vhost_user_addr() { 910 let mut addr = VhostUserVringAddr::new( 911 2, 912 VhostUserVringAddrFlags::VHOST_VRING_F_LOG, 913 0x1000, 914 0x2000, 915 0x3000, 916 0x4000, 917 ); 918 919 let a = addr.index; 920 assert_eq!(a, 2); 921 let a = addr.flags; 922 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits()); 923 let a = addr.descriptor; 924 assert_eq!(a, 0x1000); 925 let a = addr.used; 926 assert_eq!(a, 0x2000); 927 let a = addr.available; 928 assert_eq!(a, 0x3000); 929 let a = addr.log; 930 assert_eq!(a, 0x4000); 931 assert_eq!(addr.is_valid(), true); 932 933 addr.descriptor = 0x1001; 934 assert_eq!(addr.is_valid(), false); 935 addr.descriptor = 0x1000; 936 937 addr.available = 0x3001; 938 assert_eq!(addr.is_valid(), false); 939 addr.available = 0x3000; 940 941 addr.used = 0x2001; 942 assert_eq!(addr.is_valid(), false); 943 addr.used = 0x2000; 944 assert_eq!(addr.is_valid(), true); 945 } 946 947 #[test] test_vhost_user_state_from_config()948 fn test_vhost_user_state_from_config() { 949 let config = VringConfigData { 950 queue_max_size: 256, 951 queue_size: 128, 952 flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits, 953 desc_table_addr: 0x1000, 954 used_ring_addr: 0x2000, 955 avail_ring_addr: 0x3000, 956 log_addr: Some(0x4000), 957 }; 958 let addr = VhostUserVringAddr::from_config_data(2, &config); 959 960 let a = addr.index; 961 assert_eq!(a, 2); 962 let a = addr.flags; 963 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits()); 964 let a = addr.descriptor; 965 assert_eq!(a, 0x1000); 966 let a = addr.used; 967 assert_eq!(a, 0x2000); 968 let a = addr.available; 969 assert_eq!(a, 0x3000); 970 let a = addr.log; 971 assert_eq!(a, 0x4000); 972 assert_eq!(addr.is_valid(), true); 973 } 974 975 #[test] check_user_vring_addr()976 fn check_user_vring_addr() { 977 let mut msg = 978 VhostUserVringAddr::new(0, VhostUserVringAddrFlags::all(), 0x0, 0x0, 0x0, 0x0); 979 assert!(msg.is_valid()); 980 981 msg.descriptor = 1; 982 assert!(!msg.is_valid()); 983 msg.descriptor = 0; 984 985 msg.available = 1; 986 assert!(!msg.is_valid()); 987 msg.available = 0; 988 989 msg.used = 1; 990 assert!(!msg.is_valid()); 991 msg.used = 0; 992 993 msg.flags |= 0x80000000; 994 assert!(!msg.is_valid()); 995 msg.flags &= !0x80000000; 996 } 997 998 #[test] check_user_config_msg()999 fn check_user_config_msg() { 1000 let mut msg = VhostUserConfig::new( 1001 VHOST_USER_CONFIG_OFFSET, 1002 VHOST_USER_CONFIG_SIZE - VHOST_USER_CONFIG_OFFSET, 1003 VhostUserConfigFlags::WRITABLE, 1004 ); 1005 1006 assert!(msg.is_valid()); 1007 msg.size = 0; 1008 assert!(!msg.is_valid()); 1009 msg.size = 1; 1010 assert!(msg.is_valid()); 1011 msg.offset = 0; 1012 assert!(!msg.is_valid()); 1013 msg.offset = VHOST_USER_CONFIG_SIZE; 1014 assert!(!msg.is_valid()); 1015 msg.offset = VHOST_USER_CONFIG_SIZE - 1; 1016 assert!(msg.is_valid()); 1017 msg.size = 2; 1018 assert!(!msg.is_valid()); 1019 msg.size = 1; 1020 msg.flags |= VhostUserConfigFlags::LIVE_MIGRATION.bits(); 1021 assert!(msg.is_valid()); 1022 msg.flags |= 0x4; 1023 assert!(!msg.is_valid()); 1024 } 1025 1026 #[test] test_vhost_user_fs_slave()1027 fn test_vhost_user_fs_slave() { 1028 let mut fs_slave = VhostUserFSSlaveMsg::default(); 1029 1030 assert_eq!(fs_slave.is_valid(), true); 1031 1032 fs_slave.fd_offset[0] = 0xffff_ffff_ffff_ffff; 1033 fs_slave.len[0] = 0x1; 1034 assert_eq!(fs_slave.is_valid(), false); 1035 1036 assert_ne!( 1037 VhostUserFSSlaveMsgFlags::MAP_R, 1038 VhostUserFSSlaveMsgFlags::MAP_W 1039 ); 1040 assert_eq!(VhostUserFSSlaveMsgFlags::EMPTY.bits(), 0); 1041 } 1042 } 1043