use std::fmt::{self, Display};
use std::ops::Deref;
use virtio_queue::DescriptorChain;
use vm_memory::bitmap::{BitmapSlice, WithBitmapSlice};
use vm_memory::{
Address, ByteValued, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion, Le16, Le32, Le64,
VolatileMemoryError, VolatileSlice,
};
#[derive(Debug)]
pub enum Error {
DescriptorChainTooShort,
DescriptorLengthTooSmall,
DescriptorLengthTooLong,
InvalidHeaderInputSize(usize),
InvalidHeaderLen(u32),
InvalidMemoryAccess(GuestMemoryError),
InvalidVolatileAccess(VolatileMemoryError),
UnexpectedReadOnlyDescriptor,
UnexpectedWriteOnlyDescriptor,
}
impl std::error::Error for Error {}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::DescriptorChainTooShort => {
write!(f, "There are not enough descriptors in the chain.")
}
Error::DescriptorLengthTooSmall => write!(
f,
"The descriptor is pointing to a buffer that has a smaller length than expected."
),
Error::DescriptorLengthTooLong => write!(
f,
"The descriptor is pointing to a buffer that has a longer length than expected."
),
Error::InvalidHeaderInputSize(size) => {
write!(f, "Invalid header input size: {size}")
}
Error::InvalidHeaderLen(size) => {
write!(f, "Invalid header `len` field value: {size}")
}
Error::InvalidMemoryAccess(error) => {
write!(f, "Invalid guest memory access: {error}")
}
Error::InvalidVolatileAccess(error) => {
write!(f, "Invalid volatile memory access: {error}")
}
Error::UnexpectedReadOnlyDescriptor => {
write!(f, "Unexpected read-only descriptor.")
}
Error::UnexpectedWriteOnlyDescriptor => {
write!(f, "Unexpected write-only descriptor.")
}
}
}
}
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct PacketHeader {
src_cid: Le64,
dst_cid: Le64,
src_port: Le32,
dst_port: Le32,
len: Le32,
type_: Le16,
op: Le16,
flags: Le32,
buf_alloc: Le32,
fwd_cnt: Le32,
}
unsafe impl ByteValued for PacketHeader {}
pub const PKT_HEADER_SIZE: usize = std::mem::size_of::<PacketHeader>();
const SRC_CID_OFFSET: usize = 0;
const DST_CID_OFFSET: usize = 8;
const SRC_PORT_OFFSET: usize = 16;
const DST_PORT_OFFSET: usize = 20;
const LEN_OFFSET: usize = 24;
const TYPE_OFFSET: usize = 28;
const OP_OFFSET: usize = 30;
const FLAGS_OFFSET: usize = 32;
const BUF_ALLOC_OFFSET: usize = 36;
const FWD_CNT_OFFSET: usize = 40;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct VsockPacket<'a, B: BitmapSlice> {
header_slice: VolatileSlice<'a, B>,
header: PacketHeader,
data_slice: Option<VolatileSlice<'a, B>>,
}
macro_rules! set_header_field {
($packet:ident, $field:ident, $offset:ident, $value:ident) => {
$packet.header.$field = $value.into();
$packet
.header_slice
.write(&$value.to_le_bytes(), $offset)
.unwrap();
};
}
impl<'a, B: BitmapSlice> VsockPacket<'a, B> {
pub fn header_slice(&self) -> &VolatileSlice<'a, B> {
&self.header_slice
}
pub fn data_slice(&self) -> Option<&VolatileSlice<'a, B>> {
self.data_slice.as_ref()
}
pub fn set_header_from_raw(&mut self, bytes: &[u8]) -> Result<()> {
if bytes.len() != PKT_HEADER_SIZE {
return Err(Error::InvalidHeaderInputSize(bytes.len()));
}
self.header_slice
.write(bytes, 0)
.map_err(Error::InvalidVolatileAccess)?;
let header = self
.header_slice()
.read_obj::<PacketHeader>(0)
.map_err(Error::InvalidVolatileAccess)?;
self.header = header;
Ok(())
}
pub fn src_cid(&self) -> u64 {
self.header.src_cid.into()
}
pub fn set_src_cid(&mut self, cid: u64) -> &mut Self {
set_header_field!(self, src_cid, SRC_CID_OFFSET, cid);
self
}
pub fn dst_cid(&self) -> u64 {
self.header.dst_cid.into()
}
pub fn set_dst_cid(&mut self, cid: u64) -> &mut Self {
set_header_field!(self, dst_cid, DST_CID_OFFSET, cid);
self
}
pub fn src_port(&self) -> u32 {
self.header.src_port.into()
}
pub fn set_src_port(&mut self, port: u32) -> &mut Self {
set_header_field!(self, src_port, SRC_PORT_OFFSET, port);
self
}
pub fn dst_port(&self) -> u32 {
self.header.dst_port.into()
}
pub fn set_dst_port(&mut self, port: u32) -> &mut Self {
set_header_field!(self, dst_port, DST_PORT_OFFSET, port);
self
}
pub fn len(&self) -> u32 {
self.header.len.into()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn set_len(&mut self, len: u32) -> &mut Self {
set_header_field!(self, len, LEN_OFFSET, len);
self
}
pub fn type_(&self) -> u16 {
self.header.type_.into()
}
pub fn set_type(&mut self, type_: u16) -> &mut Self {
set_header_field!(self, type_, TYPE_OFFSET, type_);
self
}
pub fn op(&self) -> u16 {
self.header.op.into()
}
pub fn set_op(&mut self, op: u16) -> &mut Self {
set_header_field!(self, op, OP_OFFSET, op);
self
}
pub fn flags(&self) -> u32 {
self.header.flags.into()
}
pub fn set_flags(&mut self, flags: u32) -> &mut Self {
set_header_field!(self, flags, FLAGS_OFFSET, flags);
self
}
pub fn set_flag(&mut self, flag: u32) -> &mut Self {
self.set_flags(self.flags() | flag);
self
}
pub fn buf_alloc(&self) -> u32 {
self.header.buf_alloc.into()
}
pub fn set_buf_alloc(&mut self, buf_alloc: u32) -> &mut Self {
set_header_field!(self, buf_alloc, BUF_ALLOC_OFFSET, buf_alloc);
self
}
pub fn fwd_cnt(&self) -> u32 {
self.header.fwd_cnt.into()
}
pub fn set_fwd_cnt(&mut self, fwd_cnt: u32) -> &mut Self {
set_header_field!(self, fwd_cnt, FWD_CNT_OFFSET, fwd_cnt);
self
}
pub fn from_tx_virtq_chain<M, T>(
mem: &'a M,
desc_chain: &mut DescriptorChain<T>,
max_data_size: u32,
) -> Result<Self>
where
M: GuestMemory,
<<M as GuestMemory>::R as GuestMemoryRegion>::B: WithBitmapSlice<'a, S = B>,
T: Deref,
T::Target: GuestMemory,
{
let chain_head = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
if chain_head.is_write_only() {
return Err(Error::UnexpectedWriteOnlyDescriptor);
}
if (chain_head.len() as usize) < PKT_HEADER_SIZE {
return Err(Error::DescriptorLengthTooSmall);
}
let header_slice = mem
.get_slice(chain_head.addr(), PKT_HEADER_SIZE)
.map_err(Error::InvalidMemoryAccess)?;
let header = mem
.read_obj(chain_head.addr())
.map_err(Error::InvalidMemoryAccess)?;
let mut pkt = Self {
header_slice,
header,
data_slice: None,
};
if pkt.is_empty() {
return Ok(pkt);
}
if pkt.len() > max_data_size {
return Err(Error::InvalidHeaderLen(pkt.len()));
}
let data_slice =
if !chain_head.has_next() && chain_head.len() - PKT_HEADER_SIZE as u32 >= pkt.len() {
mem.get_slice(
chain_head
.addr()
.checked_add(PKT_HEADER_SIZE as u64)
.ok_or(Error::DescriptorLengthTooSmall)?,
pkt.len() as usize,
)
.map_err(Error::InvalidMemoryAccess)?
} else {
if !chain_head.has_next() {
return Err(Error::DescriptorChainTooShort);
}
let data_desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
if data_desc.is_write_only() {
return Err(Error::UnexpectedWriteOnlyDescriptor);
}
if data_desc.len() < pkt.len() {
return Err(Error::DescriptorLengthTooSmall);
}
mem.get_slice(data_desc.addr(), pkt.len() as usize)
.map_err(Error::InvalidMemoryAccess)?
};
pkt.data_slice = Some(data_slice);
Ok(pkt)
}
pub fn from_rx_virtq_chain<M, T>(
mem: &'a M,
desc_chain: &mut DescriptorChain<T>,
max_data_size: u32,
) -> Result<Self>
where
M: GuestMemory,
<<M as GuestMemory>::R as GuestMemoryRegion>::B: WithBitmapSlice<'a, S = B>,
T: Deref,
T::Target: GuestMemory,
{
let chain_head = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
if !chain_head.is_write_only() {
return Err(Error::UnexpectedReadOnlyDescriptor);
}
if (chain_head.len() as usize) < PKT_HEADER_SIZE {
return Err(Error::DescriptorLengthTooSmall);
}
let header_slice = mem
.get_slice(chain_head.addr(), PKT_HEADER_SIZE)
.map_err(Error::InvalidMemoryAccess)?;
let data_slice = if !chain_head.has_next() && chain_head.len() as usize > PKT_HEADER_SIZE {
mem.get_slice(
chain_head
.addr()
.checked_add(PKT_HEADER_SIZE as u64)
.ok_or(Error::DescriptorLengthTooSmall)?,
chain_head.len() as usize - PKT_HEADER_SIZE,
)
.map_err(Error::InvalidMemoryAccess)?
} else {
if !chain_head.has_next() {
return Err(Error::DescriptorChainTooShort);
}
let data_desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
if !data_desc.is_write_only() {
return Err(Error::UnexpectedReadOnlyDescriptor);
}
if data_desc.len() > max_data_size {
return Err(Error::DescriptorLengthTooLong);
}
mem.get_slice(data_desc.addr(), data_desc.len() as usize)
.map_err(Error::InvalidMemoryAccess)?
};
Ok(Self {
header_slice,
header: Default::default(),
data_slice: Some(data_slice),
})
}
}
impl<'a> VsockPacket<'a, ()> {
pub unsafe fn new(header: &mut [u8], data: Option<&mut [u8]>) -> Result<VsockPacket<'a, ()>> {
if header.len() != PKT_HEADER_SIZE {
return Err(Error::InvalidHeaderInputSize(header.len()));
}
Ok(VsockPacket {
header_slice: VolatileSlice::new(header.as_mut_ptr(), PKT_HEADER_SIZE),
header: Default::default(),
data_slice: data.map(|data| VolatileSlice::new(data.as_mut_ptr(), data.len())),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use vm_memory::{GuestAddress, GuestMemoryMmap};
use virtio_bindings::bindings::virtio_ring::VRING_DESC_F_WRITE;
use virtio_queue::desc::{split::Descriptor as SplitDescriptor, RawDescriptor};
use virtio_queue::mock::MockSplitQueue;
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
use self::Error::*;
match (self, other) {
(DescriptorChainTooShort, DescriptorChainTooShort) => true,
(DescriptorLengthTooSmall, DescriptorLengthTooSmall) => true,
(DescriptorLengthTooLong, DescriptorLengthTooLong) => true,
(InvalidHeaderInputSize(size), InvalidHeaderInputSize(other_size)) => {
size == other_size
}
(InvalidHeaderLen(size), InvalidHeaderLen(other_size)) => size == other_size,
(InvalidMemoryAccess(ref e), InvalidMemoryAccess(ref other_e)) => {
format!("{e}").eq(&format!("{other_e}"))
}
(InvalidVolatileAccess(ref e), InvalidVolatileAccess(ref other_e)) => {
format!("{e}").eq(&format!("{other_e}"))
}
(UnexpectedReadOnlyDescriptor, UnexpectedReadOnlyDescriptor) => true,
(UnexpectedWriteOnlyDescriptor, UnexpectedWriteOnlyDescriptor) => true,
_ => false,
}
}
}
const SRC_CID: u64 = 1;
const DST_CID: u64 = 2;
const SRC_PORT: u32 = 3;
const DST_PORT: u32 = 4;
const LEN: u32 = 16;
const TYPE: u16 = 5;
const OP: u16 = 6;
const FLAGS: u32 = 7;
const FLAG: u32 = 8;
const BUF_ALLOC: u32 = 256;
const FWD_CNT: u32 = 9;
const MAX_PKT_BUF_SIZE: u32 = 64 * 1024;
#[test]
fn test_from_rx_virtq_chain() {
let mem: GuestMemoryMmap =
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x1000_0000)]).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let queue = MockSplitQueue::new(&mem, 16);
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::UnexpectedReadOnlyDescriptor
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
PKT_HEADER_SIZE as u32 - 1,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::DescriptorLengthTooSmall
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
PKT_HEADER_SIZE as u32,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
MAX_PKT_BUF_SIZE + 1,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::DescriptorLengthTooLong
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
PKT_HEADER_SIZE as u32,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::DescriptorChainTooShort
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::UnexpectedReadOnlyDescriptor
);
let mem: GuestMemoryMmap =
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10_0004)]).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let queue = MockSplitQueue::new(&mem, 16);
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidMemoryAccess(GuestMemoryError::InvalidBackendAddress)
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x30_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidMemoryAccess(GuestMemoryError::InvalidGuestAddress(GuestAddress(
0x20_0000
)))
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x5_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::UnexpectedReadOnlyDescriptor
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x5_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidMemoryAccess(GuestMemoryError::InvalidBackendAddress)
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x5_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidMemoryAccess(GuestMemoryError::InvalidGuestAddress(GuestAddress(
0x20_0000
)))
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x5_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x8_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
let packet = VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
assert_eq!(packet.header, PacketHeader::default());
let header = packet.header_slice();
assert_eq!(
header.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x5_0000)).unwrap()
);
assert_eq!(header.len(), PKT_HEADER_SIZE);
let data = packet.data_slice().unwrap();
assert_eq!(
data.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x8_0000)).unwrap()
);
assert_eq!(data.len(), 0x100);
assert_eq!(
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::DescriptorChainTooShort
);
let v = vec![RawDescriptor::from(SplitDescriptor::new(
0x5_0000,
PKT_HEADER_SIZE as u32 + 0x100,
VRING_DESC_F_WRITE as u16,
0,
))];
let mut chain = queue.build_desc_chain(&v).unwrap();
let packet = VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
assert_eq!(packet.header, PacketHeader::default());
let header = packet.header_slice();
assert_eq!(
header.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x5_0000)).unwrap()
);
assert_eq!(header.len(), PKT_HEADER_SIZE);
let data = packet.data_slice().unwrap();
assert_eq!(
data.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x5_0000 + PKT_HEADER_SIZE as u64))
.unwrap()
);
assert_eq!(data.len(), 0x100);
}
#[test]
fn test_from_tx_virtq_chain() {
let mem: GuestMemoryMmap =
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x1000_0000)]).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)),
];
let queue = MockSplitQueue::new(&mem, 16);
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::UnexpectedWriteOnlyDescriptor
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
PKT_HEADER_SIZE as u32 - 1,
0,
0,
)),
RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::DescriptorLengthTooSmall
);
let v = vec![RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
PKT_HEADER_SIZE as u32,
0,
0,
))];
let mut chain = queue.build_desc_chain(&v).unwrap();
let header = PacketHeader {
src_cid: SRC_CID.into(),
dst_cid: DST_CID.into(),
src_port: SRC_PORT.into(),
dst_port: DST_PORT.into(),
len: 0.into(),
type_: 0.into(),
op: 0.into(),
flags: 0.into(),
buf_alloc: 0.into(),
fwd_cnt: 0.into(),
};
mem.write_obj(header, GuestAddress(0x10_0000)).unwrap();
let packet = VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
assert_eq!(packet.header, header);
let header_slice = packet.header_slice();
assert_eq!(
header_slice.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x10_0000)).unwrap()
);
assert_eq!(header_slice.len(), PKT_HEADER_SIZE);
assert!(packet.data_slice().is_none());
let mem: GuestMemoryMmap =
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10_0004)]).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)),
];
let queue = MockSplitQueue::new(&mem, 16);
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidMemoryAccess(GuestMemoryError::InvalidBackendAddress)
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(0x30_0000, 0x100, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidMemoryAccess(GuestMemoryError::InvalidGuestAddress(GuestAddress(
0x20_0000
)))
);
let header = PacketHeader {
src_cid: SRC_CID.into(),
dst_cid: DST_CID.into(),
src_port: SRC_PORT.into(),
dst_port: DST_PORT.into(),
len: (MAX_PKT_BUF_SIZE + 1).into(),
type_: 0.into(),
op: 0.into(),
flags: 0.into(),
buf_alloc: 0.into(),
fwd_cnt: 0.into(),
};
mem.write_obj(header, GuestAddress(0x5_0000)).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidHeaderLen(MAX_PKT_BUF_SIZE + 1)
);
let header = PacketHeader {
src_cid: SRC_CID.into(),
dst_cid: DST_CID.into(),
src_port: SRC_PORT.into(),
dst_port: DST_PORT.into(),
len: LEN.into(),
type_: 0.into(),
op: 0.into(),
flags: 0.into(),
buf_alloc: 0.into(),
fwd_cnt: 0.into(),
};
mem.write_obj(header, GuestAddress(0x5_0000)).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x5_0000, PKT_HEADER_SIZE as u32, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::DescriptorChainTooShort
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidMemoryAccess(GuestMemoryError::InvalidBackendAddress)
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::InvalidMemoryAccess(GuestMemoryError::InvalidGuestAddress(GuestAddress(
0x20_0000
)))
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(
0x8_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::UnexpectedWriteOnlyDescriptor
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(0x8_0000, LEN - 1, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::DescriptorLengthTooSmall
);
let v = vec![
RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)),
RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, 0, 0)),
];
let mut chain = queue.build_desc_chain(&v).unwrap();
let packet = VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
assert_eq!(packet.header, header);
let header_slice = packet.header_slice();
assert_eq!(
header_slice.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x5_0000)).unwrap()
);
assert_eq!(header_slice.len(), PKT_HEADER_SIZE);
assert_eq!(packet.len(), LEN);
let data = packet.data_slice().unwrap();
assert_eq!(
data.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x8_0000)).unwrap()
);
assert_eq!(data.len(), LEN as usize);
assert_eq!(
VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap_err(),
Error::DescriptorChainTooShort
);
let v = vec![RawDescriptor::from(SplitDescriptor::new(
0x5_0000,
PKT_HEADER_SIZE as u32 + 0x100,
0,
0,
))];
let mut chain = queue.build_desc_chain(&v).unwrap();
let packet = VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
assert_eq!(packet.header, header);
let header_slice = packet.header_slice();
assert_eq!(
header_slice.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x5_0000)).unwrap()
);
assert_eq!(header_slice.len(), PKT_HEADER_SIZE);
assert_eq!(packet.len(), LEN);
let data = packet.data_slice().unwrap();
assert_eq!(
data.ptr_guard().as_ptr(),
mem.get_host_address(GuestAddress(0x5_0000 + PKT_HEADER_SIZE as u64))
.unwrap()
);
assert_eq!(data.len(), LEN as usize);
}
#[test]
fn test_header_set_get() {
let mem: GuestMemoryMmap =
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x30_0000)]).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let queue = MockSplitQueue::new(&mem, 16);
let mut chain = queue.build_desc_chain(&v).unwrap();
let mut packet =
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
packet
.set_src_cid(SRC_CID)
.set_dst_cid(DST_CID)
.set_src_port(SRC_PORT)
.set_dst_port(DST_PORT)
.set_len(LEN)
.set_type(TYPE)
.set_op(OP)
.set_flags(FLAGS)
.set_flag(FLAG)
.set_buf_alloc(BUF_ALLOC)
.set_fwd_cnt(FWD_CNT);
assert_eq!(packet.flags(), FLAGS | FLAG);
assert_eq!(packet.op(), OP);
assert_eq!(packet.type_(), TYPE);
assert_eq!(packet.dst_cid(), DST_CID);
assert_eq!(packet.dst_port(), DST_PORT);
assert_eq!(packet.src_cid(), SRC_CID);
assert_eq!(packet.src_port(), SRC_PORT);
assert_eq!(packet.fwd_cnt(), FWD_CNT);
assert_eq!(packet.len(), LEN);
assert_eq!(packet.buf_alloc(), BUF_ALLOC);
let expected_header = PacketHeader {
src_cid: SRC_CID.into(),
dst_cid: DST_CID.into(),
src_port: SRC_PORT.into(),
dst_port: DST_PORT.into(),
len: LEN.into(),
type_: TYPE.into(),
op: OP.into(),
flags: (FLAGS | FLAG).into(),
buf_alloc: BUF_ALLOC.into(),
fwd_cnt: FWD_CNT.into(),
};
assert_eq!(packet.header, expected_header);
assert_eq!(
u64::from_le(
packet
.header_slice()
.read_obj::<u64>(SRC_CID_OFFSET)
.unwrap()
),
SRC_CID
);
assert_eq!(
u64::from_le(
packet
.header_slice()
.read_obj::<u64>(DST_CID_OFFSET)
.unwrap()
),
DST_CID
);
assert_eq!(
u32::from_le(
packet
.header_slice()
.read_obj::<u32>(SRC_PORT_OFFSET)
.unwrap()
),
SRC_PORT
);
assert_eq!(
u32::from_le(
packet
.header_slice()
.read_obj::<u32>(DST_PORT_OFFSET)
.unwrap()
),
DST_PORT,
);
assert_eq!(
u32::from_le(packet.header_slice().read_obj::<u32>(LEN_OFFSET).unwrap()),
LEN
);
assert_eq!(
u16::from_le(packet.header_slice().read_obj::<u16>(TYPE_OFFSET).unwrap()),
TYPE
);
assert_eq!(
u16::from_le(packet.header_slice().read_obj::<u16>(OP_OFFSET).unwrap()),
OP
);
assert_eq!(
u32::from_le(packet.header_slice().read_obj::<u32>(FLAGS_OFFSET).unwrap()),
FLAGS | FLAG
);
assert_eq!(
u32::from_le(
packet
.header_slice()
.read_obj::<u32>(BUF_ALLOC_OFFSET)
.unwrap()
),
BUF_ALLOC
);
assert_eq!(
u32::from_le(
packet
.header_slice()
.read_obj::<u32>(FWD_CNT_OFFSET)
.unwrap()
),
FWD_CNT
);
}
#[test]
fn test_set_header_from_raw() {
let mem: GuestMemoryMmap =
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x30_0000)]).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let queue = MockSplitQueue::new(&mem, 16);
let mut chain = queue.build_desc_chain(&v).unwrap();
let mut packet =
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
let header = PacketHeader {
src_cid: SRC_CID.into(),
dst_cid: DST_CID.into(),
src_port: SRC_PORT.into(),
dst_port: DST_PORT.into(),
len: LEN.into(),
type_: TYPE.into(),
op: OP.into(),
flags: (FLAGS | FLAG).into(),
buf_alloc: BUF_ALLOC.into(),
fwd_cnt: FWD_CNT.into(),
};
let slice = unsafe {
std::slice::from_raw_parts(
(&header as *const PacketHeader) as *const u8,
std::mem::size_of::<PacketHeader>(),
)
};
assert_eq!(packet.header, PacketHeader::default());
packet.set_header_from_raw(slice).unwrap();
assert_eq!(packet.header, header);
let header_from_slice: PacketHeader = packet.header_slice().read_obj(0).unwrap();
assert_eq!(header_from_slice, header);
let invalid_slice = [0; PKT_HEADER_SIZE - 1];
assert_eq!(
packet.set_header_from_raw(&invalid_slice).unwrap_err(),
Error::InvalidHeaderInputSize(PKT_HEADER_SIZE - 1)
);
}
#[test]
fn test_packet_new() {
let mut pkt_raw = [0u8; PKT_HEADER_SIZE + LEN as usize];
let (hdr_raw, data_raw) = pkt_raw.split_at_mut(PKT_HEADER_SIZE);
let packet = unsafe { VsockPacket::new(hdr_raw, Some(data_raw)).unwrap() };
assert_eq!(
packet.header_slice.ptr_guard().as_ptr(),
hdr_raw.as_mut_ptr(),
);
assert_eq!(packet.header_slice.len(), PKT_HEADER_SIZE);
assert_eq!(packet.header, PacketHeader::default());
assert_eq!(
packet.data_slice.unwrap().ptr_guard().as_ptr(),
data_raw.as_mut_ptr(),
);
assert_eq!(packet.data_slice.unwrap().len(), LEN as usize);
let packet = unsafe { VsockPacket::new(hdr_raw, None).unwrap() };
assert_eq!(
packet.header_slice.ptr_guard().as_ptr(),
hdr_raw.as_mut_ptr(),
);
assert_eq!(packet.header, PacketHeader::default());
assert!(packet.data_slice.is_none());
let mut hdr_raw = [0u8; PKT_HEADER_SIZE - 1];
assert_eq!(
unsafe { VsockPacket::new(&mut hdr_raw, None).unwrap_err() },
Error::InvalidHeaderInputSize(PKT_HEADER_SIZE - 1)
);
}
#[test]
#[should_panic]
fn test_set_header_field_with_invalid_offset() {
const INVALID_OFFSET: usize = 50;
let mem: GuestMemoryMmap =
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x30_0000)]).unwrap();
let v = vec![
RawDescriptor::from(SplitDescriptor::new(
0x10_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
RawDescriptor::from(SplitDescriptor::new(
0x20_0000,
0x100,
VRING_DESC_F_WRITE as u16,
0,
)),
];
let queue = MockSplitQueue::new(&mem, 16);
let mut chain = queue.build_desc_chain(&v).unwrap();
let mut packet =
VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap();
set_header_field!(packet, src_cid, INVALID_OFFSET, SRC_CID);
}
}