mirror of
https://github.com/slackhq/nebula.git
synced 2026-08-15 09:57:00 +02:00
913a37cfee
Device loses io.ReadWriteCloser + NewMultiQueueReader in favor of Queues(n), which returns up to n tio.Queue objects; platforms without multiqueue hand back their single queue and the interface sizes its reader routines to what it actually got. Queue.Read returns a batch of borrowed packets (single-element for every current backend) so a future backend can deliver more than one packet per syscall without another interface change. The Linux poll/eventfd machinery moves out of tun_linux.go into the new overlay/tio package: nonblocking fds, a shared shutdown eventfd owned by the queue set, and pollfd arrays built on the stack so concurrent writers parked in blockOnWrite no longer share Revents storage. Other platforms wrap their existing one-datagram Read/Write in a singleQueue adapter that owns a private scratch buffer, so multiqueue-by-sharing devices (user, disabled) no longer race concurrent readers on one buffer. This is the tun-interface subset of better-tun-interface-ordering, extracted at 18dc13b with none of the GSO/GRO offload mechanics and no udp/sendmmsg changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
53 lines
1.6 KiB
Go
53 lines
1.6 KiB
Go
package tio
|
|
|
|
import (
|
|
"io"
|
|
)
|
|
|
|
// QueueSet holds one or many Queue objects and helps close them in an orderly way.
|
|
type QueueSet interface {
|
|
io.Closer
|
|
Queues() []Queue
|
|
|
|
// Add takes a tun fd, adds it to the set, and prepares it for use as a Queue.
|
|
Add(fd int) error
|
|
}
|
|
|
|
// Queue is a readable/writable packet queue. Concurrency contract: a single
|
|
// read goroutine drives Read; plain Write is safe for concurrent callers.
|
|
type Queue interface {
|
|
io.Closer
|
|
|
|
// Read returns one or more packets. The returned Packet.Bytes slices
|
|
// are borrowed from the Queue's internal buffer and are only valid
|
|
// until the next Read or Close on this Queue - callers must encrypt
|
|
// or copy each slice before the next call. Single-reader only: not
|
|
// safe for concurrent Reads (it reuses per-queue rx scratch each call).
|
|
Read() ([]Packet, error)
|
|
|
|
// Write emits a single packet on the plaintext (outside→inside)
|
|
// delivery path. Safe for concurrent use.
|
|
Write(p []byte) (int, error)
|
|
}
|
|
|
|
// Packet is the unit Queue.Read returns. Bytes points into the queue's
|
|
// internal buffer and is only valid until the next Read or Close on the
|
|
// queue that produced it.
|
|
type Packet struct {
|
|
Bytes []byte
|
|
}
|
|
|
|
// Clone returns a Packet whose Bytes is a freshly allocated copy of p.Bytes,
|
|
// safe to retain past the next Read or Close on the originating Queue.
|
|
// Use this only when a caller genuinely needs to outlive the borrowed-slice
|
|
// contract — the hot path reads should continue to consume the borrow
|
|
// synchronously to avoid the allocation.
|
|
func (p Packet) Clone() Packet {
|
|
if p.Bytes == nil {
|
|
return p
|
|
}
|
|
cp := make([]byte, len(p.Bytes))
|
|
copy(cp, p.Bytes)
|
|
return Packet{Bytes: cp}
|
|
}
|