With direct dispatch, the receive task transmits each forwarded packet
from within if_input(), and on a lightly used ring every packet rings
the doorbell. 4a0ec469934a stopped iflib from ringing when nothing was
pending, which took three register writes per packet down to one; this
rings the remaining one once per receive batch. On an Intel I226 (igc)
a write costs about 400 cycles, a fifth of the cost of forwarding a
packet with pf disabled.
For the whole of a receive task's pass over its ring, including the LRO
flush, the transmit queues it uses defer their doorbells, and the task
rings each of them once at the end of the pass. The whole pass is
covered, not just the if_input() call after it, because with LRO
enabled and IP forwarding on, tcp_lro_queue_mbuf() hands each packet to
if_input() from inside the receive loop; igc, em, igb, ix and ixl
enable LRO by default. A queue defers only while it is at most an
eighth full, where iflib_txd_db_check() would ring for every packet;
above that iflib already batches on its own. Both the mp_ring and the
simple transmit paths take part. Other transmitters, such as the
transmit task when tx_abdicate is set, ring as before, and nothing
changes when net.iflib.min_tx_latency is set. Batched doorbells are
off by default until they have been exercised on more drivers;
net.iflib.tx_db_batched=1 turns them on, at any time.
The batch lives on the receive task's stack and the task's thread
points at it (td_netbatch), so the transmit path finds it with one load
and a thread that preempts the task does not take part. A queue is
held by one batch at a time, which links it into a list to ring at the
end, and on the mp_ring path the transmit task leaves such descriptors
to the batch: taking over the ring for them would move the draining to
a task that rings per packet, and a backlog builds whenever it falls
behind. mlx5en has held its send queues' doorbells during receive
processing since 2d5e5a0d75b0; DragonFly's ifq staging and OpenBSD's
transmit mitigation batch packets at the ifq layer instead.
Sponsored by: Rubicon Communications, LLC ("Netgate")