The trouble with a loss-only signal
By now you know the heart of classic TCP: it speeds up gently and brakes hard, the AIMD law that draws the congestion control sawtooth. But step back and ask how the sender actually learns it has pushed too hard. In plain Reno-style TCP the only signal is a dropped packet. A router somewhere along the path filled its queue, ran out of room, and threw a packet away; the missing acknowledgment is what tells the sender to back off. In other words, the network's way of saying 'slow down' is to destroy your data and let you notice the gap.
That is a remarkably crude conversation. The sender has to lose data and wait at least one round-trip time to even notice. And it raises a question that turns out to be central to everything in this guide: where exactly does that loss happen, and how long did the packet sit waiting before it was dropped or delivered? The answer lives inside the router's buffer, the queue of packets waiting for their turn on a busy link. Understanding that buffer is the key to understanding bufferbloat, ECN, and fairness all at once.
Bufferbloat: when bigger buffers make things worse
Here is one of the most counter-intuitive results in modern networking. A router needs a buffer so that a brief burst of packets does not get dropped the instant the link is busy — that is genuinely useful. So an engineer reasons, more memory is cheap, let me give it a huge buffer so it almost never has to drop anything. The result is a disaster called bufferbloat: the link feels slower and laggier, not faster, even though no packets are being lost. To see why, remember that loss-based TCP keeps pushing harder until it sees a drop. If the buffer is enormous, the sender fills it to the brim before any drop ever happens.
A full buffer means every new packet must sit behind all the packets already queued. The link still moves the same number of bits per second — your bandwidth is unchanged — but each packet now waits in a long line before it leaves. That waiting is pure latency, added on top of the unavoidable propagation delay. This is the moment to recall an honest fact from early in the ladder: bandwidth, throughput, and latency are three different things, and a fat buffer can quietly wreck latency while leaving bandwidth looking perfect. Your big download finishes fine; meanwhile your video call stutters and your keystrokes lag, because every packet is stuck behind that bulk transfer in a queue that may hold seconds of traffic.
Smarter routers: AQM and the one-bit warning
If a router only ever drops when its buffer is completely full, it has already let the queue grow long and laggy before it says anything. The cure is to let the router help on purpose, rather than waiting passively to overflow. This family of techniques is called active queue management, or AQM. The idea: watch the queue, and when it starts to build up — well before it overflows — take a small action that nudges senders to slow down, keeping the queue short and latency low.
The classic AQM scheme is RED, Random Early Detection: as the average queue grows past a threshold, the router starts dropping a small, random fraction of packets early. Each early drop is a polite hint to one flow to back off, spread fairly across whoever is sending the most, long before the buffer is genuinely full. A more modern and self-tuning scheme is CoDel, Controlled Delay, which is clever because it does not watch how many packets are queued but how LONG they have been waiting. CoDel measures the time each packet spends in the queue and acts when that delay stays high for too long — directly attacking the bufferbloat problem at its root, since the thing we actually care about is delay, not occupancy.
But notice that even RED and CoDel still send their warning by dropping a packet — destroying data to make a point. The elegant final step is to warn the sender WITHOUT throwing anything away. That is Explicit Congestion Notification, or ECN. Instead of dropping a packet when the queue builds, an ECN-aware router flips a single marking bit in the packet's IP header that says 'I am getting congested.' The receiver sees the mark, echoes it back to the sender in its acknowledgment, and the sender treats that mark exactly as if it had seen a loss — it backs off — but no data was ever lost and nothing had to be retransmitted. A one-bit 'please ease off,' delivered without breaking anything.
WITHOUT ECN (loss as signal) WITH ECN (mark as signal) --------------------------- -------------------------- queue fills -> router DROPS packet queue builds -> router MARKS packet sender notices missing ACK receiver echoes the mark in its ACK sender backs off (AIMD) sender backs off (AIMD) ...and must RETRANSMIT lost data ...nothing lost, nothing resent
Reno, CUBIC, BBR: different theories of congestion
The sender's strategy for growing and shrinking its congestion window is not fixed in stone — it is a swappable algorithm, and the choice of algorithm encodes a whole theory about what congestion even is. Reno, the classic you already studied, believes loss equals congestion: grow linearly, halve on loss. It works, but on today's very fast, long-distance links its careful linear climb takes an age to refill the pipe after each cut, leaving capacity idle.
CUBIC, the default in Linux and Android for years, keeps the loss-equals-congestion belief but grows the window along a smoother cubic curve. After a cut it climbs back quickly toward the rate that last worked, then eases off cautiously as it approaches that point, probing gently for more. This fills fast, fat links far better than Reno's straight line, which is exactly why it became the workhorse of the modern Internet.
BBR takes a genuinely different stance, and it is the reason this whole guide matters. BBR refuses to wait for loss at all. Instead it actively measures two things — the link's available bandwidth and the connection's minimum round-trip time — and tries to send at exactly the bottleneck rate while keeping the queue nearly empty. In effect, BBR is trying to avoid creating bufferbloat in the first place: it aims for the sweet spot of full bandwidth with no standing queue, rather than filling a buffer until something breaks. It is not magic and not always fairer to its neighbors, but it shows that loss is a choice of signal, not the only possible one.
Fairness, and the wireless trap
Now the deep question. Nobody is in charge of the Internet's traffic; there is no central dispatcher allocating each flow a slice of a shared link. So why does a crowded link not simply collapse into one greedy flow hogging everything? The answer is fairness, and it is a beautiful emergent property of AIMD itself. When several AIMD flows share a bottleneck, they all increase additively and all cut multiplicatively at roughly the same moments, and over time their rates drift toward an equal share — not because anyone enforces it, but because the additive-increase, multiplicative-decrease rule naturally pulls unequal flows back together. Fairness is built into the math of how everyone politely backs off.
But honesty demands the caveats. This fairness assumes everyone is running roughly the same AIMD-style algorithm and sharing similar round-trip times — and neither always holds. A flow with a shorter round-trip time reacts and grows faster, so it tends to grab a larger share than a long-distance flow at the same bottleneck. And a sender is free to run a more aggressive algorithm, or open many connections at once, to claim more than its 'fair' slice. Fairness is a tendency that emerges when participants cooperate, not a guarantee the network imposes. It is the same end-to-end principle you met long ago: the network stays simple and dumb in the middle, and the good behavior lives in the hosts at the edges, which is powerful but only as reliable as the hosts choose to be.
Which brings the most important honest caveat of the whole rung, the assumption hiding under all of loss-based TCP. Reno and CUBIC believe that loss means congestion. On a wired link that is almost always true — packets are lost because a queue overflowed. But on a wireless link, packets are frequently lost to radio interference, fading, and multipath, with no congestion at all. Loss-based TCP cannot tell the two apart: it sees the dropped packet, assumes the network is congested, and cuts its window in half — throttling itself exactly when the link was fine and there was no congestion to relieve. That mismatch is the core of poor TCP performance over wireless, and it is one big reason measurement-based designs like BBR, which do not equate loss with congestion, matter so much on today's overwhelmingly wireless edge.
Putting the whole rung together
Step back and see the arc of this rung. You separated flow control (protecting one slow receiver) from congestion control (protecting the shared network). You saw why congestion collapse can crater a network and how AIMD's gentle-up, hard-down rhythm both avoids it and, almost as a bonus, shares the link fairly. You walked the sawtooth of slow start and congestion avoidance, met timeouts and fast retransmit, and watched the algorithms evolve from Reno to CUBIC to BBR. This last guide added the other half of the picture: the network is not just a dumb pipe the sender probes blindly. Routers can help — keeping buffers short with AQM, and warning senders with a single ECN bit instead of by destroying data.