Skip to main content

virtio_spec/
features.rs

1//! Feature Bits
2
3use crate::le128;
4use crate::sealed::Sealed;
5
6/// Feature Bits
7#[doc(alias = "VIRTIO_F")]
8pub trait FeatureBits:
9    bitflags::Flags<Bits = le128> + From<F> + Into<F> + AsRef<F> + AsMut<F> + Sealed
10{
11    /// Returns `true` if all internal feature requirements are satisfied.
12    ///
13    /// # Driver Requirements
14    ///
15    /// The driver MUST NOT accept a feature which requires another feature which was not accepted.
16    ///
17    /// # Device Requirements
18    ///
19    /// The device MUST NOT offer a feature which requires another feature which was not offered.
20    ///
21    /// # Examples
22    ///
23    /// ```
24    /// # use virtio_spec as virtio;
25    /// use virtio::FeatureBits;
26    ///
27    /// assert!((virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_CSUM).requirements_satisfied());
28    /// assert!(
29    ///     (virtio::net::F::GUEST_ECN | virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_CSUM)
30    ///         .requirements_satisfied()
31    /// );
32    /// ```
33    fn requirements_satisfied(&self) -> bool {
34        true
35    }
36
37    /// Returns `true` if all internal feature recommendations are satisfied.
38    ///
39    /// # Driver Requirements
40    ///
41    /// The driver SHOULD NOT accept a feature which recommends another feature which was not accepted.
42    ///
43    /// # Device Requirements
44    ///
45    /// The device SHOULD NOT offer a feature which recommends another feature which was not offered.
46    ///
47    /// # Examples
48    ///
49    /// ```
50    /// # use virtio_spec as virtio;
51    /// use virtio::FeatureBits;
52    ///
53    /// assert!((virtio::net::F::HASH_REPORT | virtio::net::F::CTRL_VQ).recommendations_satisfied());
54    /// ```
55    fn recommendations_satisfied(&self) -> bool {
56        true
57    }
58}
59
60endian_bitflags! {
61    /// Device-independent Feature Bits
62    #[doc(alias = "VIRTIO_F")]
63    pub struct F: le128 {
64        /// Negotiating this feature indicates
65        /// that the driver can use descriptors with the VIRTQ_DESC_F_INDIRECT
66        /// flag set, as described in _Basic Facilities of a Virtio
67        /// Device / Virtqueues / The Virtqueue Descriptor Table / Indirect
68        /// Descriptors_ _Basic Facilities of a Virtio Device /
69        /// Virtqueues / The Virtqueue Descriptor Table / Indirect
70        /// Descriptors_ and _Packed Virtqueues / Indirect Flag: Scatter-Gather Support_ _Packed Virtqueues / Indirect Flag: Scatter-Gather Support_.
71        #[doc(alias = "VIRTIO_F_INDIRECT_DESC")]
72        const INDIRECT_DESC = 1 << 28;
73
74        /// This feature enables the _used_event_
75        /// and the _avail_event_ fields as described in
76        /// _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_.
77        #[doc(alias = "VIRTIO_F_EVENT_IDX")]
78        const EVENT_IDX = 1 << 29;
79
80        /// This indicates compliance with this
81        /// specification, giving a simple way to detect legacy devices or drivers.
82        #[doc(alias = "VIRTIO_F_VERSION_1")]
83        const VERSION_1 = 1 << 32;
84
85        /// This feature indicates that
86        /// the device can be used on a platform where device access to data
87        /// in memory is limited and/or translated. E.g. this is the case if the device can be located
88        /// behind an IOMMU that translates bus addresses from the device into physical
89        /// addresses in memory, if the device can be limited to only access
90        /// certain memory addresses or if special commands such as
91        /// a cache flush can be needed to synchronise data in memory with
92        /// the device. Whether accesses are actually limited or translated
93        /// is described by platform-specific means.
94        /// If this feature bit is set to 0, then the device
95        /// has same access to memory addresses supplied to it as the
96        /// driver has.
97        /// In particular, the device will always use physical addresses
98        /// matching addresses used by the driver (typically meaning
99        /// physical addresses used by the CPU)
100        /// and not translated further, and can access any address supplied to it by
101        /// the driver. When clear, this overrides any platform-specific description of
102        /// whether device access is limited or translated in any way, e.g.
103        /// whether an IOMMU may be present.
104        #[doc(alias = "VIRTIO_F_ACCESS_PLATFORM")]
105        const ACCESS_PLATFORM = 1 << 33;
106
107        /// This feature indicates
108        /// support for the packed virtqueue layout as described in
109        /// _Basic Facilities of a Virtio Device / Packed Virtqueues_ _Basic Facilities of a Virtio Device / Packed Virtqueues_.
110        #[doc(alias = "VIRTIO_F_RING_PACKED")]
111        const RING_PACKED = 1 << 34;
112
113        /// This feature indicates
114        /// that all buffers are used by the device in the same
115        /// order in which they have been made available.
116        #[doc(alias = "VIRTIO_F_IN_ORDER")]
117        const IN_ORDER = 1 << 35;
118
119        /// This feature indicates
120        /// that memory accesses by the driver and the device are ordered
121        /// in a way described by the platform.
122        ///
123        /// If this feature bit is negotiated, the ordering in effect for any
124        /// memory accesses by the driver that need to be ordered in a specific way
125        /// with respect to accesses by the device is the one suitable for devices
126        /// described by the platform. This implies that the driver needs to use
127        /// memory barriers suitable for devices described by the platform; e.g.
128        /// for the PCI transport in the case of hardware PCI devices.
129        ///
130        /// If this feature bit is not negotiated, then the device
131        /// and driver are assumed to be implemented in software, that is
132        /// they can be assumed to run on identical CPUs
133        /// in an SMP configuration.
134        /// Thus a weaker form of memory barriers is sufficient
135        /// to yield better performance.
136        #[doc(alias = "VIRTIO_F_ORDER_PLATFORM")]
137        const ORDER_PLATFORM = 1 << 36;
138
139        /// This feature indicates that
140        /// the device supports Single Root I/O Virtualization.
141        /// Currently only PCI devices support this feature.
142        #[doc(alias = "VIRTIO_F_SR_IOV")]
143        const SR_IOV = 1 << 37;
144
145        /// This feature indicates
146        /// that the driver passes extra data (besides identifying the virtqueue)
147        /// in its device notifications.
148        /// See _Basic Facilities of a Virtio Device / Driver notifications_.
149        #[doc(alias = "VIRTIO_F_NOTIFICATION_DATA")]
150        const NOTIFICATION_DATA = 1 << 38;
151
152        /// This feature indicates that the driver
153        /// uses the data provided by the device as a virtqueue identifier in available
154        /// buffer notifications.
155        /// As mentioned in section _Basic Facilities of a Virtio Device / Driver notifications_, when the
156        /// driver is required to send an available buffer notification to the device, it
157        /// sends the virtqueue index to be notified. The method of delivering
158        /// notifications is transport specific.
159        /// With the PCI transport, the device can optionally provide a per-virtqueue value
160        /// for the driver to use in driver notifications, instead of the virtqueue index.
161        /// Some devices may benefit from this flexibility by providing, for example,
162        /// an internal virtqueue identifier, or an internal offset related to the
163        /// virtqueue index.
164        ///
165        /// This feature indicates the availability of such value. The definition of the
166        /// data to be provided in driver notification and the delivery method is
167        /// transport specific.
168        /// 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_.
169        #[doc(alias = "VIRTIO_F_NOTIF_CONFIG_DATA")]
170        const NOTIF_CONFIG_DATA = 1 << 39;
171
172        /// This feature indicates
173        /// that the driver can reset a queue individually.
174        /// See _Basic Facilities of a Virtio Device / Virtqueues / Virtqueue Reset_.
175        #[doc(alias = "VIRTIO_F_RING_RESET")]
176        const RING_RESET = 1 << 40;
177
178        /// This feature indicates that the device exposes one or more
179        /// administration virtqueues.
180        /// At the moment this feature is only supported for devices using
181        /// _Virtio Transport Options / Virtio Over PCI Bus_
182        /// as the transport and is reserved for future use for
183        /// devices using other transports (see
184        /// _Basic Facilities of a Virtio Device / Feature Bits_ for
185        /// handling features reserved for future use.
186        #[doc(alias = "VIRTIO_F_ADMIN_VQ")]
187        const ADMIN_VQ = 1 << 41;
188
189        /// This feature indicates that the driver can
190        /// suspend the device by set the SUSPEND bit to 1.
191        /// See _Basic Facilities of a Virtio Device / Device Status Field_.
192        #[doc(alias = "VIRTIO_F_SUSPEND")]
193        const SUSPEND = 1 << 43;
194    }
195}
196
197impl AsRef<F> for F {
198    fn as_ref(&self) -> &F {
199        self
200    }
201}
202
203impl AsMut<F> for F {
204    fn as_mut(&mut self) -> &mut F {
205        self
206    }
207}
208
209impl FeatureBits for F {}
210
211impl Sealed for F {}
212
213macro_rules! feature_bits {
214    (
215        $(#[$outer:meta])*
216        $vis:vis struct $BitFlags:ident: $T:ty {
217            $(
218                $(#[$inner:ident $($args:tt)*])*
219                const $Flag:tt = $value:expr;
220            )*
221        }
222
223        $($t:tt)*
224    ) => {
225        endian_bitflags! {
226            $(#[$outer])*
227            $vis struct $BitFlags: $T {
228                $(
229                    $(#[$inner $($args)*])*
230                    const $Flag = $value;
231                )*
232
233                /// Device-independent Bit. See [`virtio::F::INDIRECT_DESC`](crate::F::INDIRECT_DESC).
234                const INDIRECT_DESC = $crate::F::INDIRECT_DESC.bits().to_ne();
235
236                /// Device-independent Bit. See [`virtio::F::EVENT_IDX`](crate::F::EVENT_IDX).
237                const EVENT_IDX = $crate::F::EVENT_IDX.bits().to_ne();
238
239                /// Device-independent Bit. See [`virtio::F::VERSION_1`](crate::F::VERSION_1).
240                const VERSION_1 = $crate::F::VERSION_1.bits().to_ne();
241
242                /// Device-independent Bit. See [`virtio::F::ACCESS_PLATFORM`](crate::F::ACCESS_PLATFORM).
243                const ACCESS_PLATFORM = $crate::F::ACCESS_PLATFORM.bits().to_ne();
244
245                /// Device-independent Bit. See [`virtio::F::RING_PACKED`](crate::F::RING_PACKED).
246                const RING_PACKED = $crate::F::RING_PACKED.bits().to_ne();
247
248                /// Device-independent Bit. See [`virtio::F::IN_ORDER`](crate::F::IN_ORDER).
249                const IN_ORDER = $crate::F::IN_ORDER.bits().to_ne();
250
251                /// Device-independent Bit. See [`virtio::F::ORDER_PLATFORM`](crate::F::ORDER_PLATFORM).
252                const ORDER_PLATFORM = $crate::F::ORDER_PLATFORM.bits().to_ne();
253
254                /// Device-independent Bit. See [`virtio::F::SR_IOV`](crate::F::SR_IOV).
255                const SR_IOV = $crate::F::SR_IOV.bits().to_ne();
256
257                /// Device-independent Bit. See [`virtio::F::NOTIFICATION_DATA`](crate::F::NOTIFICATION_DATA).
258                const NOTIFICATION_DATA = $crate::F::NOTIFICATION_DATA.bits().to_ne();
259
260                /// Device-independent Bit. See [`virtio::F::NOTIF_CONFIG_DATA`](crate::F::NOTIF_CONFIG_DATA).
261                const NOTIF_CONFIG_DATA = $crate::F::NOTIF_CONFIG_DATA.bits().to_ne();
262
263                /// Device-independent Bit. See [`virtio::F::RING_RESET`](crate::F::RING_RESET).
264                const RING_RESET = $crate::F::RING_RESET.bits().to_ne();
265
266                /// Device-independent Bit. See [`virtio::F::ADMIN_VQ`](crate::F::ADMIN_VQ).
267                const ADMIN_VQ = $crate::F::ADMIN_VQ.bits().to_ne();
268
269                /// Device-independent Bit. See [`virtio::F::SUSPEND`](crate::F::SUSPEND).
270                const SUSPEND = $crate::F::SUSPEND.bits().to_ne();
271            }
272        }
273
274        impl From<$crate::F> for $BitFlags {
275            fn from(value: $crate::F) -> Self {
276                Self::from_bits_retain(value.bits())
277            }
278        }
279
280        impl AsRef<$BitFlags> for $crate::F {
281            fn as_ref(&self) -> &$BitFlags {
282                unsafe { &*(self as *const Self as *const $BitFlags) }
283            }
284        }
285
286        impl AsMut<$BitFlags> for $crate::F {
287            fn as_mut(&mut self) -> &mut $BitFlags {
288                unsafe { &mut *(self as *mut Self as *mut $BitFlags) }
289            }
290        }
291
292        impl From<$BitFlags> for $crate::F {
293            /// Returns the device-independent feature bits while retaining device-specific feature bits.
294            fn from(value: $BitFlags) -> Self {
295                $crate::F::from_bits_retain(value.bits())
296            }
297        }
298
299        impl AsRef<$crate::F> for $BitFlags {
300            /// Returns a shared reference to the device-independent features while retaining device-specific feature bits.
301            fn as_ref(&self) -> &$crate::F {
302                unsafe { &*(self as *const Self as *const $crate::F) }
303            }
304        }
305
306        impl AsMut<$crate::F> for $BitFlags {
307            /// Returns a mutable reference to the device-independent features while retaining device-specific feature bits.
308            fn as_mut(&mut self) -> &mut $crate::F {
309                unsafe { &mut *(self as *mut Self as *mut $crate::F) }
310            }
311        }
312
313        impl $crate::sealed::Sealed for $BitFlags {}
314
315        feature_bits! {
316            $($t)*
317        }
318    };
319    () => {};
320}
321
322pub mod console {
323    use crate::le128;
324
325    feature_bits! {
326        /// Console Device Feature Bits
327        #[doc(alias = "VIRTIO_CONSOLE_F")]
328        pub struct F: le128 {
329            /// Configuration `cols` and `rows` are valid.
330            #[doc(alias = "VIRTIO_CONSOLE_F_SIZE")]
331            const SIZE = 1 << 0;
332
333            /// Device has support for multiple ports;
334            ///
335            /// `max_nr_ports` is valid and control virtqueues will be used.
336            #[doc(alias = "VIRTIO_CONSOLE_F_MULTIPORT")]
337            const MULTIPORT = 1 << 1;
338
339            /// Device has support for emergency write.
340            ///
341            /// Configuration field emerg_wr is valid.
342            #[doc(alias = "VIRTIO_CONSOLE_F_EMERG_WRITE")]
343            const EMERG_WRITE = 1 << 2;
344        }
345    }
346
347    impl crate::FeatureBits for F {}
348}
349
350pub mod blk {
351    use crate::le128;
352
353    feature_bits! {
354        /// Block Device Feature Bits
355        #[doc(alias = "VIRTIO_BLK_F")]
356        pub struct F: le128 {
357            /// Maximum size of any single segment is
358            // in `size_max`.
359            #[doc(alias = "VIRTIO_BLK_F_SIZE_MAX")]
360            const SIZE_MAX = 1 << 1;
361
362            /// Maximum number of segments in a
363            /// request is in `seg_max`.
364            #[doc(alias = "VIRTIO_BLK_F_SEG_MAX")]
365            const SEG_MAX = 1 << 2;
366
367            /// Disk-style geometry specified in
368            /// `geometry`.
369            #[doc(alias = "VIRTIO_BLK_F_GEOMETRY")]
370            const GEOMETRY = 1 << 4;
371
372            /// Device is read-only.
373            #[doc(alias = "VIRTIO_BLK_F_RO")]
374            const RO = 1 << 5;
375
376            /// Block size of disk is in `blk_size`.
377            #[doc(alias = "VIRTIO_BLK_F_BLK_SIZE")]
378            const BLK_SIZE = 1 << 6;
379
380            /// Cache flush command support.
381            #[doc(alias = "VIRTIO_BLK_F_FLUSH")]
382            const FLUSH = 1 << 9;
383
384            /// Device exports information on optimal I/O
385            /// alignment.
386            #[doc(alias = "VIRTIO_BLK_F_TOPOLOGY")]
387            const TOPOLOGY = 1 << 10;
388
389            /// Device can toggle its cache between writeback
390            /// and writethrough modes.
391            #[doc(alias = "VIRTIO_BLK_F_CONFIG_WCE")]
392            const CONFIG_WCE = 1 << 11;
393
394            /// Device supports multiqueue.
395            #[doc(alias = "VIRTIO_BLK_F_MQ")]
396            const MQ = 1 << 12;
397
398            /// Device can support discard command, maximum
399            /// discard sectors size in `max_discard_sectors` and maximum discard
400            /// segment number in `max_discard_seg`.
401            #[doc(alias = "VIRTIO_BLK_F_DISCARD")]
402            const DISCARD = 1 << 13;
403
404            /// Device can support write zeroes command,
405            /// maximum write zeroes sectors size in `max_write_zeroes_sectors` and
406            /// maximum write zeroes segment number in `max_write_zeroes_seg`.
407            #[doc(alias = "VIRTIO_BLK_F_WRITE_ZEROES")]
408            const WRITE_ZEROES = 1 << 14;
409
410            /// Device supports providing storage lifetime
411            /// information.
412            #[doc(alias = "VIRTIO_BLK_F_LIFETIME")]
413            const LIFETIME = 1 << 15;
414
415            /// Device supports secure erase command,
416            /// maximum erase sectors count in `max_secure_erase_sectors` and
417            /// maximum erase segment number in `max_secure_erase_seg`.
418            #[doc(alias = "VIRTIO_BLK_F_SECURE_ERASE")]
419            const SECURE_ERASE = 1 << 16;
420
421            /// Device is a Zoned Block Device, that is, a device
422            /// that follows the zoned storage device behavior that is also supported by
423            /// industry standards such as the T10 Zoned Block Command standard (ZBC r05) or
424            /// the NVMe(TM) NVM Express Zoned Namespace Command Set Specification 1.1b
425            /// (ZNS). For brevity, these standard documents are referred as "ZBD standards"
426            /// from this point on in the text.
427            #[doc(alias = "VIRTIO_BLK_F_ZONED")]
428            const ZONED = 1 << 17;
429        }
430    }
431
432    impl crate::FeatureBits for F {}
433}
434
435pub mod net {
436    use crate::le128;
437
438    feature_bits! {
439        /// Network Device Feature Bits
440        #[doc(alias = "VIRTIO_NET_F")]
441        pub struct F: le128 {
442            /// Device handles packets with partial checksum offload.
443            #[doc(alias = "VIRTIO_NET_F_CSUM")]
444            const CSUM = 1 << 0;
445
446            /// Driver handles packets with partial checksum.
447            #[doc(alias = "VIRTIO_NET_F_GUEST_CSUM")]
448            const GUEST_CSUM = 1 << 1;
449
450            /// Control channel offloads
451            /// reconfiguration support.
452            #[doc(alias = "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS")]
453            const CTRL_GUEST_OFFLOADS = 1 << 2;
454
455            /// Device maximum MTU reporting is supported. If
456            /// offered by the device, device advises driver about the value of
457            /// its maximum MTU. If negotiated, the driver uses _mtu_ as
458            /// the maximum MTU value.
459            #[doc(alias = "VIRTIO_NET_F_MTU")]
460            const MTU = 1 << 3;
461
462            /// Device has given MAC address.
463            #[doc(alias = "VIRTIO_NET_F_MAC")]
464            const MAC = 1 << 5;
465
466            /// Driver can receive TSOv4.
467            #[doc(alias = "VIRTIO_NET_F_GUEST_TSO4")]
468            const GUEST_TSO4 = 1 << 7;
469
470            /// Driver can receive TSOv6.
471            #[doc(alias = "VIRTIO_NET_F_GUEST_TSO6")]
472            const GUEST_TSO6 = 1 << 8;
473
474            /// Driver can receive TSO with ECN.
475            #[doc(alias = "VIRTIO_NET_F_GUEST_ECN")]
476            const GUEST_ECN = 1 << 9;
477
478            /// Driver can receive UFO.
479            #[doc(alias = "VIRTIO_NET_F_GUEST_UFO")]
480            const GUEST_UFO = 1 << 10;
481
482            /// Device can receive TSOv4.
483            #[doc(alias = "VIRTIO_NET_F_HOST_TSO4")]
484            const HOST_TSO4 = 1 << 11;
485
486            /// Device can receive TSOv6.
487            #[doc(alias = "VIRTIO_NET_F_HOST_TSO6")]
488            const HOST_TSO6 = 1 << 12;
489
490            /// Device can receive TSO with ECN.
491            #[doc(alias = "VIRTIO_NET_F_HOST_ECN")]
492            const HOST_ECN = 1 << 13;
493
494            /// Device can receive UFO.
495            #[doc(alias = "VIRTIO_NET_F_HOST_UFO")]
496            const HOST_UFO = 1 << 14;
497
498            /// Driver can merge receive buffers.
499            #[doc(alias = "VIRTIO_NET_F_MRG_RXBUF")]
500            const MRG_RXBUF = 1 << 15;
501
502            /// Configuration status field is
503            /// available.
504            #[doc(alias = "VIRTIO_NET_F_STATUS")]
505            const STATUS = 1 << 16;
506
507            /// Control channel is available.
508            #[doc(alias = "VIRTIO_NET_F_CTRL_VQ")]
509            const CTRL_VQ = 1 << 17;
510
511            /// Control channel RX mode support.
512            #[doc(alias = "VIRTIO_NET_F_CTRL_RX")]
513            const CTRL_RX = 1 << 18;
514
515            /// Control channel VLAN filtering.
516            #[doc(alias = "VIRTIO_NET_F_CTRL_VLAN")]
517            const CTRL_VLAN = 1 << 19;
518
519            /// Control channel RX extra mode support.
520            #[doc(alias = "VIRTIO_NET_F_CTRL_RX_EXTRA")]
521            const CTRL_RX_EXTRA = 1 << 20;
522
523            /// Driver can send gratuitous
524            /// packets.
525            #[doc(alias = "VIRTIO_NET_F_GUEST_ANNOUNCE")]
526            const GUEST_ANNOUNCE = 1 << 21;
527
528            /// Device supports multiqueue with automatic
529            /// receive steering.
530            #[doc(alias = "VIRTIO_NET_F_MQ")]
531            const MQ = 1 << 22;
532
533            /// Set MAC address through control
534            /// channel.
535            #[doc(alias = "VIRTIO_NET_F_CTRL_MAC_ADDR")]
536            const CTRL_MAC_ADDR = 1 << 23;
537
538            /// Device can provide device-level statistics
539            /// to the driver through the control virtqueue.
540            #[doc(alias = "VIRTIO_NET_F_DEVICE_STATS")]
541            const DEVICE_STATS = 1 << 50;
542
543            /// Device supports inner header hash for encapsulated packets.
544            #[doc(alias = "VIRTIO_NET_F_HASH_TUNNEL")]
545            const HASH_TUNNEL = 1 << 51;
546
547            /// Device supports virtqueue notification coalescing.
548            #[doc(alias = "VIRTIO_NET_F_VQ_NOTF_COAL")]
549            const VQ_NOTF_COAL = 1 << 52;
550
551            /// Device supports notifications coalescing.
552            #[doc(alias = "VIRTIO_NET_F_NOTF_COAL")]
553            const NOTF_COAL = 1 << 53;
554
555            /// Driver can receive USOv4 packets.
556            #[doc(alias = "VIRTIO_NET_F_GUEST_USO4")]
557            const GUEST_USO4 = 1 << 54;
558
559            /// Driver can receive USOv6 packets.
560            #[doc(alias = "VIRTIO_NET_F_GUEST_USO6")]
561            const GUEST_USO6 = 1 << 55;
562
563            /// Device can receive USO packets. Unlike UFO
564            /// (fragmenting the packet) the USO splits large UDP packet
565            /// to several segments when each of these smaller packets has UDP header.
566            #[doc(alias = "VIRTIO_NET_F_HOST_USO")]
567            const HOST_USO = 1 << 56;
568
569            /// Device can report per-packet hash
570            /// value and a type of calculated hash.
571            #[doc(alias = "VIRTIO_NET_F_HASH_REPORT")]
572            const HASH_REPORT = 1 << 57;
573
574            /// Driver can provide the exact _hdr_len_
575            /// value. Device benefits from knowing the exact header length.
576            #[doc(alias = "VIRTIO_NET_F_GUEST_HDRLEN")]
577            const GUEST_HDRLEN = 1 << 59;
578
579            /// Device supports RSS (receive-side scaling)
580            /// with Toeplitz hash calculation and configurable hash
581            /// parameters for receive steering.
582            #[doc(alias = "VIRTIO_NET_F_RSS")]
583            const RSS = 1 << 60;
584
585            /// Device can process duplicated ACKs
586            /// and report number of coalesced segments and duplicated ACKs.
587            #[doc(alias = "VIRTIO_NET_F_RSC_EXT")]
588            const RSC_EXT = 1 << 61;
589
590            /// Device may act as a standby for a primary
591            /// device with the same MAC address.
592            #[doc(alias = "VIRTIO_NET_F_STANDBY")]
593            const STANDBY = 1 << 62;
594
595            /// Device reports speed and duplex.
596            #[doc(alias = "VIRTIO_NET_F_SPEED_DUPLEX")]
597            const SPEED_DUPLEX = 1 << 63;
598
599            /// Device supports multiple RSS contexts.
600            #[doc(alias = "VIRTIO_NET_F_RSS_CONTEXT")]
601            const RSS_CONTEXT = 1 << 64;
602
603            /// Driver can receive GSO packets
604            /// carried by a UDP tunnel.
605            #[doc(alias = "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO")]
606            const GUEST_UDP_TUNNEL_GSO = 1 << 65;
607
608            /// Driver handles packets
609            /// carried by a UDP tunnel with partial csum for the outer header.
610            #[doc(alias = "VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM")]
611            const GUEST_UDP_TUNNEL_GSO_CSUM = 1 << 66;
612
613            /// Device can receive GSO packets
614            /// carried by a UDP tunnel.
615            #[doc(alias = "VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO")]
616            const HOST_UDP_TUNNEL_GSO = 1 << 67;
617
618            /// Device handles packets
619            /// carried by a UDP tunnel with partial csum for the outer header.
620            #[doc(alias = "VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM")]
621            const HOST_UDP_TUNNEL_GSO_CSUM = 1 << 68;
622
623            /// Driver can provide the start of
624            /// `outer_nh_offset` value. Device gains advantage by not reading packet
625            /// to calculate outer network header offset.
626            #[doc(alias = "VIRTIO_NET_F_OUT_NET_HEADER")]
627            const OUT_NET_HEADER = 1 << 69;
628
629            /// Device supports inline IPsec processing.
630            /// `struct virtio_net_hdr` size expands upto field `sturct ipsec_resource_hdr`
631            /// when VIRTIO_NET_F_IPSEC is negotiated. When a device offers IPsec feature, it SHOULD
632            /// also offer the VIRTIO_NET_F_OUT_NET_HEADER feature.
633            #[doc(alias = "VIRTIO_NET_F_IPSEC")]
634            const IPSEC = 1 << 70;
635        }
636    }
637
638    impl crate::FeatureBits for F {
639        fn requirements_satisfied(&self) -> bool {
640            self.iter().all(|feature| match feature {
641                Self::GUEST_TSO4 => self.contains(Self::GUEST_CSUM),
642                Self::GUEST_TSO6 => self.contains(Self::GUEST_CSUM),
643                Self::GUEST_ECN => self.intersects(Self::GUEST_TSO4 | Self::GUEST_TSO6),
644                Self::GUEST_UFO => self.contains(Self::GUEST_CSUM),
645                Self::GUEST_USO4 => self.contains(Self::GUEST_CSUM),
646                Self::GUEST_USO6 => self.contains(Self::GUEST_CSUM),
647                Self::GUEST_UDP_TUNNEL_GSO => self.contains(
648                    Self::GUEST_TSO4 | Self::GUEST_TSO6 | Self::GUEST_USO4 | Self::GUEST_USO6,
649                ),
650                Self::GUEST_UDP_TUNNEL_GSO_CSUM => self.contains(Self::GUEST_UDP_TUNNEL_GSO),
651                Self::HOST_TSO4 => self.contains(Self::CSUM),
652                Self::HOST_TSO6 => self.contains(Self::CSUM),
653                Self::HOST_ECN => self.intersects(Self::HOST_TSO4 | Self::HOST_TSO6),
654                Self::HOST_UFO => self.contains(Self::CSUM),
655                Self::HOST_USO => self.contains(Self::CSUM),
656                Self::HOST_UDP_TUNNEL_GSO => {
657                    self.contains(Self::HOST_TSO4 | Self::HOST_TSO6 | Self::HOST_USO)
658                }
659                Self::HOST_UDP_TUNNEL_GSO_CSUM => self.contains(Self::HOST_UDP_TUNNEL_GSO),
660                Self::CTRL_RX => self.contains(Self::CTRL_VQ),
661                Self::CTRL_VLAN => self.contains(Self::CTRL_VQ),
662                Self::GUEST_ANNOUNCE => self.contains(Self::CTRL_VQ),
663                Self::MQ => self.contains(Self::CTRL_VQ),
664                Self::CTRL_MAC_ADDR => self.contains(Self::CTRL_VQ),
665                Self::NOTF_COAL => self.contains(Self::CTRL_VQ),
666                Self::RSC_EXT => self.intersects(Self::HOST_TSO4 | Self::HOST_TSO6),
667                Self::RSS => self.contains(Self::CTRL_VQ),
668                Self::VQ_NOTF_COAL => self.contains(Self::CTRL_VQ),
669                Self::HASH_TUNNEL => {
670                    self.contains(Self::CTRL_VQ) && self.intersects(Self::RSS | Self::HASH_REPORT)
671                }
672                Self::RSS_CONTEXT => self.contains(Self::CTRL_VQ | Self::RSS),
673                _ => true,
674            })
675        }
676
677        fn recommendations_satisfied(&self) -> bool {
678            self.iter().all(|feature| match feature {
679                Self::HASH_REPORT => self.contains(Self::CTRL_VQ),
680                Self::CTRL_RX_EXTRA => self.contains(Self::CTRL_VQ),
681                _ => true,
682            })
683        }
684    }
685}
686
687pub mod fs {
688    use crate::le128;
689
690    feature_bits! {
691        /// File System Device Feature Bits
692        #[doc(alias = "VIRTIO_FS_F")]
693        pub struct F: le128 {
694            /// Device has support for FUSE notify
695            /// messages.  The notification queue is virtqueue 1.
696            #[doc(alias = "VIRTIO_FS_F_NOTIFICATION")]
697            const NOTIFICATION = 1 << 0;
698        }
699    }
700
701    impl crate::FeatureBits for F {}
702}
703
704pub mod vsock {
705    use crate::le128;
706
707    feature_bits! {
708        /// Socket Device Feature Bits
709        #[doc(alias = "VIRTIO_VSOCK_F")]
710        pub struct F: le128 {
711            /// stream socket type is supported.
712            #[doc(alias = "VIRTIO_VSOCK_F_STREAM")]
713            const STREAM = 1 << 0;
714
715            /// seqpacket socket type is supported.
716            #[doc(alias = "VIRTIO_VSOCK_F_SEQPACKET")]
717            const SEQPACKET = 1 << 1;
718
719            /// stream socket type is not implied.
720            #[doc(alias = "VIRTIO_VSOCK_F_NO_IMPLIED_STREAM")]
721            const NO_IMPLIED_STREAM = 1 << 2;
722        }
723    }
724
725    impl crate::FeatureBits for F {}
726}
727
728pub mod balloon {
729    use crate::le128;
730
731    feature_bits! {
732        /// Traditional Memory Balloon Device Feature Bits
733        #[doc(alias = "VIRTIO_BALLOON_F")]
734        pub struct F: le128 {
735            /// Host has to be told before pages from the balloon are used.
736            #[doc(alias = "VIRTIO_BALLOON_F_MUST_TELL_HOST")]
737            const MUST_TELL_HOST = 1 << 0;
738
739            /// A virtqueue for reporting guest memory statistics is present.
740            #[doc(alias = "VIRTIO_BALLOON_F_STATS_VQ")]
741            const STATS_VQ = 1 << 1;
742
743            /// Deflate balloon on guest out of memory condition.
744            ///
745            /// <div class="warning">
746            ///
747            /// The specification is a bit confusing on this feature, see [oasis-tcs/virtio-spec#228](https://github.com/oasis-tcs/virtio-spec/issues/228).
748            ///
749            /// </div>
750            #[doc(alias = "VIRTIO_BALLOON_F_DEFLATE_ON_OOM")]
751            const DEFLATE_ON_OOM = 1 << 2;
752
753            /// The device has support for free page hinting.
754            /// A virtqueue for providing hints as to what memory is currently free is present.
755            /// Configuration field [`free_page_hint_cmd_id`](`crate::balloon::ConfigVolatileFieldAccess::free_page_hint_cmd_id`) is valid.
756            #[doc(alias = "VIRTIO_BALLOON_F_FREE_PAGE_HINT")]
757            const FREE_PAGE_HINT = 1 << 3;
758
759            /// A hint to the device, that the driver will immediately write
760            /// [`poison_val`] to pages after deflating them.
761            /// Configuration field [`poison_val`] is valid.
762            ///
763            /// [`poison_val`]: crate::balloon::ConfigVolatileFieldAccess::poison_val
764            #[doc(alias = "VIRTIO_BALLOON_F_PAGE_POISON")]
765            const PAGE_POISON = 1 << 4;
766
767            /// The device has support for free page reporting.
768            /// A virtqueue for reporting free guest memory is present.
769            #[doc(alias = "VIRTIO_BALLOON_F_PAGE_REPORTING")]
770            const PAGE_REPORTING = 1 << 5;
771        }
772    }
773
774    impl crate::FeatureBits for F {}
775}
776
777#[cfg(test)]
778mod tests {
779    use super::*;
780
781    #[rustfmt::skip]
782    #[test]
783    fn requirements_satisfied() {
784        assert!(F::INDIRECT_DESC.requirements_satisfied());
785
786        assert!(net::F::CSUM.requirements_satisfied());
787
788        assert!(!net::F::MQ.requirements_satisfied());
789        assert!((net::F::MQ | net::F::CTRL_VQ).requirements_satisfied());
790
791        assert!(!net::F::HOST_TSO4.requirements_satisfied());
792        assert!((net::F::HOST_TSO4 | net::F::CSUM).requirements_satisfied());
793        assert!((net::F::HOST_TSO4 | net::F::HOST_TSO6 | net::F::CSUM).requirements_satisfied());
794
795        assert!(!net::F::HOST_ECN.requirements_satisfied());
796        assert!(!(net::F::HOST_ECN | net::F::CSUM).requirements_satisfied());
797        assert!(!(net::F::HOST_ECN | net::F::HOST_TSO4).requirements_satisfied());
798        assert!((net::F::HOST_ECN | net::F::HOST_TSO4 | net::F::CSUM).requirements_satisfied());
799        assert!((net::F::HOST_ECN | net::F::HOST_TSO4 | net::F::HOST_TSO6 | net::F::CSUM).requirements_satisfied());
800    }
801}