From f501198a680f5158428bb1fbece65c881879f361 Mon Sep 17 00:00:00 2001 From: Ole Martin Ruud Date: Thu, 17 May 2018 18:28:27 +0200 Subject: [PATCH] Implement fast retransmit for TcpSocket Implement a simple way to discover and respond to three duplicate ACKs from the reciver of the data. This leads to a fast retransmit of the last unacknowledged seqment. This is feature is described in [RFC 5681]. Closes: #104 Closes: #214 Approved by: whitequark --- src/socket/tcp.rs | 120 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 4 deletions(-) diff --git a/src/socket/tcp.rs b/src/socket/tcp.rs index 9686ed1..7814cb1 100644 --- a/src/socket/tcp.rs +++ b/src/socket/tcp.rs @@ -59,6 +59,7 @@ enum Timer { expires_at: Instant, delay: Duration }, + FastRetransmit, Close { expires_at: Instant } @@ -89,7 +90,8 @@ impl Timer { Timer::Retransmit { expires_at, delay } if timestamp >= expires_at => { Some(timestamp - expires_at + delay) - } + }, + Timer::FastRetransmit => Some(Duration::from_millis(0)), _ => None } } @@ -109,6 +111,7 @@ impl Timer { Timer::Idle { keep_alive_at: Some(keep_alive_at) } => PollAt::Time(keep_alive_at), Timer::Idle { keep_alive_at: None } => PollAt::Ingress, Timer::Retransmit { expires_at, .. } => PollAt::Time(expires_at), + Timer::FastRetransmit => PollAt::Now, Timer::Close { expires_at } => PollAt::Time(expires_at), } } @@ -154,10 +157,15 @@ impl Timer { } } Timer::Retransmit { .. } => (), + Timer::FastRetransmit { .. } => (), Timer::Close { .. } => () } } + fn set_for_fast_retransmit(&mut self) { + *self = Timer::FastRetransmit + } + fn set_for_close(&mut self, timestamp: Instant) { *self = Timer::Close { expires_at: timestamp + CLOSE_DELAY @@ -166,7 +174,7 @@ impl Timer { fn is_retransmit(&self) -> bool { match *self { - Timer::Retransmit {..} => true, + Timer::Retransmit {..} | Timer::FastRetransmit => true, _ => false, } } @@ -226,6 +234,11 @@ pub struct TcpSocket<'a> { remote_mss: usize, /// The timestamp of the last packet received. remote_last_ts: Option, + /// The ACK number of the last packet recived. + local_rx_last_ack: Option, + /// The number of packets recived directly after + /// each other which have the same ACK number. + local_rx_dup_acks: u8, } const DEFAULT_MSS: usize = 536; @@ -261,6 +274,8 @@ impl<'a> TcpSocket<'a> { remote_win_len: 0, remote_mss: DEFAULT_MSS, remote_last_ts: None, + local_rx_last_ack: None, + local_rx_dup_acks: 0, } } @@ -872,12 +887,10 @@ impl<'a> TcpSocket<'a> { // Every acknowledgement must be for transmitted but unacknowledged data. (_, &TcpRepr { ack_number: Some(ack_number), .. }) => { let unacknowledged = self.tx_buffer.len() + control_len; - if ack_number < self.local_seq_no { net_debug!("{}:{}:{}: duplicate ACK ({} not in {}...{})", self.meta.handle, self.local_endpoint, self.remote_endpoint, ack_number, self.local_seq_no, self.local_seq_no + unacknowledged); - // FIXME: implement fast retransmit return Err(Error::Dropped) } @@ -887,6 +900,29 @@ impl<'a> TcpSocket<'a> { ack_number, self.local_seq_no, self.local_seq_no + unacknowledged); return Ok(Some(self.ack_reply(ip_repr, &repr))) } + + // 1. Check if duplicate ACK, and change self.local_rx_dup_acks accordingly + // 2. Update the last received ACK (self.local_rx_last_ack) + match self.local_rx_last_ack { + // We have a duplicate ACK -> Increment dup ACKs count and + // set for retransmit if we just recived the third dup ACK + Some(ref mut last_rx_ack) if *last_rx_ack == ack_number => { + net_debug!("{}:{}:{}: duplicate ACK number {} for seq {}", + self.meta.handle, self.local_endpoint, self.remote_endpoint, + self.local_rx_dup_acks, ack_number); + self.local_rx_dup_acks += 1; + if self.local_rx_dup_acks == 3 { + self.timer.set_for_fast_retransmit(); + net_debug!("{}:{}:{}: set a fast retransmit for seq {}", + self.meta.handle, self.local_endpoint, self.remote_endpoint, ack_number); + } + }, + // We do not have a duplicate ACK -> Reset state + _ => { + self.local_rx_last_ack = Some(ack_number); + self.local_rx_dup_acks = 1; + } + }; } } @@ -3167,6 +3203,82 @@ mod test { })); } + #[test] + fn test_fast_retransmit_after_triple_duplicate_ack() { + let mut s = socket_established(); + s.remote_win_len = 6; + + s.send_slice(b"xxxxxxabcdef123456ABCDEFZYXWVU").unwrap(); + + recv!(s, time 1000, Ok(TcpRepr { + seq_number: LOCAL_SEQ + 1, + ack_number: Some(REMOTE_SEQ + 1), + payload: &b"xxxxxx"[..], + ..RECV_TEMPL + })); + // This packet is lost + recv!(s, time 1005, Ok(TcpRepr { + seq_number: LOCAL_SEQ + 1 + 6, + ack_number: Some(REMOTE_SEQ + 1), + payload: &b"abcdef"[..], + ..RECV_TEMPL + })); + recv!(s, time 1010, Ok(TcpRepr { + seq_number: LOCAL_SEQ + 1 + 6 + 6, + ack_number: Some(REMOTE_SEQ + 1), + payload: &b"123456"[..], + ..RECV_TEMPL + })); + recv!(s, time 1015, Ok(TcpRepr { + seq_number: LOCAL_SEQ + 1 + 6 + 6 + 6, + ack_number: Some(REMOTE_SEQ + 1), + payload: &b"ABCDEF"[..], + ..RECV_TEMPL + })); + recv!(s, time 1020, Ok(TcpRepr { + seq_number: LOCAL_SEQ + 1 + 6 + 6 + 6 + 6, + ack_number: Some(REMOTE_SEQ + 1), + payload: &b"ZYXWVU"[..], + ..RECV_TEMPL + })); + // First ACK + send!(s, time 1025, TcpRepr { + seq_number: REMOTE_SEQ + 1, + ack_number: Some(LOCAL_SEQ + 1 + 6), + window_len: 6, + ..SEND_TEMPL + }); + // Second (duplicate) ACK + send!(s, time 1030, TcpRepr { + seq_number: REMOTE_SEQ + 1, + ack_number: Some(LOCAL_SEQ + 1 + 6), + window_len: 6, + ..SEND_TEMPL + }); + // Third (duplicate) ACK + // Should trigger a fast retransmit of dropped packet + send!(s, time 1035, TcpRepr { + seq_number: REMOTE_SEQ + 1, + ack_number: Some(LOCAL_SEQ + 1 + 6), + window_len: 6, + ..SEND_TEMPL + }); + // Fast retransmit packet + recv!(s, time 1040, Ok(TcpRepr { + seq_number: LOCAL_SEQ + 1 + 6, + ack_number: Some(REMOTE_SEQ + 1), + payload: &b"abcdef"[..], + ..RECV_TEMPL + })); + // ACK all recived segments + send!(s, time 1045, TcpRepr { + seq_number: REMOTE_SEQ + 1, + ack_number: Some(LOCAL_SEQ + 1 + (6 * 5)), + window_len: 6, + ..SEND_TEMPL + }); + } + // =========================================================================================// // Tests for window management. // =========================================================================================//