-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
map logic refactoring and standardization
Moved C definitions to 'libbpfgo.c', leaving 'libbpfgo.h' only with declarations to avoid multiple declaration errors when importing 'libbpfgo.h' from different Go files. Introduce 'libbpfgo_bpf_map_batch_opts_new' and 'libbpfgo_bpf_map_batch_opts_free' struct helpers to manage the C struct lifecycle on the C side. These are replacements for 'BPFMapBatchOpts' and 'bpfMapBatchOptsToC()'. This avoids problems with structs which may contain bitfields. See #244. Prefixed all C helpers used in Go with 'libbpfgo'. Restructured libbpf BPF map logic into separate files: - 'map-common.go' contains generic BPF map types, constants, and helpers like 'GetMapInfoByFD()' and 'GetMapFDByID()'. - 'map-low.go' includes 'BPFMapLow' and low-level helpers like the newly introduced 'GetMapByID()'. - 'map-iterator.go' contains related types and logic. Introduced 'misc.go' as a place for miscellaneous generic helpers and 'btf.go' with the new 'GetBTFFDByID()' function, as a place for BTF related helpers. In the 'BPFMap' struct: - Removed fields like 'fd' and 'name' since they must be retrieved directly from 'libbpf'. - Added 'bpfMapLow' instance for access to low-level methods. - Deprecated 'BPFMap.GetMaxEntries' in favor of using 'MaxEntries'. - Exposed 'InitialValue' and 'SetInitialValue' as public wrappers. Bug Fixes: - Fixed cases where 'BPFMap.ValueSize()', possibly 0, was being passed directly to 'make()' - detected on the map of maps effort #343. - Fixed 'get_internal_map_init_value' which didn't check against NULL. Further Refactoring and Standardization on the map related logic and on lines touched by other changes: - Removed check for 'BPFMap.Name()' against nil, as 'C.GoString(C.NULL)' returns "". - Changed error returns to 'retC' in functions that return error values to avoid confusion with possible use of errno. - Changed returns to 'valueC' in functions that return values or pointers to values. - Suffixed variable names that are C types with 'C'. - Applied the use of 'defer' for better resource management.
- Loading branch information
Showing
10 changed files
with
1,507 additions
and
819 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package libbpfgo | ||
|
||
/* | ||
#cgo LDFLAGS: -lelf -lz | ||
#include "libbpfgo.h" | ||
*/ | ||
import "C" | ||
|
||
import ( | ||
"fmt" | ||
"syscall" | ||
) | ||
|
||
// | ||
// BTF (low-level API) | ||
// | ||
|
||
// GetBTFFDByID returns a file descriptor for the BTF with the given ID. | ||
func GetBTFFDByID(id uint32) (int, error) { | ||
fdC := C.bpf_btf_get_fd_by_id(C.uint(id)) | ||
if fdC < 0 { | ||
return int(fdC), fmt.Errorf("could not find BTF id %d: %w", id, syscall.Errno(-fdC)) | ||
} | ||
|
||
return int(fdC), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
#include "libbpfgo.h" | ||
|
||
extern void loggerCallback(enum libbpf_print_level level, char *output); | ||
extern void perfCallback(void *ctx, int cpu, void *data, __u32 size); | ||
extern void perfLostCallback(void *ctx, int cpu, __u64 cnt); | ||
extern int ringbufferCallback(void *ctx, void *data, size_t size); | ||
|
||
int libbpf_print_fn(enum libbpf_print_level level, // libbpf print level | ||
const char *format, // format used for the msg | ||
va_list args) | ||
{ // args used by format | ||
|
||
int ret; | ||
size_t len; | ||
char *out; | ||
va_list check; | ||
|
||
va_copy(check, args); | ||
ret = vsnprintf(NULL, 0, format, check); // get output length | ||
va_end(check); | ||
|
||
if (ret < 0) | ||
return ret; | ||
|
||
len = ret + 1; // add 1 for NUL | ||
out = malloc(len); | ||
if (!out) | ||
return -ENOMEM; | ||
|
||
va_copy(check, args); | ||
ret = vsnprintf(out, len, format, check); | ||
va_end(check); | ||
|
||
if (ret > 0) | ||
loggerCallback(level, out); | ||
|
||
free(out); | ||
|
||
return ret; | ||
} | ||
|
||
void libbpfgo_libbpf_set_print_fn() | ||
{ | ||
libbpf_set_print(libbpf_print_fn); | ||
} | ||
|
||
struct ring_buffer *libbpfgo_init_ring_buf(int map_fd, uintptr_t ctx) | ||
{ | ||
struct ring_buffer *rb = NULL; | ||
|
||
rb = ring_buffer__new(map_fd, ringbufferCallback, (void *) ctx, NULL); | ||
if (!rb) { | ||
int saved_errno = errno; | ||
fprintf(stderr, "Failed to initialize ring buffer: %s\n", strerror(errno)); | ||
errno = saved_errno; | ||
|
||
return NULL; | ||
} | ||
|
||
return rb; | ||
} | ||
|
||
struct perf_buffer *libbpfgo_init_perf_buf(int map_fd, int page_cnt, uintptr_t ctx) | ||
{ | ||
struct perf_buffer_opts pb_opts = {}; | ||
struct perf_buffer *pb = NULL; | ||
|
||
pb_opts.sz = sizeof(struct perf_buffer_opts); | ||
|
||
pb = perf_buffer__new(map_fd, page_cnt, perfCallback, perfLostCallback, (void *) ctx, &pb_opts); | ||
if (!pb) { | ||
int saved_errno = errno; | ||
fprintf(stderr, "Failed to initialize perf buffer: %s\n", strerror(errno)); | ||
errno = saved_errno; | ||
|
||
return NULL; | ||
} | ||
|
||
return pb; | ||
} | ||
|
||
void libbpfgo_bpf_map__initial_value(struct bpf_map *map, void *value) | ||
{ | ||
size_t psize; | ||
const void *data; | ||
|
||
data = bpf_map__initial_value(map, &psize); | ||
if (!data) | ||
return; | ||
|
||
memcpy(value, data, psize); | ||
} | ||
|
||
int libbpfgo_bpf_prog_attach_cgroup_legacy(int prog_fd, // eBPF program file descriptor | ||
int target_fd, // cgroup directory file descriptor | ||
int type) // BPF_CGROUP_INET_{INGRESS,EGRESS}, ... | ||
{ | ||
union bpf_attr attr; | ||
memset(&attr, 0, sizeof(attr)); | ||
attr.target_fd = target_fd; | ||
attr.attach_bpf_fd = prog_fd; | ||
attr.attach_type = type; | ||
attr.attach_flags = BPF_F_ALLOW_MULTI; // or BPF_F_ALLOW_OVERRIDE | ||
|
||
return syscall(__NR_bpf, BPF_PROG_ATTACH, &attr, sizeof(attr)); | ||
} | ||
|
||
int libbpfgo_bpf_prog_detach_cgroup_legacy(int prog_fd, // eBPF program file descriptor | ||
int target_fd, // cgroup directory file descriptor | ||
int type) // BPF_CGROUP_INET_{INGRESS,EGRESS}, ... | ||
{ | ||
union bpf_attr attr; | ||
memset(&attr, 0, sizeof(attr)); | ||
attr.target_fd = target_fd; | ||
attr.attach_bpf_fd = prog_fd; | ||
attr.attach_type = type; | ||
|
||
return syscall(__NR_bpf, BPF_PROG_DETACH, &attr, sizeof(attr)); | ||
} | ||
|
||
struct bpf_iter_attach_opts *libbpfgo_bpf_iter_attach_opts_new(__u32 map_fd, | ||
enum bpf_cgroup_iter_order order, | ||
__u32 cgroup_fd, | ||
__u64 cgroup_id, | ||
__u32 tid, | ||
__u32 pid, | ||
__u32 pid_fd) | ||
{ | ||
union bpf_iter_link_info *linfo; | ||
linfo = calloc(1, sizeof(*linfo)); | ||
if (!linfo) | ||
return NULL; | ||
|
||
linfo->map.map_fd = map_fd; | ||
linfo->cgroup.order = order; | ||
linfo->cgroup.cgroup_fd = cgroup_fd; | ||
linfo->cgroup.cgroup_id = cgroup_id; | ||
linfo->task.tid = tid; | ||
linfo->task.pid = pid; | ||
linfo->task.pid_fd = pid_fd; | ||
|
||
struct bpf_iter_attach_opts *opts; | ||
opts = calloc(1, sizeof(*opts)); | ||
if (!opts) { | ||
free(linfo); | ||
return NULL; | ||
} | ||
|
||
opts->sz = sizeof(*opts); | ||
opts->link_info_len = sizeof(*linfo); | ||
opts->link_info = linfo; | ||
|
||
return opts; | ||
} | ||
|
||
void libbpfgo_bpf_iter_attach_opts_free(struct bpf_iter_attach_opts *opts) | ||
{ | ||
if (!opts) | ||
return; | ||
|
||
free(opts->link_info); | ||
free(opts); | ||
} | ||
|
||
struct bpf_object_open_opts *libbpfgo_bpf_object_open_opts_new(const char *btf_file_path, | ||
const char *kconfig_path, | ||
const char *bpf_obj_name) | ||
{ | ||
struct bpf_object_open_opts *opts; | ||
opts = calloc(1, sizeof(*opts)); | ||
if (!opts) | ||
return NULL; | ||
|
||
opts->sz = sizeof(*opts); | ||
opts->btf_custom_path = btf_file_path; | ||
opts->kconfig = kconfig_path; | ||
opts->object_name = bpf_obj_name; | ||
|
||
return opts; | ||
} | ||
|
||
void libbpfgo_bpf_object_open_opts_free(struct bpf_object_open_opts *opts) | ||
{ | ||
free(opts); | ||
} | ||
|
||
struct bpf_map_create_opts *libbpfgo_bpf_map_create_opts_new(__u32 btf_fd, | ||
__u32 btf_key_type_id, | ||
__u32 btf_value_type_id, | ||
__u32 btf_vmlinux_value_type_id, | ||
__u32 inner_map_fd, | ||
__u32 map_flags, | ||
__u64 map_extra, | ||
__u32 numa_node, | ||
__u32 map_ifindex) | ||
{ | ||
struct bpf_map_create_opts *opts; | ||
opts = calloc(1, sizeof(*opts)); | ||
if (!opts) | ||
return NULL; | ||
|
||
opts->sz = sizeof(*opts); | ||
opts->btf_fd = btf_fd; | ||
opts->btf_key_type_id = btf_key_type_id; | ||
opts->btf_value_type_id = btf_value_type_id; | ||
opts->btf_vmlinux_value_type_id = btf_vmlinux_value_type_id; | ||
opts->inner_map_fd = inner_map_fd; | ||
opts->map_flags = map_flags; | ||
opts->map_extra = map_extra; | ||
opts->numa_node = numa_node; | ||
opts->map_ifindex = map_ifindex; | ||
|
||
return opts; | ||
} | ||
|
||
void libbpfgo_bpf_map_create_opts_free(struct bpf_map_create_opts *opts) | ||
{ | ||
free(opts); | ||
} | ||
|
||
struct bpf_map_batch_opts *libbpfgo_bpf_map_batch_opts_new(__u64 elem_flags, __u64 flags) | ||
{ | ||
struct bpf_map_batch_opts *opts; | ||
opts = calloc(1, sizeof(*opts)); | ||
if (!opts) | ||
return NULL; | ||
|
||
opts->sz = sizeof(*opts); | ||
opts->elem_flags = elem_flags; | ||
opts->flags = flags; | ||
|
||
return opts; | ||
} | ||
|
||
void libbpfgo_bpf_map_batch_opts_free(struct bpf_map_batch_opts *opts) | ||
{ | ||
free(opts); | ||
} |
Oops, something went wrong.