@@ -381,11 +381,19 @@ impl<T: Req> VhostUserMsgValidator for VhostUserMsgHeader<T> {
381381bitflags ! {
382382 #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
383383 /// 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.
384388 pub struct VhostUserVirtioFeatures : u64 {
385389 /// Log dirtied shared memory pages.
386390 const LOG_ALL = 0x400_0000 ;
387391 /// Feature flag for the protocol feature.
388392 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.
389397 }
390398}
391399
@@ -708,11 +716,23 @@ impl VhostUserMsgValidator for VhostUserVringState {}
708716
709717// Bit mask for vring address flags.
710718bitflags ! {
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.
712728 pub struct VhostUserVringAddrFlags : u32 {
713729 /// Support log of vring operations.
714730 /// Modifications to "used" vring should be logged.
715731 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 ;
716736 }
717737}
718738
@@ -777,13 +797,31 @@ impl VhostUserMsgValidator for VhostUserVringAddr {
777797 fn is_valid ( & self ) -> bool {
778798 if ( self . flags & !VhostUserVringAddrFlags :: all ( ) . bits ( ) ) != 0 {
779799 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 {
783805 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 {
785809 return false ;
786810 }
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+ }
787825 true
788826 }
789827}
@@ -1417,4 +1455,72 @@ mod tests {
14171455 msg. flags |= 0x4 ;
14181456 assert ! ( !msg. is_valid( ) ) ;
14191457 }
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+ }
14201526}
0 commit comments