QEMU QMP机制
QMP简介
QMP的全称是QEMU Machine Protocol,是一种以json格式为基础的协议,允许用户通过该接口查询、配置QEMU实例。
QEMU官方文档中对QMP的解释是:
- Lightweight, text-based, easy to parse data format
- Asynchronous messages support (events)
- Capabilities negotiation
- API/ABI stability guarantees
很多基于QEMU的应用都使用了QMP接口,比如著名的虚拟化中间件libvirt,对QEMU实例的操作就是使用了QMP接口。此外,还可以通过telnet、qmp-shell script等方式使用QMP接口,QEMU的官方文档进行了详细介绍。本博客主要使用libvirt来展示QMP相关接口,通过libvirt提供的virsh工具可以直接调用QMP接口。
1 环境准备
- 支持虚拟化的Server,装有QEMU、libvirt等相关虚拟化组件
- 虚拟机,可以通过virsh与其交互
2 相关命令使用
2.1 通过virsh list
查看虚拟机状态是否正常
Linux:~ # virsh list
Id Name State
------------------------
1 ubuntu running
2.2 查看qemu-monitor-command
子命令
Linux:~ # virsh qemu-monitor-command --help
NAME
qemu-monitor-command - QEMU Monitor Command
SYNOPSIS
qemu-monitor-command <domain> [--hmp] [--pretty] [--return-value] {[--cmd] <string>}...
DESCRIPTION
QEMU Monitor Command
OPTIONS
[--domain] <string> domain name, id or uuid
--hmp command is in human monitor protocol
--pretty pretty-print any qemu monitor protocol output
--return-value extract the value of the 'return' key from the returned string
[--cmd] <string> command
qemu-monitor-command
子命令是virsh
调用QMP的接口,通过帮助文档我们可以看到其基本用法。 其中 --pretty 可以格式化相关json输出, --hmp 是将复杂的QMP接口简化成了便于手动执行的接口,--return-value仅输出返回内部,忽略状态码等信息。
2.3 调用示例
virsh qemu-monitor-command ubuntu '{"execute":"query-commands"}'
Linux:~ # virsh qemu-monitor-command ubuntu '{"execute":"query-commands"}'
{"return":[{"name":"netdev_add"},{"name":"device_add"},{"name":"query-QMP-schema"},
{"name":"query-memory-size-summary"},{"name":"closefd"},{"name":"getfd"},
{"name":"set_link"},{"name":"query-uuid"},{"name":"query-kvm"},{"name":"query-name"},
···
忽略部分输出
···
{"name":"add_client"},{"name":"query-commands"},{"name":"query-version"},{"name":"QMP_capabilities"}],"id":"libvirt-21"}
可以看到QMP提供了非常多的接口供使用,包括query-commands
、query-qmp-schema
、query-kvm
等查询类接口,add_client
、set_link
等修改设置的接口。
virsh qemu-monitor-command ubuntu --pretty '{"execute":"query-memory-size-summary"}'
Linux:~ # virsh qemu-monitor-command ubuntu --pretty '{"execute":"query-memory-size-summary"}'
{
"return": {
"base-memory": 4294967296,
"plugged-memory": 0
},
"id": "libvirt-30"
}
加入 --pretty参数后,输出被格式化。
2.4 HMP格式
上面提到qemu-monitor-command
子命令支持 --hmp参数,是对QMP命令的简化,大大降低了使用QMP命令的复杂度,并且部分HMP就是对QMP命令进行了封装,底层实际只用的还是QMP命令。但是通过QEMU的官方说明看,HMP是QEMU上的简单交互式监视器,主要为调试和简单的人类使用而设计,更高级别的工具应该连接到QMP , QMP才能提供一个稳定的JSON接口,以便于进行可靠的解析。 以查询虚拟机内存为例,使用HMP可以简化命令的输入和输出:
Linux:~ # virsh qemu-monitor-command ubuntu --HMP info memory_size_summary
base memory: 4294967296
plugged memory: 0
3 编写新的QMP命令
下面将展示如何向QEMU中增加一个hello world接口。
3.1 QEMU源码编译安装
这里仅展示了基础步骤,还要根据不同的平台和机器安装对应的依赖。
git clone https://git.qemu.org/git/qemu.git
cd qemu
git submodule init
git submodule update --recursive
./configure
make
3.2 编写QMP接口源码
3.2.3 增加QMP接口
QEMU提供了一套QMP接口实现框架,在QEMU的源码的qapa路径下有多个***.json, 这些都是不同分类的QMP接口的定义。这里选择在qapi/misc.json文件,增加一个hell world接口声明。
##
# @hello-world:
# Print a client provided string to the standard output stream.
#
# @message: string to be printed
#
# Returns: Nothing on success.
#
# Notes: if @message is not provided, the "Hello, world" string will
# be printed instead
# Since: <next qemu stable release, eg. 1.0>
##
{ 'command': 'hello-world', 'data': { '*message': 'str' } }
3.2.3 实现QMP函数
在monitor/qmp-cmds.c添加函数实现
void qmp_hello_world(bool has_message, const char *message, Error **errp)
{
if (has_message) {
printf("%s\n", message);
} else {
printf("Hello, world\n");
}
}
3.2.4 实现HMP命令
在hmp-commands.hx添加接口
{
.name = "hello-world",
.args_type = "message:s?",
.params = "hello-world [message]",
.help = "Print message to the standard output",
.cmd = hmp_hello_world,
},
在include/monitor/hmp.h添加函数声明
void hmp_hello_world(Monitor *mon, const QDict *qdict);
在monitor/hmp-cmds.c添加函数实现
void hmp_hello_world(Monitor *mon, const QDict *qdict)
{
const char *message = qdict_get_try_str(qdict, "message");
Error *err = NULL;
qmp_hello_world(!!message, message, &err);
if (err) {
monitor_printf(mon, "%s\n", error_get_pretty(err));
error_free(err);
return;
}
}
3.2.5 验证QMP命令实现
编写完成上述代码后,重现编译安装,修改虚拟机xml中的<emulator>
标签,使用自定义的QEMU启动虚拟机,验证新的QMP命令。
- 查看QMP命令是否存在
Linux:~ # virsh qemu-monitor-command ubuntu --pretty '{"execute":"query-commands"}' | grep hello
"name": "hello-world"
- 调用QMP命令
Linux:~ # virsh qemu-monitor-command ubuntu --pretty '{ "execute": "hello-world", "arguments": { "message": "We love qemu" } }'
{
"return": {
},
"id": "libvirt-17"
}
- 查看HMP命令是否存在
Linux:~ # virsh qemu-monitor-command ubuntu --hmp help | grep hello
hello-world hello-world [message] -- Print message to the standard output