1. 程式人生 > >基於virtio在虛擬機器與主機之間傳遞訊息

基於virtio在虛擬機器與主機之間傳遞訊息

Virtio是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));

4,虛擬機器背板程式的部署和更新

隨著應用的變化,主機與虛擬機器之間的通訊模式可能會不斷變化,因此虛擬機器的背板程式也 需要做相應調整。
相對於每次在主機vmm中開啟虛擬機器,遠端登入虛擬機器修改程式,有一種更高效的方式,就是利用qemu-nbd。
qemu-nbd可以將 本地虛擬機器映象檔案對映到本地nbd塊裝置, 將該nbd塊裝置mount到本地檔案系統後,
就可以在虛擬機器映象的檔案系統中進行應用程式的部署和更新:

modprobe nbd

qemu-nbd -c /dev/nbd0 image_name

mount /dev/nbd0p1 /mnt/image

通過類似以上操作,/mnt/image目錄即虛擬機器映象的檔案系統:



此後,便可將更新後的背板程式直接部署在虛擬機器映象,比如將啟動指令碼(包括背板啟動程式和模組載入操作)置於虛機映象檔案系統中的/etc/rc.local