devices/virtio/vhost_user_backend/
handler.rs

1// Copyright 2021 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Library for implementing vhost-user device executables.
6//!
7//! This crate provides
8//! * `VhostUserDevice` trait, which is a collection of methods to handle vhost-user requests, and
9//! * `DeviceRequestHandler` struct, which makes a connection to a VMM and starts an event loop.
10//!
11//! They are expected to be used as follows:
12//!
13//! 1. Define a struct and implement `VhostUserDevice` for it.
14//! 2. Create a `DeviceRequestHandler` with the backend struct.
15//! 3. Drive the `DeviceRequestHandler::run` async fn with an executor.
16//!
17//! ```ignore
18//! struct MyBackend {
19//!   /* fields */
20//! }
21//!
22//! impl VhostUserDevice for MyBackend {
23//!   /* implement methods */
24//! }
25//!
26//! fn main() -> Result<(), Box<dyn Error>> {
27//!   let backend = MyBackend { /* initialize fields */ };
28//!   let handler = DeviceRequestHandler::new(backend);
29//!   let socket = std::path::Path("/path/to/socket");
30//!   let ex = cros_async::Executor::new()?;
31//!
32//!   if let Err(e) = ex.run_until(handler.run(socket, &ex)) {
33//!     eprintln!("error happened: {}", e);
34//!   }
35//!   Ok(())
36//! }
37//! ```
38// Implementation note:
39// This code lets us take advantage of the vmm_vhost low level implementation of the vhost user
40// protocol. DeviceRequestHandler implements the Backend trait from vmm_vhost, and includes some
41// common code for setting up guest memory and managing partially configured vrings.
42// DeviceRequestHandler::run watches the vhost-user socket and then calls handle_request() when it
43// becomes readable. handle_request() reads and parses the message and then calls one of the
44// Backend trait methods. These dispatch back to the supplied VhostUserDevice implementation (this
45// is what our devices implement).
46
47pub 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/// Keeps a mapping from the vmm's virtual addresses to guest addresses.
109/// used to translate messages from the vmm to guest offsets.
110#[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
126/// Trait for vhost-user devices. Analogous to the `VirtioDevice` trait.
127///
128/// In contrast with [[vmm_vhost::Backend]], which closely matches the vhost-user spec, this trait
129/// is designed to follow crosvm conventions for implementing devices.
130pub trait VhostUserDevice {
131    /// The maximum number of queues that this backend can manage.
132    fn max_queue_num(&self) -> usize;
133
134    /// The set of feature bits that this backend supports.
135    fn features(&self) -> u64;
136
137    /// Acknowledges that this set of features should be enabled.
138    ///
139    /// Implementations only need to handle device-specific feature bits; the `DeviceRequestHandler`
140    /// framework will manage generic vhost and vring features.
141    ///
142    /// `DeviceRequestHandler` checks for valid features before calling this function, so the
143    /// features in `value` will always be a subset of those advertised by `features()`.
144    fn ack_features(&mut self, _value: u64) -> anyhow::Result<()> {
145        Ok(())
146    }
147
148    /// The set of protocol feature bits that this backend supports.
149    fn protocol_features(&self) -> VhostUserProtocolFeatures;
150
151    /// Reads this device configuration space at `offset`.
152    fn read_config(&self, offset: u64, dst: &mut [u8]);
153
154    /// writes `data` to this device's configuration space at `offset`.
155    fn write_config(&self, _offset: u64, _data: &[u8]) {}
156
157    /// Indicates that the backend should start processing requests for virtio queue number `idx`.
158    /// This method must not block the current thread so device backends should either spawn an
159    /// async task or another thread to handle messages from the Queue.
160    fn start_queue(&mut self, idx: usize, queue: Queue, mem: GuestMemory) -> anyhow::Result<()>;
161
162    /// Indicates that the backend should stop processing requests for virtio queue number `idx`.
163    /// This method should return the queue passed to `start_queue` for the corresponding `idx`.
164    /// This method will only be called for queues that were previously started by `start_queue`.
165    fn stop_queue(&mut self, idx: usize) -> anyhow::Result<Queue>;
166
167    /// Resets the vhost-user backend.
168    fn reset(&mut self);
169
170    /// Returns the device's shared memory region if present.
171    fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
172        None
173    }
174
175    /// Accepts `VhostBackendReqConnection` to conduct Vhost backend to frontend message
176    /// handling.
177    ///
178    /// This method will be called when `VhostUserProtocolFeatures::BACKEND_REQ` is
179    /// negotiated.
180    fn set_backend_req_connection(&mut self, _conn: VhostBackendReqConnection) {}
181
182    /// Enter the "suspended device state" described in the vhost-user spec. See the spec for
183    /// requirements.
184    ///
185    /// One reasonably foolproof way to satisfy the requirements is to stop all worker threads.
186    ///
187    /// Called after a `stop_queue` call if there are no running queues left. Also called soon
188    /// after device creation to ensure the device is acting suspended immediately on construction.
189    ///
190    /// The next `start_queue` call implicitly exits the "suspend device state".
191    ///
192    /// * Ok(())    => device successfully suspended
193    /// * Err(_)    => unrecoverable error
194    fn enter_suspended_state(&mut self) -> anyhow::Result<()>;
195
196    /// Snapshot device and return serialized state.
197    fn snapshot(&mut self) -> anyhow::Result<AnySnapshot>;
198
199    /// Restore device state from a snapshot.
200    fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>;
201
202    /// Whether guest memory should be unmapped in forked processes.
203    ///
204    /// This is intended for use in combination with --protected-vm, where the guest memory can be
205    /// dangerous to access. Some systems, e.g. Android, have tools that fork processes and examine
206    /// their memory. This flag effectively hides the guest memory from those tools.
207    ///
208    /// Not compatible with sandboxing.
209    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
338/// A virtio ring entry.
339struct Vring {
340    // The queue config. This doesn't get mutated by the queue workers.
341    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
362/// Ops for running vhost-user over a stream (i.e. regular protocol).
363pub(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
413/// An adapter that implements `vmm_vhost::Backend` for any type implementing `VhostUserDevice`.
414pub 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    // Thread processing active device state FD.
424    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    /// Creates a vhost-user handler instance for `backend`.
441    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        // VhostUserDevice implementations must support `enter_suspended_state()`.
448        // Call it on startup to ensure it works and to initialize the device in a suspended state.
449        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    /// Check if all queues are stopped.
467    ///
468    /// The device can be suspended with `enter_suspended_state()` only when all queues are stopped.
469    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        // If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated, the ring is initialized in an
538        // enabled state.
539        // If VHOST_USER_F_PROTOCOL_FEATURES has been negotiated, the ring is initialized in a
540        // disabled state.
541        // Client must not pass data to/from the backend until ring is enabled by
542        // VHOST_USER_SET_VRING_ENABLE with parameter 1, or after it has been disabled by
543        // VHOST_USER_SET_VRING_ENABLE with parameter 0.
544        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        // Quotation from vhost-user spec:
660        // "The back-end must [...] stop ring upon receiving VHOST_USER_GET_VRING_BASE."
661        // We only call `queue.set_ready()` when starting the queue, so if the queue is ready, that
662        // means it is started and should be stopped.
663        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        // Remove O_NONBLOCK from kick_fd. Otherwise, uring_executor will fails when we read
706        // values via `next_val()` later.
707        // This is only required (and can only be done) on Unix platforms.
708        #[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        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
719        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        // TODO
775        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        // This request should be handled only when VHOST_USER_F_PROTOCOL_FEATURES
786        // has been negotiated.
787        if self.acked_features & 1 << VHOST_USER_F_PROTOCOL_FEATURES == 0 {
788            return Err(VhostError::InvalidOperation);
789        }
790
791        // Backend must not pass data to/from the ring until ring is enabled by
792        // VHOST_USER_SET_VRING_ENABLE with parameter 1, or after it has been disabled by
793        // VHOST_USER_SET_VRING_ENABLE with parameter 0.
794        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        //TODO
851        Ok(0)
852    }
853
854    fn add_mem_region(
855        &mut self,
856        _region: &VhostUserSingleMemoryRegion,
857        _fd: File,
858    ) -> VhostResult<()> {
859        //TODO
860        Ok(())
861    }
862
863    fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> VhostResult<()> {
864        //TODO
865        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        // `set_device_state_fd` is designed to allow snapshot/restore concurrently with other
885        // methods, but, for simplicitly, we do those operations inline and only spawn a thread to
886        // handle the serialization and data transfer (the latter which seems necessary to
887        // implement the API correctly without, e.g., deadlocking because a pipe is full).
888        match transfer_direction {
889            VhostUserTransferDirection::Save => {
890                // Snapshot the state.
891                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                // Spawn thread to write the serialized bytes.
897                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                // Spawn a thread to read the bytes and deserialize. Restore will happen in
910                // `check_device_state`.
911                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/// Keeps track of Vhost user backend request connection.
966#[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 /* offset */, u64 /* size */>,
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    /// Send `VHOST_USER_CONFIG_CHANGE_MSG` to the frontend
989    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    /// Create a SharedMemoryMapper trait object using this backend request connection.
999    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                // The last two sources use the same VhostUserMMap, continue matching here
1060                // on the aliased `source` above.
1061                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/// Errors for device operations
1127#[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        // `backend` is not dropped when `handler` is dropped.
1296        assert_eq!(backend.features(), expected_features);
1297    }
1298
1299    #[test]
1300    #[cfg(not(windows))] // Windows requries more complex connection setup.
1301    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        // First phase: Test normal usage, then take a snapshot and shutdown.
1312        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                // VMM side
1318                let mut vmm_device = VhostUserFrontend::new(
1319                    DeviceType::Console,
1320                    BASE_FEATURES,
1321                    client_connection,
1322                    vm_evt_wrtube,
1323                    None,
1324                    None,
1325                    /* is_remote_backend= */ 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                // Check if the obtained config data is correct.
1338                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                // The VMM side is supposed to stop before the device side.
1386                println!("drop");
1387
1388                snapshot
1389            });
1390
1391            // Device side
1392            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            // VhostUserFrontend::new()
1398            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            // VhostUserFrontend::read_config()
1407            handle_request(&mut req_handler, FrontendReq::GET_CONFIG).unwrap();
1408
1409            // VhostUserFrontend::activate()
1410            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            // VhostUserFrontend::reset()
1423            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            // VhostUserFrontend::activate()
1429            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                // Make sure the connection still works even after reset/reactivate.
1441                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            // VhostUserFrontend::virtio_sleep()
1452            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            // VhostUserFrontend::virtio_snapshot()
1458            handle_request(&mut req_handler, FrontendReq::SET_DEVICE_STATE_FD).unwrap();
1459            handle_request(&mut req_handler, FrontendReq::CHECK_DEVICE_STATE).unwrap();
1460
1461            // VhostUserFrontend::virtio_wake()
1462            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                // Make sure the connection still works even after sleep/wake.
1474                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            // Ask the client to shutdown, then wait to it to finish.
1485            shutdown_tx.send(()).unwrap();
1486
1487            // Verify recv_header fails with `ClientExit` after the client has disconnected.
1488            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        // Second phase: Restore the snapshot.
1497        {
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                // VMM side
1503                let mut vmm_device = VhostUserFrontend::new(
1504                    DeviceType::Console,
1505                    BASE_FEATURES,
1506                    client_connection,
1507                    vm_evt_wrtube,
1508                    None,
1509                    None,
1510                    /* is_remote_backend= */ 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                // The VMM side is supposed to stop before the device side.
1538                println!("drop");
1539            });
1540
1541            // Device side
1542            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            // VhostUserFrontend::new()
1548            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            // VhostUserFrontend::virtio_sleep()
1557            // (no-op)
1558
1559            // VhostUserFrontend::virtio_restore()
1560            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            // VhostUserFrontend::virtio_wake()
1566            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                // Make sure the connection still works even after restore.
1578                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            // Ask the client to shutdown, then wait to it to finish.
1589            shutdown_tx.send(()).unwrap();
1590            // Verify recv_header fails with `ClientExit` after the client has disconnected.
1591            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}