隨着qemu2.1的發佈,可以看到,qemu支持了vhost-user。從介紹可以看出,這是把原來vhost-backend從kernel移到了userspace,這和原來virtio架構有什麼區別呢?並且這個特性帶來了怎樣的改進?
virtio
在虛擬機中,可以通過qemu模擬e1000網卡,這樣的經典網卡一般各種客戶操作系統都會提供inbox驅動,所以從兼容性上來看,使用類似e1000的模擬網卡是非常一個不錯的選擇。
但是,e1000網卡上也包含了複雜的io端口,寄存器,緩存配置,虛擬機每次收發包都會引起更多的io和mmio操作,使得虛擬機頻繁的陷出,最終導致網絡性能不佳。
爲了解決性能問題,IBM在2005年提出了virtio, 虛擬機中的半虛擬化前端驅動和主機上的後端服務簡單的使用virtqueue共享隊列交換數據,大幅的減少了e1000模擬時複雜的io操作,從而可以較大程度的提升虛擬網絡性能。
作爲對比,從下面簡單的iperf測試中,我們就能看出兩者的性能差距:
With virtio
1 2 3 4 5 6 7 | ------------------------------------------------------------ Client connecting to virtio, TCP port 5001 TCP window size: 16.0 KByte (default) ------------------------------------------------------------ [ 3] local 10.0.1.172 port 54168 connected with 10.0.1.33 port 5001 [ 3] 0.0-10.0 sec 1.34 GBytes 1.15 Gbits/sec |
Without virtio
1
2
3
4
5
6
7
|
------------------------------------------------------------
Client
connecting
to
novirtio,
TCP
port
5001
TCP
window
size:
16.0
KByte
(default)
------------------------------------------------------------
[ 3]
local
10.0.1.172
port
34414
connected
with
10.0.1.13
port
5001
[ 3] 0.0-10.0
sec 375
MBytes 315
Mbits/sec
|
vhost
vhost技術對virtio-net進行了優化,在內核中加入了vhost-net.ko模塊,使得對網絡數據可以再內核態得到處理。
virtio的io路徑
- guest設置好tx;
- kick host;
- guest陷出到kvm;
- kvm從內核切換到用戶態的qemu進程;
- qemu將tx數據投遞到tap設備;。
vhost的io路徑
- guest設置好tx;
- kick host;
- guest陷出到kvm;
- vhost-net將tx數據投遞到tap設備;
vhost將部分virio驅動的操作從用戶態移到內核態,減少了用戶態/內核態切換時間和包的拷貝次數,從而更進一步的提升了性能, 下面的網絡延時測試可以看出vhost的優勢:
vhost-user
隨着技術的發展,將網絡數據放入用戶態處理將可以得到更靈活的形式。在原有的vhost架構中,進行了改動,增加了 一種新的vhost-backend,叫做vhost-user。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
+---------------+------+--+----------+--+
|
+------+ +----------+ |
|
user | | | | |
|
space
| | | guest
| |
|
| | | | |
| +-+-------+ |
qemu
| |
+-+------+ |
| | snabb | | | |
|
virtio
| |
| |
| | | |
|
driver
| |
| +---------+ +------+ +-+---++---+ |
|
|
|
|
|
| ^ |
|
|
| | v
|
|
v | |
+------------------------------+--+-----+
|nic
+
+-----------------------+
kvm.ko
|
|+---+
+--+-----+
| kernel
|
+---------------------------------------+
|
vhost-user的io路徑
- guest設置好tx;
- kick host;
- guest陷出到kvm;
- kvm將通知snabb;
- snabb將tx數據直接發送到nic設備。
vhost-user的提交者是Luke Gorrie,他也是snabbswitch的作者。從圖上可以看到vhost-backend從原來咋kernel中的vhost-net 變成了用戶空間的snabbswitch。 snabbswitch直接接管物理網卡的驅動,從而直接控制網絡信息的輸入輸出。
snabbswitch主要使用了下面的技術來提高性能
- 採用了大頁來作爲host和vm之間通信的內存空間
- 用戶態操作網卡,使用類似於netmap的zero copy技術來加速對物理設備的訪問
- 使用numa技術,加快中斷響應速率
值得一提的是使用snabbswitch後,不用再使用原來的tap設備模擬的網卡。
使用vhost-user技術,從虛擬機到host上實現了數據的zero copy(通過大頁共享),host到nic的zero copy(snabbswitch實現的驅動),能進一步加快數據的傳輸。
virtio架構
1, 前端驅動(如virtio_pci, virtio_net)等存在於虛擬機中
2, virtio backend存在於qemu中
3, 中間的兩層virtio是隊列,virtio-ring是環形緩存區
qemu的vhost-user特性
vhost是一種用戶空間進程(vhost client與vhost backend)通過共享內存(virtqueues, unit socket), 文件描述符(ioeventfds), (中斷號)irqfds實現快速交換數據的機制。其架構是:
這張是vhost的圖:
下面這張圖還是vhost的圖
下面這張是我在一個ppt裏梳理的virtio, vhost, vhost-user, snabb, openonload之間的關係。openonload相當於在snabb的基礎上又多出一層用戶態的tcp/ip棧
qemu目前支持使用vhost, 如下:
qemu -m 1024 -mem-path /bak/shared,prealloc=on,share=on -netdev type=vhost-user,id=net0,file=/path/to/socket -device virtio-net-pci,netdev=net0
a, -mem-path選項支持爲一個虛機分配和其他進程共享內存的guest內在vring, vring是虛機的網卡數據的緩存
b, 再通過unix socket將vring的文件描述符、中斷號、IO事件等傳給同在用戶空間的snabb app進程
c, snabb app進程就可以直接通過文件描述符去ving中取數據了
可以看出,這種機制,是不需要內核中的TAP設備的從而繞開了kernel,也是不需要再走QEMU的內核空間的從而繞開了QEMU.
UserSpace Virtio Application 與 Snabb
userspace virtio app結合了virtio與vhost,snabb是一個個基於userspace virtio app的應用:
a) Snabb用vhost-user(QEMU 2.1的新特性)去和VM通信(所以不再需要tap設備,也不需要Kernel)
b) Snabb用intel10g.lua驅動或OpenOnload提供的驅動(libcuil.so)去和硬件網卡打交道
基架構圖如下:
所以對於snabb交換機,我的理解是:
Snabb與ovs的不同是,Snabb是一個userspace virtio application, 它能繞開kernel,和同樣是usersapce的VM虛機進程直接通過共享內存實現zero-copy大大地提升性能;另一方面,kernel也會基於vhost技術爲每個vring設備分配獨立的中斷號、事件中斷、文件描述符等,並將這些通過unix socket傳給其他用戶空間進程,這樣snabb app並能直接訪問虛機網卡的文件描述符。Snabb就相當於一個neutron l2
agent,它會直接調用硬件網卡的相關功能去實現一些neutron軟件做的事情,如tagging, security group, routers, firewalls, NATs等,現在這些SRIOV硬件網卡爲了和neutron這些軟件SDN產品搶市場,它們自己也實現了neutron的那些這功能的,一個例子,開啓防火牆:
Ethtool -K ethX ntuple on
ethool -U ethX flow-type tcp4 src-ip 168.0.0.1 dst-ip 192.0.0.1 src-port 1000 dst-port 80 action 0