vmm_vhost/
backend_client.rs

1// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::fs::File;
5use std::mem;
6
7use base::AsRawDescriptor;
8#[cfg(windows)]
9use base::CloseNotifier;
10use base::Event;
11use base::RawDescriptor;
12use base::ReadNotifier;
13use zerocopy::FromBytes;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16
17use crate::backend::VhostUserMemoryRegionInfo;
18use crate::backend::VringConfigData;
19use crate::into_single_file;
20use crate::message::*;
21use crate::Connection;
22use crate::Error as VhostUserError;
23use crate::FrontendReq;
24use crate::Result as VhostUserResult;
25use crate::Result;
26
27/// Client for a vhost-user device. The API is a thin abstraction over the vhost-user protocol.
28pub struct BackendClient {
29    connection: Connection<FrontendReq>,
30}
31
32impl BackendClient {
33    /// Create a new instance.
34    pub fn new(connection: Connection<FrontendReq>) -> Self {
35        BackendClient { connection }
36    }
37
38    /// Get a bitmask of supported virtio/vhost features.
39    pub fn get_features(&mut self) -> Result<u64> {
40        let hdr = self.send_request_header(FrontendReq::GET_FEATURES, None)?;
41        let val = self.recv_reply::<VhostUserU64>(&hdr)?;
42        Ok(val.value)
43    }
44
45    /// Inform the vhost subsystem which features to enable.
46    /// This should be a subset of supported features from get_features().
47    pub fn set_features(&mut self, features: u64) -> Result<()> {
48        let val = VhostUserU64::new(features);
49        let hdr = self.send_request_with_body(FrontendReq::SET_FEATURES, &val, None)?;
50        self.wait_for_ack(&hdr)
51    }
52
53    /// Set the current process as the owner of the vhost backend.
54    /// This must be run before any other vhost commands.
55    pub fn set_owner(&self) -> Result<()> {
56        let hdr = self.send_request_header(FrontendReq::SET_OWNER, None)?;
57        self.wait_for_ack(&hdr)
58    }
59
60    /// Used to be sent to request disabling all rings
61    /// This is no longer used.
62    pub fn reset_owner(&self) -> Result<()> {
63        let hdr = self.send_request_header(FrontendReq::RESET_OWNER, None)?;
64        self.wait_for_ack(&hdr)
65    }
66
67    /// Set the memory map regions on the backend so it can translate the vring
68    /// addresses. In the ancillary data there is an array of file descriptors
69    pub fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> {
70        let mut ctx = VhostUserMemoryContext::new();
71        for region in regions.iter() {
72            let reg = VhostUserMemoryRegion {
73                guest_phys_addr: region.guest_phys_addr,
74                memory_size: region.memory_size,
75                user_addr: region.userspace_addr,
76                mmap_offset: region.mmap_offset,
77            };
78            ctx.append(&reg, region.mmap_handle);
79        }
80
81        let body = VhostUserMemory::new(ctx.regions.len() as u32);
82        let hdr = self.send_request_with_payload(
83            FrontendReq::SET_MEM_TABLE,
84            &body,
85            ctx.regions.as_bytes(),
86            Some(ctx.fds.as_slice()),
87        )?;
88        self.wait_for_ack(&hdr)
89    }
90
91    /// Set base address for page modification logging.
92    pub fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()> {
93        let val = VhostUserU64::new(base);
94        let hdr = self.send_request_with_body(
95            FrontendReq::SET_LOG_BASE,
96            &val,
97            fd.as_ref().map(std::slice::from_ref),
98        )?;
99        self.wait_for_ack(&hdr)
100    }
101
102    /// Specify an event file descriptor to signal on log write.
103    pub fn set_log_fd(&self, fd: RawDescriptor) -> Result<()> {
104        let fds = [fd];
105        let hdr = self.send_request_header(FrontendReq::SET_LOG_FD, Some(&fds))?;
106        self.wait_for_ack(&hdr)
107    }
108
109    /// Set the number of descriptors in the vring.
110    pub fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> {
111        let val = VhostUserVringState::new(queue_index as u32, num.into());
112        let hdr = self.send_request_with_body(FrontendReq::SET_VRING_NUM, &val, None)?;
113        self.wait_for_ack(&hdr)
114    }
115
116    /// Set the addresses for a given vring.
117    pub fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> {
118        let val = VhostUserVringAddr::from_config_data(queue_index as u32, config_data);
119        let hdr = self.send_request_with_body(FrontendReq::SET_VRING_ADDR, &val, None)?;
120        self.wait_for_ack(&hdr)
121    }
122
123    /// Set the first index to look for available descriptors.
124    // TODO: b/331466964 - Arguments and message format are wrong for packed queues.
125    pub fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> {
126        let val = VhostUserVringState::new(queue_index as u32, base.into());
127        let hdr = self.send_request_with_body(FrontendReq::SET_VRING_BASE, &val, None)?;
128        self.wait_for_ack(&hdr)
129    }
130
131    /// Get the available vring base offset.
132    // TODO: b/331466964 - Return type is wrong for packed queues.
133    pub fn get_vring_base(&self, queue_index: usize) -> Result<u32> {
134        let req = VhostUserVringState::new(queue_index as u32, 0);
135        let hdr = self.send_request_with_body(FrontendReq::GET_VRING_BASE, &req, None)?;
136        let reply = self.recv_reply::<VhostUserVringState>(&hdr)?;
137        Ok(reply.num)
138    }
139
140    /// Set the event to trigger when buffers have been used by the host.
141    ///
142    /// Bits (0-7) of the payload contain the vring index. Bit 8 is the invalid FD flag. This flag
143    /// is set when there is no file descriptor in the ancillary data. This signals that polling
144    /// will be used instead of waiting for the call.
145    pub fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> {
146        let hdr = self.send_fd_for_vring(
147            FrontendReq::SET_VRING_CALL,
148            queue_index,
149            event.as_raw_descriptor(),
150        )?;
151        self.wait_for_ack(&hdr)
152    }
153
154    /// Set the event that will be signaled by the guest when buffers are available for the host to
155    /// process.
156    ///
157    /// Bits (0-7) of the payload contain the vring index. Bit 8 is the invalid FD flag. This flag
158    /// is set when there is no file descriptor in the ancillary data. This signals that polling
159    /// should be used instead of waiting for a kick.
160    pub fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> {
161        let hdr = self.send_fd_for_vring(
162            FrontendReq::SET_VRING_KICK,
163            queue_index,
164            event.as_raw_descriptor(),
165        )?;
166        self.wait_for_ack(&hdr)
167    }
168
169    /// Set the event that will be signaled by the guest when error happens.
170    ///
171    /// Bits (0-7) of the payload contain the vring index. Bit 8 is the invalid FD flag. This flag
172    /// is set when there is no file descriptor in the ancillary data.
173    pub fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> {
174        let hdr = self.send_fd_for_vring(
175            FrontendReq::SET_VRING_ERR,
176            queue_index,
177            event.as_raw_descriptor(),
178        )?;
179        self.wait_for_ack(&hdr)
180    }
181
182    /// Front-end and back-end negotiate a channel over which to transfer the back-end’s internal
183    /// state during migration.
184    ///
185    /// Requires VHOST_USER_PROTOCOL_F_DEVICE_STATE to be negotiated.
186    pub fn set_device_state_fd(
187        &self,
188        transfer_direction: VhostUserTransferDirection,
189        migration_phase: VhostUserMigrationPhase,
190        fd: &impl AsRawDescriptor,
191    ) -> Result<Option<File>> {
192        // Send request.
193        let req = DeviceStateTransferParameters {
194            transfer_direction: match transfer_direction {
195                VhostUserTransferDirection::Save => 0,
196                VhostUserTransferDirection::Load => 1,
197            },
198            migration_phase: match migration_phase {
199                VhostUserMigrationPhase::Stopped => 0,
200            },
201        };
202        let hdr = self.send_request_with_body(
203            FrontendReq::SET_DEVICE_STATE_FD,
204            &req,
205            Some(&[fd.as_raw_descriptor()]),
206        )?;
207        // Receive reply.
208        let (reply, files) = self.recv_reply_with_files::<VhostUserU64>(&hdr)?;
209        let has_err = reply.value & 0xff != 0;
210        let invalid_fd = reply.value & 0x100 != 0;
211        if has_err {
212            return Err(VhostUserError::BackendInternalError);
213        }
214        match (invalid_fd, files.len()) {
215            (true, 0) => Ok(None),
216            (false, 1) => Ok(files.into_iter().next()),
217            _ => Err(VhostUserError::IncorrectFds),
218        }
219    }
220
221    /// After transferring the back-end’s internal state during migration, check whether the
222    /// back-end was able to successfully fully process the state.
223    pub fn check_device_state(&self) -> Result<()> {
224        let hdr = self.send_request_header(FrontendReq::CHECK_DEVICE_STATE, None)?;
225        let reply = self.recv_reply::<VhostUserU64>(&hdr)?;
226        if reply.value != 0 {
227            return Err(VhostUserError::BackendInternalError);
228        }
229        Ok(())
230    }
231
232    /// Get the protocol feature bitmask from the underlying vhost implementation.
233    pub fn get_protocol_features(&self) -> Result<VhostUserProtocolFeatures> {
234        let hdr = self.send_request_header(FrontendReq::GET_PROTOCOL_FEATURES, None)?;
235        let val = self.recv_reply::<VhostUserU64>(&hdr)?;
236        Ok(VhostUserProtocolFeatures::from_bits_truncate(val.value))
237    }
238
239    /// Enable protocol features in the underlying vhost implementation.
240    pub fn set_protocol_features(&mut self, features: VhostUserProtocolFeatures) -> Result<()> {
241        let val = VhostUserU64::new(features.bits());
242        let hdr = self.send_request_with_body(FrontendReq::SET_PROTOCOL_FEATURES, &val, None)?;
243        self.wait_for_ack(&hdr)
244    }
245
246    /// Query how many queues the backend supports.
247    pub fn get_queue_num(&self) -> Result<u64> {
248        let hdr = self.send_request_header(FrontendReq::GET_QUEUE_NUM, None)?;
249        let val = self.recv_reply::<VhostUserU64>(&hdr)?;
250        Ok(val.value)
251    }
252
253    /// Signal backend to enable or disable corresponding vring.
254    ///
255    /// Backend must not pass data to/from the ring until ring is enabled by
256    /// VHOST_USER_SET_VRING_ENABLE with parameter 1, or after it has been
257    /// disabled by VHOST_USER_SET_VRING_ENABLE with parameter 0.
258    pub fn set_vring_enable(&self, queue_index: usize, enable: bool) -> Result<()> {
259        let val = VhostUserVringState::new(queue_index as u32, enable.into());
260        let hdr = self.send_request_with_body(FrontendReq::SET_VRING_ENABLE, &val, None)?;
261        self.wait_for_ack(&hdr)
262    }
263
264    /// Fetch the contents of the virtio device configuration space.
265    pub fn get_config(
266        &self,
267        offset: u32,
268        size: u32,
269        flags: VhostUserConfigFlags,
270        buf: &[u8],
271    ) -> Result<(VhostUserConfig, VhostUserConfigPayload)> {
272        let body = VhostUserConfig::new(offset, size, flags);
273
274        // vhost-user spec states that:
275        // "Request payload: virtio device config space"
276        // "Reply payload: virtio device config space"
277        let hdr = self.send_request_with_payload(FrontendReq::GET_CONFIG, &body, buf, None)?;
278        let (body_reply, buf_reply, rfds) =
279            self.recv_reply_with_payload::<VhostUserConfig>(&hdr)?;
280        if !rfds.is_empty() {
281            return Err(VhostUserError::InvalidMessage);
282        } else if body_reply.size == 0 {
283            return Err(VhostUserError::BackendInternalError);
284        } else if body_reply.size != body.size
285            || body_reply.size as usize != buf.len()
286            || body_reply.offset != body.offset
287        {
288            return Err(VhostUserError::InvalidMessage);
289        }
290
291        Ok((body_reply, buf_reply))
292    }
293
294    /// Change the virtio device configuration space. It also can be used for live migration on the
295    /// destination host to set readonly configuration space fields.
296    pub fn set_config(&self, offset: u32, flags: VhostUserConfigFlags, buf: &[u8]) -> Result<()> {
297        let body = VhostUserConfig::new(
298            offset,
299            buf.len()
300                .try_into()
301                .map_err(VhostUserError::InvalidCastToInt)?,
302            flags,
303        );
304
305        let hdr = self.send_request_with_payload(FrontendReq::SET_CONFIG, &body, buf, None)?;
306        self.wait_for_ack(&hdr)
307    }
308
309    /// Setup backend communication channel.
310    pub fn set_backend_req_fd(&self, fd: &dyn AsRawDescriptor) -> Result<()> {
311        let fds = [fd.as_raw_descriptor()];
312        let hdr = self.send_request_header(FrontendReq::SET_BACKEND_REQ_FD, Some(&fds))?;
313        self.wait_for_ack(&hdr)
314    }
315
316    /// Retrieve shared buffer for inflight I/O tracking.
317    pub fn get_inflight_fd(
318        &self,
319        inflight: &VhostUserInflight,
320    ) -> Result<(VhostUserInflight, File)> {
321        let hdr = self.send_request_with_body(FrontendReq::GET_INFLIGHT_FD, inflight, None)?;
322        let (inflight, files) = self.recv_reply_with_files::<VhostUserInflight>(&hdr)?;
323
324        match into_single_file(files) {
325            Some(file) => Ok((inflight, file)),
326            None => Err(VhostUserError::IncorrectFds),
327        }
328    }
329
330    /// Set shared buffer for inflight I/O tracking.
331    pub fn set_inflight_fd(&self, inflight: &VhostUserInflight, fd: RawDescriptor) -> Result<()> {
332        let hdr =
333            self.send_request_with_body(FrontendReq::SET_INFLIGHT_FD, inflight, Some(&[fd]))?;
334        self.wait_for_ack(&hdr)
335    }
336
337    /// Query the maximum amount of memory slots supported by the backend.
338    pub fn get_max_mem_slots(&self) -> Result<u64> {
339        let hdr = self.send_request_header(FrontendReq::GET_MAX_MEM_SLOTS, None)?;
340        let val = self.recv_reply::<VhostUserU64>(&hdr)?;
341
342        Ok(val.value)
343    }
344
345    /// Add a new guest memory mapping for vhost to use.
346    pub fn add_mem_region(&self, region: &VhostUserMemoryRegionInfo) -> Result<()> {
347        let body = VhostUserSingleMemoryRegion::new(
348            region.guest_phys_addr,
349            region.memory_size,
350            region.userspace_addr,
351            region.mmap_offset,
352        );
353        let fds = [region.mmap_handle];
354        let hdr = self.send_request_with_body(FrontendReq::ADD_MEM_REG, &body, Some(&fds))?;
355        self.wait_for_ack(&hdr)
356    }
357
358    /// Remove a guest memory mapping from vhost.
359    pub fn remove_mem_region(&self, region: &VhostUserMemoryRegionInfo) -> Result<()> {
360        let body = VhostUserSingleMemoryRegion::new(
361            region.guest_phys_addr,
362            region.memory_size,
363            region.userspace_addr,
364            region.mmap_offset,
365        );
366        let hdr = self.send_request_with_body(FrontendReq::REM_MEM_REG, &body, None)?;
367        self.wait_for_ack(&hdr)
368    }
369
370    /// Get the shared memory configuration.
371    pub fn get_shmem_config(&self) -> Result<Vec<u64>> {
372        let hdr = self.send_request_header(FrontendReq::GET_SHMEM_CONFIG, None)?;
373        let (body_reply, buf_reply, _rfds) =
374            self.recv_reply_with_payload::<VhostUserShMemConfigHeader>(&hdr)?;
375        let memory_sizes = <[u64]>::ref_from_bytes_with_elems(
376            buf_reply.as_slice(),
377            body_reply.nregions.try_into().unwrap(),
378        )
379        .map_err(|_| VhostUserError::InvalidMessage)?;
380        Ok(memory_sizes.to_vec())
381    }
382
383    fn send_request_header(
384        &self,
385        code: FrontendReq,
386        fds: Option<&[RawDescriptor]>,
387    ) -> VhostUserResult<VhostUserMsgHeader<FrontendReq>> {
388        let hdr = self.new_request_header(code, 0);
389        self.connection.send_header_only_message(&hdr, fds)?;
390        Ok(hdr)
391    }
392
393    fn send_request_with_body<T: IntoBytes + Immutable>(
394        &self,
395        code: FrontendReq,
396        msg: &T,
397        fds: Option<&[RawDescriptor]>,
398    ) -> VhostUserResult<VhostUserMsgHeader<FrontendReq>> {
399        let hdr = self.new_request_header(code, mem::size_of::<T>() as u32);
400        self.connection.send_message(&hdr, msg, fds)?;
401        Ok(hdr)
402    }
403
404    fn send_request_with_payload<T: IntoBytes + Immutable>(
405        &self,
406        code: FrontendReq,
407        msg: &T,
408        payload: &[u8],
409        fds: Option<&[RawDescriptor]>,
410    ) -> VhostUserResult<VhostUserMsgHeader<FrontendReq>> {
411        let len = mem::size_of::<T>()
412            .checked_add(payload.len())
413            .ok_or(VhostUserError::OversizedMsg)?;
414        let hdr = self.new_request_header(
415            code,
416            len.try_into().map_err(VhostUserError::InvalidCastToInt)?,
417        );
418        self.connection
419            .send_message_with_payload(&hdr, msg, payload, fds)?;
420        Ok(hdr)
421    }
422
423    fn send_fd_for_vring(
424        &self,
425        code: FrontendReq,
426        queue_index: usize,
427        fd: RawDescriptor,
428    ) -> VhostUserResult<VhostUserMsgHeader<FrontendReq>> {
429        // Bits (0-7) of the payload contain the vring index. Bit 8 is the invalid FD flag.
430        // This flag is set when there is no file descriptor in the ancillary data. This signals
431        // that polling will be used instead of waiting for the call.
432        let msg = VhostUserU64::new(queue_index as u64);
433        let hdr = self.new_request_header(code, mem::size_of::<VhostUserU64>() as u32);
434        self.connection.send_message(&hdr, &msg, Some(&[fd]))?;
435        Ok(hdr)
436    }
437
438    fn recv_reply<T: Sized + FromBytes + IntoBytes + Default + VhostUserMsgValidator>(
439        &self,
440        hdr: &VhostUserMsgHeader<FrontendReq>,
441    ) -> VhostUserResult<T> {
442        if hdr.is_reply() {
443            return Err(VhostUserError::InvalidParam(
444                "recv_reply: header is not a reply",
445            ));
446        }
447        let (reply, body, rfds) = self.connection.recv_message::<T>()?;
448        if !reply.is_valid() || !reply.is_reply_for(hdr) || !rfds.is_empty() || !body.is_valid() {
449            return Err(VhostUserError::InvalidMessage);
450        }
451        Ok(body)
452    }
453
454    fn recv_reply_with_files<T: Sized + IntoBytes + FromBytes + Default + VhostUserMsgValidator>(
455        &self,
456        hdr: &VhostUserMsgHeader<FrontendReq>,
457    ) -> VhostUserResult<(T, Vec<File>)> {
458        if hdr.is_reply() {
459            return Err(VhostUserError::InvalidParam(
460                "with_files: expected a reply, but the header is not marked as a reply",
461            ));
462        }
463
464        let (reply, body, files) = self.connection.recv_message::<T>()?;
465        if !reply.is_valid() || !reply.is_reply_for(hdr) || !body.is_valid() {
466            return Err(VhostUserError::InvalidMessage);
467        }
468        Ok((body, files))
469    }
470
471    fn recv_reply_with_payload<
472        T: Sized + IntoBytes + FromBytes + Default + VhostUserMsgValidator,
473    >(
474        &self,
475        hdr: &VhostUserMsgHeader<FrontendReq>,
476    ) -> VhostUserResult<(T, Vec<u8>, Vec<File>)> {
477        if hdr.is_reply() {
478            return Err(VhostUserError::InvalidParam(
479                "with_payload: expected a reply, but the header is not marked as a reply",
480            ));
481        }
482
483        let (reply, body, buf, files, more_files) =
484            self.connection.recv_message_with_payload::<T>()?;
485        if !reply.is_valid()
486            || !reply.is_reply_for(hdr)
487            || !files.is_empty()
488            || !more_files.is_empty()
489            || !body.is_valid()
490        {
491            return Err(VhostUserError::InvalidMessage);
492        }
493
494        Ok((body, buf, files))
495    }
496
497    fn wait_for_ack(&self, hdr: &VhostUserMsgHeader<FrontendReq>) -> VhostUserResult<()> {
498        if !hdr.is_need_reply() {
499            return Ok(());
500        }
501
502        let (reply, body, rfds) = self.connection.recv_message::<VhostUserU64>()?;
503        if !reply.is_valid() || !reply.is_reply_for(hdr) || !rfds.is_empty() || !body.is_valid() {
504            return Err(VhostUserError::InvalidMessage);
505        }
506        if body.value != 0 {
507            return Err(VhostUserError::BackendInternalError);
508        }
509        Ok(())
510    }
511
512    #[inline]
513    fn new_request_header(
514        &self,
515        request: FrontendReq,
516        size: u32,
517    ) -> VhostUserMsgHeader<FrontendReq> {
518        VhostUserMsgHeader::new_request_header(request, size, false)
519    }
520}
521
522#[cfg(windows)]
523impl CloseNotifier for BackendClient {
524    fn get_close_notifier(&self) -> &dyn AsRawDescriptor {
525        self.connection.0.get_close_notifier()
526    }
527}
528
529impl ReadNotifier for BackendClient {
530    fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
531        self.connection.0.get_read_notifier()
532    }
533}
534
535// TODO(b/221882601): likely need pairs of RDs and/or SharedMemory to represent mmaps on Windows.
536/// Context object to pass guest memory configuration to BackendClient::set_mem_table().
537struct VhostUserMemoryContext {
538    regions: VhostUserMemoryPayload,
539    fds: Vec<RawDescriptor>,
540}
541
542impl VhostUserMemoryContext {
543    /// Create a context object.
544    pub fn new() -> Self {
545        VhostUserMemoryContext {
546            regions: VhostUserMemoryPayload::new(),
547            fds: Vec::new(),
548        }
549    }
550
551    /// Append a user memory region and corresponding RawDescriptor into the context object.
552    pub fn append(&mut self, region: &VhostUserMemoryRegion, fd: RawDescriptor) {
553        self.regions.push(*region);
554        self.fds.push(fd);
555    }
556}
557
558#[cfg(test)]
559mod tests {
560    use base::INVALID_DESCRIPTOR;
561
562    use super::*;
563
564    const BUFFER_SIZE: usize = 0x1001;
565    const INVALID_PROTOCOL_FEATURE: u64 = 1 << 63;
566
567    fn create_pair() -> (BackendClient, Connection<FrontendReq>) {
568        let (client_connection, server_connection) = Connection::pair().unwrap();
569        let backend_client = BackendClient::new(client_connection);
570        (backend_client, server_connection)
571    }
572
573    #[test]
574    fn create_backend_client() {
575        let (backend_client, peer) = create_pair();
576
577        assert!(backend_client.connection.as_raw_descriptor() != INVALID_DESCRIPTOR);
578        // Send two messages continuously
579        backend_client.set_owner().unwrap();
580        backend_client.reset_owner().unwrap();
581
582        let (hdr, rfds) = peer.recv_header().unwrap();
583        assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
584        assert_eq!(hdr.get_size(), 0);
585        assert_eq!(hdr.get_version(), 0x1);
586        assert!(rfds.is_empty());
587
588        let (hdr, rfds) = peer.recv_header().unwrap();
589        assert_eq!(hdr.get_code(), Ok(FrontendReq::RESET_OWNER));
590        assert_eq!(hdr.get_size(), 0);
591        assert_eq!(hdr.get_version(), 0x1);
592        assert!(rfds.is_empty());
593    }
594
595    #[test]
596    fn test_features() {
597        let (mut backend_client, peer) = create_pair();
598
599        backend_client.set_owner().unwrap();
600        let (hdr, rfds) = peer.recv_header().unwrap();
601        assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
602        assert_eq!(hdr.get_size(), 0);
603        assert_eq!(hdr.get_version(), 0x1);
604        assert!(rfds.is_empty());
605
606        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_FEATURES, 8);
607        let msg = VhostUserU64::new(0x15);
608        peer.send_message(&hdr, &msg, None).unwrap();
609        let features = backend_client.get_features().unwrap();
610        assert_eq!(features, 0x15u64);
611        let (_hdr, rfds) = peer.recv_header().unwrap();
612        assert!(rfds.is_empty());
613
614        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::SET_FEATURES, 8);
615        let msg = VhostUserU64::new(0x15);
616        peer.send_message(&hdr, &msg, None).unwrap();
617        backend_client.set_features(0x15).unwrap();
618        let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
619        assert!(rfds.is_empty());
620        let val = msg.value;
621        assert_eq!(val, 0x15);
622
623        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_FEATURES, 8);
624        let msg = 0x15u32;
625        peer.send_message(&hdr, &msg, None).unwrap();
626        assert!(backend_client.get_features().is_err());
627    }
628
629    #[test]
630    fn test_protocol_features() {
631        let (mut backend_client, peer) = create_pair();
632
633        backend_client.set_owner().unwrap();
634        let (hdr, rfds) = peer.recv_header().unwrap();
635        assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
636        assert!(rfds.is_empty());
637
638        let pfeatures = VhostUserProtocolFeatures::all();
639        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_PROTOCOL_FEATURES, 8);
640        // Unknown feature bits should be ignored.
641        let msg = VhostUserU64::new(pfeatures.bits() | INVALID_PROTOCOL_FEATURE);
642        peer.send_message(&hdr, &msg, None).unwrap();
643        let features = backend_client.get_protocol_features().unwrap();
644        assert_eq!(features, pfeatures);
645        let (_hdr, rfds) = peer.recv_header().unwrap();
646        assert!(rfds.is_empty());
647
648        backend_client
649            .set_protocol_features(VhostUserProtocolFeatures::all())
650            .unwrap();
651        let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
652        assert!(rfds.is_empty());
653        let val = msg.value;
654        assert_eq!(val, pfeatures.bits());
655
656        let vfeatures = 0x15 | 1 << VHOST_USER_F_PROTOCOL_FEATURES;
657        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_FEATURES, 8);
658        let msg = VhostUserU64::new(vfeatures);
659        peer.send_message(&hdr, &msg, None).unwrap();
660        let features = backend_client.get_features().unwrap();
661        assert_eq!(features, vfeatures);
662        let (_hdr, rfds) = peer.recv_header().unwrap();
663        assert!(rfds.is_empty());
664
665        backend_client.set_features(vfeatures).unwrap();
666        let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
667        assert!(rfds.is_empty());
668        let val = msg.value;
669        assert_eq!(val, vfeatures);
670
671        let pfeatures = VhostUserProtocolFeatures::all();
672        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_PROTOCOL_FEATURES, 8);
673        // Unknown feature bits should be ignored.
674        let msg = VhostUserU64::new(pfeatures.bits() | INVALID_PROTOCOL_FEATURE);
675        peer.send_message(&hdr, &msg, None).unwrap();
676        let features = backend_client.get_protocol_features().unwrap();
677        assert_eq!(features, pfeatures);
678        let (_hdr, rfds) = peer.recv_header().unwrap();
679        assert!(rfds.is_empty());
680
681        backend_client.set_protocol_features(pfeatures).unwrap();
682        let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
683        assert!(rfds.is_empty());
684        let val = msg.value;
685        assert_eq!(val, pfeatures.bits());
686
687        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::SET_PROTOCOL_FEATURES, 8);
688        let msg = VhostUserU64::new(pfeatures.bits());
689        peer.send_message(&hdr, &msg, None).unwrap();
690        assert!(backend_client.get_protocol_features().is_err());
691    }
692
693    #[test]
694    fn test_backend_client_get_config_negative0() {
695        let (backend_client, peer) = create_pair();
696        let buf = vec![0x0; BUFFER_SIZE];
697
698        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
699        let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
700        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
701            .unwrap();
702        assert!(backend_client
703            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
704            .is_ok());
705
706        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_FEATURES, 16);
707        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
708            .unwrap();
709        assert!(backend_client
710            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
711            .is_err());
712    }
713
714    #[test]
715    fn test_backend_client_get_config_negative1() {
716        let (backend_client, peer) = create_pair();
717        let buf = vec![0x0; BUFFER_SIZE];
718
719        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
720        let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
721        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
722            .unwrap();
723        assert!(backend_client
724            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
725            .is_ok());
726
727        let hdr = VhostUserMsgHeader::new_request_header(FrontendReq::GET_CONFIG, 16, false);
728        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
729            .unwrap();
730        assert!(backend_client
731            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
732            .is_err());
733    }
734
735    #[test]
736    fn test_backend_client_get_config_negative2() {
737        let (backend_client, peer) = create_pair();
738        let buf = vec![0x0; BUFFER_SIZE];
739
740        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
741        let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
742        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
743            .unwrap();
744        assert!(backend_client
745            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
746            .is_ok());
747    }
748
749    #[test]
750    fn test_backend_client_get_config_negative3() {
751        let (backend_client, peer) = create_pair();
752        let buf = vec![0x0; BUFFER_SIZE];
753
754        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
755        let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
756        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
757            .unwrap();
758        assert!(backend_client
759            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
760            .is_ok());
761
762        msg.offset = 0;
763        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
764            .unwrap();
765        assert!(backend_client
766            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
767            .is_err());
768    }
769
770    #[test]
771    fn test_backend_client_get_config_negative4() {
772        let (backend_client, peer) = create_pair();
773        let buf = vec![0x0; BUFFER_SIZE];
774
775        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
776        let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
777        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
778            .unwrap();
779        assert!(backend_client
780            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
781            .is_ok());
782
783        msg.offset = 0x101;
784        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
785            .unwrap();
786        assert!(backend_client
787            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
788            .is_err());
789    }
790
791    #[test]
792    fn test_backend_client_get_config_negative5() {
793        let (backend_client, peer) = create_pair();
794        let buf = vec![0x0; BUFFER_SIZE];
795
796        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
797        let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
798        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
799            .unwrap();
800        assert!(backend_client
801            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
802            .is_ok());
803
804        msg.offset = (BUFFER_SIZE) as u32;
805        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
806            .unwrap();
807        assert!(backend_client
808            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
809            .is_err());
810    }
811
812    #[test]
813    fn test_backend_client_get_config_negative6() {
814        let (backend_client, peer) = create_pair();
815        let buf = vec![0x0; BUFFER_SIZE];
816
817        let hdr = VhostUserMsgHeader::new_reply_header(FrontendReq::GET_CONFIG, 16);
818        let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
819        peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
820            .unwrap();
821        assert!(backend_client
822            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
823            .is_ok());
824
825        msg.size = 6;
826        peer.send_message_with_payload(&hdr, &msg, &buf[0..6], None)
827            .unwrap();
828        assert!(backend_client
829            .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
830            .is_err());
831    }
832}