Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a137126

Browse files
committedAug 30, 2017
Move the TCP receive window clamping hack downwards in stack.
Otherwise, our response ACKs did not get the clamping treatment, and severe packet loss resulted. Also, explain why it's needed and how it works.
1 parent 280ddde commit a137126

File tree

2 files changed

+20
-31
lines changed

2 files changed

+20
-31
lines changed
 

Diff for: ‎src/iface/ethernet.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,26 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
458458
&ip_repr.src_addr(), &ip_repr.dst_addr());
459459
})
460460
}
461-
Packet::Tcp((ip_repr, tcp_repr)) => {
461+
Packet::Tcp((ip_repr, mut tcp_repr)) => {
462+
// This is a terrible hack to make TCP performance more acceptable on systems
463+
// where the TCP buffers are significantly larger than network buffers,
464+
// e.g. a 64 kB TCP receive buffer (and so, when empty, a 64k window)
465+
// together with four 1500 B Ethernet receive buffers. If left untreated,
466+
// this would result in our peer pushing our window and sever packet loss.
467+
//
468+
// I'm really not happy about this "solution" but I don't know what else to do.
469+
let limits = self.device.limits();
470+
if let Some(max_burst_size) = limits.max_burst_size {
471+
let mut max_segment_size = limits.max_transmission_unit;
472+
max_segment_size -= ip_repr.buffer_len();
473+
max_segment_size -= tcp_repr.header_len();
474+
475+
let max_window_size = max_burst_size * max_segment_size;
476+
if tcp_repr.window_len as usize > max_window_size {
477+
tcp_repr.window_len = max_window_size as u16;
478+
}
479+
}
480+
462481
self.dispatch_ip(timestamp, ip_repr, |ip_repr, payload| {
463482
tcp_repr.emit(&mut TcpPacket::new(payload),
464483
&ip_repr.src_addr(), &ip_repr.dst_addr());

Diff for: ‎src/socket/tcp.rs

-30
Original file line numberDiff line numberDiff line change
@@ -1241,13 +1241,6 @@ impl<'a> TcpSocket<'a> {
12411241
repr.max_seg_size = Some(max_segment_size as u16);
12421242
}
12431243

1244-
if let Some(max_burst_size) = limits.max_burst_size {
1245-
let max_window_size = max_burst_size * max_segment_size;
1246-
if repr.window_len as usize > max_window_size {
1247-
repr.window_len = max_window_size as u16;
1248-
}
1249-
}
1250-
12511244
emit((ip_repr, repr))?;
12521245

12531246
// We've sent a packet successfully, so we can update the internal state now.
@@ -2893,29 +2886,6 @@ mod test {
28932886
}));
28942887
}
28952888

2896-
#[test]
2897-
fn test_window_size_clamp() {
2898-
let mut s = socket_established();
2899-
s.rx_buffer = SocketBuffer::new(vec![0; 32767]);
2900-
2901-
let mut limits = DeviceLimits::default();
2902-
limits.max_transmission_unit = 1520;
2903-
2904-
limits.max_burst_size = None;
2905-
s.send_slice(b"abcdef").unwrap();
2906-
s.dispatch(0, &limits, |(_ip_repr, tcp_repr)| {
2907-
assert_eq!(tcp_repr.window_len, 32767);
2908-
Ok(())
2909-
}).unwrap();
2910-
2911-
limits.max_burst_size = Some(4);
2912-
s.send_slice(b"abcdef").unwrap();
2913-
s.dispatch(0, &limits, |(_ip_repr, tcp_repr)| {
2914-
assert_eq!(tcp_repr.window_len, 5920);
2915-
Ok(())
2916-
}).unwrap();
2917-
}
2918-
29192889
// =========================================================================================//
29202890
// Tests for flow control.
29212891
// =========================================================================================//

0 commit comments

Comments
 (0)
Please sign in to comment.