Repository navigation
(18) policer: rate limiting with RFC 2697/2698 three color markers - #1907
Draft
daniel-noland wants to merge 8 commits into
Draft
daniel-noland wants to merge 8 commits into
daniel-noland wants to merge 8 commits into
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
daniel-noland
force-pushed
the
pr/daniel-noland/rate-limit
branch
from
October 16, 2026 04:23
7576e60 to
fb942cd
Compare
daniel-noland
changed the base branch from
pr/daniel-noland/lldp
to
pr/daniel-noland/lldp-lifecycle
October 16, 2026 04:23
This was referenced Oct 16, 2026
daniel-noland
force-pushed
the
pr/daniel-noland/rate-limit
branch
from
October 16, 2026 05:47
fb942cd to
b3bba1a
Compare
…rkers A policer colors each packet on arrival and queues nothing, so unlike a shaper it costs a few comparisons a packet at any rate. This adds the meters a rate limiting stage will build on: - profiles for the single rate (RFC 2697) and two rate (RFC 2698) markers, refusing the configurations the RFCs rule out; - limits on bytes, packets, or both: a packet takes the best color both can pay for, and pays it in both; - `Meter`, the exact single-owner meter, with exact integer refill; - `SharedMeter`/`LocalMeter`, for traffic RSS spreads over workers. Each worker leases tokens in batches (100 us of rate, at most a quarter of the bucket split among the workers), so workers do not bounce a cache line per packet. A refused worker does not ask again until the bucket could have earned what it asked for, so traffic over the limit makes no shared writes. Leases can stretch a burst by a lease per worker, and can strand tokens briefly; neither changes the long term rate. The meters are tested against a literal, tick by tick transcription of both RFCs. A single worker leasing only what it needs must match it exactly, any interleaving of workers must stay within what the buckets earn, and a model-checked (shuttle/loom) test shows concurrent workers spend each token once. RFC 2697 and 2698 are vendored for duvet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`AnyTable`, its rule rows and `build_table` were private to acl-filter, but nothing in them is about ACLs: they build a first-match table for any `MatchKey`, on rte_acl or the reference backend, and keep the rules for display. They move to `acl::table` as `Table`, so the rate limiter can classify with the same machinery. The reference backend is now gated on the acl crate's `reference` feature rather than acl-filter's `cfg(test)`; acl-filter's dev-dependency already enables it, so production still links only rte_acl. `Table` also implements `lookup::Lookup`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A rate limit names a VPC and a destination prefix (as the VPC addresses it, before NAT), the limits to meter that traffic against as one aggregate (`policer::Limits`: bytes and/or packets, RFC 2697 or 2698), and what happens to each color: pass, remark DSCP, or drop. By default green and yellow pass and red drops. Validation resolves the VPC to its VNI and refuses an unknown VPC, a repeated name, and two rate limits on the same VPC and destination. One packet is metered by one rate limit, the one with the longest matching destination, so nested destinations are fine but equal ones would be ambiguous. The overlay algebra does not generate rate limits yet; the completeness record says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`DoneReason::RateLimited` marks a packet a rate limit dropped; the bridge drops it like every other policy drop. `Ipv6::payload_length` reads the header field, so a meter can count the bytes of an IPv6 packet as RFC 2697 and 2698 do: the whole IP packet, header included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`bytes: trTCM cir 1000/s cbs 1500 pir 2000/s pbs 3000; packets: ...`, for the CLI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`RateLimiter<C>` asks its `Classify` which rule meters a packet, colors the packet with that rule's `policer::SharedMeter`, and passes, remarks the DSCP of (refreshing checksums), or drops it (`RateLimited`) as the rule says for the color. The stage knows nothing of what rules match, so the same stage can police on any key at any point of the pipeline. `VpcDestination` is the classifier for the configured rate limits: the source VNI and the destination prefix, longest prefix first, on the `acl::table` machinery (rte_acl in production). rte_acl wants a one byte first field, so the key carries the protocol, wildcarded for now. Rules reach the workers through a slot, as ACLs do. A rule that survives a new configuration with the same name and limits keeps its meter, so its buckets do not refill on every config change, and keeps its counts. Each worker keeps its own counts per rule and writes only those, so counting never contends; the CLI sums them. Tests cover classification (longest prefix, VPC, v4/v6), each color's action and the counts, packets the stage must leave alone, rules carried over and restarted across configurations, rendering, and rte_acl agreeing with the reference backend. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
show rate-limits The rate limiter runs after the ACLs, so denied packets are not charged to a limit, and before NAT, so destinations are matched as the source VPC addresses them. Each worker's stage reads the rules from one writer, sized for the number of workers so that leases scale with them. Applying a config builds the rules on rte_acl after the ACL tables. The CLI only reads: per rule, what it matches, its limits, and what each color did, in packets and bytes, summed over the workers. A rate limited drop is never punted to the control plane. The mgmt sample config now carries a rate limit, and its test checks that applying the config hands the rule to the workers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a third profile, CommittedPlusExcess (CIR, CBS, EIR, EBS). Unlike RFC 2698's peak rate, the excess rate adds to the committed rate: green packets pay only the committed bucket and yellow packets only the excess bucket, so in-profile traffic is never refused because the second bucket is small or drained by yellow traffic. RFC 4115 colors packets as RFC 2697 does and refills as RFC 2698 does, so the internals are renamed after what they describe: Shape::Separate and Shape::Nested say which buckets each color pays from, Buckets::Cascading and Buckets::Independent how the buckets refill. The shared meter sizes leases on the excess rate. Where RFC 4115's text (Tc(t) - B > 0) and its Figure 1 (B <= Tc(t-)) disagree at equality, the meter follows the figure, as RFC 2697 and 2698 do; the citation records why. Measuring rates in bits and sizing buckets above the largest packet are left to the configuration, which knows both; they are recorded as exceptions. The literal tick by tick model and the fuzzed equivalence and leasing tests cover the new profile, with unit tests for the additive rates, the independence of green from the excess bucket, and the equality case. RFC 4115 is vendored for duvet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
daniel-noland
force-pushed
the
pr/daniel-noland/rate-limit
branch
from
October 16, 2026 08:43
b3bba1a to
e8733e0
Compare
daniel-noland
force-pushed
the
pr/daniel-noland/lldp-lifecycle
branch
from
October 16, 2026 08:43
1d2adae to
5934986
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on (17g) #1925, the top of the LLDP stack ((17a) #1906 – (17g) #1925).
A rate limiting network function. Each rule matches traffic, to start with by source VNI and inner destination prefix, and limits packets per second and/or bytes per second. Every packet is colored by an RFC 2697 (srTCM) or RFC 2698 (trTCM) meter, and each color has an action: pass, remark DSCP, or drop.
Why policing, not shaping
At 100 Gb/s anything that queues is a liability. The three color markers are meters: each packet is colored when it arrives and never held, for a few comparisons a packet. What is hard at line rate is the workers, not the algorithm. RSS spreads one rule's traffic over every worker, and a bucket updated per packet would bounce one cache line between all of them.
Commits
policerMeter.SharedMeter/LocalMeter: each worker leases tokens in batches, so the shared lock is taken roughly once per lease, not once per packet. A refused worker stays off the shared state until the bucket could have refilled.refactor(acl): the first-match classifier table (rte_acl or reference) moves out ofacl-filterintoacl::table, so anyMatchKeycan use it.config: rate limits in the overlay model.net:DoneReason::RateLimited, andIpv6::payload_length.policer:Displayfor limits.rate-limit: theRateLimiter<C: Classify>stage.VpcDestinationis the first classifier.dataplane:show rate-limitsdisplays them;Tests
Passing:
policer,rate-limit,config,net,just test dataplane(87) andjust test mgmt(22). The mgmt sample-config test now applies a rate limit through rte_acl and checks that it reaches the workers.rte_aclis also checked against the reference backend.Not yet done
🤖 Generated with Claude Code