taap.digitalnetwork engineering toolkit

Bandwidth-delay product and TCP window calculator

Enter link speed and round-trip time to get the bytes in flight needed to fill the pipe. Add your current window and loss rate to see what one TCP flow will actually achieve.

tcp-bdp
ms
KiB
%
B

What the BDP tells you

TCP can only have one window of unacknowledged data in flight. To keep a link busy, the window must cover all the data that fits "in the pipe" during one round trip:

BDP (bytes) = bandwidth (bit/s) × RTT (s) / 8
max throughput per flow = window × 8 / RTT

If the window is smaller than the BDP, the sender idles while waiting for ACKs and throughput drops proportionally, no matter how fast the link is.

Worked example: 1 Gbps, 150 ms RTT

BDP = 109 × 0.150 / 8 = 18,750,000 bytes ≈ 17.9 MiB. With the classic 64 KiB window (no window scaling):

65,536 B × 8 / 0.150 s = 3.50 Mbps  (0.35% of the link)

That is why a transatlantic or Brazil–US transfer can crawl on a gigabit circuit. Paths like this are called long fat networks (LFN).

Window scaling (RFC 7323)

The TCP header window field is 16 bits, so without scaling the maximum is 65,535 bytes. RFC 7323 adds a shift count of up to 14, allowing windows up to about 1 GiB. All modern stacks negotiate it during the handshake, but it fails silently when a middlebox strips the option or when buffers are capped too low. Check the SYN in a capture for wscale.

Packet loss: the Mathis limit

Loss caps throughput even with a perfect window. The Mathis et al. approximation for Reno-style TCP:

throughput ≤ (MSS × 8 / RTT) × (1.22 / √loss)

At 150 ms, MSS 1460 and just 0.1% loss, one flow tops out around 3 Mbps. Modern congestion control (CUBIC, BBR) does better than Reno, but the trend holds: on long paths, tiny loss rates dominate. Enter a loss percentage to see which limit applies; the status line says whether the link, the window or loss is the bottleneck.

Tuning on Linux

Set the maximum buffers to at least the BDP (2× is common so the receiver can keep advertising a full window):

# 1 Gbps × 150 ms → BDP 18.75 MB, use ~40 MB max
sysctl -w net.core.rmem_max=41943040
sysctl -w net.core.wmem_max=41943040
sysctl -w net.ipv4.tcp_rmem="4096 131072 41943040"
sysctl -w net.ipv4.tcp_wmem="4096 65536 41943040"
sysctl -w net.ipv4.tcp_congestion_control=bbr

Windows auto-tunes the receive window by default (netsh int tcp show global, "Receive Window Auto-Tuning Level: normal"). Applications that set a fixed SO_RCVBUF disable auto-tuning and are a frequent cause of slow WAN transfers.

Practical notes

  • Measure RTT with ping under load, not idle; bufferbloat can double it.
  • When tuning is not possible (appliances, closed clients), run parallel flows: N flows give roughly N × window / RTT.
  • Satellite (GEO ≈ 600 ms) and intercontinental links benefit most from BBR and large buffers.

Quick answers

Frequently asked questions

What window do I need for 10 Gbps at 100 ms?

BDP = 1010 × 0.1 / 8 = 125 MB (about 119 MiB). A single flow needs window scaling and buffers of that size or more.

Does the BDP depend on MSS?

No. BDP depends only on bandwidth and RTT. MSS matters for the loss-limited (Mathis) estimate.

Why is my throughput low on a fast link with low loss?

Usually the window: the receiver buffer, an application-set SO_RCVBUF or a middlebox that removed window scaling. Compare the window you see in a capture with the BDP.

Is RTT the same as one-way latency?

No. RTT is the full round trip, roughly twice the one-way delay. Use what ping reports.

Study and design tool. Validate any configuration in a lab and against vendor documentation before applying it in production.