Skip to content

Commit

Permalink
chore(): use cgo_* helpers for struct lifecycle
Browse files Browse the repository at this point in the history
Introduced struct helpers to manage the C struct lifecycle on the C side,
which avoids problems with structs which may contain bitfields. See #244.

  - cgo_bpf_map_info_new()
  - cgo_bpf_map_info_size()
  - cgo_bpf_map_info_free()

  - cgo_bpf_tc_opts_new()
  - cgo_bpf_tc_opts_free()

  - cgo_bpf_tc_hook_new()
  - cgo_bpf_tc_hook_free()

Based on the same #244 concerns, introduced bpf_map_info getters:

  - cgo_bpf_map_info_type()
  - cgo_bpf_map_info_id()
  - cgo_bpf_map_info_key_size()
  - cgo_bpf_map_info_value_size()
  - cgo_bpf_map_info_max_entries()
  - cgo_bpf_map_info_map_flags()
  - cgo_bpf_map_info_name()
  - cgo_bpf_map_info_ifindex()
  - cgo_bpf_map_info_btf_vmlinux_value_type_id()
  - cgo_bpf_map_info_netns_dev()
  - cgo_bpf_map_info_netns_ino()
  - cgo_bpf_map_info_btf_id()
  - cgo_bpf_map_info_btf_key_type_id()
  - cgo_bpf_map_info_btf_value_type_id()
  - cgo_bpf_map_info_map_extra()

Changed these functions to use cgo_* struct handlers:

  - NewModuleFromFileArgs()
  - GetMapInfoByFD()
  - TcHook.Destroy()
  - TcHook.Attach()
  - TcHook.Detach()
  - TcHook.Query()

Removed tcOptsFromC() since libbpf doesn't seem to update bpf_tc_opts.
  • Loading branch information
geyslan committed Aug 25, 2023
1 parent 346872d commit 34cc55f
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 71 deletions.
190 changes: 190 additions & 0 deletions libbpfgo.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ int cgo_bpf_prog_detach_cgroup_legacy(int prog_fd, // eBPF program file descri
return syscall(__NR_bpf, BPF_PROG_DETACH, &attr, sizeof(attr));
}

//
// struct handlers
//

struct bpf_iter_attach_opts *cgo_bpf_iter_attach_opts_new(__u32 map_fd,
enum bpf_cgroup_iter_order order,
__u32 cgroup_fd,
Expand Down Expand Up @@ -235,3 +239,189 @@ void cgo_bpf_map_batch_opts_free(struct bpf_map_batch_opts *opts)
{
free(opts);
}

struct bpf_map_info *cgo_bpf_map_info_new()
{
struct bpf_map_info *info;
info = calloc(1, sizeof(*info));
if (!info)
return NULL;

return info;
}

__u32 cgo_bpf_map_info_size()
{
return sizeof(struct bpf_map_info);
}

void cgo_bpf_map_info_free(struct bpf_map_info *info)
{
free(info);
}

struct bpf_tc_opts *cgo_bpf_tc_opts_new(
int prog_fd, __u32 flags, __u32 prog_id, __u32 handle, __u32 priority)
{
struct bpf_tc_opts *opts;
opts = calloc(1, sizeof(*opts));
if (!opts)
return NULL;

opts->sz = sizeof(*opts);
opts->prog_fd = prog_fd;
opts->flags = flags;
opts->prog_id = prog_id;
opts->handle = handle;
opts->priority = priority;

return opts;
}

void cgo_bpf_tc_opts_free(struct bpf_tc_opts *opts)
{
free(opts);
}

struct bpf_tc_hook *cgo_bpf_tc_hook_new()
{
struct bpf_tc_hook *hook;
hook = calloc(1, sizeof(*hook));
if (!hook)
return NULL;

hook->sz = sizeof(*hook);

return hook;
}

void cgo_bpf_tc_hook_free(struct bpf_tc_hook *hook)
{
free(hook);
}

//
// struct getters
//

// bpf_map_info

__u32 cgo_bpf_map_info_type(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->type;
}

__u32 cgo_bpf_map_info_id(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->id;
}

__u32 cgo_bpf_map_info_key_size(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->key_size;
}

__u32 cgo_bpf_map_info_value_size(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->value_size;
}

__u32 cgo_bpf_map_info_max_entries(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->max_entries;
}

__u32 cgo_bpf_map_info_map_flags(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->map_flags;
}

char *cgo_bpf_map_info_name(struct bpf_map_info *info)
{
if (!info)
return NULL;

return info->name;
}

__u32 cgo_bpf_map_info_ifindex(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->ifindex;
}

__u32 cgo_bpf_map_info_btf_vmlinux_value_type_id(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->btf_vmlinux_value_type_id;
}

__u64 cgo_bpf_map_info_netns_dev(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->netns_dev;
}

__u64 cgo_bpf_map_info_netns_ino(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->netns_ino;
}

__u32 cgo_bpf_map_info_btf_id(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->btf_id;
}

__u32 cgo_bpf_map_info_btf_key_type_id(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->btf_key_type_id;
}

__u32 cgo_bpf_map_info_btf_value_type_id(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->btf_value_type_id;
}

__u64 cgo_bpf_map_info_map_extra(struct bpf_map_info *info)
{
if (!info)
return 0;

return info->map_extra;
}
33 changes: 33 additions & 0 deletions libbpfgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,37 @@ void cgo_bpf_map_create_opts_free(struct bpf_map_create_opts *opts);
struct bpf_map_batch_opts *cgo_bpf_map_batch_opts_new(__u64 elem_flags, __u64 flags);
void cgo_bpf_map_batch_opts_free(struct bpf_map_batch_opts *opts);

struct bpf_map_info *cgo_bpf_map_info_new();
__u32 cgo_bpf_map_info_size();
void cgo_bpf_map_info_free(struct bpf_map_info *info);

struct bpf_tc_opts *cgo_bpf_tc_opts_new(
int prog_fd, __u32 flags, __u32 prog_id, __u32 handle, __u32 priority);
void cgo_bpf_tc_opts_free(struct bpf_tc_opts *opts);

struct bpf_tc_hook *cgo_bpf_tc_hook_new();
void cgo_bpf_tc_hook_free(struct bpf_tc_hook *hook);

//
// struct getters
//

// bpf_map_info

__u32 cgo_bpf_map_info_type(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_id(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_key_size(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_value_size(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_max_entries(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_map_flags(struct bpf_map_info *info);
char *cgo_bpf_map_info_name(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_ifindex(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_btf_vmlinux_value_type_id(struct bpf_map_info *info);
__u64 cgo_bpf_map_info_netns_dev(struct bpf_map_info *info);
__u64 cgo_bpf_map_info_netns_ino(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_btf_id(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_btf_key_type_id(struct bpf_map_info *info);
__u32 cgo_bpf_map_info_btf_value_type_id(struct bpf_map_info *info);
__u64 cgo_bpf_map_info_map_extra(struct bpf_map_info *info);

#endif
37 changes: 19 additions & 18 deletions map-common.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,30 +137,31 @@ func GetMapFDByID(id uint32) (int, error) {

// GetMapInfoByFD returns the BPFMapInfo for the map with the given file descriptor.
func GetMapInfoByFD(fd int) (*BPFMapInfo, error) {
var info C.struct_bpf_map_info
var infoLen C.uint = C.uint(C.sizeof_struct_bpf_map_info)
infoC := C.cgo_bpf_map_info_new()
defer C.cgo_bpf_map_info_free(infoC)

retC := C.bpf_map_get_info_by_fd(C.int(fd), &info, &infoLen)
infoLenC := C.cgo_bpf_map_info_size()
retC := C.bpf_map_get_info_by_fd(C.int(fd), infoC, &infoLenC)
if retC < 0 {
return nil, fmt.Errorf("failed to get map info for fd %d: %w", fd, syscall.Errno(-retC))
}

return &BPFMapInfo{
Type: MapType(uint32(info._type)),
ID: uint32(info.id),
KeySize: uint32(info.key_size),
ValueSize: uint32(info.value_size),
MaxEntries: uint32(info.max_entries),
MapFlags: uint32(info.map_flags),
Name: C.GoString(&info.name[0]),
IfIndex: uint32(info.ifindex),
BTFVmlinuxValueTypeID: uint32(info.btf_vmlinux_value_type_id),
NetnsDev: uint64(info.netns_dev),
NetnsIno: uint64(info.netns_ino),
BTFID: uint32(info.btf_id),
BTFKeyTypeID: uint32(info.btf_key_type_id),
BTFValueTypeID: uint32(info.btf_value_type_id),
MapExtra: uint64(info.map_extra),
Type: MapType(C.cgo_bpf_map_info_type(infoC)),
ID: uint32(C.cgo_bpf_map_info_id(infoC)),
KeySize: uint32(C.cgo_bpf_map_info_key_size(infoC)),
ValueSize: uint32(C.cgo_bpf_map_info_value_size(infoC)),
MaxEntries: uint32(C.cgo_bpf_map_info_max_entries(infoC)),
MapFlags: uint32(C.cgo_bpf_map_info_map_flags(infoC)),
Name: C.GoString(C.cgo_bpf_map_info_name(infoC)),
IfIndex: uint32(C.cgo_bpf_map_info_ifindex(infoC)),
BTFVmlinuxValueTypeID: uint32(C.cgo_bpf_map_info_btf_vmlinux_value_type_id(infoC)),
NetnsDev: uint64(C.cgo_bpf_map_info_netns_dev(infoC)),
NetnsIno: uint64(C.cgo_bpf_map_info_netns_ino(infoC)),
BTFID: uint32(C.cgo_bpf_map_info_btf_id(infoC)),
BTFKeyTypeID: uint32(C.cgo_bpf_map_info_btf_key_type_id(infoC)),
BTFValueTypeID: uint32(C.cgo_bpf_map_info_btf_value_type_id(infoC)),
MapExtra: uint64(C.cgo_bpf_map_info_map_extra(infoC)),
}, nil
}

Expand Down
36 changes: 18 additions & 18 deletions module.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,30 @@ func NewModuleFromFileArgs(args NewModuleArgs) (*Module, error) {
}
}

optsC := C.struct_bpf_object_open_opts{}
optsC.sz = C.sizeof_struct_bpf_object_open_opts

bpfFileC := C.CString(args.BPFObjPath)
defer C.free(unsafe.Pointer(bpfFileC))
var btfFilePathC *C.char
var kconfigPathC *C.char

// instruct libbpf to use user provided kernel BTF file
if args.BTFObjPath != "" {
btfFileC := C.CString(args.BTFObjPath)
optsC.btf_custom_path = btfFileC
defer C.free(unsafe.Pointer(btfFileC))
btfFilePathC = C.CString(args.BTFObjPath)
defer C.free(unsafe.Pointer(btfFilePathC))
}

// instruct libbpf to use user provided KConfigFile
if args.KConfigFilePath != "" {
kConfigFileC := C.CString(args.KConfigFilePath)
optsC.kconfig = kConfigFileC
defer C.free(unsafe.Pointer(kConfigFileC))
kconfigPathC = C.CString(args.KConfigFilePath)
defer C.free(unsafe.Pointer(kconfigPathC))
}

optsC, errno := C.cgo_bpf_object_open_opts_new(btfFilePathC, kconfigPathC, nil)
if optsC == nil {
return nil, fmt.Errorf("failed to create bpf_object_open_opts: %w", errno)
}
defer C.cgo_bpf_object_open_opts_free(optsC)

bpfFileC := C.CString(args.BPFObjPath)
defer C.free(unsafe.Pointer(bpfFileC))

objC, errno := C.bpf_object__open_file(bpfFileC, &optsC)
objC, errno := C.bpf_object__open_file(bpfFileC, optsC)
if objC == nil {
return nil, fmt.Errorf("failed to open BPF object at path %s: %w", args.BPFObjPath, errno)
}
Expand Down Expand Up @@ -133,7 +136,7 @@ func NewModuleFromBufferArgs(args NewModuleArgs) (*Module, error) {

optsC, errno := C.cgo_bpf_object_open_opts_new(btfFilePathC, kConfigPathC, bpfObjNameC)
if optsC == nil {
return nil, fmt.Errorf("failed to create bpf_object_open_opts to %s: %w", args.BPFObjName, errno)
return nil, fmt.Errorf("failed to create bpf_object_open_opts: %w", errno)
}
defer C.cgo_bpf_object_open_opts_free(optsC)

Expand Down Expand Up @@ -374,11 +377,8 @@ func (m *Module) InitPerfBuf(mapName string, eventsChan chan []byte, lostChan ch
}

func (m *Module) TcHookInit() *TcHook {
hook := C.struct_bpf_tc_hook{}
hook.sz = C.sizeof_struct_bpf_tc_hook

return &TcHook{
hook: &hook,
hook: C.cgo_bpf_tc_hook_new(),
}
}

Expand Down
6 changes: 6 additions & 0 deletions selftest/tc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ func main() {
}

hook := bpfModule.TcHookInit()
defer func() {
if err := hook.Destroy(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
}()

err = hook.SetInterfaceByName("lo")
if err != nil {
fmt.Fprintln(os.Stderr, "failed to set tc hook on interface lo: %v", err)
Expand Down

0 comments on commit 34cc55f

Please sign in to comment.