RFC-compliant network performance testing — reflector, traffic generator, and certifier in one binary.
The Stem is a network performance testing tool from Mustard Seed Networks. It packages a high-performance reflector and a full suite of RFC-compliant testing modules into a single Go binary with a CLI and a React web UI.
Run it as a service-level loopback target, generate traffic against another endpoint, or drive a full RFC 2544 / Y.1564 certification suite — all from the same install.
- High-performance packet reflection on AF_PACKET or AF_XDP
- Signature detection for NetAlly, RFC 2544/Y.1564 testers, MSN
- Profile presets: NetAlly, MSN, All, Custom
- Filter by signature, OUI, or UDP/TCP port
| Module | Standard | Test Types |
|---|---|---|
| Benchmark | RFC 2544 | throughput, latency, frame loss, back-to-back |
| ServiceTest | ITU-T Y.1564, MEF 48/49 | config + performance test, full service test |
| TrafficGen | custom | scriptable stream generation |
| Measure | ITU-T Y.1731 | delay, loss, synthetic loss measurement, loopback (OAM) |
| Certify | RFC 2889 / RFC 6349 / IEEE 802.1Qbv | LAN switch certification, TCP throughput, TSN gate-timing |
- CLI — scriptable
stem <cmd>for CI integration - Web UI — React/TypeScript control plane on port 8444, HTTPS only (there is no plaintext listener and no HTTP redirector)
- REST + SSE —
/api/v1/eventsstreams live test results
# Install (Linux/macOS, requires Go 1.27+)
git clone https://github.com/MustardSeedNetworks/stem
cd stem
make build
# The daemon runs every test and the reflector; `stem reflect` and
# `stem test` are clients of it, so start it first (HTTPS by default).
sudo ./bin/stem web -p 8444 &
# → open https://localhost:8444 (self-signed cert)
# → run `sudo ./bin/stem install-ca` once to trust the cert system-wide
# Run as a reflector on eth0
sudo ./bin/stem reflect -i eth0
# Run a throughput test against a host running `stem reflect`
# (test type names are exact — see `stem list-tests`)
sudo ./bin/stem test -t rfc2544_throughput -i eth0
# → the web UI shows this run, with the same run ID the CLI printed
# List every test type, grouped by module
./bin/stem list-tests| Command | Purpose |
|---|---|
stem version |
Show version + build metadata |
stem reflect -i <iface> |
Start the reflector in the running daemon |
stem test -t <type> -i <iface> |
Run one or more tests (comma-separated) in the running daemon |
stem web -p <port> |
Start the web UI + REST API |
stem license --status |
Show license tier + activation state |
stem list-tests |
Catalogue all supported tests, grouped by module |
stem help modules |
Module + test type reference |
Run stem <cmd> --help for flags. End-to-end workflows, safety limits and
result interpretation: docs/PERFORMANCE_TESTING.md.
ui/src/ → React/TypeScript control plane (Vite)
↓ npm run build
internal/api/ui/ → Built assets (embedded via go:embed)
↓
cmd/stem/ → CLI entry point
internal/
├── services/ → Test module implementations
│ ├── reflector/
│ ├── benchmark/ (RFC 2544)
│ ├── servicetest/(Y.1564, MEF)
│ ├── trafficgen/
│ ├── measure/ (Y.1731)
│ ├── certify/ (RFC 2889/6349, TSN)
│ └── orchestrator/ test execution + lifecycle
├── api/ → HTTP/SSE handlers + WebUI embed
├── auth/ → JWT authentication
├── license/ → Tiered licensing
├── netif/ → Interface discovery
├── reflector/ → Reflector kernel-bypass plumbing
└── version/ → Build metadata (injected via ldflags)
src/dataplane/ → C dataplane (C23, Linux-only): AF_XDP / AF_PACKET
include/ → C headers
Only the Linux amd64 .deb/.rpm build links the C dataplane
(CGO_ENABLED=1, .goreleaser.yml). The Linux tarballs, Linux arm64, macOS
and Windows builds are portable CGO_ENABLED=0 binaries with no dataplane:
they serve the web UI and the API, but the reflector and every test refuse to
start with CGO dataplane not available on this platform. Ask the running
daemon rather than guessing — GET /api/v1/capabilities reports it, and the
UI gates on that answer.
Two tiers, plus a 14-day trial of the paid one.
| Tier | Price | What it unlocks |
|---|---|---|
| Free (Reflector) | free | Reflector only — the host serves as a test endpoint for another Stem or a hardware tester |
| Pro | $1,999/yr | Reflector plus RFC 2544, Y.1564, Y.1731, RFC 2889, RFC 6349, MEF, TSN and custom traffic streams |
| Trial | free, 14 days | Pro features, no key required |
Every entry in that Pro column is a feature name the binary enforces, and docs/EDITIONS.md maps each one to the code that gates it. The web UI and the REST API it runs on are how Stem is operated at every tier, including Free — neither is sold separately.
Licenses are Ed25519-signed tokens (MSN1.<payload>.<signature>, see
ADR-0007) verified entirely
offline — there is no phone-home — and bound to three devices by default via a
hardware fingerprint. The binary embeds only the public key, so a Stem build
cannot mint a license.
Start a trial from the web UI (Settings → License → Start Trial), or:
stem license --trialstem license --status prints the tier, trial days remaining, device ID and
enabled features; --activate <token> activates a key and --deactivate
releases the device.
| Command | Purpose |
|---|---|
make build |
Full build (frontend + Go backend; C dataplane on Linux) |
make test |
Go tests + frontend Vitest (run npm ci in ui/ first) |
make lint |
golangci-lint + Biome + clang-tidy + cppcheck |
make lint-go |
Go only |
make lint-c |
C only (Linux) |
make fmt |
Format all (Go + TS + C) |
make quick |
Backend-only dev iteration (do not ship) |
Packaging has no make target: .deb, .rpm, macOS .pkg and Windows
.zip are produced only by GoReleaser in .github/workflows/release.yml.
Verified versions: Go 1.27.0, Node.js 26.8.1, golangci-lint v2.13.2.
| Endpoint | Method | Purpose |
|---|---|---|
/__version |
GET | Build metadata (no auth) |
/api/v1/health |
GET | Server liveness |
/api/v1/capabilities |
GET | Platform capabilities (is a dataplane present) |
/api/v1/interfaces |
GET | List network interfaces |
/api/v1/modules |
GET | List test modules |
/api/v1/modules/{name} |
GET | Module details + supported test types |
/api/v1/test/start |
POST | Start a run plan |
/api/v1/test/stop |
POST | Stop the running test |
/api/v1/test/result |
GET | Latest result |
/api/v1/stats |
GET | Live run status |
/api/v1/events |
GET (SSE) | Live test events |
/api/v1/auth/login |
POST | Issue JWT |
/api/v1/license |
GET | License status |
/api/v1/license/activate |
POST | Activate a license key |
/api/v1/license/trial |
POST | Start trial |
/api/v1/reflector/config |
GET / POST | Reflector configuration |
/api/v1/reflector/stats |
GET | Reflector counters |
Every API route is under /api/v1/; /__version, /health/live,
/health/ready and /__capabilities are unversioned introspection endpoints
registered outside the capability registry. Test execution, settings, mode,
interfaces and the reflector routes require a JWT issued by
/api/v1/auth/login. First-run setup, password recovery and the license
routes are deliberately pre-session (there is no account yet); internal/api/server.go
carries the reason per route and scripts/check-route-policy.sh fails the
build if a route bypasses that policy.
Conventional commits drive release-please.
Release tags trigger release.yml which cross-builds binaries
(Linux amd64/arm64, macOS arm64 — Intel was dropped fleet-wide 2026-06-08 —
and Windows amd64/arm64), .deb, .rpm, macOS .pkg, and Windows
.zip — all signed via cosign keyless OIDC and shipped with SLSA-3
provenance + Syft SBOM.
Business Source License 1.1. The Stem converts to Apache-2.0 on the change date stated in the LICENSE file.
See SECURITY.md for the vulnerability-disclosure policy.
See CONTRIBUTING.md.
The Stem is the performance-testing tool. Two sibling projects round out the Mustard Seed Networks toolkit: