問題
參考 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);
}
}
/* ... */
}