From c988ede19c68e3fc0dbca0c5bbf020402aa3b30e Mon Sep 17 00:00:00 2001 From: yueguobin Date: Mon, 26 Oct 2026 11:33:24 +0800 Subject: [PATCH] docs: state the Linux 6.6 requirement of the netem seed filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aligns with uBridge's tc.md correction: TCA_NETEM_PRNG_SEED (uapi slot 14, added in Linux 6.6 — not the nonexistent TCA_NETEM_SEED at "5.1") is what the seed filter rides on; pre-6.6 kernels parse qdisc options non-strictly and silently drop the attribute, so seed determinism is unavailable there while every other netem knob applies. Stated in both filter tables and the seed section of packet-filters.md, the seed rows of the MCP and copilot tool descriptions, and the kernel-impairment spec. --- docs/design/ubridge-kernel-impairment-spec.md | 10 ++++++++-- docs/features/packet-filters.md | 6 +++--- .../agent/gns3_copilot/tools_v2/gns3_packet_filter.py | 3 ++- gns3server/agent/mcp/__init__.py | 3 ++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/design/ubridge-kernel-impairment-spec.md b/docs/design/ubridge-kernel-impairment-spec.md index 94446b8e6..9a84b1af7 100644 --- a/docs/design/ubridge-kernel-impairment-spec.md +++ b/docs/design/ubridge-kernel-impairment-spec.md @@ -142,8 +142,14 @@ direction, `loss gemodel 5 45 100` drops 10 %. (normal / pareto / paretonormal — same values iproute2 ships as `*.dist`, generated by netem's `maketable`) as const arrays in uBridge; select by name. Without DIST the kernel silently uses uniform jitter. -* seed: `TCA_NETEM_SEED` (u64 allowed) — makes random draws reproducible - for tests. When omitted keep the current behaviour (kernel picks). +* seed: `TCA_NETEM_PRNG_SEED` (u64; uapi slot 14, introduced in Linux 6.6) + — makes random draws reproducible for tests. When omitted keep the + current behaviour (kernel picks). Pre-6.6 kernels parse the qdisc + options non-strictly and silently drop the attribute: determinism is + unavailable there while every other knob still applies. A build against + pre-6.6 `linux/pkt_sched.h` must define the constant behind a + `LINUX_VERSION_CODE` guard (enum constants are invisible to the + preprocessor, so `#ifndef` cannot detect them). ### A.3 Reply contract (unchanged shape) diff --git a/docs/features/packet-filters.md b/docs/features/packet-filters.md index cc67ff230..48149f0ef 100644 --- a/docs/features/packet-filters.md +++ b/docs/features/packet-filters.md @@ -76,7 +76,7 @@ On the kernel datapath the 13 types ride three kernel objects on the anchor. The | `rate ["512kbit"]` | netem `rate B` | tc-style integer+unit (bit/kbit/mbit/gbit/bps/kbps/mbps, ≤100gbit); kernel-only type | | `reorder [%, correl, gap]` | netem `reorder P [correl C] [gap G]` | requires `delay`; kernel-only type | | `gemodel [p, r, 1-h]` | netem `loss gemodel P R H` | Gilbert-Elliot bursty loss: p = good→bad transition, r = bad→good transition, 1-h = loss chance in the bad state (good loses nothing) — mean one-way loss p/(p+r)×(1-h); mutually exclusive with `packet_loss`; kernel-only type | -| `seed [u32]` | netem `seed N` | reproducible random draws; kernel-only type | +| `seed [u32]` | netem `seed N` | reproducible random draws; kernel-only type — seeded draws need Linux ≥ 6.6, older kernels silently ignore the seed (every other knob applies) | | `limit [pkts]` | netem `limit N` | queue depth above the 1000 default (rate+delay BDP); kernel-only type | | `bpf` (one line per expression, OR) | `tc bpf_drop add ""` — cls_bpf on clsact egress + gact drop | needs uBridge `cbpf=1` (`tc capabilities`, probed once per uBridge process); a line that fails to compile on the compute is skipped with a warning, mirroring the relay | | `frequency_drop [N]` | `tc nth_drop N` — the eBPF stateful classifier's exact every-Nth mode (clsact egress prio 1) | needs uBridge `ebpf=1`; -1 = drop everything → every 1st; per-direction counters (see below) | @@ -96,7 +96,7 @@ The API surface of the 13 types — parameters, ranges and cross-filter rules, v | `rate` **K** | Bandwidth limit | Rate — tc-style string, e.g. `"512kbit"` (≤ 100gbit) | integer + unit; bps-family units count bytes/s | | `reorder` **K** | Reorder | Reorder (0…100 %) · Correlation (0…100 %) · Gap (1…1000 packets) | requires `delay` | | `gemodel` **K** | Gilbert-Elliot loss | p (good-to-bad) · r (bad-to-good) · 1-h (bad-state loss) (each 0…100 %) | mutually exclusive with `packet_loss` | -| `seed` **K** | Random seed | Seed (0…4294967295) | pins the netem draws only | +| `seed` **K** | Random seed | Seed (0…4294967295) | pins the netem draws only; reproducibility needs Linux ≥ 6.6 | | `limit` **K** | Queue limit | Limit (1…1000000 packets) | queue depth above the 1000 default | | `bpf` | Berkeley Packet Filter (BPF) | Filters — text, one expression per line | any match drops | | `frequency_drop` | Frequency drop | Frequency (−1…32767) | −1 drops everything; 0 disables | @@ -229,7 +229,7 @@ Choosing parameters: pick the target mean M and average burst length L (packets) |---|---| | Seed (0…4294967295) | the netem PRNG seed | -**Note**: pins the netem draws only — the eBPF percentage draws (quota, window) ride a PRNG seeded at program load, outside `seed`'s reach; any filter-set change resets schedules and counters. Two more boundaries: reproduction also requires the same traffic pattern (draws are consumed per arriving packet — classifier-stage drops upstream change the sequence), and a fixed seed pins one realization, not the distribution — for statistical conclusions (average throughput under loss) run several seeds. +**Note**: pins the netem draws only — the eBPF percentage draws (quota, window) ride a PRNG seeded at program load, outside `seed`'s reach; any filter-set change resets schedules and counters. Two more boundaries: reproduction also requires the same traffic pattern (draws are consumed per arriving packet — classifier-stage drops upstream change the sequence), and a fixed seed pins one realization, not the distribution — for statistical conclusions (average throughput under loss) run several seeds. One more: the seeded PRNG itself is a Linux 6.6 addition — on older kernels the seed attribute is silently ignored (no error), the draws stay random while every other netem knob applies. **Example**: `{"packet_loss": [10], "seed": [42]}`. diff --git a/gns3server/agent/gns3_copilot/tools_v2/gns3_packet_filter.py b/gns3server/agent/gns3_copilot/tools_v2/gns3_packet_filter.py index b643a26f0..0bb83eba1 100644 --- a/gns3server/agent/gns3_copilot/tools_v2/gns3_packet_filter.py +++ b/gns3server/agent/gns3_copilot/tools_v2/gns3_packet_filter.py @@ -133,7 +133,8 @@ class GNS3PacketFilterTool(BaseTool): - "gemodel": Gilbert-Elliot bursty loss (parameters: p good-to-bad transition, r bad-to-good transition, 1-h loss in the bad state; mean loss = p/(p+r)*(1-h); kernel links only) - "duplicate": Packet duplication percentage (kernel links only) - - "seed": Reproducible netem random draws (kernel links only) + - "seed": Reproducible netem random draws (kernel links only; needs kernel >= 6.6 - + older kernels silently ignore the seed) - "limit": Impairment queue depth in packets (kernel links only) - "quota": Byte cap — after the quota, drop with a chance (parameters: bytes, chance; kernel links only) diff --git a/gns3server/agent/mcp/__init__.py b/gns3server/agent/mcp/__init__.py index 2a39bdb5f..541e8793c 100644 --- a/gns3server/agent/mcp/__init__.py +++ b/gns3server/agent/mcp/__init__.py @@ -829,7 +829,8 @@ async def link_update( steady-state mean loss = p/(p+r)*(1-h) per direction; mutually exclusive with packet_loss * duplicate (K): [pct, correl?] - Duplication percentage - * seed (K): [u32] - Makes netem random draws reproducible + * seed (K): [u32] - Makes netem random draws reproducible (needs + kernel >= 6.6; older kernels silently ignore the seed) * limit (K): [pkts] - Impairment queue depth (default 1000; raise for low rate + long delay) * quota (K): [bytes, pct] - After the byte quota is consumed, each