Wi-Fi Packet Aggregation and Control Bursts: Measure Tail Latency Before Changing Drivers
Packet aggregation can improve airtime efficiency, but a late control burst does not prove that aggregation caused the delay. Separate application batching, host queue residence, active aggregation state, radio transmission and receiver processing. Then compare matched workloads and supported configuration changes. A driver patch should follow that evidence, not substitute for it.
This guide uses Linux 6.12 mac80211’s driver contract as the inspectable reference. It assumes an active, single-link infrastructure connection with power-save behavior controlled and documented. FullMAC firmware can hide the equivalent state, and newer multi-link scheduling requires separate analysis. This is not a DTIM or first-command-after-sleep investigation.
Distinguish the aggregation layer and its owner
A-MSDU and A-MPDU are different aggregation mechanisms, and A-MSDUs can also be carried within an A-MPDU. Do not use an undifferentiated “aggregation enabled” label for the entire path. Identify the actual mechanism, direction, peer and traffic identifier, then establish whether the host, driver or firmware chooses the batches. The Linux Wireless 802.11n review provides the terminology; it is rolling background documentation, not a specification of a product’s current limits. Linux Wireless 802.11n review
Linux 6.12’s ieee80211_ampdu_params identifies the peer and TID for an aggregation session. Its action contract distinguishes starting TX aggregation from reaching the operational state. Therefore, a capability bit or a start request is weaker evidence than an operational session and observed aggregated transmission. Record those separately. Linux 6.12 mac80211 aggregation API
There is also a request/status distinction. IEEE80211_TX_CTL_AMPDU requests transmission as part of an aggregate; IEEE80211_TX_STAT_AMPDU reports aggregate-level status. The latter is not a per-application-record completion timestamp. A missing block-ack status is useful error evidence, but it does not directly measure queue residence or identify which application operation became late.
Choose timestamps that expose batching
| Boundary | Record | Question answered |
|---|---|---|
| Application release | Burst ID, record sequence, intended release time | Was the producer already late? |
| Socket/stack submission | Actual submit time and accepted size | Did application buffering delay the record? |
| Driver/radio boundary | Supported enqueue, aggregate and TX-status evidence | Where did active-link scheduling hold work? |
| Receiver delivery | Record validation time and sequence | Did the final application receive the complete burst? |
Timestamp names must describe real events. A callback labeled “sent” may mean only that a buffer can be reused. An aggregate status can cover several frames, and a packet capture may observe only part of the exchange. Use supported tracing and document missing boundaries rather than assigning one timestamp to every record without evidence.

Run a matched burst-versus-stream experiment
- Establish the active-link baseline. Keep association, security, lawful channel configuration, peer and supported power policy fixed. Verify that the experiment does not cross a sleep/wake transition, roam or background scan that explains the gap independently.
- Define the burst contract. Choose record size, records per burst, inter-record spacing and inter-burst interval from the product workload. Give each burst an identity and an explicit completion deadline.
- Compare equal useful offered load. Contrast small bursts with a smoother stream using the same total useful bytes and comparable duration. Keep transport, socket options and receiver work fixed. An equal average byte rate does not make the instantaneous queue pattern equal; that difference is the experimental variable.
- Observe the actual aggregation state. Record the relevant peer/TID session and supported TX-status information. If firmware provides only a cumulative aggregate counter, state that it cannot resolve a particular late burst.
- Separate load and batching changes. Repeat at representative and lower offered load before modifying aggregation policy. If the tail disappears merely by reducing load, inspect queue residence and scheduling rather than assuming a specific aggregation timer.
- Compare one supported aggregation control. Only in an authorized test setup, apply the vendor-supported change and verify its effective state. Preserve the original configuration for restoration. Never assume a generic driver flag controls every mechanism or direction.
Repeat enough independent bursts to characterize the chosen tail metric, retain failures and report the sample count. Avoid a single long transfer whose initial and final behavior is hidden inside an average. Also record retry/failure evidence and useful throughput: reducing batching can change airtime efficiency and move the bottleneck rather than simply remove delay.
Measure the whole operation, not its first packet
Define complete-burst latency as the latest required receive/validation time minus the common burst-release time. For a hypothetical three-record command, receive offsets from that common origin are 1, 2 and 3 ms for one burst, and 1, 2 and 80 ms for another. Both first records arrive at offset 1 ms, but complete-burst latencies are 3 and 80 ms. These offsets are not individual send-to-receive delays. If the third record never arrives by the observation cutoff, report an incomplete burst rather than computing its completion from the two survivors. For staggered releases at offsets 0 and 100 ms with individual delays of 20 and 5 ms, completion is 105 ms from burst release; taking the maximum individual delay would incorrectly report 20 ms. These values are synthetic examples, not RF measurements.
Keep delivered-record percentiles, complete-burst percentiles, missing records and missed burst deadlines separate. State the percentile convention and the number of completed bursts included. A low p99 among completed operations can coexist with unacceptable incomplete operations. For one-way latency, include clock uncertainty; otherwise use a clearly defined same-clock round-trip measurement with its additional processing costs.
Interpret a configuration comparison conservatively
If a supported aggregation change reduces tails while operational-state and TX evidence show the intended mechanism changed, the result supports a configuration-specific relationship. It still does not prove a universal aggregation delay. Check whether rate selection, retry behavior, CPU work or effective offered load changed at the same time.
If the delay exists before socket submission, investigate application batching first. If it appears after prompt receiver delivery, investigate application scheduling. If the hardware boundary is invisible, report an unresolved driver/firmware interval and supply the vendor with correlated burst IDs and state snapshots. Do not invent a fixed aggregation wait from the observed pause.
For driver work, preserve the 6.12 session lifecycle contract. The documented stop actions distinguish continuing queued packets without aggregation from flushing them during station removal. Changing those paths casually can alter loss and lifetime behavior. A latency experiment does not authorize violating teardown rules. Linux 6.12 ieee80211_ampdu_mlme_action
Test status and release gate
A Python 3.12.14 fixture verified the synthetic complete-burst calculations, including a missing record and staggered releases that expose the difference between common-origin completion and individual latency. It did not emulate aggregation, access a radio or modify a driver. All target comparisons above remain proposed work.
Release a change with the exact mechanism, owner, peer/TID scope, latency distribution, incomplete-operation count and throughput trade-off. The useful outcome is a reproducible active-link explanation, not a general instruction to disable aggregation whenever a control packet is late.