Built on Rust's Async Ecosystem
A deep dive into the technology stack, operating modes, request lifecycle, and the lock-free configuration snapshot model that keeps reloads off the request path.
Core Dependencies
Every dependency was chosen for performance, correctness, and Rust-native design.
Multi-threaded async runtime. Work-stealing scheduler maximizes CPU utilization across all cores.
Production-grade HTTP/1.1 and HTTP/2 implementation. Powers most of Rust's web ecosystem.
Rust TLS protocol implementation. The default crypto provider is ring; the optional FIPS build uses AWS-LC. DTLS uses dimpl. Native dependencies remain in the full gateway build.
gRPC over HTTP/2. Used for both gRPC proxying and the CP→DP control channel.
IETF QUIC and HTTP/3 over UDP. 0-RTT connection establishment for repeat clients.
Compile-time checked SQL queries. Async connection pooling for PostgreSQL, MySQL, and SQLite.
Zero-copy deserialization of config, plugin configs, and API payloads. JSON and YAML support.
Structured, contextual logging with per-request spans. OpenTelemetry-compatible.
Atomic reference-counted pointer swaps. Config reads are wait-free. Updates are atomic. The key to zero-downtime reloads.
Sharded concurrent hash maps. Each shard has its own read-write lock, so lookups are O(1) average with no global lock, but they are not lock-free. Used for the route lookup cache, consumers, and rate limiters.
High-performance allocator on Linux and macOS. Better multi-threaded allocation performance vs. system malloc.
Eight Operating Modes
One binary, selected via FERRUM_MODE. Every topology below is the same executable.
:8000 / :8443
PG / MySQL / SQLite / Mongo
:8000 / :9000
:9000 / :50051
:8000 / :8443
:8000 / :8443
:8000 / :8443
MeshSubscribe / xDS ADS
sidecar / waypoint / gateway
one per node
FERRUM_MODE=migrate
Six Mesh Topologies
Mesh mode adapts to the topology each workload needs — all from the same binary and config model.
Sidecar
Per-pod proxy handling inbound mTLS (port 15006) and outbound capture (15001). The classic mesh pattern with the strongest per-workload isolation.
Ambient
Sidecar-less mesh using HBONE (HTTP/2 CONNECT over mTLS, port 15008) with node-level eBPF capture — mesh security without touching pod specs.
Node Waypoint (Experimental)
Per-node Layer 7 policy point for ambient workloads, resolving per-pod identity from node-agent eBPF socket records.
Service Waypoint
Service-scoped waypoint for Istio GAMMA traffic — attach L7 policy to a service without a proxy in every pod.
East-West Gateway
SNI-routed passthrough (port 15443) connecting clusters. Cross-cluster SPIFFE identity validation and trust bundle federation.
Egress Gateway
Controlled exit point for external traffic, materialized from ServiceEntry resources with identity baggage stripped at the boundary.
Request Lifecycle
Connection Accept
tokio accepts the TCP/UDP connection on the configured port. TLS handshake (rustls) if applicable. Protocol detection via ALPN for HTTP/1.1 vs HTTP/2.
Config Load (Lock-Free)
Atomic ArcSwap load. O(1), no blocking. Returns Arc pointer to current config. All concurrent requests share the same config Arc without copying.
Route Matching
Repeated (host, path) pairs are served from a bounded DashMap cache: O(1) average, one per-shard read lock. On a cache miss the route table, an ArcSwap snapshot rebuilt off the hot path whenever config changes, is searched by host tier (exact host map, then a short scan of wildcard-host patterns, then catch-all) and within a tier by exact path (O(1)), then longest prefix through an indexed walk of the path's segments (O(path depth), independent of route count), then regex routes in a single RegexSet pass. Misses are cached as well, including negative results, so a 404 for an unknown path is O(1) on repeat.
Plugin Chain Execution
Plugins execute in priority order: IP restriction → authentication → authorization → transformation → before_proxy. Any plugin can short-circuit by returning a response directly.
Upstream Selection
Load balancing algorithm selects a healthy upstream from the pool. Health state checked via atomic bool. Connection acquired from per-host pool.
Proxy & Response
Request forwarded via hyper to upstream. Response streamed back through after_proxy plugin hooks. Response body buffered only if a plugin requires it (opt-in).
Logging Phase
log() hook called on all plugins. Async, non-blocking. Access logs, metrics, traces emitted. Arc to config dropped — if config was swapped, old version is freed here.
Atomic Config Swap
Data Structure Complexity Table
| Operation | Structure | Read | Write | Notes |
|---|---|---|---|---|
| Config access | ArcSwap | O(1) atomic | O(1) atomic swap | Wait-free reads |
| Route lookup (cache hit) | DashMap cache, prefix and regex partitions | O(1) average | O(1) shard-lock on miss insert | Bounded per partition; negative results cached; per-shard read lock, not lock-free; CPU-scaled shard counts (≥64) |
| Route lookup (cache miss) | ArcSwap route table: HashMap indexes + RegexSet | O(path depth) prefix; O(path length) regex | Rebuilt off the hot path on config change | Exact host and exact path are O(1); wildcard-host patterns are scanned linearly (typically few) |
| Consumer lookup | DashMap | O(1) | O(1) shard-lock | By API key or consumer ID |
| Rate limit check | DashMap + AtomicU64 | O(1) | O(1) CAS | Lock-free token bucket |
| Health state | AtomicBool per target | O(1) atomic | O(1) atomic | Per upstream target |
| Plugin lookup | DashMap | O(1) | Build-time only | Plugins registered once at startup |
| Load balancing (RR) | AtomicUsize | O(1) | O(1) fetch_add | Atomic counter mod N |
| Load balancing (hash) | Consistent hash ring | O(log V) | O(N log V) | V = virtual nodes (150) |
| Connection pool | DashMap + AtomicU64 | O(1) | O(1) shard-lock | Lock-free epoch cleanup |
Only the ArcSwap reads (configuration and route-table snapshots) are lock-free. DashMap reads take a short per-shard read lock. Complexity figures describe the v0.9.5 implementation in src/router_cache.rs; they bound work per request, not latency under saturation, which also depends on CPU headroom, enabled plugins, and upstream behavior.