21 年因项目需要将 E810 网卡 pmd 驱动从 dpdk-20.11 移植到了 dpdk-16.04 中,本文记录移植过程中遇到的关键问题及一些解决思路以供参考。
移植之前要确定驱动源码来源版本,不同版本驱动移植在【工作量】与【稳定性】上有不同的表现。一般来说,老版本移植工作量相对小些,功能却可能不太稳定;新版本功能趋向稳定,移植工作量却相对大些。
E810 dpdk pmd 驱动名称为 ice,在 18 年底的 18.xx 版本中加入 dpdk,在 19 年与 20 年都有许多 git commit,且其中以 fix 标识的 case 有许多,说明这一阶段驱动功能还不太稳定。
最开始我选择了 18.xx 版本的驱动源码进行移植,移植后测试发现 rss hash 存在问题,查看 git log 确定这个问题在高版本已经修复,考虑到可能存在其它问题,决定选择一款稳定性最高的驱动来移植。
在 2021 年 Q2 的时候,dpdk 最新的稳定版本为 20.11,虽然 16.04 可能与 20.11 差别很大,但是从 20.11 移植驱动其稳定性最好,这样会减少很多不必要的工作量。
├── base
│ ├── ice_acl.c
│ ├── ice_acl_ctrl.c
│ ├── ice_acl.h
│ ├── ice_adminq_cmd.h
│ ├── ice_alloc.h
│ ├── ice_bitops.h
│ ├── ice_common.c
│ ├── ice_common.h
│ ├── ice_controlq.c
│ ├── ice_controlq.h
│ ├── ice_dcb.c
│ ├── ice_dcb.h
│ ├── ice_devids.h
│ ├── ice_fdir.c
│ ├── ice_fdir.h
│ ├── ice_flex_pipe.c
│ ├── ice_flex_pipe.h
│ ├── ice_flex_type.h
│ ├── ice_flow.c
│ ├── ice_flow.h
│ ├── ice_hw_autogen.h
│ ├── ice_lan_tx_rx.h
│ ├── ice_nvm.c
│ ├── ice_nvm.h
│ ├── ice_osdep.h
│ ├── ice_protocol_type.h
│ ├── ice_sbq_cmd.h
│ ├── ice_sched.c
│ ├── ice_sched.h
│ ├── ice_status.h
│ ├── ice_switch.c
│ ├── ice_switch.h
│ ├── ice_type.h
│ ├── meson.build
│ └── README
├── ice_acl_filter.c
├── ice_dcf.c
├── ice_dcf_ethdev.c
├── ice_dcf_ethdev.h
├── ice_dcf.h
├── ice_dcf_parent.c
├── ice_ethdev.c
├── ice_ethdev.h
├── ice_fdir_filter.c
├── ice_generic_flow.c
├── ice_generic_flow.h
├── ice_hash.c
├── ice_logs.h
├── ice_rxtx.c
├── ice_rxtx.h
├── ice_rxtx_vec_avx2.c
├── ice_rxtx_vec_avx512.c
├── ice_rxtx_vec_common.h
├── ice_rxtx_vec_sse.c
├── ice_switch_filter.c
├── meson.build
├── rte_pmd_ice.h
└── version.map
关键项目描述如下:
完成 ice_ethdev.c、ice_rxtc.c、base 目录中源码的适配后驱动基础功能就可用了,其它的代码可以根据项目需求进行移植、裁剪。
参照 dpdk-18.xx ice 驱动版本中的 Makefile 文件实现进行修改,同时 config 配置也参考 dpdk-18.xx 中的修改进行,同步修改 mk 子目录中的文件添加 ice 驱动库的链接项目。
bus 抽象层只影响驱动的注册逻辑,参照 i40e 驱动增加一个 rte_driver
实例,通过 PMD_REGISTER_DRIVER
注册此实例。
增加一个适配头文件,将变化的宏定义重新定义为 16.04 中的实现,并在几个通用头文件如 base/ice_osdep.h
、ice_ethdev.h
中包含这个头文件。内容示例如下:
#ifndef RTE_ETH_DEV_TO_PCI
#define RTE_ETH_DEV_TO_PCI(eth_dev) ((eth_dev)->pci_dev)
#endif
#define rte_ether_addr ether_addr
typedef uint64_t rte_iova_t;
#ifndef RTE_ETHER_MIN_LEN
#define RTE_ETHER_MIN_LEN ETHER_MIN_LEN
#endif
#ifndef rte_tcp_hdr
#define rte_tcp_hdr tcp_hdr
#endif
#ifndef rte_udp_hdr
#define rte_udp_hdr udp_hdr
#endif
20.11 中一些共享数据结构的地址使用 iova 名称存储,例如 memzone、mbuf,可以使用 sed 命令将这些名称替换为 phys_addr。
示例如下:
- mem->pa = mz->iova;
+ mem->pa = mz->phys_addr;
优先移植普通收发包函数,移植完成后再根据需求重新适配 vec 收发包函数。sse 收发包函数可以参考 i40e 修改,主要修改收包函数,发包函数逻辑非常简单。avx2、avx512 向量收发包函数可以根据需求适配。
解析描述符的逻辑可以直接复用,难点在于针对 16.04 的 mbuf 结构偏移进行适配。可以自定义一个特定的结构体,使用向量指令将合并后的内容存储到结构体中,然后使用结构体的字段分开存储到 mbuf 中的指定字段内。
16.04 的 rte_eth_conf 结构通过 rxmode 中的不同变量名称来配置队列硬件 offload 功能,20.11 中修改为使用 rxmode 的 offloads 字段的方式,需要将相关代码修改为 16.04 的方式,示例如下:
- if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
+ if (rxmode->hw_vlan_filter)
20.11 中 tx offload 功能通过 offloads 字段配置,在 16.04 中却是通过txq_flags
字段来配置。由于使用地点固定且内部使用的 OFFLOAD 宏名称不一致,可以实现一个从 tx_flags 映射到 offloads 的函数在 ice tx_queue_setup 的时候调用即可。
映射函数示例代码如下:
static uint32_t map_tx_flags_to_offloads(uint32_t txq_flags)
{
uint32_t offloads = 0;
if (txq_flags & ETH_TXQ_FLAGS_NOMULTSEGS)
offloads |= DEV_TX_OFFLOAD_MULTI_SEGS;
............................................
return offloads;
}
可以将 20.11 的 rte_flow 框架移植到 16.04 中,也可以选择裁剪掉这部分功能。rte_flow 框架移植的难度不大,主要问题在于 dpdk-16.04 内存分配机制过于原始,使用这个框架可能有大量的内存碎片产生。
Protocol extraction 技术配置硬件解析特定格式报文并将解析报文头存储到 mbuf dynamic mbuf field 字段中并设置相关 flags 让上层使用。
此改动影响过大,裁剪掉此功能。
这部分功能属于扩展功能,eth_dev_ops 中的虚函数依赖 rte_ethdev.c 中实现的 api 封装接口使用,直接裁剪掉相关功能。
例如如下项目都可以去掉:
fw_version_get
rx_burst_mode_get
tx_burst_mode_get
tx_done_cleanup
20.11 中通过 RTE_DEV_TO_PCI(dev->device)
宏来访问设备的 pci_dev
结构,此结构在驱动 probe 过程中统一初始化,16.04 中使用 rte_eth_dev
结构中的 pci_dev
字段来访问 pci_dev 结构,需要修改代码。
示例如下:
- struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev->device);
+ struct rte_pci_device *pci_dev = dev->pci_dev;
struct ice_adapter *ad =
ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private)
同时需要注意的是 16.04 使用 rte_eth_dev
结构的 data 字段指向的 drv_name
字段来保存驱动的名称,需要修改 ice_dev_init
函数,可以参照 i40e_dev_init 函数添加 rte_eth_copy_pci_info
函数调用来进行必要的初始化,否则 drv_name 字段为 NULL,访问这个字段会触发段错误。
struct ice_rx_queue 中的rxd_to_pkt_fields
字段是函数指针,属于 primary 进程【本地地址】,在 secondary 进程中指向非法位置。当 secondary 进程调用收发包函数时会调用此函数指针,此时会触发段错误。需要将这个函数指针访问进行【本地化】。
可以参考如下 git commit 进行修改:
commit 20b631efe785819eb77aabbf500b3352e5731bdb
Author: Dapeng Yu <dapengx.yu@intel.com>
Date: Tue Oct 26 09:55:42 2021 +0800
net/ice: fix function pointer in multi-process
This patch uses the index value to call the function, instead of the
function pointer assignment to save the selection of Receive Flex
Descriptor profile ID.
Otherwise the secondary process will run with wrong function address
from primary process.
Fixes: 7a340b0b4e03 ("net/ice: refactor Rx FlexiMD handling")
Cc: stable@dpdk.org
Signed-off-by: Dapeng Yu <dapengx.yu@intel.com>
Acked-by: Haiyue Wang <haiyue.wang@intel.com>
同时测试发现,在 secondary 进程收包申请 mbuf 失败增加异常统计时会触发段错误,排查确定访问方式存在问题,将访问过程修改为如下内容:
if (unlikely(!nmb)) {
- dev = ICE_VSI_TO_ETH_DEV(rxq->vsi);
- dev->data->rx_mbuf_alloc_failed++;
+ rte_eth_devices[rxq->port_id].data->rx_mbuf_alloc_failed++;
break;
}
官方 commit 信息如下:
commit 45f6a19f6565a3ae8572868c1a6fd2ad70687171
Author: Qi Zhang <qi.z.zhang@intel.com>
Date: Wed May 26 14:12:56 2021 +0800
net/ice: fix data path in secondary process
The rte_eth_devices array is not in share memory, it should not be
referenced by ice_adapter which is shared by primary and secondary.
Any process set ice_adapter->eth_dev will corrupt another process'
context.
The patch removed the field "eth_dev" from ice_adapter.
Now, when the data paths try to access the rte_eth_dev_data instance,
they should replace adapter->eth_dev->data with adapter->pf.dev_data.
Fixes: f9cf4f864150 ("net/ice: support device initialization")
Cc: stable@dpdk.org
Reported-by: Yixue Wang <yixue.wang@intel.com>
Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
dpdk-16.04 l2fwd 示例程序的收发包描述符配置如下:
#define RTE_TEST_RX_DESC_DEFAULT 128
#define RTE_TEST_TX_DESC_DEFAULT 512
上述描述符配置在低端网卡上正常使用,在百 G 网卡上就有些 out 了,在小包性能测试时表现尤其明显。dpdk 20.11 中基础描述符配置如下:
#define RTE_TEST_RX_DESC_DEFAULT 1024
#define RTE_TEST_TX_DESC_DEFAULT 1024
同时 20.11 还在程序初始化时调用了 rte_eth_dev_adjust_nb_rx_tx_desc
来调整描述符大小(尽管调整后还是 1024)。
将 dpdk-16.04 l2fwd 默认描述符调大,小包性能显著提高。
dpdk 问题分析:dpdk-20.11 ice 100G 网卡 rss_hash 配置无效问题
dpdk 问题分析:ice 100G 网卡 rx_packets 与 rx_bytes 统计问题
ice 100G 网卡分片报文 hash 问题