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