Commit Graph

873 Commits

Author SHA1 Message Date
JackDoan fbcdd83359 overlay/tio: log dropped tun reads with bad virtio headers
decodeRead failures were silently swallowed; a kernel emitting an
unnegotiated GSO type would blackhole all tun traffic with nothing in
the logs. Debug-gated per the usual idiom so the happy path pays
nothing, which means plumbing the logger down through the offload
queueset.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ugV2edVqoz3tBvq9J6yWp
2026-07-29 17:16:47 -05:00
JackDoan e9870686c8 overlay/tio: error on multi-segment WriteGSO with a bogus IP version
gsoTypeFromProto returns GSO_NONE when the IP version nibble is
neither 4 nor 6, so a multi-fragment superpacket went out as one
silent jumbo GSO_NONE packet -- exactly the silent mis-emission the
geometry checks promise not to allow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ugV2edVqoz3tBvq9J6yWp
2026-07-29 17:14:04 -05:00
JackDoan 9ce0596f5c tun: don't leak the QueueSet shutdown eventfd when Add fails
Both newTunGeneric error branches closed only the tun fd; the
Add-failure branch left the freshly created QueueSet (and its
shutdown eventfd) orphaned.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ugV2edVqoz3tBvq9J6yWp
2026-07-29 17:12:46 -05:00
JackDoan 7455ac56eb outside: drop oversized test requests regardless of log level
The return lived inside a log-level-gated else-if, so with debug
logging off, control fell out of both switches. Nothing follows the
switch today, making it a silent drop by luck; any future code added
after the switch would have run for oversized Test requests only when
debug logging was disabled. Make the drop a guard clause.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014ugV2edVqoz3tBvq9J6yWp
2026-07-29 17:11:58 -05:00
JackDoan 0b0e45582a small bugs 2026-07-29 14:33:20 -05:00
JackDoan d43bb81ae2 batch stuff 2026-07-29 14:12:16 -05:00
JackDoan 8c06802f5f UDP stuff 2026-07-29 13:19:25 -05:00
JackDoan 5a8014585d silly e2e 2026-07-29 12:07:41 -05:00
JackDoan ffab005f9d dead code 2026-07-29 12:02:05 -05:00
JackDoan 38f11f6e3a udp: drop dead cmsg write 2026-07-29 11:59:29 -05:00
JackDoan 095a421708 silly opinionated tweak 2026-07-29 11:54:34 -05:00
JackDoan b39bae57ec tio.Offload.WriteGSO: reject 0-len packets, check seg lengths 2026-07-29 11:51:12 -05:00
JackDoan 5c0f6e2b5f unslop, improve the tio interface 2026-07-28 16:20:14 -05:00
JackDoan df8955177e unslop a bit 2026-07-28 15:00:33 -05:00
JackDoan 5c2a5607e5 unslop a bit 2026-07-28 14:56:51 -05:00
JackDoan ed88422770 unslop a bit 2026-07-28 14:42:04 -05:00
JackDoan 0b817c50b3 rework tun-side segmenentation checksums 2026-07-28 14:10:59 -05:00
JackDoan db54e05bfe checkpt 2026-07-28 12:17:55 -05:00
JackDoan 46a02b663e virtio: reject the GSO_ECN qualifier on non-TCP GSO types
35596c7 added the udp-l4-ecn-rejected test but only the ECN mask, so
UDP_L4|ECN validated as plain UDP_L4. Mirror virtio_net_hdr_to_skb and
refuse ECN on anything but TCPV4/TCPV6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 10:54:03 -05:00
JackDoan b7d06615c0 Revert "tun: default pin_threads off"
This reverts commit fcf59343bd66dd3c879c8293c1429e95d9fd3ee2.
2026-07-27 16:23:34 -05:00
JackDoan 3803146bc9 improve WriteGSO again 2026-07-27 16:23:34 -05:00
JackDoan f9eb86df9d udp: smoke-test that GSO actually engages, on real sockets in CI
Nothing previously asserted the offload path works end to end -- a
silent fallback to per-packet sends would pass every test and only show
up as a throughput regression. Send a batch through a real StdConn over
loopback and assert (a) the run left as a single sendmmsg entry (GSO
engaged, via a spy around the real syscall) and (b) the kernel carved
the superpacket back into the exact original datagrams at the receiver.
Fails rather than skips when the probe reports no GSO on a UDP_SEGMENT-
capable kernel, so CI (make test, ubuntu-latest) guards engagement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:23:34 -05:00
JackDoan 66cb98e13a udp: test the partial-sendmmsg rewind
The rewind (resume after the kernel accepts fewer entries than
submitted) was the hairiest untested logic in the write path; a bug
there silently duplicates or loses packets under backpressure. Give
batchWriter an injectable sendFn and drive WriteBatch through scripted
partial-acceptance sequences over a mixed GSO-run/plain batch, decoding
what "reached the wire" straight from the prepared iovecs rather than
the entryEnd bookkeeping under test. Also pins the zero-progress abort
and the EIO runtime GSO-disable replay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:23:34 -05:00
JackDoan 3fe2cb970e udp: extract and test the GRO RX splitting 2026-07-27 16:23:34 -05:00
JackDoan 865dc9725c overlay/checksum: test each arch implementation directly
The correctness sweeps only exercised the public Checksum dispatcher, so
wherever it resolved to the gvisor fallback (non-AVX2 amd64, fallback
architectures) the suite compared gvisor against itself and the AVX2
assembly went untested -- silently green. Per-arch export_test.go files
now enumerate the hand-written implementations and every sweep runs
against the dispatcher plus each of them, skipping with an explicit
message when the running CPU can't execute one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:21:10 -05:00
JackDoan 8cebecc087 overlay: test the checksum-seeding math against an RFC 1071 reference
pseudoSumIPv4/IPv6, foldOnceNoInvert, ipv4HdrChecksum (batch) and
foldComplement (tio/virtio) feed the virtio NEEDS_CSUM contract; a wrong
seed means every coalesced packet is silently dropped by the receiver
with nothing failing on our side. Check them against an independent
reference built from explicit RFC pseudo-header bytes -- deliberately
not the production checksum code -- including the carry/fold edge cases
and an end-to-end seed -> kernel-completion -> receiver-accepts
property.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:21:10 -05:00
JackDoan fb0d20f123 docs: note the GRO receive-scratch memory cost of listen.batch
The TX arena (128 x 9033B per routine) and GRO receive scratch
(listen.batch x 64KiB per socket) stay at their worst-case bounds by
design: the arena never grows past real demand and the GRO slots cannot
be smaller without truncating coalesced superpackets. Document the
listen.batch knob's memory implication so constrained hosts know what
to tune.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:21:10 -05:00
JackDoan 921ed4360a overlay/tio: validate WriteGSO geometry instead of silently dropping
The length checks were fishy on four counts: an empty hdr/transportHdr
with real payload returned nil (silent drop with a success signal); the
HdrLen/GSOSize/CsumStart uint16 conversions could wrap unchecked;
nothing verified transportHdr covers csum_start+csum_offset, so the
kernel's NEEDS_CSUM write could land in payload bytes; and there was no
total-size bound even though every length field involved is 16-bit.

Malformed geometry is now a real error, and a single 65535 total-length
guard makes all the u16 conversions exact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:21:10 -05:00
JackDoan 6fb10c1c1a udp: make parseRecvCmsg's length check overflow-safe 2026-07-27 16:21:10 -05:00
JackDoan 8006b58758 util: unlock the OS thread when CPU pinning fails
PinThreadToCPU left the goroutine locked to its OS thread even when
sched_setaffinity failed. The lock only exists to make the affinity
stick; without it the kernel migrates the thread anyway, so a failed pin
kept a dedicated thread for zero benefit. Unwind on the error path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:20:10 -05:00
JackDoan 56d2a3841d tun: default pin_threads off
Thread pinning trades scheduler freedom for TX-ring ordering; that's the
right trade on dedicated forwarders but not as a surprise default on
hosts sharing cores with other workloads. Make it opt-in and document
the default in the example config.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:20:10 -05:00
JackDoan 6c0305c7ae overlay/tio: derive WriteGSO geometry from non-empty fragments
GSOSize came from len(pays[0]) while the iovec build skips empty
fragments, so a leading empty fragment emitted a TSO/USO header with
gso_size == 0 -- virtio_net_hdr_to_skb rejects that with EINVAL and the
whole superpacket is lost. Compute gso_size from the first non-empty
fragment and use the non-empty count to decide superpacket vs plain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:20:10 -05:00
JackDoan 5c0a5ee4be overlay/tio: guard Offload.Write against zero-length buffers
Write took &buf[0] before calling writeWithScratch, so the len==0 guard
in the helper could never run -- a zero-length buffer panicked on the
index instead of returning. Hoist the guard above the indexing and fold
writeWithScratch into Write since it was the only caller and duplicated
the iovec setup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:20:10 -05:00
JackDoan 35596c7708 another VIRTIO_NET_HDR_GSO_ECN mistake 2026-07-27 16:20:10 -05:00
JackDoan d74c5ac5c5 overlay/batch: don't false-set PSH when merging a short-tail-sealed slot, clarify PSH vs sealing 2026-07-27 16:20:10 -05:00
JackDoan c06bfb46be overlay/batch: remove end-of-batch debug scaffolding
The Warn("==== end of batch ====") delimiter (and the `logged` flag that
fed it) was left over from debugging the cross-slot gap logging.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 16:14:33 -05:00
JackDoan be35d4f059 udp: downgrade the per-batch sendmmsg failure log to debug 2026-07-27 16:14:33 -05:00
JackDoan eea3c81626 udp: disable GSO at runtime when the kernel rejects a GSO send 2026-07-27 16:12:21 -05:00
Nate Brown 88872a8433 Don't fail on the batch at the first error (#1826) 2026-07-27 14:43:30 -05:00
Nate Brown 6bf424f749 Transmit a computed-zero UDP checksum as all ones (#1823)
yum yum
2026-07-24 19:25:49 -05:00
JackDoan 9688d32f5b make it nicer 2026-07-24 16:44:51 -05:00
JackDoan 8c91fa2699 fix it! 2026-07-24 16:44:51 -05:00
JackDoan 92d51c042e fix it! 2026-07-24 16:44:51 -05:00
JackDoan 0a0b2404a2 put locks around the replay window 2026-07-24 16:44:51 -05:00
JackDoan ef0e3015f9 decrypt in place 2026-07-24 16:44:05 -05:00
JackDoan c6ebe71c08 silly optimization 2026-07-24 16:39:03 -05:00
JackDoan 1d768ac4e4 tio: accept VIRTIO_NET_HDR_GSO_ECN-qualified superpackets
TUN_F_TSO_ECN is negotiated, so once ECN feedback flows the kernel hands
us TSO superpackets typed TCPV4|GSO_ECN (CWR set). protoFromGSOType
treated the qualifier bit as an unknown type and the read path dropped
every such superpacket - a latent bug that only fires when a congested
hop CE-marks the flow, exactly when drops hurt most. The segmenter
already handles CWR (first segment only); just mask the bit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 16:39:03 -05:00
JackDoan 69fa9e4a2e unslop some comments 2026-07-24 16:39:03 -05:00
JackDoan ed55cf40d5 batch: back SendBatch with Arena instead of a hand-rolled slab
SendBatch.Reserve duplicated Arena's grow-on-demand logic byte for byte.
Use an Arena for the slot backing so the borrow/grow/recycle semantics
live in one place.
2026-07-24 16:39:03 -05:00
JackDoan a6ae44ddb1 batch: move shared-arena Reset ownership from lanes to their owner 2026-07-24 16:39:03 -05:00