首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

[linux][network]虚拟网卡技术分析

前言: 虚拟化场景下的网卡虚拟化,就是让虚拟机觉得自己有网卡。就有了e1000/rtl8139为代表的物理网卡软件模拟实现;为了加速Guest和Host之间的数据交换速度,就有了virtio网卡;再virtio的基础上,为了减少qemu进程和host os之间的数据拷贝,就有了vhost-net。这几种情况下,都是完全使用软件模拟的网卡,使用TAP技术,虚拟化出来net device,再把对应的net device接入到网桥上,这样在虚拟机内存就可以向外部写数据了。 还有一类就是物理网卡提供了虚拟化能力。比如ixgbe提供了sriov能力。那么物理网卡虚拟化成多块网卡,再把虚拟网卡passthrough给虚拟机。 再有就是DPDK这种类型的玩法。 下面重点看虚拟网卡的实现原理。 分析: 1,PCI device QEMU虚拟化的440fx主板,网卡作为PCI Device会连接在PCI bus上。

用libvirt配置网卡的时候,可以指定PCI网卡的地址,例如<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> 如果不指定,libvirt会自动选择一个空的slot配置给网卡。 2,e1000/rtl8139的实现 Guest在遍历PCI设备的时候,扫描到<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>的时候,读对应的PCI config,就会发现一个e1000网卡(以e1000为例)。Guest使用PIO,MMIO和PCI 设备进行交互。如下图,

看数据流向,例如虚拟机中发送了一个packet,那么就会通过PIO/MMIO操作操作对应的PCI设备,把数据填写到了对应的register中;QEMU截获到对应的操作,读取对应的register中的数据,再组织起来,然后写给Host OS的TAP设备。TAP设备把数据路由到BRIDGE,BRIDGE再把数据路由到NIC。数据包就发送出去了。 3,virtio-net e1000/rtl8139类型的网卡,CPU会把很多时间花费在写register,读register上。而且Guest在写register的时候,会让vm陷入异常,退出VM mode。 在虚拟化的场景下,VM的内存,和QEMU的控制代码,在同一个进程中,就意味着,内存可以互相访问。

那么virtio场景下的数据流向,就会变得短一些了:虚拟机中发送的packet,放到了虚拟机的内存(VringBuf)中。然后继续使用PIO访问,那么,QEMU就会截获到PIO操作。注意,这个PIO操作只需要写16bit就可以了,只是告诉QEMU有数据了。然后QEMU计算出来 VringBuf的HVA,把数据再写到TAP网卡中。可见,在virtio通信的过程中,是标准的PCI设备访问,不过差别就在于PIO做控制用,只需要传递少量的数据,大部分的数据通过共享内存实现。 在这个过程中,Guest中的driver没有任何一个地方需要判断自己是否跑在VM中,Host在加载Guest的时候,也不会修改Guest的virtio的二进制代码。Guest访问virtio网卡,也是使用PIO访问的标准的PCI设备。所以,KVM下的virtio为什么要叫半虚拟化设备? 有人会说,windows访问virtio网卡的时候,需要安装驱动。那么访问usb3.0的时候,也需要安装驱动,那么usb3.0也是半虚拟化设备? 同样的逻辑,是不是只能跑在虚拟机中?作者觉得是有机会跑在物理机上的。尤其是在嵌入式领域,比如你的手机,手机厂商提供的参数中内存是2G,但是实际可用的内存只会有1.6G,或者再多一些的样子。因为其他的内存被分配给了基带,硬件decode上。它们和CPU之间的通信,就是在共享内存。 4,vhost-net virtio已经优化掉了虚拟网卡路径上耗时最大的部分。但是,还有优化的空间:从Qemu把VringBuf中的数据写进了TAP网卡。这个过程是不是也可以优化? VM和QEMU在同一个进程中,所以可以共享内存。但是它们都在Host OS上,Host OS当然可以访问主机上的内存。

那么,数据路径就是:VM发送packet,写到了VringBuf中,通知Vhost-netdriver,Vhost-net计算出来Vringbuf的地址,直接填写给TAP设备。 Vhost-net减少了QEMU进程执行write系统调用的那次从user mode拷贝数据到kernel mode的过程。所以也叫zero copy。 5,virtio notify

Guest 在kick的时候,会执行到vp_notify函数。这个函数看起来很简单,就是执行了iowrite16。它的原理就在于,iowrite16的时候,就是执行PIO,PIO的指令会被Host截获到。所以Host就知道了Guest写数据了。同样,MMIO也可以。不过MMIO的处理路径比PIO要长一些,CPU消耗稍微高一点。 6,QoS libvirt提供了对网卡设置QoS的xml。需要提一下的时候,libvirt使用tc限速,不能对bridge类型的网卡限速。所以限速的位置可以选择在BRIDGE的port上。 后记: 虚拟网卡的能力,从e1000到virtio,再到vhost-net ,越来越强大。当然要比SRIOVS的能力弱一点。 但是虚拟网卡的好处在于和硬件无关,一台普通的x86服务器都可以。虚拟机的热迁移能力不会因为网卡而限制。虚拟机的运行主机也不需要过多限制。超融合,或者没有那么严格要求的性能的私有云场景下,使用vhost-net都是一个不错的选择。

下一篇
举报
领券