test(e2e): assert the §E.2 idle-silence window in every kernel scenario

The L2-anchor spec's behavioral guarantee — an idle link stays silent for
5 s once the enslavement burst settles — only ran in the Dynamips and
Docker suites. It now also runs in QEMU, IOU, the IOL container, the
switch fast path and the switch cascade, which covers every host-device
creation path:

* tap create (Dynamips/QEMU/IOU anchors), docker create_veth (Docker host
  ends; the cascade's race-loser end is hardened after create by the
  server), bridge add_nio_tap (the IOL container anchor, the fifth
  creator), and the brctl switch bridges, whose multicast snooping is off
  precisely so the bridge role can reach silence;
* each scenario silences its guests first (IOS interfaces shut through
  the console; Docker guests' links down) and re-verifies the ping after;
* the cascade measures 8 devices at once (four absorbed router anchors,
  both cascade ends, both switch bridges).

IOL 158 s, cascade 293 s, ESW fast path 378 s, QEMU 428 s, IOU 308 s —
all green.
This commit is contained in:
YueGuobin committed 2026-10-06 00:21:10 +08:00
1 parent 1f544c96a5
commit ff41a54364
11 files changed
+166 -16

No files matched your search

+10 -2
View File
@@ -224,8 +224,16 @@ is hardened like the rest — best-effort, before the NIO is handed back.
assertion is what exercises the fifth creator end-to-end (the same
uBridge creation path cloud's transient TAPs take);
- an idle link stays silent for 5 s after the settle window
(`assert_idle_silence`, §E.2) — measured with the guest interfaces shut
(silencing IOS's own CDP/keepalives) over the anchors and the bridge;
(`assert_idle_silence`, §E.2) — measured with the guests silenced (the
IOS consoles' interfaces shut, the Docker guests' links down, all four
cascade routers shut) over the anchors, the per-link bridge and the
switch bridges, in every kernel scenario: Dynamips, Docker, QEMU, IOU,
the IOL container, the switch fast path and the switch cascade. That
covers each creation
path — `tap create`, `docker create_veth` (plus the server-side
harden-after-create on the cascade's race-loser end), `bridge
add_nio_tap` and the `brctl` switch bridges (whose multicast snooping
is off precisely so the bridge role can reach silence);
- a silent-failure guard found while validating this spec: after attach, every
bridge port reports `brport/state == 3` (forwarding) (`assert_forwarding`).
A bridge device left DOWN keeps its ports `DISABLED` (`state == 0`) and
@@ -152,12 +152,14 @@ The cascade has its own in-repo e2e
(`tests/e2e/test_ethernet_switch_cascade.py`): two switches joined by the
link-owned veth pair, two c7200 routers per switch, real ICMP crossing both
bridges — the pair is born UP with exactly one end per bridge, a dot1q
trunk cascade carries two VLANs at once, the symmetric access/trunk mode
flip on the cascade ends isolates and revives a VLAN in place, a `delay`
filter lands as netem on both ends (one per direction, RTT ≈ 2×delay),
suspend admin-downs both ends, and a link delete/re-create retires the whole
pair and mints a new one under the new link id — with zero host residue
after the project goes.
trunk cascade carries two VLANs at once, the §E.2 idle-silence window with
all four router interfaces shut (the absorbed anchors, both cascade ends
and both switch bridges), the symmetric access/trunk mode flip on the
cascade ends isolates and revives a VLAN in place, a `delay` filter lands
as netem on both ends (one per direction, RTT ≈ 2×delay), suspend
admin-downs both ends, and a link delete/re-create retires the whole pair
and mints a new one under the new link id — with zero host residue after
the project goes.
The host-side checks throughout are the kernel's own view: bridge
membership under `/sys/class/net/<bridge>/brif/`, the `master` link
@@ -138,6 +138,9 @@ isolated instance, real `iol-xe/iol-xe:17-18-02` images, real uBridge with
* kernel link reports `kernel_datapath`, anchors exist from node start, the
per-link bridge enslaves exactly the two of them;
* real ICMP crosses the [unix ↔ tap] port-bridge relay (100 % ping);
* the L2-anchor spec §E.2 silence window with the guests shut — the
behavioral half of the hardening on anchors created by uBridge's bridge
TAP module (`bridge add_nio_tap`);
* `delay 100` lands as netem on both anchors, measured RTT grows ≥ 150 ms
and returns < 50 ms when cleared;
* the classifier spot check on a TAP anchor (the Docker suite runs the full
+3 -2
View File
@@ -145,8 +145,9 @@ net for the port-coordinate capture restore this work touched.
The repository's live e2e suite carries the same scenario with **real
IOU routers** (`tests/e2e/test_iou_kernel_datapath.py`, pytest marker
`e2e`): a real L3 IOU image provides the fabric and the real IOS CLI on
the server's telnet console, driving anchors-born-with-the-node, real ICMP
through the port bridge, netem delay, the TAP-anchor classifier spot check
the server's telnet console, driving anchors-born-with-the-node, the §E.2
idle-silence window with the guests shut, real ICMP through the port
bridge, netem delay, the TAP-anchor classifier spot check
(bpf match-drop; the eBPF every-nth mode at 56 % measured round-trip loss,
55.6 % expected), suspend, capture, link delete/re-create, node
stop/start rewiring with a delay filter restored on the fresh anchor
+4 -3
View File
@@ -141,9 +141,10 @@ expected), no kernel bridge holding the tap.
The repo suite `tests/e2e/test_qemu_kernel_datapath.py` covers the same
ground with a *real* guest: two IOSv routers (a real qcow2 image, linked
clone, the real IOS CLI on the telnet console) — the full kernel lifecycle
(anchors at start, per-link bridge membership, pure-L2 anchors, real ICMP,
netem delay, suspend, capture, link delete/re-create, node stop/start
rewiring, zero residue on project delete) plus the relay negative control,
(anchors at start, per-link bridge membership, pure-L2 anchors, the §E.2
idle-silence window with the guests shut, real ICMP, netem delay, suspend,
capture, link delete/re-create, node stop/start rewiring, zero residue on
project delete) plus the relay negative control,
where the anchor is up and carrying as the relay's AF_PACKET endpoint (QEMU
has no other leg — the TAP is the netdev on the relay too). It needs an L3
IOSv image in the images directory's `QEMU` subfolder; a raw node must also