Skip to content

Commit 79f0c10

Browse files
lauraltslp
authored andcommitted
Fix test for indirect table
`test_new_from_indirect_descriptor` was chaining two indirect tables, which is not a possible scenario according to the spec because you can't set VIRTQ_DESC_F_NEXT flag for a descriptor that is pointing to an indirect table, and when switching to the indirect table, there is no way to return to the main descriptor table (the `next` fields of the indirect descriptors will link to descriptors from the indirect table). This is also adding a negative test for the following MUST from the spec: `A driver MUST NOT set both VIRTQ_DESC_F_INDIRECT and VIRTQ_DESC_F_NEXT in flags.` In case the driver sets this combination of flags, we just ignore VIRTQ_DESC_F_NEXT flag and check that the device doesn't panic. Fixes: #95. The other MUSTs for indirect descriptors are related to the feature flags to which we do not have access at the queue level, so a test wouldn't make much sense. Signed-off-by: Laura Loghin <lauralg@amazon.com>
1 parent 3cb34d5 commit 79f0c10

File tree

1 file changed

+29
-23
lines changed

1 file changed

+29
-23
lines changed

crates/virtio-queue/src/lib.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ impl Descriptor {
125125

126126
/// Check whether this descriptor refers to a buffer containing an indirect descriptor table.
127127
pub fn refers_to_indirect_table(&self) -> bool {
128-
// TODO: The are a couple of restrictions in terms of which flags combinations are
129-
// actually valid for indirect descriptors. Implement those checks as well somewhere.
130128
self.flags() & VIRTQ_DESC_F_INDIRECT != 0
131129
}
132130

@@ -1221,49 +1219,57 @@ mod tests {
12211219

12221220
#[test]
12231221
fn test_new_from_indirect_descriptor() {
1222+
// This is testing that chaining an indirect table works as expected. It is also a negative
1223+
// test for the following requirement from the spec:
1224+
// `A driver MUST NOT set both VIRTQ_DESC_F_INDIRECT and VIRTQ_DESC_F_NEXT in flags.`. In
1225+
// case the driver is setting both of these flags, we check that the device doesn't panic.
12241226
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
12251227
let vq = MockSplitQueue::new(m, 16);
12261228
let dtable = vq.desc_table();
12271229

1228-
// Create a chain with two descriptors pointing to an indirect table.
1229-
let desc = Descriptor::new(0x1000, 0x1000, VIRTQ_DESC_F_INDIRECT | VIRTQ_DESC_F_NEXT, 1);
1230+
// Create a chain with one normal descriptor and one pointing to an indirect table.
1231+
let desc = Descriptor::new(0x6000, 0x1000, VIRTQ_DESC_F_NEXT, 1);
12301232
dtable.store(0, desc);
1231-
let desc = Descriptor::new(0x2000, 0x1000, VIRTQ_DESC_F_INDIRECT | VIRTQ_DESC_F_NEXT, 2);
1233+
// The spec forbids setting both VIRTQ_DESC_F_INDIRECT and VIRTQ_DESC_F_NEXT in flags. We do
1234+
// not currently enforce this rule, we just ignore the VIRTQ_DESC_F_NEXT flag.
1235+
let desc = Descriptor::new(0x7000, 0x1000, VIRTQ_DESC_F_INDIRECT | VIRTQ_DESC_F_NEXT, 2);
12321236
dtable.store(1, desc);
1233-
let desc = Descriptor::new(0x3000, 0x1000, 0, 0);
1237+
let desc = Descriptor::new(0x8000, 0x1000, 0, 0);
12341238
dtable.store(2, desc);
12351239

12361240
let mut c: DescriptorChain<&GuestMemoryMmap> = DescriptorChain::new(m, vq.start(), 16, 0);
12371241

1238-
// The chain logic hasn't parsed the indirect descriptor yet.
1239-
assert!(!c.is_indirect);
1240-
12411242
// create an indirect table with 4 chained descriptors
1242-
let idtable = DescriptorTable::new(m, GuestAddress(0x1000), 4);
1243-
for j in 0..4 {
1243+
let idtable = DescriptorTable::new(m, GuestAddress(0x7000), 4);
1244+
for i in 0..4u16 {
12441245
let desc: Descriptor;
1245-
if j < 3 {
1246-
desc = Descriptor::new(0x1000, 0x1000, VIRTQ_DESC_F_NEXT, j + 1);
1246+
if i < 3 {
1247+
desc = Descriptor::new(0x1000 * i as u64, 0x1000, VIRTQ_DESC_F_NEXT, i + 1);
12471248
} else {
1248-
desc = Descriptor::new(0x1000, 0x1000, 0, 0);
1249+
desc = Descriptor::new(0x1000 * i as u64, 0x1000, 0, 0);
12491250
}
1250-
idtable.store(j, desc);
1251+
idtable.store(i, desc);
12511252
}
12521253

1253-
let idtable2 = DescriptorTable::new(m, GuestAddress(0x2000), 1);
1254-
let desc2 = Descriptor::new(0x8000, 0x1000, 0, 0);
1255-
idtable2.store(0, desc2);
1256-
12571254
assert_eq!(c.head_index(), 0);
1258-
// try to iterate through the first indirect descriptor chain
1259-
for j in 0..4 {
1255+
// Consume the first descriptor.
1256+
c.next().unwrap();
1257+
1258+
// The chain logic hasn't parsed the indirect descriptor yet.
1259+
assert!(!c.is_indirect);
1260+
1261+
// Try to iterate through the indirect descriptor chain.
1262+
for i in 0..4 {
12601263
let desc = c.next().unwrap();
12611264
assert!(c.is_indirect);
1262-
if j < 3 {
1265+
if i < 3 {
12631266
assert_eq!(desc.flags(), VIRTQ_DESC_F_NEXT);
1264-
assert_eq!(desc.next, j + 1);
1267+
assert_eq!(desc.next, i + 1);
12651268
}
12661269
}
1270+
// Even though we added a new descriptor after the one that is pointing to the indirect
1271+
// table, this descriptor won't be available when parsing the chain.
1272+
assert!(c.next().is_none());
12671273
}
12681274

12691275
#[test]

0 commit comments

Comments
 (0)