最近在学习xpd/ebpf相关知识,利用cilium/ebpf编写demo的时候遇到几个invalid argument的错误问题。
demo代码 https://github.com/gbabyX/ebpf-examples 基于linux 4.18 kernel
- map_create invalid argument
struct bpf_map_def SEC("maps") blacklist_map = {
.type = BPF_MAP_TYPE_LPM_TRIE,
.key_size = sizeof(struct bpf_lpm_trie_key ) + sizeof(__u32),
.value_size = sizeof(__u32),
.max_entries = 16,
.map_flags = BPF_F_NO_PREALLOC,
} ;
由于使用的是BPF_MAP_TYPE_LPM_TRIE
,所以需要添加map_flags为BPF_F_NO_PREALLOC
,具体可见 https://elixir.bootlin.com/linux/v4.18/source/kernel/bpf/lpm_trie.c#L512
- BPF_MAP_UPDATE_ELEM出现invalid argument
在使用cilium/ebpf调用的时候
//examples dropId []string{“192.168.1.1/32”,”127.0.0.1/32"}
for index, ip := range dropIP {
if !strings.Contains(ip, "/") {
ip += "/32"
}
_, ipnet, err := net.ParseCIDR(ip)
if err != nil {
log.Printf("malformed ip %v \n", err)
continue
}
var res = make([]byte, objs.BlacklistMap.KeySize())
ones, _ := ipnet.Mask.Size()
binary.BigEndian.PutUint32(res, uint32(ones))
copy(res[4:], ipnet.IP)
if err := objs.BlacklistMap.Put(res, uint32(index)); err != nil {
log.Fatalf("blacklist put err %v \n", err)
}
}
运行程序发现在bpf_map_update_elem
调用的时候,内核返回invalid argument,也就是EINVAL,查看 内核中lpm trie部分对应版本的源码,可以看到有两种可能返回这种错误码,一种是flags大于2的错误,但是debug发现flags为0,第二种是prefixlen长度过长,所以只有第二种可能,上面看到prefixlen传入的是ones参数,而编码采用的是大端,所以极有可能使用大小尾出现错误。
运行命令查看机器大小尾
$ echo -n I | od -o | head -n1 | cut -f2 -d" " | cut -c6
1
可以看到返回1,1即是小端,0是大端。
将二进制编码修改为小端,问题得到解决。