11/* SPDX-License-Identifier: MIT
22 *
33 * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved.
4- *
5- * Package buffer implements a reusable buffer abstraction.
6- *
7- * Wireguard-go's data processing is constrained by both the hosts API,
8- * and the transformations performed during encapsulation:
9- *
10- * 1. Encryption requires tail- and headroom for extra headers and padding.
11- * Available via winrio, and pread(2).
12- * 2. Systems are moving towards coalesced reads for both TCP and UDP.
13- * The read data has no gaps for individual slices.
14- * 3. crypto.AEAD interface requires a contiguous dst []byte for Sealing.
15- * So we can't use scatter-gather to inject the gaps.
16- *
17- * Until one of these three conditions is changed, the encryption strategy
18- * is to copy on read into buffers with the required gaps.
19- * The buffers are right-sized for the packet to avoid memory inflation.
20- * To recycle said allocations, each buffer carries a recycle function
21- * that routes it back to its originating pool.
22- *
23- * Decryption shrinks each fragment instead of growing, so buffers can pass
24- * through the pipeline without copying till the egress coalescion.
25- * Depending on the chosen head of the coalescion, there may or may be no room
26- * and reallocation is a necessary fallback until we start passing
27- * buffers in batches.
284 */
5+
6+ // Package buffer implements a reusable buffer abstraction.
7+ //
8+ // Wireguard-go's data processing is constrained by both the hosts API,
9+ // and the transformations performed during encapsulation:
10+ //
11+ // 1. Encryption requires tail- and headroom for extra headers and padding.
12+ // Available via winrio, and pread(2).
13+ // 2. Systems are moving towards coalesced reads for both TCP and UDP.
14+ // The read data has no gaps for individual slices.
15+ // 3. crypto.AEAD interface requires a contiguous dst []byte for Sealing.
16+ // So we can't use scatter-gather to inject the gaps.
17+ //
18+ // Until one of these three conditions is changed, the encryption strategy
19+ // is to copy on read into buffers with the required gaps.
20+ // The buffers are right-sized for the packet to avoid memory inflation.
21+ // To recycle said allocations, each buffer carries a recycle function
22+ // that routes it back to its originating pool.
23+ //
24+ // Decryption shrinks each fragment instead of growing, so buffers can pass
25+ // through the pipeline without copying till the egress coalescion.
26+ // Depending on the chosen head of the coalescion, there may or may be no room
27+ // and reallocation is a necessary fallback until we start passing
28+ // buffers in batches.
29+
2930package buffer
3031
3132const (
@@ -34,9 +35,13 @@ const (
3435
3536// Source produces new Buffers.
3637type Source interface {
38+
39+ // Get returns a Buffer of at least the requested size.
40+ // Implementations may chose to return error if the request can not be fulfilled.
3741 Get (size int ) (* Buffer , error )
3842}
3943
44+ // Recycler holds state necessary for a correct Buffer return to its originating Source
4045type Recycler interface {
4146 Recycle (* Buffer )
4247}
@@ -47,29 +52,41 @@ type Buffer struct {
4752 data []byte
4853 recycler Recycler
4954
50- Size int // size of the read, excluding offset
55+ // Size is the length of the valid data within the buffer. It does not account for any head- or tailroom.
56+ // Typically implementations set it to the number of bytes read into the buffer.
57+ Size int
5158}
5259
5360// New creates a standalone Buffer.
5461func New (b []byte , recycler Recycler ) * Buffer {
5562 return & Buffer {data : b , recycler : recycler }
5663}
5764
65+ // Make creates a standalone Buffer with a new byte slice of the requested size.
66+ func Make (size int ) * Buffer {
67+ return & Buffer {data : make ([]byte , size ), recycler : nil }
68+ }
69+
70+ // Data returns the full underlying byte slice of the Buffer.
5871func (b * Buffer ) Data () []byte {
5972 return b .data
6073}
6174
62- func (b * Buffer ) Len () int {
63- return len (b .data )
75+ // Packet returns a slice starting at the given offset and ending at the end of the valid data in the buffer.
76+ func (b * Buffer ) Packet (offset int ) []byte {
77+ return b .data [offset : offset + b .Size ]
6478}
6579
80+ // Release returns the Buffer to its originating Source for reuse.
81+ // The Buffer must not be used after calling Release.
6682func (b * Buffer ) Release () {
6783 if b .recycler != nil {
6884 clear (b .data )
6985 b .recycler .Recycle (b )
7086 }
7187}
7288
89+ // ReleaseAll calls Release on each non-nil Buffer in the slice, and sets the slice elements to nil.
7390func ReleaseAll (bs []* Buffer ) {
7491 for i := range bs {
7592 if bs [i ] != nil {
@@ -79,11 +96,14 @@ func ReleaseAll(bs []*Buffer) {
7996 }
8097}
8198
99+ // Arena is a Buffer with an internal watermark for sequential allocations.
100+ // FIXME Arena needs a graceful fallback on overflow.
82101type Arena struct {
83102 * Buffer
84103 watermark int
85104}
86105
106+ // Get returns a slice of the Arena's Buffer of the requested size, and advances the watermark.
87107func (a * Arena ) Get (size int ) []byte {
88108 if a .watermark + size > len (a .Buffer .Data ()) {
89109 panic ("arena overflow" ) // or return a heap-allocated fallback
@@ -93,6 +113,7 @@ func (a *Arena) Get(size int) []byte {
93113 return b
94114}
95115
116+ // Flush resets the Arena's watermark to zero, and clears the valid data in the Buffer.
96117func (a * Arena ) Flush () {
97118 clear (a .Buffer .Data ()[:a .watermark ])
98119 a .watermark = 0
0 commit comments