Skip to content

Feature gap: time-based policy schedulers (Junos schedulers { ... }) not propagated to userspace-dp #1378

@psaab

Description

@psaab

Gap

Junos schedulers define time-of-day / weekday windows; policies reference them via then scheduler-name foo. The eBPF dataplane has a daemon goroutine that evaluates scheduler windows and toggles each policy rule's Active byte in the BPF policy_rules map. The userspace dataplane has no scheduler plumbing whatsoever — the snapshot DTO doesn't carry SchedulerName, the Rust PolicyRule has no active field, and the daemon's UpdatePolicyScheduleState only writes to BPF maps. Scheduled policies will not activate/deactivate when running on the userspace dataplane.

eBPF implementation (source of truth)

  • pkg/dataplane/dataplane.go:134UpdatePolicyScheduleState(cfg, activeState) interface method
  • pkg/dataplane/maps.go:1495-1537 — implementation: iterates cfg.Security.Policies, looks up each rule by policySetID*MaxRulesPerPolicy+i, toggles rule.Active, writes back to BPF map
  • pkg/daemon/daemon_run.go:589d.dp.UpdatePolicyScheduleState(activeCfg, activeState) ticks per scheduler window change
  • pkg/config/compiler.go:471 — config validation: policy %q: scheduler %q not defined
  • bpf/xdp/xdp_policy.c reads the Active byte; inactive rules are skipped

Userspace-dp gap

  • pkg/dataplane/userspace/protocol.go:351-360 PolicyRuleSnapshot has no SchedulerName and no Active field
  • userspace-dp/src/policy.rs:47-83 PolicyRule has no active: bool or scheduler reference; evaluate_policy does not gate on time-of-day
  • The userspace Manager embeds the eBPF DataPlane so UpdatePolicyScheduleState calls land in pkg/dataplane/maps.go:1497 and silently no-op (policy_rules BPF map is loaded but not actually consulted by the userspace XDP shim)

Recommended fix

  1. Add SchedulerName string to PolicyRuleSnapshot (Go) and matching Rust field
  2. Add Active: bool (or Inactive: bool to keep zero-valued default behavior) to the snapshot; emit current active state on every commit + on scheduler tick
  3. In userspace-dp/src/policy.rs::evaluate_policy, skip rules with active == false
  4. Daemon-side: re-publish a snapshot delta when scheduler windows change, OR add a fast-path update_policy_active(rule_idx, active) control socket call
  5. Add capability check: bare-minimum verification that scheduler-referenced policies are admitted under userspace mode

Blocker for #1373

This must land before Phase 4 (BPF source removal) of #1373. The userspace path silently ignores scheduler state today; once eBPF is removed there's no fallback to mask the loss of scheduled access control.


Refined contract (added 2026-05-17 after triple-review of #1384)

See docs/pr/1373-retire-ebpf-dataplane/plan-1378-policy-schedulers.md for the full implementation contract refined through 4 rounds of Claude+Codex+Gemini Pro 3 review. New since the original issue body:

  • Risks called out: time-source drift (monotonic clock for window evaluation, NTP rollback must not flap policies), apply-cycle race (scheduler window transition during config apply must produce either fully-old or fully-new policy decisions, not split), userspace/Go propagation latency (window changes must propagate within one snapshot cycle or operators see stale matches).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions