一、virtio-net的发展
virtio-net的驱动最初从后端再到内核怸的vhost-net,发展到用户态的vhost-user,其实就是对效率和扩展性的一个不断演进的过程。在前面提到过,提高云环境下的网络数据传输速度,一个是减少传播路径,一个是减少中断的影响。然后再辅以软件硬件上的配合,如CPU亲和性处置、内在控制和各种调优等。而在减少传播路径中,用户态直接处理设备数据则可以大大减少数据传输的流程。
从这些结果上反推刚刚的vhost的发展,就可以明白了,一开始只是一个单纯的后端,需要不断的处理用户态、内核态的数据交互;后来干脆直接搞进内核,减少了一部分;最后另起炉灶直接在用户态处理,只是为了保证有些和内核必要的通信增加了通信的接口。
这里面其实也不是说这种用户态的就一定完美,至少,它还是额外增加了开发成本。但是这种成本在实际应用中是舍得付出的,那么就可以这样做。
二、主要功能
vhost技术主要是优化了virtio-net的后端驱动。vhost后端服务主要有三个部分:内核模块、qemu部分和KVM部分。内核模块其实是把原virtio后端驱动数据部分迁移到了内核中而控制部分仍然在上层qemu中。vhost相当于实现了一个后端的virtio server server。它通过virtio ring实现了用户端对网络设备的读写。qumu主要是前面的分析的virtio部分,其通过KVM来模拟系统环境;而KVM则是独立于“传统内核模块”之外的,负责为程序提供虚拟化硬件支持内核模块。
而在最初的后端驱动中,主要的就是“虚拟队列、消息通知和中断”三大机制。为了对后端驱动进行优化,则在vhost-net中,在内核中增加了相应模块,通过中断来实现内核虚拟队列操作减少了拷贝。同样,vhost-user进一步绕过内核直接共享虚拟队列来实现用户层和设备的数据通信。
将上述说的更直白一些,就是在内核态的vhost绕过了上层qemu的模拟状态转换减少数据操作而vhost-user则是进一步绕过了内核,直接让用户层和设备进行数据操作。前者是虚拟机(client)与内核(server)的数据交互,虚拟机与内核共享数据队列,缺点是如果与用户进程进行通信比较麻烦; 而后者(vhost-user)使用unix domain来通信,用户进程间共享内存,其效果和前者一样。
三、DPDK中的应用
DPDK的vhost采用的vhost-user,有两种封装形式,即lib,PMD。前者实现了用户态的vhost驱动供其应用程序调用;而后者对lib进行了进一步的封装,抽象为一个虚拟端口,可以使其象标准端口一样通过接口调用来实现管理和数据报文的收发。DPDK的vhost-user其实是在virtio PMD基础上进行修改而来的。在DPDK中,容器环境下虚拟机是通过qemu来模拟的,这就导致数据共享时会将所有环境数据与宿主机(物理机)共享,但实际上只有数据交互部分的大页内在有实际的意义。从DPDK的角度来看,virtio-user是一个由virtio前端驱动虚拟出来的一个虚拟设备,其后端对就着相应的用户态的vhost-user,二者之间就是通过进程间通信来实现数据交互。同时,为了保证一些异常数据和内核的交互,还需要通过接口实现virtio-user和内核的交互。
四、源码
vhost的源码在包含上一节中已经展现的virtio源码的部分,另外还有lib/librte_vhost相关的一些接口代码,这里重点说一下相关的注意点:
1、通信是采用Socket通信,所以其可以采用客户端或者服务端两种形式,但在后续版本默认为服务端
2、Socket的通信数据交互是在OVS进程和QEMU进程间,而不是和VM之间(VM进程运行于QEMU进程内)
3、DPDK有自己的通信Message格式(lib/librte_vhost/vhost_user.c)
4、必须要在源码中卸载virtio在内核中原有的相关部分
5、必须处理OVS(Open vSwitch)的轮询
五、总结
vhost的存在,其实最主要的就是减少虚拟机通过Hypervisor与网卡的数据传输路径和数据的拷贝,所以在网上可以经常看到它被叫做加速器。它通过队列直接将数据和tap(内核中的虚拟以太网设备)设备进行交互,大家都知道,内核态和用户态的数据交的成本是相当高的,减少的交互越多,理论上数据传输的效率越高。而在DPDK中更是将其提到virtio-user即vhost-user,可以理解其为一个虚拟的设备,这样就可以更好的提供网络的通信。同时,它也可以支持目前云环境下的容器中virtio的应用。
不过掠过内核后,传统的TCP/UDP编程就需要改变一下,这个在网上也有很多相关的资料,反正,不可能是光有优点,没有劣势,各取所需吧。