• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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