Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8d737a4
feat(clock): Read the clock through a facade, and lint for it
daniel-noland Aug 18, 2026
724db0e
test(nat): Test flow expiry on a clock the test drives
daniel-noland Aug 18, 2026
fb185da
test(nat): Drive port forwarding with configuration-relative packets
daniel-noland Aug 18, 2026
978c3eb
test(net): Test the flow expiry state machine as an algebra
daniel-noland Aug 18, 2026
cf112c5
fix(masquerade): Keep both halves of a flow pair alive
daniel-noland Aug 18, 2026
e91fdb8
test(stats): Test the exponentially weighted moving average
daniel-noland Aug 18, 2026
bca85f2
test(stats): Test the per-vpc statistics store
daniel-noland Aug 18, 2026
2d7d351
test(stats): Test the time-slice apportioning in the collector
daniel-noland Aug 18, 2026
1ac426b
test(routing): Test the stale window on a clock the test drives
daniel-noland Aug 18, 2026
a8ea44f
test(routing): Drive the router IO loop through its own sockets
daniel-noland Aug 18, 2026
9032577
test(routing): Stand in for frr-agent and test the frrmi lifecycle
daniel-noland Aug 18, 2026
7c0cd3e
test(routing): Follow a route from the socket to the fib
daniel-noland Aug 18, 2026
ed6b0dd
test(net): Close every mutant flow_info's properties were missing
daniel-noland Aug 18, 2026
bbb45cd
test(masquerade): Pin the flow state machine, exhaustively
daniel-noland Aug 19, 2026
9e3ce32
style(routing): Take rustfmt's answer, and route the last Instant import
daniel-noland Aug 27, 2026
ddb97f7
fix(nat): Let the port-forwarding properties be selected
daniel-noland Aug 27, 2026
1ad13aa
test(nat): Drop the absolute floor here too
daniel-noland Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .cargo/mutants.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

exclude_re = [
"<impl Display for",
"<impl Debug for",
"<impl std::fmt::Display for",
"<impl std::fmt::Debug for",

"contract::",
]

exclude_globs = [
"sysfs/**",
]
25 changes: 25 additions & 0 deletions .semgrep/rules/no-std-time-direct.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
rules:
- id: rust-no-direct-clock-read
languages: [rust]
severity: ERROR
message: |
Read the clock via `clock::now()` (or `clock::system_now()` for wall
time), not `Instant::now()` / `SystemTime::now()`. The workspace's
`clock` facade reads `std` in production and tokio's pausable clock
under the `virtual` feature; reading `std` directly pins the deadline
to the wall clock while the timer waiting on it follows tokio's, so a
test that advances time sees the two diverge.

`Duration` needs no facade -- it is a plain value with no clock in it,
and `clock` re-exports it only for convenience.
paths:
exclude:
- .codeql/tests/
- clock/src/
- concurrency/tests/
pattern-either:
- pattern: Instant::now()
- pattern: std::time::Instant::now()
- pattern: SystemTime::now()
- pattern: std::time::SystemTime::now()
- pattern: tokio::time::Instant::now()
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"acl-filter",
"args",
"cli",
"clock",
"common",
"concurrency",
"concurrency-macros",
Expand Down Expand Up @@ -71,6 +72,7 @@ acl-filter = { path = "./acl-filter", package = "dataplane-acl-filter", features
args = { path = "./args", package = "dataplane-args", features = [] }
cli = { path = "./cli", package = "dataplane-cli", features = [] }
common = { path = "./common", package = "dataplane-common", features = [] }
clock = { path = "./clock", package = "dataplane-clock", features = [] }
concurrency = { path = "./concurrency", package = "dataplane-concurrency", features = [] }
concurrency-macros = { path = "./concurrency-macros", package = "dataplane-concurrency-macros", features = [] }
config = { path = "./config", package = "dataplane-config", features = [] }
Expand Down
2 changes: 2 additions & 0 deletions acl-filter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ version.workspace = true

[dependencies]
acl = { workspace = true }
clock = { workspace = true }
common = { workspace = true }
concurrency = { workspace = true }
config = { workspace = true }
Expand All @@ -22,6 +23,7 @@ tracectl = { workspace = true }
tracing = { workspace = true }

[dev-dependencies]
clock = { workspace = true, features = ["virtual"] }
# The reference (linear-scan) ACL backend is the differential-test oracle and drives the fast,
# EAL-free semantic suite. It is `cfg(test)`-gated in the source, so it is never part of a
# production build; this dev-dep just makes `acl::reference` available to test builds.
Expand Down
4 changes: 2 additions & 2 deletions acl-filter/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use concurrency::sync::Arc;
use pipeline::NetworkFunction;

use std::net::{Ipv4Addr, Ipv6Addr};
use std::time::{Duration, Instant};
use std::time::Duration;

// VNIs and IP ranges used by the standard two-VPC peering (vpc1 <-> vpc2). The manifest names
// ("vpc1"/"vpc2") double as the ACL rule `from`/`to` endpoints.
Expand Down Expand Up @@ -670,7 +670,7 @@ fn ipv6_allow_and_default_deny() {
// reply's weak `related` reference can still be upgraded.
fn attach_related_flow(reply: &mut Packet<TestBuffer>, fwd_key: FlowKey) -> Arc<FlowInfo> {
let reply_key = FlowKey::try_from(&*reply).unwrap();
let expiry = Instant::now() + Duration::from_secs(60);
let expiry = clock::now() + Duration::from_secs(60);
let (fwd_flow, reply_flow) = FlowInfo::related_pair(
expiry,
fwd_key,
Expand Down
2 changes: 2 additions & 0 deletions acl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ reference = []

[dependencies]
arrayvec = { workspace = true, default-features = true }
clock = { workspace = true }
concurrency = { workspace = true, features = [] }
dpdk = { workspace = true, optional = true }
lookup = { workspace = true, features = [] }
Expand All @@ -20,6 +21,7 @@ net = { workspace = true, features = [] }
thiserror = { workspace = true }

[dev-dependencies]
clock = { workspace = true, features = ["virtual"] }
# Enable the "reference" backend for this crate's own tests and benches. It is a non-default feature
# (production links only the rte_acl backend), but the integration tests and benches
# differential-test against it, so make it available whenever test/bench targets are built.
Expand Down
3 changes: 1 addition & 2 deletions acl/src/dpdk/dyn_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,6 @@ mod tests {
use lookup::Lookup;
use match_action::{Erased, ExactSpec, MaskSpec, MatchKey, PrefixSpec, RangeSpec};
use std::hint::black_box;
use std::time::Instant;

#[derive(MatchKey, Debug, Clone, Copy)]
struct FiveTuple {
Expand Down Expand Up @@ -969,7 +968,7 @@ mod tests {
let rules = make(n);
let max = NonZero::new(u32::try_from(n).unwrap()).unwrap();
let rss_before = rss_kb();
let t = Instant::now();
let t = clock::now();
let res: Result<DpdkAclLookup<RemoteKey<Ipv4Addr>, u32>, _> =
install_table(&unique_name("cap"), max, rules);
let dt = t.elapsed().as_secs_f64() * 1e3;
Expand Down
13 changes: 13 additions & 0 deletions clock/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "dataplane-clock"
edition.workspace = true
license.workspace = true
publish.workspace = true
version.workspace = true

[features]
default = []
virtual = ["dep:tokio"]

[dependencies]
tokio = { workspace = true, optional = true, features = ["test-util", "time"] }
48 changes: 48 additions & 0 deletions clock/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Open Network Fabric Authors

#![deny(clippy::all, clippy::pedantic)]
#![deny(rustdoc::all)]
#![deny(unsafe_code)]

pub use std::time::{Duration, Instant, SystemTime, SystemTimeError, TryFromFloatSecsError};

#[must_use]
pub fn now() -> Instant {
#[cfg(feature = "virtual")]
{
tokio::time::Instant::now().into_std()
}
#[cfg(not(feature = "virtual"))]
{
Instant::now()
}
}

#[must_use]
pub fn system_now() -> SystemTime {
SystemTime::now()
}

#[cfg(test)]
mod tests {
use super::{Duration, now, system_now};

#[test]
fn now_is_monotonic() {
let first = now();
let second = now();
assert!(second >= first, "the monotonic clock went backwards");
}

#[test]
fn now_works_with_no_runtime() {
let _ = now();
let _ = system_now();
}

#[test]
fn durations_are_plain_values() {
assert_eq!(Duration::from_secs(1).as_millis(), 1000);
}
}
2 changes: 2 additions & 0 deletions config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ bolero = ["dep:bolero", "lpm/bolero"]

[dependencies]
# internal
clock = { workspace = true }
common = { workspace = true }
concurrency = { workspace = true }
k8s-intf = { workspace = true }
Expand All @@ -33,6 +34,7 @@ linkme = { workspace = true }
tracectl = { workspace = true }

[dev-dependencies]
clock = { workspace = true, features = ["virtual"] }
# internal
pipeline = { workspace = true } # should be removed w/ NAT
lpm = { workspace = true, features = ["bolero", "testing"] }
Expand Down
Loading
Loading