@@ -17,11 +17,12 @@ cfg_select! {
1717use alloc:: boxed:: Box ;
1818use alloc:: vec:: Vec ;
1919use core:: mem:: { ManuallyDrop , MaybeUninit } ;
20+ use core:: num:: NonZeroUsize ;
2021use core:: str:: FromStr ;
2122use core:: { mem, slice} ;
2223
2324use smallvec:: SmallVec ;
24- use smoltcp:: phy:: { Checksum , ChecksumCapabilities , DeviceCapabilities } ;
25+ use smoltcp:: phy:: { Checksum , ChecksumCapabilities , DeviceCapabilities , PacketMeta } ;
2526use smoltcp:: wire:: { ETHERNET_HEADER_LEN , EthernetFrame , Ipv4Packet , Ipv6Packet } ;
2627use virtio:: DeviceConfigSpace ;
2728use 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+
183190impl 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
258271impl Drop for TxToken < ' _ > {
@@ -291,6 +304,18 @@ impl smoltcp::phy::TxToken for TxToken<'_> {
291304 header. csum_offset = csum_offset. into ( ) ;
292305 }
293306
307+ #[ cfg( feature = "tcp" ) ]
308+ if let Some ( gso_size) = token. meta . segmentation_offload_size {
309+ header. gso_type = match EthernetFrame :: new_unchecked ( & packet) . ethertype ( ) {
310+ smoltcp:: wire:: EthernetProtocol :: Ipv4 => virtio:: net:: HdrGso :: Tcpv4 . into ( ) ,
311+ smoltcp:: wire:: EthernetProtocol :: Ipv6 => virtio:: net:: HdrGso :: Tcpv6 . into ( ) ,
312+ _ => unreachable ! (
313+ "We don't advertise segmentation offload support for any other protocol."
314+ ) ,
315+ } ;
316+ header. gso_size = gso_size. get ( ) . into ( ) ;
317+ }
318+
294319 let buff_tkn = AvailBufferToken :: new (
295320 SmallVec :: from_buf ( [ BufferElem :: Sized ( header) , BufferElem :: Vector ( packet) ] ) ,
296321 SmallVec :: new ( ) ,
@@ -303,6 +328,10 @@ impl smoltcp::phy::TxToken for TxToken<'_> {
303328
304329 result
305330 }
331+
332+ fn set_meta ( & mut self , meta : PacketMeta ) {
333+ self . meta = meta;
334+ }
306335}
307336
308337pub struct RxToken < ' a > {
@@ -436,6 +465,22 @@ impl smoltcp::phy::Device for VirtioNetDriver {
436465 device_capabilities. max_burst_size =
437466 Some ( usize:: try_from ( self . inner . send_capacity ) . unwrap ( ) / usize:: from ( BUFF_PER_PACKET ) ) ;
438467 device_capabilities. checksum = self . checksums . clone ( ) ;
468+
469+ // We only support segmentation offload on and enable the corresponding feature of smoltcp for TCP.
470+ #[ cfg( feature = "tcp" ) ]
471+ {
472+ device_capabilities. segmentation . tcpv4 = self
473+ . dev_cfg
474+ . features
475+ . contains ( virtio:: net:: F :: HOST_TSO4 )
476+ . then_some ( NonZeroUsize :: new ( MAX_BUFFER_SIZE ) . unwrap ( ) ) ;
477+ device_capabilities. segmentation . tcpv6 = self
478+ . dev_cfg
479+ . features
480+ . contains ( virtio:: net:: F :: HOST_TSO6 )
481+ . then_some ( NonZeroUsize :: new ( MAX_BUFFER_SIZE ) . unwrap ( ) ) ;
482+ }
483+
439484 device_capabilities
440485 }
441486
@@ -463,6 +508,7 @@ impl smoltcp::phy::Device for VirtioNetDriver {
463508 send_vqs : & mut self . inner . send_vqs ,
464509 checksums : self . checksums . clone ( ) ,
465510 send_capacity : & mut self . inner . send_capacity ,
511+ meta : PacketMeta :: default ( ) ,
466512 } ,
467513 ) )
468514 }
@@ -479,6 +525,7 @@ impl smoltcp::phy::Device for VirtioNetDriver {
479525 send_vqs : & mut self . inner . send_vqs ,
480526 checksums : self . checksums . clone ( ) ,
481527 send_capacity : & mut self . inner . send_capacity ,
528+ meta : PacketMeta :: default ( ) ,
482529 } )
483530 }
484531}
@@ -673,7 +720,9 @@ impl VirtioNetDriver<Uninit> {
673720 // Multiqueue support
674721 | virtio:: net:: F :: MQ
675722 // Checksum calculation can partially be offloaded to the device
676- | virtio:: net:: F :: CSUM ;
723+ | virtio:: net:: F :: CSUM
724+ | virtio:: net:: F :: HOST_TSO4
725+ | virtio:: net:: F :: HOST_TSO6 ;
677726
678727 // Currently the driver does NOT support the features below.
679728 // In order to provide functionality for these, the driver
0 commit comments