Reputation: 7225
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 (
"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
// ...
The Go program compiles fine, but I when I run the program, I get this:
/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/[email protected]/bcc/module.go:132 +0x14
github.com/iovisor/gobpf/bcc.(*Module).Close(0x0)
/home/me/go/pkg/mod/github.com/iovisor/[email protected]/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/[email protected]/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("maps") 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 'struct bpf_map_def'
. I also use bpf_map_lookup_elem()
and bpf_map_update_elem()
, which are defined in the bpf/
directory.
Upvotes: 0
Views: 1006
Reputation: 7225
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("xdp")
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 (
"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()
}
Upvotes: 1