New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New CreateMap API implementing bpf_map_create, Type/name accessors #138
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,6 +124,79 @@ 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 | ||
) | ||
|
||
func (m MapType) String() string { | ||
x := map[MapType]string{ | ||
MapTypeUnspec: "BPF_MAP_TYPE_UNSPEC", | ||
MapTypeHash: "BPF_MAP_TYPE_HASH", | ||
MapTypeArray: "BPF_MAP_TYPE_ARRAY", | ||
MapTypeProgArray: "BPF_MAP_TYPE_PROG_ARRAY", | ||
MapTypePerfEventArray: "BPF_MAP_TYPE_PERF_EVENT_ARRAY", | ||
MapTypePerCPUHash: "BPF_MAP_TYPE_PERCPU_HASH", | ||
MapTypePerCPUArray: "BPF_MAP_TYPE_PERCPU_ARRAY", | ||
MapTypeStackTrace: "BPF_MAP_TYPE_STACK_TRACE", | ||
MapTypeCgroupArray: "BPF_MAP_TYPE_CGROUP_ARRAY", | ||
MapTypeLRUHash: "BPF_MAP_TYPE_LRU_HASH", | ||
MapTypeLRUPerCPUHash: "BPF_MAP_TYPE_LRU_PERCPU_HASH", | ||
MapTypeLPMTrie: "BPF_MAP_TYPE_LPM_TRIE", | ||
MapTypeArrayOfMaps: "BPF_MAP_TYPE_ARRAY_OF_MAPS", | ||
MapTypeHashOfMaps: "BPF_MAP_TYPE_HASH_OF_MAPS", | ||
MapTypeDevMap: "BPF_MAP_TYPE_DEVMAP", | ||
MapTypeSockMap: "BPF_MAP_TYPE_SOCKMAP", | ||
MapTypeCPUMap: "BPF_MAP_TYPE_CPUMAP", | ||
MapTypeXSKMap: "BPF_MAP_TYPE_XSKMAP", | ||
MapTypeSockHash: "BPF_MAP_TYPE_SOCKHASH", | ||
MapTypeCgroupStorage: "BPF_MAP_TYPE_CGROUP_STORAGE", | ||
MapTypeReusePortSockArray: "BPF_MAP_TYPE_REUSEPORT_SOCKARRAY", | ||
MapTypePerCPUCgroupStorage: "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE", | ||
MapTypeQueue: "BPF_MAP_TYPE_QUEUE", | ||
MapTypeStack: "BPF_MAP_TYPE_STACK", | ||
MapTypeSKStorage: "BPF_MAP_TYPE_SK_STORAGE", | ||
MapTypeDevmapHash: "BPF_MAP_TYPE_DEVMAP_HASH", | ||
MapTypeStructOps: "BPF_MAP_TYPE_STRUCT_OPS", | ||
MapTypeRingbuf: "BPF_MAP_TYPE_RINGBUF", | ||
MapTypeInodeStorage: "BPF_MAP_TYPE_INODE_STORAGE", | ||
MapTypeTaskStorage: "BPF_MAP_TYPE_TASK_STORAGE", | ||
MapTypeBloomFilter: "BPF_MAP_TYPE_BLOOM_FILTER", | ||
} | ||
return x[m] | ||
} | ||
|
||
type BPFProg struct { | ||
name string | ||
prog *C.struct_bpf_program | ||
|
@@ -325,6 +398,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) | ||
|
@@ -341,6 +470,30 @@ func (m *Module) GetMap(mapName string) (*BPFMap, error) { | |
}, nil | ||
} | ||
|
||
func (b *BPFMap) Name() string { | ||
cs := C.bpf_map__name(b.bpfMap) | ||
if cs == nil { | ||
return "" | ||
} | ||
s := C.GoString(cs) | ||
return s | ||
} | ||
|
||
func (b *BPFMap) Type() MapType { | ||
return MapType(C.bpf_map__type(b.bpfMap)) | ||
} | ||
|
||
// SetType is used to set the type of a bpf map that isn't associated | ||
// with a file descriptor already. If the map is already associated | ||
// with a file descriptor the libbpf API will return error code EBUSY | ||
func (b *BPFMap) SetType(mapType MapType) error { | ||
errC := C.bpf_map__set_type(b.bpfMap, C.enum_bpf_map_type(int(mapType))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
if errC != 0 { | ||
return fmt.Errorf("could not set bpf map type: %w", syscall.Errno(-errC)) | ||
} | ||
return nil | ||
} | ||
|
||
func (b *BPFMap) Pin(pinPath string) error { | ||
path := C.CString(pinPath) | ||
errC := C.bpf_map__pin(b.bpfMap, path) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../common/Makefile |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 => ../../ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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= |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Considering the comment above, is it possible to add links or example APIs here to demonstrate accessing the maps that are created in the user space? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure thing! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just pushed a comment into the selftest with further explanation. If you want to try using this in Parca and are up for working on it together please tag me in the issue/PR and i'd gladly help figure it out. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💯 Thanks! |
||
{ | ||
return 0; | ||
} | ||
|
||
char LICENSE[] SEC("license") = "Dual BSD/GPL"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package main | ||
|
||
import "C" | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"unsafe" | ||
|
||
"github.com/aquasecurity/libbpfgo" | ||
bpf "github.com/aquasecurity/libbpfgo" | ||
) | ||
|
||
/* | ||
CreateMap uses `bpf_map_create()`, a 'low-level' API in libbpf | ||
As such, it does not have access to the higher level APIs in | ||
libbpf, which are denoted by starting with `bpf_map__*`. | ||
As such, you can use bpf_map_create() to populate arrays of maps | ||
in userspace, then iterate over those arrays on the bpf side, and | ||
use them as a normal map there as those operations only require | ||
a file descriptor. | ||
You can update values in the map from userspace, but currently | ||
can't retrieve values outright. | ||
For example: | ||
https://elixir.bootlin.com/linux/latest/source/samples/bpf/fds_example.c | ||
https://elixir.bootlin.com/linux/latest/source/tools/testing/selftests/bpf/test_maps.c | ||
https://lore.kernel.org/bpf/CAO658oWagXsQDeFtRA2vZBzov7cwwVNTs5nHE9fMGrMOs6bbpQ@mail.gmail.com/ | ||
*/ | ||
|
||
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) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../common/run.sh |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quoting from CreateMap above:
So, this won't work for maps created with CreateMap, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's correct, the
struct bpf_map
is NULL whichbpf_map__name()
uses as it's parameter.CreateMap
only provides a file descriptor for the map.