ocaml-iperf3#
The iperf3 network throughput protocol in
pure OCaml: the control state machine and data-path codecs as I/O-free state
machines (iperf3), plus an Eio client and server (iperf3-eio) that
interoperate with the stock iperf3 binary in both directions.
iperf3 measures throughput between a client and a server. They negotiate over a TCP control connection -- a sequence of single-byte states, a 37-byte cookie, and length-prefixed JSON for parameters and results -- then blast payload over one or more separate data streams, in either or both directions.
Installation#
Install with opam:
$ opam install iperf3
If opam cannot find the package, it may not yet be released in the public
opam-repository. Add the overlay repository, then install it:
$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install iperf3
Layout#
| Package | What |
|---|---|
iperf3 |
Sans-IO core: Cmd, Cookie, Params, Results, Frame, and the Server / Client control state machines. No eio/unix deps; time and randomness are inputs. |
iperf3-eio |
serve / run_client over Eio sockets, and the oiperf3 CLI. |
The binary framing is built on ocaml-wire; the JSON payloads
on nox-json. Frames are read non-draining from a
Bytesrw.Bytes.Reader.t, so successive frames come off one live connection.
CLI#
# server
oiperf3 -s
# client: 10s forward test against a host
oiperf3 -c 10.0.0.2
# reverse (server sends), 4 parallel streams, 5 seconds
oiperf3 -c 10.0.0.2 -R -P 4 -t 5
The server interoperates with a stock iperf3 -c, and the client with a stock
iperf3 -s, both forward and reverse.
Library#
The Eio adapter is a byte shuttle around the core state machines. Time is injected, so the timing policy stays with the caller:
let run_client env =
let net = Eio.Stdenv.net env in
let random = Eio.Stdenv.secure_random env in
let mono = Eio.Stdenv.mono_clock env in
let clock = Eio.Stdenv.clock env in
let now () = Eio.Time.Mono.now mono in
let sleep s = Eio.Time.sleep clock s in
Eio.Switch.run @@ fun sw ->
let params = { Iperf3.Params.default with time = 5 } in
let r =
Iperf3_eio.run_client ~sw ~net ~now ~sleep ~random ~host:"10.0.0.2" params
in
Fmt.pr "received %Ld bytes@." (Iperf3.Results.total_bytes r)
The core has no I/O at all: drive Iperf3.Server / Iperf3.Client with bytes
and time and it returns the bytes to write plus structured events, so the same
machine runs under any I/O model (see test/ for the in-memory roundtrip).
Status#
- TCP data path: implemented, both directions (forward and reverse).
- UDP / SCTP data paths, and bidirectional (
--bidir) tests: not yet implemented; the UDP datagram codec is stubbed and the adapter rejects bidir.
bench/live_iperf3.ml is a live interoperability check against the stock
iperf3 binary (not part of dune test):
dune exec ocaml-iperf3/bench/live_iperf3.exe