Configuring rate limiting
dflux EdgeGuard rate-limits with token buckets keyed by source NF type, subscriber SUPI, or a Diameter dimension. Rate-limit rules are first-class entries in the control-plane store: write them as JSON, hot-reload, and watch denials through Prometheus and the structured decision logs.
The token-bucket model
Each rate-limit rule is a token bucket with two rate knobs plus a key:
rps— tokens added per second (the steady-state limit).burst— bucket capacity (peak traffic accepted instantly).- a key that selects what gets its own bucket — see Choose the right key.
A request consumes one token. If the bucket is empty, the request is denied — 429 on SBI, DIAMETER_AUTHORIZATION_REJECTED (5003) on Diameter — and the denial increments the edge_rate_limit_exceeded_total counter and is written to the structured decision log.
Write a rule
A limit at 100 RPS, burst 200, scoped to traffic from UDM consumers:
Deploy it:
d3x-edgectl talks to the admin gRPC surface on 127.0.0.1:9091 by default. See the d3x-edgectl reference for auth and the -addr flag.
Choose the right key
source_nf_type scopes which traffic a rule applies to (by source NF type). The bucket dimension — what gets its own counter — is set separately:
key_by_supi: true— one bucket per subscriber SUPI. Use this so a single misbehaving UE can't drown out other subscribers.key— selects an explicit bucket dimension. One of:global(a single cluster-wide bucket),diameter_origin_host,diameter_origin_realm,diameter_app_id,diameter_command_code, orimsi_prefix:N(the firstNIMSI digits — e.g.imsi_prefix:6is MCC+MNC).- neither set — the legacy default: one bucket per source IP on SBI, per Origin-Host on Diameter.
An unknown key value is a load-time error, so a typo fails the reload rather than silently passing traffic.
key_by_supi limits at scale.Multiple limits on the same traffic
Each entry in rate_limits[] becomes a separate filter in the request chain. A request that matches two rules consumes a token from both buckets and is denied by whichever is tighter.
Layered protection looks like:
- A
globalcap to protect producers in aggregate. - A per-source-NF-type cap to bound any single consumer class.
- A
key_by_supicap for hot-subscriber protection.
Observe
Two Prometheus series tell the rate-limiting story:
edge_rate_limit_exceeded_total{rule="…"}— counter, ticks every time a bucket denies a request, labelled by rule name.edge_filter_decisions_total{filter="ratelimit:<rule>", decision="deny"}— the same denial seen through the generic filter-decision counter (the filter label is the rule's filter name,ratelimit:plus the rule name).
Alert on edge_rate_limit_exceeded_total rising sharply — that's either a real attack or a legitimate workload outgrowing its cap. Each denial is also logged as a structured JSON record carrying request_id, source_nf, target_nf, the bucket key, and the rule name, so you can slice denials by source or subscriber in your log pipeline before reflexively raising the limit.
Hot reload
Rate-limit rules hot-reload like every other control-plane mutation — the filter chain rebuilds and the new bucket set takes effect on the next request. See Hot reload and runtime ops for the reload guarantee and how in-flight buckets carry over or reset.
Where to go next
- Request pipeline — where rate limits sit in the chain.
- Policy schema — the full RateLimitRule fields.
- Admin API → Rate limits.