Representative interview topic

Networking Interview: How Does TCP Detect and Recover from Packet Loss?

GeneralHard
Offer.cc Editorial TeamPublished Updated

Question

A sender transmits five consecutive 1,000-byte TCP data segments starting at sequence number 1,000. The second segment is lost and the next three reach the receiver. Derive the ACK, SACK, and retransmission sequence, then compare timeout, fast retransmit, and modern loss-detection boundaries.

Prompt and scope

A sender transmits five consecutive 1,000-byte TCP data segments starting at sequence number 1,000. The second segment is lost and the next three reach the receiver. Derive the ACK, SACK, and retransmission sequence, then compare timeout, fast retransmit, and modern loss-detection boundaries.

Assume the connection is established, all five segments carry data, the receive and congestion windows allow all five to be in flight, the receiver can buffer out-of-order data, and SACK was negotiated during the handshake. Sequence numbers count bytes, and ranges below are half-open. Without SACK, the cumulative ACK and classic fast-retransmit reasoning still hold; the sender simply loses information about which higher-sequence bytes have arrived.

The question fits backend, infrastructure, SRE, client, networking, and general software-engineering roles. Its core competency is deriving and validating transport-protocol state, so the category is general. It does not ask about HTTP/3 cross-stream isolation or TCP establishment, teardown, and TIME_WAIT.

What the interviewer evaluates

First, can the candidate state the units correctly? TCP numbers bytes. A segment's sequence number identifies its first data byte, and a cumulative ACK names the next byte the receiver expects; it is not a packet counter.

Second, can the candidate derive a timeline? Once the second segment is missing, later out-of-order segments do not advance the cumulative ACK, but they do cause duplicate ACKs. The third duplicate ACK is the classic RFC 5681 fast-retransmit signal. Counting the ACK that first acknowledges segment A as a duplicate creates an off-by-one answer.

Third, can the candidate separate recovery mechanisms? RTO covers losses that do not produce enough ACK feedback. Fast retransmit uses duplicate ACKs generated by later data to recover sooner. SACK describes received noncontiguous byte blocks so the sender can avoid resending delivered data, but it neither replaces the cumulative ACK nor independently controls the congestion window.

Fourth, can the candidate explain uncertainty? Reordering or replication can also create duplicate ACKs, and an RTT spike can cause a timeout without a real loss. Reliable delivery, loss detection, and congestion control interact, but they are distinct ideas.

Fifth, can the answer go beyond a textbook slogan? A strong candidate explains why a small flight or tail loss may not create three duplicate ACKs and notes that implementations can use RACK-TLP to reduce dependence on a fixed packet-count threshold and RTO by combining transmit times with SACK feedback.

Clarifying questions

  • Are sequence numbers and lengths expressed in bytes? Convert relative packet labels into byte ranges first. SYN and FIN also consume sequence space, but this problem contains only data on an established connection.
  • Was SACK negotiated during the handshake? Without it, recovery relies on cumulative ACKs and the sender's chosen algorithm. With it, duplicate ACKs can carry received out-of-order blocks.
  • Is the flight large enough to generate three duplicate ACKs? At least three new segments after the gap must arrive to supply the classic signal. A lost tail segment normally has no later data to create those ACKs.
  • Are we explaining RFC 5681 or one concrete kernel? The classic threshold is useful for derivation. A real stack may use a configurable threshold, SACK recovery, RACK-TLP, or another extension, so packet-trace conclusions need the operating system and version.
  • Is the goal protocol correctness or performance diagnosis? Correctness explains eventual in-order delivery. Diagnosis also needs RTT, RTO, congestion state, reordering, capture points, and NIC offload behavior.

30-second answer framework

“TCP sequence numbers count bytes, and the cumulative ACK is the next expected byte. Segment A covers 1,000 through 1,999, so receiving it produces ACK 2,000. Segment B, covering 2,000 through 2,999, is lost. The next three segments can be buffered, but the gap still begins at 2,000, so each produces another ACK 2,000. If SACK was negotiated, those ACKs also report the received bytes from 3,000 through 5,999.

On the classic RFC 5681 path, the third duplicate ACK triggers fast retransmission of bytes 2,000 through 2,999 without waiting for RTO. Once the gap is filled, the cumulative ACK advances directly to 6,000. If the flight is too small, the tail is lost, or ACK feedback stops, the sender may need RTO. RTO is derived from smoothed RTT and RTT variation, then exponentially backed off after a timeout, with a stronger congestion-window reduction. SACK improves recovery precision for multiple gaps. Modern RACK-TLP can also use transmit time, SACK feedback, and a probe to detect tail or retransmission loss sooner. In a trace, I would correlate cumulative ACKs, SACK blocks, retransmission timing, and the actual TCP stack rather than treating reordering or an analyzer label as proof of loss.”

Step-by-step deep dive

Step 1: Fix the byte ranges and cumulative ACK

The five logical byte ranges are:

text
A: SEQ=1000, LEN=1000 -> [1000, 2000)  delivered
B: SEQ=2000, LEN=1000 -> [2000, 3000)  lost
C: SEQ=3000, LEN=1000 -> [3000, 4000)  delivered
D: SEQ=4000, LEN=1000 -> [4000, 5000)  delivered
E: SEQ=5000, LEN=1000 -> [5000, 6000)  delivered

After A arrives, the receiver holds bytes 1,000 through 1,999 contiguously, so it sends ACK=2000. This ACK advances the acknowledgment boundary for the first time. It is a new ACK, not a duplicate.

After B is lost, C is acceptable within the receive window but cannot fill the gap beginning at 2,000. The receiver may buffer C, while its cumulative acknowledgment remains ACK=2000. The same applies to D and E. RFC 9293 defines the ACK field as the next sequence number expected by the receiving peer, which is why it does not jump to the end of each out-of-order segment.

Step 2: Derive the three duplicate ACKs and fast retransmit

On the classic RFC 5681 path, each arrival of C, D, and E causes an immediate duplicate ACK=2000:

text
Receive A             -> ACK 2000                     new ACK
Receive C; B is absent -> ACK 2000 + SACK [3000,4000) duplicate ACK 1
Receive D; B is absent -> ACK 2000 + SACK [3000,5000) duplicate ACK 2
Receive E; B is absent -> ACK 2000 + SACK [3000,6000) duplicate ACK 3
Sender retransmits B   -> SEQ 2000, LEN 1000
Receiver gets B        -> ACK 6000                     gap closes

When the third duplicate ACK reaches the sender, it infers that B was probably lost and fast-retransmits [2000,3000) instead of waiting for the retransmission timer. C, D, and E are already buffered. When B arrives, the contiguous range immediately extends through byte 5,999, so the cumulative ACK can move directly from 2,000 to 6,000.

Three duplicate ACKs are a loss heuristic, not mathematical proof. Network reordering can deliver higher-sequence data first and produce the same ACK pattern. Replicated data segments or ACKs can also create it. The threshold trades faster repair against misclassifying reordering, and actual stacks may add other algorithms.

Step 3: State what SACK adds and what it does not

A cumulative ACK says only that everything below 2,000 arrived contiguously. A SACK option can additionally report noncontiguous blocks held in the receive buffer, such as [3000,6000). It closes an information gap: the sender knows higher-sequence data arrived and can skip those blocks while repairing multiple holes.

SACK has three important boundaries:

  1. SACK-Permitted must be negotiated in the SYN exchange before the receiver can carry SACK blocks in later ACKs.
  2. A SACK block does not advance the cumulative ACK from 2,000 to 6,000. Only filling [2000,3000) advances the contiguous boundary.
  3. SACK is advisory receiver information. It helps the sender maintain a recovery scoreboard; the sender's algorithm still chooses retransmission order and congestion response.

If both B and D are lost, one fast retransmission initially repairs only B. Classic recovery without SACK has less information about whether D arrived. SACK can report the separate C and E blocks, allowing the sender to identify both gaps more precisely and avoid resending buffered C and E.

Step 4: Explain why RTO remains necessary

Fast retransmit depends on ACK feedback. If the sender transmits only A and B and loses tail segment B, no C, D, or E arrives to create duplicate ACKs. If the reverse ACK path also fails, the sender likewise cannot collect three duplicates. The retransmission timer is the final safety net.

RFC 6298 maintains smoothed round-trip time SRTT, round-trip variation RTTVAR, and clock granularity G:

text
For the first RTT sample R:
SRTT   = R
RTTVAR = R / 2
RTO    = SRTT + max(G, 4 * RTTVAR)

For a later sample R':
RTTVAR = (1 - 1/4) * RTTVAR + 1/4 * abs(SRTT - R')
SRTT   = (1 - 1/8) * SRTT   + 1/8 * R'
RTO    = SRTT + max(G, 4 * RTTVAR)

For example, with a first sample of R=120 ms and G no greater than 240 ms, SRTT=120 ms, RTTVAR=60 ms, and the raw formula gives 360 ms. RFC 6298 recommends rounding an RTO below one second up to one second, and recommends an initial one-second RTO before an RTT sample exists. Real kernels may use newer algorithms and implementation details, so an interval that is not exactly one second does not by itself disprove timeout recovery.

When the timer expires, the sender retransmits the oldest unacknowledged data and doubles RTO before restarting the timer. Exponential backoff avoids repeatedly injecting data into a persistently congested or broken path. Measuring RTT directly from a retransmitted segment creates ambiguity: did the ACK cover the original or the retransmission? Without timestamps that resolve that ambiguity, Karn's algorithm excludes that sample from RTT updates.

Step 5: Separate reliability recovery from congestion response

Retransmission answers “how do we replace missing bytes?” Congestion control answers “how much data may remain in flight afterward?” A loss signal affects both, but the two jobs are different.

Classic RFC 5681 treats RTO as the stronger signal. ssthresh is no more than max(FlightSize/2, 2*SMSS), and cwnd falls to no more than one full-sized segment before slow start resumes. Three duplicate ACKs show that later segments are still arriving and the ACK clock survives, so the sender enters fast retransmit and fast recovery, reducing the window without applying the same RTO reset.

Flow control is another separate limit. The receiver-advertised rwnd protects receive-buffer capacity, while the sender's cwnd protects the network. Both constrain actual sending. SACK describes receive state; it enlarges neither rwnd nor cwnd.

Step 6: Add the modern RACK-TLP boundary

A fixed three-duplicate-ACK rule performs poorly for short flights, tail loss, lost retransmissions, and substantial reordering. RFC 8985 recommends RACK-TLP as an alternative to traditional duplicate-ACK counting. RACK combines each segment's latest transmit time, RTT, and SACK feedback to infer whether an earlier transmission is lost. TLP sends a probe when ACK feedback is sparse near the tail, attempting to restore the ACK clock before RTO.

The interview answer should first derive the classic mechanism and then state the implementation boundary. A real trace may show recovery with fewer than three duplicate ACKs or a tail probe. Check the stack's algorithm and version. Saying every implementation “waits for exactly three duplicates or always waits for RTO” mistakes the teaching model for the complete current behavior.

Step 7: Validate with packet evidence, not a retransmission count

Build a timeline that can be reconciled across observations:

  1. Capture at sender and receiver to locate where the original segment disappears instead of relying on one vantage point.
  2. Align SEQ, LEN, cumulative ACK, and SACK blocks to prove that a byte gap exists.
  3. Count duplicates only after the previous new ACK; do not count the baseline ACK itself.
  4. Compare retransmission time with the third duplicate ACK or the expected RTO, then check congestion state, RTT, and the stack's recovery algorithm.
  5. Correlate application delay with interface loss, reordering, and queue signals rather than assigning root cause from one Wireshark label.

Wireshark's tcp.analysis.fast_retransmission, tcp.analysis.retransmission, and tcp.analysis.duplicate_ack values are analyzer inferences from the available capture, not flags carried in the TCP header. TSO and GRO can also make host-capture segment boundaries differ from packets on the wire. Important conclusions need cross-checking with both endpoints' sequence spaces and timing.

High-quality sample answer

“I would derive it in byte sequence space. A has SEQ=1000 and length 1,000, so after receiving A the receiver next expects byte 2,000 and sends a new ACK 2,000. B covers bytes 2,000 through 2,999 and is lost. C, D, and E cover bytes 3,000 through 5,999 and arrive, but none fills the gap at 2,000. The cumulative ACK therefore stays at 2,000. Each out-of-order segment generates one duplicate ACK. If SACK was negotiated, the receiver also progressively reports that bytes 3,000 through 5,999 are buffered.

Under classic RFC 5681 behavior, C, D, and E produce three duplicate ACKs for 2,000. The third causes the sender to fast-retransmit B without waiting for RTO. When B arrives, the receive buffer becomes contiguous and the cumulative ACK jumps directly to 6,000. The common off-by-one error is counting the first ACK 2,000 after A as a duplicate; it is the new ACK that advances the boundary.

If the loss is at the tail or the flight is too small, three later segments do not exist, so RTO is the final safety net. RTO is estimated from smoothed RTT plus four times RTT variation, and RFC 6298 applies exponential backoff after a timeout. RTO normally causes a stronger congestion-window reduction than fast recovery because the ACK clock may have stopped. SACK tells the sender which noncontiguous higher bytes arrived, which is especially useful for multiple gaps. It does not advance the cumulative ACK by itself and is not a congestion-control algorithm.

Real stacks may also use RACK-TLP to infer loss from transmit time and SACK feedback and to probe tail losses. Three duplicate ACKs are the required classic derivation, not the only possible trigger in every trace. In diagnosis, I would align sequence numbers, lengths, cumulative ACKs, SACK blocks, and retransmission times at both endpoints, check the stack and offload settings, and then distinguish actual loss from reordering, ACK-path loss, or analyzer inference.”

Common mistakes

  • Treating ACK as a packet number → TCP acknowledges contiguous byte space → derive the next expected byte with SEQ + LEN.
  • Counting ACK 2,000 after A as duplicate 1 → it advances the cumulative boundary for the first time → start counting later ACKs with the same number that do not advance it.
  • Claiming C produces ACK 4,000 → the byte gap at B remains → keep the cumulative ACK at 2,000 and report C with SACK.
  • Claiming SACK replaces cumulative ACK → TCP still advances a contiguous boundary cumulatively → treat SACK as additional noncontiguous-block information.
  • Claiming three duplicates prove loss → reordering and replication can create the same signal → call it the classic loss heuristic and verify the timeline.
  • Claiming every loss gets fast-retransmitted → a tail loss or small flight may not create enough duplicate ACKs → retain RTO and explain RACK-TLP's improvement.
  • Combining retransmission and congestion control → repairing data and limiting send rate solve different problems → state the recovery action, cwnd, and rwnd separately.
  • Treating a Wireshark label as an on-wire protocol bit → the label is inferred from capture context and may be distorted by offload → cross-check both endpoints' sequence spaces and timing.

Follow-up questions

Follow-up 1: If only two segments are sent and the second is lost, does fast retransmit occur?

Not on the classic path. No higher-sequence data reaches the receiver, so it cannot generate three duplicate ACKs. The sender normally waits for RTO. A RACK-TLP stack may send a tail-loss probe to solicit feedback, but RTO still provides the fallback if the probe fails.

Follow-up 2: What if C is merely reordered and B arrives later on its original transmission?

Receiving C generates duplicate ACK 2,000 and a corresponding SACK block. If B arrives before the loss threshold is reached, the cumulative ACK advances and retransmission is avoided. If reordering is deep enough to trigger three duplicates first, classic fast retransmit may be spurious. RACK uses a time-based reordering window to reduce this fixed packet-threshold failure mode.

Follow-up 3: Why is SACK more valuable when both B and D are lost?

The receiver can report the delivered C and E blocks. The sender uses that information in a gap scoreboard, skips SACKed ranges, and repairs B and D. Without SACK, the cumulative ACK exposes only the leftmost gap. Classic Reno has less information about multiple losses in one window and may need partial ACKs or eventually RTO.

Follow-up 4: If the first RTT sample is 120 ms, why not set RTO to 120 ms?

RTT varies with queues and path changes. RFC 6298 initializes RTTVAR to R/2; when G is no greater than 4 × RTTVAR, the raw RTO is R + 4 × R/2 = 3R. That is 360 ms here, and the RFC recommends rounding it up to at least one second. Using one RTT directly would make small variations cause spurious timeouts and needless retransmissions.

Follow-up 5: A capture shows a retransmission but not three duplicate ACKs. Does that prove RTO?

No. The capture may miss reverse-path ACKs, the vantage point may be before or after offload, and the stack may use RACK-TLP or another recovery algorithm. Compare the retransmission with the previous ACK timing, inspect SACK and tail probes, check sender-side kernel state, and complete the evidence with a receiver-side capture.

Follow-up 6: Why is the congestion response after timeout normally stronger than after fast recovery?

Three duplicate ACKs show that later segments are leaving the network and reaching the receiver, so the ACK clock still runs. RTO may mean an entire flight or feedback path made no progress. Classic RFC 5681 therefore reduces cwnd to no more than one full-sized segment and restarts slow start after timeout, while fast recovery retains a reduced sending window.

Public sources

Related questions