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

使用eBPF过滤数据包时出现丢包及目标主机不可达问题求助

eBPF XDP 数据包过滤导致ICMP丢包及目标不可达问题解决

问题场景

使用以下eBPF代码进行数据包过滤时,执行ping操作仅能传输部分数据包,随后出现「Destination Host Unreachable」提示,最终统计显示40%的丢包率。

原eBPF代码

SEC("xdp")
int icmp_timestamp(struct xdp_md *xdp) {
    void *data_end = (void *)(long)xdp->data_end;
    void *data = (void *)(long)xdp->data;

    if (data + sizeof(struct ethhdr) <= data_end) {
        struct ethhdr *eth = data;

        if (eth->h_proto == htons(ETH_P_IP) &&
            data + sizeof(struct ethhdr) + sizeof(struct iphdr) <= data_end) {

            struct iphdr *ip = data + sizeof(struct ethhdr);

            if (ip->protocol == IPPROTO_ICMP) {
                // Do some processing for ICMP packets

                // Allow the packet to pass
                return XDP_PASS;
            }
        }
    }

    return XDP_DROP;
}

ping操作输出

len=46 ip=10.0.2.6 ttl=63 id=29041 icmp_seq=2 rtt=8.5 ms 
len=46 ip=10.0.2.6 ttl=63 id=29172 icmp_seq=3 rtt=7.1 ms 
len=46 ip=10.0.2.6 ttl=63 id=29276 icmp_seq=4 rtt=5.8 ms 
len=46 ip=10.0.2.6 ttl=63 id=29496 icmp_seq=5 rtt=8.9 ms 
len=46 ip=10.0.2.6 ttl=63 id=29567 icmp_seq=6 rtt=4.6 ms 
len=46 ip=10.0.2.6 ttl=63 id=29721 icmp_seq=7 rtt=7.2 ms 
len=46 ip=10.0.2.6 ttl=63 id=29728 icmp_seq=8 rtt=10.1 ms
From 10.0.2.5 icmp_seq=10 Destination Host Unreachable
From 10.0.2.5 icmp_seq=11 Destination Host Unreachable
From 10.0.2.5 icmp_seq=12 Destination Host Unreachable
From 10.0.2.5 icmp_seq=13 Destination Host Unreachable 
From 10.0.2.5 icmp_seq=14 Destination Host Unreachable
From 10.0.2.5 icmp_seq=15 Destination Host Unreachable

10.0.2.6 hping statistic... 
15 packets transmitted, 9 packets received, 40% packet loss 
round-trip min/avg/max= 2.9/7.1/10.1 ms

问题根源

  1. ARP包被丢弃:原代码仅放行IP协议中的ICMP包,ARP协议(ETH_P_ARP)数据包被直接丢弃。当系统ARP缓存过期后,无法发送ARP请求获取目标主机MAC地址,导致后续ping包无法正常发送,触发目标不可达提示。
  2. IP头长度处理错误:代码直接用sizeof(struct iphdr)计算IP头长度,但IP头可能包含可变长度的选项(由ip->ihl字段指定,单位为4字节)。遇到带选项的IP包(如部分ICMP错误响应包)时,边界检查会失败,导致这些包被错误丢弃。

修复后的代码

#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

SEC("xdp")
int icmp_timestamp(struct xdp_md *xdp) {
    void *data_end = (void *)(long)xdp->data_end;
    void *data = (void *)(long)xdp->data;

    // 检查以太网头完整性
    if (data + sizeof(struct ethhdr) > data_end) {
        return XDP_DROP;
    }
    struct ethhdr *eth = data;

    // 放行ARP包,保证MAC地址解析正常
    if (eth->h_proto == htons(ETH_P_ARP)) {
        return XDP_PASS;
    }

    // 处理IP协议包
    if (eth->h_proto == htons(ETH_P_IP)) {
        // 检查IP头最小长度是否完整
        if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) > data_end) {
            return XDP_DROP;
        }
        struct iphdr *ip = data + sizeof(struct ethhdr);

        // 计算实际IP头长度(含选项),检查边界
        __u32 ip_hdr_len = ip->ihl * 4;
        if (data + sizeof(struct ethhdr) + ip_hdr_len > data_end) {
            return XDP_DROP;
        }

        // 放行所有ICMP包
        if (ip->protocol == IPPROTO_ICMP) {
            // 自定义处理逻辑可在此添加
            return XDP_PASS;
        }
    }

    // 丢弃其他非必要数据包
    return XDP_DROP;
}

char _license[] SEC("license") = "GPL";

修复说明

  • 新增ARP包放行逻辑,确保ARP请求与响应正常传输,维持ARP缓存有效性,避免因MAC解析失败导致的数据包发送失败。
  • 改用ip->ihl * 4计算实际IP头长度,正确处理带选项的IP包,避免边界检查错误导致的合法数据包被丢弃。
  • 调整边界检查顺序,先验证最小长度再处理可变长度,提升代码健壮性。

内容的提问来源于stack exchange,提问作者Manideep G

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 10:57:50