UDP loss figures incorrect and self-inconsistent against pre-3.13 peers (omitted_* substitution)
- Dominant language
- C
- Stars
- 8.8k
- Forks
- 1.5k
- PR merge metrics
- No merged PRs in 30d
Description
### Context
When the peer is an older iperf3 that does not exchange the `omitted_errors`/`omitted_packets` stream keys (≤3.12 — the keys and the backward-compat acceptance were added later), `iperf_get_results` substitutes omit baselines locally (`src/iperf_api.c`, the `j_omitted_packets == NULL` arms around lines 2914–2950 in 3.21 @ d39cf415). The substituted values make the rendered UDP loss figures incorrect and self-inconsistent in three ways, all reproducible with a stock 3.21 client against a stock 3.12 server on loopback.
Repro (loss forced via a small receive window):
```
# 3.12 server
iperf-3.12/src/iperf3 -s -1
# 3.21 client, three variants
iperf-3.21/src/iperf3 -c 127.0.0.1 -u -b 2G -l 1200 -w 8K -t 2 -J # (a)
iperf-3.21/src/iperf3 -c 127.0.0.1 -u -b 2G -l 1200 -w 8K -t 2 -O 1 -J # (b)
iperf-3.21/src/iperf3 -c 127.0.0.1 -u -b 2G -l 1200 -w 8K -t 2 -R -J # (c)
```
### Symptom 1 — real loss reported as zero (no `-O`)
In case (a) the client renders `lost_packets: 0` / `lost_percent: 0` (observed: `0/417713`) despite heavy real loss (the same setup with `-O 1` or `-R` shows hundreds to thousands of lost packets). Cause: the sender arm's else-branch assigns `sp->omitted_cnt_error = sp->cnt_error;` when there is no omit window, so the render sites' `cnt_error - omitted_cnt_error` nets the entire count away. Since the old peer's exchanged counts are gross and there is no omit window, the correct baseline here is 0.
### Symptom 2 — the same document disagrees with itself by one (`-O`)
In case (b) the stream object and the sum object differ by exactly 1 (observed: stream `lost_packets: 2852`, sum `lost_packets: 2851`). Cause: with an omit window, the sender arm stores the `-1` "unknown" sentinel in `omitted_cnt_error`; the per-stream render subtracts it unconditionally (`cnt_error - (-1)` = count+1, ~line 4312) while the sum accumulation skips it (`if (sp->omitted_cnt_error > -1)`, lines 4246–4248).
### Symptom 3 — `lost_percent: 0` beside a nonzero `lost_packets` (`-R`)
In case (c) the client's stream object renders e.g. `lost_packets: 643, packets: 417573, lost_percent: 0` while the sum shows the true percentage (0.154). Cause: the receiver arm assigns `sp->peer_omitted_packet_count = sp->peer_packet_count;` (everything omitted), and the stream `lost_percent` denominator uses `sender_packet_count - sender_omitted_packet_count` (= 0, lines 4288–4292) even though the adjacent `packets` field is computed with a different subtraction and stays nonzero.
### Suggested direction
For the no-omit case the baselines should be 0 (the exchanged gross counts are already the net figures). With `-O`, the sender side's own omitted-sent count is a usable estimate for the peer's omitted packets (the code already does this), the receiver side's own omitted-received count is a better estimate than all-omitted, and the error split is genuinely unknown — but the sentinel should not leak into the subtraction on one surface while being skipped on another.
Found while validating [riperf3](https://github.com/therealevanhenry/riperf3)'s output compatibility against 3.21/3.12 pairs; happy to provide the full JSON captures.
Contributor guide
Research direction
Start in src/iperf_api.c at the j_omitted_packets == NULL branches around lines 2914–2950, then inspect the sum and stream rendering near lines 4246–4312. Reproduce the three UDP cases against 3.12 and 3.21 peers using the commands in the issue. Done means no-omit loss is nonzero when loss occurs, stream and sum lost_packets agree, and reverse-mode lost_percent matches the nonzero sum percentage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100