资讯详情

资讯详情

基于DPDK的Open vSwitch:从内核瓶颈到用户态10倍转发

简介这是一份基于DPDK的Open vSwitch技术概述文档面向数据中心网络、SDN/NFV以及高性能数据面开发与运维人员。文档从原生OvS依赖内核数据路径、快速路径与慢速路径分工的局限讲起说明DPDK用户空间库和轮询模式驱动如何绕过内核协议栈、降低中断开销从而大幅提升转发吞吐。内容进一步展开OvS-DPDK的高级架构介绍netdev端口模型、dpif-netdev用户空间转发、ofproto OpenFlow交换与ovsdb控制面协作并详细解析EMC、dpcls、ofproto分类器组成的三级交换表匹配流程最后结合电信运营商等场景给出性能对比。资源共1个PDF文件压缩包约1.67MB单文档便于通读已有195人学习下载。阅读后既能建立OvS-DPDK的整体架构认知也能理解数据包从接入到转发的完整查找路径为后续学习源码、搭建DPDK实验环境或优化虚拟交换机性能打下基础。1. 基于DPDK的Open vSwitch到底能带来什么从10倍吞吐到部署取舍做网络虚拟化的人绕不开基于DPDK的Open vSwitchOvS-DPDK。常规的Open vSwitch把数据转发放在内核态在云内互联场景够用但一旦遇到电信级节点或互联网数据中心的高速率转发Linux协议栈就成了瓶颈。DPDK提供轮询模式驱动和用户态库把网卡收发包直接交给用户空间处理省掉中断和协议栈遍历。两者集成后转发吞吐量能比原始OvS提升约10倍在某些绑核和超线程配置下能到12倍。这份PDF概述来自一个活跃的开源社区用图例把OvS-DPDK的高层架构、三张交换表层次、支持特性、性能对比讲得比较完整适合刚接触OvS-DPDK的开发者、做NFV底层选型或者正在排障的同行阅读。接下来我按架构、查表、功能和验证的顺序拆一遍最后给出实际部署时容易踩的坑。2. 原始OvS跑不快的原因内核数据路径与上下文切换的成本2.1 快速路径和慢速路径第一条数据包总是更慢原始OvS通常通过内核空间数据路径转发数据包这段路径里有一个“快速路径”流表负责对已识别流的后续报文做简单转发。当一个流的第一条数据包到达时它无法命中快速路径中的任何条目于是被上抛到用户空间的守护进程处理这就是业界常说的“慢速路径”。守护进程分析完这条流的去向之后会把结果写回到内核流表同一条流的后续数据包就可以直接在快速路径里处理不再往返用户空间。这种设计巧妙之处在于对大多数数据包而言它避免了内核和用户空间之间昂贵的上下文切换。但代价也很明显——所有查表和转发都要先穿过Linux网络协议栈收包、路由、netfilter钩子、协议栈分发等每一步都有开销。电信运营商场景或者大规模互联网数据中心里端口速率一旦上到25G、40G这种转发带宽就吃不消了。PDF里也明确指出原始OvS的吞吐受限于Linux协议栈的转发能力不适用于高速率数据包处理。想验证现在的OvS到底走的是哪条数据路径可以先用ovs-dpctl看一眼内核侧的流表状态sudo ovs-dpctl dump-flows如果输出里能看到类似recirc_id(...)eth(...)ip(...) actions:...的大量条目说明当前数据包在快速路径中匹配得很舒服。如果输出为空或者只有零星几条那就要怀疑流量压根没被内核数据路径接住所有包都在走慢速路径性能一定难看。需要提醒的是这条命令只对内核数据路径有效如果已经切到DPDK用户态数据路径它返回的就不是真实工作状态具体见后面几章。2.2 DPDK为什么能绕过协议栈轮询模式驱动的思路DPDK的核心思想是把“网卡中断 协议栈收包”这种通用模型换成“用户态轮询 直接DMA”。它提供一系列轮询模式驱动PMD应用通过PMD直接和物理网卡的收发队列打交道网卡收到数据后直接放到用户态可访问的内存里应用不断轮询队列有包就取没包就继续转。这样做的结果就是内核网络协议栈彻底被绕开了中断处理也基本消失CPU不再为了每个数据包发生打断和上下文切换转发时延和吞吐量自然就上去了。但这里有个前提不是所有网卡都能这样干。网卡必须支持DPDK的PMD驱动常见的那几款Intel 82599、X540、X710以及部分Mellanox网卡在特定固件和驱动组合下才行。如果你的网卡不在支持列表里OvS-DPDK即使编译通过也无法把物理口拉起来。所以拿到这份PDF后第一步不是急着编译而是确认你的硬件走不走PMD路线。另一个绕不开的前提是CPU。DPDK推荐把处理数据包的CPU核隔离出来独占使用不参与系统调度。否则你刚把PMD线程绑在一个核上内核又把某个任务塞到这个核上性能就会出现随机抖动。大页内存也基本是必选项DPDK的收包内存需要从大页池中分配否则TLB缺失会吃掉不少性能。这些点PDF里没有展开但都是实际部署时绕不过去的硬条件。2.3 检查当前OvS是否已经走了DPDK数据路径OvS从2.6版本开始支持通过dpdk-init配置项来启用DPDK数据路径。检查当前实例是否初始化成功最简单的方式是用ovs-vsctl直接读ovs-vsctl get Open_vSwitch . dpdk_initialized输出为true说明vswitchd已经成功初始化DPDK输出为false或者报错说明数据路径还是传统的内核模式。老版本OvS可能不认识这个配置项需要你在启动vswitchd之前先设置一下ovs-vsctl set Open_vSwitch . other_config:dpdk-inittrue这个命令的作用是把DPDK初始化开关写进ovsdb的配置里vswitchd启动时读取这个值再去初始化大页、绑定网卡。需要特别注意的是dpdk-init必须在ovs-vswitchd启动之前设置如果vswitchd已经跑起来再回头设置它不会自动重新初始化通常要重启ovs-switchd服务。很多新手在这里翻车明明看到了dpdk-inittrue却被告知“not initialized”原因就是设置时机晚了。3. OvS-DPDK架构拆解netdev-dpdk、dpif-netdev与ofproto的分工3.1 四个关键组件谁负责转发、谁负责控制OvS-DPDK的高级架构里最底层是各种“网络设备”OvS里统称为netdev。普通的netdev由内核网络栈驱动而netdev-dpdk是DPDK加速过的网络设备。它通过三个独立的接口把转发I/O加速起来librte_eth负责物理网卡的收发librte_vhost负责和虚拟机里的virtio-net通信librte_ring则提供基于内存环的收发通道通常用于本机内快速传递数据包。物理接口和虚拟接口最终都连接到一个虚拟交换机上。在这之上dpif-netdev是用户空间转发引擎。它管理PMD线程每个PMD线程负责一部分网卡队列的轮询和转发。ofproto层实现OpenFlow交换逻辑对外通过OpenFlow协议和SDN控制器通信对内下发流表规则。ovsdb-server则维护OvS实例的交换表信息和配置并把这些状态同步给SDN控制器。这几层各司其职控制面和数据面是分开的这也是SDN语义能够在OvS上落地的基础。3.2 数据包从物理口到虚拟机librte_eth、librte_vhost与librte_ring一次典型的转发是这样发生的物理网卡收到报文后PMD线程通过librte_eth把报文从网卡队列搬到用户态内存dpif-netdev拿到报文后提取头部字段生成标识符去三张交换表里查找匹配找到之后如果出口是虚拟机数据包会通过librte_vhost写进vhost-user socket对应的共享内存虚拟机里的virtio-net驱动直接从这个内存中取走数据。整个过程没有一次穿越内核协议栈。如果两个虚拟口之间通信DPDK还可以走librte_ring直接内存拷贝连物理网卡都不经过时延更低。这也解释了为什么OvS-DPDK在“VM到VM”场景下能把性能拉起来——传统方案里两个虚拟机通信要过内核协议栈两次现在直接在用户态内存里转走了。3.3 把OvS-DPDK跑起来编译安装与初始化数据路径PDF里提供了两个可下载分支主分支和2.6分支并且附带了对应安装文档。一般编译安装OvS-DPDK的步骤可以浓缩成三步设置DPDK环境变量、配置并编译OvS、初始化DPDK。常见做法是这样的export RTE_SDK/opt/dpdk export RTE_TARGETx86_64-native-linuxapp-gcc cd /opt/ovs ./configure --with-dpdkstatic make -j4 make installRTE_SDK指向DPDK源码根目录RTE_TARGET是编译目标架构x86_64平台基本都用这套。--with-dpdkstatic让OvS静态链接DPDK库链接后的vswitchd二进制不依赖运行时的动态库部署到其他机器时不用再带着DPDK库走。如果你已经通过make install把DPDK装到了系统路径也可以不带绝对路径直接写--with-dpdk。编译完成后设置启动开关并启动服务ovs-vsctl set Open_vSwitch . other_config:dpdk-inittrue systemctl restart ovs-vswitchd注意这里的systemctl restart只是常见做法之一具体看你用的发行版服务管理方式。启动后可以用前面的dpdk_initialized确认状态。如果状态为false多半是DPDK大页没配置好或者网卡驱动没绑定。后面避坑章节会详细讲。4. 交换表的三个层次EMC、dpcls与ofproto分类器的查找流程4.1 EMC完全匹配五元组精确命中性能最高数据包进入OvS-DPDK后会从头部字段计算出一个唯一标识符然后依次和三个交换表匹配。第一个是EMC完全匹配缓存它只支持精确匹配也就是说数据包的源IP、目标IP、源端口、目标端口、协议这五元组必须和表项完全一致才算命中。EMC的表项数量有限但它提供的是最快的处理路径适合已经识别出来的热流。只要这条流没有超过EMC容量上限后续所有同五元组的包都能以最高速度转发。4.2 dpcls通配符匹配折中方案如果EMC未命中数据包会落到dpcls数据路径分类器。dpcls的表项比EMC多得多排列在多个子表里支持通配符匹配。比如你可以指定目标IP和端口而允许任意源IP只要数据包符合这个通配范围就算命中。dpcls的吞吐量大约是EMC的一半但好处是能容纳更多流。一条流在dpcls中被匹配后OvS会把它的精确五元组写进EMC让这条流后续的包走最快路径。这是OvS能在大流场景下保持高性能的关键设计。4.3 ofproto分类器慢速路径的兜底性能比EMC慢10倍以上如果dpcls也未命中数据包会进入ofproto分类器。这个分类器连接着OpenFlow控制器控制器可以决定这条流该怎么处理。这是最慢的一条路径PDF里明确说它的性能比EMC慢10倍以上。但这个慢是值得的因为ofproto分类器里的匹配结果会反过来通知更快的表建立新条目让同一流的后续数据包不用再走到这层。换句话说任何新流的第一包都不得不挨一次慢速路径的毒打之后才能享受快速路径的福利。用一张表对比会更清楚交换表匹配方式表项规模相对性能典型作用EMC完全匹配五元组精确有限最高热流高速转发dpcls通配符匹配较多多子表约为EMC一半中等规模流折中ofproto分类器OpenFlow规则匹配最大比EMC慢10倍以上新流首包控制平面决策4.4 查看本机交换表统计pmd-stats-show想确认系统里三张表的工作状态可以使用OvS自带的PMD统计接口ovs-appctl dpif-netdev/pmd-stats-show输出会显示PMD线程的信息以及每个线程收发包的累计次数。我们可以关注其中“Packets”数量在打流时是否大幅增长确认流量确实走的是用户态转发路径。这个命令比单纯看dpdk_initialized更有说服力因为即使DPDK初始化成功也可能因为配置错误导致流量压根没走PMD而是走了回退路径。习惯上我会在测试前后各取一次统计值用差值计算每秒转发包数作为性能标尺。需要注意的是pmd-stats-show只能反映用户空间PMD线程的状态它看不到EMC、dpcls各自命中多少包。想看更细的三表命中统计要打开调试日志或者用dpif-netdev的调优接口这些在PDF里没有展开但属于进阶排障方向。5. 常见问题与避坑特性清单、性能数据和四条排障记录5.1 支持的功能特性vHost user、隧道、QoS、连接跟踪等等OvS-DPDK在2.6分支时期已经带上了一大批实用功能PDF里列出的清单到今天看仍然很关键。我把它们整理成一组便于对照的项功能类别具体能力虚拟接口vHost-user、vHost重连、vHost多队列、vHost-user NUMA感知隧道VxLAN、GRE、Geneve 本地隧道二层/三层VLAN、MPLS、巨帧流表与控制连接跟踪、Ingress/Egress QoS策略运维与调试DPDK vHost与扩展统计、DPDK pdump、链路聚合、链路状态硬件与平台VFIO支持、SDN控制器/云平台对DPDK端口的识别这些特性意味着OvS-DPDK不只是能转发物理网卡数据还可以作为NFV底座支撑多租户网络、服务链和虚拟防火墙等场景。vHost多队列和NUMA感知对性能影响很大尤其是高并发VM场景如果没开启多队列虚拟机单队列吞吐会卡在单核上。连接跟踪功能则让你可以用它做有状态网关不再需要额外串接专门的防火墙设备。5.2 性能数据两个典型场景下的倍率PDF里给出了一组对比数据测试场景分两种Phy-OvS-Phy也就是物理网卡进来从OvS转发出去再回到物理网卡以及Phy-OvS-VM-OvS-Phy数据包进到虚拟机再出来。结论很直观Phy-OvS-Phy场景下OvS-DPDK比原始OvS提升约10倍在启用超线程技术也就是一个物理核心上用两个逻辑线程标记为1C2T时提升能到约12倍Phy-OvS-VM-OvS-Phy场景的提升约9倍。这个“10倍”经常被拿来宣传但我要提醒一句它是在特定硬件、特定报文长度、特定转发规则下测出来的最高值。真实业务里如果你的流表规则复杂或者有连接跟踪、QoS策略叠加增益会打折扣。用这份性能数据去做方案选型时建议只把它当作上限参考而不是保证值。PDF末尾提到完整的测试配置在某个开放式网络平台性能报告里真正较真的同学该去翻那份报告看细节。5.3 四条踩坑记录现象、原因、解决下面四条是我在复现OvS-DPDK过程中踩过或者见同行踩过的坑每一条都按“现象→原因→解决”来写坑一编译时报找不到 dpdk/rte.hconfigure卡住。现象执行./configure时输出checking for dpdk/rte.h... no然后直接退出。原因configure脚本去RTE_SDK指定的目录下找DPDK头文件但RTE_SDK没有export或者路径指向了DPDK安装后的目录而不是源码目录。DPDK的头文件布局和安装路径并不总是兼容configure的搜索逻辑。解决先把环境变量补上export RTE_SDK/opt/dpdk再确认该目录下确实存在lib/librte_eal/common/include/rte_version.h。如果仍找不到就改成./configure --with-dpdk/opt/dpdk给绝对路径。还有个常见坑是不同DPDK版本的头文件位置不一样比如DPDK 17.11之后rte_version.h挪到了lib/librte_eal/include/configure的搜索路径若固定写死就会失败。坑二vswitchd起来了dpdk0端口状态一直down。现象ovs-vsctl show里能看到dpdk0端口但state一直是down不上线。原因网卡的PCI设备没有绑定到DPDK的PMD驱动上。DPDK有两种主流驱动igb_uio和vfio-pci。如果内核自带的驱动比如ixgbe还占着网卡DPDK PMD拿不到设备。解决用DPDK自带的绑定工具把网卡切到VFIO比如dpdk-devbind.py -b vfio-pci 0000:03:00.0。先确保vfio-pci模块加载modprobe vfio-pci。绑定后重新启动vswitchd再用ovs-vsctl show看状态。注意别把管理口绑错绑了之后该网卡上跑的控制面连接会立刻断开。坑三虚拟机配了vHost-user但网络不通。现象虚拟机内看不到网卡或者能看到但ping外网不通。原因vHost-user有两种模式客户端和服务端socket路径两端必须匹配。我一般让OvS做服务端QEMU客户端去连接sock路径。如果路径不一致或者socket文件的属主不是运行QEMU的用户虚拟机连不上。另外vHost-user需要从大页内存中分配共享内存如果系统大页配置不足QEMU启动时会给一堆“Failed to allocate shared memory”的错误。解决先用ovs-vsctl show确认vhost-user socket路径然后chown qemu_user:qemu_group /var/run/openvswitch/vhost-user-1修改属主。再检查大页cat /proc/meminfo | grep HugePages_Total确保总量不低于虚拟机内存大小并且在QEMU启动参数里用-object memory-backend-file,idmem,size...,mem-path/dev/hugepages指定大页路径。坑四性能不升反降比原始OvS还差。现象同一台机器上跑OvS-DPDK的转发吞吐低于内核态OvS甚至打流时CPU使用率飙高。原因多半是PMD线程没有绑核或者跨NUMA访问了网卡和内存。DPDK推荐把PMD线程绑在物理核上并且网卡所在的NUMA节点和PMD线程所在的NUMA节点要一致否则DMA内存和CPU访问内存跨组建性能会崩。另外没有为大页保留足够的内存也会让收包丢包率上升打出来的数字自然难看。解决设置PMD核掩码例如让性能核2、4、6、8为PMD线程使用ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask0x154。再用numactl --membind0 --cpunodebind0方式启动vswitchd保证内存分配集中在同一NUMA节点。最后确认大页数量echo 1024 /proc/sys/vm/nr_hugepages。这几样都做了性能才可能接近PDF里展示的倍率。6. 验证OvS-DPDK真正生效三个命令行技巧与压测习惯6.1 确认dpdk_initialized为true且端口类型正确第一个技巧是形成一套固定的“三连查看”ovs-vsctl get Open_vSwitch . dpdk_initialized ovs-vsctl show ovs-vsctl list-ports br0第一句确认DPDK初始化状态第二句看端口是否存在第三句列出桥上所有端口。如果端口列表里有dpdk0这样的名称那么OvS已经把这个口当成netdev-dpdk管理了。注意只有dpdk_initialized和端口类型都满足时才能认定数据路径真的切换到了DPDK。我见过有人只看一两个字段就宣布“已经上DPDK了”结果实际流量还是走内核路径白忙一场。6.2 用PMD统计确认用户态转发在干活第二个技巧是抓PMD线程的真实收发包计数。先记录一次当前值再用测试流量打一段时间之后再取一次ovs-appctl dpif-netdev/pmd-stats-show对比两次输出中PMD线程的包计数差值如果差值基本等于打的测试流量说明这条路真实在跑。如果差值很小但ovs-dpctl dump-flows里却有大量活动流表那就要怀疑流量其实走了内核数据路径DPDK只是空初始化。这个排查方法我每次排障都用比看一堆抽象指标直接得多。6.3 用基线压测建立自己的性能标尺第三个技巧是建立自己的硬性压测基线。别拿PDF里的10倍数据当作承诺建议在你自己机器上分别测两次一次用原始OvS跑同样流量一次用OvS-DPDK跑然后对比。我最常用的是用打流工具比如pktgen或iperf分别从两个端口打同一批五元组流量各跑30秒记录平均包速率。重点看小包64字节小包最能体现转发管线极限。从那以后我每次切数据路径都强制走一遍这套验证序列先看初始化状态再看PMD计数最后才信性能报告。别人说“性能提升多少倍”时我也一定会要求对方给出硬件配置、报文大小、CPU绑核和流表复杂度缺一个都不算数。希望这份拆解能帮你在OvS-DPDK上少踩几个坑愿你的转发面能真正跑出该有的速度。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →