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

本文详细记录了将E810网卡的DPDK ice pmd驱动从20.11版本移植到16.04版本的过程中遇到的问题,包括编译方式差异、总线抽象层、宏定义不一致、内存管理模式变化、mbuf结构差异等,并提供了相应的解决方案。移植涉及的内容包括基础功能适配、filter框架、内存分配机制以及secondary进程支持等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

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

DPDK-20.11.1是一个开源的数据平面开发工具包,用于提高网络包处理性能。它是在Intel公司的推动下发起的,旨在提供一个高效灵活的解决方案,帮助开发人员利用现代多核处理器的强大计算能力,处理网络流量。 DPDK-20.11.1具有以下几个主要特点: 1. 高性能:DPDK-20.11.1能够充分利用现代多核处理器的并行计算能力,通过绕过操作系统内核的网络协议栈,直接访问网络包,实现高吞吐量的数据平面处理。 2. 低延迟:DPDK-20.11.1通过优化数据包处理的方式,减少了处理网络包的延迟。它采用零拷贝技术,避免了数据复制带来的额外延迟,并提供了高效的队列管理和调度算法。 3. 硬件加速:DPDK-20.11.1支持基于硬件的加速技术,如Intel的快速数据平面技术(Intel Quick Data Plane)和英特尔架构内置的虚拟化扩展(Intel Virtualization Technology)等,进一步提高了网络包处理性能。 4. 灵活性:DPDK-20.11.1提供了丰富的API和开发工具,使开发人员能够自定义网络包处理规则和算法,以满足不同应用场景的需求。它支持各种网络协议栈,如TCP/IP、UDP等,并提供了可扩展的软件定义网络(SDN)功能。 通过使用DPDK-20.11.1,开发人员可以实现高性能、低延迟的网络包处理,加速网络应用程序的性能,并提高网络服务的质量和可靠性。它被广泛应用于云计算、网络安全、电信和数据中心等领域,成为了加速网络包处理的重要工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值