virtio_spec/features.rs
1//! Feature Bits
2
3use crate::le128;
4
5/// Feature Bits
6#[doc(alias = "VIRTIO_F")]
7pub trait FeatureBits: bitflags::Flags<Bits = le128>
8where
9 Self: From<F> + AsRef<F> + AsMut<F>,
10 F: From<Self> + AsRef<Self> + AsMut<Self>,
11{
12 /// Returns the feature that this feature requires.
13 ///
14 /// If `self` is a single feature and multiple features are returned, `self` requires only one of them.
15 ///
16 /// # Examples
17 ///
18 /// ```
19 /// # use virtio_spec as virtio;
20 /// use virtio::FeatureBits;
21 ///
22 /// assert_eq!(
23 /// virtio::net::F::GUEST_TSO4.requirements(),
24 /// virtio::net::F::GUEST_CSUM
25 /// );
26 /// assert_eq!(
27 /// virtio::net::F::GUEST_ECN.requirements(),
28 /// virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_TSO6
29 /// );
30 /// ```
31 fn requirements(&self) -> Self {
32 Self::empty()
33 }
34
35 /// Returns `true` if all internal feature requirements are satisfied.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// # use virtio_spec as virtio;
41 /// use virtio::FeatureBits;
42 ///
43 /// assert!((virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_CSUM).requirements_satisfied());
44 /// assert!(
45 /// (virtio::net::F::GUEST_ECN | virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_CSUM)
46 /// .requirements_satisfied()
47 /// );
48 /// ```
49 fn requirements_satisfied(&self) -> bool {
50 self.iter()
51 .map(|feature| feature.requirements())
52 .filter(|requirements| !requirements.is_empty())
53 .all(|requirements| self.intersects(requirements))
54 }
55}
56
57endian_bitflags! {
58 /// Device-independent Feature Bits
59 #[doc(alias = "VIRTIO_F")]
60 pub struct F: le128 {
61 /// Negotiating this feature indicates
62 /// that the driver can use descriptors with the VIRTQ_DESC_F_INDIRECT
63 /// flag set, as described in _Basic Facilities of a Virtio
64 /// Device / Virtqueues / The Virtqueue Descriptor Table / Indirect
65 /// Descriptors_ _Basic Facilities of a Virtio Device /
66 /// Virtqueues / The Virtqueue Descriptor Table / Indirect
67 /// Descriptors_ and _Packed Virtqueues / Indirect Flag: Scatter-Gather Support_ _Packed Virtqueues / Indirect Flag: Scatter-Gather Support_.
68 #[doc(alias = "VIRTIO_F_INDIRECT_DESC")]
69 const INDIRECT_DESC = 1 << 28;
70
71 /// This feature enables the _used_event_
72 /// and the _avail_event_ fields as described in
73 /// _Basic Facilities of a Virtio Device / Virtqueues / Used Buffer Notification Suppression_, _Basic Facilities of a Virtio Device / Virtqueues / The Virtqueue Used Ring_ and _Packed Virtqueues / Driver and Device Event Suppression_.
74 #[doc(alias = "VIRTIO_F_EVENT_IDX")]
75 const EVENT_IDX = 1 << 29;
76
77 /// This indicates compliance with this
78 /// specification, giving a simple way to detect legacy devices or drivers.
79 #[doc(alias = "VIRTIO_F_VERSION_1")]
80 const VERSION_1 = 1 << 32;
81
82 /// This feature indicates that
83 /// the device can be used on a platform where device access to data
84 /// in memory is limited and/or translated. E.g. this is the case if the device can be located
85 /// behind an IOMMU that translates bus addresses from the device into physical
86 /// addresses in memory, if the device can be limited to only access
87 /// certain memory addresses or if special commands such as
88 /// a cache flush can be needed to synchronise data in memory with
89 /// the device. Whether accesses are actually limited or translated
90 /// is described by platform-specific means.
91 /// If this feature bit is set to 0, then the device
92 /// has same access to memory addresses supplied to it as the
93 /// driver has.
94 /// In particular, the device will always use physical addresses
95 /// matching addresses used by the driver (typically meaning
96 /// physical addresses used by the CPU)
97 /// and not translated further, and can access any address supplied to it by
98 /// the driver. When clear, this overrides any platform-specific description of
99 /// whether device access is limited or translated in any way, e.g.
100 /// whether an IOMMU may be present.
101 #[doc(alias = "VIRTIO_F_ACCESS_PLATFORM")]
102 const ACCESS_PLATFORM = 1 << 33;
103
104 /// This feature indicates
105 /// support for the packed virtqueue layout as described in
106 /// _Basic Facilities of a Virtio Device / Packed Virtqueues_ _Basic Facilities of a Virtio Device / Packed Virtqueues_.
107 #[doc(alias = "VIRTIO_F_RING_PACKED")]
108 const RING_PACKED = 1 << 34;
109
110 /// This feature indicates
111 /// that all buffers are used by the device in the same
112 /// order in which they have been made available.
113 #[doc(alias = "VIRTIO_F_IN_ORDER")]
114 const IN_ORDER = 1 << 35;
115
116 /// This feature indicates
117 /// that memory accesses by the driver and the device are ordered
118 /// in a way described by the platform.
119 ///
120 /// If this feature bit is negotiated, the ordering in effect for any
121 /// memory accesses by the driver that need to be ordered in a specific way
122 /// with respect to accesses by the device is the one suitable for devices
123 /// described by the platform. This implies that the driver needs to use
124 /// memory barriers suitable for devices described by the platform; e.g.
125 /// for the PCI transport in the case of hardware PCI devices.
126 ///
127 /// If this feature bit is not negotiated, then the device
128 /// and driver are assumed to be implemented in software, that is
129 /// they can be assumed to run on identical CPUs
130 /// in an SMP configuration.
131 /// Thus a weaker form of memory barriers is sufficient
132 /// to yield better performance.
133 #[doc(alias = "VIRTIO_F_ORDER_PLATFORM")]
134 const ORDER_PLATFORM = 1 << 36;
135
136 /// This feature indicates that
137 /// the device supports Single Root I/O Virtualization.
138 /// Currently only PCI devices support this feature.
139 #[doc(alias = "VIRTIO_F_SR_IOV")]
140 const SR_IOV = 1 << 37;
141
142 /// This feature indicates
143 /// that the driver passes extra data (besides identifying the virtqueue)
144 /// in its device notifications.
145 /// See _Virtqueues / Driver notifications_ _Virtqueues / Driver notifications_.
146 #[doc(alias = "VIRTIO_F_NOTIFICATION_DATA")]
147 const NOTIFICATION_DATA = 1 << 38;
148
149 /// This feature indicates that the driver
150 /// uses the data provided by the device as a virtqueue identifier in available
151 /// buffer notifications.
152 /// As mentioned in section _Virtqueues / Driver notifications_, when the
153 /// driver is required to send an available buffer notification to the device, it
154 /// sends the virtqueue number to be notified. The method of delivering
155 /// notifications is transport specific.
156 /// With the PCI transport, the device can optionally provide a per-virtqueue value
157 /// for the driver to use in driver notifications, instead of the virtqueue number.
158 /// Some devices may benefit from this flexibility by providing, for example,
159 /// an internal virtqueue identifier, or an internal offset related to the
160 /// virtqueue number.
161 ///
162 /// This feature indicates the availability of such value. The definition of the
163 /// data to be provided in driver notification and the delivery method is
164 /// transport specific.
165 /// For more details about driver notifications over PCI see _Virtio Transport Options / Virtio Over PCI Bus / PCI-specific Initialization And Device Operation / Available Buffer Notifications_.
166 #[doc(alias = "VIRTIO_F_NOTIF_CONFIG_DATA")]
167 const NOTIF_CONFIG_DATA = 1 << 39;
168
169 /// This feature indicates
170 /// that the driver can reset a queue individually.
171 /// See _Basic Facilities of a Virtio Device / Virtqueues / Virtqueue Reset_.
172 #[doc(alias = "VIRTIO_F_RING_RESET")]
173 const RING_RESET = 1 << 40;
174 }
175}
176
177impl AsRef<F> for F {
178 fn as_ref(&self) -> &F {
179 self
180 }
181}
182
183impl AsMut<F> for F {
184 fn as_mut(&mut self) -> &mut F {
185 self
186 }
187}
188
189impl FeatureBits for F {}
190
191macro_rules! feature_bits {
192 (
193 $(#[$outer:meta])*
194 $vis:vis struct $BitFlags:ident: $T:ty {
195 $(
196 $(#[$inner:ident $($args:tt)*])*
197 const $Flag:tt = $value:expr;
198 )*
199 }
200
201 $($t:tt)*
202 ) => {
203 endian_bitflags! {
204 $(#[$outer])*
205 $vis struct $BitFlags: $T {
206 $(
207 $(#[$inner $($args)*])*
208 const $Flag = $value;
209 )*
210
211 /// Device-independent Bit. See [`virtio::F::INDIRECT_DESC`](crate::F::INDIRECT_DESC).
212 const INDIRECT_DESC = $crate::F::INDIRECT_DESC.bits().to_ne();
213
214 /// Device-independent Bit. See [`virtio::F::EVENT_IDX`](crate::F::EVENT_IDX).
215 const EVENT_IDX = $crate::F::EVENT_IDX.bits().to_ne();
216
217 /// Device-independent Bit. See [`virtio::F::VERSION_1`](crate::F::VERSION_1).
218 const VERSION_1 = $crate::F::VERSION_1.bits().to_ne();
219
220 /// Device-independent Bit. See [`virtio::F::ACCESS_PLATFORM`](crate::F::ACCESS_PLATFORM).
221 const ACCESS_PLATFORM = $crate::F::ACCESS_PLATFORM.bits().to_ne();
222
223 /// Device-independent Bit. See [`virtio::F::RING_PACKED`](crate::F::RING_PACKED).
224 const RING_PACKED = $crate::F::RING_PACKED.bits().to_ne();
225
226 /// Device-independent Bit. See [`virtio::F::IN_ORDER`](crate::F::IN_ORDER).
227 const IN_ORDER = $crate::F::IN_ORDER.bits().to_ne();
228
229 /// Device-independent Bit. See [`virtio::F::ORDER_PLATFORM`](crate::F::ORDER_PLATFORM).
230 const ORDER_PLATFORM = $crate::F::ORDER_PLATFORM.bits().to_ne();
231
232 /// Device-independent Bit. See [`virtio::F::SR_IOV`](crate::F::SR_IOV).
233 const SR_IOV = $crate::F::SR_IOV.bits().to_ne();
234
235 /// Device-independent Bit. See [`virtio::F::NOTIFICATION_DATA`](crate::F::NOTIFICATION_DATA).
236 const NOTIFICATION_DATA = $crate::F::NOTIFICATION_DATA.bits().to_ne();
237
238 /// Device-independent Bit. See [`virtio::F::NOTIF_CONFIG_DATA`](crate::F::NOTIF_CONFIG_DATA).
239 const NOTIF_CONFIG_DATA = $crate::F::NOTIF_CONFIG_DATA.bits().to_ne();
240
241 /// Device-independent Bit. See [`virtio::F::RING_RESET`](crate::F::RING_RESET).
242 const RING_RESET = $crate::F::RING_RESET.bits().to_ne();
243 }
244 }
245
246 impl From<$crate::F> for $BitFlags {
247 fn from(value: $crate::F) -> Self {
248 Self::from_bits_retain(value.bits())
249 }
250 }
251
252 impl AsRef<$BitFlags> for $crate::F {
253 fn as_ref(&self) -> &$BitFlags {
254 unsafe { &*(self as *const Self as *const $BitFlags) }
255 }
256 }
257
258 impl AsMut<$BitFlags> for $crate::F {
259 fn as_mut(&mut self) -> &mut $BitFlags {
260 unsafe { &mut *(self as *mut Self as *mut $BitFlags) }
261 }
262 }
263
264 impl From<$BitFlags> for $crate::F {
265 /// Returns the device-independent feature bits while retaining device-specific feature bits.
266 fn from(value: $BitFlags) -> Self {
267 $crate::F::from_bits_retain(value.bits())
268 }
269 }
270
271 impl AsRef<$crate::F> for $BitFlags {
272 /// Returns a shared reference to the device-independent features while retaining device-specific feature bits.
273 fn as_ref(&self) -> &$crate::F {
274 unsafe { &*(self as *const Self as *const $crate::F) }
275 }
276 }
277
278 impl AsMut<$crate::F> for $BitFlags {
279 /// Returns a mutable reference to the device-independent features while retaining device-specific feature bits.
280 fn as_mut(&mut self) -> &mut $crate::F {
281 unsafe { &mut *(self as *mut Self as *mut $crate::F) }
282 }
283 }
284
285 feature_bits! {
286 $($t)*
287 }
288 };
289 () => {};
290}
291
292pub mod net {
293 use crate::le128;
294
295 feature_bits! {
296 /// Network Device Feature Bits
297 #[doc(alias = "VIRTIO_NET_F")]
298 pub struct F: le128 {
299 /// Device handles packets with partial checksum. This
300 /// “checksum offload” is a common feature on modern network cards.
301 #[doc(alias = "VIRTIO_NET_F_CSUM")]
302 const CSUM = 1 << 0;
303
304 /// Driver handles packets with partial checksum.
305 #[doc(alias = "VIRTIO_NET_F_GUEST_CSUM")]
306 const GUEST_CSUM = 1 << 1;
307
308 /// Control channel offloads
309 /// reconfiguration support.
310 #[doc(alias = "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS")]
311 const CTRL_GUEST_OFFLOADS = 1 << 2;
312
313 /// Device maximum MTU reporting is supported. If
314 /// offered by the device, device advises driver about the value of
315 /// its maximum MTU. If negotiated, the driver uses _mtu_ as
316 /// the maximum MTU value.
317 #[doc(alias = "VIRTIO_NET_F_MTU")]
318 const MTU = 1 << 3;
319
320 /// Device has given MAC address.
321 #[doc(alias = "VIRTIO_NET_F_MAC")]
322 const MAC = 1 << 5;
323
324 /// Driver can receive TSOv4.
325 #[doc(alias = "VIRTIO_NET_F_GUEST_TSO4")]
326 const GUEST_TSO4 = 1 << 7;
327
328 /// Driver can receive TSOv6.
329 #[doc(alias = "VIRTIO_NET_F_GUEST_TSO6")]
330 const GUEST_TSO6 = 1 << 8;
331
332 /// Driver can receive TSO with ECN.
333 #[doc(alias = "VIRTIO_NET_F_GUEST_ECN")]
334 const GUEST_ECN = 1 << 9;
335
336 /// Driver can receive UFO.
337 #[doc(alias = "VIRTIO_NET_F_GUEST_UFO")]
338 const GUEST_UFO = 1 << 10;
339
340 /// Device can receive TSOv4.
341 #[doc(alias = "VIRTIO_NET_F_HOST_TSO4")]
342 const HOST_TSO4 = 1 << 11;
343
344 /// Device can receive TSOv6.
345 #[doc(alias = "VIRTIO_NET_F_HOST_TSO6")]
346 const HOST_TSO6 = 1 << 12;
347
348 /// Device can receive TSO with ECN.
349 #[doc(alias = "VIRTIO_NET_F_HOST_ECN")]
350 const HOST_ECN = 1 << 13;
351
352 /// Device can receive UFO.
353 #[doc(alias = "VIRTIO_NET_F_HOST_UFO")]
354 const HOST_UFO = 1 << 14;
355
356 /// Driver can merge receive buffers.
357 #[doc(alias = "VIRTIO_NET_F_MRG_RXBUF")]
358 const MRG_RXBUF = 1 << 15;
359
360 /// Configuration status field is
361 /// available.
362 #[doc(alias = "VIRTIO_NET_F_STATUS")]
363 const STATUS = 1 << 16;
364
365 /// Control channel is available.
366 #[doc(alias = "VIRTIO_NET_F_CTRL_VQ")]
367 const CTRL_VQ = 1 << 17;
368
369 /// Control channel RX mode support.
370 #[doc(alias = "VIRTIO_NET_F_CTRL_RX")]
371 const CTRL_RX = 1 << 18;
372
373 /// Control channel VLAN filtering.
374 #[doc(alias = "VIRTIO_NET_F_CTRL_VLAN")]
375 const CTRL_VLAN = 1 << 19;
376
377 /// Driver can send gratuitous
378 /// packets.
379 #[doc(alias = "VIRTIO_NET_F_GUEST_ANNOUNCE")]
380 const GUEST_ANNOUNCE = 1 << 21;
381
382 /// Device supports multiqueue with automatic
383 /// receive steering.
384 #[doc(alias = "VIRTIO_NET_F_MQ")]
385 const MQ = 1 << 22;
386
387 /// Set MAC address through control
388 /// channel.
389 #[doc(alias = "VIRTIO_NET_F_CTRL_MAC_ADDR")]
390 const CTRL_MAC_ADDR = 1 << 23;
391
392 /// Device can receive USO packets. Unlike UFO
393 /// (fragmenting the packet) the USO splits large UDP packet
394 /// to several segments when each of these smaller packets has UDP header.
395 #[doc(alias = "VIRTIO_NET_F_HOST_USO")]
396 const HOST_USO = 1 << 56;
397
398 /// Device can report per-packet hash
399 /// value and a type of calculated hash.
400 #[doc(alias = "VIRTIO_NET_F_HASH_REPORT")]
401 const HASH_REPORT = 1 << 57;
402
403 /// Driver can provide the exact _hdr_len_
404 /// value. Device benefits from knowing the exact header length.
405 #[doc(alias = "VIRTIO_NET_F_GUEST_HDRLEN")]
406 const GUEST_HDRLEN = 1 << 59;
407
408 /// Device supports RSS (receive-side scaling)
409 /// with Toeplitz hash calculation and configurable hash
410 /// parameters for receive steering.
411 #[doc(alias = "VIRTIO_NET_F_RSS")]
412 const RSS = 1 << 60;
413
414 /// Device can process duplicated ACKs
415 /// and report number of coalesced segments and duplicated ACKs.
416 #[doc(alias = "VIRTIO_NET_F_RSC_EXT")]
417 const RSC_EXT = 1 << 61;
418
419 /// Device may act as a standby for a primary
420 /// device with the same MAC address.
421 #[doc(alias = "VIRTIO_NET_F_STANDBY")]
422 const STANDBY = 1 << 62;
423
424 /// Device reports speed and duplex.
425 #[doc(alias = "VIRTIO_NET_F_SPEED_DUPLEX")]
426 const SPEED_DUPLEX = 1 << 63;
427 }
428 }
429
430 impl crate::FeatureBits for F {
431 fn requirements(&self) -> Self {
432 let mut requirements = Self::empty();
433
434 for feature in self.iter() {
435 let requirement = match feature {
436 Self::GUEST_TSO4 => Self::GUEST_CSUM,
437 Self::GUEST_TSO6 => Self::GUEST_CSUM,
438 Self::GUEST_ECN => Self::GUEST_TSO4 | Self::GUEST_TSO6,
439 Self::GUEST_UFO => Self::GUEST_CSUM,
440 Self::HOST_TSO4 => Self::CSUM,
441 Self::HOST_TSO6 => Self::CSUM,
442 Self::HOST_ECN => Self::HOST_TSO4 | Self::HOST_TSO6,
443 Self::HOST_UFO => Self::CSUM,
444 Self::HOST_USO => Self::CSUM,
445 Self::CTRL_RX => Self::CTRL_VQ,
446 Self::CTRL_VLAN => Self::CTRL_VQ,
447 Self::GUEST_ANNOUNCE => Self::CTRL_VQ,
448 Self::MQ => Self::CTRL_VQ,
449 Self::CTRL_MAC_ADDR => Self::CTRL_VQ,
450 Self::RSC_EXT => Self::HOST_TSO4 | Self::HOST_TSO6,
451 Self::RSS => Self::CTRL_VQ,
452 _ => Self::empty(),
453 };
454 requirements.insert(requirement);
455 }
456
457 requirements
458 }
459 }
460}
461
462pub mod fs {
463 use crate::le128;
464
465 feature_bits! {
466 /// File System Device Feature Bits
467 #[doc(alias = "VIRTIO_FS_F")]
468 pub struct F: le128 {
469 /// Device has support for FUSE notify
470 /// messages. The notification queue is virtqueue 1.
471 #[doc(alias = "VIRTIO_FS_F_NOTIFICATION")]
472 const NOTIFICATION = 1 << 0;
473 }
474 }
475
476 impl crate::FeatureBits for F {}
477}
478
479pub mod vsock {
480 use crate::le128;
481
482 feature_bits! {
483 /// Socket Device Feature Bits
484 #[doc(alias = "VIRTIO_VSOCK_F")]
485 pub struct F: le128 {
486 /// stream socket type is supported.
487 #[doc(alias = "VIRTIO_VSOCK_F_STREAM")]
488 const STREAM = 1 << 0;
489
490 /// seqpacket socket type is supported.
491 #[doc(alias = "VIRTIO_VSOCK_F_SEQPACKET")]
492 const SEQPACKET = 1 << 1;
493 }
494 }
495
496 impl crate::FeatureBits for F {}
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502
503 #[rustfmt::skip]
504 #[test]
505 fn requirements_satisfied() {
506 assert!(F::INDIRECT_DESC.requirements_satisfied());
507
508 assert!(net::F::CSUM.requirements_satisfied());
509
510 assert!(!net::F::MQ.requirements_satisfied());
511 assert!((net::F::MQ | net::F::CTRL_VQ).requirements_satisfied());
512
513 assert!(!net::F::HOST_TSO4.requirements_satisfied());
514 assert!((net::F::HOST_TSO4 | net::F::CSUM).requirements_satisfied());
515 assert!((net::F::HOST_TSO4 | net::F::HOST_TSO6 | net::F::CSUM).requirements_satisfied());
516
517 assert!(!net::F::HOST_ECN.requirements_satisfied());
518 assert!(!(net::F::HOST_ECN | net::F::CSUM).requirements_satisfied());
519 assert!(!(net::F::HOST_ECN | net::F::HOST_TSO4).requirements_satisfied());
520 assert!((net::F::HOST_ECN | net::F::HOST_TSO4 | net::F::CSUM).requirements_satisfied());
521 assert!((net::F::HOST_ECN | net::F::HOST_TSO4 | net::F::HOST_TSO6 | net::F::CSUM).requirements_satisfied());
522 }
523}