本文首發於我的公眾號 Linux雲計算網絡(id: cloud_dev),專注於干貨分享,號內有 10T 書籍和視頻資源,后台回復「1024」即可領取,歡迎大家關注,二維碼文末可以掃。
什么是 vhost
vhost 是 virtio 的一種后端實現方案,在 virtio 簡介中,我們已經提到 virtio 是一種半虛擬化的實現方案,需要虛擬機端和主機端都提供驅動才能完成通信,通常,virtio 主機端的驅動是實現在用戶空間的 qemu 中,而 vhost 是實現在內核中,是內核的一個模塊 vhost-net.ko。為什么要實現在內核中,有什么好處呢,請接着往下看。
為什么要用 vhost
在 virtio 的機制中,guest 與 用戶空間的 Hypervisor 通信,會造成多次的數據拷貝和 CPU 特權級的上下文切換。例如 guest 發包給外部網絡,首先,guest 需要切換到 host kernel,然后 host kernel 會切換到 qemu 來處理 guest 的請求, Hypervisor 通過系統調用將數據包發送到外部網絡后,會切換回 host kernel , 最后再切換回 guest。這樣漫長的路徑無疑會帶來性能上的損失。
vhost 正是在這樣的背景下提出的一種改善方案,它是位於 host kernel 的一個模塊,用於和 guest 直接通信,數據交換直接在 guest 和 host kernel 之間通過 virtqueue 來進行,qemu 不參與通信,但也沒有完全退出舞台,它還要負責一些控制層面的事情,比如和 KVM 之間的控制指令的下發等。
vhost 的數據流程
下圖左半部分是 vhost 負責將數據發往外部網絡的過程, 右半部分是 vhost 大概的數據交互流程圖。其中,qemu 還是需要負責 virtio 設備的適配模擬,負責用戶空間某些管理控制事件的處理,而 vhost 實現較為純凈,以一個獨立的模塊完成 guest 和 host kernel 的數據交換過程。
vhost 與 virtio 前端的通信主要采用一種事件驅動 eventfd 的機制來實現,guest 通知 vhost 的事件要借助 kvm.ko 模塊來完成,vhost 初始化期間,會啟動一個工作線程 work 來監聽 eventfd,一旦 guest 發出對 vhost 的 kick event,kvm.ko 觸發 ioeventfd 通知到 vhost,vhost 通過 virtqueue 的 avail ring 獲取數據,並設置 used ring。同樣,從 vhost 工作線程向 guest 通信時,也采用同樣的機制,只不過這種情況發的是一個回調的 call envent,kvm.ko 觸發 irqfd 通知 guest。
總結
vhost 與 kvm 的事件通信通過 eventfd 機制來實現,主要包括兩個方向的 event,一個是 guest 到 vhost 方向的 kick event,通過 ioeventfd 實現;另一個是 vhost 到 guest 方向的 call event,通過 irqfd 實現。
代碼分析整個通信的流程:
http://royluo.org/2014/08/22/vhost/
我的公眾號 「Linux雲計算網絡」(id: cloud_dev) ,號內有 10T 書籍和視頻資源,后台回復 「1024」 即可領取,分享的內容包括但不限於 Linux、網絡、雲計算虛擬化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++編程技術等內容,歡迎大家關注。