Simple Two-Way Active Measurement Protocol (STAMP) implementation in Rust (RFC 8762, RFC 8972, RFC 9503, and RFC 9534)
stamp-suite is a Rust implementation of the Simple Two-Way Active Measurement Protocol (STAMP) as defined in RFC 8762, RFC 8972, RFC 9503, and RFC 9534. It provides a single binary that can operate as either a Session-Sender (client) or Session-Reflector (server) for measuring packet loss and network delays.
- Full RFC 8762 compliance (unauthenticated and authenticated modes)
- RFC 8972 TLV extension support with full processing for all defined types
- RFC 9503 Segment Routing extensions (Destination Node Address, Return Path with SR-MPLS/SRv6)
- RFC 9534 Micro-session ID TLV for LAG per-member-link measurement
- Class of Service (CoS) TLV support with DSCP/ECN measurement (RFC 8972 §5.2)
- Location, Timestamp Info, Direct Measurement, Access Report, and Follow-Up Telemetry TLVs
- HMAC authentication support
- Stateful reflector mode with per-client session tracking (RFC 8972 Section 4)
- Support for both NTP and PTP timestamp formats
- Real TTL/Hop Limit capture on all platforms
- Optional Prometheus metrics endpoint for observability
- Optional SNMP AgentX sub-agent for MIB-based monitoring (Unix only)
- Backward compatible - works with clients/reflectors without TLV support
- Async I/O using Tokio
- Cross-platform support (Linux, macOS, Windows)
STAMP measures packet loss and one-way/two-way delays between two endpoints. The Session-Sender transmits test packets to the Session-Reflector, which timestamps and reflects them back. By comparing timestamps, you can calculate:
- Round-trip time (RTT)
- One-way delay (requires synchronized clocks via NTP/PTP)
- Packet loss rate
# Default build (real TTL capture on Linux/macOS/Windows)
cargo build --release# Build the package
nix build
# Run directly without installing
nix run . -- --is-reflector
# Enter a development shell with cargo, rustc, rustfmt, and clippy
nix develop| Platform | Default Backend | TTL Capture |
|---|---|---|
| Linux | nix (IP_RECVTTL) | Real TTL, no special privileges |
| macOS | nix (IP_RECVTTL) | Real TTL, no special privileges |
| Windows | pnet (raw packets) | Real TTL, requires Npcap |
| Feature | Description |
|---|---|
ttl-nix |
Force nix backend (Linux/macOS/BSD) |
ttl-pnet |
Force pnet raw socket backend (requires root/admin) |
metrics |
Enable Prometheus metrics endpoint |
snmp |
Enable SNMP AgentX sub-agent (Unix only) |
Start the reflector to listen for incoming STAMP packets:
# Listen on all interfaces, default port 862
stamp-suite -i
# Listen on specific address and port
stamp-suite -i --local-addr 192.168.1.100 --local-port 8620
# With verbose per-packet statistics
stamp-suite -i -R
# Stateful reflector mode (RFC 8972) - maintains independent sequence
# counters per client, allowing detection of reflector-side packet loss
stamp-suite -i --stateful-reflector
# Stateful mode with custom session timeout (default: 300 seconds)
stamp-suite -i --stateful-reflector --session-timeout 600
# TLV handling modes (RFC 8972 extensions)
stamp-suite -i --tlv-mode echo # Echo TLVs back (default, RFC compliant)
stamp-suite -i --tlv-mode ignore # Strip TLVs for backward compatibility
# Reflector member link ID for LAG micro-sessions (RFC 9534)
stamp-suite -i --reflector-member-link-id 2
# Verify TLV HMAC integrity (requires --hmac-key)
stamp-suite -i --verify-tlv-hmac --hmac-key <hex-key>
# With Prometheus metrics endpoint (requires --features metrics)
stamp-suite -i --metrics --metrics-addr 127.0.0.1:9090
# With SNMP AgentX sub-agent (requires --features snmp, Unix only)
stamp-suite -i --snmp
# Custom AgentX socket path
stamp-suite -i --snmp --snmp-socket /var/agentx/masterSend test packets to a reflector:
# Basic usage - send 1000 packets to remote reflector
stamp-suite --remote-addr 192.168.1.100
# Custom settings
stamp-suite --remote-addr 192.168.1.100 \
--remote-port 8620 \
--local-port 8621 \
--count 100 \
--send-delay 100 \
-R
# With Session-Sender Identifier (RFC 8972 TLV extension)
stamp-suite --remote-addr 192.168.1.100 --ssid 12345
# With Class of Service TLV (measure DSCP/ECN handling)
stamp-suite --remote-addr 192.168.1.100 --cos --dscp 46 --ecn 2
# With Location TLV (reflector reports observed src/dst addresses)
stamp-suite --remote-addr 192.168.1.100 --location
# With Direct Measurement TLV (packet loss counters)
stamp-suite --remote-addr 192.168.1.100 --direct-measurement
# With Timestamp Info TLV (clock sync and timestamping method)
stamp-suite --remote-addr 192.168.1.100 --timestamp-info
# With Follow-Up Telemetry TLV (previous reflection data)
stamp-suite --remote-addr 192.168.1.100 --follow-up-telemetry
# With Access Report TLV (access ID 5, return code 1)
stamp-suite --remote-addr 192.168.1.100 --access-report 5
# With Destination Node Address TLV (RFC 9503 - verify reflector identity)
stamp-suite --remote-addr 192.168.1.100 --ssid 1 --dest-node-addr 192.168.1.100
# With Return Path TLV - suppress reply (RFC 9503)
stamp-suite --remote-addr 192.168.1.100 --return-path-cc 0
# With Return Path TLV - alternate reply address (RFC 9503)
stamp-suite --remote-addr 192.168.1.100 --return-address 10.0.0.5
# With Return Path TLV - SR-MPLS label stack (RFC 9503)
stamp-suite --remote-addr 192.168.1.100 --return-sr-mpls-labels 100,200,300
# With Return Path TLV - SRv6 segment list (RFC 9503)
stamp-suite --remote-addr 192.168.1.100 --return-srv6-sids 2001:db8::1,2001:db8::2
# With Micro-session ID TLV for LAG member link measurement (RFC 9534)
stamp-suite --remote-addr 192.168.1.100 --micro-session-id 1
# Combine multiple TLV types
stamp-suite --remote-addr 192.168.1.100 \
--cos --dscp 46 \
--direct-measurement \
--location \
--timestamp-infoOptions:
-r, --remote-addr <REMOTE_ADDR> Remote address for Session Reflector [default: 0.0.0.0]
-S, --local-addr <LOCAL_ADDR> Local address to bind for [default: 0.0.0.0]
-p, --remote-port <REMOTE_PORT> UDP port number for outgoing packets [default: 862]
-o, --local-port <LOCAL_PORT> UDP port number for incoming packets [default: 862]
-K, --clock-source <CLOCK_SOURCE> Clock source to be used [default: NTP]
-d, --send-delay <SEND_DELAY> Delay between packets in milliseconds [default: 1000]
-c, --count <COUNT> Number of packets to send [default: 1000]
-L, --timeout <TIMEOUT> Timeout for lost packets in seconds [default: 5]
-A, --auth-mode <AUTH_MODE> Work mode: A=authenticated, O=open [default: O]
-R Print individual statistics for each packet
-i, --is-reflector Run as Session Reflector instead of Sender
--stateful-reflector Enable stateful reflector mode (RFC 8972 Section 4)
--session-timeout <SECONDS> Session timeout for stateful mode [default: 300]
--tlv-mode <MODE> TLV handling: ignore, echo [default: echo]
--verify-tlv-hmac Verify HMAC TLV in incoming packets
--ssid <ID> Session-Sender Identifier for TLV extension
--cos Enable Class of Service TLV
--dscp <VALUE> DSCP value for CoS TLV (0-63) [default: 0]
--ecn <VALUE> ECN value for CoS TLV (0-3) [default: 0]
--location Enable Location TLV
--timestamp-info Enable Timestamp Information TLV
--direct-measurement Enable Direct Measurement TLV
--follow-up-telemetry Enable Follow-Up Telemetry TLV
--access-report <ID> Enable Access Report TLV with Access ID (0-15)
--access-return-code <CODE> Return code for Access Report TLV [default: 1]
--hmac-key <HEX> HMAC key in hex format
--hmac-key-file <PATH> Path to file containing HMAC key
--dest-node-addr <IP> Destination Node Address TLV (RFC 9503, requires --ssid)
--return-path-cc <CODE> Return Path control code: 0=suppress, 1=same-link (RFC 9503)
--return-address <IP> Return Path alternate reply address (RFC 9503)
--return-sr-mpls-labels <L> Return Path SR-MPLS label stack, comma-separated (RFC 9503)
--return-srv6-sids <SIDS> Return Path SRv6 segment list, comma-separated (RFC 9503)
--micro-session-id <ID> Sender micro-session member link ID for LAG measurement (RFC 9534)
--reflector-member-link-id <ID> Reflector member link ID for LAG micro-sessions (RFC 9534)
--metrics Enable Prometheus metrics endpoint (requires metrics feature)
--metrics-addr <ADDR> Metrics server bind address [default: 127.0.0.1:9090]
--snmp Enable SNMP AgentX sub-agent (requires snmp feature, Unix only)
--snmp-socket <PATH> AgentX master agent socket path [default: /var/agentx/master]
-h, --help Print help
-V, --version Print version
Sender with per-packet statistics (-R):
seq=0 rtt=0.523ms ttl=64 reflector_recv_ts=16890123456789 reflector_send_ts=16890123456790
seq=1 rtt=0.498ms ttl=64 reflector_recv_ts=16890123556789 reflector_send_ts=16890123556790
...
--- STAMP Statistics ---
Packets sent: 100
Packets received: 100
Packets lost: 0 (0.0%)
Min RTT: 0.412 ms
Max RTT: 1.203 ms
Avg RTT: 0.521 ms
┌─────────────────┐ UDP/862 ┌─────────────────┐
│ Session-Sender │ ──────────────────────► │Session-Reflector│
│ (stamp-suite) │ ◄────────────────────── │ (stamp-suite -i)│
└─────────────────┘ Reflected Packets └─────────────────┘
main.rs- Entry point and CLI handlingconfiguration.rs- Command-line argument parsingpackets.rs- STAMP packet structures (RFC 8762 format)sender.rs- Session-Sender implementationreceiver/- Session-Reflector implementationsnix.rs- nix crate with IP_RECVTTL (Linux/macOS)pnet.rs- Raw packet capture (Windows)
session.rs- Session state managementtime.rs- NTP/PTP timestamp generationtlv.rs- TLV extension support (RFC 8972)metrics/- Prometheus metrics (optional, requiresmetricsfeature)sender_metrics.rs- Sender-side metricsreflector_metrics.rs- Reflector-side metrics
snmp/- SNMP AgentX sub-agent (optional, requiressnmpfeature, Unix only)agentx.rs- AgentX protocol implementation (RFC 2741)handler.rs- STAMP-SUITE-MIB handleroids.rs- OID constantsstate.rs- Shared state types
The implementation supports RFC 8972 TLV (Type-Length-Value) extensions, which allow STAMP packets to carry optional data beyond the base packet format.
| Type | Name | Description | Status |
|---|---|---|---|
| 1 | Extra Padding | Can carry Session-Sender ID (SSID) in first 2 bytes | Full |
| 2 | Location | Source/destination addresses and ports (RFC 8972 §4.2) | Full |
| 3 | Timestamp Info | Sync source and timestamping method (RFC 8972 §4.3) | Full |
| 4 | Class of Service | DSCP/ECN measurement (RFC 8972 §5.2) | Full |
| 5 | Direct Measurement | Sender/reflector packet counters (RFC 8972 §4.5) | Full |
| 6 | Access Report | Access identifier and return code (RFC 8972 §4.6) | Full |
| 7 | Follow-Up Telemetry | Previous reflection seq/timestamp (RFC 8972 §4.7) | Full |
| 8 | HMAC | TLV integrity verification (must be last) | Full |
| 9 | Destination Node Address | Verify intended reflector identity (RFC 9503 §4) | Full |
| 10 | Return Path | Control reply routing: suppress, alternate address, SR-MPLS, SRv6 (RFC 9503 §5) | Full |
| 11 | Micro-session ID | LAG member link identifiers for per-link measurement (RFC 9534 §3.1) | Full |
Status: Full = structured parsing, validation, and reflector field population. SR-MPLS/SRv6 forwarding is echoed with U-flag (actual segment routing is out of scope for userspace UDP).
The reflector supports two TLV handling modes via --tlv-mode:
| Mode | Behavior |
|---|---|
echo (default) |
Echo TLVs back to sender, marking unknown types with U-flag |
ignore |
Strip all TLVs from response (backward compatibility) |
The implementation is fully backward compatible:
- No TLVs in packet: Standard RFC 8762 handling is used
- TLVs present: Handled according to
--tlv-modesetting - Old clients: Work seamlessly with TLV-enabled reflectors
- New clients with SSID: Reflectors without TLV support will zero-pad the response
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|STAMP TLV Flags| Type | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Value... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- Flags (1 octet): U=Unrecognized (bit 0), M=Malformed (bit 1), I=Integrity failed (bit 2), Reserved (bits 3-7)
- Type (1 octet): TLV type identifier (0-255)
- Length (2 octets): Length of Value field in bytes
The CoS TLV enables measurement of DSCP and ECN handling across the network path:
# Sender requests DSCP 46 (EF) and ECN 2
stamp-suite --remote-addr 192.168.1.100 --cos --dscp 46 --ecn 2The reflector automatically fills in:
- DSCP2/ECN2: Values received at the reflector's ingress
- RP (Reverse Path): Set to 1 if local policy rejected the requested DSCP
This allows detection of DSCP remarking or ECN modification in the network.
The Location TLV reports the observed source and destination addresses and ports at the reflector:
stamp-suite --remote-addr 192.168.1.100 --locationThe reflector fills in the actual destination IP from the received packet (using IP_PKTINFO/IPV6_RECVPKTINFO on nix, or parsed IP headers on pnet), so it reports the correct address even when bound to a wildcard (0.0.0.0/::). Address information is carried as sub-TLVs (IPv4 or IPv6 source/destination).
The Direct Measurement TLV carries per-session packet counters for loss measurement:
stamp-suite --remote-addr 192.168.1.100 --direct-measurement- Sender fills its transmit count (incremented per packet)
- Reflector fills its receive and transmit counts for the client's session
Counters are tracked per-client regardless of whether --stateful-reflector is enabled.
The Follow-Up Telemetry TLV carries information about the previously reflected packet:
stamp-suite --remote-addr 192.168.1.100 --follow-up-telemetryThe reflector fills in the sequence number and timestamp from the last reflection for the client's session, along with its timestamping method. Like Direct Measurement, this works independently of --stateful-reflector.
The Timestamp Info TLV reports the synchronization source and timestamping method at each endpoint:
stamp-suite --remote-addr 192.168.1.100 --timestamp-infoThe sender fills its own sync source and method; the reflector fills in its values (e.g., NTP + software-local timestamping).
The Access Report TLV carries an access identifier and return code. The reflector echoes it unchanged:
stamp-suite --remote-addr 192.168.1.100 --access-report 5 --access-return-code 1The Destination Node Address TLV lets the sender specify the intended reflector address. The reflector checks whether the address matches any of its local interfaces:
# Verify that 192.168.1.100 is handling the reflection (requires --ssid)
stamp-suite --remote-addr 192.168.1.100 --ssid 1 --dest-node-addr 192.168.1.100If the address does not match, the reflector sets the U-flag on the TLV and still reflects the packet, allowing the sender to detect misrouting (e.g., anycast failover).
The Return Path TLV controls how the reflector routes its reply. Several sub-TLV types are supported:
# Suppress reply entirely (control code 0)
stamp-suite --remote-addr 192.168.1.100 --return-path-cc 0
# Request reply to an alternate address
stamp-suite --remote-addr 192.168.1.100 --return-address 10.0.0.5
# Request SR-MPLS return path (echoed with U-flag in userspace)
stamp-suite --remote-addr 192.168.1.100 --return-sr-mpls-labels 100,200,300
# Request SRv6 return path (echoed with U-flag in userspace)
stamp-suite --remote-addr 192.168.1.100 --return-srv6-sids 2001:db8::1,2001:db8::2The reflector handles each sub-TLV type:
- Control Code: Bit 0 controls reply behavior (0=suppress, 1=reply); reserved bits are ignored per RFC 9503
- Return Address: Reflector sends the reply to the specified IP. On send failure, it sets the U-flag and falls back to the original source address
- SR-MPLS / SRv6: Echoed with U-flag set (actual segment routing forwarding is out of scope for userspace UDP)
The Micro-session ID TLV enables per-member-link performance measurement within Link Aggregation Groups (LAGs). Each member link is identified by a 16-bit ID on both sender and reflector sides:
# Sender: identify this member link as ID 1
stamp-suite --remote-addr 192.168.1.100 --micro-session-id 1
# Reflector: identify this member link as ID 2
stamp-suite -i --reflector-member-link-id 2The sender sets its member link ID in outgoing packets. The reflector validates any non-zero reflector ID in the received TLV (discards on mismatch), echoes the sender ID unchanged, and fills in its own member link ID.
When built with --features metrics, the reflector can expose Prometheus metrics:
cargo build --release --features metrics
stamp-suite -i --metrics --metrics-addr 127.0.0.1:9090Available metrics include:
stamp_reflector_packets_received_total- Total packets receivedstamp_reflector_packets_reflected_total- Total packets reflectedstamp_reflector_packets_dropped_total- Dropped packets by reasonstamp_reflector_active_sessions- Current active sessions (stateful mode)stamp_reflector_hmac_failures_total- HMAC verification failuresstamp_reflector_processing_seconds- Packet processing time histogram
When built with --features snmp (Unix only), stamp-suite can connect to an existing net-snmpd master agent via the AgentX protocol (RFC 2741) and expose reflector/sender state through a custom STAMP-SUITE-MIB.
cargo build --release --features snmp
# Reflector with SNMP
stamp-suite -i --snmp
# Custom AgentX socket path
stamp-suite -i --snmp --snmp-socket /var/agentx/master
# Query via net-snmp tools
snmpwalk -v2c -c public localhost .1.3.6.1.4.1.65134The MIB (provided in mibs/STAMP-SUITE-MIB.mib) exposes:
| Subtree | Contents |
|---|---|
| Reflector Config | Admin status, listen address/port, auth mode, TLV mode, stateful flag, session timeout |
| Reflector Stats | Packets received/reflected/dropped, active sessions, uptime |
| Session Table | Per-client address, port, packet counts, last sequence number, last active time |
| Sender Config | Remote address/port, local port, packet count, send delay, auth mode |
| Sender Stats | Packets sent/received/lost, RTT min/max/avg, jitter, loss percentage |
Sender statistics are updated live during the measurement run (not just at completion), so SNMP polling reflects current progress.
Note: The snmp feature requires a Unix platform (Linux/macOS) because AgentX uses Unix domain sockets. On non-Unix platforms, --snmp prints an error and exits.
The project is functional for STAMP measurements with the following features:
- Full RFC 8762 compliance (unauthenticated and authenticated modes)
- Full RFC 8972 TLV extension support (all 8 defined TLV types)
- RFC 9503 Segment Routing extensions (Destination Node Address and Return Path TLVs)
- RFC 9534 Micro-session ID TLV for LAG per-member-link measurement
- HMAC authentication support (base packet and TLV integrity)
- Class of Service TLV with DSCP/ECN measurement (RFC 8972 §5.2)
- Location TLV with real destination address capture (even on wildcard binds)
- Direct Measurement TLV with per-client packet counters
- Timestamp Information TLV with sync source and method reporting
- Follow-Up Telemetry TLV with previous reflection tracking
- Access Report TLV with structured validation
- Destination Node Address TLV with local address matching (RFC 9503 §4)
- Return Path TLV with suppress, alternate address, and SR echo support (RFC 9503 §5)
- Stateful reflector mode with per-client session tracking (RFC 8972 Section 4)
- Session-Sender Identifier (SSID) support via Extra Padding TLV
- Real TTL capture on all major platforms
- Optional Prometheus metrics for observability (requires
metricsfeature) - Optional SNMP AgentX sub-agent with STAMP-SUITE-MIB (requires
snmpfeature, Unix only) - Backward compatible with non-TLV implementations
- Enhanced statistics and reporting
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please ensure:
- Code passes
cargo clippy --all --all-features --tests -- -D warnings - Code is formatted with
cargo fmt - Tests are updated as appropriate
This project uses SemVer for versioning. See the tags for available versions.
- Piotr Olszewski - Original work - asmie
See the list of contributors who participated in this project.
This project is licensed under the MIT License - see the LICENSE file for details.
- RFC 8762 - Simple Two-Way Active Measurement Protocol
- RFC 8972 - Simple Two-Way Active Measurement Protocol Optional Extensions
- RFC 9503 - Simple Two-Way Active Measurement Protocol Extensions for Segment Routing Networks
- RFC 9534 - Simple Two-Way Active Measurement Protocol Extensions for Performance Measurement on a Link Aggregation Group