How the planner calculates
Bandwidth-delay product. BDP (bits) = bottleneck bandwidth (bits/s) × RTT (s), and the minimum TCP receive window is BDP ÷ 8 bytes, rounded up here to a whole byte. That is the definition in RFC 6349 §3.3.1, whose example is a 44.21 Mbps T3 at 25 ms: about 1,105,000 bits and a 138 KB window. A smaller window cannot keep enough unacknowledged data in flight to fill the link.
Window scaling. The TCP window field is 16 bits, so any window above 65,535 B needs the window scale option. The planner reports the smallest shift s for which 65,535 × 2s covers the window. RFC 7323 §2.3 limits the shift to 14, so one connection can advertise at most 1,073,725,440 B—just under 1 GiB. The option is exchanged only in SYN segments, and the window in a SYN is never scaled.
Three throughput ceilings
Link: bandwidth × MSS ÷ (MTU + framing). MSS is the MTU minus the IP header (20 B IPv4, 40 B IPv6), the 20 B TCP header, and TCP option bytes. For 100 Mbps Ethernet with a 1460 B MSS, RFC 6349 §4.1.1 gets 94.9 Mbps by counting whole frames per second; this planner uses the continuous ratio, so its figure can differ slightly.
Window: streams × window bytes × 8 ÷ RTT. With a fixed window, streams needed = ⌈BDP ÷ window⌉. For 500 Mbps at 5 ms, RFC 6349 §5.1 lists 5 connections with 64 KB windows.
Loss (optional): streams × (MSS × 8 ÷ RTT) × √(3 ÷ 2b) ÷ √p—the Reno throughput equation in RFC 5348 §3.1 without its retransmission-timeout term. b is segments acknowledged per ACK and p is the loss rate as a fraction.
What the model leaves out
RFC 5348’s p is a loss-event rate. Using packet loss is conservative when several packets are lost in the same congestion event. The equation describes Reno-style congestion control; CUBIC, BBR, and other algorithms can do much better or worse on the same path, so treat the loss ceiling as a sanity check.
All ceilings are steady-state. Connection setup, slow start, receiver CPU, storage speed, encryption, shaper bursts, and competing traffic are not modeled. Transfer time is simply bytes × 8 ÷ ceiling. To estimate a video file before uploading it, use the video bitrate and upload-time solver.
Linux buffer starting point
With receive autotuning enabled (tcp_moderate_rcvbuf, on by default), each socket’s receive buffer can grow no larger than the third tcp_rmem value; the third tcp_wmem value caps tuned send buffers. The generated lines raise those maximums to the per-stream window × your headroom, rounded up to 1 MiB. The first two numbers are the documented defaults (4 K and 131,072 B receive; 4 K and 16 K send). See the kernel IP sysctl documentation.
Buffers hold bookkeeping overhead as well as window data. The fixed-ratio setting tcp_adv_win_scale is documented as obsolete since Linux 6.6, so headroom is left as your planning assumption. An application that sets SO_RCVBUF or SO_SNDBUF disables autotuning for that socket; socket(7) notes that the kernel doubles the requested value and limits it with net.core.rmem_max or wmem_max. Any socket may grow to the maximum, so account for concurrent connections when checking memory, and test on a non-production host first.
Frequently asked questions
Why is my measured throughput lower than the link ceiling?
Common causes are a higher RTT or loss rate than entered, windows that never grew (a small autotuning maximum, or window scaling stripped by a middlebox), a fixed test window, a transfer short enough to spend most of its time in slow start, or a CPU, disk, or encryption bottleneck. Compare the modeled limit with a longer test.
Should I enter ping time or one-way latency?
BDP uses round-trip time, which is what ping reports. If you only have a one-way latency figure, choose “One way” and the planner doubles it. Asymmetric routes can differ in each direction.
Is a bigger window always better?
A window only needs to cover the bottleneck BDP. Past that point, the link, loss, or application sets the limit, and larger buffer maximums just let every socket use more memory.
Does this tool test my connection?
No. It is arithmetic in your browser. It sends no packets, reads no interface or kernel settings, and does not change host configuration.