feat(docker): expose the eBPF time-window filter on kernel links

uBridge's window mode gained the semantics the B.2 spec asked for —
`tc window_drop <if> <start> <outage> <pct> [<period> [<jitter>]]`: a
single outage that traffic passes before *and* after, recurring flaps
with period >= outage, and a per-cycle jitter — so the kernel-only
`window_drop` filter type is now exposed:

- validation mirrors the tc grammar (3-5 params, ranges, period >=
  outage, jitter cap) and adds window_drop to KERNEL_ONLY_FILTERS;
  filter_inactive_filters keeps start=0 — unlike every other filter a
  zero first parameter means "the outage starts now", not "disabled".
- `_ubridge_apply_ebpf_drops` sends `tc window_drop` (positional
  pass-through) and turns the mode off explicitly when absent, under the
  same ebpf=1 gate.
- FILTERS entry (Start/Outage/Chance/Period/Jitter) + available_filters.

The schedule is relative to the apply: reconcile re-sets the classifier
on every apply, so any filter change, node restart or link reset restarts
the window.

Verified on a two-container kernel link, 15/15: a single outage
[1000, 1500, 100] arrives per-seq as [0..4, 13..19] (passing before the
window, dropped inside, passing after); recurring 1000/2000 ms = 52 %
round trip (duty cycle); period == outage = permanent outage; period <
outage = 409 before uBridge; jittered flap keeps the ~50 % duty cycle;
30 % chance on a permanent window = 53 % round trip against the
per-direction theory 1-0.7^2 = 51 %; coexist with netem; node restart
restores; available_filters kernel vs relay (409 + hidden); teardown
clean. P6b re-run as a regression on the same uBridge build: 13/13.

Worth recording for the next rebuild: the first delivered window program
loaded as root but reported ebpf=0 through gns3-server — the verifier's
non-root path loses the loop counter's bound, treats the catch-up loop as
unbounded and rejects the *whole* program (E2BIG, 8193 pending states),
which also took frequency_drop and quota down, with ebpf=0 as the only
symptom. Smaller trip caps did not help; the loop had to go (uBridge
572ca0c), on top of a Makefile header-dependency fix (53e34bb) that had
been shipping a stale program object.
This commit is contained in:
YueGuobin committed 2026-10-06 00:21:08 +08:00
1 parent 0c4ec8c38c
commit 316e7002c1
8 files changed
+300 -48

No files matched your search

+18 -2
View File
@@ -147,6 +147,20 @@ FILTERS = [
{"name": "Chance", "minimum": 0, "maximum": 100, "type": "int", "unit": "%"},
],
},
{
"type": "window_drop",
"name": "Time window drop",
"description": "Drop packets with the given chance inside a time window starting Start ms from the "
"moment the filter is applied — a single outage (traffic passes before and after), or with a "
"period recurring flaps whose per-cycle timing a jitter randomizes (kernel-datapath links only)",
"parameters": [
{"name": "Start", "minimum": 0, "maximum": 1000000000000, "type": "int", "unit": "ms"},
{"name": "Outage", "minimum": 1, "maximum": 1000000000000, "type": "int", "unit": "ms"},
{"name": "Chance", "minimum": 0, "maximum": 100, "type": "int", "unit": "%"},
{"name": "Period", "minimum": 1, "maximum": 1000000000000, "type": "int", "unit": "ms"},
{"name": "Jitter", "minimum": 0, "maximum": 1000000000, "type": "int", "unit": "ms"},
],
},
]
@@ -308,7 +322,8 @@ class Link:
raise ControllerError(f"Invalid packet filter parameters: {e!s}")
if self._created and not self.kernel_datapath:
# Kernel-only filters (the netem extensions, the eBPF quota mode)
# Kernel-only filters (the netem extensions, the eBPF quota and
# window modes)
# have no relay equivalent. Only enforced on created links — while
# loading a project the datapath is not decided yet (a link that
# will be wired on the kernel datapath must accept them), and the
@@ -723,7 +738,8 @@ class Link:
if self.kernel_datapath:
# Kernel-datapath links serve every filter type: netem for
# delay/loss/corrupt and the netem extensions, cls_bpf for
# bpf, the eBPF classifier for frequency_drop and quota.
# bpf, the eBPF classifier for frequency_drop, quota and
# window_drop.
return FILTERS
# Relay links: hide the kernel-only types the relay cannot run
# (they would be rejected with 409 on update).