在Go程序中编译XDP源代码时找不到头文件。

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

Header file not found in XDP source compiled in Go program

问题

我的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() {
    // 从磁盘读取源代码
	source, err := ioutil.ReadFile("xdp/collect_ips.c")

	if err != nil {
		log.Fatalln("无法读取collect_ips.c")
	}

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

	// 加载模块
	fn, err := module.Load("collect_ips", C.BPF_PROG_TYPE_XDP, 1, 65536) // 问题发生在这里

    // ...
}

Go程序编译没有问题,但当我运行程序时,出现以下错误:

/virtual/main.c:2:10: 致命错误: 'bpf/bpf_helpers.h' 文件未找到
#include <bpf/bpf_helpers.h>
         ^~~~~~~~~~~~~~~~~~~
9 个警告和 1 个错误已生成。
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中的头文件?

如果我从XDP代码中删除bpf_helpers.h,我会得到一个错误,指责我的代码中使用了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的宏从bpf_helpers.h复制到我的代码中,但然后我得到error: variable has incomplete type 'struct bpf_map_def'的错误。我还使用了bpf_map_lookup_elem()bpf_map_update_elem(),它们在bpf/目录中定义。

英文:

My XDP module compiles by itself, but compilation within the context of a Go program fails because it can't find bpf/bpf_helpers.h file. Here's the code leading up the problem:

package main

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

/*
#cgo CFLAGS: -I/usr/include/bcc/compat
#cgo LDFLAGS: -lbcc
#include &lt;bcc/bcc_common.h&gt;
#include &lt;bcc/libbpf.h&gt;
void perf_reader_free(void *ptr);
*/
import &quot;C&quot;

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

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

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

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

    // ...

The Go program compiles fine, but I when I run the program, I get this:

/virtual/main.c:2:10: fatal error: &#39;bpf/bpf_helpers.h&#39; file not found
#include &lt;bpf/bpf_helpers.h&gt;
         ^~~~~~~~~~~~~~~~~~~
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

This problem is happening because of my XDP module because if I comment out this header file in the C source, the error moves to a different header file.

I think this is happening because of bpf_helpers.h does not exist here https://github.com/iovisor/gobpf/tree/master/elf/include. If this is the issue, is there a way to use the header file from /usr/include/bpf?

If I take out bpf_helpers.h from the XDP code, I get an error complaining about the use of SEC in my code:

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

I copied the macro for SEC from bpf_helpers.h to my code, but I then get error: variable has incomplete type &#39;struct bpf_map_def&#39;. I also use bpf_map_lookup_elem() and bpf_map_update_elem(), which are defined in the bpf/ directory.

答案1

得分: 1

我使用了来自Cilium的eBPF库(https://github.com/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"` // 包含XDP程序的函数的名称
		XCMap   *ebpf.Map     `ebpf:"addr_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()
}
英文:

I used the eBPF library from Cilium. Here's an example program that loads .o file to an interface, waits for 10 seconds, and prints whatever is in the BPF map.

You have to make sure your XDP function has SEC(&quot;xdp&quot;) before it. Whereas if you load the program using xdp-loader, you can pass whatever you want to SEC as long as it's different from the name of the function.

package main
import (
&quot;bytes&quot;
&quot;fmt&quot;
&quot;github.com/cilium/ebpf&quot;
log &quot;github.com/sirupsen/logrus&quot;
&quot;github.com/vishvananda/netlink&quot;
&quot;time&quot;
)
func main() {
var objects struct {
XCProg  *ebpf.Program `ebpf:&quot;collect_ips&quot;` // Name of function containing the XDP program
XCMap   *ebpf.Map     `ebpf:&quot;addr_map&quot;` // Name of the map 
}
spec, err := ebpf.LoadCollectionSpec(&quot;dist/collect_ips.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)
}
link, err := netlink.LinkByName(&quot;enp0s8&quot;)
if err != nil {
log.Fatalln(&quot;netlink.LinkByName&quot;, err)
}
err = netlink.LinkSetXdpFdWithFlags(link, objects.XCProg.FD(), 2)
if err != nil {
log.Fatalln(&quot;netlink.LinkSetXdpFdWithFlags&quot;)
}
time.Sleep(time.Second*10)
var keyBytes, valueBytes []byte
iterator := objects.XCMap.Iterate()
if iterator == nil {
log.Fatalln(&quot;nil iterator&quot;)
}
for iterator.Next(&amp;keyBytes, &amp;valueBytes) != false {
fmt.Printf(&quot;%x: %x&quot;, keyBytes, valueBytes)
}
defer objects.XCProg.Close()
defer objects.XCMap.Close()
}

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

发表评论

匿名网友

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

确定