Skip to content

Commit

Permalink
added supplementary vsock and memory unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandru Agache <[email protected]>
  • Loading branch information
alexandruag authored and acatangiu committed Dec 9, 2019
1 parent 019e7f6 commit e839b08
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 1 deletion.
11 changes: 10 additions & 1 deletion devices/src/virtio/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,8 @@ pub mod tests {

#[test]
fn test_checked_new_descriptor_chain() {
let m = &GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let m = &GuestMemory::new(&[(GuestAddress(0), 0x10000), (GuestAddress(0x20000), 0x2000)])
.unwrap();
let vq = VirtQueue::new(GuestAddress(0), m, 16);

assert!(vq.end().0 < 0x1000);
Expand All @@ -621,6 +622,14 @@ pub mod tests {
vq.dtable[0].addr.set(0x0fff_ffff_ffff);
assert!(DescriptorChain::checked_new(m, vq.dtable_start(), 16, 0).is_none());

// The following configuration is invalid because the addr + len crosses over the gap
// between the two memory regions we configured.
{
vq.dtable[0].addr.set(0x1000);
vq.dtable[0].len.set(0x20000);
assert!(DescriptorChain::checked_new(m, vq.dtable_start(), 16, 0).is_none());
}

// let's create some invalid chains

{
Expand Down
103 changes: 103 additions & 0 deletions devices/src/virtio/vsock/epoll_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ mod tests {
use super::super::*;
use super::*;
use crate::virtio::vsock::defs::{BACKEND_EVENT, EVQ_EVENT, RXQ_EVENT, TXQ_EVENT};
use crate::virtio::vsock::packet::VSOCK_PKT_HDR_SIZE;

#[test]
fn test_irq() {
Expand Down Expand Up @@ -460,4 +461,106 @@ mod tests {
other => panic!("{:?}", other),
}
}

// Creates an epoll handler context and attempts to assemble a VsockPkt from the descriptor
// chains available on the rx and tx virtqueues, but first it will set the addr and len
// of the descriptor specified by desc_idx to the provided values. We are only using this
// function for testing error cases, so the asserts always expect is_err() to be true. When
// desc_idx = 0 we are altering the header (first descriptor in the chain), and when
// desc_idx = 1 we are altering the packet buffer.
fn vsock_bof_helper(test_ctx: &mut TestContext, desc_idx: usize, addr: u64, len: u32) {
use memory_model::GuestAddress;

assert!(desc_idx <= 1);

{
let mut ctx = test_ctx.create_epoll_handler_context();
ctx.guest_rxvq.dtable[desc_idx].addr.set(addr);
ctx.guest_rxvq.dtable[desc_idx].len.set(len);
// If the descriptor chain is already declared invalid, there's no reason to assemble
// a packet.
if let Some(rx_desc) = ctx.handler.rxvq.pop(&test_ctx.mem) {
assert!(VsockPacket::from_rx_virtq_head(&rx_desc).is_err());
}
}

{
let mut ctx = test_ctx.create_epoll_handler_context();

// When modifiyng the buffer descriptor, make sure the len field is altered in the
// vsock packet header descriptor as well.
if desc_idx == 1 {
// The vsock packet len field has offset 24 in the header.
let hdr_len_addr = GuestAddress(ctx.guest_txvq.dtable[0].addr.get() as usize + 24);
test_ctx
.mem
.write_obj_at_addr(len.to_le_bytes(), hdr_len_addr)
.unwrap();
}

ctx.guest_txvq.dtable[desc_idx].addr.set(addr);
ctx.guest_txvq.dtable[desc_idx].len.set(len);

if let Some(tx_desc) = ctx.handler.txvq.pop(&test_ctx.mem) {
assert!(VsockPacket::from_tx_virtq_head(&tx_desc).is_err());
}
}
}

#[test]
fn test_vsock_bof() {
use memory_model::GuestAddress;

const GAP_SIZE: usize = 768 << 20;
const FIRST_AFTER_GAP: usize = 1 << 32;
const GAP_START_ADDR: usize = FIRST_AFTER_GAP - GAP_SIZE;
const MIB: usize = 1 << 20;

let mut test_ctx = TestContext::new();
test_ctx.mem = GuestMemory::new(&[
(GuestAddress(0), 8 * MIB),
(GuestAddress(GAP_START_ADDR - MIB), MIB),
(GuestAddress(FIRST_AFTER_GAP), MIB),
])
.unwrap();

// The default configured descriptor chains are valid.
{
let mut ctx = test_ctx.create_epoll_handler_context();
let rx_desc = ctx.handler.rxvq.pop(&test_ctx.mem).unwrap();
assert!(VsockPacket::from_rx_virtq_head(&rx_desc).is_ok());
}

{
let mut ctx = test_ctx.create_epoll_handler_context();
let tx_desc = ctx.handler.txvq.pop(&test_ctx.mem).unwrap();
assert!(VsockPacket::from_tx_virtq_head(&tx_desc).is_ok());
}

// Let's check what happens when the header descriptor is right before the gap.
vsock_bof_helper(
&mut test_ctx,
0,
GAP_START_ADDR as u64 - 1,
VSOCK_PKT_HDR_SIZE as u32,
);

// Let's check what happens when the buffer descriptor crosses into the gap, but does
// not go past its right edge.
vsock_bof_helper(
&mut test_ctx,
1,
GAP_START_ADDR as u64 - 4,
GAP_SIZE as u32 + 4,
);

// Let's modify the buffer descriptor addr and len such that it crosses over the MMIO gap,
// and check we cannot assemble the VsockPkts.
vsock_bof_helper(
&mut test_ctx,
1,
GAP_START_ADDR as u64 - 4,
GAP_SIZE as u32 + 100,
);
}
}
9 changes: 9 additions & 0 deletions devices/src/virtio/vsock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,21 @@ mod tests {
}
impl VsockChannel for TestBackend {
fn recv_pkt(&mut self, _pkt: &mut VsockPacket) -> Result<()> {
let cool_buf = [0xDu8, 0xE, 0xA, 0xD, 0xB, 0xE, 0xE, 0xF];
match self.rx_err.take() {
None => {
if let Some(buf) = _pkt.buf_mut() {
for i in 0..buf.len() {
buf[i] = cool_buf[i % cool_buf.len()];
}
}
self.rx_ok_cnt += 1;
Ok(())
}
Some(e) => Err(e),
}
}

fn send_pkt(&mut self, _pkt: &VsockPacket) -> Result<()> {
match self.tx_err.take() {
None => {
Expand All @@ -258,6 +265,7 @@ mod tests {
Some(e) => Err(e),
}
}

fn has_pending_rx(&self) -> bool {
self.pending_rx
}
Expand Down Expand Up @@ -322,6 +330,7 @@ mod tests {
1,
);
guest_rxvq.dtable[1].set(0x0040_1000, 4096, VIRTQ_DESC_F_WRITE, 0);

guest_rxvq.avail.ring[0].set(0);
guest_rxvq.avail.idx.set(1);

Expand Down

0 comments on commit e839b08

Please sign in to comment.