一个内存池(memory pool)就是固定大小对象的分配器。在dpdk中,它是经过名字来标示惟一性的,且使用环形队列来保存没有使用的空闲对象。它提供了一些可选项服务例如针对每一个核的对象缓存以及数据对齐,有助于将对象使用的内存空间均等的展开在DARM或者是DDR3通道上。linux
这个库被Mbuf Library和EAL使用。api
5.1 cookies数组
在调试模式下(CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG打开),cookies会被加到分配的内存块的头尾。分配的对象就包含了越界检查区域以帮助调试缓冲区溢出。缓存
5.2 统计安全
在调试模式下(CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG打开),对于从内存池中获取和释放的统计会保存在内存池结构体中。统计是针对每一个核的,避免并发访问统计计数器。性能优化
5.3 内存对齐限制cookie
取决于硬件内存配置,经过在对象之间作填充,性能能够获得巨大的提高。确保每一个对象的起始地址是在内存中的不一样通道和rank,以便全部的通道都是均等的加载。网络
在作数据包三层转发或者是流量分级时,这个是绝对实用的。因为只有前64个字节的访问,因此将对象的开始地址展开到不一样的通道,性能能够提高。数据结构
每一个DIMM(双列直插式内存)rank数目就是是DIMM可访问的全数据宽度的相互独立内存集合的数目。不一样rank上的内存是不能同时访问的,即便是共享一样的数据总线。DIMM自身的内存芯片的物理分布和rank的数目没有必然的联系。架构
当启动程序时,EAL命令行参数提供了设置内存通道数和rank数的选项。
注意:必须在命令行参数中指定处理器的内存通道数。
下面是不一样的DIMM架构中内存对齐的示例:
本例中,包的大小被设置成16个64字节内存块。
intel 5520芯片有3个内存通道,因此在大部分状况下,不须要在对象之间作填充扩展(除非对象的大小为N*3*64字节)。
当建立一个mempool时,用户能够配置这一特性也可不配。
5.4 本地缓存
以cpu的尿性,多核访问mempool的空闲缓冲队列的开销是很高的,即便是每一个核都只是须要一个CAS原语操做。为了不对mempool队列的太多,mempool的分配程序会保持对每一个核的缓存以及对mempool队列的批量请求,经过缓存就能够减小对实际mempool结构体的锁开销。用这种方式,每一个核均可以彻底访问它本身的空闲对象缓存(有锁)且仅当缓存满的时候,这个核会将一些空闲对象写回mempool队列,而在缓存空的时候会获取更多的对象到缓存。
这就意味着在核上的缓存中有必定量的对象是占着茅坑不拉屎的,在一个核无锁访问mempool缓存到高速缓存中的数据时,会得到性能提高。
高速缓存时由一个小巧的,针对每一个核的指针表组成,它的长度(用起来像栈同样)。
是否缓存mempool的内的对象数据能够在建立mempool的时候打开或者关闭。
最大缓存数据的大小是静态设置的,定义的是编译时变量(CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE)。
5.5 用例
全部内存的分配若是须要高性能的处理就须要使用基于内存池的分配方式。下面是一些例子:
l Mbuf Library
l EAL,日志服务
l 任何程序在数据面须要申请固定大小的对象,这些对象应该并系统重复循环利用。
Mbuf Library
mbuf库提供了分配和释放报文消息缓冲(mbufs)的能力,后者用于dpdk程序存放报文数据。mbufs是保存在mempool中,使用的是mempool Library。
rte_mbuf结构体能够传输网络报文数据或者是普通的控制数据流(用CTRL_MBUF_FLAG标示)。它也能够扩成其它类型。rte_mbuf头结构保持尽量的小,当前是使用了两个缓冲行的大小,最频繁使用的在这两个缓冲行上。
设计报文缓冲
对于报文数据(包括协议头)的存储,能够从两个方面考虑:
前者的好处是分配和释放报文所使用的内存只须要一个操做。在另外一方面,第二种方法更加灵活,且容许将metadata结构体的分配和报文数据buffer的分配彻底分离。
DPDK选用了第一种方法。metadata包含控制信息例如消息类型,长度,报文数据偏移,一个指向mbuf链表中其它mbuf结构体的指针。
mbuf用于传递网络报文,当多个mbuf用于装载一个完整的报文时,它可使用报文缓冲链表。对于巨大的数据帧,多个mbufs经过成员next链接到一块儿来保存报文。
对于刚分配的mbuf,报文段开始的位置在整个消息缓冲开头偏移RTE_PKTMBUF_HEADROOM字节,报文段是缓存对齐的。消息缓冲也用于在系统内不一样的对象间传递控制信息,报文,事件等等。消息缓冲结构体中也使用缓冲指针指向其它的消息缓冲数据区或者是其它的数据结构。
buffer存于mempool
buffer管理使用mempool来分配buffers。所以,它可以确保报文头位于不一样的通道和rank上以便于L3缓存交叉存取。一个mbuf中有一个变量代表这个pool的来源。当使用rte_ctrlmbuf_free(m)或者是rte_pktmbuf_free(m)时,将mbuf归还给所属的pool。
构造函数
报文和控制mbuf构造函数由API提供。rte_pktmbuf_init()和rte_ctrlmbuf_init()函数初始化mbuf结构体的一些一旦用户建立就不会被修改的成员(mbuf类型,所属的pool,buffer开始地址等等)。这个函数式做为回调函数在建立一个mempool的时候传递给函数rte_mempool_create()。
分配和释放mbuf
分配一个新的mbuf须要用户指定从哪一个mempool中分配。对任意新分配的mbuf,它包括一个长度为0的分段。至于数据位置的偏移,在初始化时就设置成了headroom大小(RTE_PKTMBUF_HEADROOM)。
释放一个nbuf意味着将其放回所属的mempool中。mbuf中的内容保存到mempool中时不用修改(做为一个空闲mbuf)。成员在构造mempool时就已经初始化了,不必在分配mbuf时再从新初始化。
当释放一个包含几个分片的报文mbuf时,他们会一块儿释放并放回mempool中。
对mbuf的操做
本库提供了一个函数接口操做报文mbuf中的报文数据,例如:
获取报文数据长度
获取报文数据的开始地址指针
在报文数据前添加数据
在报文数据后添加数据
从buffer中的开始位置移除数据(rte_pktmbuf_adj())
从buffer的尾部移除数据(rte_pktmbuf_trim())。
查阅dpdk的API文档获取细节信息
meta信息
一些被网卡驱动使用和存储在mbuf中的信息可使处理更加简单。例如,VLAN标志,RSS哈希的结果(请看PollMode Driver)和硬件作校验计算的标志。
mbuf也包含了来源网卡端口标志,本mbuf在分片报文存储链表中的编号。
对于分片储存报文链表,只有链表中第一个mbuf保存meta信息。
例如,以RX收包端为例,有IEEE1558报文时间戳机制,VLAN标记和IP层校验。
在TX发包端,也能够将应用程序的一些处理交给硬件来实现(若是硬件支持)。例如,PKT_TX_IP_CKSUM标志容许不作IPv4校验计算。
下面的例子解释了怎么在封装了虚拟可扩展局域网的TCP报文中配置不一样的TX标记:out_eth,out_ip,out_udp,vxlan,in_eth,in_up,in_tcp,payload.
l 计算out_ip的校验和:
mb->l2_len=len(out_eth)
mb->l3_len=len(out_ip)
mb->ol_flags |= PKT_TX_IPV4|PKT_TX_IP_CSUM
设置发送报文的ip层校验为0
这是有标志DEV_TX_OFFLOAD_IPV4_CKSUM的硬件支持的。
l 计算out_ip和out_udp校验和
mb->l2_len=len(out_eth)
mb->l3_len=len(out_ip)
mb->ol_flags |= PKT_TX_IPV4|PKT_TX_IP_CSUM|PKT_TX_UDP_CKSUM
设置out_ip检验为0
设置out_udp在虚拟头中的校验使用rte_ipv4_phdr_cksum()
这是有DEV_TX_OFFLOAD_IPV$_CKSUM和DEV_TX_OFFLOAD_UDP_CKSUM标记硬件支持的。
l 计算in_ip校验和
mb->l2_len=len(out_eth+out_ip+out_udp+vxlan+in_eth)
mb->l3_len=len(in_ip)
mb->ol_flags|=PKT_TX_IPV4|PKT_TX_IP_CSUM
设置in_ip的校验为0
这个和例子1类似的,可是l2_len不同。硬件有DEV_TX_OFFLOAD_IPV4_CKSUM标记的支持。注意,它仅在outer L4校验为0时起效。
l 计算in_ip和in_tcp校验
mb->l2_len=len(out_eth+out_ip+out_udp+vxlan+in_eth)
mb->l3_len=len(in_ip)
mb->ol_flags|=PKT_TX_IPV4|PKT_TX_IP_CSUM|PKT_TX_TCP_CKSUM
这和例2类似,可是l2_len不同。同二,硬件要有DEV_TX_OFFLOAD_IPV4_CKSUM and DEV_TX_OFFLOAD_TCP_CKSUM.注意仅在outer L4校验位0时才工做。
l TCP分片报文
mb->l2_len = len(out_eth + out_ip + out_udp + vxlan + in_eth)
mb->l3_len = len(in_ip)
mb->l4_len = len(in_tcp)
mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM|PKT_TX_TCP_SEG;
硬件支持DEV_TX_OFFLOAD_TCP_TSO。注意只在outer L4检验为0时工做。
这些标志的定义和精确的含义在mbuf的API文档中有讲到(rte_mbuf.h)。也能够查阅testpmd程序源码(特别是csumonly.c文件)获取更多的细节。
直接和间接buffer
一个直接buffer就是彻底独立的且只包含本身的。而一个间接buffer的行为看起来和直接buffer同样,可是实际上这个buffer的指针和数据偏移都是指向另一个直接buffer。当须要拷贝报文或者是分片的时候,这个颇有用。所以间接buffer提供了多个buffer直接复用一样的报文数据。
当使用rte_pktmbuf_attach()将一个buffer附加到一个直接buffer上,则buffer变成间接的。每一个buffer中有一个引用计数器成员,不管是何时一个间接的buffer附加到该直接buffer上,应用计数器都会增长。一样的,不管何时间接buffer分离,直接buffer上的计数器都会减小。当应用计数器的结果等于0时,直接buffer会被释放掉再也不使用。
在处理间接buffer时有一些事要记住。首先,不能将一个间接buffer附加到一个间接buffer上。其次,一个buffer变成间接buffer,它的引用计数器必须等于1,准确的说,它在以前必须不被其它间接buffer引用。最后,不能将一个间接buffer从新附加到一个直接buffer上(除非先detach)。
当作attach/detach操做时,能够直接使用推荐的函数rte_pktmbuf_attach()和rte_pktmbuf_detach()。建议使用更高级的函数rte_pktmbuf_clone(),它会更当心的初始化一个间接buffer且能拷贝多个分段buffer。
因为间接buffer设计成不存储任何实际数据,因此间接buffer的mempool应该配置成减小这部份内存开销。间接buffer的mempool初始化的例子(和直接buffer的例子同样)能够在几个范例应用程序中找到,好比,IPV4广播范例程序。
调试
在调试模式下(CONFIG_RTE_MBUF_DEBUG打开),mbuf库的接口在执行任何操做以前都作安全检查(例如,buffer错误,错误类型等等)
用例
全部的网络应用程序应该用mbufs来传输网络报文。
DPDK包括千兆,万兆,4万兆网卡和虚拟IO网卡设备的轮询驱动。
PMD由运行在用户态的BSD驱动提供的API组成,配置设备和收发包队列。此外,PMD不经过任何中断来直接访问RX和TX描述符(除了网卡链接状态改变的中断以外)实如今应用程序中快速收包,处理和转发。本章讲述了PMD的必要条件,系统设计原则和上层架构以及为以太网PMD的通用扩展API。
必要条件和设定
对于包处理程序DPDK容许两种模式,run-to-completion和pipe-line:
l 在run-to-completion模式下,使用API来轮询指定的网卡收包RX描述符队列。而后报文也就在这个核上处理,而后经过发送API将报文放入网卡TX描述符队列中。
l 在pipe-line模式下,一个core经过API轮询一个或者是多个端口的RX描述符队列。报文收下来以后经过ring传递给其它core。其它的core处理报文,处理完后经过发送API将报文放到端口的TX描述符ring中。
在同步的run-to-completion模式下,每一个逻辑core被分配一个DPDK执行报文处理循环,这个循环包括如下步骤:
l 经过PMD收包API从新获取报文
l 逐一处理收到的报文直到发送
l 经过PMD发送API发送报文
反之,在异步的pipe-line模式下,一些逻辑core专一于收取报文,其它逻辑core来处理以前收到的报文。从新收到的报文在逻辑core之间的交换经过ring来完成。收包循环包括如下步骤:
l 经过PMD收包API收取报文。
l 经过报文队列将收到的报文给处理的逻辑core
报文处理的循环包括如下步骤:
l 从新从报文队列获取收到的报文。
l 处理收到的报文,若是是发送则直到转发为止。
设计原则
以太网PMD的API和架构是如下面的知道原则来考虑设计的。
PMD必须适应全局策略决定了必须运行在上层的用户态。反之,网卡的PMD功能不该该是咱们经过上层全局策略获取的好处的阻碍,或者是不会让应用这些策略变得更糟。
例如,PMD的收包和发包功能有一个轮询报文/描述符的最大值。这就运行一个run-to-completion处理程序使用静态固定值或者是匹配不一样全局循环策略的动态值,例如:
l 以零碎的方式一次一个报文的接收,当即处理且发送
l 接收尽量多的报文,而后处理全部收到的报文,接着当即放松它们
l 接收给定最大数目的报文,处理收到的报文,堆积处理的报文,最后再将其一块儿发送
要达到最优的性能,软件的整体设计选择和纯粹的软件优化技术必须考虑到,且须要在底层的硬件优化特性(CPU缓存特性,总线加速,网卡PCI带宽等等)。在报文的发送中,优化网络报文burst方式的处理性能,就是软件和硬件之间的折中的例子。在初始的版本中,PMD仅支持rte_eth_tx_one功能来想一个队列中一次发送一个报文。在其之上,很轻松就能够实现rte_eth_tx_burst功能,循环调用rte_eth_tx_one函数来逐一发送多个报文。然而,rte_eth_tx_burst功能被PMD有效的执行并最小化了在驱动层的发送开销,经过如下的优化来实现:
l 在多个报文之间调用rte_eth_tx_one函数非应摊成本的开销的共享
l 使用rte_eth_tx_burst函数来一次提交多个报文,能够充分利用硬件特性(预取数据到缓存中,使用网卡的头尾寄存器)来最小化每一个报文的处理cpu时钟周期。例如,避免没必要要的访问发送描述符环形队列的内存读取,或者是系统使用指针数组来准确的匹配缓存line的边界和大小。
l 应用大量提交报文的软件优化技术来减小一些没法避免的操做开销,好比环形队列的回环管理。
以大量报文处理的功能在经过API的引进在PMD中大量的使用。特别是在nic的buffer ring中分配和释放多个报文buffer。例如,mbuf_multiple_alloc函数返回一个rte_mbuf的指针数组,当补充多个描述符到收包的ring中时,这会加速PMD的收包轮询函数。
逻辑core,内存和网卡队列的关系
dpdk支持NUMA以获取更好的性能,处理器的逻辑核和接口利用本地的内存。所以,PCIe接口的mbuf的内存池应该在本地分配。buffers若是可能应该保持在本地处理器来获取更好的处理性能,RX和TX buffer描述符装载的mbuf应该是从本地内存建立的mempool中分配。
run-to-completion模式在报文和数据操做都是在本地内存而不是remote处理器内存性能会更好。这对于pipe-line模式也是同样的,全部的逻辑核都是在一个处理器上。
多个逻辑核最好是毫不共享网卡收包和发包队列,由于这会要有全局的锁和下降性能。
设备标示和配置
每一个NIC端口的配置包括如下操做:
l 分配PCI资源
l 重置硬件的默认状态
l 创建物理链路层和链接
l 初始化统计计数器
PMD API必须提供接口开启和关闭端口的组播特性的功能以及设置和清除端口混杂模式的功能。
一些硬件加速特性必须在端口初始化时经过特定的配置参数分别配置。好比RSS和DCB。
on-eth-fly配置
全部的设备特性就是on-the-fly下启动的和中止(准确的说就是没有中止设备)不须要PMD API为这个目的提供专门的功能。
这些都须要将PCI设备寄存器映射地址来在驱动外部使用指定功能配置这些特性。
为了达到这个目的,PMD API导出一个功能,提供了在设备的驱动以外启动设备的特性的全部的关联信息。这包括PCI vendor ID,PCI device ID,pci设备寄存器映射的地址,驱动的名字。
这方面作的主要好处是给用户彻底自由的选择API来配置,开启,关闭这些特性。
举个例子,参考intel的82576千兆网卡控制器和82599万兆网卡控制器在testpmd程序中IEEE1588特性的配置。
其它特性,例如端口的L3/L4 五元组包过滤特性也能够用一样的方式配置。以太网留控(帧暂停)能够配置在个别的端口上。参考testpmd源码获取细节。还有,L4(UDP/TCP/SCTP)校验网卡加速能够针对特殊的报文打开,只要之歌报文的mbuf是正确的。看hardwareoffload(硬件加速)获取细节。
配置收发包队列
每一个发包队列都是单独配置下列信息的:
l 发送环形队列的描述符个数
l 插槽标识用于在numa架构下从合适的节点分配DMA内存区域
l 发送队列的预取值,主机和回写阀值
l 最小报文发送释放阀值(tx_free_thresh).当发送的报文描述符个数超过这个值,网络适配器应该检查是否已经写回描述符.当值是0是会采用默认值32.这就保证了PMD网卡的发包队列处理了至少32个报文时才去检索完成的报文描述符.
l 最小的RS位阀值.在发送描述符中最小数目的发送描述符用于设置状态报告位RS.注意这个参数只对万兆网卡有效.RS位
l
该部分暂略.
硬件负载均衡Hardware Offload
依赖于驱动的内力,可经过rte_eth_dev_info_get()获取,PMD可能支持硬件负载均衡,像校验和,TCP分片,或者是VLAN插入。
对上述负载特性的支持意味着在rte_mbuf结构体中添加额外的状态位。这些标志的精确描述参看API文档,在Mbuf Library章的Meta Information小节。
轮询驱动API
通常性
默认全部PMD接口都是无锁的,咱们假定它不会在不一样的逻辑核之间并行访问一样的对象。例如,PMD收包函数不会被不一样的逻辑核调用轮询一样的网卡的相同队列。固然,这个函数能够被不一样的逻辑核并行调用从不一样的rx收包队列中取包。上层应用好比遵照这个规则。
通用的报文处理
能够用一个rte_mbuf结构体表明一个报文,这是通用的metadata结构体,包含全部必须的内部信息。包括fields和硬件负载均衡状态位,例如IP头检验和或者是VLAN标记。
Rte_mbuf结构体包含特定的fields,略。
以太网设备API
参见API手册。
DPDK IVSHMEM库在虚拟机之间快速零拷贝数据(host-to-guest 或者是guest-to-guest),经过QEMU的IVSHMEM机制实现。
这个库经过命令行调用QEMU映射几个大页成单独的ivshmem设备。对于guest须要知道每一个给定的ivshmem设备(识别dpdk和非dpdk ivshmem设备)的内部信息,一个metadata成员也被映射到ivshmem段上。Guest应用程序不必将ivshmem设备映射到内存,这个是dpdk抽象层自动识别完成的。
一个典型的dpdk ivshmem用例以下:
在几个虚拟机之间也是一样的工做,提供了host-to-VM或者是VM-to-VM通信。最大数量的metadta成员数为32(默认)且每一个metadata成员可包含不一样的大页(甚至是相同的大页)。惟一的限制就是每一个VM必须和其它对象访问共享的内存(多是host或者是其它的vm)。若是用户想在两个VM之间共享同一个内存区域,每一个VM必须在其metadta成员包含这个内存区域。
下面是对使用IVSHMEM库API的简单引导:
l 调用rte_ivshmem_metadata_create()建立一个新的metadata文件。这个metadata名字用于多个metadata之间作区别。
l 在metadata结构中加入DPDK数据结构体。可经过一下API调用来实现:
n Rte_ivshmem_metadata_add_memzone()来将rte_memzone添加到metadata中。
n Rte_ivshmem_metadata_add_ring()添加rte_ring结构。
n Rte_ivshmem_metadata_add_mempool()添加rte_mempool。
最后,调用rte_ivshmem_metadata_cmdline_generate()来生成用于QEMU的命令行。多个metadata文件(对应多个命令行)能够设置到一个VM上。
注意:只有数据结构体位于DPDK大页内存区域时才能正常工做。若是支持的结构体是经过malloc,mmap,或者是其它非dpdk内存建立的,会致使没法预料的错误,甚至是栈错误。
要成功运行IVSHMEM应用程序,下面的步骤是必需的:
l 编译QEMU的特定版本
源码能够从QEMU网站获取(当前版本1.4.x是支持的,可是1.5.x也能够工做),须要打补丁才能支持啊。补丁再也不DPDK包中,能够到官网上去下。
l 在DPDK建立配置时打开IVSHMEM库开关
在默认配置下,IVSHMEM库是不编译的。要编译IVSHMEM库,要么使用有IVSHMEM目标的编译(例如,x86_64-ivshmem-linuxapp-gcc),或者是设置配置文件中CONFIG_RTE_LIBRTE_IVSHMEM为y。
l 在虚拟机中建立大页内存
Guest应用程序做为DPDK(主)程序运行,那就须要在VM中建立大页内存。这个过程在DPDK入门手册中讲到的同样。
当考虑使用IVSHMEM来共享内存,就须要评估安全问题。对于不信任的guest,IVSHMEM并不合适,由于IVSHMEM本质上是一个访问host处理程序内存的窗口。这对多个VM状况也是同样适用的。当IVSHMEM库共享尽量小的内存区域,颇有可能的,对于这个VM设计的数据也会存在于一个IVSHMEM设备下的其它VM中。因此,任何共享内存出错会影响到host和其它全部共享了该内存的VM。
IVSHMEM应用程序本质上运行就至关于多进程应用程序,因此就须要考虑数据访问的串行行和线程安全。DPDK ring结构是线程安全的,可是,任何客户数据结构的使用者都必须是线程安全的。
和PDDK多进程程序相似,在不一样的进程中访问的数据内存地址是不一样的。
作好是避免在分配的机器以外的机器释放rte_mbuf结构体,换句话说,host分配的就应该host来释放。因此,报文的发送和接收也应该在一样的机器上发生。(要么虚拟机要么物理机)。若是不是这样作可能会致使mempool缓存数据错误。
尽管IVSHMEM机制是零拷贝且有很好的性能。在批量处理上也遵循性能优化中的步骤。
处于性能上的考虑,最好将host进程和QEMU进程分配到不一样的核上以便其互不干扰。若是系统支持NUMA,也须要保证host进程的大页内存和QEMU进程的在同一个NUMA节点上。
对于跨NUMA节点的最佳性能,每一个QEMU核应该和host 核在一样的NUMA节点上。QEMU的虚拟NUMA节点也设置对应到物理NUMA节点。更多关于如何建立DPDK和QEMU numa支持能够看DPDK入门手册和QEMU文档。Dpdk源码包中脚本cpu_lauout.py(在tools目录下)能够用来识别cpu核属于那个numa节点。
QEMU IVSHMEM命令行在虚拟机中启动前须要考虑最后一步。当前,QEMU IVSHMEM设备不支持热插拔,因此一旦建立了就不能添加额外的内存到IVSHMEM设备中。所以,运行IVSHMEM程序的正确顺序是先运行host程序,得到每一个IVSHMEM设备的命令行,而后再以guest应用程序运行每一个QEMU实例。
有一点很重要的须要注意,QEMU一旦启动,它就会获取用于IVSHMEM设备的大页内存。结果就是,若是用户想要关闭或者是重启IVSHMEM host进程,就不是简单的关闭程序了。虚拟机也必须关闭(若是没有,它会一直占有host数据)。
除了物理和虚拟硬件的轮询驱动,DPDK也包括一套软件库容许物理硬件的PMD 聚合到一块儿建立一个逻辑的PMD。
链路聚合PMD库(librte_pmd_bond)支持聚合一组相同速度和双工的rte_eth_dev端口,提供和linux上bond驱动的相同功能,容许主机和交换机之间多个(slave)网卡聚合成一个逻辑接口。新的聚合PMD将按照指定的操做模式处理底层网卡,例如链路主备,故障容错,负载均衡。
Librte_pmd_bond库提供API来建立bond设备,包括配置和管理bond设备和它的slave设备。
注意:librte_pmd_bond库默认是开启的,关闭能够将CONFIG_RTE_LIBRTE_PMD_BOND设置为n再从新编译。
当前的链路聚合PMD库支持4中操做模式:
l Round-Robin(Mode 0):
这个模式提供了报文传送的负载均衡和容错处理,按顺序尝试第一个能够被动设备直到最后。在round-robind模式下运行报文会大量的从设备的队列中移除,这种模式不保证顺序的接收报文,下行的流应该能处理乱序的报文
l Active Backup(Mode 1):
在这个模式下,bond中只有一个slave设备在任什么时候间是活动的,当且仅当主活动的slave错误时,另一个slave才会变成活动状态。所以必须提供容错机制来处理slave错误。整个逻辑bond接口的mac地址在外部可见的知识一个端口以免混淆网络转换。
l Balance XOR(Mode 2):
注意:报文的颜色不一样用于标示不一样的流类别,选择的传输策略计算
这种模式提供了传输负载均和(居于选择的传输策略)和容错。默认策略(2层)使用一个简单的计算,基于报文流源和目的mac地址计以及Bond设备中可用的活动slave设备数目的结果标记报文使用指定的slave传输。2层和3层支持轮询传输策略,使用ip源地址和目的地址来计算出使用的传输slave端口,最后支持的3+4层使用源端口和目的端口,就和源ip、目的ip方式同样。
l Broadcast(Mode 3):
这种模式提供了报文传输过程当中的容错,就是每一个端口都发一遍。
l Link Aggregation 802.3AD(Mode 4):
这个模式支持802.3ad标准的动态链路聚合。它聚合管理一组网卡设备共享一样的速度和双工设置,使用选择的输出平衡策略。
DPDK要支持这种模式须要应用程序知足一些其它要求:
l Transmit Load Balancing(Mode 5):
这种模式提供了自适应的传输负载均衡。它动态的改变传输slave,依据据算的负载。每100ms收集一次统计值并每10ms计算调度一次。
Librte_pmd_bond 聚合的设备和DPDK的以太网PMD接口兼容。Link Bonding库支持在程序启动时建立bond设备,在EAL初始化时使用—vdev选项来实现,等同于程序自动调用rte_eth_bond_create函数。
绑定的设备支持动态的添加和移除slave设备,接口为rte_eth_bond_slave_add和rte_eth_bond_slave_remove。
在一个slave设备添加到绑定的设备以后,能够用rte_eth_dev_stop来stop这个slave设备且使用rte_eth_dev_configure来从新配置,rx和tx队列也能够经过rte_eth_tx_queue_setup和rte_eth_rx_queue_setup来从新配置绑定设备。
9.2.1 链路状态改变中断/轮询
链路绑定设备支持链接状态改变的回调函数注册,使用API rte_eth_dev_callback_register。当绑定的设备状态发生改变时,这个函数会被调用。例如,在一个绑定的设备有3个slave,当一个slave状态变为活动时链路的状态就变为up,或者是全部的slave变为非活动状态时,链路的状态就变为down。当单个的slave状态发生改变时不会触发回调机制,先决条件不知足。若是用户要监控单独某一个slave就必须注册这个slave对应的回调函数。
链路绑定库也支持那些链接状态改变没法触发中断的设备,经过固定时间间隔轮询链接状态来实现,设置接口为rte_eth_bond_link_monitoring_set。默认的轮询间隔为10ms。当一个设备做为slave添加到bond设备中,它须要经过使用RTE_PCI_DRV_INTR_LSC标记来肯定设备是支持中断仍是轮询获取链接状态。
9.2.2 要求和限制
当前只支持添加到bond设备的slave设备均是说一样的速度和双工。Bond设备继承第一个轰动的slave设备属性,其它以后添加的slave设备必须支持那些参数。
在启动bond设备前,bond设备下至少有最小数量即1个slave设备。
和PMD同样,全部的函数都是无锁的,咱们假定这些接口不会被不一样的逻辑核并行调用访问同一个对象。
也要注意在slave设备ijaru到bond设备中以后,PMD接口收包函数不能被slave设备直接调用,由于从slave设备直接读取的报文时不能再从bond设备读取的。
9.2.3 配置
链路bond设备经过函数rte_eth_bond_create建立,这个函数须要指定一个惟一的设备名称,bond模式以及numa节点id以便分配bond设备的资源所在。其它的配置参数是slave设备,主slave,balance XOR模式下用到的用户定义的mac地址和传输策略。
Slave Devices
Bond设备支持最大量的slave设备RTE_MAX_ETHPORTS。网卡设备最为slave添加到bond设备的最大数。Slave设备在添加到bond设备时会根据bond设备的配置从新配置。
Bond会确保当一个slave从bond设备移除时可以返回其原始的mac地址值。
Primary Slave
当bond设备是活动主备模式时,那个活动的slave即为默认的主slave。当且仅当主slave down掉时,其它的端口被用到。若是没有指定主slave则默认是将第一个添加到bond设备的端口设为主端口。
MAC Address
Bond设备能够配置为用户指定的mac地址,这个地址会被全部的或者是部分slave继承,具体依赖于操做模式。当设备处于活动主备模式时,只有主设备有用户指定的mac,全部其它的slave保留原有的mac地址。在模式0,2,3,4中,全部的slave设备配置成bond设备的mac地址。
若是用户没有定义bond设备的mac地址则默认使用主slave的mac地址。
Balance XOR Transmit Policies
有3种支持bond设备在Balance XOR 模式下运行的传输策略:
n Layer 2:基于以太网mac地址的均衡策略是Balance XOR模式的默认传输策略。它通过一个简单的基于报文中源mac地址和目的mac的异或运算,再与slave个数取模获得具体传输用的slave设备的值。
n Layer 2+3:基于源和目的mac地址、ip地址联合计算来决定使用哪一个slave端口来传输报文。
n Layer3+4:IP地址和udp端口号为基础来计算出用哪一个port传输。
全部这些策略支持802.1Q VLAN以太网报文,包括IPv4,IPv6和UDP协议的负载均衡。
Librte_pmd_bond库支持两种方式的设备建立,要么C语言的API接口,要么在程序启动时传入EAL命令行参数来静态的配置bond设备。使用后者不须要对API库有必定的了解就能够建立bond设备。
9.3.1 应用程序使用轮询模式
使用librte_pmd_bond库的API能够在程序内存动态的建立和管理bond设备。这一段实际上上面都讲过了,日,估计这个文档是多我的写的。
能够经过如下api来配置或者是查询配置rte_eth_bond_mode_set/get,rte_eth_bond_primary_set/get,rte_eth_bond_mac_set/reset,rte_eth_bond_xmit_policy_set/get.
9.3.2 经过EAL命令行来使用链路聚合设备
链路聚合设备的能够在程序启动时使用命令行—vdev 选项建立。设备名称必须以eth_bond开头,后面接数字或者是字母。名字且必须是惟一的。每一个设备的多个选项数组以逗号分隔的列表。多个设备选项能够屡次调用—vdev。
例如:
$RTE_TARGET/app/testpmd –c f –n 4 –vdev ‘eth_bond0,bond_opt0=..,bond_opt1=..’ –vdev ‘eth_bond1,……….’
链路聚合EAL选项
略