1 // Copyright (C) 2019 Alibaba Cloud. All rights reserved.
2 // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
3 //
4 // Copyright 2017 The Chromium OS Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style license that can be
6 // found in the LICENSE-BSD-Google file.
7 
8 //! Kernel-based vhost-vsock backend.
9 
10 use std::fs::{File, OpenOptions};
11 use std::os::unix::fs::OpenOptionsExt;
12 use std::os::unix::io::{AsRawFd, RawFd};
13 
14 use vm_memory::GuestAddressSpace;
15 use vmm_sys_util::ioctl::ioctl_with_ref;
16 
17 use super::vhost_binding::{VHOST_VSOCK_SET_GUEST_CID, VHOST_VSOCK_SET_RUNNING};
18 use super::{ioctl_result, Error, Result, VhostKernBackend};
19 use crate::vsock::VhostVsock;
20 
21 const VHOST_PATH: &str = "/dev/vhost-vsock";
22 
23 /// Handle for running VHOST_VSOCK ioctls.
24 pub struct Vsock<AS: GuestAddressSpace> {
25     fd: File,
26     mem: AS,
27 }
28 
29 impl<AS: GuestAddressSpace> Vsock<AS> {
30     /// Open a handle to a new VHOST-VSOCK instance.
new(mem: AS) -> Result<Self>31     pub fn new(mem: AS) -> Result<Self> {
32         Ok(Vsock {
33             fd: OpenOptions::new()
34                 .read(true)
35                 .write(true)
36                 .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK)
37                 .open(VHOST_PATH)
38                 .map_err(Error::VhostOpen)?,
39             mem,
40         })
41     }
42 
set_running(&self, running: bool) -> Result<()>43     fn set_running(&self, running: bool) -> Result<()> {
44         let on: ::std::os::raw::c_int = if running { 1 } else { 0 };
45 
46         // SAFETY: This ioctl is called on a valid vhost-vsock fd and has its
47         // return value checked.
48         let ret = unsafe { ioctl_with_ref(&self.fd, VHOST_VSOCK_SET_RUNNING(), &on) };
49         ioctl_result(ret, ())
50     }
51 }
52 
53 impl<AS: GuestAddressSpace> VhostVsock for Vsock<AS> {
set_guest_cid(&self, cid: u64) -> Result<()>54     fn set_guest_cid(&self, cid: u64) -> Result<()> {
55         // SAFETY: This ioctl is called on a valid vhost-vsock fd and has its
56         // return value checked.
57         let ret = unsafe { ioctl_with_ref(&self.fd, VHOST_VSOCK_SET_GUEST_CID(), &cid) };
58         ioctl_result(ret, ())
59     }
60 
start(&self) -> Result<()>61     fn start(&self) -> Result<()> {
62         self.set_running(true)
63     }
64 
stop(&self) -> Result<()>65     fn stop(&self) -> Result<()> {
66         self.set_running(false)
67     }
68 }
69 
70 impl<AS: GuestAddressSpace> VhostKernBackend for Vsock<AS> {
71     type AS = AS;
72 
mem(&self) -> &Self::AS73     fn mem(&self) -> &Self::AS {
74         &self.mem
75     }
76 }
77 
78 impl<AS: GuestAddressSpace> AsRawFd for Vsock<AS> {
as_raw_fd(&self) -> RawFd79     fn as_raw_fd(&self) -> RawFd {
80         self.fd.as_raw_fd()
81     }
82 }
83 
84 #[cfg(test)]
85 mod tests {
86     use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap};
87     use vmm_sys_util::eventfd::EventFd;
88 
89     use super::*;
90     use crate::{
91         VhostBackend, VhostUserDirtyLogRegion, VhostUserMemoryRegionInfo, VringConfigData,
92     };
93 
94     #[test]
test_vsock_new_device()95     fn test_vsock_new_device() {
96         let m = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10_0000)]).unwrap();
97         let vsock = Vsock::new(&m).unwrap();
98 
99         assert!(vsock.as_raw_fd() >= 0);
100         assert!(vsock.mem().find_region(GuestAddress(0x100)).is_some());
101         assert!(vsock.mem().find_region(GuestAddress(0x10_0000)).is_none());
102     }
103 
104     #[test]
test_vsock_is_valid()105     fn test_vsock_is_valid() {
106         let m = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10_0000)]).unwrap();
107         let vsock = Vsock::new(&m).unwrap();
108 
109         let mut config = VringConfigData {
110             queue_max_size: 32,
111             queue_size: 32,
112             flags: 0,
113             desc_table_addr: 0x1000,
114             used_ring_addr: 0x2000,
115             avail_ring_addr: 0x3000,
116             log_addr: None,
117         };
118         assert!(vsock.is_valid(&config));
119 
120         config.queue_size = 0;
121         assert!(!vsock.is_valid(&config));
122         config.queue_size = 31;
123         assert!(!vsock.is_valid(&config));
124         config.queue_size = 33;
125         assert!(!vsock.is_valid(&config));
126     }
127 
128     #[test]
test_vsock_ioctls()129     fn test_vsock_ioctls() {
130         let m = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10_0000)]).unwrap();
131         let vsock = Vsock::new(&m).unwrap();
132 
133         let features = vsock.get_features().unwrap();
134         vsock.set_features(features).unwrap();
135 
136         vsock.set_owner().unwrap();
137 
138         vsock.set_mem_table(&[]).unwrap_err();
139 
140         /*
141         let region = VhostUserMemoryRegionInfo {
142             guest_phys_addr: 0x0,
143             memory_size: 0x10_0000,
144             userspace_addr: 0,
145             mmap_offset: 0,
146             mmap_handle: -1,
147         };
148         vsock.set_mem_table(&[region]).unwrap_err();
149          */
150 
151         let region = VhostUserMemoryRegionInfo::new(
152             0x0,
153             0x10_0000,
154             m.get_host_address(GuestAddress(0x0)).unwrap() as u64,
155             0,
156             -1,
157         );
158         vsock.set_mem_table(&[region]).unwrap();
159 
160         vsock
161             .set_log_base(
162                 0x4000,
163                 Some(VhostUserDirtyLogRegion {
164                     mmap_size: 0x1000,
165                     mmap_offset: 0x10,
166                     mmap_handle: 1,
167                 }),
168             )
169             .unwrap_err();
170         vsock.set_log_base(0x4000, None).unwrap();
171 
172         let eventfd = EventFd::new(0).unwrap();
173         vsock.set_log_fd(eventfd.as_raw_fd()).unwrap();
174 
175         vsock.set_vring_num(0, 32).unwrap();
176 
177         let config = VringConfigData {
178             queue_max_size: 32,
179             queue_size: 32,
180             flags: 0,
181             desc_table_addr: 0x1000,
182             used_ring_addr: 0x2000,
183             avail_ring_addr: 0x3000,
184             log_addr: None,
185         };
186         vsock.set_vring_addr(0, &config).unwrap();
187         vsock.set_vring_base(0, 1).unwrap();
188         vsock.set_vring_call(0, &eventfd).unwrap();
189         vsock.set_vring_kick(0, &eventfd).unwrap();
190         vsock.set_vring_err(0, &eventfd).unwrap();
191         assert_eq!(vsock.get_vring_base(0).unwrap(), 1);
192         vsock.set_guest_cid(0xdead).unwrap();
193         //vsock.start().unwrap();
194         //vsock.stop().unwrap();
195     }
196 }
197