fix(client): use kernel transmit time for upstream OWD #105

Merged
Lochnair merged 1 commits from fix/client-kernel-tx-owd into main 2026-08-15 12:01:14 +00:00
Lochnair commented 2026-08-15 11:55:24 +00:00 (Migrated from github.com)

Summary

  • upstream one-way delay now prefers the correlated Linux TX_SOFTWARE wall
    timestamp when it is locally plausible;
  • userspace sent_at.wall remains the fallback;
  • normal and measurable late replies use the same policy;
  • RTT, downstream OWD, IPDV, timeout and scheduling semantics are unchanged.

Measurement semantics

Before:

upstream OWD =
    server receive wall
    -
    client userspace pre-send wall

After when valid:

upstream OWD =
    server receive wall
    -
    client kernel TX_SOFTWARE wall

Fallback: the existing userspace equation.

TX_SOFTWARE is still a software timestamp near the driver/qdisc handoff, not physical NIC hardware departure.

Plausibility

Kernel TX is accepted only when:

sent_at.wall <= kernel_tx_timestamp <= reply_received_at.wall
  • same-client clock ordering only (never compared against the remote server's wall clock);
  • inclusive bounds;
  • no arbitrary one-second limit — legitimate send-to-reply time can exceed a second, unlike kernel RX scheduling delay;
  • failed plausibility falls back to sent_at.wall rather than failing the probe; the raw observation on PendingProbe is never erased or mutated.

Non-regression

Explicitly unchanged:

  • RTT (raw/adjusted/effective);
  • downstream OWD (server_to_client, still governed solely by the existing kernel-RX selection);
  • IPDV;
  • timeout/loss behavior;
  • server timing;
  • socket timestamp configuration, MSG_ERRQUEUE parsing, drains, automatic-ID correlation (all from #104, untouched here).

Late replies

  • a measurable late reply (probe still retained in TimedOutMap) applies the identical preferred-send-wall policy using its retained kernel_tx_timestamp;
  • an untracked late reply has no retained probe and stays unmeasurable — nothing is synthesized;
  • a kernel timestamp that arrives after a reply has already been processed is simply never observed by that reply (no waiting, no revision, no follow-up event).

Scope

No:

  • F-04 userspace send timestamp movement;
  • public kernel TX provenance field;
  • socket/correlation redesign;
  • hardware timestamping;
  • server change;
  • stats special handling;
  • public API change (ClientTimestamp, PacketMeta, ClientEvent, OneWayDelaySample, RttSample, IpdvSample, ServerTiming all unchanged).

Tests

  • preferred_send_wall plausibility unit tests (no timestamp, strictly between, equal to each bound, earlier than sent_at, later than received_at, extreme values without panicking);
  • exact deterministic upstream OWD improvement (20ms fallback -> 15ms with kernel TX, using 1000/1005/1020/1040 ms endpoints);
  • fallback cases: no kernel TX, too early, too late;
  • normal reply, measurable late reply, untracked late reply;
  • server midpoint timestamp;
  • send-only server timestamp layout still yields no upstream OWD;
  • RTT / downstream OWD non-regression (kernel_tx_timestamp_changes_only_upstream_one_way_delay, replacing the prior #104 "presence does not change OWD" pin now that it has exactly one consumer).

Verification

  • cargo test -p irtt-client --all-features --locked
  • cargo test -p irtt-stats --all-features --locked
  • cargo test -p irtt-cli --all-features --locked
  • cargo fmt --all -- --check
  • cargo check --workspace --all-targets --all-features --locked
  • cargo test --workspace --all-targets --all-features --locked
  • cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
  • RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --locked
  • cargo check -p irtt-cli --no-default-features --features client|tui|server --all-targets --locked
  • git diff --check
  • cross-target cargo check -p irtt-client --target <T> for x86_64-unknown-linux-gnu, aarch64-unknown-linux-musl, x86_64-unknown-freebsd, x86_64-pc-windows-gnu, i686-unknown-linux-gnu

All passed.

## Summary - upstream one-way delay now prefers the correlated Linux TX_SOFTWARE wall timestamp when it is locally plausible; - userspace `sent_at.wall` remains the fallback; - normal and measurable late replies use the same policy; - RTT, downstream OWD, IPDV, timeout and scheduling semantics are unchanged. ## Measurement semantics Before: upstream OWD = server receive wall - client userspace pre-send wall After when valid: upstream OWD = server receive wall - client kernel TX_SOFTWARE wall Fallback: the existing userspace equation. `TX_SOFTWARE` is still a software timestamp near the driver/qdisc handoff, not physical NIC hardware departure. ## Plausibility Kernel TX is accepted only when: sent_at.wall <= kernel_tx_timestamp <= reply_received_at.wall - same-client clock ordering only (never compared against the remote server's wall clock); - inclusive bounds; - no arbitrary one-second limit — legitimate send-to-reply time can exceed a second, unlike kernel RX scheduling delay; - failed plausibility falls back to `sent_at.wall` rather than failing the probe; the raw observation on `PendingProbe` is never erased or mutated. ## Non-regression Explicitly unchanged: - RTT (raw/adjusted/effective); - downstream OWD (`server_to_client`, still governed solely by the existing kernel-RX selection); - IPDV; - timeout/loss behavior; - server timing; - socket timestamp configuration, MSG_ERRQUEUE parsing, drains, automatic-ID correlation (all from #104, untouched here). ## Late replies - a measurable late reply (probe still retained in `TimedOutMap`) applies the identical preferred-send-wall policy using its retained `kernel_tx_timestamp`; - an untracked late reply has no retained probe and stays unmeasurable — nothing is synthesized; - a kernel timestamp that arrives after a reply has already been processed is simply never observed by that reply (no waiting, no revision, no follow-up event). ## Scope No: - F-04 userspace send timestamp movement; - public kernel TX provenance field; - socket/correlation redesign; - hardware timestamping; - server change; - stats special handling; - public API change (`ClientTimestamp`, `PacketMeta`, `ClientEvent`, `OneWayDelaySample`, `RttSample`, `IpdvSample`, `ServerTiming` all unchanged). ## Tests - `preferred_send_wall` plausibility unit tests (no timestamp, strictly between, equal to each bound, earlier than sent_at, later than received_at, extreme values without panicking); - exact deterministic upstream OWD improvement (20ms fallback -> 15ms with kernel TX, using 1000/1005/1020/1040 ms endpoints); - fallback cases: no kernel TX, too early, too late; - normal reply, measurable late reply, untracked late reply; - server midpoint timestamp; - send-only server timestamp layout still yields no upstream OWD; - RTT / downstream OWD non-regression (`kernel_tx_timestamp_changes_only_upstream_one_way_delay`, replacing the prior #104 "presence does not change OWD" pin now that it has exactly one consumer). ## Verification - `cargo test -p irtt-client --all-features --locked` - `cargo test -p irtt-stats --all-features --locked` - `cargo test -p irtt-cli --all-features --locked` - `cargo fmt --all -- --check` - `cargo check --workspace --all-targets --all-features --locked` - `cargo test --workspace --all-targets --all-features --locked` - `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings` - `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --locked` - `cargo check -p irtt-cli --no-default-features --features client|tui|server --all-targets --locked` - `git diff --check` - cross-target `cargo check -p irtt-client --target <T>` for x86_64-unknown-linux-gnu, aarch64-unknown-linux-musl, x86_64-unknown-freebsd, x86_64-pc-windows-gnu, i686-unknown-linux-gnu All passed.
Sign in to join this conversation.