1pub mod sys;
48
49use std::collections::BTreeMap;
50use std::convert::From;
51use std::fs::File;
52use std::io::BufReader;
53use std::io::Write;
54use std::num::Wrapping;
55#[cfg(any(target_os = "android", target_os = "linux"))]
56use std::os::unix::io::AsRawFd;
57use std::sync::Arc;
58
59use anyhow::bail;
60use anyhow::Context;
61#[cfg(any(target_os = "android", target_os = "linux"))]
62use base::clear_fd_flags;
63use base::error;
64use base::trace;
65use base::warn;
66use base::Event;
67use base::Protection;
68use base::SafeDescriptor;
69use base::SharedMemory;
70use base::WorkerThread;
71use cros_async::TaskHandle;
72use hypervisor::MemCacheType;
73use serde::Deserialize;
74use serde::Serialize;
75use snapshot::AnySnapshot;
76use sync::Mutex;
77use thiserror::Error as ThisError;
78use vm_control::VmMemorySource;
79use vm_memory::GuestAddress;
80use vm_memory::GuestMemory;
81use vm_memory::MemoryRegion;
82use vmm_vhost::message::VhostUserConfigFlags;
83use vmm_vhost::message::VhostUserExternalMapMsg;
84use vmm_vhost::message::VhostUserGpuMapMsg;
85use vmm_vhost::message::VhostUserInflight;
86use vmm_vhost::message::VhostUserMMap;
87use vmm_vhost::message::VhostUserMMapFlags;
88use vmm_vhost::message::VhostUserMemoryRegion;
89use vmm_vhost::message::VhostUserMigrationPhase;
90use vmm_vhost::message::VhostUserProtocolFeatures;
91use vmm_vhost::message::VhostUserSingleMemoryRegion;
92use vmm_vhost::message::VhostUserTransferDirection;
93use vmm_vhost::message::VhostUserVringAddrFlags;
94use vmm_vhost::message::VhostUserVringState;
95use vmm_vhost::Connection;
96use vmm_vhost::Error as VhostError;
97use vmm_vhost::Frontend;
98use vmm_vhost::FrontendClient;
99use vmm_vhost::Result as VhostResult;
100use vmm_vhost::VHOST_USER_F_PROTOCOL_FEATURES;
101
102use crate::virtio::Interrupt;
103use crate::virtio::Queue;
104use crate::virtio::QueueConfig;
105use crate::virtio::SharedMemoryMapper;
106use crate::virtio::SharedMemoryRegion;
107
108#[derive(Default)]
111pub struct MappingInfo {
112 pub vmm_addr: u64,
113 pub guest_phys: u64,
114 pub size: u64,
115}
116
117pub fn vmm_va_to_gpa(maps: &[MappingInfo], vmm_va: u64) -> VhostResult<GuestAddress> {
118 for map in maps {
119 if vmm_va >= map.vmm_addr && vmm_va < map.vmm_addr + map.size {
120 return Ok(GuestAddress(vmm_va - map.vmm_addr + map.guest_phys));
121 }
122 }
123 Err(VhostError::InvalidMessage)
124}
125
126pub trait VhostUserDevice {
131 fn max_queue_num(&self) -> usize;
133
134 fn features(&self) -> u64;
136
137 fn ack_features(&mut self, _value: u64) -> anyhow::Result<()> {
145 Ok(())
146 }
147
148 fn protocol_features(&self) -> VhostUserProtocolFeatures;
150
151 fn read_config(&self, offset: u64, dst: &mut [u8]);
153
154 fn write_config(&self, _offset: u64, _data: &[u8]) {}
156
157 fn start_queue(&mut self, idx: usize, queue: Queue, mem: GuestMemory) -> anyhow::Result<()>;
161
162 fn stop_queue(&mut self, idx: usize) -> anyhow::Result<Queue>;
166
167 fn reset(&mut self);
169
170 fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
172 None
173 }
174
175 fn set_backend_req_connection(&mut self, _conn: VhostBackendReqConnection) {}
181
182 fn enter_suspended_state(&mut self) -> anyhow::Result<()>;
195
196 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot>;
198
199 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>;
201
202 fn unmap_guest_memory_on_fork(&self) -> bool {
210 false
211 }
212}
213
214impl<T: VhostUserDevice + ?Sized> VhostUserDevice for &mut T {
215 fn max_queue_num(&self) -> usize {
216 (**self).max_queue_num()
217 }
218
219 fn features(&self) -> u64 {
220 (**self).features()
221 }
222
223 fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
224 (**self).ack_features(value)
225 }
226
227 fn protocol_features(&self) -> VhostUserProtocolFeatures {
228 (**self).protocol_features()
229 }
230
231 fn read_config(&self, offset: u64, dst: &mut [u8]) {
232 (**self).read_config(offset, dst)
233 }
234
235 fn write_config(&self, offset: u64, data: &[u8]) {
236 (**self).write_config(offset, data)
237 }
238
239 fn start_queue(&mut self, idx: usize, queue: Queue, mem: GuestMemory) -> anyhow::Result<()> {
240 (**self).start_queue(idx, queue, mem)
241 }
242
243 fn stop_queue(&mut self, idx: usize) -> anyhow::Result<Queue> {
244 (**self).stop_queue(idx)
245 }
246
247 fn reset(&mut self) {
248 (**self).reset()
249 }
250
251 fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
252 (**self).get_shared_memory_region()
253 }
254
255 fn set_backend_req_connection(&mut self, conn: VhostBackendReqConnection) {
256 (**self).set_backend_req_connection(conn)
257 }
258
259 fn enter_suspended_state(&mut self) -> anyhow::Result<()> {
260 (**self).enter_suspended_state()
261 }
262
263 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
264 (**self).snapshot()
265 }
266
267 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
268 (**self).restore(data)
269 }
270
271 fn unmap_guest_memory_on_fork(&self) -> bool {
272 (**self).unmap_guest_memory_on_fork()
273 }
274}
275
276impl<T: VhostUserDevice + ?Sized> VhostUserDevice for Box<T> {
277 fn max_queue_num(&self) -> usize {
278 (**self).max_queue_num()
279 }
280
281 fn features(&self) -> u64 {
282 (**self).features()
283 }
284
285 fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
286 (**self).ack_features(value)
287 }
288
289 fn protocol_features(&self) -> VhostUserProtocolFeatures {
290 (**self).protocol_features()
291 }
292
293 fn read_config(&self, offset: u64, dst: &mut [u8]) {
294 (**self).read_config(offset, dst)
295 }
296
297 fn write_config(&self, offset: u64, data: &[u8]) {
298 (**self).write_config(offset, data)
299 }
300
301 fn start_queue(&mut self, idx: usize, queue: Queue, mem: GuestMemory) -> anyhow::Result<()> {
302 (**self).start_queue(idx, queue, mem)
303 }
304
305 fn stop_queue(&mut self, idx: usize) -> anyhow::Result<Queue> {
306 (**self).stop_queue(idx)
307 }
308
309 fn reset(&mut self) {
310 (**self).reset()
311 }
312
313 fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
314 (**self).get_shared_memory_region()
315 }
316
317 fn set_backend_req_connection(&mut self, conn: VhostBackendReqConnection) {
318 (**self).set_backend_req_connection(conn)
319 }
320
321 fn enter_suspended_state(&mut self) -> anyhow::Result<()> {
322 (**self).enter_suspended_state()
323 }
324
325 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
326 (**self).snapshot()
327 }
328
329 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
330 (**self).restore(data)
331 }
332
333 fn unmap_guest_memory_on_fork(&self) -> bool {
334 (**self).unmap_guest_memory_on_fork()
335 }
336}
337
338struct Vring {
340 queue: QueueConfig,
342 doorbell: Option<Interrupt>,
343 enabled: bool,
344}
345
346impl Vring {
347 fn new(max_size: u16, features: u64) -> Self {
348 Self {
349 queue: QueueConfig::new(max_size, features),
350 doorbell: None,
351 enabled: false,
352 }
353 }
354
355 fn reset(&mut self) {
356 self.queue.reset();
357 self.doorbell = None;
358 self.enabled = false;
359 }
360}
361
362pub(super) struct VhostUserRegularOps;
364
365impl VhostUserRegularOps {
366 pub fn set_mem_table(
367 contexts: &[VhostUserMemoryRegion],
368 files: Vec<File>,
369 ) -> VhostResult<(GuestMemory, Vec<MappingInfo>)> {
370 if files.len() != contexts.len() {
371 return Err(VhostError::InvalidParam(
372 "number of files & contexts was not equal",
373 ));
374 }
375
376 let mut regions = Vec::with_capacity(files.len());
377 for (region, file) in contexts.iter().zip(files.into_iter()) {
378 let region = MemoryRegion::new_from_shm(
379 region.memory_size,
380 GuestAddress(region.guest_phys_addr),
381 region.mmap_offset,
382 Arc::new(
383 SharedMemory::from_safe_descriptor(
384 SafeDescriptor::from(file),
385 region.memory_size,
386 )
387 .unwrap(),
388 ),
389 )
390 .map_err(|e| {
391 error!("failed to create a memory region: {}", e);
392 VhostError::InvalidOperation
393 })?;
394 regions.push(region);
395 }
396 let guest_mem = GuestMemory::from_regions(regions).map_err(|e| {
397 error!("failed to create guest memory: {}", e);
398 VhostError::InvalidOperation
399 })?;
400
401 let vmm_maps = contexts
402 .iter()
403 .map(|region| MappingInfo {
404 vmm_addr: region.user_addr,
405 guest_phys: region.guest_phys_addr,
406 size: region.memory_size,
407 })
408 .collect();
409 Ok((guest_mem, vmm_maps))
410 }
411}
412
413pub struct DeviceRequestHandler<T: VhostUserDevice> {
415 vrings: Vec<Vring>,
416 owned: bool,
417 vmm_maps: Option<Vec<MappingInfo>>,
418 mem: Option<GuestMemory>,
419 acked_features: u64,
420 acked_protocol_features: VhostUserProtocolFeatures,
421 backend: T,
422 backend_req_connection: Option<VhostBackendReqConnection>,
423 device_state_thread: Option<DeviceStateThread>,
425}
426
427enum DeviceStateThread {
428 Save(WorkerThread<Result<(), ciborium::ser::Error<std::io::Error>>>),
429 Load(WorkerThread<Result<DeviceRequestHandlerSnapshot, ciborium::de::Error<std::io::Error>>>),
430}
431
432#[derive(Serialize, Deserialize)]
433pub struct DeviceRequestHandlerSnapshot {
434 acked_features: u64,
435 acked_protocol_features: u64,
436 backend: AnySnapshot,
437}
438
439impl<T: VhostUserDevice> DeviceRequestHandler<T> {
440 pub fn new(mut backend: T) -> Self {
442 let mut vrings = Vec::with_capacity(backend.max_queue_num());
443 for _ in 0..backend.max_queue_num() {
444 vrings.push(Vring::new(Queue::MAX_SIZE, backend.features()));
445 }
446
447 backend
450 .enter_suspended_state()
451 .expect("enter_suspended_state failed on device init");
452
453 DeviceRequestHandler {
454 vrings,
455 owned: false,
456 vmm_maps: None,
457 mem: None,
458 acked_features: 0,
459 acked_protocol_features: VhostUserProtocolFeatures::empty(),
460 backend,
461 backend_req_connection: None,
462 device_state_thread: None,
463 }
464 }
465
466 fn all_queues_stopped(&self) -> bool {
470 self.vrings.iter().all(|vring| !vring.queue.ready())
471 }
472}
473
474impl<T: VhostUserDevice> Drop for DeviceRequestHandler<T> {
475 fn drop(&mut self) {
476 for (index, vring) in self.vrings.iter().enumerate() {
477 if vring.queue.ready() {
478 if let Err(e) = self.backend.stop_queue(index) {
479 error!("Failed to stop queue {} during drop: {:#}", index, e);
480 }
481 }
482 }
483 }
484}
485
486impl<T: VhostUserDevice> AsRef<T> for DeviceRequestHandler<T> {
487 fn as_ref(&self) -> &T {
488 &self.backend
489 }
490}
491
492impl<T: VhostUserDevice> AsMut<T> for DeviceRequestHandler<T> {
493 fn as_mut(&mut self) -> &mut T {
494 &mut self.backend
495 }
496}
497
498impl<T: VhostUserDevice> vmm_vhost::Backend for DeviceRequestHandler<T> {
499 fn set_owner(&mut self) -> VhostResult<()> {
500 if self.owned {
501 return Err(VhostError::InvalidOperation);
502 }
503 self.owned = true;
504 Ok(())
505 }
506
507 fn reset_owner(&mut self) -> VhostResult<()> {
508 self.owned = false;
509 self.acked_features = 0;
510 self.backend.reset();
511 Ok(())
512 }
513
514 fn get_features(&mut self) -> VhostResult<u64> {
515 let features = self.backend.features();
516 Ok(features)
517 }
518
519 fn set_features(&mut self, features: u64) -> VhostResult<()> {
520 if !self.owned {
521 return Err(VhostError::InvalidOperation);
522 }
523
524 let unexpected_features = features & !self.backend.features();
525 if unexpected_features != 0 {
526 error!("unexpected set_features {:#x}", unexpected_features);
527 return Err(VhostError::InvalidParam("unexpected set_features"));
528 }
529
530 if let Err(e) = self.backend.ack_features(features) {
531 error!("failed to acknowledge features 0x{:x}: {}", features, e);
532 return Err(VhostError::InvalidOperation);
533 }
534
535 self.acked_features |= features;
536
537 let vring_enabled = self.acked_features & 1 << VHOST_USER_F_PROTOCOL_FEATURES != 0;
545 for v in &mut self.vrings {
546 v.enabled = vring_enabled;
547 }
548
549 Ok(())
550 }
551
552 fn get_protocol_features(&mut self) -> VhostResult<VhostUserProtocolFeatures> {
553 Ok(self.backend.protocol_features() | VhostUserProtocolFeatures::REPLY_ACK)
554 }
555
556 fn set_protocol_features(&mut self, features: u64) -> VhostResult<()> {
557 let features = match VhostUserProtocolFeatures::from_bits(features) {
558 Some(proto_features) => proto_features,
559 None => {
560 error!(
561 "unsupported bits in VHOST_USER_SET_PROTOCOL_FEATURES: {:#x}",
562 features
563 );
564 return Err(VhostError::InvalidOperation);
565 }
566 };
567 let supported = self.get_protocol_features()?;
568 self.acked_protocol_features = features & supported;
569 Ok(())
570 }
571
572 fn set_mem_table(
573 &mut self,
574 contexts: &[VhostUserMemoryRegion],
575 files: Vec<File>,
576 ) -> VhostResult<()> {
577 let (guest_mem, vmm_maps) = VhostUserRegularOps::set_mem_table(contexts, files)?;
578 if self.backend.unmap_guest_memory_on_fork() {
579 #[cfg(any(target_os = "android", target_os = "linux"))]
580 if let Err(e) = guest_mem.use_dontfork() {
581 error!("failed to set MADV_DONTFORK on guest memory: {e:#}");
582 }
583 #[cfg(not(any(target_os = "android", target_os = "linux")))]
584 error!("unmap_guest_memory_on_fork unsupported; skipping");
585 }
586 self.mem = Some(guest_mem);
587 self.vmm_maps = Some(vmm_maps);
588 Ok(())
589 }
590
591 fn get_queue_num(&mut self) -> VhostResult<u64> {
592 Ok(self.vrings.len() as u64)
593 }
594
595 fn set_vring_num(&mut self, index: u32, num: u32) -> VhostResult<()> {
596 if index as usize >= self.vrings.len() || num == 0 || num > Queue::MAX_SIZE.into() {
597 return Err(VhostError::InvalidParam(
598 "set_vring_num: invalid index or num",
599 ));
600 }
601 self.vrings[index as usize].queue.set_size(num as u16);
602
603 Ok(())
604 }
605
606 fn set_vring_addr(
607 &mut self,
608 index: u32,
609 _flags: VhostUserVringAddrFlags,
610 descriptor: u64,
611 used: u64,
612 available: u64,
613 _log: u64,
614 ) -> VhostResult<()> {
615 if index as usize >= self.vrings.len() {
616 return Err(VhostError::InvalidParam(
617 "set_vring_addr: index out of range",
618 ));
619 }
620
621 let vmm_maps = self
622 .vmm_maps
623 .as_ref()
624 .ok_or(VhostError::InvalidParam("set_vring_addr: missing vmm_maps"))?;
625 let vring = &mut self.vrings[index as usize];
626 vring
627 .queue
628 .set_desc_table(vmm_va_to_gpa(vmm_maps, descriptor)?);
629 vring
630 .queue
631 .set_avail_ring(vmm_va_to_gpa(vmm_maps, available)?);
632 vring.queue.set_used_ring(vmm_va_to_gpa(vmm_maps, used)?);
633
634 Ok(())
635 }
636
637 fn set_vring_base(&mut self, index: u32, base: u32) -> VhostResult<()> {
638 if index as usize >= self.vrings.len() {
639 return Err(VhostError::InvalidParam(
640 "set_vring_base: index out of range",
641 ));
642 }
643
644 let vring = &mut self.vrings[index as usize];
645 vring.queue.set_next_avail(Wrapping(base as u16));
646 vring.queue.set_next_used(Wrapping(base as u16));
647
648 Ok(())
649 }
650
651 fn get_vring_base(&mut self, index: u32) -> VhostResult<VhostUserVringState> {
652 let vring = self
653 .vrings
654 .get_mut(index as usize)
655 .ok_or(VhostError::InvalidParam(
656 "get_vring_base: index out of range",
657 ))?;
658
659 let vring_base = if vring.queue.ready() {
664 let queue = match self.backend.stop_queue(index as usize) {
665 Ok(q) => q,
666 Err(e) => {
667 error!("Failed to stop queue in get_vring_base: {:#}", e);
668 return Err(VhostError::BackendInternalError);
669 }
670 };
671
672 trace!("stopped queue {index}");
673 vring.reset();
674
675 if self.all_queues_stopped() {
676 trace!("all queues stopped; entering suspended state");
677 self.backend
678 .enter_suspended_state()
679 .map_err(VhostError::EnterSuspendedState)?;
680 }
681
682 queue.next_avail_to_process()
683 } else {
684 0
685 };
686
687 Ok(VhostUserVringState::new(index, vring_base.into()))
688 }
689
690 fn set_vring_kick(&mut self, index: u8, file: Option<File>) -> VhostResult<()> {
691 if index as usize >= self.vrings.len() {
692 return Err(VhostError::InvalidParam(
693 "set_vring_kick: index out of range",
694 ));
695 }
696
697 let vring = &mut self.vrings[index as usize];
698 if vring.queue.ready() {
699 error!("kick fd cannot replaced after queue is started");
700 return Err(VhostError::InvalidOperation);
701 }
702
703 let file = file.ok_or(VhostError::InvalidParam("missing file for set_vring_kick"))?;
704
705 #[cfg(any(target_os = "android", target_os = "linux"))]
709 if let Err(e) = clear_fd_flags(file.as_raw_fd(), libc::O_NONBLOCK) {
710 error!("failed to remove O_NONBLOCK for kick fd: {}", e);
711 return Err(VhostError::InvalidParam(
712 "could not remove O_NONBLOCK from vring_kick",
713 ));
714 }
715
716 let kick_evt = Event::from(SafeDescriptor::from(file));
717
718 vring.queue.ack_features(self.acked_features);
720 vring.queue.set_ready(true);
721
722 let mem = self
723 .mem
724 .as_ref()
725 .cloned()
726 .ok_or(VhostError::InvalidOperation)?;
727
728 let doorbell = vring.doorbell.clone().ok_or(VhostError::InvalidOperation)?;
729
730 let queue = match vring.queue.activate(&mem, kick_evt, doorbell) {
731 Ok(queue) => queue,
732 Err(e) => {
733 error!("failed to activate vring: {:#}", e);
734 return Err(VhostError::BackendInternalError);
735 }
736 };
737
738 if let Err(e) = self.backend.start_queue(index as usize, queue, mem) {
739 error!("Failed to start queue {}: {}", index, e);
740 return Err(VhostError::BackendInternalError);
741 }
742 trace!("started queue {index}");
743
744 Ok(())
745 }
746
747 fn set_vring_call(&mut self, index: u8, file: Option<File>) -> VhostResult<()> {
748 if index as usize >= self.vrings.len() {
749 return Err(VhostError::InvalidParam(
750 "set_vring_call: index out of range",
751 ));
752 }
753
754 let backend_req_conn = self.backend_req_connection.clone();
755 let signal_config_change_fn = Box::new(move || {
756 if let Some(frontend) = backend_req_conn.as_ref() {
757 if let Err(e) = frontend.send_config_changed() {
758 error!("Failed to notify config change: {:#}", e);
759 }
760 } else {
761 error!("No Backend request connection found");
762 }
763 });
764
765 let file = file.ok_or(VhostError::InvalidParam("missing file for set_vring_call"))?;
766 self.vrings[index as usize].doorbell = Some(Interrupt::new_vhost_user(
767 Event::from(SafeDescriptor::from(file)),
768 signal_config_change_fn,
769 ));
770 Ok(())
771 }
772
773 fn set_vring_err(&mut self, _index: u8, _fd: Option<File>) -> VhostResult<()> {
774 Ok(())
776 }
777
778 fn set_vring_enable(&mut self, index: u32, enable: bool) -> VhostResult<()> {
779 if index as usize >= self.vrings.len() {
780 return Err(VhostError::InvalidParam(
781 "set_vring_enable: index out of range",
782 ));
783 }
784
785 if self.acked_features & 1 << VHOST_USER_F_PROTOCOL_FEATURES == 0 {
788 return Err(VhostError::InvalidOperation);
789 }
790
791 self.vrings[index as usize].enabled = enable;
795
796 Ok(())
797 }
798
799 fn get_config(
800 &mut self,
801 offset: u32,
802 size: u32,
803 _flags: VhostUserConfigFlags,
804 ) -> VhostResult<Vec<u8>> {
805 let mut data = vec![0; size as usize];
806 self.backend.read_config(u64::from(offset), &mut data);
807 Ok(data)
808 }
809
810 fn set_config(
811 &mut self,
812 offset: u32,
813 buf: &[u8],
814 _flags: VhostUserConfigFlags,
815 ) -> VhostResult<()> {
816 self.backend.write_config(u64::from(offset), buf);
817 Ok(())
818 }
819
820 fn set_backend_req_fd(&mut self, ep: Connection) {
821 let conn = VhostBackendReqConnection::new(
822 FrontendClient::new(
823 ep,
824 self.acked_protocol_features
825 .contains(VhostUserProtocolFeatures::REPLY_ACK),
826 ),
827 self.backend.get_shared_memory_region().map(|r| r.id),
828 );
829
830 if self.backend_req_connection.is_some() {
831 warn!("Backend Request Connection already established. Overwriting");
832 }
833 self.backend_req_connection = Some(conn.clone());
834
835 self.backend.set_backend_req_connection(conn);
836 }
837
838 fn get_inflight_fd(
839 &mut self,
840 _inflight: &VhostUserInflight,
841 ) -> VhostResult<(VhostUserInflight, File)> {
842 unimplemented!("get_inflight_fd");
843 }
844
845 fn set_inflight_fd(&mut self, _inflight: &VhostUserInflight, _file: File) -> VhostResult<()> {
846 unimplemented!("set_inflight_fd");
847 }
848
849 fn get_max_mem_slots(&mut self) -> VhostResult<u64> {
850 Ok(0)
852 }
853
854 fn add_mem_region(
855 &mut self,
856 _region: &VhostUserSingleMemoryRegion,
857 _fd: File,
858 ) -> VhostResult<()> {
859 Ok(())
861 }
862
863 fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> VhostResult<()> {
864 Ok(())
866 }
867
868 fn set_device_state_fd(
869 &mut self,
870 transfer_direction: VhostUserTransferDirection,
871 migration_phase: VhostUserMigrationPhase,
872 fd: File,
873 ) -> VhostResult<Option<File>> {
874 if migration_phase != VhostUserMigrationPhase::Stopped {
875 return Err(VhostError::InvalidOperation);
876 }
877 if !self.all_queues_stopped() {
878 return Err(VhostError::InvalidOperation);
879 }
880 if self.device_state_thread.is_some() {
881 error!("must call check_device_state before starting new state transfer");
882 return Err(VhostError::InvalidOperation);
883 }
884 match transfer_direction {
889 VhostUserTransferDirection::Save => {
890 let snapshot = DeviceRequestHandlerSnapshot {
892 acked_features: self.acked_features,
893 acked_protocol_features: self.acked_protocol_features.bits(),
894 backend: self.backend.snapshot().map_err(VhostError::SnapshotError)?,
895 };
896 self.device_state_thread = Some(DeviceStateThread::Save(WorkerThread::start(
898 "device_state_save",
899 move |_kill_event| -> Result<(), ciborium::ser::Error<std::io::Error>> {
900 let mut w = std::io::BufWriter::new(fd);
901 ciborium::into_writer(&snapshot, &mut w)?;
902 w.flush()?;
903 Ok(())
904 },
905 )));
906 Ok(None)
907 }
908 VhostUserTransferDirection::Load => {
909 self.device_state_thread = Some(DeviceStateThread::Load(WorkerThread::start(
912 "device_state_load",
913 move |_kill_event| ciborium::from_reader(&mut BufReader::new(fd)),
914 )));
915 Ok(None)
916 }
917 }
918 }
919
920 fn check_device_state(&mut self) -> VhostResult<()> {
921 let Some(thread) = self.device_state_thread.take() else {
922 error!("check_device_state: no active state transfer");
923 return Err(VhostError::InvalidOperation);
924 };
925 match thread {
926 DeviceStateThread::Save(worker) => {
927 worker.stop().map_err(|e| {
928 error!("device state save thread failed: {:#}", e);
929 VhostError::BackendInternalError
930 })?;
931 Ok(())
932 }
933 DeviceStateThread::Load(worker) => {
934 let snapshot = worker.stop().map_err(|e| {
935 error!("device state load thread failed: {:#}", e);
936 VhostError::BackendInternalError
937 })?;
938 self.acked_features = snapshot.acked_features;
939 self.acked_protocol_features =
940 VhostUserProtocolFeatures::from_bits(snapshot.acked_protocol_features)
941 .with_context(|| {
942 format!(
943 "unsupported bits in acked_protocol_features: {:#x}",
944 snapshot.acked_protocol_features
945 )
946 })
947 .map_err(VhostError::RestoreError)?;
948 self.backend
949 .restore(snapshot.backend)
950 .map_err(VhostError::RestoreError)?;
951 Ok(())
952 }
953 }
954 }
955
956 fn get_shmem_config(&mut self) -> VhostResult<Vec<SharedMemoryRegion>> {
957 Ok(self
958 .backend
959 .get_shared_memory_region()
960 .into_iter()
961 .collect())
962 }
963}
964
965#[derive(Clone)]
967pub struct VhostBackendReqConnection {
968 shared: Arc<Mutex<VhostBackendReqConnectionShared>>,
969 shmid: Option<u8>,
970}
971
972struct VhostBackendReqConnectionShared {
973 conn: FrontendClient,
974 mapped_regions: BTreeMap<u64 , u64 >,
975}
976
977impl VhostBackendReqConnection {
978 fn new(conn: FrontendClient, shmid: Option<u8>) -> Self {
979 Self {
980 shared: Arc::new(Mutex::new(VhostBackendReqConnectionShared {
981 conn,
982 mapped_regions: BTreeMap::new(),
983 })),
984 shmid,
985 }
986 }
987
988 fn send_config_changed(&self) -> anyhow::Result<()> {
990 let mut shared = self.shared.lock();
991 shared
992 .conn
993 .handle_config_change()
994 .context("Could not send config change message")?;
995 Ok(())
996 }
997
998 pub fn shmem_mapper(&self) -> Option<Box<dyn SharedMemoryMapper>> {
1000 if let Some(shmid) = self.shmid {
1001 Some(Box::new(VhostShmemMapper {
1002 shared: self.shared.clone(),
1003 shmid,
1004 }))
1005 } else {
1006 None
1007 }
1008 }
1009}
1010
1011#[derive(Clone)]
1012struct VhostShmemMapper {
1013 shared: Arc<Mutex<VhostBackendReqConnectionShared>>,
1014 shmid: u8,
1015}
1016
1017impl SharedMemoryMapper for VhostShmemMapper {
1018 fn add_mapping(
1019 &mut self,
1020 source: VmMemorySource,
1021 offset: u64,
1022 prot: Protection,
1023 _cache: MemCacheType,
1024 ) -> anyhow::Result<()> {
1025 let mut shared = self.shared.lock();
1026 let size = match source {
1027 VmMemorySource::Vulkan {
1028 descriptor,
1029 handle_type,
1030 memory_idx,
1031 device_uuid,
1032 driver_uuid,
1033 size,
1034 } => {
1035 let msg = VhostUserGpuMapMsg::new(
1036 self.shmid,
1037 offset,
1038 size,
1039 memory_idx,
1040 handle_type,
1041 device_uuid,
1042 driver_uuid,
1043 );
1044 shared
1045 .conn
1046 .gpu_map(&msg, &descriptor)
1047 .context("map GPU memory")?;
1048 size
1049 }
1050 VmMemorySource::ExternalMapping { ptr, size } => {
1051 let msg = VhostUserExternalMapMsg::new(self.shmid, offset, size, ptr);
1052 shared
1053 .conn
1054 .external_map(&msg)
1055 .context("create external mapping")?;
1056 size
1057 }
1058 source => {
1059 let (descriptor, fd_offset, size) = match source {
1062 VmMemorySource::Descriptor {
1063 descriptor,
1064 offset,
1065 size,
1066 } => (descriptor, offset, size),
1067 VmMemorySource::SharedMemory(shmem) => {
1068 let size = shmem.size();
1069 let descriptor = SafeDescriptor::from(shmem);
1070 (descriptor, 0, size)
1071 }
1072 _ => bail!("unsupported source"),
1073 };
1074 let mut flags = VhostUserMMapFlags::empty();
1075 anyhow::ensure!(prot.allows(&Protection::read()), "mapping must be readable");
1076 if prot.allows(&Protection::write()) {
1077 flags |= VhostUserMMapFlags::MAP_RW;
1078 }
1079 let msg = VhostUserMMap {
1080 shmid: self.shmid,
1081 padding: Default::default(),
1082 fd_offset,
1083 shm_offset: offset,
1084 len: size,
1085 flags,
1086 };
1087 shared
1088 .conn
1089 .shmem_map(&msg, &descriptor)
1090 .context("map shmem")?;
1091 size
1092 }
1093 };
1094
1095 shared.mapped_regions.insert(offset, size);
1096 Ok(())
1097 }
1098
1099 fn remove_mapping(&mut self, offset: u64) -> anyhow::Result<()> {
1100 let mut shared = self.shared.lock();
1101 let size = shared
1102 .mapped_regions
1103 .remove(&offset)
1104 .context("unknown offset")?;
1105 let msg = VhostUserMMap {
1106 shmid: self.shmid,
1107 padding: Default::default(),
1108 fd_offset: 0,
1109 shm_offset: offset,
1110 len: size,
1111 flags: VhostUserMMapFlags::empty(),
1112 };
1113 shared
1114 .conn
1115 .shmem_unmap(&msg)
1116 .context("unmap shmem")
1117 .map(|_| ())
1118 }
1119}
1120
1121pub struct WorkerState<T, U> {
1122 pub queue_task: TaskHandle<U>,
1123 pub queue: T,
1124}
1125
1126#[derive(Debug, ThisError)]
1128pub enum Error {
1129 #[error("worker not found when stopping queue")]
1130 WorkerNotFound,
1131}
1132
1133#[cfg(test)]
1134mod tests {
1135 use std::sync::mpsc::channel;
1136
1137 use anyhow::bail;
1138 use base::Event;
1139 use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
1140 use vmm_vhost::BackendServer;
1141 use vmm_vhost::FrontendReq;
1142 use zerocopy::FromBytes;
1143 use zerocopy::FromZeros;
1144 use zerocopy::Immutable;
1145 use zerocopy::IntoBytes;
1146 use zerocopy::KnownLayout;
1147
1148 use super::*;
1149 use crate::virtio::vhost_user_frontend::VhostUserFrontend;
1150 use crate::virtio::DeviceType;
1151 use crate::virtio::VirtioDevice;
1152
1153 #[derive(Clone, Copy, Debug, PartialEq, Eq, FromBytes, Immutable, IntoBytes, KnownLayout)]
1154 #[repr(C, packed(4))]
1155 struct FakeConfig {
1156 x: u32,
1157 y: u64,
1158 }
1159
1160 const FAKE_CONFIG_DATA: FakeConfig = FakeConfig { x: 1, y: 2 };
1161
1162 pub(super) struct FakeBackend {
1163 avail_features: u64,
1164 acked_features: u64,
1165 active_queues: Vec<Option<Queue>>,
1166 allow_backend_req: bool,
1167 backend_conn: Option<VhostBackendReqConnection>,
1168 }
1169
1170 #[derive(Deserialize, Serialize)]
1171 struct FakeBackendSnapshot {
1172 data: Vec<u8>,
1173 }
1174
1175 impl FakeBackend {
1176 const MAX_QUEUE_NUM: usize = 16;
1177
1178 pub(super) fn new() -> Self {
1179 let mut active_queues = Vec::new();
1180 active_queues.resize_with(Self::MAX_QUEUE_NUM, Default::default);
1181 Self {
1182 avail_features: 1 << VHOST_USER_F_PROTOCOL_FEATURES | 1 << VIRTIO_RING_F_EVENT_IDX,
1183 acked_features: 0,
1184 active_queues,
1185 allow_backend_req: false,
1186 backend_conn: None,
1187 }
1188 }
1189 }
1190
1191 impl VhostUserDevice for FakeBackend {
1192 fn max_queue_num(&self) -> usize {
1193 Self::MAX_QUEUE_NUM
1194 }
1195
1196 fn features(&self) -> u64 {
1197 self.avail_features
1198 }
1199
1200 fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
1201 let unrequested_features = value & !self.avail_features;
1202 if unrequested_features != 0 {
1203 bail!(
1204 "invalid protocol features are given: 0x{:x}",
1205 unrequested_features
1206 );
1207 }
1208 self.acked_features |= value;
1209 Ok(())
1210 }
1211
1212 fn protocol_features(&self) -> VhostUserProtocolFeatures {
1213 let mut features =
1214 VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::DEVICE_STATE;
1215 if self.allow_backend_req {
1216 features |= VhostUserProtocolFeatures::BACKEND_REQ;
1217 }
1218 features
1219 }
1220
1221 fn read_config(&self, offset: u64, dst: &mut [u8]) {
1222 dst.copy_from_slice(&FAKE_CONFIG_DATA.as_bytes()[offset as usize..]);
1223 }
1224
1225 fn reset(&mut self) {}
1226
1227 fn start_queue(
1228 &mut self,
1229 idx: usize,
1230 queue: Queue,
1231 _mem: GuestMemory,
1232 ) -> anyhow::Result<()> {
1233 self.active_queues[idx] = Some(queue);
1234 Ok(())
1235 }
1236
1237 fn stop_queue(&mut self, idx: usize) -> anyhow::Result<Queue> {
1238 Ok(self.active_queues[idx]
1239 .take()
1240 .ok_or(Error::WorkerNotFound)?)
1241 }
1242
1243 fn set_backend_req_connection(&mut self, conn: VhostBackendReqConnection) {
1244 self.backend_conn = Some(conn);
1245 }
1246
1247 fn enter_suspended_state(&mut self) -> anyhow::Result<()> {
1248 Ok(())
1249 }
1250
1251 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
1252 AnySnapshot::to_any(FakeBackendSnapshot {
1253 data: vec![1, 2, 3],
1254 })
1255 .context("failed to serialize snapshot")
1256 }
1257
1258 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
1259 let snapshot: FakeBackendSnapshot =
1260 AnySnapshot::from_any(data).context("failed to deserialize snapshot")?;
1261 assert_eq!(snapshot.data, vec![1, 2, 3], "bad snapshot data");
1262 Ok(())
1263 }
1264 }
1265
1266 fn create_queues(
1267 num: usize,
1268 mem: &GuestMemory,
1269 interrupt: &Interrupt,
1270 ) -> BTreeMap<usize, Queue> {
1271 let mut queues = BTreeMap::new();
1272 for idx in 0..num {
1273 let mut queue = QueueConfig::new(0x10, 0);
1274 queue.set_ready(true);
1275 let queue = queue
1276 .activate(mem, Event::new().unwrap(), interrupt.clone())
1277 .expect("QueueConfig::activate");
1278 queues.insert(idx, queue);
1279 }
1280 queues
1281 }
1282
1283 #[test]
1284 fn test_vhost_user_lifecycle() {
1285 test_vhost_user_lifecycle_parameterized(false);
1286 }
1287
1288 #[test]
1289 fn test_vhost_user_lifecycle_by_ref() {
1290 let mut backend = FakeBackend::new();
1291 let expected_features = backend.features();
1292 let handler = DeviceRequestHandler::new(&mut backend);
1293 assert_eq!(handler.as_ref().features(), expected_features);
1294 drop(handler);
1295 assert_eq!(backend.features(), expected_features);
1297 }
1298
1299 #[test]
1300 #[cfg(not(windows))] fn test_vhost_user_lifecycle_with_backend_req() {
1302 test_vhost_user_lifecycle_parameterized(true);
1303 }
1304
1305 fn test_vhost_user_lifecycle_parameterized(allow_backend_req: bool) {
1306 const QUEUES_NUM: usize = 2;
1307 const BASE_FEATURES: u64 = 1 << VIRTIO_RING_F_EVENT_IDX;
1308 const EXPECTED_FEATURES: u64 =
1309 1 << VHOST_USER_F_PROTOCOL_FEATURES | 1 << VIRTIO_RING_F_EVENT_IDX;
1310
1311 let snapshot = {
1313 let (client_connection, server_connection) = vmm_vhost::Connection::pair().unwrap();
1314 let (shutdown_tx, shutdown_rx) = channel();
1315 let (vm_evt_wrtube, _vm_evt_rdtube) = base::Tube::directional_pair().unwrap();
1316 let vmm_thread = std::thread::spawn(move || {
1317 let mut vmm_device = VhostUserFrontend::new(
1319 DeviceType::Console,
1320 BASE_FEATURES,
1321 client_connection,
1322 vm_evt_wrtube,
1323 None,
1324 None,
1325 true,
1326 )
1327 .unwrap();
1328
1329 vmm_device.ack_features(BASE_FEATURES);
1330
1331 let mem = GuestMemory::new(&[(GuestAddress(0x0), 0x10000)]).unwrap();
1332 let interrupt = Interrupt::new_for_test_with_msix();
1333
1334 println!("read_config");
1335 let mut config = FakeConfig::new_zeroed();
1336 vmm_device.read_config(0, config.as_mut_bytes());
1337 assert_eq!(config, FAKE_CONFIG_DATA);
1339
1340 println!("activate");
1341 vmm_device
1342 .activate(
1343 mem.clone(),
1344 interrupt.clone(),
1345 create_queues(QUEUES_NUM, &mem, &interrupt),
1346 )
1347 .unwrap();
1348
1349 println!("reset");
1350 let reset_result = vmm_device.reset();
1351 assert!(
1352 reset_result.is_ok(),
1353 "reset failed: {:#}",
1354 reset_result.unwrap_err()
1355 );
1356
1357 println!("activate");
1358 vmm_device
1359 .activate(
1360 mem.clone(),
1361 interrupt.clone(),
1362 create_queues(QUEUES_NUM, &mem, &interrupt),
1363 )
1364 .unwrap();
1365
1366 println!("virtio_sleep");
1367 let queues = vmm_device
1368 .virtio_sleep()
1369 .unwrap()
1370 .expect("virtio_sleep unexpectedly returned None");
1371
1372 println!("virtio_snapshot");
1373 let snapshot = vmm_device
1374 .virtio_snapshot()
1375 .expect("virtio_snapshot failed");
1376
1377 println!("virtio_wake");
1378 vmm_device
1379 .virtio_wake(Some((mem.clone(), interrupt.clone(), queues)))
1380 .unwrap();
1381
1382 println!("wait for shutdown signal");
1383 shutdown_rx.recv().unwrap();
1384
1385 println!("drop");
1387
1388 snapshot
1389 });
1390
1391 let mut handler = DeviceRequestHandler::new(FakeBackend::new());
1393 handler.as_mut().allow_backend_req = allow_backend_req;
1394
1395 let mut req_handler = BackendServer::new(server_connection, handler);
1396
1397 handle_request(&mut req_handler, FrontendReq::SET_OWNER).unwrap();
1399 handle_request(&mut req_handler, FrontendReq::GET_FEATURES).unwrap();
1400 handle_request(&mut req_handler, FrontendReq::GET_PROTOCOL_FEATURES).unwrap();
1401 handle_request(&mut req_handler, FrontendReq::SET_PROTOCOL_FEATURES).unwrap();
1402 if allow_backend_req {
1403 handle_request(&mut req_handler, FrontendReq::SET_BACKEND_REQ_FD).unwrap();
1404 }
1405
1406 handle_request(&mut req_handler, FrontendReq::GET_CONFIG).unwrap();
1408
1409 handle_request(&mut req_handler, FrontendReq::SET_FEATURES).unwrap();
1411 assert_eq!(req_handler.as_ref().acked_features, EXPECTED_FEATURES);
1412 handle_request(&mut req_handler, FrontendReq::SET_MEM_TABLE).unwrap();
1413 for _ in 0..QUEUES_NUM {
1414 handle_request(&mut req_handler, FrontendReq::SET_VRING_NUM).unwrap();
1415 handle_request(&mut req_handler, FrontendReq::SET_VRING_ADDR).unwrap();
1416 handle_request(&mut req_handler, FrontendReq::SET_VRING_BASE).unwrap();
1417 handle_request(&mut req_handler, FrontendReq::SET_VRING_CALL).unwrap();
1418 handle_request(&mut req_handler, FrontendReq::SET_VRING_KICK).unwrap();
1419 handle_request(&mut req_handler, FrontendReq::SET_VRING_ENABLE).unwrap();
1420 }
1421
1422 for _ in 0..QUEUES_NUM {
1424 handle_request(&mut req_handler, FrontendReq::SET_VRING_ENABLE).unwrap();
1425 handle_request(&mut req_handler, FrontendReq::GET_VRING_BASE).unwrap();
1426 }
1427
1428 handle_request(&mut req_handler, FrontendReq::SET_MEM_TABLE).unwrap();
1430 for _ in 0..QUEUES_NUM {
1431 handle_request(&mut req_handler, FrontendReq::SET_VRING_NUM).unwrap();
1432 handle_request(&mut req_handler, FrontendReq::SET_VRING_ADDR).unwrap();
1433 handle_request(&mut req_handler, FrontendReq::SET_VRING_BASE).unwrap();
1434 handle_request(&mut req_handler, FrontendReq::SET_VRING_CALL).unwrap();
1435 handle_request(&mut req_handler, FrontendReq::SET_VRING_KICK).unwrap();
1436 handle_request(&mut req_handler, FrontendReq::SET_VRING_ENABLE).unwrap();
1437 }
1438
1439 if allow_backend_req {
1440 req_handler
1442 .as_ref()
1443 .as_ref()
1444 .backend_conn
1445 .as_ref()
1446 .expect("backend_conn missing")
1447 .send_config_changed()
1448 .expect("send_config_changed failed");
1449 }
1450
1451 for _ in 0..QUEUES_NUM {
1453 handle_request(&mut req_handler, FrontendReq::SET_VRING_ENABLE).unwrap();
1454 handle_request(&mut req_handler, FrontendReq::GET_VRING_BASE).unwrap();
1455 }
1456
1457 handle_request(&mut req_handler, FrontendReq::SET_DEVICE_STATE_FD).unwrap();
1459 handle_request(&mut req_handler, FrontendReq::CHECK_DEVICE_STATE).unwrap();
1460
1461 handle_request(&mut req_handler, FrontendReq::SET_MEM_TABLE).unwrap();
1463 for _ in 0..QUEUES_NUM {
1464 handle_request(&mut req_handler, FrontendReq::SET_VRING_NUM).unwrap();
1465 handle_request(&mut req_handler, FrontendReq::SET_VRING_ADDR).unwrap();
1466 handle_request(&mut req_handler, FrontendReq::SET_VRING_BASE).unwrap();
1467 handle_request(&mut req_handler, FrontendReq::SET_VRING_CALL).unwrap();
1468 handle_request(&mut req_handler, FrontendReq::SET_VRING_KICK).unwrap();
1469 handle_request(&mut req_handler, FrontendReq::SET_VRING_ENABLE).unwrap();
1470 }
1471
1472 if allow_backend_req {
1473 req_handler
1475 .as_ref()
1476 .as_ref()
1477 .backend_conn
1478 .as_ref()
1479 .expect("backend_conn missing")
1480 .send_config_changed()
1481 .expect("send_config_changed failed");
1482 }
1483
1484 shutdown_tx.send(()).unwrap();
1486
1487 match req_handler.recv_header() {
1489 Err(VhostError::ClientExit) => (),
1490 r => panic!("expected Err(ClientExit) but got {r:?}"),
1491 }
1492
1493 vmm_thread.join().unwrap()
1494 };
1495
1496 {
1498 let (client_connection, server_connection) = vmm_vhost::Connection::pair().unwrap();
1499 let (shutdown_tx, shutdown_rx) = channel();
1500 let (vm_evt_wrtube, _vm_evt_rdtube) = base::Tube::directional_pair().unwrap();
1501 let vmm_thread = std::thread::spawn(move || {
1502 let mut vmm_device = VhostUserFrontend::new(
1504 DeviceType::Console,
1505 BASE_FEATURES,
1506 client_connection,
1507 vm_evt_wrtube,
1508 None,
1509 None,
1510 true,
1511 )
1512 .unwrap();
1513
1514 let mem = GuestMemory::new(&[(GuestAddress(0x0), 0x10000)]).unwrap();
1515 let interrupt = Interrupt::new_for_test_with_msix();
1516
1517 println!("virtio_sleep");
1518 assert!(vmm_device.virtio_sleep().unwrap().is_none());
1519
1520 println!("virtio_restore");
1521 vmm_device
1522 .virtio_restore(snapshot)
1523 .expect("virtio_restore failed");
1524
1525 println!("virtio_wake");
1526 vmm_device
1527 .virtio_wake(Some((
1528 mem.clone(),
1529 interrupt.clone(),
1530 create_queues(QUEUES_NUM, &mem, &interrupt),
1531 )))
1532 .unwrap();
1533
1534 println!("wait for shutdown signal");
1535 shutdown_rx.recv().unwrap();
1536
1537 println!("drop");
1539 });
1540
1541 let mut handler = DeviceRequestHandler::new(FakeBackend::new());
1543 handler.as_mut().allow_backend_req = allow_backend_req;
1544
1545 let mut req_handler = BackendServer::new(server_connection, handler);
1546
1547 handle_request(&mut req_handler, FrontendReq::SET_OWNER).unwrap();
1549 handle_request(&mut req_handler, FrontendReq::GET_FEATURES).unwrap();
1550 handle_request(&mut req_handler, FrontendReq::GET_PROTOCOL_FEATURES).unwrap();
1551 handle_request(&mut req_handler, FrontendReq::SET_PROTOCOL_FEATURES).unwrap();
1552 if allow_backend_req {
1553 handle_request(&mut req_handler, FrontendReq::SET_BACKEND_REQ_FD).unwrap();
1554 }
1555
1556 handle_request(&mut req_handler, FrontendReq::SET_FEATURES).unwrap();
1561 assert_eq!(req_handler.as_ref().acked_features, EXPECTED_FEATURES);
1562 handle_request(&mut req_handler, FrontendReq::SET_DEVICE_STATE_FD).unwrap();
1563 handle_request(&mut req_handler, FrontendReq::CHECK_DEVICE_STATE).unwrap();
1564
1565 handle_request(&mut req_handler, FrontendReq::SET_MEM_TABLE).unwrap();
1567 for _ in 0..QUEUES_NUM {
1568 handle_request(&mut req_handler, FrontendReq::SET_VRING_NUM).unwrap();
1569 handle_request(&mut req_handler, FrontendReq::SET_VRING_ADDR).unwrap();
1570 handle_request(&mut req_handler, FrontendReq::SET_VRING_BASE).unwrap();
1571 handle_request(&mut req_handler, FrontendReq::SET_VRING_CALL).unwrap();
1572 handle_request(&mut req_handler, FrontendReq::SET_VRING_KICK).unwrap();
1573 handle_request(&mut req_handler, FrontendReq::SET_VRING_ENABLE).unwrap();
1574 }
1575
1576 if allow_backend_req {
1577 req_handler
1579 .as_ref()
1580 .as_ref()
1581 .backend_conn
1582 .as_ref()
1583 .expect("backend_conn missing")
1584 .send_config_changed()
1585 .expect("send_config_changed failed");
1586 }
1587
1588 shutdown_tx.send(()).unwrap();
1590 match req_handler.recv_header() {
1592 Err(VhostError::ClientExit) => (),
1593 r => panic!("expected Err(ClientExit) but got {r:?}"),
1594 }
1595 vmm_thread.join().unwrap();
1596 }
1597 }
1598
1599 #[track_caller]
1600 fn handle_request<S: vmm_vhost::Backend>(
1601 handler: &mut BackendServer<S>,
1602 expected_message_type: FrontendReq,
1603 ) -> Result<(), VhostError> {
1604 let (hdr, files) = handler.recv_header()?;
1605 assert_eq!(hdr.get_code(), Ok(expected_message_type));
1606 handler.process_message(hdr, files)
1607 }
1608}