Skip to content

(11) feat(acl): crate scaffolding + software reference backend#1575

Open
daniel-noland wants to merge 1 commit into
pr/daniel-noland/match-actionfrom
pr/daniel-noland/acl-reference
Open

(11) feat(acl): crate scaffolding + software reference backend#1575
daniel-noland wants to merge 1 commit into
pr/daniel-noland/match-actionfrom
pr/daniel-noland/acl-reference

Conversation

@daniel-noland
Copy link
Copy Markdown
Collaborator

@daniel-noland daniel-noland commented May 31, 2026

Stack (11). Base: pr/daniel-noland/match-action.

The ACL crate scaffolding and the software reference backend -- the readable
oracle that defines ACL semantics and the public API surface.

  • feat(acl): crate scaffolding + software reference backend.

The DPDK backend (proven equivalent to this oracle via a differential test)
lands in the next PR.

Review stack (merge bottom -> top):

Introduces the dataplane-acl crate with the software reference
classifier.  The DPDK rte_acl backend lands behind a feature gate in
a follow-up PR.

The reference backend is a linear-scan software classifier built on
the canonical FieldPredicate form from match-action
(rule.into_backend_fields::<Erased>()), so it speaks the same four
predicate kinds (Prefix / Mask / Range / Exact) as every other
backend.  Two roles:

1. Differential-testing oracle against rte_acl (a future PR's
   differential property tests pit both backends against the same
   random rule + packet draws).
2. Non-lossy substrate for a small-delta cascade front over a slow
   tail backend.

Layout:

- src/lib.rs declares the crate-level docs and re-exports the
  reference module.  The dpdk feature gate and dpdk_table_alias!
  macro land alongside the rte_acl backend itself in the next PR.
- src/reference/table.rs is the typed surface: ReferenceTable<K, A>
  parameterised by a MatchKey and an action; RefRule wraps the
  lowered Erased predicates plus an action.  Inline unit tests cover
  positional precedence (first match wins) and the four predicate
  kinds.
- src/reference/dyn_table.rs is the runtime-shape twin:
  DynReferenceTable carries its FieldSpec layout at runtime so
  property tests can fuzz the schema itself.  Returns DynShapeError
  on shape mismatch.

just fmt; cargo check --workspace --all-targets passes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new dataplane-acl workspace crate that defines the ACL public API surface and implements a pure-software “reference/oracle” backend (typed and dynamic) behind the lookup::Lookup interface.

Changes:

  • Add acl as a workspace member and workspace dependency, plus package metadata for miri/wasm selection.
  • Introduce dataplane-acl crate scaffolding with strict linting and a reference module.
  • Implement ReferenceTable (typed MatchKey) and DynReferenceTable (runtime FieldSpec) linear-scan classifiers with unit tests.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
Cargo.toml Adds acl to workspace + workspace deps; introduces miri/wasm metadata entry.
Cargo.lock Locks the new dataplane-acl crate and its dependencies.
acl/Cargo.toml Defines the new dataplane-acl package and dependencies.
acl/src/lib.rs Crate-level lint policy and top-level documentation; exports reference module.
acl/src/reference/mod.rs Wires up reference backend modules + re-exports.
acl/src/reference/table.rs Implements typed ReferenceTable/RefRule and Lookup<K, A> integration.
acl/src/reference/dyn_table.rs Implements runtime-shaped DynReferenceTable with validation and byte-slice lookup.

Comment on lines +29 to +35
pub(crate) fn matches_packed(&self, specs: &[FieldSpec], buf: &[u8]) -> bool {
debug_assert_eq!(self.fields.len(), specs.len());
self.fields
.iter()
.zip(specs)
.all(|(pred, spec)| pred.matches(&buf[spec.offset..spec.offset + spec.size]))
}
Comment on lines +66 to +73
fn pack(key: &K) -> Option<[u8; MAX_KEY_BYTES]> {
if K::KEY_SIZE > MAX_KEY_BYTES {
return None;
}
let mut buf = [0u8; MAX_KEY_BYTES];
key.as_key_into(&mut buf[..K::KEY_SIZE]);
Some(buf)
}
Comment on lines +88 to +103
#[must_use]
pub fn lookup_bytes(&self, key: &[u8]) -> Option<&A> {
assert_eq!(key.len(), self.key_size, "key length must equal key_size");
self.rules
.iter()
.find(|rule| rule.matches_packed(&self.specs, key))
.map(RefRule::action)
}
#[must_use]
pub fn matches_bytes(&self, key: &[u8]) -> Vec<&RefRule<A>> {
assert_eq!(key.len(), self.key_size, "key length must equal key_size");
self.rules
.iter()
.filter(|rule| rule.matches_packed(&self.specs, key))
.collect()
}
Comment thread Cargo.toml
Comment on lines +265 to +272
[workspace.metadata.package.acl]
package = "dataplane-acl"
# Default features enable the DPDK `rte_acl` backend, which pulls in
# `dpdk-sys` (bindgen against the system DPDK headers). miri can't
# build that path on the cross target, and the reference backend's
# unit tests run fine outside the miri profile.
miri = false # hopeless + pointless
wasm = false # hopeless + pointless
Comment thread acl/src/lib.rs
Comment on lines +17 to +18
//! - [`reference`](mod@reference): linear-scan software classifier;
//! differential oracle and a mutable cascade front. Always built.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants