diff --git a/overlay/overlaytest/noop.go b/overlay/overlaytest/noop.go index 6a39ab43..f7c77478 100644 --- a/overlay/overlaytest/noop.go +++ b/overlay/overlaytest/noop.go @@ -15,6 +15,10 @@ import ( // exercise the datapath. type NoopTun struct{} +func (NoopTun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} + func (NoopTun) RoutesFor(addr netip.Addr) routing.Gateways { return routing.Gateways{} } diff --git a/overlay/tio/tio.go b/overlay/tio/tio.go index 47a64138..d576084e 100644 --- a/overlay/tio/tio.go +++ b/overlay/tio/tio.go @@ -34,15 +34,16 @@ type Queue interface { // 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. A Packet may carry a - // GSO/USO superpacket (see GSOInfo); when GSO.IsSuperpacket() is - // true the caller must segment Bytes before treating it as a single - // IP datagram. Not safe for concurrent Reads. + // or copy each slice before the next call. Read() ([]Packet, error) // Write emits a single packet on the plaintext (outside→inside) // delivery path. Not safe for concurrent Writes. Write(p []byte) (int, error) + + // Capabilities returns the Queue's negotiated offload capabilities, + // or the zero value when q does not advertise any. + Capabilities() Capabilities } // Packet is the unit Queue.Read returns. Bytes points into the queue's @@ -79,38 +80,6 @@ type GSOInfo struct { // and sent on the wire. func (g GSOInfo) IsSuperpacket() bool { return g.Size > 0 } -// 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. -// GSO metadata is copied verbatim. 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, GSO: p.GSO} -} - -// CapsProvider is an optional interface implemented by Queues that -// successfully negotiated kernel offload features at open time. Callers -// pick a write-path coalescer based on the result. Queues that don't -// implement it are treated as having no offload capability — callers must -// fall back to plain per-packet writes. -type CapsProvider interface { - Capabilities() Capabilities -} - -// QueueCapabilities returns q's negotiated offload capabilities, or the -// zero value when q does not advertise any. -func QueueCapabilities(q Queue) Capabilities { - if cp, ok := q.(CapsProvider); ok { - return cp.Capabilities() - } - return Capabilities{} -} - // GSOProto selects the L4 protocol for a GSO superpacket. Determines which // VIRTIO_NET_HDR_GSO_* type the writer stamps and which checksum offset // inside the transport header virtio NEEDS_CSUM expects. diff --git a/overlay/tun_android.go b/overlay/tun_android.go index ea2e1295..d3664298 100644 --- a/overlay/tun_android.go +++ b/overlay/tun_android.go @@ -128,3 +128,7 @@ func (t *tun) NewMultiQueueReader() error { func (t *tun) Readers() []tio.Queue { return []tio.Queue{t} } + +func (t *tun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} diff --git a/overlay/tun_darwin.go b/overlay/tun_darwin.go index 9ace4fc8..adf11bdf 100644 --- a/overlay/tun_darwin.go +++ b/overlay/tun_darwin.go @@ -573,3 +573,7 @@ func (t *tun) NewMultiQueueReader() error { func (t *tun) Readers() []tio.Queue { return []tio.Queue{t} } + +func (t *tun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} diff --git a/overlay/tun_disabled.go b/overlay/tun_disabled.go index ff86bc29..524b6a0b 100644 --- a/overlay/tun_disabled.go +++ b/overlay/tun_disabled.go @@ -33,6 +33,10 @@ type disabledQueue struct { batchRet [1]tio.Packet } +func (q *disabledQueue) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} + func (q *disabledQueue) Read() ([]tio.Packet, error) { r, ok := <-q.parent.read if !ok { diff --git a/overlay/tun_freebsd.go b/overlay/tun_freebsd.go index 71784ad7..f22d15ac 100644 --- a/overlay/tun_freebsd.go +++ b/overlay/tun_freebsd.go @@ -609,6 +609,10 @@ func (t *tun) Readers() []tio.Queue { return []tio.Queue{t} } +func (t *tun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} + func (t *tun) removeRoutes(routes []Route) error { for _, r := range routes { if !r.Install { diff --git a/overlay/tun_ios.go b/overlay/tun_ios.go index 2c332e06..79edd90b 100644 --- a/overlay/tun_ios.go +++ b/overlay/tun_ios.go @@ -184,3 +184,7 @@ func (t *tun) NewMultiQueueReader() error { func (t *tun) Readers() []tio.Queue { return []tio.Queue{t} } + +func (t *tun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} diff --git a/overlay/tun_netbsd.go b/overlay/tun_netbsd.go index e8678959..8b373800 100644 --- a/overlay/tun_netbsd.go +++ b/overlay/tun_netbsd.go @@ -84,6 +84,10 @@ func (t *tun) Readers() []tio.Queue { return []tio.Queue{t} } +func (t *tun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} + var deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`) func newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (*tun, error) { diff --git a/overlay/tun_openbsd.go b/overlay/tun_openbsd.go index 0e754732..80005b14 100644 --- a/overlay/tun_openbsd.go +++ b/overlay/tun_openbsd.go @@ -383,6 +383,10 @@ func (t *tun) Readers() []tio.Queue { return []tio.Queue{t} } +func (t *tun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} + func addRoute(prefix netip.Prefix, gateways []netip.Prefix) error { sock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC) if err != nil { diff --git a/overlay/tun_tester.go b/overlay/tun_tester.go index 898adc23..fe33703e 100644 --- a/overlay/tun_tester.go +++ b/overlay/tun_tester.go @@ -197,6 +197,10 @@ func (t *TestTun) Readers() []tio.Queue { return []tio.Queue{t} } +func (t *TestTun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} + func (t *TestTun) SupportsMultiqueue() bool { return false } diff --git a/overlay/tun_windows.go b/overlay/tun_windows.go index a5ee063c..2ab83821 100644 --- a/overlay/tun_windows.go +++ b/overlay/tun_windows.go @@ -284,6 +284,10 @@ func (t *winTun) Readers() []tio.Queue { return []tio.Queue{t} } +func (t *winTun) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} + func (t *winTun) Close() error { // It seems that the Windows networking stack doesn't like it when we destroy interfaces that have active routes, // so to be certain, just remove everything before destroying. diff --git a/overlay/user.go b/overlay/user.go index 3128ebf0..1ffd03b7 100644 --- a/overlay/user.go +++ b/overlay/user.go @@ -42,6 +42,10 @@ type UserDevice struct { batchRet [1]tio.Packet } +func (d *UserDevice) Capabilities() tio.Capabilities { + return tio.Capabilities{} +} + func (d *UserDevice) Read() ([]tio.Packet, error) { if d.readBuf == nil { d.readBuf = make([]byte, defaultBatchBufSize)