@@ -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,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
308336pub 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