参考 DPDK 例子程序 ip_fragment.c 来实现分片。
无论 I350 电口 还是 82599ES 光口,小包都是可以通过的。
但是在大包的时候,82599ES 光口就有问题。
场景 | I350 电口 | 82599ES 光口 |
---|---|---|
启用 tx checksum offload | 小包可以通过 | 小包可以通过 |
启用 tx checksum offload | 小包可以通过 | 小包可以通过 |
启用 tx checksum offload | 大包可以通过 | 大包不可以通过 |
不用 tx checksum offload,CPU 填充 checksum | 大包可以通过 | 大包不可以通过 |
由于使用了 CPU 填充 checksum 也有问题。所以排除 tx checksum offload 的问题。
因为 DPDK 后的报文,会由多个 segment 组成,所以怀疑 82599ES 光口 的发包函数不支持 多 segment 的 报文发送。
所以要查看发包函数。
# get 82599ES pci address
lspci | grep Eth
> 08:00.1 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
# get 82599ES device id
cat /sys/bus/pci/devices/0000:08:00.0/device
> 0x10fb
从 0x10fb 得出 82599ES 的 设置类型为 IXGBE_DEV_ID_82599_SFP
,所以 82599ES 使用的是 ixgbe 的驱动。
ixgbe 的驱动的 发包函数有三个。
发包函数 | 描述 |
---|---|
ixgbe_xmit_pkts_vec | 万兆 Rx Vector enabled |
ixgbe_xmit_pkts_simple | 万兆 Tx simple |
ixgbe_xmit_pkts | 万兆 默认发包函数 |
使用 gdb 对以上函数来打断点。确认当前的是 ixgbe_xmit_pkts_vec 发包函数。
查看驱动的 ixgbe_set_tx_function 函数的代码。发现不同发包函数原来是有区别的:
ixgbe_set_tx_function(struct rte_eth_dev *dev, struct ixgbe_tx_queue *txq)
{
/* Use a simple Tx queue (no offloads, no multi segs) if possible */ // <-- no offloads, no multi segs supports
if (((txq->txq_flags & IXGBE_SIMPLE_FLAGS) == IXGBE_SIMPLE_FLAGS)
&& (txq->tx_rs_thresh >= RTE_PMD_IXGBE_TX_MAX_BURST)) {
PMD_INIT_LOG(DEBUG, "Using simple tx code path");
#ifdef RTE_IXGBE_INC_VECTOR
if (txq->tx_rs_thresh <= RTE_IXGBE_TX_MAX_FREE_BUF_SZ &&
(rte_eal_process_type() != RTE_PROC_PRIMARY ||
ixgbe_txq_vec_setup(txq) == 0)) {
PMD_INIT_LOG(DEBUG, "Vector tx enabled.");
dev->tx_pkt_burst = ixgbe_xmit_pkts_vec; // <-- DON'T WORK
} else
#endif
dev->tx_pkt_burst = ixgbe_xmit_pkts_simple; // <-- DON'T WORK
} else {
PMD_INIT_LOG(DEBUG, "Using full-featured tx code path"); // <-- offloads, multi segs supports
PMD_INIT_LOG(DEBUG,
" - txq_flags = %lx " "[IXGBE_SIMPLE_FLAGS=%lx]",
(unsigned long)txq->txq_flags,
(unsigned long)IXGBE_SIMPLE_FLAGS);
PMD_INIT_LOG(DEBUG,
" - tx_rs_thresh = %lu " "[RTE_PMD_IXGBE_TX_MAX_BURST=%lu]",
(unsigned long)txq->tx_rs_thresh,
(unsigned long)RTE_PMD_IXGBE_TX_MAX_BURST);
dev->tx_pkt_burst = ixgbe_xmit_pkts; // <-- WORK
}
}
总结一下,可以得出不同发包函数的区别如下:
发包函数 | 是否支持offload, 和 多 segment 的 报文 |
---|---|
ixgbe_xmit_pkts_vec | 否 |
ixgbe_xmit_pkts_simple | 否 |
ixgbe_xmit_pkts | 是(全功能) |
看来 82599ES 需要使用 ixgbe_xmit_pkts 才支持offload, 和 多 segment。
参考 DPDK 例子程序 ip_fragment.c 的代码。
设置 txq_flags 为 0,使用 ixgbe_xmit_pkts 发包函数,就可以支持 offload 和 多 segment 的 报文 发送。
ip_fragment.c 的代码:
main()
{
/* ... */
/* init one TX queue per couple (lcore,port) */
for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
if (rte_lcore_is_enabled(lcore_id) == 0)
continue;
socket = (int) rte_lcore_to_socket_id(lcore_id);
/* set txq_flags to ZERO,
* to use defualt tx function (ixgbe_xmit_pkts),
* which support multi-segment and offload for ixgbe driver
* with NIC 82599ES (device: IXGBE_DEV_ID_82599_SFP).
* reference: example of ip_fragmentation.c, DPDK.
*/
rte_eth_dev_info_get(portid, &dev_info);
txconf = &dev_info.default_txconf;
txconf->txq_flags = 0; /* <-- use defualt tx function */
ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd,
socket, txconf);
if (ret < 0) {
printf("\n");
rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup: "
"err=%d, port=%d\n", ret, portid);
}
}
/* ... */
}