我正在使用 rk3588 设备将一些数据传输到与 phy 连接的设备,并且设备接收数据无序,例如 pack 0 pack 2 pack 1。但我确信我使用 0 1 2 顺序发送它1个线程,所以我使用tcpdump来定位数据出错的地方,我发现tcpdump中的数据在设备中已经乱序了,所以问题不是udp它自己(我想想),设备中的buf。
我试过
放大内存,如 sysctl -w net.core.wmem_default=33554423
sysctl -w net.core.wmem_max=33554423
ethtool -K eth tso 关闭 gso 关闭 tx 关闭,
它不起作用。dmesg 看起来一切都很好,我想找到问题并解决(如果有任何方法),至少定位问题。
根据研究,很多人建议使用tcp,并在我的数据中添加seq,但是在成熟的产品中不可能切换协议,而我已经添加了seq。但我的领导要求我找出原因,而不仅仅是逃避问题。我不知道,请帮助我。
设备接收乱序是可以接受的,但在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 slove out of oder problem
}
}
您的网络接口可能有多个传输队列(大多数现代网卡都有),并且根据您设置的流量整形排队规则,您生成的 UDP 包可能会根据填充状态放入不同的队列中每个队列——这可能会导致数据包重新排序。 (例如,默认的
mqprio
tc qdisc 就会执行此操作。)
您有几个选择:
您可以选择始终将生成的 UDP 数据包排序到同一队列中的排队规则(但可能将其他数据包排序到不同的队列中)。不过,流量整形基础设施非常难以理解。
您可以使用
ethtool --set-channels ethXYZ tx 1
(如果您的 NIC 驱动程序不支持单独配置 tx/rx,则使用 ethtool --set-channels ethXYZ combined 1
)强制您的 NIC 仅使用单个传输队列(systemd-networkd 也将其公开为 TxChannels=
/CombinedChannels=
*.link
文件的配置选项)。这可能会带来性能/CPU 使用率分布的缺点,特别是对于快速 NIC。 (特别是如果您必须将其用于组合通道,这也会影响您的接收队列。)
您可以接受这样一个事实:NIC 中的多个传输队列会导致网络数据包重新排序。