Skip to content

Commit e8fe5cd

Browse files
authored
Merge pull request #404 from smoltcp-rs/delayed-ack
tcp: add Delayed ACK
2 parents 4d0d4ae + e9e1477 commit e8fe5cd

File tree

2 files changed

+192
-16
lines changed

2 files changed

+192
-16
lines changed

src/socket/mod.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,6 @@ pub(crate) enum PollAt {
7171
Ingress,
7272
}
7373

74-
impl PollAt {
75-
#[cfg(feature = "socket-tcp")]
76-
fn is_ingress(&self) -> bool {
77-
match *self {
78-
PollAt::Ingress => true,
79-
_ => false,
80-
}
81-
}
82-
}
83-
8474
/// A network socket.
8575
///
8676
/// This enumeration abstracts the various types of sockets based on the IP protocol.

src/socket/tcp.rs

Lines changed: 192 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ enum Timer {
162162
}
163163
}
164164

165+
const ACK_DELAY_DEFAULT: Duration = Duration { millis: 10 };
165166
const CLOSE_DELAY: Duration = Duration { millis: 10_000 };
166167

167168
impl Default for Timer {
@@ -341,6 +342,12 @@ pub struct TcpSocket<'a> {
341342
/// each other which have the same ACK number.
342343
local_rx_dup_acks: u8,
343344

345+
/// Duration for Delayed ACK. If None no ACKs will be delayed.
346+
ack_delay: Option<Duration>,
347+
/// Delayed ack timer. If set, packets containing exclusively
348+
/// ACK or window updates (ie, no data) won't be sent until expiry.
349+
ack_delay_until: Option<Instant>,
350+
344351
#[cfg(feature = "async")]
345352
rx_waker: WakerRegistration,
346353
#[cfg(feature = "async")]
@@ -397,6 +404,8 @@ impl<'a> TcpSocket<'a> {
397404
local_rx_last_ack: None,
398405
local_rx_last_seq: None,
399406
local_rx_dup_acks: 0,
407+
ack_delay: Some(ACK_DELAY_DEFAULT),
408+
ack_delay_until: None,
400409

401410
#[cfg(feature = "async")]
402411
rx_waker: WakerRegistration::new(),
@@ -453,6 +462,13 @@ impl<'a> TcpSocket<'a> {
453462
self.timeout
454463
}
455464

465+
/// Return the ACK delay duration.
466+
///
467+
/// See also the [set_ack_delay](#method.set_ack_delay) method.
468+
pub fn ack_delay(&self) -> Option<Duration> {
469+
self.ack_delay
470+
}
471+
456472
/// Return the current window field value, including scaling according to RFC 1323.
457473
///
458474
/// Used in internal calculations as well as packet generation.
@@ -478,6 +494,13 @@ impl<'a> TcpSocket<'a> {
478494
self.timeout = duration
479495
}
480496

497+
/// Set the ACK delay duration.
498+
///
499+
/// By default, the ACK delay is set to 10ms.
500+
pub fn set_ack_delay(&mut self, duration: Option<Duration>) {
501+
self.ack_delay = duration
502+
}
503+
481504
/// Return the keep-alive interval.
482505
///
483506
/// See also the [set_keep_alive](#method.set_keep_alive) method.
@@ -578,6 +601,8 @@ impl<'a> TcpSocket<'a> {
578601
self.remote_win_shift = rx_cap_log2.saturating_sub(16) as u8;
579602
self.remote_mss = DEFAULT_MSS;
580603
self.remote_last_ts = None;
604+
self.ack_delay = Some(ACK_DELAY_DEFAULT);
605+
self.ack_delay_until = None;
581606

582607
#[cfg(feature = "async")]
583608
{
@@ -1541,6 +1566,30 @@ impl<'a> TcpSocket<'a> {
15411566
self.assembler);
15421567
}
15431568

1569+
// Handle delayed acks
1570+
if let Some(ack_delay) = self.ack_delay {
1571+
if self.ack_to_transmit() || self.window_to_update() {
1572+
self.ack_delay_until = match self.ack_delay_until {
1573+
None => {
1574+
net_trace!("{}:{}:{}: starting delayed ack timer",
1575+
self.meta.handle, self.local_endpoint, self.remote_endpoint
1576+
);
1577+
1578+
Some(timestamp + ack_delay)
1579+
}
1580+
// RFC1122 says "in a stream of full-sized segments there SHOULD be an ACK
1581+
// for at least every second segment".
1582+
// For now, we send an ACK every second received packet, full-sized or not.
1583+
Some(_) => {
1584+
net_trace!("{}:{}:{}: delayed ack timer already started, forcing expiry",
1585+
self.meta.handle, self.local_endpoint, self.remote_endpoint
1586+
);
1587+
None
1588+
}
1589+
};
1590+
}
1591+
}
1592+
15441593
// Per RFC 5681, we should send an immediate ACK when either:
15451594
// 1) an out-of-order segment is received, or
15461595
// 2) a segment arrives that fills in all or part of a gap in sequence space.
@@ -1590,6 +1639,13 @@ impl<'a> TcpSocket<'a> {
15901639
can_data || can_fin
15911640
}
15921641

1642+
fn delayed_ack_expired(&self, timestamp: Instant) -> bool {
1643+
match self.ack_delay_until {
1644+
None => true,
1645+
Some(t) => t <= timestamp,
1646+
}
1647+
}
1648+
15931649
fn ack_to_transmit(&self) -> bool {
15941650
if let Some(remote_last_ack) = self.remote_last_ack {
15951651
remote_last_ack < self.remote_seq_no + self.rx_buffer.len()
@@ -1644,11 +1700,11 @@ impl<'a> TcpSocket<'a> {
16441700
// If we have data to transmit and it fits into partner's window, do it.
16451701
net_trace!("{}:{}:{}: outgoing segment will send data or flags",
16461702
self.meta.handle, self.local_endpoint, self.remote_endpoint);
1647-
} else if self.ack_to_transmit() {
1703+
} else if self.ack_to_transmit() && self.delayed_ack_expired(timestamp) {
16481704
// If we have data to acknowledge, do it.
16491705
net_trace!("{}:{}:{}: outgoing segment will acknowledge",
16501706
self.meta.handle, self.local_endpoint, self.remote_endpoint);
1651-
} else if self.window_to_update() {
1707+
} else if self.window_to_update() && self.delayed_ack_expired(timestamp) {
16521708
// If we have window length increase to advertise, do it.
16531709
net_trace!("{}:{}:{}: outgoing segment will update window",
16541710
self.meta.handle, self.local_endpoint, self.remote_endpoint);
@@ -1812,6 +1868,15 @@ impl<'a> TcpSocket<'a> {
18121868
// the keep-alive timer.
18131869
self.timer.rewind_keep_alive(timestamp, self.keep_alive);
18141870

1871+
// Reset delayed-ack timer
1872+
if self.ack_delay_until.is_some() {
1873+
net_trace!("{}:{}:{}: stop delayed ack timer",
1874+
self.meta.handle, self.local_endpoint, self.remote_endpoint
1875+
);
1876+
1877+
self.ack_delay_until = None;
1878+
}
1879+
18151880
// Leave the rest of the state intact if sending a keep-alive packet, since those
18161881
// carry a fake segment.
18171882
if is_keep_alive { return Ok(()) }
@@ -1851,10 +1916,17 @@ impl<'a> TcpSocket<'a> {
18511916
} else if self.state == State::Closed {
18521917
// Socket was aborted, we have an RST packet to transmit.
18531918
PollAt::Now
1854-
} else if self.seq_to_transmit() || self.ack_to_transmit() || self.window_to_update() {
1919+
} else if self.seq_to_transmit() {
18551920
// We have a data or flag packet to transmit.
18561921
PollAt::Now
18571922
} else {
1923+
let want_ack = self.ack_to_transmit() || self.window_to_update();
1924+
let delayed_ack_poll_at = match (want_ack, self.ack_delay_until) {
1925+
(false, _) => PollAt::Ingress,
1926+
(true, None) => PollAt::Now,
1927+
(true, Some(t)) => PollAt::Time(t),
1928+
};
1929+
18581930
let timeout_poll_at = match (self.remote_last_ts, self.timeout) {
18591931
// If we're transmitting or retransmitting data, we need to poll at the moment
18601932
// when the timeout would expire.
@@ -1864,9 +1936,8 @@ impl<'a> TcpSocket<'a> {
18641936
};
18651937

18661938
// We wait for the earliest of our timers to fire.
1867-
*[self.timer.poll_at(), timeout_poll_at]
1939+
*[self.timer.poll_at(), timeout_poll_at, delayed_ack_poll_at]
18681940
.iter()
1869-
.filter(|x| !x.is_ingress())
18701941
.min().unwrap_or(&PollAt::Ingress)
18711942
}
18721943
}
@@ -2076,7 +2147,9 @@ mod test {
20762147

20772148
let rx_buffer = SocketBuffer::new(vec![0; rx_len]);
20782149
let tx_buffer = SocketBuffer::new(vec![0; tx_len]);
2079-
TcpSocket::new(rx_buffer, tx_buffer)
2150+
let mut socket = TcpSocket::new(rx_buffer, tx_buffer);
2151+
socket.set_ack_delay(None);
2152+
socket
20802153
}
20812154

20822155
fn socket_syn_received_with_buffer_sizes(
@@ -5084,6 +5157,119 @@ mod test {
50845157
assert_eq!(s.recv(|_| (0, ())), Err(Error::Illegal));
50855158
}
50865159

5160+
// =========================================================================================//
5161+
// Tests for delayed ACK
5162+
// =========================================================================================//
5163+
5164+
#[test]
5165+
fn test_delayed_ack() {
5166+
let mut s = socket_established();
5167+
s.set_ack_delay(Some(ACK_DELAY_DEFAULT));
5168+
send!(s, TcpRepr {
5169+
seq_number: REMOTE_SEQ + 1,
5170+
ack_number: Some(LOCAL_SEQ + 1),
5171+
payload: &b"abc"[..],
5172+
..SEND_TEMPL
5173+
});
5174+
5175+
// No ACK is immediately sent.
5176+
recv!(s, Err(Error::Exhausted));
5177+
5178+
// After 10ms, it is sent.
5179+
recv!(s, time 11, Ok(TcpRepr {
5180+
seq_number: LOCAL_SEQ + 1,
5181+
ack_number: Some(REMOTE_SEQ + 1 + 3),
5182+
window_len: 61,
5183+
..RECV_TEMPL
5184+
}));
5185+
}
5186+
5187+
#[test]
5188+
fn test_delayed_ack_win() {
5189+
let mut s = socket_established();
5190+
s.set_ack_delay(Some(ACK_DELAY_DEFAULT));
5191+
send!(s, TcpRepr {
5192+
seq_number: REMOTE_SEQ + 1,
5193+
ack_number: Some(LOCAL_SEQ + 1),
5194+
payload: &b"abc"[..],
5195+
..SEND_TEMPL
5196+
});
5197+
5198+
// Reading the data off the buffer should cause a window update.
5199+
s.recv(|data| {
5200+
assert_eq!(data, b"abc");
5201+
(3, ())
5202+
}).unwrap();
5203+
5204+
// However, no ACK or window update is immediately sent.
5205+
recv!(s, Err(Error::Exhausted));
5206+
5207+
// After 10ms, it is sent.
5208+
recv!(s, time 11, Ok(TcpRepr {
5209+
seq_number: LOCAL_SEQ + 1,
5210+
ack_number: Some(REMOTE_SEQ + 1 + 3),
5211+
..RECV_TEMPL
5212+
}));
5213+
}
5214+
5215+
#[test]
5216+
fn test_delayed_ack_reply() {
5217+
let mut s = socket_established();
5218+
s.set_ack_delay(Some(ACK_DELAY_DEFAULT));
5219+
send!(s, TcpRepr {
5220+
seq_number: REMOTE_SEQ + 1,
5221+
ack_number: Some(LOCAL_SEQ + 1),
5222+
payload: &b"abc"[..],
5223+
..SEND_TEMPL
5224+
});
5225+
5226+
s.recv(|data| {
5227+
assert_eq!(data, b"abc");
5228+
(3, ())
5229+
}).unwrap();
5230+
5231+
s.send_slice(&b"xyz"[..]).unwrap();
5232+
5233+
// Writing data to the socket causes ACK to not be delayed,
5234+
// because it is immediately sent with the data.
5235+
recv!(s, Ok(TcpRepr {
5236+
seq_number: LOCAL_SEQ + 1,
5237+
ack_number: Some(REMOTE_SEQ + 1 + 3),
5238+
payload: &b"xyz"[..],
5239+
..RECV_TEMPL
5240+
}));
5241+
}
5242+
5243+
#[test]
5244+
fn test_delayed_ack_every_second_packet() {
5245+
let mut s = socket_established();
5246+
s.set_ack_delay(Some(ACK_DELAY_DEFAULT));
5247+
send!(s, TcpRepr {
5248+
seq_number: REMOTE_SEQ + 1,
5249+
ack_number: Some(LOCAL_SEQ + 1),
5250+
payload: &b"abc"[..],
5251+
..SEND_TEMPL
5252+
});
5253+
5254+
// No ACK is immediately sent.
5255+
recv!(s, Err(Error::Exhausted));
5256+
5257+
send!(s, TcpRepr {
5258+
seq_number: REMOTE_SEQ + 1 + 3,
5259+
ack_number: Some(LOCAL_SEQ + 1),
5260+
payload: &b"def"[..],
5261+
..SEND_TEMPL
5262+
});
5263+
5264+
// Every 2nd packet, ACK is sent without delay.
5265+
recv!(s, Ok(TcpRepr {
5266+
seq_number: LOCAL_SEQ + 1,
5267+
ack_number: Some(REMOTE_SEQ + 1 + 6),
5268+
window_len: 58,
5269+
..RECV_TEMPL
5270+
}));
5271+
}
5272+
50875273
// =========================================================================================//
50885274
// Tests for packet filtering.
50895275
// =========================================================================================//

0 commit comments

Comments
 (0)