AI Quotas and QoS¶
LoxiLB provides request and token admission controls plus network byte-rate controls. This page explains where each control runs and gives repeatable attach, measure, detach, and recovery procedures.
Enforcement paths¶
flowchart TD
API["POST /config/policy"] --> ATT{"targetObject.attachment"}
ATT -->|"0: LB rule"| RULE{"Rule mode"}
ATT -->|"1: ingress port"| INGRESS["Ingress-port datapath policer<br/>wire bytes"]
ATT -->|"2: egress port"| EHOOK{"Gateway started<br/>with --egr-hooks?"}
RULE -->|"L4 / NAT"| L4["LB-rule datapath policer<br/>bidirectional wire bytes"]
RULE -->|"mode 4 fullproxy"| L7["L7 userspace shaper<br/>plaintext payload bytes"]
EHOOK -->|no| REJECT([Reject policy])
EHOOK -->|yes| EGRESS["Egress-port datapath policer<br/>host and transit egress"]
style API fill:#fce4ec,stroke:#e91e63
style L4 fill:#e8f5e9,stroke:#43a047
style L7 fill:#e1f5fe,stroke:#0288d1
style INGRESS fill:#e8f5e9,stroke:#43a047
style EGRESS fill:#e8f5e9,stroke:#43a047
style REJECT fill:#ffcdd2,stroke:#e53935
The attachment value selects the object. Attachment 0 then branches on LB
rule mode: L4/NAT rules drop excess packets in the datapath, while fullproxy
rules pace payload bytes in userspace.
| Attachment | polObjName |
Enforcement | Important condition |
|---|---|---|---|
0 |
IPv4 VIP:PORT:PROTO; IPv6 [VIP]:PORT:PROTO for L4 |
L4 policer or fullproxy L7 shaper | Fullproxy shaping currently accepts IPv4 rule keys only |
1 |
Ingress port name | Ingress port policer | Verify the named port resolves and enforcement becomes active |
2 |
Egress port name | Host-originated and transit-egress policer | Gateway must run with --egr-hooks; verify the named port resolves |
An accepted policy may still be pending its target
A missing LB rule or port is not always a create-time error. The Gateway can retain the policy and retry synchronization. After every attach, read the policy back and prove the expected rate with a new test flow or the fullproxy shaper metrics before treating it as enforced.
IPv6 applies to the L4 policer, not the current fullproxy shaper
Bracketed IPv6 keys are valid for attachment-0 L4 policies. The current fullproxy userspace shaper supports IPv4 rule keys only; an IPv6 fullproxy rule cannot use this shaper path.
These policies are independent from API-key and tenant request-per-second (RPS) limits and token-per-minute (TPM) quotas. See AI Traffic Governance for admission controls.
Units and behavior¶
| Field or metric | Unit | Notes |
|---|---|---|
committedInfoRate |
Megabits per second (Mbps) | Minimum 8 Mbps; converted internally to bits per second |
peakInfoRate |
Mbps | 0 is valid for a single-rate policy |
committedBlkSize |
Bytes | Configured burst depth; defaults apply when omitted |
| Tier-0 L4/port metering | L3 wire bytes | Excess traffic is policed, normally by dropping packets |
| Tier-1 fullproxy metering | Plaintext payload bytes | Traffic is paced; TLS framing and L3 overhead are not counted |
loxilb_proxy_qos_cir_bytes_per_second |
Bytes per second | API Mbps divided by 8; 16 Mbps exports as 2,000,000 B/s |
loxilb_proxy_qos_cbs_bytes |
Bytes | Effective shaper burst depth |
The fullproxy upload and download directions have independent buckets. Each enabled direction refills at the full configured CIR; the rate is not divided between directions.
Prerequisites¶
- A configured LB rule or port that you can safely test.
- A control-plane identity authorized to create and delete policies.
- A traffic generator such as
iperf3for L4 tests orcurlfor fullproxy payload tests. - Baseline throughput comfortably above the intended policy rate.
- Metrics enabled if you want to validate fullproxy shaper counters.
Use a staging service first. A policer can drop traffic immediately, and a bad port or rule choice can affect unrelated workloads.
The examples use a protected management header file:
export CONTROL_API="https://gateway.example.com/netlox/v1"
install -m 600 /dev/null ./control-plane.headers
printf 'Authorization: Bearer %s\n' "$CONTROL_PLANE_TOKEN" > ./control-plane.headers
Lab 1 — Rule-attached L4 policer¶
Baseline¶
Measure both client-to-backend and reverse traffic through the target NAT LB rule. Record the baseline before attaching anything:
iperf3 --client 192.0.2.10 --port 2020 --time 10
iperf3 --client 192.0.2.10 --port 2020 --time 10 --reverse
Replace 192.0.2.10 with your test VIP. Stop if the baseline is already near
the planned CIR; the lab would not distinguish policy enforcement from an
unhealthy path.
Attach¶
This policy attaches 10 Mbps to an IPv4 TCP rule:
curl --fail-with-body --silent --show-error \
--request POST "$CONTROL_API/config/policy" \
--header @control-plane.headers \
--header 'Content-Type: application/json' \
--data '{
"policyIdent": "example-rule-policy",
"policyInfo": {
"type": 0,
"committedInfoRate": 10,
"peakInfoRate": 10,
"committedBlkSize": 125000
},
"targetObject": {
"attachment": 0,
"polObjName": "192.0.2.10:2020:tcp"
}
}'
For IPv6, include brackets: [2001:db8::10]:2020:tcp. A bare IPv6 address is
ambiguous and is rejected for an LB-rule attachment.
Measure and recover¶
Open new test connections and repeat both directions. Throughput should fall toward the configured rate and remain bounded for the whole flow. Then detach and confirm the baseline returns:
curl --fail-with-body --silent --show-error \
--request DELETE \
--header @control-plane.headers \
"$CONTROL_API/config/policy/ident/example-rule-policy"
iperf3 --client 192.0.2.10 --port 2020 --time 10
iperf3 --client 192.0.2.10 --port 2020 --time 10 --reverse
Successful recovery proves the policy is no longer attached. It does not prove an exact production throughput value; transport overhead, burst depth, round-trip time, and the test host influence measurements.
Lab 2 — Egress port policer¶
Attachment 2 covers host-originated traffic and transit traffic after the
forwarding decision selects the actual egress port.
Start with --egr-hooks
The API rejects an egress attachment if the Gateway was not started with
--egr-hooks. This prevents a policy from being accepted when no egress
hook could enforce it.
Baseline and attach¶
Measure a host-originated upload from the Gateway and a transit upload through the LB rule. Then attach the policy to the backend-facing port:
curl --fail-with-body --silent --show-error \
--request POST "$CONTROL_API/config/policy" \
--header @control-plane.headers \
--header 'Content-Type: application/json' \
--data '{
"policyIdent": "example-egress-policy",
"policyInfo": {
"type": 0,
"committedInfoRate": 10,
"peakInfoRate": 10,
"committedBlkSize": 125000
},
"targetObject": {
"attachment": 2,
"polObjName": "backend-facing-port"
}
}'
Expected result: missing egress hooks are rejected. A missing named port can leave the policy pending instead of returning an error, so confirm read-back and enforcement on the intended egress port.
Measure, detach, and clean up¶
Repeat both baseline transfers. Host-originated and transit uploads leaving through the named port should be bounded. Traffic leaving another port should not be charged to this policy.
curl --fail-with-body --silent --show-error \
--request DELETE \
--header @control-plane.headers \
"$CONTROL_API/config/policy/ident/example-egress-policy"
Confirm both traffic classes recover. If they do not, verify the policy is gone and inspect the actual forwarding egress port before changing another policy.
Lab 3 — Fullproxy bidirectional L7 shaper¶
An attachment-0 policy on a mode: 4 rule does not install an L4 NAT policer.
It configures the fullproxy relay to pace plaintext payload bytes.
Baseline and attach¶
Measure a sufficiently large upload and download through the fullproxy VIP. Small probes can fit entirely inside the burst and will not show the steady rate.
Attach a 16 Mbps policy:
curl --fail-with-body --silent --show-error \
--request POST "$CONTROL_API/config/policy" \
--header @control-plane.headers \
--header 'Content-Type: application/json' \
--data '{
"policyIdent": "example-fullproxy-shaper",
"policyInfo": {
"type": 0,
"committedInfoRate": 16,
"peakInfoRate": 16,
"committedBlkSize": 250000
},
"targetObject": {
"attachment": 0,
"polObjName": "192.0.2.20:2020:tcp"
}
}'
Large uploads and downloads should approach 2,000,000 bytes per second after the initial burst. Upload and download are independently metered.
Verify with metrics¶
Every series uses vip, port, proto, and direction labels.
| Metric | Type | Unit and interpretation |
|---|---|---|
loxilb_proxy_qos_bytes_passed_total |
Counter | Plaintext payload bytes granted |
loxilb_proxy_qos_bytes_delayed_total |
Counter | Granted bytes that waited through at least one park/resume cycle |
loxilb_proxy_qos_parks_total |
Counter | Reader pause events caused by an empty bucket |
loxilb_proxy_qos_park_seconds_total |
Counter | Summed wall time for parks that later resumed, in seconds |
loxilb_proxy_qos_parked_connections |
Gauge | Readers currently paused |
loxilb_proxy_qos_tokens_bytes |
Gauge | Current bucket level in bytes |
loxilb_proxy_qos_cir_bytes_per_second |
Gauge | Configured refill rate in bytes/s |
loxilb_proxy_qos_cbs_bytes |
Gauge | Effective burst depth in bytes |
bytes_delayed_total / bytes_passed_total estimates the fraction of payload
that encountered shaping. park_seconds_total / parks_total estimates mean
resume delay. Avoid dividing raw counters without applying rate() over the
same interval in Prometheus.
SSE and timeout behavior¶
Time spent paused by the shaper is excluded from idle and stream-duration reaping. This prevents configured shaping from manufacturing an SSE timeout. Genuinely slow unshaped streams remain subject to their configured duration limit.
Detach and confirm series removal¶
curl --fail-with-body --silent --show-error \
--request DELETE \
--header @control-plane.headers \
"$CONTROL_API/config/policy/ident/example-fullproxy-shaper"
Confirm upload and download recover. After the metrics collection interval, series for the detached shaped service should disappear rather than freeze at their previous values.
Troubleshooting¶
| Symptom | Evidence | Likely cause and correction |
|---|---|---|
| Policy is rejected | API error mentions attachment | Use only attachment 0, 1, or 2; verify the request shape |
| Policy is accepted but target is absent | Policy read-back exists; traffic is unchanged | Create/correct the target rule or port, then wait for synchronization and re-test |
| Egress policy is rejected | Error mentions egress hooks | Restart through the approved deployment process with --egr-hooks, then retry |
| Policy is accepted but traffic is unchanged | Baseline and new-flow measurement | Verify the policy targets the real rule/port and that the test exceeds burst depth |
| Fullproxy traffic drops instead of pacing | Rule read-back | Confirm the target is the intended mode: 4 rule |
| IPv6 fullproxy rule is not shaped | Rule address family | The current L7 shaper is IPv4-only; use a supported IPv4 service or an independently validated control |
| Metric CIR looks eight times smaller than API CIR | Compare units | Expected: API uses Mbps, shaper metric uses bytes/s |
| Shaper metrics are absent | Rule mode, attachment, scrape timing | Metrics exist only for actively shaped fullproxy services; wait for collection after attach |
| Traffic remains slow after detach | Policy list and independent baseline | Confirm delete succeeded, use a new connection, and isolate backend/network bottlenecks |
HA and security boundaries¶
- Policy configuration must be identical on both nodes. Verify the effective policy and target object on each node before promotion.
- Runtime policer and shaper token buckets are node-local. Promotion rebuilds or resets that transient state, so a newly active node can begin with fresh burst credit.
- Single-node functional scenarios do not prove quota or rate-limit failover, cross-node bucket continuity, or connection migration.
- Active TCP, TLS, and SSE connections are not transferred to another process; clients must reconnect.
- Restrict policy CRUD to least-privileged operators. A policy can degrade or interrupt service even though it does not contain a credential.
- Do not expose raw headers, prompts, credentials, private addresses, or customer labels in troubleshooting output.
See HA and Upgrade Limitations before changing a peer pair.
Final cleanup checklist¶
- Delete every temporary policy by
policyIdent. - Confirm the policy no longer appears in policy read-back.
- Open new upload and download connections and confirm baseline recovery.
- Confirm fullproxy shaper series disappear after collection refresh.
- Remove local header files and unset secret-bearing variables.
What these labs do not prove¶
They validate attachment behavior, directional enforcement, detach recovery, and metric units on one Gateway. They do not establish a production service level, two-node failover behavior, or seamless rolling upgrades.