通常我们使用qemu创建虚拟机时,会使用下面的选项指定虚拟网卡设备的类型,以及桥接、tap设备参 数等,如下:
-device选项用于给虚拟机分配虚拟设备,如磁盘设备、网卡设备等
-netdev选项用于配置虚拟设备的后端,对于网卡设备,常见的有tap、bridge、vhost-user等,tap设备 是非常常见的一个后端,如使用libvirt创建虚拟机时,libvirt生成的qemu参数中,使用的就是tap设备,直接使用tap设备更加灵活。vhost-user通常用在dpdk等环境。
本文主要使用tap设备为后端,介绍数据包是如果从tap设备中读取出来,发送给虚拟机设备,以及如果从虚拟机中读取数据包,然后发送给tap设备。
tap设备是一个虚拟机设备,在kernel中没有相对应的物理设备,因此只创建出一个tap设备是没有任何 用途的,我们可以使用以下命令在linux中创建一个tap设备:
tap设备主要由内核的tun模块实现,使用’ip tuntap’命令创建设备时,有两种模式,一种是tun,另一个是 tap,分别对应点对点设备和以太网设备,或者说一个是三层设备,另一个是二层设备。
即使手工把网卡设置成UP状态,tap也是处于断开的状态,如下:
只有当应用程序连接到这个设备时,tap设备的状态才会被kernel设置为连接状态,我们可以写个demo 程序,从tap设备读取数据包,模拟qemu读取的过程。
程序会输出数据包的长度和数据包的目的mac地址,程序代码如下:
qemu使用tap设备时,读写的逻辑和以上的demo程序是一样的,以下是qemu程序从tap设备读取报文的逻辑:
当qemu启动时,会使用qemu_set_fd_handler函数把tap设备的文件描述符注册到事件循环中,当tap设备从kernel收到数据包时,kernel会通知到qemu,然后qemu会调用tap_send函数去读取,如下:
从tap_send,可以看出qemu一次最多读取50个数据包,防止tap_send函数过多的占用cpu时间。
tap_read_packet函数会调用read函数读取数据包。
qemu_send_packet_async函数会调用虚拟设备的相关函数发送给虚拟机。
qemu在初始化虚拟设备的时候,会调用qemu_new_nic函数去注册相关回调函数,如下:
qemu从tap接口读取到数据包后,会调用设备注册的rtl8139_can_receive函数。tap接口的处理流程基 本就完成了,后续就是各个虚拟设备的实现了,如e1000/rtl8139等设备要模拟出相关的PCI物理设备,这样虚拟机中的驱动无需做任何修改就可以识别到设备。
根据各种硬件特性,预处理数据包,如计算hash值等。
选择合适的queue。一般qemu在初始化设备时,会把tap的queue和虚拟设备的queue对应起来。
把数据包放入queue中,构造metadata信息。
本文章选择rtl8139为例,介绍rtl8139如何处理buf。 qemu从tap读取数据包后,会调用rtl8139_receive 函数去处理数据包,如下:
在rtl8139_receive函数的参数中,我们可以看到两个重要的参数,buf和size。buf就是数据包本身, size是数据包的大小,这两个信息也就是我们平时在抓包时所看到的内容。我们对应着代码中的顺序,介绍下接受函数主要做了什么处理:
rtl8139_receiver_enabled函数检查驱动是否开启了收取功能,如在虚拟机中未加载设备驱动或者关 闭了网卡设备,那么rtl8139没有必要再继续进行处理。
接着是根据驱动的配置是对数据包以太网头部的一个检查,驱动可以配置设备只收取单播、组播、广 播或者所有数据包。
如果数据包小于64bytes,设备会填充至64bytes。
rtl8139设备有两种缓冲管理模式,c mode和c+ mode,后者是一个增强模式,相比前者可以更高效 的处理数据包以及支持更多的特性。qemu在这里会把数据包放到rtl8139的缓冲中,这个缓冲区域属于虚拟机的一块内存区域。
调用qemu相关函数,触发中断。这个时候虚拟机内部OS开始处理设备中断。
从虚拟机中发包的流程和上述收包的流程类似,不过方向是反过来的,发包前,虚拟机内部驱动需要构 造出数据包的相关metadata,如并且告诉硬件数据包的地址和长度等信息,我们以rtl8139 c mode为例,看下linux内核如何处理这个过程:
数据包在linux内核中经过tcpip协议栈后,最后一步要调用驱动程序的ndo_start_xmit方法,对于 rtl8139设备,这个函数是rtl8139_start_xmit。
把数据包复制到发送缓冲区域。rtl8139 c mode对数据包的处理比较简单。
qemu收到设备的IO接口写操作时,会调用如下的rtl8139设备代码:
可以看到qemu调用writev函数往tap设备写入数据包。
九州云成立于2012年,是中国早期从事开放云边基础架构服务的专业公司。公司成立至今,始终秉承“开源·赋能云边变革”的理念,完成了从中心云到边缘云解决方案的拓展和积累,建立了完整的“云+边”生态体系和解决方案,赋能车路协同、工业元宇宙、园区数字孪生、文旅元宇宙等不同行业落地。九州云已先后为运营商、政府、金融、能源、制造业、商业、交通、物流、教育、医疗等各大行业的企业级客户提供了高质量的开放云边基础架构服务。目前拥有中国移动、中国电信、中国联通、国家电网、南方电网广东公司、中国人民银行、中国银联、中国人寿、中国资源卫星、Intel、国际陆港集团、一汽富晟、广西交科、中国青田元宇宙创新赋能中心等众多重量级客户。
2023年2月2日 / 通过: admin
https://www.99cloud.net/wp-content/uploads/2023/02/0-1675332221.jpeg
544
1276
admin
https://www.99cloud.net/wp-content/uploads/2023/03/九州云logo-白底1-ai.jpg
admin 2023-02-02 10:01:19 2023-02-02 18:04:13 技术周 | qemu网络收发包流程
喜报!九州云获评浙江省企业研究院称号 九州云:元宇宙时代,赋能工业制造新场景
滚动到顶部