82599ES 光口无法通过大包的问题记录

问题

参考 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);
			}
		}

	/* ... */
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章