vhost protocol
发布网友
发布时间:2024-10-23 01:22
我来回答
共1个回答
热心网友
时间:2024-11-05 03:57
本文深入探讨了Virtio网络和vhost-net协议,重点在于用QEMU实现的virtio网卡。
virtio网络设备是虚拟以太网卡,支持TX/RX多队列。接收数据包时,空缓冲区放置在RX virtqueue中,输出数据包则在TX virtqueue中进行传输。管理通信通过另一个队列完成,例如设置MAC地址或调整队列数量。此设备支持卸载功能,如计算校验和、GSO/GRO,让真实物理网络设备执行。
发送数据包时,驱动程序填充描述符,包括卸载信息和数据帧缓冲区。数据帧可以以SG形式串联成多个描述符。这些数据结构由guest中的驱动程序分配和管理,但由于设备实际在QEMU内,QEMU可以访问所有guest内存,因此设备能够定位缓冲区并读写它们。
接收数据包流程类似,唯一的区别是空缓冲区由guest预先分配,以便将接收到的数据写入这些缓冲区。
然而,QEMU实现virtio-net设备存在一些缺点,包括高昂的上下文切换成本、需要额外的任务/线程同步机制、每个报文收发需要系统调用和数据拷贝、使用ioctl发送通知以及需要额外系统调用来恢复vCPU执行。
为了解决这些问题,设计了vhost协议,它是一种基于消息的协议,允许hypervisor将数据平面卸载到更高效的组件。使用vhost API,hypervisor向handler发送内存布局、文件描述符等配置信息,卸载设备完全由handler处理,它直接访问virtqueues内存区域并直接向guest发送/接收通知。
vhost消息可以在主机本地传输协议中交换,如Unix套接字或字符设备,hypervisor和handler可以作为服务器或客户端进行通信。在这种情况下,vhost-net内核驱动程序作为handler实现vhost协议,与QEMU交互并处理数据包转发。
加载vhost-net内核驱动程序后,创建/dev/vhost-net字符设备,qemu使用ioctl调用初始化vhost-net实例,包括将hypervisor与实例关联、准备功能协商并传递guest物理内存映射。初始化期间创建名为vhost-$pid的内核线程,用于处理I/O事件,如轮询guest驱动的通知或tap事件。
使用eventfd实现通知绕过机制,vhost工作线程轮询它,当guest写入特定PCI MMIO地址触发vm-exit进入KVM时,KVM检测到关联的ioeventfd并写入fd。这避免了昂贵的QEMU进程唤醒,同时实现异步处理,无需立即上下文切换。
另外,使用irqfd实现直接vCPU中断注入机制,允许主机进程通过写入irqfd向guest注入中断,同样具备异步处理和无需立即上下文切换的优点。
值得注意的是,尽管此类更改发生在后端数据包处理中,但对仍然使用标准virtio接口的guest来说,这一变化是透明的。