• 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 
11 use std::fmt::Debug;
12 use std::marker::PhantomData;
13 
14 use crate::VringConfigData;
15 
16 /// The vhost-user specification uses a field of u32 to store message length.
17 /// On the other hand, preallocated buffers are needed to receive messages from the Unix domain
18 /// socket. To preallocating a 4GB buffer for each vhost-user message is really just an overhead.
19 /// Among all defined vhost-user messages, only the VhostUserConfig and VhostUserMemory has variable
20 /// message size. For the VhostUserConfig, a maximum size of 4K is enough because the user
21 /// configuration space for virtio devices is (4K - 0x100) bytes at most. For the VhostUserMemory,
22 /// 4K should be enough too because it can support 255 memory regions at most.
23 pub const MAX_MSG_SIZE: usize = 0x1000;
24 
25 /// The VhostUserMemory message has variable message size and variable number of attached file
26 /// descriptors. Each user memory region entry in the message payload occupies 32 bytes,
27 /// so setting maximum number of attached file descriptors based on the maximum message size.
28 /// But rust only implements Default and AsMut traits for arrays with 0 - 32 entries, so further
29 /// reduce the maximum number...
30 // pub const MAX_ATTACHED_FD_ENTRIES: usize = (MAX_MSG_SIZE - 8) / 32;
31 pub const MAX_ATTACHED_FD_ENTRIES: usize = 32;
32 
33 /// Starting position (inclusion) of the device configuration space in virtio devices.
34 pub const VHOST_USER_CONFIG_OFFSET: u32 = 0x100;
35 
36 /// Ending position (exclusion) of the device configuration space in virtio devices.
37 pub const VHOST_USER_CONFIG_SIZE: u32 = 0x1000;
38 
39 /// Maximum number of vrings supported.
40 pub const VHOST_USER_MAX_VRINGS: u64 = 0x8000u64;
41 
42 pub(super) trait Req:
43     Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Into<u32>
44 {
is_valid(&self) -> bool45     fn is_valid(&self) -> bool;
46 }
47 
48 /// Type of requests sending from masters to slaves.
49 #[repr(u32)]
50 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
51 pub enum MasterReq {
52     /// Null operation.
53     NOOP = 0,
54     /// Get from the underlying vhost implementation the features bit mask.
55     GET_FEATURES = 1,
56     /// Enable features in the underlying vhost implementation using a bit mask.
57     SET_FEATURES = 2,
58     /// Set the current Master as an owner of the session.
59     SET_OWNER = 3,
60     /// No longer used.
61     RESET_OWNER = 4,
62     /// Set the memory map regions on the slave so it can translate the vring addresses.
63     SET_MEM_TABLE = 5,
64     /// Set logging shared memory space.
65     SET_LOG_BASE = 6,
66     /// Set the logging file descriptor, which is passed as ancillary data.
67     SET_LOG_FD = 7,
68     /// Set the size of the queue.
69     SET_VRING_NUM = 8,
70     /// Set the addresses of the different aspects of the vring.
71     SET_VRING_ADDR = 9,
72     /// Set the base offset in the available vring.
73     SET_VRING_BASE = 10,
74     /// Get the available vring base offset.
75     GET_VRING_BASE = 11,
76     /// Set the event file descriptor for adding buffers to the vring.
77     SET_VRING_KICK = 12,
78     /// Set the event file descriptor to signal when buffers are used.
79     SET_VRING_CALL = 13,
80     /// Set the event file descriptor to signal when error occurs.
81     SET_VRING_ERR = 14,
82     /// Get the protocol feature bit mask from the underlying vhost implementation.
83     GET_PROTOCOL_FEATURES = 15,
84     /// Enable protocol features in the underlying vhost implementation.
85     SET_PROTOCOL_FEATURES = 16,
86     /// Query how many queues the backend supports.
87     GET_QUEUE_NUM = 17,
88     /// Signal slave to enable or disable corresponding vring.
89     SET_VRING_ENABLE = 18,
90     /// Ask vhost user backend to broadcast a fake RARP to notify the migration is terminated
91     /// for guest that does not support GUEST_ANNOUNCE.
92     SEND_RARP = 19,
93     /// Set host MTU value exposed to the guest.
94     NET_SET_MTU = 20,
95     /// Set the socket file descriptor for slave initiated requests.
96     SET_SLAVE_REQ_FD = 21,
97     /// Send IOTLB messages with struct vhost_iotlb_msg as payload.
98     IOTLB_MSG = 22,
99     /// Set the endianness of a VQ for legacy devices.
100     SET_VRING_ENDIAN = 23,
101     /// Fetch the contents of the virtio device configuration space.
102     GET_CONFIG = 24,
103     /// Change the contents of the virtio device configuration space.
104     SET_CONFIG = 25,
105     /// Create a session for crypto operation.
106     CREATE_CRYPTO_SESSION = 26,
107     /// Close a session for crypto operation.
108     CLOSE_CRYPTO_SESSION = 27,
109     /// Advise slave that a migration with postcopy enabled is underway.
110     POSTCOPY_ADVISE = 28,
111     /// Advise slave that a transition to postcopy mode has happened.
112     POSTCOPY_LISTEN = 29,
113     /// Advise that postcopy migration has now completed.
114     POSTCOPY_END = 30,
115     /// Get a shared buffer from slave.
116     GET_INFLIGHT_FD = 31,
117     /// Send the shared inflight buffer back to slave.
118     SET_INFLIGHT_FD = 32,
119     /// Sets the GPU protocol socket file descriptor.
120     GPU_SET_SOCKET = 33,
121     /// Ask the vhost user backend to disable all rings and reset all internal
122     /// device state to the initial state.
123     RESET_DEVICE = 34,
124     /// Indicate that a buffer was added to the vring instead of signalling it
125     /// using the vring’s kick file descriptor.
126     VRING_KICK = 35,
127     /// Return a u64 payload containing the maximum number of memory slots.
128     GET_MAX_MEM_SLOTS = 36,
129     /// Update the memory tables by adding the region described.
130     ADD_MEM_REG = 37,
131     /// Update the memory tables by removing the region described.
132     REM_MEM_REG = 38,
133     /// Notify the backend with updated device status as defined in the VIRTIO
134     /// specification.
135     SET_STATUS = 39,
136     /// Query the backend for its device status as defined in the VIRTIO
137     /// specification.
138     GET_STATUS = 40,
139     /// Upper bound of valid commands.
140     MAX_CMD = 41,
141 }
142 
143 impl Into<u32> for MasterReq {
into(self) -> u32144     fn into(self) -> u32 {
145         self as u32
146     }
147 }
148 
149 impl Req for MasterReq {
is_valid(&self) -> bool150     fn is_valid(&self) -> bool {
151         (*self > MasterReq::NOOP) && (*self < MasterReq::MAX_CMD)
152     }
153 }
154 
155 /// Type of requests sending from slaves to masters.
156 #[repr(u32)]
157 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
158 pub enum SlaveReq {
159     /// Null operation.
160     NOOP = 0,
161     /// Send IOTLB messages with struct vhost_iotlb_msg as payload.
162     IOTLB_MSG = 1,
163     /// Notify that the virtio device's configuration space has changed.
164     CONFIG_CHANGE_MSG = 2,
165     /// Set host notifier for a specified queue.
166     VRING_HOST_NOTIFIER_MSG = 3,
167     /// Indicate that a buffer was used from the vring.
168     VRING_CALL = 4,
169     /// Indicate that an error occurred on the specific vring.
170     VRING_ERR = 5,
171     /// Virtio-fs draft: map file content into the window.
172     FS_MAP = 6,
173     /// Virtio-fs draft: unmap file content from the window.
174     FS_UNMAP = 7,
175     /// Virtio-fs draft: sync file content.
176     FS_SYNC = 8,
177     /// Virtio-fs draft: perform a read/write from an fd directly to GPA.
178     FS_IO = 9,
179     /// Upper bound of valid commands.
180     MAX_CMD = 10,
181 }
182 
183 impl Into<u32> for SlaveReq {
into(self) -> u32184     fn into(self) -> u32 {
185         self as u32
186     }
187 }
188 
189 impl Req for SlaveReq {
is_valid(&self) -> bool190     fn is_valid(&self) -> bool {
191         (*self > SlaveReq::NOOP) && (*self < SlaveReq::MAX_CMD)
192     }
193 }
194 
195 /// Vhost message Validator.
196 pub trait VhostUserMsgValidator {
197     /// Validate message syntax only.
198     /// It doesn't validate message semantics such as protocol version number and dependency
199     /// on feature flags etc.
is_valid(&self) -> bool200     fn is_valid(&self) -> bool {
201         true
202     }
203 }
204 
205 // Bit mask for common message flags.
206 bitflags! {
207     /// Common message flags for vhost-user requests and replies.
208     pub struct VhostUserHeaderFlag: u32 {
209         /// Bits[0..2] is message version number.
210         const VERSION = 0x3;
211         /// Mark message as reply.
212         const REPLY = 0x4;
213         /// Sender anticipates a reply message from the peer.
214         const NEED_REPLY = 0x8;
215         /// All valid bits.
216         const ALL_FLAGS = 0xc;
217         /// All reserved bits.
218         const RESERVED_BITS = !0xf;
219     }
220 }
221 
222 /// Common message header for vhost-user requests and replies.
223 /// A vhost-user message consists of 3 header fields and an optional payload. All numbers are in the
224 /// machine native byte order.
225 #[allow(safe_packed_borrows)]
226 #[repr(packed)]
227 #[derive(Debug, Clone, Copy, PartialEq)]
228 pub(super) struct VhostUserMsgHeader<R: Req> {
229     request: u32,
230     flags: u32,
231     size: u32,
232     _r: PhantomData<R>,
233 }
234 
235 impl<R: Req> VhostUserMsgHeader<R> {
236     /// Create a new instance of `VhostUserMsgHeader`.
new(request: R, flags: u32, size: u32) -> Self237     pub fn new(request: R, flags: u32, size: u32) -> Self {
238         // Default to protocol version 1
239         let fl = (flags & VhostUserHeaderFlag::ALL_FLAGS.bits()) | 0x1;
240         VhostUserMsgHeader {
241             request: request.into(),
242             flags: fl,
243             size,
244             _r: PhantomData,
245         }
246     }
247 
248     /// Get message type.
get_code(&self) -> R249     pub fn get_code(&self) -> R {
250         // It's safe because R is marked as repr(u32).
251         unsafe { std::mem::transmute_copy::<u32, R>(&self.request) }
252     }
253 
254     /// Set message type.
set_code(&mut self, request: R)255     pub fn set_code(&mut self, request: R) {
256         self.request = request.into();
257     }
258 
259     /// Get message version number.
get_version(&self) -> u32260     pub fn get_version(&self) -> u32 {
261         self.flags & 0x3
262     }
263 
264     /// Set message version number.
set_version(&mut self, ver: u32)265     pub fn set_version(&mut self, ver: u32) {
266         self.flags &= !0x3;
267         self.flags |= ver & 0x3;
268     }
269 
270     /// Check whether it's a reply message.
is_reply(&self) -> bool271     pub fn is_reply(&self) -> bool {
272         (self.flags & VhostUserHeaderFlag::REPLY.bits()) != 0
273     }
274 
275     /// Mark message as reply.
set_reply(&mut self, is_reply: bool)276     pub fn set_reply(&mut self, is_reply: bool) {
277         if is_reply {
278             self.flags |= VhostUserHeaderFlag::REPLY.bits();
279         } else {
280             self.flags &= !VhostUserHeaderFlag::REPLY.bits();
281         }
282     }
283 
284     /// Check whether reply for this message is requested.
is_need_reply(&self) -> bool285     pub fn is_need_reply(&self) -> bool {
286         (self.flags & VhostUserHeaderFlag::NEED_REPLY.bits()) != 0
287     }
288 
289     /// Mark that reply for this message is needed.
set_need_reply(&mut self, need_reply: bool)290     pub fn set_need_reply(&mut self, need_reply: bool) {
291         if need_reply {
292             self.flags |= VhostUserHeaderFlag::NEED_REPLY.bits();
293         } else {
294             self.flags &= !VhostUserHeaderFlag::NEED_REPLY.bits();
295         }
296     }
297 
298     /// Check whether it's the reply message for the request `req`.
is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool299     pub fn is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool {
300         self.is_reply() && !req.is_reply() && self.get_code() == req.get_code()
301     }
302 
303     /// Get message size.
get_size(&self) -> u32304     pub fn get_size(&self) -> u32 {
305         self.size
306     }
307 
308     /// Set message size.
set_size(&mut self, size: u32)309     pub fn set_size(&mut self, size: u32) {
310         self.size = size;
311     }
312 }
313 
314 impl<R: Req> Default for VhostUserMsgHeader<R> {
default() -> Self315     fn default() -> Self {
316         VhostUserMsgHeader {
317             request: 0,
318             flags: 0x1,
319             size: 0,
320             _r: PhantomData,
321         }
322     }
323 }
324 
325 impl<T: Req> VhostUserMsgValidator for VhostUserMsgHeader<T> {
326     #[allow(clippy::if_same_then_else)]
is_valid(&self) -> bool327     fn is_valid(&self) -> bool {
328         if !self.get_code().is_valid() {
329             return false;
330         } else if self.size as usize > MAX_MSG_SIZE {
331             return false;
332         } else if self.get_version() != 0x1 {
333             return false;
334         } else if (self.flags & VhostUserHeaderFlag::RESERVED_BITS.bits()) != 0 {
335             return false;
336         }
337         true
338     }
339 }
340 
341 // Bit mask for transport specific flags in VirtIO feature set defined by vhost-user.
342 bitflags! {
343     /// Transport specific flags in VirtIO feature set defined by vhost-user.
344     pub struct VhostUserVirtioFeatures: u64 {
345         /// Feature flag for the protocol feature.
346         const PROTOCOL_FEATURES = 0x4000_0000;
347     }
348 }
349 
350 // Bit mask for vhost-user protocol feature flags.
351 bitflags! {
352     /// Vhost-user protocol feature flags.
353     pub struct VhostUserProtocolFeatures: u64 {
354         /// Support multiple queues.
355         const MQ = 0x0000_0001;
356         /// Support logging through shared memory fd.
357         const LOG_SHMFD = 0x0000_0002;
358         /// Support broadcasting fake RARP packet.
359         const RARP = 0x0000_0004;
360         /// Support sending reply messages for requests with NEED_REPLY flag set.
361         const REPLY_ACK = 0x0000_0008;
362         /// Support setting MTU for virtio-net devices.
363         const MTU = 0x0000_0010;
364         /// Allow the slave to send requests to the master by an optional communication channel.
365         const SLAVE_REQ = 0x0000_0020;
366         /// Support setting slave endian by SET_VRING_ENDIAN.
367         const CROSS_ENDIAN = 0x0000_0040;
368         /// Support crypto operations.
369         const CRYPTO_SESSION = 0x0000_0080;
370         /// Support sending userfault_fd from slaves to masters.
371         const PAGEFAULT = 0x0000_0100;
372         /// Support Virtio device configuration.
373         const CONFIG = 0x0000_0200;
374         /// Allow the slave to send fds (at most 8 descriptors in each message) to the master.
375         const SLAVE_SEND_FD = 0x0000_0400;
376         /// Allow the slave to register a host notifier.
377         const HOST_NOTIFIER = 0x0000_0800;
378         /// Support inflight shmfd.
379         const INFLIGHT_SHMFD = 0x0000_1000;
380         /// Support resetting the device.
381         const RESET_DEVICE = 0x0000_2000;
382         /// Support inband notifications.
383         const INBAND_NOTIFICATIONS = 0x0000_4000;
384         /// Support configuring memory slots.
385         const CONFIGURE_MEM_SLOTS = 0x0000_8000;
386         /// Support reporting status.
387         const STATUS = 0x0001_0000;
388     }
389 }
390 
391 /// A generic message to encapsulate a 64-bit value.
392 #[repr(packed)]
393 #[derive(Default)]
394 pub struct VhostUserU64 {
395     /// The encapsulated 64-bit common value.
396     pub value: u64,
397 }
398 
399 impl VhostUserU64 {
400     /// Create a new instance.
new(value: u64) -> Self401     pub fn new(value: u64) -> Self {
402         VhostUserU64 { value }
403     }
404 }
405 
406 impl VhostUserMsgValidator for VhostUserU64 {}
407 
408 /// Memory region descriptor for the SET_MEM_TABLE request.
409 #[repr(packed)]
410 #[derive(Default)]
411 pub struct VhostUserMemory {
412     /// Number of memory regions in the payload.
413     pub num_regions: u32,
414     /// Padding for alignment.
415     pub padding1: u32,
416 }
417 
418 impl VhostUserMemory {
419     /// Create a new instance.
new(cnt: u32) -> Self420     pub fn new(cnt: u32) -> Self {
421         VhostUserMemory {
422             num_regions: cnt,
423             padding1: 0,
424         }
425     }
426 }
427 
428 impl VhostUserMsgValidator for VhostUserMemory {
429     #[allow(clippy::if_same_then_else)]
is_valid(&self) -> bool430     fn is_valid(&self) -> bool {
431         if self.padding1 != 0 {
432             return false;
433         } else if self.num_regions == 0 || self.num_regions > MAX_ATTACHED_FD_ENTRIES as u32 {
434             return false;
435         }
436         true
437     }
438 }
439 
440 /// Memory region descriptors as payload for the SET_MEM_TABLE request.
441 #[repr(packed)]
442 #[derive(Default, Clone, Copy)]
443 pub struct VhostUserMemoryRegion {
444     /// Guest physical address of the memory region.
445     pub guest_phys_addr: u64,
446     /// Size of the memory region.
447     pub memory_size: u64,
448     /// Virtual address in the current process.
449     pub user_addr: u64,
450     /// Offset where region starts in the mapped memory.
451     pub mmap_offset: u64,
452 }
453 
454 impl VhostUserMemoryRegion {
455     /// Create a new instance.
new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self456     pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self {
457         VhostUserMemoryRegion {
458             guest_phys_addr,
459             memory_size,
460             user_addr,
461             mmap_offset,
462         }
463     }
464 }
465 
466 impl VhostUserMsgValidator for VhostUserMemoryRegion {
is_valid(&self) -> bool467     fn is_valid(&self) -> bool {
468         if self.memory_size == 0
469             || self.guest_phys_addr.checked_add(self.memory_size).is_none()
470             || self.user_addr.checked_add(self.memory_size).is_none()
471             || self.mmap_offset.checked_add(self.memory_size).is_none()
472         {
473             return false;
474         }
475         true
476     }
477 }
478 
479 /// Payload of the VhostUserMemory message.
480 pub type VhostUserMemoryPayload = Vec<VhostUserMemoryRegion>;
481 
482 /// Single memory region descriptor as payload for ADD_MEM_REG and REM_MEM_REG
483 /// requests.
484 #[repr(C)]
485 #[derive(Default, Clone, Copy)]
486 pub struct VhostUserSingleMemoryRegion {
487     /// Padding for correct alignment
488     padding: u64,
489     /// Guest physical address of the memory region.
490     pub guest_phys_addr: u64,
491     /// Size of the memory region.
492     pub memory_size: u64,
493     /// Virtual address in the current process.
494     pub user_addr: u64,
495     /// Offset where region starts in the mapped memory.
496     pub mmap_offset: u64,
497 }
498 
499 impl VhostUserSingleMemoryRegion {
500     /// Create a new instance.
new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self501     pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self {
502         VhostUserSingleMemoryRegion {
503             padding: 0,
504             guest_phys_addr,
505             memory_size,
506             user_addr,
507             mmap_offset,
508         }
509     }
510 }
511 
512 impl VhostUserMsgValidator for VhostUserSingleMemoryRegion {
is_valid(&self) -> bool513     fn is_valid(&self) -> bool {
514         if self.memory_size == 0
515             || self.guest_phys_addr.checked_add(self.memory_size).is_none()
516             || self.user_addr.checked_add(self.memory_size).is_none()
517             || self.mmap_offset.checked_add(self.memory_size).is_none()
518         {
519             return false;
520         }
521         true
522     }
523 }
524 
525 /// Vring state descriptor.
526 #[repr(packed)]
527 #[derive(Default)]
528 pub struct VhostUserVringState {
529     /// Vring index.
530     pub index: u32,
531     /// A common 32bit value to encapsulate vring state etc.
532     pub num: u32,
533 }
534 
535 impl VhostUserVringState {
536     /// Create a new instance.
new(index: u32, num: u32) -> Self537     pub fn new(index: u32, num: u32) -> Self {
538         VhostUserVringState { index, num }
539     }
540 }
541 
542 impl VhostUserMsgValidator for VhostUserVringState {}
543 
544 // Bit mask for vring address flags.
545 bitflags! {
546     /// Flags for vring address.
547     pub struct VhostUserVringAddrFlags: u32 {
548         /// Support log of vring operations.
549         /// Modifications to "used" vring should be logged.
550         const VHOST_VRING_F_LOG = 0x1;
551     }
552 }
553 
554 /// Vring address descriptor.
555 #[repr(packed)]
556 #[derive(Default)]
557 pub struct VhostUserVringAddr {
558     /// Vring index.
559     pub index: u32,
560     /// Vring flags defined by VhostUserVringAddrFlags.
561     pub flags: u32,
562     /// Ring address of the vring descriptor table.
563     pub descriptor: u64,
564     /// Ring address of the vring used ring.
565     pub used: u64,
566     /// Ring address of the vring available ring.
567     pub available: u64,
568     /// Guest address for logging.
569     pub log: u64,
570 }
571 
572 impl VhostUserVringAddr {
573     /// Create a new instance.
new( index: u32, flags: VhostUserVringAddrFlags, descriptor: u64, used: u64, available: u64, log: u64, ) -> Self574     pub fn new(
575         index: u32,
576         flags: VhostUserVringAddrFlags,
577         descriptor: u64,
578         used: u64,
579         available: u64,
580         log: u64,
581     ) -> Self {
582         VhostUserVringAddr {
583             index,
584             flags: flags.bits(),
585             descriptor,
586             used,
587             available,
588             log,
589         }
590     }
591 
592     /// Create a new instance from `VringConfigData`.
593     #[cfg_attr(feature = "cargo-clippy", allow(clippy::identity_conversion))]
from_config_data(index: u32, config_data: &VringConfigData) -> Self594     pub fn from_config_data(index: u32, config_data: &VringConfigData) -> Self {
595         let log_addr = config_data.log_addr.unwrap_or(0);
596         VhostUserVringAddr {
597             index,
598             flags: config_data.flags,
599             descriptor: config_data.desc_table_addr,
600             used: config_data.used_ring_addr,
601             available: config_data.avail_ring_addr,
602             log: log_addr,
603         }
604     }
605 }
606 
607 impl VhostUserMsgValidator for VhostUserVringAddr {
608     #[allow(clippy::if_same_then_else)]
is_valid(&self) -> bool609     fn is_valid(&self) -> bool {
610         if (self.flags & !VhostUserVringAddrFlags::all().bits()) != 0 {
611             return false;
612         } else if self.descriptor & 0xf != 0 {
613             return false;
614         } else if self.available & 0x1 != 0 {
615             return false;
616         } else if self.used & 0x3 != 0 {
617             return false;
618         }
619         true
620     }
621 }
622 
623 // Bit mask for the vhost-user device configuration message.
624 bitflags! {
625     /// Flags for the device configuration message.
626     pub struct VhostUserConfigFlags: u32 {
627         /// Vhost master messages used for writeable fields.
628         const WRITABLE = 0x1;
629         /// Vhost master messages used for live migration.
630         const LIVE_MIGRATION = 0x2;
631     }
632 }
633 
634 /// Message to read/write device configuration space.
635 #[repr(packed)]
636 #[derive(Default)]
637 pub struct VhostUserConfig {
638     /// Offset of virtio device's configuration space.
639     pub offset: u32,
640     /// Configuration space access size in bytes.
641     pub size: u32,
642     /// Flags for the device configuration operation.
643     pub flags: u32,
644 }
645 
646 impl VhostUserConfig {
647     /// Create a new instance.
new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self648     pub fn new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self {
649         VhostUserConfig {
650             offset,
651             size,
652             flags: flags.bits(),
653         }
654     }
655 }
656 
657 impl VhostUserMsgValidator for VhostUserConfig {
658     #[allow(clippy::if_same_then_else)]
is_valid(&self) -> bool659     fn is_valid(&self) -> bool {
660         if (self.flags & !VhostUserConfigFlags::all().bits()) != 0 {
661             return false;
662         } else if self.offset < 0x100 {
663             return false;
664         } else if self.size == 0
665             || self.size > VHOST_USER_CONFIG_SIZE
666             || self.size + self.offset > VHOST_USER_CONFIG_SIZE
667         {
668             return false;
669         }
670         true
671     }
672 }
673 
674 /// Payload for the VhostUserConfig message.
675 pub type VhostUserConfigPayload = Vec<u8>;
676 
677 /*
678  * TODO: support dirty log, live migration and IOTLB operations.
679 #[repr(packed)]
680 pub struct VhostUserVringArea {
681     pub index: u32,
682     pub flags: u32,
683     pub size: u64,
684     pub offset: u64,
685 }
686 
687 #[repr(packed)]
688 pub struct VhostUserLog {
689     pub size: u64,
690     pub offset: u64,
691 }
692 
693 #[repr(packed)]
694 pub struct VhostUserIotlb {
695     pub iova: u64,
696     pub size: u64,
697     pub user_addr: u64,
698     pub permission: u8,
699     pub optype: u8,
700 }
701 */
702 
703 // Bit mask for flags in virtio-fs slave messages
704 bitflags! {
705     #[derive(Default)]
706     /// Flags for virtio-fs slave messages.
707     pub struct VhostUserFSSlaveMsgFlags: u64 {
708         /// Empty permission.
709         const EMPTY = 0x0;
710         /// Read permission.
711         const MAP_R = 0x1;
712         /// Write permission.
713         const MAP_W = 0x2;
714     }
715 }
716 
717 /// Max entries in one virtio-fs slave request.
718 pub const VHOST_USER_FS_SLAVE_ENTRIES: usize = 8;
719 
720 /// Slave request message to update the MMIO window.
721 #[repr(packed)]
722 #[derive(Default)]
723 pub struct VhostUserFSSlaveMsg {
724     /// File offset.
725     pub fd_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES],
726     /// Offset into the DAX window.
727     pub cache_offset: [u64; VHOST_USER_FS_SLAVE_ENTRIES],
728     /// Size of region to map.
729     pub len: [u64; VHOST_USER_FS_SLAVE_ENTRIES],
730     /// Flags for the mmap operation
731     pub flags: [VhostUserFSSlaveMsgFlags; VHOST_USER_FS_SLAVE_ENTRIES],
732 }
733 
734 impl VhostUserMsgValidator for VhostUserFSSlaveMsg {
is_valid(&self) -> bool735     fn is_valid(&self) -> bool {
736         for i in 0..VHOST_USER_FS_SLAVE_ENTRIES {
737             if ({ self.flags[i] }.bits() & !VhostUserFSSlaveMsgFlags::all().bits()) != 0
738                 || self.fd_offset[i].checked_add(self.len[i]).is_none()
739                 || self.cache_offset[i].checked_add(self.len[i]).is_none()
740             {
741                 return false;
742             }
743         }
744         true
745     }
746 }
747 
748 #[cfg(test)]
749 mod tests {
750     use super::*;
751     use std::mem;
752 
753     #[test]
check_master_request_code()754     fn check_master_request_code() {
755         let code = MasterReq::NOOP;
756         assert!(!code.is_valid());
757         let code = MasterReq::MAX_CMD;
758         assert!(!code.is_valid());
759         assert!(code > MasterReq::NOOP);
760         let code = MasterReq::GET_FEATURES;
761         assert!(code.is_valid());
762         assert_eq!(code, code.clone());
763         let code: MasterReq = unsafe { std::mem::transmute::<u32, MasterReq>(10000u32) };
764         assert!(!code.is_valid());
765     }
766 
767     #[test]
check_slave_request_code()768     fn check_slave_request_code() {
769         let code = SlaveReq::NOOP;
770         assert!(!code.is_valid());
771         let code = SlaveReq::MAX_CMD;
772         assert!(!code.is_valid());
773         assert!(code > SlaveReq::NOOP);
774         let code = SlaveReq::CONFIG_CHANGE_MSG;
775         assert!(code.is_valid());
776         assert_eq!(code, code.clone());
777         let code: SlaveReq = unsafe { std::mem::transmute::<u32, SlaveReq>(10000u32) };
778         assert!(!code.is_valid());
779     }
780 
781     #[test]
msg_header_ops()782     fn msg_header_ops() {
783         let mut hdr = VhostUserMsgHeader::new(MasterReq::GET_FEATURES, 0, 0x100);
784         assert_eq!(hdr.get_code(), MasterReq::GET_FEATURES);
785         hdr.set_code(MasterReq::SET_FEATURES);
786         assert_eq!(hdr.get_code(), MasterReq::SET_FEATURES);
787 
788         assert_eq!(hdr.get_version(), 0x1);
789 
790         assert_eq!(hdr.is_reply(), false);
791         hdr.set_reply(true);
792         assert_eq!(hdr.is_reply(), true);
793         hdr.set_reply(false);
794 
795         assert_eq!(hdr.is_need_reply(), false);
796         hdr.set_need_reply(true);
797         assert_eq!(hdr.is_need_reply(), true);
798         hdr.set_need_reply(false);
799 
800         assert_eq!(hdr.get_size(), 0x100);
801         hdr.set_size(0x200);
802         assert_eq!(hdr.get_size(), 0x200);
803 
804         assert_eq!(hdr.is_need_reply(), false);
805         assert_eq!(hdr.is_reply(), false);
806         assert_eq!(hdr.get_version(), 0x1);
807 
808         // Check message length
809         assert!(hdr.is_valid());
810         hdr.set_size(0x2000);
811         assert!(!hdr.is_valid());
812         hdr.set_size(0x100);
813         assert_eq!(hdr.get_size(), 0x100);
814         assert!(hdr.is_valid());
815         hdr.set_size((MAX_MSG_SIZE - mem::size_of::<VhostUserMsgHeader<MasterReq>>()) as u32);
816         assert!(hdr.is_valid());
817         hdr.set_size(0x0);
818         assert!(hdr.is_valid());
819 
820         // Check version
821         hdr.set_version(0x0);
822         assert!(!hdr.is_valid());
823         hdr.set_version(0x2);
824         assert!(!hdr.is_valid());
825         hdr.set_version(0x1);
826         assert!(hdr.is_valid());
827 
828         assert_eq!(hdr, hdr.clone());
829     }
830 
831     #[test]
test_vhost_user_message_u64()832     fn test_vhost_user_message_u64() {
833         let val = VhostUserU64::default();
834         let val1 = VhostUserU64::new(0);
835 
836         let a = val.value;
837         let b = val1.value;
838         assert_eq!(a, b);
839         let a = VhostUserU64::new(1).value;
840         assert_eq!(a, 1);
841     }
842 
843     #[test]
check_user_memory()844     fn check_user_memory() {
845         let mut msg = VhostUserMemory::new(1);
846         assert!(msg.is_valid());
847         msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32;
848         assert!(msg.is_valid());
849 
850         msg.num_regions += 1;
851         assert!(!msg.is_valid());
852         msg.num_regions = 0xFFFFFFFF;
853         assert!(!msg.is_valid());
854         msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32;
855         msg.padding1 = 1;
856         assert!(!msg.is_valid());
857     }
858 
859     #[test]
check_user_memory_region()860     fn check_user_memory_region() {
861         let mut msg = VhostUserMemoryRegion {
862             guest_phys_addr: 0,
863             memory_size: 0x1000,
864             user_addr: 0,
865             mmap_offset: 0,
866         };
867         assert!(msg.is_valid());
868         msg.guest_phys_addr = 0xFFFFFFFFFFFFEFFF;
869         assert!(msg.is_valid());
870         msg.guest_phys_addr = 0xFFFFFFFFFFFFF000;
871         assert!(!msg.is_valid());
872         msg.guest_phys_addr = 0xFFFFFFFFFFFF0000;
873         msg.memory_size = 0;
874         assert!(!msg.is_valid());
875         let a = msg.guest_phys_addr;
876         let b = msg.guest_phys_addr;
877         assert_eq!(a, b);
878 
879         let msg = VhostUserMemoryRegion::default();
880         let a = msg.guest_phys_addr;
881         assert_eq!(a, 0);
882         let a = msg.memory_size;
883         assert_eq!(a, 0);
884         let a = msg.user_addr;
885         assert_eq!(a, 0);
886         let a = msg.mmap_offset;
887         assert_eq!(a, 0);
888     }
889 
890     #[test]
test_vhost_user_state()891     fn test_vhost_user_state() {
892         let state = VhostUserVringState::new(5, 8);
893 
894         let a = state.index;
895         assert_eq!(a, 5);
896         let a = state.num;
897         assert_eq!(a, 8);
898         assert_eq!(state.is_valid(), true);
899 
900         let state = VhostUserVringState::default();
901         let a = state.index;
902         assert_eq!(a, 0);
903         let a = state.num;
904         assert_eq!(a, 0);
905         assert_eq!(state.is_valid(), true);
906     }
907 
908     #[test]
test_vhost_user_addr()909     fn test_vhost_user_addr() {
910         let mut addr = VhostUserVringAddr::new(
911             2,
912             VhostUserVringAddrFlags::VHOST_VRING_F_LOG,
913             0x1000,
914             0x2000,
915             0x3000,
916             0x4000,
917         );
918 
919         let a = addr.index;
920         assert_eq!(a, 2);
921         let a = addr.flags;
922         assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits());
923         let a = addr.descriptor;
924         assert_eq!(a, 0x1000);
925         let a = addr.used;
926         assert_eq!(a, 0x2000);
927         let a = addr.available;
928         assert_eq!(a, 0x3000);
929         let a = addr.log;
930         assert_eq!(a, 0x4000);
931         assert_eq!(addr.is_valid(), true);
932 
933         addr.descriptor = 0x1001;
934         assert_eq!(addr.is_valid(), false);
935         addr.descriptor = 0x1000;
936 
937         addr.available = 0x3001;
938         assert_eq!(addr.is_valid(), false);
939         addr.available = 0x3000;
940 
941         addr.used = 0x2001;
942         assert_eq!(addr.is_valid(), false);
943         addr.used = 0x2000;
944         assert_eq!(addr.is_valid(), true);
945     }
946 
947     #[test]
test_vhost_user_state_from_config()948     fn test_vhost_user_state_from_config() {
949         let config = VringConfigData {
950             queue_max_size: 256,
951             queue_size: 128,
952             flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits,
953             desc_table_addr: 0x1000,
954             used_ring_addr: 0x2000,
955             avail_ring_addr: 0x3000,
956             log_addr: Some(0x4000),
957         };
958         let addr = VhostUserVringAddr::from_config_data(2, &config);
959 
960         let a = addr.index;
961         assert_eq!(a, 2);
962         let a = addr.flags;
963         assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits());
964         let a = addr.descriptor;
965         assert_eq!(a, 0x1000);
966         let a = addr.used;
967         assert_eq!(a, 0x2000);
968         let a = addr.available;
969         assert_eq!(a, 0x3000);
970         let a = addr.log;
971         assert_eq!(a, 0x4000);
972         assert_eq!(addr.is_valid(), true);
973     }
974 
975     #[test]
check_user_vring_addr()976     fn check_user_vring_addr() {
977         let mut msg =
978             VhostUserVringAddr::new(0, VhostUserVringAddrFlags::all(), 0x0, 0x0, 0x0, 0x0);
979         assert!(msg.is_valid());
980 
981         msg.descriptor = 1;
982         assert!(!msg.is_valid());
983         msg.descriptor = 0;
984 
985         msg.available = 1;
986         assert!(!msg.is_valid());
987         msg.available = 0;
988 
989         msg.used = 1;
990         assert!(!msg.is_valid());
991         msg.used = 0;
992 
993         msg.flags |= 0x80000000;
994         assert!(!msg.is_valid());
995         msg.flags &= !0x80000000;
996     }
997 
998     #[test]
check_user_config_msg()999     fn check_user_config_msg() {
1000         let mut msg = VhostUserConfig::new(
1001             VHOST_USER_CONFIG_OFFSET,
1002             VHOST_USER_CONFIG_SIZE - VHOST_USER_CONFIG_OFFSET,
1003             VhostUserConfigFlags::WRITABLE,
1004         );
1005 
1006         assert!(msg.is_valid());
1007         msg.size = 0;
1008         assert!(!msg.is_valid());
1009         msg.size = 1;
1010         assert!(msg.is_valid());
1011         msg.offset = 0;
1012         assert!(!msg.is_valid());
1013         msg.offset = VHOST_USER_CONFIG_SIZE;
1014         assert!(!msg.is_valid());
1015         msg.offset = VHOST_USER_CONFIG_SIZE - 1;
1016         assert!(msg.is_valid());
1017         msg.size = 2;
1018         assert!(!msg.is_valid());
1019         msg.size = 1;
1020         msg.flags |= VhostUserConfigFlags::LIVE_MIGRATION.bits();
1021         assert!(msg.is_valid());
1022         msg.flags |= 0x4;
1023         assert!(!msg.is_valid());
1024     }
1025 
1026     #[test]
test_vhost_user_fs_slave()1027     fn test_vhost_user_fs_slave() {
1028         let mut fs_slave = VhostUserFSSlaveMsg::default();
1029 
1030         assert_eq!(fs_slave.is_valid(), true);
1031 
1032         fs_slave.fd_offset[0] = 0xffff_ffff_ffff_ffff;
1033         fs_slave.len[0] = 0x1;
1034         assert_eq!(fs_slave.is_valid(), false);
1035 
1036         assert_ne!(
1037             VhostUserFSSlaveMsgFlags::MAP_R,
1038             VhostUserFSSlaveMsgFlags::MAP_W
1039         );
1040         assert_eq!(VhostUserFSSlaveMsgFlags::EMPTY.bits(), 0);
1041     }
1042 }
1043