mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-19 18:01:01 +00:00
dragonball: vsock: support single descriptor
Since kernel v6.3 the vsock packet is not split over two descriptors and
is instead included in a single one.
Therefore, we currently decide the specific method of obtaining
BufWrapper based on the length of descriptor.
Refer:
a2752fe04f
https://git.kernel.org/torvalds/c/71dc9ec9ac7d
Signed-off-by: Xingru Li <lixingru.lxr@linux.alibaba.com>
[ Gao Xiang: port this patch from the internal branch to address Linux 6.1.63+. ]
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
This commit is contained in:
parent
b6cafba5f6
commit
71b6acfd7e
@ -14,7 +14,7 @@ mod packet;
|
|||||||
|
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
use vm_memory::GuestMemoryError;
|
use vm_memory::{GuestAddress, GuestMemoryError};
|
||||||
|
|
||||||
pub use self::defs::{NUM_QUEUES, QUEUE_SIZES};
|
pub use self::defs::{NUM_QUEUES, QUEUE_SIZES};
|
||||||
pub use self::device::Vsock;
|
pub use self::device::Vsock;
|
||||||
@ -136,6 +136,9 @@ pub enum VsockError {
|
|||||||
/// Encountered an unexpected read-only virtio descriptor.
|
/// Encountered an unexpected read-only virtio descriptor.
|
||||||
#[error("Encountered an unexpected read-only virtio descriptor")]
|
#[error("Encountered an unexpected read-only virtio descriptor")]
|
||||||
UnwritableDescriptor,
|
UnwritableDescriptor,
|
||||||
|
/// Overflow occurred during an arithmetic operation.
|
||||||
|
#[error("Overflow occurred during an arithmetic operation, base({0:?}) + offset({0:?})")]
|
||||||
|
Overflow(GuestAddress, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, VsockError>;
|
type Result<T> = std::result::Result<T, VsockError>;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use virtio_queue::{Descriptor, DescriptorChain};
|
use virtio_queue::{Descriptor, DescriptorChain};
|
||||||
use vm_memory::GuestMemory;
|
use vm_memory::{Address, GuestMemory};
|
||||||
|
|
||||||
use super::defs;
|
use super::defs;
|
||||||
use super::{Result, VsockError};
|
use super::{Result, VsockError};
|
||||||
@ -190,15 +190,25 @@ pub struct BufWrapper {
|
|||||||
|
|
||||||
impl BufWrapper {
|
impl BufWrapper {
|
||||||
/// Create the data wrapper from a virtq descriptor.
|
/// Create the data wrapper from a virtq descriptor.
|
||||||
pub fn from_virtq_desc<M: GuestMemory>(desc: &Descriptor, mem: &M) -> Result<Self> {
|
/// Add offset and size, to support different forms of descriptor.
|
||||||
|
pub fn from_virtq_desc<M: GuestMemory>(
|
||||||
|
desc: &Descriptor,
|
||||||
|
mem: &M,
|
||||||
|
offset: usize,
|
||||||
|
size: usize,
|
||||||
|
) -> Result<Self> {
|
||||||
// Check the guest provided pointer and data size.
|
// Check the guest provided pointer and data size.
|
||||||
mem.checked_offset(desc.addr(), desc.len() as usize)
|
mem.checked_offset(desc.addr(), desc.len() as usize)
|
||||||
.ok_or_else(|| VsockError::GuestMemoryBounds(desc.addr().0, desc.len() as usize))?;
|
.ok_or_else(|| VsockError::GuestMemoryBounds(desc.addr().0, desc.len() as usize))?;
|
||||||
|
|
||||||
Ok(Self::from_fat_ptr_unchecked(
|
Ok(Self::from_fat_ptr_unchecked(
|
||||||
mem.get_host_address(desc.addr())
|
mem.get_host_address(
|
||||||
.map_err(VsockError::GuestMemory)?,
|
desc.addr()
|
||||||
desc.len() as usize,
|
.checked_add(offset as u64)
|
||||||
|
.ok_or(VsockError::Overflow(desc.addr(), offset))?,
|
||||||
|
)
|
||||||
|
.map_err(VsockError::GuestMemory)?,
|
||||||
|
size,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,23 +275,48 @@ impl VsockPacket {
|
|||||||
return Ok(Self { hdr, buf: None });
|
return Ok(Self { hdr, buf: None });
|
||||||
}
|
}
|
||||||
|
|
||||||
let buf_desc = desc_chain.next().ok_or(VsockError::BufDescMissing)?;
|
if desc.has_next() {
|
||||||
|
let buf_desc = desc_chain.next().ok_or(VsockError::BufDescMissing)?;
|
||||||
|
|
||||||
// All TX buffers must be readable.
|
// All TX buffers must be readable.
|
||||||
if buf_desc.is_write_only() {
|
if buf_desc.is_write_only() {
|
||||||
return Err(VsockError::UnreadableDescriptor);
|
return Err(VsockError::UnreadableDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The data descriptor should be large enough to hold the data length
|
||||||
|
// indicated by the header.
|
||||||
|
if buf_desc.len() < hdr.len {
|
||||||
|
return Err(VsockError::BufDescTooSmall);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
hdr,
|
||||||
|
buf: Some(BufWrapper::from_virtq_desc(
|
||||||
|
&buf_desc,
|
||||||
|
desc_chain.memory(),
|
||||||
|
0,
|
||||||
|
buf_desc.len() as usize,
|
||||||
|
)?),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let buf_size = desc.len() as usize - VSOCK_PKT_HDR_SIZE;
|
||||||
|
|
||||||
|
// The data descriptor should be large enough to hold the data length
|
||||||
|
// indicated by the header.
|
||||||
|
if buf_size < hdr.len as usize {
|
||||||
|
return Err(VsockError::BufDescTooSmall);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
hdr,
|
||||||
|
buf: Some(BufWrapper::from_virtq_desc(
|
||||||
|
&desc,
|
||||||
|
desc_chain.memory(),
|
||||||
|
VSOCK_PKT_HDR_SIZE,
|
||||||
|
buf_size,
|
||||||
|
)?),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// The data descriptor should be large enough to hold the data length
|
|
||||||
// indicated by the header.
|
|
||||||
if buf_desc.len() < hdr.len {
|
|
||||||
return Err(VsockError::BufDescTooSmall);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
hdr,
|
|
||||||
buf: Some(BufWrapper::from_virtq_desc(&buf_desc, desc_chain.memory())?),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the packet wrapper from an RX virtq chain head.
|
/// Create the packet wrapper from an RX virtq chain head.
|
||||||
@ -301,15 +336,34 @@ impl VsockPacket {
|
|||||||
|
|
||||||
let hdr = HdrWrapper::from_virtq_desc(&desc, desc_chain.memory())?;
|
let hdr = HdrWrapper::from_virtq_desc(&desc, desc_chain.memory())?;
|
||||||
|
|
||||||
let buf_desc = desc_chain.next().ok_or(VsockError::BufDescMissing)?;
|
if desc.has_next() {
|
||||||
if !buf_desc.is_write_only() {
|
let buf_desc = desc_chain.next().ok_or(VsockError::BufDescMissing)?;
|
||||||
return Err(VsockError::UnwritableDescriptor);
|
if !buf_desc.is_write_only() {
|
||||||
}
|
return Err(VsockError::UnwritableDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
hdr,
|
hdr,
|
||||||
buf: Some(BufWrapper::from_virtq_desc(&buf_desc, desc_chain.memory())?),
|
buf: Some(BufWrapper::from_virtq_desc(
|
||||||
})
|
&buf_desc,
|
||||||
|
desc_chain.memory(),
|
||||||
|
0,
|
||||||
|
buf_desc.len() as usize,
|
||||||
|
)?),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let buf_size = desc.len() as usize - VSOCK_PKT_HDR_SIZE;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
hdr,
|
||||||
|
buf: Some(BufWrapper::from_virtq_desc(
|
||||||
|
&desc,
|
||||||
|
desc_chain.memory(),
|
||||||
|
VSOCK_PKT_HDR_SIZE,
|
||||||
|
buf_size,
|
||||||
|
)?),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides in-place, byte-slice, access to the vsock packet header.
|
/// Provides in-place, byte-slice, access to the vsock packet header.
|
||||||
@ -575,11 +629,12 @@ mod tests {
|
|||||||
// Test case:
|
// Test case:
|
||||||
// - packet header advertises some data length; and
|
// - packet header advertises some data length; and
|
||||||
// - the data descriptor is missing.
|
// - the data descriptor is missing.
|
||||||
|
// This will be treated as single descriptor now.
|
||||||
{
|
{
|
||||||
create_context!(test_ctx, handler_ctx);
|
create_context!(test_ctx, handler_ctx);
|
||||||
set_pkt_len(1024, &handler_ctx.guest_txvq.dtable(0), &test_ctx.mem);
|
set_pkt_len(1024, &handler_ctx.guest_txvq.dtable(0), &test_ctx.mem);
|
||||||
handler_ctx.guest_txvq.dtable(0).flags().store(0);
|
handler_ctx.guest_txvq.dtable(0).flags().store(0);
|
||||||
expect_asm_error!(tx, test_ctx, handler_ctx, VsockError::BufDescMissing);
|
expect_asm_error!(tx, test_ctx, handler_ctx, VsockError::BufDescTooSmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test case: error on write-only buf descriptor.
|
// Test case: error on write-only buf descriptor.
|
||||||
@ -641,6 +696,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test case: RX descriptor chain is missing the packet buffer descriptor.
|
// Test case: RX descriptor chain is missing the packet buffer descriptor.
|
||||||
|
// This will be treated as single descriptor now.
|
||||||
{
|
{
|
||||||
create_context!(test_ctx, handler_ctx);
|
create_context!(test_ctx, handler_ctx);
|
||||||
handler_ctx
|
handler_ctx
|
||||||
@ -648,7 +704,14 @@ mod tests {
|
|||||||
.dtable(0)
|
.dtable(0)
|
||||||
.flags()
|
.flags()
|
||||||
.store(VIRTQ_DESC_F_WRITE);
|
.store(VIRTQ_DESC_F_WRITE);
|
||||||
expect_asm_error!(rx, test_ctx, handler_ctx, VsockError::BufDescMissing);
|
let pkt = VsockPacket::from_rx_virtq_head(
|
||||||
|
&mut handler_ctx.queues[RXQ_EVENT as usize]
|
||||||
|
.queue_mut()
|
||||||
|
.pop_descriptor_chain(&test_ctx.mem)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(pkt.buf(), Some(vec![]).as_deref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user