SubnetLayerRFCs

RFC 896

HISTORIC · IDEAS LIVE ON

Congestion Control in IP/TCP Internetworks

John Nagle (Ford Aerospace) · January 1984 · original status: Unknown (pre-standards-track memo) · current status: Historic

obsoleted by: RFC 7805

Historic (RFC 7805). Half prophecy, half patch: it predicted congestion collapse four years before it happened (answered by slow start, today's RFC 5681), and its small-packet rule survives in every stack as 'the Nagle algorithm' (RFC 9293 §3.7.4, off-switch: TCP_NODELAY).

This module teaches BOTH the historical problem and today's rules

This document

  • RFC 896 — 'Congestion collapse' (the prophecy)
  • RFC 896 — 'The small-packet problem' and the inhibit-while-unacked rule (the Nagle algorithm)
  • RFC 896 — 'The source quench problem' (obsolete: ICMP Source Quench deprecated by RFC 6633)

Where the current rules live

  • RFC 9293 §3.7.4 — Nagle algorithm (SHOULD, with an application off-switch)
  • RFC 1122 §4.2.3.4 — sender SWS avoidance incorporating Nagle
  • RFC 5681 — the congestion-control machinery that answered the collapse prediction

Congestion & the Small-Packet Problem (Nagle)

New to these ideas? Switch to the beginner level for a from-zero concept primer.

The problem this document answered

A telnet keystroke costs 4000% overhead: 1 payload byte, 40 header bytes, plus the ACK coming back. Nagle's rule — while anything is unacknowledged, buffer small writes until the ACK returns or a full segment accumulates — batches exactly as aggressively as the network is slow. No timers, no configuration.

Historical context

RFC 896 (January 1984) is a field report from Ford Aerospace's congested networks. Historic status (RFC 7805) — yet the small-packet rule is in every stack as 'the Nagle algorithm', and the collapse analysis became the founding problem statement of congestion control. Its third topic, ICMP Source Quench, is fully retired (RFC 6633).

Current practice

Nagle is on by default everywhere (RFC 9293 §3.7.4, SHOULD) with a mandatory application off-switch (TCP_NODELAY). Latency-sensitive software — games, trading, many RPC frameworks — disables it deliberately and knowingly pays the tinygram tax.

Interactive laboratory

⌨️ Typing laboratory — every number below comes from a live engine run

app writes
11
data segments
5
total packets
13
header bytes
734
payload bytes
11
overhead
98.5%
avg perceived latency
36 ms
delack timer fires
0
t= 100ms · 1 B · "s"
t= 140ms · 2 B · "ub"
t= 180ms · 3 B · "net"
t= 220ms · 3 B · "lay"
t= 260ms · 2 B · "er"

Nagle and delayed ACK solve different problems (sender efficiency vs receiver ACK economy) — try Nagle ON + delayed ACK ON with a big RTT and watch them wait on each other.

Guided walkthroughs — coached, packet by packet

Watch it on the wire

RFC 896 · The small-packet problem

Eight keystrokes typed into a remote session with Nagle disabled: one 41-byte-overhead packet per byte of typing.

RFC 896 · The Nagle algorithm

The same eight keystrokes with Nagle enabled: the first byte goes immediately, the rest coalesce behind the outstanding ACK — self-clocked batching.

RFC 896 · Congestion collapse in miniature

A slow link (60 B/ms), a 4-packet router queue, and a sender whose RTO (80 ms) is shorter than the queue-inflated RTT: premature retransmissions flood the queue with duplicates, drops multiply, and goodput falls while total traffic rises.

RFC 896 · Same link, patient timer

The identical slow, shallow-queued link — but with a conservative 1-second RTO. The burst tail still overflows the queue, yet every retry now answers a REAL loss: no spurious copies, no duplicates competing with live data.

Compare correct vs historic / naive behaviour

Original RFC vs current standard

The small-segment rule

Original behaviour
RFC 896: inhibit new small segments while ANY data is unacknowledged — stated absolutely, no escape hatch.
Current behaviour
RFC 9293 §3.7.4: SHOULD implement, MUST allow the application to disable per connection.
What changed
A mandatory off-switch was added.
Why it changed
Interactive and request/response workloads legitimately prefer latency over efficiency — the X Window System fight made this famous.

📷 In a capture: Nagle on: bursts of coalesced writes released by returning ACKs. TCP_NODELAY: every write on the wire immediately, tiny or not.

Common misconceptions

  • “Nagle adds a fixed delay” — it adds NO timer; data waits only for the in-flight ACK, so on a fast LAN the wait is microseconds.
  • “Nagle and delayed ACK are the same feature” — sender-side batching vs receiver-side ACK economy; they solve different problems and can deadlock each other briefly.
  • “Disabling Nagle makes everything faster” — it trades bandwidth for latency; bulk transfers gain nothing and chatty apps flood the wire.
  • “Congestion collapse means total outage” — it's worse: the network stays busy at full load while delivering almost nothing useful.

Glossary terms used here

Knowledge check

1/3 · With Nagle enabled, keystroke 'a' left immediately but 'b','c','d' travelled together. What released them?

2/3 · Which workload is the textbook case for setting TCP_NODELAY (disabling Nagle)?

3/3 · A client does write(header); write(body); read(reply) and stalls ~200 ms per request. The classic explanation?