@@ -381,11 +381,19 @@ impl<T: Req> VhostUserMsgValidator for VhostUserMsgHeader<T> {
381
381
bitflags ! {
382
382
#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
383
383
/// Transport specific flags in VirtIO feature set defined by vhost-user.
384
+ ///
385
+ /// NOTE: This is for vhost-user transport-specific features only.
386
+ /// Standard VirtIO device features (like VIRTIO_F_RING_PACKED) should be
387
+ /// negotiated through the normal VirtIO device feature mechanism, not here.
384
388
pub struct VhostUserVirtioFeatures : u64 {
385
389
/// Log dirtied shared memory pages.
386
390
const LOG_ALL = 0x400_0000 ;
387
391
/// Feature flag for the protocol feature.
388
392
const PROTOCOL_FEATURES = 0x4000_0000 ;
393
+ // NOTE: VIRTIO_F_RING_PACKED was incorrectly placed here. It's a standard
394
+ // VirtIO device feature and should be negotiated through device features,
395
+ // not vhost-user transport features. Packed virtqueue configuration is
396
+ // handled through VhostUserVringAddrFlags::VHOST_VRING_F_PACKED.
389
397
}
390
398
}
391
399
@@ -708,11 +716,23 @@ impl VhostUserMsgValidator for VhostUserVringState {}
708
716
709
717
// Bit mask for vring address flags.
710
718
bitflags ! {
711
- /// Flags for vring address.
719
+ /// Flags for vring address configuration.
720
+ ///
721
+ /// These flags control vring setup and are used AFTER device feature negotiation.
722
+ /// The proper flow is:
723
+ /// 1. Device features (like VIRTIO_F_RING_PACKED) are negotiated through VirtIO standard mechanism
724
+ /// 2. These flags configure the actual vring layout based on negotiated features
725
+ ///
726
+ /// NOTE: These values must match the constants in crate::backend::vring_flags
727
+ /// to ensure compatibility between vhost-user and vhost-kern backends.
712
728
pub struct VhostUserVringAddrFlags : u32 {
713
729
/// Support log of vring operations.
714
730
/// Modifications to "used" vring should be logged.
715
731
const VHOST_VRING_F_LOG = 0x1 ;
732
+ /// Indicates packed virtqueue format.
733
+ /// When set, the vring uses packed layout instead of split layout.
734
+ /// This should only be set if VIRTIO_F_RING_PACKED was negotiated as a device feature.
735
+ const VHOST_VRING_F_PACKED = 0x2 ;
716
736
}
717
737
}
718
738
@@ -777,13 +797,31 @@ impl VhostUserMsgValidator for VhostUserVringAddr {
777
797
fn is_valid ( & self ) -> bool {
778
798
if ( self . flags & !VhostUserVringAddrFlags :: all ( ) . bits ( ) ) != 0 {
779
799
return false ;
780
- } else if self . descriptor & 0xf != 0 {
781
- return false ;
782
- } else if self . available & 0x1 != 0 {
800
+ }
801
+
802
+ // Common validation for both packed and split rings
803
+ // Descriptor table must be 16-byte aligned for both formats
804
+ if self . descriptor & 0xf != 0 {
783
805
return false ;
784
- } else if self . used & 0x3 != 0 {
806
+ }
807
+ // Used ring must be 4-byte aligned for both formats
808
+ if self . used & 0x3 != 0 {
785
809
return false ;
786
810
}
811
+
812
+ // Available ring alignment depends on format
813
+ let is_packed = self . flags & VhostUserVringAddrFlags :: VHOST_VRING_F_PACKED . bits ( ) != 0 ;
814
+ if is_packed {
815
+ // Packed: available ring (device event suppression) must be 4-byte aligned
816
+ if self . available & 0x3 != 0 {
817
+ return false ;
818
+ }
819
+ } else {
820
+ // Split: available ring must be 2-byte aligned
821
+ if self . available & 0x1 != 0 {
822
+ return false ;
823
+ }
824
+ }
787
825
true
788
826
}
789
827
}
@@ -1417,4 +1455,72 @@ mod tests {
1417
1455
msg. flags |= 0x4 ;
1418
1456
assert ! ( !msg. is_valid( ) ) ;
1419
1457
}
1458
+
1459
+ #[ test]
1460
+ fn test_packed_virtqueue_vring_flags ( ) {
1461
+ // Test vring address flags for packed virtqueue configuration
1462
+ // NOTE: VIRTIO_F_RING_PACKED device feature negotiation happens separately
1463
+
1464
+ let a = VhostUserVringAddrFlags :: VHOST_VRING_F_PACKED . bits ( ) ;
1465
+ assert_eq ! ( a, 0x2 ) ;
1466
+
1467
+ let combined = VhostUserVringAddrFlags :: VHOST_VRING_F_LOG
1468
+ | VhostUserVringAddrFlags :: VHOST_VRING_F_PACKED ;
1469
+ let a = combined. bits ( ) ;
1470
+ assert_eq ! ( a, 0x3 ) ;
1471
+ }
1472
+
1473
+ #[ test]
1474
+ fn test_packed_vring_addr_validation ( ) {
1475
+ let mut addr = VhostUserVringAddr :: new (
1476
+ 0 ,
1477
+ VhostUserVringAddrFlags :: VHOST_VRING_F_PACKED ,
1478
+ 0x1000 ,
1479
+ 0x2000 ,
1480
+ 0x3000 ,
1481
+ 0x4000 ,
1482
+ ) ;
1483
+
1484
+ let a = addr. index ;
1485
+ assert_eq ! ( a, 0 ) ;
1486
+ let a = addr. flags ;
1487
+ assert_eq ! ( a, VhostUserVringAddrFlags :: VHOST_VRING_F_PACKED . bits( ) ) ;
1488
+ let a = addr. descriptor ;
1489
+ assert_eq ! ( a, 0x1000 ) ;
1490
+ let a = addr. used ;
1491
+ assert_eq ! ( a, 0x2000 ) ;
1492
+ let a = addr. available ;
1493
+ assert_eq ! ( a, 0x3000 ) ;
1494
+ let a = addr. log ;
1495
+ assert_eq ! ( a, 0x4000 ) ;
1496
+ assert ! ( addr. is_valid( ) ) ;
1497
+
1498
+ addr. descriptor = 0x1001 ;
1499
+ assert ! ( !addr. is_valid( ) ) ;
1500
+ addr. descriptor = 0x1000 ;
1501
+
1502
+ addr. available = 0x3001 ;
1503
+ assert ! ( !addr. is_valid( ) ) ;
1504
+ addr. available = 0x3000 ;
1505
+
1506
+ addr. used = 0x2001 ;
1507
+ assert ! ( !addr. is_valid( ) ) ;
1508
+ addr. used = 0x2000 ;
1509
+ assert ! ( addr. is_valid( ) ) ;
1510
+ }
1511
+
1512
+ #[ test]
1513
+ fn test_vring_flags_compatibility ( ) {
1514
+ // Ensure vhost-user flags match the shared backend constants
1515
+ use crate :: backend:: vring_flags;
1516
+
1517
+ assert_eq ! (
1518
+ VhostUserVringAddrFlags :: VHOST_VRING_F_LOG . bits( ) ,
1519
+ vring_flags:: VHOST_VRING_F_LOG
1520
+ ) ;
1521
+ assert_eq ! (
1522
+ VhostUserVringAddrFlags :: VHOST_VRING_F_PACKED . bits( ) ,
1523
+ vring_flags:: VHOST_VRING_F_PACKED
1524
+ ) ;
1525
+ }
1420
1526
}
0 commit comments