§7.5
Chapter 07 · Transport Parameterization and Negotiation

§7.5Example: Selecting Parameters for a Target Network Profile

RFC 9000

Learning objective. Pull the whole chapter together by selecting a complete, coherent set of transport parameters for three concrete network profiles, reasoning each value from the traffic and the path rather than copying defaults.

A method, not a table of magic numbers #

Every parameter in this chapter answers one of four questions about a connection: how much data may be in flight (flow control, §7.2), how many streams may exist (stream limits, §7.2), how long silence is tolerated (idle timeout, §7.3), and what identity/mobility the connection needs (connection-ID limit and migration, Chapter 10). Selecting a profile means answering those four for the traffic you actually carry:

  1. Estimate the bandwidth-delay product (throughput × RTT). It sets the floor for initial_max_data and any bulk stream's initial_max_stream_data_*.
  2. Estimate concurrency (peak simultaneous streams) for initial_max_streams_bidi.
  3. Decide longevity vs. reclaim (how fast to drop dead peers, and whether NATs force keepalive) for max_idle_timeout.
  4. Multiply the receive limits by expected connection count to check the memory budget, and trim if it doesn't fit.

Three profiles #

Applying that method to three very different deployments gives three coherent parameter sets. The values are illustrative, but the reasoning is the point.

Parameter Long-lived mobile Bulk transfer (data-center) High-fanout edge
Path assumption 50 ms, 20 Mbps, NATs 10 ms, 10 Gbps 30 ms, mixed, millions of conns
BDP (≈) 125 KB 12 MB — (memory-bound)
initial_max_data 3 MB 64 MB 256 KB
initial_max_stream_data_bidi_remote 1 MB 16 MB 128 KB
initial_max_streams_bidi 100 16 100
max_idle_timeout 30 s 60 s 10 s
keepalive ~20 s (under NAT horizon) none none
active_connection_id_limit 4 (migration) 2 (default) 2

Read down each column and the logic is visible. Mobile wants the connection to survive: long-ish idle timeout with keepalive under the ~30 s middlebox horizon (§7.3), and a raised active_connection_id_limit so it can migrate across Wi-Fi/cellular changes without a new handshake (Chapter 10); its windows sit comfortably above a modest BDP. Bulk transfer is throughput-first: windows far above a large BDP so flow control never caps the congestion window (§7.2), but only a handful of streams because the work is a few big transfers, not many small ones. High-fanout edge inverts the priority to memory: per-connection receive limits are deliberately small (worst-case buffering × millions of connections must fit in RAM), the idle timeout is short to reclaim dead peers fast, and autotuning grows the windows only for the connections that prove they need it.

The encoded block #

For the mobile profile, the parameters serialize into the same (ID, Length, Value) triples from §7.1. Here are the load-bearing ones as they appear on the wire:

Remember the direction from §7.1: these are the server's declarations, so initial_max_stream_data_bidi_remote = 1 MB is the ceiling on each client request body, and initial_max_streams_bidi = 100 is how many requests the client may have in flight. The client sends its own mirror-image block governing the server's responses.

Sanity-checking the set #

Before shipping a profile, three quick cross-checks catch most mistakes:

  • Throughput check. Is initial_max_data above the BDP, and is the per-stream limit above the BDP for a single bulk stream? If not, throughput is flow-control-capped no matter the link ([RFC 9000 §4.3]).
  • Memory check. Worst-case buffering ≈ (streams × per-stream limit) + connection limit, per connection. Times your connection count, does it fit? The high-fanout column exists because for some deployments it doesn't.
  • Longevity check. Is the keepalive interval below both the effective idle timeout and the ~30 s middlebox horizon (§7.3)? A long idle timeout without keepalive is a trap — the NAT drops the flow first.
Note

0-RTT constrains this profile choice over time. Because a server accepting 0-RTT must not shrink the receive limits a client remembered (§7.4.1 rule, §7.1), you can raise a profile's limits freely between deployments but lowering them only takes effect for clients that don't resume with 0-RTT; resuming clients keep using the older, larger values until they start a fresh connection. Plan reductions as gradual, not instant.

In practice

editorial Start from your library's defaults, then change only the parameters your profile's reasoning actually touches, and write the reason next to each override. The most common real-world miss is a single number: leaving initial_max_stream_data_ bidi_remote at a small default on a server that receives large uploads, which throttles POST bodies while GETs look perfect and sends everyone hunting in congestion control. Measure against the two failure signatures from §7.2 (throughput plateau → flow control; uploads slow, downloads fast → wrong bidi_remote) and adjust the one parameter, not the whole set.

Takeaways #

Selecting transport parameters is a four-question method (BDP for flow control, concurrency for stream counts, longevity for idle timeout, mobility for connection-ID limit) cross-checked against a memory budget, not a table of magic numbers. The mobile, bulk-transfer, and high-fanout profiles differ precisely because those four answers differ, and each parameter you declare is a limit on your peer. This closes Chapter 7 and the connection-configuration story; the chapter quiz checks the model, and Chapter 8 takes these parameters into the hardest environment for them — high-latency and long-RTT networks.