1#![allow(dead_code)]
9#![allow(non_camel_case_types)]
10#![allow(clippy::upper_case_acronyms)]
11
12use std::fmt::Debug;
13use std::marker::PhantomData;
14
15use bitflags::bitflags;
16use zerocopy::FromBytes;
17use zerocopy::Immutable;
18use zerocopy::IntoBytes;
19use zerocopy::KnownLayout;
20
21use crate::VringConfigData;
22
23pub const MAX_ATTACHED_FD_ENTRIES: usize = 32;
30
31pub const VHOST_USER_CONFIG_OFFSET: u32 = 0x100;
33
34pub const VHOST_USER_CONFIG_SIZE: u32 = 0x1000;
36
37pub const VHOST_USER_MAX_VRINGS: u64 = 0x8000u64;
39
40pub trait Req:
42 Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Into<u32> + TryFrom<u32> + Send + Sync
43{
44}
45
46#[derive(Copy, Clone, Debug, PartialEq, Eq, thiserror::Error)]
48pub enum ReqError {
49 #[error("The value {0} does not correspond to a valid message code.")]
51 InvalidValue(u32),
52}
53
54#[repr(u32)]
60#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, enumn::N)]
61pub enum FrontendReq {
62 GET_FEATURES = 1,
64 SET_FEATURES = 2,
66 SET_OWNER = 3,
68 RESET_OWNER = 4,
70 SET_MEM_TABLE = 5,
72 SET_LOG_BASE = 6,
74 SET_LOG_FD = 7,
76 SET_VRING_NUM = 8,
78 SET_VRING_ADDR = 9,
80 SET_VRING_BASE = 10,
82 GET_VRING_BASE = 11,
84 SET_VRING_KICK = 12,
86 SET_VRING_CALL = 13,
88 SET_VRING_ERR = 14,
90 GET_PROTOCOL_FEATURES = 15,
92 SET_PROTOCOL_FEATURES = 16,
94 GET_QUEUE_NUM = 17,
96 SET_VRING_ENABLE = 18,
98 SEND_RARP = 19,
101 NET_SET_MTU = 20,
103 SET_BACKEND_REQ_FD = 21,
105 IOTLB_MSG = 22,
107 SET_VRING_ENDIAN = 23,
109 GET_CONFIG = 24,
111 SET_CONFIG = 25,
113 CREATE_CRYPTO_SESSION = 26,
115 CLOSE_CRYPTO_SESSION = 27,
117 POSTCOPY_ADVISE = 28,
119 POSTCOPY_LISTEN = 29,
121 POSTCOPY_END = 30,
123 GET_INFLIGHT_FD = 31,
125 SET_INFLIGHT_FD = 32,
127 GPU_SET_SOCKET = 33,
129 RESET_DEVICE = 34,
132 VRING_KICK = 35,
135 GET_MAX_MEM_SLOTS = 36,
137 ADD_MEM_REG = 37,
139 REM_MEM_REG = 38,
141 SET_STATUS = 39,
144 GET_STATUS = 40,
147 SET_DEVICE_STATE_FD = 42,
150 CHECK_DEVICE_STATE = 43,
153 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#[repr(u32)]
179#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, enumn::N)]
180pub enum BackendReq {
181 IOTLB_MSG = 1,
183 CONFIG_CHANGE_MSG = 2,
185 VRING_HOST_NOTIFIER_MSG = 3,
187 VRING_CALL = 4,
189 VRING_ERR = 5,
191 SHMEM_MAP = 9,
193 SHMEM_UNMAP = 10,
195
196 DEPRECATED__FS_MAP = 1002,
199 DEPRECATED__FS_UNMAP = 1003,
201 DEPRECATED__FS_SYNC = 1004,
203 DEPRECATED__FS_IO = 1005,
205 GPU_MAP = 1006,
207 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
227pub trait VhostUserMsgValidator {
229 fn is_valid(&self) -> bool {
233 true
234 }
235}
236
237bitflags! {
239 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
241 #[repr(transparent)]
242 pub struct VhostUserHeaderFlag: u32 {
243 const VERSION = 0x3;
245 const REPLY = 0x4;
247 const NEED_REPLY = 0x8;
249 const ALL_FLAGS = 0xc;
251 const RESERVED_BITS = !0xf;
253 }
254}
255
256#[repr(C)]
260#[derive(Copy)]
261pub struct VhostUserMsgHeader<R: Req> {
262 request: u32,
263 flags: u32,
264 size: u32,
265 _r: PhantomData<R>,
266}
267
268impl<R: Req> Debug for VhostUserMsgHeader<R> {
269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 f.debug_struct("VhostUserMsgHeader")
271 .field("request", &{ self.request })
272 .field("flags", &{ self.flags })
273 .field("size", &{ self.size })
274 .finish()
275 }
276}
277
278impl<R: Req> Clone for VhostUserMsgHeader<R> {
279 fn clone(&self) -> VhostUserMsgHeader<R> {
280 *self
281 }
282}
283
284impl<R: Req> PartialEq for VhostUserMsgHeader<R> {
285 fn eq(&self, other: &Self) -> bool {
286 self.request == other.request && self.flags == other.flags && self.size == other.size
287 }
288}
289
290impl<R: Req> VhostUserMsgHeader<R> {
291 pub fn new(request: R, flags: u32, size: u32) -> Self {
293 let fl = (flags & VhostUserHeaderFlag::ALL_FLAGS.bits()) | 0x1;
295 VhostUserMsgHeader {
296 request: request.into(),
297 flags: fl,
298 size,
299 _r: PhantomData,
300 }
301 }
302
303 pub fn into_raw(self) -> [u32; 3] {
304 [self.request, self.flags, self.size]
305 }
306
307 pub fn from_raw(raw: [u32; 3]) -> Self {
308 Self {
309 request: raw[0],
310 flags: raw[1],
311 size: raw[2],
312 _r: PhantomData,
313 }
314 }
315
316 pub fn get_code(&self) -> std::result::Result<R, R::Error> {
318 R::try_from(self.request)
319 }
320
321 pub fn set_code(&mut self, request: R) {
323 self.request = request.into();
324 }
325
326 pub fn get_version(&self) -> u32 {
328 self.flags & 0x3
329 }
330
331 pub fn set_version(&mut self, ver: u32) {
333 self.flags &= !0x3;
334 self.flags |= ver & 0x3;
335 }
336
337 pub fn is_reply(&self) -> bool {
339 (self.flags & VhostUserHeaderFlag::REPLY.bits()) != 0
340 }
341
342 pub fn set_reply(&mut self, is_reply: bool) {
344 if is_reply {
345 self.flags |= VhostUserHeaderFlag::REPLY.bits();
346 } else {
347 self.flags &= !VhostUserHeaderFlag::REPLY.bits();
348 }
349 }
350
351 pub fn is_need_reply(&self) -> bool {
353 (self.flags & VhostUserHeaderFlag::NEED_REPLY.bits()) != 0
354 }
355
356 pub fn set_need_reply(&mut self, need_reply: bool) {
358 if need_reply {
359 self.flags |= VhostUserHeaderFlag::NEED_REPLY.bits();
360 } else {
361 self.flags &= !VhostUserHeaderFlag::NEED_REPLY.bits();
362 }
363 }
364
365 pub fn is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool {
367 self.is_reply() && !req.is_reply() && self.request == req.request
368 }
369
370 pub fn get_size(&self) -> u32 {
372 self.size
373 }
374
375 pub fn set_size(&mut self, size: u32) {
377 self.size = size;
378 }
379}
380
381impl<R: Req> Default for VhostUserMsgHeader<R> {
382 fn default() -> Self {
383 VhostUserMsgHeader {
384 request: 0,
385 flags: 0x1,
386 size: 0,
387 _r: PhantomData,
388 }
389 }
390}
391
392impl<T: Req> VhostUserMsgValidator for VhostUserMsgHeader<T> {
393 #[allow(clippy::if_same_then_else)]
394 fn is_valid(&self) -> bool {
395 if self.get_code().is_err() {
396 return false;
397 } else if self.get_version() != 0x1 {
398 return false;
399 } else if (self.flags & VhostUserHeaderFlag::RESERVED_BITS.bits()) != 0 {
400 return false;
401 }
402 true
403 }
404}
405
406pub const VIRTIO_F_RING_PACKED: u32 = 34;
407
408pub const VHOST_USER_F_PROTOCOL_FEATURES: u32 = 30;
410
411bitflags! {
413 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
415 #[repr(transparent)]
416 pub struct VhostUserProtocolFeatures: u64 {
417 const MQ = 0x0000_0001;
419 const LOG_SHMFD = 0x0000_0002;
421 const RARP = 0x0000_0004;
423 const REPLY_ACK = 0x0000_0008;
425 const MTU = 0x0000_0010;
427 const BACKEND_REQ = 0x0000_0020;
429 const CROSS_ENDIAN = 0x0000_0040;
431 const CRYPTO_SESSION = 0x0000_0080;
433 const PAGEFAULT = 0x0000_0100;
435 const CONFIG = 0x0000_0200;
437 const BACKEND_SEND_FD = 0x0000_0400;
439 const HOST_NOTIFIER = 0x0000_0800;
441 const INFLIGHT_SHMFD = 0x0000_1000;
443 const RESET_DEVICE = 0x0000_2000;
445 const INBAND_NOTIFICATIONS = 0x0000_4000;
447 const CONFIGURE_MEM_SLOTS = 0x0000_8000;
449 const STATUS = 0x0001_0000;
451 const XEN_MMAP = 0x0002_0000;
453 const DEVICE_STATE = 0x0008_0000;
455 const SHMEM_MAP = 0x0010_0000;
457 }
458}
459
460#[repr(C)]
462#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
463pub struct VhostUserU64 {
464 pub value: u64,
466}
467
468impl VhostUserU64 {
469 pub fn new(value: u64) -> Self {
471 VhostUserU64 { value }
472 }
473}
474
475impl VhostUserMsgValidator for VhostUserU64 {}
476
477#[repr(C)]
479#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
480pub struct VhostUserEmptyMsg;
481
482impl VhostUserMsgValidator for VhostUserEmptyMsg {}
483
484#[repr(C)]
487#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
488pub struct VhostUserEmptyMessage;
489
490impl VhostUserMsgValidator for VhostUserEmptyMessage {}
491
492#[repr(C)]
494#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
495pub struct VhostUserMemory {
496 pub num_regions: u32,
498 pub padding1: u32,
500}
501
502impl VhostUserMemory {
503 pub fn new(cnt: u32) -> Self {
505 VhostUserMemory {
506 num_regions: cnt,
507 padding1: 0,
508 }
509 }
510}
511
512impl VhostUserMsgValidator for VhostUserMemory {
513 #[allow(clippy::if_same_then_else)]
514 fn is_valid(&self) -> bool {
515 if self.padding1 != 0 {
516 return false;
517 } else if self.num_regions == 0 || self.num_regions > MAX_ATTACHED_FD_ENTRIES as u32 {
518 return false;
519 }
520 true
521 }
522}
523
524#[repr(C)]
526#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
527pub struct VhostUserMemoryRegion {
528 pub guest_phys_addr: u64,
530 pub memory_size: u64,
532 pub user_addr: u64,
534 pub mmap_offset: u64,
536}
537
538impl VhostUserMemoryRegion {
539 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self {
541 VhostUserMemoryRegion {
542 guest_phys_addr,
543 memory_size,
544 user_addr,
545 mmap_offset,
546 }
547 }
548}
549
550impl VhostUserMsgValidator for VhostUserMemoryRegion {
551 fn is_valid(&self) -> bool {
552 if self.memory_size == 0
553 || self.guest_phys_addr.checked_add(self.memory_size).is_none()
554 || self.user_addr.checked_add(self.memory_size).is_none()
555 || self.mmap_offset.checked_add(self.memory_size).is_none()
556 {
557 return false;
558 }
559 true
560 }
561}
562
563pub type VhostUserMemoryPayload = Vec<VhostUserMemoryRegion>;
565
566#[repr(C)]
569#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
570pub struct VhostUserSingleMemoryRegion {
571 padding: u64,
573 pub guest_phys_addr: u64,
575 pub memory_size: u64,
577 pub user_addr: u64,
579 pub mmap_offset: u64,
581}
582
583impl VhostUserSingleMemoryRegion {
584 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self {
586 VhostUserSingleMemoryRegion {
587 padding: 0,
588 guest_phys_addr,
589 memory_size,
590 user_addr,
591 mmap_offset,
592 }
593 }
594}
595
596impl VhostUserMsgValidator for VhostUserSingleMemoryRegion {
597 fn is_valid(&self) -> bool {
598 if self.memory_size == 0
599 || self.guest_phys_addr.checked_add(self.memory_size).is_none()
600 || self.user_addr.checked_add(self.memory_size).is_none()
601 || self.mmap_offset.checked_add(self.memory_size).is_none()
602 {
603 return false;
604 }
605 true
606 }
607}
608
609#[repr(C)]
611#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
612pub struct VhostUserVringState {
613 pub index: u32,
615 pub num: u32,
617}
618
619impl VhostUserVringState {
620 pub fn new(index: u32, num: u32) -> Self {
622 VhostUserVringState { index, num }
623 }
624}
625
626impl VhostUserMsgValidator for VhostUserVringState {}
627
628bitflags! {
630 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
632 #[repr(transparent)]
633 pub struct VhostUserVringAddrFlags: u32 {
634 const VHOST_VRING_F_LOG = 0x1;
637 }
638}
639
640#[repr(C)]
642#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
643pub struct VhostUserVringAddr {
644 pub index: u32,
646 pub flags: u32,
648 pub descriptor: u64,
650 pub used: u64,
652 pub available: u64,
654 pub log: u64,
656}
657
658impl VhostUserVringAddr {
659 pub fn new(
661 index: u32,
662 flags: VhostUserVringAddrFlags,
663 descriptor: u64,
664 used: u64,
665 available: u64,
666 log: u64,
667 ) -> Self {
668 VhostUserVringAddr {
669 index,
670 flags: flags.bits(),
671 descriptor,
672 used,
673 available,
674 log,
675 }
676 }
677
678 pub fn from_config_data(index: u32, config_data: &VringConfigData) -> Self {
680 let log_addr = config_data.log_addr.unwrap_or(0);
681 VhostUserVringAddr {
682 index,
683 flags: config_data.flags,
684 descriptor: config_data.desc_table_addr,
685 used: config_data.used_ring_addr,
686 available: config_data.avail_ring_addr,
687 log: log_addr,
688 }
689 }
690}
691
692impl VhostUserMsgValidator for VhostUserVringAddr {
693 #[allow(clippy::if_same_then_else)]
694 fn is_valid(&self) -> bool {
695 if (self.flags & !VhostUserVringAddrFlags::all().bits()) != 0 {
696 return false;
697 } else if self.descriptor & 0xf != 0 {
698 return false;
699 } else if self.available & 0x1 != 0 {
700 return false;
701 } else if self.used & 0x3 != 0 {
702 return false;
703 }
704 true
705 }
706}
707
708bitflags! {
710 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
712 #[repr(transparent)]
713 pub struct VhostUserConfigFlags: u32 {
714 const WRITABLE = 0x1;
716 const LIVE_MIGRATION = 0x2;
718 }
719}
720
721#[repr(C)]
723#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
724pub struct VhostUserConfig {
725 pub offset: u32,
727 pub size: u32,
729 pub flags: u32,
731}
732
733impl VhostUserConfig {
734 pub fn new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self {
736 VhostUserConfig {
737 offset,
738 size,
739 flags: flags.bits(),
740 }
741 }
742}
743
744impl VhostUserMsgValidator for VhostUserConfig {
745 #[allow(clippy::if_same_then_else)]
746 fn is_valid(&self) -> bool {
747 let end_addr = match self.size.checked_add(self.offset) {
748 Some(addr) => addr,
749 None => return false,
750 };
751 if (self.flags & !VhostUserConfigFlags::all().bits()) != 0 {
752 return false;
753 } else if self.size == 0 || end_addr > VHOST_USER_CONFIG_SIZE {
754 return false;
755 }
756 true
757 }
758}
759
760pub type VhostUserConfigPayload = Vec<u8>;
762
763#[repr(C)]
769#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
770pub struct VhostUserInflight {
771 pub mmap_size: u64,
773 pub mmap_offset: u64,
775 pub num_queues: u16,
777 pub queue_size: u16,
779 pub _padding: [u8; 4],
781}
782
783impl VhostUserInflight {
784 pub fn new(mmap_size: u64, mmap_offset: u64, num_queues: u16, queue_size: u16) -> Self {
786 VhostUserInflight {
787 mmap_size,
788 mmap_offset,
789 num_queues,
790 queue_size,
791 ..Default::default()
792 }
793 }
794}
795
796impl VhostUserMsgValidator for VhostUserInflight {
797 fn is_valid(&self) -> bool {
798 if self.num_queues == 0 || self.queue_size == 0 {
799 return false;
800 }
801 true
802 }
803}
804
805#[repr(C)]
807#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
808pub struct DeviceStateTransferParameters {
809 pub transfer_direction: u32,
811 pub migration_phase: u32,
813}
814
815impl VhostUserMsgValidator for DeviceStateTransferParameters {
816 fn is_valid(&self) -> bool {
817 true
819 }
820}
821
822#[repr(transparent)]
850#[derive(
851 FromBytes,
852 Immutable,
853 IntoBytes,
854 KnownLayout,
855 Copy,
856 Clone,
857 Debug,
858 Default,
859 Eq,
860 Hash,
861 Ord,
862 PartialEq,
863 PartialOrd,
864)]
865pub struct VhostUserMMapFlags(u64);
866
867bitflags! {
868 impl VhostUserMMapFlags: u64 {
869 const MAP_RW = 0x1;
871 }
872}
873
874#[repr(C)]
876#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
877pub struct VhostUserMMap {
878 pub shmid: u8,
880 pub padding: [u8; 7],
882 pub fd_offset: u64,
884 pub shm_offset: u64,
886 pub len: u64,
888 pub flags: VhostUserMMapFlags,
890}
891
892impl VhostUserMsgValidator for VhostUserMMap {
893 fn is_valid(&self) -> bool {
894 (self.flags.bits() & !VhostUserMMapFlags::all().bits()) == 0
895 && self.fd_offset.checked_add(self.len).is_some()
896 && self.shm_offset.checked_add(self.len).is_some()
897 }
898}
899
900#[repr(C)]
902#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
903pub struct VhostUserGpuMapMsg {
904 pub shmid: u8,
906 padding: [u8; 7],
907 pub shm_offset: u64,
909 pub len: u64,
911 pub memory_idx: u32,
913 pub handle_type: u32,
915 pub device_uuid: [u8; 16],
917 pub driver_uuid: [u8; 16],
919}
920
921impl VhostUserMsgValidator for VhostUserGpuMapMsg {
922 fn is_valid(&self) -> bool {
923 self.len > 0
924 }
925}
926
927impl VhostUserGpuMapMsg {
928 pub fn new(
930 shmid: u8,
931 shm_offset: u64,
932 len: u64,
933 memory_idx: u32,
934 handle_type: u32,
935 device_uuid: [u8; 16],
936 driver_uuid: [u8; 16],
937 ) -> Self {
938 Self {
939 shmid,
940 padding: [0; 7],
941 shm_offset,
942 len,
943 memory_idx,
944 handle_type,
945 device_uuid,
946 driver_uuid,
947 }
948 }
949}
950
951#[repr(C)]
953#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
954pub struct VhostUserExternalMapMsg {
955 pub shmid: u8,
957 padding: [u8; 7],
958 pub shm_offset: u64,
960 pub len: u64,
962 pub ptr: u64,
964}
965
966impl VhostUserMsgValidator for VhostUserExternalMapMsg {
967 fn is_valid(&self) -> bool {
968 self.len > 0
969 }
970}
971
972impl VhostUserExternalMapMsg {
973 pub fn new(shmid: u8, shm_offset: u64, len: u64, ptr: u64) -> Self {
975 Self {
976 shmid,
977 padding: [0; 7],
978 shm_offset,
979 len,
980 ptr,
981 }
982 }
983}
984
985#[repr(C)]
987#[derive(Clone, Copy, Default)]
988pub struct DescStateSplit {
989 pub inflight: u8,
991 padding: [u8; 5],
993 pub next: u16,
995 pub counter: u64,
997}
998
999impl DescStateSplit {
1000 pub fn new() -> Self {
1002 Self::default()
1003 }
1004}
1005
1006#[repr(C)]
1008pub struct QueueRegionSplit {
1009 pub features: u64,
1011 pub version: u16,
1013 pub desc_num: u16,
1015 pub last_batch_head: u16,
1017 pub used_idx: u16,
1019 pub desc: u64,
1021}
1022
1023impl QueueRegionSplit {
1024 pub fn new(features: u64, queue_size: u16) -> Self {
1026 QueueRegionSplit {
1027 features,
1028 version: 1,
1029 desc_num: queue_size,
1030 last_batch_head: 0,
1031 used_idx: 0,
1032 desc: 0,
1033 }
1034 }
1035}
1036
1037#[repr(C)]
1039#[derive(Clone, Copy, Default)]
1040pub struct DescStatePacked {
1041 pub inflight: u8,
1043 padding: u8,
1045 pub next: u16,
1047 pub last: u16,
1049 pub num: u16,
1051 pub counter: u64,
1053 pub id: u16,
1055 pub flags: u16,
1057 pub len: u32,
1059 pub addr: u64,
1061}
1062
1063impl DescStatePacked {
1064 pub fn new() -> Self {
1066 Self::default()
1067 }
1068}
1069
1070#[repr(C)]
1072pub struct QueueRegionPacked {
1073 pub features: u64,
1075 pub version: u16,
1077 pub desc_num: u16,
1079 pub free_head: u16,
1081 pub old_free_head: u16,
1083 pub used_idx: u16,
1085 pub old_used_idx: u16,
1087 pub used_wrap_counter: u8,
1089 pub old_used_wrap_counter: u8,
1091 padding: [u8; 7],
1093 pub desc: u64,
1095}
1096
1097impl QueueRegionPacked {
1098 pub fn new(features: u64, queue_size: u16) -> Self {
1100 QueueRegionPacked {
1101 features,
1102 version: 1,
1103 desc_num: queue_size,
1104 free_head: 0,
1105 old_free_head: 0,
1106 used_idx: 0,
1107 old_used_idx: 0,
1108 used_wrap_counter: 0,
1109 old_used_wrap_counter: 0,
1110 padding: [0; 7],
1111 desc: 0,
1112 }
1113 }
1114}
1115
1116#[repr(C)]
1117#[derive(Debug, Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
1118pub struct VhostUserShMemConfigHeader {
1119 pub nregions: u32,
1121 padding: u32,
1123}
1124
1125impl VhostUserMsgValidator for VhostUserShMemConfigHeader {
1126 #[allow(clippy::if_same_then_else)]
1127 fn is_valid(&self) -> bool {
1128 true
1129 }
1130}
1131
1132impl VhostUserShMemConfigHeader {
1133 pub fn new(nregions: u32) -> Self {
1135 Self {
1136 nregions,
1137 padding: 0,
1138 }
1139 }
1140}
1141
1142#[derive(Debug, PartialEq, Eq)]
1143pub enum VhostUserTransferDirection {
1144 Save,
1145 Load,
1146}
1147
1148#[derive(Debug, PartialEq, Eq)]
1149pub enum VhostUserMigrationPhase {
1150 Stopped,
1151}
1152
1153#[cfg(test)]
1154mod tests {
1155 use super::*;
1156
1157 #[test]
1158 fn check_frontend_request_code() {
1159 FrontendReq::try_from(0).expect_err("invalid value");
1160 FrontendReq::try_from(46).expect_err("invalid value");
1161 FrontendReq::try_from(10000).expect_err("invalid value");
1162
1163 let code = FrontendReq::try_from(FrontendReq::GET_FEATURES as u32).unwrap();
1164 assert_eq!(code, code.clone());
1165 }
1166
1167 #[test]
1168 fn check_backend_request_code() {
1169 BackendReq::try_from(0).expect_err("invalid value");
1170 BackendReq::try_from(14).expect_err("invalid value");
1171 BackendReq::try_from(10000).expect_err("invalid value");
1172
1173 let code = BackendReq::try_from(BackendReq::CONFIG_CHANGE_MSG as u32).unwrap();
1174 assert_eq!(code, code.clone());
1175 }
1176
1177 #[test]
1178 fn msg_header_ops() {
1179 let mut hdr = VhostUserMsgHeader::new(FrontendReq::GET_FEATURES, 0, 0x100);
1180 assert_eq!(hdr.get_code(), Ok(FrontendReq::GET_FEATURES));
1181 hdr.set_code(FrontendReq::SET_FEATURES);
1182 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_FEATURES));
1183
1184 assert_eq!(hdr.get_version(), 0x1);
1185
1186 assert!(!hdr.is_reply());
1187 hdr.set_reply(true);
1188 assert!(hdr.is_reply());
1189 hdr.set_reply(false);
1190
1191 assert!(!hdr.is_need_reply());
1192 hdr.set_need_reply(true);
1193 assert!(hdr.is_need_reply());
1194 hdr.set_need_reply(false);
1195
1196 assert_eq!(hdr.get_size(), 0x100);
1197 hdr.set_size(0x200);
1198 assert_eq!(hdr.get_size(), 0x200);
1199
1200 assert!(!hdr.is_need_reply());
1201 assert!(!hdr.is_reply());
1202 assert_eq!(hdr.get_version(), 0x1);
1203
1204 hdr.set_version(0x0);
1206 assert!(!hdr.is_valid());
1207 hdr.set_version(0x2);
1208 assert!(!hdr.is_valid());
1209 hdr.set_version(0x1);
1210 assert!(hdr.is_valid());
1211
1212 assert_eq!(hdr, hdr.clone());
1214 assert_eq!(hdr.clone().get_code(), hdr.get_code());
1215 assert_eq!(format!("{:?}", hdr.clone()), format!("{:?}", hdr));
1216 }
1217
1218 #[test]
1219 fn test_vhost_user_message_u64() {
1220 let val = VhostUserU64::default();
1221 let val1 = VhostUserU64::new(0);
1222
1223 let a = val.value;
1224 let b = val1.value;
1225 assert_eq!(a, b);
1226 let a = VhostUserU64::new(1).value;
1227 assert_eq!(a, 1);
1228 }
1229
1230 #[test]
1231 fn check_user_memory() {
1232 let mut msg = VhostUserMemory::new(1);
1233 assert!(msg.is_valid());
1234 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32;
1235 assert!(msg.is_valid());
1236
1237 msg.num_regions += 1;
1238 assert!(!msg.is_valid());
1239 msg.num_regions = 0xFFFFFFFF;
1240 assert!(!msg.is_valid());
1241 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32;
1242 msg.padding1 = 1;
1243 assert!(!msg.is_valid());
1244 }
1245
1246 #[test]
1247 fn check_user_memory_region() {
1248 let mut msg = VhostUserMemoryRegion {
1249 guest_phys_addr: 0,
1250 memory_size: 0x1000,
1251 user_addr: 0,
1252 mmap_offset: 0,
1253 };
1254 assert!(msg.is_valid());
1255 msg.guest_phys_addr = 0xFFFFFFFFFFFFEFFF;
1256 assert!(msg.is_valid());
1257 msg.guest_phys_addr = 0xFFFFFFFFFFFFF000;
1258 assert!(!msg.is_valid());
1259 msg.guest_phys_addr = 0xFFFFFFFFFFFF0000;
1260 msg.memory_size = 0;
1261 assert!(!msg.is_valid());
1262 let a = msg.guest_phys_addr;
1263 let b = msg.guest_phys_addr;
1264 assert_eq!(a, b);
1265
1266 let msg = VhostUserMemoryRegion::default();
1267 let a = msg.guest_phys_addr;
1268 assert_eq!(a, 0);
1269 let a = msg.memory_size;
1270 assert_eq!(a, 0);
1271 let a = msg.user_addr;
1272 assert_eq!(a, 0);
1273 let a = msg.mmap_offset;
1274 assert_eq!(a, 0);
1275 }
1276
1277 #[test]
1278 fn test_vhost_user_state() {
1279 let state = VhostUserVringState::new(5, 8);
1280
1281 let a = state.index;
1282 assert_eq!(a, 5);
1283 let a = state.num;
1284 assert_eq!(a, 8);
1285 assert!(state.is_valid());
1286
1287 let state = VhostUserVringState::default();
1288 let a = state.index;
1289 assert_eq!(a, 0);
1290 let a = state.num;
1291 assert_eq!(a, 0);
1292 assert!(state.is_valid());
1293 }
1294
1295 #[test]
1296 fn test_vhost_user_addr() {
1297 let mut addr = VhostUserVringAddr::new(
1298 2,
1299 VhostUserVringAddrFlags::VHOST_VRING_F_LOG,
1300 0x1000,
1301 0x2000,
1302 0x3000,
1303 0x4000,
1304 );
1305
1306 let a = addr.index;
1307 assert_eq!(a, 2);
1308 let a = addr.flags;
1309 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits());
1310 let a = addr.descriptor;
1311 assert_eq!(a, 0x1000);
1312 let a = addr.used;
1313 assert_eq!(a, 0x2000);
1314 let a = addr.available;
1315 assert_eq!(a, 0x3000);
1316 let a = addr.log;
1317 assert_eq!(a, 0x4000);
1318 assert!(addr.is_valid());
1319
1320 addr.descriptor = 0x1001;
1321 assert!(!addr.is_valid());
1322 addr.descriptor = 0x1000;
1323
1324 addr.available = 0x3001;
1325 assert!(!addr.is_valid());
1326 addr.available = 0x3000;
1327
1328 addr.used = 0x2001;
1329 assert!(!addr.is_valid());
1330 addr.used = 0x2000;
1331 assert!(addr.is_valid());
1332 }
1333
1334 #[test]
1335 fn test_vhost_user_state_from_config() {
1336 let config = VringConfigData {
1337 queue_size: 128,
1338 flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits(),
1339 desc_table_addr: 0x1000,
1340 used_ring_addr: 0x2000,
1341 avail_ring_addr: 0x3000,
1342 log_addr: Some(0x4000),
1343 };
1344 let addr = VhostUserVringAddr::from_config_data(2, &config);
1345
1346 let a = addr.index;
1347 assert_eq!(a, 2);
1348 let a = addr.flags;
1349 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits());
1350 let a = addr.descriptor;
1351 assert_eq!(a, 0x1000);
1352 let a = addr.used;
1353 assert_eq!(a, 0x2000);
1354 let a = addr.available;
1355 assert_eq!(a, 0x3000);
1356 let a = addr.log;
1357 assert_eq!(a, 0x4000);
1358 assert!(addr.is_valid());
1359 }
1360
1361 #[test]
1362 fn check_user_vring_addr() {
1363 let mut msg =
1364 VhostUserVringAddr::new(0, VhostUserVringAddrFlags::all(), 0x0, 0x0, 0x0, 0x0);
1365 assert!(msg.is_valid());
1366
1367 msg.descriptor = 1;
1368 assert!(!msg.is_valid());
1369 msg.descriptor = 0;
1370
1371 msg.available = 1;
1372 assert!(!msg.is_valid());
1373 msg.available = 0;
1374
1375 msg.used = 1;
1376 assert!(!msg.is_valid());
1377 msg.used = 0;
1378
1379 msg.flags |= 0x80000000;
1380 assert!(!msg.is_valid());
1381 msg.flags &= !0x80000000;
1382 }
1383
1384 #[test]
1385 fn check_user_config_msg() {
1386 let mut msg =
1387 VhostUserConfig::new(0, VHOST_USER_CONFIG_SIZE, VhostUserConfigFlags::WRITABLE);
1388
1389 assert!(msg.is_valid());
1390 msg.size = 0;
1391 assert!(!msg.is_valid());
1392 msg.size = 1;
1393 assert!(msg.is_valid());
1394 msg.offset = u32::MAX;
1395 assert!(!msg.is_valid());
1396 msg.offset = VHOST_USER_CONFIG_SIZE;
1397 assert!(!msg.is_valid());
1398 msg.offset = VHOST_USER_CONFIG_SIZE - 1;
1399 assert!(msg.is_valid());
1400 msg.size = 2;
1401 assert!(!msg.is_valid());
1402 msg.size = 1;
1403 msg.flags |= VhostUserConfigFlags::LIVE_MIGRATION.bits();
1404 assert!(msg.is_valid());
1405 msg.flags |= 0x4;
1406 assert!(!msg.is_valid());
1407 }
1408}