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}