DPDK 报文调度与保序终极解决方案 EventDev 简介

1、背景介绍

网络报文的分发以及保序一直以来是让人头痛的问题, 为了完整的解释Event Dev的背景,我们可以从两个基本概念的定义开始:

  • 报文分发是指针对网络通信报文的某种特征(例如 5 tuples)对网络报文进行分类以及对这个分类进行对应的特定处理。这种分类通常称为是flow, 例如 src ip, src port, dest ip, dest port, 一致的报文被认为是一个flow, 还可以更进一步提取特征来加强判断同一flow的条件, 例如协议类型, tunnel id 等等。
  • 保序, 是指在包文处理过程中不改变原有的顺序, 大多数情况下可以弱化为在同一flow内的包文顺序不变。这里和协议倒不是非常相关。

首先最常见的包文分发技术是基于NIC 多队列的 Receive Side Scaling, NIC 首先根据算法对包文进行分类,然后尽可能平均的把不同flow放置到不同的接受队列中。 RSS虽然解决了包文分发到多个cpu core的问题, 但是RSS并不了解哪个flow应该到哪个cpu core, 也无法通过配置解决, 同时RSS只能分发没有其它选择, 为了解决这个问题 Intel 引入了更进一步的方案 Flow Director, 通过Flow Director, NIC 不但可以分发包文还可以指定特定的flow到特定的cpu core,同时除了分发也可以选择drop 包文。要更加精准和灵活, 更多细节请参考 Flow Director Ref

无论RSS/Flow Director 都可以分发/同一flow保序 但是很难满足更复杂的应用场景。在PIPELINE 处理模型中, 除了接受端分发以外, 每个节点处理后还会 二次, 三次, N次分发包文, 这下该怎么办 ?
如下图所示, 同一flow 4个包文开始分发, 1,3 进入一个路径, 2,4 进入一个路径, 因为没有任何锁来控制同步(性能考量) 所以在处理结束的时候包文的顺序以及打乱, 原因是在两个完全并行的路径上顺序是无法保证的, 最直接的想法就是引入一个reordering的功能节点, 当然代价是昂贵的, 同时在CPU core之间做包文的分发也是代价昂贵的操作。

2、CPU软件包调度

通过网卡来分发调度只能在接收端进行一次, 在更加复杂的PIPELINE模型中无法进一步进行调度, 所以非常直接的解决方案就是通过CPU 来对报文进行调度/保序, 一个高效的实现方案并不是显而易见的, 主要的困难在于两个方面:

  • 如何高效的分发
  • 如何高效的保序

DPDK的组件 Packet Distributor 在这方面进行了有益的探索。
调度报文, 本质上就是CPU core之间的通信, X86的架构下 , CPU core 之间最高效的通信方式就是通过 L3 cache-line, 一个 cache-line 是64Byte, 也就是说 在一个cache-line中最多可以包含8个64bits指针,恰恰8个指针可以代表8个报文。 Distributor Core 和 Worker Core 通过cache-line来通信, Distributor/Worker Core 通过首个报文的最低4位来判断读写的状态 (mbuf 默认都是 64Bytes 对齐, 所以低6位都是空余的可以用来表示状态), 如下图所示:

以下是状态位的定义:

其工作流程如下(引自dpdk.org), 不再赘述:

Distributor 作为纯软件报文分发确实做到了比较极致, 但是却没有完美的解决保序的要求, 依然需要引入 reorder buffer来重建报文顺序。 同时如果worker core 是处理异步业务 Distributor core 也需要引入更加复杂的逻辑来应对。大家可以参考源代码: example/distributor/

3、终极形态

报文分发/保序的最终形态终于演化至Hardware实现 (i e基于CPU的软件方案在灵活性,性能上都遭遇了瓶颈)。当前的Hardware主要有两家厂商, NXP 和Cavium, 我们今天的讨论主要基于后者, 主要的原因是因为公开的资料比较全面。

Cavium eventdev HW 介绍

对于HW实现来说, 显而易见的是把分发/保序的工作分担给HW,从而节省CPU的计算资源。
核心的HW框架如下(引用自Cavium的资料):

  • 蓝色的队列/粉色的调度器都是基于HW实现
  • 每一个硬件的队列中包含若干的基于flow 划分的子队列, 每一个event会根据其相关flow最终插入到其中一个子队列
  • 在event enqueue阶段, event的发送源需要显式地指定队列号,亦即,该event应该进入那个队列
  • 之后调度器会根据 event 类型, event优先级, 队列类型等参数进行调度
  • 在event dequeue 阶段 每一个worker cpu core 会polling对应的port, 获取event, 处理结束后需要指定下一阶段的queue id 等信息再enqueue回对应队列
  • 有两个特殊的阶段是NIC RX/TX, RX 只有enqueue, 而TX 只有dequeue。理想情况下 RX/TX 可以做成inline 形式, 免去CPU 还需要polling NIC Ring

以下是简化的event定义, 前64位是 meta data, 后64位是mbuf的地址。Meta data中包含各种控制信息可以参考代码,这里不再赘述。

报文调度主要有两种类型:
Atomic: 在特定时间点, 每一个flow 只有一个报文被调度到一个CPU进行处理, 从而保证处理过程中相关数据结构的原子性, 达到无锁处理的目标,可以简化应用设计.
Ordered: 在特定时间点, 每一个flow可以有多个报文被调度到多个CPU进行处理, 但是处理结束后报文的顺序没有变化.
下面结合EventDev HW 设计来描述一下一个报文的生命周期。首先来看下图:

  • 网卡收到报文,填写好flowid ,queue id从而enqueue到queue 0
  • 调度器HW根据入队的event flow id 和queue id将其分配至queue 0的flow0子队列
  • 调度器根据Queue0和 Dequeue port 0 的链接状态, 将其分发到port0 出队
  • CPU 0 从port0 取出event 进行相关处理, 业务逻辑代码根据配置信息将event 转发到queue1, 填写好queue id后, 从port0 入队
  • 调度器硬件根据queue id 这次将event分配到queue 1的flow0子队列
  • 调度器根据queue 1和 port1 链接的状态, 将其分发到port1出队
  • CPU 1 从 port1 取出event 进行加密处理, 之后依旧从por1入队到队列, 但是指定event 类型为TX
  • 调度器这次将根据事件类型将event分发至TX出队port, 从而发送

影响调度器行为的参数有:

  • flow id: event 所属的flow
  • queue id: event 入队时指定的队列id
  • event type: event的类型
  • queue type: 队列的分发属性
  • op type: event 是new/forward/release主要是指这个事件是新引入事件(例如RX),还是转发(node节点之间),还是释放(含异常处理)

结合下图可以更好的理解一下队列类型的影响:

Atomic 类型队列:
首先一个flow的event会保序进入queue 0的flow0 子队列, 调度器只会分发该flow的一个event到一个出队port, 在这个event被重新入队以前不会分发下一个event。
例如 e0 被分发到port0, 在e0被重新入队之前, e1,e2,e3都要等待。
Ordered 类型队列:

  • 首先一个flow的event会保序进入queue 0 的flow0 子队列, 调度器会同时分发e0, e1, e2, e3 到多个port上。例如 e3 被分发到port0, e0 被分发到port1, e1被分发到port2, e2被分发到port3。
  • 当e0,e1,e2,e3重新入队的时刻, HW会对其顺序重整。 保证对下一个阶段的处理是保序的。

在目录/driver/event/sw下, Intel 公司贡献了基于软件实现的eventdev-sw PMD。eventdev-sw PMD 和基于硬件实现的 eventdev PMD 在api 级别兼容, 功能上也基本一致。 在/example/eventdev_pipeline_sw_pmd 目录下有基于eventdev-sw PMD的例子程序。 这也是目前唯一upstream的 eventdev 例子程序, 非常有参考价值。
到这里, eventdev 的前世今生基本上已经讨论完毕。虽然event dev还是dpdk家族中相对新的组件, 但是我相信event dev最终会成为包处理业务的中流砥柱,不可或缺的一环。希望大家多提宝贵意见。

相关链接

Receive Side Scaling (RSS):
https://docs.microsoft.com/en-us/windows-hardware/drivers/network/rss-with-hardware-queuing
Flow Director Ref:
https://www.intel.com/content/www/us/en/ethernet-products/converged-network-adapters/ethernet-flow-director.html
Cavium eventdev HW 介绍:
https://dpdksummit.com/Archive/pdf/2016USA/Day01-Session04-JerinJacob-DPDKUSASummit2016.pdf

原文:DPDK开源社区

发表评论

电子邮件地址不会被公开。 必填项已用*标注