BPF尾调用未被调用

huangapple go评论73阅读模式
英文:

BPF tail call not called

问题

在下面的代码中,tail_prog程序没有从main_prog中调用:

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct bpf_map_def SEC("maps") jump_table = {
   .type = BPF_MAP_TYPE_PROG_ARRAY,
   .key_size = sizeof(__u32),
   .value_size = sizeof(__u32),
   .max_entries = 8,
};

SEC("xdp")
int main_prog(struct xdp_md *ctx) {
    bpf_printk("Making tail call");
    bpf_tail_call(ctx, &jump_table, 0);

    return XDP_PASS;
}

SEC("xdp_1")
int tail_prog(struct xdp_md *ctx) {
    bpf_printk("Inside tail call");

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

我观察到只有main_prog中的打印语句被打印出来。

我正在使用Cilium的eBPF Go包加载BPF程序。以下是加载程序和映射的代码:

type BpfObjects struct {
    MainProg *ebpf.Program  `ebpf:"main_prog"`
    TailProg *ebpf.Program  `ebpf:"tail_prog"`
    JumpTable *ebpf.Map     `ebpf:"jump_table"`
}

var objects BpfObjects

spec, err := ebpf.LoadCollectionSpec("prog.o")

if err != nil {
    log.Fatalln("ebpf.LoadCollectionSpec", err)
}

if err := spec.LoadAndAssign(&objects, nil); err != nil {
    log.Fatalln("ebpf.LoadAndAssign", err)
}

objects.JumpTable.Update(0, objects.TailProg.FD(), ebpf.UpdateAny)

根据这里的说明,跳转表必须从用户空间初始化,这就是我认为上面最后一行代码应该做的事情。然而,无论该行是否存在,我都没有看到任何区别。

英文:

In the following code BPF program tail_prog is not getting tail called from main_prog:

#include &lt;linux/bpf.h&gt;
#include &lt;bpf/bpf_helpers.h&gt;

struct bpf_map_def SEC(&quot;maps&quot;) jump_table = {
   .type = BPF_MAP_TYPE_PROG_ARRAY,
   .key_size = sizeof(__u32),
   .value_size = sizeof(__u32),
   .max_entries = 8,
};

SEC(&quot;xdp&quot;)
int main_prog(struct xdp_md *ctx) {
    bpf_printk(&quot;Making tail call&quot;);
    bpf_tail_call(ctx, &amp;jump_table, 0);

    return XDP_PASS;
}

SEC(&quot;xdp_1&quot;)
int tail_prog(struct xdp_md *ctx) {
    bpf_printk(&quot;Inside tail call&quot;);

    return XDP_PASS;
}

char _license[] SEC(&quot;license&quot;) = &quot;GPL&quot;;

I observe only the print in main_prog is printed.

I'm loading the BPF programs using Cilium's eBPF Go package. Here's the code for loading the programs and maps:

type BpfObjects struct {
	MainProg *ebpf.Program  `ebpf:&quot;main_prog&quot;`
	TailProg *ebpf.Program  `ebpf:&quot;tail_prog&quot;`
	JumpTable *ebpf.Map     `ebpf:&quot;jump_table&quot;`
}

	var objects BpfObjects

	spec, err := ebpf.LoadCollectionSpec(&quot;prog.o&quot;)

	if err != nil {
		log.Fatalln(&quot;ebpf.LoadCollectionSpec&quot;, err)
	}

	if err := spec.LoadAndAssign(&amp;objects, nil); err != nil {
		log.Fatalln(&quot;ebpf.LoadAndAssign&quot;, err)
	}

	objects.JumpTable.Update(0, objects.TailProg.FD(), ebpf.UpdateAny)

According to this, the jump table has be initialized from user space, which is what I think the last line above is supposed to do. However, I don't see any difference whether that line is there or not.

答案1

得分: 2

我没有注意到Update函数返回的错误:Update can't marshal key: encoding int: binary.Write: invalid type int。因此,程序数组映射没有被更新。我改成了以下方式:

	err = objects.JumpTable.Update(uint32(0), uint32(objects.CopyHttpHostnameProg.FD()), ebpf.UpdateAny)

	if err != nil {
		println("Update", err.Error())
	}

如果将0作为键传递,键的大小为8个字节,这就是为什么你需要使用uint32(0),以匹配映射的定义。现在尾调用成功了。

英文:

I wasn't looking at the error returned from the Update function: Update can&#39;t marshal key: encoding int: binary.Write: invalid type int. Therefore, the program array map was not updated. I changed to the following:

	err = objects.JumpTable.Update(uint32(0), uint32(objects.CopyHttpHostnameProg.FD()), ebpf.UpdateAny)

	if err != nil {
		println(&quot;Update&quot;, err.Error())
	}

If you pass 0 as the key, the size of the key is 8 bytes, which is why you have to do uint32(0), which matches the map's definition. Now the tail calls succeed.

huangapple
  • 本文由 发表于 2022年1月28日 05:45:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/70886166.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定