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的顺序)
排查方向建议
DMA发送队列/调度机制排查
代码中调用dma_write_func_0发送数据,需确认该DMA函数是否为异步调用:如果是异步提交,RK3588的DMA控制器可能存在多通道调度优先级差异,或队列内部的乱序调度逻辑。可查看SDK文档中该DMA函数的实现,确认是否提交后立即返回、实际发送由硬件调度,且硬件调度未严格保证提交顺序。网卡驱动发送队列检查
即使关闭了TSO/GSO,网卡驱动的发送队列可能存在批量提交或重排序逻辑。可查看RK3588对应的网卡驱动(如rk_gmac)代码,确认ndo_start_xmit函数中是否有对skb的重排序处理,或是否存在多队列发送未绑定CPU导致的乱序。内存缓存一致性问题
检查st_read_restult.arr_pic_data的内存属性:如果是DMA缓冲区,是否存在缓存未同步导致的数据包内容提交顺序异常?比如前一个包的缓存未刷新,后一个包已被DMA提交发送。可尝试在调用dma_write_func_0前添加内存屏障(如mb()、dma_wmb()),强制内存操作顺序。工具链/编译选项排查
检查编译时是否开启了O2/O3优化,导致代码中n_pack_seq的赋值、DMA提交的顺序被编译器重排。可尝试添加volatile修饰n_pack_seq,或在DMA调用前添加编译屏障(asm volatile("" ::: "memory")),阻止编译器乱序优化。硬件级别的调度验证
使用RK3588的硬件调试工具(如perf、内核trace)跟踪DMA发送的提交和完成事件,对比序列号的提交顺序与硬件实际发送顺序。例如使用trace-cmd跟踪net_dev_queue、net_dev_xmit等内核事件,查看skb的入队顺序与出队顺序是否一致。
内容的提问来源于stack exchange,提问作者user28690465

