irtio是Linux虛擬機平台上統一的虛擬IO接口驅動。通常主機為了讓客戶機像在真實環境中一樣運行,需要為客戶機創建各式各樣的虛擬設備,
如磁盤,網卡,顯卡,時鍾,USB 等。這些虛擬設備大大降低了客戶機的性能。使用virtio。虛擬機guest不用關注如何創建各種虛擬硬件設備
(如磁盤,網卡,顯卡等),可以用統一的虛擬設備,因此大大提高虛擬機的性能。這個統一的虛擬設備就是virtio。
關於virtio原理以及在kvm和libvirt中的使用,可以參考:
理解Virtio的原理:http://www.ibm.com/developerworks/cn/linux/l-virtio/
Virtio在kvm中的使用:http://www.linux-kvm.org/page/Virtio
Virtio在libvirt中的使用:http://wiki.libvirt.org/page/Virtio
本文會側重於virtio一個有趣的應用:如何使用virtio在虛擬機guest和主機host之間傳遞消息。這里的消息既包括控制指令,也包括文件傳輸(比如通過主機向虛擬機傳遞腳本的場景)。使用virtio傳遞消息有兩點優勢:
1,對虛擬機和主機的網絡設置沒有任何要求
2,效率更高
使用virtio來傳遞消息的示意圖為:
以下看虛擬機和主機的相關程序如何構建
1,通過libvirt在虛擬機創建時啟動virtio通道
以上圖中啟動兩個virtio通道為例(數據通道和控制通道),libvirt啟動配置xml中需要加入:
<channel type=’unix’> <source mode=’bind’ path=’vm.ctl’/> <target type=’virtio’ address=’virtio-serial’ port=’0′/> </channel> <channel type=’unix’> <source mode=’bind’ path=’vm.data’/> <target type=’virtio’ address=’virtio-serial’ port=’1′/> </channel> <controller type=’virtio-serial’ index=’0′ ports=’16′/>
1)vm.ctl與vm.data為兩個virtio通道在主機本地的映射節點文件,主機應用可以基於這兩個映射文件通過unix sock實現與虛擬機的通信
2)index=’0′ ports=’16′表示使用的是virtio的0號總線,這個總線總共可以開辟16個虛擬端口
3)port=’0′和port=’1′表示兩個virtio通道對應在虛擬機的端口號
虛擬機啟動后,在虛擬機操作系統中可以發現兩個新的字符設備
/dev/vport0p0,對應控制通道
/dev/vport0p1,對應數據通道
對應xml中的定義,vport0表示使用的是0號virtio總線,p0和p1則分別對應每個通道指定的端口號。虛擬機中對這兩個字符設備的讀寫操作即相當於對virtio通道的讀寫,以此可以實現與主機的通信。
2,虛擬機端的背板程序(back-end app)
在上面xml定義的應用場景,虛擬機中會發現兩個新的字符設備,其中/dev/vport0p0對應控制通道,/dev/vport0p1對應數 據通道。虛擬機中的背板程序是一個運行於虛機os的后台進程,基於poll(沒有並發需求,使用poll即可)對控制端口/dev/vport0p0進行 異步監聽,讀取主機向控制通道發送的請求,並完成響應。為充分利用虛擬機資源,數據端口/dev/vport0p1在背板程序中初始是關閉的,當主機需要 向虛擬機傳遞文件時,首先通過控制通道向虛擬機的背板程序發送請求,虛擬機背板程序異步監聽到該請求后,打開/dev/vport0p1數據端口,數據傳 輸完畢后,背板程序會重新關閉該端口。
對於部分虛擬機的os,可能沒有默認加入virtio的支持,因此需要在啟動背板程序前加載相關模塊:
insmod virtio.ko
insmod virtio_ring.ko
insmod virtio_pci.ko
insmod hvc_console.ko
insmod nscatterlist.ko
insmod virtio_console.ko
下面的鏈接中包括一個不錯的背板程序的示例:(此鏈接可能失效,大家自己去找找!)
http://fedorapeople.org/gitweb?p=amitshah/public_git/test-virtserial.git;a=blob;f=auto-virtserial-guest.c;hb=HEAD
3,主機端的應用程序
由於virtio通道通過libvirt啟動配置xml中的相關定義,在host本地映射為兩個文件,主機程序可以通過unix套接字的方式對virtio通道進行讀寫,實現與虛擬機的消息數據傳遞:
sock = socket(AF_UNIX, SOCK_STREAM, 0);
sockaddr_un.sun_family = AF_UNIX;
memcpy(&sockaddr_un.sun_path, “vm.ctl”, sizeof(sockaddr_un.sun_path));
connect(sock, sockaddr_un, sizeof(sockaddr_un));