创建 bpf map 时,出现了如下错误:
1
|
failed to load bpf: failed to create map: invalid argument
|
看下需要创建的 bpf map:
1
2
3
4
5
6
|
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u8);
__type(value, bitmap);
__uint(max_entries, PROTO_MAX_ENTRIES);
} acl_protocol SEC(".maps");
|
想着,需要处理的 protocol 也就 TCP、UDP 和 ICMP 这 3 个,所以就使用最节省内存的
key 类型 __u8
;因为每个 key 只需要占用 1 个字节。
可是,为什么出现无效参数的错误呢?
话不多说,直接查看 BPF_MAP_TYPE_ARRAY 对应 bpf map 的源代码吧。
在创建 bpf map 时,会先调用 map_ops->map_alloc_check()
进行一次检查;
这次检查是每个 bpf map 类型做的一次针对类型需求进行的检查。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
// ${KERNEL}/kernel/bpf/arraymap.c
const struct bpf_map_ops array_map_ops = {
.map_meta_equal = array_map_meta_equal,
.map_alloc_check = array_map_alloc_check,
.map_alloc = array_map_alloc,
.map_free = array_map_free,
.map_get_next_key = array_map_get_next_key,
.map_release_uref = array_map_free_timers,
.map_lookup_elem = array_map_lookup_elem,
.map_update_elem = array_map_update_elem,
.map_delete_elem = array_map_delete_elem,
// ...
};
int array_map_alloc_check(union bpf_attr *attr)
{
bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
int numa_node = bpf_map_attr_numa_node(attr);
/* check sanity of attributes */
if (attr->max_entries == 0 || attr->key_size != 4 ||
attr->value_size == 0 ||
attr->map_flags & ~ARRAY_CREATE_FLAG_MASK ||
!bpf_map_flags_access_ok(attr->map_flags) ||
(percpu && numa_node != NUMA_NO_NODE))
return -EINVAL;
// ...
if (attr->value_size > KMALLOC_MAX_SIZE)
/* if value_size is bigger, the user space won't be able to
* access the elements.
*/
return -E2BIG;
return 0;
}
|
ARRAY bpf map 做了以下检查:
- max_entries 不能为 0。
- key 大小只能是 4。
- value 大小不能为 0。
- flags 检查。
- NUMA flags 检查。
- value 大小不能大于 “Maximum allocatable size”。
所以,acl_protocol
的 key 大小是 1,违反了第 2 条。
最终,只需要将 key 的类型从 __u8
改为 __u32
即可。
1
2
3
4
5
6
|
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u32);
__type(value, bitmap);
__uint(max_entries, PROTO_MAX_ENTRIES);
} acl_protocol SEC(".maps");
|