參考:《深入淺出DPDK》及大佬們的各種博客
Virtio簡介&運行環境
Virtio 是一種用于虛擬化環境中的半虛擬化 I/O 框架,目的是在虛擬機和主機之間提供一種高效的 I/O 機制。關于什么是半虛擬化和全虛擬化:見SR-IOV學習筆記。
YES,virtio 是作為客戶機訪問主機上的設備的接口而開發的,因此可以分為兩部分:
- virtio Guest OS(虛擬機)中實現的前端程序,定義了如何在客戶機和主機之間創建控制平面和數據平面
- vhost 協議,在宿主機(物理機或主機)實現的后端驅動, 允許將 virtio 數據平面實現外置到另一部分(用戶進程或內核模塊)以提高性能的協議,核心目的是通過將虛擬設備的數據處理任務從虛擬機監視器(如 QEMU)轉移到主機上的用戶態或內核態進程
ps:大家伙耳熟能詳(呃,或許并不太熟悉)的virtio-net是虛擬以太網卡,是一種virtio支持的IO設備。
Virtio 被廣泛應用于 KVM(Kernel-based Virtual Machine)和 QEMU 等虛擬化平臺,提供了包括網絡、塊設備等在內的多種虛擬設備支持。其工作環境如下:
圖片來源:https://www.redhat.com/en/blog/introduction-virtio-networking-and-vhost-net
下面淺談下Virtio的同事們:
-
KVM
- 個人簡介:基于Linux內核的開源虛擬化解決方案
- 工作團隊:內核空間
- 工作內容:提供虛擬化支持,允許在同一臺物理機上運行多個操作系統作為虛擬機,實現硬件資源的高效利用和靈活管理,相當于把 Linux 內核轉變為虛擬機管理程序,使得虛擬機可以直接利用硬件虛擬化擴展(如 Intel VT-x 和 AMD-V)運行。
-
QEMU
- 個人簡介:通用且開源的虛擬機模擬器和虛擬化工具
- 工作團隊:用戶空間
- 工作內容:1. 模擬整個計算機系統,包括處理器、內存、硬盤、網絡接口等, 適用于運行不同架構的完整操作系統(比如在x86系統上運行ARM, 斗宗強者,竟恐怖如斯) 2. 提供虛擬化支持,可以利用硬件虛擬化技術(如 Intel VT-x 和 AMD-V)運行虛擬機,大大的提高性能。
-
Libvirt
- 個人簡介:虛擬化技術管理員
- 工作團隊:用戶空間
- 工作內容:1. 調用qemu創建、啟動、恢復、暫停虛擬機,是真正的虛擬機管理者,并提供API供用戶調用 2. 為每個虛擬機啟動一個 qemu 進程,并將 XML 格式的配置轉換為 qemu CLI 調用的接口,供用戶使用
半虛擬化Virtio
Virtio使用場景
在現代數據中心中大量采用虛擬化技術,IO全虛擬方案中,虛擬機以寄存器的方式訪問外設,比如網卡發送一個報文,需要寫很多次寄存器,造成大量的(VM-exit,虛擬機暫停運行),性能很差。IO透傳方案性能很好,但不能從硬件上支持虛擬機的動態遷移以及缺乏足夠靈活的流分類規則。于是,就有了很多Vritio的使用場景。其實現有的云計算廠商,很多都是用的virtio實現的虛擬機和裸金屬場景的熱遷移。
以下是virio設備的典型場景
宿主機使用虛擬交換機聯通物理網卡和虛擬機。虛擬交換機內部有DPDK vhost,實現了Virtio的后端網絡設備驅動程序邏輯,虛擬機里有DPDK的前端網絡設備驅動。前端和后端通過virtio的虛擬隊列交換數據。
這樣虛擬機中的網絡數據遍剋發送到虛擬交換機中,通過轉發邏輯,經由物理網卡進入外部網絡。
Virtio架構&原理
Virtio架構如下圖所示,
-
前端驅動程序
- 包含不同前端驅動程序,如塊設備(例如磁盤)驅動、網絡設備驅動等驅動程序。每個前端驅動程序在虛擬機管理程序中都有相應的后端驅動程序。 驅動程序可以根據需要使用零個或多個隊列。例如,virtio網絡驅動程序使用兩個虛擬隊列(一個用于接收,一個用于發送),而virtio塊驅動程序僅使用一個。虛擬隊列是虛擬的,實際上被實現為環以遍歷客戶機到虛擬機管理程序的轉換。
-
虛擬隊列
- 連接客戶機操作系統 和宿主機后端驅動的實際數據鏈路
虛擬隊列
虛擬隊列主要由描述符列表(descriptor table)、可用換標和已用環表(used ring)組成。描述符列表指向的是實際要傳輸的數據。兩個環表指向的是描述符列表,分別用來標記前端和后端驅動程序對描述符列表中描述符的處理進度。詳細來看:
- 描述符列表
/* dpdk/drivers/net/virtio/virtio_ring.h */
struct vring_desc {uint64_t addr; /* 數據緩沖區的客戶機物理地址 */uint32_t len; /* 數據緩沖區的長度 */uint16_t flags; /* 標志位,表示當前描述符的書香,如next是否有效等 */uint16_t next; /* 描述符鏈中下一個描述符的地址 */
};
- 可用環表
/* dpdk/drivers/net/virtio/virtio_ring.h */
struct vring_avail {uint16_t flags; /* 標志位,表示環表的一些屬性,比如是否需要設備在使用了環表中的表項后發送中斷給驅動 */uint16_t idx; /* 驅動寫入下一個可用描述符的位置 */uint16_t ring[0]; /* 存儲描述符指針(id)的數組 */
};
- 已用環表
/* dpdk/drivers/net/virtio/virtio_ring.h */
struct vring_used_elem {/* Index of start of used descriptor chain. */uint32_t id;/* Total length of the descriptor chain which was written to. */uint32_t len;
};struct vring_used {uint16_t flags; /* 標志位,包括是否需要驅動在回收了已用環表中的表項后發送提醒給設備 */volatile uint16_t idx;struct vring_used_elem ring[0];
};
Virtio設備的使用
設備的使用主要包括兩部分:
- 驅動通過描述符列表和可用環表提供的數據緩沖區給設備用
- 把數據緩沖區地址、長度等信息賦值到空閑的描述符中
- 把改描述符指針添加到該虛擬隊列的可用環表的頭部
- 更新可用環表中的頭部指針
- 寫入該虛擬隊列編號到Queue Notify寄存器以通知設備
- 設備使用描述符后再通過已用環表還給驅動
- 把使用過的數據緩沖區描述符的頭指針添加到該虛擬隊列的已用環表的頭部
- 更新該已用環表的頭部指針
- 根據是否開啟MSI-X中斷,用不同的中斷方式通知驅動。
Virtio網絡設備
virtio網絡設備Linux驅動主要包括三部分:
- 底層PCI-e設備層
- 負責監測PCI-e設備,并初始化設備對應的驅動程序
- 中間Virtio虛擬隊列層
- 實現了Virtiio協議中的虛擬隊列
- 上層網絡設備層
- 實現了兩個抽象類:virtio設備和網絡設備,從而Linux系統能夠對待普通網卡一樣操作這個virtio網絡設備
/* dpdk/lib/librte_vhost/rte_virtio_net.h */
/*** Device and vring operations.*/
struct virtio_net_device_ops {int (*new_device)(int vid); /**< Add device. */void (*destroy_device)(int vid); /**< Remove device. */int (*vring_state_changed)(int vid, uint16_t queue_id, int enable); /**< triggered when a vring is enabled or disabled */void *reserved[5]; /**< Reserved for future extension */
};
以上,順心順意!
參考:
《深入淺出dpdk》
https://www.redhat.com/en/blog/introduction-virtio-networking-and-vhost-net
https://developer.ibm.com/articles/l-virtio/
https://tinylab.org/virtio-intro/