libbpfgo 使用示例:在内核态和用户态使用 ebpf map

前言

记录一下如何在 libbpfgo 程序中使用 ebpf map(ebpf map 本身的资料可以参考参考资料)。

ebpf 程序中使用 ebpf map

定义 map

先看一下定义一个 ebpf map 的方法,比如类型为 BPF_MAP_TYPE_HASH 的 map:

struct {
        __uint(type, BPF_MAP_TYPE_HASH);
        __type(key, u32);
        __type(value, struct event_t);
        __uint(max_entries, 1024 * 16);
} event_map SEC(".maps");

可以看到主要需要指定 typekeyvaluemax_entries 这几个字段。

对 map 进行操作

在 ebpf 程序中可以通过下面几个常用的辅助函数对 map 对象进行操作:

void bpf_map_lookup_elem(map, void *key. ...) 通过 key 查找对应的 value

event = bpf_map_lookup_elem(&event_map, &pid);
if (!event) {    // key 不存在
    return 0;
}

void bpf_map_update_elem(map, void *key, ..., __u64 flags) 更新指定 key 的值, flags 参数用于控制更新行为

/* File: include/uapi/linux/bpf.h */
/* flags for BPF_MAP_UPDATE_ELEM command */
#define BPF_ANY       0 /* create new element or update existing */
#define BPF_NOEXIST   1 /* create new element only if it didn't exist */
#define BPF_EXIST     2 /* only update existing element */

bpf_map_update_elem(&event_map, &pid, &event, BPF_ANY);

void bpf_map_delete_elem(map, void *key) 删除指定 key

bpf_map_delete_elem(&event_map, &pid);

完整示例程序详见: https://github.com/mozillazg/hello-libbpfgo/tree/master/08-map-map-type-hash-kernel

pin map

pin map 用于将 map 保存到本地文件系统中进行持久化, libbpf 中是会自动保存到 /sys/fs/bpf/<map_name> 路径下。

定义 pin map 的方法只是在普通 map 的基础上加一个 pinning 字段:

struct {
        __uint(type, BPF_MAP_TYPE_HASH);
        __type(key, u32);
        __type(value, struct event_t);
        __uint(max_entries, 1024 * 16);
        __uint(pinning, LIBBPF_PIN_BY_NAME);  // <- pin
} event_map SEC(".maps");

完整示例程序详见: https://github.com/mozillazg/hello-libbpfgo/tree/master/11-map-pin

go 程序中使用 ebpf map

可以使用 libbpfgo 在 go 程序中操作 ebpf 程序中定义的 ebpf map。

对 map 进行操作

先通过 bpfmap, err := bpfModule.GetMap("bpf_map") 拿到定义的 map 对象,然后就可以 做一些常见的操作了:

Update(key, value unsafe.Pointer) error 更新指定 key 的值,使用的 flags 是 BPF_ANY 即 创建新元素或者更新已有的 key:

key := 1
value := 233
keyPtr := unsafe.Pointer(&key)
valuePtr := unsafe.Pointer(&value)
bpfmap.Update(keyPtr, valuePtr)

GetValue(key unsafe.Pointer) ([]byte, error) 获取指定 key 的值,当 key 不存在时会返回 error:

key := 1
keyPtr := unsafe.Pointer(&key)
data, err := bpfmap.GetValue(keyPtr)

DeleteKey(key unsafe.Pointer) error 删除指定 key,当 key 不存在时会返回 error:

key := 1
keyPtr := unsafe.Pointer(&key)
err := bpfmap.DeleteKey(keyPtr)

完整示例程序详见: https://github.com/mozillazg/hello-libbpfgo/tree/master/09-map-map-type-hash-userspace


Comments