ebpf

xdp ebpf出现invalid argument

最近在学习xpd/ebpf相关知识,利用cilium/ebpf编写demo的时候遇到几个invalid argument的错误问题。

demo代码 https://github.com/gbabyX/ebpf-examples 基于linux 4.18 kernel

  1. 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

  1. 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是大端。
将二进制编码修改为小端,问题得到解决。