The link was full. The call was unusable.
An interactive modern Fortran simulator for the latency hidden behind healthy link utilization. It makes queue sojourn time, buffer occupancy, active queue management, packet loss, ECN feedback, and sender pacing visible—and demonstrates how telemetry.sh can connect network congestion to user-visible latency.
Buffers absorb useful bursts. An oversized unmanaged buffer under sustained overload does something different: it stores congestion as delay. The bottleneck keeps transmitting at line rate, so throughput and utilization look healthy while latency-sensitive traffic waits behind a standing queue.
The model replays one deterministic bottleneck workload through four policies:
| Strategy | Congestion behavior | Constraint |
|---|---|---|
| Oversized DropTail | A deep FIFO fills before tail loss begins | Preserves a full pipe by allowing extreme queue delay |
| Right-sized DropTail | The queue is bounded near twice the base RTT | Limits latency, but loss remains the only feedback signal |
| CoDel-inspired AQM | Persistent sojourn above a target triggers early drops | Controls standing delay without endpoint support |
| ECN-aware pacing | Congestion is marked and the sender reduces its input rate | Requires ECN preservation and a responsive endpoint |
With a 20 Mb/s bottleneck, 28 Mb/s base offered load, 12 Mb/s bursts, a 35 ms base RTT, an 800 ms buffer, and a 100 ms interactive budget, the deterministic default produces:
| Strategy | Link utilization | Queue p99 | Interactive p99 | Loss | Budget violations |
|---|---|---|---|---|---|
| Oversized DropTail | 100.0% | 790 ms | 825 ms | 35.4% | 99.7% |
| Right-sized DropTail | 100.0% | 60 ms | 95 ms | 37.7% | 0.0% |
| CoDel-inspired AQM | 100.0% | 0 ms | 35 ms | 37.9% | 0.0% |
| ECN-aware pacing | 98.1% | 14 ms | 49 ms | 0.0% | 0.0% |
The CoDel-inspired row reports a 0 ms p99 because its brief startup queue occupies less than one percent of 10 ms model ticks; its maximum queue delay is 30 ms. It is a comparative control-loop model, not a byte-for-byte implementation of RFC 8289.
These are analytical results, not a packet-level network benchmark or an implementation conformance test. Use the lab to form a hypothesis, then validate the actual interface, qdisc, transport, and application with telemetry.
Requirements: a Fortran 2018 compiler, Node.js 20+, curl, jq, and make.
make check
make runOpen http://127.0.0.1:8080.
Or use the exact compiler and runtime images:
docker build -t bufferbloat-lab .
docker run --rm -p 8080:8080 bufferbloat-labThe multi-stage image compiles with GCC/GFortran 15.3.0, serves with Node.js
24.18.0 LTS on Debian Trixie slim, and runs as the unprivileged
10001:10001 user.
The browser calls:
curl 'http://127.0.0.1:8080/api/simulate?capacity_mbps=20&buffer_ms=800'Numeric query parameters are normalized to safe model ranges:
capacity_mbpsoffered_load_mbpsburst_mbpsburst_period_msburst_duty_percentbuffer_msbase_rtt_msduration_mslatency_budget_msaqm_target_ms
Print the default result without starting a server:
make jsonMeasure time in the queue beside throughput and application latency:
net.queue.sojourn_ms
net.queue.depth_bytes
net.link.utilization
net.congestion.signal
net.ecn.ce_count
net.packet.drop_count
net.flow.pacing_mbps
net.rtt.observed_ms
Useful investigation sequence:
- Find latency-sensitive operations with observed RTT above their budget.
- Split base path RTT from queue sojourn time.
- Group queue depth and sojourn by interface, qdisc, and traffic class.
- Overlay link utilization, tail drops, AQM drops, and ECN-CE marks.
- Verify that congestion feedback reaches the endpoint and changes pacing.
- Compare user-visible p99 after bounding the queue or enabling AQM.
- Keep burst absorption, steady-state delay, loss, and goodput in the same decision.
Utilization, queue events, transport feedback, and application latency usually live in different telemetry domains. Joining them is the point of this lab.
The Fortran model advances in 10 ms fluid steps and samples the browser timeline every 20 ms. Offered traffic is a steady base rate plus a periodic burst. The bottleneck drains at its configured capacity.
Policy semantics alter only the queue bound or congestion response:
- oversized DropTail uses the configured buffer depth;
- right-sized DropTail bounds the queue to the smaller of the configured depth or twice the base RTT, with a 20 ms floor;
- CoDel-inspired AQM watches persistent delay above the target and removes excess queue with an early-drop signal;
- ECN-aware pacing marks above-target traffic and feeds the signal into a deterministic sender-rate control loop.
Intentional simplifications:
- traffic is a fluid rate, not discrete packets;
- there is one bottleneck and one aggregate queue;
- flows share one deterministic demand profile;
- transport congestion windows, retransmission timers, and ACK behavior are omitted;
- the CoDel-inspired controller is comparative, not RFC-conformant;
- ECN feedback is immediate rather than delayed by a round trip;
- CPU, NIC offload, wireless scheduling, and qdisc implementation cost are excluded.
- RFC 8289: Controlled Delay Active Queue Management
- RFC 8290: Flow Queue CoDel
- RFC 7928: Characterization Guidelines for AQM
- RFC 3168: Explicit Congestion Notification
- GCC release history
- Node.js release schedule
- Modern Fortran 2018 for the deterministic queue model, percentiles, fixtures, and JSON serialization
- Node.js standard library for the HTTP adapter and safe model process boundary
- semantic HTML, modern CSS, vanilla JavaScript, and Canvas 2D
- strict compiler warnings, runtime checks, input normalization, security headers, and deterministic fixtures
- non-root multi-stage image plus model, HTTP, and container CI lanes