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 /// 119 /// An event-polling control loop will use `get_polled_fd()` and `get_polled_evset()` to query 120 /// the listener for the file descriptor and the set of events it's interested in. When such an 121 /// event occurs, the control loop will route the event to the listener via `notify()`. 122 /// 123 pub trait VsockEpollListener { 124 /// Get the file descriptor the listener needs polled. 125 fn get_polled_fd(&self) -> RawFd; 126 127 /// Get the set of events for which the listener wants to be notified. 128 fn get_polled_evset(&self) -> epoll::Events; 129 130 /// Notify the listener that one or more events have occurred. 131 fn notify(&mut self, evset: epoll::Events); 132 } 133 134 /// Trait to describe any channel that handles vsock packet traffic (sending and receiving packets) 135 /// 136 /// Since we're implementing the device model here, our responsibility is to always process the sending of 137 /// packets (i.e. the TX queue). So, any locally generated data, addressed to the driver (e.g. 138 /// a connection response or RST), will have to be queued, until we get to processing the RX queue. 139 /// 140 /// Note: `recv_pkt()` and `send_pkt()` are named analogous to `Read::read()` and `Write::write()`, 141 /// respectively. I.e. 142 /// - `recv_pkt(&mut pkt)` will read data from the channel, and place it into `pkt`; and 143 /// - `send_pkt(&pkt)` will fetch data from `pkt`, and place it into the channel. 144 pub trait VsockChannel { 145 /// Read/receive an incoming packet from the channel. 146 fn recv_pkt(&mut self, pkt: &mut VsockPacket) -> Result<()>; 147 148 /// Write/send a packet through the channel. 149 fn send_pkt(&mut self, pkt: &VsockPacket) -> Result<()>; 150 151 /// Checks whether there is pending incoming data inside the channel, meaning that a subsequent 152 /// call to `recv_pkt()` won't fail. 153 fn has_pending_rx(&self) -> bool; 154 } 155 156 /// The vsock backend, which is basically an epoll-event-driven vsock channel 157 /// 158 /// It that needs to be sendable through a mpsc channel (the latter due to how `vmm::EpollContext` works). 159 /// Currently, the only implementation we have is `crate::virtio::unix::muxer::VsockMuxer`, which 160 /// translates guest-side vsock connections to host-side Unix domain socket connections. 161 pub trait VsockBackend: VsockChannel + VsockEpollListener + Send {} 162 163 #[cfg(test)] 164 mod tests { 165 use super::device::{VsockEpollHandler, RX_QUEUE_EVENT, TX_QUEUE_EVENT}; 166 use super::packet::VSOCK_PKT_HDR_SIZE; 167 use super::*; 168 use crate::device::{VirtioInterrupt, VirtioInterruptType}; 169 use crate::epoll_helper::EpollHelperHandler; 170 use crate::EpollHelper; 171 use crate::GuestMemoryMmap; 172 use libc::EFD_NONBLOCK; 173 use std::os::unix::io::AsRawFd; 174 use std::path::PathBuf; 175 use std::sync::{Arc, RwLock}; 176 use virtio_bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; 177 use vm_memory::{GuestAddress, GuestMemoryAtomic}; 178 use vm_virtio::queue::testing::VirtQueue as GuestQ; 179 use vmm_sys_util::eventfd::EventFd; 180 181 pub struct NoopVirtioInterrupt {} 182 183 impl VirtioInterrupt for NoopVirtioInterrupt { 184 fn trigger( 185 &self, 186 _int_type: VirtioInterruptType, 187 ) -> std::result::Result<(), std::io::Error> { 188 Ok(()) 189 } 190 } 191 192 pub struct TestBackend { 193 pub evfd: EventFd, 194 pub rx_err: Option<VsockError>, 195 pub tx_err: Option<VsockError>, 196 pub pending_rx: bool, 197 pub rx_ok_cnt: usize, 198 pub tx_ok_cnt: usize, 199 pub evset: Option<epoll::Events>, 200 } 201 impl TestBackend { 202 pub fn new() -> Self { 203 Self { 204 evfd: EventFd::new(EFD_NONBLOCK).unwrap(), 205 rx_err: None, 206 tx_err: None, 207 pending_rx: false, 208 rx_ok_cnt: 0, 209 tx_ok_cnt: 0, 210 evset: None, 211 } 212 } 213 pub fn set_rx_err(&mut self, err: Option<VsockError>) { 214 self.rx_err = err; 215 } 216 pub fn set_tx_err(&mut self, err: Option<VsockError>) { 217 self.tx_err = err; 218 } 219 pub fn set_pending_rx(&mut self, prx: bool) { 220 self.pending_rx = prx; 221 } 222 } 223 impl VsockChannel for TestBackend { 224 fn recv_pkt(&mut self, _pkt: &mut VsockPacket) -> Result<()> { 225 match self.rx_err.take() { 226 None => { 227 self.rx_ok_cnt += 1; 228 Ok(()) 229 } 230 Some(e) => Err(e), 231 } 232 } 233 fn send_pkt(&mut self, _pkt: &VsockPacket) -> Result<()> { 234 match self.tx_err.take() { 235 None => { 236 self.tx_ok_cnt += 1; 237 Ok(()) 238 } 239 Some(e) => Err(e), 240 } 241 } 242 fn has_pending_rx(&self) -> bool { 243 self.pending_rx 244 } 245 } 246 impl VsockEpollListener for TestBackend { 247 fn get_polled_fd(&self) -> RawFd { 248 self.evfd.as_raw_fd() 249 } 250 fn get_polled_evset(&self) -> epoll::Events { 251 epoll::Events::EPOLLIN 252 } 253 fn notify(&mut self, evset: epoll::Events) { 254 self.evset = Some(evset); 255 } 256 } 257 impl VsockBackend for TestBackend {} 258 259 pub struct TestContext { 260 pub cid: u64, 261 pub mem: GuestMemoryMmap, 262 pub device: Vsock<TestBackend>, 263 } 264 265 impl TestContext { 266 pub fn new() -> Self { 267 const CID: u32 = 52; 268 const MEM_SIZE: usize = 1024 * 1024 * 128; 269 Self { 270 cid: CID as u64, 271 mem: GuestMemoryMmap::from_ranges(&[(GuestAddress(0), MEM_SIZE)]).unwrap(), 272 device: Vsock::new( 273 String::from("vsock"), 274 CID, 275 PathBuf::from("/test/sock"), 276 TestBackend::new(), 277 false, 278 seccompiler::SeccompAction::Trap, 279 EventFd::new(EFD_NONBLOCK).unwrap(), 280 None, 281 ) 282 .unwrap(), 283 } 284 } 285 286 pub fn create_epoll_handler_context(&self) -> EpollHandlerContext { 287 const QSIZE: u16 = 2; 288 289 let guest_rxvq = GuestQ::new(GuestAddress(0x0010_0000), &self.mem, QSIZE); 290 let guest_txvq = GuestQ::new(GuestAddress(0x0020_0000), &self.mem, QSIZE); 291 let guest_evvq = GuestQ::new(GuestAddress(0x0030_0000), &self.mem, QSIZE); 292 let rxvq = guest_rxvq.create_queue(); 293 let txvq = guest_txvq.create_queue(); 294 let evvq = guest_evvq.create_queue(); 295 296 // Set up one available descriptor in the RX queue. 297 guest_rxvq.dtable[0].set( 298 0x0040_0000, 299 VSOCK_PKT_HDR_SIZE as u32, 300 (VRING_DESC_F_WRITE | VRING_DESC_F_NEXT).try_into().unwrap(), 301 1, 302 ); 303 guest_rxvq.dtable[1].set(0x0040_1000, 4096, VRING_DESC_F_WRITE.try_into().unwrap(), 0); 304 guest_rxvq.avail.ring[0].set(0); 305 guest_rxvq.avail.idx.set(1); 306 307 // Set up one available descriptor in the TX queue. 308 guest_txvq.dtable[0].set( 309 0x0050_0000, 310 VSOCK_PKT_HDR_SIZE as u32, 311 VRING_DESC_F_NEXT.try_into().unwrap(), 312 1, 313 ); 314 guest_txvq.dtable[1].set(0x0050_1000, 4096, 0, 0); 315 guest_txvq.avail.ring[0].set(0); 316 guest_txvq.avail.idx.set(1); 317 318 let queues = vec![rxvq, txvq, evvq]; 319 let queue_evts = vec![ 320 EventFd::new(EFD_NONBLOCK).unwrap(), 321 EventFd::new(EFD_NONBLOCK).unwrap(), 322 EventFd::new(EFD_NONBLOCK).unwrap(), 323 ]; 324 let interrupt_cb = Arc::new(NoopVirtioInterrupt {}); 325 326 EpollHandlerContext { 327 guest_rxvq, 328 guest_txvq, 329 guest_evvq, 330 handler: VsockEpollHandler { 331 mem: GuestMemoryAtomic::new(self.mem.clone()), 332 queues, 333 queue_evts, 334 kill_evt: EventFd::new(EFD_NONBLOCK).unwrap(), 335 pause_evt: EventFd::new(EFD_NONBLOCK).unwrap(), 336 interrupt_cb, 337 backend: Arc::new(RwLock::new(TestBackend::new())), 338 access_platform: None, 339 }, 340 } 341 } 342 } 343 344 pub struct EpollHandlerContext<'a> { 345 pub handler: VsockEpollHandler<TestBackend>, 346 pub guest_rxvq: GuestQ<'a>, 347 pub guest_txvq: GuestQ<'a>, 348 pub guest_evvq: GuestQ<'a>, 349 } 350 351 impl<'a> EpollHandlerContext<'a> { 352 pub fn signal_txq_event(&mut self) { 353 self.handler.queue_evts[1].write(1).unwrap(); 354 let events = epoll::Events::EPOLLIN; 355 let event = epoll::Event::new(events, TX_QUEUE_EVENT as u64); 356 let mut epoll_helper = 357 EpollHelper::new(&self.handler.kill_evt, &self.handler.pause_evt).unwrap(); 358 self.handler.handle_event(&mut epoll_helper, &event).ok(); 359 } 360 pub fn signal_rxq_event(&mut self) { 361 self.handler.queue_evts[0].write(1).unwrap(); 362 let events = epoll::Events::EPOLLIN; 363 let event = epoll::Event::new(events, RX_QUEUE_EVENT as u64); 364 let mut epoll_helper = 365 EpollHelper::new(&self.handler.kill_evt, &self.handler.pause_evt).unwrap(); 366 self.handler.handle_event(&mut epoll_helper, &event).ok(); 367 } 368 } 369 } 370