mirror of
https://github.com/threefoldtech/mycelium.git
synced 2026-08-27 21:19:58 +00:00
Only attempt UDP coalescing in tun interface if USO is enabled
Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
@@ -92,6 +92,7 @@ nix::ioctl_write_ptr_bad!(
|
||||
pub struct Tun {
|
||||
fd: OwnedFd,
|
||||
name: String,
|
||||
uso_enabled: bool,
|
||||
}
|
||||
|
||||
impl Tun {
|
||||
@@ -140,7 +141,8 @@ impl Tun {
|
||||
let uso_flags = offload_flags | TUN_F_USO4 | TUN_F_USO6;
|
||||
// SAFETY: file is a valid TUN fd.
|
||||
let ret = unsafe { libc::ioctl(file.as_raw_fd(), TUNSETOFFLOAD, uso_flags) };
|
||||
if ret == 0 {
|
||||
let uso_enabled = ret == 0;
|
||||
if uso_enabled {
|
||||
debug!(name = %actual_name, "enabled USO offload");
|
||||
}
|
||||
|
||||
@@ -155,6 +157,7 @@ impl Tun {
|
||||
Ok(Tun {
|
||||
fd: owned_fd,
|
||||
name: actual_name,
|
||||
uso_enabled,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -260,6 +263,7 @@ impl Tun {
|
||||
let write_half = WriteHalf {
|
||||
fd: AsyncFd::new(write_fd)?,
|
||||
write_buf: vec![0u8; READ_BUF_SIZE],
|
||||
uso_enabled: self.uso_enabled,
|
||||
};
|
||||
|
||||
Ok((read_half, write_half))
|
||||
@@ -351,6 +355,8 @@ pub struct WriteHalf {
|
||||
fd: AsyncFd<OwnedFd>,
|
||||
/// Internal buffer for building coalesced packets (virtio_net_hdr + payload).
|
||||
write_buf: Vec<u8>,
|
||||
/// Whether USO (UDP Segmentation Offload) is available on this device.
|
||||
uso_enabled: bool,
|
||||
}
|
||||
|
||||
impl WriteHalf {
|
||||
@@ -366,7 +372,11 @@ impl WriteHalf {
|
||||
let mut remaining = pkts;
|
||||
|
||||
while remaining.len() > 1 {
|
||||
match offload::gro_coalesce(remaining, &mut self.write_buf[VIRTIO_NET_HDR_LEN..]) {
|
||||
match offload::gro_coalesce(
|
||||
remaining,
|
||||
&mut self.write_buf[VIRTIO_NET_HDR_LEN..],
|
||||
self.uso_enabled,
|
||||
) {
|
||||
Ok((len, vhdr, consumed)) => {
|
||||
vhdr.encode(&mut self.write_buf[..VIRTIO_NET_HDR_LEN]);
|
||||
self.write_raw(&self.write_buf[..VIRTIO_NET_HDR_LEN + len])
|
||||
|
||||
@@ -433,7 +433,11 @@ fn pseudo_header_acc(pkt: &[u8], info: &HeaderInfo) -> u64 {
|
||||
/// If even the first two packets cannot be coalesced (incompatible flows, single packet, etc.),
|
||||
/// returns an error. The caller should then fall back to writing the first packet individually
|
||||
/// with a `GSO_NONE` header.
|
||||
pub fn gro_coalesce(pkts: &[&[u8]], out: &mut [u8]) -> io::Result<(usize, VirtioNetHdr, usize)> {
|
||||
pub fn gro_coalesce(
|
||||
pkts: &[&[u8]],
|
||||
out: &mut [u8],
|
||||
can_uso: bool,
|
||||
) -> io::Result<(usize, VirtioNetHdr, usize)> {
|
||||
if pkts.len() < 2 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
@@ -446,6 +450,13 @@ pub fn gro_coalesce(pkts: &[&[u8]], out: &mut [u8]) -> io::Result<(usize, Virtio
|
||||
|
||||
let is_tcp = info.protocol == IPPROTO_TCP;
|
||||
|
||||
if !is_tcp && !can_uso {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"USO not available for UDP coalescing",
|
||||
));
|
||||
}
|
||||
|
||||
// Extract flow key from first packet.
|
||||
let flow = FlowKey::from_packet(first, &info)?;
|
||||
|
||||
@@ -876,7 +887,7 @@ mod tests {
|
||||
|
||||
let pkts: Vec<&[u8]> = vec![&pkt0, &pkt1];
|
||||
let mut out = vec![0u8; 65536];
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut out).unwrap();
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut out, true).unwrap();
|
||||
|
||||
assert_eq!(consumed, 2);
|
||||
assert_eq!(vhdr.gso_type, VIRTIO_NET_HDR_GSO_TCPV4);
|
||||
@@ -909,7 +920,7 @@ mod tests {
|
||||
|
||||
let pkts: Vec<&[u8]> = vec![&pkt0, &pkt1];
|
||||
let mut out = vec![0u8; 65536];
|
||||
assert!(gro_coalesce(&pkts, &mut out).is_err());
|
||||
assert!(gro_coalesce(&pkts, &mut out, true).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -936,7 +947,7 @@ mod tests {
|
||||
|
||||
let pkts: Vec<&[u8]> = vec![&pkt0, &pkt1];
|
||||
let mut out = vec![0u8; 65536];
|
||||
assert!(gro_coalesce(&pkts, &mut out).is_err());
|
||||
assert!(gro_coalesce(&pkts, &mut out, true).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -974,7 +985,7 @@ mod tests {
|
||||
// Coalesce.
|
||||
let pkts: Vec<&[u8]> = vec![&pkt0, &pkt1, &pkt2];
|
||||
let mut coalesced = vec![0u8; 65536];
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut coalesced).unwrap();
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut coalesced, true).unwrap();
|
||||
assert_eq!(consumed, 3);
|
||||
|
||||
// Build raw buffer as if read from kernel.
|
||||
@@ -1049,7 +1060,7 @@ mod tests {
|
||||
|
||||
let pkts: Vec<&[u8]> = vec![&pkt0, &pkt1];
|
||||
let mut out = vec![0u8; 65536];
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut out).unwrap();
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut out, true).unwrap();
|
||||
|
||||
assert_eq!(consumed, 2);
|
||||
assert_eq!(vhdr.gso_type, VIRTIO_NET_HDR_GSO_UDP_L4);
|
||||
@@ -1102,7 +1113,7 @@ mod tests {
|
||||
let out_size = header_len + PAYLOAD_SIZE * 2 + 10; // just enough for 2
|
||||
let mut out = vec![0u8; out_size];
|
||||
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut out).unwrap();
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut out, true).unwrap();
|
||||
|
||||
assert_eq!(consumed, 2);
|
||||
assert_eq!(vhdr.gso_type, VIRTIO_NET_HDR_GSO_UDP_L4);
|
||||
@@ -1145,7 +1156,7 @@ mod tests {
|
||||
let pkts: Vec<&[u8]> = vec![&pkt0, &pkt1, &pkt2];
|
||||
let mut out = vec![0u8; 65536];
|
||||
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut out).unwrap();
|
||||
let (len, vhdr, consumed) = gro_coalesce(&pkts, &mut out, true).unwrap();
|
||||
|
||||
// Should coalesce only the first 2 packets.
|
||||
assert_eq!(consumed, 2);
|
||||
|
||||
Reference in New Issue
Block a user