A Rust implementation of the Dynamic Link Exchange Protocol (DLEP, RFC 8175), covering both the router and modem sides from a single workspace.
DLEP is an event-driven protocol that lets a router obtain timely link-state and link-quality information from a co-located modem (typically a wireless or radio modem) over a single Layer-2 segment. Discovery happens over UDP multicast; the session itself is a long-lived TCP (or TLS) connection over which the modem reports destinations, advertises and updates per-destination metrics (data rate, latency, link quality, MTU, …) and exchanges heartbeats.
Status: all nine milestones complete. Wire codec, both state machines, TCP + TLS (mutual TLS supported) transport, UDP multicast discovery with GTSM, destinations & metrics, the extension plug-in API, and deployable CLI binaries. See §9 of
doc/architecture.mdfor the milestone log and remaining follow-ups, anddoc/deployment.mdfor deployment.
- Implement both sides of the protocol from a single tree, so end-to-end tests can run on loopback.
- Expose the daemon as a library (
dlep-daemon) so a third party can embed DLEP into their own networking stack without taking the bundled binaries. - Keep wire format and state machines fully tested in isolation (no I/O), so logic bugs are caught without spinning up sockets.
- Provide a stable plug-in API for DLEP extensions (RFC 8175 §13.6 reserves a Private Use range for them).
- Support TLS as a first-class transport, per the RFC's security guidance.
crates/
├── dlep-core wire types, data items, byte-level codec
├── dlep-fsm state machines (no I/O, no tokio)
├── dlep-net transport: UDP multicast, TCP, TLS, framing
├── dlep-ext extension plug-in trait + registry
├── dlep-daemon integration layer + public library API
├── dlep-router router-side daemon binary
└── dlep-modem modem-side daemon binary
The dependency DAG is acyclic; dlep-core is the leaf and has no internal
dependencies. See doc/architecture.md for per-crate
responsibilities and the design rationale.
Requires Rust 1.85 or newer (edition 2024).
cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warningsCI (.github/workflows/ci.yml) runs fmt, clippy -D warnings, and build +
test across the workspace.
Both binaries take a TOML configuration file:
cargo run -p dlep-router -- --config examples/router.toml
cargo run -p dlep-modem -- --config examples/modem.tomlCLI flags shared by both binaries:
| Flag | Purpose |
|---|---|
--config |
Path to the TOML config file. |
--interface |
Override the network interface from config. |
--log-level |
Override RUST_LOG-style level (info, debug, …). |
--no-tls |
Force plain TCP regardless of config. |
A minimal configuration:
[network]
interface = "eth0"
discovery_v4_group = "224.0.0.117"
discovery_v6_group = "ff02::1:7"
discovery_port = 854
tcp_port = 854
use_tls = false
gtsm_enforce = true
[timers]
heartbeat_interval_ms = 60000
discovery_interval_ms = 5000The full schema (network, TLS, timers, plus router/modem-specific keys) is
documented in §6 of doc/architecture.md.
Port 854 is below 1024 and requires
CAP_NET_BIND_SERVICEon Linux (setcap cap_net_bind_service=+epon the binary, orAmbientCapabilities=CAP_NET_BIND_SERVICEin a systemd unit).
use std::sync::Arc;
use dlep_daemon::{RouterDaemon, RouterConfig};
use dlep_ext::DlepExtension;
let daemon = RouterDaemon::builder()
.config(RouterConfig::default())
.register_extension(my_extension as Arc<dyn DlepExtension>)
.with_rustls_client(my_client_tls_config)
.spawn()
.await?;
let mut events = daemon.subscribe(); // broadcast::Receiver<DaemonEvent>
daemon.start_discovery().await?;
while let Ok(event) = events.recv().await {
// react to PeerDiscovered, SessionUp, Destination(...), Metrics(...) …
}
daemon.shutdown().await?;The modem-side API is symmetric, with
add_destination / update_destination / drop_destination /
announce_destination in place of start_discovery / connect_static.
doc/architecture.md— full architecture document: per-crate responsibilities, design decisions, configuration schema, public API shape, testing strategy, milestone status and open questions. Read this before contributing.- RFC 8175 — the protocol specification.
MIT — see LICENSE.