vmm/devices/virtio/vsock/mod.rs
1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Portions 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 THIRD-PARTY file.
7
8//! The Firecracker vsock device aims to provide full virtio-vsock support to
9//! software running inside the guest VM, while bypassing vhost kernel code on the
10//! host. To that end, Firecracker implements the virtio-vsock device model, and
11//! mediates communication between AF_UNIX sockets (on the host end) and AF_VSOCK
12//! sockets (on the guest end).
13
14mod csm;
15mod device;
16mod event_handler;
17pub mod metrics;
18mod packet;
19pub mod persist;
20pub mod test_utils;
21mod unix;
22
23use std::os::unix::io::AsRawFd;
24
25use vm_memory::GuestMemoryError;
26use vmm_sys_util::epoll::EventSet;
27
28pub use self::defs::VSOCK_DEV_ID;
29pub use self::device::Vsock;
30use self::packet::{VsockPacketRx, VsockPacketTx};
31pub use self::unix::{VsockUnixBackend, VsockUnixBackendError};
32use super::iov_deque::IovDequeError;
33use crate::devices::virtio::iovec::IoVecError;
34use crate::devices::virtio::persist::PersistError as VirtioStateError;
35
36mod defs {
37 use crate::devices::virtio::queue::FIRECRACKER_MAX_QUEUE_SIZE;
38
39 /// Device ID used in MMIO device identification.
40 /// Because Vsock is unique per-vm, this ID can be hardcoded.
41 pub const VSOCK_DEV_ID: &str = "vsock";
42
43 /// Number of virtio queues.
44 pub const VSOCK_NUM_QUEUES: usize = 3;
45
46 /// Virtio queue sizes, in number of descriptor chain heads.
47 /// There are 3 queues for a virtio device (in this order): RX, TX, Event
48 pub const VSOCK_QUEUE_SIZES: [u16; VSOCK_NUM_QUEUES] = [
49 FIRECRACKER_MAX_QUEUE_SIZE,
50 FIRECRACKER_MAX_QUEUE_SIZE,
51 FIRECRACKER_MAX_QUEUE_SIZE,
52 ];
53
54 /// Max vsock packet data/buffer size.
55 pub const MAX_PKT_BUF_SIZE: u32 = 64 * 1024;
56
57 pub mod uapi {
58 /// Vsock packet operation IDs.
59 /// Defined in `/include/uapi/linux/virtio_vsock.h`.
60 ///
61 /// Connection request.
62 pub const VSOCK_OP_REQUEST: u16 = 1;
63 /// Connection response.
64 pub const VSOCK_OP_RESPONSE: u16 = 2;
65 /// Connection reset.
66 pub const VSOCK_OP_RST: u16 = 3;
67 /// Connection clean shutdown.
68 pub const VSOCK_OP_SHUTDOWN: u16 = 4;
69 /// Connection data (read/write).
70 pub const VSOCK_OP_RW: u16 = 5;
71 /// Flow control credit update.
72 pub const VSOCK_OP_CREDIT_UPDATE: u16 = 6;
73 /// Flow control credit update request.
74 pub const VSOCK_OP_CREDIT_REQUEST: u16 = 7;
75
76 /// Vsock packet flags.
77 /// Defined in `/include/uapi/linux/virtio_vsock.h`.
78 ///
79 /// Valid with a VSOCK_OP_SHUTDOWN packet: the packet sender will receive no more data.
80 pub const VSOCK_FLAGS_SHUTDOWN_RCV: u32 = 1;
81 /// Valid with a VSOCK_OP_SHUTDOWN packet: the packet sender will send no more data.
82 pub const VSOCK_FLAGS_SHUTDOWN_SEND: u32 = 2;
83
84 /// Vsock packet type.
85 /// Defined in `/include/uapi/linux/virtio_vsock.h`.
86 ///
87 /// Stream / connection-oriented packet (the only currently valid type).
88 pub const VSOCK_TYPE_STREAM: u16 = 1;
89
90 pub const VSOCK_HOST_CID: u64 = 2;
91 }
92}
93
94/// Vsock device related errors.
95#[derive(Debug, thiserror::Error, displaydoc::Display)]
96#[rustfmt::skip]
97pub enum VsockError {
98 /** The total length of the descriptor chain ({0}) is too short to hold a packet of length {1} + header */
99 DescChainTooShortForPacket(u32, u32),
100 /// Empty queue
101 EmptyQueue,
102 /// EventFd error: {0}
103 EventFd(std::io::Error),
104 /// Chained GuestMemoryMmap error: {0}
105 GuestMemoryMmap(GuestMemoryError),
106 /// Bounds check failed on guest memory pointer.
107 GuestMemoryBounds,
108 /** The total length of the descriptor chain ({0}) is less than the number of bytes required\
109 to hold a vsock packet header.*/
110 DescChainTooShortForHeader(usize),
111 /// The descriptor chain length was greater than the max ([u32::MAX])
112 DescChainOverflow,
113 /// The vsock header `len` field holds an invalid value: {0}
114 InvalidPktLen(u32),
115 /// A data fetch was attempted when no data was available.
116 NoData,
117 /// A data buffer was expected for the provided packet, but it is missing.
118 PktBufMissing,
119 /// Encountered an unexpected write-only virtio descriptor.
120 UnreadableDescriptor,
121 /// Encountered an unexpected read-only virtio descriptor.
122 UnwritableDescriptor,
123 /// Invalid virtio configuration: {0}
124 VirtioState(VirtioStateError),
125 /// Vsock uds backend error: {0}
126 VsockUdsBackend(VsockUnixBackendError),
127 /// Underlying IovDeque error: {0}
128 IovDeque(IovDequeError),
129 /// Tried to push to full IovDeque.
130 IovDequeOverflow,
131}
132
133impl From<IoVecError> for VsockError {
134 fn from(value: IoVecError) -> Self {
135 match value {
136 IoVecError::WriteOnlyDescriptor => VsockError::UnreadableDescriptor,
137 IoVecError::ReadOnlyDescriptor => VsockError::UnwritableDescriptor,
138 IoVecError::GuestMemory(err) => VsockError::GuestMemoryMmap(err),
139 IoVecError::OverflowedDescriptor => VsockError::DescChainOverflow,
140 IoVecError::IovDeque(err) => VsockError::IovDeque(err),
141 IoVecError::IovDequeOverflow => VsockError::IovDequeOverflow,
142 }
143 }
144}
145
146/// A passive, event-driven object, that needs to be notified whenever an epoll-able event occurs.
147/// An event-polling control loop will use `as_raw_fd()` and `get_polled_evset()` to query
148/// the listener for the file descriptor and the set of events it's interested in. When such an
149/// event occurs, the control loop will route the event to the listener via `notify()`.
150pub trait VsockEpollListener: AsRawFd {
151 /// Get the set of events for which the listener wants to be notified.
152 fn get_polled_evset(&self) -> EventSet;
153
154 /// Notify the listener that one ore more events have occurred.
155 fn notify(&mut self, evset: EventSet);
156}
157
158/// Any channel that handles vsock packet traffic: sending and receiving packets. Since we're
159/// implementing the device model here, our responsibility is to always process the sending of
160/// packets (i.e. the TX queue). So, any locally generated data, addressed to the driver (e.g.
161/// a connection response or RST), will have to be queued, until we get to processing the RX queue.
162///
163/// Note: `recv_pkt()` and `send_pkt()` are named analogous to `Read::read()` and `Write::write()`,
164/// respectively. I.e.
165/// - `recv_pkt(&mut pkt)` will read data from the channel, and place it into `pkt`; and
166/// - `send_pkt(&pkt)` will fetch data from `pkt`, and place it into the channel.
167pub trait VsockChannel {
168 /// Read/receive an incoming packet from the channel.
169 fn recv_pkt(&mut self, pkt: &mut VsockPacketRx) -> Result<(), VsockError>;
170
171 /// Write/send a packet through the channel.
172 fn send_pkt(&mut self, pkt: &VsockPacketTx) -> Result<(), VsockError>;
173
174 /// Checks whether there is pending incoming data inside the channel, meaning that a subsequent
175 /// call to `recv_pkt()` won't fail.
176 fn has_pending_rx(&self) -> bool;
177}
178
179/// The vsock backend, which is basically an epoll-event-driven vsock channel.
180/// Currently, the only implementation we have is `crate::devices::virtio::unix::muxer::VsockMuxer`,
181/// which translates guest-side vsock connections to host-side Unix domain socket connections.
182pub trait VsockBackend: VsockChannel + VsockEpollListener + Send {}