Kernel channel-switch baseline: measured matrix + go/no-go for standard-driver FHSS (exp 1/5)#313
Merged
Merged
Conversation
The per-frame rx.frame stream was hard-gated to the canonical TX SA, so an
RX oracle could not observe a foreign transmitter (a kernel-driver DUT's own
MAC address). When DEVOURER_RX_AGG_SA is set, its filter now also selects
the stream ("canon"/mac/"any"); unset keeps the historic canonical-only
stream byte-for-byte. rx.frame gains the matched SA as a hex field so an
"any"-gated consumer can attribute frames per transmitter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Measures the channel-switch primitives a standard Linux/Realtek kernel
driver exposes — monitor set-channel, AP/CSA (wpa_supplicant AP mode),
remain-on-channel, single-freq active scan, TDLS capability, vendor MCC
attempt — with ftrace instrumentation (cfg80211/mac80211 events + kchansw/
kprobes on driver internals, trace_clock=mono) and a mandatory on-air
oracle: two devourer rxdemo receivers pinned to the source/destination
channels plus a 2 kHz tagged-frame injector whose payload trailer
(magic+nonce+counter+send-mono-ns) survives kernel seq rewrites. A switch
whose API succeeded without destination-channel RF evidence is a failed
measurement.
kchansw_bench.py orchestrator (inventory/smoke/phase-a/cold/phase-b/-c);
reuses regress.py's adapter bind/VBUS/process machinery
kchansw_trace.py tracefs session ctx-mgr, kprobe group, markers, cleanup
kchansw_inject.py AF_PACKET paced injector with per-frame send log
kchansw_analyze.py offline: tsfl→mono robust fit, per-switch CSV,
median/p90/p99/max, <5/5-20/>20 ms gate verdicts;
--self-test fabricates a run with known truth
kchansw_vendor_build.sh build reference/rtl88x2bu with CONFIG_TDLS=y
CONFIG_MCC_MODE=y (H2C 0x1C ch-sw offload + MCC family),
insmod rtw_wifi_spec=1, restore in-tree binding
kchansw_setup.sh venv + preflight + launch wrapper
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…aced Session-0 findings folded back into the harness: - tracefs kprobe_events rejects python text-mode append (its open() lseeks to EOF; tracefs → EINVAL): write through a raw O_APPEND fd. Disarm the kchansw/ event group before probe removal (armed kretprobes → EBUSY). - rtw88_8822bu wedges under sustained monitor injection: once as a full USB disconnect (ENODEV, dmesg shows EPROTO then disconnect), once as silent TX (sends ack fine, nothing airs, dmesg clean). Detect both — ENODEV from iw, and an oracle frame-progress stall — and recover through a ladder (re-probe → module reload → authorized/VBUS cycle), respawning the injector; every later row is flagged post_recovery, so the wedge count itself becomes the endurance datum. - oracle liveness gate now counts rx.frame decodes, not stdout lines. - default oracle A is the 8821AU: the 8812AU in its bench position decodes <10% of near-field injector frames (60% CRC-broken at RSSI ~68) while the 8821AU/8812CU decode 90-97% clean. - vendor build: TDLS and MCC are mutually exclusive (drv_conf.h #errors; MCC additionally needs CONCURRENT_MODE=y + BT_COEXIST=n) — VARIANT=tdls and VARIANT=mcc build modes replace the combined attempt. - headline phase-a config runs 2× switches (≥1000 per direction). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix the ko path, lsmod checks and module name; the earlier missing-symbol warning was the wrong filename — rtw_hal_ch_sw_oper_offload is present in the TDLS-variant build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The headline run escalated past every soft recovery: the T3U wedged its uPD720201 host controller outright (re-probe -110), and only a PCI bus reset + D3hot→D0 bounce + rescan followed by a 12 s per-port power-off brought it back — re-enumerated on the USB2 companion bus. Encode that as the ladder's final rung (with VID:PID rediscovery, since recovery moves the device across buses), verify DUT aliveness between configs, add ROC-specific distributions (grant/dwell/return) to the analyzer, and add tests/kchansw_b210_gap.py — a partial-band B210 energy-gap probe that compares energy-silence gaps against decode-derived gaps statistically, needing no cross-clock alignment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…he host Kprobing was innocent: the vendor TDLS-variant build (no CONCURRENT_MODE) livelocks the kernel in its cfg80211 add-interface op with RTNL held (ssh dead, dmesg blocked, no panic — power cycle to recover), isolated step-by-step after it took the host down twice via the ROC config's injector monitor vif. phase-b-vm runs the DUT + trace session inside the pinned-kernel VM (kchansw_vm.sh prepare/mcc/restore + kchansw_vm_dut.py), oracles stay on the host, and a min-RTT-midpoint ssh probe maps the VM clock onto the host timeline (analyzer applies meta vm_clock_shift_ns; VM-internal spans are shift-invariant). The host phase-b path is gated behind KCHANSW_HOST_VENDOR_OK=1. ROC on the vendor build is trace-only (no second vif possible); the MCC attempt uses the auto-created CONCURRENT_MODE vif and the mcc/ proc directory, persisting each step so a mid-step wedge loses nothing. udev's wlan0->wlxMAC rename race gets a settle+re-resolve in dut_up and the helper bring-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Full like-for-like matrix for issue 269: rtw88_8822bu (set-channel / ROC / scan / CSA-policy-rejected / cold / endurance incl. the USB3 wedge ladder), the vendor rtl88x2bu in the VM (set-channel 36<->40 dead-air median 1.08 ms p99 4.42 ms -> ADVANCE, 48x under rtw88 on the same silicon; trace-only ROC; MCC machinery live to mcc_enable=1), and rtw89_8852bu (set-channel 31 ms; CSA works — TBTT-quantized ~1-2 beacon intervals; hardware ROC 53 ms grant). Go: exp-2 targets rtw_hal_ch_sw_oper_offload -> H2C 0x1C, exp-3 the MCC H2C 0x10/0x11/0x18/0x19 family. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #269.
Measurement-only experiment: a like-for-like latency/behavior matrix of every channel-switch primitive the standard Linux/Realtek kernel drivers expose on devourer-supported silicon, with kernel-side instrumentation (ftrace
trace_clock=mono, cfg80211/mac80211 events, grouped kprobes) and a mandatory on-air oracle — two devourerrxdemoreceivers whose MAC-latchedtsfltimestamps are mapped to host time by a robust linear fit (σ 40–280 µs), so dead air is measured at the RF, not at the API.Headline results (full note:
docs/kernel-channel-switch-baseline.md)The silicon retunes in ~1 ms; rtw88's 52 ms is its software sequence. Host-command latency alone (the number an API benchmark would report) overstates the 2.4 GHz RF transition by 14× — the oracle is not optional.
Go: exp-2 (#270) targets
rtw_hal_ch_sw_oper_offload→ H2C 0x1CCHNL_SWITCH_OPER_OFFLOAD(compiled + runtime-armed in the exact module that measured 1.08 ms); exp-3 (#271) targets the MCC H2C 0x10/0x11/0x18/0x19 family (verified live throughmcc_enable=1).What's in the PR
tests/kchansw_{bench,trace,inject,analyze}.py+kchansw_setup.sh— the reusable harness (tracefs session mgr with grouped kprobes + clean teardown, 2 kHz tagged injector immune to kernel seq rewrite, offline analyzer with--self-test, wedge-recovery ladder up to a PCI controller revive).tests/kchansw_vm.sh+kchansw_vm_dut.py— the vendor phase runs in the pinned-kernel VM: the vendor TDLS-variant build livelocks the kernel in its cfg80211 add-interface op with RTNL held (took the host down twice before isolation; reproducible on demand). DUT is USB-passed-through, oracles stay host-side, VM clock bridged by a min-RTT-midpoint probe (±0.15 ms); the host insmod path is gated behindKCHANSW_HOST_VENDOR_OK=1.tests/kchansw_vendor_build.sh— TDLS/MCC variant builds of thereference/rtl88x2bufork (mutually exclusive families); submodule gains two kernel-compat commits (tdls_mgmt link_id≥ 6.0,timer_container_of≥ 6.16).tests/kchansw_b210_gap.py— B210 partial-band energy probe quantifying the decode-vs-energy oracle bias.examples/rx/main.cpp—rx.frameper-frame events followDEVOURER_RX_AGG_SAand carry ansafield (default behavior unchanged); the oracle enabler.docs/kernel-channel-switch-baseline.md— method, capability matrix, distributions, endurance/USB-link findings, go/no-go.Raw per-switch CSVs stay in
/tmp(regenerable); the doc carries the summary tables per the agreed scope.🤖 Generated with Claude Code