mirror of
https://github.com/n0-computer/noq.git
synced 2026-09-19 01:36:08 +00:00
refactor: introduce Transmit::effective_segment_size
This commit is contained in:
committed by
Dirkjan Ochtman
parent
0dcf9d9db7
commit
99abc2b3e2
@@ -150,6 +150,25 @@ pub struct Transmit<'a> {
|
||||
pub src_ip: Option<IpAddr>,
|
||||
}
|
||||
|
||||
impl Transmit<'_> {
|
||||
/// Computes the effective segment-size of the packet.
|
||||
///
|
||||
/// Some (older) network drivers don't like being told to do GSO even if
|
||||
/// there is effectively only a single segment.
|
||||
/// (i.e. `segment_size == contents.len()`)
|
||||
/// Additionally, a `segment_size` that is greater than the content also
|
||||
/// means there is effectively only a single segment.
|
||||
/// This case is actually quite common when splitting up a prepared GSO batch
|
||||
/// again after GSO has been disabled because the last datagram in a GSO
|
||||
/// batch is allowed to be smaller than the segment size.
|
||||
fn effective_segment_size(&self) -> Option<usize> {
|
||||
match self.segment_size? {
|
||||
size if size >= self.contents.len() => None,
|
||||
size => Some(size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Log at most 1 IO error per minute
|
||||
#[cfg(not(wasm_browser))]
|
||||
const IO_ERROR_LOG_INTERVAL: Duration = std::time::Duration::from_secs(60);
|
||||
@@ -238,3 +257,44 @@ impl EcnCodepoint {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn effective_segment_size() {
|
||||
assert_eq!(
|
||||
make_transmit(&[0u8; 10], Some(15)).effective_segment_size(),
|
||||
None,
|
||||
"segment_size > content_len should yield no effective segment_size"
|
||||
);
|
||||
assert_eq!(
|
||||
make_transmit(&[0u8; 10], Some(10)).effective_segment_size(),
|
||||
None,
|
||||
"segment_size == content_len should yield no effective segment_size"
|
||||
);
|
||||
assert_eq!(
|
||||
make_transmit(&[0u8; 10], None).effective_segment_size(),
|
||||
None,
|
||||
"no segment_size should yield no effective segment_size"
|
||||
);
|
||||
assert_eq!(
|
||||
make_transmit(&[0u8; 10], Some(5)).effective_segment_size(),
|
||||
Some(5),
|
||||
"segment_size < content_len should yield effective segment_size"
|
||||
);
|
||||
}
|
||||
|
||||
fn make_transmit(contents: &[u8], segment_size: Option<usize>) -> Transmit<'_> {
|
||||
Transmit {
|
||||
destination: SocketAddr::from((Ipv4Addr::UNSPECIFIED, 1)),
|
||||
ecn: None,
|
||||
contents,
|
||||
segment_size,
|
||||
src_ip: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,14 +625,7 @@ fn prepare_msg(
|
||||
encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn);
|
||||
}
|
||||
|
||||
// Only set the segment size if it is less than the size of the contents.
|
||||
// Some network drivers don't like being told to do GSO even if there is effectively only a single segment (i.e. `segment_size == transmit.contents.len()`)
|
||||
// Additionally, a `segment_size` that is greater than the content also means there is effectively only a single segment.
|
||||
// This case is actually quite common when splitting up a prepared GSO batch again after GSO has been disabled because the last datagram in a GSO batch is allowed to be smaller than the segment size.
|
||||
if let Some(segment_size) = transmit
|
||||
.segment_size
|
||||
.filter(|segment_size| *segment_size < transmit.contents.len())
|
||||
{
|
||||
if let Some(segment_size) = transmit.effective_segment_size() {
|
||||
gso::set_segment_size(&mut encoder, segment_size as u16);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user