xref: /cloud-hypervisor/virtio-devices/src/vsock/mod.rs (revision 3ce0fef7fd546467398c914dbc74d8542e45cf6f)
1 // Copyright 2019 Intel Corporation. All Rights Reserved.
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 // Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 // SPDX-License-Identifier: Apache-2.0
6 //
7 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
8 // Use of this source code is governed by a BSD-style license that can be
9 // found in the THIRD-PARTY file.
10 
11 mod csm;
12 mod device;
13 mod packet;
14 mod unix;
15 
16 pub use self::device::Vsock;
17 pub use self::unix::VsockUnixBackend;
18 pub use self::unix::VsockUnixError;
19 
20 use packet::VsockPacket;
21 use std::os::unix::io::RawFd;
22 
23 mod defs {
24 
25     /// Max vsock packet data/buffer size.
26     pub const MAX_PKT_BUF_SIZE: usize = 64 * 1024;
27 
28     pub mod uapi {
29 
30         /// Vsock packet operation IDs.
31         /// Defined in `/include/uapi/linux/virtio_vsock.h`.
32         ///
33         /// Connection request.
34         pub const VSOCK_OP_REQUEST: u16 = 1;
35         /// Connection response.
36         pub const VSOCK_OP_RESPONSE: u16 = 2;
37         /// Connection reset.
38         pub const VSOCK_OP_RST: u16 = 3;
39         /// Connection clean shutdown.
40         pub const VSOCK_OP_SHUTDOWN: u16 = 4;
41         /// Connection data (read/write).
42         pub const VSOCK_OP_RW: u16 = 5;
43         /// Flow control credit update.
44         pub const VSOCK_OP_CREDIT_UPDATE: u16 = 6;
45         /// Flow control credit update request.
46         pub const VSOCK_OP_CREDIT_REQUEST: u16 = 7;
47 
48         /// Vsock packet flags.
49         /// Defined in `/include/uapi/linux/virtio_vsock.h`.
50         ///
51         /// Valid with a VSOCK_OP_SHUTDOWN packet: the packet sender will receive no more data.
52         pub const VSOCK_FLAGS_SHUTDOWN_RCV: u32 = 1;
53         /// Valid with a VSOCK_OP_SHUTDOWN packet: the packet sender will send no more data.
54         pub const VSOCK_FLAGS_SHUTDOWN_SEND: u32 = 2;
55 
56         /// Vsock packet type.
57         /// Defined in `/include/uapi/linux/virtio_vsock.h`.
58         ///
59         /// Stream / connection-oriented packet (the only currently valid type).
60         pub const VSOCK_TYPE_STREAM: u16 = 1;
61 
62         pub const VSOCK_HOST_CID: u64 = 2;
63     }
64 }
65 
66 #[derive(Debug)]
67 pub enum VsockError {
68     /// The vsock data/buffer virtio descriptor length is smaller than expected.
69     BufDescTooSmall,
70     /// The vsock data/buffer virtio descriptor is expected, but missing.
71     BufDescMissing,
72     /// Chained GuestMemory error.
73     GuestMemory,
74     /// Bounds check failed on guest memory pointer.
75     GuestMemoryBounds,
76     /// The vsock header descriptor length is too small.
77     HdrDescTooSmall(u32),
78     /// The vsock header descriptor is expected, but missing.
79     HdrDescMissing,
80     /// The vsock header `len` field holds an invalid value.
81     InvalidPktLen(u32),
82     /// A data fetch was attempted when no data was available.
83     NoData,
84     /// A data buffer was expected for the provided packet, but it is missing.
85     PktBufMissing,
86     /// Encountered an unexpected write-only virtio descriptor.
87     UnreadableDescriptor,
88     /// Encountered an unexpected read-only virtio descriptor.
89     UnwritableDescriptor,
90 }
91 type Result<T> = std::result::Result<T, VsockError>;
92 
93 #[derive(Debug)]
94 pub enum VsockEpollHandlerError {
95     /// The vsock data/buffer virtio descriptor length is smaller than expected.
96     BufDescTooSmall,
97     /// The vsock data/buffer virtio descriptor is expected, but missing.
98     BufDescMissing,
99     /// Chained GuestMemory error.
100     GuestMemory,
101     /// Bounds check failed on guest memory pointer.
102     GuestMemoryBounds,
103     /// The vsock header descriptor length is too small.
104     HdrDescTooSmall(u32),
105     /// The vsock header `len` field holds an invalid value.
106     InvalidPktLen(u32),
107     /// A data fetch was attempted when no data was available.
108     NoData,
109     /// A data buffer was expected for the provided packet, but it is missing.
110     PktBufMissing,
111     /// Encountered an unexpected write-only virtio descriptor.
112     UnreadableDescriptor,
113     /// Encountered an unexpected read-only virtio descriptor.
114     UnwritableDescriptor,
115 }
116 
117 /// A passive, event-driven object, that needs to be notified whenever an epoll-able event occurs.
118 /// An event-polling control loop will use `get_polled_fd()` and `get_polled_evset()` to query
119 /// the listener for the file descriptor and the set of events it's interested in. When such an
120 /// event occurs, the control loop will route the event to the listener via `notify()`.
121 ///
122 pub trait VsockEpollListener {
123     /// Get the file descriptor the listener needs polled.
124     fn get_polled_fd(&self) -> RawFd;
125 
126     /// Get the set of events for which the listener wants to be notified.
127     fn get_polled_evset(&self) -> epoll::Events;
128 
129     /// Notify the listener that one ore more events have occurred.
130     fn notify(&mut self, evset: epoll::Events);
131 }
132 
133 /// Any channel that handles vsock packet traffic: sending and receiving packets. Since we're
134 /// implementing the device model here, our responsibility is to always process the sending of
135 /// packets (i.e. the TX queue). So, any locally generated data, addressed to the driver (e.g.
136 /// a connection response or RST), will have to be queued, until we get to processing the RX queue.
137 ///
138 /// Note: `recv_pkt()` and `send_pkt()` are named analogous to `Read::read()` and `Write::write()`,
139 ///       respectively. I.e.
140 ///       - `recv_pkt(&mut pkt)` will read data from the channel, and place it into `pkt`; and
141 ///       - `send_pkt(&pkt)` will fetch data from `pkt`, and place it into the channel.
142 pub trait VsockChannel {
143     /// Read/receive an incoming packet from the channel.
144     fn recv_pkt(&mut self, pkt: &mut VsockPacket) -> Result<()>;
145 
146     /// Write/send a packet through the channel.
147     fn send_pkt(&mut self, pkt: &VsockPacket) -> Result<()>;
148 
149     /// Checks whether there is pending incoming data inside the channel, meaning that a subsequent
150     /// call to `recv_pkt()` won't fail.
151     fn has_pending_rx(&self) -> bool;
152 }
153 
154 /// The vsock backend, which is basically an epoll-event-driven vsock channel, that needs to be
155 /// sendable through a mpsc channel (the latter due to how `vmm::EpollContext` works).
156 /// Currently, the only implementation we have is `crate::virtio::unix::muxer::VsockMuxer`, which
157 /// translates guest-side vsock connections to host-side Unix domain socket connections.
158 pub trait VsockBackend: VsockChannel + VsockEpollListener + Send {}
159 
160 #[cfg(test)]
161 mod tests {
162     use super::device::{VsockEpollHandler, RX_QUEUE_EVENT, TX_QUEUE_EVENT};
163     use super::packet::VSOCK_PKT_HDR_SIZE;
164     use super::*;
165     use crate::device::{VirtioInterrupt, VirtioInterruptType};
166     use crate::epoll_helper::EpollHelperHandler;
167     use crate::EpollHelper;
168     use crate::GuestMemoryMmap;
169     use libc::EFD_NONBLOCK;
170     use std::os::unix::io::AsRawFd;
171     use std::path::PathBuf;
172     use std::sync::{Arc, RwLock};
173     use virtio_bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE};
174     use vm_memory::{GuestAddress, GuestMemoryAtomic};
175     use vm_virtio::queue::testing::VirtQueue as GuestQ;
176     use vmm_sys_util::eventfd::EventFd;
177 
178     pub struct NoopVirtioInterrupt {}
179 
180     impl VirtioInterrupt for NoopVirtioInterrupt {
181         fn trigger(
182             &self,
183             _int_type: VirtioInterruptType,
184         ) -> std::result::Result<(), std::io::Error> {
185             Ok(())
186         }
187     }
188 
189     pub struct TestBackend {
190         pub evfd: EventFd,
191         pub rx_err: Option<VsockError>,
192         pub tx_err: Option<VsockError>,
193         pub pending_rx: bool,
194         pub rx_ok_cnt: usize,
195         pub tx_ok_cnt: usize,
196         pub evset: Option<epoll::Events>,
197     }
198     impl TestBackend {
199         pub fn new() -> Self {
200             Self {
201                 evfd: EventFd::new(EFD_NONBLOCK).unwrap(),
202                 rx_err: None,
203                 tx_err: None,
204                 pending_rx: false,
205                 rx_ok_cnt: 0,
206                 tx_ok_cnt: 0,
207                 evset: None,
208             }
209         }
210         pub fn set_rx_err(&mut self, err: Option<VsockError>) {
211             self.rx_err = err;
212         }
213         pub fn set_tx_err(&mut self, err: Option<VsockError>) {
214             self.tx_err = err;
215         }
216         pub fn set_pending_rx(&mut self, prx: bool) {
217             self.pending_rx = prx;
218         }
219     }
220     impl VsockChannel for TestBackend {
221         fn recv_pkt(&mut self, _pkt: &mut VsockPacket) -> Result<()> {
222             match self.rx_err.take() {
223                 None => {
224                     self.rx_ok_cnt += 1;
225                     Ok(())
226                 }
227                 Some(e) => Err(e),
228             }
229         }
230         fn send_pkt(&mut self, _pkt: &VsockPacket) -> Result<()> {
231             match self.tx_err.take() {
232                 None => {
233                     self.tx_ok_cnt += 1;
234                     Ok(())
235                 }
236                 Some(e) => Err(e),
237             }
238         }
239         fn has_pending_rx(&self) -> bool {
240             self.pending_rx
241         }
242     }
243     impl VsockEpollListener for TestBackend {
244         fn get_polled_fd(&self) -> RawFd {
245             self.evfd.as_raw_fd()
246         }
247         fn get_polled_evset(&self) -> epoll::Events {
248             epoll::Events::EPOLLIN
249         }
250         fn notify(&mut self, evset: epoll::Events) {
251             self.evset = Some(evset);
252         }
253     }
254     impl VsockBackend for TestBackend {}
255 
256     pub struct TestContext {
257         pub cid: u64,
258         pub mem: GuestMemoryMmap,
259         pub mem_size: usize,
260         pub device: Vsock<TestBackend>,
261     }
262 
263     impl TestContext {
264         pub fn new() -> Self {
265             const CID: u32 = 52;
266             const MEM_SIZE: usize = 1024 * 1024 * 128;
267             Self {
268                 cid: CID as u64,
269                 mem: GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap(),
270                 mem_size: MEM_SIZE,
271                 device: Vsock::new(
272                     String::from("vsock"),
273                     CID,
274                     PathBuf::from("/test/sock"),
275                     TestBackend::new(),
276                     false,
277                     seccompiler::SeccompAction::Trap,
278                     EventFd::new(EFD_NONBLOCK).unwrap(),
279                     None,
280                 )
281                 .unwrap(),
282             }
283         }
284 
285         pub fn create_epoll_handler_context(&self) -> EpollHandlerContext {
286             const QSIZE: u16 = 2;
287 
288             let guest_rxvq = GuestQ::new(GuestAddress(0x0010_0000), &self.mem, QSIZE);
289             let guest_txvq = GuestQ::new(GuestAddress(0x0020_0000), &self.mem, QSIZE);
290             let guest_evvq = GuestQ::new(GuestAddress(0x0030_0000), &self.mem, QSIZE);
291             let rxvq = guest_rxvq.create_queue();
292             let txvq = guest_txvq.create_queue();
293             let evvq = guest_evvq.create_queue();
294 
295             // Set up one available descriptor in the RX queue.
296             guest_rxvq.dtable[0].set(
297                 0x0040_0000,
298                 VSOCK_PKT_HDR_SIZE as u32,
299                 (VRING_DESC_F_WRITE | VRING_DESC_F_NEXT).try_into().unwrap(),
300                 1,
301             );
302             guest_rxvq.dtable[1].set(0x0040_1000, 4096, VRING_DESC_F_WRITE.try_into().unwrap(), 0);
303             guest_rxvq.avail.ring[0].set(0);
304             guest_rxvq.avail.idx.set(1);
305 
306             // Set up one available descriptor in the TX queue.
307             guest_txvq.dtable[0].set(
308                 0x0050_0000,
309                 VSOCK_PKT_HDR_SIZE as u32,
310                 VRING_DESC_F_NEXT.try_into().unwrap(),
311                 1,
312             );
313             guest_txvq.dtable[1].set(0x0050_1000, 4096, 0, 0);
314             guest_txvq.avail.ring[0].set(0);
315             guest_txvq.avail.idx.set(1);
316 
317             let queues = vec![rxvq, txvq, evvq];
318             let queue_evts = vec![
319                 EventFd::new(EFD_NONBLOCK).unwrap(),
320                 EventFd::new(EFD_NONBLOCK).unwrap(),
321                 EventFd::new(EFD_NONBLOCK).unwrap(),
322             ];
323             let interrupt_cb = Arc::new(NoopVirtioInterrupt {});
324 
325             EpollHandlerContext {
326                 guest_rxvq,
327                 guest_txvq,
328                 guest_evvq,
329                 handler: VsockEpollHandler {
330                     mem: GuestMemoryAtomic::new(self.mem.clone()),
331                     queues,
332                     queue_evts,
333                     kill_evt: EventFd::new(EFD_NONBLOCK).unwrap(),
334                     pause_evt: EventFd::new(EFD_NONBLOCK).unwrap(),
335                     interrupt_cb,
336                     backend: Arc::new(RwLock::new(TestBackend::new())),
337                     access_platform: None,
338                 },
339             }
340         }
341     }
342 
343     pub struct EpollHandlerContext<'a> {
344         pub handler: VsockEpollHandler<TestBackend>,
345         pub guest_rxvq: GuestQ<'a>,
346         pub guest_txvq: GuestQ<'a>,
347         pub guest_evvq: GuestQ<'a>,
348     }
349 
350     impl<'a> EpollHandlerContext<'a> {
351         pub fn signal_txq_event(&mut self) {
352             self.handler.queue_evts[1].write(1).unwrap();
353             let events = epoll::Events::EPOLLIN;
354             let event = epoll::Event::new(events, TX_QUEUE_EVENT as u64);
355             let mut epoll_helper =
356                 EpollHelper::new(&self.handler.kill_evt, &self.handler.pause_evt).unwrap();
357             self.handler.handle_event(&mut epoll_helper, &event).ok();
358         }
359         pub fn signal_rxq_event(&mut self) {
360             self.handler.queue_evts[0].write(1).unwrap();
361             let events = epoll::Events::EPOLLIN;
362             let event = epoll::Event::new(events, RX_QUEUE_EVENT as u64);
363             let mut epoll_helper =
364                 EpollHelper::new(&self.handler.kill_evt, &self.handler.pause_evt).unwrap();
365             self.handler.handle_event(&mut epoll_helper, &event).ok();
366         }
367     }
368 }
369