首页 > 解决方案 > bpf_xdp_adjust_head 问题

问题描述

使用 bpf 开发一个小程序来扩展数据包(即:添加 mpls encap)。设法扩展没有问题,但我写回标题 s_mac 和 d_mac 不正确。我假设因为新空间较小,所以我与原始 eth 标头重叠,因此我得到了错误的值。

    /* extend the packet for mpls header encapsulation */
    if (bpf_xdp_adjust_head(ctx, 0 - (int)sizeof(struct mpls_hdr)))
        return XDP_DROP;

    data = (void *)(long)ctx->data;
    data_end = (void *)(long)ctx->data_end;

    /* relocate ethernet header to start of packet and set MACs */
    new_eth = data;
    old_eth = data + (int)sizeof(struct mpls_hdr);
    //set new header while swaping src/dst mac
    set_ethhdr(new_eth, old_eth, bpf_htons(ETH_P_MPLS_UC));

这就是我认为问题发生的地方,当我 memcpy 进入 new_eth 时,我正在咬入 old_eth 空间。有没有办法通过将 old_eth 的值复制到另一个结构中然后使用该结构创建 new_eth 来解决这个问题?

static __always_inline void set_ethhdr(struct ethhdr *new_eth,
                                       const struct ethhdr *old_eth,
                                       __be16 h_proto)
{
    memcpy(new_eth->h_source, old_eth->h_source, ETH_ALEN);
    memcpy(new_eth->h_dest, old_eth->h_dest, ETH_ALEN);
    new_eth->h_proto = h_proto;
}

一般来说,我对 BPF 和 C 很陌生,所以不确定这是否确实是问题所在。

谢谢。

标签: ebpfxdp-bpf

解决方案


我已经按照下面的方式进行了更改。不确定这是否是解决它的最佳方法,但它适用于我的用例( poc )。

static __always_inline void set_ethhdr(struct ethhdr *new_eth,
                                       const struct ethhdr *old_eth,
                                       __be16 h_proto)
{
    __u8 h_tmp_src[ETH_ALEN];
    __u8 h_tmp_dst[ETH_ALEN];

    __builtin_memcpy(h_tmp_src, old_eth->h_source, ETH_ALEN);
    __builtin_memcpy(h_tmp_dst, old_eth->h_dest, ETH_ALEN);

    __builtin_memcpy(new_eth->h_dest, h_tmp_src, ETH_ALEN);
    __builtin_memcpy(new_eth->h_source, h_tmp_dst, ETH_ALEN);
    
    new_eth->h_proto = h_proto;
}

推荐阅读