有哪些比较好的基于dpdktcp如何实现可靠传输的tcp/ip stack

High Performance
Physical limits of NIC, 10M CC, 5M RPS, 1M CPS
Low latency
Kernel bypass, lockless, no scheduling, no interruption
High Expansibility
Easy adaption for any application
Introduction
With the rapid development of NIC, the poor performance of data packets processing with Linux kernel has become the bottleneck. However, the rapid development of the Internet needs high performance of network processing, kernel bypass has caught more and more attention. There are various similar technologies appear, such as DPDK, NETMAP and PF_RING. The main idea of kernel bypass is that Linux is only used to deal with control flow, all data streams are processed in user space. Therefore, kernel bypass can avoid performance bottlenecks caused by kernel packet copy, thread scheduling, system calls and interrupt. Furthermore, kernel bypass can achieve higher performance with multi optimizing methods. Within various techniques, DPDK has been widely used because of its more thorough isolation from kernel scheduling and active community support.
F-Stack is an open source network framework with high performance based on DPDK, include an user space TCP/IP stack(port FreeBSD 11.0 stable), Posix API(Socket, Epoll, Kqueue), Progamming SDK(Coroutine) and some apps(Nginx, Redis) interface.
F-Stack with follow characteristics
Ultra high network performance which can achieve network card under full load, 10 million concurrent connection, 5 million RPS, 1 million CPS.
Transplant FreeBSD 11.01 user space stack, provides a complete stack function, cut a great amount of irrelevant features. Therefore greatly enhance the performance.
Support Nginx, Redis and other mature applications, service can easily use F-Stack
With Multi-process architecture, easy to extend
Provide micro thread interface. Various applications with stateful app can easily use F-Stack to get high performance without processing complex asynchronous logic.
Provide Epoll/Kqueue interface that allow many kinds of applications easily use F-Stack
Currently, there are various products in Tencent Cloud has used the F-Stack, such as DKDNS(DNSPod's authorization DNS server), HttpDNS (D+), COS access module, CDN access module, etc..Intel 推出 DPDK 开发包的意义是什么?
/question/?sort=created
基于intel dpdk的包处理器,相较于基于内核网络协议栈的包处理器,优势和价值在哪里?基于dpdk的包处理性能,是否会比基于内核协议栈高,如果高会高多少,内核网络协议栈的瓶颈又主要在哪里?
市场一句话:Intel推出dpdk,就是为了让自己的硬件产品卖得更好。功能多了,灵活度高了,性能又不赖,谁不愿意买哟?dpdk只适合在x86平台下使用,其达到相当高的性能水平,仰赖的也完全是Intel硬件内部的独特机制(详情参照楼上技术剖析)。这非常明显地抬高了Intel硬件产品的身价。这应该是Intel的主要目的。
需求dpdk在我目前关注的领域(IP的做,非IP的也做;未来三五年的技术验证做,未来三五十年的概念原型也做),主要是用于开发内核尚不具备的新功能。就更新速度而言,内核更新慢,基于dpdk的网络功能更新快。将一种新的网络功能写入内核并纳入发行版linux,需要较为复杂的调试和完善过程。一般要求该功能已经相当成熟可靠,且复杂度不高,适合在内核中运行。而dpdk为厂商提供了更广阔的发挥空间,可以说很好地推动了新机制、新技术的试验和改良
首先dpdk总的来说是一个2层的东西,也就是说本来驱动做的事情放到用户层来做了,并且根据体系结构提供了各种各样的优化,一般只用来做IO,当然也提供了很多3层的库,转发的库,lpm的库等,dpdk并没有提供开源的高性能tcp/ip协议栈。不清楚楼主说的基于内核协议栈的包处理器具体指什么,如果是指linux内核本身的协议栈的话,其实主要还是兼容性和通用性。当然也有一些硬件实现的Tcp offline engine,但是受限于硬件网卡内存的限制,在tcp的并发量和性能上并不会比基于dpdk的高。至于具体性能,其实是可以量化的,10Gbps ,64bytes包长,如果一个包的处理时间大于67ns,那么肯定会丢包,也就是说所有处理基本只能全部在cache里,长时间稳定的不丢包还是很难做到的。至于dpdk的轮询机制,不管有没有包,cpu都是100%,一旦收包的这个线程绑定的cpu被别的线程抢占,那么性能会大幅度下降。dpdk高性能限制非常非常多,配置也基本无法通用,要充分考虑numa+nuio等各种体系结构,一旦cpu配置错了,性能渣得要死。dpdk出来之前,也有很多类似的解决方案,基本原理都是大同小异,ioengine,netmap,ntop 10g系列。不过dpdk和他们相比性能上没有多大优势,配置和操作上比他们都复杂的多,不稳定性也大,但是dpdk有一个他们没法比的巨大优势,就是dpdk支持几乎所有intel 网卡,包括最新出的网卡。如果过几年不想在你的驱动程序里手动添加新的intel网卡支持,那么选择dpdk没错的。还有一个,就是可以用gdb调试了。
首先,DPDK和内核网络协议栈不是对等的概念。
DPDK只是单纯的从驱动拿数据,然后组织成数据块给人用,跑在用户态。功能相当于linux的设备无关接口层,处于socket之下,驱动之上。只不过linux协议栈的这部分在核心态。你说的包处理器,很多时候是不用linux内核协议栈的,而是用专用包处理程序,类似于DPDK加上层应用处理。通常会有些硬件加速器,包处理效率更高些。缺点是一旦用不上某些功能,那些加速器就白费了。而纯软件处理就非常灵活,不过代价就是功耗和性能。纯DPDK性能非常高,intel自己给出的数据是,处理一个包80时钟周期。一个3.6Ghz的单核双线程至强,64字节小包,纯转发能力超过90Mpps,也就是每秒9千万包。不知你有没有看出来,80周期是一个非常惊人的数字?正常情况下,处理器访问一下ddr3内存都需要200个周期,而包处理程序所需要操作的数据,是从pcie设备送到ddr内存的,然后再由处理器读出来,也就是说,通常至少需要200周期。为啥现在80周期就能完成所有处理?我查了下文档,发现原因是使用了stashing或者叫direct cache access技术,对于PCIe网卡发过来的包,会存在一个特殊字段。x86的pcie控制器看到这个字段后,会把包头自动塞到处理器的缓存,无序处理器来干预。由于包头肯定是会被读取的,这样相当于提前预测,访问的时间大大缩短。如果加上linux socket协议栈,比如跑个纯http包反弹,那么根据我的测量,会掉到周期处理一个包,单核双线程在2.4Mpps,每秒两百四十万包,性能差40倍。性能高在哪?关键一点,DPDK并没有做socket层的协议处理,当然快。其他的,主要是使用轮询替代中断,还有避免核心态到用户态拷贝,并绑定核,避免线程切换开销,还有避免进入系统调用的开销,使用巨页等。还有很关键的一点,当线程数大于12的时候,使用linux协议栈会遇到互斥的瓶颈,用性能工具看的话,你会发现大部分的时间消耗在spin_lock上。解决方法之一是如github上面的fastsocket,改写内核协议栈,使包始终在一个核上处理,避免竞争等。缺点是需要经常自己改协议栈,且应用程序兼容性不够。另外一个方法是使用虚拟机,每个特征流只在一个核处理,并用虚拟机隔绝竞争,底层用dpdk做转发,上层用虚拟机做包处理,这样保证了原生的linux协议栈被调用,做到完全兼容应用程序。不过这种方法好像还没有人做成开源的,最近似的是dpdk+虚拟交换机ovs的一个项目。如果你只想要dpdk的高性能加tcp/ip/udp的处理,不考虑兼容性,那么还可以去买商业代码,我看了下供应商的网站介绍,纯转发性能大概在500-1000周期左右一个包。
阅读(...) 评论()基于DPDK开发高性能DNS服务器实践总结
快网CloudXNS授权转发简述
有幸全程参与了基于DPDK[^1]下一代高性能CloudXNS[^2]服务器开发,从未知到慢慢熟悉,其中也走了些弯路也踩过一些坑,一路走来有些感受与心得体会,在此进行梳理下,以对这一阶段做下些小的总结,也可以与同僚们进行交流学**。
上一代XNS服务器是基于Linux内核进行开发,单机性能达到数百万级别QPS[^3],相对于BIND[^4]来说已经高了很多,平常处理正常毫无压力,但在受大量DDOS攻击时服务质量**降低,虽然我们采用了远端清洗与近地防御的安措施,与受攻击时调度其他应急服务器来抗,但增加了服务器与人工干预成本。为了更好的抗DDOS攻击与服务更多的用户,需求单机处理千万级别的替代方案呼之欲出。
单机处理能力千万级别。
性能,性能,性能。(重要的事重复三遍)
稳定压倒一切。(此话不是我说的)
社区活跃,已有商用案例。
按照上述的目标设定需求,要达到单机处理千万级别的只能采用轮询而非中断方式,在市面上的可实现技术方案有DPDK/pf_ring/netmap等。
其中DPDK为Intel公司主推,并有BAT之类的大型公司进行商用,而且也比较适合处理UDP类型协议。经过权衡之下,我们决定采用DPDK进行下一代XNS的替代方案。
用户态开发
死后易重启
无网络协议栈
开发困难,周期长
参考资料相对还匮乏
DPDK核心思想组织结构
DPDK 的组成架构如下图所示,相关技术原理概述如下:
在最底部的内核态(Linux Kernel)DPDK 有两个模块:KNI 与 IGB_UIO。其中,KNI 提供给用户一个使用 Linux 内核态的协议栈,以及传统的 Linux 网络工具(如ethtool, ifconfig)。IGB_UIO(igb_uio.ko 和kni.ko. IGB_UIO)则借助了 UIO 技术,在初始化过程中将网卡硬件寄存器映射到用户态。
DPDK 的上层用户态由很多库组成,主要包括核心部件库(Core Libraries)、平台相关模块(Platform)、网卡轮询模式驱动模块(PMD-Natives&Virtual)、QoS 库、报文转发分类算法(Classify)等几大类,用户应用程序可以使用这些库进行二次开发。
用户态模式下的PMD Driver
去除了中断影响,减少了操作系统内核的开销,消除了IO吞吐瓶颈;
避免了内核态和用户态的报文拷贝;用户态下软件崩溃,不会影响系统的稳定性;
Intel提供的PMD驱动,充分利用指令和网卡的性能;
HugePage和m_buf管理
提供2M和1G的巨页,减少了TLB Miss,TLB Miss严重影响报文转发性能;
高效的m_buf管理,能够灵活的组织报文,包括多buffer接收,分片/重组,都能够轻松应对;
无锁化的消息队列,实际验证,性能充足;
82599 SR-IOV NIC
实现虚拟化下高速吞吐;
Vector Instance /向量指令
明显的降低内存等待开销,提升CPU的流水线效率。
为了使DPDK更好的在我司使用与发扬光大,我大致规划了初期、中期与长期三步走策略实现目标。
实现一个最简单的DNS demo.
网络可达。
Dig示例域名可正确响应。
实现一个高性能高并发的DNS服务
单机性能提高5倍以上。
形成完整DNS产品服务(XNS、public DNS)。
平台与服务逻辑分离。
实现高性能高并发的网络加速平台与应用体系
平台具有可移植性。
可透明承载多种业务(UDP/TCP)服务。
平台与服务物理分离。
可承载其他高级语言与虚拟化。
为了验证其的可行性,我们对它进行了最小原型开发,实现了一个最简单的DNS服务程序,使其网络可达,dig能正确响应。
由于刚开始对DPDK一无所知,为了网络可达首先要面对的问题是服务器IP在哪儿配置的问题(这也许是一些初学者会面对的幼稚问题),还好已有前辈在QQ大致网上了解一些原理与其源码示例,采用其源码examples目录下l3fwd为基础进行最小原型开发demo。
为了使网络可达,我们做了如下开发:
先在simpleDNS服务端中临时配置一个服务IP进行过滤.
在DNS客户端通过手工配置ARP表使得客户端ping/dig操作的请求包可达服务端,
在simpleDNS服务端做解析请求包,如果是DNS请求构造响应包,其他类型如ARP/ICMP请求则通过KNI入接口ingress()重入Linux内核由其来处理后再通过KNI的egress()接口响应给客户端。经过上述编码调试后,最简单的原型验证通过了,为下面的全面开发提供了参考依据。
由于此项目是在基于DPDK进行二次开发,我一般对开源项目的使用原则是:
应使开源项目融入到项目工程中,而不是项目工程融入到开源项目中
因此我对它们进行分3层设计与实现:
内核层主要为Linux内核本身与**igb_uio.ko与rte_kni.ko.
分为DPDK原生库与fastNP扩展库,分别在不同目录进行隔离。
DPDK源码树本身,没有任务的修改,是为了更好的升级、开发与维护。
对DPDK某些接口进行二次封装与业务所需的公共库,一般各种业务应用调用。
业务层业务应用的各种实现,可直接调用fastNP平台层与DPDK原生层的API。
全面开发源码组织管理
为了所有源码可以一键编译、一键打包,编写一套符合所需的Makefile进行源码管理。
fastNP扩展库开发
扩展库源码不在DPDK源码目录中,需要很好的理解DPDK下面mk/目录下的各种Makefile原理,使其的各种编译选项与属性能够传递到扩展库中。
扩展库主要实现如下部分功能:
基础数据结构库。如:高效双链表、用户态RCU接口等。
轻量级用户态协议栈目前主要实现轻量级简易型UDP协议栈,以实现二三层转发为主。
HOOK挂载与处理机制仿造了Linux netfilter框架实现5个点钩子挂载与处理。
高性能日志库参考了目录主流高性能日志与线程安全,实现了一个数百万行打印的高性能日志系统。等等…
业务层开发
第一个应用主要是把原有内核版本的KANS源码移植到用户态的SANSD中。
控制查看命令开发
为了方便对平台与业务层的查看与控制,我们基于Libcmdline库开发了sansctl命令,可支持命令补全等。
发包工具开发
为了能进行千万级别的高性能测试,基于pktgen-dpdk进行开发使其可以构造DNS请求与控制发送速率功能的spktgen,主界面如下图:
抓包工具开发
由于现有tcpdump不能抓取DPDK接管的网卡数据,也在其基础上开发可在DPDK下抓包的spktdump,以便调试与定位。
踩过的坑架构模式选择
DPDK提供了两种模式可供选择:Run-to-completion与pipeline模式。在官网文档与DPDK开发者大会中都提到了这两种模式,但都没说哪种模式更好,要看场景而定。我们在最初设计时,不仅考虑DNS服务器还考虑以后负载均衡设备的使用,选择了可支持这两种模式。
在测试性能时,发现某种情况下不同模式都有优缺点,经常在这两种模式中来回切换测试,造成了一些干扰与浪费了点时间。
编译选项一致
在测试性能时一定使用-O3选项并且编译选项需与DPDK本身app编译选项一致。否则会影响很大的性能。
DPDK本身app编译选项可以在编译目录下的.XXX.o.cmd文件查看到。
变量percore化
所用的全局变量尽量percore化,这样可以防止cache miss。例如统计部分要用percore化,计算或显示时再把他们加到一起,这个也影响不小的性能。
代码逻辑简化
由于业务层代码是从内核版本中移植过来的,老早功能就通过了,但性能一直上不来,后来经过代码review发现很多影响性能点,又重新优化或精简了下代码逻辑,去掉了不少冗余代码。
RCU锁占用性能
扩大RCU临界区
域名压缩占用性能
应答区中的域名不压缩。
有待完善DPDK 缺少配置文件
现在DPDK代码与核数越来越多,依然使用命令行参数的方式进行启动,可配置与阅读性比较差,应该有自己的配置文件进行解析即可。
尤其是网卡、队列、逻辑核配置序列太难配置了,尤其是使用核数比较多的情况。
例如:(0,0,2),(0,1,4),(0,2,6),(0,3,8),(0,4,10),(0,5,12),(0,6,14),(0,7,16),(0,8,18),(0,9,20),(0,10,22),(0,11,24),(0,12,26),(0,13,28)
不知道各位同学知不道有什么国际规范的缩写方式配置,请麻烦告知一下,OK?
pktgen-dpdk驱动bug
当使用pktgen-dpdk进行测试时,频繁的启停可能会使万兆光纤网卡处于DOWN状态,重启命令或reboot系统都不管用,必须对服务器进行冷重启才行,这对测试比较浪费时间或者远程调试操作堪忧。
examples下编码质量参差不齐
DPDK库本身的编码质量还是比较规范统一的,而其examples下的示例代码编码质量参差不齐。
fastNP本身
BOND与多网卡有待支持。
邻居发现与路由功能有待支持。
TCP协议栈有待支持。
虚拟化功能有待支持。
更高级语言功能有待支持。
Libc与系统调用劫持功能有待支持。
经过这一段时间的开发,使得我对DPDK、内存、CPU、用户态网卡驱动有了更深的了解,使得性能达到了万兆网卡线速水平,单机抗攻击能力为1300万QPS,收发平衡能力为1000万QPS的预期目标,总之DPDK框架代码写得还是挺不错的,值得仔细研究,现在我只是对它怎么使用与部分源码有了一定的认识,很多精华部分有待深入剖析。
[^1]: DPDK: intel dpdk(Data Plane Development Kit,数据面开发套件)是 intel 公司发布的一款数据包转发处理套件;
[^2]: CloudXNS: 面向云计算的权威智能DNS。
[^3]: QPS: 每秒查询率(Query Per Second).
[^4]: BIND: Bind是一款开放源码的DNS服务器软件,Bind由美国加州大学Berkeley分校开发和维护的,全名为Berkeley Internet Name Domain, 它是目前世界上使用最为广泛的DNS服务器软件.
近期技术活动 ,期待与你线下相见
「北京、上海」
商务合作,请加微信yunweibang555
责任编辑:
声明:本文由入驻搜狐号的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
今日搜狐热点与《》相关:15132人阅读
开发(166)
linux 相关(186)
网络(254)
http://www.dpdk.org/
Intel开源的x86平台上的报文处理套件。
Kernel &= 2.6.33
glibc &= 2.7
Kernel需要支持UIO、HUGETLBFS、PROC_PAGE_MONITOR
如果使用HPET支持, Kernel需要支持HPET和HPET_MMAP
如果使用HPET timer和电源管理(power management)功能, 需要设置BIOS
HUGETLBFS是指通过使用大的内存页, 减少TLB条目的数量, 提高TLB缓存的命中率, 提高了内存地址转换的效率,从而提高了内存的操作效率。
dpdk中用来存放报文的内存使用的就是HUGEPAGE
下载源码解压。按照doc/build-sdk-quick.txt指示编译,安装。
make config T=x86_64-default-linuxapp-gcc
DESTDIR=/opt/dpdk/
//编译过程中发现有个别结构体重复定义,注释掉就可以了
make install
T=x86_64-default-linuxapp-gcc DESTDIR=/opt/dpdk/
在另一个目录中编译:
make config T=x86_64-default-linuxapp-gcc
O=my_sdk_build_dir
然后在my_sdk_build_dir中直接make, 就在新的目录中完成了dpdk的编译
安装后在安装目录下生成两个目录:
//dpdk开发框架的的全套makefile
x86_64-default-linuxapp-gcc
//dpdk的头文件和对应架构下的链接库
到安装目录下找到kmod/igb_uio.ko kmod/rte_kni.ko
modprobe uio
insmod igb_uio.ko
运行前准备
在运行dpdk应用时需要准备的事项。
设置hugepages
系统启动前,通过内核参数分配内存:
// 分配1024个2M的页
hugepages=1024
// 分配4个1G的页, 64位应用推荐使用1G的页
default_hugepages=1G hugepagesz=1G hugepages=4
在系统运行的情况,通过修改/proc中参数分配:
// 分配24个2MB的页
echo 24 &/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
在系统运行时,直接mount挂载hugepages:
mkdir /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
或者添加到添加到/etc/fstab中,启动时自动挂载:
nodev /mnt/huge hugetlbfs defaults 0 0
1GB的页需要指定页的大小
nodev /mnt/huge_1GB hugetlbfs pagesize=1GB 0 0
加载内核模块
dpdk依赖uio, 提供了igb_uio.ko, 需要将这两个内核模块加载:
sudo modprobe uio
sudo insmod kmod/igb_uio.ko
在dpdk编译后的目录中可以看到dpdk提供的驱动:
[root@localhost kmod]# ls
igb_uio.ko
rte_kni.ko
替换网卡的驱动
在dpdk对网卡的称呼是port, 就是网口。
dpdk的应用程序要使用某块网卡是,需要使用tools/pci_unbind.py将网卡绑定到驱动igb_uio。
依赖lspci命令
使用pci_unbind.py查看网卡状态:
[root@localhost tools]# ./pci_unbind.py --status
//查看网卡状态
Network devices using IGB_UIO driver
====================================
Network devices using kernel driver
===================================
.0 '82545EM Gigabit Ethernet Controller (Copper)' if=eth1 drv=e1000 unused=igb_uio *Active*
.0 '82545EM Gigabit Ethernet Controller (Copper)' if=eth2 drv=e1000 unused=igb_uio
Other network devices
=====================
设置eth2使用igb_uio:
[root@localhost tools]# ./pci_unbind.py --bind=igb_uio eth2
//eth2绑定到驱动igb_uio
查看绑定后的网卡状态:
[root@localhost tools]# ./pci_unbind.py --status
//绑定后的网卡状态
Network devices using IGB_UIO driver
====================================
.0 '82545EM Gigabit Ethernet Controller (Copper)' drv=igb_uio unused=e1000
Network devices using kernel driver
===================================
.0 '82545EM Gigabit Ethernet Controller (Copper)' if=eth1 drv=e1000 unused=igb_uio *Active*
Other network devices
=====================
自动化工具
dpdk中提供了一个脚本(tools/setup.sh), 用于方便的编译以及设置运行环境.
[root@localhost dpdk-1.5.0r1]# source tools/setup.sh
------------------------------------------------------------------------------
RTE_SDK exported as /export/App/ads/dpdk/dpdk-1.5.0r1
------------------------------------------------------------------------------
----------------------------------------------------------
Step 1: Select the DPDK environment to build
----------------------------------------------------------
[1] i686-default-linuxapp-gcc
[2] i686-default-linuxapp-icc
[3] x86_64-default-linuxapp-gcc
[4] x86_64-default-linuxapp-icc
----------------------------------------------------------
Step 2: Setup linuxapp environment
----------------------------------------------------------
[5] Insert IGB UIO module
[6] Insert KNI module
[7] Setup hugepage mappings for non-NUMA systems
[8] Setup hugepage mappings for NUMA systems
[9] Display current Ethernet device settings
[10] Bind Ethernet device to IGB UIO module
使用其它特性
HPET需要BIOS支持:
Advanced-&PCH-IO Configuration -& High Precision Timer
可以从/proc/timer_list中查看HPET是否已经开启:
grep hpet /proc/timer_list
内核选项需要勾选HPET_MMAP
在Fedora、Ubuntu等发行版中, HPET_MMAP默认是disable的, 需要重新编译内核。
dpdk默认是不使用HPET的,因此还需要在dpdk的配置文件(源码config目录下)中设置支持HPET:
CONFIG_RTE_LIBEAL_USE_HPET=n
使用非Root身份运行
dpdk可以使用非root身份运行,需要设置好一下的目录或文件的所属:
hugepage挂在点:
userspace-io设备文件:
/dev/uio0 ...
如果使用HPET:
使用电源管理功能
需要在BIOS中启用Enhanced Intel SpeedStep Technology
Advanced-&Processor Configuration-&Enhanced Intel SpeedStep(R) Tech
还需要在BIOS中启用C3、C6
Advanced-&Processor Configuration-&Processor C3
Advanced-&Processor Configuration-& Processor C6
core isolation – 独占CPU核心
将dpdk应用绑定到特定的CPU上后, 这些CPU还是参与系统调度,承担系统的其它的任务。
可以通过配置Linux的内核参数使dpdk占用的CPU不参与调度,从而使dpdk应用独占CPU。
isolcpus=2,4,6
//核2, 4, 6不参与任务调度
Kernel NIC Interface
dpdk的示例程序中给出了一个KNI(Kernel NIC Interface)示例, 要使用该示例, 需要加载kni模块:
#insmod kmod/rte_kni.ko
这个模块和igb_uio.ko在一个目录,前面已经见过。
使用利用Intel VT-d的IOMMU Pass-Through
TODO: 对IOMMU不了解,这里是猜测
经查Passthrough I/O模型是指在客户机内部能够直接对硬件进行操作, Intel的支持技术叫做VT-d(Virtualization Technology for Directed I/O),AMD的支持技术叫做IOMMU(I/O Memory Management Unit)。这里涉及的应当是dpdk应用运行在虚拟机中的情形, 在虚拟机中的dpdk应用需要能够透过虚拟机直接访问设备硬件。
首先要启用Intel VT技术, 需要设置内核的编译选项:
IOMMU_SUPPORT
INTEL_IOMMU
运行时需要指定内核参数:
iommu = pt
如果编译的内核中没有设置INTEL_IOMMU_DEFAULT_ON, 还需要指定内核参数:
intel_iommu=on
TODO:这一节的内容还需要继续深挖, 特别是虚拟化相关的内容。
dpdk提供了一个统一的环境抽象层(EAL, Environmental Abstraction Layer), 这一层为dpdk应用提供了通用的统一的选项。
./rte-app -c COREMASK -n NUM [-b &domain:bus:devid.func&] [--socket-mem=MB,...]
[-m MB] [-r NUM] [-v] [--file-prefix] [--proc-type &primary|secondary|auto&] [--xen-dom0]
-c: coremask, 指定使用的CPU
-n: Num of memory channels per processor socket
-b: blacklisting of port
--use-device: 只是用指定的网卡, 与-b互斥
--socket-mem: 从每个socket上申请的hugepage内存的大小
-m: 从hugepage申请的内存的大小, 注意如果使用这个选项, 每个socket贡献的内存大小是不确定的
-r: Num of memory ranks
--huge-dir: hugetlbfs挂载位置
--file-prefix: the prefix text used for hugepage filenames
--proc-type: 进程类型
--xen-dom0: 在没有hugetlbfs的Xen Domain0上运行
--vmware-tsc-map: 使用vmware的TSC map代替native RDSTC
--base-virtaddr: 指定虚拟基址
这里涉及到两个内存相关的指标: channels和ranks, 含义不明!!TODO:
rte_eal是核心的基础库, rte_eal+libc是dpdk中其它的lib库的根基。
eal通过dpdk提供的igb_uio.ko或的设备信息,igb_uio是使用了内核的UIO特性, 可以在用户空间访问操作设备.
关于UIO: 参考
eal通过mmap将hugetlbfs映射到进程地址中, ring、buf等使用的内存都来自hugetlbfs
dpdk使用run-to-completion模式进行报文的处理。在进入Data Plane之前,事先将相关资源准备好, 然后作为一个执行单元直接在core上执行。
dpdk还提供了一种pipeline模式作为对run-to-completion模式的补充。pipleline模式中,cores之间通过ring传递报文或者消息,从而可以控制任务的执行阶段, 提高cores的利用率。
dpdk提供的编程的模型是并发的, 并发的数量与CPU的核数相关, 每个核上的执行单元是最小的并发单位。
使用dpdk开发的应用可以看做是多个单独的执行单元分别依附在各自的核心默默的跑着。
dpdk提供了ring等内存结构, 执行单元借助这些数据结构互相传递信息。
dpdk开发环境使用相当简单, 只需要指定两个环境变量RTE_SDK和RTE_TARGET, 和撰写一个dpdk的makefile即可。
通过环境变量指定SDK的路径和系统类型:
export RTE_SDK=/home/user/DPDK
//DPDK安装路径
export RTE_TARGET=x86_64-default-linuxapp-gcc
//系统类型
dpdk提供了一套的Makefile, 正是得益于这套Makefile, 开发环境才得以如此简单。在dpdk项目中需要撰写一个符合dpdk要求的Makefile。
dpdk的Makefile的详细可以使用参考《intel-dpdk-programmers-guide.pdf》 Part2 Development Environment
Hello World
这是dpdk自带的一个示例。
export RTE_SDK=/opt/dpdk-1.5
export RTE_TARGET=x86_64-default-linuxapp-gcc
也可以在Makefile中重置RTE_SDK, 例如在文件开始出添加一行:
export RTE_SDK=/export/App/ads/dpdk/dpdk-1.6.0r1
/root/dpdk-1.6.0r1/examples/helloworld
[root@localhost helloworld]# ls
项目的Makefile:
include $(RTE_SDK)/mk/DPDK.vars.mk
# binary name
APP = helloworld
#指定应用名称,编译得到的程序将会使用这个名字
# all source are stored in SRCS-y
SRCS-y := main.c
#指定源文件
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
include $(RTE_SDK)/mk/DPDK.extapp.mk
#include &main.h&
/***************** lcore_hello是每个执行单元的工作内容
******************/
static int
lcore_hello(__attribute__((unused)) void *arg)
unsigned lcore_
lcore_id = rte_lcore_id();
printf(&hello from core %u\n&, lcore_id);
MAIN(int argc, char **argv)
unsigned lcore_
ret = rte_eal_init(argc, argv);
if (ret & 0)
rte_panic(&Cannot init EAL\n&);
/*** 将工作内容下发到其它的执行单元 ***/
/* call lcore_hello() on every slave lcore */
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
rte_eal_remote_launch(lcore_hello, NULL, lcore_id);
/*** 当前执行单元的工作内容 ***/
/* call it on master lcore too */
lcore_hello(NULL);
/*** 等待所有的执行单元结束 ***/
rte_eal_mp_wait_lcore();
make O=`pwd`/../out
O=指定输出路径, 如果不指定默认是当前路径下的build目录
[root@localhost build]# ls -R
helloworld
helloworld.map
_postbuild
_postinstall
_preinstall
helloworld
helloworld.map
echo 24 &/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
mkdir /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
sudo modprobe uio
sudo insmod kmod/igb_uio.ko
./helloworld -c 3 -n 1
[root@localhost build]# ./helloworld -c 7 -n 1
EAL: Detected lcore 0 as core 0 on socket 0
//CPU核心检测
EAL: Detected lcore 1 as core 1 on socket 0
EAL: Detected lcore 2 as core 2 on socket 0
EAL: Skip lcore 3 (not detected)
EAL: Skip lcore 63 (not detected)
EAL: Setting up memory...
EAL: Ask a virtual area of 0x2097152 bytes
EAL: Virtual area found at 0x7f056fe00000 (size = 0x200000)
EAL: Ask a virtual area of 0x2097152 bytes
EAL: Virtual area found at 0x7f056fa00000 (size = 0x200000)
EAL: Ask a virtual area of 0x bytes
EAL: Virtual area found at 0x7f056ec00000 (size = 0xc00000)
EAL: Ask a virtual area of 0x2097152 bytes
EAL: Virtual area found at 0x7f056e800000 (size = 0x200000)
EAL: Ask a virtual area of 0x2097152 bytes
EAL: Virtual area found at 0x7f056e400000 (size = 0x200000)
EAL: Requesting 10 pages of size 2MB from socket 0
EAL: TSC frequency is ~2459655 KHz
EAL: WARNING: cpu flags constant_tsc=yes nonstop_tsc=no -& using unreliable clock cycles !
EAL: Master core 0 is ready (tid=)
EAL: Core 2 is ready (tid=6d3fd700)
EAL: Core 1 is ready (tid=6dbfe700)
hello from core 1
//执行单元的工作结果
hello from core 0
hello from core 2
从运行结果的输出可以看到,启动时首先会检测设备的CPU核心数(检测0-63,如果存在就显示Core的位置), 然后申请内存等, Core就位后开始执行单元的执行。
首先到dpdk的安装目录下查看一下dpdk提供的内容:
[root@localhost dpdk-1.5]# ls
x86_64-default-linuxapp-gcc
其中mk目录下dpdk提供的一套makefile, 在这些makefile的辅助下, 项目的顶层Makefile变得非常整洁。
x86_64-default-linuxapp-gcc对应平台上的开发接口。
[root@localhost x86_64-default-linuxapp-gcc]# ls
编译得到dpdk的应用程序
include: dpdk对外提供的接口文件(.h文件)
dpdk的相关内核模块
dpdk的静态库文件(.a)
这里关心的是include目录中的.h文件中都提供了哪些接口, 分别作什么用途。intel-dpdk-programmers-guide.pdf做了分类说明。
详细内容可以查看
dpdk提供了对网卡进行操作的接口, 关于网卡的知识可以从这里获取Intel官网上获取。
rte_eal_init(int argc, char **argv)
//EAL的初始化,在master core上运行
rte_pmd_init_all
rte_eal_pci_probe
rte_lcore_count
rte_eth_dev_count
rte_eth_macaddr_get
rte_eth_dev_configure
//设置网卡的接收队列和发送队列数目, 以及硬件特性
rte_lcore_is_enabled
rte_lcore_to_socket_id
rte_mempool_create
rte_eth_tx_queue_setup
rte_eth_rx_queue_setup
rte_eth_dev_start
rte_eth_promiscuous_enable
rte_eth_link_get_nowait
rte_ring_create
rte_eal_mp_remote_launch
rte_lcore_id
rte_ring_dequeue_burst
rte_pktmbuf_mtod
rte_eth_rx_burst
rte_prefetch0
rte_be_to_cpu_16
rte_jhash_2words
rte_ring_enqueue
RTE_PER_LCORE
《intel-dpdk-programmers-guide.pdf》给出了一些性能优化建议
在data plane操作内存的时候, 使用dpdk的api, 不要使用libc
例如: rte_memcpy – memcpy rte_malloc – malloc
降低cache miss
通过使用RTE_PER_LCORE
均衡Memory Channels
使用dpdk ring进行核间通信
Poll Mode Driver (PMD)
低延迟与高吞吐之间的延迟
控制每次轮询网卡时处理的报文的数量
锁和原子操作
在data plane避免使用锁
使用per-lcore variables 使用RCU算法替代rwlocks
使用inline函数
使用分支预测
if (likely(x&1)) XXXX;
设置CPU类型
dpdk支持对特定的CPU架构进行优化
通过CONFIG_RTE_MACHINE指定CPU特性
对虚拟化的支持
DPDK对虚拟化提供了比较全面的支持。可以用于虚拟机中。
对比pf_ring
直观感觉,dpdk的定位是sdk, 提供了更多的支持库, 自成体系, 绑定在intel平台上。pf_ring定位是高效的抓包工具, 支持的硬件更多一些。
intel-dpdk-programmers-guide.pdfintel-dpdk-getting-started-guide.pdf
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:874045次
积分:10464
积分:10464
排名:第1639名
原创:62篇
转载:806篇
评论:31条
(1)(1)(4)(1)(4)(1)(1)(10)(1)(1)(4)(2)(3)(5)(16)(16)(11)(38)(12)(21)(18)(7)(18)(6)(8)(2)(4)(10)(4)(9)(11)(4)(8)(7)(55)(51)(23)(69)(49)(74)(42)(59)(51)(23)(40)(3)(3)(2)(12)(7)(36)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'}

我要回帖

更多关于 伪代码实现tcp服务器 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信