The live suite asserted the datapath over IPv4 only. Give every guest a
ULA IPv6 address next to its v4 one and twin every v4 assertion point,
sharing the impairment window (one filter application, both families
asserted) so the runtime grows by minutes, not double.
- harness: configure_ios(eth_ipv6=), ping() dispatches to `ping ipv6`,
docker_bring_up_ipv6 (the Docker daemon leaves eth0 with
disable_ipv6=1 on v6-less bridge networks, so the interfaces-file
route cannot work), family-aware docker_wait_address, pcap_records
scans every record (a leading DAD/MLD frame must not mask the
sampled ethertype), and pcap_icmp_rtt measures the wire round trip
from capture timestamps;
- scenarios: connectivity/delay/suspend/isolation/churn checks in both
families, captures assert 86dd next to 0800, the libpcap bpf drops
are asserted family-selective (icmp vs icmp6, each killing its own
family and leaving the other alive), the eBPF classifier modes on
both families, marker v6 twins with an echo-specific expression
(bare icmp6 also matches DAD/MLD and would break the exact counts),
the v6 sharkd replay, and the link-local matrix gains the 86dd
all-nodes row; serial (HDLC) legs stay v4-only;
- the dynamips-emulated classic IOS under-reports its `ping ipv6` RTT
by ~40 % of a delayed round trip (pcap-verified: the wire carries the
v6 echo exchange in the same ~230 ms as v4 while the console reports
~130 ms), so the dynamips-family scenarios assert the v6 delay from
the capture's own timestamps — recorded in tests/e2e/README.md.
Full suite: 17 passed in 58m50s.
The 'impairment cleared' asserts used avg < 50 on three-packet IOS pings;
the unimpaired baseline is 20-45 ms with 4 ms quantization, and host
scheduling jitter pushed averages to 54/56 in two full-suite runs
(esw, dynamips) — a margin, not an impairment (the qdisc asserts pass,
success is 100 %). The contrasted delayed regime is >= 150 ms, so a
100 ms bound still separates the two cleanly. Docker's sub-millisecond
veth asserts keep their 50 ms bound (three orders of magnitude of
headroom, never observed to flake).
Same guard the ethernet-switch scenario already carries: NetworkManager
can release an NM-managed TAP from its bridge shortly after
(re-)enslavement (docs/bugs/networkmanager-tap-release.md). Applied to
the Dynamips, QEMU, IOU, IOL-runner and switch-cascade scenarios after
their nodes have booted (no-op where nmcli/NetworkManager is absent).
This keeps those tests deterministic on un-declared hosts.
The relay engines' observable paths had no live coverage: every
capture/start call in the suite sat on a kernel anchor (AF_PACKET
capture start_kernel) and markers were only asserted on marker
add_kernel. The two relay engines' own command shapes were unit-tested
only:
* bridge engine - bridge start_capture / bridge add_packet_filter ... mark
* iol_bridge engine - iol_bridge start_capture / iol_bridge add_packet_filter ... mark
Docker relay control (bridge engine, 1 passed 33s): the capture start
REST call writes the ICMP exchange to a pcap off the relay bridge; a
mark filter attached with capture_node_id n1 signals exactly 10
marker.match events over the dedicated marker WS for 5 pings (5
requests + 5 replies, both directions), carrying node_id/link_id/tag and
the busybox frame length, writes exactly those 10 frames to the marker
pcap, and deleting the marker takes the pcap with it.
IOU relay control (iol_bridge engine, 1 passed 173s): the same two
checks on iol_bridge start_capture and the port's mark filter, driven
by the real IOS ping through the fabric socket relay.
Not duplicated in the ESW/VPCS/cloud relay controls: they issue the same
uBridge bridge commands through their own call sites, which stay covered
by unit tests; the IOL container relay goes through the same iol_bridge
engine already exercised here.
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.
The filter matrix (cls_bpf, the eBPF classifier) only ran on Docker veth
host ends; the IOU and IOL-container scenarios now spot-check it on their
TAP anchors and prove a filter survives a node restart:
* bpf "icmp" drops everything with clsact on the anchor, both ends, and
clears back to an empty qdisc;
* frequency_drop 3 (the eBPF every-nth mode) measured 56 % round-trip
loss (1 - (2/3)^2 = 55.6 % expected) in both scenarios;
* the IOU test applies delay 100 before a router stop/start: the fresh
anchor gets netem back (tc level) and the restarted router's pings
measure RTT >= 150 ms until the filter is cleared (a re-attach that
dropped the filter would show ~100 ms).
IOU file 492 s, IOL file 182 s, both green.
Extend the docker and IOU relay negative controls with the filters the
relay itself supports (delay, frequency_drop, bpf), asserted through real
ICMP — the first live coverage of the relay filter path:
* bridge engine (docker): delay 100 grows the RTT by ~200 ms and comes
back on clear; frequency_drop 2 kills the round trips (the filter counts
every packet crossing the bridge, both directions sharing one counter,
so on an alternating ping stream one whole direction dies; verified
against uBridge directly), frequency_drop -1 blackholes, and bpf drops
by libpcap expression ('icmp', then 'greater 150' discriminating by
frame size).
* iol_bridge engine (IOU): the same delay and frequency_drop effects
through the port's iol_bridge filter list, plus the available_filters
spot check.
Docker 33 s, IOU 168 s, both green.
Two real IOU routers on a real L3 image (the image's own IOL fabric, the
real IOS CLI on the server's telnet console), driving the anchor TAPs the
kernel datapath builds on: anchors born with the node (one per Ethernet
bay/unit), real ICMP through the [fabric <-> TAP] port bridge, netem
delay, suspend, capture, link delete/re-create, node stop/start rewiring,
the serial link staying on the relay (serial bays never anchor) and a
relay negative control on an isolated instance. Every scenario ends with
no anchors, bridges or tmpdirs left behind.
harness: create_iou_node/iou_images/iou_anchor_name, and the IOS console
helper is now ios_console (dynamips, IOU and the IOL containers share it).