Libvirt代码架构
Libvirt介绍
Libvirt学习
- 通过virsh了解libvirt api的调用方式
- 通过virHypervisorDriver了解libvirt api的实现
virsh代码阅读
通过阅读virsh代码我们能够了解libvirt api的作用以及调用方法
文件名 | 对应vshCmdDef变量 | 对应virsh命令 |
---|---|---|
virsh-domain-monitor.c | domMonitoringCmds | virsh XX(虚拟机监控) |
virsh-domain.c | domManagementCmds | virsh XX(虚拟机操作) |
virsh-host.c | hostAndHypervisorCmds | virsh XX(虚拟机配置) |
virsh-interface.c | ifaceCmds | virsh iface-XX |
virsh-network.c | networkCmds | virsh net-XX |
virsh-nodedev.c | nodedevCmds | virsh net-XX |
virsh-nwfilter.c | nwfilterCmds | virsh nwfilter-XX |
virsh-pool.c | storagePoolCmds | virsh pool-XX |
virsh-secret.c | secretCmds | virsh secret-XX |
virsh-snapshot.c | snapshotCmds | virsh snapshot-XX |
virsh-volume.c | storageVolCmds | virsh vol-XX |
有了上面的表格我们就能够根据使用的virsh命令找到对应文件的对应vshCmdDef变量
/*
* vshCmdDef - command definition
*/
struct _vshCmdDef {
const char *name; /* name of command, or NULL for list end */
bool (*handler) (vshControl *, const vshCmd *); /* command handler */
const vshCmdOptDef *opts; /* definition of command options */
const vshCmdInfo *info; /* details about command */
unsigned int flags; /* bitwise OR of VSH_CMD_FLAG */
};
一个vshCmdDef
结构对应一个virsh
命令,其中vshCmdOptDef
定义了命令的参数,vshCmdInfo
定义了命令的帮助信息,bool (*handler) (vshControl *, const vshCmd *)
定义了命令的处理函数。
实际应用
如何阅读virsh start
处理代码
- 查看virsh-domain.c文件的domManagementCmds变量,找到
{.name = "start",
.handler = cmdStart,
.opts = opts_start,
.info = info_start,
.flags = 0
}
- 查看opts_start了解命令参数
static const vshCmdOptDef opts_start[] = {
VIRSH_COMMON_OPT_DOMAIN(N_("name of the inactive domain")),
#ifndef WIN32
{.name = "console",
.type = VSH_OT_BOOL,
.help = N_("attach to console after creation")
},
#endif
{.name = "paused",
.type = VSH_OT_BOOL,
.help = N_("leave the guest paused after creation")
},
{.name = "autodestroy",
.type = VSH_OT_BOOL,
.help = N_("automatically destroy the guest when virsh disconnects")
},
{.name = "bypass-cache",
.type = VSH_OT_BOOL,
.help = N_("avoid file system cache when loading")
},
{.name = "force-boot",
.type = VSH_OT_BOOL,
.help = N_("force fresh boot by discarding any managed save")
},
{.name = "pass-fds",
.type = VSH_OT_STRING,
.help = N_("pass file descriptors N,M,... to the guest")
},
{.name = NULL}
};
- 查看cmdStart了解命令处理代码,即对应libvirt api的调用方法,此处是对
virDomainCreateWithFiles
或virDomainCreate
的调用
static bool cmdStart(vshControl *ctl, const vshCmd *cmd)
libvirt代码阅读
理解libvirt的代码架构就需要理解三个接口,libvirt通过高度抽象的接口对上层应用提供统一的入口,屏蔽底层的具体实现
接口 | 说明 | 代码目录 |
---|---|---|
virHypervisorDriver | 虚拟机管理接口 | qemu目录(qemu-kvm虚拟化)、xen目录(xen虚拟化)、lxc目录(lxc虚拟化)、vmware目录(vmware虚拟化) |
virStorageDriver | 磁盘管理接口 | storage目录 |
virNetworkDriver | 网络管理接口 | network目录 |
qemu-kvm虚拟化实现
首先我们进入qemu目录来看qemu_driver.c中的静态变量qemuHypervisorDriver
,它就是virHypervisorDriver
接口的qemu-kvm实现,例如通过查询这个变量,我们就知道libvirt api的domainListAllSnapshots
的qemu-kvm实现就是qemuDomainListAllSnapshots
函数
static virHypervisorDriver qemuHypervisorDriver = {
****省略****
.domainListAllSnapshots = qemuDomainListAllSnapshots, /* 0.9.13 */
****省略****
}
实际应用
虚拟机启动,libvirt磁盘的backing_chain形成过程
- 通过
virsh start
命令我们知道虚拟机启动调用的api为domainCreateWithFlags
,然后我们知道对应的实现为qemuDomainCreateWithFlags
- 分析
qemuDomainCreateWithFlags
函数
qemuDomainObjStart()
{
qemuProcessStart()
{
qemuProcessPrepareDomain()
{
qemuDomainCheckDiskPresence()
{
// 磁盘的backing_chain形成逻辑
qemuDomainDetermineDiskChain()
}
}
}
}
-
分析
qemuDomainDetermineDiskChain
我们了解到virStorageFileGetMetadataRecurse
就是正真实现磁盘backing_chain的函数,这边相当于libvirt执行了qemu-img info
命令 -
我们再看点更底层的东西,例如在backing_chain形成中是如何读取磁盘的backing信息,即
virStorageFileGetMetadataInternal
函数实现细节
virStorageFileGetMetadataInternal
{
//读取backing信息,fileTypeInfo是util/virstoragefile.c中的静态变量,该变量定义了各种格式文件的backing信息读取方法
fileTypeInfo[meta->format].getBackingStore()
}
static struct FileTypeInfo const fileTypeInfo[] = {
****省略****
[VIR_STORAGE_FILE_QCOW2] = {
0, "QFI", NULL,
LV_BIG_ENDIAN, 4, 4, {2, 3},
QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore,
qcow2GetFeatures
},
****省略****
}
- 仔细分析
qcow2GetBackingStore
函数可以知道backing_format信息在标准header信息之外,这就是qemu-img create -f qcow2 -b
生成的backing_chain会有问题,而qemu-img create -f qcow2 -o
不会的原因