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