Update
This commit is contained in:
1 parent
3530afb854
commit
6903fcff27
2146 files changed
+112256
-190703
No files matched your search
+122
-9
@@ -17,18 +17,55 @@ const (
|
||||
EventMTUUpdate
|
||||
)
|
||||
|
||||
type Device interface {
|
||||
// File returns the file descriptor of the device.
|
||||
// ReadPacket describes a packet read by [Reader.Read].
|
||||
type ReadPacket struct {
|
||||
// Offset is the starting byte offset.
|
||||
Offset int
|
||||
// Size is the size of the packet.
|
||||
Size int
|
||||
}
|
||||
|
||||
// ReadPacketSpacing is the number of bytes reserved before the first packet,
|
||||
// between adjacent packets, and after the final packet filled by [Reader.Read].
|
||||
const ReadPacketSpacing = 64
|
||||
|
||||
// Reader reads packets from a single queue of a [Device].
|
||||
type Reader interface {
|
||||
// Read reads one or more packets from the queue into slab. On return, it
|
||||
// populates packets and returns the number of entries to evaluate. Those
|
||||
// entries are valid even when err is non-nil. Callers must provide at least
|
||||
// [Device.BatchSize] entries.
|
||||
//
|
||||
// Read reserves [ReadPacketSpacing] bytes before the first packet, between
|
||||
// adjacent packets, and after the final packet. The contents of the reserved
|
||||
// space are unspecified; the [Device] may use them while Read is executing.
|
||||
// Callers must provide a slab of at least 2*[ReadPacketSpacing] bytes.
|
||||
//
|
||||
// Read returns [ErrTooManySegments] if packets or slab cannot accommodate
|
||||
// all packets produced by the read.
|
||||
Read(slab []byte, packets []ReadPacket) (n int, err error)
|
||||
}
|
||||
|
||||
// Queue is a single read queue of a [Device]. Distinct Queues of one Device
|
||||
// may be used concurrently.
|
||||
//
|
||||
// A [Device] implementation may return read-only Queues in addition to those
|
||||
// backed by file descriptors. [MultiQueueDevice.WriteTo] is the way to
|
||||
// dispatch writes to the queues that accept them.
|
||||
type Queue interface {
|
||||
Reader
|
||||
|
||||
// File returns the queue's file descriptor, or nil if the queue is not
|
||||
// backed by one.
|
||||
File() *os.File
|
||||
}
|
||||
|
||||
// Read one or more packets from the Device (without any additional headers).
|
||||
// On a successful read it returns the number of packets read, and sets
|
||||
// packet lengths within the sizes slice. len(sizes) must be >= len(bufs).
|
||||
// A nonzero offset can be used to instruct the Device on where to begin
|
||||
// reading into each element of the bufs slice.
|
||||
Read(bufs [][]byte, sizes []int, offset int) (n int, err error)
|
||||
type Device interface {
|
||||
// Queue is the Device's first queue. A [MultiQueueDevice] exposes the
|
||||
// rest.
|
||||
Queue
|
||||
|
||||
// Write one or more packets to the device (without any additional headers).
|
||||
// Write one or more packets to the Device.
|
||||
// On a successful write it returns the number of packets written. A nonzero
|
||||
// offset can be used to instruct the Device on where to begin writing from
|
||||
// each packet contained within the bufs slice.
|
||||
@@ -52,6 +89,82 @@ type Device interface {
|
||||
BatchSize() int
|
||||
}
|
||||
|
||||
// MultiQueueDevice is a Device that exposes more than one kernel queue, each
|
||||
// backed by its own file descriptor. The count is fixed for the Device's
|
||||
// lifetime.
|
||||
type MultiQueueDevice interface {
|
||||
Device
|
||||
|
||||
// Queues returns one [Queue] per kernel queue with at least one entry.
|
||||
// Entry 0 is equivalent to the Device's own [Reader.Read].
|
||||
Queues() []Queue
|
||||
|
||||
// WriteTo is [Device.Write] directed at one of the Device's write queues.
|
||||
// Data written with the same flow id lands on the same write queue.
|
||||
WriteTo(flow int, bufs [][]byte, offset int) (int, error)
|
||||
}
|
||||
|
||||
// WriteToOf returns dev's queue-aware write, or [Device.Write] for a Device
|
||||
// with one write queue.
|
||||
func WriteToOf(dev Device) func(flow int, bufs [][]byte, offset int) (int, error) {
|
||||
if w, ok := dev.(MultiQueueDevice); ok {
|
||||
return w.WriteTo
|
||||
}
|
||||
return func(_ int, bufs [][]byte, offset int) (int, error) {
|
||||
return dev.Write(bufs, offset)
|
||||
}
|
||||
}
|
||||
|
||||
// QueuesOf returns dev's queues, or dev itself as the single queue. The result
|
||||
// always has at least one entry.
|
||||
func QueuesOf(dev Device) []Queue {
|
||||
if mq, ok := dev.(MultiQueueDevice); ok {
|
||||
if qs := mq.Queues(); len(qs) > 0 {
|
||||
return qs
|
||||
}
|
||||
}
|
||||
return []Queue{dev}
|
||||
}
|
||||
|
||||
// An Option configures a [Device] at creation time.
|
||||
type Option interface {
|
||||
apply(*config)
|
||||
}
|
||||
|
||||
type optionFunc func(*config)
|
||||
|
||||
func (f optionFunc) apply(config *config) {
|
||||
f(config)
|
||||
}
|
||||
|
||||
type config struct {
|
||||
queues int // Tun fd's in IFF_MULTI_QUEUE group to open.
|
||||
}
|
||||
|
||||
func defaultConfig() config {
|
||||
return config{
|
||||
queues: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// WithQueues requests that the [Device] be created with n queues. n must be at
|
||||
// least 1.
|
||||
//
|
||||
// Only Linux implements multiqueue TUN. Errors are returned if more queues
|
||||
// are requested than the Linux kernel supports (at the time of writing,
|
||||
// v7.0 has MAX_TAP_QUEUES at 256) or if the per-process limit was reached.
|
||||
//
|
||||
// Implementations may choose to return more read queues than was requested.
|
||||
// Callers must consult [QueuesOf] rather than assume they got n.
|
||||
//
|
||||
// EXPERIMENTAL: Current implementation introduces nonce reordering with more
|
||||
// than one queue.
|
||||
func WithQueues(n int) Option {
|
||||
return optionFunc(func(config *config) {
|
||||
config.queues = n
|
||||
})
|
||||
}
|
||||
|
||||
// GRODevice is a Device extended with methods for disabling GRO. Certain OS
|
||||
// versions may have offload bugs. Where these bugs negatively impact throughput
|
||||
// or break connectivity entirely we can use these methods to disable the
|
||||
|
||||
Reference in new issue
Block a user