Every flow keeps a congestion window (cwnd) — how many packets it has in flight per RTT. Each round, every active flow offers cwnd packets to a single shared bottleneck link that can genuinely drain only C packets per RTT into a finite buffer of B packets. Whatever the buffer can't hold is really dropped that round — the drop isn't scheduled or scripted, it falls out of actual queue arithmetic. A flow that loses a packet halves its cwnd (multiplicative decrease) and sets its slow-start threshold there; every flow that gets through clean grows its cwnd — doubling each RTT during slow start, then by a flat +1/RTT once past its threshold (additive increase). Bigger flows send more packets, so they proportionally take more of any overflow drop — which is exactly the negative feedback that makes AIMD converge toward roughly equal cwnd across flows over time, the same fairness result real TCP relies on across the internet.
newQueue = max(0, queue + Σcwnd_i − C)
overflow = max(0, newQueue − B)
drop_i ~ overflow · (cwnd_i / Σcwnd_i) [proportional to offered load]
on drop: ssthresh_i = cwnd_i/2 ; cwnd_i = ssthresh_i
no drop: cwnd_i = min(cwnd_i·2, ssthresh_i) if cwnd_i < ssthresh_i (slow start)
cwnd_i = cwnd_i + 1 otherwise (congestion avoidance)
- Bottleneck capacity — how many packets/RTT the shared link can actually drain; this is the resource every flow is competing for.
- Buffer size — how many packets the router can queue beyond capacity before it has no choice but to drop; a bigger buffer delays loss but doesn't prevent it once total demand keeps exceeding capacity.
- RTT — only the simulation's playback speed here; it doesn't change the algorithm, just how fast rounds tick by.
- Flows — new flows join a few rounds apart on purpose, so you can watch an established flow get muscled back down as a newcomer's slow start collides with it — and both settle back toward a fair split.
Real-world relevance: this additive-increase/multiplicative-decrease loop, running inside every TCP stack on the internet, is the actual mechanism that keeps millions of unrelated connections sharing routers without a central scheduler — congestion is discovered only by real loss, and fairness is an emergent side-effect of every flow running the same halving rule.