Vhost-user详解
在软件实现的网络I/O半虚拟化中,vhost-user在性能、灵活性和兼容性等方面达到了近乎完美的权衡。虽然它的提出已经过了四年多,也已经有了越来越多的新特性加入,但是万变不离其宗,那么今天就从整个vhost-user数据通路的建立过程,以及数据包传输流程等方面详细介绍下vhost-user架构,本文基于DPDK 17.11分析。
vhost-user的最好实现在DPDK的vhost库里,该库包含了完整的virtio后端逻辑,可以直接在虚拟交换机中抽象成一个端口使用。在最主流的软件虚拟交换机OVS(openvswitch)中,就可以使用DPDK库。
vhost-user典型部署场景.png
vhost-user最典型的应用场景如图所示,OVS为每个虚拟机创建一个vhost端口,实现virtio后端驱动逻辑,包括响应虚拟机收发数据包的请求,处理数据包拷贝等。每个VM实际上运行在一个独立的QEMU进程内,QEMU是负责对虚拟机设备模拟的,它已经整合了KVM通信模块,因此QEMU进程已经成为VM的主进程,其中包含vcpu等线程。QEMU启动的命令行参数可以选择网卡设备类型为virtio,它就会为每个VM虚拟出virtio设备,结合VM中使用的virtio驱动,构成了virtio的前端。
1.建立连接
前面说到VM实际上是运行在QEMU进程内的,那么VM启动的时候要想和OVS进程的vhost端口建立连接,从而实现数据包通路,就需要先建立起来一套控制信道。这套控制信道是基于socket进程间通信,是发生在OVS进程与QEMU进程之间,而不是与VM,另外这套通信有自己的协议标准和message的格式。在DPDK的lib/librte_vhost/vhost_user.c中可以看到所有的消息类型:
static const char *vhost_message_str[VHOST_USER_MAX] = {
[VHOST_USER_NONE] = "VHOST_USER_NONE",
[VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES",
[VHOST_USER_SET_FEATURES] = "VHOST_USER_SET_FEATURES",
[VHOST_USER_SET_OWNER] = "VHOST_USER_SET_OWNER",
[VHOST_USER_RESET_OWNER] = "VHOST_USER_RESET_OWNER",
[VHOST_USER_SET_MEM_TABLE] = "VHOST_USER_SET_MEM_TABLE",
[VHOST_USER_SET_LOG_BASE] = "VHOST_USER_SET_LOG_BASE",
[VHOST_USER_SET_LOG_FD] = "VHOST_USER_SET_LOG_FD",
[VHOST_USER_SET_VRING_NUM] = "VHOST_USER_SET_VRING_NUM",
[VHOST_USER_SET_VRING_ADDR] = "VHOST_USER_SET_VRING_ADDR",
[VHOST_USER_SET_VRING_BASE] = "VHOST_USER_SET_VRING_BASE",
[VHOST_USER_GET_VRING_BASE] = "VHOST_USER_GET_VRING_BASE",
[VHOST_USER_SET_VRING_KICK] = "VHOST_USER_SET_VRING_KICK",
[VHOST_USER_SET_VRING_CALL] = "VHOST_USER_SET_VRING_CALL",
[VHOST_USER_SET_VRING_ERR] = "VHOST_USER_SET_VRING_ERR",
[VHOST_USER_GET_PROTOCOL_FEATURES] = "VHOST_USER_GET_PROTOCOL_FEATURES",
[VHOST_USER_SET_PROTOCOL_FEATURES] = "VHOST_USER_SET_PROTOCOL_FEATURES",
[VHOST_USER_GET_QUEUE_NUM] = "VHOST_USER_GET_QUEUE_NUM",
[VHOST_USER_SET_VRING_ENABLE] = "VHOST_USER_SET_VRING_ENABLE",
[VHOST_USER_SEND_RARP] = "VHOST_USER_SEND_RARP",
[VHOST_USER_NET_SET_MTU] = "VHOST_USER_NET_SET_MTU",
[VHOST_USER_SET_SLAVE_REQ_FD] = "VHOST_USER_SET_SLAVE_REQ_FD",
[VHOST_USER_IOTLB_MSG] = "VHOST_USER_IOTLB_MSG",
};
随着版本迭代,越来越多的feature被加进来,消息类型也越来越多,但是控制信道最主要的功能就是:传递建立数据通路必须的数据结构;控制数据通路的开启和关闭以及重连功能;热迁移或关闭虚拟机时传递断开连接的消息。
从虚拟机启动到数据通路建立完毕,所传递的消息都会记录在OVS日志文件中,对这些消息整理过后,实际流程如下图所示:
vhost-user控制信道消息流.png
左边一半为一些协商特性,尤其像后端驱动与前端驱动互相都不知道对方协议版本的时候,协商这些特性是必要的。特性协商完毕,接下来就要传递建立数据通路所必须的数据结构,主要包括传递共享内存的文件描述符和内存地址的转换关系,以及virtio中虚拟队列的状态信息。下面对这些最关键的部分一一详细解读。
设置共享内存
在虚拟机中,内存是由QEMU进程提前分配好的。QEMU一旦选择了使用vhost-user的方式进行网络通信,就需要配置VM的内存访问方式为共享的,具体的命令行参数在DPDK的文档中也有说明:
-object memory-bac