调用bpf_trace_printk导致XDP BPF程序加载失败的问题求助
XDP BPF程序加载失败:libbpf报"unrecognized relo data pointing to section 6"错误
错误信息
加载编译后的BPF目标文件./k.o时,libbpf抛出以下错误:
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
问题代码
#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 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"); 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")); } } } } return XDP_DROP; }
错误原因
这个错误核心是BPF程序中存在无法被libbpf正确解析的重定位信息,结合代码具体分析:
边界检查逻辑完全反向
代码中if(ip+1>data_end)的逻辑是错误的:当ip+1 > data_end时,说明IP头部没有完整出现在数据包中,此时直接访问ip->protocol会触发非法内存访问。这种错误的内存访问逻辑会导致编译器生成异常的重定位数据,libbpf无法识别,最终加载失败。自定义结构体与内核布局不匹配
手动定义的icmphdr1结构体,即使字段和内核标准icmphdr一致,也可能因为编译对齐、字段偏移等问题,导致访问结构体成员时的重定位计算错误,libbpf无法处理这种非标准的重定位指向。冗余代码干扰编译
未使用的struct a等冗余定义,可能在编译时生成多余的段信息,间接导致重定位指向错误的段(错误信息中的section 6)。
解决方法
修正边界检查逻辑
所有边界检查改为"不完整则丢弃"的正确逻辑:// IP头部检查 struct iphdr *ip = (struct iphdr *)((void *)eth + sizeof(struct ethhdr)); if ((void *)(ip + 1) > data_end) return XDP_DROP; __u8 protocol_ip = ip->protocol; // ICMP头部检查 struct icmphdr *icmp = (struct icmphdr *)((void *)ip + sizeof(struct iphdr)); if ((void *)(icmp + 1) > data_end) return XDP_DROP;使用内核标准结构体
删除自定义的icmphdr1,包含标准头文件<linux/icmp.h>,直接使用内核定义的struct icmphdr:#include <linux/icmp.h>清理冗余代码
删除未使用的struct a、注释掉的代码块,减少编译时的冗余段。规范bpf_trace_printk调用
确保字符串格式正确,避免潜在的重定位问题:bpf_trace_printk("hello\n", sizeof("hello\n")); // 打印变量时格式符要匹配 bpf_trace_printk("icmp type: %d, code: %d\n", sizeof("icmp type: %d, code: %d\n"), type, code);
内容的提问来源于stack exchange,提问作者user786
相关产品推荐
相关产品推荐

