Skip to content

Commit 3371083

Browse files
committed
net: avoid vector allocation in MMDS path
When handling network traffic from the guest destined towards MMDS we create a vector to copy the packet from guest to host memory. This is because, the packet in guest memory might be stored in multiple (non-contiguous) descriptors and MMDS code can't handle those. Change this logic to always keep a buffer inside the Net struct to handle these cases, so that we avoid the vector allocation. Also, introduce a check in the TX path that ensures we only handle sensibly-sized packets from the guest (MAX_BUFFER_SIZE). Signed-off-by: Babis Chalios <bchalios@amazon.es>
1 parent c9cc8d1 commit 3371083

File tree

1 file changed

+30
-15
lines changed

1 file changed

+30
-15
lines changed

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

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ pub struct Net {
127127

128128
rx_bytes_read: usize,
129129
rx_frame_buf: [u8; MAX_BUFFER_SIZE],
130-
131-
tx_frame_headers: [u8; frame_hdr_len()],
130+
tx_frame_buf: [u8; MAX_BUFFER_SIZE],
132131

133132
pub(crate) irq_trigger: IrqTrigger,
134133

@@ -189,7 +188,7 @@ impl Net {
189188
rx_deferred_frame: false,
190189
rx_bytes_read: 0,
191190
rx_frame_buf: [0u8; MAX_BUFFER_SIZE],
192-
tx_frame_headers: [0u8; frame_hdr_len()],
191+
tx_frame_buf: [0u8; MAX_BUFFER_SIZE],
193192
irq_trigger: IrqTrigger::new().map_err(NetError::EventFd)?,
194193
config_space,
195194
guest_mac,
@@ -438,37 +437,42 @@ impl Net {
438437
fn write_to_mmds_or_tap(
439438
mmds_ns: Option<&mut MmdsNetworkStack>,
440439
rate_limiter: &mut RateLimiter,
441-
headers: &mut [u8],
440+
tx_frame_buf: &mut [u8],
442441
frame_iovec: &IoVecBuffer,
443442
tap: &mut Tap,
444443
guest_mac: Option<MacAddr>,
445444
net_metrics: &NetDeviceMetrics,
446445
) -> Result<bool, NetError> {
447446
// Read the frame headers from the IoVecBuffer
448-
let max_header_len = headers.len();
447+
let max_header_len = frame_hdr_len();
449448
let header_len = frame_iovec
450-
.read_volatile_at(&mut &mut *headers, 0, max_header_len)
449+
.read_volatile_at(&mut &mut *tx_frame_buf, 0, max_header_len)
451450
.map_err(|err| {
452451
error!("Received malformed TX buffer: {:?}", err);
453452
net_metrics.tx_malformed_frames.inc();
454453
NetError::VnetHeaderMissing
455454
})?;
456455

457-
let headers = frame_bytes_from_buf(&headers[..header_len]).map_err(|e| {
456+
// First read just the headers of the frame so we can check if this is
457+
// destined for MMDS.
458+
let headers = frame_bytes_from_buf(&tx_frame_buf[..header_len]).map_err(|e| {
458459
error!("VNET headers missing in TX frame");
459460
net_metrics.tx_malformed_frames.inc();
460461
e
461462
})?;
462463

463464
if let Some(ns) = mmds_ns {
464465
if ns.is_mmds_frame(headers) {
465-
let mut frame = vec![0u8; frame_iovec.len() - vnet_hdr_len()];
466-
// Ok to unwrap here, because we are passing a buffer that has the exact size
467-
// of the `IoVecBuffer` minus the VNET headers.
468-
frame_iovec
469-
.read_exact_volatile_at(&mut frame, vnet_hdr_len())
470-
.unwrap();
471-
let _ = ns.detour_frame(&frame);
466+
// This frame is destined for MMDS. So, now read the rest of the frame (if there's
467+
// anything to read)
468+
if frame_iovec.len() > header_len {
469+
// Ok to unwrap here, because we are passing a buffer that has the exact size
470+
// of the `IoVecBuffer` minus the VNET headers.
471+
frame_iovec
472+
.read_exact_volatile_at(&mut tx_frame_buf[header_len..], header_len)
473+
.unwrap();
474+
}
475+
let _ = ns.detour_frame(&tx_frame_buf[vnet_hdr_len()..]);
472476
METRICS.mmds.rx_accepted.inc();
473477

474478
// MMDS frames are not accounted by the rate limiter.
@@ -607,6 +611,17 @@ impl Net {
607611
continue;
608612
}
609613
};
614+
615+
// We only handle frames that are up to MAX_BUFFER_SIZE
616+
if buffer.len() > MAX_BUFFER_SIZE {
617+
error!("net: received too big frame from driver");
618+
self.metrics.tx_fails.inc();
619+
tx_queue
620+
.add_used(mem, head_index, 0)
621+
.map_err(DeviceError::QueueError)?;
622+
continue;
623+
}
624+
610625
if !Self::rate_limiter_consume_op(&mut self.tx_rate_limiter, buffer.len() as u64) {
611626
tx_queue.undo_pop();
612627
self.metrics.tx_rate_limiter_throttled.inc();
@@ -616,7 +631,7 @@ impl Net {
616631
let frame_consumed_by_mmds = Self::write_to_mmds_or_tap(
617632
self.mmds_ns.as_mut(),
618633
&mut self.tx_rate_limiter,
619-
&mut self.tx_frame_headers,
634+
&mut self.tx_frame_buf[..buffer.len()],
620635
&buffer,
621636
&mut self.tap,
622637
self.guest_mac,

0 commit comments

Comments
 (0)