Skip to content

Commit

Permalink
Add bpf_map_create() API and selftest
Browse files Browse the repository at this point in the history
Signed-off-by: grantseltzer <grantseltzer@gmail.com>
  • Loading branch information
grantseltzer committed Mar 15, 2022
1 parent c46f053 commit bd41892
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 0 deletions.
92 changes: 92 additions & 0 deletions libbpfgo.go
Expand Up @@ -124,6 +124,42 @@ type BPFMap struct {
module *Module
}

type MapType uint32

const (
MapTypeUnspec MapType = iota
MapTypeHash
MapTypeArray
MapTypeProgArray
MapTypePerfEventArray
MapTypePerCPUHash
MapTypePerCPUArray
MapTypeStackTrace
MapTypeCgroupArray
MapTypeLRUHash
MapTypeLRUPerCPUHash
MapTypeLPMTrie
MapTypeArrayOfMaps
MapTypeHashOfMaps
MapTypeDevMap
MapTypeSockMap
MapTypeCPUMap
MapTypeXSKMap
MapTypeSockHash
MapTypeCgroupStorage
MapTypeReusePortSockArray
MapTypePerCPUCgroupStorage
MapTypeQueue
MapTypeStack
MapTypeSKStorage
MapTypeDevmapHash
MapTypeStructOps
MapTypeRingbuf
MapTypeInodeStorage
MapTypeTaskStorage
MapTypeBloomFilter
)

type BPFProg struct {
name string
prog *C.struct_bpf_program
Expand Down Expand Up @@ -325,6 +361,62 @@ func (m *Module) BPFLoadObject() error {
return nil
}

// BPFMapCreateOpts mirrors the C structure bpf_map_create_opts
type BPFMapCreateOpts struct {
Size uint64
BtfFD uint32
BtfKeyTypeID uint32
BtfValueTypeID uint32
BtfVmlinuxValueTypeID uint32
InnerMapFD uint32
MapFlags uint32
MapExtra uint64
NumaNode uint32
MapIfIndex uint32
}

func bpfMapCreateOptsToC(createOpts *BPFMapCreateOpts) *C.struct_bpf_map_create_opts {
if createOpts == nil {
return nil
}
opts := C.struct_bpf_map_create_opts{}
opts.sz = C.ulong(createOpts.Size)
opts.btf_fd = C.uint(createOpts.BtfFD)
opts.btf_key_type_id = C.uint(createOpts.BtfKeyTypeID)
opts.btf_value_type_id = C.uint(createOpts.BtfValueTypeID)
opts.btf_vmlinux_value_type_id = C.uint(createOpts.BtfVmlinuxValueTypeID)
opts.inner_map_fd = C.uint(createOpts.InnerMapFD)
opts.map_flags = C.uint(createOpts.MapFlags)
opts.map_extra = C.ulonglong(createOpts.MapExtra)
opts.numa_node = C.uint(createOpts.NumaNode)
opts.map_ifindex = C.uint(createOpts.MapIfIndex)

return &opts
}

// CreateMap creates a BPF map from userspace. This can be used for populating
// BPF array of maps or hash of maps. However, this function uses a low-level
// libbpf API; maps created in this way do not conform to libbpf map formats,
// and therefore do not have access to libbpf high level bpf_map__* APIS
// which causes different behavior from maps created in the kernel side code
//
// See usage of `bpf_map_create()` in kernel selftests for more info
func CreateMap(mapType MapType, mapName string, keySize, valueSize, maxEntries int, opts *BPFMapCreateOpts) (*BPFMap, error) {
cs := C.CString(mapName)
fdOrError := C.bpf_map_create(uint32(mapType), cs, C.uint(keySize), C.uint(valueSize), C.uint(maxEntries), bpfMapCreateOptsToC(opts))
C.free(unsafe.Pointer(cs))
if fdOrError < 0 {
return nil, fmt.Errorf("could not create map: %w", syscall.Errno(-fdOrError))
}

return &BPFMap{
name: mapName,
fd: fdOrError,
module: nil,
bpfMap: nil,
}, nil
}

func (m *Module) GetMap(mapName string) (*BPFMap, error) {
cs := C.CString(mapName)
bpfMap, errno := C.bpf_object__find_map_by_name(m.obj, cs)
Expand Down
1 change: 1 addition & 0 deletions selftest/create-map/Makefile
7 changes: 7 additions & 0 deletions selftest/create-map/go.mod
@@ -0,0 +1,7 @@
module github.com/aquasecurity/libbpfgo/selftest/map-pin-info

go 1.16

require github.com/aquasecurity/libbpfgo v0.2.1-libbpf-0.4.0

replace github.com/aquasecurity/libbpfgo => ../../
11 changes: 11 additions & 0 deletions selftest/create-map/go.sum
@@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
11 changes: 11 additions & 0 deletions selftest/create-map/main.bpf.c
@@ -0,0 +1,11 @@
//+build ignore
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

SEC("kprobe/sys_execve")
int kprobe__sys_execve(struct pt_regs *ctx)
{
return 0;
}

char LICENSE[] SEC("license") = "Dual BSD/GPL";
40 changes: 40 additions & 0 deletions selftest/create-map/main.go
@@ -0,0 +1,40 @@
package main

import "C"

import (
"fmt"
"log"
"os"
"unsafe"

"github.com/aquasecurity/libbpfgo"
bpf "github.com/aquasecurity/libbpfgo"
)

func main() {
bpfModule, err := bpf.NewModuleFromFile("main.bpf.o")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(-1)
}
defer bpfModule.Close()

bpfModule.BPFLoadObject()
opts := bpf.BPFMapCreateOpts{}
opts.Size = uint64(unsafe.Sizeof(opts))

m, err := libbpfgo.CreateMap(libbpfgo.MapTypeHash, "foobar", 4, 4, 420, nil)
if err != nil {
log.Fatal(err)
}

key1 := uint32(1)
value1 := uint32(55)
key1Unsafe := unsafe.Pointer(&key1)
value1Unsafe := unsafe.Pointer(&value1)
err = m.Update(key1Unsafe, value1Unsafe)
if err != nil {
log.Fatal(err)
}
}
1 change: 1 addition & 0 deletions selftest/create-map/run.sh

0 comments on commit bd41892

Please sign in to comment.