聯(lián)系 Tim
Tim 是我們最受歡迎并且很多產(chǎn)的作者之一。查看
Tim 的個人資料 并與他和 My developerWorks 上的其他作者和讀者聯(lián)系。
概而言之,virtio
是半虛擬化 hypervisor 中位于設(shè)備之上的抽象層。virtio
由 Rusty Russell 開發(fā),他當時的目的是支持自己的虛擬化解決方案 lguest
。本文在開篇時介紹半虛擬化和模擬設(shè)備,然后探索 virtio
的細節(jié)。本文的重點是來自 2.6.30 內(nèi)核發(fā)行版的 virtio
框架。
Linux 是 hypervisor 展臺。如我的 剖析 Linux hypervisor 所述,Linux 提供各種 hypervisor 解決方案,這些解決方案都有自己的特點和優(yōu)點。這些解決方案包括 Kernel-based Virtual Machine (KVM)、lguest
和 User-mode Linux 等。在 Linux 上配備這些不同的 hypervisor 解決方案會給操作系統(tǒng)帶來負擔(dān),負擔(dān)的大小取決于各個解決方案的需求。其中的一項開銷為設(shè)備的虛擬化。virtio
并沒有提供多種設(shè)備模擬機制(針對網(wǎng)絡(luò)、塊和其他驅(qū)動程序),而是為這些設(shè)備模擬提供一個通用的前端,從而標準化接口和增加代碼的跨平臺重用。
完全虛擬化和半虛擬化
加入 My developerWorks 上的綠色小組
讓我們快速討論一下兩種類型完全不同的虛擬化模式:完全虛擬化和半虛擬化。在完全虛擬化 中,來賓操作系統(tǒng)運行在位于物理機器上的 hypervisor 之上。來賓操作系統(tǒng)并不知道它已被虛擬化,并且不需要任何更改就可以在該配置下工作。相反,在半虛擬化 中,來賓操作系統(tǒng)不僅知道它運行在 hypervisor 之上,還包含讓來賓操作系統(tǒng)更高效地過渡到 hypervisor 的代碼(見 圖 1)。
在完全虛擬化模式中,hypervisor 必須模擬設(shè)備硬件,它是在會話的最低級別進行模擬的(例如,網(wǎng)絡(luò)驅(qū)動程序)。盡管在該抽象中模擬很干凈,但它同時也是最低效、最復(fù)雜的。在半虛擬化模式中,來賓操作系統(tǒng)和 hypervisor 能夠共同合作,讓模擬更加高效。半虛擬化方法的缺點是操作系統(tǒng)知道它被虛擬化,并且需要修改才能工作。
圖 1. 在完全虛擬化和半虛擬化環(huán)境下的設(shè)備模擬
硬件隨著虛擬化技術(shù)而不斷改變。新的處理器通過納入高級指令來讓來賓操作系統(tǒng)到 hypervisor 的過渡更加高效。此外,硬件也隨著輸入/輸出(I/O)虛擬化而不斷改變(參見 參考資料 了解 Peripheral Controller Interconnect [PCI] passthrough 和 single- and multi-root I/O 虛擬化)。
virtio 的替換者
virtio
并不是該領(lǐng)域中的唯一霸主。Xen 提供半虛擬化設(shè)備驅(qū)動程序,VMware 也提供 Guest Tools。
但是在傳統(tǒng)的完全虛擬化環(huán)境中,hypervisor 必須捕捉這些請求,然后模擬物理硬件的行為。盡管這樣做提供很大的靈活性(即運行未更改的操作系統(tǒng)),但它的效率比較低(參見 圖 1 左邊)。圖 1 的右邊是半虛擬化示例。在這里,來賓操作系統(tǒng)知道它運行在 hypervisor 之上,并包含了充當前端的驅(qū)動程序。Hypervisor 為特定的設(shè)備模擬實現(xiàn)后端驅(qū)動程序。通過在這些前端和后端驅(qū)動程序中的 virtio
,為開發(fā)模擬設(shè)備提供標準化接口,從而增加代碼的跨平臺重用率并提高效率。
回頁首
針對 Linux 的抽象
從前面的小節(jié)可以看到,virtio
是對半虛擬化 hypervisor 中的一組通用模擬設(shè)備的抽象。該設(shè)置還允許 hypervisor 導(dǎo)出一組通用的模擬設(shè)備,并通過一個通用的應(yīng)用編程接口(API)讓它們變得可用。圖 2 展示了為什么這很重要。有了半虛擬化 hypervisor 之后,來賓操作系統(tǒng)能夠?qū)崿F(xiàn)一組通用的接口,在一組后端驅(qū)動程序之后采用特定的設(shè)備模擬。后端驅(qū)動程序不需要是通用的,因為它們只實現(xiàn)前端所需的行為。
圖 2. virtio 的驅(qū)動程序抽象
注意,在現(xiàn)實中(盡管不需要),設(shè)備模擬發(fā)生在使用 QEMU 的空間,因此后端驅(qū)動程序與 hypervisor 的用戶空間交互,以通過 QEMU 為 I/O 提供便利。QEMU 是一個系統(tǒng)模擬器,它不僅提供來賓操作系統(tǒng)虛擬化平臺,還提供整個系統(tǒng)(PCI 主機控制器、磁盤、網(wǎng)絡(luò)、視頻硬件、USB 控制器和其他硬件元素)的模擬。
virtio
API 依賴一個簡單的緩沖抽象來封裝來賓操作系統(tǒng)需要的命令和數(shù)據(jù)。讓我們查看 virtio
API 的內(nèi)部及其組件。
回頁首
Virtio 架構(gòu)
除了前端驅(qū)動程序(在來賓操作系統(tǒng)中實現(xiàn))和后端驅(qū)動程序(在 hypervisor 中實現(xiàn))之外,virtio
還定義了兩個層來支持來賓操作系統(tǒng)到 hypervisor 的通信。在頂級(稱為 virtio)的是虛擬隊列接口,它在概念上將前端驅(qū)動程序附加到后端驅(qū)動程序。驅(qū)動程序可以使用 0 個或多個隊列,具體數(shù)量取決于需求。例如,virtio
網(wǎng)絡(luò)驅(qū)動程序使用兩個虛擬隊列(一個用于接收,另一個用于發(fā)送),而 virtio
塊驅(qū)動程序僅使用一個虛擬隊列。虛擬隊列實際上被實現(xiàn)為跨越來賓操作系統(tǒng)和 hypervisor 的銜接點。但這可以通過任意方式實現(xiàn),前提是來賓操作系統(tǒng)和 hypervisor 以相同的方式實現(xiàn)它。
圖 3. vital 框架的高級架構(gòu)
如 圖 3 所示,分別為塊設(shè)備(比如磁盤)、網(wǎng)絡(luò)設(shè)備、PCI 模擬和 balloon 驅(qū)動程序列出了 5 個前端驅(qū)動程序。每個前端驅(qū)動程序在 hypervisor 中有一個對應(yīng)的后端驅(qū)動程序。
概念層次結(jié)構(gòu)
從來賓操作系統(tǒng)的角度來看,對象層次結(jié)構(gòu) 的定義如 圖 4 所示。在頂級的是 virtio_driver
,它在來賓操作系統(tǒng)中表示前端驅(qū)動程序。與該驅(qū)動程序匹配的設(shè)備由 virtio_device
(設(shè)備在來賓操作系統(tǒng)中的表示)封裝。這引用 virtio_config_ops
結(jié)構(gòu)(它定義配置 virtio
設(shè)備的操作)。virtio_device
由 virtqueue
引用(它包含一個到它服務(wù)的 virtio_device
的引用)。最后,每個 virtqueue
對象引用 virtqueue_ops
對象,后者定義處理 hypervisor 的驅(qū)動程序的底層隊列操作。盡管隊列操作是 virtio
API 的核心,我還是先簡單討論一下新的發(fā)現(xiàn),然后再詳細探討 virtqueue_ops
操作。
圖 4. virtio 前端的對象層次結(jié)構(gòu)
該流程以創(chuàng)建 virtio_driver
并通過 register_virtio_driver
進行注冊開始。virtio_driver
結(jié)構(gòu)定義上層設(shè)備驅(qū)動程序、驅(qū)動程序支持的設(shè)備 ID 的列表、一個特性表單(取決于設(shè)備類型)和一個回調(diào)函數(shù)列表。當 hypervisor 識別到與設(shè)備列表中的設(shè)備 ID 相匹配的新設(shè)備時,將調(diào)用 probe
函數(shù)(由 virtio_driver
對象提供)來傳入 virtio_device
對象。將這個對象和設(shè)備的管理數(shù)據(jù)緩存起來(以獨立于驅(qū)動程序的方式緩存)。可能要調(diào)用 virtio_config_ops
函數(shù)來獲取或設(shè)置特定于設(shè)備的選項,例如,為 virtio_blk
設(shè)備獲取磁盤的 Read/Write 狀態(tài)或設(shè)置塊設(shè)備的塊大小,具體情況取決于啟動器的類型。
注意,virtio_device
不包含到 virtqueue
的引用(但 virtqueue
確實引用了 virtio_device
)。要識別與該 virtio_device
相關(guān)聯(lián)的 virtqueue
,您需要結(jié)合使用 virtio_config_ops
對象和 find_vq
函數(shù)。該對象返回與這個 virtio_device
實例相關(guān)聯(lián)的虛擬隊列。find_vq
函數(shù)還允許為 virtqueue
指定一個回調(diào)函數(shù)(查看 圖 4 中的 virtqueue
結(jié)構(gòu))。
virtqueue
是一個簡單的結(jié)構(gòu),它識別一個可選的回調(diào)函數(shù)(在 hypervisor 使用緩沖池時調(diào)用)、一個到 virtio_device
的引用、一個到 virtqueue
操作的引用,以及一個引用要使用的底層實現(xiàn)的特殊 priv
引用。雖然 callback
是可選的,但是它能夠動態(tài)地啟用或禁用回調(diào)。
該層次結(jié)構(gòu)的核心是 virtqueue_ops
,它定義在來賓操作系統(tǒng)和 hypervisor 之間移動命令和數(shù)據(jù)的方式。讓我們首先探索添加到或從 virtqueue
移除的對象。
Virtio 緩沖池
來賓操作系統(tǒng)(前端)驅(qū)動程序通過緩沖池與 hypervisor 交互。對于 I/O,來賓操作系統(tǒng)提供一個或多個表示請求的緩沖池。例如,您可以提供 3 個緩沖池,第一個表示 Read 請求,后面兩個表示響應(yīng)數(shù)據(jù)。該配置在內(nèi)部被表示為一個散集列表(scatter-gather),列表中的每個條目表示一個地址和一個長度。
核心 API
通過 virtio_device
和 virtqueue
(更常見)將來賓操作系統(tǒng)驅(qū)動程序與 hypervisor 的驅(qū)動程序鏈接起來。virtqueue
支持它自己的由 5 個函數(shù)組成的 API。您可以使用第一個函數(shù) add_buf
來向 hypervisor 提供請求。如前面所述,該請求以散集列表的形式存在。對于 add_buf
,來賓操作系統(tǒng)提供用于將請求添加到隊列的 virtqueue
、散集列表(地址和長度數(shù)組)、用作輸出條目(目標是底層 hypervisor)的緩沖池數(shù)量,以及用作輸入條目(hypervisor 將為它們儲存數(shù)據(jù)并返回到來賓操作系統(tǒng))的緩沖池數(shù)量。當通過 add_buf
向 hypervisor 發(fā)出請求時,來賓操作系統(tǒng)能夠通過 kick
函數(shù)通知 hypervisor 新的請求。為了獲得最佳的性能,來賓操作系統(tǒng)應(yīng)該在通過 kick
發(fā)出通知之前將盡可能多的緩沖池裝載到 virtqueue
。
通過 get_buf
函數(shù)觸發(fā)來自 hypervisor 的響應(yīng)。來賓操作系統(tǒng)僅需調(diào)用該函數(shù)或通過提供的 virtqueue callback
函數(shù)等待通知就可以實現(xiàn)輪詢。當來賓操作系統(tǒng)知道緩沖區(qū)可用時,調(diào)用 get_buf
返回完成的緩沖區(qū)。
virtqueue
API 的最后兩個函數(shù)是 enable_cb
和 disable_cb
。您可以使用這兩個函數(shù)來啟用或禁用回調(diào)進程(通過在 virtqueue
中由 virtqueue
初始化的 callback
函數(shù))。注意,該回調(diào)函數(shù)和 hypervisor 位于獨立的地址空間中,因此調(diào)用通過一個間接的 hypervisor 來觸發(fā)(比如 kvm_hypercall
)。
緩沖區(qū)的格式、順序和內(nèi)容僅對前端和后端驅(qū)動程序有意義。內(nèi)部傳輸(當前實現(xiàn)中的連接點)僅移動緩沖區(qū),并且不知道它們的內(nèi)部表示。
回頁首
示例 virtio 驅(qū)動程序
您可以在 Linux 內(nèi)核的 ./drivers 子目錄內(nèi)找到各種前端驅(qū)動程序的源代碼??梢栽?./drivers/net/virtio_net.c 中找到 virtio
網(wǎng)絡(luò)驅(qū)動程序,在 ./drivers/block/virtio_blk.c 中找到 virtio
塊驅(qū)動程序。子目錄 ./drivers/virtio 提供 virtio
接口的實現(xiàn)(virtio
設(shè)備、驅(qū)動程序、virtqueue
和連接點)。virtio
還應(yīng)用在 High-Performance Computing (HPC) 研究中,以開發(fā)出通過共享內(nèi)存?zhèn)鬟f的 inter-virtual machine (VM) 通信。尤其是,這是通過使用 virtio
PCI 驅(qū)動程序的虛擬化 PCI 接口實現(xiàn)的。您可以在 參考資料 部分更多地了解這個知識點。
現(xiàn)在,您可以在 Linux 內(nèi)核中實踐這個半虛擬化基礎(chǔ)架構(gòu)。您所需的包括一個充當 hypervisor 的內(nèi)核、一個來賓操作性內(nèi)核和用于設(shè)備模擬的 QEMU。您可以使用 KVM(位于主機內(nèi)核中的一個模塊)或 Rusty Russell 的 lguest
(修改版的 Linux 來賓操作系統(tǒng)內(nèi)核)。這兩個虛擬化解決方案都支持 virtio
(以及用于系統(tǒng)模擬的 QEMU 和用于虛擬化管理的 libvirt
)。
Rusty 的 lguest
是針對半虛擬化驅(qū)動程序和更快速地模擬虛擬設(shè)備的更簡潔代碼庫。但更重要的是,實踐證明 virtio
比現(xiàn)有的商業(yè)解決方案提供更出色的性能(網(wǎng)絡(luò) I/O 能夠提升 2-3 倍)。性能的提升是需要付出代價的,但是如果您使用 Linux 作為 hypervisor 和來賓操作系統(tǒng),那么這樣做是值得的。
回頁首
結(jié)束語
也許您可能從來沒有為 virtio
開發(fā)過前端或后端驅(qū)動程序,它實現(xiàn)了一個有趣的架構(gòu),值得您仔細去探索。virtio
為提高半虛擬化 I/O 環(huán)境中的效率帶來了新的機會,同時能夠利用 Xen 以前的成果。Linux 不斷地證明它是一個產(chǎn)品 hypervisor,并且是新虛擬化技術(shù)研究平臺。virtio
這個例子展示了將 Linux 用作 hypervisor 的強大之處和開放性。
參考資料
學(xué)習(xí)
獲得產(chǎn)品和技術(shù)
討論
關(guān)于作者
M. Tim Jones 是一名嵌入式固件架構(gòu)師,同時也是 Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming(第二版)、AI Application Programming(第二版)和 BSD Sockets Programming from a Multilanguage Perspective 的作者。他的工程背景包括地球同步航天器內(nèi)核開發(fā)、嵌入式系統(tǒng)架構(gòu)和網(wǎng)絡(luò)協(xié)議開發(fā)等。Tim 還是科羅拉多州朗蒙特市 Emulex Corp. 的顧問工程師。