为什么 BPF 验证器在使用 BPF_MAP_TYPE_QUEUE 时会出现 null key 错误?
Why does BPF verifier error with null key when using BPF_MAP_TYPE_QUEUE?
我正在尝试使用队列映射加载 BPF 程序。我似乎收到与空键相关的错误。
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r1 = 123
1: (63) *(u32 *)(r10 -4) = r1
2: (bf) r3 = r10
3: (07) r3 += -4
4: (18) r1 = 0xffff9df655207800
6: (b7) r2 = 0
7: (b7) r4 = 0
8: (85) call bpf_map_update_elem#2
R2 type=inv expected=fp
processed 8 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
BPF 程序
#include <bpf/bpf.h>
#include <string.h>
struct bpf_map SEC("maps") queue_map = {
.type = BPF_MAP_TYPE_QUEUE,
.key_size = 0,
.value_size = sizeof(int),
.max_entries = 100,
.map_flags = 0,
};
SEC("tracepoint/syscalls/sys_enter_execve")
int bpf_prog(void *ctx) {
int value;
value = 123;
bpf_map_update_elem(&queue_map, NULL, &value, BPF_ANY);
return 0;
}
char _license[] SEC("license") = "GPL";
但是,如果我通过更新 .type = BPF_MAP_TYPE_ARRAY
、.key_size = sizeof(int)
将队列映射切换为数组映射,并向 bpf_map_update_elem
函数提供有效键,bpf 程序加载并作品。我正在使用 libbpf 加载程序。
int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj, int *prog_fd)
{
struct bpf_prog_load_attr attr;
memset(&attr, 0, sizeof(struct bpf_prog_load_attr));
attr.file = file;
attr.prog_type = type;
attr.expected_attach_type = 0;
return bpf_prog_load_xattr(&attr, pobj, prog_fd);
}
- 导致错误的原因是什么?
- 我正在使用 /tools/perf 中的头文件。我应该使用不同的头文件吗?
- 我需要以不同于数组映射的方式加载队列映射吗?
- 是否需要为队列映射添加映射标志?
验证器抱怨,因为它期望第二个参数指向 bpf_map_update_elem()
(fp
对应 frame pointer
,而你有 NULL
)。但是正如 pchaigno 提到的,它对 queue 地图无效;我不认为它什么都不做,我相信它不会通过验证程序(如果你能以某种方式传递这个指针错误,就会被 check_map_func_compatibility()
拒绝)。
对于 queues(或堆栈),您要使用 bpf_map_(push|pull|peek)_elem()
helpers。
关于您的其他问题:
不确定 headers 您具体使用什么。我想取决于你需要什么定义。
您以相同的方式创建地图,但以不同的方式更新它们(不同的助手,如上所述)——这就是使用 queue 而不是例如一个数组。
不,我认为您不需要特定的标志来创建地图。
我正在尝试使用队列映射加载 BPF 程序。我似乎收到与空键相关的错误。
libbpf: -- BEGIN DUMP LOG ---
libbpf:
0: (b7) r1 = 123
1: (63) *(u32 *)(r10 -4) = r1
2: (bf) r3 = r10
3: (07) r3 += -4
4: (18) r1 = 0xffff9df655207800
6: (b7) r2 = 0
7: (b7) r4 = 0
8: (85) call bpf_map_update_elem#2
R2 type=inv expected=fp
processed 8 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
BPF 程序
#include <bpf/bpf.h>
#include <string.h>
struct bpf_map SEC("maps") queue_map = {
.type = BPF_MAP_TYPE_QUEUE,
.key_size = 0,
.value_size = sizeof(int),
.max_entries = 100,
.map_flags = 0,
};
SEC("tracepoint/syscalls/sys_enter_execve")
int bpf_prog(void *ctx) {
int value;
value = 123;
bpf_map_update_elem(&queue_map, NULL, &value, BPF_ANY);
return 0;
}
char _license[] SEC("license") = "GPL";
但是,如果我通过更新 .type = BPF_MAP_TYPE_ARRAY
、.key_size = sizeof(int)
将队列映射切换为数组映射,并向 bpf_map_update_elem
函数提供有效键,bpf 程序加载并作品。我正在使用 libbpf 加载程序。
int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
struct bpf_object **pobj, int *prog_fd)
{
struct bpf_prog_load_attr attr;
memset(&attr, 0, sizeof(struct bpf_prog_load_attr));
attr.file = file;
attr.prog_type = type;
attr.expected_attach_type = 0;
return bpf_prog_load_xattr(&attr, pobj, prog_fd);
}
- 导致错误的原因是什么?
- 我正在使用 /tools/perf 中的头文件。我应该使用不同的头文件吗?
- 我需要以不同于数组映射的方式加载队列映射吗?
- 是否需要为队列映射添加映射标志?
验证器抱怨,因为它期望第二个参数指向 bpf_map_update_elem()
(fp
对应 frame pointer
,而你有 NULL
)。但是正如 pchaigno 提到的,它对 queue 地图无效;我不认为它什么都不做,我相信它不会通过验证程序(如果你能以某种方式传递这个指针错误,就会被 check_map_func_compatibility()
拒绝)。
对于 queues(或堆栈),您要使用 bpf_map_(push|pull|peek)_elem()
helpers。
关于您的其他问题:
不确定 headers 您具体使用什么。我想取决于你需要什么定义。
您以相同的方式创建地图,但以不同的方式更新它们(不同的助手,如上所述)——这就是使用 queue 而不是例如一个数组。
不,我认为您不需要特定的标志来创建地图。