序言
設(shè)備虛擬化技術(shù),一直是云計(jì)算領(lǐng)域最重要的基礎(chǔ)技術(shù)之一。我們在虛擬機(jī)里面看到的形形色色的設(shè)備,比如:網(wǎng)卡,磁盤,鍵盤,鼠標(biāo)等,都離不開這項(xiàng)技術(shù)的幫助。這篇文章,我們將從技術(shù)演進(jìn)的角度來談一談 Linux 現(xiàn)有的以及即將到來的設(shè)備虛擬化技術(shù)。
Trap-and-emulate
在最早期階段,設(shè)備虛擬化常常和機(jī)器模擬器技術(shù),比如:QEMU,綁定在一起。我們可以通過 QEMU 模擬真實(shí)設(shè)備的所有寄存器布局和操作流程,當(dāng) QEMU 虛擬機(jī)里面設(shè)備驅(qū)動需要訪問該虛擬設(shè)備的寄存器時(shí),這條訪問指令會被 trap 到 QEMU,由 QEMU 來進(jìn)行處理。這樣,虛擬機(jī)里面的設(shè)備驅(qū)動在操作該虛擬設(shè)備時(shí)就像在訪問真實(shí)的硬件設(shè)備一樣,設(shè)備驅(qū)動也不需要任何變更。
Virtio
通過上述這種 trap-and-emulate 的方式來模擬設(shè)備,雖然不需要對真實(shí)設(shè)備驅(qū)動進(jìn)行變更,但是設(shè)備訪問過程中,頻繁的陷入&陷出帶來了嚴(yán)重的性能問題,因此,virtio 這類半虛擬化技術(shù)應(yīng)運(yùn)而生,并于 2008 年合入 Linux 內(nèi)核主線。
相較于 trap-and-emulate 這種方式,Virtio 不再拘泥于依賴已有的設(shè)備驅(qū)動,而是定義了一套全新的專用于虛擬設(shè)備的驅(qū)動框架。設(shè)備驅(qū)動清楚自己是在操作虛擬設(shè)備,因此,在真正的 I/O 路徑上規(guī)避了大量可能導(dǎo)致陷入&陷出的 mmio/pio 操作,從而提高了性能。虛機(jī)里面的 Virtio 驅(qū)動和 QEMU 模擬的 Virtio 設(shè)備的數(shù)據(jù)交互,本質(zhì)上是一套基于共享內(nèi)存 + 環(huán)形隊(duì)列的通信機(jī)制。核心數(shù)據(jù)結(jié)構(gòu)(split virtqueue)包括:兩個(gè) ringbuffer (avail ring, used ring) 和一個(gè) descriptor table。工作機(jī)制類似 DMA,虛機(jī)內(nèi) virtio 驅(qū)動首先會將一個(gè)請求在內(nèi)存中需要傳輸?shù)纳⒘?buffer 的地址、長度組成一個(gè)個(gè)描述符寫入到 descriptor table 中,然后將這些描述符對應(yīng)的 descriptor table 上的 index 寫入到 avail ring 中,并通過 eventfd 機(jī)制通知到宿主機(jī)上的 virtio backend。由于這些 ringbuffer、descriptor table 以及散列 buffer 都在共享內(nèi)存中(虛機(jī)本質(zhì)上是一個(gè)用戶態(tài)進(jìn)程,因此虛機(jī)內(nèi)存是由用戶態(tài)申請和分配,并可以 share 給其他進(jìn)程,如:SPDK,DPDK 等),因此,Virtio Backend 可以直接訪問并獲取到散列 buffer 的地址、長度,進(jìn)而直接存取這些散列 buffer。當(dāng)處理完請求之后,Virtio Backend 將數(shù)據(jù)填充到相應(yīng)的 buffer,并將對應(yīng)的 descriptor table index 寫入 used ring 中,并通過 eventfd 機(jī)制注入中斷通知虛機(jī)內(nèi) virtio 驅(qū)動。
Vhost
Virtio 技術(shù)提出之后,Virtio 設(shè)備通常是在 QEMU 里面來進(jìn)行模擬,數(shù)據(jù)收發(fā)都需要經(jīng)過 QEMU,再到虛機(jī)內(nèi)部。但逐漸地,開發(fā)者們發(fā)現(xiàn),當(dāng)模擬網(wǎng)卡時(shí),在 QEMU 里面進(jìn)行數(shù)據(jù)收發(fā),最終都需要通過系統(tǒng)調(diào)用的方式,陷入內(nèi)核來操作網(wǎng)卡硬件進(jìn)行實(shí)際的數(shù)據(jù)收發(fā)。那么,QEMU 到內(nèi)核的這次上下文切換以及帶來的額外拷貝開銷,有沒有辦法優(yōu)化呢?
Linux 內(nèi)核社區(qū)最終在 2010 年合入了 vhost 這個(gè)技術(shù)來進(jìn)行優(yōu)化,通過將 virtio 的數(shù)據(jù)面 offload 到一個(gè)內(nèi)核線程來進(jìn)行處理,這樣 virtio 通信機(jī)制從原本的 QEMU 用戶態(tài) I/O 線程和虛機(jī)驅(qū)動(QEMU 用戶態(tài) vcpu 線程)通信變成了 vhost 內(nèi)核 I/O 線程和虛機(jī)驅(qū)動(QEMU 用戶態(tài) vcpu 線程)通信。vhost 內(nèi)核 I/O 線程拿到數(shù)據(jù)包之后,直接走內(nèi)核協(xié)議棧和網(wǎng)卡驅(qū)動進(jìn)行處理,從而優(yōu)化掉了 QEMU 到內(nèi)核態(tài)的額外開銷。
VFIO
隨著云計(jì)算規(guī)模的不斷擴(kuò)大,用戶一方面不再滿足于 Virtio 這類半虛擬化設(shè)備帶來的性能體驗(yàn),另一方面 GPU 這類很難進(jìn)行 virtio 化的設(shè)備應(yīng)用場景與日俱增。在這種背景下,VFIO 這項(xiàng)技術(shù)被提出并在 2012 年合入 Linux 內(nèi)核主線。VFIO 全稱是 Virtual Function I/O,它實(shí)際是一個(gè)用戶態(tài)設(shè)備驅(qū)動框架,相較于更早的 uio 這個(gè)用戶態(tài)設(shè)備驅(qū)動框架,VFIO 能夠有效利用硬件 IOMMU 機(jī)制進(jìn)行安全隔離,從而能夠廣泛地應(yīng)用在云計(jì)算這類有多租戶需求的場景中。
如上圖所示,通過 VFIO,QEMU 能夠直接將自己虛擬出的一個(gè) PCI 設(shè)備和一個(gè)物理 PCI 設(shè)備的數(shù)據(jù)鏈路直接打通,當(dāng)虛擬機(jī)里面的設(shè)備驅(qū)動訪問虛擬 PCI 設(shè)備的 bar 空間時(shí),通過 EPT 機(jī)制,這次 mmio 訪問會被重定向到真實(shí)物理設(shè)備相應(yīng)的 bar 空間位置,而不再需要 trap 到 QEMU。這樣,虛機(jī)驅(qū)動就相當(dāng)于可以以接近零消耗的方式直接訪問真實(shí)物理設(shè)備,性能可以達(dá)到最佳。同時(shí),VFIO 驅(qū)動利用 IOMMU 實(shí)現(xiàn)了設(shè)備 DMA 和中斷的重映射,一方面起到隔離作用,即某個(gè)虛機(jī)無法操作 VFIO 直通設(shè)備向同一宿主機(jī)上的其他虛機(jī)發(fā)起 DMA 和中斷,一方面也保證了設(shè)備進(jìn)行 DMA 時(shí)通過給定的虛機(jī)物理地址能夠直接訪問到正確的物理內(nèi)存。
Vhost-user
雖然,VFIO 能夠給虛機(jī)帶來接近物理機(jī)的 I/O 性能體驗(yàn),但該技術(shù)仍存在一個(gè)缺陷,即不支持熱遷移,帶 VFIO 設(shè)備的虛機(jī)將沒法像傳統(tǒng)帶 virtio 設(shè)備的虛機(jī)那樣進(jìn)行熱遷移。這就使得開發(fā)者們,又開始探尋新的既能滿足性能需求又具備運(yùn)維靈活性的設(shè)備虛擬化技術(shù)。2014 年 QEMU 社區(qū)合入的 vhost-user 技術(shù)就是其中之一,由于 QEMU 和 vhost 的線程模型對 I/O 性能的優(yōu)化并不友好,而且由每個(gè)虛機(jī)單獨(dú)分出線程來處理 I/O 這種方式從系統(tǒng)全局角度來看可能也并不是最優(yōu)的,因此,vhost-user 提出了一種新的方式,即將 virtio 設(shè)備的數(shù)據(jù)面 offload 到另一個(gè)專用進(jìn)程來處理。這樣,由于是專用進(jìn)程,線程模型不再受傳統(tǒng) QEMU 和 vhost 線程模型制約,可以任意優(yōu)化,同時(shí),還可以以 1:M 的方式同時(shí)處理多個(gè)虛機(jī)的 I/O 請求,而且相較于 vhost 這種內(nèi)核線程方式,用戶進(jìn)程在運(yùn)維方面更加具備靈活性,vhost-user 框架在提出之初,就受到廣泛關(guān)注,并引申出了 SPDK 和 OVS-DPDK 這類以 polling + 用戶態(tài)驅(qū)動為核心的新的虛機(jī) I/O 服務(wù)模型。
VFIO-mdev
VFIO 技術(shù)在實(shí)際應(yīng)用場景,除了之前提到的不支持熱遷移的問題外,還有一個(gè)限制就是一個(gè)設(shè)備只能透傳給一個(gè)虛機(jī),無法做到資源共享。SR-IOV 技術(shù)從某種程度上能夠解決這個(gè)問題,即將一個(gè)物理 PCI 設(shè)備從硬件層面進(jìn)行資源劃分,劃分成多個(gè) VF,透傳給多個(gè)虛機(jī)進(jìn)行使用,但是有很多設(shè)備可能并不具備 SR-IOV 能力,因此,Linux 內(nèi)核社區(qū)在 2016 年合入了 VFIO-mdev 這個(gè)技術(shù)框架,希望提供一個(gè)標(biāo)準(zhǔn)的接口來幫助設(shè)備驅(qū)動實(shí)現(xiàn)軟件層面的資源切分并能夠利用 VFIO 技術(shù)透傳給虛機(jī)。
該技術(shù)本質(zhì)上是在內(nèi)核實(shí)現(xiàn)了一個(gè)虛擬設(shè)備(Mediated device)總線驅(qū)動模型,并在 VFIO 內(nèi)核框架上進(jìn)行了擴(kuò)展,增加了對 mdev 這類虛擬設(shè)備的支持(mdev bus driver),從原來只支持從標(biāo)準(zhǔn)的硬件 PCI 設(shè)備和硬件 platform 設(shè)備獲取透傳信息,比如:PCI bar 空間,變成了既支持直接從硬件設(shè)備獲取又可以從 mdev 設(shè)備驅(qū)動定義的虛擬設(shè)備接口來獲取。這樣,比如,當(dāng)需要將一個(gè) PCI 設(shè)備的 bar 空間作為資源切分的話,通過實(shí)現(xiàn)合適的 mdev 設(shè)備驅(qū)動,就可以將 bar 空間以 4KB(頁面大小)為粒度,分別透傳給不同虛機(jī)使用。
vDPA
VFIO 和 virtio 這兩類技術(shù)一直是最主流的設(shè)備虛擬化技術(shù)。VFIO 能夠直接將硬件資源透傳給虛機(jī)使用,性能最佳,virtio 性能稍遜,但勝在更加靈活。那有沒有可能將兩者的優(yōu)勢結(jié)合起來呢?2020 年被合入 Linux 內(nèi)核主線的 vDPA 技術(shù)框架,就是為了實(shí)現(xiàn)這一目標(biāo)。
vDPA 的全稱是 Virtio Data Path Acceleration,它表示一類設(shè)備:這類設(shè)備的數(shù)據(jù)面處理是嚴(yán)格遵循 Virtio 協(xié)議規(guī)范的,即驅(qū)動和設(shè)備會按照第三節(jié)提到的 Virtio 通信流程來進(jìn)行通信,但控制路徑,比如:通信流程里面提到的 ring buffer 和 descriptor table 的內(nèi)存地址,驅(qū)動如何告知設(shè)備,設(shè)備支持的特性,驅(qū)動如何感知,這些都是廠商自定義的,不一定會遵循 Virtio 協(xié)議。這樣做的好處是,可以降低廠商在實(shí)現(xiàn)這類設(shè)備時(shí)的復(fù)雜度。
Linux 內(nèi)核為了將這類設(shè)備應(yīng)用起來,就提出了 vDPA 這樣一個(gè)技術(shù)框架。這個(gè)技術(shù)框架本質(zhì)上和 VFIO-mdev 類似,也實(shí)現(xiàn)了一個(gè)虛擬設(shè)備(vDPA device)總線驅(qū)動模型,和 VFIO-mdev 不同的是,通過 vDPA 框架虛擬出來的設(shè)備,既可以給虛機(jī)使用,又可以直接從宿主機(jī)(比如:容器)進(jìn)行訪問。這一切都?xì)w功于,vDPA 設(shè)備的數(shù)據(jù)路徑是遵循 Virtio 協(xié)議規(guī)范的,因此,可以直接被宿主機(jī)上的 virtio 驅(qū)動直接訪問。同時(shí),該技術(shù)框架對 vhost 內(nèi)核子系統(tǒng)進(jìn)行了擴(kuò)展,賦予了類似 VFIO 技術(shù)框架的功能,允許將 vDPA 設(shè)備用來進(jìn)行數(shù)據(jù)通信的硬件資源(ring buffer, descriptor table,doorbell 寄存器等)透傳給虛機(jī)使用,這樣,虛擬機(jī)的 virtio 驅(qū)動進(jìn)行數(shù)據(jù)通信時(shí),也是直接訪問硬件資源,而不再需要通過 vhost、vhost-user 等方式進(jìn)行處理了。更重要的一點(diǎn)是,由于虛機(jī)驅(qū)動是原本的 virtio 驅(qū)動,因此,當(dāng)需要支持熱遷移時(shí),QEMU 可以靈活切換會軟件模擬的方式,來保證熱遷移的順利進(jìn)行。這樣,vDPA 這個(gè)設(shè)備虛擬化技術(shù)框架既保證了最佳性能又保留了 virtio 設(shè)備的靈活性,而且還統(tǒng)一了虛機(jī)和容器的 I/O 技術(shù)棧。
VDUSE
通過上述 vDPA 技術(shù)框架,我們基本解決了長期以來設(shè)備虛擬化技術(shù)在虛機(jī)場景下暴露的一些問題,而更重要的是,它將 virtio 技術(shù)也帶到了容器領(lǐng)域。但這個(gè)技術(shù)框架還存在一個(gè)問題,就是需要硬件設(shè)備的支持?;叵胫疤岬降?virtio、vhost、vhost-user,本質(zhì)上都是軟件定義的虛擬設(shè)備。那 vDPA 這個(gè)技術(shù)框架有沒有可能也能夠使用軟件定義的設(shè)備呢?VDUSE 這項(xiàng)技術(shù)就是用來實(shí)現(xiàn)這個(gè)目標(biāo)的,通過 VDUSE,我們可以在一個(gè)用戶進(jìn)程實(shí)現(xiàn)一個(gè)軟件定義的 vDPA 設(shè)備,并可以通過上述 vDPA 框架接入 virtio 或者 vhost 子系統(tǒng),供容器或者虛機(jī)使用。
該項(xiàng)技術(shù)是由我們自主研發(fā)并在去年 10 月向 Linux 內(nèi)核社區(qū)正式開源的?,F(xiàn)階段我們的方案已經(jīng)被合入 Linux 內(nèi)核主線,將在 Linux 5.15 版本與大家見面。同時(shí),我們也會在 9 月 15 日舉辦的 KVM Forum 這個(gè)虛擬化領(lǐng)域的高端技術(shù)論壇會議上進(jìn)行線上分享。
結(jié)束語
從服務(wù)虛擬機(jī)到支持容器,從純軟件模擬到硬件直通再到軟硬件結(jié)合,Linux 設(shè)備虛擬化技術(shù)這幾十年里一直在朝著極致性能、應(yīng)用靈活等方向不斷演進(jìn)。隨著云原生的浪潮,各大硬件廠商的入局,全新的軟硬件結(jié)合方式不斷涌現(xiàn),我們相信后續(xù)也會有更多精彩技術(shù)在等待著我們。
參考鏈接
- 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/