当前位置: 首页 > 工具软件 > Intel® DPDK > 使用案例 >

从 dpdk-20.11 移植 intel E810 百 G 网卡 pmd 驱动到 dpdk-16.04 中

东方修谨
2023-12-01

前言

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 移植驱动其稳定性最好,这样会减少很多不必要的工作量。

dpdk-20.11 ice pmd 驱动源码的组成

├── 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

关键项目描述如下:

  1. 编译配置文件 meson.build 与符号描述文件 version.map
  2. base 目录中存放驱动内部硬件配置逻辑代码
  3. 顶层目录中的文件存放用于对接 dpdk 软件框架的代码,对硬件的操作主要依赖 base 目录中的实现
  4. ice_ethdev.c、ice_dcf_ethdev.c 对接 dpdk pci 驱动框架
  5. ice_rxtx*.c 是驱动收发包函数的实现,可以分为普通收发包函数、sse 向量收发包函数、avx2 向量收发包函数、avx512 向量收发包函数
  6. 顶层目录中的 xxx_filter.c 抽象网卡支持的不同 filter 功能,ice_generic_flow.c 使用 dpdk rte_flow 框架来统一不同 filter 的处理流程

完成 ice_ethdev.c、ice_rxtc.c、base 目录中源码的适配后驱动基础功能就可用了,其它的代码可以根据项目需求进行移植、裁剪。

移植问题与解决方案记录

16.04 使用 make 编译,20.11 使用 meson 与 ninja 方式编译

参照 dpdk-18.xx ice 驱动版本中的 Makefile 文件实现进行修改,同时 config 配置也参考 dpdk-18.xx 中的修改进行,同步修改 mk 子目录中的文件添加 ice 驱动库的链接项目。

16.04 没有总线的抽象层,20.11 有总线抽象层

bus 抽象层只影响驱动的注册逻辑,参照 i40e 驱动增加一个 rte_driver
实例,通过 PMD_REGISTER_DRIVER注册此实例。

16.04 与 20.11 中的一些通用宏定义名称不一致

增加一个适配头文件,将变化的宏定义重新定义为 16.04 中的实现,并在几个通用头文件如 base/ice_osdep.hice_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

16.04 不支持 iova 模式

20.11 中一些共享数据结构的地址使用 iova 名称存储,例如 memzone、mbuf,可以使用 sed 命令将这些名称替换为 phys_addr。

示例如下:

-       mem->pa = mz->iova;
+       mem->pa = mz->phys_addr;

16.04 rte_mbuf 的结构与 20.11 rte_mbuf 的结构存在差异,vec 收发包函数需要重新适配

优先移植普通收发包函数,移植完成后再根据需求重新适配 vec 收发包函数。sse 收发包函数可以参考 i40e 修改,主要修改收包函数,发包函数逻辑非常简单。avx2、avx512 向量收发包函数可以根据需求适配。

解析描述符的逻辑可以直接复用,难点在于针对 16.04 的 mbuf 结构偏移进行适配。可以自定义一个特定的结构体,使用向量指令将合并后的内容存储到结构体中,然后使用结构体的字段分开存储到 mbuf 中的指定字段内。

16.04 中 rte_eth_conf 结构 rxmode、txconf 中配置的硬件 offload 字段与 20.11 不一致

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;
}

16.04 不支持 rte_flow 框架,20.11 中驱动的 filter 功能均通过 rte_flow 框架实现

可以将 20.11 的 rte_flow 框架移植到 16.04 中,也可以选择裁剪掉这部分功能。rte_flow 框架移植的难度不大,主要问题在于 dpdk-16.04 内存分配机制过于原始,使用这个框架可能有大量的内存碎片产生。

16.04 rte_mbuf 不支持 dynamic mbuf field 字段,ice Protocol extraction 功能要使用需要修改 rte_mbuf 结构

Protocol extraction 技术配置硬件解析特定格式报文并将解析报文头存储到 mbuf dynamic mbuf field 字段中并设置相关 flags 让上层使用。

此改动影响过大,裁剪掉此功能。

16.04 中未实现 20.11 中存在的一些 eth_dev_ops 的虚函数

这部分功能属于扩展功能,eth_dev_ops 中的虚函数依赖 rte_ethdev.c 中实现的 api 封装接口使用,直接裁剪掉相关功能。

例如如下项目都可以去掉:

fw_version_get 
rx_burst_mode_get 
tx_burst_mode_get
tx_done_cleanup 

16.04 中 pci 结构初始化与访问方式与 20.11 不一致

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,访问这个字段会触发段错误。

secondary 进程收发包支持

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.4 l2fwd 测试 100G 网卡小包性能差问题

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 问题

 类似资料: