VIRTIO-Virtual IO Based On VPP/DPDK at front

news2024/10/6 0:36:43

简介

虚拟化技术是云计算的基石,是构建上层弹性计算、弹性存储、弹性网络的基本成份。所谓虚拟化,即对计算所需的资源进行模拟,提供与物理资源一般无二的特性和运行环境。如Qemu将整个VM所需环境进行虚拟化:一个Qemu进程代表一台VM,本质是运行OS软件的计算机程序 。可利用Qemu进程上下文摸拟真实的计算机硬件环境,如将线程抽象为vcpu,将进程虚拟内存抽象为Guest物理内存,还有若干IO外设,如键盘、图形显示器、串口、网卡等由KVM/Qemu配合实现抽象,或借助宿主机第三方服务。

大多数抽象设备涉及频繁的IO操作,这些IO操作最终会作用到真实的硬件环境中。为了保证物理环境的安全,当虚机调用到特殊指令时,将触发中断陷入,并由KVM捕获并代理完成指令操作。同普通进程一样,每次进程中断的陷入都涉及到用户态到内核态的上下文切换,使CPU产生额外的调度开销。虚机进程中断陷入导致这样的调度开销更大(涉及虚机用户态、虚机内核态、宿主机内核态三者之间的切换),这种方式必须不利于虚机的高频次网络IO。

针对此类应用特点,在网络虚拟化方面提出两种主流加速方案:基于SRIOV的网卡虚拟化技术和半虚拟的VIRTIO技术。SRIOV属于硬件(网卡)加速一类,等效于CPU的VT-x,内存的IOMMU,而VIRTIO则完全属于软件加速一类。VIRTIO将IO处理分为两段,一段为Guest内OS的处理,另一段为Guest陷出到宿主机KVM后的处理,但本质是基于计算机冯诺依曼架构,即指令和数据的分离思想。大批量高频次的数据通过Vring在虚机和宿主机之间共享,不需要虚机陷入/陷出;而指令的抽象更为多样化,可以是普通中断方式,也可以是Socket或消息机制。

本文将从VPP/DPDK源码出发,聚焦VPP驱动DPDK的报文收发过程,分析VirtIO(前端驱动)在整个过程中所处位置及实现。

VPP/DPDK

DPDK之于VPP,犹如Driver之于Kernel。

VPP采用矢量并发编程,实现了相对完整的TCP/IP协议栈,除覆盖基础的L2/L3转发特性外,支持包括VXLAN、NAT、ACL等云网特性;DPDK作为高效的用户态驱动应用于大多数知名的开源软件中,如OVS、VPP、SPDK。可以看出VPP聚焦协议本身的处理,在IO方面较弱;DPDK聚焦IO的处理,欠缺丰富的协议功能。DPDK采用标准PCI网卡方式,提供了一套通用的RTE驱动,即对上暴露统一设备配置和收发API,屏蔽了不同设备的内部实现细节。

VPP报文收发

VPP(Vector Packet Processing)矢量包处理引擎,符合其现有性能特点。VPP通过node图组织报文转发关系,如流水线一般的协同分工。一个node仅需高效完成一件事即可,其通过报文批处理方式,结合若干并行指令和预处理指令最大化的“压榨”了CPU缓存以及指令流水线,使N个包的处理时间接近1个包的处理时间,极速提升了转发性能。

VPP聚焦点在协议处理本身,并不直接与网卡打交通,而采用一种更高效的DPDK UIO方案。其仅需通过新增DPDK Device Plugin,并在此Plugin中加载DPDK驱动的方式实现对网卡的管理。VPP中的Device与DPDK的设备相对应,其将DPDK网卡设备实例化为网络接口,并挂载统一的报文收发函数:

node.c: VLIB_NODE_FN (dpdk_input_node)

  • 所有报文接收几乎都在node.c中实现,注册为INPUT类型,即流量生产入口。VPP将在此入口中实现报文的批量接收,并将MBUF转VLIB BUF(关键报文头信息拷贝/转换)后,结合报文特征,参照VPP node/feature依赖逻辑递交报文至后继node。

device.c: VNET_DEVICE_CLASS_TX_FN (dpdk_device_class)

  • DPDK rte设备发送出口,VPP调用DPDK发送函数完成网卡rewrite,VPP处理在此节点终结,VPP仅需传入DPDK设备及其发送队列,以及MBUF list即可。

DPDK隐藏了包括网卡类型、工作模式等具体网卡驱动细节,对上提供了统一的报文收发函数:

rte_eth_rx_burst,rte_eth_tx_burst,后文将描述此部分。

接口与设备

设备表示具体的非主板挂件,即“外设”,可以是物理的或虚拟的,受驱动管理,如DPDK;协议栈通常用接口表示IO"出入口”,接口属于通信挂件,是虚拟的,其和设备为1:1关系。

VPP DPDK Plugin调用DPDK实现对设备的驱动,DPDK屏蔽内部驱动细节,对上暴露统一的设备管理函数,如接口UP/DOWN,MAC变更,报文RX/TX等通用或特定属性API。

VPP通过startup.conf中的dpdk节点定义了需要纳管的设备PCI,如:

VPP DPDK Plugin将使用startup.conf中的参数进行初始化设备,在函数dpdk_config中,将调用DPDK对纳管的设备进行初始化,参见《DPDK init》、《VPP init》。接着,将启动dpdk_process实现对DPDK驱动的持续管理。在此过程中,VPP DPDK Plugin将同步完成接口的注册,这里的接口指的是"Hardware Interface",区别于subif,vxlan,loop等逻辑接口。参见函数src\plugins\dpdk\device.c\dpdk_lib_init,在此函数中完成物理接口的创建,并绑定设备到物理接口。通过vppctl show hardware-interface [verbose | detail]可查看当前的物理接口的PCI及Queue参数。

DPDK

DPDK UIO

DPDK支持通过UIO、VFIO、MLX等工作模式驱动网卡,需要根据网卡类型和工作模型为不同的网卡加载相应驱动,通过预置dpdk-devbind.py可对网卡绑定的驱动程序。其中,UIO为标准的用户态驱动框架,DPDK基于此框架实现了igb_uio.ko的用户态PMD驱动,通过此驱动来绕过内核,将网卡(寄存器)映射到用户态。

DPDK通过PCI地址的方式绑定网卡,并由dpdk-devbind脚本为网卡绑定驱动,在目录/sys/bus/pci/drivers/生成了igb_uio软链接,从中可获得绑定后的信息。

igb_uio将网卡映射到用户态后(实则将网卡从内核解绑,完成网卡必要的初始化,获取网卡属性并生成系列文件供用户态程序使用),后续DPDK将通过内部注册的网卡驱动完成对网卡的再次纳管。纳管时通过Vendor和Device区配设备和驱动程序 ,如VIRTIO驱动注册支持的{PCI Vendor,Device}如下:

/* VirtIO PCI vendor/device ID. */

#define VIRTIO_PCI_VENDORID     0x1AF4

#define VIRTIO_PCI_LEGACY_DEVICEID_NET 0x1000

#define VIRTIO_PCI_MODERN_DEVICEID_NET 0x1041

仅网卡和驱动的{PCI Vendor,Device}完全匹配时才能成功绑定。执行命令lscpu -n可查看网卡PCI地址的Vendor和Device信息:

参考PCI官网PCI IDS定义:

可见1AF4厂商为Red Hat,且主要支持Virtio类设备(包括网卡、串口、显卡等),其中,网卡设备号为1000和1041。

在网卡成功绑定驱后,参见《接口与设备》章节,VPP会根据vpp startup.conf配置,生成供自己管理的DPDK 设备和接口,完成了与DPDK的对接。

PCI基础

组成计算机系统的主要成为包括CPU、内存、主板+外设。在早期计算机系统中,外设接入CPU存在诸多限制,如受限于CPU总线架构、寻址方式、工作频率等,这些限制导致了外设的读写速率过低、计算机可扩展性差、甚至系统蓝屏现象。这些问题, 直到Peripheral Component Interconnect(直译为外设内联标准,用于CPU对外围设备的连接和控制的标准方式,由Intel提出并制定的标准南桥接入方案)的提出得以解决。

支持PCI的设备在系统开机时,会向系统注册其配置空间,不同的外设将注册到不同的配置空间。配置空间中,配置了包括Device和Vendor信息,以及PCI BAR(基地址)和若干扩展信息。其中,Device和Vendor将指示OS为外设加载合适驱动,参见上文。PCI BAR为系统指示了访问外设的基地址,通过“基地址+寄存器”即可实现对外设的操作。PCI BAR主要包括内存BAR、IO BAR、中断BAR。

通常,系统通过内存映射方式访问外设。基于类UNIX的OS支持虚拟内存Page,进程通过虚拟Page方式共享系统内存;仅在实际发生读写时,将虚拟内存映射到实际的物理内存,并根据映射对象的类型调用对应的驱动指令来实现真实访问;整个过程对进程透明,由OS内存管理负责内存调度。这种虚拟内存Page技术,同时支持将外设内存BAR映射到虚拟地址空间,进程通过访问虚拟地址空间,即可同步访问外设。

VIRTIO 驱动和设备

虚拟化软件,如KVM,为虚机提供了和物理机等同的运行环境,OS不需要关心自己处于虚拟化环境中还是真实的物理环境中,所有外设皆由KVM/Qemu为虚机OS抽象,包括网卡。这些虚拟外设通常以VIRTIO类型提供给虚机,参考如下虚机配置文件:

Qemu在拉起虚机OS时,已根据上述配置注入到虚机配置空间,虚机OS启动后,识别PCI设置时,根据Vendor和Device信息加载相应VIRTIO类型驱动来操作虚拟外设。虚拟VIRTIO类型的网卡,可由内核态的virtio-pci驱动管理,或可由用户态的igb_uio驱动管理,具体可以虚机内执行lspci -vvv查看:

上文提到,igb_uio不做实际的网卡收发操作,而交由DPDK完成,一些操作必须在内核完成的,由igb_uio代理,如中断处理。DPDK通过igb_uio对网卡的映射,在用户态空间即可实现对网卡的操作。

VIRTIO Probe

在OS识别到网卡后,实则已用igb_uio驱动完成网卡的加载工作,后续用户态DPDK可基于igb_uio映射的地址信息直接管理网卡,从Probe的字面意思也可见一斑。用户态DPDK中针对不同的厂商和网卡类型实现对应的网卡驱动,搜索"rte_pci_driver"可查看注册的PCI类型的驱动(部分):

驱动通过调用RTE_INIT向DPDK框架注册,注册时,携带了rte_pci_driver指标的参数信息,id表和probe/remove操作函数,其中id表中,含有上文提到的Vendor和Device信息。VIRTIO亦是如此,其向DPDK注册支持{0x1AF4,0x1000}、{0x1AF4,0x1041}两种类型的网卡(参见上文),VIRTIO rte_pci_driver如下:

RTE_INIT宏由RTE_INIT_PRIO展开为:

static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)

使rte_eal_iopl_init、rte_pci_register先于main函数执行,这两个函数,主要实现VIRTIO驱动的注册(而非加载),即向rte_pci_bus.driver_list链中挂载驱动识别信息。

PCI Probe

DPDK的总线类型比较丰富,搜索'RTE_REGISTER_BUS'可查看(或直接查看driver/bus/pci目录):

PCI为现代服务器支持的主流扩展总线,DPDK中定义rte_pci_bus来注册PCI总线管理函数:

备注:不同类型的PCI应注册不同的PCI bus,如显卡、磁盘等与网卡不同的设备。

DPDK init

在上述Probe就绪后,DPDK将在main阶段调用rte_eal_init->rte_bus_scan->rte_pci_scan来扫描总线上所有的PCI设备并加载对应驱动(与内核行为一致)。

在《DPDK UIO》提到,DPDK将扫描PCI目录(Linux):/sys/bus/pci/devices,并从调用pci_scan_one逐一识别PCI:

扫描出来的PCI信息将会与rte_pci_bus.device_list中注册的驱动比对(比对Vendor和Device),仅和DPDK注册驱动相匹配的PCI才能被加载。

接着,同scan相同的套路,rte_eal_init->rte_bus_probe->pci_probe加载PCI总线驱动,实现PCI设备化,VIRTIO类型的网卡将调用VIRTIO Probe函数:eth_virtio_pci_probe。

eth_virtio_pci_probe调用rte_eth_dev_pci_generic_probe生成标准的ETH网卡设备(rte_eth_dev eth_dev),并同时调用eth_virtio_dev_init注册设备配置函数,包括设备启停、MTU配置、MAC设置、VIRTIO队列配置等(参见virtio_eth_dev_ops)。

VIRTIO报文收发函数在设备启动函数中配置,即由virtio_dev_start->set_rxtx_funcs设置(回调):

eth_dev->rx_pkt_burst = virtio_recv_pkts

eth_dev->tx_pkt_burst = virtio_xmit_pkts

最终将PCI设备生成了标准的ETH设备,挂载了ETH相关的操作函数,主要的为报文接收和发送函数(参见下文分解)。

VPP init

在《VPP接口与设备》章节提到了VPP将调用dpdk_lib_init初始化DPDK设备为接口(物理接口),实现设备到协议栈的抽象。此函数中,将查询所有DPDK的设备,并同时检查本地startup.conf中配置由DPDK纳管的网卡,并通过调用(dpdk function):

dpdk_device_setup

dpdk_device_startrte_eth_dev_start

rte_eth_dev_configure

rte_eth_tx_queue_setup

rte_eth_rx_queue_setup

rte_eth_dev_set_mtu

正式配置ETH设备,ETH设备到此才正式从OS中脱离并被VPP/DPDK纳管。

备注:参见rte_eth_dev_xxx实现,此类函数中,将调用相应设备注册的配置函数,VIRTIO类型的设备的配置参见virtio_eth_dev_ops。

报文发送

在VPP完成协议处理后,如涉及报文发送,将调用DPDK驱动函数rte_eth_tx_burst,并传入设备ID参数、设备队列ID和待发送的MBUF。其中,VPP发送基于接口而非设备,根据接口和设备的1:1映射关系,即可找到设备ID;设备通常配置为多队列,一般一个队列映射到一个转发Worker上,不同的转发Worker选择不同的设备队列发送数据。

DPDK将根据设备ID找到ETH设备实例,ETH实例中注册了eth_dev->tx_pkt_burst发送回调函数,不同的实例发送函数实现方式不同,但大多基于Queue工作机制,即向网卡发送队列中塞入待发数据,由网卡DMA数据并发送到物理线路。

VIRTIO类型的虚拟网卡基于前后端分离的驱动模式,前端驱动工作于虚机OS内部,后端驱动工作于宿主机。基于VPP/DPDK架构的数据面中,由DPDK作为VIRTIO前端将待发数据写入发送Queue,由于Queu共享于宿主机和虚拟机之间,后端驱动可通过Kernel或OVS或DPDK OVS从发送Queue中直接读出数据,并代为调用网卡发送到物理线路。

报文接收

基于高性能数据转发平面的VPP通常采用Polling轮询调度方案接收数据。DPDK可配置网卡为轮询模式,在网卡接收数据后将DMA塞入数据到接收Queue后,由VPP异步检视接收Queue有的数据,如有,将调用rte_eth_rx_burst尽可能多的批量读取数据。

同报文发送,DPDK将调用ETH实例注册的eth_dev->rx_pkt_burst实现数据接收。VIRTIO使用软队列实现前后端数据交互,前端DPDK中,将数据从接收Queue出队即可。

VIRTIO队列配置

Queue仅仅是packet desc queue,即报文描述符队列,或叫指针队列。与普通网卡操作方式一样,它并不直接存放报文,而是存放报文的指针(即存放DMA转换后可供网卡使用的地址)。它工作在虚机和宿主机之间,Queue由虚机分配(参见virtio_init_queue),并配置到Qemu进程空间进而被宿主机应用感知。

关于如何与外设交互,或读写外设配置,在PCI probe时已配置了相关操作接口,参见:

函数eth_virtio_pci_init->vtpci_init中,将设置VIRTIO_OPS(hw) = &legacy_ops, 后续与外界的交互将通过此类接口进行,包括告知外界发送Queue或接收Queue的地址。

在函数virtio_init_queue中,将根据Qemu xml中的配置(参见 《VIRTIO驱动和设备》)的队列参数来创建queue。期间,将调用VIRTIO_OPS(hw)->setup_queue(hw, vq)将队列共享给后端驱动:

见上述函数,共享队列vq通过rte_pci_ioport_write写入网卡pci配置空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1150848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vue】初步认识<script setup>语法糖和组合式 API

▒ 目录 ▒ &#x1f6eb; 导读需求开发环境 1️⃣ &#x1f6eb; 导读 需求 最近写代码的时候&#xff0c;发现<script setup>这样的代码&#xff0c;没见过&#xff0c;好奇&#xff0c;想知道。 所以就有了这篇文章。 很多文章都说setup是vue3的特权。但是&#xff…

2023.10.29 关于 HashTable 和 ConcurrentHashMap 区别

目录 HashTable ConcurrentHashMap 优化点一 优化点二 优化点三 优化点四 不关键的小区别 HashTable HashMap 和 HashTable 都是常见的哈希表数据结构&#xff0c;用于存储键值对 注意&#xff1a; HashMap 是线程不安全的HashTable 是线程安全的&#xff0c;其关键方法…

MapBox获取点位高程的三种方式

以下提供了三种方法和思路 1&#xff0c;通过mapbox全球dem数据获取高程 这里我们利用了mapbox的tilequery 官网地址在这里 https://docs.mapbox.com/api/maps/tilequery/ 以下是示例代码&#xff0c;这个方式是简单快捷&#xff0c;缺点就是精度不高&#xff0c;大概是以10m…

世界前沿技术发展报告2023《世界航空技术发展报告》(五)直升机技术

&#xff08;五&#xff09;直升机技术 1.常规直升机技术1.1 北约六国联合启动下一代旋翼飞行器能力项目1.2 美国和法国重视发展有人/无人直升机编组能力1.3 美国“黑鹰”直升机完成不载人全自主飞行 2.新概念直升机技术2.1 美国“劫掠者”X型直升机参与陆军“未来攻击侦察机”…

【电路笔记】-交流电感和感抗

交流电感和感抗 文章目录 交流电感和感抗1、概述1.1 电感1.2 电感器 2、频率特性2.1 电抗(Reactance)2.2 相移2.3 感应现象 3、RL滤波器4、总结 在之前有 交流电阻的文章中&#xff0c;我们已经看到电阻器在正常频率下的直流或交流状态下的行为是相同的。 然而&#xff0c;其他…

吃透进程地址空间,理清OS内存管理机制

文章目录 一、前言二、细说进程地址空间1、一段测试的代码2、引入地址空间① 富豪与他的私生子&#x1f468;② 38线竟是这么来的&#xff01;③ 地址空间的深层理解 三、分页 & 虚拟地址空间1、页表的概念2、疑难解答&#xff1a;为何父子进程没有发生同步修改&#xff1f…

注意点细节

部署esxi: VLAN 装esxi的时候如果没有设置trunk就不要设置VLAN&#xff0c; 否则无法访问 。 设置了trunk接口才设置VLAN&#xff0c;否则无法访问 部署esxi: DNS dns服务器配置&#xff1a; esxi 上的配置 部署ESXI &#xff1a;RAID 生成环境中需要先设置RAID 作为系统…

协同网络入侵检测CIDS

协同网络入侵检测CIDS 1、概念2、CIDS的分类3、解决办法4、CIDS模型5、挑战与不足 ⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计2598字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&…

Spring Security授权架构介绍

授权架构重点在于从 Authentication 中获得该认证所具有的权限 GrantedAuthority&#xff0c;以及对请求或路径设置访问所需权限。 GrantedAuthority 在之前的Spring Security&#xff1a;认证架构中&#xff0c;我们已经介绍了在 Authentication 中存储 GrantedAuthority 的…

21. 合并两个有序链表、Leetcode的Python实现

博客主页&#xff1a;&#x1f3c6;看看是李XX还是李歘歘 &#x1f3c6; &#x1f33a;每天不定期分享一些包括但不限于计算机基础、算法、后端开发相关的知识点&#xff0c;以及职场小菜鸡的生活。&#x1f33a; &#x1f497;点关注不迷路&#xff0c;总有一些&#x1f4d6;知…

自相矛盾的LLM幻觉:评估、检测、缓解10.30

自相矛盾的LLM幻觉&#xff1a;评估、检测、缓解 摘要引言相关工作定义和激励自我矛盾4 触发、检测和减轻自相矛盾的行为5 实例化到开放文本生成6 实验 摘要 大型语言模型&#xff08;Large LMs&#xff09;容易产生包含虚构内容的文本。其中一个重要问题是自相矛盾&#xff0…

windows server 2016-IIS静态服务器-设置详细过程

文章目录 1.打开仪表盘新建角色2.iis功能模块3.启动服务器4.优点 1.打开仪表盘新建角色 2.iis功能模块 能选上的尽量选上&#xff0c;除非知道自己用不上。 然后确认&#xff0c;下一步&#xff0c;安装。 3.启动服务器 搜索IIS&#xff0c;启动IIS管理器。 启动网站。 右…

【杂记】Filter过滤器和Interceptor拦截器的区别

过滤器Filter与拦截器Interception区别&#xff1f; 包的位置不同。 filter位于tomcat里面&#xff0c;interception位于Spring-webmvc filter位置&#xff1a; interceptor位置&#xff1a; 实现方式不同。在自定义的时候&#xff0c;filter我们可以实现Filter接口&#xf…

精品Python产品销售数据可视化大屏系统-仓库出入库进销存储

《[含文档PPT源码等]精品基于Python的产品销售数据可视化系统的设计与实现》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django …

组学数据上传(六)|GEO数据库数据上传实操

最近有些老师反馈文章发表时要求提供GEO登录号,如:GSEXXXX&#xff0c;问要怎么获取这种登录号?这时就需要把数据上传至GEO数据库了。还在等什么&#xff0c;跟着小编了解下GEO数据库&#xff0c;手把手教您上传数据至GEO数据库。 GEO数据库全称GENE EXPRESSION OMNIBUS&…

北京新一代信息技术产教联合体成立,360以ISC安全课助力建设工作

10月29日&#xff0c;北京新一代信息技术产教联合体&#xff08;简称联合体&#xff09;成立大会在北京360大厦A座报告厅成功举行。本次大会在中关村科技园区朝阳园管理委员会、北京市教委职业教育与成人教育处的指导下&#xff0c;由360数字安全集团、北京电子城高科技集团股份…

产品经理如何写好互联网产品说明书

互联网产品说明书是产品经理在产品开发过程中必不可少的文档之一。它起到了明确产品的功能和特性的作用&#xff0c;帮助团队成员更好地理解和掌握产品的核心功能。因此&#xff0c;作为产品经理&#xff0c;应该重视互联网产品说明书。那么产品经理该如何写好互联网产品说明书…

Mac电脑VS Code配置Flutter开发环境(图文超详细)

一、安装Android Studio 官网地址&#xff1a; https://developer.android.google.cn/ 历史版本下载地址&#xff1a; https://developer.android.com/studio/archive?hlzh-cn 二、安装Xcode 到App Store下载安装最新版本&#xff0c;如果MacOS更新不到13.0以上就无法安装…

【多线程面试题十四】、说一说synchronized的底层实现原理

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说一说synchronized的底…

三分钟带你了解JS、原型、原型链

1.什么是JS&#xff1f; JavaScript是一种基于对象的脚本语言&#xff0c;它不仅可以创建对象&#xff0c;也能使用现有的对象&#xff1b; 它是基于原型编程、多范式的动态脚本语言&#xff0c;并且支持面向对象、命令式、声明式、函数式编程范式&#xff1b; 白话一点说就是…