ebpf对我来说,是个新玩意。
1、知道用哪些api?
2、这些api的参数和返回值?在哪里找这些内容?
3、各个api如何有机结合,实现一个功能?
一、功能概述
第一节课是纯用户态来操作ebpf map的api,下节课讲述内核态创建map并写入元素,用户态获取到map后遍历读取元素进行展示。
用户态程序 (test_maps.c):
演示ebpf map的创建、删除、更新、查找等操作api
支持优雅退出(Ctrl+C)
二、编译和运行
在src/user_map目录下执行make命令,会在当前目录生成
三、核心API函数
写代码前,先熟悉下主要使用到的api函数
1、创建map bpf_map_create
函数定义
Definition
int bpf_map_create(enum bpf_map_type map_type, const char *map_name, __u32 key_size, __u32 value_size, __u32 max_entries, const struct bpf_map_create_opts *opts);Parameters
map_type: type of the map to createmap_name: name of the mapkey_size: size of the key in bytesvalue_size: size of the value in bytesmax_entries: maximum number of entries in the mapopts: options for the map creation
详情链接:https://docs.ebpf.io/ebpf-library/libbpf/userspace/bpf_map_create/
2、创建元素和更新元素 bpf_map_update_elem
Definition
int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags);Parameters
fd: file descriptor of the map to updatekey: pointer to memory containing bytes of the keyvalue: pointer to memory containing bytes of the valueflags: flags passed to kernel for this operation
Return
0, on success; negative error, otherwise
函数参数中的最后一个能填写什么呢?进入源代码可以看到定义
/* flags for BPF_MAP_UPDATE_ELEM command */
enum {
BPF_ANY = 0, /* create new element or update existing */
BPF_NOEXIST = 1, /* create new element if it didn't exist */
BPF_EXIST = 2, /* update existing element */
BPF_F_LOCK = 4, /* spin_lock-ed map_lookup/map_update */
};每个枚举变量的解释已经很清晰。
详情链接:https://docs.ebpf.io/ebpf-library/libbpf/userspace/bpf_map_update_elem/
3、在map中查找元素 bpf_map_lookup_elem
Definition
int bpf_map_lookup_elem(int fd, const void *key, void *value);Parameters
fd: file descriptor of the map to lookup element inkey: pointer to memory containing bytes of the key used for lookupvalue: pointer to memory in which looked up value will be stored
Return
0, on success; negative error, otherwise
详情链接:https://docs.ebpf.io/ebpf-library/libbpf/userspace/bpf_map_lookup_elem/
4、在map中查找并且删除元素
bpf_map_lookup_and_delete_elem
Definition
int bpf_map_lookup_and_delete_elem(int fd, const void *key, void *value);Parameters
fd: file descriptor of the map to lookup element inkey: pointer to memory containing bytes of the key used for lookupvalue: pointer to memory in which looked up value will be stored
Return
0, on success; negative error, otherwise
详情链接:https://docs.ebpf.io/ebpf-library/libbpf/userspace/bpf_map_lookup_and_delete_elem/
5、在map中删除某个元素 bpf_map_delete_elem
Definition
int bpf_map_delete_elem(int fd, const void *key);Parameters
fd: file descriptor of the map to delete element fromkey: pointer to memory containing bytes of the key
Return
0, on success; negative error, otherwise
详情链接:https://docs.ebpf.io/ebpf-library/libbpf/userspace/bpf_map_delete_elem/
6、遍历map表 bpf_map_get_next_key
Definition
int bpf_map_get_next_key(int fd, const void *key, void *next_key);Parameters
fd: file descriptor of the map to get the next key fromkey: pointer to memory containing bytes of the key used for lookupnext_key: pointer to memory in which the next key will be stored
Return
0, on success; negative error, otherwise
详情链接:https://docs.ebpf.io/ebpf-library/libbpf/userspace/bpf_map_get_next_key/
四、疑问点
细心的小伙伴会发现一个问题。
用户态程序中调用时map系列的api时,传递的第一个参数都是map的文件描述符。
而内核态ebpf程序中调用map系列的api时,传递的第一个参数都是指向map变量的指针。
通过阅读如下链接:
https://docs.ebpf.io/linux/helper-function/bpf_map_update_elem/
内核态调用的bpf_map_update_elem是helper function
其函数原型位于/usr/include/bpf/bpf_helper_defs.h文件
static long (*bpf_map_update_elem)(void *map, const void *key, const void *value, __u64 flags) = (void *) 2;用户态调用的bpf_map_update_elem是userspace library function
其函数原型位于/usr/include/bpf/bpf.h文件
LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags);所以两者之间对于map系列的api使用都是没问题的。
https://docs.ebpf.io/ebpf-library/libbpf/userspace/bpf_map__update_elem/
这个链接中的内容是bpf_map__update_elem,在map和update之间是两个下划线哦。