Skip to content

Commit 362d976

Browse files
committed
feat(net): TCP segmentation offload
1 parent ab66435 commit 362d976

3 files changed

Lines changed: 53 additions & 21 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ smp = ["acpi"]
150150
#! ### Network Features
151151

152152
## Enables TCP support.
153-
tcp = ["net", "smoltcp", "smoltcp/socket-tcp"]
153+
tcp = ["net", "smoltcp", "smoltcp/socket-tcp", "smoltcp/segmentation-offload"]
154154

155155
## Enables UDP support.
156156
udp = ["net", "smoltcp", "smoltcp/socket-udp"]
@@ -417,6 +417,7 @@ exclude = [
417417

418418
[patch.crates-io]
419419
safe-mmio = { git = "https://github.com/hermit-os/safe-mmio", branch = "be" }
420+
smoltcp = { git = "https://github.com/cagatay-y/smoltcp", branch = "segmentation-offload" }
420421

421422
[profile.profiling]
422423
inherits = "release"

src/drivers/net/virtio/mod.rs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ cfg_select! {
1717
use alloc::boxed::Box;
1818
use alloc::vec::Vec;
1919
use core::mem::{ManuallyDrop, MaybeUninit};
20+
use core::num::NonZeroUsize;
2021
use core::str::FromStr;
2122
use core::{mem, slice};
2223

2324
use smallvec::SmallVec;
24-
use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities};
25+
use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities, PacketMeta};
2526
use smoltcp::wire::{ETHERNET_HEADER_LEN, EthernetFrame, Ipv4Packet, Ipv6Packet};
2627
use virtio::DeviceConfigSpace;
2728
use virtio::net::{ConfigVolatileFieldAccess, Hdr, HdrF};
@@ -180,12 +181,23 @@ pub struct TxQueues {
180181
buf_size: u32,
181182
}
182183

184+
#[expect(
185+
clippy::decimal_literal_representation,
186+
reason = "In the VIRTIO specification the size limit is provided in decimal."
187+
)]
188+
const MAX_BUFFER_SIZE: usize = 65550;
189+
183190
impl TxQueues {
184191
pub fn new(vqs: Vec<VirtQueue>, dev_cfg: &NetDevCfg) -> Self {
185-
Self {
186-
vqs,
187-
buf_size: determine_mtu(dev_cfg).into(),
188-
}
192+
let buf_size = if dev_cfg
193+
.features
194+
.intersects(virtio::net::F::HOST_TSO4 | virtio::net::F::HOST_TSO6)
195+
{
196+
MAX_BUFFER_SIZE.try_into().unwrap()
197+
} else {
198+
determine_mtu(dev_cfg).into()
199+
};
200+
Self { vqs, buf_size }
189201
}
190202

191203
#[allow(dead_code)]
@@ -253,6 +265,7 @@ pub struct TxToken<'a> {
253265
send_vqs: &'a mut TxQueues,
254266
checksums: ChecksumCapabilities,
255267
send_capacity: &'a mut u32,
268+
meta: PacketMeta,
256269
}
257270

258271
impl Drop for TxToken<'_> {
@@ -291,6 +304,17 @@ impl smoltcp::phy::TxToken for TxToken<'_> {
291304
header.csum_offset = csum_offset.into();
292305
}
293306

307+
if let Some(gso_size) = token.meta.segmentation_offload_size {
308+
header.gso_type = match EthernetFrame::new_unchecked(&packet).ethertype() {
309+
smoltcp::wire::EthernetProtocol::Ipv4 => virtio::net::HdrGso::Tcpv4.into(),
310+
smoltcp::wire::EthernetProtocol::Ipv6 => virtio::net::HdrGso::Tcpv6.into(),
311+
_ => unreachable!(
312+
"We don't advertise segmentation offload support for any other protocol."
313+
),
314+
};
315+
header.gso_size = gso_size.get().into();
316+
}
317+
294318
let buff_tkn = AvailBufferToken::new(
295319
SmallVec::from_buf([BufferElem::Sized(header), BufferElem::Vector(packet)]),
296320
SmallVec::new(),
@@ -303,6 +327,10 @@ impl smoltcp::phy::TxToken for TxToken<'_> {
303327

304328
result
305329
}
330+
331+
fn set_meta(&mut self, meta: PacketMeta) {
332+
self.meta = meta;
333+
}
306334
}
307335

308336
pub struct RxToken<'a> {
@@ -436,6 +464,16 @@ impl smoltcp::phy::Device for VirtioNetDriver {
436464
device_capabilities.max_burst_size =
437465
Some(usize::try_from(self.inner.send_capacity).unwrap() / usize::from(BUFF_PER_PACKET));
438466
device_capabilities.checksum = self.checksums.clone();
467+
device_capabilities.segmentation.tcpv4 = self
468+
.dev_cfg
469+
.features
470+
.contains(virtio::net::F::HOST_TSO4)
471+
.then_some(NonZeroUsize::new(MAX_BUFFER_SIZE).unwrap());
472+
device_capabilities.segmentation.tcpv6 = self
473+
.dev_cfg
474+
.features
475+
.contains(virtio::net::F::HOST_TSO6)
476+
.then_some(NonZeroUsize::new(MAX_BUFFER_SIZE).unwrap());
439477
device_capabilities
440478
}
441479

@@ -463,6 +501,7 @@ impl smoltcp::phy::Device for VirtioNetDriver {
463501
send_vqs: &mut self.inner.send_vqs,
464502
checksums: self.checksums.clone(),
465503
send_capacity: &mut self.inner.send_capacity,
504+
meta: PacketMeta::default(),
466505
},
467506
))
468507
}
@@ -479,6 +518,7 @@ impl smoltcp::phy::Device for VirtioNetDriver {
479518
send_vqs: &mut self.inner.send_vqs,
480519
checksums: self.checksums.clone(),
481520
send_capacity: &mut self.inner.send_capacity,
521+
meta: PacketMeta::default(),
482522
})
483523
}
484524
}
@@ -673,7 +713,9 @@ impl VirtioNetDriver<Uninit> {
673713
// Multiqueue support
674714
| virtio::net::F::MQ
675715
// Checksum calculation can partially be offloaded to the device
676-
| virtio::net::F::CSUM;
716+
| virtio::net::F::CSUM
717+
| virtio::net::F::HOST_TSO4
718+
| virtio::net::F::HOST_TSO6;
677719

678720
// Currently the driver does NOT support the features below.
679721
// In order to provide functionality for these, the driver

0 commit comments

Comments
 (0)