【发布时间】:2019-07-03 14:32:55
【问题描述】:
因此,根据标题,我正在尝试加载 XDP 程序,但令人惊讶的是,bpf 验证程序会以著名的 back-edge 错误向我吐口水:
libbpf: load bpf program failed: Invalid argument
libbpf: -- BEGIN DUMP LOG ---
libbpf:
back-edge from insn 271 to 69
libbpf: -- END LOG --
libbpf: failed to load program 'xdp_prog'
即使在我的受限 ebpf C 代码中,唯一的 for 循环 - 在编译时已知迭代次数 - 由 pragma unroll 保护。这是一个代码 sn-p,显示了在 __alwais_inlined 函数中定义的受影响的 for 循环:
#pragma unroll
for (i = 0; i < 8; i++)
{
int k = idx + i;
mask = bpf_map_lookup_elem(&a_map, &k);
if (!mask || (mask->an_idx == 0))
return -1;
*m_key = *key;
foo(m_key, mask); // an __alwais_inline func
id = bpf_map_lookup_elem(&b_map, m_key);
if (id)
{
*out_id = *id;
return 0;
}
}
也许问题在于 clang 无法展开循环?如果这是正确的,为什么它会失败,有什么解决方法吗?手动展开循环是不可接受的,因为它会导致可怕的、不可维护的和不可读的代码。
哦,我正在与:
- 内核 4.19.3
- llvm-clang 8
有什么想法吗?
更新
刚刚注意到,即使是以下虚拟 for 循环似乎也没有展开,bpf 验证器抱怨后端:
#pragma unroll
for (i = 0; i < 8; i++)
{
int k = i;
mask = bpf_map_lookup_elem(&a_map, &k);
}
难道只有我这样没有任何意义吗?
【问题讨论】:
-
如果您使用编译指示,为什么“不出所料”?如果您不是 100% 确定,为什么要“清楚”:) 一些评论: 1) 您在编译时收到警告了吗?我相信当它无法展开循环时,clang 会打印一个。 2) 您是否查看了生成的 BPF 指令 (
llvm-objdump -S objfile.o) 以确保后端来自该特定循环? 3) 如果您对内核版本比较灵活,您可能想知道 linux 5.3(目前正在开发中)支持有界循环。 -
同意“unsurprisingly”到“surprisingly”,也同意“clearly”到“maybe”。我会首先编辑它。回答您的问题:1)编译时没有警告; 2)很确定,因为它是我的代码中定义的唯一“循环”,也因为如果注释掉这个for循环,验证就会通过; 3)这能解决问题吗?
-
在 bpf_map_lookup_elem 中查找 EINVAL。
-
3) 在 BPF 验证器中提供了对这种循环的支持,因此不会再拒绝该循环的后端。所以是的,它应该可以解决问题。不过听起来有点矫枉过正。根据我的经验,当 clang 无法展开时,我总是收到警告 (like this one):/。如果没有 C 或 BPF 代码,真的无法提供更多帮助,抱歉。 (同样对于 Linux 4.19,您不必内联所有函数,支持 BPF 函数调用。但这与问题无关。)
-
@JL2210 在这种情况下这意味着什么?
标签: c clang llvm-clang ebpf