diff --git a/vm/devices/net/netvsp/src/lib.rs b/vm/devices/net/netvsp/src/lib.rs index d71185bd6b..c0a8d75e50 100644 --- a/vm/devices/net/netvsp/src/lib.rs +++ b/vm/devices/net/netvsp/src/lib.rs @@ -761,12 +761,12 @@ impl OffloadConfig { if self.lso4 { lso.ipv4_encapsulation = rndisprot::NDIS_ENCAPSULATION_IEEE_802_3; lso.ipv4_max_offload_size = MAX_OFFLOAD_SIZE; - lso.ipv4_min_segment_count = 2; + lso.ipv4_min_segment_count = rndisprot::LSO_MIN_SEGMENT_COUNT; } if self.lso6 { lso.ipv6_encapsulation = rndisprot::NDIS_ENCAPSULATION_IEEE_802_3; lso.ipv6_max_offload_size = MAX_OFFLOAD_SIZE; - lso.ipv6_min_segment_count = 2; + lso.ipv6_min_segment_count = rndisprot::LSO_MIN_SEGMENT_COUNT; lso.ipv6_flags = rndisprot::Ipv6LsoFlags::new() .with_ip_extension_headers_supported(rndisprot::NDIS_OFFLOAD_SUPPORTED) .with_tcp_options_supported(rndisprot::NDIS_OFFLOAD_SUPPORTED); @@ -1901,6 +1901,8 @@ enum WorkerError { RndisMessageTooSmall, #[error("unsupported rndis behavior")] UnsupportedRndisBehavior, + #[error("invalid lso packet with insufficient segments: {0}")] + InvalidLsoPacketInsufficientSegments(u32), #[error("vmbus queue error")] Queue(#[from] queue::Error), #[error("too many control messages")] @@ -2477,6 +2479,14 @@ impl NetChannel { }); } + if metadata.offload_tcp_segmentation { + if segments.len() < rndisprot::LSO_MIN_SEGMENT_COUNT as usize { + return Err(WorkerError::InvalidLsoPacketInsufficientSegments( + segments.len() as u32, + )); + } + } + metadata.segment_count = segments.len() - start; stats.tx_packets.increment(); diff --git a/vm/devices/net/netvsp/src/rndisprot.rs b/vm/devices/net/netvsp/src/rndisprot.rs index 43765d5103..e08b5035ca 100644 --- a/vm/devices/net/netvsp/src/rndisprot.rs +++ b/vm/devices/net/netvsp/src/rndisprot.rs @@ -954,6 +954,8 @@ pub struct Ipv6ChecksumOffload { } pub const NDIS_ENCAPSULATION_IEEE_802_3: u32 = 2; +// Use the same minimum as vswitch. +pub const LSO_MIN_SEGMENT_COUNT: u32 = 2; #[repr(C)] #[derive(Debug, Copy, Clone, IntoBytes, Immutable, KnownLayout, FromBytes)]