Skip to content

Commit 434c358

Browse files
flubRalith
authored andcommitted
fix: Do not produce tail-loss probes larger than segment size
When needing to send tail-loss probes and building a GSO batch the tail-loss probe should not exceed the GSO segment size.
1 parent 55845bd commit 434c358

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

quinn-proto/src/connection/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ impl Connection {
699699
// Clamp the datagram to at most the minimum MTU to ensure that loss probes
700700
// can get through and enable recovery even if the path MTU has shrank
701701
// unexpectedly.
702-
usize::from(INITIAL_MTU)
702+
std::cmp::min(segment_size, usize::from(INITIAL_MTU))
703703
}
704704
};
705705
buf_capacity += next_datagram_size_limit;

quinn-proto/src/tests/mod.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,55 @@ fn congested_tail_loss() {
17801780
pair.client_send(client_ch, s).write(&[42; 1024]).unwrap();
17811781
}
17821782

1783+
// Send a tail-loss probe when GSO segment_size is less than INITIAL_MTU
1784+
#[test]
1785+
fn tail_loss_small_segment_size() {
1786+
let _guard = subscribe();
1787+
let mut pair = Pair::default();
1788+
let (client_ch, server_ch) = pair.connect();
1789+
1790+
// No datagrams frames received in the handshake.
1791+
let server_stats = pair.server_conn_mut(server_ch).stats();
1792+
assert_eq!(server_stats.frame_rx.datagram, 0);
1793+
1794+
const DGRAM_LEN: usize = 1000; // Below INITIAL_MTU after packet overhead.
1795+
const DGRAM_NUM: u64 = 5; // Enough to build a GSO batch.
1796+
1797+
info!("Sending an ack-eliciting datagram");
1798+
pair.client_conn_mut(client_ch).ping();
1799+
pair.drive_client();
1800+
1801+
// Drop these packets on the server side.
1802+
assert!(!pair.server.inbound.is_empty());
1803+
pair.server.inbound.clear();
1804+
1805+
// Doing one step makes the client advance time to the PTO fire time.
1806+
info!("stepping forward to PTO");
1807+
pair.step();
1808+
1809+
// Still no datagrams frames received by the server.
1810+
let server_stats = pair.server_conn_mut(server_ch).stats();
1811+
assert_eq!(server_stats.frame_rx.datagram, 0);
1812+
1813+
// Now we can send another batch of datagrams, so the PTO can send them instead of
1814+
// sending a ping. These are small enough that the segment_size is less than the
1815+
// INITIAL_MTU.
1816+
info!("Sending datagram batch");
1817+
for _ in 0..DGRAM_NUM {
1818+
pair.client_datagrams(client_ch)
1819+
.send(vec![0; DGRAM_LEN].into(), false)
1820+
.unwrap();
1821+
}
1822+
1823+
// If this succeeds the datagrams are received by the server and the client did not
1824+
// crash.
1825+
pair.drive();
1826+
1827+
// Finally the server should have received some datagrams.
1828+
let server_stats = pair.server_conn_mut(server_ch).stats();
1829+
assert_eq!(server_stats.frame_rx.datagram, DGRAM_NUM);
1830+
}
1831+
17831832
#[test]
17841833
fn datagram_send_recv() {
17851834
let _guard = subscribe();

0 commit comments

Comments
 (0)