Re: [libvirt] [RFC v1 4/6] migration: Migration support for ephemeral hostdevs
On 05/13/2015 04:36 PM, Peter Krempa wrote: On Wed, May 13, 2015 at 11:36:30 +0800, Chen Fan wrote: add migration support for ephemeral host devices, introduce two 'detach' and 'restore' functions to unplug/plug host devices during migration. Signed-off-by: Chen Fan --- src/qemu/qemu_migration.c | 171 -- src/qemu/qemu_migration.h | 9 +++ src/qemu/qemu_process.c | 11 +++ 3 files changed, 187 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 56112f9..d5a698f 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3384,6 +3384,158 @@ qemuMigrationPrepareDef(virQEMUDriverPtr driver, return def; } +int +qemuMigrationDetachEphemeralDevices(virQEMUDriverPtr driver, +virDomainObjPtr vm, +bool live) +{ +qemuDomainObjPrivatePtr priv = vm->privateData; +virDomainHostdevDefPtr hostdev; +virDomainNetDefPtr net; +virDomainDeviceDef dev; +virDomainDeviceDefPtr dev_copy = NULL; +virCapsPtr caps = NULL; +int actualType; +int ret = -1; +size_t i; + +VIR_DEBUG("Rum domain detach ephemeral devices"); + +if (!(caps = virQEMUDriverGetCapabilities(driver, false))) +return ret; + +for (i = 0; i < vm->def->nnets;) { +net = vm->def->nets[i]; + +actualType = virDomainNetGetActualType(net); +if (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV) { +i++; +continue; +} + +hostdev = virDomainNetGetActualHostdev(net); +if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || +hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI || +!hostdev->ephemeral) { +i++; +continue; +} + +dev.type = VIR_DOMAIN_DEVICE_NET; +dev.data.net = net; + +dev_copy = virDomainDeviceDefCopy(&dev, vm->def, + caps, driver->xmlopt); +if (!dev_copy) +goto cleanup; + +if (live) { +/* nnets reduced */ +if (qemuDomainDetachNetDevice(driver, vm, dev_copy) < 0) +goto cleanup; So this is where the fun begins. qemuDomainDetachNetDevice is not designed to be called this way since the detach API where it's used normally returns 0 in the following two cases: 1) The detach was successfull, the guest removed the device 2) The detach request was successful, but guest did not remove the device yet In the latter case you need to wait for a event to successfully know when the device was removed. Since this might very well happen the code will need to be changed to take that option into account. Please note that that step will make all the things really complicated. did you said the event is "DEVICE_DELETED" ? I saw the code the funcition qemuDomainWaitForDeviceRemoval has been used for waiting device removed from guest. Thanks, Chen Peter -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [RFC v1 4/6] migration: Migration support for ephemeral hostdevs
On 05/13/2015 10:30 PM, Laine Stump wrote: On 05/13/2015 05:57 AM, Daniel P. Berrange wrote: On Wed, May 13, 2015 at 11:36:30AM +0800, Chen Fan wrote: add migration support for ephemeral host devices, introduce two 'detach' and 'restore' functions to unplug/plug host devices during migration. Signed-off-by: Chen Fan --- src/qemu/qemu_migration.c | 171 -- src/qemu/qemu_migration.h | 9 +++ src/qemu/qemu_process.c | 11 +++ 3 files changed, 187 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 56112f9..d5a698f 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c +void +qemuMigrationRestoreEphemeralDevices(virQEMUDriverPtr driver, + virConnectPtr conn, + virDomainObjPtr vm, + bool live) +{ +qemuDomainObjPrivatePtr priv = vm->privateData; +virDomainDeviceDefPtr dev; +int ret = -1; +size_t i; + +VIR_DEBUG("Rum domain restore ephemeral devices"); + +for (i = 0; i < priv->nEphemeralDevices; i++) { +dev = priv->ephemeralDevices[i]; + +switch ((virDomainDeviceType) dev->type) { +case VIR_DOMAIN_DEVICE_NET: +if (live) { +ret = qemuDomainAttachNetDevice(conn, driver, vm, +dev->data.net); +} else { +ret = virDomainNetInsert(vm->def, dev->data.net); +} + +if (!ret) +dev->data.net = NULL; +break; +case VIR_DOMAIN_DEVICE_HOSTDEV: +if (live) { +ret = qemuDomainAttachHostDevice(conn, driver, vm, + dev->data.hostdev); + } else { +ret =virDomainHostdevInsert(vm->def, dev->data.hostdev); +} This re-attach step is where we actually have far far far worse problems than with detach. This is blindly assuming that the guest on the target host can use the same hostdev that it was using on the source host. (kind of pointless to comment on, since pkrempa has changed my opinion by forcing me to think about the "failure to reattach" condition, but could be useful info for others) For a , yes, but not for (which would point to a libvirt network pool of VFs). This is essentially useless in the real world. Agreed (for plain ) Even if the same vendor/model device is available on the target host, it is very unlikely to be available at the same bus/slot/function that it was on the source. It is quite likely neccessary to allocate a complete different NIC, or if using SRIOV allocate a different function. It is also not uncommon to have different vendor/models, so a completely different NIC may be required. In the case of a network device, a different brand/model of NIC at a different PCI address using a different guest driver shouldn't be a problem for the guest, as long as the MAC address is the same (for a Linux guest anyway; not sure what a Windows guest would do with a NIC that had the same MAC but used a different driver). This points out the folly of trying to do migration with attached hostdevs (managed at *any* level), for anything other than SRIOV VFs (which can have their MAC address set before attach, unlike non-SRIOV NICs). . So should we focus on implementing the feature that support migration with SRIOV VFs at first? I think that is simple to achieve my original target that implement NIC passthrough device migration. because sometimes we assign a native NIC to guest to keep the performance of network I/O, due to the MAC limitation of the non-SRIOV NICs, as laine said the cost of SRIOV NIC is cheaper than what we try. Thanks, Chen -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [RFC v1 3/6] qemu: add check ephemeral devices only for PCI host devices
On 05/13/2015 04:17 PM, Peter Krempa wrote: On Wed, May 13, 2015 at 11:36:29 +0800, Chen Fan wrote: currently, we only support PCI host devices with ephemeral flag. and USB already supports migration. so maybe in the near future we can support SCSI. Signed-off-by: Chen Fan --- src/qemu/qemu_command.c | 10 ++ src/qemu/qemu_migration.c | 11 +++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index fc81214..5acd8b4 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -10182,6 +10182,16 @@ qemuBuildCommandLine(virConnectPtr conn, /* PCI */ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && +hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && +(hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && + hostdev->ephemeral)) { +virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("non-USB and non-PCI device assignment with ephemeral " + "flag are not supported by this version of qemu")); This functionality is not based on qemu support but on libvirt implementation so the error message is incorrect. indeed. thanks for pointing out this. Chen +goto error; +} + +if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { int backend = hostdev->source.subsys.u.pci.backend; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 83be435..56112f9 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1981,21 +1981,24 @@ qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm, def = vm->def; } -/* Migration with USB host devices is allowed, all other devices are - * forbidden. +/* + * Migration with USB and ephemeral PCI host devices host devices are allowed, + * all other devices are forbidden. */ forbid = false; for (i = 0; i < def->nhostdevs; i++) { virDomainHostdevDefPtr hostdev = def->hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || -hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { +(hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && +!hostdev->ephemeral)) { forbid = true; break; } } if (forbid) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("domain has assigned non-USB host devices")); + _("domain has assigned non-USB and " + "non-ephemeral host devices")); return false; } This patch has to be moved after you actually implement the ephemeral device unplug code, since an intermediate state would allow to bypass the check while the devices actually would not be unplugged. Peter -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC v1 0/6] Live Migration with ephemeral host NIC devices
my main goal is to add support migration with host NIC passthrough devices and keep the network connectivity. this series patch base on Shradha's patches on https://www.redhat.com/archives/libvir-list/2012-November/msg01324.html which is add migration support for host passthrough devices. 1) unplug the ephemeral devices before migration 2) do native migration 3) when migration finished, hotplug the ephemeral devices TODO: keep network connectivity on guest level by bonding device. Chen Fan (6): conf: add ephemeral element for hostdev supporting migration qemu: Save ephemeral devices into qemuDomainObjPrivate qemu: add check ephemeral devices only for PCI host devices migration: Migration support for ephemeral hostdevs managedsave: move the domain xml handling forward to stop CPU managedsave: add managedsave support for ephemeral host devices docs/schemas/domaincommon.rng | 10 ++ docs/schemas/network.rng | 5 + src/conf/domain_conf.c | 14 +- src/conf/domain_conf.h | 1 + src/conf/network_conf.c| 13 ++ src/conf/network_conf.h| 1 + src/network/bridge_driver.c| 1 + src/qemu/qemu_command.c| 11 ++ src/qemu/qemu_domain.c | 5 + src/qemu/qemu_domain.h | 3 + src/qemu/qemu_driver.c | 48 +++--- src/qemu/qemu_migration.c | 182 - src/qemu/qemu_migration.h | 9 + src/qemu/qemu_process.c| 12 ++ tests/networkxml2xmlin/hostdev-pf.xml | 2 +- tests/networkxml2xmlin/hostdev.xml | 2 +- tests/networkxml2xmlout/hostdev-pf.xml | 2 +- tests/networkxml2xmlout/hostdev.xml| 2 +- .../qemuxml2argv-controller-order.xml | 2 +- .../qemuxml2argv-hostdev-pci-address-device.xml| 2 +- .../qemuxml2argv-hostdev-pci-address.xml | 2 +- .../qemuxml2argv-hostdev-scsi-autogen-address.xml | 22 +-- .../qemuxml2argv-hostdev-scsi-lsi-iscsi-auth.xml | 4 +- .../qemuxml2argv-hostdev-scsi-lsi-iscsi.xml| 4 +- .../qemuxml2argv-hostdev-scsi-lsi.xml | 2 +- .../qemuxml2argv-hostdev-scsi-rawio.xml| 2 +- .../qemuxml2argv-hostdev-scsi-readonly.xml | 2 +- .../qemuxml2argv-hostdev-scsi-sgio.xml | 2 +- .../qemuxml2argv-hostdev-scsi-shareable.xml| 2 +- ...qemuxml2argv-hostdev-scsi-virtio-iscsi-auth.xml | 4 +- .../qemuxml2argv-hostdev-scsi-virtio-iscsi.xml | 4 +- .../qemuxml2argv-hostdev-scsi-virtio-scsi.xml | 2 +- ...emuxml2argv-hostdev-usb-address-device-boot.xml | 2 +- .../qemuxml2argv-hostdev-usb-address-device.xml| 2 +- .../qemuxml2argv-hostdev-usb-address.xml | 2 +- .../qemuxml2argv-hostdev-vfio-multidomain.xml | 2 +- .../qemuxml2argvdata/qemuxml2argv-hostdev-vfio.xml | 2 +- .../qemuxml2argv-net-hostdev-multidomain.xml | 2 +- .../qemuxml2argv-net-hostdev-vfio-multidomain.xml | 2 +- .../qemuxml2argv-net-hostdev-vfio.xml | 2 +- .../qemuxml2argvdata/qemuxml2argv-net-hostdev.xml | 2 +- tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml| 4 +- ...qemuxml2xmlout-hostdev-scsi-autogen-address.xml | 22 +-- 43 files changed, 340 insertions(+), 83 deletions(-) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC v1 1/6] conf: add ephemeral element for hostdev supporting migration
the ephemeral flag helps support migration with PCI-passthrough. An ephemeral hostdev is automatically unplugged before migration and replugged (if one is available on the destination) after migration. Signed-off-by: Chen Fan --- docs/schemas/domaincommon.rng | 10 ++ docs/schemas/network.rng | 5 + src/conf/domain_conf.c | 14 +- src/conf/domain_conf.h | 1 + src/conf/network_conf.c| 13 + src/conf/network_conf.h| 1 + src/network/bridge_driver.c| 1 + src/qemu/qemu_command.c| 1 + tests/networkxml2xmlin/hostdev-pf.xml | 2 +- tests/networkxml2xmlin/hostdev.xml | 2 +- tests/networkxml2xmlout/hostdev-pf.xml | 2 +- tests/networkxml2xmlout/hostdev.xml| 2 +- .../qemuxml2argv-controller-order.xml | 2 +- .../qemuxml2argv-hostdev-pci-address-device.xml| 2 +- .../qemuxml2argv-hostdev-pci-address.xml | 2 +- .../qemuxml2argv-hostdev-scsi-autogen-address.xml | 22 +++--- .../qemuxml2argv-hostdev-scsi-lsi-iscsi-auth.xml | 4 ++-- .../qemuxml2argv-hostdev-scsi-lsi-iscsi.xml| 4 ++-- .../qemuxml2argv-hostdev-scsi-lsi.xml | 2 +- .../qemuxml2argv-hostdev-scsi-rawio.xml| 2 +- .../qemuxml2argv-hostdev-scsi-readonly.xml | 2 +- .../qemuxml2argv-hostdev-scsi-sgio.xml | 2 +- .../qemuxml2argv-hostdev-scsi-shareable.xml| 2 +- ...qemuxml2argv-hostdev-scsi-virtio-iscsi-auth.xml | 4 ++-- .../qemuxml2argv-hostdev-scsi-virtio-iscsi.xml | 4 ++-- .../qemuxml2argv-hostdev-scsi-virtio-scsi.xml | 2 +- ...emuxml2argv-hostdev-usb-address-device-boot.xml | 2 +- .../qemuxml2argv-hostdev-usb-address-device.xml| 2 +- .../qemuxml2argv-hostdev-usb-address.xml | 2 +- .../qemuxml2argv-hostdev-vfio-multidomain.xml | 2 +- .../qemuxml2argvdata/qemuxml2argv-hostdev-vfio.xml | 2 +- .../qemuxml2argv-net-hostdev-multidomain.xml | 2 +- .../qemuxml2argv-net-hostdev-vfio-multidomain.xml | 2 +- .../qemuxml2argv-net-hostdev-vfio.xml | 2 +- .../qemuxml2argvdata/qemuxml2argv-net-hostdev.xml | 2 +- tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml| 4 ++-- ...qemuxml2xmlout-hostdev-scsi-autogen-address.xml | 22 +++--- 37 files changed, 99 insertions(+), 55 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index b1d883f..6f4551c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2261,6 +2261,11 @@ + + + + + @@ -3717,6 +3722,11 @@ + + + + + diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 4edb6eb..d63b066 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -115,6 +115,11 @@ + + + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 3d05844..a1a0602 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4823,6 +4823,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, { xmlNodePtr sourcenode; char *managed = NULL; +char *ephemeral = NULL; char *sgio = NULL; char *rawio = NULL; char *backendStr = NULL; @@ -4841,6 +4842,11 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, def->managed = true; } +if ((ephemeral = virXMLPropString(node, "ephemeral")) != NULL) { +if (STREQ(ephemeral, "yes")) +def->ephemeral = true; +} + sgio = virXMLPropString(node, "sgio"); rawio = virXMLPropString(node, "rawio"); @@ -18064,8 +18070,10 @@ virDomainActualNetDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "managed) +if (hostdef && hostdef->managed) virBufferAddLit(buf, " managed='yes'"); +if (hostdef && hostdef->ephemeral) +virBufferAddLit(buf, " ephemeral='yes'"); } if (def->trustGuestRxFilters) virBufferAsprintf(buf, " trustGuestRxFilters='%s'", @@ -18236,6 +18244,8 @@ virDomainNetDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "managed) virBufferAddLit(buf, " managed='yes'"); +if (hostdef && hostdef->ephemeral) +virBufferAddLit(buf, " ephemeral='yes'"); if
[libvirt] [RFC v1 5/6] managedsave: move the domain xml handling forward to stop CPU
we should save the XML information to image head before we hotunplug the ephemeral devices. so here we handle XML ahead. Signed-off-by: Chen Fan --- src/qemu/qemu_driver.c | 40 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b3263ac..86d93d2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3179,26 +3179,6 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom, priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED; -/* Pause */ -if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) { -was_running = true; -if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE, -QEMU_ASYNC_JOB_SAVE) < 0) -goto endjob; - -if (!virDomainObjIsActive(vm)) { -virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("guest unexpectedly quit")); -goto endjob; -} -} - - /* libvirt.c already guaranteed these two flags are exclusive. */ -if (flags & VIR_DOMAIN_SAVE_RUNNING) -was_running = true; -else if (flags & VIR_DOMAIN_SAVE_PAUSED) -was_running = false; - /* Get XML for the domain. Restore needs only the inactive xml, * including secure. We should get the same result whether xmlin * is NULL or whether it was the live xml of the domain moments @@ -3225,6 +3205,26 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom, goto endjob; } +/* Pause */ +if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) { +was_running = true; +if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE, +QEMU_ASYNC_JOB_SAVE) < 0) +goto endjob; + +if (!virDomainObjIsActive(vm)) { +virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("guest unexpectedly quit")); +goto endjob; +} +} + + /* libvirt.c already guaranteed these two flags are exclusive. */ +if (flags & VIR_DOMAIN_SAVE_RUNNING) +was_running = true; +else if (flags & VIR_DOMAIN_SAVE_PAUSED) +was_running = false; + ret = qemuDomainSaveMemory(driver, vm, path, xml, compressed, was_running, flags, QEMU_ASYNC_JOB_SAVE); if (ret < 0) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC v1 4/6] migration: Migration support for ephemeral hostdevs
add migration support for ephemeral host devices, introduce two 'detach' and 'restore' functions to unplug/plug host devices during migration. Signed-off-by: Chen Fan --- src/qemu/qemu_migration.c | 171 -- src/qemu/qemu_migration.h | 9 +++ src/qemu/qemu_process.c | 11 +++ 3 files changed, 187 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 56112f9..d5a698f 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -3384,6 +3384,158 @@ qemuMigrationPrepareDef(virQEMUDriverPtr driver, return def; } +int +qemuMigrationDetachEphemeralDevices(virQEMUDriverPtr driver, +virDomainObjPtr vm, +bool live) +{ +qemuDomainObjPrivatePtr priv = vm->privateData; +virDomainHostdevDefPtr hostdev; +virDomainNetDefPtr net; +virDomainDeviceDef dev; +virDomainDeviceDefPtr dev_copy = NULL; +virCapsPtr caps = NULL; +int actualType; +int ret = -1; +size_t i; + +VIR_DEBUG("Rum domain detach ephemeral devices"); + +if (!(caps = virQEMUDriverGetCapabilities(driver, false))) +return ret; + +for (i = 0; i < vm->def->nnets;) { +net = vm->def->nets[i]; + +actualType = virDomainNetGetActualType(net); +if (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV) { +i++; +continue; +} + +hostdev = virDomainNetGetActualHostdev(net); +if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || +hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI || +!hostdev->ephemeral) { +i++; +continue; +} + +dev.type = VIR_DOMAIN_DEVICE_NET; +dev.data.net = net; + +dev_copy = virDomainDeviceDefCopy(&dev, vm->def, + caps, driver->xmlopt); +if (!dev_copy) +goto cleanup; + +if (live) { +/* nnets reduced */ +if (qemuDomainDetachNetDevice(driver, vm, dev_copy) < 0) +goto cleanup; +} else { +virDomainNetDefFree(virDomainNetRemove(vm->def, i)); +} +if (VIR_APPEND_ELEMENT(priv->ephemeralDevices, + priv->nEphemeralDevices, + dev_copy) < 0) { +goto cleanup; +} +dev_copy = NULL; +} + +for (i = 0; i < vm->def->nhostdevs;) { +hostdev = vm->def->hostdevs[i]; + +if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || +hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI || +!hostdev->ephemeral) { +i++; +continue; +} + +dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; +dev.data.hostdev = hostdev; + +VIR_FREE(dev_copy); +dev_copy = virDomainDeviceDefCopy(&dev, vm->def, + caps, driver->xmlopt); +if (!dev_copy) +goto cleanup; + +if (live) { +/* nhostdevs reduced */ +if (qemuDomainDetachHostDevice(driver, vm, dev_copy) < 0) +goto cleanup; +} else { +virDomainHostdevDefFree(virDomainHostdevRemove(vm->def, i)); +} +if (VIR_APPEND_ELEMENT(priv->ephemeralDevices, + priv->nEphemeralDevices, + dev_copy) < 0) { +goto cleanup; +} +dev_copy = NULL; +} + +ret = 0; + cleanup: +virDomainDeviceDefFree(dev_copy); +virObjectUnref(caps); + +return ret; +} + +void +qemuMigrationRestoreEphemeralDevices(virQEMUDriverPtr driver, + virConnectPtr conn, + virDomainObjPtr vm, + bool live) +{ +qemuDomainObjPrivatePtr priv = vm->privateData; +virDomainDeviceDefPtr dev; +int ret = -1; +size_t i; + +VIR_DEBUG("Rum domain restore ephemeral devices"); + +for (i = 0; i < priv->nEphemeralDevices; i++) { +dev = priv->ephemeralDevices[i]; + +switch ((virDomainDeviceType) dev->type) { +case VIR_DOMAIN_DEVICE_NET: +if (live) { +ret = qemuDomainAttachNetDevice(conn, driver, vm, +dev->data.net); +} else { +ret = virDomainNetInsert(vm->def, dev->data.net); +} + +if (!ret) +dev->data.net = NULL; +break; +case VIR_DOMAIN_DEVICE_HOSTDEV: +if (live) { +ret = qemuDomainAttachHostDevice(conn, driver
[libvirt] [RFC v1 3/6] qemu: add check ephemeral devices only for PCI host devices
currently, we only support PCI host devices with ephemeral flag. and USB already supports migration. so maybe in the near future we can support SCSI. Signed-off-by: Chen Fan --- src/qemu/qemu_command.c | 10 ++ src/qemu/qemu_migration.c | 11 +++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index fc81214..5acd8b4 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -10182,6 +10182,16 @@ qemuBuildCommandLine(virConnectPtr conn, /* PCI */ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && +hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && +(hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && + hostdev->ephemeral)) { +virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("non-USB and non-PCI device assignment with ephemeral " + "flag are not supported by this version of qemu")); +goto error; +} + +if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { int backend = hostdev->source.subsys.u.pci.backend; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 83be435..56112f9 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1981,21 +1981,24 @@ qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm, def = vm->def; } -/* Migration with USB host devices is allowed, all other devices are - * forbidden. +/* + * Migration with USB and ephemeral PCI host devices host devices are allowed, + * all other devices are forbidden. */ forbid = false; for (i = 0; i < def->nhostdevs; i++) { virDomainHostdevDefPtr hostdev = def->hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || -hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { +(hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && +!hostdev->ephemeral)) { forbid = true; break; } } if (forbid) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("domain has assigned non-USB host devices")); + _("domain has assigned non-USB and " + "non-ephemeral host devices")); return false; } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC v1 6/6] managedsave: add managedsave support for ephemeral host devices
Signed-off-by: Chen Fan --- src/qemu/qemu_driver.c | 8 src/qemu/qemu_process.c | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 86d93d2..112acb1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3208,6 +3208,10 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom, /* Pause */ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) { was_running = true; +/* Detach ephemeral host devices first */ +if (qemuMigrationDetachEphemeralDevices(driver, vm, true) < 0) +goto endjob; + if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE, QEMU_ASYNC_JOB_SAVE) < 0) goto endjob; @@ -3249,6 +3253,8 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom, VIR_DOMAIN_EVENT_SUSPENDED, VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR); } +qemuMigrationRestoreEphemeralDevices(driver, dom->conn, vm, true); + virSetError(save_err); virFreeError(save_err); } @@ -6404,6 +6410,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn, if (event) qemuDomainEventQueue(driver, event); +/* Restore ephemeral devices */ +qemuMigrationRestoreEphemeralDevices(driver, NULL, vm, true); /* If it was running before, resume it now unless caller requested pause. */ if (header->was_running && !start_paused) { diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 904c447..6519477 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4501,7 +4501,8 @@ int qemuProcessStart(virConnectPtr conn, * during migration. hence we should remove the reserved * PCI address for ephemeral device. */ -if (vmop == VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START) +if (vmop == VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START || +vmop == VIR_NETDEV_VPORT_PROFILE_OP_RESTORE) if (qemuMigrationDetachEphemeralDevices(driver, vm, false) < 0) goto cleanup; -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC v1 2/6] qemu: Save ephemeral devices into qemuDomainObjPrivate
after migration we should restore the ephemeral devices. so we save them to qemuDomainObjPrivate. Signed-off-by: Chen Fan --- src/qemu/qemu_domain.c | 5 + src/qemu/qemu_domain.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index d8a2087..5ce933d 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -425,6 +425,7 @@ static void qemuDomainObjPrivateFree(void *data) { qemuDomainObjPrivatePtr priv = data; +size_t i; virObjectUnref(priv->qemuCaps); @@ -441,6 +442,10 @@ qemuDomainObjPrivateFree(void *data) virCondDestroy(&priv->unplugFinished); virChrdevFree(priv->devs); +for (i = 0; i < priv->nEphemeralDevices; i++) +virDomainDeviceDefFree(priv->ephemeralDevices[i]); +VIR_FREE(priv->ephemeralDevices); + /* This should never be non-NULL if we get here, but just in case... */ if (priv->mon) { VIR_ERROR(_("Unexpected QEMU monitor still active during domain deletion")); diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index fe3e2b1..e75c828 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -180,6 +180,9 @@ struct _qemuDomainObjPrivate { size_t ncleanupCallbacks; size_t ncleanupCallbacks_max; +virDomainDeviceDefPtr *ephemeralDevices; +size_t nEphemeralDevices; + virCgroupPtr cgroup; virCond unplugFinished; /* signals that unpluggingDevice was unplugged */ -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [RFC 0/7] Live Migration with Pass-through Devices proposal
On 04/20/2015 06:29 AM, Laine Stump wrote: On 04/17/2015 04:53 AM, Chen Fan wrote: backgrond: Live migration is one of the most important features of virtualization technology. With regard to recent virtualization techniques, performance of network I/O is critical. Current network I/O virtualization (e.g. Para-virtualized I/O, VMDq) has a significant performance gap with native network I/O. Pass-through network devices have near native performance, however, they have thus far prevented live migration. No existing methods solve the problem of live migration with pass-through devices perfectly. There was an idea to solve the problem in website: https://www.kernel.org/doc/ols/2008/ols2008v2-pages-261-267.pdf Please refer to above document for detailed information. This functionality has been on my mind/bug list for a long time, but I haven't been able to pursue it much. See this BZ, along with the original patches submitted by Shradha Shah from SolarFlare: https://bugzilla.redhat.com/show_bug.cgi?id=896716 (I was a bit optimistic in my initial review of the patches - there are actually a lot of issues that weren't handled by those patches.) So I think this problem maybe could be solved by using the combination of existing technology. and the following steps are we considering to implement: - before boot VM, we anticipate to specify two NICs for creating bonding device (one plugged and one virtual NIC) in XML. here we can specify the NIC's mac addresses in XML, which could facilitate qemu-guest-agent to find the network interfaces in guest. An interesting idea, but I think that is a 2nd level enhancement, not necessary initially (and maybe not ever, due to the high possibility of it being extremely difficult to get right in 100% of the cases). - when qemu-guest-agent startup in guest it would send a notification to libvirt, then libvirt will call the previous registered initialize callbacks. so through the callback functions, we can create the bonding device according to the XML configuration. and here we use netcf tool which can facilitate to create bonding device easily. This isn't quite making sense - the bond will be on the guest, which may not have netcf installed. Anyway, I think it should be up to the guest's own system network config to have the bond already setup. If you try to impose it from outside that infrastructure, you run too much risk of running afoul of something on the guest (e.g. NetworkManager) - during migration, unplug the passthroughed NIC. then do native migration. Correct. This is the most important part. But not just unplugging it, you also need to wait until the unplug operation completes (it is asynchronous). (After this point, the emulated NIC that is part of the bond would get all of the traffic). - on destination side, check whether need to hotplug new NIC according to specified XML. usually, we use migrate "--xml" command option to specify the destination host NIC mac address to hotplug a new NIC, because source side passthrough NIC mac address is different, then hotplug the deivce according to the destination XML configuration. Why does the MAC address need to be different? Are you suggesting doing this with passed-through non-SRIOV NICs? An SRIOV virtual function gets its MAC address from the libvirt config, so it's very simple to use the same MAC address across the migration. Any network card that would be able to do this on any sort of useful scale will be SRIOV-capable (or should be replaced with one that is - some of them are not that expensive). Hi Laine, I think SRIOV virtual NIC to support migration is good idea, but I also think some passthrough NIC without SRIOV-capable. for these NIC devices we only able to use to specify the passthrough function, so for these NIC I think we should support too. Thanks, Chen TODO: 1. when hot add a new NIC in destination side after migration finished, the NIC device need to re-enslave on bonding device in guest. otherwise, it is offline. maybe we should consider bonding driver to support add interfaces dynamically. I never looked at the details of how SolarFlare's code handled the guest side (they have/had their own patchset they maintained for some older version of libvirt which integrated with some sort of enhanced bonding driver on the guests). I assumed the bond driver could handle this already, but have to say I never investigated. This is an example on how this might work, so I want to hear some voices about this scenario. Thanks, Chen Chen Fan (7): qemu-agent: add agent init callback when detecting guest setup qemu: add guest init event callback to do the initialize work for guest hostdev: add a 'bond' type element in element Putting this into is the wrong approach, for two reasons: 1) it doesn't account for the device to be used being i
Re: [libvirt] [RFC 0/7] Live Migration with Pass-through Devices proposal
Hi Laine, Thanks for your review for my patches. and do you know that solarflare's patches have made some update version since https://www.redhat.com/archives/libvir-list/2012-November/msg01324.html ? if not, I hope to go on to complete this work. ;) Thanks, Chen On 04/20/2015 06:29 AM, Laine Stump wrote: On 04/17/2015 04:53 AM, Chen Fan wrote: backgrond: Live migration is one of the most important features of virtualization technology. With regard to recent virtualization techniques, performance of network I/O is critical. Current network I/O virtualization (e.g. Para-virtualized I/O, VMDq) has a significant performance gap with native network I/O. Pass-through network devices have near native performance, however, they have thus far prevented live migration. No existing methods solve the problem of live migration with pass-through devices perfectly. There was an idea to solve the problem in website: https://www.kernel.org/doc/ols/2008/ols2008v2-pages-261-267.pdf Please refer to above document for detailed information. This functionality has been on my mind/bug list for a long time, but I haven't been able to pursue it much. See this BZ, along with the original patches submitted by Shradha Shah from SolarFlare: https://bugzilla.redhat.com/show_bug.cgi?id=896716 (I was a bit optimistic in my initial review of the patches - there are actually a lot of issues that weren't handled by those patches.) So I think this problem maybe could be solved by using the combination of existing technology. and the following steps are we considering to implement: - before boot VM, we anticipate to specify two NICs for creating bonding device (one plugged and one virtual NIC) in XML. here we can specify the NIC's mac addresses in XML, which could facilitate qemu-guest-agent to find the network interfaces in guest. An interesting idea, but I think that is a 2nd level enhancement, not necessary initially (and maybe not ever, due to the high possibility of it being extremely difficult to get right in 100% of the cases). - when qemu-guest-agent startup in guest it would send a notification to libvirt, then libvirt will call the previous registered initialize callbacks. so through the callback functions, we can create the bonding device according to the XML configuration. and here we use netcf tool which can facilitate to create bonding device easily. This isn't quite making sense - the bond will be on the guest, which may not have netcf installed. Anyway, I think it should be up to the guest's own system network config to have the bond already setup. If you try to impose it from outside that infrastructure, you run too much risk of running afoul of something on the guest (e.g. NetworkManager) - during migration, unplug the passthroughed NIC. then do native migration. Correct. This is the most important part. But not just unplugging it, you also need to wait until the unplug operation completes (it is asynchronous). (After this point, the emulated NIC that is part of the bond would get all of the traffic). - on destination side, check whether need to hotplug new NIC according to specified XML. usually, we use migrate "--xml" command option to specify the destination host NIC mac address to hotplug a new NIC, because source side passthrough NIC mac address is different, then hotplug the deivce according to the destination XML configuration. Why does the MAC address need to be different? Are you suggesting doing this with passed-through non-SRIOV NICs? An SRIOV virtual function gets its MAC address from the libvirt config, so it's very simple to use the same MAC address across the migration. Any network card that would be able to do this on any sort of useful scale will be SRIOV-capable (or should be replaced with one that is - some of them are not that expensive). TODO: 1. when hot add a new NIC in destination side after migration finished, the NIC device need to re-enslave on bonding device in guest. otherwise, it is offline. maybe we should consider bonding driver to support add interfaces dynamically. I never looked at the details of how SolarFlare's code handled the guest side (they have/had their own patchset they maintained for some older version of libvirt which integrated with some sort of enhanced bonding driver on the guests). I assumed the bond driver could handle this already, but have to say I never investigated. This is an example on how this might work, so I want to hear some voices about this scenario. Thanks, Chen Chen Fan (7): qemu-agent: add agent init callback when detecting guest setup qemu: add guest init event callback to do the initialize work for guest hostdev: add a 'bond' type element in element Putting this into is the wrong approach, for two reasons: 1) it doesn't account for the device to be used being i
[libvirt] [RFC 4/7] qemu-agent: add qemuAgentCreateBond interface
via initialize callback to create bond device. Signed-off-by: Chen Fan --- src/qemu/qemu_agent.c | 118 src/qemu/qemu_agent.h | 10 src/qemu/qemu_domain.c | 70 src/qemu/qemu_domain.h | 7 +++ src/qemu/qemu_process.c | 4 ++ 5 files changed, 209 insertions(+) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index cee0f8b..b8eba01 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -2169,3 +2169,121 @@ qemuAgentGetInterfaces(qemuAgentPtr mon, goto cleanup; } + +static virDomainInterfacePtr +findInterfaceByMac(virDomainInterfacePtr *info, + size_t len, + const char *macstr) +{ +size_t i; +bool found = false; + +for (i = 0; i < len; i++) { +if (info[i]->hwaddr && +STREQ(info[i]->hwaddr, macstr)) { +found = true; +break; +} +} + +if (found) { +return info[i]; +} + +return NULL; +} + +/* + * qemuAgentSetInterface: + */ +int +qemuAgentCreateBond(qemuAgentPtr mon, +virDomainHostdevSubsysPCIPtr pcisrc) +{ +int ret = -1; +virJSONValuePtr cmd = NULL; +virJSONValuePtr reply = NULL; +size_t i; +char macstr[VIR_MAC_STRING_BUFLEN]; +virDomainInterfacePtr *interfaceInfo = NULL; +virDomainInterfacePtr interface; +virJSONValuePtr new_interface = NULL; +virJSONValuePtr subInterfaces = NULL; +virJSONValuePtr subInterface = NULL; +int len; + +if (!(pcisrc->nmac || pcisrc->macs)) +return ret; + +len = qemuAgentGetInterfaces(mon, &interfaceInfo); +if (len < 0) +return ret; + +if (!(new_interface = virJSONValueNewObject())) +goto cleanup; + +if (virJSONValueObjectAppendString(new_interface, "type", "bond") < 0) +goto cleanup; + +if (virJSONValueObjectAppendString(new_interface, "name", "bond0") < 0) +goto cleanup; + +if (virJSONValueObjectAppendString(new_interface, "onboot", "onboot") < 0) +goto cleanup; + +if (!(subInterfaces = virJSONValueNewArray())) +goto cleanup; + +for (i = 0; i < pcisrc->nmac; i++) { +virMacAddrFormat(&pcisrc->macs[i], macstr); +interface = findInterfaceByMac(interfaceInfo, len, macstr); +if (!interface) { +goto cleanup; +} + +if (!(subInterface = virJSONValueNewObject())) +goto cleanup; + +if (virJSONValueObjectAppendString(subInterface, "name", interface->name) < 0) +goto cleanup; + +if (virJSONValueArrayAppend(subInterfaces, subInterface) < 0) +goto cleanup; + +subInterface = NULL; +} + +if (i && virJSONValueObjectAppend(new_interface, "subInterfaces", subInterfaces) < 0) +goto cleanup; + +cmd = qemuAgentMakeCommand("guest-network-set-interface", + "a:interface", new_interface, + NULL); + +if (!cmd) +goto cleanup; + +subInterfaces = NULL; +new_interface = NULL; + +if (qemuAgentCommand(mon, cmd, &reply, true, + VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) +goto cleanup; + +if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed return value")); +} + + cleanup: +virJSONValueFree(subInterfaces); +virJSONValueFree(subInterface); +virJSONValueFree(new_interface); +virJSONValueFree(cmd); +virJSONValueFree(reply); +if (interfaceInfo) +for (i = 0; i < len; i++) +virDomainInterfaceFree(interfaceInfo[i]); +VIR_FREE(interfaceInfo); +return ret; +} diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index 42414a7..744cb0a 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -97,6 +97,13 @@ struct _qemuAgentCPUInfo { bool offlinable;/* true if the CPU can be offlined */ }; +typedef struct _qemuAgentInterfaceInfo qemuAgentInterfaceInfo; +typedef qemuAgentInterfaceInfo *qemuAgentInterfaceInfoPtr; +struct _qemuAgentInterfaceInfo { +char *name; +char *hardware_address; +}; + int qemuAgentGetVCPUs(qemuAgentPtr mon, qemuAgentCPUInfoPtr *info); int qemuAgentSetVCPUs(qemuAgentPtr mon, qemuAgentCPUInfoPtr cpus, size_t ncpus); int qemuAgentUpdateCPUInfo(unsigned int nvcpus, @@ -114,4 +121,7 @@ int qemuAgentSetTime(qemuAgentPtr mon, int qemuAgentGetInterfaces(qemuAgentPtr mon, virDomainInterfacePtr **ifaces); +int qemuAgentCreateBond(qemuAgentPtr mon, +virDomainHostdevSubsysPCIPtr pcisrc); + #en
[libvirt] [RFC 1/7] qemu-agent: add agent init callback when detecting guest setup
sometimes, we want to do some initialize work in guest when guest startup, but currently, qemu-agent doesn't support that. so here we add an init callback, when guest startup, notify libvirt it has been up, then libvirt can do some work for guest. Signed-off-by: Chen Fan --- src/qemu/qemu_agent.c | 26 +++--- src/qemu/qemu_agent.h | 2 ++ src/qemu/qemu_process.c | 6 ++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 548d580..cee0f8b 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -92,6 +92,7 @@ struct _qemuAgent { int watch; bool connectPending; +bool connected; virDomainObjPtr vm; @@ -306,6 +307,7 @@ qemuAgentIOProcessLine(qemuAgentPtr mon, virJSONValuePtr obj = NULL; int ret = -1; unsigned long long id; +const char *status; VIR_DEBUG("Line [%s]", line); @@ -318,7 +320,11 @@ qemuAgentIOProcessLine(qemuAgentPtr mon, goto cleanup; } -if (virJSONValueObjectHasKey(obj, "QMP") == 1) { +if (virJSONValueObjectHasKey(obj, "QMP") == 1 || +virJSONValueObjectHasKey(obj, "status") == 1) { +status = virJSONValueObjectGetString(obj, "status"); +if (STREQ(status, "connected")) +mon->connected = true; ret = 0; } else if (virJSONValueObjectHasKey(obj, "event") == 1) { ret = qemuAgentIOProcessEvent(mon, obj); @@ -700,8 +706,22 @@ qemuAgentIO(int watch, int fd, int events, void *opaque) VIR_DEBUG("Triggering error callback"); (errorNotify)(mon, vm); } else { -virObjectUnlock(mon); -virObjectUnref(mon); +if (mon->connected) { +void (*init)(qemuAgentPtr, virDomainObjPtr) += mon->cb->init; +virDomainObjPtr vm = mon->vm; + +mon->connected = false; + +virObjectUnlock(mon); +virObjectUnref(mon); + +VIR_DEBUG("Triggering init callback"); +(init)(mon, vm); +} else { +virObjectUnlock(mon); +virObjectUnref(mon); +} } } diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index 1cd5749..42414a7 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -34,6 +34,8 @@ typedef qemuAgent *qemuAgentPtr; typedef struct _qemuAgentCallbacks qemuAgentCallbacks; typedef qemuAgentCallbacks *qemuAgentCallbacksPtr; struct _qemuAgentCallbacks { +void (*init)(qemuAgentPtr mon, + virDomainObjPtr vm); void (*destroy)(qemuAgentPtr mon, virDomainObjPtr vm); void (*eofNotify)(qemuAgentPtr mon, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 276837e..e6fc53a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -194,8 +194,14 @@ static void qemuProcessHandleAgentDestroy(qemuAgentPtr agent, virObjectUnref(vm); } +static void qemuProcessHandleAgentInit(qemuAgentPtr agent ATTRIBUTE_UNUSED, + virDomainObjPtr vm) +{ +VIR_DEBUG("Received init from agent on %p '%s'", vm, vm->def->name); +} static qemuAgentCallbacks agentCallbacks = { +.init = qemuProcessHandleAgentInit, .destroy = qemuProcessHandleAgentDestroy, .eofNotify = qemuProcessHandleAgentEOF, .errorNotify = qemuProcessHandleAgentError, -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC 0/3] add support migration with passthrough device
the patches is for libvirt to support migration with passthrough device using existing feacture. Chen Fan (3): qemu-agent: add guest-network-set-interface command qemu-agent: add guest-network-delete-interface command qemu-agent: add notify for qemu-ga boot configure| 16 +++ qga/commands-posix.c | 312 +++ qga/commands-win32.c | 13 +++ qga/main.c | 13 +++ qga/qapi-schema.json | 65 +++ 5 files changed, 419 insertions(+) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC 5/7] hostdev: add parse ip and route for bond configure
bond device always need to configure the ip address and route way address. so here we add the interface. xml like: Signed-off-by: Chen Fan --- docs/schemas/domaincommon.rng | 21 +++ src/conf/domain_conf.c| 87 --- src/conf/domain_conf.h| 24 src/conf/networkcommon_conf.c | 17 - src/conf/networkcommon_conf.h | 17 + src/qemu/qemu_agent.c | 58 +++-- 6 files changed, 183 insertions(+), 41 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 0cf82cb..4056cbd 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3779,6 +3779,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 14bcae1..7d1cd3e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -797,6 +797,8 @@ static virClassPtr virDomainXMLOptionClass; static void virDomainObjDispose(void *obj); static void virDomainObjListDispose(void *obj); static void virDomainXMLOptionClassDispose(void *obj); +static virDomainNetIpDefPtr virDomainNetIpParseXML(xmlNodePtr node); + static int virDomainObjOnceInit(void) { @@ -1914,8 +1916,17 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def) } } else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci; -if (pcisrc->device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) -VIR_FREE(pcisrc->macs); +if (pcisrc->device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) { +for (i = 0; i < pcisrc->net.nmacs; i++) +VIR_FREE(pcisrc->net.macs[i]); +VIR_FREE(pcisrc->net.macs); +for (i = 0; i < pcisrc->net.nips; i++) +VIR_FREE(pcisrc->net.ips[i]); +VIR_FREE(pcisrc->net.ips); +for (i = 0; i < pcisrc->net.nroutes; i++) +VIR_FREE(pcisrc->net.routes[i]); +VIR_FREE(pcisrc->net.routes); +} } break; } @@ -5102,26 +5113,68 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, if (device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) { xmlNodePtr *macs = NULL; int n = 0; -int i; +size_t i; char *macStr = NULL; +xmlNodePtr *ipnodes = NULL; +int nipnodes; +xmlNodePtr *routenodes = NULL; +int nroutenodes; if (!(virXPathNode("./bond", ctxt))) { virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing node specified by bond type")); + _("missing node specified by bond type")); goto error; } +if ((nipnodes = virXPathNodeSet("./bond/ip", ctxt, &ipnodes)) < 0) +goto error; + +if (nipnodes) { +for (i = 0; i < nipnodes; i++) { +virDomainNetIpDefPtr ip = virDomainNetIpParseXML(ipnodes[i]); + +if (!ip) +goto error; + +if (VIR_APPEND_ELEMENT(pcisrc->net.ips, + pcisrc->net.nips, ip) < 0) { +VIR_FREE(ip); +goto error; +} +} +} + +if ((nroutenodes = virXPathNodeSet("./bond/route", ctxt, &routenodes)) < 0) +goto error; + +if (nroutenodes) { +for (i = 0; i < nroutenodes; i++) { +virNetworkRouteDefPtr route = NULL; + +if (!(route = virNetworkRouteDefParseXML(_("Domain hostdev device"), + routenodes[i], + ctxt))) +goto error; + +if (VIR_APPEND_ELEMENT(pcisrc->net.routes, + pcisrc->net.nroutes, route) < 0) { +virNetworkRouteDefFree(route); +goto error; +} +} +} + if ((n = virXPathNodeSet("
[libvirt] [RFC 2/3] qemu-agent: add guest-network-delete-interface command
Add a corresponding command to guest-network-set-interface. Signed-off-by: Chen Fan --- qga/commands-posix.c | 51 +++ qga/commands-win32.c | 6 ++ qga/qapi-schema.json | 11 +++ 3 files changed, 68 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 5ee7949..058085f 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -1971,6 +1971,51 @@ int64_t qmp_guest_network_set_interface(GuestNetworkInterface2 *interface, return 0; } + +int64_t qmp_guest_network_delete_interface(const char *name, Error **errp) +{ +struct netcf_if *iface; +int ret = -1; +unsigned int flags = 0; + +/* open netcf */ +if (netcf == NULL) { +if (ncf_init(&netcf, NULL) != 0) { +error_setg(errp, "netcf init failed"); +return ret; +} +} + +iface = ncf_lookup_by_name(netcf, name); +if (!iface) { + error_setg(errp, "couldn't find interface named '%s'", name); + return ret; +} + +if (ncf_if_status(iface, &flags) < 0) { +error_setg(errp, "netcf interface get status failed"); +goto cleanup; +} + +if (flags & NETCF_IFACE_ACTIVE) { +ret = ncf_if_down(iface); +if (ret < 0) { +error_setg(errp, "netcf interface stop failed"); +goto cleanup; +} +} + +ret = ncf_if_undefine(iface); +if (ret < 0) { +error_setg(errp, "netcf interface delete failed"); +goto cleanup; +} + +ret = 0; +cleanup: +ncf_if_free(iface); +return ret; +} #else int64_t qmp_guest_network_set_interface(GuestNetworkInterface2 *interface, Error **errp) @@ -1978,6 +2023,12 @@ int64_t qmp_guest_network_set_interface(GuestNetworkInterface2 *interface, error_set(errp, QERR_UNSUPPORTED); return -1; } + +int64_t qmp_guest_network_delete_interface(const char *name, Error **errp) +{ +error_set(errp, QERR_UNSUPPORTED); +return -1; +} #endif #define SYSCONF_EXACT(name, errp) sysconf_exact((name), #name, (errp)) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 4c14514..52f6e47 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -453,6 +453,12 @@ int64_t qmp_guest_network_set_interface(GuestNetworkInterface2 *interface, return -1; } +int64_t qmp_guest_network_delete_interface(const char *name, Error **errp) +{ +error_set(errp, QERR_UNSUPPORTED); +return -1; +} + /* add unsupported commands to the blacklist */ GList *ga_command_blacklist_init(GList *blacklist) { diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 77f499b..b886f97 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -642,6 +642,17 @@ 'returns': 'int' } ## +# @guest-network-delete-interface: +# +# @name: interface name. +# +# Since: 2.3 +## +{ 'command': 'guest-network-delete-interface', + 'data' : {'name': 'str' }, + 'returns': 'int' } + +## # @GuestLogicalProcessor: # # @logical-id: Arbitrary guest-specific unique identifier of the VCPU. -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC 0/7] Live Migration with Pass-through Devices proposal
backgrond: Live migration is one of the most important features of virtualization technology. With regard to recent virtualization techniques, performance of network I/O is critical. Current network I/O virtualization (e.g. Para-virtualized I/O, VMDq) has a significant performance gap with native network I/O. Pass-through network devices have near native performance, however, they have thus far prevented live migration. No existing methods solve the problem of live migration with pass-through devices perfectly. There was an idea to solve the problem in website: https://www.kernel.org/doc/ols/2008/ols2008v2-pages-261-267.pdf Please refer to above document for detailed information. So I think this problem maybe could be solved by using the combination of existing technology. and the following steps are we considering to implement: - before boot VM, we anticipate to specify two NICs for creating bonding device (one plugged and one virtual NIC) in XML. here we can specify the NIC's mac addresses in XML, which could facilitate qemu-guest-agent to find the network interfaces in guest. - when qemu-guest-agent startup in guest it would send a notification to libvirt, then libvirt will call the previous registered initialize callbacks. so through the callback functions, we can create the bonding device according to the XML configuration. and here we use netcf tool which can facilitate to create bonding device easily. - during migration, unplug the passthroughed NIC. then do native migration. - on destination side, check whether need to hotplug new NIC according to specified XML. usually, we use migrate "--xml" command option to specify the destination host NIC mac address to hotplug a new NIC, because source side passthrough NIC mac address is different, then hotplug the deivce according to the destination XML configuration. TODO: 1. when hot add a new NIC in destination side after migration finished, the NIC device need to re-enslave on bonding device in guest. otherwise, it is offline. maybe we should consider bonding driver to support add interfaces dynamically. This is an example on how this might work, so I want to hear some voices about this scenario. Thanks, Chen Chen Fan (7): qemu-agent: add agent init callback when detecting guest setup qemu: add guest init event callback to do the initialize work for guest hostdev: add a 'bond' type element in element qemu-agent: add qemuAgentCreateBond interface hostdev: add parse ip and route for bond configure migrate: hot remove hostdev at perform phase for bond device migrate: add hostdev migrate status to support hostdev migration docs/schemas/basictypes.rng | 6 ++ docs/schemas/domaincommon.rng | 37 src/conf/domain_conf.c| 195 ++--- src/conf/domain_conf.h| 40 +++-- src/conf/networkcommon_conf.c | 17 src/conf/networkcommon_conf.h | 17 src/libvirt_private.syms | 1 + src/qemu/qemu_agent.c | 196 +- src/qemu/qemu_agent.h | 12 +++ src/qemu/qemu_command.c | 3 + src/qemu/qemu_domain.c| 70 +++ src/qemu/qemu_domain.h| 14 +++ src/qemu/qemu_driver.c| 38 src/qemu/qemu_hotplug.c | 8 +- src/qemu/qemu_migration.c | 91 src/qemu/qemu_migration.h | 4 + src/qemu/qemu_process.c | 32 +++ src/util/virhostdev.c | 3 + 18 files changed, 745 insertions(+), 39 deletions(-) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC 1/3] qemu-agent: add guest-network-set-interface command
Nowadays, qemu has supported physical NIC hotplug for high network throughput. but it's in conflict with live migration feature, to keep network connectivity, we could to create bond device interface which provides a mechanism for enslaving multiple network interfaces into a single "bond" interface. the active-backup mode can be used for an automatic switch. so this patch is adding a guest-network-set-interface command for creating bond device. so the management can easy to create a bond device dynamically when guest running. Signed-off-by: Chen Fan --- configure| 16 qga/commands-posix.c | 261 +++ qga/commands-win32.c | 7 ++ qga/qapi-schema.json | 54 +++ 4 files changed, 338 insertions(+) diff --git a/configure b/configure index f185dd0..ebfcc6a 100755 --- a/configure +++ b/configure @@ -3618,6 +3618,18 @@ if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \ fi ## +# Do we need netcf +netcf=no +cat > $TMPC << EOF +#include +int main(void) { return 0; } +EOF +if compile_prog "" "-lnetcf" ; then +netcf=yes +libs_qga="$libs_qga -lnetcf" +fi + +## # spice probe if test "$spice" != "no" ; then cat > $TMPC << EOF @@ -4697,6 +4709,10 @@ if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak fi +if test "$netcf" = "yes" ; then + echo "CONFIG_NETCF=y" >> $config_host_mak +fi + if test "$smartcard_nss" = "yes" ; then echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak echo "NSS_LIBS=$nss_libs" >> $config_host_mak diff --git a/qga/commands-posix.c b/qga/commands-posix.c index f6f3e3c..5ee7949 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -46,6 +46,10 @@ extern char **environ; #include #include +#ifdef CONFIG_NETCF +#include +#endif + #ifdef FIFREEZE #define CONFIG_FSFREEZE #endif @@ -1719,6 +1723,263 @@ error: return NULL; } +#ifdef CONFIG_NETCF +static const char *interface_type_string[] = { +"bond", +}; + +static const char *ip_address_type_string[] = { +"ipv4", +"ipv6", +}; + +static char *parse_options(const char *str, const char *needle) +{ +char *start, *end, *buffer = NULL; +char *ret = NULL; + +buffer = g_strdup(str); +start = buffer; +if ((start = strstr(start, needle))) { +start += strlen(needle); +end = strchr(start, ' '); +if (end) { +*end = '\0'; +} +if (strlen(start) == 0) { +goto cleanup; +} +ret = g_strdup(start); +} + +cleanup: +g_free(buffer); +return ret; +} + +/** + * @buffer: xml string data to be formatted + * @indent: indent number relative to first line + * + */ +static void adjust_indent(char **buffer, int indent) +{ +char spaces[1024]; +int i; + +if (!*buffer) { +return; +} + +if (indent < 0 || indent >= 1024) { +return; +} +memset(spaces, 0, sizeof(spaces)); +for (i = 0; i < indent; i++) { +spaces[i] = ' '; +} + +sprintf(*buffer + strlen(*buffer), "%s", spaces); +} + +static char *create_bond_interface(GuestNetworkInterface2 *interface) +{ +char *target_xml; + +target_xml = g_malloc0(1024); +if (!target_xml) { +return NULL; +} + +sprintf(target_xml, "\n", +interface_type_string[interface->type], interface->name); +adjust_indent(&target_xml, 2); +sprintf(target_xml + strlen(target_xml), "\n", +interface->has_onboot ? interface->onboot : "none"); +if (interface->has_ip_address) { +GuestIpAddress *address_item = interface->ip_address; + +adjust_indent(&target_xml, 2); +sprintf(target_xml + strlen(target_xml), "\n", +ip_address_type_string[address_item->ip_address_type]); +adjust_indent(&target_xml, 4); +sprintf(target_xml + strlen(target_xml), "\n", +address_item->ip_address, address_item->prefix); +if (address_item->has_gateway) { +adjust_indent(&target_xml, 4); +sprintf(target_xml + strlen(target_xml), "\n", +address_item->gateway); +} +adjust_indent(&target_xml, 2); +sprintf(target_xml + strlen(target_xml), "%s\n", ""); +} + +adjust_indent(&target_xml, 2); +if (interface->has_options) { +char *value; + +value = parse_
[libvirt] [RFC 6/7] migrate: hot remove hostdev at perform phase for bond device
For bond device, we can support the migrate, we can simple to hot remove the device from source side, and after migration end, we hot add the new device at destination side. Signed-off-by: Chen Fan --- src/qemu/qemu_driver.c| 57 +++ src/qemu/qemu_migration.c | 7 ++ 2 files changed, 64 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7368145..0ba9e4a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12353,6 +12353,58 @@ qemuDomainMigrateBegin3(virDomainPtr domain, cookieout, cookieoutlen, flags); } +static int +qemuDomainRemovePciPassThruDevices(virConnectPtr conn, + virDomainObjPtr vm) +{ +virQEMUDriverPtr driver = conn->privateData; +virDomainDeviceDef dev; +virDomainDeviceDefPtr dev_copy = NULL; +virCapsPtr caps = NULL; +int ret = -1; +size_t i; + +if (!(caps = virQEMUDriverGetCapabilities(driver, false))) +goto cleanup; + +if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT)) +goto cleanup; + +/* unplug passthrough bond device */ +for (i = 0; i < vm->def->nhostdevs; i++) { +virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i]; + +if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && +hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && +hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO && +hostdev->source.subsys.u.pci.device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) { + +dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; +dev.data.hostdev = hostdev; + +dev_copy = virDomainDeviceDefCopy(&dev, vm->def, caps, driver->xmlopt); +if (!dev_copy) +goto cleanup; + +if (qemuDomainDetachHostDevice(driver, vm, dev_copy) < 0) { +virDomainDeviceDefFree(dev_copy); +goto cleanup; +} + +virDomainDeviceDefFree(dev_copy); +if (qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE) < 0) +goto cleanup; +} +} + +ret = 0; + + cleanup: +virObjectUnref(caps); + +return ret; +} + static char * qemuDomainMigrateBegin3Params(virDomainPtr domain, virTypedParameterPtr params, @@ -12688,6 +12740,11 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, return -1; } +if (qemuDomainRemovePciPassThruDevices(dom->conn, vm) < 0) { +qemuDomObjEndAPI(&vm); +return -1; +} + return qemuMigrationPerform(driver, dom->conn, vm, dom_xml, dconnuri, uri, graphicsuri, listenAddress, cookiein, cookieinlen, cookieout, cookieoutlen, diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 611f53a..9ea83df 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2000,6 +2000,13 @@ qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm, forbid = false; for (i = 0; i < def->nhostdevs; i++) { virDomainHostdevDefPtr hostdev = def->hostdevs[i]; + +if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && +hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && +hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO && +hostdev->source.subsys.u.pci.device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) +continue; + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) { forbid = true; -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC 3/3] qemu-agent: add notify for qemu-ga boot
Signed-off-by: Chen Fan --- qga/main.c | 13 + 1 file changed, 13 insertions(+) diff --git a/qga/main.c b/qga/main.c index 9939a2b..f011ce0 100644 --- a/qga/main.c +++ b/qga/main.c @@ -1170,6 +1170,19 @@ int main(int argc, char **argv) g_critical("failed to initialize guest agent channel"); goto out_bad; } + +/* send a notification to path */ +if (ga_state->channel) { +QDict *qdict = qdict_new(); +int ret; + +qdict_put_obj(qdict, "status", QOBJECT(qstring_from_str("connected"))); +ret = send_response(s, QOBJECT(qdict)); +if (ret < 0) { +g_warning("error sending connected status"); +} +} + #ifndef _WIN32 g_main_loop_run(ga_state->main_loop); #else -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC 2/7] qemu: add guest init event callback to do the initialize work for guest
Signed-off-by: Chen Fan --- src/qemu/qemu_domain.h | 7 +++ src/qemu/qemu_driver.c | 32 src/qemu/qemu_process.c | 22 ++ 3 files changed, 61 insertions(+) diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 3225abb..19f4b27 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -136,6 +136,8 @@ struct qemuDomainJobObj { typedef void (*qemuDomainCleanupCallback)(virQEMUDriverPtr driver, virDomainObjPtr vm); +typedef void (*qemuDomainInitCallback)(virDomainObjPtr vm); + typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate; typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr; struct _qemuDomainObjPrivate { @@ -185,6 +187,10 @@ struct _qemuDomainObjPrivate { size_t ncleanupCallbacks; size_t ncleanupCallbacks_max; +qemuDomainInitCallback *initCallbacks; +size_t nInitCallbacks; +size_t nInitCallbacks_max; + virCgroupPtr cgroup; virCond unplugFinished; /* signals that unpluggingDevice was unplugged */ @@ -205,6 +211,7 @@ typedef enum { QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED, QEMU_PROCESS_EVENT_SERIAL_CHANGED, QEMU_PROCESS_EVENT_BLOCK_JOB, +QEMU_PROCESS_EVENT_GUESTINIT, QEMU_PROCESS_EVENT_LAST } qemuProcessEventType; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f37b95d..7368145 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4073,6 +4073,35 @@ processGuestPanicEvent(virQEMUDriverPtr driver, static void +processGuestInitEvent(virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ +qemuDomainObjPrivatePtr priv; +int i; + +VIR_DEBUG("init guest from domain %p %s", + vm, vm->def->name); + +if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) +return; + +if (!virDomainObjIsActive(vm)) { +VIR_DEBUG("Domain is not running"); +goto endjob; +} + +priv = vm->privateData; + +for (i = 0; i < priv->nInitCallbacks; i++) { +if (priv->initCallbacks[i]) +priv->initCallbacks[i](vm); +} + + endjob: +qemuDomainObjEndJob(driver, vm); +} + +static void processDeviceDeletedEvent(virQEMUDriverPtr driver, virDomainObjPtr vm, char *devAlias) @@ -4627,6 +4656,9 @@ static void qemuProcessEventHandler(void *data, void *opaque) processEvent->action, processEvent->status); break; +case QEMU_PROCESS_EVENT_GUESTINIT: +processGuestInitEvent(driver, vm); +break; case QEMU_PROCESS_EVENT_LAST: break; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index e6fc53a..fcc0566 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -197,7 +197,29 @@ static void qemuProcessHandleAgentDestroy(qemuAgentPtr agent, static void qemuProcessHandleAgentInit(qemuAgentPtr agent ATTRIBUTE_UNUSED, virDomainObjPtr vm) { +struct qemuProcessEvent *processEvent = NULL; +virQEMUDriverPtr driver = qemu_driver; + +virObjectLock(vm); + VIR_DEBUG("Received init from agent on %p '%s'", vm, vm->def->name); + +if (VIR_ALLOC(processEvent) < 0) +goto cleanup; + +processEvent->eventType = QEMU_PROCESS_EVENT_GUESTINIT; +processEvent->vm = vm; + +virObjectRef(vm); +if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) { +if (!virObjectUnref(vm)) +vm = NULL; +VIR_FREE(processEvent); +} + + cleanup: +if (vm) +virObjectUnlock(vm); } static qemuAgentCallbacks agentCallbacks = { -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [RFC 7/7] migrate: add hostdev migrate status to support hostdev migration
we add a migrate status for hostdev to specify the device don't need to initialze when VM startup, after migration end, we add the migrate status hostdev, so can support hostdev migration. Signed-off-by: Chen Fan --- src/conf/domain_conf.c| 3 ++ src/conf/domain_conf.h| 7 src/qemu/qemu_command.c | 3 ++ src/qemu/qemu_driver.c| 53 +-- src/qemu/qemu_hotplug.c | 8 +++-- src/qemu/qemu_migration.c | 92 --- src/qemu/qemu_migration.h | 4 +++ src/util/virhostdev.c | 3 ++ 8 files changed, 114 insertions(+), 59 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7d1cd3e..b56c6fa 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3035,6 +3035,9 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def, device.type = VIR_DOMAIN_DEVICE_HOSTDEV; for (i = 0; i < def->nhostdevs; i++) { device.data.hostdev = def->hostdevs[i]; +if (device.data.hostdev->state == VIR_DOMAIN_HOSTDEV_STATE_READY_FOR_MIGRATE) +continue; + if (cb(def, &device, def->hostdevs[i]->info, opaque) < 0) return -1; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 723f07b..4b7b4c9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -543,6 +543,12 @@ struct _virDomainHostdevCaps { } u; }; +typedef enum { +VIR_DOMAIN_HOSTDEV_STATE_DEFAULT, +VIR_DOMAIN_HOSTDEV_STATE_READY_FOR_MIGRATE, + +VIR_DOMAIN_HOSTDEV_STATE_LAST +} virDomainHostdevState; /* basic device for direct passthrough */ struct _virDomainHostdevDef { @@ -559,6 +565,7 @@ struct _virDomainHostdevDef { } source; virDomainHostdevOrigStates origstates; virDomainDeviceInfoPtr info; /* Guest address */ +int state; }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index e7e0937..dc5245a 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -10365,6 +10365,9 @@ qemuBuildCommandLine(virConnectPtr conn, virDomainHostdevDefPtr hostdev = def->hostdevs[i]; char *devstr; +if (hostdev->state == VIR_DOMAIN_HOSTDEV_STATE_READY_FOR_MIGRATE) +continue; + if (hostdev->info->bootIndex) { if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0ba9e4a..4724171 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12353,57 +12353,6 @@ qemuDomainMigrateBegin3(virDomainPtr domain, cookieout, cookieoutlen, flags); } -static int -qemuDomainRemovePciPassThruDevices(virConnectPtr conn, - virDomainObjPtr vm) -{ -virQEMUDriverPtr driver = conn->privateData; -virDomainDeviceDef dev; -virDomainDeviceDefPtr dev_copy = NULL; -virCapsPtr caps = NULL; -int ret = -1; -size_t i; - -if (!(caps = virQEMUDriverGetCapabilities(driver, false))) -goto cleanup; - -if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT)) -goto cleanup; - -/* unplug passthrough bond device */ -for (i = 0; i < vm->def->nhostdevs; i++) { -virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i]; - -if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && -hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && -hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO && -hostdev->source.subsys.u.pci.device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) { - -dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; -dev.data.hostdev = hostdev; - -dev_copy = virDomainDeviceDefCopy(&dev, vm->def, caps, driver->xmlopt); -if (!dev_copy) -goto cleanup; - -if (qemuDomainDetachHostDevice(driver, vm, dev_copy) < 0) { -virDomainDeviceDefFree(dev_copy); -goto cleanup; -} - -virDomainDeviceDefFree(dev_copy); -if (qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE) < 0) -goto cleanup; -} -} - -ret = 0; - - cleanup: -virObjectUnref(caps); - -return ret; -} static char * qemuDomainMigrateBegin3Params(virDomainPtr domain, @@ -12740,7 +12689,7 @@ qemuDomainMigratePerform3Params(virDomainPtr dom, return -1; } -if (qemuDomainRemovePciPassThruDevices(dom->conn, vm) < 0) { +if (qemuDomainMigratePciPassThruDevices(driver, vm, false) < 0) { qemuDomObjEndAPI(&vm); return -1; } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index f07c54d..13a7338 100
[libvirt] [RFC 3/7] hostdev: add a 'bond' type element in element
this 'bond' element is to create bond device when guest startup, the xml like: Signed-off-by: Chen Fan --- docs/schemas/basictypes.rng | 6 ++ docs/schemas/domaincommon.rng | 16 ++ src/conf/domain_conf.c| 131 ++ src/conf/domain_conf.h| 13 + src/libvirt_private.syms | 1 + 5 files changed, 157 insertions(+), 10 deletions(-) diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng index f086ad2..aef24fe 100644 --- a/docs/schemas/basictypes.rng +++ b/docs/schemas/basictypes.rng @@ -66,6 +66,12 @@ + + + + + + diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 03fd541..0cf82cb 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3766,9 +3766,25 @@ xen + + + +bond + + + + + + + + + + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4d7e3c9..14bcae1 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -610,6 +610,11 @@ VIR_ENUM_IMPL(virDomainHostdevSubsysPCIBackend, "vfio", "xen") +VIR_ENUM_IMPL(virDomainHostdevSubsysPCIDevice, + VIR_DOMAIN_HOSTDEV_PCI_DEVICE_TYPE_LAST, + "default", + "bond") + VIR_ENUM_IMPL(virDomainHostdevSubsysSCSIProtocol, VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_LAST, "adapter", @@ -1907,6 +1912,10 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def) } else { VIR_FREE(scsisrc->u.host.adapter); } +} else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { +virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci; +if (pcisrc->device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) +VIR_FREE(pcisrc->macs); } break; } @@ -4978,7 +4987,9 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, char *sgio = NULL; char *rawio = NULL; char *backendStr = NULL; +char *deviceStr = NULL; int backend; +int device; int ret = -1; virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi; @@ -5077,6 +5088,68 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, } pcisrc->backend = backend; +device = VIR_DOMAIN_HOSTDEV_PCI_DEVICE_DEFAULT; +if ((deviceStr = virXPathString("string(./driver/@type)", ctxt)) && +(((device = virDomainHostdevSubsysPCIDeviceTypeFromString(deviceStr)) < 0) || + device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_DEFAULT)) { +virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown PCI device " + "has been specified"), deviceStr); +goto error; +} +pcisrc->device = device; + +if (device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) { +xmlNodePtr *macs = NULL; +int n = 0; +int i; +char *macStr = NULL; + +if (!(virXPathNode("./bond", ctxt))) { +virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing node specified by bond type")); +goto error; +} + +if ((n = virXPathNodeSet("./bond/interface", ctxt, &macs)) < 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot extract interface nodes")); +goto error; +} + +VIR_FREE(pcisrc->macs); +if (VIR_ALLOC_N(pcisrc->macs, n) < 0) +goto error; + +pcisrc->nmac = n; +for (i = 0; i < n; i++) { +xmlNodePtr cur_node = macs[i]; + +macStr = virXMLPropString(cur_node, "address"); +if (!macStr) { +virReportError(VIR_ERR_XML_ERROR, "%s", + _("Missing required address attribute " + "in interface element")); +goto error; +} +if (virMacAddrParse((const char *)macStr, &pcisrc->macs[i]) < 0) { +virReportError(VIR_ERR_XML_ERROR, + _("unable t
[libvirt] [PATCH 0/2] fix domain documentation error
Chen Fan (2): docs: no 'via' attribute in route element docs: route element must specify network address docs/formatdomain.html.in | 8 1 file changed, 4 insertions(+), 4 deletions(-) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 1/2] docs: no 'via' attribute in route element
via -> gateway Signed-off-by: Chen Fan --- docs/formatdomain.html.in | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 82aa14f..3b3d2d9 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -4471,8 +4471,8 @@ qemu-kvm -net nic,model=? /dev/null <source network='default'/> <target dev='vnet0'/> <ip address='192.168.122.5' prefix='24'/> - <route family='ipv4' address='192.168.122.0' prefix='24' via='192.168.122.1'/> - <route family='ipv4' via='192.168.122.1'/> + <route family='ipv4' address='192.168.122.0' prefix='24' gateway='192.168.122.1'/> + <route family='ipv4' gateway='192.168.122.1'/> </interface> ... <hostdev mode='capabilities' type='net'> @@ -4480,8 +4480,8 @@ qemu-kvm -net nic,model=? /dev/null <interface>eth0</interface> </source> <ip address='192.168.122.6' prefix='24'/> - <route family='ipv4' address='192.168.122.0' prefix='24' via='192.168.122.1'/> - <route family='ipv4' via='192.168.122.1'/> + <route family='ipv4' address='192.168.122.0' prefix='24' gateway='192.168.122.1'/> + <route family='ipv4' gateway='192.168.122.1'/> </hostdev> </devices> -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 2/2] docs: route element must specify network address
because network address is required by route, so here we should add one avoid user misunderstand. Signed-off-by: Chen Fan --- docs/formatdomain.html.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 3b3d2d9..d7fe942 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -4472,7 +4472,7 @@ qemu-kvm -net nic,model=? /dev/null <target dev='vnet0'/> <ip address='192.168.122.5' prefix='24'/> <route family='ipv4' address='192.168.122.0' prefix='24' gateway='192.168.122.1'/> - <route family='ipv4' gateway='192.168.122.1'/> + <route family='ipv4' address='192.168.122.8' gateway='192.168.122.1'/> </interface> ... <hostdev mode='capabilities' type='net'> @@ -4481,7 +4481,7 @@ qemu-kvm -net nic,model=? /dev/null </source> <ip address='192.168.122.6' prefix='24'/> <route family='ipv4' address='192.168.122.0' prefix='24' gateway='192.168.122.1'/> - <route family='ipv4' gateway='192.168.122.1'/> + <route family='ipv4' address='192.168.122.8' gateway='192.168.122.1'/> </hostdev> </devices> -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] qemu: fix memory leak in qemuAgentGetFSInfo
On 03/10/2015 05:32 PM, Ján Tomko wrote: On Tue, Mar 10, 2015 at 01:56:11PM +0800, Chen Fan wrote: in virDomainFSInfoFree(), don't free the virDomainFSInfo data. ==10670== 80 bytes in 2 blocks are definitely lost in loss record 576 of 793 ==10670==at 0x4A06BC3: calloc (vg_replace_malloc.c:618) ==10670==by 0x509DEBD: virAlloc (viralloc.c:144) ==10670==by 0x19FBD558: qemuAgentGetFSInfo (qemu_agent.c:1837) ==10670==by 0x1A03CF91: qemuDomainGetFSInfo (qemu_driver.c:19238) Signed-off-by: Chen Fan --- src/libvirt-domain.c | 2 ++ 1 file changed, 2 insertions(+) This does fix the memory leak and makes the function behave like it's documented in virDomainGetFSInfo and virDomainFSInfoFree: http://libvirt.org/html/libvirt-libvirt-domain.html#virDomainGetFSInfo http://libvirt.org/html/libvirt-libvirt-domain.html#virDomainFSInfoFree But it changes the public API - if there are applications that already work around this function by freeing the info, this change would introduce a double free. I would NACK this if the documentation for both APIs didn't say that's how this function should behave. I'd like to hear a second opinion. I don't think this documentation make any confusable. for using the function virDomainGetFSInfo(), user also need to call virDomainFSInfoFree() on each array element, and call free() info. example: virDomainFSInfoPtr *info; ndata = virDomainGetFSInfo(dom, &info, 0); for (i = 0; i < ndata; i++) virDomainFSInfoFree(info[i]); VIR_FREE(info); Thanks, Chen Jan diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 04545fd..7f8a7ce 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11337,4 +11337,6 @@ virDomainFSInfoFree(virDomainFSInfoPtr info) for (i = 0; i < info->ndevAlias; i++) VIR_FREE(info->devAlias[i]); VIR_FREE(info->devAlias); + +VIR_FREE(info); } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] qemu: fix memory leak in qemuAgentGetFSInfo
in virDomainFSInfoFree(), don't free the virDomainFSInfo data. ==10670== 80 bytes in 2 blocks are definitely lost in loss record 576 of 793 ==10670==at 0x4A06BC3: calloc (vg_replace_malloc.c:618) ==10670==by 0x509DEBD: virAlloc (viralloc.c:144) ==10670==by 0x19FBD558: qemuAgentGetFSInfo (qemu_agent.c:1837) ==10670==by 0x1A03CF91: qemuDomainGetFSInfo (qemu_driver.c:19238) Signed-off-by: Chen Fan --- src/libvirt-domain.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 04545fd..7f8a7ce 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -11337,4 +11337,6 @@ virDomainFSInfoFree(virDomainFSInfoPtr info) for (i = 0; i < info->ndevAlias; i++) VIR_FREE(info->devAlias[i]); VIR_FREE(info->devAlias); + +VIR_FREE(info); } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] docs: network: fix some trivial typos in docs/formatnetwork.html
this patch fix some weird typos: 1. < hostdev> => 2. < type>=> 3. => 4. redundant comma 5. missing right-half bracket Signed-off-by: Chen Fan --- docs/formatnetwork.html.in | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index dc438ae..7bcf316 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -288,7 +288,7 @@ (Single Root I/O Virtualization) virtual function (VF) devices can be assigned in this manner; to assign a standard single-port PCI or PCIe ethernet card to a guest, -use the traditional < hostdev> device +use the traditional <hostdev> device definition. Since 0.10.0 @@ -312,9 +312,9 @@ Note that this "intelligent passthrough" of network devices is very similar to the functionality of a -standard < hostdev> device, the +standard <hostdev> device, the difference being that this method allows specifying a MAC -address, vlan tag, and <virtualport > +address, vlan tag, and <virtualport> for the passed-through device. If these capabilities are not required, if you have a standard single-port PCI, PCIe, or USB network card that doesn't support SR-IOV (and @@ -383,9 +383,9 @@ since 0.10.0 When using forward mode 'hostdev', the interface pool is specified with a list of <address> elements, each of which has - < type> (must always be 'pci', + <type> (must always be 'pci'), <domain>, <bus>, - <slot>, and <function> + <slot>and <function> attributes. -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] docs: fix a typo in formatdomain.html
Signed-off-by: Chen Fan --- docs/formatdomain.html.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 9364eb5..6a15074 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -3413,7 +3413,7 @@ setting for the attribute is no for security reasons and support depends on the guest network device model as well as the type of connection on the host - currently it is - only supported for the virtio ddevice model and for macvtap + only supported for the virtio device model and for macvtap connections on the host. -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] virnuma: add notset NULL check in virNumaSetupMemoryPolicy
introduce by commit c63ef0452b, when nodeset is NULL, validation will pass in virNumaSetupMemoryPolicy, but virBitmapNextSetBit must ensure bitmap is not Null. there will cause a segmentation fault. this patch fixed it. Signed-off-by: Chen Fan --- src/util/virnuma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 06520f7..b8d76f4 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -97,6 +97,9 @@ virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode, size_t i; int maxnode = 0; +if (!nodeset) +return 0; + if (!virNumaNodesetIsAvailable(nodeset)) return -1; -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v5 3/3] virnuma: use virNumaNodesetIsAvailable checking nodeset in virNumaSetupMemoryPolicy
Signed-off-by: Chen Fan --- src/util/virnuma.c | 15 --- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 2540bd2..89435de 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -98,16 +98,13 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, int maxnode = 0; virBitmapPtr tmp_nodemask = NULL; +if (!virNumaNodesetIsAvailable(numatune)) +return -1; + tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask, -1); if (!tmp_nodemask) return 0; -if (numa_available() < 0) { -virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Host kernel is not aware of NUMA.")); -return -1; -} - maxnode = numa_max_node(); maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; @@ -347,12 +344,8 @@ int virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, virBitmapPtr nodemask ATTRIBUTE_UNUSED) { -if (virDomainNumatuneGetNodeset(numatune, NULL, -1)) { -virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("libvirt is compiled without NUMA tuning support")); - +if (!virNumaNodesetIsAvailable(numatune)) return -1; -} return 0; } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v5 1/3] bitmap: add virBitmapLastSetBit for finding the last bit position of bitmap
Signed-off-by: Chen Fan --- src/libvirt_private.syms | 1 + src/util/virbitmap.c | 45 + src/util/virbitmap.h | 3 +++ tests/virbitmaptest.c| 13 - 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d63a8f0..1e2bc0a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1011,6 +1011,7 @@ virBitmapFree; virBitmapGetBit; virBitmapIsAllClear; virBitmapIsAllSet; +virBitmapLastSetBit; virBitmapNew; virBitmapNewCopy; virBitmapNewData; diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index b6bd074..04a2388 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -651,6 +651,51 @@ virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) } /** + * virBitmapLastSetBit: + * @bitmap: the bitmap + * + * Search for the last set bit in bitmap @bitmap. + * + * Returns the position of the found bit, or -1 if no bit is set. + */ +ssize_t +virBitmapLastSetBit(virBitmapPtr bitmap) +{ +ssize_t i; +int unusedBits; +ssize_t sz; +unsigned long bits; + +unusedBits = bitmap->map_len * VIR_BITMAP_BITS_PER_UNIT - bitmap->max_bit; + +sz = bitmap->map_len - 1; +if (unusedBits > 0) { +bits = bitmap->map[sz] & (VIR_BITMAP_BIT(VIR_BITMAP_BITS_PER_UNIT - unusedBits) - 1); +if (bits != 0) +goto found; + +sz--; +} + +for (; sz >= 0; sz--) { +bits = bitmap->map[sz]; +if (bits != 0) +goto found; +} + +if (bits == 0) +return -1; + + found: +for (i = VIR_BITMAP_BITS_PER_UNIT - 1; i >= 0; i--) { +if (bits & 1UL << i) +return i + sz * VIR_BITMAP_BITS_PER_UNIT; +} + +return -1; +} + +/** * virBitmapNextClearBit: * @bitmap: the bitmap * @pos: the position after which to search for a clear bit diff --git a/src/util/virbitmap.h b/src/util/virbitmap.h index 4493cc9..565264c 100644 --- a/src/util/virbitmap.h +++ b/src/util/virbitmap.h @@ -105,6 +105,9 @@ bool virBitmapIsAllClear(virBitmapPtr bitmap) ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) ATTRIBUTE_NONNULL(1); +ssize_t virBitmapLastSetBit(virBitmapPtr bitmap) +ATTRIBUTE_NONNULL(1); + ssize_t virBitmapNextClearBit(virBitmapPtr bitmap, ssize_t pos) ATTRIBUTE_NONNULL(1); diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c index ea832ad..ac5f298 100644 --- a/tests/virbitmaptest.c +++ b/tests/virbitmaptest.c @@ -171,7 +171,7 @@ test3(const void *data ATTRIBUTE_UNUSED) return ret; } -/* test for virBitmapNextSetBit, virBitmapNextClearBit */ +/* test for virBitmapNextSetBit, virBitmapLastSetBit, virBitmapNextClearBit */ static int test4(const void *data ATTRIBUTE_UNUSED) { @@ -200,6 +200,9 @@ test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextSetBit(bitmap, -1) != -1) goto error; +if (virBitmapLastSetBit(bitmap) != -1) +goto error; + for (i = 0; i < size; i++) { if (virBitmapNextClearBit(bitmap, i - 1) != i) goto error; @@ -232,6 +235,11 @@ test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextSetBit(bitmap, i) != -1) goto error; +j = sizeof(bitsPos)/sizeof(int) - 1; + +if (virBitmapLastSetBit(bitmap) != bitsPos[j]) +goto error; + j = 0; i = -1; @@ -255,6 +263,9 @@ test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextSetBit(bitmap, i) != -1) goto error; +if (virBitmapLastSetBit(bitmap) != size - 1) +goto error; + if (virBitmapNextClearBit(bitmap, -1) != -1) goto error; -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v5 0/3] add nodeset check in numatune
when setting elements memnode and nodeset in attribute numatune more than the host nodes in XML file, VM boot should fail. so add check for that. Chen Fan (3): bitmap: add virBitmapLastSetBit for finding the last bit position of bitmap numatune: add check for numatune nodeset range virnuma: use virNumaNodesetIsAvailable checking nodeset in virNumaSetupMemoryPolicy src/conf/numatune_conf.c | 28 src/conf/numatune_conf.h | 1 + src/libvirt_private.syms | 2 + src/qemu/qemu_command.c| 4 ++ src/util/virbitmap.c | 45 ++ src/util/virbitmap.h | 3 ++ src/util/virnuma.c | 53 +- src/util/virnuma.h | 1 + ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 ++ tests/qemuxml2argvmock.c | 9 tests/qemuxml2argvtest.c | 2 + tests/virbitmaptest.c | 13 +- 12 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v5 2/3] numatune: add check for numatune nodeset range
There was no check for 'nodeset' attribute in numatune-related elements. This patch adds validation that any nodeset specified does not exceed maximum host node. Signed-off-by: Chen Fan --- src/conf/numatune_conf.c | 28 src/conf/numatune_conf.h | 1 + src/libvirt_private.syms | 1 + src/qemu/qemu_command.c| 4 +++ src/util/virnuma.c | 38 ++ src/util/virnuma.h | 1 + ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 tests/qemuxml2argvmock.c | 9 + tests/qemuxml2argvtest.c | 2 ++ 9 files changed, 119 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c index 21d9a64..6986739 100644 --- a/src/conf/numatune_conf.c +++ b/src/conf/numatune_conf.c @@ -612,3 +612,31 @@ virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune) return false; } + +int +virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune) +{ +int ret = -1; +virBitmapPtr nodemask = NULL; +size_t i; +int bit; + +if (!numatune) +return ret; + +nodemask = virDomainNumatuneGetNodeset(numatune, NULL, -1); +if (nodemask) +ret = virBitmapLastSetBit(nodemask); + +for (i = 0; i < numatune->nmem_nodes; i++) { +nodemask = numatune->mem_nodes[i].nodeset; +if (!nodemask) +continue; + +bit = virBitmapLastSetBit(nodemask); +if (bit > ret) +ret = bit; +} + +return ret; +} diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h index 5254629..15dc0d6 100644 --- a/src/conf/numatune_conf.h +++ b/src/conf/numatune_conf.h @@ -102,4 +102,5 @@ bool virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune); bool virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune); +int virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune); #endif /* __NUMATUNE_CONF_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1e2bc0a..4a30ad7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1729,6 +1729,7 @@ virNumaGetPageInfo; virNumaGetPages; virNumaIsAvailable; virNumaNodeIsAvailable; +virNumaNodesetIsAvailable; virNumaSetPagePoolSize; virNumaSetupMemoryPolicy; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2e5af4f..d2c5f0c 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -53,6 +53,7 @@ #include "virstoragefile.h" #include "virtpm.h" #include "virscsi.h" +#include "virnuma.h" #if defined(__linux__) # include #endif @@ -6663,6 +6664,9 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, goto cleanup; } +if (!virNumaNodesetIsAvailable(def->numatune)) +goto cleanup; + for (i = 0; i < def->mem.nhugepages; i++) { ssize_t next_bit, pos = 0; diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 690615f..2540bd2 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -165,6 +165,33 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, return ret; } +bool +virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) +{ +int maxnode; +int bit; + +if (!numatune) +return true; + +bit = virDomainNumatuneSpecifiedMaxNode(numatune); +if (bit < 0) +return true; + +if ((maxnode = virNumaGetMaxNode()) < 0) +return false; + +maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; +if (bit > maxnode) +goto error; + +return true; + + error: +virReportError(VIR_ERR_INTERNAL_ERROR, + _("NUMA node %d is out of range"), bit); +return false; +} bool virNumaIsAvailable(void) @@ -330,6 +357,17 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, return 0; } +bool +virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) +{ +if (virDomainNumatuneSpecifiedMaxNode(numatune) >= 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("libvirt is compiled without NUMA tuning support")); +return false; +} + +return true; +} bool virNumaIsAvailable(void) diff --git a/src/util/virnuma.h b/src/util/virnuma.h index 04b6b8c..5bb37b8 100644 --- a/src/util/virnuma.h +++ b/src/util/virnuma.h @@ -34,6 +34,7 @@ char *virNumaGetAutoPlacementAdvice(unsigned short vcups, int virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, virBitmapPtr nodemask); +bool virNumaNodesetIsAvailable(virDomainNumatunePtr numatune); bool virNumaIsAvailable(void); in
Re: [libvirt] [PATCH v4 0/3] add nodeset check in numatune
On Mon, 2014-11-03 at 14:18 +0100, Martin Kletzander wrote: > On Thu, Oct 30, 2014 at 01:44:16PM +0800, Chen Fan wrote: > >when setting elements memnode and nodeset in attribute numatune more > >than the host nodes in XML file, VM boot should fail. so add check for > >that. > > > > You should run "make syntax-check" and "make check" on those patches, > it would find at least two things ;) > > Anyway, ACK series with the changes I mentioned. If you're OK with > them, I'll push the series. I will send a new series after change them. and Thanks for your review. Chen > > Martin -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v4 3/3] virnuma: use virNumaNodesetIsAvailable checking nodeset in virNumaSetupMemoryPolicy
On Mon, 2014-11-03 at 14:18 +0100, Martin Kletzander wrote: > On Thu, Oct 30, 2014 at 01:44:19PM +0800, Chen Fan wrote: > >Signed-off-by: Chen Fan > >--- > > src/util/virnuma.c | 23 --- > > 1 file changed, 4 insertions(+), 19 deletions(-) > > > >diff --git a/src/util/virnuma.c b/src/util/virnuma.c > >index 4188ef5..613a43c 100644 > >--- a/src/util/virnuma.c > >+++ b/src/util/virnuma.c > >@@ -95,31 +95,19 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, > > int ret = -1; > > int bit = 0; > > size_t i; > >-int maxnode = 0; > > virBitmapPtr tmp_nodemask = NULL; > > > >+if (!virNumaNodesetIsAvailable(numatune)) > >+return -1; > >+ > > tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask, -1); > > if (!tmp_nodemask) > > return 0; > > > >-if (numa_available() < 0) { > >-virReportError(VIR_ERR_INTERNAL_ERROR, > >- "%s", _("Host kernel is not aware of NUMA.")); > >-return -1; > >-} > >- > >-maxnode = numa_max_node(); > >-maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; > >- > > /* Convert nodemask to NUMA bitmask. */ > > nodemask_zero(&mask); > > bit = -1; > > while ((bit = virBitmapNextSetBit(tmp_nodemask, bit)) >= 0) { > >-if (bit > maxnode) { > >-virReportError(VIR_ERR_INTERNAL_ERROR, > >- _("NUMA node %d is out of range"), bit); > >-return -1; > >-} > > nodemask_set(&mask, bit); > > } > > > > I think this is safe, "numad" returning nodeset that's not on the host > would be weird error and it is easy to find in the logs. I think virNumaNodesetIsAvailable() has checked the case, but retain it here is ok. > > >@@ -347,10 +335,7 @@ int > > virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, > > virBitmapPtr nodemask ATTRIBUTE_UNUSED) > > { > >-if (virDomainNumatuneGetNodeset(numatune, NULL, -1)) { > >-virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > >- _("libvirt is compiled without NUMA tuning > >support")); > >- > >+if (!virNumaNodesetIsAvailable(numatune)) { > > return -1; > > } > > This makes the square brackets obsolete. Thanks, Chen -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v4 2/3] numatune: add check for numatune nodeset range
On Mon, 2014-11-03 at 14:18 +0100, Martin Kletzander wrote: > On Thu, Oct 30, 2014 at 01:44:18PM +0800, Chen Fan wrote: > >There was no check for 'nodeset' attribute in numatune-related > >elements. This patch adds validation that any nodeset specified does > >not exceed maximum host node. > > > >Signed-off-by: Chen Fan > >--- > > src/conf/numatune_conf.c | 28 > > src/conf/numatune_conf.h | 1 + > > src/libvirt_private.syms | 1 + > > src/qemu/qemu_command.c| 4 +++ > > src/util/virnuma.c | 38 > > ++ > > src/util/virnuma.h | 1 + > > ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 36 > > tests/qemuxml2argvmock.c | 9 + > > tests/qemuxml2argvtest.c | 1 + > > 9 files changed, 119 insertions(+) > > create mode 100644 > > tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml > > > >diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c > >index 21d9a64..6986739 100644 > >--- a/src/conf/numatune_conf.c > >+++ b/src/conf/numatune_conf.c > >@@ -612,3 +612,31 @@ virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr > >numatune) > > > > return false; > > } > >+ > >+int > >+virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune) > >+{ > >+int ret = -1; > >+virBitmapPtr nodemask = NULL; > >+size_t i; > >+int bit; > >+ > >+if (!numatune) > >+return ret; > >+ > >+nodemask = virDomainNumatuneGetNodeset(numatune, NULL, -1); > >+if (nodemask) > >+ret = virBitmapLastSetBit(nodemask); > >+ > >+for (i = 0; i < numatune->nmem_nodes; i++) { > >+nodemask = numatune->mem_nodes[i].nodeset; > >+if (!nodemask) > >+continue; > >+ > >+bit = virBitmapLastSetBit(nodemask); > >+if (bit > ret) > >+ret = bit; > >+} > >+ > >+return ret; > >+} > >diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h > >index 5254629..15dc0d6 100644 > >--- a/src/conf/numatune_conf.h > >+++ b/src/conf/numatune_conf.h > >@@ -102,4 +102,5 @@ bool > >virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune); > > > > bool virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune); > > > >+int virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune); > > #endif /* __NUMATUNE_CONF_H__ */ > >diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > >index 1e2bc0a..4a30ad7 100644 > >--- a/src/libvirt_private.syms > >+++ b/src/libvirt_private.syms > >@@ -1729,6 +1729,7 @@ virNumaGetPageInfo; > > virNumaGetPages; > > virNumaIsAvailable; > > virNumaNodeIsAvailable; > >+virNumaNodesetIsAvailable; > > virNumaSetPagePoolSize; > > virNumaSetupMemoryPolicy; > > > >diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c > >index 2e5af4f..d2c5f0c 100644 > >--- a/src/qemu/qemu_command.c > >+++ b/src/qemu/qemu_command.c > >@@ -53,6 +53,7 @@ > > #include "virstoragefile.h" > > #include "virtpm.h" > > #include "virscsi.h" > >+#include "virnuma.h" > > #if defined(__linux__) > > # include > > #endif > >@@ -6663,6 +6664,9 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, > > goto cleanup; > > } > > > >+if (!virNumaNodesetIsAvailable(def->numatune)) > >+goto cleanup; > >+ > > for (i = 0; i < def->mem.nhugepages; i++) { > > ssize_t next_bit, pos = 0; > > > >diff --git a/src/util/virnuma.c b/src/util/virnuma.c > >index 690615f..4188ef5 100644 > >--- a/src/util/virnuma.c > >+++ b/src/util/virnuma.c > >@@ -165,6 +165,33 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, > > return ret; > > } > > > >+bool > >+virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) > >+{ > >+int maxnode; > >+int bit; > >+ > >+if (!numatune) > >+return true; > >+ > >+bit = virDomainNumatuneSpecifiedMaxNode(numatune); > >+if (bit == -1) > > (bit < 0) would go with the rest of the code, the functions can be > then modified t
Re: [libvirt] [PATCH v4 1/3] bitmap: add virBitmapLastSetBit for finding the last bit position of bitmap
On Mon, 2014-11-03 at 14:18 +0100, Martin Kletzander wrote: > On Thu, Oct 30, 2014 at 01:44:17PM +0800, Chen Fan wrote: > >Signed-off-by: Chen Fan > >--- > > src/libvirt_private.syms | 1 + > > src/util/virbitmap.c | 45 + > > src/util/virbitmap.h | 3 +++ > > tests/virbitmaptest.c| 13 - > > 4 files changed, 61 insertions(+), 1 deletion(-) > > > >diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > >index d63a8f0..1e2bc0a 100644 > >--- a/src/libvirt_private.syms > >+++ b/src/libvirt_private.syms > >@@ -1011,6 +1011,7 @@ virBitmapFree; > > virBitmapGetBit; > > virBitmapIsAllClear; > > virBitmapIsAllSet; > >+virBitmapLastSetBit; > > virBitmapNew; > > virBitmapNewCopy; > > virBitmapNewData; > >diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c > >index b6bd074..3e7269e 100644 > >--- a/src/util/virbitmap.c > >+++ b/src/util/virbitmap.c > >@@ -651,6 +651,51 @@ virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) > > } > > > > /** > >+ * virBitmapLastSetBit: > >+ * @bitmap: the bitmap > >+ * > >+ * Search for the last set bit in bitmap @bitmap. > >+ * > >+ * Returns the position of the found bit, or -1 if no bit found. > > s/found/is set/ > > >+ */ > >+ssize_t > >+virBitmapLastSetBit(virBitmapPtr bitmap) > >+{ > >+ssize_t i; > >+int unusedBits; > >+ssize_t sz; > >+unsigned long bits; > >+ > >+unusedBits = bitmap->map_len * VIR_BITMAP_BITS_PER_UNIT - > >bitmap->max_bit; > >+ > >+sz = bitmap->map_len - 1; > >+if (unusedBits > 0) { > >+bits = bitmap->map[sz] & (VIR_BITMAP_BIT(VIR_BITMAP_BITS_PER_UNIT - > >unusedBits) - 1); > >+if (bits != 0) > >+goto found; > >+ > >+sz--; > >+} > >+ > >+for (; sz >= 0; sz--) { > >+bits = bitmap->map[sz]; > >+if (bits != 0) > >+goto found; > >+} > >+ > >+if (bits == 0) > >+return -1; > >+ > >+found: > > Missing space before label. "make syntax-check" would tell you that > instead of me ;) Thanks for your remind. I will do that. Chen -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v3 1/3] numatune: add check for numatune nodeset range
On Thu, 2014-10-30 at 07:55 +0100, Martin Kletzander wrote: > On Thu, Oct 30, 2014 at 02:23:00AM +0000, Chen, Fan wrote: > >On Wed, 2014-10-29 at 14:20 +0100, Martin Kletzander wrote: > >> On Wed, Oct 29, 2014 at 08:33:32PM +0800, Chen Fan wrote: > >> >diff --git a/src/util/virnuma.c b/src/util/virnuma.c > >> >@@ -373,6 +400,12 @@ virNumaGetNodeCPUs(int node ATTRIBUTE_UNUSED, > >> >_("NUMA isn't available on this host")); > >> > return -1; > >> > } > >> >+ > >> >+bool > >> >+virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) > >> >+{ > >> >+return true; > >> >+} > >> > #endif > >> > > >> > >> In what case would you like this to return true? > > > >when libvirt does not support numa, we can not check it. > >maybe we should return false if setting nodeset. > > > > That was my idea, I just wanted to make sure we're on the same page. > The thing is that if you want something that's not available, it makes > more sense to say "NO" then just allow it because libvirt doesn't > know. Make the user fix it :) Yes, I had made a v4 and sent it, please help to review. Thanks, Chen > > Martin -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v4 3/3] virnuma: use virNumaNodesetIsAvailable checking nodeset in virNumaSetupMemoryPolicy
Signed-off-by: Chen Fan --- src/util/virnuma.c | 23 --- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 4188ef5..613a43c 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -95,31 +95,19 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, int ret = -1; int bit = 0; size_t i; -int maxnode = 0; virBitmapPtr tmp_nodemask = NULL; +if (!virNumaNodesetIsAvailable(numatune)) +return -1; + tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask, -1); if (!tmp_nodemask) return 0; -if (numa_available() < 0) { -virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Host kernel is not aware of NUMA.")); -return -1; -} - -maxnode = numa_max_node(); -maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; - /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); bit = -1; while ((bit = virBitmapNextSetBit(tmp_nodemask, bit)) >= 0) { -if (bit > maxnode) { -virReportError(VIR_ERR_INTERNAL_ERROR, - _("NUMA node %d is out of range"), bit); -return -1; -} nodemask_set(&mask, bit); } @@ -347,10 +335,7 @@ int virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, virBitmapPtr nodemask ATTRIBUTE_UNUSED) { -if (virDomainNumatuneGetNodeset(numatune, NULL, -1)) { -virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("libvirt is compiled without NUMA tuning support")); - +if (!virNumaNodesetIsAvailable(numatune)) { return -1; } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v4 2/3] numatune: add check for numatune nodeset range
There was no check for 'nodeset' attribute in numatune-related elements. This patch adds validation that any nodeset specified does not exceed maximum host node. Signed-off-by: Chen Fan --- src/conf/numatune_conf.c | 28 src/conf/numatune_conf.h | 1 + src/libvirt_private.syms | 1 + src/qemu/qemu_command.c| 4 +++ src/util/virnuma.c | 38 ++ src/util/virnuma.h | 1 + ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 36 tests/qemuxml2argvmock.c | 9 + tests/qemuxml2argvtest.c | 1 + 9 files changed, 119 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c index 21d9a64..6986739 100644 --- a/src/conf/numatune_conf.c +++ b/src/conf/numatune_conf.c @@ -612,3 +612,31 @@ virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune) return false; } + +int +virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune) +{ +int ret = -1; +virBitmapPtr nodemask = NULL; +size_t i; +int bit; + +if (!numatune) +return ret; + +nodemask = virDomainNumatuneGetNodeset(numatune, NULL, -1); +if (nodemask) +ret = virBitmapLastSetBit(nodemask); + +for (i = 0; i < numatune->nmem_nodes; i++) { +nodemask = numatune->mem_nodes[i].nodeset; +if (!nodemask) +continue; + +bit = virBitmapLastSetBit(nodemask); +if (bit > ret) +ret = bit; +} + +return ret; +} diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h index 5254629..15dc0d6 100644 --- a/src/conf/numatune_conf.h +++ b/src/conf/numatune_conf.h @@ -102,4 +102,5 @@ bool virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune); bool virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune); +int virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune); #endif /* __NUMATUNE_CONF_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1e2bc0a..4a30ad7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1729,6 +1729,7 @@ virNumaGetPageInfo; virNumaGetPages; virNumaIsAvailable; virNumaNodeIsAvailable; +virNumaNodesetIsAvailable; virNumaSetPagePoolSize; virNumaSetupMemoryPolicy; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2e5af4f..d2c5f0c 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -53,6 +53,7 @@ #include "virstoragefile.h" #include "virtpm.h" #include "virscsi.h" +#include "virnuma.h" #if defined(__linux__) # include #endif @@ -6663,6 +6664,9 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, goto cleanup; } +if (!virNumaNodesetIsAvailable(def->numatune)) +goto cleanup; + for (i = 0; i < def->mem.nhugepages; i++) { ssize_t next_bit, pos = 0; diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 690615f..4188ef5 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -165,6 +165,33 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, return ret; } +bool +virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) +{ +int maxnode; +int bit; + +if (!numatune) +return true; + +bit = virDomainNumatuneSpecifiedMaxNode(numatune); +if (bit == -1) +return true; + +if ((maxnode = virNumaGetMaxNode()) < 0) +return false; + +maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; +if (bit > maxnode) +goto error; + +return true; + + error: +virReportError(VIR_ERR_INTERNAL_ERROR, + _("NUMA node %d is out of range"), bit); +return false; +} bool virNumaIsAvailable(void) @@ -330,6 +357,17 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, return 0; } +bool +virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) +{ +if (virDomainNumatuneSpecifiedMaxNode(numatune) != -1) { +virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("libvirt is compiled without NUMA tuning support")); +return false; +} + +return true; +} bool virNumaIsAvailable(void) diff --git a/src/util/virnuma.h b/src/util/virnuma.h index 04b6b8c..5bb37b8 100644 --- a/src/util/virnuma.h +++ b/src/util/virnuma.h @@ -34,6 +34,7 @@ char *virNumaGetAutoPlacementAdvice(unsigned short vcups, int virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, virBitmapPtr nodemask); +bool virNumaNodesetIsAvailable(virDomainNumatunePtr numatune); bool virNumaIsAvailable(void); int virN
[libvirt] [PATCH v4 1/3] bitmap: add virBitmapLastSetBit for finding the last bit position of bitmap
Signed-off-by: Chen Fan --- src/libvirt_private.syms | 1 + src/util/virbitmap.c | 45 + src/util/virbitmap.h | 3 +++ tests/virbitmaptest.c| 13 - 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d63a8f0..1e2bc0a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1011,6 +1011,7 @@ virBitmapFree; virBitmapGetBit; virBitmapIsAllClear; virBitmapIsAllSet; +virBitmapLastSetBit; virBitmapNew; virBitmapNewCopy; virBitmapNewData; diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index b6bd074..3e7269e 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -651,6 +651,51 @@ virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) } /** + * virBitmapLastSetBit: + * @bitmap: the bitmap + * + * Search for the last set bit in bitmap @bitmap. + * + * Returns the position of the found bit, or -1 if no bit found. + */ +ssize_t +virBitmapLastSetBit(virBitmapPtr bitmap) +{ +ssize_t i; +int unusedBits; +ssize_t sz; +unsigned long bits; + +unusedBits = bitmap->map_len * VIR_BITMAP_BITS_PER_UNIT - bitmap->max_bit; + +sz = bitmap->map_len - 1; +if (unusedBits > 0) { +bits = bitmap->map[sz] & (VIR_BITMAP_BIT(VIR_BITMAP_BITS_PER_UNIT - unusedBits) - 1); +if (bits != 0) +goto found; + +sz--; +} + +for (; sz >= 0; sz--) { +bits = bitmap->map[sz]; +if (bits != 0) +goto found; +} + +if (bits == 0) +return -1; + +found: +for (i = VIR_BITMAP_BITS_PER_UNIT - 1; i >= 0; i--) { +if (bits & 1UL << i) +return i + sz * VIR_BITMAP_BITS_PER_UNIT; +} + +return -1; +} + +/** * virBitmapNextClearBit: * @bitmap: the bitmap * @pos: the position after which to search for a clear bit diff --git a/src/util/virbitmap.h b/src/util/virbitmap.h index 4493cc9..565264c 100644 --- a/src/util/virbitmap.h +++ b/src/util/virbitmap.h @@ -105,6 +105,9 @@ bool virBitmapIsAllClear(virBitmapPtr bitmap) ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) ATTRIBUTE_NONNULL(1); +ssize_t virBitmapLastSetBit(virBitmapPtr bitmap) +ATTRIBUTE_NONNULL(1); + ssize_t virBitmapNextClearBit(virBitmapPtr bitmap, ssize_t pos) ATTRIBUTE_NONNULL(1); diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c index ea832ad..ac5f298 100644 --- a/tests/virbitmaptest.c +++ b/tests/virbitmaptest.c @@ -171,7 +171,7 @@ test3(const void *data ATTRIBUTE_UNUSED) return ret; } -/* test for virBitmapNextSetBit, virBitmapNextClearBit */ +/* test for virBitmapNextSetBit, virBitmapLastSetBit, virBitmapNextClearBit */ static int test4(const void *data ATTRIBUTE_UNUSED) { @@ -200,6 +200,9 @@ test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextSetBit(bitmap, -1) != -1) goto error; +if (virBitmapLastSetBit(bitmap) != -1) +goto error; + for (i = 0; i < size; i++) { if (virBitmapNextClearBit(bitmap, i - 1) != i) goto error; @@ -232,6 +235,11 @@ test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextSetBit(bitmap, i) != -1) goto error; +j = sizeof(bitsPos)/sizeof(int) - 1; + +if (virBitmapLastSetBit(bitmap) != bitsPos[j]) +goto error; + j = 0; i = -1; @@ -255,6 +263,9 @@ test4(const void *data ATTRIBUTE_UNUSED) if (virBitmapNextSetBit(bitmap, i) != -1) goto error; +if (virBitmapLastSetBit(bitmap) != size - 1) +goto error; + if (virBitmapNextClearBit(bitmap, -1) != -1) goto error; -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v4 0/3] add nodeset check in numatune
when setting elements memnode and nodeset in attribute numatune more than the host nodes in XML file, VM boot should fail. so add check for that. Chen Fan (3): bitmap: add virBitmapLastSetBit for finding the last bit position of bitmap numatune: add check for numatune nodeset range virnuma: use virNumaNodesetIsAvailable checking nodeset in virNumaSetupMemoryPolicy src/conf/numatune_conf.c | 28 ++ src/conf/numatune_conf.h | 1 + src/libvirt_private.syms | 2 + src/qemu/qemu_command.c| 4 ++ src/util/virbitmap.c | 45 src/util/virbitmap.h | 3 ++ src/util/virnuma.c | 61 +++--- src/util/virnuma.h | 1 + ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 36 + tests/qemuxml2argvmock.c | 9 tests/qemuxml2argvtest.c | 1 + tests/virbitmaptest.c | 13 - 12 files changed, 184 insertions(+), 20 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v3 1/3] numatune: add check for numatune nodeset range
On Wed, 2014-10-29 at 14:20 +0100, Martin Kletzander wrote: > On Wed, Oct 29, 2014 at 08:33:32PM +0800, Chen Fan wrote: > >For memnode in numatune element, the range of attribute 'nodeset' > >was not validated. on my host maxnodes was 1, but when setting nodeset > >to '0-2' or more, guest also started succuss. there probably was qemu's > >bug too. > > > > How about rewording this as: > > There was no check for 'nodeset' attribute in numatune-related > elements. This patch adds validation that any nodeset specified does > not exceed maximum host node. Look good to me. > > >Signed-off-by: Chen Fan > >--- > > src/conf/numatune_conf.c | 28 + > > src/conf/numatune_conf.h | 1 + > > src/libvirt_private.syms | 2 + > > src/qemu/qemu_command.c| 3 ++ > > src/qemu/qemu_command.h| 1 + > > src/util/virbitmap.c | 49 > > ++ > > src/util/virbitmap.h | 3 ++ > > src/util/virnuma.c | 33 +++ > > src/util/virnuma.h | 2 + > > ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 > > tests/qemuxml2argvmock.c | 9 > > tests/qemuxml2argvtest.c | 1 + > > tests/virbitmaptest.c | 26 +++- > > 13 files changed, 192 insertions(+), 1 deletion(-) > > create mode 100644 > > tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml > > > >diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c > >index 21d9a64..54f309a 100644 > >--- a/src/conf/numatune_conf.c > >+++ b/src/conf/numatune_conf.c > >@@ -612,3 +612,31 @@ virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr > >numatune) > > > > return false; > > } > >+ > >+int > >+virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune) > >+{ > >+int ret = -1; > >+virBitmapPtr nodemask = NULL; > >+size_t i; > >+ > >+if (!numatune) > >+return ret; > >+ > >+nodemask = virDomainNumatuneGetNodeset(numatune, NULL, -1); > >+if (nodemask) { > >+ret = virBitmapLastSetBit(nodemask, -1); > >+} > >+for (i = 0; i < numatune->nmem_nodes; i++) { > > Well, you're using the advantage of accessible structure members here > (numatune->nmem_nodes), but using accessors around. These particular > ones are useless here when you don't need any of the logic they > provide. right, I should use numatune->mem_nodes[i].nodeset directly. > > >+int bit = -1; > >+nodemask = virDomainNumatuneGetNodeset(numatune, NULL, i); > >+if (!nodemask) > >+continue; > >+ > >+bit = virBitmapLastSetBit(nodemask, -1); > >+if (bit > ret) > >+ret = bit; > >+} > >+ > >+return ret; > >+} > >diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h > >index 5254629..15dc0d6 100644 > >--- a/src/conf/numatune_conf.h > >+++ b/src/conf/numatune_conf.h > >@@ -102,4 +102,5 @@ bool > >virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune); > > > > bool virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune); > > > >+int virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune); > > #endif /* __NUMATUNE_CONF_H__ */ > >diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > >index d63a8f0..4a30ad7 100644 > >--- a/src/libvirt_private.syms > >+++ b/src/libvirt_private.syms > >@@ -1011,6 +1011,7 @@ virBitmapFree; > > virBitmapGetBit; > > virBitmapIsAllClear; > > virBitmapIsAllSet; > >+virBitmapLastSetBit; > > virBitmapNew; > > virBitmapNewCopy; > > virBitmapNewData; > >@@ -1728,6 +1729,7 @@ virNumaGetPageInfo; > > virNumaGetPages; > > virNumaIsAvailable; > > virNumaNodeIsAvailable; > >+virNumaNodesetIsAvailable; > > virNumaSetPagePoolSize; > > virNumaSetupMemoryPolicy; > > > >diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c > >index 2e5af4f..9757d3e 100644 > >--- a/src/qemu/qemu_command.c > >+++ b/src/qemu/qemu_command.c > >@@ -6663,6 +6663,9 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, > > goto cleanup;
Re: [libvirt] [PATCH v3 3/3] virnuma: remove redundant check for numanode
On Wed, 2014-10-29 at 14:23 +0100, Martin Kletzander wrote: > On Wed, Oct 29, 2014 at 08:33:34PM +0800, Chen Fan wrote: > >Signed-off-by: Chen Fan > >--- > > src/util/virnuma.c | 15 --- > > 1 file changed, 15 deletions(-) > > > > I think this harmless check may prevent future problems (if > SetupMemoryPolicy is called from some new codepath. Either keep it > here or call virNumaNodesetIsAvailable() in the start of the function. call virNumaNodesetIsAvailable() in the start of the function will be fine. Thanks, Chen > > >diff --git a/src/util/virnuma.c b/src/util/virnuma.c > >index fbe8fd1..5a08049 100644 > >--- a/src/util/virnuma.c > >+++ b/src/util/virnuma.c > >@@ -95,31 +95,16 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, > > int ret = -1; > > int bit = 0; > > size_t i; > >-int maxnode = 0; > > virBitmapPtr tmp_nodemask = NULL; > > > > tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask, -1); > > if (!tmp_nodemask) > > return 0; > > > >-if (numa_available() < 0) { > >-virReportError(VIR_ERR_INTERNAL_ERROR, > >- "%s", _("Host kernel is not aware of NUMA.")); > >-return -1; > >-} > >- > >-maxnode = numa_max_node(); > >-maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; > >- > > /* Convert nodemask to NUMA bitmask. */ > > nodemask_zero(&mask); > > bit = -1; > > while ((bit = virBitmapNextSetBit(tmp_nodemask, bit)) >= 0) { > >-if (bit > maxnode) { > >-virReportError(VIR_ERR_INTERNAL_ERROR, > >- _("NUMA node %d is out of range"), bit); > >-return -1; > >-} > > nodemask_set(&mask, bit); > > } > > > >-- > >1.9.3 > > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v3 3/3] virnuma: remove redundant check for numanode
Signed-off-by: Chen Fan --- src/util/virnuma.c | 15 --- 1 file changed, 15 deletions(-) diff --git a/src/util/virnuma.c b/src/util/virnuma.c index fbe8fd1..5a08049 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -95,31 +95,16 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, int ret = -1; int bit = 0; size_t i; -int maxnode = 0; virBitmapPtr tmp_nodemask = NULL; tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask, -1); if (!tmp_nodemask) return 0; -if (numa_available() < 0) { -virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Host kernel is not aware of NUMA.")); -return -1; -} - -maxnode = numa_max_node(); -maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; - /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); bit = -1; while ((bit = virBitmapNextSetBit(tmp_nodemask, bit)) >= 0) { -if (bit > maxnode) { -virReportError(VIR_ERR_INTERNAL_ERROR, - _("NUMA node %d is out of range"), bit); -return -1; -} nodemask_set(&mask, bit); } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v3 1/3] numatune: add check for numatune nodeset range
For memnode in numatune element, the range of attribute 'nodeset' was not validated. on my host maxnodes was 1, but when setting nodeset to '0-2' or more, guest also started succuss. there probably was qemu's bug too. Signed-off-by: Chen Fan --- src/conf/numatune_conf.c | 28 + src/conf/numatune_conf.h | 1 + src/libvirt_private.syms | 2 + src/qemu/qemu_command.c| 3 ++ src/qemu/qemu_command.h| 1 + src/util/virbitmap.c | 49 ++ src/util/virbitmap.h | 3 ++ src/util/virnuma.c | 33 +++ src/util/virnuma.h | 2 + ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 tests/qemuxml2argvmock.c | 9 tests/qemuxml2argvtest.c | 1 + tests/virbitmaptest.c | 26 +++- 13 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c index 21d9a64..54f309a 100644 --- a/src/conf/numatune_conf.c +++ b/src/conf/numatune_conf.c @@ -612,3 +612,31 @@ virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune) return false; } + +int +virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune) +{ +int ret = -1; +virBitmapPtr nodemask = NULL; +size_t i; + +if (!numatune) +return ret; + +nodemask = virDomainNumatuneGetNodeset(numatune, NULL, -1); +if (nodemask) { +ret = virBitmapLastSetBit(nodemask, -1); +} +for (i = 0; i < numatune->nmem_nodes; i++) { +int bit = -1; +nodemask = virDomainNumatuneGetNodeset(numatune, NULL, i); +if (!nodemask) +continue; + +bit = virBitmapLastSetBit(nodemask, -1); +if (bit > ret) +ret = bit; +} + +return ret; +} diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h index 5254629..15dc0d6 100644 --- a/src/conf/numatune_conf.h +++ b/src/conf/numatune_conf.h @@ -102,4 +102,5 @@ bool virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune); bool virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune); +int virDomainNumatuneSpecifiedMaxNode(virDomainNumatunePtr numatune); #endif /* __NUMATUNE_CONF_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d63a8f0..4a30ad7 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1011,6 +1011,7 @@ virBitmapFree; virBitmapGetBit; virBitmapIsAllClear; virBitmapIsAllSet; +virBitmapLastSetBit; virBitmapNew; virBitmapNewCopy; virBitmapNewData; @@ -1728,6 +1729,7 @@ virNumaGetPageInfo; virNumaGetPages; virNumaIsAvailable; virNumaNodeIsAvailable; +virNumaNodesetIsAvailable; virNumaSetPagePoolSize; virNumaSetupMemoryPolicy; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2e5af4f..9757d3e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6663,6 +6663,9 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, goto cleanup; } +if (!virNumaNodesetIsAvailable(def->numatune)) +goto cleanup; + for (i = 0; i < def->mem.nhugepages; i++) { ssize_t next_bit, pos = 0; diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index aa40c9e..f263665 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -27,6 +27,7 @@ # include "domain_addr.h" # include "domain_conf.h" # include "vircommand.h" +# include "virnuma.h" # include "capabilities.h" # include "qemu_conf.h" # include "qemu_domain.h" diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index b6bd074..aed525a 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -651,6 +651,55 @@ virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) } /** + * virBitmapLastSetBit: + * @bitmap: the bitmap + * @pos: the position after which to search for a set bit + * + * Search for the last set bit before position @pos in bitmap @bitmap. + * @pos can be -1 to search for the last set bit. Position starts + * at max_bit. + * + * Returns the position of the found bit, or -1 if no bit found. + */ +ssize_t +virBitmapLastSetBit(virBitmapPtr bitmap, ssize_t pos) +{ +size_t nl; +size_t nb; +unsigned long bits; +size_t i; + +if (pos < 0) +pos = bitmap->max_bit; + +pos--; + +if (pos >= bitmap->max_bit) +return -1; + +nl = pos / VIR_BITMAP_BITS_PER_UNIT; +nb = pos % VIR_BITMAP_BITS_PER_UNIT; + +bits = bitmap->map[nl] & ((1UL << (nb + 1)) -
[libvirt] [PATCH v3 0/3] add nodeset check in numatune
when setting elements memnode and nodeset in attribute numatune more than the host nodes in XML file, VM boot should fail. so add check for that. Chen Fan (3): numatune: add check for numatune nodeset range lxc controller: add check for numatune virnuma: remove redundant check for numanode src/conf/numatune_conf.c | 28 + src/conf/numatune_conf.h | 1 + src/libvirt_private.syms | 2 + src/lxc/lxc_controller.c | 1 + src/qemu/qemu_command.c| 3 ++ src/qemu/qemu_command.h| 1 + src/util/virbitmap.c | 49 ++ src/util/virbitmap.h | 3 ++ src/util/virnuma.c | 48 ++--- src/util/virnuma.h | 2 + ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 tests/qemuxml2argvmock.c | 9 tests/qemuxml2argvtest.c | 1 + tests/virbitmaptest.c | 26 +++- 14 files changed, 193 insertions(+), 16 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v3 2/3] lxc controller: add check for numatune
Signed-off-by: Chen Fan --- src/lxc/lxc_controller.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 1861dd6..a23dff7 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -689,6 +689,7 @@ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) int ret = -1; if (virLXCControllerGetNumadAdvice(ctrl, &nodemask) < 0 || +!virNumaNodesetIsAvailable (ctrl->def->numatune) || virNumaSetupMemoryPolicy(ctrl->def->numatune, nodemask) < 0) goto cleanup; -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v2 1/3] numatune: add check for numatune nodeset range
On Wed, 2014-10-29 at 07:58 +0100, Martin Kletzander wrote: > On Tue, Oct 28, 2014 at 04:22:21PM +0800, Chen Fan wrote: > >For memnode in numatune element, the range of attribute 'nodeset' > >was not validated. on my host maxnodes was 1, but when setting nodeset > >to '0-2' or more, guest also started succuss. there probably was qemu's > >bug too. > > > >Signed-off-by: Chen Fan > >--- > > src/conf/numatune_conf.c | 21 - > > src/conf/numatune_conf.h | 19 > > src/libvirt_private.syms | 1 + > > src/qemu/qemu_command.c| 3 ++ > > src/qemu/qemu_command.h| 1 + > > src/util/virnuma.c | 55 > > ++ > > src/util/virnuma.h | 2 + > > ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 ++ > > tests/qemuxml2argvmock.c | 9 > > tests/qemuxml2argvtest.c | 1 + > > 10 files changed, 126 insertions(+), 21 deletions(-) > > create mode 100644 > > tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml > > > >diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c > >index 21d9a64..d440b86 100644 > >--- a/src/conf/numatune_conf.c > >+++ b/src/conf/numatune_conf.c > >@@ -42,27 +42,6 @@ VIR_ENUM_IMPL(virDomainNumatunePlacement, > > "static", > > "auto"); > > > >-typedef struct _virDomainNumatuneNode virDomainNumatuneNode; > >-typedef virDomainNumatuneNode *virDomainNumatuneNodePtr; > >- > >-struct _virDomainNumatune { > >-struct { > >-bool specified; > >-virBitmapPtr nodeset; > >-virDomainNumatuneMemMode mode; > >-virDomainNumatunePlacement placement; > >-} memory; /* pinning for all the memory */ > >- > >-struct _virDomainNumatuneNode { > >-virBitmapPtr nodeset; > >-virDomainNumatuneMemMode mode; > >-} *mem_nodes; /* fine tuning per guest node */ > >-size_t nmem_nodes; > >- > >-/* Future NUMA tuning related stuff should go here. */ > >-}; > >- > >- > > static inline bool > > virDomainNumatuneNodeSpecified(virDomainNumatunePtr numatune, > >int cellid) > >diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h > >index 5254629..650b6e7 100644 > >--- a/src/conf/numatune_conf.h > >+++ b/src/conf/numatune_conf.h > >@@ -45,6 +45,25 @@ typedef enum { > > VIR_ENUM_DECL(virDomainNumatunePlacement) > > VIR_ENUM_DECL(virDomainNumatuneMemMode) > > > >+typedef struct _virDomainNumatuneNode virDomainNumatuneNode; > >+typedef virDomainNumatuneNode *virDomainNumatuneNodePtr; > >+ > >+struct _virDomainNumatune { > >+struct { > >+bool specified; > >+virBitmapPtr nodeset; > >+virDomainNumatuneMemMode mode; > >+virDomainNumatunePlacement placement; > >+} memory; /* pinning for all the memory */ > >+ > >+struct _virDomainNumatuneNode { > >+virBitmapPtr nodeset; > >+virDomainNumatuneMemMode mode; > >+} *mem_nodes; /* fine tuning per guest node */ > >+size_t nmem_nodes; > >+ > >+/* Future NUMA tuning related stuff should go here. */ > >+}; > > > > void virDomainNumatuneFree(virDomainNumatunePtr numatune); > > > > NACK to these two hunks. The point of the structure being hidden in > the .c file was to abstract it. You can provide accessors to those > members you need if they are not available already. Got it! > > >diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > >index d63a8f0..16a5864 100644 > >--- a/src/libvirt_private.syms > >+++ b/src/libvirt_private.syms > >@@ -1728,6 +1728,7 @@ virNumaGetPageInfo; > > virNumaGetPages; > > virNumaIsAvailable; > > virNumaNodeIsAvailable; > >+virNumaNodesetIsAvailable; > > virNumaSetPagePoolSize; > > virNumaSetupMemoryPolicy; > > > >diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c > >index 2e5af4f..9757d3e 100644 > >--- a/src/qemu/qemu_command.c > >+++ b/src/qemu/qemu_command.c > >@@ -6663,6 +6663,9 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, > > goto cleanup; > > } > > > >+if (
Re: [libvirt] [PATCH v2 2/3] lxc controller: add check for numatune
On Wed, 2014-10-29 at 08:00 +0100, Martin Kletzander wrote: > On Tue, Oct 28, 2014 at 04:22:22PM +0800, Chen Fan wrote: > >Signed-off-by: Chen Fan > >--- > > src/lxc/lxc_controller.c | 3 ++- > > 1 file changed, 2 insertions(+), 1 deletion(-) > > > >diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c > >index 1861dd6..1ee89ab 100644 > >--- a/src/lxc/lxc_controller.c > >+++ b/src/lxc/lxc_controller.c > >@@ -689,7 +689,8 @@ static int > >virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) > > int ret = -1; > > > > if (virLXCControllerGetNumadAdvice(ctrl, &nodemask) < 0 || > >-virNumaSetupMemoryPolicy(ctrl->def->numatune, nodemask) < 0) > >+(virNumaNodesetIsAvailable (ctrl->def->numatune) && > >+ virNumaSetupMemoryPolicy(ctrl->def->numatune, nodemask) < 0)) > > goto cleanup; > > > > This would mean it will succeed if the numa node is not available on > the host. Don't you want to error out? By the way, it would make > sense to make the check in virNumaSetupMemoryPolicy() itself. Oh, you are right. As for output because virNumaNodesetIsAvailable is self error output. so I think it not necessary. I think the check !virNumaNodesetIsAvailable (ctrl->def->numatune) || virNumaSetupMemoryPolicy(ctrl->def->numatune, nodemask) < 0 would be OK. Thanks, Chen > > Martin -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2 2/3] lxc controller: add check for numatune
Signed-off-by: Chen Fan --- src/lxc/lxc_controller.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 1861dd6..1ee89ab 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -689,7 +689,8 @@ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) int ret = -1; if (virLXCControllerGetNumadAdvice(ctrl, &nodemask) < 0 || -virNumaSetupMemoryPolicy(ctrl->def->numatune, nodemask) < 0) +(virNumaNodesetIsAvailable (ctrl->def->numatune) && + virNumaSetupMemoryPolicy(ctrl->def->numatune, nodemask) < 0)) goto cleanup; if (virLXCControllerSetupCpuAffinity(ctrl) < 0) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2 0/3] add nodeset check in numatune
when setting elements memnode and nodeset in attribute numatune more than the host nodes in XML file, VM boot should fail. so add check for that. Chen Fan (3): numatune: add check for numatune nodeset range lxc controller: add check for numatune virnuma: remove redundant check for numanode src/conf/numatune_conf.c | 21 --- src/conf/numatune_conf.h | 19 ++ src/libvirt_private.syms | 1 + src/lxc/lxc_controller.c | 3 +- src/qemu/qemu_command.c| 3 + src/qemu/qemu_command.h| 1 + src/util/virnuma.c | 70 +- src/util/virnuma.h | 2 + ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 +++ tests/qemuxml2argvmock.c | 9 +++ tests/qemuxml2argvtest.c | 1 + 11 files changed, 128 insertions(+), 37 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2 1/3] numatune: add check for numatune nodeset range
For memnode in numatune element, the range of attribute 'nodeset' was not validated. on my host maxnodes was 1, but when setting nodeset to '0-2' or more, guest also started succuss. there probably was qemu's bug too. Signed-off-by: Chen Fan --- src/conf/numatune_conf.c | 21 - src/conf/numatune_conf.h | 19 src/libvirt_private.syms | 1 + src/qemu/qemu_command.c| 3 ++ src/qemu/qemu_command.h| 1 + src/util/virnuma.c | 55 ++ src/util/virnuma.h | 2 + ...rgv-numatune-static-nodeset-exceed-hostnode.xml | 35 ++ tests/qemuxml2argvmock.c | 9 tests/qemuxml2argvtest.c | 1 + 10 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-numatune-static-nodeset-exceed-hostnode.xml diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c index 21d9a64..d440b86 100644 --- a/src/conf/numatune_conf.c +++ b/src/conf/numatune_conf.c @@ -42,27 +42,6 @@ VIR_ENUM_IMPL(virDomainNumatunePlacement, "static", "auto"); -typedef struct _virDomainNumatuneNode virDomainNumatuneNode; -typedef virDomainNumatuneNode *virDomainNumatuneNodePtr; - -struct _virDomainNumatune { -struct { -bool specified; -virBitmapPtr nodeset; -virDomainNumatuneMemMode mode; -virDomainNumatunePlacement placement; -} memory; /* pinning for all the memory */ - -struct _virDomainNumatuneNode { -virBitmapPtr nodeset; -virDomainNumatuneMemMode mode; -} *mem_nodes; /* fine tuning per guest node */ -size_t nmem_nodes; - -/* Future NUMA tuning related stuff should go here. */ -}; - - static inline bool virDomainNumatuneNodeSpecified(virDomainNumatunePtr numatune, int cellid) diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h index 5254629..650b6e7 100644 --- a/src/conf/numatune_conf.h +++ b/src/conf/numatune_conf.h @@ -45,6 +45,25 @@ typedef enum { VIR_ENUM_DECL(virDomainNumatunePlacement) VIR_ENUM_DECL(virDomainNumatuneMemMode) +typedef struct _virDomainNumatuneNode virDomainNumatuneNode; +typedef virDomainNumatuneNode *virDomainNumatuneNodePtr; + +struct _virDomainNumatune { +struct { +bool specified; +virBitmapPtr nodeset; +virDomainNumatuneMemMode mode; +virDomainNumatunePlacement placement; +} memory; /* pinning for all the memory */ + +struct _virDomainNumatuneNode { +virBitmapPtr nodeset; +virDomainNumatuneMemMode mode; +} *mem_nodes; /* fine tuning per guest node */ +size_t nmem_nodes; + +/* Future NUMA tuning related stuff should go here. */ +}; void virDomainNumatuneFree(virDomainNumatunePtr numatune); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d63a8f0..16a5864 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1728,6 +1728,7 @@ virNumaGetPageInfo; virNumaGetPages; virNumaIsAvailable; virNumaNodeIsAvailable; +virNumaNodesetIsAvailable; virNumaSetPagePoolSize; virNumaSetupMemoryPolicy; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2e5af4f..9757d3e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6663,6 +6663,9 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg, goto cleanup; } +if (!virNumaNodesetIsAvailable(def->numatune)) +goto cleanup; + for (i = 0; i < def->mem.nhugepages; i++) { ssize_t next_bit, pos = 0; diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index aa40c9e..f263665 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -27,6 +27,7 @@ # include "domain_addr.h" # include "domain_conf.h" # include "vircommand.h" +# include "virnuma.h" # include "capabilities.h" # include "qemu_conf.h" # include "qemu_domain.h" diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 690615f..411719d 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -312,6 +312,55 @@ virNumaGetNodeCPUs(int node, return ret; } + +bool +virNumaNodesetIsAvailable(virDomainNumatunePtr numatune) +{ +int maxnode; +int bit = -1; +size_t i; +virBitmapPtr nodemask = NULL; + +if (!numatune) +return true; + +if ((maxnode = virNumaGetMaxNode()) < 0) +return false; + +maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; + +/* verify and element in */ +nodemask = virDomainNumatuneGetNodeset(numatune, NULL, -1); +if (nodemask)
[libvirt] [PATCH v2 3/3] virnuma: remove redundant check for numanode
Signed-off-by: Chen Fan --- src/util/virnuma.c | 15 --- 1 file changed, 15 deletions(-) diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 411719d..8431b3c 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -95,31 +95,16 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, int ret = -1; int bit = 0; size_t i; -int maxnode = 0; virBitmapPtr tmp_nodemask = NULL; tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask, -1); if (!tmp_nodemask) return 0; -if (numa_available() < 0) { -virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Host kernel is not aware of NUMA.")); -return -1; -} - -maxnode = numa_max_node(); -maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; - /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); bit = -1; while ((bit = virBitmapNextSetBit(tmp_nodemask, bit)) >= 0) { -if (bit > maxnode) { -virReportError(VIR_ERR_INTERNAL_ERROR, - _("NUMA node %d is out of range"), bit); -return -1; -} nodemask_set(&mask, bit); } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] conf: fix an memory leak in virSocketAddrIsNumericLocalhost()
Signed-off-by: Chen Fan --- src/util/virsocketaddr.c | 15 ++- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 8c9f05f..5f54e68 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -894,19 +894,24 @@ virSocketAddrIsNumericLocalhost(const char *addr) struct in_addr tmp = { .s_addr = htonl(INADDR_LOOPBACK) }; struct sockaddr_in *inet4; struct sockaddr_in6 *inet6; +bool ret = false; if (virSocketAddrParseInternal(&res, addr, AF_UNSPEC, false) < 0) -return false; +return ret; switch (res->ai_addr->sa_family) { case AF_INET: inet4 = (struct sockaddr_in*) res->ai_addr; -return memcmp(&inet4->sin_addr.s_addr, &tmp.s_addr, - sizeof(inet4->sin_addr.s_addr)) == 0; +ret = memcmp(&inet4->sin_addr.s_addr, &tmp.s_addr, + sizeof(inet4->sin_addr.s_addr)) == 0; +break; case AF_INET6: inet6 = (struct sockaddr_in6*) res->ai_addr; -return IN6_IS_ADDR_LOOPBACK(&(inet6->sin6_addr)); +ret = IN6_IS_ADDR_LOOPBACK(&(inet6->sin6_addr)); +break; } -return false; + +freeaddrinfo(res); +return ret; } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v3 2/3] conf: add check if migration_host is a localhost address
On Wed, 2014-10-15 at 04:46 -0400, John Ferlan wrote: > This patch has triggered a Coverity RESOURCE_LEAK (3 actually) Right, I will make a patch to fix it. Thank you for catching that. > > On 10/08/2014 09:54 PM, Chen, Fan wrote: > > On Wed, 2014-10-08 at 12:33 +0200, Ján Tomko wrote: > >> On 10/07/2014 06:07 AM, Chen Fan wrote: > >>> Signed-off-by: Chen Fan > >> diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c > >> index 6d36689..a19e3af 100644 > >> --- a/src/util/virsocketaddr.c > >> +++ b/src/util/virsocketaddr.c > >> @@ -889,15 +889,24 @@ virSocketAddrNumericFamily(const char *address) > >> * false otherwise > >> */ > >> bool > >> -virSocketAddrIsNumericLocalhost(const virSocketAddr *addr) > >> +virSocketAddrIsNumericLocalhost(const char *addr) > >> { > >> +struct addrinfo *res; > >> struct in_addr tmp = { .s_addr = htonl(INADDR_LOOPBACK) }; > >> -switch (addr->data.stor.ss_family) { > >> +struct sockaddr_in *inet4; > >> +struct sockaddr_in6 *inet6; > >> + > >> +if (virSocketAddrParseInternal(&res, addr, AF_UNSPEC, false) < 0) > >> +return false; > >> + > > 'res' allocates something that must be free'd > > > >> +switch (res->ai_addr->sa_family) { > >> case AF_INET: > >> -return memcmp(&addr->data.inet4.sin_addr.s_addr, &tmp.s_addr, > >> - sizeof(addr->data.inet4.sin_addr.s_addr)) == 0; > >> +inet4 = (struct sockaddr_in*) res->ai_addr; > > Leak #1 > > >> +return memcmp(&inet4->sin_addr.s_addr, &tmp.s_addr, > >> + sizeof(inet4->sin_addr.s_addr)) == 0; > >> case AF_INET6: > >> -return IN6_IS_ADDR_LOOPBACK(&addr->data.inet6.sin6_addr); > >> +inet6 = (struct sockaddr_in6*) res->ai_addr; > > Leak #2 > > >> +return IN6_IS_ADDR_LOOPBACK(&(inet6->sin6_addr)); > >> } > > Leak #3 > >> return false; > >> > > Other callers will call 'freeaddrinfo(res);' > > In order to resolve - you probably need to create a local ret = false, > then assign ret = to either memcmp/IN6_IS_ADDR_LOOPBACK return, then > call freeaddrinfo() before return ret > > John -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] conf: fix a wrong comment in virSocketAddrNumericFamily()
Signed-off-by: Chen Fan --- src/util/virsocketaddr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index a19e3af..8c9f05f 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -859,8 +859,7 @@ virSocketAddrGetIpPrefix(const virSocketAddr *address, * virSocketAddrNumericFamily: * @address: address to check * - * Check if passed address is an IP address in numeric format. and - * return the address family, otherwise return 0. + * Check if passed address is an IP address in numeric format. * * Returns: AF_INET or AF_INET6 if @address is an numeric IP address, * -1 otherwise. -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] conf: fix a wrong comment in virSocketAddrNumericFamily()
Signed-off-by: Chen Fan --- src/util/virsocketaddr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index a19e3af..8c9f05f 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -859,8 +859,7 @@ virSocketAddrGetIpPrefix(const virSocketAddr *address, * virSocketAddrNumericFamily: * @address: address to check * - * Check if passed address is an IP address in numeric format. and - * return the address family, otherwise return 0. + * Check if passed address is an IP address in numeric format. * * Returns: AF_INET or AF_INET6 if @address is an numeric IP address, * -1 otherwise. -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 0/3] lxc: Implement emulator pin APIs to set/get cpuset
On Fri, 2014-10-10 at 13:58 +0800, Wang Rui wrote: > Ping? I found some wrong indentation in the 3 patches. like following in patch 1/3: +static int virLXCCgroupSetupCpusetTuneForEmulator(virDomainDefPtr def, + virCgroupPtr cgroup, + virBitmapPtr nodemask) Thanks, Chen > > On 2014/9/4 15:52, Wang Rui wrote: > > We can specify cpuset for a container defined with the xml > > like to achieve cpu > > isolation. It works when container is started. But there > > is no implements we can use to either change or get cpuset. > > > > The following patches implement the lxc driver methods for > > virDomainPinEmulator and virDomainGetEmulatorPinInfo. Also > > support container startup with emulator affinity info in xml. > > > > After these patches, we can set and get libvirt_lxc cpuset. > > > > Yue Wenyuan (3): > > lxc: Implement pin emulator for container startup > > lxc: Implement emulator pin API in lxc driver > > lxc: Implement geting emulator pin info API in lxc driver > > > > src/lxc/lxc_cgroup.c | 88 > > src/lxc/lxc_cgroup.h | 7 ++ > > src/lxc/lxc_controller.c | 4 + > > src/lxc/lxc_driver.c | 206 > > +++ > > 4 files changed, 305 insertions(+) > > > > > -- > libvir-list mailing list > libvir-list@redhat.com > https://www.redhat.com/mailman/listinfo/libvir-list -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v3 0/3] Check migration configuration
On Thu, 2014-10-09 at 14:54 +0200, Ján Tomko wrote: > On 10/07/2014 06:07 AM, Chen Fan wrote: > > add some check in migration configuration. > > > > Chen Fan (3): > > migration: add migration_host support for Ipv6 address without > > brackets > > conf: add check if migration_host is a localhost address > > conf: Check migration_address whether is localhost > > > > src/libvirt_private.syms | 3 +- > > src/qemu/qemu.conf | 2 +- > > src/qemu/qemu_conf.c | 58 > > ++ > > src/qemu/qemu_conf.h | 2 ++ > > src/qemu/qemu_migration.c | 49 > > src/qemu/test_libvirtd_qemu.aug.in | 2 +- > > src/util/virsocketaddr.c | 43 +--- > > src/util/virsocketaddr.h | 4 ++- > > tests/sockettest.c | 2 +- > > 9 files changed, 125 insertions(+), 40 deletions(-) > > > > Now pushed. Thanks, Chen > > Jan > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v3 2/3] conf: add check if migration_host is a localhost address
On Wed, 2014-10-08 at 12:33 +0200, Ján Tomko wrote: > On 10/07/2014 06:07 AM, Chen Fan wrote: > > Signed-off-by: Chen Fan > > --- > > src/libvirt_private.syms | 1 + > > src/qemu/qemu_conf.c | 50 > > > > src/qemu/qemu_conf.h | 2 ++ > > src/util/virsocketaddr.c | 24 +++ > > src/util/virsocketaddr.h | 2 ++ > > 5 files changed, 79 insertions(+) > > > > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > > index 8ab1394..a104bc6 100644 > > --- a/src/libvirt_private.syms > > +++ b/src/libvirt_private.syms > > @@ -1911,6 +1911,7 @@ virSocketAddrGetIpPrefix; > > virSocketAddrGetPort; > > virSocketAddrGetRange; > > virSocketAddrIsNetmask; > > +virSocketAddrIsNumericLocalhost; > > virSocketAddrIsPrivate; > > virSocketAddrIsWildcard; > > virSocketAddrMask; > > diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c > > index adc6caf..6b0ac5c 100644 > > --- a/src/qemu/qemu_conf.c > > +++ b/src/qemu/qemu_conf.c > > @@ -707,6 +707,15 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr > > cfg, > > GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox); > > > > GET_VALUE_STR("migration_host", cfg->migrateHost); > > +if (cfg->migrateHost && > > +qemuCheckLocalhost(cfg->migrateHost)) { > > +virReportError(VIR_ERR_CONF_SYNTAX, > > + _("migration_host must not be the address of" > > + " the local machine: %s"), > > + cfg->migrateHost); > > +goto cleanup; > > +} > > + > > GET_VALUE_STR("migration_address", cfg->migrationAddress); > > > > GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); > > @@ -1371,3 +1380,44 @@ qemuGetDefaultHugepath(virHugeTLBFSPtr hugetlbfs, > > > > return qemuGetHugepagePath(&hugetlbfs[i]); > > } > > + > > +bool > > +qemuCheckLocalhost(const char *addrStr) > > +{ > > +virSocketAddr addr; > > +char *hostname, *tmp; > > +bool encloseAddress = false; > > +int family; > > +bool ret = true; > > + > > +if (VIR_STRDUP(hostname, addrStr) < 0) > > +return false; > > + > > +tmp = hostname; > > + > > +if (STRPREFIX(hostname, "[")) { > > +char *end = strchr(hostname, ']'); > > +if (end) { > > +*end = '\0'; > > +hostname++; > > +encloseAddress = true; > > +} > > +} > > We don't format the qemu.conf back and we don't need the brackets for > anything. We can just store the migration host without them in > cfg->migrationHost > > > + > > +if (STRPREFIX(hostname, "localhost")) > > +goto cleanup; > > + > > +family = virSocketAddrNumericFamily(hostname); > > +if ((family == AF_INET && !encloseAddress) || > > +family == AF_INET6) { > > +if (virSocketAddrParse(&addr, hostname, family) > 0 && > > +virSocketAddrIsNumericLocalhost(&addr)) { > > +goto cleanup; > > +} > > +} > > There's no need to check for family upfront. > > > + > > +ret = false; > > +cleanup: > > +VIR_FREE(tmp); > > +return ret; > > +} > > diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h > > index cb01fb6..c9ce53c 100644 > > --- a/src/qemu/qemu_conf.h > > +++ b/src/qemu/qemu_conf.h > > @@ -322,4 +322,6 @@ int qemuTranslateSnapshotDiskSourcePool(virConnectPtr > > conn, > > char * qemuGetHugepagePath(virHugeTLBFSPtr hugepage); > > char * qemuGetDefaultHugepath(virHugeTLBFSPtr hugetlbfs, > >size_t nhugetlbfs); > > + > > +bool qemuCheckLocalhost(const char *addrStr); > > #endif /* __QEMUD_CONF_H */ > > diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c > > index 7fe7a15..6d36689 100644 > > --- a/src/util/virsocketaddr.c > > +++ b/src/util/virsocketaddr.c > > @@ -878,3 +878,27 @@ virSocketAddrNumericFamily(const char *address) > > freeaddrinfo(res); > > return family; > > } > > + > > +/** > > + * virSocketAddrIsNumericLocalhost: > > + * @address: address to check > > + * > >
Re: [libvirt] [PATCH v3 1/3] migration: add migration_host support for Ipv6 address without brackets
On Tue, 2014-10-07 at 11:08 +0200, Ján Tomko wrote: > On 10/07/2014 06:07 AM, Chen Fan wrote: > > if specifying migration_host to an Ipv6 address without brackets, > > it was resolved to an incorrect address, such as: > > tcp:2001:0DB8::1428:, > > but the correct address should be: > > tcp:[2001:0DB8::1428]: > > so we should add brackets when parsing it. > > > > Signed-off-by: Chen Fan > > --- > > src/libvirt_private.syms | 2 +- > > src/qemu/qemu_migration.c | 49 > > +++ > > src/util/virsocketaddr.c | 19 +- > > src/util/virsocketaddr.h | 2 +- > > tests/sockettest.c| 2 +- > > 5 files changed, 36 insertions(+), 38 deletions(-) > > ACK Thanks. > > Jan > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v2 3/4] conf: add virSocketAddrIsLocalhost to Check migration_host
On Fri, 2014-10-03 at 15:58 +0200, Ján Tomko wrote: > On 09/23/2014 06:04 AM, Chen Fan wrote: > > Signed-off-by: Chen Fan > > --- > > src/libvirt_private.syms | 1 + > > src/qemu/qemu_conf.c | 8 > > src/util/virsocketaddr.c | 35 +++ > > src/util/virsocketaddr.h | 3 +++ > > 4 files changed, 47 insertions(+) > > > > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > > index 51a692b..f7172b0 100644 > > --- a/src/libvirt_private.syms > > +++ b/src/libvirt_private.syms > > @@ -1885,6 +1885,7 @@ virSocketAddrGetPort; > > virSocketAddrGetRange; > > virSocketAddrIsNetmask; > > virSocketAddrIsNumeric; > > +virSocketAddrIsLocalhost; > > virSocketAddrIsPrivate; > > virSocketAddrIsWildcard; > > virSocketAddrMask; > > diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c > > index adc6caf..30169cf 100644 > > --- a/src/qemu/qemu_conf.c > > +++ b/src/qemu/qemu_conf.c > > @@ -707,6 +707,14 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr > > cfg, > > GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox); > > > > GET_VALUE_STR("migration_host", cfg->migrateHost); > > +if (cfg->migrateHost && > > +virSocketAddrIsLocalhost(cfg->migrateHost)) { > > +virReportError(VIR_ERR_CONF_SYNTAX, > > + _("migration_host must not be 'localhost' address: > > %s"), > > + cfg->migrateHost); > > +goto cleanup; > > +} > > + > > GET_VALUE_STR("migration_address", cfg->migrationAddress); > > > > GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); > > diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c > > index 64409a6..dfcaf72 100644 > > --- a/src/util/virsocketaddr.c > > +++ b/src/util/virsocketaddr.c > > @@ -884,3 +884,38 @@ virSocketAddrIsNumeric(const char *address, int > > *family) > > } > > return sa_family == AF_INET || sa_family == AF_INET6; > > } > > + > > +/** > > + * virSocketAddrIsLocalhost: > > + * @address: address to check > > + * > > + * Check if passed address is a 'localhost' address. > > + * > > + * Returns: true if @address is 'localhost' address, > > + * false otherwise > > + */ > > +bool > > +virSocketAddrIsLocalhost(const char *address) > > I think this function should be named 'IsNumericLocalhost' and only check for > the numeric representation of localhost. If the address is numeric, we can > parse it and catch all the cases (like 127.0.0.1, 2130706433, 0177.0.0.1, > 0:0:0::1). But we can't check if a hostname points to localhost without > resolving it. > > > +{ > > + int family; > > + > > + if (virSocketAddrIsNumeric(address, &family)) { > > + if (family == AF_INET) { > > + if (STREQ(address, "127.0.0.1")) > > + return true; > > + } > > + > > This should do what virSocketAddrIsWildcard does, only using > INADDR_LOOPBACK instead of INADDR_ANY > and IN6_IS_ADDR_LOOPBACK instead of IN6_IS_ADDR_UNSPECIFIED. > > > + if (family == AF_INET6) { > > + if (STREQ(address, "::1")) > > + return true; > > + } > > + } else { > > + if (STRPREFIX(address, "localhost")) > > + return true; > > I'd put this check in qemu_conf.c. > > > + > > + if (STREQ(address, "[::1]")) > > + return true; > > And strip the brackets before calling virSocketAddrParse. I had sent V3 patch that including the above solution. please help to review it. Thanks, Chen > > Jan > > > + } > > + > > + return false; > > +} > > diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h > > index 7b11afb..5269f35 100644 > > --- a/src/util/virsocketaddr.h > > +++ b/src/util/virsocketaddr.h > > @@ -126,4 +126,7 @@ bool virSocketAddrIsPrivate(const virSocketAddr *addr); > > bool virSocketAddrIsWildcard(const virSocketAddr *addr); > > > > bool virSocketAddrIsNumeric(const char *address, int *family); > > + > > +bool virSocketAddrIsLocalhost(const char *address); > > + > > #endif /* __VIR_SOCKETADDR_H__ */ > > > > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v3 0/3] Check migration configuration
add some check in migration configuration. Chen Fan (3): migration: add migration_host support for Ipv6 address without brackets conf: add check if migration_host is a localhost address conf: Check migration_address whether is localhost src/libvirt_private.syms | 3 +- src/qemu/qemu.conf | 2 +- src/qemu/qemu_conf.c | 58 ++ src/qemu/qemu_conf.h | 2 ++ src/qemu/qemu_migration.c | 49 src/qemu/test_libvirtd_qemu.aug.in | 2 +- src/util/virsocketaddr.c | 43 +--- src/util/virsocketaddr.h | 4 ++- tests/sockettest.c | 2 +- 9 files changed, 125 insertions(+), 40 deletions(-) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v3 3/3] conf: Check migration_address whether is localhost
When enabling the migration_address option, by default it is set to "127.0.0.1", but it's not a valid address for migration. so we should add verification and set the default migration_address to "0.0.0.0". Signed-off-by: Chen Fan --- src/qemu/qemu.conf | 2 +- src/qemu/qemu_conf.c | 8 src/qemu/test_libvirtd_qemu.aug.in | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 92ca715..c6db568 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -467,7 +467,7 @@ # Override the listen address for all incoming migrations. Defaults to # 0.0.0.0, or :: if both host and qemu are capable of IPv6. -#migration_address = "127.0.0.1" +#migration_address = "0.0.0.0" # The default hostname or IP address which will be used by a migration diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 6b0ac5c..f34fa06 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -717,6 +717,14 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, } GET_VALUE_STR("migration_address", cfg->migrationAddress); +if (cfg->migrationAddress && +qemuCheckLocalhost(cfg->migrationAddress)) { +virReportError(VIR_ERR_CONF_SYNTAX, + _("migration_address must not be the address of" + " the local machine: %s"), + cfg->migrationAddress); +goto cleanup; +} GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index d2bc2c0..30fd27e 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -69,7 +69,7 @@ module Test_libvirtd_qemu = { "keepalive_interval" = "5" } { "keepalive_count" = "5" } { "seccomp_sandbox" = "1" } -{ "migration_address" = "127.0.0.1" } +{ "migration_address" = "0.0.0.0" } { "migration_host" = "host.example.com" } { "migration_port_min" = "49152" } { "migration_port_max" = "49215" } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v3 1/3] migration: add migration_host support for Ipv6 address without brackets
if specifying migration_host to an Ipv6 address without brackets, it was resolved to an incorrect address, such as: tcp:2001:0DB8::1428:, but the correct address should be: tcp:[2001:0DB8::1428]: so we should add brackets when parsing it. Signed-off-by: Chen Fan --- src/libvirt_private.syms | 2 +- src/qemu/qemu_migration.c | 49 +++ src/util/virsocketaddr.c | 19 +- src/util/virsocketaddr.h | 2 +- tests/sockettest.c| 2 +- 5 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7cbc35b..8ab1394 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1911,11 +1911,11 @@ virSocketAddrGetIpPrefix; virSocketAddrGetPort; virSocketAddrGetRange; virSocketAddrIsNetmask; -virSocketAddrIsNumeric; virSocketAddrIsPrivate; virSocketAddrIsWildcard; virSocketAddrMask; virSocketAddrMaskByPrefix; +virSocketAddrNumericFamily; virSocketAddrParse; virSocketAddrParseIPv4; virSocketAddrParseIPv6; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 284cd5a..e135249 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2605,7 +2605,6 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, if (VIR_STRDUP(migrateFrom, "stdio") < 0) goto cleanup; } else { -virSocketAddr listenAddressSocket; bool encloseAddress = false; bool hostIPv6Capable = false; bool qemuIPv6Capable = false; @@ -2627,28 +2626,21 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, virObjectUnref(qemuCaps); if (listenAddress) { -if (virSocketAddrIsNumeric(listenAddress)) { -/* listenAddress is numeric IPv4 or IPv6 */ -if (virSocketAddrParse(&listenAddressSocket, listenAddress, AF_UNSPEC) < 0) +if (virSocketAddrNumericFamily(listenAddress) == AF_INET6) { +if (!qemuIPv6Capable) { +virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("qemu isn't capable of IPv6")); goto cleanup; - -/* address parsed successfully */ -if (VIR_SOCKET_ADDR_IS_FAMILY(&listenAddressSocket, AF_INET6)) { -if (!qemuIPv6Capable) { -virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("qemu isn't capable of IPv6")); -goto cleanup; -} -if (!hostIPv6Capable) { -virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", - _("host isn't capable of IPv6")); -goto cleanup; -} -/* IPv6 address must be escaped in brackets on the cmd line */ -encloseAddress = true; } +if (!hostIPv6Capable) { +virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("host isn't capable of IPv6")); +goto cleanup; +} +/* IPv6 address must be escaped in brackets on the cmd line */ +encloseAddress = true; } else { -/* listenAddress is a hostname */ +/* listenAddress is a hostname or IPv4 */ } } else if (qemuIPv6Capable && hostIPv6Capable) { /* Listen on :: instead of 0.0.0.0 if QEMU understands it @@ -2950,15 +2942,17 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, * to be a correct hostname which refers to the target machine). */ if (uri_in == NULL) { +bool encloseAddress = false; +const char *incFormat; + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) goto cleanup; if (migrateHost != NULL) { -if (virSocketAddrIsNumeric(migrateHost) && -virSocketAddrParse(NULL, migrateHost, AF_UNSPEC) < 0) -goto cleanup; +if (virSocketAddrNumericFamily(migrateHost) == AF_INET6) +encloseAddress = true; - if (VIR_STRDUP(hostname, migrateHost) < 0) +if (VIR_STRDUP(hostname, migrateHost) < 0) goto cleanup; } else { if ((hostname = virGetHostname()) == NULL) @@ -2977,7 +2971,12 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, * compatibility with old targets. We at least make the * new targets accept both syntaxes though. */ -if (virAsprintf(uri_out, "tcp:%s:%d", hostname, port) < 0) +if (enclose
[libvirt] [PATCH v3 2/3] conf: add check if migration_host is a localhost address
Signed-off-by: Chen Fan --- src/libvirt_private.syms | 1 + src/qemu/qemu_conf.c | 50 src/qemu/qemu_conf.h | 2 ++ src/util/virsocketaddr.c | 24 +++ src/util/virsocketaddr.h | 2 ++ 5 files changed, 79 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8ab1394..a104bc6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1911,6 +1911,7 @@ virSocketAddrGetIpPrefix; virSocketAddrGetPort; virSocketAddrGetRange; virSocketAddrIsNetmask; +virSocketAddrIsNumericLocalhost; virSocketAddrIsPrivate; virSocketAddrIsWildcard; virSocketAddrMask; diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index adc6caf..6b0ac5c 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -707,6 +707,15 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox); GET_VALUE_STR("migration_host", cfg->migrateHost); +if (cfg->migrateHost && +qemuCheckLocalhost(cfg->migrateHost)) { +virReportError(VIR_ERR_CONF_SYNTAX, + _("migration_host must not be the address of" + " the local machine: %s"), + cfg->migrateHost); +goto cleanup; +} + GET_VALUE_STR("migration_address", cfg->migrationAddress); GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); @@ -1371,3 +1380,44 @@ qemuGetDefaultHugepath(virHugeTLBFSPtr hugetlbfs, return qemuGetHugepagePath(&hugetlbfs[i]); } + +bool +qemuCheckLocalhost(const char *addrStr) +{ +virSocketAddr addr; +char *hostname, *tmp; +bool encloseAddress = false; +int family; +bool ret = true; + +if (VIR_STRDUP(hostname, addrStr) < 0) +return false; + +tmp = hostname; + +if (STRPREFIX(hostname, "[")) { +char *end = strchr(hostname, ']'); +if (end) { +*end = '\0'; +hostname++; +encloseAddress = true; +} +} + +if (STRPREFIX(hostname, "localhost")) +goto cleanup; + +family = virSocketAddrNumericFamily(hostname); +if ((family == AF_INET && !encloseAddress) || +family == AF_INET6) { +if (virSocketAddrParse(&addr, hostname, family) > 0 && +virSocketAddrIsNumericLocalhost(&addr)) { +goto cleanup; +} +} + +ret = false; +cleanup: +VIR_FREE(tmp); +return ret; +} diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index cb01fb6..c9ce53c 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -322,4 +322,6 @@ int qemuTranslateSnapshotDiskSourcePool(virConnectPtr conn, char * qemuGetHugepagePath(virHugeTLBFSPtr hugepage); char * qemuGetDefaultHugepath(virHugeTLBFSPtr hugetlbfs, size_t nhugetlbfs); + +bool qemuCheckLocalhost(const char *addrStr); #endif /* __QEMUD_CONF_H */ diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 7fe7a15..6d36689 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -878,3 +878,27 @@ virSocketAddrNumericFamily(const char *address) freeaddrinfo(res); return family; } + +/** + * virSocketAddrIsNumericLocalhost: + * @address: address to check + * + * Check if passed address is a numeric 'localhost' address. + * + * Returns: true if @address is a numeric 'localhost' address, + * false otherwise + */ +bool +virSocketAddrIsNumericLocalhost(const virSocketAddr *addr) +{ +struct in_addr tmp = { .s_addr = htonl(INADDR_LOOPBACK) }; +switch (addr->data.stor.ss_family) { +case AF_INET: +return memcmp(&addr->data.inet4.sin_addr.s_addr, &tmp.s_addr, + sizeof(addr->data.inet4.sin_addr.s_addr)) == 0; +case AF_INET6: +return IN6_IS_ADDR_LOOPBACK(&addr->data.inet6.sin6_addr); +} +return false; + +} diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 35c9c1a..fa9e98b 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -126,4 +126,6 @@ bool virSocketAddrIsPrivate(const virSocketAddr *addr); bool virSocketAddrIsWildcard(const virSocketAddr *addr); int virSocketAddrNumericFamily(const char *address); + +bool virSocketAddrIsNumericLocalhost(const virSocketAddr *addr); #endif /* __VIR_SOCKETADDR_H__ */ -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v2 2/4] migration: add migration_host support for Ipv6 address without brackets
On Fri, 2014-10-03 at 15:58 +0200, Ján Tomko wrote: > On 09/23/2014 06:04 AM, Chen Fan wrote: > > if specifying migration_host to an Ipv6 address without brackets, > > it was resolved to an incorrect address, such as: > > tcp:2001:0DB8::1428:, > > but the correct address should be: > > tcp:[2001:0DB8::1428]: > > so we should add brackets when parsing it. > > > > Signed-off-by: Chen Fan > > --- > > src/qemu/qemu_migration.c | 24 +--- > > 1 file changed, 13 insertions(+), 11 deletions(-) > > > > diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c > > index 155f5b9..016d131 100644 > > --- a/src/qemu/qemu_migration.c > > +++ b/src/qemu/qemu_migration.c > > @@ -2544,7 +2544,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, > > if (VIR_STRDUP(migrateFrom, "stdio") < 0) > > goto cleanup; > > } else { > > -virSocketAddr listenAddressSocket; > > +int listenAddressFamily; > > bool encloseAddress = false; > > bool hostIPv6Capable = false; > > bool qemuIPv6Capable = false; > > @@ -2565,13 +2565,9 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, > > virObjectUnref(qemuCaps); > > > > if (listenAddress) { > > -if (virSocketAddrIsNumeric(listenAddress, NULL)) { > > +if (virSocketAddrIsNumeric(listenAddress, > > &listenAddressFamily)) { > > Both uses of this function are in this patch (I didn't realize that when > reviewing v1). > > We can rename it to virSocketAddrNumericFamily and do > if (virSocketAddrNumericFamily(listenAddress) == AF_INET6), removing the need > for a temporary variable. Right, Agreed. > > > /* listenAddress is numeric IPv4 or IPv6 */ > > -if (virSocketAddrParse(&listenAddressSocket, > > listenAddress, AF_UNSPEC) < 0) > > -goto cleanup; > > - > > -/* address parsed successfully */ > > -if (VIR_SOCKET_ADDR_IS_FAMILY(&listenAddressSocket, > > AF_INET6)) { > > +if (listenAddressFamily == AF_INET6) { > > if (!qemuIPv6Capable) { > > virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", > > _("qemu isn't capable of IPv6")); > > @@ -2850,11 +2846,17 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, > > goto cleanup; > > > > if (migrateHost != NULL) { > > -if (virSocketAddrIsNumeric(migrateHost, NULL) && > > -virSocketAddrParse(NULL, migrateHost, AF_UNSPEC) < 0) > > -goto cleanup; > > +int family; > > +bool migrateHostisIpv6Address = false; > > + > > +if (virSocketAddrIsNumeric(migrateHost, &family) && > > +(family == AF_INET6)) > > +migrateHostisIpv6Address = true; > > > > - if (VIR_STRDUP(hostname, migrateHost) < 0) > > +if ((migrateHostisIpv6Address && > > + virAsprintf(&hostname, "[%s]", migrateHost) < 0) || > > +(!migrateHostisIpv6Address && > > + virAsprintf(&hostname, "%s", migrateHost) < 0)) > > goto cleanup; > > In qemuMigrationPrepareAny, we have: > if (encloseAddress) > incFormat = "%s:[%s]:%d"; > else > incFormat = "%s:%s:%d"; > if (virAsprintf(&migrateFrom, incFormat, > protocol, listenAddress, port) < 0) > goto cleanup; > > Using the same pattern here as well would make it more readable. > Thanks, Chen > Jan > > > } else { > > if ((hostname = virGetHostname()) == NULL) > > > > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v2 0/4] Check migration configuration
any feedback? Thanks, Chen On Thu, 2014-09-25 at 01:10 +, Chen, Fan wrote: > ping? > > > On Tue, 2014-09-23 at 12:04 +0800, Chen Fan wrote: > > add some check in migration configuration. > > > > Chen Fan (4): > > virsocketaddr: return address family in virSocketAddrIsNumeric > > migration: add migration_host support for Ipv6 address without > > brackets > > conf: add virSocketAddrIsLocalhost to Check migration_host > > conf: Check migration_address whether is localhost > > > > src/libvirt_private.syms | 1 + > > src/qemu/qemu.conf | 2 +- > > src/qemu/qemu_conf.c | 15 > > src/qemu/qemu_migration.c | 24 ++- > > src/qemu/test_libvirtd_qemu.aug.in | 2 +- > > src/util/virsocketaddr.c | 48 > > ++ > > src/util/virsocketaddr.h | 5 +++- > > tests/sockettest.c | 2 +- > > 8 files changed, 80 insertions(+), 19 deletions(-) > > > > > -- > libvir-list mailing list > libvir-list@redhat.com > https://www.redhat.com/mailman/listinfo/libvir-list -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v2 0/4] Check migration configuration
ping? On Tue, 2014-09-23 at 12:04 +0800, Chen Fan wrote: > add some check in migration configuration. > > Chen Fan (4): > virsocketaddr: return address family in virSocketAddrIsNumeric > migration: add migration_host support for Ipv6 address without > brackets > conf: add virSocketAddrIsLocalhost to Check migration_host > conf: Check migration_address whether is localhost > > src/libvirt_private.syms | 1 + > src/qemu/qemu.conf | 2 +- > src/qemu/qemu_conf.c | 15 > src/qemu/qemu_migration.c | 24 ++- > src/qemu/test_libvirtd_qemu.aug.in | 2 +- > src/util/virsocketaddr.c | 48 > ++ > src/util/virsocketaddr.h | 5 +++- > tests/sockettest.c | 2 +- > 8 files changed, 80 insertions(+), 19 deletions(-) > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 2/2] numatune: move up verification codes in virNumaSetupMemoryPolicy
On Tue, 2014-09-23 at 14:42 +0200, Michal Privoznik wrote: > On 23.09.2014 11:34, Chen Fan wrote: > > use virDomainNumatuneNodeSetIsAvailable() to verify momory.nodeset > > whether is out of range. and move up the verification. > > > > Signed-off-by: Chen Fan > > --- > > src/conf/numatune_conf.c | 3 +++ > > src/util/virnuma.c | 15 --- > > 2 files changed, 3 insertions(+), 15 deletions(-) > > I'd expect a test case for this. Ok, I will add it. thanks, Chen > > > > > diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c > > index a9b20aa..8b43167 100644 > > --- a/src/conf/numatune_conf.c > > +++ b/src/conf/numatune_conf.c > > @@ -278,6 +278,9 @@ virDomainNumatuneParseXML(virDomainNumatunePtr > > *numatunePtr, > >nodeset) < 0) > > goto cleanup; > > > > +if (!virDomainNumatuneNodeSetIsAvailable(*numatunePtr, -1)) > > +goto cleanup; > > + > > if (virDomainNumatuneNodeParseXML(numatunePtr, ncells, ctxt) < 0) > > goto cleanup; > > > > diff --git a/src/util/virnuma.c b/src/util/virnuma.c > > index 1a34398..4766f16 100644 > > --- a/src/util/virnuma.c > > +++ b/src/util/virnuma.c > > @@ -95,31 +95,16 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, > > int ret = -1; > > int bit = 0; > > size_t i; > > -int maxnode = 0; > > virBitmapPtr tmp_nodemask = NULL; > > > > tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask, -1); > > if (!tmp_nodemask) > > return 0; > > > > -if (numa_available() < 0) { > > -virReportError(VIR_ERR_INTERNAL_ERROR, > > - "%s", _("Host kernel is not aware of NUMA.")); > > -return -1; > > -} > > - > > -maxnode = numa_max_node(); > > -maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; > > - > > /* Convert nodemask to NUMA bitmask. */ > > nodemask_zero(&mask); > > bit = -1; > > while ((bit = virBitmapNextSetBit(tmp_nodemask, bit)) >= 0) { > > -if (bit > maxnode) { > > -virReportError(VIR_ERR_INTERNAL_ERROR, > > - _("NUMA node %d is out of range"), bit); > > -return -1; > > -} > > nodemask_set(&mask, bit); > > } > > > > > > Yet again, this suffers the same problem that 1/2 does: domain may be lost. > > Michal -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 1/2] numatune: add check for memnode.nodeset range
On Tue, 2014-09-23 at 14:41 +0200, Michal Privoznik wrote: > On 23.09.2014 11:34, Chen Fan wrote: > > For memnode in numatune element, the range of attribute 'nodeset' > > was not validated. on my host maxnodes was 1, but when setting nodeset > > to '0-2' or more, guest also started succuss. there probably was qemu's > > bug too. > > > > Signed-off-by: Chen Fan > > --- > > src/conf/numatune_conf.c | 29 + > > src/conf/numatune_conf.h | 4 > > 2 files changed, 33 insertions(+) > > > > diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c > > index 21d9a64..a9b20aa 100644 > > --- a/src/conf/numatune_conf.c > > +++ b/src/conf/numatune_conf.c > > @@ -183,6 +183,9 @@ virDomainNumatuneNodeParseXML(virDomainNumatunePtr > > *numatunePtr, > > VIR_DOMAIN_CPUMASK_LEN) < 0) > > goto cleanup; > > VIR_FREE(tmp); > > + > > +if (!virDomainNumatuneNodeSetIsAvailable(numatune, cellid)) > > +goto cleanup; > > Well, if there already exists such configuration within an existing > domain, this will cause a failure on XML parsing when the daemon is > starting and hence domain is lost. Right, I would move this check to VM start routine. > > > } > > > > ret = 0; > > @@ -612,3 +615,29 @@ > > virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune) > > > > return false; > > } > > + > > +bool > > +virDomainNumatuneNodeSetIsAvailable(virDomainNumatunePtr numatune, > > +int cellid) > > +{ > > +int maxnode; > > +int bit = -1; > > +virBitmapPtr nodemask = NULL; > > + > > +nodemask = virDomainNumatuneGetNodeset(numatune, NULL, cellid); > > +if (!nodemask) > > +return false; > > + > > +if ((maxnode = virNumaGetMaxNode()) < 0) > > +return false; > > This will work in real environment, but won't work in tests. You need to > mock this to get predictable max numa node. I will add test case for this. Thanks, Chen > > > + > > +while ((bit = virBitmapNextSetBit(nodemask, bit)) >= 0) { > > +if (bit > maxnode) { > > +virReportError(VIR_ERR_INTERNAL_ERROR, > > + _("NUMA node %d is out of range"), bit); > > +return false; > > +} > > +} > > + > > +return true; > > +} > > diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h > > index 5254629..cab0b83 100644 > > --- a/src/conf/numatune_conf.h > > +++ b/src/conf/numatune_conf.h > > @@ -102,4 +102,8 @@ bool > > virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune); > > > > bool virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune); > > > > +extern int virNumaGetMaxNode(void); > > +bool virDomainNumatuneNodeSetIsAvailable(virDomainNumatunePtr numatune, > > + int cellid); > > + > > #endif /* __NUMATUNE_CONF_H__ */ > > > > Michal -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 0/2] add nodeset check in numatune
for memnode.nodeset in numatune, when setting it more than the host nodes, it should fail. Chen Fan (2): numatune: add check for memnode.nodeset range numatune: move up verification codes in virNumaSetupMemoryPolicy src/conf/numatune_conf.c | 32 src/conf/numatune_conf.h | 4 src/util/virnuma.c | 15 --- 3 files changed, 36 insertions(+), 15 deletions(-) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 2/2] numatune: move up verification codes in virNumaSetupMemoryPolicy
use virDomainNumatuneNodeSetIsAvailable() to verify momory.nodeset whether is out of range. and move up the verification. Signed-off-by: Chen Fan --- src/conf/numatune_conf.c | 3 +++ src/util/virnuma.c | 15 --- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c index a9b20aa..8b43167 100644 --- a/src/conf/numatune_conf.c +++ b/src/conf/numatune_conf.c @@ -278,6 +278,9 @@ virDomainNumatuneParseXML(virDomainNumatunePtr *numatunePtr, nodeset) < 0) goto cleanup; +if (!virDomainNumatuneNodeSetIsAvailable(*numatunePtr, -1)) +goto cleanup; + if (virDomainNumatuneNodeParseXML(numatunePtr, ncells, ctxt) < 0) goto cleanup; diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 1a34398..4766f16 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -95,31 +95,16 @@ virNumaSetupMemoryPolicy(virDomainNumatunePtr numatune, int ret = -1; int bit = 0; size_t i; -int maxnode = 0; virBitmapPtr tmp_nodemask = NULL; tmp_nodemask = virDomainNumatuneGetNodeset(numatune, nodemask, -1); if (!tmp_nodemask) return 0; -if (numa_available() < 0) { -virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Host kernel is not aware of NUMA.")); -return -1; -} - -maxnode = numa_max_node(); -maxnode = maxnode < NUMA_NUM_NODES ? maxnode : NUMA_NUM_NODES; - /* Convert nodemask to NUMA bitmask. */ nodemask_zero(&mask); bit = -1; while ((bit = virBitmapNextSetBit(tmp_nodemask, bit)) >= 0) { -if (bit > maxnode) { -virReportError(VIR_ERR_INTERNAL_ERROR, - _("NUMA node %d is out of range"), bit); -return -1; -} nodemask_set(&mask, bit); } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 1/2] numatune: add check for memnode.nodeset range
For memnode in numatune element, the range of attribute 'nodeset' was not validated. on my host maxnodes was 1, but when setting nodeset to '0-2' or more, guest also started succuss. there probably was qemu's bug too. Signed-off-by: Chen Fan --- src/conf/numatune_conf.c | 29 + src/conf/numatune_conf.h | 4 2 files changed, 33 insertions(+) diff --git a/src/conf/numatune_conf.c b/src/conf/numatune_conf.c index 21d9a64..a9b20aa 100644 --- a/src/conf/numatune_conf.c +++ b/src/conf/numatune_conf.c @@ -183,6 +183,9 @@ virDomainNumatuneNodeParseXML(virDomainNumatunePtr *numatunePtr, VIR_DOMAIN_CPUMASK_LEN) < 0) goto cleanup; VIR_FREE(tmp); + +if (!virDomainNumatuneNodeSetIsAvailable(numatune, cellid)) +goto cleanup; } ret = 0; @@ -612,3 +615,29 @@ virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune) return false; } + +bool +virDomainNumatuneNodeSetIsAvailable(virDomainNumatunePtr numatune, +int cellid) +{ +int maxnode; +int bit = -1; +virBitmapPtr nodemask = NULL; + +nodemask = virDomainNumatuneGetNodeset(numatune, NULL, cellid); +if (!nodemask) +return false; + +if ((maxnode = virNumaGetMaxNode()) < 0) +return false; + +while ((bit = virBitmapNextSetBit(nodemask, bit)) >= 0) { +if (bit > maxnode) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _("NUMA node %d is out of range"), bit); +return false; +} +} + +return true; +} diff --git a/src/conf/numatune_conf.h b/src/conf/numatune_conf.h index 5254629..cab0b83 100644 --- a/src/conf/numatune_conf.h +++ b/src/conf/numatune_conf.h @@ -102,4 +102,8 @@ bool virDomainNumatuneHasPlacementAuto(virDomainNumatunePtr numatune); bool virDomainNumatuneHasPerNodeBinding(virDomainNumatunePtr numatune); +extern int virNumaGetMaxNode(void); +bool virDomainNumatuneNodeSetIsAvailable(virDomainNumatunePtr numatune, + int cellid); + #endif /* __NUMATUNE_CONF_H__ */ -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2 3/4] conf: add virSocketAddrIsLocalhost to Check migration_host
Signed-off-by: Chen Fan --- src/libvirt_private.syms | 1 + src/qemu/qemu_conf.c | 8 src/util/virsocketaddr.c | 35 +++ src/util/virsocketaddr.h | 3 +++ 4 files changed, 47 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 51a692b..f7172b0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1885,6 +1885,7 @@ virSocketAddrGetPort; virSocketAddrGetRange; virSocketAddrIsNetmask; virSocketAddrIsNumeric; +virSocketAddrIsLocalhost; virSocketAddrIsPrivate; virSocketAddrIsWildcard; virSocketAddrMask; diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index adc6caf..30169cf 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -707,6 +707,14 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox); GET_VALUE_STR("migration_host", cfg->migrateHost); +if (cfg->migrateHost && +virSocketAddrIsLocalhost(cfg->migrateHost)) { +virReportError(VIR_ERR_CONF_SYNTAX, + _("migration_host must not be 'localhost' address: %s"), + cfg->migrateHost); +goto cleanup; +} + GET_VALUE_STR("migration_address", cfg->migrationAddress); GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 64409a6..dfcaf72 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -884,3 +884,38 @@ virSocketAddrIsNumeric(const char *address, int *family) } return sa_family == AF_INET || sa_family == AF_INET6; } + +/** + * virSocketAddrIsLocalhost: + * @address: address to check + * + * Check if passed address is a 'localhost' address. + * + * Returns: true if @address is 'localhost' address, + * false otherwise + */ +bool +virSocketAddrIsLocalhost(const char *address) +{ + int family; + + if (virSocketAddrIsNumeric(address, &family)) { + if (family == AF_INET) { + if (STREQ(address, "127.0.0.1")) + return true; + } + + if (family == AF_INET6) { + if (STREQ(address, "::1")) + return true; + } + } else { + if (STRPREFIX(address, "localhost")) + return true; + + if (STREQ(address, "[::1]")) + return true; + } + + return false; +} diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 7b11afb..5269f35 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -126,4 +126,7 @@ bool virSocketAddrIsPrivate(const virSocketAddr *addr); bool virSocketAddrIsWildcard(const virSocketAddr *addr); bool virSocketAddrIsNumeric(const char *address, int *family); + +bool virSocketAddrIsLocalhost(const char *address); + #endif /* __VIR_SOCKETADDR_H__ */ -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2 0/4] Check migration configuration
add some check in migration configuration. Chen Fan (4): virsocketaddr: return address family in virSocketAddrIsNumeric migration: add migration_host support for Ipv6 address without brackets conf: add virSocketAddrIsLocalhost to Check migration_host conf: Check migration_address whether is localhost src/libvirt_private.syms | 1 + src/qemu/qemu.conf | 2 +- src/qemu/qemu_conf.c | 15 src/qemu/qemu_migration.c | 24 ++- src/qemu/test_libvirtd_qemu.aug.in | 2 +- src/util/virsocketaddr.c | 48 ++ src/util/virsocketaddr.h | 5 +++- tests/sockettest.c | 2 +- 8 files changed, 80 insertions(+), 19 deletions(-) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2 2/4] migration: add migration_host support for Ipv6 address without brackets
if specifying migration_host to an Ipv6 address without brackets, it was resolved to an incorrect address, such as: tcp:2001:0DB8::1428:, but the correct address should be: tcp:[2001:0DB8::1428]: so we should add brackets when parsing it. Signed-off-by: Chen Fan --- src/qemu/qemu_migration.c | 24 +--- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 155f5b9..016d131 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2544,7 +2544,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, if (VIR_STRDUP(migrateFrom, "stdio") < 0) goto cleanup; } else { -virSocketAddr listenAddressSocket; +int listenAddressFamily; bool encloseAddress = false; bool hostIPv6Capable = false; bool qemuIPv6Capable = false; @@ -2565,13 +2565,9 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, virObjectUnref(qemuCaps); if (listenAddress) { -if (virSocketAddrIsNumeric(listenAddress, NULL)) { +if (virSocketAddrIsNumeric(listenAddress, &listenAddressFamily)) { /* listenAddress is numeric IPv4 or IPv6 */ -if (virSocketAddrParse(&listenAddressSocket, listenAddress, AF_UNSPEC) < 0) -goto cleanup; - -/* address parsed successfully */ -if (VIR_SOCKET_ADDR_IS_FAMILY(&listenAddressSocket, AF_INET6)) { +if (listenAddressFamily == AF_INET6) { if (!qemuIPv6Capable) { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", _("qemu isn't capable of IPv6")); @@ -2850,11 +2846,17 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, goto cleanup; if (migrateHost != NULL) { -if (virSocketAddrIsNumeric(migrateHost, NULL) && -virSocketAddrParse(NULL, migrateHost, AF_UNSPEC) < 0) -goto cleanup; +int family; +bool migrateHostisIpv6Address = false; + +if (virSocketAddrIsNumeric(migrateHost, &family) && +(family == AF_INET6)) +migrateHostisIpv6Address = true; - if (VIR_STRDUP(hostname, migrateHost) < 0) +if ((migrateHostisIpv6Address && + virAsprintf(&hostname, "[%s]", migrateHost) < 0) || +(!migrateHostisIpv6Address && + virAsprintf(&hostname, "%s", migrateHost) < 0)) goto cleanup; } else { if ((hostname = virGetHostname()) == NULL) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2 1/4] virsocketaddr: return address family in virSocketAddrIsNumeric
nowadays, virSocketAddrIsNumeric only validated the income address if numeric, but sometimes we need to know whether the address is an IPv4 or an IPv6 address. Signed-off-by: Chen Fan --- src/qemu/qemu_migration.c | 4 ++-- src/util/virsocketaddr.c | 13 + src/util/virsocketaddr.h | 2 +- tests/sockettest.c| 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index ce1a5cd..155f5b9 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2565,7 +2565,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, virObjectUnref(qemuCaps); if (listenAddress) { -if (virSocketAddrIsNumeric(listenAddress)) { +if (virSocketAddrIsNumeric(listenAddress, NULL)) { /* listenAddress is numeric IPv4 or IPv6 */ if (virSocketAddrParse(&listenAddressSocket, listenAddress, AF_UNSPEC) < 0) goto cleanup; @@ -2850,7 +2850,7 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, goto cleanup; if (migrateHost != NULL) { -if (virSocketAddrIsNumeric(migrateHost) && +if (virSocketAddrIsNumeric(migrateHost, NULL) && virSocketAddrParse(NULL, migrateHost, AF_UNSPEC) < 0) goto cleanup; diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 7cc4bde..64409a6 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -858,6 +858,7 @@ virSocketAddrGetIpPrefix(const virSocketAddr *address, /** * virSocketAddrIsNumeric: * @address: address to check + * @family: where to store the address family, optional. * * Check if passed address is an IP address in numeric format. For * instance, for 0.0.0.0 true is returned, for 'examplehost" @@ -867,15 +868,19 @@ virSocketAddrGetIpPrefix(const virSocketAddr *address, * false otherwise */ bool -virSocketAddrIsNumeric(const char *address) +virSocketAddrIsNumeric(const char *address, int *family) { struct addrinfo *res; -unsigned short family; +unsigned short sa_family; if (virSocketAddrParseInternal(&res, address, AF_UNSPEC, false) < 0) return false; -family = res->ai_addr->sa_family; +sa_family = res->ai_addr->sa_family; freeaddrinfo(res); -return family == AF_INET || family == AF_INET6; + +if (family != NULL) { +*family = sa_family; +} +return sa_family == AF_INET || sa_family == AF_INET6; } diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 27defa0..7b11afb 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -125,5 +125,5 @@ bool virSocketAddrIsPrivate(const virSocketAddr *addr); bool virSocketAddrIsWildcard(const virSocketAddr *addr); -bool virSocketAddrIsNumeric(const char *address); +bool virSocketAddrIsNumeric(const char *address, int *family); #endif /* __VIR_SOCKETADDR_H__ */ diff --git a/tests/sockettest.c b/tests/sockettest.c index 68b0536..dde0bb8 100644 --- a/tests/sockettest.c +++ b/tests/sockettest.c @@ -229,7 +229,7 @@ testIsNumericHelper(const void *opaque) { const struct testIsNumericData *data = opaque; -if (virSocketAddrIsNumeric(data->addr)) +if (virSocketAddrIsNumeric(data->addr, NULL)) return data->pass ? 0 : -1; return data->pass ? -1 : 0; } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2 4/4] conf: Check migration_address whether is localhost
When enabling the migration_address option, by default it is set to "127.0.0.1", but it's not a valid address for migration. so we should add verification and set the default migration_address to "0.0.0.0". Signed-off-by: Chen Fan --- src/qemu/qemu.conf | 2 +- src/qemu/qemu_conf.c | 7 +++ src/qemu/test_libvirtd_qemu.aug.in | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 79bba36..666c303 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -459,7 +459,7 @@ # Override the listen address for all incoming migrations. Defaults to # 0.0.0.0, or :: if both host and qemu are capable of IPv6. -#migration_address = "127.0.0.1" +#migration_address = "0.0.0.0" # The default hostname or IP address which will be used by a migration diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 30169cf..65f98d7 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -716,6 +716,13 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, } GET_VALUE_STR("migration_address", cfg->migrationAddress); +if (cfg->migrationAddress && +virSocketAddrIsLocalhost(cfg->migrationAddress)) { +virReportError(VIR_ERR_CONF_SYNTAX, + _("migration_address must not be 'localhost' address: %s"), + cfg->migrationAddress); +goto cleanup; +} GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index d2bc2c0..30fd27e 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -69,7 +69,7 @@ module Test_libvirtd_qemu = { "keepalive_interval" = "5" } { "keepalive_count" = "5" } { "seccomp_sandbox" = "1" } -{ "migration_address" = "127.0.0.1" } +{ "migration_address" = "0.0.0.0" } { "migration_host" = "host.example.com" } { "migration_port_min" = "49152" } { "migration_port_max" = "49215" } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v1 1/3] migration: add migration_host support for Ipv6 address without brackets
On Mon, 2014-09-22 at 15:34 +0200, Ján Tomko wrote: > On 09/12/2014 06:31 AM, Chen Fan wrote: > > when specifying migration_host to an Ipv6 address without brackets, > > it was resolved to an incorrect address, such as: > >tcp:2001:0DB8::1428:, > > but the correct address should be: > >tcp:[2001:0DB8::1428]: > > so we should add brackets when parsing it. > > > > Signed-off-by: Chen Fan > > --- > > src/qemu/qemu_migration.c | 19 +++ > > 1 file changed, 15 insertions(+), 4 deletions(-) > > > > diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c > > index e4b664b..c7eb305 100644 > > --- a/src/qemu/qemu_migration.c > > +++ b/src/qemu/qemu_migration.c > > @@ -2850,11 +2850,22 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, > > goto cleanup; > > > > if (migrateHost != NULL) { > > -if (virSocketAddrIsNumeric(migrateHost) && > > -virSocketAddrParse(NULL, migrateHost, AF_UNSPEC) < 0) > > -goto cleanup; > > Hmm, I'm not sure what this check was doing - if the address was succesfully > parsed in AddrIsNumeric, it should be parsed by virSocketAddrParse as well. agreed. > > > +virSocketAddr migrateHostSocket; > > +bool migrateHostisIpv6Address = false; > > + > > +if (virSocketAddrIsNumeric(migrateHost)) { > > +if (virSocketAddrParse(&migrateHostSocket, migrateHost, > > AF_UNSPEC) < 0) > > +goto cleanup; > > + > > +if (VIR_SOCKET_ADDR_IS_FAMILY(&migrateHostSocket, > > AF_INET6)) { > > +migrateHostisIpv6Address = true; > > +} > > +} > > > > We also do this parsing to chceck for numeric IPv6 addresses in > qemuMigrationPrepareAny. It would be nicer to create a new > 'virSocketAddrIsNumericIPv6' function and use it in both of them. I will follow this. Thanks, Chen > > Jan > > > - if (VIR_STRDUP(hostname, migrateHost) < 0) > > +if ((migrateHostisIpv6Address && > > + virAsprintf(&hostname, "[%s]", migrateHost) < 0) || > > +(!migrateHostisIpv6Address && > > + virAsprintf(&hostname, "%s", migrateHost) < 0)) > > goto cleanup; > > } else { > > if ((hostname = virGetHostname()) == NULL) > > > > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] cpu: fix wrong single quote mark
Signed-off-by: Chen Fan --- src/conf/cpu_conf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 6c454ee..116aa58 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -413,7 +413,7 @@ virCPUDefParseXML(xmlNodePtr node, for (j = 0; j < i; j++) { if (STREQ(name, def->features[j].name)) { virReportError(VIR_ERR_XML_ERROR, - _("CPU feature `%s' specified more than once"), + _("CPU feature '%s' specified more than once"), name); VIR_FREE(name); goto error; @@ -731,7 +731,7 @@ virCPUDefUpdateFeatureInternal(virCPUDefPtr def, } virReportError(VIR_ERR_INTERNAL_ERROR, - _("CPU feature `%s' specified more than once"), + _("CPU feature '%s' specified more than once"), name); return -1; -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v1 2/3] conf: Check migration_host is localhost or not during restart
On Mon, 2014-09-22 at 15:34 +0200, Ján Tomko wrote: > On 09/12/2014 06:33 AM, Chen Fan wrote: > > Signed-off-by: Chen Fan > > --- > > src/qemu/qemu_conf.c | 11 +++ > > 1 file changed, 11 insertions(+) > > > > diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c > > index ac10b64..013f3de 100644 > > --- a/src/qemu/qemu_conf.c > > +++ b/src/qemu/qemu_conf.c > > @@ -707,6 +707,17 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr > > cfg, > > GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox); > > > > GET_VALUE_STR("migration_host", cfg->migrateHost); > > +if (cfg->migrateHost) { > > +if (STRPREFIX(cfg->migrateHost, "localhost") || > > +STREQ(cfg->migrateHost, "127.0.0.1") || > > +STREQ(cfg->migrateHost, "::1") || > > +STREQ(cfg->migrateHost, "[::1]")) {\ > > I think we need a 'virSocketAddrIsLocalhost' function similar to > virSocketAddrIsWildcard, which would check any numeric represnation of the > address: > > if (STRPREFIX(cfg->migrateHost, "localhost") || > virSocketAddrIsLocalhost(cfg->migrateHost)) It's a good point. > > > +virReportError(VIR_ERR_CONF_SYNTAX, "%s", > > + _("migration_host must be a valid address or > > hostname")); > > Something more specific, like: "migration_host must not be localhost" is more > user-friendly. I will update the output. Thanks, Chen > > Jan > > > +goto cleanup; > > +} > > +} > > + > > GET_VALUE_STR("migration_address", cfg->migrationAddress); > > > > GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); > > > > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v1 0/3] Check migration configuration
Hi jiri, Please help to review this patches. Thanks, Chen On Fri, 2014-09-12 at 12:32 +0800, Chen Fan wrote: > This version differs from the patch set > "conf: Check migration_host is valid or not during libvirt restarts" > I posted 2 weeks ago, I droped checking the migration_host on target > host. and find an issue when setting migration_host. > > Chen Fan (3): > migration: add migration_host support for Ipv6 address without > brackets > conf: Check migration_host is localhost or not during restart > conf: Check migration_address is valid or not during restart > > src/qemu/qemu.conf | 2 +- > src/qemu/qemu_conf.c | 21 + > src/qemu/qemu_migration.c | 19 +++ > src/qemu/test_libvirtd_qemu.aug.in | 2 +- > 4 files changed, 38 insertions(+), 6 deletions(-) > -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v1 3/3] conf: Check migration_address is valid or not during restart
When enabling the migration_address option, by default it is set to "127.0.0.1", but it's not a valid address for migration. so we should add verification and set the default migration_address to "0.0.0.0". Signed-off-by: Chen Fan --- src/qemu/qemu.conf | 2 +- src/qemu/qemu_conf.c | 10 ++ src/qemu/test_libvirtd_qemu.aug.in | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index 79bba36..666c303 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -459,7 +459,7 @@ # Override the listen address for all incoming migrations. Defaults to # 0.0.0.0, or :: if both host and qemu are capable of IPv6. -#migration_address = "127.0.0.1" +#migration_address = "0.0.0.0" # The default hostname or IP address which will be used by a migration diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 013f3de..2cbf2a6 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -719,6 +719,16 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, } GET_VALUE_STR("migration_address", cfg->migrationAddress); +if (cfg->migrationAddress) { +if (STRPREFIX(cfg->migrationAddress, "localhost") || +STREQ(cfg->migrationAddress, "127.0.0.1") || +STREQ(cfg->migrationAddress, "::1") || +STREQ(cfg->migrationAddress, "[::1]")) { +virReportError(VIR_ERR_CONF_SYNTAX, "%s", + _("migration_address must be a valid address or hostname")); +goto cleanup; +} +} GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index d2bc2c0..30fd27e 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -69,7 +69,7 @@ module Test_libvirtd_qemu = { "keepalive_interval" = "5" } { "keepalive_count" = "5" } { "seccomp_sandbox" = "1" } -{ "migration_address" = "127.0.0.1" } +{ "migration_address" = "0.0.0.0" } { "migration_host" = "host.example.com" } { "migration_port_min" = "49152" } { "migration_port_max" = "49215" } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v1 2/3] conf: Check migration_host is localhost or not during restart
Signed-off-by: Chen Fan --- src/qemu/qemu_conf.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index ac10b64..013f3de 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -707,6 +707,17 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox); GET_VALUE_STR("migration_host", cfg->migrateHost); +if (cfg->migrateHost) { +if (STRPREFIX(cfg->migrateHost, "localhost") || +STREQ(cfg->migrateHost, "127.0.0.1") || +STREQ(cfg->migrateHost, "::1") || +STREQ(cfg->migrateHost, "[::1]")) { +virReportError(VIR_ERR_CONF_SYNTAX, "%s", + _("migration_host must be a valid address or hostname")); +goto cleanup; +} +} + GET_VALUE_STR("migration_address", cfg->migrationAddress); GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v1 0/3] Check migration configuration
This version differs from the patch set "conf: Check migration_host is valid or not during libvirt restarts" I posted 2 weeks ago, I droped checking the migration_host on target host. and find an issue when setting migration_host. Chen Fan (3): migration: add migration_host support for Ipv6 address without brackets conf: Check migration_host is localhost or not during restart conf: Check migration_address is valid or not during restart src/qemu/qemu.conf | 2 +- src/qemu/qemu_conf.c | 21 + src/qemu/qemu_migration.c | 19 +++ src/qemu/test_libvirtd_qemu.aug.in | 2 +- 4 files changed, 38 insertions(+), 6 deletions(-) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v1 1/3] migration: add migration_host support for Ipv6 address without brackets
when specifying migration_host to an Ipv6 address without brackets, it was resolved to an incorrect address, such as: tcp:2001:0DB8::1428:, but the correct address should be: tcp:[2001:0DB8::1428]: so we should add brackets when parsing it. Signed-off-by: Chen Fan --- src/qemu/qemu_migration.c | 19 +++ 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index e4b664b..c7eb305 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2850,11 +2850,22 @@ qemuMigrationPrepareDirect(virQEMUDriverPtr driver, goto cleanup; if (migrateHost != NULL) { -if (virSocketAddrIsNumeric(migrateHost) && -virSocketAddrParse(NULL, migrateHost, AF_UNSPEC) < 0) -goto cleanup; +virSocketAddr migrateHostSocket; +bool migrateHostisIpv6Address = false; + +if (virSocketAddrIsNumeric(migrateHost)) { +if (virSocketAddrParse(&migrateHostSocket, migrateHost, AF_UNSPEC) < 0) +goto cleanup; + +if (VIR_SOCKET_ADDR_IS_FAMILY(&migrateHostSocket, AF_INET6)) { +migrateHostisIpv6Address = true; +} +} - if (VIR_STRDUP(hostname, migrateHost) < 0) +if ((migrateHostisIpv6Address && + virAsprintf(&hostname, "[%s]", migrateHost) < 0) || +(!migrateHostisIpv6Address && + virAsprintf(&hostname, "%s", migrateHost) < 0)) goto cleanup; } else { if ((hostname = virGetHostname()) == NULL) -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] conf: Check migration_host is valid or not during libvirt restarts
if user specified an invalid strings as migration hostname, like setting: migration_host = "XXX", libvirt should check it and return error during lbivirt restart. Signed-off-by: Chen Fan --- src/qemu/qemu_conf.c | 40 1 file changed, 40 insertions(+) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index e2ec54f..450ac5b 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "virerror.h" #include "qemu_conf.h" @@ -650,6 +651,45 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, GET_VALUE_LONG("seccomp_sandbox", cfg->seccompSandbox); GET_VALUE_STR("migration_host", cfg->migrateHost); +if (cfg->migrateHost) { +struct addrinfo hints; +struct addrinfo *res; + +memset(&hints, 0, sizeof(hints)); +hints.ai_flags = AI_ADDRCONFIG; +hints.ai_family = AF_UNSPEC; + +if (getaddrinfo(cfg->migrateHost, NULL, &hints, &res) != 0) { +virReportError(VIR_ERR_CONF_SYNTAX, + _("migration_host: '%s' is not a valid hostname"), + cfg->migrateHost); +goto cleanup; +} + +if (res == NULL) { +virReportError(VIR_ERR_CONF_SYNTAX, + _("No IP address for host '%s' found"), + cfg->migrateHost); +goto cleanup; +} + +freeaddrinfo(res); + +if (STRPREFIX(cfg->migrateHost, "localhost")) { +virReportError(VIR_ERR_CONF_SYNTAX, "%s", + _("setting migration_host to 'localhost' is not allowed")); +goto cleanup; +} + +if (STREQ(cfg->migrateHost, "127.0.0.1") || +STREQ(cfg->migrateHost, "::1")) { +virReportError(VIR_ERR_CONF_SYNTAX, "%s", + _("setting migration_host to '127.0.0.1' or '::1' " + "is not allowed")); +goto cleanup; +} +} + GET_VALUE_STR("migration_address", cfg->migrationAddress); GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp); -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] storage: remove unused 'canonPath' in virStorageFileGetMetadata
Signed-off-by: Chen Fan --- src/storage/storage_driver.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 3604613..5ddc23a 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -2892,7 +2892,6 @@ virStorageFileGetMetadata(virStorageSourcePtr src, src->path, src->format, (int)uid, (int)gid, allow_probe); virHashTablePtr cycle = NULL; -char *canonPath = NULL; int ret = -1; if (!(cycle = virHashCreate(5, NULL))) @@ -2904,7 +2903,6 @@ virStorageFileGetMetadata(virStorageSourcePtr src, ret = virStorageFileGetMetadataRecurse(src, uid, gid, allow_probe, cycle); -VIR_FREE(canonPath); virHashFree(cycle); return ret; } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] domain conf: Fix whitespace around judgement operation when parsing 'managed' attribute.
Signed-off-by: Chen Fan --- src/conf/domain_conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 02c394f..b7aa4f5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4261,7 +4261,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, * element that might be (pure hostdev, or higher level device * (e.g. ) with type='hostdev') */ -if ((managed = virXMLPropString(node, "managed"))!= NULL) { +if ((managed = virXMLPropString(node, "managed")) != NULL) { if (STREQ(managed, "yes")) def->managed = true; } -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 2/3] conf: add memdev device in XML
Since qemu has supported memory-backend-ram and memory-backend-file object, so we should add a new 'memdev' device type in XML to introduce the memory element, Its definition like the following: ram0 1000 then we enable to support -numa memdev=ram0 command line for binding guest numa nodes to host numa nodes. Signed-off-by: Chen Fan --- src/conf/domain_conf.c | 203 ++- src/conf/domain_conf.h | 42 + src/libvirt_private.syms | 4 + src/qemu/qemu_capabilities.c | 4 + src/qemu/qemu_capabilities.h | 2 + src/qemu/qemu_command.c | 74 src/qemu/qemu_command.h | 4 + src/qemu/qemu_hotplug.c | 1 + 8 files changed, 333 insertions(+), 1 deletion(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index be81dbe..c55bf47 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -204,7 +204,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, "chr", "memballoon", "nvram", - "rng") + "rng", + "memdev") VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "none", @@ -454,6 +455,16 @@ VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST, "xen", "none") +VIR_ENUM_IMPL(virDomainMemDev, VIR_DOMAIN_MEMDEV_LAST, + "ram", + "file") + +VIR_ENUM_IMPL(virDomainHostNodePolicy, VIR_DOMAIN_HOST_NODE_POLICY_LAST, + "default", + "preferred", + "bind", + "interleave") + VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST, "none", "emulate", @@ -770,6 +781,10 @@ static void virDomainObjDispose(void *obj); static void virDomainObjListDispose(void *obj); static void virDomainXMLOptionClassDispose(void *obj); +static int +virDomainParseMemory(const char *xpath, xmlXPathContextPtr ctxt, + unsigned long long *mem, bool required); + static int virDomainObjOnceInit(void) { if (!(virDomainObjClass = virClassNew(virClassForObjectLockable(), @@ -1661,6 +1676,18 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def) VIR_FREE(def); } +void virDomainMemDevDefFree(virDomainMemDevDefPtr def) +{ +if (!def) +return; + +VIR_FREE(def->name); +VIR_FREE(def->mempath); +VIR_FREE(def->hostnodes); +VIR_FREE(def); +} + + void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def) { if (!def) @@ -1864,6 +1891,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_NVRAM: virDomainNVRAMDefFree(def->data.nvram); break; +case VIR_DOMAIN_DEVICE_MEMDEV: +virDomainMemDevDefFree(def->data.memdev); +break; case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: break; @@ -2543,6 +2573,7 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device) /* The following devices do not contain virDomainDeviceInfo */ case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_GRAPHICS: +case VIR_DOMAIN_DEVICE_MEMDEV: case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: break; @@ -2780,6 +2811,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def, case VIR_DOMAIN_DEVICE_NVRAM: case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_RNG: +case VIR_DOMAIN_DEVICE_MEMDEV: break; } @@ -9192,6 +9224,104 @@ virDomainMemballoonDefParseXML(xmlNodePtr node, goto cleanup; } +static virDomainMemDevDefPtr +virDomainMemDevDefParseXML(xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ +char *type; +virDomainMemDevDefPtr def; +xmlNodePtr save = ctxt->node; +char *tmp = NULL; +char *policy = NULL; + +if (VIR_ALLOC(def) < 0) +return NULL; + +type = virXMLPropString(node, "type"); +if (type == NULL) { +virReportError(VIR_ERR_XML_ERROR, "%s", + _("memory device must contain a type name")); +goto error; +} + +if ((def->type = virDomainMemDevTypeFromString(type)) < 0) { +virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown memory device type '%s'"), type); +goto error; +} + +if ((tmp = virXMLPropString(node, "merge")) != NULL) { +if (STREQ(tmp, "yes")) +def->merge = true; +VIR_FREE(tmp); +} + +if ((tmp = virXMLPropString(node, "dump")) != NULL) { +if (STREQ(tmp, "yes")) +def->dump = t
[libvirt] [PATCH 3/3] tests: add numa -memdev testing and docs support
Signed-off-by: Chen Fan --- docs/formatdomain.html.in | 71 +++- docs/schemas/domaincommon.rng | 76 +- tests/qemuxml2argvdata/qemuxml2argv-cpu-numa3.args | 9 +++ tests/qemuxml2argvdata/qemuxml2argv-cpu-numa3.xml | 35 ++ tests/qemuxml2argvdata/qemuxml2argv-cpu-numa4.args | 10 +++ tests/qemuxml2argvdata/qemuxml2argv-cpu-numa4.xml | 35 ++ tests/qemuxml2argvtest.c | 2 + 7 files changed, 233 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa3.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa3.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa4.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa4.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 1b6ced8..5313c76 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1032,6 +1032,9 @@ <numa> <cell cpus='0-3' memory='512000'/> <cell cpus='4-7' memory='512000'/> + <!-- OR --> + <cell cpus='0-3' memdev='ram0'/> + <cell cpus='4-7' memdev='ram1'/> </numa> ... </cpu> @@ -1041,8 +1044,11 @@ Each cell element specifies a NUMA cell or a NUMA node. cpus specifies the CPU or range of CPUs that are part of the node. memory specifies the node memory in kibibytes - (i.e. blocks of 1024 bytes). Each cell or node is assigned cellid - or nodeid in the increasing order starting from 0. + (i.e. blocks of 1024 bytes). Since 2.1, + memdev specifies the Host NUMA node that the Guest NUMA + node bind to. if memdev specified for one node, it must + be specified for all nodes. Each cell or node is assigned cellid or + nodeid in the increasing order starting from 0. @@ -5249,6 +5255,67 @@ qemu-kvm -net nic,model=? /dev/null +memory device + + A memory device can be added to guest via memdev element. + Since 2.1, QEMU and KVM only + + + Example: usage of memory device configuration + + + ... + <devices> +<memdev type='ram' merge='yes' dump='yes' prealloc='yes'> + <name>ram0</name> + <capacity unit='KiB'>102400</capacity> + <source host-nodes='0-1' policy='bind'/> +</memdev> + </devices> + ... + + +type + + +The required type attribute specifies what type of memory device +is provided. Valid type are: + + + 'ram' — memory ram backend. + 'file' — memory file backend. + + +merge + + +The optional merge attribute enables memory merge support. + + +dump + + +The optional dump attribute enables to dump memory device's memory in a +core dump file. + + +prealloc + + +The optional prealloc attribute enables memory preallocation. + + + source + The source element describes the device as seen from the host. + the optional mem-path element is required when specified type = 'file'. + the optional host-nodes element specified the Host nodes ids that the + Guest memory device binds to. the optional policy element specified the + memory policy of memory device. the policy is either "default", "preferred", + "bind", "interleave". defaults to "default". + + + + Security label diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 6cc922c..0334b28 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3148,6 +3148,32 @@ + + + + + ram + file + + + + + yes + + + + + yes + + + + + yes + + + + + @@ -3671,6 +3697,7 @@ + @@ -3895,9 +3922,18 @@ - - - + + + + + + + + + + + + @@ -4527,6 +4563,40 @@ + + + + + + + + + + + + + + + + + + [a-zA-Z0-9\-_]+ + + + + + + +
[libvirt] [PATCH 0/3] add binding guest numa nodes to host numa nodes support
Since qemu has supported numa option -memdev config: -object memory-backend-ram,size=1024M,policy=membind,host-nodes=0,id=ram-node0 \ -numa node,nodeid=0,cpus=0,memdev=ram-node0 \ for binding guest numa nodes to host numa nodes. So we introduce this capability in libvirt by configuration domain XML like: ... ... ram0 1000 Chen Fan (3): numa: add '-numa memdev=' support conf: add memdev device in XML tests: add numa -memdev testing and docs support docs/formatdomain.html.in | 71 ++- docs/schemas/domaincommon.rng | 76 +++- src/conf/cpu_conf.c| 73 ++-- src/conf/cpu_conf.h| 13 +- src/conf/domain_conf.c | 203 - src/conf/domain_conf.h | 42 + src/libvirt_private.syms | 4 + src/qemu/qemu_capabilities.c | 4 + src/qemu/qemu_capabilities.h | 2 + src/qemu/qemu_command.c| 84 - src/qemu/qemu_command.h| 4 + src/qemu/qemu_hotplug.c| 1 + tests/qemuxml2argvdata/qemuxml2argv-cpu-numa3.args | 9 + tests/qemuxml2argvdata/qemuxml2argv-cpu-numa3.xml | 35 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa4.args | 10 + tests/qemuxml2argvdata/qemuxml2argv-cpu-numa4.xml | 35 tests/qemuxml2argvtest.c | 2 + 17 files changed, 644 insertions(+), 24 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa3.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa3.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa4.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-numa4.xml -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 1/3] numa: add '-numa memdev=' support
Since qemu has supported '-numa memdev=ram0' command option, so libvirt should add numa element to support specified memdev attrubute in XML. Signed-off-by: Chen Fan --- src/conf/cpu_conf.c | 73 +++-- src/conf/cpu_conf.h | 13 - src/qemu/qemu_command.c | 10 +-- 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index ebdaa19..2d0980e 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -29,6 +29,7 @@ #include "cpu_conf.h" #include "domain_conf.h" #include "virstring.h" +#include "c-ctype.h" #define VIR_FROM_THIS VIR_FROM_CPU @@ -84,6 +85,8 @@ virCPUDefFree(virCPUDefPtr def) for (i = 0; i < def->ncells; i++) { virBitmapFree(def->cells[i].cpumask); VIR_FREE(def->cells[i].cpustr); +if (def->cells[i].memtype == VIR_CPU_CELL_MEMORY_DEV) +VIR_FREE(def->cells[i].data.memstr); } VIR_FREE(def->cells); VIR_FREE(def->vendor_id); @@ -153,7 +156,13 @@ virCPUDefCopy(const virCPUDef *cpu) for (i = 0; i < cpu->ncells; i++) { copy->cells[i].cellid = cpu->cells[i].cellid; -copy->cells[i].mem = cpu->cells[i].mem; +copy->cells[i].memtype = cpu->cells[i].memtype; +if (cpu->cells[i].memtype == VIR_CPU_CELL_MEMORY_DEV) { +if (VIR_STRDUP(copy->cells[i].data.memstr, cpu->cells[i].data.memstr) < 0) +goto error; +} else { +copy->cells[i].data.mem = cpu->cells[i].data.mem; +} copy->cells[i].cpumask = virBitmapNewCopy(cpu->cells[i].cpumask); @@ -436,7 +445,7 @@ virCPUDefParseXML(xmlNodePtr node, def->ncells = n; for (i = 0; i < n; i++) { -char *cpus, *memory; +char *cpus, *memory, *memdev; int ret, ncpus = 0; def->cells[i].cellid = i; @@ -455,20 +464,52 @@ virCPUDefParseXML(xmlNodePtr node, def->cells_cpus += ncpus; memory = virXMLPropString(nodes[i], "memory"); -if (!memory) { -virReportError(VIR_ERR_XML_ERROR, "%s", - _("Missing 'memory' attribute in NUMA cell")); -goto error; -} - -ret = virStrToLong_ui(memory, NULL, 10, &def->cells[i].mem); -if (ret == -1) { +memdev = virXMLPropString(nodes[i], "memdev"); +if (memory || memdev) { +if (memory && memdev) { +virReportError(VIR_ERR_XML_ERROR, "%s", + _("Both 'memory' and 'memdev' attribute in NUMA cell is not allowed")); +goto error; +} + +if (memory) { +ret = virStrToLong_ui(memory, NULL, 10, &def->cells[i].data.mem); +if (ret == -1) { +virReportError(VIR_ERR_XML_ERROR, "%s", + _("Invalid 'memory' attribute in NUMA cell")); +VIR_FREE(memory); +goto error; +} +def->cells[i].memtype = VIR_CPU_CELL_MEMORY_SIZE; +VIR_FREE(memory); +} else { +if (strlen(memdev) < 1) { +virReportError(VIR_ERR_XML_ERROR, "%s", + _("Empty 'memdev' attribute in NUMA cell")); +VIR_FREE(memdev); +goto error; +} + +if (!c_isalpha(memdev[0])) { +virReportError(VIR_ERR_XML_ERROR, "%s", + _("Invalid 'memdev' attribute name in NUMA cell, " + "it must begin with a letter")); +VIR_FREE(memdev); +goto error; +} + +if (VIR_STRDUP(def->cells[i].data.memstr, memdev) < 0) { +VIR_FREE(memdev); +goto error; +} +def->cells[i].memtype = VIR_CPU_CELL_MEMORY_DEV; +VIR_FREE(memdev); +} +} else { virReportError(VIR_ERR_XML_ERROR, "%s", - _("Invalid 'memory' attribute in NUMA cell")); -VIR_FREE(memory); + _("Missing 'memory
[libvirt] [patch v2 1/1] manual: Add virsh manual about specified migration host
the 'migration_host' description maybe have a bit of difficulty to understand for user, so add this manual for them. Signed-off-by: Chen Fan --- tools/virsh.pod | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/virsh.pod b/tools/virsh.pod index 02671b4..7b30292 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1208,7 +1208,8 @@ such as GFS2 or GPFS. If you are sure the migration is safe or you just do not care, use I<--unsafe> to force the migration. The I is the connection URI of the destination host, and -I is the migration URI, which usually can be omitted (see below). +I is the migration URI for specifying which IP address/URI of the +destination host to tansfer migration data, which usually can be omitted (see below). I is used for renaming the domain to new name during migration, which also usually can be omitted. Likewise, I<--xml> B is usually omitted, but can be used to supply an alternative XML file for use on @@ -1238,6 +1239,15 @@ seen from the source machine. When I is not specified, libvirt will automatically determine the hypervisor specific URI, by looking up the target host's configured hostname. + +For QEMU/KVM hypervisor, when I is not specified, at first libvirt +will ask the destination side whether the optional "migration_host" is specified +or not, if the "migration_host" is specified, libvirt will use the specified +network for transferring migration data(the "migrateion_host" is useful when +hosts has multiple network interface). if the "migrateion_host" is not specified +too, libvirt will automatically determine the hypervisor specific URI, by looking +up the target host's configured hostname. + There are a few scenarios where specifying I may help: =over 4 -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] manual: Add virsh manual about specified migration host
the 'migration_host' description maybe have a bit of difficulty to understand for user, so add this manual for them. Signed-off-by: Chen Fan --- tools/virsh.pod | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/virsh.pod b/tools/virsh.pod index de9a4f7..8d77a2f 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1238,6 +1238,11 @@ seen from the source machine. When I is not specified, libvirt will automatically determine the hypervisor specific URI, by looking up the target host's configured hostname. +In particular, some hypervisors support having this migration hostname specified +separately by setting 'migration_host' in definition file, if 'migration_host' +is specified, the hostname or IP address will be used to as the default I +while running migration from source host. if 'migration_host' is not specified, +the migration hostname is set to the host's configured hostname by default. There are a few scenarios where specifying I may help: =over 4 @@ -1251,7 +1256,9 @@ explicitly specified, using an IP address, or a correct hostname. interfaces, it might be desirable for the migration data stream to be sent over a specific interface for either security or performance reasons. In this case I should be explicitly specified, using an IP address associated -with the network to be used. +with the network to be used. In particular, Some hypervisors could be easy to +specify the default network interface by setting 'migration_host'. then the +I can be omitted. =item * The firewall restricts what ports are available. When libvirt generates a migration URI, it will pick a port number using hypervisor specific rules. -- 1.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list