0

我的 XDP 模块自行编译,但在 Go 程序的上下文中编译失败,因为它找不到bpf/bpf_helpers.h文件。这是导致问题的代码:

package main

import (
    "fmt"
    bpf "github.com/iovisor/gobpf/bcc"
    log "github.com/sirupsen/logrus"
    "io/ioutil"
    "os"
)

/*
#cgo CFLAGS: -I/usr/include/bcc/compat
#cgo LDFLAGS: -lbcc
#include <bcc/bcc_common.h>
#include <bcc/libbpf.h>
void perf_reader_free(void *ptr);
*/
import "C"

func main() {
    // Get the source code from disk
    source, err := ioutil.ReadFile("xdp/collect_ips.c")

    if err != nil {
        log.Fatalln("Cannot read collect_ips.c")
    }

    // Compile module
    module := bpf.NewModule(string(source), []string{
        "-Wall",
        "-O2",
    })
    defer module.Close()

    // Load module
    fn, err := module.Load("collect_ips", C.BPF_PROG_TYPE_XDP, 1, 65536) // Problem happens here

    // ...

Go 程序编译得很好,但是当我运行程序时,我得到了这个:

/virtual/main.c:2:10: fatal error: 'bpf/bpf_helpers.h' file not found
#include <bpf/bpf_helpers.h>
         ^~~~~~~~~~~~~~~~~~~
9 warnings and 1 error generated.
panic: runtime error: invalid memory address or nil pointer dereference
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4b23d4]

goroutine 1 [running]:
github.com/iovisor/gobpf/bcc.(*Module).Close.func1(0x203000)
        /home/me/go/pkg/mod/github.com/iovisor/gobpf@v0.2.0/bcc/module.go:132 +0x14
github.com/iovisor/gobpf/bcc.(*Module).Close(0x0)
        /home/me/go/pkg/mod/github.com/iovisor/gobpf@v0.2.0/bcc/module.go:132 +0x36
panic({0x4da720, 0x59ec60})
        /usr/lib/go-1.17/src/runtime/panic.go:1038 +0x215
github.com/iovisor/gobpf/bcc.(*Module).Load(0x0, {0x4ef9f2, 0xb}, 0x2, 0x2, 0x8001)
        /home/me/go/pkg/mod/github.com/iovisor/gobpf@v0.2.0/bcc/module.go:202 +0x36
main.main()
        /home/me/go/src/code.squarespace.net/net/prism-stream/cmd/server/main.go:35 +0x1b7

这个问题是因为我的 XDP 模块而发生的,因为如果我在 C 源代码中注释掉这个头文件,错误会移动到另一个头文件。

我认为发生这种情况是因为bpf_helpers.h这里不存在https://github.com/iovisor/gobpf/tree/master/elf/include。如果这是问题,有没有办法使用头文件/usr/include/bpf

如果我bpf_helpers.h从 XDP 代码中取出,我会收到一个错误,抱怨SEC在我的代码中使用了:

struct bpf_map_def SEC("maps") addr_map = {
    .type = BPF_MAP_TYPE_LRU_HASH,
    .key_size = sizeof(struct addr_desc_struct),
    .value_size = sizeof(long),
    .max_entries = 4096
};

SEC我将from的宏复制bpf_helpers.h到我的代码中,但我得到了error: variable has incomplete type 'struct bpf_map_def'. 我也使用bpf_map_lookup_elem()and bpf_map_update_elem(),它们是在bpf/目录中定义的。

4

1 回答 1

1

我使用了Cilium 的eBPF 库。这是一个示例程序,它将 .o 文件加载到接口,等待 10 秒,然后打印 BPF 映射中的任何内容。

你必须确保你的 XDP 函数SEC("xdp")在它之前。而如果你使用 加载程序xdp-loader,你可以传递任何你想要的SEC,只要它与函数名不同。

package main

import (
    "bytes"
    "fmt"
    "github.com/cilium/ebpf"
    log "github.com/sirupsen/logrus"
    "github.com/vishvananda/netlink"
    "time"
)


func main() {
    var objects struct {
        XCProg  *ebpf.Program `ebpf:"collect_ips"` // Name of function containing the XDP program
        XCMap   *ebpf.Map     `ebpf:"addr_map"` // Name of the map 
    }

    spec, err := ebpf.LoadCollectionSpec("dist/collect_ips.o")

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

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

    link, err := netlink.LinkByName("enp0s8")

    if err != nil {
        log.Fatalln("netlink.LinkByName", err)
    }

    err = netlink.LinkSetXdpFdWithFlags(link, objects.XCProg.FD(), 2)

    if err != nil {
        log.Fatalln("netlink.LinkSetXdpFdWithFlags")
    }

    time.Sleep(time.Second*10)

    var keyBytes, valueBytes []byte

    iterator := objects.XCMap.Iterate()

    if iterator == nil {
        log.Fatalln("nil iterator")
    }

    for iterator.Next(&keyBytes, &valueBytes) != false {
        fmt.Printf("%x: %x", keyBytes, valueBytes)
    }

    defer objects.XCProg.Close()
    defer objects.XCMap.Close()
}
于 2022-01-12T01:48:19.713 回答