following is my code and libbpf throws error that
libbpf: Program 'xdp' contains unrecognized relo data pointing to section 6
ERR: loading BPF-OBJ file(./k.o) (-2): No such file or directory
ERR: loading file: ./k.o
Why is that. This is how I am printing with bpf_trace_printk
bpf_trace_printk("hello\n",sizeof("hello\n"));
this is full code
#include <stddef.h>
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
/* Defines xdp_stats_map from packet04 */
#include "../common/xdp_stats_kern_user.h"
#include "../common/xdp_stats_kern.h"
#include <../common/parsing_helpers.h>
#include <bpf/bpf_helpers.h>
#define ETH_ALEN 6
#define MAX_ENTRIES 1000
/*struct {
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
__type(key, __u32);
__type(value, __u64);
__uint(max_entries, MAX_ENTRIES);
} hash_map SEC(".maps");
*/
struct hash_elem {
int cnt;
struct bpf_spin_lock lock;
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, struct hash_elem);
__uint(max_entries, 100);
} hash_map SEC(".maps");
struct a{struct bpf_spin_lock lock;};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, long);
__uint(max_entries, 2);
} hash_map1 SEC(".maps");
//static __u32 i=0;
struct icmphdr1
{
__u8 type; /* message type */
__u8 code; /* type sub-code */
__u16 checksum;
union
{
struct
{
__u16 id;
__u16 sequence;
} echo; /* echo datagram */
__u32 gateway; /* gateway address */
struct
{
__u16 __glibc_reserved;
__u16 mtu;
} frag; /* path mtu discovery */
} un;
};
SEC("xdp")
int xdp_prog_simple(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
__u16 h_proto;
if (eth + 1 > data_end)
return XDP_DROP;
h_proto = eth->h_proto;
if (h_proto == bpf_htons(ETH_P_IP))
{
struct iphdr *ip=(struct iphdr *)(eth+sizeof(struct ethhdr));
if(ip+1>data_end)
{
__u8 protocol_ip=ip->protocol;
if(protocol_ip==0x01)
{
struct icmphdr1 *icmp=(struct icmphdr1 *)(ip+sizeof(struct iphdr));
if(icmp+1>data_end)
{
__u8 type=icmp->type;
__u8 code=icmp->code;
if(type!=10 && code!=11)
bpf_trace_printk("hello\n",sizeof("hello\n"));
// if(type==8)
// if(code==0)
// bpf_trace_printk("code is 0\n",sizeof("code is 0\n"));
// bpf_trace_printk("icmp type:code = %d:%d\n",sizeof("icmp type:code = %d:%d\n"),type,code);
}
//__u32 key=i;
//__u64 val=bpf_ktime_get_ns();
//int x=bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY);
}
}
}
return XDP_DROP;
}
Do not call your helper like this:
// BAD
bpf_trace_printk("hello\n", sizeof("hello\n"));
or like this:
// BAD
const char *msg = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));
But instead, declare your string as a dynamic array of characters:
// GOOD
char msg[] = "hello\n";
bpf_trace_printk(msg, sizeof(msg));
This will prevent clang from creating a relocation that libbpf cannot handle.
Let's have a look at the object file, when passing the string directly:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
bpf_trace_printk("hello\n", sizeof("hello\n"));
return 0;
}
When doing this, clang puts the string into a read-only section, and requests a relocation. We can observe this with llvm-objdump
. Let's inspect the relocations and disassemble the program:
$ clang -O2 -emit-llvm -c foo.c -o - | llc -march=bpf -filetype=obj -o foo.
$ llvm-objdump -r foo.o
foo.o: file format elf64-bpf
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000000 R_BPF_64_64 .rodata.str1.1
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
000000000000001c R_BPF_64_ABS64 .text
$ lvm-objdump --section=.text -D foo.o
foo.o: file format elf64-bpf
Disassembly of section .text:
0000000000000000 <foo>:
0: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
2: b7 02 00 00 07 00 00 00 r2 = 7
3: 85 00 00 00 06 00 00 00 call 6
4: b7 00 00 00 00 00 00 00 r0 = 0
5: 95 00 00 00 00 00 00 00 exit
We note that the .text
section, containing the program, starts with a single load r1 = 0
: the register r1
, containing the first argument to pass to the call to bpf_trace_printk()
(call 6
), is not set until this relocation happens.
But libbpf does not support this kind of relocations, this is why you get your error message:
Program 'xdp' contains unrecognized relo data pointing to section 6
The same can be observed with:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
const char* msg = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));
return 0;
}
This is equivalent, clang creates a relocation too.
However, we can instead declare the string as a dynamic array of characters:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
char msg[] = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));
return 0;
}
In that case, the array goes to the stack. No relocation happens. The .rodata.str1.1
section is not present in the file. We can check what llvm-objdump
says:
$ clang -O2 -emit-llvm -c foo.c -o - | llc -march=bpf -filetype=obj -o foo.o
$ llvm-objdump -r foo.o
foo.o: file format elf64-bpf
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
000000000000001c R_BPF_64_ABS64 .text
$ lvm-objdump --section=.text -D foo.o
foo.o: file format elf64-bpf
Disassembly of section .text:
0000000000000000 <foo>:
0: b7 01 00 00 6f 0a 00 00 r1 = 2671
1: 6b 1a fc ff 00 00 00 00 *(u16 *)(r10 - 4) = r1
2: b7 01 00 00 68 65 6c 6c r1 = 1819043176
3: 63 1a f8 ff 00 00 00 00 *(u32 *)(r10 - 8) = r1
4: b7 01 00 00 00 00 00 00 r1 = 0
5: 73 1a fe ff 00 00 00 00 *(u8 *)(r10 - 2) = r1
6: bf a1 00 00 00 00 00 00 r1 = r10
7: 07 01 00 00 f8 ff ff ff r1 += -8
8: b7 02 00 00 07 00 00 00 r2 = 7
9: 85 00 00 00 06 00 00 00 call 6
10: b7 00 00 00 00 00 00 00 r0 = 0
11: 95 00 00 00 00 00 00 00 exit
Here, we fill the stack (r10
is the stack pointer) with the characters of the string (68 65 6c 6c 6f 0a 00 00
is hello\n\0\0
). Everything is processed in BPF, there is no relocation involved. And this works just fine.
Could we do better? Yes, with Linux 5.2 and older, we can avoid having the array on the stack by declaring the string as:
static const char msg[] = "hello\n";
This time, this results in a relocation to section .rodata
, but one that libbpf does handle, through the support of static variables. More details are available here.
Generally speaking, BPF tips & tricks: the guide to bpf_trace_printk() and bpf_printk() is an excellent reference on the bpf_trace_printk()
helper.