- QEMU/KVM源碼解析與應用
- 李強編著
- 1380字
- 2021-08-24 11:53:40
2.5 hmp與qmp介紹
2.5.1 hmp與qmp
QEMU程序在運行時提供了一個所謂的監(jiān)控器(monitor)來跟外界進行數(shù)據(jù)交互。QEMU monitor有很多功能,如得到虛擬機運行的一些統(tǒng)計信息、進行設備的熱插拔、動態(tài)設置一些參數(shù)、開啟一些功能等。QEMU monitor能夠使用多種方式進行交互,如QEMU的控制臺、TCP網(wǎng)絡、UNIX套接字、文件等。
與QEMU monitor進行交互的協(xié)議有兩類,傳統(tǒng)的是基于字符串的協(xié)議,叫作Human Monitor Protocol(HMP),其功能比較簡單,可用于進行簡單的調(diào)試和查看虛擬機狀態(tài)等。其基本原理如圖2-23所示。

圖2-23 hmp原理
另一個協(xié)議是QEMU Monitor Protocol(qmp),它是一個基于json、用來與QEMU進行交互的協(xié)議,采用典型的服務器-客戶端架構(gòu)。通過qmp,上層管理軟件可以很方便地對QEMU虛擬機進行管理,如virsh就能夠使用qmp對虛擬機進行管理。qmp原理如圖2-24所示。

圖2-24 qmp原理
現(xiàn)在的QEMU底層其實都是通過qmp完成功能的,只是還保留了hmp的接口。
從圖2-23可以看出,hmp是針對人的,所以采用了基于“info xxx”等簡單易記字符串的協(xié)議,而qmp主要是針對機器和其他程序的,所以采用了更加規(guī)范的json格式來傳遞數(shù)據(jù)。
2.5.2 qmp的使用
1.通過TCP使用qmp
使用-qmp添加qmp相關(guān)參數(shù):

使用telnet連接localhost:1234。

之后就可以使用qmp的命令和虛擬機交互了。

2.通過unix socket使用qmp
使用unix socket創(chuàng)建qmp。

使用nc連接該socket:

之后就跟TCP一樣,可以向其發(fā)送qmp命令了。

qmp的詳細命令格式可以在QEMU代碼樹主目錄下面的qmp-commands.hx中找到。
2.5.3 qmp源碼分析
與qmp參數(shù)相關(guān)的解析函數(shù)是monitor_parse,從vl.c可以看到,多個命令都會引起monitor參數(shù)的解析。

這里以qmp為例介紹,其參數(shù)是-qmp unix:/tmp/qmp-test,server,nowait。
由于解析過程比較煩瑣并且脫離主題,因此這里只進行簡單介紹。在解析qmp命令時會創(chuàng)建一個-chardev參數(shù),解析chardev參數(shù)的時候會創(chuàng)建chardev設備,然后根據(jù)所指定的unix地址,最終創(chuàng)建一個unix socket,代碼如下。

socket_listen返回一個新創(chuàng)建的fd,這個fd會被添加到QEMU的主程序循環(huán)中進行事件監(jiān)聽,這樣qmp的unix socket就處在監(jiān)聽狀態(tài)了,其接收連接的函數(shù)是tcp_chr_accept,客戶端可以去連接它并且進行數(shù)據(jù)交互。
使用nc進行連接。

tcp_chr_accept會調(diào)用tcp_chr_new_client將之前的監(jiān)聽取消,然后tcp_chr_new_client調(diào)用tcp_chr_connect,設置新的監(jiān)聽函數(shù)來對這個連接進行處理,此時這個socket的監(jiān)聽函數(shù)為tcp_chr_read。
qmp連接好之后的第一步是協(xié)商,客戶端通過發(fā)送{"execute":"qmp_capabilities"}完成。經(jīng)過tcp_chr_read的一系列調(diào)用,最終會調(diào)用到handle_qmp_command。handle_qmp_command調(diào)用qmp_dispatch->do_qmp_dispatch,最后一個函數(shù)調(diào)用cmd->fn,從而實現(xiàn)命令的處理函數(shù),其中cmd是注冊的qmp命令,用QmpCommand表示。


就"qmp_capabilities"命令來說,do_qmp_dispatch函數(shù)最終會調(diào)用到qmp_qmp_capabilities。幾乎所有qmp命令的處理函數(shù)形式都是qmp_xxx_yyy,后面的xxx和yyy表示對應的qmp命令。
2.5.4 qmp命令添加
這里簡單介紹了qmp的原理,實際中其實很多時候需要添加一個qmp來定制一些功能。這里以一個例子介紹如何添加qmp命令。添加一個qmp命令包括如下4個步驟。
1)定義符合QAPI方式的qmp命令及其參數(shù)和返回值的類型。
2)完成新增qmp的功能函數(shù),既可以將這個函數(shù)放在相關(guān)功能的模塊,也可以放在qmp.c文件中。
3)此時完成了一個qmp命令的編寫,可以通過2.5.2節(jié)的方式調(diào)用該qmp功能。
4)編寫相應的hmp命令。這不是一個必需的步驟,只有在該命令對human有意義的時候才需要編寫。hmp功能函數(shù)直接調(diào)用對應的qmp函數(shù)。
比如要添加一個“qmp-test”的qmp命令,執(zhí)行該命令的時候會設置一個全局變量。第一步在qapi-schema.json文件的最后一行添加如下內(nèi)容。

接著,在qmp.c文件的最后實現(xiàn)“qmp-test”命令的處理函數(shù)。


這個時候可以使用如下的json命令向qmp發(fā)起功能請求。

將這個命令作為hmp也比較合適,這里也可以添加一個hmp命令,在hmp-commands.hx的中間添加下面的內(nèi)容。

在hmp.c的文件最后添加實現(xiàn)hmp命令功能的函數(shù)。

需要在hmp.h中聲明一下該函數(shù)。

重新編譯QEMU之后,就能夠使用“qmp-test 80”向QEMU發(fā)送hmp命令了。