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