@@ -32,7 +32,7 @@ use crate::{
3232 token:: ResetToken ,
3333 transport_parameters:: TransportParameters ,
3434 Dir , Duration , EndpointConfig , Frame , Instant , Side , StreamId , Transmit , TransportError ,
35- TransportErrorCode , VarInt , MAX_CID_SIZE , MAX_STREAM_COUNT , MIN_INITIAL_SIZE ,
35+ TransportErrorCode , VarInt , INITIAL_MTU , MAX_CID_SIZE , MAX_STREAM_COUNT , MIN_INITIAL_SIZE ,
3636 TIMER_GRANULARITY ,
3737} ;
3838
@@ -700,13 +700,21 @@ impl Connection {
700700 // waste large amounts of bandwidth. The exact threshold is a bit arbitrary
701701 // and might benefit from further tuning, though there's no universally
702702 // optimal value.
703+ //
704+ // Additionally, if this datagram is a loss probe and `segment_size` is
705+ // larger than `INITIAL_MTU`, then padding it to `segment_size` to continue
706+ // the GSO batch would risk failure to recover from a reduction in path
707+ // MTU. Loss probes are the only packets for which we might grow
708+ // `buf_capacity` by less than `segment_size`.
703709 const MAX_PADDING : usize = 16 ;
704710 let packet_len_unpadded = cmp:: max ( builder. min_size , buf. len ( ) )
705711 - datagram_start
706712 + builder. tag_len ;
707- if packet_len_unpadded + MAX_PADDING < segment_size {
713+ if packet_len_unpadded + MAX_PADDING < segment_size
714+ || datagram_start + segment_size > buf_capacity
715+ {
708716 trace ! (
709- "GSO truncated by demand for {} padding bytes" ,
717+ "GSO truncated by demand for {} padding bytes or loss probe " ,
710718 segment_size - packet_len_unpadded
711719 ) ;
712720 builder_storage = Some ( builder) ;
@@ -749,7 +757,17 @@ impl Connection {
749757 }
750758
751759 // Allocate space for another datagram
752- buf_capacity += segment_size;
760+ let next_datagram_size_limit = match self . spaces [ space_id] . loss_probes {
761+ 0 => segment_size,
762+ _ => {
763+ self . spaces [ space_id] . loss_probes -= 1 ;
764+ // Clamp the datagram to at most the minimum MTU to ensure that loss probes
765+ // can get through and enable recovery even if the path MTU has shrank
766+ // unexpectedly.
767+ usize:: from ( INITIAL_MTU )
768+ }
769+ } ;
770+ buf_capacity += next_datagram_size_limit;
753771 if buf. capacity ( ) < buf_capacity {
754772 // We reserve the maximum space for sending `max_datagrams` upfront
755773 // to avoid any reallocations if more datagrams have to be appended later on.
@@ -963,14 +981,10 @@ impl Connection {
963981 // Send MTU probe if necessary
964982 if buf. is_empty ( ) && self . state . is_established ( ) {
965983 let space_id = SpaceId :: Data ;
966- let probe_size = match self
984+ let probe_size = self
967985 . path
968986 . mtud
969- . poll_transmit ( now, self . packet_number_filter . peek ( & self . spaces [ space_id] ) )
970- {
971- Some ( next_probe_size) => next_probe_size,
972- None => return None ,
973- } ;
987+ . poll_transmit ( now, self . packet_number_filter . peek ( & self . spaces [ space_id] ) ) ?;
974988
975989 let buf_capacity = probe_size as usize ;
976990 buf. reserve ( buf_capacity) ;
@@ -1645,7 +1659,7 @@ impl Connection {
16451659 None if self
16461660 . path
16471661 . first_packet_after_rtt_sample
1648- . map_or ( false , |x| x < ( pn_space, packet) ) =>
1662+ . is_some_and ( |x| x < ( pn_space, packet) ) =>
16491663 {
16501664 persistent_congestion_start = Some ( info. time_sent ) ;
16511665 }
@@ -2220,7 +2234,7 @@ impl Connection {
22202234 let _guard = span. enter ( ) ;
22212235
22222236 let is_duplicate = |n| self . spaces [ packet. header . space ( ) ] . dedup . insert ( n) ;
2223- if number. map_or ( false , is_duplicate) {
2237+ if number. is_some_and ( is_duplicate) {
22242238 debug ! ( "discarding possible duplicate packet" ) ;
22252239 return ;
22262240 } else if self . state . is_handshake ( ) && packet. header . is_short ( ) {
@@ -3640,13 +3654,13 @@ impl Connection {
36403654 || self
36413655 . prev_path
36423656 . as_ref ( )
3643- . map_or ( false , |( _, x) | x. challenge_pending )
3657+ . is_some_and ( |( _, x) | x. challenge_pending )
36443658 || !self . path_responses . is_empty ( )
36453659 || self
36463660 . datagrams
36473661 . outgoing
36483662 . front ( )
3649- . map_or ( false , |x| x. size ( true ) <= max_size)
3663+ . is_some_and ( |x| x. size ( true ) <= max_size)
36503664 }
36513665
36523666 /// Update counters to account for a packet becoming acknowledged, lost, or abandoned
0 commit comments