You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用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正确解析的重定位信息,结合代码具体分析:

  1. 边界检查逻辑完全反向
    代码中if(ip+1>data_end)的逻辑是错误的:当ip+1 > data_end时,说明IP头部没有完整出现在数据包中,此时直接访问ip->protocol会触发非法内存访问。这种错误的内存访问逻辑会导致编译器生成异常的重定位数据,libbpf无法识别,最终加载失败。

  2. 自定义结构体与内核布局不匹配
    手动定义的icmphdr1结构体,即使字段和内核标准icmphdr一致,也可能因为编译对齐、字段偏移等问题,导致访问结构体成员时的重定位计算错误,libbpf无法处理这种非标准的重定位指向。

  3. 冗余代码干扰编译
    未使用的struct a等冗余定义,可能在编译时生成多余的段信息,间接导致重定位指向错误的段(错误信息中的section 6)。

解决方法

  1. 修正边界检查逻辑
    所有边界检查改为"不完整则丢弃"的正确逻辑:

    // 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;
    
  2. 使用内核标准结构体
    删除自定义的icmphdr1,包含标准头文件<linux/icmp.h>,直接使用内核定义的struct icmphdr:

    #include <linux/icmp.h>
    
  3. 清理冗余代码
    删除未使用的struct a、注释掉的代码块,减少编译时的冗余段。

  4. 规范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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:09:28