开通VIP,畅享免费电子书等14项超值服
首页
好书
留言交流
下载APP
联系客服
2023.07.26湖南
前言:开源(OpenSource,开放源码)被非盈利软件组织(美国的OpenSourceInitiative协会)注册为认证标记,并对其进行了正式的定义,用于描述那些源码可以被公众使用的软件,并且此软件的使用、修改和发行也不受许可证的限制。
OVS-DPDK(OpenvSwitchwithDPDK)是一种高性能的虚拟交换机,它将DPDK(DataPlaneDevelopmentKit)和OpenvSwitch技术相结合,用于在虚拟化环境中加速数据平面处理。OVS-DPDK采用用户空间数据包处理模式,利用DPDK提供高效、低延迟的数据包处理功能,并且可以与传统的内核态网络协议栈进行无缝衔接。
通过使用OVS-DPDK,可以实现更高的吞吐量和更低的延迟,从而提升网络性能。同时,OVS-DPDK还支持灵活配置和管理网络服务,并且可以与其他开源软件如OpenStack等集成使用。因此,在云计算、SDN、NFV等领域中得到了广泛应用。
要使用ovs-dpdk,需要在node上构建DPDK并使用相应的DPDKflag重新构建ovs。OVS-DPDK需要从源码编译,因为高度依赖内核等所在机器的环境,并需要配置很多参数以达到高性能。这意味着很难提供一个ovs-dpdkdocker镜像来满足所有情况。
OVS-DPDK需要大页内存作为资源。由于DPDK会剥夺系统对nic的控制权,我们需要一个ovs-dpdk专用的nic来传输容器网络,另一个nic用于普通主机网络。
普通Pod的ovs网络是在pod和ovs端口之间放置了一个veth对。veth的一端移动到容器网络命名空间。不能用OVS-DPDK做到这一点。当我们请求一个新的DPDK端口时,我们最终会在/var/run/openvswitch/这样的目录中得到一个类似vhost-user套接字文件的东西。它不能在命名空间之间移动,它必须被挂载到pod中就像一个普通的文件(由Userspace-CNI提供的功能)。所以不能使用OVS-DPDK作为默认网络。Pod对K8SAPI不可达,K8S不能对pod进行健康检查。因此,需要依赖Multus来连接多个网络。Kernel-OVS仍然是默认网络。此外,Multus允许为Pod提供OVS-DPDK网络。这是同一个OVS实例,但是DPDKport位于另一个支持DPDK的bridge上。
ovs-dpdk创建br和port,ovs集成网桥类型更改为netdev,端口类型更改为dpdkvhostuser并设置其他ovs-dpdk参数。
1.1准备工作
[root@backendcloud-fedora27~]#dnfgroupinstall"DevelopmentTools"[root@backendcloud-fedora27~]#dnfgroupinstall"Virtualization"[root@backendcloud-fedora27~]#dnfinstallqemu[root@backendcloud-fedora27~]#dnfinstallautomaketunctlkernel-toolspciutilshwlocnumactl[root@backendcloud-fedora27~]#dnfinstalllibpcap-devel[root@backendcloud-fedora27~]#dnfinstallnumactl-devel[root@backendcloud-fedora27~]#dnfinstalllibtool1.2编译DPDK
[root@backendcloud-fedora27~]#tarxfdpdk-17.08.1.tar.xz[root@backendcloud-fedora27~]#lsanaconda-ks.cfgdpdk-17.08.1.tar.xzdpdk-stable-17.08.1[root@backendcloud-fedora27~]#cddpdk--bash:cd:dpdk-:Nosuchfileordirectory[root@backendcloud-fedora27~]#cddpdk-stable-17.08.1/[root@backendcloud-fedora27dpdk-stable-17.08.1]#exportDPDK_DIR=`pwd`/build[root@backendcloud-fedora27dpdk-stable-17.08.1]#makeconfigT=x86_64-native-linuxapp-gccConfigurationdoneusingx86_64-native-linuxapp-gcc[root@backendcloud-fedora27dpdk-stable-17.08.1]#sed-ri's,(PMD_PCAP=).*,\1y,'build/.config[root@backendcloud-fedora27dpdk-stable-17.08.1]#makemake报错:
/usr/src/kernels/4.18.19-100.fc27.x86_64/Makefile:945:***"CannotgenerateORCmetadataforCONFIG_UNWINDER_ORC=y,pleaseinstalllibelf-dev,libelf-develorelfutils-libelf-devel".Stop.安装elfutils-libelf-devel解决:
[root@backendcloud-fedora27dpdk-stable-17.08.1]#yuminstall-yelfutils-libelf-devel编译OvS-DPDK
[root@backendcloud-fedora27openvswitch-2.8.1]#pkill-9ovs[root@backendcloud-fedora27openvswitch-2.8.1]#rm-rf/usr/local/var/run/openvswitch[root@backendcloud-fedora27openvswitch-2.8.1]#rm-rf/usr/local/etc/openvswitch/[root@backendcloud-fedora27openvswitch-2.8.1]#rm-f/usr/local/etc/openvswitch/conf.db[root@backendcloud-fedora27openvswitch-2.8.1]#mkdir-p/usr/local/etc/openvswitch[root@backendcloud-fedora27openvswitch-2.8.1]#mkdir-p/usr/local/var/run/openvswitch[root@backendcloud-fedora27openvswitch-2.8.1]#cd$OVS_DIR[root@backendcloud-fedora27openvswitch-2.8.1]#./ovsdb/ovsdb-toolcreate/usr/local/etc/openvswitch/conf.db./vswitchd/vswitch.ovsschema[root@backendcloud-fedora27openvswitch-2.8.1]#./ovsdb/ovsdb-server--remote=punix:/usr/local/var/run/openvswitch/db.sock--remote=db:Open_vSwitch,Open_vSwitch,manager_options--pidfile--detach[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctl--no-waitinitConfigureFedora27forOvS-DPDK
[root@backendcloud-fedora27openvswitch-2.8.1]#vim/etc/default/grub...GRUB_CMDLINE_LINUX_DEFAULT="default_hugepagesz=1Ghugepagesz=1Ghugepages=4hugepagesz=2Mhugepages=512iommu=ptintel_iommu=on"[root@backendcloud-fedora27openvswitch-2.8.1]#grub2-mkconfig-o/boot/grub2/grub.cfgGeneratinggrubconfigurationfile...Foundlinuximage:/boot/vmlinuz-4.18.19-100.fc27.x86_64Foundinitrdimage:/boot/initramfs-4.18.19-100.fc27.x86_64.imgFoundlinuximage:/boot/vmlinuz-0-rescue-98bddbf29a4f40009b8390e2c27a80acFoundinitrdimage:/boot/initramfs-0-rescue-98bddbf29a4f40009b8390e2c27a80ac.imgdone[root@backendcloud-fedora27openvswitch-2.8.1]#reboot可以设置cpu隔离:GRUB_CMDLINE_LINUX_DEFAULT=”default_hugepagesz=1Ghugepagesz=1Ghugepages=16hugepagesz=2Mhugepages=2048iommu=ptintel_iommu=onisolcpus=1-27,29-55”
[root@backendcloud-fedora27~]#mkdir-p/mnt/huge[root@backendcloud-fedora27~]#mkdir-p/mnt/huge_2mb[root@backendcloud-fedora27~]#mount-thugetlbfshugetlbfs/mnt/huge[root@backendcloud-fedora27~]#mount-thugetlbfsnone/mnt/huge_2mb-opagesize=2MB[root@backendcloud-fedora27~]#cat/proc/meminfoMemTotal:17650724kBMemFree:11744728kBMemAvailable:11867184kB...HugePages_Total:4HugePages_Free:4HugePages_Rsvd:0HugePages_Surp:0Hugepagesize:1048576kBHugetlb:5242880kBDirectMap4k:124736kBDirectMap2M:5273600kBDirectMap1G:13631488kB[root@backendcloud-fedora27~]#cat/proc/cmdlineBOOT_IMAGE=/vmlinuz-4.18.19-100.fc27.x86_64root=/dev/mapper/fedora-rootrord.lvm.lv=fedora/rootrhgbquietdefault_hugepagesz=1Ghugepagesz=1Ghugepages=4hugepagesz=2Mhugepages=512iommu=ptintel_iommu=on配置OVS-DPDK
[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctlsetOpen_vSwitch.other_config:pmd-cpu-mask=0x10000001[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctl--no-waitsetOpen_vSwitch.other_config:dpdk-lcore-mask=0xffffffeffffffe[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctl--no-waitsetOpen_vSwitch.other_config:dpdk-socket-mem="1024,1024"CreatinganOvS-DPDKBridgeandPorts
[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctlshow52de1671-20cc-438c-be6a-d41e7923100b[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctladd-brbr0--setbridgebr0datapath_type=netdev[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctladd-portbr0vhost-user1--setInterfacevhost-user1type=dpdkvhostuser[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctladd-portbr0vhost-user2--setInterfacevhost-user2type=dpdkvhostuser[root@backendcloud-fedora27openvswitch-2.8.1]#./utilities/ovs-vsctlshow52de1671-20cc-438c-be6a-d41e7923100bBridge"br0"Port"vhost-user1"Interface"vhost-user1"type:dpdkvhostuserPort"br0"Interface"br0"type:internalPort"vhost-user2"Interface"vhost-user2"type:dpdkvhostuserBindingNicDevicetoDPDK
去官网下载镜像并修改root密码:
[root@backendcloud-fedora27~]#virt-customize-acentos7vm1.qcow2--root-passwordpassword:666666-bash:virt-customize:commandnotfound[root@backendcloud-fedora27~]#dnfinstall-ylibguestfs-tools[root@backendcloud-centos9~]#virt-customize-acentos7vm1.qcow2--root-passwordpassword:666666[0.0]Examiningtheguest...[6.8]Settingarandomseed[6.8]Settingpasswords[8.3]SELinuxrelabelling[12.9]Finishingoff[root@backendcloud-centos9~]#virt-customize-acentos7vm2.qcow2--root-passwordpassword:666666启动两个dpdkvm:
qemu-system-x86_64-m1024-smp4-cpuhost,pmu=off-hda/root/centos7vm1.qcow2-bootc-enable-kvm-no-reboot-netnone-nographic\-chardevsocket,id=char1,path=/usr/local/var/run/openvswitch/vhost-user1\-netdevtype=vhost-user,id=mynet1,chardev=char1,vhostforce\-devicevirtio-net-pci,mac=00:00:00:00:00:01,netdev=mynet1\-objectmemory-backend-file,id=mem,size=1G,mem-path=/dev/hugepages,share=on\-numanode,memdev=mem-mem-preallocqemu-system-x86_64-m1024-smp4-cpuhost,pmu=off-hda/root/centos7vm2.qcow2-bootc-enable-kvm-no-reboot-netnone-nographic\-chardevsocket,id=char2,path=/usr/local/var/run/openvswitch/vhost-user2\-netdevtype=vhost-user,id=mynet2,chardev=char2,vhostforce\-devicevirtio-net-pci,mac=00:00:00:00:00:02,netdev=mynet2\-objectmemory-backend-file,id=mem,size=1G,mem-path=/dev/hugepages,share=on\-numanode,memdev=mem-mem-prealloc若上面的操作是在vmware上操作,需要加上上面额外的参数pmu=off,为了规避vmware的bug。若不加会报下面的错误:
[root@backendcloud-fedora27~]#qemu-system-x86_64-m1024-smp4-cpuhost-hda/root/centos7vm1.qcow2-bootc-enable-kvm-no-reboot-netnone-nographic\>-chardevsocket,id=char1,path=/usr/local/var/run/openvswitch/vhost-user1\>-netdevtype=vhost-user,id=mynet1,chardev=char1,vhostforce\>-devicevirtio-net-pci,mac=00:00:00:00:00:01,netdev=mynet1\>-objectmemory-backend-file,id=mem,size=1G,mem-path=/dev/hugepages,share=on\>-numanode,memdev=mem-mem-preallocqemu-system-x86_64:error:failedtosetMSR0x38dto0x0qemu-system-x86_64:/builddir/build/BUILD/qemu-2.10.2/target/i386/kvm.c:1806:kvm_put_msrs:Assertion`ret==cpu->kvm_msr_buf->nmsrs'failed.Aborted(coredumped)1.3安装iperf3,并测试
Lagopus支持多种不同类型的网络接口和数据包格式,可以在物理服务器上或虚拟机中运行。它提供灵活的配置选项和API接口,使得用户可以轻松地进行自定义设置和扩展。同时,Lagopus还支持与其他SDN控制器集成使用。
由于其高性能、可定制化以及与其他开源软件兼容等特点,Lagopus在云计算、网络虚拟化、NFV等领域中具有广泛应用价值。
高性能软件OpenFlow1.3交换机和路由器
特征
MoonGen是建立在一个脚本化的高速数据包生成libmoon。整个负载生成器由Lua脚本控制:发送的所有数据包均由用户提供的脚本制作。多亏了令人难以置信的快速LuaJITVM和数据包处理库DPDK,它可以在仅使用单个CPU内核的情况下用64字节数据包使10Gbit/s以太网链路饱和。即使每个数据包都被Lua脚本修改,MoonGen也能达到这个速率。它不依赖于重播相同缓冲区之类的技巧。
MoonGen还可以接收数据包,例如,检查被测系统丢弃了哪些数据包。由于接收也完全由用户的Lua脚本控制,因此可用于实现高级测试脚本。例如,可以使用两个相互建立连接的MoonGen实例。此设置可用于对防火墙等中间设备进行基准测试。
MoonGen建立在libmoon之上,它是DPDK的Lua包装器。
用户可以为他们的实验编写自定义脚本。建议在脚本中使用硬编码的设置特定常量。脚本就是配置,为脚本编写一个复杂的配置界面是无关紧要的。或者,有一个简化(但功能较弱)的命令行界面可用于快速测试。
下图显示了架构以及如何处理多核支持。
执行从必须在用户脚本中定义的主任务开始。此任务在使用的NIC上配置队列和过滤器,然后启动一个或多个从属任务。
请注意,Lua没有任何对多线程的本机支持。因此,MoonGen会为每个线程启动一个新的且完全独立的LuaJITVM。新的VM接收序列化参数:要执行的函数和参数,例如要从中发送数据包的队列。线程仅通过底层库共享状态。
示例脚本quality-of-service-test.lua展示了如何使用此线程模型来实现典型的负载生成任务。它通过发送两种不同类型的数据包来实现QoS测试并测量它们的吞吐量和延迟。它通过启动两项数据包生成任务来实现:一项用于后台流量,一项用于优先流量。第三个任务用于对传入的数据包进行分类和计数。
FastClick通过将数据包处理逻辑移动到用户空间,并使用自定义算法来实现快速匹配和过滤,从而实现了比内核中处理更高效的数据包接收和处理。它支持多线程操作,并具有灵活、可配置的流水线模型,可以轻松地进行定制以适应不同类型的网络应用程序。
FastClick已被广泛用于高性能网络设备(例如路由器、交换机等)和分布式系统中,以提供快速、可靠的数据包处理功能。
4.1安装fastclick
安装fastclick可以使用npm,Component和Bower。另外也提供了Ruby版的gemfastclick-rails以及.NET提供了NuGetpackage。最直接的可以在页面引入fastclickjs文件。如:
在页面直接引入fastclick.js
npminstallfastclick初始化FastClick实例
初始化FastClick实例建议在页面的DOM文档加载完成后。
纯Javascript版
if('addEventListener'indocument){document.addEventListener('DOMContentLoaded',function(){FastClick.attach(document.body);},false);}jQuery版
$(function(){FastClick.attach(document.body);});类似CommonJS的模块系统方式
varattachFastClick=require('fastclick');attachFastClick(document.body);调用require('fastclick')会返回FastClick.attach函数。
使用needsclick过滤特定的元素
如果页面上有一些特定的元素不需要使用fastclick来立刻触发点击事件,可以在元素的class上添加needsclick:
以下这几种情况是不需要使用fastclick:
1、FastClick是不会对PC浏览器添加监听事件
2、Android版Chrome32+浏览器,如果设置viewportmeta的值为width=device-width,这种情况下浏览器会马上出发点击事件,不会延迟300毫秒。
4、IE11+浏览器设置了css的属性touch-action:manipulation,它会在某些标签(a,button等)禁止双击事件,IE10的为-ms-touch-action:manipulation
OpenFastPath(OFP)是一个高性能的数据包处理框架,可以用于构建网络应用程序和设备,例如路由器、交换机等。它提供了一个用户空间的数据包处理引擎,可以通过与多种硬件平台和操作系统集成来实现快速、可扩展的网络应用程序。
OFP支持多个协议栈(例如TCP/IP、UDP/IP等),并提供了一系列基本功能模块,如ARP缓存管理、IP地址管理、ACL过滤等。它还支持虚拟化和容器化部署,并具有灵活的API和可扩展的插件架构,可以轻松地定制以适应不同类型的网络应用程序需求。
OFP最初由Linux基金会主导开发,并已成为Linux基金会项目之一。目前,它已经被广泛应用于各种高性能网络设备和云计算环境中。
fastpath的介绍:
1.提供了Workgroup协议的实现,Workgroup的概念就是专门对应在线客服这个典型场景了。这是企业或组织机构的客服需求的核心概念和功能,类似于呼叫中心。
2.Server端的历史记录存储。默认Openfire本身是不记录信息历史记录的,只记录离线留言。注意,离线消息和消息历史记录是两个不同的概念,离线消息是对方不在线的情况,server端先保存起来,等对方上线后再发给他,发完了消息在server端就被删除了;而消息历史记录是只server端记录的所有对话消息,当然客户端也可以实现在客户端上自己的历史记录。
fasthpath:主要分为两端:agent-客服,user-用户,为人工客服实现了排队路由等基本的呼叫中心功能。
fasthpath:实现的原理就是以技能组为标准对用户加入对应的技能组在路由给对应技能组的客服人员,客服人员收到offer之后,可以接受,fastpath就可以创建openfire的聊天室邀请用户和agent加入进来进行会话,实现客服功能。其中fastpath还提供了一些其他的附加功能:比如转接,路由过程指定客服,设置最大聊天室等等,这些功能可以再以后开发过程中有需要的情况下查看源码即可了解。
下面给出最简单的:user去排队,客服加入技能组,来显示整个的客服功能。
这是openfire提供的插件,在smack中也提供了对应的api,这里提供一个agent端的实例
VPP支持多个协议栈(例如TCP/IP、UDP/IP等),并提供了一系列基本功能模块,如ARP缓存管理、IP地址管理、ACL过滤等。它还支持虚拟化和容器化部署,并具有灵活的API和可扩展的插件架构,可以轻松地定制以适应不同类型的网络应用程序需求。
VPP是一个高度可编程化和可定制化的数据包处理框架,在运营商级网络设备、云计算环境中得到广泛应用。除了Cisco之外,许多公司和组织也在使用VPP构建自己的网络产品或服务。
以下安装方式在centos7上安装测试(可用)
有三种安装方式:源码安装、yum安装、vpp-config安装
源码安装:
1.使用git将VPP源码克隆下来(没有git可使用yuminstallgit-y安装)
[root@localhostsource]#cdvpp[root@localhostvpp]#yuminstall-yepel-releasepython-pipnet-tools[root@localhostvpp]#makeinstall-dep3.安装dpdk,执行第4步代码编译时,会自动下载dpdk并一起编译(可忽略)
[root@localhostvpp]#makedpdk-install-dev4.进行代码编译(makedistclean可以清除编译生成文件)
[root@localhostvpp]#makebuild5.制作rpm包
[root@localhostvpp]#makepkg-rpm6.安装VPP
[root@localhostvpp]#cdbuild-root/[root@localhostbuild-root]#rpm-ivpp*.rpm7.启动VPP(并设置开机启动)
[root@localhost~]#systemctlenablevpp[root@localhost~]#systemctlstartvpp[root@localhost~]#systemctlstatusvpp.service8.测试安装是否成功
VPP简介
VPP到底是什么?一个软件路由器?一个虚拟交换机?一个虚拟网络功能?事实上,它包含所有这些,并且包含更多。VPP是一个模块化和可扩展的软件框架,用于创建网络数据面应用程序。更重要的是,VPP代码为现代通用处理器平台(x86、ARM、PowerPC等)而生,并把重点放在优化软件和硬件接口上,以便用于实时的网络输入输出操作和报文处理。
VPP充分利用通用处理器优化技术,包括矢量指令(例如IntelSSE,AVX)以及I/O和CPU缓存间的直接交互(例如IntelDDIO),以达到最好的报文处理性能。利用这些优化技术的好处是:使用最少的CPU核心指令和时钟周期来处理每个报文。在最新的IntelXeon-SP处理器上,可以达到Tbps的处理性能。
VPP架构
VPP采用插件(plugin)架构,插件与直接内嵌于VPP框架中的模块一样被同等对待。原则上,插件是实现某一特定功能的转发图形节点,但也可以是一个驱动程序,或者另外的CLI。插件能被插入到VPP有向图的任意位置,从而有利于快速灵活地开发新功能。因此,插件架构使开发者能够充分利用现有模块快速开发出新功能。
输入节点轮询(或中断驱动)接口的接收队列,获取批量报文。接着把这些报文按照下个节点功能组成一个矢量(vector)或者一帧(frame)。比如:输入节点收集所有IPv4的报文并把它们传递给ip4-input节点;输入节点收集所有IPv6的报文并把它们传递给ip6-input节点。当ip6-input节点被调度时,它取出这一帧报文,利用双循环(dual-loop)或四循环(quad-loop)以及预取报文到CPU缓存技术处理报文,以达到最优性能。这能够通过减少缓存未命中数来有效利用CPU缓存。当ip6-input节点处理完当前帧的所有报文后,把报文传递到后续不同的节点。比如:如果某报文校验失败,就被传送到error-drop节点;正常报文被传送到ip6-lookup节点。一帧报文依次通过不同的图形节点,直到它们被interface-output节点发送出去。
按照网络功能一次处理一帧报文,有几个好处:
VPP有向图处理的特性,使它成为一个松耦合、高度一致的软件架构。每一个图形节点利用一帧报文作为输入和输出的最小处理单位,这就提供了松耦合的特性。通用功能被组合到每个图形节点中,这就提供了高度一致的架构。
在有向图中的节点是可替代的。当这个特性和VPP支持动态加载插件节点相结合时,新功能能被快速开发,而不需要新建和编译一个定制的代码版本。
Pktgen-DPDK是一种基于DPDK(DataPlaneDevelopmentKit)的数据包生成工具,可以用于测试和评估网络设备、协议栈等各种网络应用程序。它提供了丰富的功能,可以进行不同类型和大小的数据包生成,以及流量控制、速率控制等测试。此外,Pktgen-DPDK还支持多核处理、超线程和NUMA架构,并提供了Web界面来方便用户使用。由于采用了DPDK技术,Pktgen-DPDK具有非常高的性能和低延迟,并广泛应用于云计算、虚拟化、SDN/NFV等领域。
pktgen-dpdk使用dpdk加速包的发送接收,也可以发送接收pcap包,命令行如下:
./app/app/x86_64-native-linuxapp-gcc/pktgen-l0-4-n3---P-m"[11:3].0,[2:4].1"-s0:[.pcap_filepath](pktgen-dpdk.3.4.8)pktgen-dpdk逻辑设计
在pktgen-main.c文件中包含了main主入口函数main()以及参数配置函数pktgen_parse_args(),其中pktgen结构体是所有的参数都是用的,参数配置函数主要是对pktgen结构中个成员赋值。
main函数中pktgen初始化如下:
memset(&pktgen,0,sizeof(pktgen));pktgen.flags=PRINT_LABELS_FLAG;pktgen.ident=0x1234;pktgen.nb_rxd=DEFAULT_RX_DESC;pktgen.nb_txd=DEFAULT_TX_DESC;pktgen.nb_ports_per_page=DEFAULT_PORTS_PER_PAGE;if((pktgen.l2p=l2p_create())==NULL)pktgen_log_panic("Unabletocreatel2p");pktgen.portdesc_cnt=get_portdesc(pktgen.portlist,pktgen.portdesc,RTE_MAX_ETHPORTS,0);然后初始化log,cpu
pktgen_init_log();pktgen_cpu_init();配置初始化port信息
voidpktgen_config_ports(void){uint32_tlid,pid,i,s,q,sid;rxtx_trt;pkt_seq_t*pkt;port_info_t*info;charbuff[RTE_MEMZONE_NAMESIZE];int32_tret,cache_size;charoutput_buff[256]={0};uint64_tticks;/*Findoutthetotalnumberofportsinthesystem.*//*Wehavealreadyblacklistedtheonesweneededtoinmainroutine.*/pktgen.nb_ports=rte_eth_dev_count();if(pktgen.nb_ports>RTE_MAX_ETHPORTS)pktgen.nb_ports=RTE_MAX_ETHPORTS;if(pktgen.nb_ports==0)pktgen_log_panic("***Didnotfindanyportstouse***");pktgen.starting_port=0;/*Setupthenumberofportstodisplayatatime*/if(pktgen.nb_ports>pktgen.nb_ports_per_page)pktgen.ending_port=pktgen.starting_port+pktgen.nb_ports_per_page;elsepktgen.ending_port=pktgen.starting_port+pktgen.nb_ports;pg_port_matrix_dump(pktgen.l2p);........for(s=0;s main()往下调用的函数是pktgen_clear_display(): voidpktgen_clear_display(void){if(!scrn_is_paused()){scrn_pause();scrn_cls();scrn_pos(100,1);pktgen_update_display();scrn_resume();pktgen_page_display(NULL,NULL);}}其中pktgen_update_dsiplay()修改pktgen.flag标志: voidpktgen_page_display(structrte_timer*tim__rte_unused,void*arg__rte_unused){staticunsignedintupdate_display=1;/*Leaveifthescreenispaused*/if(scrn_is_paused())return;scrn_save();if(pktgen.flags&UPDATE_DISPLAY_FLAG){pktgen.flags&=~UPDATE_DISPLAY_FLAG;update_display=1;}update_display--;if(update_display==0){update_display=UPDATE_DISPLAY_TICK_INTERVAL;_page_display();if(pktgen.flags&PRINT_LABELS_FLAG)pktgen.flags&=~PRINT_LABELS_FLAG;}scrn_restore();pktgen_print_packet_dump();}函数中主要执行两个函数_page_display(),pktgen_printf_paket_dump(),前者调用pktgen_page_stats(),显示端口上的统计信息: voidpktgen_page_stats(void){port_info_t*info;unsignedintpid,col,row;structrte_eth_stats*rate,*cumm,*prev;unsignedsp;charbuff[32];intdisplay_cnt;if(pktgen.flags&PRINT_LABELS_FLAG)pktgen_print_static_data();......其中函数pktgen_print_static_data()显示一些静态数据,动态数据主要通过info结构体传输。 然后main函数调用rte_timer_setup() voidrte_timer_setup(void){intlcore_id=rte_get_master_lcore();/*initRTEtimerlibrary*/rte_timer_subsystem_init();/*inittimerstructures*/rte_timer_init(&timer0);rte_timer_init(&timer1);/*loadtimer0,every1/2seconds,onDisplaylcore,reloadedautomatically*/rte_timer_reset(&timer0,UPDATE_DISPLAY_TICK_RATE,PERIODICAL,lcore_id,pktgen_page_display,NULL);/*loadtimer1,everysecond,ontimerlcore,reloadedautomatically*/rte_timer_reset(&timer1,pktgen.hz,PERIODICAL,lcore_id,pktgen_process_stats,NULL);}其中timer0,用于更新显示,timer1用于统计数据。 main函数接着调用pktgen_cli_start(),最终调用cli_start(),用于执行运行时参数。 pktgen流量生成器 下面说一下发送接收包,在main函数的前部分还有一个重要的函数: ret=rte_eal_remote_launch(pktgen_launch_one_lcore,NULL,i); /*Configureandinitializetheports*/pktgen_config_ports();pktgen_log_info("");pktgen_log_info("===Displayprocessingonlcore%d",rte_lcore_id());/*launchper-lcoreinitoneverylcoreexceptmasterandmaster+1lcores*/for(i=0;i 这些函数相应的调用函数,同时更新pktgen结构或是其中的成员,以pktgen_main_rxtx_loop()为例。 pktgen_main_rxtx_loop()->pktgen_main_transmit()->pktgen_send_pkts()->pktgen_send_burst()->_send_burst_..()->pkt_do_tx_tap()->write() 下面说一下pktgen作为流量生成器的一些个人理解。 pktgen作为linux内核模块的一部分,因此可以直接加载内核模块generate流量(lsmodpktgen),网上参考资料说是产生udp类型的packet,在此详细探讨一下。 在pktgen_main_transmit()中: static__inline__voidpktgen_main_transmit(port_info_t*info,uint16_tqid){structrte_mempool*mp=NULL;uint32_tflags;flags=rte_atomic32_read(&info->port_flags);/**TransmitARP/Pingpacketsifneeded*/if((flags&SEND_ARP_PING_REQUESTS))pktgen_send_special(info,flags);/*Whennottransmittingonthisportthencontinue.*/if(flags&SENDING_PACKETS){mp=info->q[qid].tx_mp;if(flags&(SEND_RANGE_PKTS|SEND_PCAP_PKTS|SEND_SEQ_PKTS)){if(flags&SEND_RANGE_PKTS)mp=info->q[qid].range_mp;elseif(flags&SEND_SEQ_PKTS)mp=info->q[qid].seq_mp;elseif(flags&SEND_PCAP_PKTS)mp=info->q[qid].pcap_mp;}if(rte_atomic32_read(&info->q[qid].flags)&CLEAR_FAST_ALLOC_FLAG)pktgen_setup_packets(info,mp,qid);pktgen_send_pkts(info,qid,mp);}flags=rte_atomic32_read(&info->q[qid].flags);if(flags&DO_TX_FLUSH)pktgen_tx_flush(info,qid);}最终调用函数pktgen_setup_cb(),调用了pktgen_range_ctor()和pktgen_packet_ctor() 其中结构体: 从上面可以看书pktgen不只是产生udp类型的数据包,也可以产生其他类型的数据包,但是只是产生了流量,而没有payload。 pktgen-dpdk发送pcap包 发送pcap数据包需要使用-s:[pcap.filepcath]参数。 staticintpktgen_parse_args(intargc,char**argv){....case's':/*ReadaPCAPpacketcapturefile(stream)*/port=strtol(optarg,NULL,10);//将字符串port转换为长整型portp=strchr(optarg,':');//++p指向待发送的pcap文件if((p==NULL)||(pktgen.info[port].pcap=_pcap_open(++p,port))==NULL){pktgen_log_error("InvalidPCAPfilename(%s)mustincludeportnumberasP:filename",optarg);pktgen_usage(prgname);return-1;.......}此处p指向pcap文件(此处为绝对路劲) /*SetupthePCAPfileforeachport*/if(pktgen.info[pid].pcap!=NULL)if(pktgen_pcap_parse(pktgen.info[pid].pcap,info,q)==-1)pktgen_log_panic("CannotloadPCAPfileforport%d",pid);/*FindoutthelinkspeedtoprogramtheWTHRESHvaluecorrectly.*/pktgen_get_link_status(info,pid,0);其中调用了pktgen_pcap_parse(),在里面读取pcap文件数据的函数是_pcap_read() size_t_pcap_read(pcap_info_t*pcap,pcaprec_hdr_t*pHdr,char*pktBuff,uint32_tbufLen){do{if(fread(pHdr,1,sizeof(pcaprec_hdr_t),pcap->fd)!=sizeof(pcaprec_hdr_t))return0;/*Convertthepacketheadertothecorrectformat.*/_pcap_convert(pcap,pHdr);/*Skippacketslargerthenthebuffersize.*/if(pHdr->incl_len>bufLen){(void)fseek(pcap->fd,pHdr->incl_len,SEEK_CUR);returnpHdr->incl_len;}returnfread(pktBuff,1,pHdr->incl_len,pcap->fd);}while(1);}然后调用dpdk的rte_mempool_create(),可以看到每次只能发送一个pcap文件,如果需要发送多个pcap文件,则需要解析多个pcap文件路劲,赋值给pcap.fd(可以使用缓存预先存储)。 MTCP(Many-to-ManyTCP)是一种基于用户态的高性能TCP/IP协议栈,主要用于数据中心、云计算等高吞吐量和低延迟的网络应用。相比于传统内核态协议栈,MTCP具有更低的上下文切换开销、更少的锁竞争以及更好的可扩展性和灵活性。MTCP支持多线程套接字API,并提供了类似POSIXsocketAPI的接口,可以很方便地替换标准socketAPI使用。此外,MTCP还提供了丰富的工具来帮助用户进行网络应用程序开发和调试,如PacketGenerator、FlowMonitor等等。 所以说在mTCP的源码文件中是直接附带了一个DPDK的。总的说来,官方的安装步骤大致分成三部分: 接下来详细叙述安装步骤 -libdpdk(Intel'sDPDKpackage*)-libnuma-libpthread-librt-libgmp(forDPDK/ONVMdriver)-ForDebian/Ubuntu,tryapt-getinstalllinux-headers-$(uname-r)$注意,这些库的名字可能在不同的系统上略有不同,可能是"-dev","-devel"形式的。另外千万注意检查是否存在运行内核版本一致的linux头文件。 Downloaddpdksubmodulegitsubmoduleinitgitsubmoduleupdate进入dpdk文件夹,安装dpdk,推荐参考dpdk官方文档。主要参考其中的第3部分与第5部分。 创建一个单独的build文件夹,在dpdk目录下执行meson。 cdbuildninjaninjainstallldconfig注意最后两条命令需要root身份执行。至此dpdk安装完毕,可以去检查一下是否存在一个kmod目录。 sudomodprobeuiosudoinsmodkmod/igb_uio.ko至此dpdk部分已经安装完毕。可以使用ifconfig命令观察一下网卡情况,记一下那张以太网的网卡名称,可能是eth0,也可能是eno1类似的名字。 最后设置DPDK的环境,可以使用dpdk里面附带的脚本来操作,mtcp/dpdk/usertools/dpdk-devbind.sh用于网卡的绑定,先使用命令/dpdk-devbind.sh--status查看当前的网卡状态,应该会得到类似如下的信息: 1.最后我们使用mtcp自带的工具来注册以太网端口 ./setup_mtcp_dpdk_env.sh注意选择registertheEthernetports项,我的版本上是24,你的版本可能不同的。然后选择选项退出这个脚本,我的版本是35选项,你的可能不同。 mTCP环境安装,主要参考官方文档: sudoifconfigdpdk0x.x.x.xnetmask255.255.255.0upexportRTE_SDK=exportRTE_TARGET=x86_64-native-linuxapp-gcc./configure--with-dpdk-lib=RTESDK/RTE_SDK/RTESDK/RTE_TARGETmake十一、Butterfly–连接虚拟机Butterfly连接虚拟机(VM)并控制其流量。 每个VM流量都包含在特定的VXLAN网络中,并且流量由(EC2/Openstack-like)安全组过滤。 安全组可以应用于任何VM接口,并包含一个简单的网络规则列表(默认丢弃流量)。 虚拟网卡 在Butterfly中,虚拟NIC(或vnic)使您能够通过vhost-user向QemuVM添加虚拟网络接口。每个vnic都有一个24位的网络ID,称为VNI。如果两个具有相同VNI的vnic位于不同的物理主机上,Butterfly会通过VXLAN封装VM数据包,并将它们发送到相应的物理主机。一旦收到,数据包将被解封装并路由到它们的最终目的地。使用相同VNI创建的所有vnic都位于同一网络上。如果具有相同VNI的两个vnic位于同一物理主机上,则数据包不会退出到物理网络。 Butterfly旨在使用专用DPDK端口连接到物理网络。它允许Butterfly在使用物理NIC卸载功能时在VM之间具有非常低的延迟。 对于VM到VM通信,不会发生校验和和分段,因为数据包不会在物理网络上传输。这使Butterfly能够在VM之间进行高速和低延迟的通信。 示例:在vni"1337"上创建新的vnic"vnic_1": butterflynicadd--ip42.0.0.1--mac52:54:00:12:34:01--vni1337--idvnic_1数据筛选 使用Butterfly中的集成防火墙(NetBSD的NPF)为每个vnic过滤VM流量。过滤规则根据其安全组中包含的规则应用于每个VM。一个vnic可以使用多个安全组,一个安全组可以由多个vnic使用。当一个vnic使用多个安全组时,规则会累积。安全组包含要允许的规则列表(默认策略是阻止)和成员列表(IP地址)。 Butterfly规则主要由协议/端口和允许的源描述。此源可以是CIDR块或安全组的成员。 示例:在“mysg”安全组中添加一条规则,允许22端口上的TCP协议中的42.0.3.1: butterflysgruleaddmysg--ip-prototcp--port22--cidr42.0.3.1/32示例:在“mysg”安全组中添加一条规则,允许“users”安全组成员在80端口使用TCP协议: butterflysgruleaddmysg--ip-prototcp--port80--sg-membersusers注意:当一个或多个vnic使用的安全组被修改时,附加到每个受影响的VM的防火墙规则会重新加载。 使用 Butterfly是一个可以通过网络API控制的守护进程。 它与客户端打包在一起,主要允许您添加/删除/列出vnic和安全组。 您当然可以直接编写对ButterflyAPI的调用。API消息传输基于ZeroMQ,消息以Protobuf格式编码。查看协议以获取更多详细信息。 下面是一个Butterfly示例,其中6个VM隔离在三个网络(VNI42、51和1337)中。 Butterfly绑定一个专用网卡来发送/接收VXLAN数据包,并绑定一个套接字(默认:tcp)来监听对其API的查询。如果您使用DPDK兼容卡,您将无法通过它访问API。 您可以使用几行客户端调用来构建此配置: butterflynicadd--ip42.0.0.1--mac52:54:00:12:34:01--vni42--idvnic_1butterflynicadd--ip42.0.0.1--mac52:54:00:12:34:01--vni51--idvnic_2butterflynicadd--ip42.0.0.2--mac52:54:00:12:34:02--vni51--idvnic_3butterflynicadd--ip42.0.0.3--mac52:54:00:12:34:03--vni51--idvnic_4butterflynicadd--ip42.0.0.1--mac52:54:00:12:34:01--vni1337--idvnic_5butterflynicadd--ip42.0.0.2--mac52:54:00:12:34:02--vni1337--idvnic_6提示:如果您想查看图形的外观:运行butterflystatus并复制webgraphviz.com中的点图 butterflysgaddsg-webbutterflysgruleaddsg-web--ip-prototcp--port80--cidr0.0.0.0/0butterflynicsgaddvnic_1sg-webbutterflynicsgaddvnic_2sg-web注意:ButterflyAPI使用幂等性,这意味着两次调用应该产生相同的结果。 OpenNet是一个高性能的开源网络库,由中国电信研究院开发。它提供了一组可扩展、可重用和易于使用的网络编程接口,支持TCP、UDP、HTTP等协议。OpenNet采用事件驱动模型,基于epoll或kqueue实现高并发网络通信,在处理海量并发连接时表现出色,被广泛应用于互联网服务端开发领域。 NetBricks是一个高性能的网络函数框架,由斯坦福大学研究团队开发。它提供了一组可扩展、可重用和易于使用的网络编程接口,支持TCP、UDP等协议。NetBricks采用数据包处理管线(packetprocessingpipeline)模型,基于DPDK实现高速数据包处理,在网络功能虚拟化(NetworkFunctionVirtualization,NFV)、边缘计算(EdgeComputing)等领域有广泛应用。 F-Stack是一个基于DPDK(DataPlaneDevelopmentKit)的高性能网络框架,由中国国内开发团队研发。它提供了一组可扩展、高效和易用的网络编程接口,支持TCP/IP协议栈和UDP等协议,具有零拷贝(zerocopy)、多核并行处理、CPU亲和性等特性。F-Stack被广泛应用于虚拟化环境、大规模互联网服务器集群等场景中。 F-Stack的主要特点包括: hunderXNFV是卡普林公司(Cavium)推出的一款面向网络功能虚拟化(NFV)场景的处理器,基于ARMv8架构。它具有高性能、低功耗和可扩展性等优势,适合用于构建大规模的虚拟化网络环境。 ThunderXNFV采用了多核心设计,每个核心都可以支持多线程,最多可以实现96个物理核心和192个虚拟核心。此外,它还集成了丰富的硬件加速引擎,例如加密/解密、压缩/解压、流量管理等,并且支持RDMA和SR-IOV等新型技术。 除了硬件方面的优势外,ThunderXNFV还提供了全套的软件生态系统。它可以兼容Linux操作系统,并且支持OpenStack、DPDK和OPNFV等开源平台。此外,卡普林公司还提供了完整的SDK和工具链,使得用户可以轻松地进行应用开发和调试。 DPVS(DirectProjectVirtualServer)是一个高性能、轻量级的四层负载均衡软件,由中国电信开发。它基于Linux内核实现,可以在多个服务器之间分配并平衡网络流量,以提高应用的可靠性和可扩展性。 DPVS支持多种负载均衡算法,例如轮询、最小连接数和源地址哈希等。它还支持会话保持和健康检查等功能,可以确保请求被正确地路由到目标服务器,并避免单个服务器出现过载情况。此外,DPVS还可以与其他网络设备集成使用,例如防火墙和VPN等。 DPVS采用了用户态数据包处理技术,在数据包转发时无需进入内核空间进行处理。这种设计使得DPVS具有卓越的性能和吞吐量,并且能够快速响应高峰期的流量负载。同时,DPVS还支持CPU亲和性调度、NUMA感知和动态配置等特性,以优化系统资源利用率。 编译安装 虽然github官方上说明不再支持dpdk-stable-20.11.1之前的版本了,但是目前新分支还出与开发阶段,我没有编译通过。所以我用的版本还是dpdk18.11.2+dpvs1.8.首先安装dpvs1.8版本在github上的官方介绍一样下载1.8版本的dpvs源代码。 yuminstallpython3(Python3.5orlater.)pip3installmesonninja//Meson(version0.49.2+)andninjapip3installpyelftools或者yuminstallpyelftoolsyuminstall-ypopt-develautomakelibnl3libnl3-developensslopenssl-develnumactlkernel-devellibpcap-develunzippatchnumactl-devel另外,注意安装gcc前要安装和内核版本匹配的kernel-devel,查看ls/usr/src/kernels/,并且ldd--version查看glibc版本要求glibc>=2.7(拜托2.17大于2.7) 编译dpdk 在编译dpvs之前要先编译DPDK: 编译dpvs比较简单,只需要配置exportPKG_CONFIG_PATH=/opt/sj/dpvs-1.8/dpdk-stable-18.11.2/dpdklib/lib64/pkgconfig/libdpdk.pc然后到dpvs目录下编译即可 cd..make//报inline函数未定义的错误,需要在src/MakefileCFLAGS参数最后-mcmodel=medium之前加上-fgnu89-inlinemakeinstall运行DPVS 拷贝./conf/下合适的配置文件到/etc/dpvs.conf总结一下,我遇到过的问题: ProgramreceivedsignalSIGSEGV,Segmentationfault.[SwitchingtoThread0x7ffff440d700(LWP47658)]0x00000000006162f9inconn_term_lcore()Missingseparatedebuginfos,use:debuginfo-installglibc-2.17-196.el7.x86_64libgcc-4.8.5-16.el7.x86_64li.0.2k-24.el7_9.x86_64zlib-1.2.7-19.el7_9.x86_64于是,我又打开了/etc/dpvs.conf中的log_level为DEBUG,再次启动程序得到有效信息如下所示: EAL:rte_mem_virt2phy():cannotopen/proc/self/pagemap:Toomanyopenfiles应该是系统允许最大打开文件数太小所致,用ulimit-a查看果然只有1024,用ulimit-n1048576改成较大的数量,再次启动DPVS进程这次可以了。 3.报错“DPVS_MAX_SOCKETissmallerthansystemnumanodes!”,查看源码发现是numa节点数小于系统常量DPVS_MAX_SOCKET,再次查找这个DPVS_MAX_SOCKET,发现它是在src/config.mk文件中定义并被编译到源码里,因此需要修改成numa节点数(numactl--hardware查看numa节点数)并再次编译。 Vhost-user-net是一种虚拟化网络设备技术,它通过将网络设备抽象为一个用户态程序来实现高性能和灵活性。具体来说,它使用了vhost-user协议来进行数据交换,从而避免了内核空间与用户空间之间的上下文切换和数据复制等开销。 在Vhost-user-net中,vhost-user程序扮演着两个角色:vhost-user客户端和vhost-user服务器。其中,vhost-user客户端运行在虚拟机中,负责接收和发送网络数据包。而vhost-user服务器则运行在主机上,负责处理网络数据包并将其转发到物理网卡或其他虚拟机中。 Vhost-user-net可以与多种虚拟化管理器和操作系统集成使用,例如QEMU、KVM、Xen等。通过这些软件的支持,Vhost-user-net可以实现多租户隔离、动态配置、快速迁移等特性,并且支持多种协议(如TCP/IP、UDP/IP、VLAN等)和各种网络功能(如防火墙、NAT、负载均衡等)的部署。 OpenNFP(OpenNetworkFunctionPipeline)是一种基于FPGA实现的高性能网络功能虚拟化(NFV)框架。它提供了一个可编程的数据平面,并且允许将各种网络功能模块组合在一起,以构建自定义的网络应用程序。 OpenNFP具有以下几个特点: VCL(VirtualComputingLab)是一种基于云计算技术的虚拟化实验平台,用于支持远程教育和在线实验。它允许用户通过网络连接到云端的虚拟机上,进行各种软件开发、测试和实验等操作。 VCL的主要特点如下: ibmoon是一个基于DPDK和LuaJIT的高性能网络应用框架,主要用于开发高速数据包处理、网络测试和流量生成工具。 Libmoon的主要特点如下: 目前Libmoon已被广泛应用于各种网络应用场景,如大规模分布式系统测试、DDoS攻击仿真、智能路由器设计等。它为用户提供了高度灵活、易于使用和高性能的网络应用开发框架,是一种非常有价值的技术。 那什么样的程序员适合学习dpdk技术? 对于dpdk来说,它更看重计算机原理和底层技术,和业务上的关联不大,适合: 这里给大家推荐零声教育全网独家的【dpdk-网络协议栈-vpp-OVS-DDos-虚拟化技术】课程体系,通过32个项目案例,2W+行手写代码,全面解析4个dpdk技术方向: (1)dpdk基础知识 (2)网络协议栈 (3)dpdk组件项目 (4)dpdk经典项目 (1)高效磁盘io读写spdk(C) (2)spdk文件系统的实现 (3)spdkkv存储的实现 (1)可扩展的矢量数据包处理框架vpp(c/c++) (2)golang的网络开发框架nff-go(golang) (1)DPDK的虚拟交换机框架OvS (2)高性能4层负载均衡器DPVS (1)perf3 (2)TRex (3)dpdk-pktgen (4)fio (1)性能指标 (2)测试方法 还不熟悉的朋友,这里可以先领取一份dpdk新手学习资料包(入坑不亏):