-
Here is the code. // xsk_def_xdp_prog.c
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <xdp/xdp_helpers.h>
#include "xsk_def_xdp_prog.h"
#define DEFAULT_QUEUE_IDS 64
struct {
__uint(type, BPF_MAP_TYPE_XSKMAP);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
__uint(max_entries, DEFAULT_QUEUE_IDS);
} xsks_map SEC(".maps");
struct {
__uint(priority, 20);
__uint(XDP_PASS, 1);
} XDP_RUN_CONFIG(xsk_def_prog);
/* Program refcount, in order to work properly,
* must be declared before any other global variables
* and initialized with '1'.
*/
volatile int refcnt = 1;
/* This is the program for post 5.3 kernels. */
SEC("xdp")
int xsk_def_prog(struct xdp_md *ctx)
{
/* Make sure refcount is referenced by the program */
if (!refcnt)
return XDP_PASS;
/* A set entry here means that the corresponding queue_id
* has an active AF_XDP socket bound to it.
*/
return bpf_redirect_map(&xsks_map, ctx->rx_queue_index, XDP_PASS);
}
char _license[] SEC("license") = "GPL";
__uint(xsk_prog_version, XSK_PROG_VERSION) SEC(XDP_METADATA_SECTION);
// "xsk_def_xdp_prog.h"
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
#ifndef __LIBXDP_XSK_DEF_XDP_PROG_H
#define __LIBXDP_XSK_DEF_XDP_PROG_H
#define XDP_METADATA_SECTION "xdp_metadata"
#define XSK_PROG_VERSION 1
#endif /* __LIBXDP_XSK_DEF_XDP_PROG_H */ I use bpf2go to compile it and generate Go code. go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -cflags -O2 -g -Wall -c xsk_def_xdp_prog ./xdp/xsk_def_xdp_prog.c I use the loading function generated by bpf2go to load the XDP program and bind it to the interface. Then, when I try to get the BTF using the BTF ID, an error(reference to invalid type id: 7) occurs. ifaceName := "ens1"
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
t.Fatal(err)
}
obj := &xsk_def_xdp_progObjects{}
err = loadXsk_def_xdp_progObjects(obj, nil)
if err != nil {
t.Fatal(err)
}
defer obj.Close()
l, err := link.AttachXDP(link.XDPOptions{
Program: obj.XskDefProg,
Interface: iface.Index,
Flags: link.XDPGenericMode,
})
if err != nil {
t.Fatal(err)
}
defer l.Close()
link, err := netlink.LinkByIndex(iface.Index)
if err != nil {
t.Fatal(err)
}
prog, err := ebpf.NewProgramFromID(ebpf.ProgramID(link.Attrs().Xdp.ProgId))
if err != nil {
t.Fatal(err)
}
fmt.Println(prog)
info, err := prog.Info()
if err != nil {
t.Fatal(err)
}
fmt.Println(info)
btfID, has := info.BTFID()
if has {
handle, err := btf.NewHandleFromID(btfID)
if err != nil {
t.Fatal(err)
}
spec, err := handle.Spec(&btf.Spec{})
// error: reference to invalid type id: 7
if err != nil {
t.Fatal(err)
}
fmt.Println(spec)
} Then, I used bpftool to load the same program and used bpftool to get the BTF for the program loaded by bpftool and the program loaded by bpf2go. # bpftool prog list
...
162: xdp name xsk_def_prog tag 8f9c40757cb0a6a2 gpl
loaded_at 2024-07-14T17:10:10+0800 uid 0
xlated 96B jited 64B memlock 4096B map_ids 245,243
btf_id 308
174: xdp name xsk_def_prog tag 8f9c40757cb0a6a2 gpl
loaded_at 2024-07-14T17:12:50+0800 uid 0
xlated 96B jited 64B memlock 4096B map_ids 259,260
btf_id 324
pids __debug_bin1895(3178060)
# bpftool btf dump id 308
[1] PTR '(anon)' type_id=3
[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
[3] ARRAY '(anon)' type_id=2 index_type_id=4 nr_elems=17
[4] INT '__ARRAY_SIZE_TYPE__' size=4 bits_offset=0 nr_bits=32 encoding=(none)
[5] PTR '(anon)' type_id=6
[6] ARRAY '(anon)' type_id=2 index_type_id=4 nr_elems=4
[7] PTR '(anon)' type_id=8
[8] ARRAY '(anon)' type_id=2 index_type_id=4 nr_elems=64
[9] STRUCT '(anon)' size=32 vlen=4
'type' type_id=1 bits_offset=0
'key_size' type_id=5 bits_offset=64
'value_size' type_id=5 bits_offset=128
'max_entries' type_id=7 bits_offset=192
[10] VAR 'xsks_map' type_id=9, linkage=global
[11] PTR '(anon)' type_id=12
[12] STRUCT 'xdp_md' size=24 vlen=6
'data' type_id=13 bits_offset=0
'data_end' type_id=13 bits_offset=32
'data_meta' type_id=13 bits_offset=64
'ingress_ifindex' type_id=13 bits_offset=96
'rx_queue_index' type_id=13 bits_offset=128
'egress_ifindex' type_id=13 bits_offset=160
[13] TYPEDEF '__u32' type_id=14
[14] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)
[15] FUNC_PROTO '(anon)' ret_type_id=2 vlen=1
'ctx' type_id=11
[16] FUNC 'xsk_def_prog' type_id=15 linkage=global
[17] VOLATILE '(anon)' type_id=2
[18] VAR 'refcnt' type_id=17, linkage=global
[19] INT 'char' size=1 bits_offset=0 nr_bits=8 encoding=SIGNED
[20] ARRAY '(anon)' type_id=19 index_type_id=4 nr_elems=4
[21] VAR '_license' type_id=20, linkage=global
[22] STRUCT '(anon)' size=16 vlen=2
'priority' type_id=23 bits_offset=0
'XDP_PASS' type_id=25 bits_offset=64
[23] PTR '(anon)' type_id=24
[24] ARRAY '(anon)' type_id=2 index_type_id=4 nr_elems=20
[25] PTR '(anon)' type_id=26
[26] ARRAY '(anon)' type_id=2 index_type_id=4 nr_elems=1
[27] VAR '_xsk_def_prog' type_id=22, linkage=global
[28] VAR 'xsk_prog_version' type_id=25, linkage=global
[29] DATASEC '.data' size=4 vlen=1
type_id=18 offset=0 size=4 (VAR 'refcnt')
[30] DATASEC '.maps' size=32 vlen=1
type_id=10 offset=0 size=32 (VAR 'xsks_map')
[31] DATASEC '.xdp_run_config' size=16 vlen=1
type_id=27 offset=0 size=16 (VAR '_xsk_def_prog')
[32] DATASEC 'license' size=4 vlen=1
type_id=21 offset=0 size=4 (VAR '_license')
[33] DATASEC 'xdp_metadata' size=8 vlen=1
type_id=28 offset=0 size=8 (VAR 'xsk_prog_version')
# bpftool btf dump id 324
[1] FUNC 'xsk_def_prog' type_id=7 linkage=global
[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
[3] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)
[4] TYPEDEF '__u32' type_id=3
[5] STRUCT 'xdp_md' size=24 vlen=6
'data' type_id=4 bits_offset=0
'data_end' type_id=4 bits_offset=32
'data_meta' type_id=4 bits_offset=64
'ingress_ifindex' type_id=4 bits_offset=96
'rx_queue_index' type_id=4 bits_offset=128
'egress_ifindex' type_id=4 bits_offset=160
[6] PTR '(anon)' type_id=5
[7] FUNC_PROTO '(anon)' ret_type_id=2 vlen=1
'ctx' type_id=6 I found that the BTF for the program loaded by bpf2go is incomplete. I don't know why this is happening. How can I make the BTF complete? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
2 observations here:
|
Beta Was this translation helpful? Give feedback.
2 observations here:
I don't think your use of
spec, err := handle.Spec(&btf.Spec{})
is correct, afaik you need to callhandle.Spec(nil)
since the Handle doesn't represent a kmod BTF blob. The parameter is to specify a base BTF that a kmod BTF needs to parse successfully. That may fix your application and should let you obtain the BTF for the loaded BPF program.ebpf-go has a fundamentally different way of passing (user) program BTF to the kernel. Unlike libbpf, it completely parses the BTF blob into Go structures and attaches each funcinfo and lineinfo and the types they point to directly to each
asm.Instruction
in ProgramSpec.Instructions. When loading a program into the kernel, it …