Skip to content

Commit

Permalink
feat(map): Add GetNextKey and GetValueAndDeleteKey
Browse files Browse the repository at this point in the history
Add GetNextKey() and GetValueAndDeleteKey() for map
and map-low.

Signed-off-by: Tao Chen <chen.dylane@gmail.com>
  • Loading branch information
chentao-kernel committed Apr 2, 2024
1 parent 3c5cd66 commit 72f0885
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 12 deletions.
56 changes: 50 additions & 6 deletions map-low.go
Expand Up @@ -279,9 +279,44 @@ func (m *BPFMapLow) GetValueFlags(key unsafe.Pointer, flags MapFlag) ([]byte, er
return value, nil
}

// TODO: implement `bpf_map__lookup_and_delete_elem`
// func (m *BPFMapLow) GetValueAndDeleteKey(key unsafe.Pointer) ([]byte, error) {
// }
// GetValueAndDeleteKeyFlags gets the value with the given key and flags, delete the key from the map.
// It returns the value and delete the given key.
func (m *BPFMapLow) GetValueAndDeleteKeyFlags(key unsafe.Pointer, flags MapFlag) ([]byte, error) {
valueSize, err := calcMapValueSize(m.ValueSize(), m.Type())
if err != nil {
return nil, fmt.Errorf("map %s %w", m.Name(), err)
}

value := make([]byte, valueSize)
valuePtr := unsafe.Pointer(&(value[0]))
retC := C.bpf_map_lookup_and_delete_elem_flags(
C.int(m.FileDescriptor()),
key,
valuePtr,
C.ulonglong(flags),
)
if retC < 0 {
return nil, fmt.Errorf("failed to lookup and delete value %v in map %s: %w", key, m.Name(), syscall.Errno(-retC))
}
return value, nil
}

// GetValueAndDeleteKey gets the value with the given key and delete the key from the map.
// It returns the value and delete the given key.
func (m *BPFMapLow) GetValueAndDeleteKey(key unsafe.Pointer) ([]byte, error) {
valueSize, err := calcMapValueSize(m.ValueSize(), m.Type())
if err != nil {
return nil, fmt.Errorf("map %s %w", m.Name(), err)
}

value := make([]byte, valueSize)
valuePtr := unsafe.Pointer(&(value[0]))
retC := C.bpf_map_lookup_and_delete_elem(C.int(m.FileDescriptor()), key, valuePtr)
if retC < 0 {
return nil, fmt.Errorf("failed to lookup and delete value %v in map %s: %w", key, m.Name(), syscall.Errno(-retC))
}
return value, nil
}

func (m *BPFMapLow) Update(key, value unsafe.Pointer) error {
return m.UpdateValueFlags(key, value, MapFlagUpdateAny)
Expand Down Expand Up @@ -310,9 +345,18 @@ func (m *BPFMapLow) DeleteKey(key unsafe.Pointer) error {
return nil
}

// TODO: implement `bpf_map__get_next_key`
// func (m *BPFMapLow) GetNextKey(key unsafe.Pointer) (unsafe.Pointer, error) {
// }
// GetNextKey gets the next key with the given key from the map.
// It returns the next key.
func (m *BPFMapLow) GetNextKey(key unsafe.Pointer) (unsafe.Pointer, error) {
next := make([]byte, m.KeySize())
nextPtr := unsafe.Pointer(&next[0])

retC := C.bpf_map_get_next_key(C.int(m.FileDescriptor()), key, nextPtr)
if retC < 0 {
return nil, fmt.Errorf("failed to get next key in map %s: %w", m.Name(), syscall.Errno(-retC))
}
return nextPtr, nil
}

//
// BPFMapLow Batch Operations
Expand Down
42 changes: 36 additions & 6 deletions map.go
Expand Up @@ -405,9 +405,32 @@ func (m *BPFMap) GetValueFlags(key unsafe.Pointer, flags MapFlag) ([]byte, error
return value, nil
}

// TODO: implement `bpf_map__lookup_and_delete_elem` wrapper
// func (m *BPFMap) GetValueAndDeleteKey(key unsafe.Pointer) ([]byte, error) {
// }
// GetValue retrieves the value associated with a given key and delete the key in the BPFMap.
func (m *BPFMap) GetValueAndDeleteKey(key unsafe.Pointer) ([]byte, error) {
return m.GetValueAndDeleteKeyFlags(key, MapFlagUpdateAny)
}

func (m *BPFMap) GetValueAndDeleteKeyFlags(key unsafe.Pointer, flags MapFlag) ([]byte, error) {
valueSize, err := calcMapValueSize(m.ValueSize(), m.Type())
if err != nil {
return nil, fmt.Errorf("map %s %w", m.Name(), err)
}

value := make([]byte, valueSize)
valuePtr := unsafe.Pointer(&(value[0]))

retC := C.bpf_map__lookup_and_delete_elem(
m.bpfMap, key,
C.ulong(m.KeySize()),
valuePtr,
C.ulong(valueSize),
C.ulonglong(flags),
)
if retC < 0 {
return nil, fmt.Errorf("failed to lookup and delete value %v in map %s: %w", key, m.Name(), syscall.Errno(-retC))
}
return value, nil
}

// Deprecated: use BPFMap.GetValue() or BPFMap.GetValueFlags() instead, since
// they already calculate the value size for per-cpu maps.
Expand Down Expand Up @@ -480,9 +503,16 @@ func (m *BPFMap) DeleteKey(key unsafe.Pointer) error {
return nil
}

// TODO: implement `bpf_map__get_next_key` wrapper
// func (m *BPFMap) GetNextKey(key unsafe.Pointer) (unsafe.Pointer, error) {
// }
// GetNextKey with a given key from the BPFMap.
func (m *BPFMap) GetNextKey(key unsafe.Pointer) (unsafe.Pointer, error) {
next := make([]byte, m.KeySize())
nextPtr := unsafe.Pointer(&next[0])
retC := C.bpf_map__get_next_key(m.bpfMap, key, nextPtr, C.ulong(m.KeySize()))
if retC < 0 {
return nil, fmt.Errorf("failed to get next key %d in map %s: %w", key, m.Name(), syscall.Errno(-retC))
}
return nextPtr, nil
}

//
// BPFMap Batch Operations (low-level API)
Expand Down
58 changes: 58 additions & 0 deletions selftest/map-batch/main.go
Expand Up @@ -247,6 +247,64 @@ func main() {
if count != uint32(fewer) {
log.Fatalf("testerMap.DeleteKeyBatch failed: count=%d", count)
}

//
// GetNextKey
//

// Test get next key
_, err = testerMap.UpdateBatch(
unsafe.Pointer(&keys[0]),
unsafe.Pointer(&values[0]),
uint32(len(keys)),
)
if err != nil {
log.Fatal(err)
}

key := unsafe.Pointer(nil)
keyCnt := 0
for {
nextKey, err := testerMap.GetNextKey(key)
key = nextKey
if err != nil {
break
}
keyCnt++
}
if keyCnt != len(keys) {
log.Fatalf("testerMap.GetNextKey failed: count=%d", keyCnt)
}

//
// GetValueAndDelete
//

// Test get value and delete
for i, key := range keys {
val, err := testerMap.GetValueAndDeleteKey(unsafe.Pointer(&key))
if err != nil {
log.Fatalf("testerMap.GetValueAndDelete failed: err=%v", err)
}
if endian().Uint32(val) != values[i] {
log.Fatalf("testerMpa.GetValueAndDetele failed: val=%d", endian().Uint32(val))
}
}

// check all keys deleted
key = unsafe.Pointer(nil)
keyCnt = 0
for {
nextKey, err := testerMap.GetNextKey(key)
key = nextKey
if err != nil {
break
}
keyCnt++
}
if keyCnt != 0 {
log.Fatalf("testerMap.GetValueAndDeleteKey failed: count=%d", keyCnt)
}
}

func endian() binary.ByteOrder {
Expand Down

0 comments on commit 72f0885

Please sign in to comment.