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