我观察到,如果我在尾部程序中写入环形缓冲区并从用户空间读取环形缓冲区,尾部程序最终会被删除。尾部程序不再出现在bpftool prog. bpftool map dump name jump_table说它Found 0 elements;它最初有 1 个元素,尾部程序。
这个 BPF 程序由main_prog调用一个尾部程序组成。尾部程序写入0环形缓冲区。
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
struct bpf_map_def SEC("maps") flow_ring_buf = {
.type = BPF_MAP_TYPE_RINGBUF,
.max_entries = 1<<12
};
struct bpf_map_def SEC("maps") jump_table = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u32),
.max_entries = 1,
};
SEC("xdp")
int main_prog(struct xdp_md *ctx) {
bpf_tail_call(ctx, &jump_table, 0);
bpf_printk("Tail call failed");
return XDP_PASS;
}
SEC("xdp_2")
int tail_prog(struct xdp_md *ctx) {
__u32 num = 0;
bpf_ringbuf_output(&flow_ring_buf, &num, sizeof(__u32), 0);
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
这个 Go 程序加载程序和映射并从环形缓冲区读取:
package main
import "C"
import (
"errors"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/ringbuf"
"github.com/vishvananda/netlink"
"log"
)
type bpfObjects struct {
MainProg *ebpf.Program `ebpf:"main_prog"`
TailProg *ebpf.Program `ebpf:"tail_prog"`
JumpTable *ebpf.Map `ebpf:"jump_table"`
FlowRingBuf *ebpf.Map `ebpf:"flow_ring_buf"`
}
func main() {
var objects bpfObjects
spec, err := ebpf.LoadCollectionSpec("test.o")
if err != nil {
log.Fatalln("ebpf.LoadCollectionSpec", err)
}
if err := spec.LoadAndAssign(&objects, nil); err != nil {
log.Fatalln("ebpf.LoadAndAssign", err)
}
// Update the jump table with the tail prog
if err = objects.JumpTable.Update(uint32(0), uint32(objects.TailProg.FD()), ebpf.UpdateAny); err != nil {
log.Fatalln("Update prog_array", err)
}
link, err := netlink.LinkByName("enp0s8")
if err != nil {
log.Fatalln("netlink.LinkByName", err)
}
当我向接口发送流量时遇到了问题。reader.Read()从不返回错误并且返回的Record对象有0. 因为跳转表是空的,所以尾调用失败,我bpf_printk在内核日志中看到了输出。
如果注释掉下面的代码A并将其替换为无限等待,例如select {},我不会遇到问题
千万里不及你
慕勒3428872
随时随地看视频慕课网APP
相关分类