pin tun reader threads to CPUs so per-flow packets keep wire order

Each listenIn goroutine locks its OS thread and pins it to one CPU
(sched_setaffinity), so every UDP send from that goroutine leaves
through the same XPS-selected NIC TX ring instead of being sprayed
across rings and reordered. On by default via tun.pin_threads; queue i
pins to the i-th entry of the process's allowed CPU set (respecting
cpuset/taskset masks, whose IDs are often not 0..NumCPU-1), or to an
explicit tun.cpu_affinity list, validated against that same allowed
set. Linux only; pinning is a no-op elsewhere.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
JackDoan
2026-07-16 12:25:23 -05:00
parent 913a37cfee
commit 10e9514e44
6 changed files with 242 additions and 2 deletions
+18
View File
@@ -0,0 +1,18 @@
//go:build !linux || android || e2e_testing
package util
// PinThreadToCPU is a no-op outside Linux: only Linux exposes a stable
// per-thread CPU affinity API and only Linux has XPS-driven TX ring
// selection in the first place. On every other platform there's nothing
// to fix here.
func PinThreadToCPU(_ int) error {
return nil
}
// AllowedCPUs has no meaningful answer off Linux (no sched_getaffinity), so it
// reports "unknown" by returning a nil slice and nil error. Callers treat an
// empty result as "fall back to the default CPU choice".
func AllowedCPUs() ([]int, error) {
return nil, nil
}