From e41083f6cc1c28348116989fa803122749c3ad03 Mon Sep 17 00:00:00 2001 From: Francisco Javier Honduvilla Coto Date: Wed, 3 Aug 2022 11:26:20 +0100 Subject: [PATCH] batch: Fix GetValueBatch when dealing with partial gets, more context on #162 Signed-off-by: Francisco Javier Honduvilla Coto --- libbpfgo.go | 19 ++++++++----------- selftest/map-batch/main.go | 7 +++++++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libbpfgo.go b/libbpfgo.go index 9074d030..51bb1c90 100644 --- a/libbpfgo.go +++ b/libbpfgo.go @@ -760,19 +760,16 @@ func (b *BPFMap) GetValueBatch(keys unsafe.Pointer, startKey, nextKey unsafe.Poi Flags: C.BPF_ANY, } - errC := C.bpf_map_lookup_batch(b.fd, startKey, nextKey, keys, valuesPtr, &countC, bpfMapBatchOptsToC(opts)) - if errC != 0 { - sc := syscall.Errno(-errC) - if sc != syscall.EFAULT { - if uint32(countC) != count { - return collectBatchValues(values, uint32(countC), b.ValueSize()), - fmt.Errorf("failed to retrieve ALL elements in map %s, fetched (%d/%d): %w", b.name, uint32(countC), count, sc) - } - } - return nil, fmt.Errorf("failed to batch lookup values %v in map %s: %w", keys, b.name, syscall.Errno(-errC)) + ret, errC := C.bpf_map_lookup_batch(b.fd, startKey, nextKey, keys, valuesPtr, &countC, bpfMapBatchOptsToC(opts)) + processed := uint32(countC) + + if ret != 0 && errC != syscall.ENOENT { + // ret = -1 && errno == syscall.ENOENT indicates a partial read. + return nil, fmt.Errorf("failed to batch get value %v in map %s: ret %d (err: %s)", keys, b.name, ret, errC) } - return collectBatchValues(values, count, b.ValueSize()), nil + // Either some or all entries were read. + return collectBatchValues(values, processed, b.ValueSize()), nil } // GetValueAndDeleteBatch allows for batch lookup and deletion of elements where each element is deleted after being retrieved from the map. diff --git a/selftest/map-batch/main.go b/selftest/map-batch/main.go index d3abade6..de14a9a3 100644 --- a/selftest/map-batch/main.go +++ b/selftest/map-batch/main.go @@ -73,6 +73,13 @@ func main() { } } + // Test batch get value with more elements than we have. + _, err = testerMap.GetValueBatch(unsafe.Pointer(&batchKeys[0]), prevKey, unsafe.Pointer(&nextKey), uint32(len(batchKeys))+100) + if err != nil { + fmt.Fprintf(os.Stderr, "testerMap.GetValueBatch failed: %v", err) + os.Exit(-1) + } + // Test batch lookup and delete. deleteKeys := make([]uint32, 2) nextKey = uint32(0)