Skip to content

Commit

Permalink
chore(bufferdecoder): readability refactors
Browse files Browse the repository at this point in the history
Move some functions around, rename and improve documentation.
  • Loading branch information
NDStrahilevitz committed Oct 16, 2024
1 parent 8a30a56 commit ebe9be2
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 41 deletions.
22 changes: 20 additions & 2 deletions pkg/bufferdecoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,14 @@ func (decoder *EbpfDecoder) BuffLen() int {
return len(decoder.buffer)
}

// ReadAmountBytes returns the total amount of bytes that decoder has read from its buffer up until now.
func (decoder *EbpfDecoder) ReadAmountBytes() int {
// BytesRead returns the total amount of bytes that decoder has read from its buffer up until now.
func (decoder *EbpfDecoder) BytesRead() int {
return decoder.cursor
}

// MoveCursor moves the buffer cursor over n bytes. Returns the new cursor position.
func (decoder *EbpfDecoder) MoveCursor(n int) int {
decoder.cursor += n
return decoder.cursor
}

Expand Down Expand Up @@ -260,6 +266,18 @@ func (decoder *EbpfDecoder) DecodeBytes(msg []byte, size int) error {
return nil
}

// ReadBytesLen is a helper which allocates a known size bytes buffer and decodes
// the bytes from the buffer into it.
func (decoder *EbpfDecoder) ReadBytesLen(len int) ([]byte, error) {
var err error
res := make([]byte, len)
err = decoder.DecodeBytes(res[:], len)
if err != nil {
return nil, errfmt.Errorf("error reading byte array: %v", err)
}
return res, nil
}

// DecodeIntArray translate from the decoder buffer, starting from the decoder cursor, to msg, size * 4 bytes (in order to get int32).
func (decoder *EbpfDecoder) DecodeIntArray(msg []int32, size int) error {
offset := decoder.cursor
Expand Down
55 changes: 24 additions & 31 deletions pkg/bufferdecoder/eventsreader.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,22 @@ func readArgFromBuff(id events.ID, ebpfMsgDecoder *EbpfDecoder, params []trace.A
case trace.STR_T:
res, err = readStringFromBuff(ebpfMsgDecoder)
case trace.STR_ARR_T:
// TODO optimization: create slice after getting arrLen
var ss []string
var arrLen uint8
err = ebpfMsgDecoder.DecodeUint8(&arrLen)
if err != nil {
return uint(argIdx), arg, errfmt.Errorf("error reading string array number of elements: %v", err)
}
strSlice := make([]string, 0, arrLen)
for i := 0; i < int(arrLen); i++ {
s, err := readStringFromBuff(ebpfMsgDecoder)
if err != nil {
return uint(argIdx), arg, errfmt.Errorf("error reading string element: %v", err)
}
ss = append(ss, s)
strSlice = append(strSlice, s)
}
res = ss
res = strSlice
case trace.ARGS_ARR_T:
var ss []string
var strSlice []string
var arrLen uint32
var argNum uint32

Expand All @@ -104,18 +103,18 @@ func readArgFromBuff(id events.ID, ebpfMsgDecoder *EbpfDecoder, params []trace.A
if err != nil {
return uint(argIdx), arg, errfmt.Errorf("error reading args number: %v", err)
}
resBytes, err := ReadByteSliceFromBuff(ebpfMsgDecoder, int(arrLen))
resBytes, err := ebpfMsgDecoder.ReadBytesLen(int(arrLen))
if err != nil {
return uint(argIdx), arg, errfmt.Errorf("error reading args array: %v", err)
}
ss = strings.Split(string(resBytes), "\x00")
if ss[len(ss)-1] == "" {
ss = ss[:len(ss)-1]
strSlice = strings.Split(string(resBytes), "\x00")
if strSlice[len(strSlice)-1] == "" {
strSlice = strSlice[:len(strSlice)-1]
}
for int(argNum) > len(ss) {
ss = append(ss, "?")
for int(argNum) > len(strSlice) {
strSlice = append(strSlice, "?")
}
res = ss
res = strSlice
case trace.BYTES_T:
var size uint32
err = ebpfMsgDecoder.DecodeUint32(&size)
Expand All @@ -126,7 +125,7 @@ func readArgFromBuff(id events.ID, ebpfMsgDecoder *EbpfDecoder, params []trace.A
if size > 4096 && (id < events.NetPacketBase || id > events.MaxNetID) {
return uint(argIdx), arg, errfmt.Errorf("byte array size too big: %d", size)
}
res, err = ReadByteSliceFromBuff(ebpfMsgDecoder, int(size))
res, err = ebpfMsgDecoder.ReadBytesLen(int(size))
case trace.INT_ARR_2_T:
var intArray [2]int32
err = ebpfMsgDecoder.DecodeIntArray(intArray[:], 2)
Expand Down Expand Up @@ -225,7 +224,7 @@ func readSockaddrFromBuff(ebpfMsgDecoder *EbpfDecoder) (map[string]string, error
char sun_path[108]; // Pathname
};
*/
sunPath, err := readStringVarFromBuff(ebpfMsgDecoder, 108)
sunPath, err := readVarStringFromBuffer(ebpfMsgDecoder, 108)
if err != nil {
return nil, errfmt.Errorf("error parsing sockaddr_un: %v", err)
}
Expand Down Expand Up @@ -255,7 +254,7 @@ func readSockaddrFromBuff(ebpfMsgDecoder *EbpfDecoder) (map[string]string, error
return nil, errfmt.Errorf("error parsing sockaddr_in: %v", err)
}
res["sin_addr"] = PrintUint32IP(addr)
_, err := ReadByteSliceFromBuff(ebpfMsgDecoder, 8)
_, err := ebpfMsgDecoder.ReadBytesLen(8)
if err != nil {
return nil, errfmt.Errorf("error parsing sockaddr_in: %v", err)
}
Expand Down Expand Up @@ -286,7 +285,7 @@ func readSockaddrFromBuff(ebpfMsgDecoder *EbpfDecoder) (map[string]string, error
return nil, errfmt.Errorf("error parsing sockaddr_in6: %v", err)
}
res["sin6_flowinfo"] = strconv.Itoa(int(flowinfo))
addr, err := ReadByteSliceFromBuff(ebpfMsgDecoder, 16)
addr, err := ebpfMsgDecoder.ReadBytesLen(16)
if err != nil {
return nil, errfmt.Errorf("error parsing sockaddr_in6: %v", err)
}
Expand All @@ -301,6 +300,9 @@ func readSockaddrFromBuff(ebpfMsgDecoder *EbpfDecoder) (map[string]string, error
return res, nil
}

// readStringFromBuff reads strings from the event buffer using the following format:
//
// [32bit:string_size][string_size-1:byte_buffer][8bit:null_terminator]
func readStringFromBuff(ebpfMsgDecoder *EbpfDecoder) (string, error) {
var err error
var size uint32
Expand All @@ -311,7 +313,7 @@ func readStringFromBuff(ebpfMsgDecoder *EbpfDecoder) (string, error) {
if size > 4096 {
return "", errfmt.Errorf("string size too big: %d", size)
}
res, err := ReadByteSliceFromBuff(ebpfMsgDecoder, int(size-1)) // last byte is string terminating null
res, err := ebpfMsgDecoder.ReadBytesLen(int(size - 1)) // last byte is string terminating null
defer func() {
var dummy int8
err := ebpfMsgDecoder.DecodeInt8(&dummy) // discard last byte which is string terminating null
Expand All @@ -325,9 +327,10 @@ func readStringFromBuff(ebpfMsgDecoder *EbpfDecoder) (string, error) {
return string(res), nil
}

// readStringVarFromBuff reads a null-terminated string from `buff`
// max length can be passed as `max` to optimize memory allocation, otherwise pass 0
func readStringVarFromBuff(decoder *EbpfDecoder, max int) (string, error) {
// readVarStringFromBuffer reads a null-terminated string from the ebpf buffer where the size is not
// known. The helper will read from the buffer char-by-char until it hits the null terminator
// or the given max length. The cursor will then skip to the point in the buffer after the max length.
func readVarStringFromBuffer(decoder *EbpfDecoder, max int) (string, error) {
var err error
var char int8
res := make([]byte, 0, max)
Expand All @@ -352,20 +355,10 @@ func readStringVarFromBuff(decoder *EbpfDecoder, max int) (string, error) {
// The exact reason for this Trim is not known, so remove it for now,
// since it increases processing time.
// res = bytes.TrimLeft(res[:], "\000")
decoder.cursor += max - count // move cursor to the end of the buffer
decoder.MoveCursor(max - count) // skip the cursor to the desired endpoint
return string(res), nil
}

func ReadByteSliceFromBuff(ebpfMsgDecoder *EbpfDecoder, len int) ([]byte, error) {
var err error
res := make([]byte, len)
err = ebpfMsgDecoder.DecodeBytes(res[:], len)
if err != nil {
return nil, errfmt.Errorf("error reading byte array: %v", err)
}
return res, nil
}

// PrintUint32IP prints the IP address encoded as a uint32
func PrintUint32IP(in uint32) string {
ip := make(net.IP, net.IPv4len)
Expand Down
8 changes: 4 additions & 4 deletions pkg/bufferdecoder/eventsreader_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func BenchmarkReadStringVarFromBuff_ShortString(b *testing.B) {

for i := 0; i < b.N; i++ {
decoder := New(buffer)
str, _ = readStringVarFromBuff(decoder, max)
str, _ = readVarStringFromBuffer(decoder, max)
}
_ = str
}
Expand All @@ -24,7 +24,7 @@ func BenchmarkReadStringVarFromBuff_MediumString(b *testing.B) {

for i := 0; i < b.N; i++ {
decoder := New(buffer)
str, _ = readStringVarFromBuff(decoder, max)
str, _ = readVarStringFromBuffer(decoder, max)
}
_ = str
}
Expand All @@ -37,7 +37,7 @@ func BenchmarkReadStringVarFromBuff_LongString(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
decoder := New(buffer)
str, _ = readStringVarFromBuff(decoder, max)
str, _ = readVarStringFromBuffer(decoder, max)
}
_ = str
}
Expand All @@ -50,7 +50,7 @@ func BenchmarkReadStringVarFromBuff_LongStringLowMax(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
decoder := New(buffer)
str, _ = readStringVarFromBuff(decoder, max)
str, _ = readVarStringFromBuffer(decoder, max)
}
_ = str
}
6 changes: 3 additions & 3 deletions pkg/bufferdecoder/eventsreader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func TestReadArgFromBuff(t *testing.T) {
if tc.name == "unknown" {
return
}
assert.Empty(t, decoder.BuffLen()-decoder.ReadAmountBytes(), tc.name) // passed in buffer should be emptied out
assert.Empty(t, decoder.BuffLen()-decoder.BytesRead(), tc.name) // passed in buffer should be emptied out
})
}
}
Expand Down Expand Up @@ -258,13 +258,13 @@ func TestReadStringVarFromBuff(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
decoder := New(tt.buffer)
actual, err := readStringVarFromBuff(decoder, tt.max)
actual, err := readVarStringFromBuffer(decoder, tt.max)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expected, actual)
assert.Equal(t, tt.expectedCursor, decoder.ReadAmountBytes())
assert.Equal(t, tt.expectedCursor, decoder.BytesRead())
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/ebpf/capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (t *Tracee) handleFileCaptures(ctx context.Context) {
}
}

dataBytes, err := bufferdecoder.ReadByteSliceFromBuff(ebpfMsgDecoder, int(meta.Size))
dataBytes, err := ebpfMsgDecoder.ReadBytesLen(int(meta.Size))
if err != nil {
if err := f.Close(); err != nil {
t.handleError(err)
Expand Down

0 comments on commit ebe9be2

Please sign in to comment.