mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 20:46:52 +01:00
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>
50 lines
1.0 KiB
Go
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
|
|
}
|