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

RK3588设备UDP发送数据包乱序问题排查求助

RK3588 UDP数据包发送乱序问题排查求助

问题现象

使用RK3588通过PHY连接向外部设备传输UDP数据,单线程严格按0、1、2顺序发送,但接收端出现乱序(如包0、包2、包1)。通过tcpdump在RK3588本地抓包,发现设备端发出的数据包已乱序,排除UDP协议本身特性,推测问题出在设备内部缓存或发送链路。

已尝试的无效操作

  • 增大发送内存缓冲区:
    sysctl -w net.core.wmem_default=33554423
    sysctl -w net.core.wmem_max=33554423
    
  • 关闭网卡相关特性:
    ethtool -K eth tso off gso off tx off
    
  • dmesg无异常日志

当前限制

  • 成熟产品无法切换为TCP协议
  • 已在数据包中添加序列号,接收端可处理乱序,但RK3588自身发送乱序属于异常,需定位根源而非规避

发送核心代码结构

while (rate < 100)
{
    memset(&st_read_restult.arr_pic_data, 0, sizeof(st_read_restult.arr_pic_data));
    st_read_restult.pic_data_index = 0;
    n_ret = st_sdk_bkg_dma_process.read_file_buf(&st_read_in, &st_read_restult);
    
    LOG_DEBUG(LOG_PICTURE, "n_picture_id [%d] en_file_type [%d] arr_file_path[%s] n_effective_num [%d]", g_st_bkg_tmp.n_picture_id, g_st_bkg_tmp.en_file_type, \
            g_st_bkg_tmp.arr_file_path, n_effective_num);
    //calculate package num
    n_op_cnt = 0;
    n_write_start = 0;
    n_effective_num = (st_read_restult.pic_data_index % PICTURE_DMA_WRITE_LEN) ? (st_read_restult.pic_data_index / PICTURE_DMA_WRITE_LEN + 1) : st_read_restult.pic_data_index / PICTURE_DMA_WRITE_LEN;

    for (i = 0; i < n_effective_num; i++)
    {
        bkg_write_t st_bkg_write = {0};
        //assign seq
        st_read_restult.n_pack_seq = n_pack_seq++;
        st_bkg_write.arr_pic_data = st_read_restult.arr_pic_data;
        st_bkg_write.n_write_start = n_write_start;
        st_bkg_write.n_bkg_data_len = (n_write_start + PICTURE_DMA_WRITE_LEN > st_read_restult.pic_data_index) ? (st_read_restult.pic_data_index - n_write_start) : PICTURE_DMA_WRITE_LEN;
        n_write_start += st_bkg_write.n_bkg_data_len;


        LOG_DEBUG(LOG_PICTURE,"start send dma[%d]", j);
        p_bkg_data_op[n_op_cnt] = NULL;
        SDK_MEM_ALLOC(p_bkg_data_op[n_op_cnt], sizeof(transfer_op_t), (transfer_op_t *)malloc, LOG_PICTURE, &n_ret, SDK_RET_MEM_OVER);
        n_ret = st_sdk_bkg_dma_process.dma_write_func_0(&st_bkg_write, p_index[j], p_bkg_data_op[n_op_cnt]);//send called finally
        n_op_cnt++;
        SDK_RET_CHECK(n_ret, LOG_PICTURE);
        // usleep(20);//add this sleep can solve out of order problem
    }
}

tcpdump结果

本地抓包可见数据包序列号乱序(如0、2、1的顺序)


排查方向建议

  1. DMA发送队列/调度机制排查
    代码中调用dma_write_func_0发送数据,需确认该DMA函数是否为异步调用:如果是异步提交,RK3588的DMA控制器可能存在多通道调度优先级差异,或队列内部的乱序调度逻辑。可查看SDK文档中该DMA函数的实现,确认是否提交后立即返回、实际发送由硬件调度,且硬件调度未严格保证提交顺序。

  2. 网卡驱动发送队列检查
    即使关闭了TSO/GSO,网卡驱动的发送队列可能存在批量提交或重排序逻辑。可查看RK3588对应的网卡驱动(如rk_gmac)代码,确认ndo_start_xmit函数中是否有对skb的重排序处理,或是否存在多队列发送未绑定CPU导致的乱序。

  3. 内存缓存一致性问题
    检查st_read_restult.arr_pic_data的内存属性:如果是DMA缓冲区,是否存在缓存未同步导致的数据包内容提交顺序异常?比如前一个包的缓存未刷新,后一个包已被DMA提交发送。可尝试在调用dma_write_func_0前添加内存屏障(如mb()、dma_wmb()),强制内存操作顺序。

  4. 工具链/编译选项排查
    检查编译时是否开启了O2/O3优化,导致代码中n_pack_seq的赋值、DMA提交的顺序被编译器重排。可尝试添加volatile修饰n_pack_seq,或在DMA调用前添加编译屏障(asm volatile("" ::: "memory")),阻止编译器乱序优化。

  5. 硬件级别的调度验证
    使用RK3588的硬件调试工具(如perf、内核trace)跟踪DMA发送的提交和完成事件,对比序列号的提交顺序与硬件实际发送顺序。例如使用trace-cmd跟踪net_dev_queue、net_dev_xmit等内核事件,查看skb的入队顺序与出队顺序是否一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 16:20:54