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

以太网帧跨网口克隆转发异常问题排查求助

问题

我正在尝试编写一个简单的网络桥接模块,编写了如下RX处理函数:

static rx_handler_result_t handle_frame(struct sk_buff **pskb) {
    struct sk_buff *skb = *pskb;
    struct sk_buff *cloned_skb;

    // Forward packets from eth1 to eth0
    if (skb->dev == dev_eth1) {
        struct ethhdr *eth = eth_hdr(skb);
        pr_info("Incoming packet: src MAC %pM, dst MAC %pM, ethertype 0x%04x\n",
                eth->h_source, eth->h_dest, ntohs(eth->h_proto));
        cloned_skb = skb_clone(skb, GFP_ATOMIC);
        if (!cloned_skb) {
            pr_err("Failed to clone skb\n");
            return RX_HANDLER_PASS;
        }
        cloned_skb->dev = dev_eth0;
        //skb_reset_mac_header(cloned_skb);
        // skb_reset_network_header(cloned_skb);
        // skb_reset_transport_header(cloned_skb);

        eth = eth_hdr(cloned_skb);
        pr_info("Sending packet on eth0: src MAC %pM, dst MAC %pM, ethertype 0x%04x\n",
                eth->h_source, eth->h_dest, ntohs(eth->h_proto));

        dev_queue_xmit(cloned_skb);


        return RX_HANDLER_CONSUMED;
    }
}

尽管两次打印的帧内容一致,但实际网络中捕获到的帧完全错乱(MAC地址随机且递增,仿佛克隆的skb数据影响了头部)。参考vlan等内核驱动的类似实现方式仍未解决,恳请指点错误原因。

分析与解决

你的问题核心是skb克隆后未正确处理缓冲区的头部偏移与数据所有权,具体原因及修复方式如下:

  • skb_clone的共享数据隐患
    skb_clone()仅克隆skb的元数据(各header指针、设备信息等),但数据缓冲区是与原skb共享的。直接修改克隆skb的dev就调用dev_queue_xmit(),会导致原skb后续被内核其他逻辑修改时,克隆包的数据同步被篡改;同时原skb的头部偏移是基于原设备上下文设置的,切换到新设备后未重置,会让内核在传输过程中错判数据位置,出现乱码MAC地址。

  • 头部指针必须重置
    你注释掉的skb_reset_mac_header()等函数是关键操作:克隆skb切换到新设备后,必须重置所有头部指针,确保内核处理克隆包时能正确定位各层头部。打印时eth_hdr()能正常获取是因为此时元数据还未被破坏,但传输阶段的校验和计算、驱动头部处理等逻辑会依赖这些指针,未重置必然导致数据偏移错误。

  • 正确的修复代码
    修改后的代码如下:

static rx_handler_result_t handle_frame(struct sk_buff **pskb) {
    struct sk_buff *skb = *pskb;
    struct sk_buff *cloned_skb;

    // Forward packets from eth1 to eth0
    if (skb->dev == dev_eth1) {
        struct ethhdr *eth = eth_hdr(skb);
        pr_info("Incoming packet: src MAC %pM, dst MAC %pM, ethertype 0x%04x\n",
                eth->h_source, eth->h_dest, ntohs(eth->h_proto));
        
        // 使用skb_copy获取独立数据缓冲区,避免共享数据被篡改
        cloned_skb = skb_copy(skb, GFP_ATOMIC);
        if (!cloned_skb) {
            pr_err("Failed to copy skb\n");
            return RX_HANDLER_PASS;
        }
        
        cloned_skb->dev = dev_eth0;
        // 重置所有头部指针
        skb_reset_mac_header(cloned_skb);
        skb_reset_network_header(cloned_skb);
        skb_reset_transport_header(cloned_skb);
        // 重新设置各层头部偏移,确保内核能正确解析
        skb_set_mac_header(cloned_skb, 0);
        skb_set_network_header(cloned_skb, ETH_HLEN);

        eth = eth_hdr(cloned_skb);
        pr_info("Sending packet on eth0: src MAC %pM, dst MAC %pM, ethertype 0x%04x\n",
                eth->h_source, eth->h_dest, ntohs(eth->h_proto));

        dev_queue_xmit(cloned_skb);

        return RX_HANDLER_CONSUMED;
    }
    // 处理非eth1的数据包,返回PASS让内核继续处理
    return RX_HANDLER_PASS;
}

额外细节注意:原代码未处理skb->dev != dev_eth1的情况,会导致函数无返回值的未定义行为,必须补充返回RX_HANDLER_PASS。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 06:12:38