unslop a bit

This commit is contained in:
JackDoan
2026-07-28 14:56:51 -05:00
parent ed88422770
commit 5c2a5607e5
+47 -68
View File
@@ -13,33 +13,28 @@ type QueueSet interface {
Add(fd int) error Add(fd int) error
} }
// Capabilities advertises which kernel offload features a Queue // Capabilities advertises which kernel offload features a Queue successfully negotiated.
// successfully negotiated. Callers consult this to decide which coalescers // Callers consult this to decide which coalescers to wire onto the write path.
// to wire onto the write path — a Queue without TSO can't usefully accept a
// TCPCoalescer, and a Queue without USO can't accept a UDPCoalescer.
type Capabilities struct { type Capabilities struct {
// TSO means the FD was opened with IFF_VNET_HDR and the kernel agreed // TSO means the FD was opened with IFF_VNET_HDR and the kernel agreed to TUN_F_TSO4|TSO6,
// to TUN_F_TSO4|TSO6 — i.e. WriteGSO with GSOProtoTCP is safe. // and WriteGSO with GSOProtoTCP is safe.
TSO bool TSO bool
// USO means the kernel additionally agreed to TUN_F_USO4|USO6, so // USO means the kernel additionally agreed to TUN_F_USO4|USO6,
// WriteGSO with GSOProtoUDP is safe. Linux ≥ 6.2. // so WriteGSO with GSOProtoUDP is safe. Linux ≥ 6.2.
USO bool USO bool
} }
// Queue is a readable/writable Poll queue. Concurrency contract: a single // Queue is a readable/writable Poll queue.
// read goroutine drives Read; plain Write is safe for concurrent callers; // Concurrency contract: a single read goroutine drives Read; plain Write is safe for concurrent callers;
// WriteGSO (on Queues that implement GSOWriter) is single-writer per queue. // WriteGSO (on Queues that implement GSOWriter) is single-writer per queue.
type Queue interface { type Queue interface {
io.Closer io.Closer
// Read returns one or more packets. The returned Packet.Bytes slices // Read returns one or more packets.
// are borrowed from the Queue's internal buffer and are only valid // 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 // until the next Read or Close on this Queue.
// or copy each slice before the next call. A Packet may carry a // A Packet may carry a GSO/USO superpacket (see GSOInfo)
// GSO/USO superpacket (see GSOInfo); when GSO.IsSuperpacket() is // Single-reader only: not safe for concurrent Reads (it reuses per-queue rx scratch each call).
// true the caller must segment Bytes before treating it as a single
// IP datagram. Single-reader only: not safe for concurrent Reads (it
// reuses per-queue rx scratch each call).
Read() ([]Packet, error) Read() ([]Packet, error)
// Write emits a single packet on the plaintext (outside→inside) // Write emits a single packet on the plaintext (outside→inside)
@@ -47,19 +42,17 @@ type Queue interface {
Write(p []byte) (int, error) Write(p []byte) (int, error)
} }
// Packet is the unit Queue.Read returns. Bytes points into the queue's // Packet is the unit Queue.Read returns.
// internal buffer and is only valid until the next Read or Close on the // Bytes points into the queue's internal buffer and is only valid until the next Read or Close on the queue that produced it.
// queue that produced it. GSO is the zero value for an already-segmented // GSO is the zero value for an already-segmented IP datagram;
// IP datagram; when non-zero it describes a kernel-supplied TSO/USO // when non-zero it describes a kernel-supplied TSO/USO superpacket the caller must segment before consuming.
// superpacket the caller must segment before consuming.
type Packet struct { type Packet struct {
Bytes []byte Bytes []byte
GSO GSOInfo GSO GSOInfo
} }
// GSOInfo describes a kernel-supplied superpacket sitting in Packet.Bytes. // GSOInfo describes a kernel-supplied superpacket sitting in Packet.Bytes.
// The zero value means "not a superpacket" — Bytes is one regular IP // The zero value means Bytes is one regular IP datagram and no segmentation is required.
// datagram and no segmentation is required.
type GSOInfo struct { type GSOInfo struct {
// Size is the GSO segment size: max payload bytes per segment // Size is the GSO segment size: max payload bytes per segment
// (== TCP MSS for TSO, == UDP payload chunk for USO). Zero means // (== TCP MSS for TSO, == UDP payload chunk for USO). Zero means
@@ -77,15 +70,13 @@ type GSOInfo struct {
} }
// IsSuperpacket reports whether g describes a multi-segment GSO/USO // IsSuperpacket reports whether g describes a multi-segment GSO/USO
// superpacket that needs segmentation before its bytes can be encrypted // superpacket that needs segmentation before its bytes can be encrypted and sent on the wire.
// and sent on the wire.
func (g GSOInfo) IsSuperpacket() bool { return g.Size > 0 } func (g GSOInfo) IsSuperpacket() bool { return g.Size > 0 }
// Clone returns a Packet whose Bytes is a freshly allocated copy of p.Bytes, // 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. // 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 // GSO metadata is copied verbatim.
// needs to outlive the borrowed-slice contract — the hot path reads should // Use this only when a caller needs the data to outlive the borrowed-slice contract.
// continue to consume the borrow synchronously to avoid the allocation.
func (p Packet) Clone() Packet { func (p Packet) Clone() Packet {
if p.Bytes == nil { if p.Bytes == nil {
return p return p
@@ -95,26 +86,23 @@ func (p Packet) Clone() Packet {
return Packet{Bytes: cp, GSO: p.GSO} return Packet{Bytes: cp, GSO: p.GSO}
} }
// CapsProvider is an optional interface implemented by Queues that // CapsProvider is an optional interface implemented by Queues that negotiate kernel offload features at open time.
// successfully negotiated kernel offload features at open time. Callers // Callers pick a write-path coalescer based on the result.
// pick a write-path coalescer based on the result. Queues that don't // Queues that don't implement it are treated as having no offload capability.
// implement it are treated as having no offload capability — callers must
// fall back to plain per-packet writes.
type CapsProvider interface { type CapsProvider interface {
Capabilities() Capabilities Capabilities() Capabilities
} }
// QueueCapabilities returns q's negotiated offload capabilities, or the // QueueCapabilities returns q's negotiated offload capabilities, or the zero value when q does not advertise any.
// zero value when q does not advertise any. func QueueCapabilities(q io.Writer) Capabilities {
func QueueCapabilities(q Queue) Capabilities {
if cp, ok := q.(CapsProvider); ok { if cp, ok := q.(CapsProvider); ok {
return cp.Capabilities() return cp.Capabilities()
} }
return Capabilities{} return Capabilities{}
} }
// GSOProto selects the L4 protocol for a GSO superpacket. Determines which // GSOProto selects the L4 protocol for a GSO superpacket.
// VIRTIO_NET_HDR_GSO_* type the writer stamps and which checksum offset // Determines which VIRTIO_NET_HDR_GSO_* type the writer stamps and which checksum offset
// inside the transport header virtio NEEDS_CSUM expects. // inside the transport header virtio NEEDS_CSUM expects.
type GSOProto uint8 type GSOProto uint8
@@ -125,49 +113,40 @@ const (
) )
// GSOWriter is implemented by Queues that can emit a TCP or UDP superpacket // GSOWriter is implemented by Queues that can emit a TCP or UDP superpacket
// assembled from a header prefix plus one or more borrowed payload // assembled from a header prefix plus one or more borrowed payload fragments,
// fragments, in a single vectored write (writev with a leading // in a single vectored write (writev with a leading virtio_net_hdr).
// virtio_net_hdr). This lets the coalescer avoid copying payload bytes // This lets the coalescer avoid copying payload bytes between the caller's decrypt buffer and the TUN.
// between the caller's decrypt buffer and the TUN. Backends without GSO // Backends without GSO support do not implement this interface and coalescing is skipped.
// support do not implement this interface and coalescing is skipped.
// //
// hdr contains the IPv4/IPv6 header prefix (mutable - callers will have // hdr contains the IPv4/IPv6 header prefix (mutable: callers will have filled in total length and IP csum).
// filled in total length and IP csum). transportHdr is the TCP or UDP // transportHdr is the TCP or UDP header
// header (mutable - the L4 checksum field must hold the pseudo-header // (mutable: the L4 checksum field must hold the pseudo-header partial, single-fold not inverted, per virtio NEEDS_CSUM semantics).
// partial, single-fold not inverted, per virtio NEEDS_CSUM semantics). // pays are non-overlapping payload fragments whose concatenation is the full superpacket payload.
// pays are non-overlapping payload fragments whose concatenation is the // They are read-only from the writer's perspective and must remain valid until the call returns.
// full superpacket payload; they are read-only from the writer's // Every segment in pays except possibly the last is exactly the same size.
// perspective and must remain valid until the call returns. Every segment // proto picks the L4 protocol so the writer knows which gsoType / CsumOffset to set.
// in pays except possibly the last is exactly the same size. proto picks
// the L4 protocol so the writer knows which gsoType / CsumOffset to set.
// //
// Callers should also consult CapsProvider (via SupportsGSO or // Callers should also consult CapsProvider (via SupportsGSO or QueueCapabilities)
// QueueCapabilities) for the per-protocol negotiated capability; an // for the per-protocol negotiated capability: USO may not have been negotiated even when TSO was.
// implementation of GSOWriter is necessary but not sufficient since USO
// may not have been negotiated even when TSO was.
type GSOWriter interface { type GSOWriter interface {
CapsProvider
WriteGSO(hdr []byte, transportHdr []byte, pays [][]byte, proto GSOProto) error WriteGSO(hdr []byte, transportHdr []byte, pays [][]byte, proto GSOProto) error
} }
// SupportsGSO reports whether w implements GSOWriter and the underlying // SupportsGSO reports whether w implements GSOWriter and the underlying
// queue advertises the negotiated capability for `want`. A writer that // queue advertises the negotiated capability for `want`.
// implements GSOWriter but not CapsProvider is treated as permissive func SupportsGSO(w io.Writer, want GSOProto) (GSOWriter, bool) {
// (used by tests and fakes that don't negotiate).
func SupportsGSO(w any, want GSOProto) (GSOWriter, bool) {
gw, ok := w.(GSOWriter) gw, ok := w.(GSOWriter)
if !ok { if !ok {
return nil, false return nil, false
} }
cp, ok := w.(CapsProvider) caps := gw.Capabilities()
if !ok {
return gw, true
}
caps := cp.Capabilities()
switch want { switch want {
case GSOProtoTCP: case GSOProtoTCP:
return gw, caps.TSO return gw, caps.TSO
case GSOProtoUDP: case GSOProtoUDP:
return gw, caps.USO return gw, caps.USO
default:
return gw, false
} }
return gw, false
} }