9.2 libvirt中对Qemu的控制


本节以libvirt 1.2.8为基础,来分析libvirt如何控制qemu虚拟机.

 

9.2.1 libvirt qemu的架构

int qemuRegister(void) (qemu/qemu_driver.c)

{

    if(virRegisterDriver(&qemuDriver) < 0)

        return -1;

    if(virRegisterStateDriver(&qemuStateDriver) < 0)

        return -1;

    return 0;

}

 

static virDriver qemuDriver = {

    .no = VIR_DRV_QEMU,

    .name =QEMU_DRIVER_NAME,

    .connectOpen =qemuConnectOpen, /* 0.2.0 */

    .connectClose =qemuConnectClose, /* 0.2.0 */

   .connectSupportsFeature = qemuConnectSupportsFeature, /* 0.5.0 */

    .connectGetType =qemuConnectGetType, /* 0.2.0 */

    .connectGetVersion =qemuConnectGetVersion, /* 0.2.0 */

    .connectGetHostname = qemuConnectGetHostname,/* 0.3.3 */

    .connectGetSysinfo =qemuConnectGetSysinfo, /* 0.8.8 */

    .connectGetMaxVcpus =qemuConnectGetMaxVcpus, /* 0.2.1 */

    .............

} //该结构为qemu的底层操作接口

virRegisterDriver  会将上述结构存于:

virDriverTab[virDriverTabCount] = driver;

virDriverTabCount++;

 

下面看看libvirt如何从上层调用到底层qemu_driver.

上一节的例子中,代码首先会调用virConnectOpenReadOnly

virConnectOpenReadOnly ==> do_open

a .因为name 为null所以调用virConnectGetDefaultURI 从环境变量中获取name.

b. 遍历驱动,调用virDriverTab[i]->connectOpen ==> qemuConnectOpen

 

9.2.2 qemu调用情景分析

本小节通过如下几个情景来分析,libvirt对qemu的控制方式

a.虚拟机的配置与创建

b. vcpu信息和最大内存信息查询

c. 虚拟机supspend

 

(1) 虚拟机的配置与创建

virDomainCreateXML (libvirt.c) ==>

    conn->driver->domainCreateXML(conn,xmlDesc, flags);

 

qemuDomainCreateXML

a)  virQEMUDriverGetCapabilities取得虚拟机支持的能力; 存于driver->caps= caps;

b)  XML 解析virDomainDefParseString  

c)  创建domain, 并加入列表

qemuDomainAssignAddresses

virDomainObjListAdd

d)  准备启动,建立job

qemuDomainObjBeginJob(driver,vm, QEMU_JOB_MODIFY);

e)  根据配置启动qemu进程

qemuProcessStart

f)  建立虚拟机创建与引导的event

virDomainEventLifecycleNewFromObj

g)  取得domain结构指针

virGetDomain(conn,vm->def->name, vm->def->uuid);

 

下面看看qemuProcessStart的流程:

a)  得到配置结构cfg =virQEMUDriverGetConfig(driver);

b)  初始化虚拟机id, 和domain 状态

vm->def->id= qemuDriverAllocateID(driver);

qemuDomainSetFakeReboot(driver,vm, false);

virDomainObjSetState(vm,VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_UNKNOWN);

c)  设备的准备

qemuNetworkPrepareDevices

qemuPrepareHostDevices

virDomainChrDefForeach

d)  Cgroup的准备

e)  log qemuDomainCreateLog

f)  vcpu数量检察

g)  直接io 设备准备qemuAssignDeviceAliases

h)  根据配置机建立qemu的启动命令行参数

qemuBuildCommandLine

启动qemu

ret= virCommandRun(cmd, NULL);

virCommandHandshakeWait(cmd);

i)  后处理,如设置cgroupqemuSetupCgroup;cpu亲和性设置qemuProcessInitCpuAffinity

j)  连接qemu 的monitor : qemuProcessWaitForMonitor

向qemu发送monitor命令,例如:qemuProcessVerifyGuestCPU==》qemuMonitorGetGuestCPU 取guest的vcpu.

退出 qemu monitor. qemuDomainObjExitMonitor

 

qemu启动的核心在于commandline, 我们下面分析qemuBuildCommandLine(qemu_command.c)

a)  建立启动command结构cmd = virCommandNew(emulator);

b)  cpu相关命令行建立qemuBuildCpuArgStr

c)  内存

virCommandAddArg(cmd,"-m");

def->mem.max_balloon= VIR_DIV_UP(def->mem.max_balloon, 1024) * 1024;

virCommandAddArgFormat(cmd,"%llu", def->mem.max_balloon / 1024);

d)  smp, smbios,graphics chardev, rtc等设置

e)  VIR_DOMAIN_CONTROLLER_TYPE_PCI  guest os 的pci controller设置

f)  usb,与usbdevice相关设置

。。。。。

该函数较长,但功能比较单一。

 

(2) vcpu信息和最大内存信息查询

qemuConnectGetMaxVcpus ==》  kvmGetMaxVCPUs ==》

ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_NR_VCPUS);

通过iotrl方式获得vcpu数目。

 

qemuDomainGetMaxMemory ==》

  return  vm->def->mem.max_balloon;

直接通过配置信息返回

 

(3) 虚拟机supspend

qemuDomainSuspend

a)  根据虚拟机domain的到虚拟机vm = qemuDomObjFromDomain(dom);

b)  qemuDomainObjBeginJob ==》 qemuDomainObjBeginJobInternal(qem_domain.c)启动任务

c)  生成事件VIR_DOMAIN_EVENT_SUSPENDED

d)  qemuProcessStopCPUs停止vcpu的运行

virDomainSaveStatus保存虚拟机状态

e)  qemuDomainObjEndJob(driver,vm);

qemuDomainEventQueue(driver,event);

 

其中重点是qemuProcessStopCPUs:

{

   .......

    if(qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)

        goto cleanup;

 

    ret = qemuMonitorStopCPUs(priv->mon);

   qemuDomainObjExitMonitor(driver, vm);

}

 

如果支持json, 将使用json向qemu发送命令

qemuMonitorStopCPUs ==> qemuMonitorJSONStopCPUs(mon);

qemuMonitorJSONStopCPUs(qemuMonitorPtr mon) {

    ..........

    ret =qemuMonitorJSONCommand(mon, cmd, &reply);

 

    if (ret == 0)

        ret =qemuMonitorJSONCheckError(cmd, reply);

 

     ..........

    return ret;

}

qemuMonitorJSONCommand ==> qemuMonitorJSONCommandWithFd

 

小结: libvrit 可以直接通过ioctl 获取内核态kvm信息,或通过qemumonitor控制qemu. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值