vmm_vhost/
message.rs

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