Skip to content

Commit 4bf2b1b

Browse files
committed
refactor(vsock): make vsock reuse packets
Add rx_packet and tx_packet members to the Vsock type and reuse them for RX and TX processing. This removed overhead of creating new packets for each request. As an additional improvement, we split VsockPacket type into 2 types: VsockPacketRx and VsockPacketTx which allows us to separate logic for RX and TX processing. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 9b136c0 commit 4bf2b1b

File tree

8 files changed

+534
-504
lines changed

8 files changed

+534
-504
lines changed

src/vmm/src/devices/virtio/iovec.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,14 +219,18 @@ impl IoVecBuffer {
219219
/// It describes a write-only buffer passed to us by the guest that is scattered across multiple
220220
/// memory regions. Additionally, this wrapper provides methods that allow reading arbitrary ranges
221221
/// of data from that buffer.
222-
#[derive(Debug, Default, Clone)]
222+
#[derive(Debug, Default)]
223223
pub struct IoVecBufferMut {
224224
// container of the memory regions included in this IO vector
225225
vecs: IoVecVec,
226226
// Total length of the IoVecBufferMut
227227
len: u32,
228228
}
229229

230+
// SAFETY: `IoVecBufferMut` doesn't allow for interior mutability and no shared ownership is possible
231+
// as it doesn't implement clone
232+
unsafe impl Send for IoVecBufferMut {}
233+
230234
impl IoVecBufferMut {
231235
/// Create an `IoVecBuffer` from a `DescriptorChain`
232236
///

src/vmm/src/devices/virtio/vsock/csm/connection.rs

Lines changed: 96 additions & 88 deletions
Large diffs are not rendered by default.

src/vmm/src/devices/virtio/vsock/device.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use vmm_sys_util::eventfd::EventFd;
2727

2828
use super::super::super::DeviceError;
2929
use super::defs::uapi;
30-
use super::packet::{VsockPacket, VSOCK_PKT_HDR_SIZE};
30+
use super::packet::{VsockPacketRx, VsockPacketTx, VSOCK_PKT_HDR_SIZE};
3131
use super::{defs, VsockBackend};
3232
use crate::devices::virtio::device::{DeviceState, IrqTrigger, IrqType, VirtioDevice};
3333
use crate::devices::virtio::queue::Queue as VirtQueue;
@@ -68,6 +68,9 @@ pub struct Vsock<B> {
6868
// continuous triggers from happening before the device gets activated.
6969
pub(crate) activate_evt: EventFd,
7070
pub(crate) device_state: DeviceState,
71+
72+
pub rx_packet: VsockPacketRx,
73+
pub tx_packet: VsockPacketTx,
7174
}
7275

7376
// TODO: Detect / handle queue deadlock:
@@ -101,6 +104,8 @@ where
101104
irq_trigger: IrqTrigger::new().map_err(VsockError::EventFd)?,
102105
activate_evt: EventFd::new(libc::EFD_NONBLOCK).map_err(VsockError::EventFd)?,
103106
device_state: DeviceState::Inactive,
107+
rx_packet: VsockPacketRx::default(),
108+
tx_packet: VsockPacketTx::default(),
104109
})
105110
}
106111

@@ -147,14 +152,14 @@ where
147152

148153
while let Some(head) = self.queues[RXQ_INDEX].pop() {
149154
let index = head.index;
150-
let used_len = match VsockPacket::from_rx_virtq_head(mem, head) {
151-
Ok(mut pkt) => {
152-
if self.backend.recv_pkt(&mut pkt).is_ok() {
153-
match pkt.commit_hdr() {
155+
let used_len = match self.rx_packet.parse(mem, head) {
156+
Ok(()) => {
157+
if self.backend.recv_pkt(&mut self.rx_packet).is_ok() {
158+
match self.rx_packet.commit_hdr() {
154159
// This addition cannot overflow, because packet length
155160
// is previously validated against `MAX_PKT_BUF_SIZE`
156161
// bound as part of `commit_hdr()`.
157-
Ok(()) => VSOCK_PKT_HDR_SIZE + pkt.len(),
162+
Ok(()) => VSOCK_PKT_HDR_SIZE + self.rx_packet.hdr.len(),
158163
Err(err) => {
159164
warn!(
160165
"vsock: Error writing packet header to guest memory: \
@@ -200,8 +205,9 @@ where
200205

201206
while let Some(head) = self.queues[TXQ_INDEX].pop() {
202207
let index = head.index;
203-
let pkt = match VsockPacket::from_tx_virtq_head(mem, head) {
204-
Ok(pkt) => pkt,
208+
// let pkt = match VsockPacket::from_tx_virtq_head(mem, head) {
209+
match self.tx_packet.parse(mem, head) {
210+
Ok(()) => (),
205211
Err(err) => {
206212
error!("vsock: error reading TX packet: {:?}", err);
207213
have_used = true;
@@ -214,7 +220,7 @@ where
214220
}
215221
};
216222

217-
if self.backend.send_pkt(&pkt).is_err() {
223+
if self.backend.send_pkt(&self.tx_packet).is_err() {
218224
self.queues[TXQ_INDEX].undo_pop();
219225
break;
220226
}

src/vmm/src/devices/virtio/vsock/event_handler.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,9 @@ mod tests {
439439
// If the descriptor chain is already declared invalid, there's no reason to assemble
440440
// a packet.
441441
if let Some(rx_desc) = ctx.device.queues[RXQ_INDEX].pop() {
442-
VsockPacket::from_rx_virtq_head(&test_ctx.mem, rx_desc).unwrap_err();
442+
VsockPacketRx::default()
443+
.parse(&test_ctx.mem, rx_desc)
444+
.unwrap_err();
443445
}
444446
}
445447

@@ -461,7 +463,9 @@ mod tests {
461463
ctx.guest_txvq.dtable[desc_idx].len.set(len);
462464

463465
if let Some(tx_desc) = ctx.device.queues[TXQ_INDEX].pop() {
464-
VsockPacket::from_tx_virtq_head(&test_ctx.mem, tx_desc).unwrap_err();
466+
VsockPacketTx::default()
467+
.parse(&test_ctx.mem, tx_desc)
468+
.unwrap_err();
465469
}
466470
}
467471
}
@@ -486,13 +490,17 @@ mod tests {
486490
{
487491
let mut ctx = test_ctx.create_event_handler_context();
488492
let rx_desc = ctx.device.queues[RXQ_INDEX].pop().unwrap();
489-
VsockPacket::from_rx_virtq_head(&test_ctx.mem, rx_desc).unwrap();
493+
VsockPacketRx::default()
494+
.parse(&test_ctx.mem, rx_desc)
495+
.unwrap();
490496
}
491497

492498
{
493499
let mut ctx = test_ctx.create_event_handler_context();
494500
let tx_desc = ctx.device.queues[TXQ_INDEX].pop().unwrap();
495-
VsockPacket::from_tx_virtq_head(&test_ctx.mem, tx_desc).unwrap();
501+
VsockPacketTx::default()
502+
.parse(&test_ctx.mem, tx_desc)
503+
.unwrap();
496504
}
497505

498506
// Let's check what happens when the header descriptor is right before the gap.

src/vmm/src/devices/virtio/vsock/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ mod unix;
2222

2323
use std::os::unix::io::AsRawFd;
2424

25-
use packet::VsockPacket;
2625
use vm_memory::GuestMemoryError;
2726
use vmm_sys_util::epoll::EventSet;
2827

2928
pub use self::defs::uapi::VIRTIO_ID_VSOCK as TYPE_VSOCK;
3029
pub use self::defs::VSOCK_DEV_ID;
3130
pub use self::device::Vsock;
31+
use self::packet::{VsockPacketRx, VsockPacketTx};
3232
pub use self::unix::{VsockUnixBackend, VsockUnixBackendError};
3333
use crate::devices::virtio::iovec::IoVecError;
3434
use crate::devices::virtio::persist::PersistError as VirtioStateError;
@@ -174,10 +174,10 @@ pub trait VsockEpollListener: AsRawFd {
174174
/// - `send_pkt(&pkt)` will fetch data from `pkt`, and place it into the channel.
175175
pub trait VsockChannel {
176176
/// Read/receive an incoming packet from the channel.
177-
fn recv_pkt(&mut self, pkt: &mut VsockPacket) -> Result<(), VsockError>;
177+
fn recv_pkt(&mut self, pkt: &mut VsockPacketRx) -> Result<(), VsockError>;
178178

179179
/// Write/send a packet through the channel.
180-
fn send_pkt(&mut self, pkt: &VsockPacket) -> Result<(), VsockError>;
180+
fn send_pkt(&mut self, pkt: &VsockPacketTx) -> Result<(), VsockError>;
181181

182182
/// Checks whether there is pending incoming data inside the channel, meaning that a subsequent
183183
/// call to `recv_pkt()` won't fail.

0 commit comments

Comments
 (0)