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