Skip to content

Commit

Permalink
feat(map): introduce SetInnerMapFD()
Browse files Browse the repository at this point in the history
This allows to set the inner map prototype of a map of maps which
doesn't have a pre-allocated inner map.

Initial effort: #213

Co-authored-by: Kemal Akkoyun <kakkoyun@gmail.com>
  • Loading branch information
geyslan and kakkoyun committed Aug 17, 2023
1 parent b28c448 commit c834f37
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 3 deletions.
22 changes: 19 additions & 3 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,25 @@ func (m *BPFMap) Unpin(pinPath string) error {
// func (m *BPFMap) InnerMap() *BPFMap {
// }

// TODO: implement `bpf_map__set_inner_map_fd` wrapper
// func (m *BPFMap) SetInnerMapFD(innerMapFD int) error {
// }
// SetInnerMap configures the inner map prototype for a BPFMap that represents
// a map of maps.
//
// This function accepts the file descriptor of another map, which will serve as
// a prototype.
//
// NOTE: It must be called before the module is loaded.
func (m *BPFMap) SetInnerMap(templateMapFD int) error {
if templateMapFD < 0 {
return fmt.Errorf("invalid inner map fd %d", templateMapFD)
}

retC := C.bpf_map__set_inner_map_fd(m.bpfMap, C.int(templateMapFD))
if retC < 0 {
return fmt.Errorf("failed to set inner map for %s: %w", m.Name(), syscall.Errno(-retC))
}

return nil
}

//
// BPFMap Operations
Expand Down
1 change: 1 addition & 0 deletions selftest/map-setinner/Makefile
7 changes: 7 additions & 0 deletions selftest/map-setinner/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/map-setinner/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=
15 changes: 15 additions & 0 deletions selftest/map-setinner/main.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//+build ignore

#include <vmlinux.h>

#include <bpf/bpf_helpers.h>

// Hash map of maps with no inner maps preallocated.
struct {
__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, __u32);
} outer_hash SEC(".maps");

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

import "C"

import (
"log"
"syscall"

bpf "github.com/aquasecurity/libbpfgo"
)

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

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

templateInnerMap, err := bpf.CreateMap(bpf.MapTypeHash, "template_inner_map", 4, 4, 420, nil)
if err != nil {
log.Fatal(err)
}

// As the "outer_hash" map does not have an inner map prototype pre-allocated,
// an active map (from any origin) must be used as a template, by calling
// SetInnerMap() before the object is loaded, otherwise the BPF program will
// fail to load. The template map can be removed after the object is loaded.
err = outerHash.SetInnerMap(templateInnerMap.FileDescriptor())
if err != nil {
log.Fatal(err)
}

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

//
// "outer_hash" map of maps is now fully loaded and can be used.
//

// Attempting to set inner map after the object is loaded will fail.
err = outerHash.SetInnerMap(templateInnerMap.FileDescriptor())
if err == nil {
log.Fatal("should fail after object is loaded")
}

// If not needed anymore, remove the "template_inner_map",
// freeing up resources.
err = syscall.Close(templateInnerMap.FileDescriptor())
if err != nil {
log.Fatal(err)
}
}
1 change: 1 addition & 0 deletions selftest/map-setinner/run.sh

0 comments on commit c834f37

Please sign in to comment.