• 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的调用方法,此处是对virDomainCreateWithFilesvirDomainCreate的调用
    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 apidomainListAllSnapshotsqemu-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不会的原因
  • 相关阅读:
    开发笔记--git代码回退,撤回到上一个版本
    开发笔记--Navicat导出postgresql表结构数据成excel文件
    使用Aspose.Words组件给word加水印
    JSON JavaScriptSerializer 字符串的长度超过了为 maxJsonLength 属性设置的值。
    http content-type详解
    Linux CPU使用率超过100%的原因
    Qt查找依赖库的简单方法及如何简便地在pro中添加依赖库
    OSI七层网络模型分别是哪七层?各运行那些协议?
    配置文件管理
    Java中日期转json时日期格式转换
  • 原文地址:https://www.cnblogs.com/silvermagic/p/7666179.html
Copyright © 2020-2023  润新知