Files
nebula/overlay/batch/passthrough.go
T
Ryan HuberandClaude Opus 5.5 81f991f1fd overlay/darwin: batch tun writes with sendmsg_x, drain reads, 64 pending packets
tun.WriteBatch writes up to 64 packets per sendmsg_x on the utun control
socket, and Passthrough.Flush hands its lane to it whole through the new
tio.BatchWriter (Caleb Jasik's #1896). Only the darwin tun implements
BatchWriter, so every other platform keeps one Write per packet.

tunQueue.Read drains every packet already queued on the utun, up to 64,
so a burst reaches the send batch together.

xnu lets only one packet wait on a utun control socket by default, so
each read found one packet. The tun now raises
UTUN_OPT_MAX_PENDING_PACKETS to 64, growing SO_RCVBUF to hold that many
packets first; on failure it logs and keeps xnu's default.

Tests: #1896's WriteBatch tests over sendmsg_x and the writev fallback,
the drain tests, the pending-packet setsockopts, and #1906's framing and
zero-alloc Read/Write tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:11:48 +00:00

50 lines
1.0 KiB
Go

package batch
import (
"io"
"github.com/slackhq/nebula/overlay/tio"
)
// Passthrough is MultiCoalescer's verbatim lane: no coalescing, packets are written at Flush in the
// order enqueued, in one WriteBatch when out implements tio.BatchWriter.
type Passthrough struct {
out io.Writer
bw tio.BatchWriter // nil: Flush writes one packet per Write
slots [][]byte
}
func NewPassthrough(w io.Writer) *Passthrough {
bw, _ := w.(tio.BatchWriter)
return &Passthrough{
out: w,
bw: bw,
slots: make([][]byte, 0, 128),
}
}
// enqueue accepts one packet, already sorted into transmission order by dispatch.
func (p *Passthrough) enqueue(pkt []byte) error {
p.slots = append(p.slots, pkt)
return nil
}
func (p *Passthrough) Flush() error {
var firstErr error
if p.bw != nil {
if len(p.slots) > 0 {
firstErr = p.bw.WriteBatch(p.slots)
}
} else {
for _, s := range p.slots {
_, err := p.out.Write(s)
if err != nil && firstErr == nil {
firstErr = err
}
}
}
clear(p.slots)
p.slots = p.slots[:0]
return firstErr
}