淺談 Linux 設備虛擬化技術的演進之路
序言
設備虛擬化技術,一直是雲計算領域最重要的基礎技術之一。我們在虛擬機裏面看到的形形色色的設備,比如:網卡,磁盤,鍵盤,鼠標等,都離不開這項技術的幫助。這篇文章,我們將從技術演進的角度來談一談 Linux 現有的以及即將到來的設備虛擬化技術。
Trap-and-emulate
在最早期階段,設備虛擬化常常和機器模擬器技術,比如:QEMU,綁定在一起。我們可以通過 QEMU 模擬真實設備的所有寄存器佈局和操作流程,當 QEMU 虛擬機裏面設備驅動需要訪問該虛擬設備的寄存器時,這條訪問指令會被 trap 到 QEMU,由 QEMU 來進行處理。這樣,虛擬機裏面的設備驅動在操作該虛擬設備時就像在訪問真實的硬件設備一樣,設備驅動也不需要任何變更。
Virtio
通過上述這種 trap-and-emulate 的方式來模擬設備,雖然不需要對真實設備驅動進行變更,但是設備訪問過程中,頻繁的陷入 & 陷出帶來了嚴重的性能問題,因此,virtio 這類半虛擬化技術應運而生,並於 2008 年合入 Linux 內核主線。
相較於 trap-and-emulate 這種方式,Virtio 不再拘泥於依賴已有的設備驅動,而是定義了一套全新的專用於虛擬設備的驅動框架。設備驅動清楚自己是在操作虛擬設備,因此,在真正的 I/O 路徑上規避了大量可能導致陷入 & 陷出的 mmio/pio 操作,從而提高了性能。虛機裏面的 Virtio 驅動和 QEMU 模擬的 Virtio 設備的數據交互,本質上是一套基於共享內存 + 環形隊列的通信機制。核心數據結構(split virtqueue)包括:兩個 ringbuffer (avail ring, used ring) 和一個 descriptor table。工作機制類似 DMA,虛機內 virtio 驅動首先會將一個請求在內存中需要傳輸的散列 buffer 的地址、長度組成一個個描述符寫入到 descriptor table 中,然後將這些描述符對應的 descriptor table 上的 index 寫入到 avail ring 中,並通過 eventfd 機制通知到宿主機上的 virtio backend。由於這些 ringbuffer、descriptor table 以及散列 buffer 都在共享內存中(虛機本質上是一個用戶態進程,因此虛機內存是由用戶態申請和分配,並可以 share 給其他進程,如:SPDK,DPDK 等),因此,Virtio Backend 可以直接訪問並獲取到散列 buffer 的地址、長度,進而直接存取這些散列 buffer。當處理完請求之後,Virtio Backend 將數據填充到相應的 buffer,並將對應的 descriptor table index 寫入 used ring 中,並通過 eventfd 機制注入中斷通知虛機內 virtio 驅動。
Vhost
Virtio 技術提出之後,Virtio 設備通常是在 QEMU 裏面來進行模擬,數據收發都需要經過 QEMU,再到虛機內部。但逐漸地,開發者們發現,當模擬網卡時,在 QEMU 裏面進行數據收發,最終都需要通過系統調用的方式,陷入內核來操作網卡硬件進行實際的數據收發。那麼,QEMU 到內核的這次上下文切換以及帶來的額外拷貝開銷,有沒有辦法優化呢?
Linux 內核社區最終在 2010 年合入了 vhost 這個技術來進行優化,通過將 virtio 的數據面 offload 到一個內核線程來進行處理,這樣 virtio 通信機制從原本的 QEMU 用戶態 I/O 線程和虛機驅動(QEMU 用戶態 vcpu 線程)通信變成了 vhost 內核 I/O 線程和虛機驅動(QEMU 用戶態 vcpu 線程)通信。vhost 內核 I/O 線程拿到數據包之後,直接走內核協議棧和網卡驅動進行處理,從而優化掉了 QEMU 到內核態的額外開銷。
VFIO
隨着雲計算規模的不斷擴大,用戶一方面不再滿足於 Virtio 這類半虛擬化設備帶來的性能體驗,另一方面 GPU 這類很難進行 virtio 化的設備應用場景與日俱增。在這種背景下,VFIO 這項技術被提出並在 2012 年合入 Linux 內核主線。VFIO 全稱是 Virtual Function I/O,它實際是一個用戶態設備驅動框架,相較於更早的 uio 這個用戶態設備驅動框架,VFIO 能夠有效利用硬件 IOMMU 機制進行安全隔離,從而能夠廣泛地應用在雲計算這類有多租戶需求的場景中。
如上圖所示,通過 VFIO,QEMU 能夠直接將自己虛擬出的一個 PCI 設備和一個物理 PCI 設備的數據鏈路直接打通,當虛擬機裏面的設備驅動訪問虛擬 PCI 設備的 bar 空間時,通過 EPT 機制,這次 mmio 訪問會被重定向到真實物理設備相應的 bar 空間位置,而不再需要 trap 到 QEMU。這樣,虛機驅動就相當於可以以接近零消耗的方式直接訪問真實物理設備,性能可以達到最佳。同時,VFIO 驅動利用 IOMMU 實現了設備 DMA 和中斷的重映射,一方面起到隔離作用,即某個虛機無法操作 VFIO 直通設備向同一宿主機上的其他虛機發起 DMA 和中斷,一方面也保證了設備進行 DMA 時通過給定的虛機物理地址能夠直接訪問到正確的物理內存。
Vhost-user
雖然,VFIO 能夠給虛機帶來接近物理機的 I/O 性能體驗,但該技術仍存在一個缺陷,即不支持熱遷移,帶 VFIO 設備的虛機將沒法像傳統帶 virtio 設備的虛機那樣進行熱遷移。這就使得開發者們,又開始探尋新的既能滿足性能需求又具備運維靈活性的設備虛擬化技術。2014 年 QEMU 社區合入的 vhost-user 技術就是其中之一,由於 QEMU 和 vhost 的線程模型對 I/O 性能的優化並不友好,而且由每個虛機單獨分出線程來處理 I/O 這種方式從系統全局角度來看可能也並不是最優的,因此,vhost-user 提出了一種新的方式,即將 virtio 設備的數據面 offload 到另一個專用進程來處理。這樣,由於是專用進程,線程模型不再受傳統 QEMU 和 vhost 線程模型制約,可以任意優化,同時,還可以以 1:M 的方式同時處理多個虛機的 I/O 請求,而且相較於 vhost 這種內核線程方式,用戶進程在運維方面更加具備靈活性,vhost-user 框架在提出之初,就受到廣泛關注,並引申出了 SPDK 和 OVS-DPDK 這類以 polling + 用戶態驅動爲核心的新的虛機 I/O 服務模型。
VFIO-mdev
VFIO 技術在實際應用場景,除了之前提到的不支持熱遷移的問題外,還有一個限制就是一個設備只能透傳給一個虛機,無法做到資源共享。SR-IOV 技術從某種程度上能夠解決這個問題,即將一個物理 PCI 設備從硬件層面進行資源劃分,劃分成多個 VF,透傳給多個虛機進行使用,但是有很多設備可能並不具備 SR-IOV 能力,因此,Linux 內核社區在 2016 年合入了 VFIO-mdev 這個技術框架,希望提供一個標準的接口來幫助設備驅動實現軟件層面的資源切分並能夠利用 VFIO 技術透傳給虛機。
該技術本質上是在內核實現了一個虛擬設備(Mediated device)總線驅動模型,並在 VFIO 內核框架上進行了擴展,增加了對 mdev 這類虛擬設備的支持(mdev bus driver),從原來只支持從標準的硬件 PCI 設備和硬件 platform 設備獲取透傳信息,比如:PCI bar 空間,變成了既支持直接從硬件設備獲取又可以從 mdev 設備驅動定義的虛擬設備接口來獲取。這樣,比如,當需要將一個 PCI 設備的 bar 空間作爲資源切分的話,通過實現合適的 mdev 設備驅動,就可以將 bar 空間以 4KB(頁面大小)爲粒度,分別透傳給不同虛機使用。
vDPA
VFIO 和 virtio 這兩類技術一直是最主流的設備虛擬化技術。VFIO 能夠直接將硬件資源透傳給虛機使用,性能最佳,virtio 性能稍遜,但勝在更加靈活。那有沒有可能將兩者的優勢結合起來呢?2020 年被合入 Linux 內核主線的 vDPA 技術框架,就是爲了實現這一目標。
vDPA 的全稱是 Virtio Data Path Acceleration,它表示一類設備:這類設備的數據面處理是嚴格遵循 Virtio 協議規範的,即驅動和設備會按照第三節提到的 Virtio 通信流程來進行通信,但控制路徑,比如:通信流程裏面提到的 ring buffer 和 descriptor table 的內存地址,驅動如何告知設備,設備支持的特性,驅動如何感知,這些都是廠商自定義的,不一定會遵循 Virtio 協議。這樣做的好處是,可以降低廠商在實現這類設備時的複雜度。
Linux 內核爲了將這類設備應用起來,就提出了 vDPA 這樣一個技術框架。這個技術框架本質上和 VFIO-mdev 類似,也實現了一個虛擬設備(vDPA device)總線驅動模型,和 VFIO-mdev 不同的是,通過 vDPA 框架虛擬出來的設備,既可以給虛機使用,又可以直接從宿主機(比如:容器)進行訪問。這一切都歸功於,vDPA 設備的數據路徑是遵循 Virtio 協議規範的,因此,可以直接被宿主機上的 virtio 驅動直接訪問。同時,該技術框架對 vhost 內核子系統進行了擴展,賦予了類似 VFIO 技術框架的功能,允許將 vDPA 設備用來進行數據通信的硬件資源(ring buffer, descriptor table,doorbell 寄存器等)透傳給虛機使用,這樣,虛擬機的 virtio 驅動進行數據通信時,也是直接訪問硬件資源,而不再需要通過 vhost、vhost-user 等方式進行處理了。更重要的一點是,由於虛機驅動是原本的 virtio 驅動,因此,當需要支持熱遷移時,QEMU 可以靈活切換會軟件模擬的方式,來保證熱遷移的順利進行。這樣,vDPA 這個設備虛擬化技術框架既保證了最佳性能又保留了 virtio 設備的靈活性,而且還統一了虛機和容器的 I/O 技術棧。
VDUSE
通過上述 vDPA 技術框架,我們基本解決了長期以來設備虛擬化技術在虛機場景下暴露的一些問題,而更重要的是,它將 virtio 技術也帶到了容器領域。但這個技術框架還存在一個問題,就是需要硬件設備的支持。回想之前提到的 virtio、vhost、vhost-user,本質上都是軟件定義的虛擬設備。那 vDPA 這個技術框架有沒有可能也能夠使用軟件定義的設備呢?VDUSE 這項技術就是用來實現這個目標的,通過 VDUSE,我們可以在一個用戶進程實現一個軟件定義的 vDPA 設備,並可以通過上述 vDPA 框架接入 virtio 或者 vhost 子系統,供容器或者虛機使用。
該項技術是由我們自主研發並在去年 10 月向 Linux 內核社區正式開源的。現階段我們的方案已經被合入 Linux 內核主線,將在 Linux 5.15 版本與大家見面。同時,我們也會在 9 月 15 日舉辦的 KVM Forum 這個虛擬化領域的高端技術論壇會議上進行線上分享。
結束語
從服務虛擬機到支持容器,從純軟件模擬到硬件直通再到軟硬件結合,Linux 設備虛擬化技術這幾十年裏一直在朝着極致性能、應用靈活等方向不斷演進。隨着雲原生的浪潮,各大硬件廠商的入局,全新的軟硬件結合方式不斷湧現,我們相信後續也會有更多精彩技術在等待着我們。
參考鏈接
-
https://www.ozlabs.org/~rusty/virtio-spec/virtio-paper.pdf
-
https://www.redhat.com/en/blog/introduction-virtio-networking-and-vhost-net
-
https://www.kernel.org/doc/html/latest/driver-api/vfio.html
-
https://gitlab.com/qemu-project/qemu/-/blob/master/docs/interop/vhost-user.rst
-
https://www.kernel.org/doc/html/latest/driver-api/vfio-mediated-device.html
-
https://www.redhat.com/en/blog/introduction-vdpa-kernel-framework
-
https://www.kernel.org/doc/html/latest/userspace-api/vduse.html
-
https://events.linuxfoundation.org/kvm-forum/program/schedule/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/g1kt0DDJwDk2Lg56R5suKw