Files
irtt-rs/docs/INTEROP_COMPARISON.md
T
Nils Andreas Svee 97bd903769
Rust CI / cargo fmt (push) Successful in 17s
Rust CI / cargo clippy (push) Successful in 33s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 23s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Successful in 33s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 1m7s
Rust CI / cargo doc (push) Successful in 27s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Successful in 1m21s
Fuzz Smoke / cargo fuzz smoke (push) Successful in 1m40s
Netem Interop / netem interop (push) Successful in 1m18s
Supply chain / cargo-deny advisories (push) Successful in 18s
Supply chain / actionlint (push) Failing after 4s
Supply chain / cargo-deny bans licenses sources (push) Successful in 17s
Build binaries / Build (arm-musleabi) (push) Successful in 4m58s
Build binaries / Build (aarch64-musl) (push) Successful in 5m6s
Build binaries / Build (arm-musleabihf) (push) Successful in 4m38s
Build binaries / Build (armv7-musleabi) (push) Successful in 4m33s
Build binaries / Build (armv7-musleabihf) (push) Successful in 4m57s
Build binaries / Build (i686-musl) (push) Successful in 5m1s
Build binaries / Build (mips64-muslabi64) (push) Successful in 4m35s
Build binaries / Build (mips-musl) (push) Successful in 4m42s
Build binaries / Build (mips64el-muslabi64) (push) Successful in 4m54s
Build binaries / Build (mipsel-musl) (push) Successful in 4m54s
Build binaries / Build (riscv64gc-musl) (push) Successful in 4m36s
Build binaries / Build (x86_64-musl) (push) Successful in 4m40s
chore: improve documentation and README
2026-10-28 12:17:48 +07:00

178 lines
7.5 KiB
Markdown

# Interop comparison
## Feature comparison
This compares `irtt-rs` with the original [heistp/irtt](https://github.com/heistp/irtt)
release [v0.9.2](https://github.com/heistp/irtt/releases/tag/v0.9.2) (2026-07-17).
The aim is for the two implementations to interoperate, though the interop
tests and verified protocol baseline still use upstream v0.9.1. Both
upstream releases use wire protocol version 1, but v0.9.2 hasn't been run
through this project's interop harness. See [`docs/protocol/`](protocol/)
for the verified protocol baseline.
| Capability | irtt-rs | Upstream IRTT (v0.9.2) |
| --- | --- | --- |
| Wire protocol | Version 1, verified against upstream v0.9.1 | Version 1, unchanged from v0.9.1 |
| Finite probing | Default duration of 10s | Default duration of 1m |
| Continuous probing | `--continuous` or `--duration 0`, with optional per-target reconnection | Streaming mode (`-s`, added in v0.9.2) |
| Statistics in continuous mode | Optional count/min/max/mean/variance per session, with bounded IPDV tracking and no exact medians. Disable with `--no-stats` or omit the `stats` feature | No statistics; raw/event output only to avoid unbounded memory |
| Multiple targets | Labels and staggered/burst pacing in one invocation | One remote address per invocation |
| Terminal UI | Live graph and dashboard through `irtt-tui` | None |
| Output formats | table, csv, tsv, jsonl, with selectable columns | Text summary, JSON (optionally gzip to file), and fixed-field raw output; no CSV/TSV or column selection |
| Replay saved results | Not implemented | `report` subcommand for saved JSON results |
| Benchmarking and clock diagnostics | Not implemented | Benchmarking and timer/clock-diagnostic subcommands |
| Client payload and timing controls | No client-side payload fill or don't-fragment/wait-strategy/timer-algorithm controls | Client-side payload fill and controls for don't-fragment, wait strategy, and timer algorithm |
| Kernel timestamps | Best-effort preference on Linux for its own send/receive endpoint | Not implemented |
| Server listeners | Several listeners in one process, supervised by `ServerSet` | Multiple requested addresses through `ListenAndServe` |
| Server wildcard reply-source selection | Default on Linux/macOS/FreeBSD; other platforms refuse wildcard binds | Opt-in through `--set-src-ip`, with a documented per-packet allocation cost |
| Server default bind | Wildcard addresses for both families, subject to the platform restriction above | Wildcard addresses for both families; no documented platform restriction |
| Server payload fill policy | Honors the session's negotiated request, with a fixed fallback pattern; no options to restrict or override it | Options to restrict or override client fill requests |
| Syslog logging | Not implemented | Supported |
| Bundled service files | None | systemd and OpenRC |
| Client/server library API | Separate, independently versioned Rust crates (`irtt-client`, `irtt-server`) | One Go package exposing both roles |
| Prebuilt release binaries | Published for six target triples | None published; install through `go install` or build manually |
## Black-box testing
`scripts/compare_irtt_clients.py` is a black-box comparison harness for running
upstream `irtt` and `irtt-rs` clients concurrently against the same server. It
captures raw stdout/stderr, upstream JSON, parsed RTT samples, per-case
summaries, and comparison JSON under `target/interop-comparisons` by default.
The harness does not inspect upstream source or tests. It only invokes the
upstream executable.
### Remote or Existing Local Server
Build `irtt-rs` and ensure an upstream `irtt` executable is available:
```sh
cargo build -p irtt-rs --bin irtt-client
go install github.com/heistp/irtt/cmd/irtt@v0.9.1
```
Run the default comparison set:
```sh
python3 scripts/compare_irtt_clients.py --upstream-irtt "$HOME/go/bin/irtt"
```
To compare against a specific target:
```sh
python3 scripts/compare_irtt_clients.py \
--target netperf-eu.bufferbloat.net \
--duration 15s \
--interval 250ms \
--upstream-irtt "$HOME/go/bin/irtt"
```
Remote comparisons are useful for smoke coverage, but Internet paths are noisy
and can make RTT/loss differences hard to interpret.
### Linux Netem Interop
`scripts/run_netem_interop_ci.py` provides deterministic Linux CI coverage using
network namespaces, a veth pair, and `tc netem`. It is intended for GitHub
Actions Ubuntu runners or a Linux host with passwordless `sudo` for `ip` and
`tc`.
The harness creates two namespaces:
- `irtt-client` with `veth-client` at `10.10.0.1/24`
- `irtt-server` with `veth-server` at `10.10.0.2/24`
It runs the upstream server in the server namespace:
```sh
irtt server -b 10.10.0.2:2112 --tstamp=dual
```
Both clients run in the client namespace through the existing comparison
harness:
```sh
sudo ip netns exec irtt-client ...
```
Netem qdiscs are applied on veth egress:
- `veth-client` controls client-to-server delay/loss
- `veth-server` controls server-to-client delay/loss
Cleanup deletes qdiscs, stops the server process, and removes both namespaces in
a `finally` path.
#### Scenarios
The CI harness implements:
| scenario | client-to-server | server-to-client | duration | interval | policy |
| --- | --- | --- | --- | --- | --- |
| `baseline-no-netem` | none | none | `5s` | `100ms` | deterministic |
| `symmetric-20ms` | `delay 20ms` | `delay 20ms` | `5s` | `100ms` | deterministic |
| `symmetric-50ms-jitter` | `delay 50ms 5ms` | `delay 50ms 5ms` | `5s` | `100ms` | jitter |
| `asymmetric-delay` | `delay 40ms` | `delay 10ms` | `5s` | `100ms` | deterministic |
| `packet-loss` | `loss 5%` | `loss 5%` | `10s` | `50ms` | stochastic loss |
Asymmetric one-way delay fields include client/server wall-clock offset. Since
both clients run in the same client namespace against the same server namespace,
relative one-way shape is still useful for diagnostics, but the CI pass/fail
policy is based on RTT and packet behavior.
#### Pass/Fail Policy
Deterministic scenarios fail when:
- either client exits non-zero
- parsed mean RTT or received packet counts are missing
- either client receives no packets
- unexpected loss exceeds `0.5%`
- mean RTT delta exceeds `max(2000us, 5% of expected RTT)`
The jitter scenario fails on crashes, parser failures, no received packets, or
mean RTT delta above `max(8000us, 10% of expected RTT)`.
The packet-loss scenario fails on crashes, parser failures, or no received
packets. Loss-rate deltas above `10%` are warnings because packet loss is
stochastic and exact percentages are not stable enough for CI.
Thresholds can be adjusted with:
```sh
python3 scripts/run_netem_interop_ci.py \
--mean-abs-tolerance-us 3000 \
--mean-pct-tolerance 0.08 \
--jitter-mean-abs-tolerance-us 10000 \
--loss-rate-warning-pct 12
```
#### Manual Linux Usage
On Linux:
```sh
cargo build -p irtt-rs --bin irtt-client
go install github.com/heistp/irtt/cmd/irtt@v0.9.1
python3 scripts/run_netem_interop_ci.py \
--all \
--skip-build \
--upstream-irtt "$HOME/go/bin/irtt" \
--irtt-rs-command "$PWD/target/debug/irtt-client"
```
Run one scenario:
```sh
python3 scripts/run_netem_interop_ci.py --scenario symmetric-20ms
```
Artifacts are written under `target/interop-netem/<timestamp>/` by default. Each
scenario contains the existing comparison harness output under
`<scenario>/comparison/<timestamp>/`, plus netem-specific `summary.md` and
`netem-summary.json` files. Server stdout/stderr are captured at the run root as
`server.stdout` and `server.stderr`.
On macOS, `ip netns` and `tc netem` are unavailable; use the Gitea Actions
workflow for netem coverage.