qemu使用PCI passthrough裝置
為了提高虛擬機器中的io吞吐量業界現在採用的方式就是直接將物理裝置給虛擬機器直接使用。
方式上有兩種
- pci assign
- vfio
不過現在業界已經基本都採用vfio的方式了。主要是因為在vfio方式下對虛擬裝置的許可權和dma隔離上做的更好。但是這麼做也有個缺點,這個物理裝置在主機和其他虛擬機器都不能使用了。
qemu直接使用物理裝置本身命令列是很簡單的,關鍵在於事先在主機上對系統、核心和物理裝置的一些配置。
最後執行的qemu命令列
先來看一下系統都配置完成後要執行的命令,是不是很簡單~
qemu-system-x86_64 -m 4096 -smp 4 --enable-kvm \
-drive file=~/guest/fedora.img \
-device vfio-pci,host=0000:00:01.0
單純從qemu的命令列來看,其實和普通虛擬機器啟動就差了最後那個-device的選項。這個選項也比較容易理解,就是把主機上的裝置0000:00:01.0傳給了虛擬機器使用。
系統及硬體準備
BIOS中開啟IOMMU
裝置直通在x86平臺上需要開啟iommu功能。這是Intel虛擬技術VT-d(Virtualization Technology for Device IO)中的一個部分。有時候這部分的功能沒有被開啟。
開啟的方式在BIOS設定中Security->Virtualization->VT-d這個位置。當然不同的BIOS位置可能會略有不同。記得在使用直通裝置前要將這個選項開啟。
核心配置勾選IOMMU
對應的在核心編譯過程中需要勾選IOMMU的功能。在menuconfig中有這樣的顯示。
INTEL_IOMMU
│ Location: │
│ -> Device Drivers │
│ (2) -> IOMMU Hardware Support (IOMMU_SUPPORT [=y])
如果你看到核心編譯選項INTEL_IOMMU被設定為y,則表明已經配置成功。
核心啟動引數enable IOMMU
BIOS中開啟,核心編譯選項勾選還不夠。還需要在載入程式中新增上核心啟動引數 intel_iommu=on.
具體位置和使用的載入程式相關,請自行根據你使用的載入程式配置。
確認IOMMU功能確實開啟
所有的準備工作做完,重啟主機後為了保證一切無誤,可以採用如下方法檢查是否已經enable了IOMMU.
dmesg | grep -e DMAR -e IOMMU
如果能搜尋到
DMAR: IOMMU enabled
表示上述配置成功。
VFIO相關模組配置
vfio的相關配置選項
在x86平臺,裝置直通需要使用核心中vfio相關的模組。隨意要確保核心配置選項中,相關的模組已編譯。
相關的選項有
- VFIO
- VFIO-PCI
- VFIO_IOMMU_TYPE1
載入並確認vfio相關模組已經載入
如果上述選項設定是built-in的,那就不需要載入了。如果是模組的話,那需要載入並且這樣還能確認是否選項勾選正確。
載入的命令:
modprobe vfio
mod prove vfio-pci
檢視是否載入成功的命令是:
$ lsmod | grep vfio
vfio_pci 45056 0
vfio_virqfd 16384 1 vfio_pci
vfio_iommu_type1 20480 0
vfio 28672 2 vfio_iommu_type1,vfio_pci
irqbypass 16384 2 kvm,vfio_pci
如果沒有看到相關的模組載入,就需要重複上一個步驟重新配置並編譯。
裝置配置
使能VF (可選)
不算背景知識的背景
這裡得先插播一個廣告了,VF字面上的理解就是虛擬裝置。實際上是通過硬體和軟體手段,使得同樣的一個物理裝置在系統上可以展現出多個邏輯裝置。舉一個不恰當的例子,就好像西遊記裡的孫悟空,碰到妖怪太多可以拔兩根毫毛變換出多個和自己一模一樣的齊天大聖來。
然而這畢竟是一個高階功能
* 首先是要硬體本身支援,就好像這高階本事要孫悟空級別的人物才有
* 其次我們用的時候需要使能,就好像孫悟空平時也就是一個真身
有興趣的同學可以搜尋SRIOV關鍵字去找相關資料,不過感覺網上對這個的解釋非常少。如果希望再深入理解的話,恐怕要找SRIOV的規範來看了。我在這裡儘量用通俗的語言解釋。
現在使能某個裝置的VF已經變得很簡單了,找到帶有SRIOV功能的裝置,向其驅動中sysfs的某個檔案echo你想要使能的VF個數即可。這裡還要強調一下,被直通的裝置可以是VF(virtual function),也可以是PF(physical function)。PF就好像是孫悟空的那個真身,而VF則是他毫毛的化身,這兩個概念正好是對應的。但是一旦直通了PF給某個虛擬機器,他就不能使用VF功能了。就好像如果孫悟空的真身去了另一個世界,他在這個世界的法力(化身)也就消失了。
自己都感覺說的有點繞,沒看懂沒有關係,按照下面的步驟直接操作即可~
找到PF
# lspci -vvv | grep "Single"
如果能找到,則表示系統中有PF,否則沒有PF就不能使能VF。
記住擁有這個屬性的PCI裝置編號,假設編號為0000:00:01.0。
使能VF
自從有了sysfs介面,使能VF變得簡潔多了。方法就是向需要使能的PF裝置的sysfs檔案寫入一個需要使能的VF個數。
假設PF的裝置編號為0000:00:01.0, 想要使能10個VF
echo 10 > /sys/bus/pci/devices/0000:00:01.0/sriov_numvfs
是不是很簡單。
確認使能成功
一般情況下VF的裝置名會帶有”Virtual Function”字樣,所以通過搜尋lspci的輸出可以確認是否使能成功。
lspci | grep "Virtual Function"
如果相對於使能前多出了相同指定個數的pci裝置,則表示使能成功。
找到同一iommu group上所有裝置
接下來的幾個小節適用於所有的想要直通給虛擬機器的pci裝置,不管是PF還是VF,都需要如此操作。
- 首先是找到目標裝置所在的iommu group
- 然後將同一個組的所有裝置都解除安裝原有驅動並繫結到vfio-pci驅動上。
找同一個組的裝置也是通過sysfs
ls /sys/bus/pci/devices/0000:00:01.0/iommu_group/devices
這樣就會列出這個組下所有的裝置~
解繫結原有驅動
找到了同一個組下的裝置,需要一一對裝置做解繫結驅動的操作。
echo 0000:00:01.0 > /sys/bus/pci/devices/0000:00:01.0/driver/unbind
繫結vfio-pci驅動
繫結驅動和解繫結的操作類似,但是多了一個獲取裝置廠商號和型號的動作。
先獲取裝置廠商號和型號
lspci -ns 0000:00:01.0
00:02.0 0300: 8086:0412 (rev 06)
再繫結
echo 8086 0412 > /sys/bus/pci/drivers/vfio-pci/new_id
大功告成~現在你就可以執行最開始的那段程式碼執行帶有直通裝置的虛擬機器了~