mirror of
https://github.com/slackhq/nebula.git
synced 2026-08-16 01:46:58 +02:00
unslop a bit
This commit is contained in:
+47
-68
@@ -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
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user