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 #![allow(clippy::upper_case_acronyms)] 11 12 use std::convert::TryInto; 13 use std::fmt::Debug; 14 use std::marker::PhantomData; 15 16 use bitflags::bitflags; 17 use data_model::DataInit; 18 19 use crate::VringConfigData; 20 21 /// The vhost-user specification uses a field of u32 to store message length. 22 /// On the other hand, preallocated buffers are needed to receive messages from the Unix domain 23 /// socket. To preallocating a 4GB buffer for each vhost-user message is really just an overhead. 24 /// Among all defined vhost-user messages, only the VhostUserConfig and VhostUserMemory has variable 25 /// message size. For the VhostUserConfig, a maximum size of 4K is enough because the user 26 /// configuration space for virtio devices is (4K - 0x100) bytes at most. For the VhostUserMemory, 27 /// 4K should be enough too because it can support 255 memory regions at most. 28 pub const MAX_MSG_SIZE: usize = 0x1000; 29 30 /// The VhostUserMemory message has variable message size and variable number of attached file 31 /// descriptors. Each user memory region entry in the message payload occupies 32 bytes, 32 /// so setting maximum number of attached file descriptors based on the maximum message size. 33 /// But rust only implements Default and AsMut traits for arrays with 0 - 32 entries, so further 34 /// reduce the maximum number... 35 // pub const MAX_ATTACHED_FD_ENTRIES: usize = (MAX_MSG_SIZE - 8) / 32; 36 pub const MAX_ATTACHED_FD_ENTRIES: usize = 32; 37 38 /// Starting position (inclusion) of the device configuration space in virtio devices. 39 pub const VHOST_USER_CONFIG_OFFSET: u32 = 0x100; 40 41 /// Ending position (exclusion) of the device configuration space in virtio devices. 42 pub const VHOST_USER_CONFIG_SIZE: u32 = 0x1000; 43 44 /// Maximum number of vrings supported. 45 pub const VHOST_USER_MAX_VRINGS: u64 = 0x8000u64; 46 47 /// Used for the payload in Vhost Master messages. 48 pub trait Req: 49 Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Into<u32> + Send + Sync 50 { 51 /// Is the entity valid. is_valid(&self) -> bool52 fn is_valid(&self) -> bool; 53 } 54 55 /// Type of requests sending from masters to slaves. 56 #[repr(u32)] 57 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 58 pub enum MasterReq { 59 /// Null operation. 60 NOOP = 0, 61 /// Get from the underlying vhost implementation the features bit mask. 62 GET_FEATURES = 1, 63 /// Enable features in the underlying vhost implementation using a bit mask. 64 SET_FEATURES = 2, 65 /// Set the current Master as an owner of the session. 66 SET_OWNER = 3, 67 /// No longer used. 68 RESET_OWNER = 4, 69 /// Set the memory map regions on the slave so it can translate the vring addresses. 70 SET_MEM_TABLE = 5, 71 /// Set logging shared memory space. 72 SET_LOG_BASE = 6, 73 /// Set the logging file descriptor, which is passed as ancillary data. 74 SET_LOG_FD = 7, 75 /// Set the size of the queue. 76 SET_VRING_NUM = 8, 77 /// Set the addresses of the different aspects of the vring. 78 SET_VRING_ADDR = 9, 79 /// Set the base offset in the available vring. 80 SET_VRING_BASE = 10, 81 /// Get the available vring base offset. 82 GET_VRING_BASE = 11, 83 /// Set the event file descriptor for adding buffers to the vring. 84 SET_VRING_KICK = 12, 85 /// Set the event file descriptor to signal when buffers are used. 86 SET_VRING_CALL = 13, 87 /// Set the event file descriptor to signal when error occurs. 88 SET_VRING_ERR = 14, 89 /// Get the protocol feature bit mask from the underlying vhost implementation. 90 GET_PROTOCOL_FEATURES = 15, 91 /// Enable protocol features in the underlying vhost implementation. 92 SET_PROTOCOL_FEATURES = 16, 93 /// Query how many queues the backend supports. 94 GET_QUEUE_NUM = 17, 95 /// Signal slave to enable or disable corresponding vring. 96 SET_VRING_ENABLE = 18, 97 /// Ask vhost user backend to broadcast a fake RARP to notify the migration is terminated 98 /// for guest that does not support GUEST_ANNOUNCE. 99 SEND_RARP = 19, 100 /// Set host MTU value exposed to the guest. 101 NET_SET_MTU = 20, 102 /// Set the socket file descriptor for slave initiated requests. 103 SET_SLAVE_REQ_FD = 21, 104 /// Send IOTLB messages with struct vhost_iotlb_msg as payload. 105 IOTLB_MSG = 22, 106 /// Set the endianness of a VQ for legacy devices. 107 SET_VRING_ENDIAN = 23, 108 /// Fetch the contents of the virtio device configuration space. 109 GET_CONFIG = 24, 110 /// Change the contents of the virtio device configuration space. 111 SET_CONFIG = 25, 112 /// Create a session for crypto operation. 113 CREATE_CRYPTO_SESSION = 26, 114 /// Close a session for crypto operation. 115 CLOSE_CRYPTO_SESSION = 27, 116 /// Advise slave that a migration with postcopy enabled is underway. 117 POSTCOPY_ADVISE = 28, 118 /// Advise slave that a transition to postcopy mode has happened. 119 POSTCOPY_LISTEN = 29, 120 /// Advise that postcopy migration has now completed. 121 POSTCOPY_END = 30, 122 /// Get a shared buffer from slave. 123 GET_INFLIGHT_FD = 31, 124 /// Send the shared inflight buffer back to slave. 125 SET_INFLIGHT_FD = 32, 126 /// Sets the GPU protocol socket file descriptor. 127 GPU_SET_SOCKET = 33, 128 /// Ask the vhost user backend to disable all rings and reset all internal 129 /// device state to the initial state. 130 RESET_DEVICE = 34, 131 /// Indicate that a buffer was added to the vring instead of signalling it 132 /// using the vring’s kick file descriptor. 133 VRING_KICK = 35, 134 /// Return a u64 payload containing the maximum number of memory slots. 135 GET_MAX_MEM_SLOTS = 36, 136 /// Update the memory tables by adding the region described. 137 ADD_MEM_REG = 37, 138 /// Update the memory tables by removing the region described. 139 REM_MEM_REG = 38, 140 /// Notify the backend with updated device status as defined in the VIRTIO 141 /// specification. 142 SET_STATUS = 39, 143 /// Query the backend for its device status as defined in the VIRTIO 144 /// specification. 145 GET_STATUS = 40, 146 /// Upper bound of valid commands. 147 MAX_CMD = 41, 148 } 149 150 impl From<MasterReq> for u32 { from(req: MasterReq) -> u32151 fn from(req: MasterReq) -> u32 { 152 req as u32 153 } 154 } 155 156 impl Req for MasterReq { is_valid(&self) -> bool157 fn is_valid(&self) -> bool { 158 (*self > MasterReq::NOOP) && (*self < MasterReq::MAX_CMD) 159 } 160 } 161 162 /// Type of requests sending from slaves to masters. 163 #[repr(u32)] 164 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 165 pub enum SlaveReq { 166 /// Null operation. 167 NOOP = 0, 168 /// Send IOTLB messages with struct vhost_iotlb_msg as payload. 169 IOTLB_MSG = 1, 170 /// Notify that the virtio device's configuration space has changed. 171 CONFIG_CHANGE_MSG = 2, 172 /// Set host notifier for a specified queue. 173 VRING_HOST_NOTIFIER_MSG = 3, 174 /// Indicate that a buffer was used from the vring. 175 VRING_CALL = 4, 176 /// Indicate that an error occurred on the specific vring. 177 VRING_ERR = 5, 178 /// Virtio-fs draft: map file content into the window. 179 FS_MAP = 6, 180 /// Virtio-fs draft: unmap file content from the window. 181 FS_UNMAP = 7, 182 /// Virtio-fs draft: sync file content. 183 FS_SYNC = 8, 184 /// Virtio-fs draft: perform a read/write from an fd directly to GPA. 185 FS_IO = 9, 186 /// Upper bound of valid commands. 187 MAX_CMD = 10, 188 } 189 190 impl From<SlaveReq> for u32 { from(req: SlaveReq) -> u32191 fn from(req: SlaveReq) -> u32 { 192 req as u32 193 } 194 } 195 196 impl Req for SlaveReq { is_valid(&self) -> bool197 fn is_valid(&self) -> bool { 198 (*self > SlaveReq::NOOP) && (*self < SlaveReq::MAX_CMD) 199 } 200 } 201 202 /// Vhost message Validator. 203 pub trait VhostUserMsgValidator { 204 /// Validate message syntax only. 205 /// It doesn't validate message semantics such as protocol version number and dependency 206 /// on feature flags etc. is_valid(&self) -> bool207 fn is_valid(&self) -> bool { 208 true 209 } 210 } 211 212 // Bit mask for common message flags. 213 bitflags! { 214 /// Common message flags for vhost-user requests and replies. 215 pub struct VhostUserHeaderFlag: u32 { 216 /// Bits[0..2] is message version number. 217 const VERSION = 0x3; 218 /// Mark message as reply. 219 const REPLY = 0x4; 220 /// Sender anticipates a reply message from the peer. 221 const NEED_REPLY = 0x8; 222 /// All valid bits. 223 const ALL_FLAGS = 0xc; 224 /// All reserved bits. 225 const RESERVED_BITS = !0xf; 226 } 227 } 228 229 /// Common message header for vhost-user requests and replies. 230 /// A vhost-user message consists of 3 header fields and an optional payload. All numbers are in the 231 /// machine native byte order. 232 #[repr(packed)] 233 #[derive(Copy)] 234 pub struct VhostUserMsgHeader<R: Req> { 235 request: u32, 236 flags: u32, 237 size: u32, 238 _r: PhantomData<R>, 239 } 240 // Safe because it only has data and has no implicit padding. 241 unsafe impl<R: Req> DataInit for VhostUserMsgHeader<R> {} 242 243 impl<R: Req> Debug for VhostUserMsgHeader<R> { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 245 f.debug_struct("Point") 246 .field("request", &{ self.request }) 247 .field("flags", &{ self.flags }) 248 .field("size", &{ self.size }) 249 .finish() 250 } 251 } 252 253 impl<R: Req> Clone for VhostUserMsgHeader<R> { clone(&self) -> VhostUserMsgHeader<R>254 fn clone(&self) -> VhostUserMsgHeader<R> { 255 *self 256 } 257 } 258 259 impl<R: Req> PartialEq for VhostUserMsgHeader<R> { eq(&self, other: &Self) -> bool260 fn eq(&self, other: &Self) -> bool { 261 self.request == other.request && self.flags == other.flags && self.size == other.size 262 } 263 } 264 265 impl<R: Req> VhostUserMsgHeader<R> { 266 /// Create a new instance of `VhostUserMsgHeader`. new(request: R, flags: u32, size: u32) -> Self267 pub fn new(request: R, flags: u32, size: u32) -> Self { 268 // Default to protocol version 1 269 let fl = (flags & VhostUserHeaderFlag::ALL_FLAGS.bits()) | 0x1; 270 VhostUserMsgHeader { 271 request: request.into(), 272 flags: fl, 273 size, 274 _r: PhantomData, 275 } 276 } 277 278 /// Get message type. get_code(&self) -> R279 pub fn get_code(&self) -> R { 280 // It's safe because R is marked as repr(u32). 281 unsafe { std::mem::transmute_copy::<u32, R>(&{ self.request }) } 282 } 283 284 /// Set message type. set_code(&mut self, request: R)285 pub fn set_code(&mut self, request: R) { 286 self.request = request.into(); 287 } 288 289 /// Get message version number. get_version(&self) -> u32290 pub fn get_version(&self) -> u32 { 291 self.flags & 0x3 292 } 293 294 /// Set message version number. set_version(&mut self, ver: u32)295 pub fn set_version(&mut self, ver: u32) { 296 self.flags &= !0x3; 297 self.flags |= ver & 0x3; 298 } 299 300 /// Check whether it's a reply message. is_reply(&self) -> bool301 pub fn is_reply(&self) -> bool { 302 (self.flags & VhostUserHeaderFlag::REPLY.bits()) != 0 303 } 304 305 /// Mark message as reply. set_reply(&mut self, is_reply: bool)306 pub fn set_reply(&mut self, is_reply: bool) { 307 if is_reply { 308 self.flags |= VhostUserHeaderFlag::REPLY.bits(); 309 } else { 310 self.flags &= !VhostUserHeaderFlag::REPLY.bits(); 311 } 312 } 313 314 /// Check whether reply for this message is requested. is_need_reply(&self) -> bool315 pub fn is_need_reply(&self) -> bool { 316 (self.flags & VhostUserHeaderFlag::NEED_REPLY.bits()) != 0 317 } 318 319 /// Mark that reply for this message is needed. set_need_reply(&mut self, need_reply: bool)320 pub fn set_need_reply(&mut self, need_reply: bool) { 321 if need_reply { 322 self.flags |= VhostUserHeaderFlag::NEED_REPLY.bits(); 323 } else { 324 self.flags &= !VhostUserHeaderFlag::NEED_REPLY.bits(); 325 } 326 } 327 328 /// Check whether it's the reply message for the request `req`. is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool329 pub fn is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool { 330 self.is_reply() && !req.is_reply() && self.get_code() == req.get_code() 331 } 332 333 /// Get message size. get_size(&self) -> u32334 pub fn get_size(&self) -> u32 { 335 self.size 336 } 337 338 /// Set message size. set_size(&mut self, size: u32)339 pub fn set_size(&mut self, size: u32) { 340 self.size = size; 341 } 342 } 343 344 impl<R: Req> Default for VhostUserMsgHeader<R> { default() -> Self345 fn default() -> Self { 346 VhostUserMsgHeader { 347 request: 0, 348 flags: 0x1, 349 size: 0, 350 _r: PhantomData, 351 } 352 } 353 } 354 355 impl From<[u8; 12]> for VhostUserMsgHeader<MasterReq> { from(buf: [u8; 12]) -> Self356 fn from(buf: [u8; 12]) -> Self { 357 // Convert 4-length slice into [u8; 4]. This must succeed. 358 let req = u32::from_le_bytes(buf[0..4].try_into().unwrap()); 359 // Safe because `MasterReq` is defined with `#[repr(u32)]`. 360 let req = unsafe { std::mem::transmute_copy::<u32, MasterReq>(&req) }; 361 362 let flags = u32::from_le_bytes(buf[4..8].try_into().unwrap()); 363 let size = u32::from_le_bytes(buf[8..12].try_into().unwrap()); 364 Self::new(req, flags, size) 365 } 366 } 367 368 impl<T: Req> VhostUserMsgValidator for VhostUserMsgHeader<T> { 369 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool370 fn is_valid(&self) -> bool { 371 if !self.get_code().is_valid() { 372 return false; 373 } else if self.size as usize > MAX_MSG_SIZE { 374 return false; 375 } else if self.get_version() != 0x1 { 376 return false; 377 } else if (self.flags & VhostUserHeaderFlag::RESERVED_BITS.bits()) != 0 { 378 return false; 379 } 380 true 381 } 382 } 383 384 // Bit mask for transport specific flags in VirtIO feature set defined by vhost-user. 385 bitflags! { 386 /// Transport specific flags in VirtIO feature set defined by vhost-user. 387 pub struct VhostUserVirtioFeatures: u64 { 388 /// Feature flag for the protocol feature. 389 const PROTOCOL_FEATURES = 0x4000_0000; 390 } 391 } 392 393 // Bit mask for vhost-user protocol feature flags. 394 bitflags! { 395 /// Vhost-user protocol feature flags. 396 pub struct VhostUserProtocolFeatures: u64 { 397 /// Support multiple queues. 398 const MQ = 0x0000_0001; 399 /// Support logging through shared memory fd. 400 const LOG_SHMFD = 0x0000_0002; 401 /// Support broadcasting fake RARP packet. 402 const RARP = 0x0000_0004; 403 /// Support sending reply messages for requests with NEED_REPLY flag set. 404 const REPLY_ACK = 0x0000_0008; 405 /// Support setting MTU for virtio-net devices. 406 const MTU = 0x0000_0010; 407 /// Allow the slave to send requests to the master by an optional communication channel. 408 const SLAVE_REQ = 0x0000_0020; 409 /// Support setting slave endian by SET_VRING_ENDIAN. 410 const CROSS_ENDIAN = 0x0000_0040; 411 /// Support crypto operations. 412 const CRYPTO_SESSION = 0x0000_0080; 413 /// Support sending userfault_fd from slaves to masters. 414 const PAGEFAULT = 0x0000_0100; 415 /// Support Virtio device configuration. 416 const CONFIG = 0x0000_0200; 417 /// Allow the slave to send fds (at most 8 descriptors in each message) to the master. 418 const SLAVE_SEND_FD = 0x0000_0400; 419 /// Allow the slave to register a host notifier. 420 const HOST_NOTIFIER = 0x0000_0800; 421 /// Support inflight shmfd. 422 const INFLIGHT_SHMFD = 0x0000_1000; 423 /// Support resetting the device. 424 const RESET_DEVICE = 0x0000_2000; 425 /// Support inband notifications. 426 const INBAND_NOTIFICATIONS = 0x0000_4000; 427 /// Support configuring memory slots. 428 const CONFIGURE_MEM_SLOTS = 0x0000_8000; 429 /// Support reporting status. 430 const STATUS = 0x0001_0000; 431 } 432 } 433 434 /// A generic message to encapsulate a 64-bit value. 435 #[repr(packed)] 436 #[derive(Default, Clone, Copy)] 437 pub struct VhostUserU64 { 438 /// The encapsulated 64-bit common value. 439 pub value: u64, 440 } 441 // Safe because it only has data and has no implicit padding. 442 unsafe impl DataInit for VhostUserU64 {} 443 444 impl VhostUserU64 { 445 /// Create a new instance. new(value: u64) -> Self446 pub fn new(value: u64) -> Self { 447 VhostUserU64 { value } 448 } 449 } 450 451 impl VhostUserMsgValidator for VhostUserU64 {} 452 453 /// Memory region descriptor for the SET_MEM_TABLE request. 454 #[repr(packed)] 455 #[derive(Default, Clone, Copy)] 456 pub struct VhostUserMemory { 457 /// Number of memory regions in the payload. 458 pub num_regions: u32, 459 /// Padding for alignment. 460 pub padding1: u32, 461 } 462 // Safe because it only has data and has no implicit padding. 463 unsafe impl DataInit for VhostUserMemory {} 464 465 impl VhostUserMemory { 466 /// Create a new instance. new(cnt: u32) -> Self467 pub fn new(cnt: u32) -> Self { 468 VhostUserMemory { 469 num_regions: cnt, 470 padding1: 0, 471 } 472 } 473 } 474 475 impl VhostUserMsgValidator for VhostUserMemory { 476 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool477 fn is_valid(&self) -> bool { 478 if self.padding1 != 0 { 479 return false; 480 } else if self.num_regions == 0 || self.num_regions > MAX_ATTACHED_FD_ENTRIES as u32 { 481 return false; 482 } 483 true 484 } 485 } 486 487 /// Memory region descriptors as payload for the SET_MEM_TABLE request. 488 #[repr(packed)] 489 #[derive(Default, Clone, Copy)] 490 pub struct VhostUserMemoryRegion { 491 /// Guest physical address of the memory region. 492 pub guest_phys_addr: u64, 493 /// Size of the memory region. 494 pub memory_size: u64, 495 /// Virtual address in the current process. 496 pub user_addr: u64, 497 /// Offset where region starts in the mapped memory. 498 pub mmap_offset: u64, 499 } 500 // Safe because it only has data and has no implicit padding. 501 unsafe impl DataInit for VhostUserMemoryRegion {} 502 503 impl VhostUserMemoryRegion { 504 /// Create a new instance. new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self505 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self { 506 VhostUserMemoryRegion { 507 guest_phys_addr, 508 memory_size, 509 user_addr, 510 mmap_offset, 511 } 512 } 513 } 514 515 impl VhostUserMsgValidator for VhostUserMemoryRegion { is_valid(&self) -> bool516 fn is_valid(&self) -> bool { 517 if self.memory_size == 0 518 || self.guest_phys_addr.checked_add(self.memory_size).is_none() 519 || self.user_addr.checked_add(self.memory_size).is_none() 520 || self.mmap_offset.checked_add(self.memory_size).is_none() 521 { 522 return false; 523 } 524 true 525 } 526 } 527 528 /// Payload of the VhostUserMemory message. 529 pub type VhostUserMemoryPayload = Vec<VhostUserMemoryRegion>; 530 531 /// Single memory region descriptor as payload for ADD_MEM_REG and REM_MEM_REG 532 /// requests. 533 #[repr(C)] 534 #[derive(Default, Clone, Copy)] 535 pub struct VhostUserSingleMemoryRegion { 536 /// Padding for correct alignment 537 padding: u64, 538 /// Guest physical address of the memory region. 539 pub guest_phys_addr: u64, 540 /// Size of the memory region. 541 pub memory_size: u64, 542 /// Virtual address in the current process. 543 pub user_addr: u64, 544 /// Offset where region starts in the mapped memory. 545 pub mmap_offset: u64, 546 } 547 // Safe because it only has data and has no implicit padding. 548 unsafe impl DataInit for VhostUserSingleMemoryRegion {} 549 550 impl VhostUserSingleMemoryRegion { 551 /// Create a new instance. new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self552 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self { 553 VhostUserSingleMemoryRegion { 554 padding: 0, 555 guest_phys_addr, 556 memory_size, 557 user_addr, 558 mmap_offset, 559 } 560 } 561 } 562 563 impl VhostUserMsgValidator for VhostUserSingleMemoryRegion { is_valid(&self) -> bool564 fn is_valid(&self) -> bool { 565 if self.memory_size == 0 566 || self.guest_phys_addr.checked_add(self.memory_size).is_none() 567 || self.user_addr.checked_add(self.memory_size).is_none() 568 || self.mmap_offset.checked_add(self.memory_size).is_none() 569 { 570 return false; 571 } 572 true 573 } 574 } 575 576 /// Vring state descriptor. 577 #[repr(packed)] 578 #[derive(Default, Clone, Copy)] 579 pub struct VhostUserVringState { 580 /// Vring index. 581 pub index: u32, 582 /// A common 32bit value to encapsulate vring state etc. 583 pub num: u32, 584 } 585 586 // Safe because it only has data and has no implicit padding. 587 unsafe impl DataInit for VhostUserVringState {} 588 589 impl VhostUserVringState { 590 /// Create a new instance. new(index: u32, num: u32) -> Self591 pub fn new(index: u32, num: u32) -> Self { 592 VhostUserVringState { index, num } 593 } 594 } 595 596 impl VhostUserMsgValidator for VhostUserVringState {} 597 598 // Bit mask for vring address flags. 599 bitflags! { 600 /// Flags for vring address. 601 pub struct VhostUserVringAddrFlags: u32 { 602 /// Support log of vring operations. 603 /// Modifications to "used" vring should be logged. 604 const VHOST_VRING_F_LOG = 0x1; 605 } 606 } 607 608 /// Vring address descriptor. 609 #[repr(packed)] 610 #[derive(Default, Clone, Copy)] 611 pub struct VhostUserVringAddr { 612 /// Vring index. 613 pub index: u32, 614 /// Vring flags defined by VhostUserVringAddrFlags. 615 pub flags: u32, 616 /// Ring address of the vring descriptor table. 617 pub descriptor: u64, 618 /// Ring address of the vring used ring. 619 pub used: u64, 620 /// Ring address of the vring available ring. 621 pub available: u64, 622 /// Guest address for logging. 623 pub log: u64, 624 } 625 626 // Safe because it only has data and has no implicit padding. 627 unsafe impl DataInit for VhostUserVringAddr {} 628 629 impl VhostUserVringAddr { 630 /// Create a new instance. new( index: u32, flags: VhostUserVringAddrFlags, descriptor: u64, used: u64, available: u64, log: u64, ) -> Self631 pub fn new( 632 index: u32, 633 flags: VhostUserVringAddrFlags, 634 descriptor: u64, 635 used: u64, 636 available: u64, 637 log: u64, 638 ) -> Self { 639 VhostUserVringAddr { 640 index, 641 flags: flags.bits(), 642 descriptor, 643 used, 644 available, 645 log, 646 } 647 } 648 649 /// Create a new instance from `VringConfigData`. 650 #[cfg_attr(feature = "cargo-clippy", allow(clippy::identity_conversion))] from_config_data(index: u32, config_data: &VringConfigData) -> Self651 pub fn from_config_data(index: u32, config_data: &VringConfigData) -> Self { 652 let log_addr = config_data.log_addr.unwrap_or(0); 653 VhostUserVringAddr { 654 index, 655 flags: config_data.flags, 656 descriptor: config_data.desc_table_addr, 657 used: config_data.used_ring_addr, 658 available: config_data.avail_ring_addr, 659 log: log_addr, 660 } 661 } 662 } 663 664 impl VhostUserMsgValidator for VhostUserVringAddr { 665 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool666 fn is_valid(&self) -> bool { 667 if (self.flags & !VhostUserVringAddrFlags::all().bits()) != 0 { 668 return false; 669 } else if self.descriptor & 0xf != 0 { 670 return false; 671 } else if self.available & 0x1 != 0 { 672 return false; 673 } else if self.used & 0x3 != 0 { 674 return false; 675 } 676 true 677 } 678 } 679 680 // Bit mask for the vhost-user device configuration message. 681 bitflags! { 682 /// Flags for the device configuration message. 683 pub struct VhostUserConfigFlags: u32 { 684 /// Vhost master messages used for writeable fields. 685 const WRITABLE = 0x1; 686 /// Vhost master messages used for live migration. 687 const LIVE_MIGRATION = 0x2; 688 } 689 } 690 691 /// Message to read/write device configuration space. 692 #[repr(packed)] 693 #[derive(Default, Clone, Copy)] 694 pub struct VhostUserConfig { 695 /// Offset of virtio device's configuration space. 696 pub offset: u32, 697 /// Configuration space access size in bytes. 698 pub size: u32, 699 /// Flags for the device configuration operation. 700 pub flags: u32, 701 } 702 // Safe because it only has data and has no implicit padding. 703 unsafe impl DataInit for VhostUserConfig {} 704 705 impl VhostUserConfig { 706 /// Create a new instance. new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self707 pub fn new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self { 708 VhostUserConfig { 709 offset, 710 size, 711 flags: flags.bits(), 712 } 713 } 714 } 715 716 impl VhostUserMsgValidator for VhostUserConfig { 717 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool718 fn is_valid(&self) -> bool { 719 let end_addr = match self.size.checked_add(self.offset) { 720 Some(addr) => addr, 721 None => return false, 722 }; 723 if (self.flags & !VhostUserConfigFlags::all().bits()) != 0 { 724 return false; 725 } else if self.size == 0 || end_addr > VHOST_USER_CONFIG_SIZE { 726 return false; 727 } 728 true 729 } 730 } 731 732 /// Payload for the VhostUserConfig message. 733 pub type VhostUserConfigPayload = Vec<u8>; 734 735 /// Single memory region descriptor as payload for ADD_MEM_REG and REM_MEM_REG 736 /// requests. 737 #[repr(C)] 738 #[derive(Default, Clone, Copy)] 739 pub struct VhostUserInflight { 740 /// Size of the area to track inflight I/O. 741 pub mmap_size: u64, 742 /// Offset of this area from the start of the supplied file descriptor. 743 pub mmap_offset: u64, 744 /// Number of virtqueues. 745 pub num_queues: u16, 746 /// Size of virtqueues. 747 pub queue_size: u16, 748 } 749 750 // Safe because it only has data and has no implicit padding. 751 unsafe impl DataInit for VhostUserInflight {} 752 753 impl VhostUserInflight { 754 /// Create a new instance. new(mmap_size: u64, mmap_offset: u64, num_queues: u16, queue_size: u16) -> Self755 pub fn new(mmap_size: u64, mmap_offset: u64, num_queues: u16, queue_size: u16) -> Self { 756 VhostUserInflight { 757 mmap_size, 758 mmap_offset, 759 num_queues, 760 queue_size, 761 } 762 } 763 } 764 765 impl VhostUserMsgValidator for VhostUserInflight { is_valid(&self) -> bool766 fn is_valid(&self) -> bool { 767 if self.num_queues == 0 || self.queue_size == 0 { 768 return false; 769 } 770 true 771 } 772 } 773 774 /* 775 * TODO: support dirty log, live migration and IOTLB operations. 776 #[repr(packed)] 777 pub struct VhostUserVringArea { 778 pub index: u32, 779 pub flags: u32, 780 pub size: u64, 781 pub offset: u64, 782 } 783 784 #[repr(packed)] 785 pub struct VhostUserLog { 786 pub size: u64, 787 pub offset: u64, 788 } 789 790 #[repr(packed)] 791 pub struct VhostUserIotlb { 792 pub iova: u64, 793 pub size: u64, 794 pub user_addr: u64, 795 pub permission: u8, 796 pub optype: u8, 797 } 798 */ 799 800 // Bit mask for flags in virtio-fs slave messages 801 bitflags! { 802 #[derive(Default)] 803 /// Flags for virtio-fs slave messages. 804 pub struct VhostUserFSSlaveMsgFlags: u64 { 805 /// Empty permission. 806 const EMPTY = 0x0; 807 /// Read permission. 808 const MAP_R = 0x1; 809 /// Write permission. 810 const MAP_W = 0x2; 811 } 812 } 813 814 /// Max entries in one virtio-fs slave request. 815 pub const VHOST_USER_FS_SLAVE_ENTRIES: usize = 8; 816 817 /// Slave request message to update the MMIO window. 818 #[repr(packed)] 819 #[derive(Default, Copy, Clone)] 820 pub struct VhostUserFSSlaveMsg { 821 /// File offset. 822 pub fd_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES], 823 /// Offset into the DAX window. 824 pub cache_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES], 825 /// Size of region to map. 826 pub len: [u64; VHOST_USER_FS_SLAVE_ENTRIES], 827 /// Flags for the mmap operation 828 pub flags: [VhostUserFSSlaveMsgFlags; VHOST_USER_FS_SLAVE_ENTRIES], 829 } 830 // Safe because it only has data and has no implicit padding. 831 unsafe impl DataInit for VhostUserFSSlaveMsg {} 832 833 impl VhostUserMsgValidator for VhostUserFSSlaveMsg { is_valid(&self) -> bool834 fn is_valid(&self) -> bool { 835 for i in 0..VHOST_USER_FS_SLAVE_ENTRIES { 836 if ({ self.flags[i] }.bits() & !VhostUserFSSlaveMsgFlags::all().bits()) != 0 837 || self.fd_offset[i].checked_add(self.len[i]).is_none() 838 || self.cache_offset[i].checked_add(self.len[i]).is_none() 839 { 840 return false; 841 } 842 } 843 true 844 } 845 } 846 847 /// Inflight I/O descriptor state for split virtqueues 848 #[repr(packed)] 849 #[derive(Clone, Copy, Default)] 850 pub struct DescStateSplit { 851 /// Indicate whether this descriptor (only head) is inflight or not. 852 pub inflight: u8, 853 /// Padding 854 padding: [u8; 5], 855 /// List of last batch of used descriptors, only when batching is used for submitting 856 pub next: u16, 857 /// Preserve order of fetching available descriptors, only for head descriptor 858 pub counter: u64, 859 } 860 861 impl DescStateSplit { 862 /// New instance of DescStateSplit struct new() -> Self863 pub fn new() -> Self { 864 Self::default() 865 } 866 } 867 868 /// Inflight I/O queue region for split virtqueues 869 #[repr(packed)] 870 pub struct QueueRegionSplit { 871 /// Features flags of this region 872 pub features: u64, 873 /// Version of this region 874 pub version: u16, 875 /// Number of DescStateSplit entries 876 pub desc_num: u16, 877 /// List to track last batch of used descriptors 878 pub last_batch_head: u16, 879 /// Idx value of used ring 880 pub used_idx: u16, 881 /// Pointer to an array of DescStateSplit entries 882 pub desc: u64, 883 } 884 885 impl QueueRegionSplit { 886 /// New instance of QueueRegionSplit struct new(features: u64, queue_size: u16) -> Self887 pub fn new(features: u64, queue_size: u16) -> Self { 888 QueueRegionSplit { 889 features, 890 version: 1, 891 desc_num: queue_size, 892 last_batch_head: 0, 893 used_idx: 0, 894 desc: 0, 895 } 896 } 897 } 898 899 /// Inflight I/O descriptor state for packed virtqueues 900 #[repr(packed)] 901 #[derive(Clone, Copy, Default)] 902 pub struct DescStatePacked { 903 /// Indicate whether this descriptor (only head) is inflight or not. 904 pub inflight: u8, 905 /// Padding 906 padding: u8, 907 /// Link to next free entry 908 pub next: u16, 909 /// Link to last entry of descriptor list, only for head 910 pub last: u16, 911 /// Length of descriptor list, only for head 912 pub num: u16, 913 /// Preserve order of fetching avail descriptors, only for head 914 pub counter: u64, 915 /// Buffer ID 916 pub id: u16, 917 /// Descriptor flags 918 pub flags: u16, 919 /// Buffer length 920 pub len: u32, 921 /// Buffer address 922 pub addr: u64, 923 } 924 925 impl DescStatePacked { 926 /// New instance of DescStatePacked struct new() -> Self927 pub fn new() -> Self { 928 Self::default() 929 } 930 } 931 932 /// Inflight I/O queue region for packed virtqueues 933 #[repr(packed)] 934 pub struct QueueRegionPacked { 935 /// Features flags of this region 936 pub features: u64, 937 /// version of this region 938 pub version: u16, 939 /// size of descriptor state array 940 pub desc_num: u16, 941 /// head of free DescStatePacked entry list 942 pub free_head: u16, 943 /// old head of free DescStatePacked entry list 944 pub old_free_head: u16, 945 /// used idx of descriptor ring 946 pub used_idx: u16, 947 /// old used idx of descriptor ring 948 pub old_used_idx: u16, 949 /// device ring wrap counter 950 pub used_wrap_counter: u8, 951 /// old device ring wrap counter 952 pub old_used_wrap_counter: u8, 953 /// Padding 954 padding: [u8; 7], 955 /// Pointer to array tracking state of each descriptor from descriptor ring 956 pub desc: u64, 957 } 958 959 impl QueueRegionPacked { 960 /// New instance of QueueRegionPacked struct new(features: u64, queue_size: u16) -> Self961 pub fn new(features: u64, queue_size: u16) -> Self { 962 QueueRegionPacked { 963 features, 964 version: 1, 965 desc_num: queue_size, 966 free_head: 0, 967 old_free_head: 0, 968 used_idx: 0, 969 old_used_idx: 0, 970 used_wrap_counter: 0, 971 old_used_wrap_counter: 0, 972 padding: [0; 7], 973 desc: 0, 974 } 975 } 976 } 977 978 #[cfg(test)] 979 mod tests { 980 use super::*; 981 use std::mem; 982 983 #[test] check_master_request_code()984 fn check_master_request_code() { 985 let code = MasterReq::NOOP; 986 assert!(!code.is_valid()); 987 let code = MasterReq::MAX_CMD; 988 assert!(!code.is_valid()); 989 assert!(code > MasterReq::NOOP); 990 let code = MasterReq::GET_FEATURES; 991 assert!(code.is_valid()); 992 assert_eq!(code, code.clone()); 993 let code: MasterReq = unsafe { std::mem::transmute::<u32, MasterReq>(10000u32) }; 994 assert!(!code.is_valid()); 995 } 996 997 #[test] check_slave_request_code()998 fn check_slave_request_code() { 999 let code = SlaveReq::NOOP; 1000 assert!(!code.is_valid()); 1001 let code = SlaveReq::MAX_CMD; 1002 assert!(!code.is_valid()); 1003 assert!(code > SlaveReq::NOOP); 1004 let code = SlaveReq::CONFIG_CHANGE_MSG; 1005 assert!(code.is_valid()); 1006 assert_eq!(code, code.clone()); 1007 let code: SlaveReq = unsafe { std::mem::transmute::<u32, SlaveReq>(10000u32) }; 1008 assert!(!code.is_valid()); 1009 } 1010 1011 #[test] msg_header_ops()1012 fn msg_header_ops() { 1013 let mut hdr = VhostUserMsgHeader::new(MasterReq::GET_FEATURES, 0, 0x100); 1014 assert_eq!(hdr.get_code(), MasterReq::GET_FEATURES); 1015 hdr.set_code(MasterReq::SET_FEATURES); 1016 assert_eq!(hdr.get_code(), MasterReq::SET_FEATURES); 1017 1018 assert_eq!(hdr.get_version(), 0x1); 1019 1020 assert!(!hdr.is_reply()); 1021 hdr.set_reply(true); 1022 assert!(hdr.is_reply()); 1023 hdr.set_reply(false); 1024 1025 assert!(!hdr.is_need_reply()); 1026 hdr.set_need_reply(true); 1027 assert!(hdr.is_need_reply()); 1028 hdr.set_need_reply(false); 1029 1030 assert_eq!(hdr.get_size(), 0x100); 1031 hdr.set_size(0x200); 1032 assert_eq!(hdr.get_size(), 0x200); 1033 1034 assert!(!hdr.is_need_reply()); 1035 assert!(!hdr.is_reply()); 1036 assert_eq!(hdr.get_version(), 0x1); 1037 1038 // Check message length 1039 assert!(hdr.is_valid()); 1040 hdr.set_size(0x2000); 1041 assert!(!hdr.is_valid()); 1042 hdr.set_size(0x100); 1043 assert_eq!(hdr.get_size(), 0x100); 1044 assert!(hdr.is_valid()); 1045 hdr.set_size((MAX_MSG_SIZE - mem::size_of::<VhostUserMsgHeader<MasterReq>>()) as u32); 1046 assert!(hdr.is_valid()); 1047 hdr.set_size(0x0); 1048 assert!(hdr.is_valid()); 1049 1050 // Check version 1051 hdr.set_version(0x0); 1052 assert!(!hdr.is_valid()); 1053 hdr.set_version(0x2); 1054 assert!(!hdr.is_valid()); 1055 hdr.set_version(0x1); 1056 assert!(hdr.is_valid()); 1057 1058 // Test Debug, Clone, PartiaEq trait 1059 assert_eq!(hdr, hdr.clone()); 1060 assert_eq!(hdr.clone().get_code(), hdr.get_code()); 1061 assert_eq!(format!("{:?}", hdr.clone()), format!("{:?}", hdr)); 1062 } 1063 1064 #[test] test_vhost_user_message_u64()1065 fn test_vhost_user_message_u64() { 1066 let val = VhostUserU64::default(); 1067 let val1 = VhostUserU64::new(0); 1068 1069 let a = val.value; 1070 let b = val1.value; 1071 assert_eq!(a, b); 1072 let a = VhostUserU64::new(1).value; 1073 assert_eq!(a, 1); 1074 } 1075 1076 #[test] check_user_memory()1077 fn check_user_memory() { 1078 let mut msg = VhostUserMemory::new(1); 1079 assert!(msg.is_valid()); 1080 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32; 1081 assert!(msg.is_valid()); 1082 1083 msg.num_regions += 1; 1084 assert!(!msg.is_valid()); 1085 msg.num_regions = 0xFFFFFFFF; 1086 assert!(!msg.is_valid()); 1087 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32; 1088 msg.padding1 = 1; 1089 assert!(!msg.is_valid()); 1090 } 1091 1092 #[test] check_user_memory_region()1093 fn check_user_memory_region() { 1094 let mut msg = VhostUserMemoryRegion { 1095 guest_phys_addr: 0, 1096 memory_size: 0x1000, 1097 user_addr: 0, 1098 mmap_offset: 0, 1099 }; 1100 assert!(msg.is_valid()); 1101 msg.guest_phys_addr = 0xFFFFFFFFFFFFEFFF; 1102 assert!(msg.is_valid()); 1103 msg.guest_phys_addr = 0xFFFFFFFFFFFFF000; 1104 assert!(!msg.is_valid()); 1105 msg.guest_phys_addr = 0xFFFFFFFFFFFF0000; 1106 msg.memory_size = 0; 1107 assert!(!msg.is_valid()); 1108 let a = msg.guest_phys_addr; 1109 let b = msg.guest_phys_addr; 1110 assert_eq!(a, b); 1111 1112 let msg = VhostUserMemoryRegion::default(); 1113 let a = msg.guest_phys_addr; 1114 assert_eq!(a, 0); 1115 let a = msg.memory_size; 1116 assert_eq!(a, 0); 1117 let a = msg.user_addr; 1118 assert_eq!(a, 0); 1119 let a = msg.mmap_offset; 1120 assert_eq!(a, 0); 1121 } 1122 1123 #[test] test_vhost_user_state()1124 fn test_vhost_user_state() { 1125 let state = VhostUserVringState::new(5, 8); 1126 1127 let a = state.index; 1128 assert_eq!(a, 5); 1129 let a = state.num; 1130 assert_eq!(a, 8); 1131 assert!(state.is_valid()); 1132 1133 let state = VhostUserVringState::default(); 1134 let a = state.index; 1135 assert_eq!(a, 0); 1136 let a = state.num; 1137 assert_eq!(a, 0); 1138 assert!(state.is_valid()); 1139 } 1140 1141 #[test] test_vhost_user_addr()1142 fn test_vhost_user_addr() { 1143 let mut addr = VhostUserVringAddr::new( 1144 2, 1145 VhostUserVringAddrFlags::VHOST_VRING_F_LOG, 1146 0x1000, 1147 0x2000, 1148 0x3000, 1149 0x4000, 1150 ); 1151 1152 let a = addr.index; 1153 assert_eq!(a, 2); 1154 let a = addr.flags; 1155 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits()); 1156 let a = addr.descriptor; 1157 assert_eq!(a, 0x1000); 1158 let a = addr.used; 1159 assert_eq!(a, 0x2000); 1160 let a = addr.available; 1161 assert_eq!(a, 0x3000); 1162 let a = addr.log; 1163 assert_eq!(a, 0x4000); 1164 assert!(addr.is_valid()); 1165 1166 addr.descriptor = 0x1001; 1167 assert!(!addr.is_valid()); 1168 addr.descriptor = 0x1000; 1169 1170 addr.available = 0x3001; 1171 assert!(!addr.is_valid()); 1172 addr.available = 0x3000; 1173 1174 addr.used = 0x2001; 1175 assert!(!addr.is_valid()); 1176 addr.used = 0x2000; 1177 assert!(addr.is_valid()); 1178 } 1179 1180 #[test] test_vhost_user_state_from_config()1181 fn test_vhost_user_state_from_config() { 1182 let config = VringConfigData { 1183 queue_max_size: 256, 1184 queue_size: 128, 1185 flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits, 1186 desc_table_addr: 0x1000, 1187 used_ring_addr: 0x2000, 1188 avail_ring_addr: 0x3000, 1189 log_addr: Some(0x4000), 1190 }; 1191 let addr = VhostUserVringAddr::from_config_data(2, &config); 1192 1193 let a = addr.index; 1194 assert_eq!(a, 2); 1195 let a = addr.flags; 1196 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits()); 1197 let a = addr.descriptor; 1198 assert_eq!(a, 0x1000); 1199 let a = addr.used; 1200 assert_eq!(a, 0x2000); 1201 let a = addr.available; 1202 assert_eq!(a, 0x3000); 1203 let a = addr.log; 1204 assert_eq!(a, 0x4000); 1205 assert!(addr.is_valid()); 1206 } 1207 1208 #[test] check_user_vring_addr()1209 fn check_user_vring_addr() { 1210 let mut msg = 1211 VhostUserVringAddr::new(0, VhostUserVringAddrFlags::all(), 0x0, 0x0, 0x0, 0x0); 1212 assert!(msg.is_valid()); 1213 1214 msg.descriptor = 1; 1215 assert!(!msg.is_valid()); 1216 msg.descriptor = 0; 1217 1218 msg.available = 1; 1219 assert!(!msg.is_valid()); 1220 msg.available = 0; 1221 1222 msg.used = 1; 1223 assert!(!msg.is_valid()); 1224 msg.used = 0; 1225 1226 msg.flags |= 0x80000000; 1227 assert!(!msg.is_valid()); 1228 msg.flags &= !0x80000000; 1229 } 1230 1231 #[test] check_user_config_msg()1232 fn check_user_config_msg() { 1233 let mut msg = 1234 VhostUserConfig::new(0, VHOST_USER_CONFIG_SIZE, VhostUserConfigFlags::WRITABLE); 1235 1236 assert!(msg.is_valid()); 1237 msg.size = 0; 1238 assert!(!msg.is_valid()); 1239 msg.size = 1; 1240 assert!(msg.is_valid()); 1241 msg.offset = u32::MAX; 1242 assert!(!msg.is_valid()); 1243 msg.offset = VHOST_USER_CONFIG_SIZE; 1244 assert!(!msg.is_valid()); 1245 msg.offset = VHOST_USER_CONFIG_SIZE - 1; 1246 assert!(msg.is_valid()); 1247 msg.size = 2; 1248 assert!(!msg.is_valid()); 1249 msg.size = 1; 1250 msg.flags |= VhostUserConfigFlags::LIVE_MIGRATION.bits(); 1251 assert!(msg.is_valid()); 1252 msg.flags |= 0x4; 1253 assert!(!msg.is_valid()); 1254 } 1255 1256 #[test] test_vhost_user_fs_slave()1257 fn test_vhost_user_fs_slave() { 1258 let mut fs_slave = VhostUserFSSlaveMsg::default(); 1259 1260 assert!(fs_slave.is_valid()); 1261 1262 fs_slave.fd_offset[0] = 0xffff_ffff_ffff_ffff; 1263 fs_slave.len[0] = 0x1; 1264 assert!(!fs_slave.is_valid()); 1265 1266 assert_ne!( 1267 VhostUserFSSlaveMsgFlags::MAP_R, 1268 VhostUserFSSlaveMsgFlags::MAP_W 1269 ); 1270 assert_eq!(VhostUserFSSlaveMsgFlags::EMPTY.bits(), 0); 1271 } 1272 } 1273