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
//! Feature Bits
use crate::le128;
/// Feature Bits
#[doc(alias = "VIRTIO_F")]
pub trait FeatureBits: bitflags::Flags<Bits = le128>
where
Self: From<F> + AsRef<F> + AsMut<F>,
F: From<Self> + AsRef<Self> + AsMut<Self>,
{
/// Returns the feature that this feature requires.
///
/// If `self` is a single feature and multiple features are returned, `self` requires only one of them.
///
/// # Examples
///
/// ```
/// # use virtio_spec as virtio;
/// use virtio::FeatureBits;
///
/// assert_eq!(
/// virtio::net::F::GUEST_TSO4.requirements(),
/// virtio::net::F::GUEST_CSUM
/// );
/// assert_eq!(
/// virtio::net::F::GUEST_ECN.requirements(),
/// virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_TSO6
/// );
/// ```
fn requirements(&self) -> Self {
Self::empty()
}
/// Returns `true` if all internal feature requirements are satisfied.
///
/// # 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 {
self.iter()
.map(|feature| feature.requirements())
.filter(|requirements| !requirements.is_empty())
.all(|requirements| self.intersects(requirements))
}
}
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 _Virtqueues / Driver notifications_ _Virtqueues / 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 _Virtqueues / Driver notifications_, when the
/// driver is required to send an available buffer notification to the device, it
/// sends the virtqueue number 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 number.
/// Some devices may benefit from this flexibility by providing, for example,
/// an internal virtqueue identifier, or an internal offset related to the
/// virtqueue number.
///
/// 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;
}
}
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 {}
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();
}
}
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) }
}
}
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 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. This
/// “checksum offload” is a common feature on modern network cards.
#[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;
/// 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 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;
}
}
impl crate::FeatureBits for F {
fn requirements(&self) -> Self {
let mut requirements = Self::empty();
for feature in self.iter() {
let requirement = match feature {
Self::GUEST_TSO4 => Self::GUEST_CSUM,
Self::GUEST_TSO6 => Self::GUEST_CSUM,
Self::GUEST_ECN => Self::GUEST_TSO4 | Self::GUEST_TSO6,
Self::GUEST_UFO => Self::GUEST_CSUM,
Self::HOST_TSO4 => Self::CSUM,
Self::HOST_TSO6 => Self::CSUM,
Self::HOST_ECN => Self::HOST_TSO4 | Self::HOST_TSO6,
Self::HOST_UFO => Self::CSUM,
Self::HOST_USO => Self::CSUM,
Self::CTRL_RX => Self::CTRL_VQ,
Self::CTRL_VLAN => Self::CTRL_VQ,
Self::GUEST_ANNOUNCE => Self::CTRL_VQ,
Self::MQ => Self::CTRL_VQ,
Self::CTRL_MAC_ADDR => Self::CTRL_VQ,
Self::RSC_EXT => Self::HOST_TSO4 | Self::HOST_TSO6,
Self::RSS => Self::CTRL_VQ,
_ => Self::empty(),
};
requirements.insert(requirement);
}
requirements
}
}
}
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;
}
}
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());
}
}