Docs / Architecture

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.

tokio
Async Runtime

Multi-threaded async runtime. Work-stealing scheduler maximizes CPU utilization across all cores.

hyper 1.x
HTTP Engine

Production-grade HTTP/1.1 and HTTP/2 implementation. Powers most of Rust's web ecosystem.

rustls
TLS Implementation

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.

tonic
gRPC

gRPC over HTTP/2. Used for both gRPC proxying and the CP→DP control channel.

quinn + h3
HTTP/3 / QUIC

IETF QUIC and HTTP/3 over UDP. 0-RTT connection establishment for repeat clients.

sqlx
Async Database

Compile-time checked SQL queries. Async connection pooling for PostgreSQL, MySQL, and SQLite.

serde
Serialization

Zero-copy deserialization of config, plugin configs, and API payloads. JSON and YAML support.

tracing
Observability

Structured, contextual logging with per-request spans. OpenTelemetry-compatible.

ArcSwap
Lock-Free Config

Atomic reference-counted pointer swaps. Config reads are wait-free. Updates are atomic. The key to zero-downtime reloads.

DashMap
Concurrent Maps

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.

jemalloc
Memory Allocator

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.

File Mode
YAML Config File
Ferrum Edge
:8000 / :8443
Backends
No database required. Config reloaded via SIGHUP or restart. Admin API is read-only.
Database Mode
Database
PG / MySQL / SQLite / Mongo
Ferrum Edge
:8000 / :9000
Backends
Admin API has full CRUD. Config cached in ArcSwap — survives DB outages.
Control Plane / Data Plane Mode
Database
Control Plane
:9000 / :50051
Data Plane 1
:8000 / :8443
Data Plane 2
:8000 / :8443
Data Plane N
:8000 / :8443
Backends
CP reads from DB and pushes config to DPs via gRPC streaming. DPs cache config locally. DP auto-reconnects on CP loss. Horizontally scalable — add DP instances without touching CP.
Mesh Mode
Control Plane
MeshSubscribe / xDS ADS
Ferrum Mesh Proxy
sidecar / waypoint / gateway
Workloads
Service-mesh data plane consuming native MeshSubscribe, standard xDS ADS, or a local mesh config file. SPIFFE identity, mesh authorization, transparent DNS proxying, and REGISTRY_ONLY egress policy.
Injector & Node Agent Modes (Kubernetes)
K8s API Server
Injector
Pods
Node Agent
one per node
Ambient Workloads
The Injector mutates opted-in pods with Ferrum mesh sidecars and init capture containers (iptables or eBPF), deriving SPIFFE IDs from service accounts. The Node Agent programs per-node eBPF socket maps and identity enrollment for the ambient mesh — it runs no proxy listeners.
Migrate Mode
Ferrum Edge
FERRUM_MODE=migrate
Database
Exit 0
Applies database schema migrations, reports status, or rewrites config files to the current schema — then exits. Designed for CI/CD pipelines and Kubernetes Jobs; no proxy listeners started.

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.

ℹ️
Mesh identity and policy: SPIFFE identities are extracted from mTLS peer certificates and HBONE baggage, with SPIRE integration or Ferrum's built-in Workload API (X.509 and JWT SVIDs). Mesh authorization policies support mesh-wide, namespace, and workload scopes with DENY-first, Istio-compatible evaluation. Kubernetes translation covers Gateway API routes, Istio VirtualService splits, AuthorizationPolicy, RequestAuthentication, and PeerAuthentication.

Request Lifecycle

1

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.

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.

3

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.

4

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.

5

Upstream Selection

Load balancing algorithm selects a healthy upstream from the pool. Health state checked via atomic bool. Connection acquired from per-host pool.

6

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).

7

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

Config Update Flow (Zero Downtime)
Admin API / DB Poll
Build New Config Object
ArcSwap::swap(new_config)
In-flight requests (before swap)
Hold Arc to old config. Complete normally with old routing/plugins.
New requests (after swap)
Load new Arc. See updated routing and plugin configs immediately.
Old config object is freed when the last in-flight request drops its Arc reference. No double-write, no lock, no downtime.

Data Structure Complexity Table

OperationStructureReadWriteNotes
Config accessArcSwapO(1) atomicO(1) atomic swapWait-free reads
Route lookup (cache hit)DashMap cache, prefix and regex partitionsO(1) averageO(1) shard-lock on miss insertBounded 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 + RegexSetO(path depth) prefix; O(path length) regexRebuilt off the hot path on config changeExact host and exact path are O(1); wildcard-host patterns are scanned linearly (typically few)
Consumer lookupDashMapO(1)O(1) shard-lockBy API key or consumer ID
Rate limit checkDashMap + AtomicU64O(1)O(1) CASLock-free token bucket
Health stateAtomicBool per targetO(1) atomicO(1) atomicPer upstream target
Plugin lookupDashMapO(1)Build-time onlyPlugins registered once at startup
Load balancing (RR)AtomicUsizeO(1)O(1) fetch_addAtomic counter mod N
Load balancing (hash)Consistent hash ringO(log V)O(N log V)V = virtual nodes (150)
Connection poolDashMap + AtomicU64O(1)O(1) shard-lockLock-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.

Want to Extend the Architecture?

Write a Custom Plugin → Contributing Guide