【问题标题】:BPF verifier rejecting XDP program due to back-edge even though pragma unroll is used即使使用了 pragma unroll,BPF 验证程序也会由于后沿而拒绝 XDP 程序
【发布时间】: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


【解决方案1】:

我写了以下代码,它可以工作。

#pragma clang loop unroll(full)
for (int i = 0; i < 128; i++)
{
    if (bpf_map_lookup_elem(&conntrack_hash_tab, &reply_key) == NULL)
    {
        break;
    }
    reply_key.dport = reply_key.dport+1;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 2012-06-21
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    相关资源
    最近更新 更多