Skip to content

Commit

Permalink
chore(map): introduce ReuseFD() to reuse a map fd
Browse files Browse the repository at this point in the history
The `ReuseFD` function links the current BPFMap instance to a provided
map file descriptor. This enables the reuse of a map that was initiated
by another process.

Initial effort: #346

Co-authored-by: Francisco Javier Honduvilla Coto <[email protected]>
  • Loading branch information
geyslan and javierhonduco committed Aug 9, 2023
1 parent 7f40338 commit f3bceb3
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 3 deletions.
29 changes: 29 additions & 0 deletions map-low.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,35 @@ func (m *BPFMapLow) FileDescriptor() int {
return m.fd
}

func (m *BPFMapLow) ReuseFD(fd int) error {
info, err := GetMapInfoByFD(fd)
if err != nil {
return fmt.Errorf("failed to reuse fd %d: %w", fd, err)
}

newFD, err := syscall.Open("/", syscall.O_RDONLY|syscall.O_CLOEXEC, 0)
if err != nil {
return fmt.Errorf("failed to reuse fd %d: %w", fd, err)
}

err = syscall.Dup3(fd, newFD, syscall.O_CLOEXEC)
if err != nil {
_ = syscall.Close(newFD)
return fmt.Errorf("failed to reuse fd %d: %w", fd, err)
}

err = syscall.Close(m.FileDescriptor())
if err != nil {
_ = syscall.Close(newFD)
return fmt.Errorf("failed to reuse fd %d: %w", fd, err)
}

m.fd = newFD
m.info = info

return nil
}

func (m *BPFMapLow) Name() string {
return m.info.Name
}
Expand Down
30 changes: 27 additions & 3 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,33 @@ func (m *BPFMap) GetFd() int {
return m.FileDescriptor()
}

// bpf_map__reuse_fd
// func (m *BPFMap) ReuseFD(fd int) error {
// }
// ReuseFD associates the BPFMap instance with the provided map file descriptor.
//
// This function is useful for reusing a map that was previously created by a
// different process. By passing the file descriptor of the existing map, the
// current BPFMap instance becomes linked to that map.
//
// NOTE: The function closes the current file descriptor associated with the
// BPFMap instance and replaces it with a duplicated descriptor pointing to the
// given fd. As a result, the instance original file descriptor becomes invalid,
// and all associated information is overwritten.
func (m *BPFMap) ReuseFD(fd int) error {
retC := C.bpf_map__reuse_fd(m.bpfMap, C.int(fd))
if retC < 0 {
return fmt.Errorf("failed to reuse fd %d: %w", fd, syscall.Errno(-retC))
}

newFD := m.FileDescriptor()
info, err := GetMapInfoByFD(newFD)
if err != nil {
return err
}

m.bpfMapLow.fd = newFD
m.bpfMapLow.info = info

return nil
}

func (m *BPFMap) Name() string {
return C.GoString(C.bpf_map__name(m.bpfMap))
Expand Down
1 change: 1 addition & 0 deletions selftest/reuse-fd/Makefile
7 changes: 7 additions & 0 deletions selftest/reuse-fd/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/aquasecurity/libbpfgo/selftest/map-update

go 1.18

require github.com/aquasecurity/libbpfgo v0.4.7-libbpf-1.2.0-b2e29a1

replace github.com/aquasecurity/libbpfgo => ../../
4 changes: 4 additions & 0 deletions selftest/reuse-fd/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
26 changes: 26 additions & 0 deletions selftest/reuse-fd/main.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//+build ignore

#include <vmlinux.h>

#include <bpf/bpf_helpers.h>

struct value {
int x;
char y;
};

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, struct value);
__uint(max_entries, 1 << 4);
} tester SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u32);
__type(value, struct value);
__uint(max_entries, 1 << 4);
} tester_reused SEC(".maps");

char LICENSE[] SEC("license") = "Dual BSD/GPL";
91 changes: 91 additions & 0 deletions selftest/reuse-fd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package main

import "C"

import (
"bytes"
"log"
"unsafe"

bpf "github.com/aquasecurity/libbpfgo"
)

func main() {
bpfModule, err := bpf.NewModuleFromFile("main.bpf.o")
if err != nil {
log.Fatal(err)
}
defer bpfModule.Close()

bpfModule.BPFLoadObject()

testerMap, err := bpfModule.GetMap("tester")
if err != nil {
log.Fatal(err)
}

testerReusedMap, err := bpfModule.GetMap("tester_reused")
if err != nil {
log.Fatal(err)
}

//
// BPFMap ReuseFD
//

// The current instance of "tester_reused" will be closed, and testerReusedMap
// will now point to the same map as testerMap "tester", however, via a
// different FD.
err = testerReusedMap.ReuseFD(testerMap.FileDescriptor())
if err != nil {
log.Fatal(err)
}

if err != nil {
log.Fatal(err)
}

key1 := uint32(1)
value1 := struct{ x int }{50}
key1Unsafe := unsafe.Pointer(&key1)
value1Unsafe := unsafe.Pointer(&value1)
err = testerMap.Update(key1Unsafe, value1Unsafe) // update "tester"
if err != nil {
log.Fatal(err)
}

key2 := int64(42069420)
value2 := []byte{'a', 'b', 'c'}
key2Unsafe := unsafe.Pointer(&key2)
value2Unsafe := unsafe.Pointer(&value2[0])
err = testerReusedMap.Update(key2Unsafe, value2Unsafe) // also update "tester"
if err != nil {
log.Fatal(err)
}

//
// BPFMapLow ReuseFD
//

toReuseCreated, err := bpf.CreateMap(bpf.MapTypeArray, "toreuse", 4, 4, 420, nil)
if err != nil {
log.Fatal(err)
}

// The current instance of "toreuse" will be closed, and toReuseCreated
// will now point to the same map as testerMap "tester", however, via a
// different FD.
err = toReuseCreated.ReuseFD(testerMap.FileDescriptor())
if err != nil {
log.Fatal(err)
}

val2, err := toReuseCreated.GetValue(key2Unsafe) // lookup "tester"
if err != nil {
log.Fatal(err)
}

if bytes.Equal(val2, value2) {
log.Fatal("wrong value")
}
}
1 change: 1 addition & 0 deletions selftest/reuse-fd/run.sh

0 comments on commit f3bceb3

Please sign in to comment.