Under a number of circumstances, TCP may initiate a retransmission even when no data has been lost. Such undesirable retransmissions are called spurious retrans- missions and are caused by spurious timeouts (timeouts firing too early) and other reasons such as packet reordering, packet duplication, or lost ACKs. Spurious timeouts can occur when the real RTT has recently increased significantly, beyond the RTO. This happens more frequently in environments where lower-layer pro- tocols have widely varying performance (e.g., wireless) and was a concern men- tioned in [KP87]. Here we focus primarily on spurious retransmissions caused by spurious timeouts. The effects of reordering and duplication on TCP are deferred until the following section.
A number of approaches have been suggested to deal with spurious time- outs. They generally involve a detection algorithm and a response algorithm. The detection algorithm attempts to determine whether a timeout or timer-based retransmission was spurious. The response algorithm is invoked once a timeout or retransmission is deemed spurious. Its purpose is to undo or mitigate some action that is otherwise normally performed by TCP when a retransmission timer expires. In this chapter we discuss only the segment retransmission behavior. The response algorithms typically involve congestion control changes as well, and those aspects are discussed in Chapter 16.
Figure 14-12 illustrates a highly simplified exchange that shows what happens to a basic TCP when a spurious retransmission occurs because of a delay spike in the ACK path after segment 8 is sent. After the retransmission of segment 5 occurs because of a timeout, there are still ACKs in flight from the original transmis- sions of segments 5 through 8. In this illustration, sequence and ACK numbers are based on packets instead of bytes, with ACKs indicating what has already arrived instead of what is expected next, for simplicity. When they arrive, TCP begins to retransmit additional segments that have already been received, starting with the segment following the ACKed segment. This causes TCP to behave in an unde- sirable “go-back-N” behavior pattern and in turn causes a collection of duplicate ACKs to be generated and returned to the sender, possibly triggering fast retrans- mit as well. Several techniques have been developed to mitigate these problems.
We now have a look at some of the more popular ones.
14.7.1 Duplicate SACK (DSACK) Extension
With a non-SACK TCP, an ACK can indicate only the highest in-sequence segment back to the sender. With SACK, it can signal other (out-of-order) segments as well.
The basic SACK mechanism we discussed previously does not say what happens when a receiver receives duplicate data segments. Such segments can be the result of spurious retransmissions, duplication within the network, or other reasons.
ptg999
DSACK or D-SACK, which stands for duplicate SACK [RFC2883], is a rule, applied at the SACK receiver and interoperable with conventional SACK senders, that causes the first SACK block to indicate the sequence numbers of a duplicate segment that has arrived at the receiver. The main purpose of DSACK is to deter- mine when a retransmission was not necessary and to learn additional facts about the network. With it, a sender has at least the possibility of inferring whether packet reordering, loss of ACKs, packet replication, and/or spurious retransmis- sions are taking place.
The implementation of DSACK is compatible with conventional SACK in the sense that no separate negotiation is required to make use of it. For it to work properly, a change is made to the content of SACKs sent from the receiver and a corresponding change to the logic at the sender. If a non-DSACK TCP shares a connection with a DSACK TCP, they will interoperate, but without any of the benefits of DSACK.
The change to the SACK receiver is to allow a SACK block to be included even if it covers sequence numbers below (or equal to) the cumulative ACK Number field.
$
$
$
$
$
$ $ $
$
$
$
7LPHRXW
)DVW 57;
$
Figure 14-12 A delay spike occurs after the transmission of packet 8, causing a spurious retransmis- sion timeout and retransmission of packet 5. After retransmission, an ACK for the first copy of 5 arrives. The retransmission for 5 creates a duplicate packet at the receiver, fol- lowed by an undesirable “go-back-N” behavior whereby packets 6, 7, and 8 are retrans- mitted even though they are already present at the receiver.
ptg999 Section 14.7 Spurious Timeouts and Retransmissions 679
This was not the original intent of SACK, but its capability is well matched to this purpose. (It applies equally well in cases where the DSACK information is above the cumulative ACK Number field; this happens for duplicated out-of-order seg- ments.) DSACK information is included in only a single ACK, and such an ACK is called a DSACK. DSACK information is not repeated across multiple SACKs as conventional SACK information is. As a consequence, DSACKs are less robust to ACK loss than regular SACKs.
Exactly what a sender given DSACK information is supposed to do with it is not specified by [RFC2883]. An experimental algorithm is given in [RFC3708]
for detecting spurious retransmissions using DSACK but does not provide any response algorithm. One option it mentions is to use the Eifel Response Algo- rithm, which we investigate in Section 14.7.4 after introducing a few other detec- tion algorithms.
14.7.2 The Eifel Detection Algorithm
At the beginning of this chapter, we discussed the retransmission ambiguity prob- lem. The experimental Eifel Detection Algorithm [RFC3522] deals with this problem using the TCP TSOPT to detect spurious retransmissions. After a retransmission timeout occurs, Eifel awaits the next acceptable ACK. If the next acceptable ACK indicates that the first copy of a retransmitted packet (called the original transmit) was the cause for the ACK, the retransmission is considered to be spurious.
The Eifel Detection Algorithm is able to detect spurious behavior earlier than the approach using only DSACK because it relies on ACKs generated as a result of packets arriving before loss recovery is initiated. DSACKs, conversely, are able to be sent only after a duplicate segment has arrived at the receiver and able to be acted upon only after the DSACK is returned to the sender. Detecting spurious retransmissions early can offer advantages, because it allows the sender to avoid most of the go-back-N behavior mentioned earlier.
The mechanics of the Eifel Detection Algorithm are simple. It requires the use of the TCP TSOPT. When a retransmission is sent (either a timer-based retransmis- sion or a fast retransmit), the TSV value is stored. When the first acceptable ACK covering its sequence number is received, the incoming ACK’s TSER is examined.
If it is smaller than the stored value, the ACK corresponds to the original transmis- sion of the packet and not the retransmission, implying that the retransmission must have been spurious. This approach is fairly robust to ACK loss as well. If an ACK is lost, any subsequent ACKs still have TSER values less than the stored TSV of the retransmitted segment. Thus, a retransmission can be deemed spurious as a result of any of the window’s worth of ACKs arriving, so a loss of any single ACK is not likely to cause a problem.
The Eifel Detection Algorithm can be combined with DSACKs. This can be beneficial in the situation where an entire window’s worth of ACKs are lost but both the original transmit and retransmission have arrived at the receiver. In this particular case, the arriving retransmit causes a DSACK to be generated. The Eifel
ptg999 Detection Algorithm would by default conclude that the retransmission is spuri-
ous. It is thought, however, that if so many ACKs are being lost, allowing TCP to believe the retransmission was not spurious is useful (e.g., to induce it to start sending more slowly—a consequence of the congestion control procedures we dis- cuss in Chapter 16). Thus, arriving DSACKs cause the Eifel Detection Algorithm to conclude that the corresponding retransmission is not spurious.
14.7.3 Forward-RTO Recovery (F-RTO)
Forward-RTO Recovery (F-RTO) [RFC5682] is a standard algorithm for detecting spurious retransmissions. It does not require any TCP options, so when it is imple- mented in a sender, it can be used effectively even with an older receiver that does not support the TCP TSOPT. It attempts to detect only spurious retransmissions caused by expiration of the retransmission timer; it does not deal with the other causes for spurious retransmissions or duplications mentioned before.
F-RTO makes a modification to the action TCP ordinarily takes after a timer- based retransmission. These retransmissions are for the smallest sequence number for which no ACK has yet been received. Ordinarily, TCP continues sending addi- tional adjacent packets in order as additional ACKs arrive. This is the go-back-N behavior described previously.
F-RTO modifies the ordinary behavior of TCP by having TCP send new (so far unsent) data after the timeout-based retransmission when the first ACK arrives.
It then inspects the second arriving ACK. If either of the first two ACKs arriv- ing after the retransmission was sent are duplicate ACKs, the retransmission is deemed OK. If they are both acceptable ACKs that advance the sender’s window, the retransmission is deemed to have been spurious. This approach is fairly intui- tive. If the transmission of new data results in the arrival of acceptable ACKs, the arrival of the new data is moving the receiver’s window forward. If such data is only causing duplicate ACKs, there must be one or more holes at the receiver. In either case, the reception of new data at the receiver does not harm the overall data transfer performance (provided there are sufficient buffers at the receiver).
14.7.4 The Eifel Response Algorithm
The Eifel Response Algorithm [RFC4015] is a standard set of operations to be exe- cuted by a TCP once a retransmission has been deemed spurious. Because the response algorithm is logically decoupled from the Eifel Detection Algorithm, it can be used with any of the detection algorithms we just discussed. The Eifel Response Algorithm was originally intended to operate for both timer-based and fast retransmit spurious retransmissions but is currently specified only for timer- based retransmissions.
Although the Eifel Response Algorithm can be used with any of the detec- tion algorithms, it behaves somewhat differently based on whether a spurious timeout was detected early (e.g., by the Eifel or F-RTO detection algorithms) or
ptg999 Section 14.7 Spurious Timeouts and Retransmissions 681
later (e.g., by DSACKs). The former cases are called spurious timeouts and operate by inspecting ACKs for original transmissions. The latter are called late spurious timeouts and are based on ACKs for retransmissions invoked as a result of (spuri- ous) timeouts.
The response algorithm operates on the first retransmission timer event only.
It is not executed if a subsequent timeout occurs before recovery is complete. After the retransmission timer expires, it takes a snapshot of the values in srtt and rttvar and records them in new variables srtt_prev and rttvar_prev as follows:
srtt_prev = srtt + 2(G) rttvar_prev = rttvar
These variables are assigned on any timer expiration but are used only when the timeout is determined to be spurious. If so, they help form the basis for setting the new RTO. In the formula, the value G represents the TCP clock granularity.
srtt_prev is set to srtt plus twice the timer granularity based on the following chain of reasoning: The spurious timeout may have been invoked because the value of srtt is just a tad too small. If it were just a bit larger, no timeout would have hap- pened. Adding the term 2(G) to srtt deals with this situation by storing a slightly increased value into srtt_prev, which is used later for setting the RTO.
After the srtt_prev and rttvar_prev values are stored, one of the detection algo- rithms is invoked. The result of running the algorithm produces a value assigned to a special variable called SpuriousRecovery. If the algorithm detects a spurious timeout, SpuriousRecovery is set to SPUR_TO. If it detects a late spurious timeout, it sets SpuriousRecovery to LATE_SPUR_TO. Otherwise, the timeout is not spurious, and ordinary TCP timeout processing continues.
If SpuriousRecovery is SPUR_TO, TCP can take action before recovery is com- plete. It does this by adjusting the sequence number of the next segment it is about to send (called SND.NXT) to the first new, unsent segment (called SND.MAX).
This avoids the undesirable go-back-N behavior after the initial retransmission discussed previously. If the detection algorithm detects a late spurious timeout, an ACK for the initial retransmission has already taken place, so SND.NXT is not changed. In either case, however, the congestion control state is reset (see Chapter 16). In addition, once an acceptable ACK is received for a segment transmitted after the retransmission timer expires, the values of srtt, rttvar, and RTO can be updated as follows:
srtt ← max(srtt_prev, m) rttvar ← max(rttvar_prev, m/2)
RTO = srtt + max(G, 4(rttvar))
Here, m is a sample of the RTT of the connection based on the arrival of the first acceptable ACK for data sent after the timeout. The motivation for these
ptg999 modifications is that the real RTT may have changed so significantly that the RTT
history in the current estimators is no longer a valid basis for setting the RTO. If the real path RTT has increased abruptly (e.g., because of wireless handoff to a new base station), the current srtt and rttvar values are likely to be too small and should be reinitialized. On the other hand, an increase in path RTT could be only temporary, implying that reinitializing srtt and rttvar might not be such a good idea because they are likely to be approximately correct.
These equations try to balance between the two situations by reassigning the moving averages srtt and rttvar only if the new RTT samples are larger. Doing so effectively throws out the previous history of the RTT (and RTT variance). The val- ues of srtt and rttvar can only increase as a result of the response algorithm. If the RTT does not appear to be increasing, the running estimators remain unchanged, essentially ignoring the fact that a timeout has occurred. The RTO is reassigned in the conventional way in any case, and a new retransmission timer is set for this timeout value.