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 {}