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::fmt::Debug; 13 use std::marker::PhantomData; 14 15 use base::Protection; 16 use bitflags::bitflags; 17 use zerocopy::AsBytes; 18 use zerocopy::FromBytes; 19 use zerocopy::FromZeroes; 20 21 use crate::VringConfigData; 22 23 /// The VhostUserMemory message has variable message size and variable number of attached file 24 /// descriptors. Each user memory region entry in the message payload occupies 32 bytes, 25 /// so setting maximum number of attached file descriptors based on the maximum message size. 26 /// But rust only implements Default and AsMut traits for arrays with 0 - 32 entries, so further 27 /// reduce the maximum number... 28 // pub const MAX_ATTACHED_FD_ENTRIES: usize = (MAX_MSG_SIZE - 8) / 32; 29 pub const MAX_ATTACHED_FD_ENTRIES: usize = 32; 30 31 /// Starting position (inclusion) of the device configuration space in virtio devices. 32 pub const VHOST_USER_CONFIG_OFFSET: u32 = 0x100; 33 34 /// Ending position (exclusion) of the device configuration space in virtio devices. 35 pub const VHOST_USER_CONFIG_SIZE: u32 = 0x1000; 36 37 /// Maximum number of vrings supported. 38 pub const VHOST_USER_MAX_VRINGS: u64 = 0x8000u64; 39 40 /// Message type. Either [[FrontendReq]] or [[BackendReq]]. 41 pub trait Req: 42 Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Into<u32> + TryFrom<u32> + Send + Sync 43 { 44 } 45 46 /// Error when converting an integer to an enum value. 47 #[derive(Copy, Clone, Debug, PartialEq, Eq, thiserror::Error)] 48 pub enum ReqError { 49 /// The value does not correspond to a valid message code. 50 #[error("The value {0} does not correspond to a valid message code.")] 51 InvalidValue(u32), 52 } 53 54 /// Type of requests sent to the backend. 55 /// 56 /// These are called "front-end message types" in the spec, so we call them `FrontendReq` here even 57 /// though it is somewhat confusing that the `BackendClient` sends `FrontendReq`s to a 58 /// `BackendServer`. 59 #[repr(u32)] 60 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, enumn::N)] 61 pub enum FrontendReq { 62 /// Get from the underlying vhost implementation the features bit mask. 63 GET_FEATURES = 1, 64 /// Enable features in the underlying vhost implementation using a bit mask. 65 SET_FEATURES = 2, 66 /// Set the current frontend as an owner of the session. 67 SET_OWNER = 3, 68 /// No longer used. 69 RESET_OWNER = 4, 70 /// Set the memory map regions on the backend so it can translate the vring addresses. 71 SET_MEM_TABLE = 5, 72 /// Set logging shared memory space. 73 SET_LOG_BASE = 6, 74 /// Set the logging file descriptor, which is passed as ancillary data. 75 SET_LOG_FD = 7, 76 /// Set the size of the queue. 77 SET_VRING_NUM = 8, 78 /// Set the addresses of the different aspects of the vring. 79 SET_VRING_ADDR = 9, 80 /// Set the base offset in the available vring. 81 SET_VRING_BASE = 10, 82 /// Get the available vring base offset. 83 GET_VRING_BASE = 11, 84 /// Set the event file descriptor for adding buffers to the vring. 85 SET_VRING_KICK = 12, 86 /// Set the event file descriptor to signal when buffers are used. 87 SET_VRING_CALL = 13, 88 /// Set the event file descriptor to signal when error occurs. 89 SET_VRING_ERR = 14, 90 /// Get the protocol feature bit mask from the underlying vhost implementation. 91 GET_PROTOCOL_FEATURES = 15, 92 /// Enable protocol features in the underlying vhost implementation. 93 SET_PROTOCOL_FEATURES = 16, 94 /// Query how many queues the backend supports. 95 GET_QUEUE_NUM = 17, 96 /// Signal backend to enable or disable corresponding vring. 97 SET_VRING_ENABLE = 18, 98 /// Ask vhost user backend to broadcast a fake RARP to notify the migration is terminated 99 /// for guest that does not support GUEST_ANNOUNCE. 100 SEND_RARP = 19, 101 /// Set host MTU value exposed to the guest. 102 NET_SET_MTU = 20, 103 /// Set the socket file descriptor for backend initiated requests. 104 SET_BACKEND_REQ_FD = 21, 105 /// Send IOTLB messages with struct vhost_iotlb_msg as payload. 106 IOTLB_MSG = 22, 107 /// Set the endianness of a VQ for legacy devices. 108 SET_VRING_ENDIAN = 23, 109 /// Fetch the contents of the virtio device configuration space. 110 GET_CONFIG = 24, 111 /// Change the contents of the virtio device configuration space. 112 SET_CONFIG = 25, 113 /// Create a session for crypto operation. 114 CREATE_CRYPTO_SESSION = 26, 115 /// Close a session for crypto operation. 116 CLOSE_CRYPTO_SESSION = 27, 117 /// Advise backend that a migration with postcopy enabled is underway. 118 POSTCOPY_ADVISE = 28, 119 /// Advise backend that a transition to postcopy mode has happened. 120 POSTCOPY_LISTEN = 29, 121 /// Advise that postcopy migration has now completed. 122 POSTCOPY_END = 30, 123 /// Get a shared buffer from backend. 124 GET_INFLIGHT_FD = 31, 125 /// Send the shared inflight buffer back to backend. 126 SET_INFLIGHT_FD = 32, 127 /// Sets the GPU protocol socket file descriptor. 128 GPU_SET_SOCKET = 33, 129 /// Ask the vhost user backend to disable all rings and reset all internal 130 /// device state to the initial state. 131 RESET_DEVICE = 34, 132 /// Indicate that a buffer was added to the vring instead of signalling it 133 /// using the vring’s kick file descriptor. 134 VRING_KICK = 35, 135 /// Return a u64 payload containing the maximum number of memory slots. 136 GET_MAX_MEM_SLOTS = 36, 137 /// Update the memory tables by adding the region described. 138 ADD_MEM_REG = 37, 139 /// Update the memory tables by removing the region described. 140 REM_MEM_REG = 38, 141 /// Notify the backend with updated device status as defined in the VIRTIO 142 /// specification. 143 SET_STATUS = 39, 144 /// Query the backend for its device status as defined in the VIRTIO 145 /// specification. 146 GET_STATUS = 40, 147 148 // Non-standard message types. 149 /// Stop all queue handlers and save each queue state. 150 SLEEP = 1000, 151 /// Start up all queue handlers with their saved queue state. 152 WAKE = 1001, 153 /// Request serialized state of vhost process. 154 SNAPSHOT = 1002, 155 /// Request to restore state of vhost process. 156 RESTORE = 1003, 157 /// Get a list of the device's shared memory regions. 158 GET_SHARED_MEMORY_REGIONS = 1004, 159 } 160 161 impl From<FrontendReq> for u32 { from(req: FrontendReq) -> u32162 fn from(req: FrontendReq) -> u32 { 163 req as u32 164 } 165 } 166 167 impl Req for FrontendReq {} 168 169 impl TryFrom<u32> for FrontendReq { 170 type Error = ReqError; 171 try_from(value: u32) -> Result<Self, Self::Error>172 fn try_from(value: u32) -> Result<Self, Self::Error> { 173 FrontendReq::n(value).ok_or(ReqError::InvalidValue(value)) 174 } 175 } 176 177 /// Type of requests sending from backends to frontends. 178 /// 179 /// These are called "backend-end message types" in the spec, so we call them `BackendReq` here 180 /// even though it is somewhat confusing that the `FrontendClient` sends `BackendReq`s to a 181 /// `FrontendServer`. 182 #[repr(u32)] 183 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, enumn::N)] 184 pub enum BackendReq { 185 /// Send IOTLB messages with struct vhost_iotlb_msg as payload. 186 IOTLB_MSG = 1, 187 /// Notify that the virtio device's configuration space has changed. 188 CONFIG_CHANGE_MSG = 2, 189 /// Set host notifier for a specified queue. 190 VRING_HOST_NOTIFIER_MSG = 3, 191 /// Indicate that a buffer was used from the vring. 192 VRING_CALL = 4, 193 /// Indicate that an error occurred on the specific vring. 194 VRING_ERR = 5, 195 196 // Non-standard message types. 197 /// Indicates a request to map a fd into a shared memory region. 198 SHMEM_MAP = 1000, 199 /// Indicates a request to unmap part of a shared memory region. 200 SHMEM_UNMAP = 1001, 201 /// Virtio-fs draft: map file content into the window. 202 DEPRECATED__FS_MAP = 1002, 203 /// Virtio-fs draft: unmap file content from the window. 204 DEPRECATED__FS_UNMAP = 1003, 205 /// Virtio-fs draft: sync file content. 206 DEPRECATED__FS_SYNC = 1004, 207 /// Virtio-fs draft: perform a read/write from an fd directly to GPA. 208 DEPRECATED__FS_IO = 1005, 209 /// Indicates a request to map GPU memory into a shared memory region. 210 GPU_MAP = 1006, 211 /// Indicates a request to map external memory into a shared memory region. 212 EXTERNAL_MAP = 1007, 213 } 214 215 impl From<BackendReq> for u32 { from(req: BackendReq) -> u32216 fn from(req: BackendReq) -> u32 { 217 req as u32 218 } 219 } 220 221 impl Req for BackendReq {} 222 223 impl TryFrom<u32> for BackendReq { 224 type Error = ReqError; 225 try_from(value: u32) -> Result<Self, Self::Error>226 fn try_from(value: u32) -> Result<Self, Self::Error> { 227 BackendReq::n(value).ok_or(ReqError::InvalidValue(value)) 228 } 229 } 230 231 /// Vhost message Validator. 232 pub trait VhostUserMsgValidator { 233 /// Validate message syntax only. 234 /// It doesn't validate message semantics such as protocol version number and dependency 235 /// on feature flags etc. is_valid(&self) -> bool236 fn is_valid(&self) -> bool { 237 true 238 } 239 } 240 241 // Bit mask for common message flags. 242 bitflags! { 243 /// Common message flags for vhost-user requests and replies. 244 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 245 #[repr(transparent)] 246 pub struct VhostUserHeaderFlag: u32 { 247 /// Bits[0..2] is message version number. 248 const VERSION = 0x3; 249 /// Mark message as reply. 250 const REPLY = 0x4; 251 /// Sender anticipates a reply message from the peer. 252 const NEED_REPLY = 0x8; 253 /// All valid bits. 254 const ALL_FLAGS = 0xc; 255 /// All reserved bits. 256 const RESERVED_BITS = !0xf; 257 } 258 } 259 260 /// Common message header for vhost-user requests and replies. 261 /// A vhost-user message consists of 3 header fields and an optional payload. All numbers are in the 262 /// machine native byte order. 263 #[repr(C, packed)] 264 #[derive(Copy, FromZeroes, FromBytes, AsBytes)] 265 pub struct VhostUserMsgHeader<R: Req> { 266 request: u32, 267 flags: u32, 268 size: u32, 269 _r: PhantomData<R>, 270 } 271 272 impl<R: Req> Debug for VhostUserMsgHeader<R> { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 274 f.debug_struct("VhostUserMsgHeader") 275 .field("request", &{ self.request }) 276 .field("flags", &{ self.flags }) 277 .field("size", &{ self.size }) 278 .finish() 279 } 280 } 281 282 impl<R: Req> Clone for VhostUserMsgHeader<R> { clone(&self) -> VhostUserMsgHeader<R>283 fn clone(&self) -> VhostUserMsgHeader<R> { 284 *self 285 } 286 } 287 288 impl<R: Req> PartialEq for VhostUserMsgHeader<R> { eq(&self, other: &Self) -> bool289 fn eq(&self, other: &Self) -> bool { 290 self.request == other.request && self.flags == other.flags && self.size == other.size 291 } 292 } 293 294 impl<R: Req> VhostUserMsgHeader<R> { 295 /// Create a new instance of `VhostUserMsgHeader`. new(request: R, flags: u32, size: u32) -> Self296 pub fn new(request: R, flags: u32, size: u32) -> Self { 297 // Default to protocol version 1 298 let fl = (flags & VhostUserHeaderFlag::ALL_FLAGS.bits()) | 0x1; 299 VhostUserMsgHeader { 300 request: request.into(), 301 flags: fl, 302 size, 303 _r: PhantomData, 304 } 305 } 306 307 /// Get message type. get_code(&self) -> std::result::Result<R, R::Error>308 pub fn get_code(&self) -> std::result::Result<R, R::Error> { 309 R::try_from(self.request) 310 } 311 312 /// Set message type. set_code(&mut self, request: R)313 pub fn set_code(&mut self, request: R) { 314 self.request = request.into(); 315 } 316 317 /// Get message version number. get_version(&self) -> u32318 pub fn get_version(&self) -> u32 { 319 self.flags & 0x3 320 } 321 322 /// Set message version number. set_version(&mut self, ver: u32)323 pub fn set_version(&mut self, ver: u32) { 324 self.flags &= !0x3; 325 self.flags |= ver & 0x3; 326 } 327 328 /// Check whether it's a reply message. is_reply(&self) -> bool329 pub fn is_reply(&self) -> bool { 330 (self.flags & VhostUserHeaderFlag::REPLY.bits()) != 0 331 } 332 333 /// Mark message as reply. set_reply(&mut self, is_reply: bool)334 pub fn set_reply(&mut self, is_reply: bool) { 335 if is_reply { 336 self.flags |= VhostUserHeaderFlag::REPLY.bits(); 337 } else { 338 self.flags &= !VhostUserHeaderFlag::REPLY.bits(); 339 } 340 } 341 342 /// Check whether reply for this message is requested. is_need_reply(&self) -> bool343 pub fn is_need_reply(&self) -> bool { 344 (self.flags & VhostUserHeaderFlag::NEED_REPLY.bits()) != 0 345 } 346 347 /// Mark that reply for this message is needed. set_need_reply(&mut self, need_reply: bool)348 pub fn set_need_reply(&mut self, need_reply: bool) { 349 if need_reply { 350 self.flags |= VhostUserHeaderFlag::NEED_REPLY.bits(); 351 } else { 352 self.flags &= !VhostUserHeaderFlag::NEED_REPLY.bits(); 353 } 354 } 355 356 /// Check whether it's the reply message for the request `req`. is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool357 pub fn is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool { 358 self.is_reply() && !req.is_reply() && self.request == req.request 359 } 360 361 /// Get message size. get_size(&self) -> u32362 pub fn get_size(&self) -> u32 { 363 self.size 364 } 365 366 /// Set message size. set_size(&mut self, size: u32)367 pub fn set_size(&mut self, size: u32) { 368 self.size = size; 369 } 370 } 371 372 impl<R: Req> Default for VhostUserMsgHeader<R> { default() -> Self373 fn default() -> Self { 374 VhostUserMsgHeader { 375 request: 0, 376 flags: 0x1, 377 size: 0, 378 _r: PhantomData, 379 } 380 } 381 } 382 383 impl<T: Req> VhostUserMsgValidator for VhostUserMsgHeader<T> { 384 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool385 fn is_valid(&self) -> bool { 386 if self.get_code().is_err() { 387 return false; 388 } else if self.get_version() != 0x1 { 389 return false; 390 } else if (self.flags & VhostUserHeaderFlag::RESERVED_BITS.bits()) != 0 { 391 return false; 392 } 393 true 394 } 395 } 396 397 pub const VIRTIO_F_RING_PACKED: u32 = 34; 398 399 /// Virtio feature flag for the vhost-user protocol features. 400 pub const VHOST_USER_F_PROTOCOL_FEATURES: u32 = 30; 401 402 // Bit mask for vhost-user protocol feature flags. 403 bitflags! { 404 /// Vhost-user protocol feature flags. 405 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 406 #[repr(transparent)] 407 pub struct VhostUserProtocolFeatures: u64 { 408 /// Support multiple queues. 409 const MQ = 0x0000_0001; 410 /// Support logging through shared memory fd. 411 const LOG_SHMFD = 0x0000_0002; 412 /// Support broadcasting fake RARP packet. 413 const RARP = 0x0000_0004; 414 /// Support sending reply messages for requests with NEED_REPLY flag set. 415 const REPLY_ACK = 0x0000_0008; 416 /// Support setting MTU for virtio-net devices. 417 const MTU = 0x0000_0010; 418 /// Allow the backend to send requests to the frontend by an optional communication channel. 419 const BACKEND_REQ = 0x0000_0020; 420 /// Support setting backend endian by SET_VRING_ENDIAN. 421 const CROSS_ENDIAN = 0x0000_0040; 422 /// Support crypto operations. 423 const CRYPTO_SESSION = 0x0000_0080; 424 /// Support sending userfault_fd from backends to frontends. 425 const PAGEFAULT = 0x0000_0100; 426 /// Support Virtio device configuration. 427 const CONFIG = 0x0000_0200; 428 /// Allow the backend to send fds (at most 8 descriptors in each message) to the frontend. 429 const BACKEND_SEND_FD = 0x0000_0400; 430 /// Allow the backend to register a host notifier. 431 const HOST_NOTIFIER = 0x0000_0800; 432 /// Support inflight shmfd. 433 const INFLIGHT_SHMFD = 0x0000_1000; 434 /// Support resetting the device. 435 const RESET_DEVICE = 0x0000_2000; 436 /// Support inband notifications. 437 const INBAND_NOTIFICATIONS = 0x0000_4000; 438 /// Support configuring memory slots. 439 const CONFIGURE_MEM_SLOTS = 0x0000_8000; 440 /// Support reporting status. 441 const STATUS = 0x0001_0000; 442 /// Support Xen mmap. 443 const XEN_MMAP = 0x0002_0000; 444 /// Support shared memory regions. (Non-standard.) 445 const SHARED_MEMORY_REGIONS = 0x8000_0000; 446 } 447 } 448 449 /// A generic message to encapsulate a 64-bit value. 450 #[repr(packed)] 451 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 452 pub struct VhostUserU64 { 453 /// The encapsulated 64-bit common value. 454 pub value: u64, 455 } 456 457 impl VhostUserU64 { 458 /// Create a new instance. new(value: u64) -> Self459 pub fn new(value: u64) -> Self { 460 VhostUserU64 { value } 461 } 462 } 463 464 impl VhostUserMsgValidator for VhostUserU64 {} 465 466 /// An empty message. 467 #[repr(C)] 468 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 469 pub struct VhostUserEmptyMsg; 470 471 impl VhostUserMsgValidator for VhostUserEmptyMsg {} 472 473 /// A generic message to encapsulate a success or failure. 474 /// use i8 instead of bool to allow FromBytes to be derived. 475 /// type layout is same for all supported architectures. 476 #[repr(C, packed)] 477 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 478 pub struct VhostUserSuccess { 479 /// True if request was successful. 480 bool_store: i8, 481 } 482 483 impl VhostUserSuccess { 484 /// Create a new instance. new(success: bool) -> Self485 pub fn new(success: bool) -> Self { 486 VhostUserSuccess { 487 bool_store: success.into(), 488 } 489 } 490 491 /// Convert i8 storage back to bool 492 #[inline(always)] success(&self) -> bool493 pub fn success(&self) -> bool { 494 self.bool_store != 0 495 } 496 } 497 498 impl VhostUserMsgValidator for VhostUserSuccess {} 499 500 /// A generic message for empty message. 501 /// ZST in repr(C) has same type layout as repr(rust) 502 #[repr(C)] 503 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 504 pub struct VhostUserEmptyMessage; 505 506 impl VhostUserMsgValidator for VhostUserEmptyMessage {} 507 508 /// Memory region descriptor for the SET_MEM_TABLE request. 509 #[repr(C, packed)] 510 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 511 pub struct VhostUserMemory { 512 /// Number of memory regions in the payload. 513 pub num_regions: u32, 514 /// Padding for alignment. 515 pub padding1: u32, 516 } 517 518 impl VhostUserMemory { 519 /// Create a new instance. new(cnt: u32) -> Self520 pub fn new(cnt: u32) -> Self { 521 VhostUserMemory { 522 num_regions: cnt, 523 padding1: 0, 524 } 525 } 526 } 527 528 impl VhostUserMsgValidator for VhostUserMemory { 529 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool530 fn is_valid(&self) -> bool { 531 if self.padding1 != 0 { 532 return false; 533 } else if self.num_regions == 0 || self.num_regions > MAX_ATTACHED_FD_ENTRIES as u32 { 534 return false; 535 } 536 true 537 } 538 } 539 540 /// Memory region descriptors as payload for the SET_MEM_TABLE request. 541 #[repr(C, packed)] 542 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 543 pub struct VhostUserMemoryRegion { 544 /// Guest physical address of the memory region. 545 pub guest_phys_addr: u64, 546 /// Size of the memory region. 547 pub memory_size: u64, 548 /// Virtual address in the current process. 549 pub user_addr: u64, 550 /// Offset where region starts in the mapped memory. 551 pub mmap_offset: u64, 552 } 553 554 impl VhostUserMemoryRegion { 555 /// Create a new instance. new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self556 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self { 557 VhostUserMemoryRegion { 558 guest_phys_addr, 559 memory_size, 560 user_addr, 561 mmap_offset, 562 } 563 } 564 } 565 566 impl VhostUserMsgValidator for VhostUserMemoryRegion { is_valid(&self) -> bool567 fn is_valid(&self) -> bool { 568 if self.memory_size == 0 569 || self.guest_phys_addr.checked_add(self.memory_size).is_none() 570 || self.user_addr.checked_add(self.memory_size).is_none() 571 || self.mmap_offset.checked_add(self.memory_size).is_none() 572 { 573 return false; 574 } 575 true 576 } 577 } 578 579 /// Payload of the VhostUserMemory message. 580 pub type VhostUserMemoryPayload = Vec<VhostUserMemoryRegion>; 581 582 /// Single memory region descriptor as payload for ADD_MEM_REG and REM_MEM_REG 583 /// requests. 584 #[repr(C)] 585 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 586 pub struct VhostUserSingleMemoryRegion { 587 /// Padding for correct alignment 588 padding: u64, 589 /// Guest physical address of the memory region. 590 pub guest_phys_addr: u64, 591 /// Size of the memory region. 592 pub memory_size: u64, 593 /// Virtual address in the current process. 594 pub user_addr: u64, 595 /// Offset where region starts in the mapped memory. 596 pub mmap_offset: u64, 597 } 598 599 impl VhostUserSingleMemoryRegion { 600 /// Create a new instance. new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self601 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self { 602 VhostUserSingleMemoryRegion { 603 padding: 0, 604 guest_phys_addr, 605 memory_size, 606 user_addr, 607 mmap_offset, 608 } 609 } 610 } 611 612 impl VhostUserMsgValidator for VhostUserSingleMemoryRegion { is_valid(&self) -> bool613 fn is_valid(&self) -> bool { 614 if self.memory_size == 0 615 || self.guest_phys_addr.checked_add(self.memory_size).is_none() 616 || self.user_addr.checked_add(self.memory_size).is_none() 617 || self.mmap_offset.checked_add(self.memory_size).is_none() 618 { 619 return false; 620 } 621 true 622 } 623 } 624 625 /// Vring state descriptor. 626 #[repr(packed)] 627 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 628 pub struct VhostUserVringState { 629 /// Vring index. 630 pub index: u32, 631 /// A common 32bit value to encapsulate vring state etc. 632 pub num: u32, 633 } 634 635 impl VhostUserVringState { 636 /// Create a new instance. new(index: u32, num: u32) -> Self637 pub fn new(index: u32, num: u32) -> Self { 638 VhostUserVringState { index, num } 639 } 640 } 641 642 impl VhostUserMsgValidator for VhostUserVringState {} 643 644 // Bit mask for vring address flags. 645 bitflags! { 646 /// Flags for vring address. 647 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 648 #[repr(transparent)] 649 pub struct VhostUserVringAddrFlags: u32 { 650 /// Support log of vring operations. 651 /// Modifications to "used" vring should be logged. 652 const VHOST_VRING_F_LOG = 0x1; 653 } 654 } 655 656 /// Vring address descriptor. 657 #[repr(C, packed)] 658 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 659 pub struct VhostUserVringAddr { 660 /// Vring index. 661 pub index: u32, 662 /// Vring flags defined by VhostUserVringAddrFlags. 663 pub flags: u32, 664 /// Ring address of the vring descriptor table. 665 pub descriptor: u64, 666 /// Ring address of the vring used ring. 667 pub used: u64, 668 /// Ring address of the vring available ring. 669 pub available: u64, 670 /// Guest address for logging. 671 pub log: u64, 672 } 673 674 impl VhostUserVringAddr { 675 /// Create a new instance. new( index: u32, flags: VhostUserVringAddrFlags, descriptor: u64, used: u64, available: u64, log: u64, ) -> Self676 pub fn new( 677 index: u32, 678 flags: VhostUserVringAddrFlags, 679 descriptor: u64, 680 used: u64, 681 available: u64, 682 log: u64, 683 ) -> Self { 684 VhostUserVringAddr { 685 index, 686 flags: flags.bits(), 687 descriptor, 688 used, 689 available, 690 log, 691 } 692 } 693 694 /// Create a new instance from `VringConfigData`. from_config_data(index: u32, config_data: &VringConfigData) -> Self695 pub fn from_config_data(index: u32, config_data: &VringConfigData) -> Self { 696 let log_addr = config_data.log_addr.unwrap_or(0); 697 VhostUserVringAddr { 698 index, 699 flags: config_data.flags, 700 descriptor: config_data.desc_table_addr, 701 used: config_data.used_ring_addr, 702 available: config_data.avail_ring_addr, 703 log: log_addr, 704 } 705 } 706 } 707 708 impl VhostUserMsgValidator for VhostUserVringAddr { 709 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool710 fn is_valid(&self) -> bool { 711 if (self.flags & !VhostUserVringAddrFlags::all().bits()) != 0 { 712 return false; 713 } else if self.descriptor & 0xf != 0 { 714 return false; 715 } else if self.available & 0x1 != 0 { 716 return false; 717 } else if self.used & 0x3 != 0 { 718 return false; 719 } 720 true 721 } 722 } 723 724 // Bit mask for the vhost-user device configuration message. 725 bitflags! { 726 /// Flags for the device configuration message. 727 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 728 #[repr(transparent)] 729 pub struct VhostUserConfigFlags: u32 { 730 /// Vhost frontend messages used for writeable fields. 731 const WRITABLE = 0x1; 732 /// Vhost frontend messages used for live migration. 733 const LIVE_MIGRATION = 0x2; 734 } 735 } 736 737 /// Message to read/write device configuration space. 738 #[repr(packed)] 739 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 740 pub struct VhostUserConfig { 741 /// Offset of virtio device's configuration space. 742 pub offset: u32, 743 /// Configuration space access size in bytes. 744 pub size: u32, 745 /// Flags for the device configuration operation. 746 pub flags: u32, 747 } 748 749 impl VhostUserConfig { 750 /// Create a new instance. new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self751 pub fn new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self { 752 VhostUserConfig { 753 offset, 754 size, 755 flags: flags.bits(), 756 } 757 } 758 } 759 760 impl VhostUserMsgValidator for VhostUserConfig { 761 #[allow(clippy::if_same_then_else)] is_valid(&self) -> bool762 fn is_valid(&self) -> bool { 763 let end_addr = match self.size.checked_add(self.offset) { 764 Some(addr) => addr, 765 None => return false, 766 }; 767 if (self.flags & !VhostUserConfigFlags::all().bits()) != 0 { 768 return false; 769 } else if self.size == 0 || end_addr > VHOST_USER_CONFIG_SIZE { 770 return false; 771 } 772 true 773 } 774 } 775 776 /// Payload for the VhostUserConfig message. 777 pub type VhostUserConfigPayload = Vec<u8>; 778 779 /// Single memory region descriptor as payload for ADD_MEM_REG and REM_MEM_REG 780 /// requests. 781 /// This struct is defined by qemu and compiles with arch-dependent padding. 782 /// Interestingly, all our supported archs (arm, aarch64, x86_64) has same 783 /// data layout for this type. 784 #[repr(C)] 785 #[derive(Default, Clone, Copy, AsBytes, FromZeroes, FromBytes)] 786 pub struct VhostUserInflight { 787 /// Size of the area to track inflight I/O. 788 pub mmap_size: u64, 789 /// Offset of this area from the start of the supplied file descriptor. 790 pub mmap_offset: u64, 791 /// Number of virtqueues. 792 pub num_queues: u16, 793 /// Size of virtqueues. 794 pub queue_size: u16, 795 /// implicit padding on 64-bit platforms 796 pub _padding: [u8; 4], 797 } 798 799 impl VhostUserInflight { 800 /// Create a new instance. new(mmap_size: u64, mmap_offset: u64, num_queues: u16, queue_size: u16) -> Self801 pub fn new(mmap_size: u64, mmap_offset: u64, num_queues: u16, queue_size: u16) -> Self { 802 VhostUserInflight { 803 mmap_size, 804 mmap_offset, 805 num_queues, 806 queue_size, 807 ..Default::default() 808 } 809 } 810 } 811 812 impl VhostUserMsgValidator for VhostUserInflight { is_valid(&self) -> bool813 fn is_valid(&self) -> bool { 814 if self.num_queues == 0 || self.queue_size == 0 { 815 return false; 816 } 817 true 818 } 819 } 820 821 /* 822 * TODO: support dirty log, live migration and IOTLB operations. 823 #[repr(packed)] 824 pub struct VhostUserVringArea { 825 pub index: u32, 826 pub flags: u32, 827 pub size: u64, 828 pub offset: u64, 829 } 830 831 #[repr(packed)] 832 pub struct VhostUserLog { 833 pub size: u64, 834 pub offset: u64, 835 } 836 837 #[repr(packed)] 838 pub struct VhostUserIotlb { 839 pub iova: u64, 840 pub size: u64, 841 pub user_addr: u64, 842 pub permission: u8, 843 pub optype: u8, 844 } 845 */ 846 847 /// Flags for SHMEM_MAP messages. 848 #[repr(transparent)] 849 #[derive( 850 AsBytes, 851 FromZeroes, 852 FromBytes, 853 Copy, 854 Clone, 855 Debug, 856 Default, 857 Eq, 858 Hash, 859 Ord, 860 PartialEq, 861 PartialOrd, 862 )] 863 pub struct VhostUserShmemMapMsgFlags(u8); 864 865 bitflags! { 866 impl VhostUserShmemMapMsgFlags: u8 { 867 /// Empty permission. 868 const EMPTY = 0x0; 869 /// Read permission. 870 const MAP_R = 0x1; 871 /// Write permission. 872 const MAP_W = 0x2; 873 } 874 } 875 876 impl From<Protection> for VhostUserShmemMapMsgFlags { from(prot: Protection) -> Self877 fn from(prot: Protection) -> Self { 878 let mut flags = Self::EMPTY; 879 flags.set(Self::MAP_R, prot.allows(&Protection::read())); 880 flags.set(Self::MAP_W, prot.allows(&Protection::write())); 881 flags 882 } 883 } 884 885 impl From<VhostUserShmemMapMsgFlags> for Protection { from(flags: VhostUserShmemMapMsgFlags) -> Self886 fn from(flags: VhostUserShmemMapMsgFlags) -> Self { 887 let mut prot = Protection::default(); 888 if flags.contains(VhostUserShmemMapMsgFlags::MAP_R) { 889 prot = prot.set_read(); 890 } 891 if flags.contains(VhostUserShmemMapMsgFlags::MAP_W) { 892 prot = prot.set_write(); 893 } 894 prot 895 } 896 } 897 898 /// Backend request message to map a file into a shared memory region. 899 #[repr(C, packed)] 900 #[derive(Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)] 901 pub struct VhostUserShmemMapMsg { 902 /// Flags for the mmap operation 903 pub flags: VhostUserShmemMapMsgFlags, 904 /// Shared memory region id. 905 pub shmid: u8, 906 padding: [u8; 6], 907 /// Offset into the shared memory region. 908 pub shm_offset: u64, 909 /// File offset. 910 pub fd_offset: u64, 911 /// Size of region to map. 912 pub len: u64, 913 } 914 915 impl VhostUserMsgValidator for VhostUserShmemMapMsg { is_valid(&self) -> bool916 fn is_valid(&self) -> bool { 917 (self.flags.bits() & !VhostUserShmemMapMsgFlags::all().bits()) == 0 918 && self.fd_offset.checked_add(self.len).is_some() 919 && self.shm_offset.checked_add(self.len).is_some() 920 } 921 } 922 923 impl VhostUserShmemMapMsg { 924 /// New instance of VhostUserShmemMapMsg struct new( shmid: u8, shm_offset: u64, fd_offset: u64, len: u64, flags: VhostUserShmemMapMsgFlags, ) -> Self925 pub fn new( 926 shmid: u8, 927 shm_offset: u64, 928 fd_offset: u64, 929 len: u64, 930 flags: VhostUserShmemMapMsgFlags, 931 ) -> Self { 932 Self { 933 flags, 934 shmid, 935 padding: [0; 6], 936 shm_offset, 937 fd_offset, 938 len, 939 } 940 } 941 } 942 943 /// Backend request message to map GPU memory into a shared memory region. 944 #[repr(C, packed)] 945 #[derive(Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)] 946 pub struct VhostUserGpuMapMsg { 947 /// Shared memory region id. 948 pub shmid: u8, 949 padding: [u8; 7], 950 /// Offset into the shared memory region. 951 pub shm_offset: u64, 952 /// Size of region to map. 953 pub len: u64, 954 /// Index of the memory type. 955 pub memory_idx: u32, 956 /// Type of share handle. 957 pub handle_type: u32, 958 /// Device UUID 959 pub device_uuid: [u8; 16], 960 /// Driver UUID 961 pub driver_uuid: [u8; 16], 962 } 963 964 impl VhostUserMsgValidator for VhostUserGpuMapMsg { is_valid(&self) -> bool965 fn is_valid(&self) -> bool { 966 self.len > 0 967 } 968 } 969 970 impl VhostUserGpuMapMsg { 971 /// New instance of VhostUserGpuMapMsg struct new( shmid: u8, shm_offset: u64, len: u64, memory_idx: u32, handle_type: u32, device_uuid: [u8; 16], driver_uuid: [u8; 16], ) -> Self972 pub fn new( 973 shmid: u8, 974 shm_offset: u64, 975 len: u64, 976 memory_idx: u32, 977 handle_type: u32, 978 device_uuid: [u8; 16], 979 driver_uuid: [u8; 16], 980 ) -> Self { 981 Self { 982 shmid, 983 padding: [0; 7], 984 shm_offset, 985 len, 986 memory_idx, 987 handle_type, 988 device_uuid, 989 driver_uuid, 990 } 991 } 992 } 993 994 /// Backend request message to map external memory into a shared memory region. 995 #[repr(C, packed)] 996 #[derive(Default, Copy, Clone, AsBytes, FromZeroes, FromBytes)] 997 pub struct VhostUserExternalMapMsg { 998 /// Shared memory region id. 999 pub shmid: u8, 1000 padding: [u8; 7], 1001 /// Offset into the shared memory region. 1002 pub shm_offset: u64, 1003 /// Size of region to map. 1004 pub len: u64, 1005 /// Pointer to the memory. 1006 pub ptr: u64, 1007 } 1008 1009 impl VhostUserMsgValidator for VhostUserExternalMapMsg { is_valid(&self) -> bool1010 fn is_valid(&self) -> bool { 1011 self.len > 0 1012 } 1013 } 1014 1015 impl VhostUserExternalMapMsg { 1016 /// New instance of VhostUserExternalMapMsg struct new(shmid: u8, shm_offset: u64, len: u64, ptr: u64) -> Self1017 pub fn new(shmid: u8, shm_offset: u64, len: u64, ptr: u64) -> Self { 1018 Self { 1019 shmid, 1020 padding: [0; 7], 1021 shm_offset, 1022 len, 1023 ptr, 1024 } 1025 } 1026 } 1027 1028 /// Backend request message to unmap part of a shared memory region. 1029 #[repr(C, packed)] 1030 #[derive(Default, Copy, Clone, FromZeroes, FromBytes, AsBytes)] 1031 pub struct VhostUserShmemUnmapMsg { 1032 /// Shared memory region id. 1033 pub shmid: u8, 1034 padding: [u8; 7], 1035 /// Offset into the shared memory region. 1036 pub shm_offset: u64, 1037 /// Size of region to unmap. 1038 pub len: u64, 1039 } 1040 1041 impl VhostUserMsgValidator for VhostUserShmemUnmapMsg { is_valid(&self) -> bool1042 fn is_valid(&self) -> bool { 1043 self.shm_offset.checked_add(self.len).is_some() 1044 } 1045 } 1046 1047 impl VhostUserShmemUnmapMsg { 1048 /// New instance of VhostUserShmemUnmapMsg struct new(shmid: u8, shm_offset: u64, len: u64) -> Self1049 pub fn new(shmid: u8, shm_offset: u64, len: u64) -> Self { 1050 Self { 1051 shmid, 1052 padding: [0; 7], 1053 shm_offset, 1054 len, 1055 } 1056 } 1057 } 1058 1059 /// Inflight I/O descriptor state for split virtqueues 1060 #[repr(packed)] 1061 #[derive(Clone, Copy, Default)] 1062 pub struct DescStateSplit { 1063 /// Indicate whether this descriptor (only head) is inflight or not. 1064 pub inflight: u8, 1065 /// Padding 1066 padding: [u8; 5], 1067 /// List of last batch of used descriptors, only when batching is used for submitting 1068 pub next: u16, 1069 /// Preserve order of fetching available descriptors, only for head descriptor 1070 pub counter: u64, 1071 } 1072 1073 impl DescStateSplit { 1074 /// New instance of DescStateSplit struct new() -> Self1075 pub fn new() -> Self { 1076 Self::default() 1077 } 1078 } 1079 1080 /// Inflight I/O queue region for split virtqueues 1081 #[repr(packed)] 1082 pub struct QueueRegionSplit { 1083 /// Features flags of this region 1084 pub features: u64, 1085 /// Version of this region 1086 pub version: u16, 1087 /// Number of DescStateSplit entries 1088 pub desc_num: u16, 1089 /// List to track last batch of used descriptors 1090 pub last_batch_head: u16, 1091 /// Idx value of used ring 1092 pub used_idx: u16, 1093 /// Pointer to an array of DescStateSplit entries 1094 pub desc: u64, 1095 } 1096 1097 impl QueueRegionSplit { 1098 /// New instance of QueueRegionSplit struct new(features: u64, queue_size: u16) -> Self1099 pub fn new(features: u64, queue_size: u16) -> Self { 1100 QueueRegionSplit { 1101 features, 1102 version: 1, 1103 desc_num: queue_size, 1104 last_batch_head: 0, 1105 used_idx: 0, 1106 desc: 0, 1107 } 1108 } 1109 } 1110 1111 /// Inflight I/O descriptor state for packed virtqueues 1112 #[repr(packed)] 1113 #[derive(Clone, Copy, Default)] 1114 pub struct DescStatePacked { 1115 /// Indicate whether this descriptor (only head) is inflight or not. 1116 pub inflight: u8, 1117 /// Padding 1118 padding: u8, 1119 /// Link to next free entry 1120 pub next: u16, 1121 /// Link to last entry of descriptor list, only for head 1122 pub last: u16, 1123 /// Length of descriptor list, only for head 1124 pub num: u16, 1125 /// Preserve order of fetching avail descriptors, only for head 1126 pub counter: u64, 1127 /// Buffer ID 1128 pub id: u16, 1129 /// Descriptor flags 1130 pub flags: u16, 1131 /// Buffer length 1132 pub len: u32, 1133 /// Buffer address 1134 pub addr: u64, 1135 } 1136 1137 impl DescStatePacked { 1138 /// New instance of DescStatePacked struct new() -> Self1139 pub fn new() -> Self { 1140 Self::default() 1141 } 1142 } 1143 1144 /// Inflight I/O queue region for packed virtqueues 1145 #[repr(packed)] 1146 pub struct QueueRegionPacked { 1147 /// Features flags of this region 1148 pub features: u64, 1149 /// version of this region 1150 pub version: u16, 1151 /// size of descriptor state array 1152 pub desc_num: u16, 1153 /// head of free DescStatePacked entry list 1154 pub free_head: u16, 1155 /// old head of free DescStatePacked entry list 1156 pub old_free_head: u16, 1157 /// used idx of descriptor ring 1158 pub used_idx: u16, 1159 /// old used idx of descriptor ring 1160 pub old_used_idx: u16, 1161 /// device ring wrap counter 1162 pub used_wrap_counter: u8, 1163 /// old device ring wrap counter 1164 pub old_used_wrap_counter: u8, 1165 /// Padding 1166 padding: [u8; 7], 1167 /// Pointer to array tracking state of each descriptor from descriptor ring 1168 pub desc: u64, 1169 } 1170 1171 impl QueueRegionPacked { 1172 /// New instance of QueueRegionPacked struct new(features: u64, queue_size: u16) -> Self1173 pub fn new(features: u64, queue_size: u16) -> Self { 1174 QueueRegionPacked { 1175 features, 1176 version: 1, 1177 desc_num: queue_size, 1178 free_head: 0, 1179 old_free_head: 0, 1180 used_idx: 0, 1181 old_used_idx: 0, 1182 used_wrap_counter: 0, 1183 old_used_wrap_counter: 0, 1184 padding: [0; 7], 1185 desc: 0, 1186 } 1187 } 1188 } 1189 1190 /// Virtio shared memory descriptor. 1191 #[repr(packed)] 1192 #[derive(Default, Copy, Clone, FromZeroes, FromBytes, AsBytes)] 1193 pub struct VhostSharedMemoryRegion { 1194 /// The shared memory region's shmid. 1195 pub id: u8, 1196 /// Padding 1197 padding: [u8; 7], 1198 /// The length of the shared memory region. 1199 pub length: u64, 1200 } 1201 1202 impl VhostSharedMemoryRegion { 1203 /// New instance of VhostSharedMemoryRegion struct new(id: u8, length: u64) -> Self1204 pub fn new(id: u8, length: u64) -> Self { 1205 VhostSharedMemoryRegion { 1206 id, 1207 padding: [0; 7], 1208 length, 1209 } 1210 } 1211 } 1212 1213 #[cfg(test)] 1214 mod tests { 1215 use super::*; 1216 1217 #[test] check_frontend_request_code()1218 fn check_frontend_request_code() { 1219 FrontendReq::try_from(0).expect_err("invalid value"); 1220 FrontendReq::try_from(46).expect_err("invalid value"); 1221 FrontendReq::try_from(10000).expect_err("invalid value"); 1222 1223 let code = FrontendReq::try_from(FrontendReq::GET_FEATURES as u32).unwrap(); 1224 assert_eq!(code, code.clone()); 1225 } 1226 1227 #[test] check_backend_request_code()1228 fn check_backend_request_code() { 1229 BackendReq::try_from(0).expect_err("invalid value"); 1230 BackendReq::try_from(14).expect_err("invalid value"); 1231 BackendReq::try_from(10000).expect_err("invalid value"); 1232 1233 let code = BackendReq::try_from(BackendReq::CONFIG_CHANGE_MSG as u32).unwrap(); 1234 assert_eq!(code, code.clone()); 1235 } 1236 1237 #[test] msg_header_ops()1238 fn msg_header_ops() { 1239 let mut hdr = VhostUserMsgHeader::new(FrontendReq::GET_FEATURES, 0, 0x100); 1240 assert_eq!(hdr.get_code(), Ok(FrontendReq::GET_FEATURES)); 1241 hdr.set_code(FrontendReq::SET_FEATURES); 1242 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_FEATURES)); 1243 1244 assert_eq!(hdr.get_version(), 0x1); 1245 1246 assert!(!hdr.is_reply()); 1247 hdr.set_reply(true); 1248 assert!(hdr.is_reply()); 1249 hdr.set_reply(false); 1250 1251 assert!(!hdr.is_need_reply()); 1252 hdr.set_need_reply(true); 1253 assert!(hdr.is_need_reply()); 1254 hdr.set_need_reply(false); 1255 1256 assert_eq!(hdr.get_size(), 0x100); 1257 hdr.set_size(0x200); 1258 assert_eq!(hdr.get_size(), 0x200); 1259 1260 assert!(!hdr.is_need_reply()); 1261 assert!(!hdr.is_reply()); 1262 assert_eq!(hdr.get_version(), 0x1); 1263 1264 // Check version 1265 hdr.set_version(0x0); 1266 assert!(!hdr.is_valid()); 1267 hdr.set_version(0x2); 1268 assert!(!hdr.is_valid()); 1269 hdr.set_version(0x1); 1270 assert!(hdr.is_valid()); 1271 1272 // Test Debug, Clone, PartiaEq trait 1273 assert_eq!(hdr, hdr.clone()); 1274 assert_eq!(hdr.clone().get_code(), hdr.get_code()); 1275 assert_eq!(format!("{:?}", hdr.clone()), format!("{:?}", hdr)); 1276 } 1277 1278 #[test] test_vhost_user_message_u64()1279 fn test_vhost_user_message_u64() { 1280 let val = VhostUserU64::default(); 1281 let val1 = VhostUserU64::new(0); 1282 1283 let a = val.value; 1284 let b = val1.value; 1285 assert_eq!(a, b); 1286 let a = VhostUserU64::new(1).value; 1287 assert_eq!(a, 1); 1288 } 1289 1290 #[test] check_user_memory()1291 fn check_user_memory() { 1292 let mut msg = VhostUserMemory::new(1); 1293 assert!(msg.is_valid()); 1294 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32; 1295 assert!(msg.is_valid()); 1296 1297 msg.num_regions += 1; 1298 assert!(!msg.is_valid()); 1299 msg.num_regions = 0xFFFFFFFF; 1300 assert!(!msg.is_valid()); 1301 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32; 1302 msg.padding1 = 1; 1303 assert!(!msg.is_valid()); 1304 } 1305 1306 #[test] check_user_memory_region()1307 fn check_user_memory_region() { 1308 let mut msg = VhostUserMemoryRegion { 1309 guest_phys_addr: 0, 1310 memory_size: 0x1000, 1311 user_addr: 0, 1312 mmap_offset: 0, 1313 }; 1314 assert!(msg.is_valid()); 1315 msg.guest_phys_addr = 0xFFFFFFFFFFFFEFFF; 1316 assert!(msg.is_valid()); 1317 msg.guest_phys_addr = 0xFFFFFFFFFFFFF000; 1318 assert!(!msg.is_valid()); 1319 msg.guest_phys_addr = 0xFFFFFFFFFFFF0000; 1320 msg.memory_size = 0; 1321 assert!(!msg.is_valid()); 1322 let a = msg.guest_phys_addr; 1323 let b = msg.guest_phys_addr; 1324 assert_eq!(a, b); 1325 1326 let msg = VhostUserMemoryRegion::default(); 1327 let a = msg.guest_phys_addr; 1328 assert_eq!(a, 0); 1329 let a = msg.memory_size; 1330 assert_eq!(a, 0); 1331 let a = msg.user_addr; 1332 assert_eq!(a, 0); 1333 let a = msg.mmap_offset; 1334 assert_eq!(a, 0); 1335 } 1336 1337 #[test] test_vhost_user_state()1338 fn test_vhost_user_state() { 1339 let state = VhostUserVringState::new(5, 8); 1340 1341 let a = state.index; 1342 assert_eq!(a, 5); 1343 let a = state.num; 1344 assert_eq!(a, 8); 1345 assert!(state.is_valid()); 1346 1347 let state = VhostUserVringState::default(); 1348 let a = state.index; 1349 assert_eq!(a, 0); 1350 let a = state.num; 1351 assert_eq!(a, 0); 1352 assert!(state.is_valid()); 1353 } 1354 1355 #[test] test_vhost_user_addr()1356 fn test_vhost_user_addr() { 1357 let mut addr = VhostUserVringAddr::new( 1358 2, 1359 VhostUserVringAddrFlags::VHOST_VRING_F_LOG, 1360 0x1000, 1361 0x2000, 1362 0x3000, 1363 0x4000, 1364 ); 1365 1366 let a = addr.index; 1367 assert_eq!(a, 2); 1368 let a = addr.flags; 1369 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits()); 1370 let a = addr.descriptor; 1371 assert_eq!(a, 0x1000); 1372 let a = addr.used; 1373 assert_eq!(a, 0x2000); 1374 let a = addr.available; 1375 assert_eq!(a, 0x3000); 1376 let a = addr.log; 1377 assert_eq!(a, 0x4000); 1378 assert!(addr.is_valid()); 1379 1380 addr.descriptor = 0x1001; 1381 assert!(!addr.is_valid()); 1382 addr.descriptor = 0x1000; 1383 1384 addr.available = 0x3001; 1385 assert!(!addr.is_valid()); 1386 addr.available = 0x3000; 1387 1388 addr.used = 0x2001; 1389 assert!(!addr.is_valid()); 1390 addr.used = 0x2000; 1391 assert!(addr.is_valid()); 1392 } 1393 1394 #[test] test_vhost_user_state_from_config()1395 fn test_vhost_user_state_from_config() { 1396 let config = VringConfigData { 1397 queue_size: 128, 1398 flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits(), 1399 desc_table_addr: 0x1000, 1400 used_ring_addr: 0x2000, 1401 avail_ring_addr: 0x3000, 1402 log_addr: Some(0x4000), 1403 }; 1404 let addr = VhostUserVringAddr::from_config_data(2, &config); 1405 1406 let a = addr.index; 1407 assert_eq!(a, 2); 1408 let a = addr.flags; 1409 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits()); 1410 let a = addr.descriptor; 1411 assert_eq!(a, 0x1000); 1412 let a = addr.used; 1413 assert_eq!(a, 0x2000); 1414 let a = addr.available; 1415 assert_eq!(a, 0x3000); 1416 let a = addr.log; 1417 assert_eq!(a, 0x4000); 1418 assert!(addr.is_valid()); 1419 } 1420 1421 #[test] check_user_vring_addr()1422 fn check_user_vring_addr() { 1423 let mut msg = 1424 VhostUserVringAddr::new(0, VhostUserVringAddrFlags::all(), 0x0, 0x0, 0x0, 0x0); 1425 assert!(msg.is_valid()); 1426 1427 msg.descriptor = 1; 1428 assert!(!msg.is_valid()); 1429 msg.descriptor = 0; 1430 1431 msg.available = 1; 1432 assert!(!msg.is_valid()); 1433 msg.available = 0; 1434 1435 msg.used = 1; 1436 assert!(!msg.is_valid()); 1437 msg.used = 0; 1438 1439 msg.flags |= 0x80000000; 1440 assert!(!msg.is_valid()); 1441 msg.flags &= !0x80000000; 1442 } 1443 1444 #[test] check_user_config_msg()1445 fn check_user_config_msg() { 1446 let mut msg = 1447 VhostUserConfig::new(0, VHOST_USER_CONFIG_SIZE, VhostUserConfigFlags::WRITABLE); 1448 1449 assert!(msg.is_valid()); 1450 msg.size = 0; 1451 assert!(!msg.is_valid()); 1452 msg.size = 1; 1453 assert!(msg.is_valid()); 1454 msg.offset = u32::MAX; 1455 assert!(!msg.is_valid()); 1456 msg.offset = VHOST_USER_CONFIG_SIZE; 1457 assert!(!msg.is_valid()); 1458 msg.offset = VHOST_USER_CONFIG_SIZE - 1; 1459 assert!(msg.is_valid()); 1460 msg.size = 2; 1461 assert!(!msg.is_valid()); 1462 msg.size = 1; 1463 msg.flags |= VhostUserConfigFlags::LIVE_MIGRATION.bits(); 1464 assert!(msg.is_valid()); 1465 msg.flags |= 0x4; 1466 assert!(!msg.is_valid()); 1467 } 1468 } 1469