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 base::Protection;
16use bitflags::bitflags;
17use zerocopy::FromBytes;
18use zerocopy::Immutable;
19use zerocopy::IntoBytes;
20use zerocopy::KnownLayout;
21
22use crate::VringConfigData;
23
24pub const MAX_ATTACHED_FD_ENTRIES: usize = 32;
31
32pub const VHOST_USER_CONFIG_OFFSET: u32 = 0x100;
34
35pub const VHOST_USER_CONFIG_SIZE: u32 = 0x1000;
37
38pub const VHOST_USER_MAX_VRINGS: u64 = 0x8000u64;
40
41pub trait Req:
43 Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Into<u32> + TryFrom<u32> + Send + Sync
44{
45}
46
47#[derive(Copy, Clone, Debug, PartialEq, Eq, thiserror::Error)]
49pub enum ReqError {
50 #[error("The value {0} does not correspond to a valid message code.")]
52 InvalidValue(u32),
53}
54
55#[repr(u32)]
61#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, enumn::N)]
62pub enum FrontendReq {
63 GET_FEATURES = 1,
65 SET_FEATURES = 2,
67 SET_OWNER = 3,
69 RESET_OWNER = 4,
71 SET_MEM_TABLE = 5,
73 SET_LOG_BASE = 6,
75 SET_LOG_FD = 7,
77 SET_VRING_NUM = 8,
79 SET_VRING_ADDR = 9,
81 SET_VRING_BASE = 10,
83 GET_VRING_BASE = 11,
85 SET_VRING_KICK = 12,
87 SET_VRING_CALL = 13,
89 SET_VRING_ERR = 14,
91 GET_PROTOCOL_FEATURES = 15,
93 SET_PROTOCOL_FEATURES = 16,
95 GET_QUEUE_NUM = 17,
97 SET_VRING_ENABLE = 18,
99 SEND_RARP = 19,
102 NET_SET_MTU = 20,
104 SET_BACKEND_REQ_FD = 21,
106 IOTLB_MSG = 22,
108 SET_VRING_ENDIAN = 23,
110 GET_CONFIG = 24,
112 SET_CONFIG = 25,
114 CREATE_CRYPTO_SESSION = 26,
116 CLOSE_CRYPTO_SESSION = 27,
118 POSTCOPY_ADVISE = 28,
120 POSTCOPY_LISTEN = 29,
122 POSTCOPY_END = 30,
124 GET_INFLIGHT_FD = 31,
126 SET_INFLIGHT_FD = 32,
128 GPU_SET_SOCKET = 33,
130 RESET_DEVICE = 34,
133 VRING_KICK = 35,
136 GET_MAX_MEM_SLOTS = 36,
138 ADD_MEM_REG = 37,
140 REM_MEM_REG = 38,
142 SET_STATUS = 39,
145 GET_STATUS = 40,
148 SET_DEVICE_STATE_FD = 42,
151 CHECK_DEVICE_STATE = 43,
154
155 GET_SHARED_MEMORY_REGIONS = 1004,
158}
159
160impl From<FrontendReq> for u32 {
161 fn from(req: FrontendReq) -> u32 {
162 req as u32
163 }
164}
165
166impl Req for FrontendReq {}
167
168impl TryFrom<u32> for FrontendReq {
169 type Error = ReqError;
170
171 fn try_from(value: u32) -> Result<Self, Self::Error> {
172 FrontendReq::n(value).ok_or(ReqError::InvalidValue(value))
173 }
174}
175
176#[repr(u32)]
182#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, enumn::N)]
183pub enum BackendReq {
184 IOTLB_MSG = 1,
186 CONFIG_CHANGE_MSG = 2,
188 VRING_HOST_NOTIFIER_MSG = 3,
190 VRING_CALL = 4,
192 VRING_ERR = 5,
194
195 SHMEM_MAP = 1000,
198 SHMEM_UNMAP = 1001,
200 DEPRECATED__FS_MAP = 1002,
202 DEPRECATED__FS_UNMAP = 1003,
204 DEPRECATED__FS_SYNC = 1004,
206 DEPRECATED__FS_IO = 1005,
208 GPU_MAP = 1006,
210 EXTERNAL_MAP = 1007,
212}
213
214impl From<BackendReq> for u32 {
215 fn from(req: BackendReq) -> u32 {
216 req as u32
217 }
218}
219
220impl Req for BackendReq {}
221
222impl TryFrom<u32> for BackendReq {
223 type Error = ReqError;
224
225 fn try_from(value: u32) -> Result<Self, Self::Error> {
226 BackendReq::n(value).ok_or(ReqError::InvalidValue(value))
227 }
228}
229
230pub trait VhostUserMsgValidator {
232 fn is_valid(&self) -> bool {
236 true
237 }
238}
239
240bitflags! {
242 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
244 #[repr(transparent)]
245 pub struct VhostUserHeaderFlag: u32 {
246 const VERSION = 0x3;
248 const REPLY = 0x4;
250 const NEED_REPLY = 0x8;
252 const ALL_FLAGS = 0xc;
254 const RESERVED_BITS = !0xf;
256 }
257}
258
259#[repr(C, packed)]
263#[derive(Copy)]
264pub struct VhostUserMsgHeader<R: Req> {
265 request: u32,
266 flags: u32,
267 size: u32,
268 _r: PhantomData<R>,
269}
270
271impl<R: Req> Debug for VhostUserMsgHeader<R> {
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 f.debug_struct("VhostUserMsgHeader")
274 .field("request", &{ self.request })
275 .field("flags", &{ self.flags })
276 .field("size", &{ self.size })
277 .finish()
278 }
279}
280
281impl<R: Req> Clone for VhostUserMsgHeader<R> {
282 fn clone(&self) -> VhostUserMsgHeader<R> {
283 *self
284 }
285}
286
287impl<R: Req> PartialEq for VhostUserMsgHeader<R> {
288 fn eq(&self, other: &Self) -> bool {
289 self.request == other.request && self.flags == other.flags && self.size == other.size
290 }
291}
292
293impl<R: Req> VhostUserMsgHeader<R> {
294 pub fn new(request: R, flags: u32, size: u32) -> Self {
296 let fl = (flags & VhostUserHeaderFlag::ALL_FLAGS.bits()) | 0x1;
298 VhostUserMsgHeader {
299 request: request.into(),
300 flags: fl,
301 size,
302 _r: PhantomData,
303 }
304 }
305
306 pub fn into_raw(self) -> [u32; 3] {
307 [self.request, self.flags, self.size]
308 }
309
310 pub fn from_raw(raw: [u32; 3]) -> Self {
311 Self {
312 request: raw[0],
313 flags: raw[1],
314 size: raw[2],
315 _r: PhantomData,
316 }
317 }
318
319 pub fn get_code(&self) -> std::result::Result<R, R::Error> {
321 R::try_from(self.request)
322 }
323
324 pub fn set_code(&mut self, request: R) {
326 self.request = request.into();
327 }
328
329 pub fn get_version(&self) -> u32 {
331 self.flags & 0x3
332 }
333
334 pub fn set_version(&mut self, ver: u32) {
336 self.flags &= !0x3;
337 self.flags |= ver & 0x3;
338 }
339
340 pub fn is_reply(&self) -> bool {
342 (self.flags & VhostUserHeaderFlag::REPLY.bits()) != 0
343 }
344
345 pub fn set_reply(&mut self, is_reply: bool) {
347 if is_reply {
348 self.flags |= VhostUserHeaderFlag::REPLY.bits();
349 } else {
350 self.flags &= !VhostUserHeaderFlag::REPLY.bits();
351 }
352 }
353
354 pub fn is_need_reply(&self) -> bool {
356 (self.flags & VhostUserHeaderFlag::NEED_REPLY.bits()) != 0
357 }
358
359 pub fn set_need_reply(&mut self, need_reply: bool) {
361 if need_reply {
362 self.flags |= VhostUserHeaderFlag::NEED_REPLY.bits();
363 } else {
364 self.flags &= !VhostUserHeaderFlag::NEED_REPLY.bits();
365 }
366 }
367
368 pub fn is_reply_for(&self, req: &VhostUserMsgHeader<R>) -> bool {
370 self.is_reply() && !req.is_reply() && self.request == req.request
371 }
372
373 pub fn get_size(&self) -> u32 {
375 self.size
376 }
377
378 pub fn set_size(&mut self, size: u32) {
380 self.size = size;
381 }
382}
383
384impl<R: Req> Default for VhostUserMsgHeader<R> {
385 fn default() -> Self {
386 VhostUserMsgHeader {
387 request: 0,
388 flags: 0x1,
389 size: 0,
390 _r: PhantomData,
391 }
392 }
393}
394
395impl<T: Req> VhostUserMsgValidator for VhostUserMsgHeader<T> {
396 #[allow(clippy::if_same_then_else)]
397 fn is_valid(&self) -> bool {
398 if self.get_code().is_err() {
399 return false;
400 } else if self.get_version() != 0x1 {
401 return false;
402 } else if (self.flags & VhostUserHeaderFlag::RESERVED_BITS.bits()) != 0 {
403 return false;
404 }
405 true
406 }
407}
408
409pub const VIRTIO_F_RING_PACKED: u32 = 34;
410
411pub const VHOST_USER_F_PROTOCOL_FEATURES: u32 = 30;
413
414bitflags! {
416 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
418 #[repr(transparent)]
419 pub struct VhostUserProtocolFeatures: u64 {
420 const MQ = 0x0000_0001;
422 const LOG_SHMFD = 0x0000_0002;
424 const RARP = 0x0000_0004;
426 const REPLY_ACK = 0x0000_0008;
428 const MTU = 0x0000_0010;
430 const BACKEND_REQ = 0x0000_0020;
432 const CROSS_ENDIAN = 0x0000_0040;
434 const CRYPTO_SESSION = 0x0000_0080;
436 const PAGEFAULT = 0x0000_0100;
438 const CONFIG = 0x0000_0200;
440 const BACKEND_SEND_FD = 0x0000_0400;
442 const HOST_NOTIFIER = 0x0000_0800;
444 const INFLIGHT_SHMFD = 0x0000_1000;
446 const RESET_DEVICE = 0x0000_2000;
448 const INBAND_NOTIFICATIONS = 0x0000_4000;
450 const CONFIGURE_MEM_SLOTS = 0x0000_8000;
452 const STATUS = 0x0001_0000;
454 const XEN_MMAP = 0x0002_0000;
456 const DEVICE_STATE = 0x0008_0000;
458 const SHARED_MEMORY_REGIONS = 0x8000_0000;
460 }
461}
462
463#[repr(C, packed)]
465#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
466pub struct VhostUserU64 {
467 pub value: u64,
469}
470
471impl VhostUserU64 {
472 pub fn new(value: u64) -> Self {
474 VhostUserU64 { value }
475 }
476}
477
478impl VhostUserMsgValidator for VhostUserU64 {}
479
480#[repr(C)]
482#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
483pub struct VhostUserEmptyMsg;
484
485impl VhostUserMsgValidator for VhostUserEmptyMsg {}
486
487#[repr(C)]
490#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
491pub struct VhostUserEmptyMessage;
492
493impl VhostUserMsgValidator for VhostUserEmptyMessage {}
494
495#[repr(C, packed)]
497#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
498pub struct VhostUserMemory {
499 pub num_regions: u32,
501 pub padding1: u32,
503}
504
505impl VhostUserMemory {
506 pub fn new(cnt: u32) -> Self {
508 VhostUserMemory {
509 num_regions: cnt,
510 padding1: 0,
511 }
512 }
513}
514
515impl VhostUserMsgValidator for VhostUserMemory {
516 #[allow(clippy::if_same_then_else)]
517 fn is_valid(&self) -> bool {
518 if self.padding1 != 0 {
519 return false;
520 } else if self.num_regions == 0 || self.num_regions > MAX_ATTACHED_FD_ENTRIES as u32 {
521 return false;
522 }
523 true
524 }
525}
526
527#[repr(C, packed)]
529#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
530pub struct VhostUserMemoryRegion {
531 pub guest_phys_addr: u64,
533 pub memory_size: u64,
535 pub user_addr: u64,
537 pub mmap_offset: u64,
539}
540
541impl VhostUserMemoryRegion {
542 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self {
544 VhostUserMemoryRegion {
545 guest_phys_addr,
546 memory_size,
547 user_addr,
548 mmap_offset,
549 }
550 }
551}
552
553impl VhostUserMsgValidator for VhostUserMemoryRegion {
554 fn is_valid(&self) -> bool {
555 if self.memory_size == 0
556 || self.guest_phys_addr.checked_add(self.memory_size).is_none()
557 || self.user_addr.checked_add(self.memory_size).is_none()
558 || self.mmap_offset.checked_add(self.memory_size).is_none()
559 {
560 return false;
561 }
562 true
563 }
564}
565
566pub type VhostUserMemoryPayload = Vec<VhostUserMemoryRegion>;
568
569#[repr(C)]
572#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
573pub struct VhostUserSingleMemoryRegion {
574 padding: u64,
576 pub guest_phys_addr: u64,
578 pub memory_size: u64,
580 pub user_addr: u64,
582 pub mmap_offset: u64,
584}
585
586impl VhostUserSingleMemoryRegion {
587 pub fn new(guest_phys_addr: u64, memory_size: u64, user_addr: u64, mmap_offset: u64) -> Self {
589 VhostUserSingleMemoryRegion {
590 padding: 0,
591 guest_phys_addr,
592 memory_size,
593 user_addr,
594 mmap_offset,
595 }
596 }
597}
598
599impl VhostUserMsgValidator for VhostUserSingleMemoryRegion {
600 fn is_valid(&self) -> bool {
601 if self.memory_size == 0
602 || self.guest_phys_addr.checked_add(self.memory_size).is_none()
603 || self.user_addr.checked_add(self.memory_size).is_none()
604 || self.mmap_offset.checked_add(self.memory_size).is_none()
605 {
606 return false;
607 }
608 true
609 }
610}
611
612#[repr(C, packed)]
614#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
615pub struct VhostUserVringState {
616 pub index: u32,
618 pub num: u32,
620}
621
622impl VhostUserVringState {
623 pub fn new(index: u32, num: u32) -> Self {
625 VhostUserVringState { index, num }
626 }
627}
628
629impl VhostUserMsgValidator for VhostUserVringState {}
630
631bitflags! {
633 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
635 #[repr(transparent)]
636 pub struct VhostUserVringAddrFlags: u32 {
637 const VHOST_VRING_F_LOG = 0x1;
640 }
641}
642
643#[repr(C, packed)]
645#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
646pub struct VhostUserVringAddr {
647 pub index: u32,
649 pub flags: u32,
651 pub descriptor: u64,
653 pub used: u64,
655 pub available: u64,
657 pub log: u64,
659}
660
661impl VhostUserVringAddr {
662 pub fn new(
664 index: u32,
665 flags: VhostUserVringAddrFlags,
666 descriptor: u64,
667 used: u64,
668 available: u64,
669 log: u64,
670 ) -> Self {
671 VhostUserVringAddr {
672 index,
673 flags: flags.bits(),
674 descriptor,
675 used,
676 available,
677 log,
678 }
679 }
680
681 pub fn from_config_data(index: u32, config_data: &VringConfigData) -> Self {
683 let log_addr = config_data.log_addr.unwrap_or(0);
684 VhostUserVringAddr {
685 index,
686 flags: config_data.flags,
687 descriptor: config_data.desc_table_addr,
688 used: config_data.used_ring_addr,
689 available: config_data.avail_ring_addr,
690 log: log_addr,
691 }
692 }
693}
694
695impl VhostUserMsgValidator for VhostUserVringAddr {
696 #[allow(clippy::if_same_then_else)]
697 fn is_valid(&self) -> bool {
698 if (self.flags & !VhostUserVringAddrFlags::all().bits()) != 0 {
699 return false;
700 } else if self.descriptor & 0xf != 0 {
701 return false;
702 } else if self.available & 0x1 != 0 {
703 return false;
704 } else if self.used & 0x3 != 0 {
705 return false;
706 }
707 true
708 }
709}
710
711bitflags! {
713 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
715 #[repr(transparent)]
716 pub struct VhostUserConfigFlags: u32 {
717 const WRITABLE = 0x1;
719 const LIVE_MIGRATION = 0x2;
721 }
722}
723
724#[repr(C, packed)]
726#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
727pub struct VhostUserConfig {
728 pub offset: u32,
730 pub size: u32,
732 pub flags: u32,
734}
735
736impl VhostUserConfig {
737 pub fn new(offset: u32, size: u32, flags: VhostUserConfigFlags) -> Self {
739 VhostUserConfig {
740 offset,
741 size,
742 flags: flags.bits(),
743 }
744 }
745}
746
747impl VhostUserMsgValidator for VhostUserConfig {
748 #[allow(clippy::if_same_then_else)]
749 fn is_valid(&self) -> bool {
750 let end_addr = match self.size.checked_add(self.offset) {
751 Some(addr) => addr,
752 None => return false,
753 };
754 if (self.flags & !VhostUserConfigFlags::all().bits()) != 0 {
755 return false;
756 } else if self.size == 0 || end_addr > VHOST_USER_CONFIG_SIZE {
757 return false;
758 }
759 true
760 }
761}
762
763pub type VhostUserConfigPayload = Vec<u8>;
765
766#[repr(C)]
772#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
773pub struct VhostUserInflight {
774 pub mmap_size: u64,
776 pub mmap_offset: u64,
778 pub num_queues: u16,
780 pub queue_size: u16,
782 pub _padding: [u8; 4],
784}
785
786impl VhostUserInflight {
787 pub fn new(mmap_size: u64, mmap_offset: u64, num_queues: u16, queue_size: u16) -> Self {
789 VhostUserInflight {
790 mmap_size,
791 mmap_offset,
792 num_queues,
793 queue_size,
794 ..Default::default()
795 }
796 }
797}
798
799impl VhostUserMsgValidator for VhostUserInflight {
800 fn is_valid(&self) -> bool {
801 if self.num_queues == 0 || self.queue_size == 0 {
802 return false;
803 }
804 true
805 }
806}
807
808#[repr(C)]
810#[derive(Default, Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
811pub struct DeviceStateTransferParameters {
812 pub transfer_direction: u32,
814 pub migration_phase: u32,
816}
817
818impl VhostUserMsgValidator for DeviceStateTransferParameters {
819 fn is_valid(&self) -> bool {
820 true
822 }
823}
824
825#[repr(transparent)]
853#[derive(
854 FromBytes,
855 Immutable,
856 IntoBytes,
857 KnownLayout,
858 Copy,
859 Clone,
860 Debug,
861 Default,
862 Eq,
863 Hash,
864 Ord,
865 PartialEq,
866 PartialOrd,
867)]
868pub struct VhostUserShmemMapMsgFlags(u8);
869
870bitflags! {
871 impl VhostUserShmemMapMsgFlags: u8 {
872 const EMPTY = 0x0;
874 const MAP_R = 0x1;
876 const MAP_W = 0x2;
878 }
879}
880
881impl From<Protection> for VhostUserShmemMapMsgFlags {
882 fn from(prot: Protection) -> Self {
883 let mut flags = Self::EMPTY;
884 flags.set(Self::MAP_R, prot.allows(&Protection::read()));
885 flags.set(Self::MAP_W, prot.allows(&Protection::write()));
886 flags
887 }
888}
889
890impl From<VhostUserShmemMapMsgFlags> for Protection {
891 fn from(flags: VhostUserShmemMapMsgFlags) -> Self {
892 let mut prot = Protection::default();
893 if flags.contains(VhostUserShmemMapMsgFlags::MAP_R) {
894 prot = prot.set_read();
895 }
896 if flags.contains(VhostUserShmemMapMsgFlags::MAP_W) {
897 prot = prot.set_write();
898 }
899 prot
900 }
901}
902
903#[repr(C, packed)]
905#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
906pub struct VhostUserShmemMapMsg {
907 pub flags: VhostUserShmemMapMsgFlags,
909 pub shmid: u8,
911 padding: [u8; 6],
912 pub shm_offset: u64,
914 pub fd_offset: u64,
916 pub len: u64,
918}
919
920impl VhostUserMsgValidator for VhostUserShmemMapMsg {
921 fn is_valid(&self) -> bool {
922 (self.flags.bits() & !VhostUserShmemMapMsgFlags::all().bits()) == 0
923 && self.fd_offset.checked_add(self.len).is_some()
924 && self.shm_offset.checked_add(self.len).is_some()
925 }
926}
927
928impl VhostUserShmemMapMsg {
929 pub fn new(
931 shmid: u8,
932 shm_offset: u64,
933 fd_offset: u64,
934 len: u64,
935 flags: VhostUserShmemMapMsgFlags,
936 ) -> Self {
937 Self {
938 flags,
939 shmid,
940 padding: [0; 6],
941 shm_offset,
942 fd_offset,
943 len,
944 }
945 }
946}
947
948#[repr(C, packed)]
950#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
951pub struct VhostUserGpuMapMsg {
952 pub shmid: u8,
954 padding: [u8; 7],
955 pub shm_offset: u64,
957 pub len: u64,
959 pub memory_idx: u32,
961 pub handle_type: u32,
963 pub device_uuid: [u8; 16],
965 pub driver_uuid: [u8; 16],
967}
968
969impl VhostUserMsgValidator for VhostUserGpuMapMsg {
970 fn is_valid(&self) -> bool {
971 self.len > 0
972 }
973}
974
975impl VhostUserGpuMapMsg {
976 pub fn new(
978 shmid: u8,
979 shm_offset: u64,
980 len: u64,
981 memory_idx: u32,
982 handle_type: u32,
983 device_uuid: [u8; 16],
984 driver_uuid: [u8; 16],
985 ) -> Self {
986 Self {
987 shmid,
988 padding: [0; 7],
989 shm_offset,
990 len,
991 memory_idx,
992 handle_type,
993 device_uuid,
994 driver_uuid,
995 }
996 }
997}
998
999#[repr(C, packed)]
1001#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
1002pub struct VhostUserExternalMapMsg {
1003 pub shmid: u8,
1005 padding: [u8; 7],
1006 pub shm_offset: u64,
1008 pub len: u64,
1010 pub ptr: u64,
1012}
1013
1014impl VhostUserMsgValidator for VhostUserExternalMapMsg {
1015 fn is_valid(&self) -> bool {
1016 self.len > 0
1017 }
1018}
1019
1020impl VhostUserExternalMapMsg {
1021 pub fn new(shmid: u8, shm_offset: u64, len: u64, ptr: u64) -> Self {
1023 Self {
1024 shmid,
1025 padding: [0; 7],
1026 shm_offset,
1027 len,
1028 ptr,
1029 }
1030 }
1031}
1032
1033#[repr(C, packed)]
1035#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
1036pub struct VhostUserShmemUnmapMsg {
1037 pub shmid: u8,
1039 padding: [u8; 7],
1040 pub shm_offset: u64,
1042 pub len: u64,
1044}
1045
1046impl VhostUserMsgValidator for VhostUserShmemUnmapMsg {
1047 fn is_valid(&self) -> bool {
1048 self.shm_offset.checked_add(self.len).is_some()
1049 }
1050}
1051
1052impl VhostUserShmemUnmapMsg {
1053 pub fn new(shmid: u8, shm_offset: u64, len: u64) -> Self {
1055 Self {
1056 shmid,
1057 padding: [0; 7],
1058 shm_offset,
1059 len,
1060 }
1061 }
1062}
1063
1064#[repr(C, packed)]
1066#[derive(Clone, Copy, Default)]
1067pub struct DescStateSplit {
1068 pub inflight: u8,
1070 padding: [u8; 5],
1072 pub next: u16,
1074 pub counter: u64,
1076}
1077
1078impl DescStateSplit {
1079 pub fn new() -> Self {
1081 Self::default()
1082 }
1083}
1084
1085#[repr(C, packed)]
1087pub struct QueueRegionSplit {
1088 pub features: u64,
1090 pub version: u16,
1092 pub desc_num: u16,
1094 pub last_batch_head: u16,
1096 pub used_idx: u16,
1098 pub desc: u64,
1100}
1101
1102impl QueueRegionSplit {
1103 pub fn new(features: u64, queue_size: u16) -> Self {
1105 QueueRegionSplit {
1106 features,
1107 version: 1,
1108 desc_num: queue_size,
1109 last_batch_head: 0,
1110 used_idx: 0,
1111 desc: 0,
1112 }
1113 }
1114}
1115
1116#[repr(C, packed)]
1118#[derive(Clone, Copy, Default)]
1119pub struct DescStatePacked {
1120 pub inflight: u8,
1122 padding: u8,
1124 pub next: u16,
1126 pub last: u16,
1128 pub num: u16,
1130 pub counter: u64,
1132 pub id: u16,
1134 pub flags: u16,
1136 pub len: u32,
1138 pub addr: u64,
1140}
1141
1142impl DescStatePacked {
1143 pub fn new() -> Self {
1145 Self::default()
1146 }
1147}
1148
1149#[repr(C, packed)]
1151pub struct QueueRegionPacked {
1152 pub features: u64,
1154 pub version: u16,
1156 pub desc_num: u16,
1158 pub free_head: u16,
1160 pub old_free_head: u16,
1162 pub used_idx: u16,
1164 pub old_used_idx: u16,
1166 pub used_wrap_counter: u8,
1168 pub old_used_wrap_counter: u8,
1170 padding: [u8; 7],
1172 pub desc: u64,
1174}
1175
1176impl QueueRegionPacked {
1177 pub fn new(features: u64, queue_size: u16) -> Self {
1179 QueueRegionPacked {
1180 features,
1181 version: 1,
1182 desc_num: queue_size,
1183 free_head: 0,
1184 old_free_head: 0,
1185 used_idx: 0,
1186 old_used_idx: 0,
1187 used_wrap_counter: 0,
1188 old_used_wrap_counter: 0,
1189 padding: [0; 7],
1190 desc: 0,
1191 }
1192 }
1193}
1194
1195#[repr(C, packed)]
1197#[derive(Default, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
1198pub struct VhostSharedMemoryRegion {
1199 pub id: u8,
1201 padding: [u8; 7],
1203 pub length: u64,
1205}
1206
1207impl VhostSharedMemoryRegion {
1208 pub fn new(id: u8, length: u64) -> Self {
1210 VhostSharedMemoryRegion {
1211 id,
1212 padding: [0; 7],
1213 length,
1214 }
1215 }
1216}
1217
1218#[derive(Debug, PartialEq, Eq)]
1219pub enum VhostUserTransferDirection {
1220 Save,
1221 Load,
1222}
1223
1224#[derive(Debug, PartialEq, Eq)]
1225pub enum VhostUserMigrationPhase {
1226 Stopped,
1227}
1228
1229#[cfg(test)]
1230mod tests {
1231 use super::*;
1232
1233 #[test]
1234 fn check_frontend_request_code() {
1235 FrontendReq::try_from(0).expect_err("invalid value");
1236 FrontendReq::try_from(46).expect_err("invalid value");
1237 FrontendReq::try_from(10000).expect_err("invalid value");
1238
1239 let code = FrontendReq::try_from(FrontendReq::GET_FEATURES as u32).unwrap();
1240 assert_eq!(code, code.clone());
1241 }
1242
1243 #[test]
1244 fn check_backend_request_code() {
1245 BackendReq::try_from(0).expect_err("invalid value");
1246 BackendReq::try_from(14).expect_err("invalid value");
1247 BackendReq::try_from(10000).expect_err("invalid value");
1248
1249 let code = BackendReq::try_from(BackendReq::CONFIG_CHANGE_MSG as u32).unwrap();
1250 assert_eq!(code, code.clone());
1251 }
1252
1253 #[test]
1254 fn msg_header_ops() {
1255 let mut hdr = VhostUserMsgHeader::new(FrontendReq::GET_FEATURES, 0, 0x100);
1256 assert_eq!(hdr.get_code(), Ok(FrontendReq::GET_FEATURES));
1257 hdr.set_code(FrontendReq::SET_FEATURES);
1258 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_FEATURES));
1259
1260 assert_eq!(hdr.get_version(), 0x1);
1261
1262 assert!(!hdr.is_reply());
1263 hdr.set_reply(true);
1264 assert!(hdr.is_reply());
1265 hdr.set_reply(false);
1266
1267 assert!(!hdr.is_need_reply());
1268 hdr.set_need_reply(true);
1269 assert!(hdr.is_need_reply());
1270 hdr.set_need_reply(false);
1271
1272 assert_eq!(hdr.get_size(), 0x100);
1273 hdr.set_size(0x200);
1274 assert_eq!(hdr.get_size(), 0x200);
1275
1276 assert!(!hdr.is_need_reply());
1277 assert!(!hdr.is_reply());
1278 assert_eq!(hdr.get_version(), 0x1);
1279
1280 hdr.set_version(0x0);
1282 assert!(!hdr.is_valid());
1283 hdr.set_version(0x2);
1284 assert!(!hdr.is_valid());
1285 hdr.set_version(0x1);
1286 assert!(hdr.is_valid());
1287
1288 assert_eq!(hdr, hdr.clone());
1290 assert_eq!(hdr.clone().get_code(), hdr.get_code());
1291 assert_eq!(format!("{:?}", hdr.clone()), format!("{:?}", hdr));
1292 }
1293
1294 #[test]
1295 fn test_vhost_user_message_u64() {
1296 let val = VhostUserU64::default();
1297 let val1 = VhostUserU64::new(0);
1298
1299 let a = val.value;
1300 let b = val1.value;
1301 assert_eq!(a, b);
1302 let a = VhostUserU64::new(1).value;
1303 assert_eq!(a, 1);
1304 }
1305
1306 #[test]
1307 fn check_user_memory() {
1308 let mut msg = VhostUserMemory::new(1);
1309 assert!(msg.is_valid());
1310 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32;
1311 assert!(msg.is_valid());
1312
1313 msg.num_regions += 1;
1314 assert!(!msg.is_valid());
1315 msg.num_regions = 0xFFFFFFFF;
1316 assert!(!msg.is_valid());
1317 msg.num_regions = MAX_ATTACHED_FD_ENTRIES as u32;
1318 msg.padding1 = 1;
1319 assert!(!msg.is_valid());
1320 }
1321
1322 #[test]
1323 fn check_user_memory_region() {
1324 let mut msg = VhostUserMemoryRegion {
1325 guest_phys_addr: 0,
1326 memory_size: 0x1000,
1327 user_addr: 0,
1328 mmap_offset: 0,
1329 };
1330 assert!(msg.is_valid());
1331 msg.guest_phys_addr = 0xFFFFFFFFFFFFEFFF;
1332 assert!(msg.is_valid());
1333 msg.guest_phys_addr = 0xFFFFFFFFFFFFF000;
1334 assert!(!msg.is_valid());
1335 msg.guest_phys_addr = 0xFFFFFFFFFFFF0000;
1336 msg.memory_size = 0;
1337 assert!(!msg.is_valid());
1338 let a = msg.guest_phys_addr;
1339 let b = msg.guest_phys_addr;
1340 assert_eq!(a, b);
1341
1342 let msg = VhostUserMemoryRegion::default();
1343 let a = msg.guest_phys_addr;
1344 assert_eq!(a, 0);
1345 let a = msg.memory_size;
1346 assert_eq!(a, 0);
1347 let a = msg.user_addr;
1348 assert_eq!(a, 0);
1349 let a = msg.mmap_offset;
1350 assert_eq!(a, 0);
1351 }
1352
1353 #[test]
1354 fn test_vhost_user_state() {
1355 let state = VhostUserVringState::new(5, 8);
1356
1357 let a = state.index;
1358 assert_eq!(a, 5);
1359 let a = state.num;
1360 assert_eq!(a, 8);
1361 assert!(state.is_valid());
1362
1363 let state = VhostUserVringState::default();
1364 let a = state.index;
1365 assert_eq!(a, 0);
1366 let a = state.num;
1367 assert_eq!(a, 0);
1368 assert!(state.is_valid());
1369 }
1370
1371 #[test]
1372 fn test_vhost_user_addr() {
1373 let mut addr = VhostUserVringAddr::new(
1374 2,
1375 VhostUserVringAddrFlags::VHOST_VRING_F_LOG,
1376 0x1000,
1377 0x2000,
1378 0x3000,
1379 0x4000,
1380 );
1381
1382 let a = addr.index;
1383 assert_eq!(a, 2);
1384 let a = addr.flags;
1385 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits());
1386 let a = addr.descriptor;
1387 assert_eq!(a, 0x1000);
1388 let a = addr.used;
1389 assert_eq!(a, 0x2000);
1390 let a = addr.available;
1391 assert_eq!(a, 0x3000);
1392 let a = addr.log;
1393 assert_eq!(a, 0x4000);
1394 assert!(addr.is_valid());
1395
1396 addr.descriptor = 0x1001;
1397 assert!(!addr.is_valid());
1398 addr.descriptor = 0x1000;
1399
1400 addr.available = 0x3001;
1401 assert!(!addr.is_valid());
1402 addr.available = 0x3000;
1403
1404 addr.used = 0x2001;
1405 assert!(!addr.is_valid());
1406 addr.used = 0x2000;
1407 assert!(addr.is_valid());
1408 }
1409
1410 #[test]
1411 fn test_vhost_user_state_from_config() {
1412 let config = VringConfigData {
1413 queue_size: 128,
1414 flags: VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits(),
1415 desc_table_addr: 0x1000,
1416 used_ring_addr: 0x2000,
1417 avail_ring_addr: 0x3000,
1418 log_addr: Some(0x4000),
1419 };
1420 let addr = VhostUserVringAddr::from_config_data(2, &config);
1421
1422 let a = addr.index;
1423 assert_eq!(a, 2);
1424 let a = addr.flags;
1425 assert_eq!(a, VhostUserVringAddrFlags::VHOST_VRING_F_LOG.bits());
1426 let a = addr.descriptor;
1427 assert_eq!(a, 0x1000);
1428 let a = addr.used;
1429 assert_eq!(a, 0x2000);
1430 let a = addr.available;
1431 assert_eq!(a, 0x3000);
1432 let a = addr.log;
1433 assert_eq!(a, 0x4000);
1434 assert!(addr.is_valid());
1435 }
1436
1437 #[test]
1438 fn check_user_vring_addr() {
1439 let mut msg =
1440 VhostUserVringAddr::new(0, VhostUserVringAddrFlags::all(), 0x0, 0x0, 0x0, 0x0);
1441 assert!(msg.is_valid());
1442
1443 msg.descriptor = 1;
1444 assert!(!msg.is_valid());
1445 msg.descriptor = 0;
1446
1447 msg.available = 1;
1448 assert!(!msg.is_valid());
1449 msg.available = 0;
1450
1451 msg.used = 1;
1452 assert!(!msg.is_valid());
1453 msg.used = 0;
1454
1455 msg.flags |= 0x80000000;
1456 assert!(!msg.is_valid());
1457 msg.flags &= !0x80000000;
1458 }
1459
1460 #[test]
1461 fn check_user_config_msg() {
1462 let mut msg =
1463 VhostUserConfig::new(0, VHOST_USER_CONFIG_SIZE, VhostUserConfigFlags::WRITABLE);
1464
1465 assert!(msg.is_valid());
1466 msg.size = 0;
1467 assert!(!msg.is_valid());
1468 msg.size = 1;
1469 assert!(msg.is_valid());
1470 msg.offset = u32::MAX;
1471 assert!(!msg.is_valid());
1472 msg.offset = VHOST_USER_CONFIG_SIZE;
1473 assert!(!msg.is_valid());
1474 msg.offset = VHOST_USER_CONFIG_SIZE - 1;
1475 assert!(msg.is_valid());
1476 msg.size = 2;
1477 assert!(!msg.is_valid());
1478 msg.size = 1;
1479 msg.flags |= VhostUserConfigFlags::LIVE_MIGRATION.bits();
1480 assert!(msg.is_valid());
1481 msg.flags |= 0x4;
1482 assert!(!msg.is_valid());
1483 }
1484}