1#![allow(dead_code)]
9#![allow(non_camel_case_types)]
10#![allow(clippy::upper_case_acronyms)]
11
12use std::fmt::Debug;
13
14use bitflags::bitflags;
15use zerocopy::FromBytes;
16use zerocopy::Immutable;
17use zerocopy::IntoBytes;
18use zerocopy::KnownLayout;
19
20use crate::SharedMemoryRegion;
21use crate::VringConfigData;
22
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
237#[bit_field::bitfield]
238#[derive(
239 Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, FromBytes, Immutable, IntoBytes, KnownLayout,
240)]
241pub struct VhostUserHeaderFlags {
242 version: bit_field::B2,
243 #[bits = 1]
244 is_reply: bool,
245 #[bits = 1]
246 need_reply: bool,
247 reserved: bit_field::B28,
248}
249
250#[repr(C)]
254#[derive(Copy, Clone, Debug, PartialEq, Eq, FromBytes, Immutable, IntoBytes, KnownLayout)]
255pub struct VhostUserMsgHeader {
256 request: u32,
257 flags: VhostUserHeaderFlags,
258 size: u32,
259}
260
261impl VhostUserMsgHeader {
262 pub fn new_request_header(request: impl Req, size: u32, need_reply: bool) -> Self {
264 let mut flags = VhostUserHeaderFlags::new();
265 flags.set_version(1);
266 flags.set_need_reply(need_reply);
267 VhostUserMsgHeader {
268 request: request.into(),
269 flags,
270 size,
271 }
272 }
273
274 pub fn new_reply_header(request: impl Req, size: u32) -> Self {
276 let mut flags = VhostUserHeaderFlags::new();
277 flags.set_version(1);
278 flags.set_is_reply(true);
279 VhostUserMsgHeader {
280 request: request.into(),
281 flags,
282 size,
283 }
284 }
285
286 pub fn get_code<R: Req>(&self) -> std::result::Result<R, R::Error> {
288 R::try_from(self.request)
289 }
290
291 fn set_code(&mut self, request: impl Req) {
293 self.request = request.into();
294 }
295
296 pub fn get_version(&self) -> u32 {
298 self.flags.get_version().into()
299 }
300
301 pub fn is_reply(&self) -> bool {
303 self.flags.get_is_reply()
304 }
305
306 pub fn is_need_reply(&self) -> bool {
308 self.flags.get_need_reply()
309 }
310
311 pub fn is_reply_for(&self, req: &VhostUserMsgHeader) -> bool {
313 self.is_reply() && !req.is_reply() && self.request == req.request
314 }
315
316 pub fn get_size(&self) -> u32 {
318 self.size
319 }
320}
321
322impl VhostUserMsgValidator for VhostUserMsgHeader {
323 #[allow(clippy::if_same_then_else)]
324 fn is_valid(&self) -> bool {
325 if self.get_version() != 0x1 {
326 return false;
327 } else if self.flags.get_reserved() != 0 {
328 return false;
329 }
330 true
331 }
332}
333
334pub const VIRTIO_F_RING_PACKED: u32 = 34;
335
336pub const VHOST_USER_F_PROTOCOL_FEATURES: u32 = 30;
338
339bitflags! {
341 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
343 #[repr(transparent)]
344 pub struct VhostUserProtocolFeatures: u64 {
345 const MQ = 0x0000_0001;
347 const LOG_SHMFD = 0x0000_0002;
349 const RARP = 0x0000_0004;
351 const REPLY_ACK = 0x0000_0008;
353 const MTU = 0x0000_0010;
355 const BACKEND_REQ = 0x0000_0020;
357 const CROSS_ENDIAN = 0x0000_0040;
359 const CRYPTO_SESSION = 0x0000_0080;
361 const PAGEFAULT = 0x0000_0100;
363 const CONFIG = 0x0000_0200;
365 const BACKEND_SEND_FD = 0x0000_0400;
367 const HOST_NOTIFIER = 0x0000_0800;
369 const INFLIGHT_SHMFD = 0x0000_1000;
371 const RESET_DEVICE = 0x0000_2000;
373 const INBAND_NOTIFICATIONS = 0x0000_4000;
375 const CONFIGURE_MEM_SLOTS = 0x0000_8000;
377 const STATUS = 0x0001_0000;
379 const XEN_MMAP = 0x0002_0000;
381 const DEVICE_STATE = 0x0008_0000;
383 const SHMEM_MAP = 0x0010_0000;
385 }
386}
387
388#[repr(C)]
390#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
391pub struct VhostUserU64 {
392 pub value: u64,
394}
395
396impl VhostUserU64 {
397 pub fn new(value: u64) -> Self {
399 VhostUserU64 { value }
400 }
401}
402
403impl VhostUserMsgValidator for VhostUserU64 {}
404
405#[repr(C)]
407#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
408pub struct VhostUserEmptyMsg;
409
410impl VhostUserMsgValidator for VhostUserEmptyMsg {}
411
412#[repr(C)]
415#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
416pub struct VhostUserEmptyMessage;
417
418impl VhostUserMsgValidator for VhostUserEmptyMessage {}
419
420#[repr(C)]
422#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
423pub struct VhostUserMemory {
424 pub num_regions: u32,
426 pub padding1: u32,
428}
429
430impl VhostUserMemory {
431 pub fn new(cnt: u32) -> Self {
433 VhostUserMemory {
434 num_regions: cnt,
435 padding1: 0,
436 }
437 }
438}
439
440impl VhostUserMsgValidator for VhostUserMemory {
441 #[allow(clippy::if_same_then_else)]
442 fn is_valid(&self) -> bool {
443 if self.padding1 != 0 {
444 return false;
445 } else if self.num_regions == 0 || self.num_regions > MAX_ATTACHED_FD_ENTRIES as u32 {
446 return false;
447 }
448 true
449 }
450}
451
452#[repr(C)]
454#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
455pub struct VhostUserMemoryRegion {
456 pub guest_phys_addr: u64,
458 pub memory_size: u64,
460 pub user_addr: u64,
462 pub mmap_offset: u64,
464}
465
466impl VhostUserMemoryRegion {
467 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self {
469 VhostUserMemoryRegion {
470 guest_phys_addr,
471 memory_size,
472 user_addr,
473 mmap_offset,
474 }
475 }
476}
477
478impl VhostUserMsgValidator for VhostUserMemoryRegion {
479 fn is_valid(&self) -> bool {
480 if self.memory_size == 0
481 || self.guest_phys_addr.checked_add(self.memory_size).is_none()
482 || self.user_addr.checked_add(self.memory_size).is_none()
483 || self.mmap_offset.checked_add(self.memory_size).is_none()
484 {
485 return false;
486 }
487 true
488 }
489}
490
491pub type VhostUserMemoryPayload = Vec<VhostUserMemoryRegion>;
493
494#[repr(C)]
497#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
498pub struct VhostUserSingleMemoryRegion {
499 padding: u64,
501 pub guest_phys_addr: u64,
503 pub memory_size: u64,
505 pub user_addr: u64,
507 pub mmap_offset: u64,
509}
510
511impl VhostUserSingleMemoryRegion {
512 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self {
514 VhostUserSingleMemoryRegion {
515 padding: 0,
516 guest_phys_addr,
517 memory_size,
518 user_addr,
519 mmap_offset,
520 }
521 }
522}
523
524impl VhostUserMsgValidator for VhostUserSingleMemoryRegion {
525 fn is_valid(&self) -> bool {
526 if self.memory_size == 0
527 || self.guest_phys_addr.checked_add(self.memory_size).is_none()
528 || self.user_addr.checked_add(self.memory_size).is_none()
529 || self.mmap_offset.checked_add(self.memory_size).is_none()
530 {
531 return false;
532 }
533 true
534 }
535}
536
537#[repr(C)]
539#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
540pub struct VhostUserVringState {
541 pub index: u32,
543 pub num: u32,
545}
546
547impl VhostUserVringState {
548 pub fn new(index: u32, num: u32) -> Self {
550 VhostUserVringState { index, num }
551 }
552}
553
554impl VhostUserMsgValidator for VhostUserVringState {}
555
556bitflags! {
558 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
560 #[repr(transparent)]
561 pub struct VhostUserVringAddrFlags: u32 {
562 const VHOST_VRING_F_LOG = 0x1;
565 }
566}
567
568#[repr(C)]
570#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
571pub struct VhostUserVringAddr {
572 pub index: u32,
574 pub flags: u32,
576 pub descriptor: u64,
578 pub used: u64,
580 pub available: u64,
582 pub log: u64,
584}
585
586impl VhostUserVringAddr {
587 pub fn new(
589 index: u32,
590 flags: VhostUserVringAddrFlags,
591 descriptor: u64,
592 used: u64,
593 available: u64,
594 log: u64,
595 ) -> Self {
596 VhostUserVringAddr {
597 index,
598 flags: flags.bits(),
599 descriptor,
600 used,
601 available,
602 log,
603 }
604 }
605
606 pub fn from_config_data(index: u32, config_data: &VringConfigData) -> Self {
608 let log_addr = config_data.log_addr.unwrap_or(0);
609 VhostUserVringAddr {
610 index,
611 flags: config_data.flags,
612 descriptor: config_data.desc_table_addr,
613 used: config_data.used_ring_addr,
614 available: config_data.avail_ring_addr,
615 log: log_addr,
616 }
617 }
618}
619
620impl VhostUserMsgValidator for VhostUserVringAddr {
621 #[allow(clippy::if_same_then_else)]
622 fn is_valid(&self) -> bool {
623 if (self.flags & !VhostUserVringAddrFlags::all().bits()) != 0 {
624 return false;
625 } else if self.descriptor & 0xf != 0 {
626 return false;
627 } else if self.available & 0x1 != 0 {
628 return false;
629 } else if self.used & 0x3 != 0 {
630 return false;
631 }
632 true
633 }
634}
635
636bitflags! {
638 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
640 #[repr(transparent)]
641 pub struct VhostUserConfigFlags: u32 {
642 const WRITABLE = 0x1;
644 const LIVE_MIGRATION = 0x2;
646 }
647}
648
649#[repr(C)]
651#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
652pub struct VhostUserConfig {
653 pub offset: u32,
655 pub size: u32,
657 pub flags: u32,
659}
660
661impl VhostUserConfig {
662 pub fn new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self {
664 VhostUserConfig {
665 offset,
666 size,
667 flags: flags.bits(),
668 }
669 }
670}
671
672impl VhostUserMsgValidator for VhostUserConfig {
673 #[allow(clippy::if_same_then_else)]
674 fn is_valid(&self) -> bool {
675 let end_addr = match self.size.checked_add(self.offset) {
676 Some(addr) => addr,
677 None => return false,
678 };
679 if (self.flags & !VhostUserConfigFlags::all().bits()) != 0 {
680 return false;
681 } else if self.size == 0 || end_addr > VHOST_USER_CONFIG_SIZE {
682 return false;
683 }
684 true
685 }
686}
687
688pub type VhostUserConfigPayload = Vec<u8>;
690
691#[repr(C)]
697#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
698pub struct VhostUserInflight {
699 pub mmap_size: u64,
701 pub mmap_offset: u64,
703 pub num_queues: u16,
705 pub queue_size: u16,
707 pub _padding: [u8; 4],
709}
710
711impl VhostUserInflight {
712 pub fn new(mmap_size: u64, mmap_offset: u64, num_queues: u16, queue_size: u16) -> Self {
714 VhostUserInflight {
715 mmap_size,
716 mmap_offset,
717 num_queues,
718 queue_size,
719 ..Default::default()
720 }
721 }
722}
723
724impl VhostUserMsgValidator for VhostUserInflight {
725 fn is_valid(&self) -> bool {
726 if self.num_queues == 0 || self.queue_size == 0 {
727 return false;
728 }
729 true
730 }
731}
732
733#[repr(C)]
735#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
736pub struct DeviceStateTransferParameters {
737 pub transfer_direction: u32,
739 pub migration_phase: u32,
741}
742
743impl VhostUserMsgValidator for DeviceStateTransferParameters {
744 fn is_valid(&self) -> bool {
745 true
747 }
748}
749
750#[repr(transparent)]
778#[derive(
779 FromBytes,
780 Immutable,
781 IntoBytes,
782 KnownLayout,
783 Copy,
784 Clone,
785 Debug,
786 Default,
787 Eq,
788 Hash,
789 Ord,
790 PartialEq,
791 PartialOrd,
792)]
793pub struct VhostUserMMapFlags(u64);
794
795bitflags! {
796 impl VhostUserMMapFlags: u64 {
797 const MAP_RW = 0x1;
799 }
800}
801
802#[repr(C)]
804#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
805pub struct VhostUserMMap {
806 pub shmid: u8,
808 pub padding: [u8; 7],
810 pub fd_offset: u64,
812 pub shm_offset: u64,
814 pub len: u64,
816 pub flags: VhostUserMMapFlags,
818}
819
820impl VhostUserMsgValidator for VhostUserMMap {
821 fn is_valid(&self) -> bool {
822 (self.flags.bits() & !VhostUserMMapFlags::all().bits()) == 0
823 && self.fd_offset.checked_add(self.len).is_some()
824 && self.shm_offset.checked_add(self.len).is_some()
825 }
826}
827
828#[repr(C)]
830#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
831pub struct VhostUserGpuMapMsg {
832 pub shmid: u8,
834 padding: [u8; 7],
835 pub shm_offset: u64,
837 pub len: u64,
839 pub memory_idx: u32,
841 pub handle_type: u32,
843 pub device_uuid: [u8; 16],
845 pub driver_uuid: [u8; 16],
847}
848
849impl VhostUserMsgValidator for VhostUserGpuMapMsg {
850 fn is_valid(&self) -> bool {
851 self.len > 0
852 }
853}
854
855impl VhostUserGpuMapMsg {
856 pub fn new(
858 shmid: u8,
859 shm_offset: u64,
860 len: u64,
861 memory_idx: u32,
862 handle_type: u32,
863 device_uuid: [u8; 16],
864 driver_uuid: [u8; 16],
865 ) -> Self {
866 Self {
867 shmid,
868 padding: [0; 7],
869 shm_offset,
870 len,
871 memory_idx,
872 handle_type,
873 device_uuid,
874 driver_uuid,
875 }
876 }
877}
878
879#[repr(C)]
881#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
882pub struct VhostUserExternalMapMsg {
883 pub shmid: u8,
885 padding: [u8; 7],
886 pub shm_offset: u64,
888 pub len: u64,
890 pub ptr: u64,
892}
893
894impl VhostUserMsgValidator for VhostUserExternalMapMsg {
895 fn is_valid(&self) -> bool {
896 self.len > 0
897 }
898}
899
900impl VhostUserExternalMapMsg {
901 pub fn new(shmid: u8, shm_offset: u64, len: u64, ptr: u64) -> Self {
903 Self {
904 shmid,
905 padding: [0; 7],
906 shm_offset,
907 len,
908 ptr,
909 }
910 }
911}
912
913#[repr(C)]
915#[derive(Clone, Copy, Default)]
916pub struct DescStateSplit {
917 pub inflight: u8,
919 padding: [u8; 5],
921 pub next: u16,
923 pub counter: u64,
925}
926
927impl DescStateSplit {
928 pub fn new() -> Self {
930 Self::default()
931 }
932}
933
934#[repr(C)]
936pub struct QueueRegionSplit {
937 pub features: u64,
939 pub version: u16,
941 pub desc_num: u16,
943 pub last_batch_head: u16,
945 pub used_idx: u16,
947 pub desc: u64,
949}
950
951impl QueueRegionSplit {
952 pub fn new(features: u64, queue_size: u16) -> Self {
954 QueueRegionSplit {
955 features,
956 version: 1,
957 desc_num: queue_size,
958 last_batch_head: 0,
959 used_idx: 0,
960 desc: 0,
961 }
962 }
963}
964
965#[repr(C)]
967#[derive(Clone, Copy, Default)]
968pub struct DescStatePacked {
969 pub inflight: u8,
971 padding: u8,
973 pub next: u16,
975 pub last: u16,
977 pub num: u16,
979 pub counter: u64,
981 pub id: u16,
983 pub flags: u16,
985 pub len: u32,
987 pub addr: u64,
989}
990
991impl DescStatePacked {
992 pub fn new() -> Self {
994 Self::default()
995 }
996}
997
998#[repr(C)]
1000pub struct QueueRegionPacked {
1001 pub features: u64,
1003 pub version: u16,
1005 pub desc_num: u16,
1007 pub free_head: u16,
1009 pub old_free_head: u16,
1011 pub used_idx: u16,
1013 pub old_used_idx: u16,
1015 pub used_wrap_counter: u8,
1017 pub old_used_wrap_counter: u8,
1019 padding: [u8; 7],
1021 pub desc: u64,
1023}
1024
1025impl QueueRegionPacked {
1026 pub fn new(features: u64, queue_size: u16) -> Self {
1028 QueueRegionPacked {
1029 features,
1030 version: 1,
1031 desc_num: queue_size,
1032 free_head: 0,
1033 old_free_head: 0,
1034 used_idx: 0,
1035 old_used_idx: 0,
1036 used_wrap_counter: 0,
1037 old_used_wrap_counter: 0,
1038 padding: [0; 7],
1039 desc: 0,
1040 }
1041 }
1042}
1043
1044#[repr(C)]
1045#[derive(Debug, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
1046pub struct VhostUserShMemConfig {
1047 pub nregions: u32,
1049 padding: u32,
1051 pub sizes: [u64; 256],
1053}
1054
1055impl Default for VhostUserShMemConfig {
1056 fn default() -> Self {
1057 VhostUserShMemConfig {
1058 nregions: 0,
1059 padding: 0,
1060 sizes: [0; 256],
1061 }
1062 }
1063}
1064
1065impl VhostUserMsgValidator for VhostUserShMemConfig {
1066 #[allow(clippy::if_same_then_else)]
1067 fn is_valid(&self) -> bool {
1068 true
1069 }
1070}
1071
1072impl VhostUserShMemConfig {
1073 pub fn new(regions: &[SharedMemoryRegion]) -> Self {
1075 let mut sizes = [0; 256];
1076 for region in regions {
1077 *sizes.get_mut(usize::from(region.id)).unwrap() = region.length;
1078 }
1079
1080 Self {
1081 nregions: regions.len().try_into().unwrap(),
1082 padding: 0,
1083 sizes,
1084 }
1085 }
1086}
1087
1088#[derive(Debug, PartialEq, Eq)]
1089pub enum VhostUserTransferDirection {
1090 Save,
1091 Load,
1092}
1093
1094#[derive(Debug, PartialEq, Eq)]
1095pub enum VhostUserMigrationPhase {
1096 Stopped,
1097}
1098
1099#[cfg(test)]
1100mod tests {
1101 use super::*;
1102
1103 #[test]
1104 fn check_frontend_request_code() {
1105 FrontendReq::try_from(0).expect_err("invalid value");
1106 FrontendReq::try_from(46).expect_err("invalid value");
1107 FrontendReq::try_from(10000).expect_err("invalid value");
1108
1109 let code = FrontendReq::try_from(FrontendReq::GET_FEATURES as u32).unwrap();
1110 assert_eq!(code, code.clone());
1111 }
1112
1113 #[test]
1114 fn check_backend_request_code() {
1115 BackendReq::try_from(0).expect_err("invalid value");
1116 BackendReq::try_from(14).expect_err("invalid value");
1117 BackendReq::try_from(10000).expect_err("invalid value");
1118
1119 let code = BackendReq::try_from(BackendReq::CONFIG_CHANGE_MSG as u32).unwrap();
1120 assert_eq!(code, code.clone());
1121 }
1122
1123 #[test]
1124 fn msg_header_ops() {
1125 let mut hdr =
1126 VhostUserMsgHeader::new_request_header(FrontendReq::GET_FEATURES, 0x100, false);
1127 assert_eq!(hdr.get_code(), Ok(FrontendReq::GET_FEATURES));
1128 hdr.set_code(FrontendReq::SET_FEATURES);
1129 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_FEATURES));
1130
1131 assert_eq!(hdr.get_version(), 0x1);
1132
1133 assert!(!hdr.is_reply());
1134 hdr.flags.set_is_reply(true);
1135 assert!(hdr.is_reply());
1136 hdr.flags.set_is_reply(false);
1137
1138 assert!(!hdr.is_need_reply());
1139 hdr.flags.set_need_reply(true);
1140 assert!(hdr.is_need_reply());
1141 hdr.flags.set_need_reply(false);
1142
1143 assert_eq!(hdr.get_size(), 0x100);
1144 hdr.size = 0x200;
1145 assert_eq!(hdr.get_size(), 0x200);
1146
1147 assert!(!hdr.is_need_reply());
1148 assert!(!hdr.is_reply());
1149 assert_eq!(hdr.get_version(), 0x1);
1150
1151 hdr.flags.set_version(0x0);
1153 assert!(!hdr.is_valid());
1154 hdr.flags.set_version(0x2);
1155 assert!(!hdr.is_valid());
1156 hdr.flags.set_version(0x1);
1157 assert!(hdr.is_valid());
1158 }
1159
1160 #[test]
1161 fn test_vhost_user_message_u64() {
1162 let val = VhostUserU64::default();
1163 let val1 = VhostUserU64::new(0);
1164
1165 let a = val.value;
1166 let b = val1.value;
1167 assert_eq!(a, b);
1168 let a = VhostUserU64::new(1).value;
1169 assert_eq!(a, 1);
1170 }
1171
1172 #[test]
1173 fn check_user_memory() {
1174 let mut msg = VhostUserMemory::new(1);
1175 assert!(msg.is_valid());
1176 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32;
1177 assert!(msg.is_valid());
1178
1179 msg.num_regions += 1;
1180 assert!(!msg.is_valid());
1181 msg.num_regions = 0xFFFFFFFF;
1182 assert!(!msg.is_valid());
1183 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32;
1184 msg.padding1 = 1;
1185 assert!(!msg.is_valid());
1186 }
1187
1188 #[test]
1189 fn check_user_memory_region() {
1190 let mut msg = VhostUserMemoryRegion {
1191 guest_phys_addr: 0,
1192 memory_size: 0x1000,
1193 user_addr: 0,
1194 mmap_offset: 0,
1195 };
1196 assert!(msg.is_valid());
1197 msg.guest_phys_addr = 0xFFFFFFFFFFFFEFFF;
1198 assert!(msg.is_valid());
1199 msg.guest_phys_addr = 0xFFFFFFFFFFFFF000;
1200 assert!(!msg.is_valid());
1201 msg.guest_phys_addr = 0xFFFFFFFFFFFF0000;
1202 msg.memory_size = 0;
1203 assert!(!msg.is_valid());
1204 let a = msg.guest_phys_addr;
1205 let b = msg.guest_phys_addr;
1206 assert_eq!(a, b);
1207
1208 let msg = VhostUserMemoryRegion::default();
1209 let a = msg.guest_phys_addr;
1210 assert_eq!(a, 0);
1211 let a = msg.memory_size;
1212 assert_eq!(a, 0);
1213 let a = msg.user_addr;
1214 assert_eq!(a, 0);
1215 let a = msg.mmap_offset;
1216 assert_eq!(a, 0);
1217 }
1218
1219 #[test]
1220 fn test_vhost_user_state() {
1221 let state = VhostUserVringState::new(5, 8);
1222
1223 let a = state.index;
1224 assert_eq!(a, 5);
1225 let a = state.num;
1226 assert_eq!(a, 8);
1227 assert!(state.is_valid());
1228
1229 let state = VhostUserVringState::default();
1230 let a = state.index;
1231 assert_eq!(a, 0);
1232 let a = state.num;
1233 assert_eq!(a, 0);
1234 assert!(state.is_valid());
1235 }
1236
1237 #[test]
1238 fn test_vhost_user_addr() {
1239 let mut addr = VhostUserVringAddr::new(
1240 2,
1241 VhostUserVringAddrFlags::VHOST_VRING_F_LOG,
1242 0x1000,
1243 0x2000,
1244 0x3000,
1245 0x4000,
1246 );
1247
1248 let a = addr.index;
1249 assert_eq!(a, 2);
1250 let a = addr.flags;
1251 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits());
1252 let a = addr.descriptor;
1253 assert_eq!(a, 0x1000);
1254 let a = addr.used;
1255 assert_eq!(a, 0x2000);
1256 let a = addr.available;
1257 assert_eq!(a, 0x3000);
1258 let a = addr.log;
1259 assert_eq!(a, 0x4000);
1260 assert!(addr.is_valid());
1261
1262 addr.descriptor = 0x1001;
1263 assert!(!addr.is_valid());
1264 addr.descriptor = 0x1000;
1265
1266 addr.available = 0x3001;
1267 assert!(!addr.is_valid());
1268 addr.available = 0x3000;
1269
1270 addr.used = 0x2001;
1271 assert!(!addr.is_valid());
1272 addr.used = 0x2000;
1273 assert!(addr.is_valid());
1274 }
1275
1276 #[test]
1277 fn test_vhost_user_state_from_config() {
1278 let config = VringConfigData {
1279 queue_size: 128,
1280 flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits(),
1281 desc_table_addr: 0x1000,
1282 used_ring_addr: 0x2000,
1283 avail_ring_addr: 0x3000,
1284 log_addr: Some(0x4000),
1285 };
1286 let addr = VhostUserVringAddr::from_config_data(2, &config);
1287
1288 let a = addr.index;
1289 assert_eq!(a, 2);
1290 let a = addr.flags;
1291 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits());
1292 let a = addr.descriptor;
1293 assert_eq!(a, 0x1000);
1294 let a = addr.used;
1295 assert_eq!(a, 0x2000);
1296 let a = addr.available;
1297 assert_eq!(a, 0x3000);
1298 let a = addr.log;
1299 assert_eq!(a, 0x4000);
1300 assert!(addr.is_valid());
1301 }
1302
1303 #[test]
1304 fn check_user_vring_addr() {
1305 let mut msg =
1306 VhostUserVringAddr::new(0, VhostUserVringAddrFlags::all(), 0x0, 0x0, 0x0, 0x0);
1307 assert!(msg.is_valid());
1308
1309 msg.descriptor = 1;
1310 assert!(!msg.is_valid());
1311 msg.descriptor = 0;
1312
1313 msg.available = 1;
1314 assert!(!msg.is_valid());
1315 msg.available = 0;
1316
1317 msg.used = 1;
1318 assert!(!msg.is_valid());
1319 msg.used = 0;
1320
1321 msg.flags |= 0x80000000;
1322 assert!(!msg.is_valid());
1323 msg.flags &= !0x80000000;
1324 }
1325
1326 #[test]
1327 fn check_user_config_msg() {
1328 let mut msg =
1329 VhostUserConfig::new(0, VHOST_USER_CONFIG_SIZE, VhostUserConfigFlags::WRITABLE);
1330
1331 assert!(msg.is_valid());
1332 msg.size = 0;
1333 assert!(!msg.is_valid());
1334 msg.size = 1;
1335 assert!(msg.is_valid());
1336 msg.offset = u32::MAX;
1337 assert!(!msg.is_valid());
1338 msg.offset = VHOST_USER_CONFIG_SIZE;
1339 assert!(!msg.is_valid());
1340 msg.offset = VHOST_USER_CONFIG_SIZE - 1;
1341 assert!(msg.is_valid());
1342 msg.size = 2;
1343 assert!(!msg.is_valid());
1344 msg.size = 1;
1345 msg.flags |= VhostUserConfigFlags::LIVE_MIGRATION.bits();
1346 assert!(msg.is_valid());
1347 msg.flags |= 0x4;
1348 assert!(!msg.is_valid());
1349 }
1350}