1 //! This module defines the socket device protocol according to the virtio spec v1.1 5.10 Socket Device 2 3 use super::error::{self, SocketError}; 4 use crate::config::ReadOnly; 5 use bitflags::bitflags; 6 use core::{ 7 convert::{TryFrom, TryInto}, 8 fmt, 9 }; 10 use zerocopy::{ 11 byteorder::{LittleEndian, U16, U32, U64}, 12 FromBytes, Immutable, IntoBytes, KnownLayout, 13 }; 14 15 /// Well-known CID for the host. 16 pub const VMADDR_CID_HOST: u64 = 2; 17 18 /// Currently only stream sockets are supported. type is 1 for stream socket types. 19 #[derive(Copy, Clone, Debug)] 20 #[repr(u16)] 21 pub enum SocketType { 22 /// Stream sockets provide in-order, guaranteed, connection-oriented delivery without message boundaries. 23 Stream = 1, 24 /// seqpacket socket type introduced in virtio-v1.2. 25 SeqPacket = 2, 26 } 27 28 impl From<SocketType> for U16<LittleEndian> { from(socket_type: SocketType) -> Self29 fn from(socket_type: SocketType) -> Self { 30 (socket_type as u16).into() 31 } 32 } 33 34 /// VirtioVsockConfig is the vsock device configuration space. 35 #[derive(FromBytes, Immutable, IntoBytes)] 36 #[repr(C)] 37 pub struct VirtioVsockConfig { 38 /// The guest_cid field contains the guest’s context ID, which uniquely identifies 39 /// the device for its lifetime. The upper 32 bits of the CID are reserved and zeroed. 40 /// 41 /// According to virtio spec v1.1 2.4.1 Driver Requirements: Device Configuration Space, 42 /// drivers MUST NOT assume reads from fields greater than 32 bits wide are atomic. 43 /// So we need to split the u64 guest_cid into two parts. 44 pub guest_cid_low: ReadOnly<u32>, 45 pub guest_cid_high: ReadOnly<u32>, 46 } 47 48 /// The message header for data packets sent on the tx/rx queues 49 #[repr(C, packed)] 50 #[derive(Clone, Copy, Debug, Eq, FromBytes, Immutable, IntoBytes, KnownLayout, PartialEq)] 51 pub struct VirtioVsockHdr { 52 pub src_cid: U64<LittleEndian>, 53 pub dst_cid: U64<LittleEndian>, 54 pub src_port: U32<LittleEndian>, 55 pub dst_port: U32<LittleEndian>, 56 pub len: U32<LittleEndian>, 57 pub socket_type: U16<LittleEndian>, 58 pub op: U16<LittleEndian>, 59 pub flags: U32<LittleEndian>, 60 /// Total receive buffer space for this socket. This includes both free and in-use buffers. 61 pub buf_alloc: U32<LittleEndian>, 62 /// Free-running bytes received counter. 63 pub fwd_cnt: U32<LittleEndian>, 64 } 65 66 impl Default for VirtioVsockHdr { default() -> Self67 fn default() -> Self { 68 Self { 69 src_cid: 0.into(), 70 dst_cid: 0.into(), 71 src_port: 0.into(), 72 dst_port: 0.into(), 73 len: 0.into(), 74 socket_type: SocketType::Stream.into(), 75 op: 0.into(), 76 flags: 0.into(), 77 buf_alloc: 0.into(), 78 fwd_cnt: 0.into(), 79 } 80 } 81 } 82 83 impl VirtioVsockHdr { 84 /// Returns the length of the data. len(&self) -> u3285 pub fn len(&self) -> u32 { 86 u32::from(self.len) 87 } 88 op(&self) -> error::Result<VirtioVsockOp>89 pub fn op(&self) -> error::Result<VirtioVsockOp> { 90 self.op.try_into() 91 } 92 source(&self) -> VsockAddr93 pub fn source(&self) -> VsockAddr { 94 VsockAddr { 95 cid: self.src_cid.get(), 96 port: self.src_port.get(), 97 } 98 } 99 destination(&self) -> VsockAddr100 pub fn destination(&self) -> VsockAddr { 101 VsockAddr { 102 cid: self.dst_cid.get(), 103 port: self.dst_port.get(), 104 } 105 } 106 check_data_is_empty(&self) -> error::Result<()>107 pub fn check_data_is_empty(&self) -> error::Result<()> { 108 if self.len() == 0 { 109 Ok(()) 110 } else { 111 Err(SocketError::UnexpectedDataInPacket) 112 } 113 } 114 } 115 116 /// Socket address. 117 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 118 pub struct VsockAddr { 119 /// Context Identifier. 120 pub cid: u64, 121 /// Port number. 122 pub port: u32, 123 } 124 125 /// An event sent to the event queue 126 #[derive(Copy, Clone, Debug, Default, IntoBytes, FromBytes, Immutable, KnownLayout)] 127 #[repr(C)] 128 pub struct VirtioVsockEvent { 129 // ID from the virtio_vsock_event_id struct in the virtio spec 130 pub id: U32<LittleEndian>, 131 } 132 133 #[derive(Copy, Clone, Eq, PartialEq)] 134 #[repr(u16)] 135 pub enum VirtioVsockOp { 136 Invalid = 0, 137 138 /* Connect operations */ 139 Request = 1, 140 Response = 2, 141 Rst = 3, 142 Shutdown = 4, 143 144 /* To send payload */ 145 Rw = 5, 146 147 /* Tell the peer our credit info */ 148 CreditUpdate = 6, 149 /* Request the peer to send the credit info to us */ 150 CreditRequest = 7, 151 } 152 153 impl From<VirtioVsockOp> for U16<LittleEndian> { from(op: VirtioVsockOp) -> Self154 fn from(op: VirtioVsockOp) -> Self { 155 (op as u16).into() 156 } 157 } 158 159 impl TryFrom<U16<LittleEndian>> for VirtioVsockOp { 160 type Error = SocketError; 161 try_from(v: U16<LittleEndian>) -> Result<Self, Self::Error>162 fn try_from(v: U16<LittleEndian>) -> Result<Self, Self::Error> { 163 let op = match u16::from(v) { 164 0 => Self::Invalid, 165 1 => Self::Request, 166 2 => Self::Response, 167 3 => Self::Rst, 168 4 => Self::Shutdown, 169 5 => Self::Rw, 170 6 => Self::CreditUpdate, 171 7 => Self::CreditRequest, 172 _ => return Err(SocketError::UnknownOperation(v.into())), 173 }; 174 Ok(op) 175 } 176 } 177 178 impl fmt::Debug for VirtioVsockOp { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 180 match self { 181 Self::Invalid => write!(f, "VIRTIO_VSOCK_OP_INVALID"), 182 Self::Request => write!(f, "VIRTIO_VSOCK_OP_REQUEST"), 183 Self::Response => write!(f, "VIRTIO_VSOCK_OP_RESPONSE"), 184 Self::Rst => write!(f, "VIRTIO_VSOCK_OP_RST"), 185 Self::Shutdown => write!(f, "VIRTIO_VSOCK_OP_SHUTDOWN"), 186 Self::Rw => write!(f, "VIRTIO_VSOCK_OP_RW"), 187 Self::CreditUpdate => write!(f, "VIRTIO_VSOCK_OP_CREDIT_UPDATE"), 188 Self::CreditRequest => write!(f, "VIRTIO_VSOCK_OP_CREDIT_REQUEST"), 189 } 190 } 191 } 192 193 bitflags! { 194 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] 195 pub(crate) struct Feature: u64 { 196 /// stream socket type is supported. 197 const STREAM = 1 << 0; 198 /// seqpacket socket type is supported. 199 const SEQ_PACKET = 1 << 1; 200 201 // device independent 202 const NOTIFY_ON_EMPTY = 1 << 24; // legacy 203 const ANY_LAYOUT = 1 << 27; // legacy 204 const RING_INDIRECT_DESC = 1 << 28; 205 const RING_EVENT_IDX = 1 << 29; 206 const UNUSED = 1 << 30; // legacy 207 const VERSION_1 = 1 << 32; // detect legacy 208 209 // since virtio v1.1 210 const ACCESS_PLATFORM = 1 << 33; 211 const RING_PACKED = 1 << 34; 212 const IN_ORDER = 1 << 35; 213 const ORDER_PLATFORM = 1 << 36; 214 const SR_IOV = 1 << 37; 215 const NOTIFICATION_DATA = 1 << 38; 216 } 217 } 218 219 bitflags! { 220 /// Flags sent with a shutdown request to hint that the peer won't send or receive more data. 221 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] 222 pub struct StreamShutdown: u32 { 223 /// The peer will not receive any more data. 224 const RECEIVE = 1 << 0; 225 /// The peer will not send any more data. 226 const SEND = 1 << 1; 227 } 228 } 229 230 impl From<StreamShutdown> for U32<LittleEndian> { from(flags: StreamShutdown) -> Self231 fn from(flags: StreamShutdown) -> Self { 232 flags.bits().into() 233 } 234 } 235