mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 20:46:52 +01:00
tun: Add opt-in staged transmit processing
Set tun.staged.workers to a positive count on Linux, with tun.use_offloads
enabled, to move encryption off each tun reader. The reader filters and
reserves counters for a whole read, hands the batch to that many encrypt
workers, and an ordered sender flushes the batches in read order. Eight slots
per routine bound the batches in flight; a full pipeline blocks the reader.
Zero workers, the default, keeps today's inline path, as do tun queues that
cannot hand off their read buffer and builds whose AES-GCM needs nonce-ordered
encryption (BoringCrypto, FIPS).
IMPORTANT: staged senders need peers with the 8192-entry replay window of
master. Released v1.11.x peers use 1024 and will drop reordered batches. The
window is not negotiated.
Readers keep today's pinning. The sender is only pinned with an explicit
tun.cpu_affinity: sender i uses entry i+1, unless that is its reader's CPU,
so a one-entry list leaves the sender unpinned rather than sharing it: two
busy transmit threads on one CPU serialise (eight TCP streams over 100 GbE
fell from 25.9 to 22.8 Gbit/s). Without a list the sender is not pinned. Placing it by queue index on a
hybrid CPU put it on an efficiency core, and one TCP stream over 100 GbE
reached 18.6-19.6 Gbit/s pinned against 20.2-20.6 unpinned.
New API, each needed across a package boundary:
- tio.Offload.SwapRxBuf hands the buffer of the last Read to the reader and
reads into the one given. It is a method on the concrete queue, found through
an unexported interface in nebula, so tio.Queue and its other
implementations are unchanged.
- batch.SendBatch.Reset drops queued packets without sending, for a sender
whose sockets are already closed; Flush now uses it.
Metrics, registered only for active pipelines: flow.tx.batches counts reads
handed to the sender, flow.stage.{tx_read,tx_encrypt,tx_send}.q<N>.busy_ns the
elapsed busy time of each stage, to find the limiting one.
Tests cover ordering and counters under backpressure with both ciphers (AES
skipped where nonce order is required), read errors with batches in flight,
shutdown, exhaustion, relays, fallback, firewall parity, and the actual reader
and send thread affinity for every placement, with pinning on and off: the
sender is pinned only to an explicit entry other than its reader's CPU.
This commit is contained in:
1 parent
6146f3e4a6
commit
f3f98e1690
11 files changed
+832
-24
No files matched your search
+12
-1
@@ -275,9 +275,18 @@ tun:
|
||||
# the use_offloads setting controls if Nebula will attempt to enable GSO and GRO for the tun device. Linux only, not reloadable.
|
||||
#use_offloads: false
|
||||
|
||||
# Linux only. staged.workers enables staged packet processing: each routine hands its batches to this many crypto
|
||||
# workers per direction, then sends or writes them in order. 0, the default, keeps processing inline. Not reloadable.
|
||||
# Transmit needs use_offloads; BoringCrypto and FIPS builds keep it inline because AES-GCM there needs ordered nonces.
|
||||
# IMPORTANT: staged senders require peers with at least the 8192-entry replay window of this release. Released
|
||||
# v1.11.x peers use 1024 and are incompatible. The window is not negotiated.
|
||||
#staged:
|
||||
# workers: 0
|
||||
|
||||
# Linux only. pin_threads pins each tun reader/encrypt OS thread to a single CPU. This keeps every goroutine's
|
||||
# batched sends flowing through one XPS-selected NIC TX ring, so packets within a flow stay ordered on the wire
|
||||
# instead of being sprayed across multiple TX rings and reordered. Not reloadable. Coerced to false if routines <= 1.
|
||||
# Staged senders are only pinned with an explicit cpu_affinity, see below; otherwise the scheduler places them.
|
||||
#pin_threads: true
|
||||
|
||||
# pin_threads_key helps the CPU-auto-selector shuffle which CPUs are chosen for pinning.
|
||||
@@ -287,7 +296,9 @@ tun:
|
||||
|
||||
# Linux only. cpu_affinity overrides which CPUs the tun reader threads pin to: a list of CPU IDs, one per routine
|
||||
# (see the top-level `routines` setting). Lists shorter than `routines` are modulo-cycled across the queues; extra
|
||||
# entries are ignored. IDs must be within the process's allowed CPU set, so this respects taskset / cgroup cpusets;
|
||||
# entries are ignored. Staged sender i pins to entry i+1, modulo-cycled the same way, unless that is its reader's
|
||||
# CPU, as with a one-entry list: a sender never shares its reader's CPU and stays unpinned instead.
|
||||
# IDs must be within the process's allowed CPU set, so this respects taskset / cgroup cpusets;
|
||||
# a non-integer or not-allowed entry disables the override, leaving the default pin selection described below.
|
||||
# Only meaningful while pin_threads is true. Not reloadable.
|
||||
# When unset (or rejected), the default spread prefers performance cores on heterogeneous CPUs (ARM big.LITTLE,
|
||||
|
||||
Reference in new issue
Block a user