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