libvirt/src/qemu/qemu_hotplug.c

4390 lines
146 KiB
C
Raw Normal View History

/*
* qemu_hotplug.c: QEMU device hotplug management
*
* Copyright (C) 2006-2016 Red Hat, Inc.
* Copyright (C) 2006 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include <config.h>
#include "qemu_hotplug.h"
#include "qemu_hotplugpriv.h"
#include "qemu_alias.h"
#include "qemu_capabilities.h"
#include "qemu_domain.h"
#include "qemu_domain_address.h"
#include "qemu_command.h"
#include "qemu_hostdev.h"
#include "qemu_interface.h"
#include "qemu_process.h"
#include "domain_audit.h"
#include "netdev_bandwidth_conf.h"
#include "domain_nwfilter.h"
2012-12-12 17:59:27 +00:00
#include "virlog.h"
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
#include "datatypes.h"
#include "virerror.h"
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
2012-12-13 14:52:25 +00:00
#include "virpci.h"
#include "virfile.h"
#include "virprocess.h"
#include "qemu_cgroup.h"
#include "locking/domain_lock.h"
#include "network/bridge_driver.h"
#include "virnetdev.h"
#include "virnetdevbridge.h"
#include "virnetdevtap.h"
#include "virnetdevopenvswitch.h"
#include "virnetdevmidonet.h"
#include "device_conf.h"
#include "virstoragefile.h"
#include "virstring.h"
#include "virtime.h"
#include "storage/storage_driver.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_hotplug");
#define CHANGE_MEDIA_TIMEOUT 5000
/* Wait up to 5 seconds for device removal to finish. */
unsigned long long qemuDomainRemoveDeviceWaitTime = 1000ull * 5;
/**
* qemuDomainPrepareDisk:
* @driver: qemu driver struct
* @vm: domain object
* @disk: disk to prepare
* @overridesrc: Source different than @disk->src when necessary
* @teardown: Teardown the disk instead of adding it to a vm
*
* Setup the locks, cgroups and security permissions on a disk of a VM.
* If @overridesrc is specified the source struct is used instead of the
* one present in @disk. If @teardown is true, then the labels and cgroups
* are removed instead.
*
* Returns 0 on success and -1 on error. Reports libvirt error.
*/
static int
qemuDomainPrepareDisk(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk,
virStorageSourcePtr overridesrc,
bool teardown)
{
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
int ret = -1;
virStorageSourcePtr origsrc = NULL;
if (overridesrc) {
origsrc = disk->src;
disk->src = overridesrc;
}
/* just tear down the disk access */
if (teardown) {
ret = 0;
goto rollback_cgroup;
}
if (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
vm, disk) < 0)
goto cleanup;
if (virSecurityManagerSetDiskLabel(driver->securityManager,
vm->def, disk) < 0)
goto rollback_lock;
if (qemuSetupDiskCgroup(vm, disk) < 0)
goto rollback_label;
ret = 0;
goto cleanup;
rollback_cgroup:
if (qemuTeardownDiskCgroup(vm, disk) < 0)
VIR_WARN("Unable to tear down cgroup access on %s",
virDomainDiskGetSource(disk));
rollback_label:
if (virSecurityManagerRestoreDiskLabel(driver->securityManager,
vm->def, disk) < 0)
VIR_WARN("Unable to restore security label on %s",
virDomainDiskGetSource(disk));
rollback_lock:
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
VIR_WARN("Unable to release lock on %s",
virDomainDiskGetSource(disk));
cleanup:
if (origsrc)
disk->src = origsrc;
virObjectUnref(cfg);
return ret;
}
static int
qemuHotplugWaitForTrayEject(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk,
const char *driveAlias,
bool force)
{
unsigned long long now;
int rc;
if (virTimeMillisNow(&now) < 0)
return -1;
while (disk->tray_status != VIR_DOMAIN_DISK_TRAY_OPEN) {
if ((rc = virDomainObjWaitUntil(vm, now + CHANGE_MEDIA_TIMEOUT)) < 0)
return -1;
if (rc > 0) {
/* the caller called qemuMonitorEjectMedia which usually reports an
* error. Report the failure in an off-chance that it didn't. */
if (!virGetLastError()) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("timed out waiting for disk tray status update"));
}
return -1;
}
}
/* re-issue ejection command to pop out the media */
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorEjectMedia(qemuDomainGetMonitor(vm), driveAlias, force);
if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
return -1;
return 0;
}
/**
* qemuDomainChangeEjectableMedia:
* @driver: qemu driver structure
* @vm: domain definition
* @disk: disk definition to change the source of
* @newsrc: new disk source to change to
* @force: force the change of media
*
* Change the media in an ejectable device to the one described by
* @newsrc. This function also removes the old source from the
* shared device table if appropriate. Note that newsrc is consumed
* on success and the old source is freed on success.
*
* Returns 0 on success, -1 on error and reports libvirt error
*/
int
qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk,
virStorageSourcePtr newsrc,
bool force)
{
int ret = -1, rc;
char *driveAlias = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
const char *format = NULL;
char *sourcestr = NULL;
if (!disk->info.alias) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing disk device alias name for %s"), disk->dst);
goto cleanup;
}
if (disk->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Removable media not supported for %s device"),
virDomainDiskDeviceTypeToString(disk->device));
goto cleanup;
}
if (qemuDomainPrepareDisk(driver, vm, disk, newsrc, false) < 0)
goto cleanup;
if (!(driveAlias = qemuDeviceDriveHostAlias(disk)))
goto error;
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
/* If the tray is present and tray change event is supported wait for it to open. */
if (diskPriv->tray &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_TRAY_MOVED)) {
rc = qemuHotplugWaitForTrayEject(driver, vm, disk, driveAlias, force);
if (rc < 0)
goto error;
} else {
/* otherwise report possible errors from the attempt to eject the media*/
if (rc < 0)
goto error;
}
if (!virStorageSourceIsEmpty(newsrc)) {
if (qemuGetDriveSourceString(newsrc, diskPriv->secinfo, &sourcestr) < 0)
goto error;
if (virStorageSourceGetActualType(newsrc) != VIR_STORAGE_TYPE_DIR) {
if (newsrc->format > 0) {
format = virStorageFileFormatTypeToString(newsrc->format);
} else {
if (disk->src->format > 0)
format = virStorageFileFormatTypeToString(disk->src->format);
}
}
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorChangeMedia(priv->mon,
driveAlias,
sourcestr,
format);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
}
virDomainAuditDisk(vm, disk->src, newsrc, "update", rc >= 0);
if (rc < 0)
goto error;
/* remove the old source from shared device list */
ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));
ignore_value(qemuDomainPrepareDisk(driver, vm, disk, NULL, true));
virStorageSourceFree(disk->src);
disk->src = newsrc;
newsrc = NULL;
ret = 0;
cleanup:
VIR_FREE(driveAlias);
VIR_FREE(sourcestr);
return ret;
error:
virDomainAuditDisk(vm, disk->src, newsrc, "update", false);
ignore_value(qemuDomainPrepareDisk(driver, vm, disk, newsrc, true));
goto cleanup;
}
static int
qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk)
{
int ret = -1;
int rv;
qemuDomainObjPrivatePtr priv = vm->privateData;
virErrorPtr orig_err;
char *devstr = NULL;
char *drivestr = NULL;
char *drivealias = NULL;
bool releaseaddr = false;
bool driveAdded = false;
bool secobjAdded = false;
bool encobjAdded = false;
virDomainCCWAddressSetPtr ccwaddrs = NULL;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
const char *src = virDomainDiskGetSource(disk);
virJSONValuePtr secobjProps = NULL;
virJSONValuePtr encobjProps = NULL;
qemuDomainDiskPrivatePtr diskPriv;
qemuDomainSecretInfoPtr secinfo;
qemuDomainSecretInfoPtr encinfo;
if (!disk->info.type) {
if (qemuDomainMachineIsS390CCW(vm->def) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW))
disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390))
disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390;
} else {
if (!qemuCheckCCWS390AddressSupport(vm->def, disk->info, priv->qemuCaps,
disk->dst))
goto cleanup;
}
if (qemuDomainPrepareDisk(driver, vm, disk, NULL, false) < 0)
goto cleanup;
if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
goto error;
if (virDomainCCWAddressAssign(&disk->info, ccwaddrs,
!disk->info.addr.ccw.assigned) < 0)
goto error;
} else if (!disk->info.type ||
disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
goto error;
}
releaseaddr = true;
if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
goto error;
if (qemuDomainSecretDiskPrepare(conn, priv, disk) < 0)
goto error;
diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
secinfo = diskPriv->secinfo;
if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
if (qemuBuildSecretInfoProps(secinfo, &secobjProps) < 0)
goto error;
}
encinfo = diskPriv->encinfo;
if (encinfo && qemuBuildSecretInfoProps(encinfo, &encobjProps) < 0)
goto error;
if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
goto error;
if (!(drivealias = qemuDeviceDriveHostAlias(disk)))
goto error;
if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
goto error;
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
goto error;
qemuDomainObjEnterMonitor(driver, vm);
if (secobjProps) {
rv = qemuMonitorAddObject(priv->mon, "secret", secinfo->s.aes.alias,
secobjProps);
secobjProps = NULL; /* qemuMonitorAddObject consumes */
if (rv < 0)
goto exit_monitor;
secobjAdded = true;
}
if (encobjProps) {
rv = qemuMonitorAddObject(priv->mon, "secret", encinfo->s.aes.alias,
encobjProps);
encobjProps = NULL; /* qemuMonitorAddObject consumes */
if (rv < 0)
goto exit_monitor;
encobjAdded = true;
}
if (qemuMonitorAddDrive(priv->mon, drivestr) < 0)
goto exit_monitor;
driveAdded = true;
if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
goto exit_monitor;
if (qemuDomainObjExitMonitor(driver, vm) < 0) {
releaseaddr = false;
goto error;
}
virDomainAuditDisk(vm, NULL, disk->src, "attach", true);
virDomainDiskInsertPreAlloced(vm->def, disk);
ret = 0;
cleanup:
virJSONValueFree(secobjProps);
virJSONValueFree(encobjProps);
qemuDomainSecretDiskDestroy(disk);
virDomainCCWAddressSetFree(ccwaddrs);
VIR_FREE(devstr);
VIR_FREE(drivestr);
VIR_FREE(drivealias);
virObjectUnref(cfg);
return ret;
exit_monitor:
orig_err = virSaveLastError();
if (driveAdded && qemuMonitorDriveDel(priv->mon, drivealias) < 0) {
VIR_WARN("Unable to remove drive %s (%s) after failed "
"qemuMonitorAddDevice", drivealias, drivestr);
}
if (secobjAdded)
ignore_value(qemuMonitorDelObject(priv->mon, secinfo->s.aes.alias));
if (encobjAdded)
ignore_value(qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias));
if (orig_err) {
virSetError(orig_err);
virFreeError(orig_err);
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
releaseaddr = false;
virDomainAuditDisk(vm, NULL, disk->src, "attach", false);
error:
if (releaseaddr)
qemuDomainReleaseDeviceAddress(vm, &disk->info, src);
ignore_value(qemuDomainPrepareDisk(driver, vm, disk, NULL, true));
goto cleanup;
}
int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainControllerDefPtr controller)
{
int ret = -1;
const char* type = virDomainControllerTypeToString(controller->type);
char *devstr = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainCCWAddressSetPtr ccwaddrs = NULL;
bool releaseaddr = false;
if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("'%s' controller cannot be hot plugged."),
virDomainControllerTypeToString(controller->type));
return -1;
}
/* default idx would normally be set by virDomainDefPostParse(),
* which isn't called in the case of live attach of a single
* device.
*/
if (controller->idx == -1)
controller->idx = virDomainControllerFindUnusedIndex(vm->def,
controller->type);
if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("target %s:%d already exists"),
type, controller->idx);
return -1;
}
if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
if (qemuDomainMachineIsS390CCW(vm->def) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW))
controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390))
controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390;
} else {
if (!qemuCheckCCWS390AddressSupport(vm->def, controller->info,
priv->qemuCaps, "controller"))
goto cleanup;
}
if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
goto cleanup;
} else if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
goto cleanup;
if (virDomainCCWAddressAssign(&controller->info, ccwaddrs,
!controller->info.addr.ccw.assigned) < 0)
goto cleanup;
}
releaseaddr = true;
if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, controller) < 0)
goto cleanup;
if (!(devstr = qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, NULL)))
goto cleanup;
if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorAddDevice(priv->mon, devstr);
if (qemuDomainObjExitMonitor(driver, vm) < 0) {
releaseaddr = false;
ret = -1;
goto cleanup;
}
if (ret == 0) {
if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
virDomainControllerInsertPreAlloced(vm->def, controller);
}
cleanup:
if (ret != 0 && releaseaddr)
qemuDomainReleaseDeviceAddress(vm, &controller->info, NULL);
VIR_FREE(devstr);
virDomainCCWAddressSetFree(ccwaddrs);
return ret;
}
static virDomainControllerDefPtr
qemuDomainFindOrCreateSCSIDiskController(virQEMUDriverPtr driver,
virDomainObjPtr vm,
int controller)
{
size_t i;
virDomainControllerDefPtr cont;
for (i = 0; i < vm->def->ncontrollers; i++) {
cont = vm->def->controllers[i];
if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
continue;
if (cont->idx == controller)
return cont;
}
/* No SCSI controller present, for backward compatibility we
* now hotplug a controller */
if (VIR_ALLOC(cont) < 0)
return NULL;
cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
cont->idx = controller;
cont->model = -1;
VIR_INFO("No SCSI controller present, hotplugging one");
if (qemuDomainAttachControllerDevice(driver,
vm, cont) < 0) {
VIR_FREE(cont);
return NULL;
}
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("guest unexpectedly quit"));
/* cont doesn't need freeing here, since the reference
* now held in def->controllers */
return NULL;
}
return cont;
}
static int
qemuDomainAttachSCSIDisk(virConnectPtr conn,
virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk)
{
size_t i;
qemuDomainObjPrivatePtr priv = vm->privateData;
virErrorPtr orig_err;
char *drivestr = NULL;
char *devstr = NULL;
bool driveAdded = false;
bool encobjAdded = false;
int ret = -1;
int rv;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
virJSONValuePtr encobjProps = NULL;
qemuDomainDiskPrivatePtr diskPriv;
qemuDomainSecretInfoPtr encinfo;
if (qemuDomainPrepareDisk(driver, vm, disk, NULL, false) < 0)
goto cleanup;
/* We should have an address already, so make sure */
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected disk address type %s"),
virDomainDeviceAddressTypeToString(disk->info.type));
goto error;
}
/* Let's make sure the disk has a controller defined and loaded before
* trying to add it. The controller used by the disk must exist before a
* qemu command line string is generated.
*
* Ensure that the given controller and all controllers with a smaller index
* exist; there must not be any missing index in between.
*/
for (i = 0; i <= disk->info.addr.drive.controller; i++) {
if (!qemuDomainFindOrCreateSCSIDiskController(driver, vm, i))
goto error;
}
if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
goto error;
if (qemuDomainSecretDiskPrepare(conn, priv, disk) < 0)
goto error;
diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
encinfo = diskPriv->encinfo;
if (encinfo && qemuBuildSecretInfoProps(encinfo, &encobjProps) < 0)
goto error;
if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
goto error;
if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
goto error;
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
goto error;
qemuDomainObjEnterMonitor(driver, vm);
if (encobjProps) {
rv = qemuMonitorAddObject(priv->mon, "secret", encinfo->s.aes.alias,
encobjProps);
encobjProps = NULL; /* qemuMonitorAddObject consumes */
if (rv < 0)
goto exit_monitor;
encobjAdded = true;
}
if (qemuMonitorAddDrive(priv->mon, drivestr) < 0)
goto exit_monitor;
driveAdded = true;
if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
goto exit_monitor;
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto error;
virDomainAuditDisk(vm, NULL, disk->src, "attach", true);
virDomainDiskInsertPreAlloced(vm->def, disk);
ret = 0;
cleanup:
virJSONValueFree(encobjProps);
qemuDomainSecretDiskDestroy(disk);
VIR_FREE(devstr);
VIR_FREE(drivestr);
virObjectUnref(cfg);
return ret;
exit_monitor:
/* XXX should call 'drive_del' on error but this does not exist yet */
if (driveAdded)
VIR_WARN("qemuMonitorAddDevice failed on %s (%s)", drivestr, devstr);
orig_err = virSaveLastError();
if (encobjAdded)
ignore_value(qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias));
if (orig_err) {
virSetError(orig_err);
virFreeError(orig_err);
}
ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditDisk(vm, NULL, disk->src, "attach", false);
error:
ignore_value(qemuDomainPrepareDisk(driver, vm, disk, NULL, true));
goto cleanup;
}
static int
qemuDomainAttachUSBMassStorageDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret = -1;
char *drivestr = NULL;
char *devstr = NULL;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
const char *src = virDomainDiskGetSource(disk);
bool releaseaddr = false;
if (priv->usbaddrs) {
if (virDomainUSBAddressEnsure(priv->usbaddrs, &disk->info) < 0)
goto cleanup;
releaseaddr = true;
}
if (qemuDomainPrepareDisk(driver, vm, disk, NULL, false) < 0)
goto cleanup;
/* XXX not correct once we allow attaching a USB CDROM */
if (!src) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("disk source path is missing"));
goto error;
}
if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
goto error;
if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
goto error;
if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
goto error;
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
goto error;
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorAddDrive(priv->mon, drivestr);
if (ret == 0) {
ret = qemuMonitorAddDevice(priv->mon, devstr);
if (ret < 0) {
VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
drivestr, devstr);
/* XXX should call 'drive_del' on error but this does not
exist yet */
}
}
if (qemuDomainObjExitMonitor(driver, vm) < 0) {
ret = -1;
goto error;
}
virDomainAuditDisk(vm, NULL, disk->src, "attach", ret >= 0);
if (ret < 0)
goto error;
virDomainDiskInsertPreAlloced(vm->def, disk);
cleanup:
if (ret < 0 && releaseaddr)
virDomainUSBAddressRelease(priv->usbaddrs, &disk->info);
VIR_FREE(devstr);
VIR_FREE(drivestr);
virObjectUnref(cfg);
return ret;
error:
ignore_value(qemuDomainPrepareDisk(driver, vm, disk, NULL, true));
goto cleanup;
}
int
qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
size_t i;
virDomainDiskDefPtr disk = dev->data.disk;
virDomainDiskDefPtr orig_disk = NULL;
int ret = -1;
const char *src = virDomainDiskGetSource(disk);
if (STRNEQ_NULLABLE(virDomainDiskGetDriver(disk), "qemu")) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported driver name '%s' for disk '%s'"),
virDomainDiskGetDriver(disk), src);
goto cleanup;
}
if (virStorageTranslateDiskSourcePool(conn, disk) < 0)
goto cleanup;
if (qemuAddSharedDevice(driver, dev, vm->def->name) < 0)
goto cleanup;
if (qemuSetUnprivSGIO(dev) < 0)
goto cleanup;
if (qemuDomainDetermineDiskChain(driver, vm, disk, false, true) < 0)
goto cleanup;
switch ((virDomainDiskDevice) disk->device) {
case VIR_DOMAIN_DISK_DEVICE_CDROM:
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
if (!(orig_disk = virDomainDiskFindByBusAndDst(vm->def,
disk->bus, disk->dst))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("No device with bus '%s' and target '%s'. "
"cdrom and floppy device hotplug isn't supported "
"by libvirt"),
virDomainDiskBusTypeToString(disk->bus),
disk->dst);
goto cleanup;
}
if (qemuDomainChangeEjectableMedia(driver, vm, orig_disk,
disk->src, false) < 0)
goto cleanup;
disk->src = NULL;
ret = 0;
break;
case VIR_DOMAIN_DISK_DEVICE_DISK:
case VIR_DOMAIN_DISK_DEVICE_LUN:
for (i = 0; i < vm->def->ndisks; i++) {
if (virDomainDiskDefCheckDuplicateInfo(vm->def->disks[i], disk) < 0)
goto cleanup;
}
switch ((virDomainDiskBus) disk->bus) {
case VIR_DOMAIN_DISK_BUS_USB:
if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("disk device='lun' is not supported for usb bus"));
break;
}
ret = qemuDomainAttachUSBMassStorageDevice(driver, vm, disk);
break;
case VIR_DOMAIN_DISK_BUS_VIRTIO:
ret = qemuDomainAttachVirtioDiskDevice(conn, driver, vm, disk);
break;
case VIR_DOMAIN_DISK_BUS_SCSI:
ret = qemuDomainAttachSCSIDisk(conn, driver, vm, disk);
break;
case VIR_DOMAIN_DISK_BUS_IDE:
case VIR_DOMAIN_DISK_BUS_FDC:
case VIR_DOMAIN_DISK_BUS_XEN:
case VIR_DOMAIN_DISK_BUS_UML:
case VIR_DOMAIN_DISK_BUS_SATA:
case VIR_DOMAIN_DISK_BUS_SD:
case VIR_DOMAIN_DISK_BUS_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("disk bus '%s' cannot be hotplugged."),
virDomainDiskBusTypeToString(disk->bus));
}
break;
case VIR_DOMAIN_DISK_DEVICE_LAST:
break;
}
cleanup:
if (ret != 0)
ignore_value(qemuRemoveSharedDevice(driver, dev, vm->def->name));
return ret;
}
int
qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainNetDefPtr net)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
char **tapfdName = NULL;
int *tapfd = NULL;
size_t tapfdSize = 0;
char **vhostfdName = NULL;
int *vhostfd = NULL;
size_t vhostfdSize = 0;
char *nicstr = NULL;
char *netstr = NULL;
virNetDevVPortProfilePtr vport = NULL;
int ret = -1;
int vlan;
bool releaseaddr = false;
bool iface_connected = false;
int actualType;
virNetDevBandwidthPtr actualBandwidth;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
virDomainCCWAddressSetPtr ccwaddrs = NULL;
size_t i;
qemu: support type=hostdev network device live hotplug attach/detach qemuDomainAttachNetDevice - re-ordered some things at start of function because networkAllocateActualDevice should always be run and a slot in def->nets always allocated, but host_net_add isn't needed if the actual type is hostdev. - if actual type is hostdev, defer to qemuDomainAttachHostDevice (which will reach up to the NetDef for things like MAC address when necessary). After return from qemuDomainAttachHostDevice, slip directly to cleanup, since the rest of the function is specific to emulated net devices. - put assignment of new NetDef into expanded def->nets down below cleanup: (but only on success) since it is also needed for emulated and hostdev net devices. qemuDomainDetachHostDevice - after locating the exact device to detach, check if it's a network device and, if so, use toplevel qemuDomainDetachNetDevice instead so that the def->nets list is properly updated, and 'actual device' properly returned to network pool if appropriate. Otherwise, for normal hostdevs, call the lower level qemuDomainDetachThisDevice. qemuDomainDetachNetDevice - This is where it gets a bit tricky. After locating the device on the def->nets list, if the network device type == hostdev, call the *lower level* qemuDomainDetachThisDevice (which will reach back up to the parent net device for MAC address / virtualport when appropriate, then clear the device out of def->hostdevs) before skipping past all the emulated net-device-specific code to cleanup:, where the network device is removed from def->nets, and the network device object is freed. In short, any time a hostdev-type network device is detached, we must go through the toplevel virDomaineDetachNetDevice function first and last, to make sure 1) the def->nnets list is properly managed, and 2) any device allocated with networkAllocateActualDevice is properly freed. At the same time, in the middle we need to go through the lower-level vidDomainDetach*This*HostDevice to be sure that 1) the def->hostdevs list is properly managed, 2) the PCI device is properly detached from the guest and reattached to the host (if appropriate), and 3) any higher level teardown is called at the appropriate time, by reaching back up to the NetDef config (part (3) will be covered in a separate patch).
2012-02-27 19:20:17 +00:00
/* preallocate new slot for device */
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
goto cleanup;
/* If appropriate, grab a physical device from the configured
* network's pool of devices, or resolve bridge device name
* to the one defined in the network definition.
*/
if (networkAllocateActualDevice(vm->def, net) < 0)
goto cleanup;
actualType = virDomainNetGetActualType(net);
qemu: support type=hostdev network device live hotplug attach/detach qemuDomainAttachNetDevice - re-ordered some things at start of function because networkAllocateActualDevice should always be run and a slot in def->nets always allocated, but host_net_add isn't needed if the actual type is hostdev. - if actual type is hostdev, defer to qemuDomainAttachHostDevice (which will reach up to the NetDef for things like MAC address when necessary). After return from qemuDomainAttachHostDevice, slip directly to cleanup, since the rest of the function is specific to emulated net devices. - put assignment of new NetDef into expanded def->nets down below cleanup: (but only on success) since it is also needed for emulated and hostdev net devices. qemuDomainDetachHostDevice - after locating the exact device to detach, check if it's a network device and, if so, use toplevel qemuDomainDetachNetDevice instead so that the def->nets list is properly updated, and 'actual device' properly returned to network pool if appropriate. Otherwise, for normal hostdevs, call the lower level qemuDomainDetachThisDevice. qemuDomainDetachNetDevice - This is where it gets a bit tricky. After locating the device on the def->nets list, if the network device type == hostdev, call the *lower level* qemuDomainDetachThisDevice (which will reach back up to the parent net device for MAC address / virtualport when appropriate, then clear the device out of def->hostdevs) before skipping past all the emulated net-device-specific code to cleanup:, where the network device is removed from def->nets, and the network device object is freed. In short, any time a hostdev-type network device is detached, we must go through the toplevel virDomaineDetachNetDevice function first and last, to make sure 1) the def->nnets list is properly managed, and 2) any device allocated with networkAllocateActualDevice is properly freed. At the same time, in the middle we need to go through the lower-level vidDomainDetach*This*HostDevice to be sure that 1) the def->hostdevs list is properly managed, 2) the PCI device is properly detached from the guest and reattached to the host (if appropriate), and 3) any higher level teardown is called at the appropriate time, by reaching back up to the NetDef config (part (3) will be covered in a separate patch).
2012-02-27 19:20:17 +00:00
if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
/* This is really a "smart hostdev", so it should be attached
* as a hostdev (the hostdev code will reach over into the
* netdev-specific code as appropriate), then also added to
* the nets list (see cleanup:) if successful.
*
* qemuDomainAttachHostDevice uses a connection to resolve
* a SCSI hostdev secret, which is not this case, so pass NULL.
qemu: support type=hostdev network device live hotplug attach/detach qemuDomainAttachNetDevice - re-ordered some things at start of function because networkAllocateActualDevice should always be run and a slot in def->nets always allocated, but host_net_add isn't needed if the actual type is hostdev. - if actual type is hostdev, defer to qemuDomainAttachHostDevice (which will reach up to the NetDef for things like MAC address when necessary). After return from qemuDomainAttachHostDevice, slip directly to cleanup, since the rest of the function is specific to emulated net devices. - put assignment of new NetDef into expanded def->nets down below cleanup: (but only on success) since it is also needed for emulated and hostdev net devices. qemuDomainDetachHostDevice - after locating the exact device to detach, check if it's a network device and, if so, use toplevel qemuDomainDetachNetDevice instead so that the def->nets list is properly updated, and 'actual device' properly returned to network pool if appropriate. Otherwise, for normal hostdevs, call the lower level qemuDomainDetachThisDevice. qemuDomainDetachNetDevice - This is where it gets a bit tricky. After locating the device on the def->nets list, if the network device type == hostdev, call the *lower level* qemuDomainDetachThisDevice (which will reach back up to the parent net device for MAC address / virtualport when appropriate, then clear the device out of def->hostdevs) before skipping past all the emulated net-device-specific code to cleanup:, where the network device is removed from def->nets, and the network device object is freed. In short, any time a hostdev-type network device is detached, we must go through the toplevel virDomaineDetachNetDevice function first and last, to make sure 1) the def->nnets list is properly managed, and 2) any device allocated with networkAllocateActualDevice is properly freed. At the same time, in the middle we need to go through the lower-level vidDomainDetach*This*HostDevice to be sure that 1) the def->hostdevs list is properly managed, 2) the PCI device is properly detached from the guest and reattached to the host (if appropriate), and 3) any higher level teardown is called at the appropriate time, by reaching back up to the NetDef config (part (3) will be covered in a separate patch).
2012-02-27 19:20:17 +00:00
*/
ret = qemuDomainAttachHostDevice(NULL, driver, vm,
qemu: support type=hostdev network device live hotplug attach/detach qemuDomainAttachNetDevice - re-ordered some things at start of function because networkAllocateActualDevice should always be run and a slot in def->nets always allocated, but host_net_add isn't needed if the actual type is hostdev. - if actual type is hostdev, defer to qemuDomainAttachHostDevice (which will reach up to the NetDef for things like MAC address when necessary). After return from qemuDomainAttachHostDevice, slip directly to cleanup, since the rest of the function is specific to emulated net devices. - put assignment of new NetDef into expanded def->nets down below cleanup: (but only on success) since it is also needed for emulated and hostdev net devices. qemuDomainDetachHostDevice - after locating the exact device to detach, check if it's a network device and, if so, use toplevel qemuDomainDetachNetDevice instead so that the def->nets list is properly updated, and 'actual device' properly returned to network pool if appropriate. Otherwise, for normal hostdevs, call the lower level qemuDomainDetachThisDevice. qemuDomainDetachNetDevice - This is where it gets a bit tricky. After locating the device on the def->nets list, if the network device type == hostdev, call the *lower level* qemuDomainDetachThisDevice (which will reach back up to the parent net device for MAC address / virtualport when appropriate, then clear the device out of def->hostdevs) before skipping past all the emulated net-device-specific code to cleanup:, where the network device is removed from def->nets, and the network device object is freed. In short, any time a hostdev-type network device is detached, we must go through the toplevel virDomaineDetachNetDevice function first and last, to make sure 1) the def->nnets list is properly managed, and 2) any device allocated with networkAllocateActualDevice is properly freed. At the same time, in the middle we need to go through the lower-level vidDomainDetach*This*HostDevice to be sure that 1) the def->hostdevs list is properly managed, 2) the PCI device is properly detached from the guest and reattached to the host (if appropriate), and 3) any higher level teardown is called at the appropriate time, by reaching back up to the NetDef config (part (3) will be covered in a separate patch).
2012-02-27 19:20:17 +00:00
virDomainNetGetActualHostdev(net));
goto cleanup;
}
/* Currently only TAP/macvtap devices supports multiqueue. */
2013-04-18 08:47:01 +00:00
if (net->driver.virtio.queues > 0 &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
actualType == VIR_DOMAIN_NET_TYPE_DIRECT ||
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
2013-04-18 08:47:01 +00:00
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Multiqueue network is not supported for: %s"),
virDomainNetTypeToString(actualType));
return -1;
}
/* and only TAP devices support nwfilter rules */
if (net->filter &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("filterref is not supported for "
"network interfaces of type %s"),
virDomainNetTypeToString(actualType));
return -1;
}
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
2013-04-18 08:47:01 +00:00
tapfdSize = vhostfdSize = net->driver.virtio.queues;
if (!tapfdSize)
tapfdSize = vhostfdSize = 1;
if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
goto cleanup;
memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
goto cleanup;
memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
if (qemuInterfaceBridgeConnect(vm->def, driver, net,
tapfd, &tapfdSize) < 0)
goto cleanup;
iface_connected = true;
if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
vhostfd, &vhostfdSize) < 0)
goto cleanup;
} else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
tapfdSize = vhostfdSize = net->driver.virtio.queues;
if (!tapfdSize)
tapfdSize = vhostfdSize = 1;
if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
goto cleanup;
memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
goto cleanup;
memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
if (qemuInterfaceDirectConnect(vm->def, driver, net,
tapfd, tapfdSize,
VIR_NETDEV_VPORT_PROFILE_OP_CREATE) < 0)
goto cleanup;
iface_connected = true;
if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
vhostfd, &vhostfdSize) < 0)
goto cleanup;
} else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
tapfdSize = vhostfdSize = net->driver.virtio.queues;
if (!tapfdSize)
tapfdSize = vhostfdSize = 1;
if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
goto cleanup;
memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
goto cleanup;
memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
if (qemuInterfaceEthernetConnect(vm->def, driver, net,
tapfd, tapfdSize) < 0)
goto cleanup;
iface_connected = true;
if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
vhostfd, &vhostfdSize) < 0)
goto cleanup;
}
/* Set device online immediately */
if (qemuInterfaceStartDevice(net) < 0)
goto cleanup;
/* Set bandwidth or warn if requested and not supported. */
actualBandwidth = virDomainNetGetActualBandwidth(net);
if (actualBandwidth) {
if (virNetDevSupportBandwidth(actualType)) {
if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false) < 0)
goto cleanup;
} else {
VIR_WARN("setting bandwidth on interfaces of "
"type '%s' is not implemented yet",
virDomainNetTypeToString(actualType));
}
}
for (i = 0; i < tapfdSize; i++) {
if (virSecurityManagerSetTapFDLabel(driver->securityManager,
vm->def, tapfd[i]) < 0)
goto cleanup;
}
if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
goto cleanup;
if (qemuDomainMachineIsS390CCW(vm->def) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
goto cleanup;
if (virDomainCCWAddressAssign(&net->info, ccwaddrs,
!net->info.addr.ccw.assigned) < 0)
goto cleanup;
} else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("virtio-s390 net device cannot be hotplugged."));
goto cleanup;
} else if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0) {
goto cleanup;
}
releaseaddr = true;
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
vlan = -1;
} else {
vlan = qemuDomainNetVLAN(net);
if (vlan < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Unable to attach network devices without vlan"));
goto cleanup;
}
}
if (VIR_ALLOC_N(tapfdName, tapfdSize) < 0 ||
VIR_ALLOC_N(vhostfdName, vhostfdSize) < 0)
goto cleanup;
for (i = 0; i < tapfdSize; i++) {
if (virAsprintf(&tapfdName[i], "fd-%s%zu", net->info.alias, i) < 0)
goto cleanup;
}
for (i = 0; i < vhostfdSize; i++) {
if (virAsprintf(&vhostfdName[i], "vhostfd-%s%zu", net->info.alias, i) < 0)
goto cleanup;
}
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
if (!(netstr = qemuBuildHostNetStr(net, driver,
',', -1,
tapfdName, tapfdSize,
vhostfdName, vhostfdSize)))
goto cleanup;
} else {
if (!(netstr = qemuBuildHostNetStr(net, driver,
' ', vlan,
tapfdName, tapfdSize,
vhostfdName, vhostfdSize)))
goto cleanup;
}
qemuDomainObjEnterMonitor(driver, vm);
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
if (qemuMonitorAddNetdev(priv->mon, netstr,
tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditNet(vm, NULL, net, "attach", false);
goto cleanup;
}
} else {
if (qemuMonitorAddHostNetwork(priv->mon, netstr,
tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditNet(vm, NULL, net, "attach", false);
goto cleanup;
}
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
for (i = 0; i < tapfdSize; i++)
VIR_FORCE_CLOSE(tapfd[i]);
for (i = 0; i < vhostfdSize; i++)
VIR_FORCE_CLOSE(vhostfd[i]);
if (!(nicstr = qemuBuildNicDevStr(vm->def, net, vlan, 0,
vhostfdSize, priv->qemuCaps)))
goto try_remove;
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditNet(vm, NULL, net, "attach", false);
goto try_remove;
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
/* set link state */
if (net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
if (!net->info.alias) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("device alias not found: cannot set link state to down"));
} else {
qemuDomainObjEnterMonitor(driver, vm);
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
if (qemuMonitorSetLink(priv->mon, net->info.alias, VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditNet(vm, NULL, net, "attach", false);
goto try_remove;
}
} else {
maint: don't permit format strings without % Any time we have a string with no % passed through gettext, a translator can inject a % to cause a stack overread. When there is nothing to format, it's easier to ask for a string that cannot be used as a formatter, by using a trivial "%s" format instead. In the past, we have used --disable-nls to catch some of the offenders, but that doesn't get run very often, and many more uses have crept in. Syntax check to the rescue! The syntax check can catch uses such as virReportError(code, _("split " "string")); by using a sed script to fold context lines into one pattern space before checking for a string without %. This patch is just mechanical insertion of %s; there are probably several messages touched by this patch where we would be better off giving the user more information than a fixed string. * cfg.mk (sc_prohibit_diagnostic_without_format): New rule. * src/datatypes.c (virUnrefConnect, virGetDomain) (virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface) (virUnrefInterface, virGetStoragePool, virUnrefStoragePool) (virGetStorageVol, virUnrefStorageVol, virGetNodeDevice) (virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter) (virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper. * src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters) (lxcDomainGetBlkioParameters): Likewise. * src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML) (virDomainDiskDefParseXML, virDomainGraphicsDefParseXML): Likewise. * src/conf/network_conf.c (virNetworkDNSHostsDefParseXML) (virNetworkDefParseXML): Likewise. * src/conf/nwfilter_conf.c (virNWFilterIsValidChainName): Likewise. * src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple) (virNWFilterVarAccessParse): Likewise. * src/libvirt.c (virDomainSave, virDomainSaveFlags) (virDomainRestore, virDomainRestoreFlags) (virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML) (virDomainCoreDump, virDomainGetXMLDesc) (virDomainMigrateVersion1, virDomainMigrateVersion2) (virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2) (virStreamSendAll, virStreamRecvAll) (virDomainSnapshotGetXMLDesc): Likewise. * src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel) (virNWFilterDHCPSnoopReq): Likewise. * src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise. * src/openvz/openvz_util.c (openvzKBPerPages): Likewise. * src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise. * src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr) (qemuBuildCommandLine): Likewise. * src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise. * src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity): Likewise. * src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX) (virNetSocketSendFD, virNetSocketRecvFD): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskBuildPool): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendFileSystemProbe) (virStorageBackendFileSystemBuild): Likewise. * src/storage/storage_backend_rbd.c (virStorageBackendRBDOpenRADOSConn): Likewise. * src/storage/storage_driver.c (storageVolumeResize): Likewise. * src/test/test_driver.c (testInterfaceChangeBegin) (testInterfaceChangeCommit, testInterfaceChangeRollback): Likewise. * src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise. * src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk) (xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("setting of link state not supported: Link is up"));
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
}
/* link set to down */
}
virDomainAuditNet(vm, NULL, net, "attach", true);
ret = 0;
cleanup:
qemu: support type=hostdev network device live hotplug attach/detach qemuDomainAttachNetDevice - re-ordered some things at start of function because networkAllocateActualDevice should always be run and a slot in def->nets always allocated, but host_net_add isn't needed if the actual type is hostdev. - if actual type is hostdev, defer to qemuDomainAttachHostDevice (which will reach up to the NetDef for things like MAC address when necessary). After return from qemuDomainAttachHostDevice, slip directly to cleanup, since the rest of the function is specific to emulated net devices. - put assignment of new NetDef into expanded def->nets down below cleanup: (but only on success) since it is also needed for emulated and hostdev net devices. qemuDomainDetachHostDevice - after locating the exact device to detach, check if it's a network device and, if so, use toplevel qemuDomainDetachNetDevice instead so that the def->nets list is properly updated, and 'actual device' properly returned to network pool if appropriate. Otherwise, for normal hostdevs, call the lower level qemuDomainDetachThisDevice. qemuDomainDetachNetDevice - This is where it gets a bit tricky. After locating the device on the def->nets list, if the network device type == hostdev, call the *lower level* qemuDomainDetachThisDevice (which will reach back up to the parent net device for MAC address / virtualport when appropriate, then clear the device out of def->hostdevs) before skipping past all the emulated net-device-specific code to cleanup:, where the network device is removed from def->nets, and the network device object is freed. In short, any time a hostdev-type network device is detached, we must go through the toplevel virDomaineDetachNetDevice function first and last, to make sure 1) the def->nnets list is properly managed, and 2) any device allocated with networkAllocateActualDevice is properly freed. At the same time, in the middle we need to go through the lower-level vidDomainDetach*This*HostDevice to be sure that 1) the def->hostdevs list is properly managed, 2) the PCI device is properly detached from the guest and reattached to the host (if appropriate), and 3) any higher level teardown is called at the appropriate time, by reaching back up to the NetDef config (part (3) will be covered in a separate patch).
2012-02-27 19:20:17 +00:00
if (!ret) {
vm->def->nets[vm->def->nnets++] = net;
} else {
if (releaseaddr)
qemuDomainReleaseDeviceAddress(vm, &net->info, NULL);
if (iface_connected) {
virDomainConfNWFilterTeardown(net);
if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
net->ifname, &net->mac,
virDomainNetGetActualDirectDev(net),
virDomainNetGetActualDirectMode(net),
virDomainNetGetActualVirtPortProfile(net),
cfg->stateDir));
}
vport = virDomainNetGetActualVirtPortProfile(net);
if (vport) {
if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_MIDONET) {
ignore_value(virNetDevMidonetUnbindPort(vport));
} else if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
ignore_value(virNetDevOpenvswitchRemovePort(
virDomainNetGetActualBridgeName(net),
net->ifname));
}
}
}
virDomainNetRemoveHostdev(vm->def, net);
networkReleaseActualDevice(vm->def, net);
}
VIR_FREE(nicstr);
VIR_FREE(netstr);
2013-04-18 08:47:01 +00:00
for (i = 0; tapfd && i < tapfdSize; i++) {
VIR_FORCE_CLOSE(tapfd[i]);
2013-04-18 08:47:01 +00:00
if (tapfdName)
VIR_FREE(tapfdName[i]);
}
VIR_FREE(tapfd);
VIR_FREE(tapfdName);
2013-04-18 08:47:01 +00:00
for (i = 0; vhostfd && i < vhostfdSize; i++) {
VIR_FORCE_CLOSE(vhostfd[i]);
2013-04-18 08:47:01 +00:00
if (vhostfdName)
VIR_FREE(vhostfdName[i]);
}
VIR_FREE(vhostfd);
VIR_FREE(vhostfdName);
virObjectUnref(cfg);
virDomainCCWAddressSetFree(ccwaddrs);
return ret;
try_remove:
if (!virDomainObjIsActive(vm))
goto cleanup;
if (vlan < 0) {
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
char *netdev_name;
if (virAsprintf(&netdev_name, "host%s", net->info.alias) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
VIR_WARN("Failed to remove network backend for netdev %s",
netdev_name);
ignore_value(qemuDomainObjExitMonitor(driver, vm));
VIR_FREE(netdev_name);
} else {
VIR_WARN("Unable to remove network backend");
}
} else {
char *hostnet_name;
if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
VIR_WARN("Failed to remove network backend for vlan %d, net %s",
vlan, hostnet_name);
ignore_value(qemuDomainObjExitMonitor(driver, vm));
VIR_FREE(hostnet_name);
}
goto cleanup;
}
static int
qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret;
char *devstr = NULL;
int configfd = -1;
char *configfd_name = NULL;
bool releaseaddr = false;
bool teardowncgroup = false;
bool teardownlabel = false;
int backend;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
unsigned int flags = 0;
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
goto cleanup;
if (!cfg->relaxedACS)
flags |= VIR_HOSTDEV_STRICT_ACS_CHECK;
if (qemuHostdevPreparePCIDevices(driver, vm->def->name, vm->def->uuid,
&hostdev, 1, priv->qemuCaps, flags) < 0)
goto cleanup;
/* this could have been changed by qemuHostdevPreparePCIDevices */
backend = hostdev->source.subsys.u.pci.backend;
switch ((virDomainHostdevSubsysPCIBackendType) backend) {
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("VFIO PCI device assignment is not "
"supported by this version of qemu"));
goto error;
}
break;
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
break;
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN:
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("QEMU does not support device assignment mode '%s'"),
virDomainHostdevSubsysPCIBackendTypeToString(backend));
goto error;
break;
}
/* Temporarily add the hostdev to the domain definition. This is needed
* because qemuDomainAdjustMaxMemLock() requires the hostdev to be already
* part of the domain definition, but other functions like
* qemuAssignDeviceHostdevAlias() used below expect it *not* to be there.
* A better way to handle this would be nice */
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
if (qemuDomainAdjustMaxMemLock(vm) < 0) {
vm->def->hostdevs[--(vm->def->nhostdevs)] = NULL;
goto error;
}
vm->def->hostdevs[--(vm->def->nhostdevs)] = NULL;
if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
goto error;
teardowncgroup = true;
if (virSecurityManagerSetHostdevLabel(driver->securityManager,
vm->def, hostdev, NULL) < 0)
goto error;
if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
teardownlabel = true;
if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
goto error;
if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, hostdev->info) < 0)
goto error;
releaseaddr = true;
if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_PCI_CONFIGFD)) {
configfd = qemuOpenPCIConfig(hostdev);
if (configfd >= 0) {
if (virAsprintf(&configfd_name, "fd-%s",
hostdev->info->alias) < 0)
goto error;
}
}
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("guest unexpectedly quit during hotplug"));
goto error;
}
if (!(devstr = qemuBuildPCIHostdevDevStr(vm->def, hostdev, 0,
configfd_name, priv->qemuCaps)))
goto error;
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr,
configfd, configfd_name);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto error;
virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
if (ret < 0)
goto error;
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
VIR_FREE(devstr);
VIR_FREE(configfd_name);
VIR_FORCE_CLOSE(configfd);
virObjectUnref(cfg);
return 0;
error:
if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
if (teardownlabel &&
virSecurityManagerRestoreHostdevLabel(driver->securityManager,
vm->def, hostdev, NULL) < 0)
VIR_WARN("Unable to restore host device labelling on hotplug fail");
if (releaseaddr)
qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
VIR_FREE(devstr);
VIR_FREE(configfd_name);
VIR_FORCE_CLOSE(configfd);
cleanup:
virObjectUnref(cfg);
return -1;
}
int qemuDomainAttachRedirdevDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainRedirdevDefPtr redirdev)
{
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainDefPtr def = vm->def;
char *charAlias = NULL;
char *devstr = NULL;
if (qemuAssignDeviceRedirdevAlias(def, redirdev, -1) < 0)
goto cleanup;
if (virAsprintf(&charAlias, "char%s", redirdev->info.alias) < 0)
goto cleanup;
if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, priv->qemuCaps)))
goto cleanup;
if (VIR_REALLOC_N(def->redirdevs, def->nredirdevs+1) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorAttachCharDev(priv->mon,
charAlias,
&(redirdev->source.chr)) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm));
goto audit;
}
if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
/* detach associated chardev on error */
qemuMonitorDetachCharDev(priv->mon, charAlias);
ignore_value(qemuDomainObjExitMonitor(driver, vm));
goto audit;
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto audit;
def->redirdevs[def->nredirdevs++] = redirdev;
ret = 0;
audit:
virDomainAuditRedirdev(vm, redirdev, "attach", ret == 0);
cleanup:
VIR_FREE(charAlias);
VIR_FREE(devstr);
return ret;
}
static int
qemuDomainChrPreInsert(virDomainDefPtr vmdef,
virDomainChrDefPtr chr)
{
if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("attaching serial console is not supported"));
return -1;
}
if (virDomainChrFind(vmdef, chr)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("chardev already exists"));
return -1;
}
if (virDomainChrPreAlloc(vmdef, chr) < 0)
return -1;
/* Due to some crazy backcompat stuff, the first serial device is an alias
* to the first console too. If this is the case, the definition must be
* duplicated as first console device. */
if (vmdef->nserials == 0 && vmdef->nconsoles == 0 &&
chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
if (!vmdef->consoles && VIR_ALLOC(vmdef->consoles) < 0)
return -1;
if (VIR_ALLOC(vmdef->consoles[0]) < 0) {
VIR_FREE(vmdef->consoles);
return -1;
}
vmdef->nconsoles++;
}
return 0;
}
static void
qemuDomainChrInsertPreAlloced(virDomainDefPtr vmdef,
virDomainChrDefPtr chr)
{
virDomainChrInsertPreAlloced(vmdef, chr);
if (vmdef->nserials == 1 && vmdef->nconsoles == 0 &&
chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
vmdef->nconsoles = 1;
/* Create an console alias for the serial port */
vmdef->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
vmdef->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
}
}
static void
qemuDomainChrInsertPreAllocCleanup(virDomainDefPtr vmdef,
virDomainChrDefPtr chr)
{
/* Remove the stub console added by qemuDomainChrPreInsert */
if (vmdef->nserials == 0 && vmdef->nconsoles == 1 &&
chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
VIR_FREE(vmdef->consoles[0]);
VIR_FREE(vmdef->consoles);
vmdef->nconsoles = 0;
}
}
int
qemuDomainChrInsert(virDomainDefPtr vmdef,
virDomainChrDefPtr chr)
{
if (qemuDomainChrPreInsert(vmdef, chr) < 0) {
qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
return -1;
}
qemuDomainChrInsertPreAlloced(vmdef, chr);
return 0;
}
virDomainChrDefPtr
qemuDomainChrRemove(virDomainDefPtr vmdef,
virDomainChrDefPtr chr)
{
virDomainChrDefPtr ret;
bool removeCompat;
if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("detaching serial console is not supported"));
return NULL;
}
/* Due to some crazy backcompat stuff, the first serial device is an alias
* to the first console too. If this is the case, the definition must be
* duplicated as first console device. */
removeCompat = vmdef->nserials && vmdef->nconsoles &&
vmdef->consoles[0]->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
vmdef->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL &&
virDomainChrEquals(vmdef->serials[0], chr);
if (!(ret = virDomainChrRemove(vmdef, chr))) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("device not present in domain configuration"));
return NULL;
}
if (removeCompat)
VIR_DELETE_ELEMENT(vmdef->consoles, 0, vmdef->nconsoles);
return ret;
}
static int
qemuDomainAttachChrDeviceAssignAddr(virDomainDefPtr def,
qemuDomainObjPrivatePtr priv,
virDomainChrDefPtr chr)
{
int ret = -1;
virDomainVirtioSerialAddrSetPtr vioaddrs = NULL;
if (!(vioaddrs = virDomainVirtioSerialAddrSetCreateFromDomain(def)))
goto cleanup;
if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
if (virDomainVirtioSerialAddrAutoAssign(NULL, vioaddrs,
&chr->info, true) < 0)
goto cleanup;
ret = 1;
} else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) {
if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &chr->info) < 0)
goto cleanup;
ret = 1;
} else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB) {
if (virDomainUSBAddressEnsure(priv->usbaddrs, &chr->info) < 0)
goto cleanup;
ret = 1;
} else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
if (virDomainVirtioSerialAddrAutoAssign(NULL, vioaddrs,
&chr->info, false) < 0)
goto cleanup;
ret = 1;
}
if (ret == 1)
goto cleanup;
if (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL ||
chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Unsupported address type for character device"));
goto cleanup;
}
ret = 0;
cleanup:
virDomainVirtioSerialAddrSetFree(vioaddrs);
return ret;
}
int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainChrDefPtr chr)
{
int ret = -1, rc;
qemuDomainObjPrivatePtr priv = vm->privateData;
virErrorPtr orig_err;
virDomainDefPtr vmdef = vm->def;
char *devstr = NULL;
char *charAlias = NULL;
bool chardevAttached = false;
bool need_release = false;
if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
qemuDomainPrepareChannel(chr, priv->channelTargetDir) < 0)
goto cleanup;
if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0)
goto cleanup;
if ((rc = qemuDomainAttachChrDeviceAssignAddr(vm->def, priv, chr)) < 0)
goto cleanup;
if (rc == 1)
need_release = true;
if (qemuBuildChrDeviceStr(&devstr, vmdef, chr, priv->qemuCaps) < 0)
goto cleanup;
2014-06-27 06:44:15 +00:00
if (virAsprintf(&charAlias, "char%s", chr->info.alias) < 0)
goto cleanup;
if (qemuDomainChrPreInsert(vmdef, chr) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorAttachCharDev(priv->mon, charAlias, &chr->source) < 0)
goto exit_monitor;
chardevAttached = true;
if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
goto exit_monitor;
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto audit;
qemuDomainChrInsertPreAlloced(vmdef, chr);
ret = 0;
audit:
virDomainAuditChardev(vm, NULL, chr, "attach", ret == 0);
cleanup:
if (ret < 0 && virDomainObjIsActive(vm))
qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
if (ret < 0 && need_release)
qemuDomainReleaseDeviceAddress(vm, &chr->info, NULL);
VIR_FREE(charAlias);
VIR_FREE(devstr);
return ret;
exit_monitor:
orig_err = virSaveLastError();
/* detach associated chardev on error */
if (chardevAttached)
qemuMonitorDetachCharDev(priv->mon, charAlias);
if (orig_err) {
virSetError(orig_err);
virFreeError(orig_err);
}
ignore_value(qemuDomainObjExitMonitor(driver, vm));
goto audit;
}
int
qemuDomainAttachRNGDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainRNGDefPtr rng)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virErrorPtr orig_err;
char *devstr = NULL;
char *charAlias = NULL;
char *objAlias = NULL;
bool releaseaddr = false;
bool chardevAdded = false;
bool objAdded = false;
virJSONValuePtr props = NULL;
virDomainCCWAddressSetPtr ccwaddrs = NULL;
const char *type;
int ret = -1;
int rv;
if (qemuAssignDeviceRNGAlias(vm->def, rng) < 0)
return -1;
/* preallocate space for the device definition */
if (VIR_REALLOC_N(vm->def->rngs, vm->def->nrngs + 1) < 0)
return -1;
if (rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
if (qemuDomainMachineIsS390CCW(vm->def) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
rng->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
} else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
rng->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390;
}
} else {
if (!qemuCheckCCWS390AddressSupport(vm->def, rng->info, priv->qemuCaps,
rng->source.file))
return -1;
}
releaseaddr = true;
if (rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &rng->info) < 0)
return -1;
} else if (rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
goto cleanup;
if (virDomainCCWAddressAssign(&rng->info, ccwaddrs,
!rng->info.addr.ccw.assigned) < 0)
goto cleanup;
}
/* build required metadata */
if (!(devstr = qemuBuildRNGDevStr(vm->def, rng, priv->qemuCaps)))
goto cleanup;
if (qemuBuildRNGBackendProps(rng, priv->qemuCaps, &type, &props) < 0)
goto cleanup;
if (virAsprintf(&objAlias, "obj%s", rng->info.alias) < 0)
goto cleanup;
if (virAsprintf(&charAlias, "char%s", rng->info.alias) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
qemuMonitorAttachCharDev(priv->mon, charAlias,
rng->source.chardev) < 0)
goto exit_monitor;
chardevAdded = true;
rv = qemuMonitorAddObject(priv->mon, type, objAlias, props);
props = NULL; /* qemuMonitorAddObject consumes */
if (rv < 0)
goto exit_monitor;
objAdded = true;
if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
goto exit_monitor;
if (qemuDomainObjExitMonitor(driver, vm) < 0) {
releaseaddr = false;
goto cleanup;
}
VIR_APPEND_ELEMENT_INPLACE(vm->def->rngs, vm->def->nrngs, rng);
ret = 0;
audit:
virDomainAuditRNG(vm, NULL, rng, "attach", ret == 0);
cleanup:
virJSONValueFree(props);
if (ret < 0 && releaseaddr)
qemuDomainReleaseDeviceAddress(vm, &rng->info, NULL);
VIR_FREE(charAlias);
VIR_FREE(objAlias);
VIR_FREE(devstr);
virDomainCCWAddressSetFree(ccwaddrs);
return ret;
exit_monitor:
orig_err = virSaveLastError();
if (objAdded)
ignore_value(qemuMonitorDelObject(priv->mon, objAlias));
if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD && chardevAdded)
ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
if (orig_err) {
virSetError(orig_err);
virFreeError(orig_err);
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
releaseaddr = false;
goto audit;
}
/**
* qemuDomainAttachMemory:
* @driver: qemu driver data
* @vm: VM object
* @mem: Definition of the memory device to be attached. @mem is always consumed
*
* Attaches memory device described by @mem to domain @vm.
*
* Returns 0 on success -1 on error.
*/
int
qemuDomainAttachMemory(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainMemoryDefPtr mem)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virErrorPtr orig_err;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
unsigned long long newmem = oldmem + mem->size;
char *devstr = NULL;
char *objalias = NULL;
const char *backendType;
bool objAdded = false;
virJSONValuePtr props = NULL;
virObjectEventPtr event;
int id;
int ret = -1;
int rv;
qemuDomainMemoryDeviceAlignSize(vm->def, mem);
if (qemuDomainDefValidateMemoryHotplug(vm->def, priv->qemuCaps, mem) < 0)
goto cleanup;
if (qemuAssignDeviceMemoryAlias(vm->def, mem) < 0)
goto cleanup;
if (virAsprintf(&objalias, "mem%s", mem->info.alias) < 0)
goto cleanup;
if (!(devstr = qemuBuildMemoryDeviceStr(mem)))
goto cleanup;
if (qemuBuildMemoryBackendStr(mem->size, mem->pagesize,
mem->targetNode, mem->sourceNodes, NULL,
vm->def, priv->qemuCaps, cfg,
&backendType, &props, true) < 0)
goto cleanup;
if (virDomainMemoryInsert(vm->def, mem) < 0) {
virJSONValueFree(props);
goto cleanup;
}
if (qemuDomainAdjustMaxMemLock(vm) < 0) {
virJSONValueFree(props);
goto removedef;
}
qemuDomainObjEnterMonitor(driver, vm);
rv = qemuMonitorAddObject(priv->mon, backendType, objalias, props);
props = NULL; /* qemuMonitorAddObject consumes */
if (rv < 0)
goto exit_monitor;
objAdded = true;
if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
goto exit_monitor;
if (qemuDomainObjExitMonitor(driver, vm) < 0) {
/* we shouldn't touch mem now, as the def might be freed */
mem = NULL;
goto audit;
}
event = virDomainEventDeviceAddedNewFromObj(vm, objalias);
qemuDomainEventQueue(driver, event);
/* fix the balloon size */
ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));
/* mem is consumed by vm->def */
mem = NULL;
/* this step is best effort, removing the device would be so much trouble */
ignore_value(qemuDomainUpdateMemoryDeviceInfo(driver, vm,
QEMU_ASYNC_JOB_NONE));
ret = 0;
audit:
virDomainAuditMemory(vm, oldmem, newmem, "update", ret == 0);
cleanup:
virObjectUnref(cfg);
VIR_FREE(devstr);
VIR_FREE(objalias);
virDomainMemoryDefFree(mem);
return ret;
exit_monitor:
orig_err = virSaveLastError();
if (objAdded)
ignore_value(qemuMonitorDelObject(priv->mon, objalias));
if (orig_err) {
virSetError(orig_err);
virFreeError(orig_err);
}
if (qemuDomainObjExitMonitor(driver, vm) < 0) {
mem = NULL;
goto audit;
}
removedef:
if ((id = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
mem = virDomainMemoryRemove(vm->def, id);
else
mem = NULL;
/* reset the mlock limit */
orig_err = virSaveLastError();
ignore_value(qemuDomainAdjustMaxMemLock(vm));
virSetError(orig_err);
virFreeError(orig_err);
goto audit;
}
static int
qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
char *devstr = NULL;
bool releaseaddr = false;
bool added = false;
bool teardowncgroup = false;
bool teardownlabel = false;
int ret = -1;
if (priv->usbaddrs) {
if (virDomainUSBAddressEnsure(priv->usbaddrs, hostdev->info) < 0)
goto cleanup;
releaseaddr = true;
}
if (qemuHostdevPrepareUSBDevices(driver, vm->def->name, &hostdev, 1, 0) < 0)
goto cleanup;
added = true;
if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
goto cleanup;
teardowncgroup = true;
if (virSecurityManagerSetHostdevLabel(driver->securityManager,
vm->def, hostdev, NULL) < 0)
goto cleanup;
teardownlabel = true;
if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
goto cleanup;
if (!(devstr = qemuBuildUSBHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
goto cleanup;
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorAddDevice(priv->mon, devstr);
if (qemuDomainObjExitMonitor(driver, vm) < 0) {
ret = -1;
goto cleanup;
}
virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
if (ret < 0)
goto cleanup;
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
ret = 0;
cleanup:
if (ret < 0) {
if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
if (teardownlabel &&
virSecurityManagerRestoreHostdevLabel(driver->securityManager,
vm->def, hostdev, NULL) < 0)
VIR_WARN("Unable to restore host device labelling on hotplug fail");
if (added)
qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
if (releaseaddr)
virDomainUSBAddressRelease(priv->usbaddrs, hostdev->info);
}
VIR_FREE(devstr);
return ret;
}
static int
qemuDomainAttachHostSCSIDevice(virConnectPtr conn,
virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
size_t i;
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
virErrorPtr orig_err;
char *devstr = NULL;
char *drvstr = NULL;
bool teardowncgroup = false;
bool teardownlabel = false;
bool driveAdded = false;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("SCSI passthrough is not supported by this version of qemu"));
return -1;
}
/* Let's make sure the disk has a controller defined and loaded before
* trying to add it. The controller used by the disk must exist before a
* qemu command line string is generated.
*
* Ensure that the given controller and all controllers with a smaller index
* exist; there must not be any missing index in between.
*/
for (i = 0; i <= hostdev->info->addr.drive.controller; i++) {
if (!qemuDomainFindOrCreateSCSIDiskController(driver, vm, i))
return -1;
}
if (qemuHostdevPrepareSCSIDevices(driver, vm->def->name,
&hostdev, 1)) {
virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unable to prepare scsi hostdev for iSCSI: %s"),
iscsisrc->path);
} else {
virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unable to prepare scsi hostdev: %s:%u:%u:%llu"),
scsihostsrc->adapter, scsihostsrc->bus,
scsihostsrc->target, scsihostsrc->unit);
}
return -1;
}
if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
goto cleanup;
teardowncgroup = true;
if (virSecurityManagerSetHostdevLabel(driver->securityManager,
vm->def, hostdev, NULL) < 0)
goto cleanup;
teardownlabel = true;
if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
goto cleanup;
if (qemuDomainSecretHostdevPrepare(conn, priv, hostdev) < 0)
goto cleanup;
if (!(drvstr = qemuBuildSCSIHostdevDrvStr(hostdev)))
goto cleanup;
if (!(devstr = qemuBuildSCSIHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
goto cleanup;
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorAddDrive(priv->mon, drvstr) < 0)
goto exit_monitor;
driveAdded = true;
if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
goto exit_monitor;
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditHostdev(vm, hostdev, "attach", true);
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
ret = 0;
cleanup:
qemuDomainSecretHostdevDestroy(hostdev);
if (ret < 0) {
qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
if (teardownlabel &&
virSecurityManagerRestoreHostdevLabel(driver->securityManager,
vm->def, hostdev, NULL) < 0)
VIR_WARN("Unable to restore host device labelling on hotplug fail");
}
VIR_FREE(drvstr);
VIR_FREE(devstr);
return ret;
exit_monitor:
orig_err = virSaveLastError();
if (driveAdded && qemuMonitorDriveDel(priv->mon, drvstr) < 0) {
VIR_WARN("Unable to remove drive %s (%s) after failed "
"qemuMonitorAddDevice",
drvstr, devstr);
}
if (orig_err) {
virSetError(orig_err);
virFreeError(orig_err);
}
ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditHostdev(vm, hostdev, "attach", false);
goto cleanup;
}
int
qemuDomainAttachHostDevice(virConnectPtr conn,
virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("hostdev mode '%s' not supported"),
virDomainHostdevModeTypeToString(hostdev->mode));
return -1;
}
switch (hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
if (qemuDomainAttachHostPCIDevice(driver, vm,
hostdev) < 0)
goto error;
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
if (qemuDomainAttachHostUSBDevice(driver, vm,
hostdev) < 0)
goto error;
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
if (qemuDomainAttachHostSCSIDevice(conn, driver, vm,
hostdev) < 0)
goto error;
break;
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("hostdev subsys type '%s' not supported"),
virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
goto error;
}
return 0;
error:
return -1;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
static int
qemuDomainChangeNetBridge(virDomainObjPtr vm,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
virDomainNetDefPtr olddev,
virDomainNetDefPtr newdev)
{
int ret = -1;
const char *oldbridge = virDomainNetGetActualBridgeName(olddev);
const char *newbridge = virDomainNetGetActualBridgeName(newdev);
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (!oldbridge || !newbridge) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
goto cleanup;
}
VIR_DEBUG("Change bridge for interface %s: %s -> %s",
olddev->ifname, oldbridge, newbridge);
if (virNetDevExists(newbridge) != 1) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("bridge %s doesn't exist"), newbridge);
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
goto cleanup;
}
if (oldbridge) {
ret = virNetDevBridgeRemovePort(oldbridge, olddev->ifname);
virDomainAuditNet(vm, olddev, NULL, "detach", ret == 0);
if (ret < 0) {
/* warn but continue - possibly the old network
* had been destroyed and reconstructed, leaving the
* tap device orphaned.
*/
VIR_WARN("Unable to detach device %s from bridge %s",
olddev->ifname, oldbridge);
}
}
ret = virNetDevBridgeAddPort(newbridge, olddev->ifname);
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
virDomainAuditNet(vm, NULL, newdev, "attach", ret == 0);
if (ret < 0) {
ret = virNetDevBridgeAddPort(oldbridge, olddev->ifname);
virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
if (ret < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("unable to recover former state by adding port "
"to bridge %s"), oldbridge);
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
goto cleanup;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
/* caller will replace entire olddev with newdev in domain nets list */
ret = 0;
cleanup:
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
return ret;
}
static int
qemuDomainChangeNetFilter(virDomainObjPtr vm,
virDomainNetDefPtr olddev,
virDomainNetDefPtr newdev)
{
/* make sure this type of device supports filters. */
switch (virDomainNetGetActualType(newdev)) {
case VIR_DOMAIN_NET_TYPE_ETHERNET:
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
break;
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("filters not supported on interfaces of type %s"),
virDomainNetTypeToString(virDomainNetGetActualType(newdev)));
return -1;
}
virDomainConfNWFilterTeardown(olddev);
if (newdev->filter &&
virDomainConfNWFilterInstantiate(vm->def->uuid, newdev) < 0) {
virErrorPtr errobj;
virReportError(VIR_ERR_OPERATION_FAILED,
_("failed to add new filter rules to '%s' "
"- attempting to restore old rules"),
olddev->ifname);
errobj = virSaveLastError();
ignore_value(virDomainConfNWFilterInstantiate(vm->def->uuid, olddev));
virSetError(errobj);
virFreeError(errobj);
return -1;
}
return 0;
}
int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainNetDefPtr dev,
int linkstate)
{
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
if (!dev->info.alias) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("can't change link state: device alias not found"));
return -1;
}
VIR_DEBUG("dev: %s, state: %d", dev->info.alias, linkstate);
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorSetLink(priv->mon, dev->info.alias, linkstate);
if (ret < 0)
goto cleanup;
if (virDomainNetGetActualType(dev) == VIR_DOMAIN_NET_TYPE_ETHERNET) {
switch (linkstate) {
case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP:
case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT:
if ((ret = virNetDevSetOnline(dev->ifname, true)) < 0)
goto cleanup;
break;
case VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN:
if ((ret = virNetDevSetOnline(dev->ifname, false)) < 0)
goto cleanup;
break;
}
}
/* modify the device configuration */
dev->linkstate = linkstate;
cleanup:
if (qemuDomainObjExitMonitor(driver, vm) < 0)
return -1;
return ret;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
int
qemuDomainChangeNet(virQEMUDriverPtr driver,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
virDomainNetDefPtr newdev = dev->data.net;
virDomainNetDefPtr *devslot = NULL;
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
virDomainNetDefPtr olddev;
int oldType, newType;
bool needReconnect = false;
bool needBridgeChange = false;
bool needFilterChange = false;
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
bool needLinkStateChange = false;
bool needReplaceDevDef = false;
bool needBandwidthSet = false;
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
int ret = -1;
int changeidx = -1;
if ((changeidx = virDomainNetFindIdx(vm->def, newdev)) < 0)
goto cleanup;
devslot = &vm->def->nets[changeidx];
if (!(olddev = *devslot)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("cannot find existing network device to modify"));
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
goto cleanup;
}
oldType = virDomainNetGetActualType(olddev);
if (oldType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
/* no changes are possible to a type='hostdev' interface */
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot change config of '%s' network type"),
virDomainNetTypeToString(oldType));
goto cleanup;
}
/* Check individual attributes for changes that can't be done to a
* live netdev. These checks *mostly* go in order of the
* declarations in virDomainNetDef in order to assure nothing is
* omitted. (exceptiong where noted in comments - in particular,
* some things require that a new "actual device" be allocated
* from the network driver first, but we delay doing that until
* after we've made as many other checks as possible)
*/
/* type: this can change (with some restrictions), but the actual
* type of the new device connection isn't known until after we
* allocate the "actual" device.
*/
if (virMacAddrCmp(&olddev->mac, &newdev->mac)) {
char oldmac[VIR_MAC_STRING_BUFLEN], newmac[VIR_MAC_STRING_BUFLEN];
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot change network interface mac address "
"from %s to %s"),
virMacAddrFormat(&olddev->mac, oldmac),
virMacAddrFormat(&newdev->mac, newmac));
goto cleanup;
}
if (STRNEQ_NULLABLE(olddev->model, newdev->model)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify network device model from %s to %s"),
olddev->model ? olddev->model : "(default)",
newdev->model ? newdev->model : "(default)");
goto cleanup;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (olddev->model && STREQ(olddev->model, "virtio") &&
(olddev->driver.virtio.name != newdev->driver.virtio.name ||
olddev->driver.virtio.txmode != newdev->driver.virtio.txmode ||
olddev->driver.virtio.ioeventfd != newdev->driver.virtio.ioeventfd ||
olddev->driver.virtio.event_idx != newdev->driver.virtio.event_idx ||
olddev->driver.virtio.queues != newdev->driver.virtio.queues ||
olddev->driver.virtio.host.csum != newdev->driver.virtio.host.csum ||
olddev->driver.virtio.host.gso != newdev->driver.virtio.host.gso ||
olddev->driver.virtio.host.tso4 != newdev->driver.virtio.host.tso4 ||
olddev->driver.virtio.host.tso6 != newdev->driver.virtio.host.tso6 ||
olddev->driver.virtio.host.ecn != newdev->driver.virtio.host.ecn ||
olddev->driver.virtio.host.ufo != newdev->driver.virtio.host.ufo ||
olddev->driver.virtio.host.mrg_rxbuf != newdev->driver.virtio.host.mrg_rxbuf ||
olddev->driver.virtio.guest.csum != newdev->driver.virtio.guest.csum ||
olddev->driver.virtio.guest.tso4 != newdev->driver.virtio.guest.tso4 ||
olddev->driver.virtio.guest.tso6 != newdev->driver.virtio.guest.tso6 ||
olddev->driver.virtio.guest.ecn != newdev->driver.virtio.guest.ecn ||
olddev->driver.virtio.guest.ufo != newdev->driver.virtio.guest.ufo)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify virtio network device driver attributes"));
goto cleanup;
}
/* data: this union will be examined later, after allocating new actualdev */
/* virtPortProfile: will be examined later, after allocating new actualdev */
if (olddev->tune.sndbuf_specified != newdev->tune.sndbuf_specified ||
olddev->tune.sndbuf != newdev->tune.sndbuf) {
needReconnect = true;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (STRNEQ_NULLABLE(olddev->script, newdev->script)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify network device script attribute"));
goto cleanup;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
/* ifname: check if it's set in newdev. If not, retain the autogenerated one */
if (!newdev->ifname && VIR_STRDUP(newdev->ifname, olddev->ifname) < 0)
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
goto cleanup;
if (STRNEQ_NULLABLE(olddev->ifname, newdev->ifname)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify network device tap name"));
goto cleanup;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
/* info: if newdev->info is empty, fill it in from olddev,
* otherwise verify that it matches - nothing is allowed to
* change. (There is no helper function to do this, so
* individually check the few feidls of virDomainDeviceInfo that
* are relevant in this case).
*/
if (!virDomainDeviceAddressIsValid(&newdev->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
virDomainDeviceInfoCopy(&newdev->info, &olddev->info) < 0) {
goto cleanup;
}
if (!virPCIDeviceAddressEqual(&olddev->info.addr.pci,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
&newdev->info.addr.pci)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify network device guest PCI address"));
goto cleanup;
}
/* grab alias from olddev if not set in newdev */
if (!newdev->info.alias &&
VIR_STRDUP(newdev->info.alias, olddev->info.alias) < 0)
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
goto cleanup;
if (STRNEQ_NULLABLE(olddev->info.alias, newdev->info.alias)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify network device alias"));
goto cleanup;
}
if (olddev->info.rombar != newdev->info.rombar) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify network device rom bar setting"));
goto cleanup;
}
if (STRNEQ_NULLABLE(olddev->info.romfile, newdev->info.romfile)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify network rom file"));
goto cleanup;
}
if (olddev->info.bootIndex != newdev->info.bootIndex) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot modify network device boot index setting"));
goto cleanup;
}
/* (end of device info checks) */
if (STRNEQ_NULLABLE(olddev->filter, newdev->filter) ||
!virNWFilterHashTableEqual(olddev->filterparams, newdev->filterparams)) {
needFilterChange = true;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
/* bandwidth can be modified, and will be checked later */
/* vlan can be modified, and will be checked later */
/* linkstate can be modified */
/* allocate new actual device to compare to old - we will need to
* free it if we fail for any reason
*/
if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
networkAllocateActualDevice(vm->def, newdev) < 0) {
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
goto cleanup;
}
newType = virDomainNetGetActualType(newdev);
if (newType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
/* can't turn it into a type='hostdev' interface */
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("cannot change network interface type to '%s'"),
virDomainNetTypeToString(newType));
goto cleanup;
}
if (olddev->type == newdev->type && oldType == newType) {
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
/* if type hasn't changed, check the relevant fields for the type */
switch (newdev->type) {
case VIR_DOMAIN_NET_TYPE_USER:
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
conf/openvz: eliminate incorrect/undocumented use of <source dev='blah'/> When support for <interface type='ethernet'> was added in commit 9a4b705f back in 2010, it erroneously looked at <source dev='blah'/> for a user-specified guest-side interface name. This was never documented though. (that attribute already existed at the time in the data.ethernet union member of virDomainNetDef, but apparently had no practical use - it was only used as a storage place for a NetDef's bridge name during qemuDomainXMLToNative(), but even then that was never used for anything). When support for similar guest-side device naming was added to the lxc driver several years later, it was put in a new subelement <guest dev='blah'/>. In the intervening years, since there was no validation that ethernet.dev was NULL in the other drivers that didn't actually use it, innocent souls who were adding other features assuming they needed to account for non-NULL ethernet.dev when really they didn't, so little bits of the usual pointless cargo-cult code showed up. This patch not only switches the openvz driver to use the documented <guest dev='blah'/> notation for naming the guest-side device (just in case anyone is still using the openvz driver), and logs an error if anyone tries to set <source dev='blah'/> for a type='ethernet' interface, it also removes the cargo-cult uses of ethernet.dev and <source dev='blah'/>, and eliminates if from the RNG and from virDomainNetDef. NB: I decided on this course of action after mentioning the inconsistency here: https://www.redhat.com/archives/libvir-list/2016-May/msg02038.html and getting encouragement do eliminate it in a later IRC discussion with danpb.
2016-06-21 19:20:57 +00:00
break;
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
case VIR_DOMAIN_NET_TYPE_SERVER:
case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_UDP:
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (STRNEQ_NULLABLE(olddev->data.socket.address,
newdev->data.socket.address) ||
olddev->data.socket.port != newdev->data.socket.port) {
needReconnect = true;
}
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
if (STRNEQ(olddev->data.network.name, newdev->data.network.name)) {
if (virDomainNetGetActualVirtPortProfile(newdev))
needReconnect = true;
else
needBridgeChange = true;
}
/* other things handled in common code directly below this switch */
break;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
/* all handled in bridge name checked in common code below */
break;
case VIR_DOMAIN_NET_TYPE_INTERNAL:
if (STRNEQ_NULLABLE(olddev->data.internal.name,
newdev->data.internal.name)) {
needReconnect = true;
}
break;
case VIR_DOMAIN_NET_TYPE_DIRECT:
/* all handled in common code directly below this switch */
break;
default:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("unable to change config on '%s' network type"),
virDomainNetTypeToString(newdev->type));
break;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
} else {
/* interface type has changed. There are a few special cases
* where this can only require a minor (or even no) change,
* but in most cases we need to do a full reconnection.
*
* If we switch (in either direction) between type='bridge'
* and type='network' (for a traditional managed virtual
* network that uses a host bridge, i.e. forward
* mode='route|nat'), we just need to change the bridge.
*/
if ((oldType == VIR_DOMAIN_NET_TYPE_NETWORK &&
newType == VIR_DOMAIN_NET_TYPE_BRIDGE) ||
(oldType == VIR_DOMAIN_NET_TYPE_BRIDGE &&
newType == VIR_DOMAIN_NET_TYPE_NETWORK)) {
needBridgeChange = true;
} else if (oldType == VIR_DOMAIN_NET_TYPE_DIRECT &&
newType == VIR_DOMAIN_NET_TYPE_DIRECT) {
/* this is the case of switching from type='direct' to
* type='network' for a network that itself uses direct
* (macvtap) devices. If the physical device and mode are
* the same, this doesn't require any actual setup
* change. If the physical device or mode *does* change,
* that will be caught in the common section below */
} else {
/* for all other combinations, we'll need a full reconnect */
needReconnect = true;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
/* now several things that are in multiple (but not all)
* different types, and can be safely compared even for those
* cases where they don't apply to a particular type.
*/
if (STRNEQ_NULLABLE(virDomainNetGetActualBridgeName(olddev),
virDomainNetGetActualBridgeName(newdev))) {
if (virDomainNetGetActualVirtPortProfile(newdev))
needReconnect = true;
else
needBridgeChange = true;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (STRNEQ_NULLABLE(virDomainNetGetActualDirectDev(olddev),
virDomainNetGetActualDirectDev(newdev)) ||
virDomainNetGetActualDirectMode(olddev) != virDomainNetGetActualDirectMode(olddev) ||
!virNetDevVPortProfileEqual(virDomainNetGetActualVirtPortProfile(olddev),
virDomainNetGetActualVirtPortProfile(newdev)) ||
!virNetDevVlanEqual(virDomainNetGetActualVlan(olddev),
virDomainNetGetActualVlan(newdev))) {
needReconnect = true;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (olddev->linkstate != newdev->linkstate)
needLinkStateChange = true;
if (!virNetDevBandwidthEqual(virDomainNetGetActualBandwidth(olddev),
virDomainNetGetActualBandwidth(newdev)))
needBandwidthSet = true;
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
/* FINALLY - actually perform the required actions */
if (needReconnect) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
_("unable to change config on '%s' network type"),
virDomainNetTypeToString(newdev->type));
goto cleanup;
}
if (needBandwidthSet) {
if (virNetDevBandwidthSet(newdev->ifname,
virDomainNetGetActualBandwidth(newdev),
false) < 0)
goto cleanup;
needReplaceDevDef = true;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (needBridgeChange) {
if (qemuDomainChangeNetBridge(vm, olddev, newdev) < 0)
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
goto cleanup;
/* we successfully switched to the new bridge, and we've
* determined that the rest of newdev is equivalent to olddev,
* so move newdev into place */
needReplaceDevDef = true;
}
if (needFilterChange) {
if (qemuDomainChangeNetFilter(vm, olddev, newdev) < 0)
goto cleanup;
/* we successfully switched to the new filter, and we've
* determined that the rest of newdev is equivalent to olddev,
* so move newdev into place */
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
needReplaceDevDef = true;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (needLinkStateChange &&
qemuDomainChangeNetLinkState(driver, vm, olddev, newdev->linkstate) < 0) {
goto cleanup;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
if (needReplaceDevDef) {
/* the changes above warrant replacing olddev with newdev in
* the domain's nets list.
*/
/* this function doesn't work with HOSTDEV networks yet, thus
* no need to change the pointer in the hostdev structure */
networkReleaseActualDevice(vm->def, olddev);
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
virDomainNetDefFree(olddev);
/* move newdev into the nets list, and NULL it out from the
* virDomainDeviceDef that we were given so that the caller
* won't delete it on return.
*/
*devslot = newdev;
newdev = dev->data.net = NULL;
dev->type = VIR_DOMAIN_DEVICE_NONE;
}
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
ret = 0;
cleanup:
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
/* When we get here, we will be in one of these two states:
*
* 1) newdev has been moved into the domain's list of nets and
* newdev set to NULL, and dev->data.net will be NULL (and
* dev->type is NONE). olddev will have been completely
* released and freed. (aka success) In this case no extra
* cleanup is needed.
*
* 2) newdev has *not* been moved into the domain's list of nets,
* and dev->data.net == newdev (and dev->type == NET). In this *
* case, we need to at least release the "actual device" from *
* newdev (the caller will free dev->data.net a.k.a. newdev, and
* the original olddev is still in used)
*
* Note that case (2) isn't necessarily a failure. It may just be
* that the changes were minor enough that we didn't need to
* replace the entire device object.
*/
if (newdev)
networkReleaseActualDevice(vm->def, newdev);
qemu: reorganize qemuDomainChangeNet and qemuDomainChangeNetBridge This patch resolves: https://bugzilla.redhat.com/show_bug.cgi?id=805071 to the extent that it can be resolved with current qemu functionality. It attempts to detect as many situations as possible when the simple operation of disconnecting an existing tap device from one bridge and attaching it to another will satisfy the change requested in virDomainUpdateDeviceFlags() for a network device. Before this patch, that situation could only be detected if the pre-change interface *and* the post-change interface definition were both "type='bridge'". After this patch, it can also be detected if the before or after interfaces are any combination of type='bridge' and type='network' (the networks can be <forward mode='nat|route|bridge'>, as long as they use a Linux host bridge and not macvtap connections). This extra effort is especially useful since the recent discovery that a netdev_del+netdev_add combo (to reconnect the network device with completely different hostside configuration) doesn't work properly with current qemu (1.2) unless it is accompanied by the matching device_del+device_add - see this mailing list message for details: http://lists.nongnu.org/archive/html/qemu-devel/2012-10/msg02355.html (A slight modification of the patch referenced there has been prepared to apply on top of this patch, but won't be pushed until qemu can be made to work with it.) * qemuDomainChangeNet needs access to the virDomainDeviceDef that holds the new netdef (so that it can clear out the virDomainDeviceDef if it ends up using the NetDef to replace the original), so the virDomainNetDefPtr arg is replaced with a virDomainDeviceDefPtr. * qemuDomainChangeNet previously checked for *some* changes to the interface config, but this check was by no means complete. It was also a bit disorganized. This refactoring of the code is (I believe) complete in its check of all NetDef attributes that might be changed, and either returns a failure (for changes that are simply impossible), or sets one of three flags: needLinkStateChange - if the device link state needs to go up/down needBridgeChange - if everything else is the same, but it needs to be connected to a difference linux host bridge needReconnect - if the entire host side of the device needs to be torn down and reconstructed (currently non-working, as mentioned above) Note that this function will refuse to make any change that requires the *guest* side of the device to be detached (e.g. changing the PCI address or mac address). Those would be disruptive enough to the guest that it's reasonable to require an explicit detach/attach sequence from the management application. * As mentioned above, qemuDomainChangeNet also does its best to understand when a simple change in attached bridge for the existing tap device will work vs. the need to completely tear down/reconstruct the host side of the device (including tap device). This patch *does not* implement the "reconnect" code anyway - there is a placeholder that turns that into an error. Rather, the purpose of this patch is to replicate existing behavior with code that is ready to have that functionality plugged in in a later patch. * The expanded uses for qemuDomainChangeNetBridge meant that it needed to be enhanced as well - it no longer replaces the original brname string in olddev with the new brname; instead, it relies on the caller to replace the *entire* olddev with newdev (since we've gone to great lengths to assure they are functionally identical other than the name of the bridge, this is now not only safe, but more correct). Additionally, qemuDomainNetChangeBridge can now set the bridge for type='network' interfaces as well as plain type='bridge' interfaces. (Note that I had to make this change simultaneous to the reorganization of qemuDomainChangeNet because the two are too closely intertwined to separate).
2012-10-10 19:38:00 +00:00
return ret;
}
static virDomainGraphicsDefPtr
qemuDomainFindGraphics(virDomainObjPtr vm,
virDomainGraphicsDefPtr dev)
{
size_t i;
for (i = 0; i < vm->def->ngraphics; i++) {
if (vm->def->graphics[i]->type == dev->type)
return vm->def->graphics[i];
}
return NULL;
}
int
qemuDomainFindGraphicsIndex(virDomainDefPtr def,
virDomainGraphicsDefPtr dev)
{
size_t i;
for (i = 0; i < def->ngraphics; i++) {
if (def->graphics[i]->type == dev->type)
return i;
}
return -1;
}
int
qemuDomainChangeGraphics(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainGraphicsDefPtr dev)
{
virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
const char *type = virDomainGraphicsTypeToString(dev->type);
size_t i;
int ret = -1;
if (!olddev) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot find existing graphics device to modify"));
goto cleanup;
}
if (dev->nListens != olddev->nListens) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("cannot change the number of listen addresses "
"on '%s' graphics"), type);
goto cleanup;
}
for (i = 0; i < dev->nListens; i++) {
virDomainGraphicsListenDefPtr newlisten = &dev->listens[i];
virDomainGraphicsListenDefPtr oldlisten = &olddev->listens[i];
if (newlisten->type != oldlisten->type) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("cannot change the type of listen address "
"on '%s' graphics"), type);
goto cleanup;
}
switch (newlisten->type) {
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
if (STRNEQ_NULLABLE(newlisten->address, oldlisten->address)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("cannot change listen address setting "
"on '%s' graphics"), type);
goto cleanup;
}
break;
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
if (STRNEQ_NULLABLE(newlisten->network, oldlisten->network)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("cannot change listen address setting "
"on '%s' graphics"), type);
goto cleanup;
}
break;
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET:
if (STRNEQ_NULLABLE(newlisten->socket, oldlisten->socket)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("cannot change listen socket setting "
"on '%s' graphics"), type);
goto cleanup;
}
break;
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE:
case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST:
/* nada */
break;
}
}
conf: add <listen> subelement to domain <graphics> element Once it's plugged in, the <listen> element will be an optional replacement for the "listen" attribute that graphics elements already have. If the <listen> element is type='address', it will have an attribute called 'address' which will contain an IP address or dns name that the guest's display server should listen on. If, however, type='network', the <listen> element should have an attribute called 'network' that will be set to the name of a network configuration to get the IP address from. * docs/schemas/domain.rng: updated to allow the <listen> element * docs/formatdomain.html.in: document the <listen> element and its attributes. * src/conf/domain_conf.[hc]: 1) The domain parser, formatter, and data structure are modified to support 0 or more <listen> subelements to each <graphics> element. The old style "legacy" listen attribute is also still accepted, and will be stored internally just as if it were a separate <listen> element. On output (i.e. format), the address attribute of the first <listen> element of type 'address' will be duplicated in the legacy "listen" attribute of the <graphic> element. 2) The "listenAddr" attribute has been removed from the unions in virDomainGRaphicsDef for graphics types vnc, rdp, and spice. This attribute is now in the <listen> subelement (aka virDomainGraphicsListenDef) 3) Helper functions were written to provide simple access (both Get and Set) to the listen elements and their attributes. * src/libvirt_private.syms: export the listen helper functions * src/qemu/qemu_command.c, src/qemu/qemu_hotplug.c, src/qemu/qemu_migration.c, src/vbox/vbox_tmpl.c, src/vmx/vmx.c, src/xenxs/xen_sxpr.c, src/xenxs/xen_xm.c Modify all these files to use the listen helper functions rather than directly referencing the (now missing) listenAddr attribute. There can be multiple <listen> elements to a single <graphics>, but the drivers all currently only support one, so all replacements of direct access with a helper function indicate index "0". * tests/* - only 3 of these are new files added explicitly to test the new <listen> element. All the others have been modified to reflect the fact that any legacy "listen" attributes passed in to the domain parse will be saved in a <listen> element (i.e. one of the virDomainGraphicsListenDefs), and during the domain format function, both the <listen> element as well as the legacy attributes will be output.
2011-07-07 04:20:28 +00:00
switch (dev->type) {
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
(!dev->data.vnc.autoport &&
(olddev->data.vnc.port != dev->data.vnc.port))) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("cannot change port settings on vnc graphics"));
goto cleanup;
}
if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("cannot change keymap setting on vnc graphics"));
goto cleanup;
}
/* If a password lifetime was, or is set, or action if connected has
* changed, then we must always run, even if new password matches
* old password */
if (olddev->data.vnc.auth.expires ||
dev->data.vnc.auth.expires ||
olddev->data.vnc.auth.connected != dev->data.vnc.auth.connected ||
STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd,
dev->data.vnc.auth.passwd)) {
VIR_DEBUG("Updating password on VNC server %p %p",
dev->data.vnc.auth.passwd, cfg->vncPassword);
ret = qemuDomainChangeGraphicsPasswords(driver, vm,
VIR_DOMAIN_GRAPHICS_TYPE_VNC,
&dev->data.vnc.auth,
cfg->vncPassword,
QEMU_ASYNC_JOB_NONE);
if (ret < 0)
goto cleanup;
/* Steal the new dev's char * reference */
VIR_FREE(olddev->data.vnc.auth.passwd);
olddev->data.vnc.auth.passwd = dev->data.vnc.auth.passwd;
dev->data.vnc.auth.passwd = NULL;
olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo;
olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires;
olddev->data.vnc.auth.connected = dev->data.vnc.auth.connected;
} else {
ret = 0;
}
break;
case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
if ((olddev->data.spice.autoport != dev->data.spice.autoport) ||
(!dev->data.spice.autoport &&
(olddev->data.spice.port != dev->data.spice.port)) ||
(!dev->data.spice.autoport &&
(olddev->data.spice.tlsPort != dev->data.spice.tlsPort))) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("cannot change port settings on spice graphics"));
goto cleanup;
}
if (STRNEQ_NULLABLE(olddev->data.spice.keymap,
dev->data.spice.keymap)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("cannot change keymap setting on spice graphics"));
goto cleanup;
}
/* We must reset the password if it has changed but also if:
* - password lifetime is or was set
* - the requested action has changed
* - the action is "disconnect"
*/
if (olddev->data.spice.auth.expires ||
dev->data.spice.auth.expires ||
olddev->data.spice.auth.connected != dev->data.spice.auth.connected ||
dev->data.spice.auth.connected ==
VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DISCONNECT ||
STRNEQ_NULLABLE(olddev->data.spice.auth.passwd,
dev->data.spice.auth.passwd)) {
VIR_DEBUG("Updating password on SPICE server %p %p",
dev->data.spice.auth.passwd, cfg->spicePassword);
ret = qemuDomainChangeGraphicsPasswords(driver, vm,
VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
&dev->data.spice.auth,
cfg->spicePassword,
QEMU_ASYNC_JOB_NONE);
if (ret < 0)
goto cleanup;
/* Steal the new dev's char * reference */
VIR_FREE(olddev->data.spice.auth.passwd);
olddev->data.spice.auth.passwd = dev->data.spice.auth.passwd;
dev->data.spice.auth.passwd = NULL;
olddev->data.spice.auth.validTo = dev->data.spice.auth.validTo;
olddev->data.spice.auth.expires = dev->data.spice.auth.expires;
olddev->data.spice.auth.connected = dev->data.spice.auth.connected;
} else {
VIR_DEBUG("Not updating since password didn't change");
ret = 0;
}
break;
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unable to change config on '%s' graphics type"), type);
break;
}
cleanup:
virObjectUnref(cfg);
return ret;
}
static int qemuComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
virDomainDeviceInfoPtr info1,
void *opaque)
{
virDomainDeviceInfoPtr info2 = opaque;
if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
return 0;
if (info1->addr.pci.domain == info2->addr.pci.domain &&
info1->addr.pci.bus == info2->addr.pci.bus &&
info1->addr.pci.slot == info2->addr.pci.slot &&
info1->addr.pci.function != info2->addr.pci.function)
return -1;
return 0;
}
static bool qemuIsMultiFunctionDevice(virDomainDefPtr def,
virDomainDeviceInfoPtr dev)
{
if (virDomainDeviceInfoIterate(def, qemuComparePCIDevice, dev) < 0)
return true;
return false;
}
static int
qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk)
{
virDomainDeviceDef dev;
virObjectEventPtr event;
size_t i;
const char *src = virDomainDiskGetSource(disk);
qemuDomainObjPrivatePtr priv = vm->privateData;
char *drivestr;
char *objAlias = NULL;
char *encAlias = NULL;
VIR_DEBUG("Removing disk %s from domain %p %s",
disk->info.alias, vm, vm->def->name);
/* build the actual drive id string as the disk->info.alias doesn't
* contain the QEMU_DRIVE_HOST_PREFIX that is passed to qemu */
if (virAsprintf(&drivestr, "%s%s",
QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0)
return -1;
/* Let's look for some markers for a secret object and create an alias
* object to be used to attempt to delete the object that was created.
* We cannot just use the disk private secret info since it would have
* been removed during cleanup of qemuProcessLaunch. Likewise, libvirtd
* restart wouldn't have them, so no assumption can be made. */
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_SECRET) &&
qemuDomainSecretDiskCapable(disk->src)) {
if (!(objAlias =
qemuDomainGetSecretAESAlias(disk->info.alias, false))) {
VIR_FREE(drivestr);
return -1;
}
}
/* Similarly, if this is possible a device using LUKS encryption, we
* can remove the luks object password too
*/
if (!virStorageSourceIsEmpty(disk->src) && disk->src->encryption &&
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
disk->src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
if (!(encAlias =
qemuDomainGetSecretAESAlias(disk->info.alias, true))) {
VIR_FREE(objAlias);
VIR_FREE(drivestr);
return -1;
}
}
qemuDomainObjEnterMonitor(driver, vm);
/* If it fails, then so be it - it was a best shot */
if (objAlias)
ignore_value(qemuMonitorDelObject(priv->mon, objAlias));
VIR_FREE(objAlias);
/* If it fails, then so be it - it was a best shot */
if (encAlias)
ignore_value(qemuMonitorDelObject(priv->mon, encAlias));
VIR_FREE(encAlias);
qemuMonitorDriveDel(priv->mon, drivestr);
VIR_FREE(drivestr);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
return -1;
virDomainAuditDisk(vm, disk->src, NULL, "detach", true);
event = virDomainEventDeviceRemovedNewFromObj(vm, disk->info.alias);
qemuDomainEventQueue(driver, event);
for (i = 0; i < vm->def->ndisks; i++) {
if (vm->def->disks[i] == disk) {
virDomainDiskRemove(vm->def, i);
break;
}
}
qemuDomainReleaseDeviceAddress(vm, &disk->info, src);
if (virSecurityManagerRestoreDiskLabel(driver->securityManager,
vm->def, disk) < 0)
VIR_WARN("Unable to restore security label on %s", src);
if (qemuTeardownDiskCgroup(vm, disk) < 0)
VIR_WARN("Failed to tear down cgroup for disk path %s", src);
if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
VIR_WARN("Unable to release lock on %s", src);
dev.type = VIR_DOMAIN_DEVICE_DISK;
dev.data.disk = disk;
ignore_value(qemuRemoveSharedDevice(driver, &dev, vm->def->name));
if (priv->usbaddrs)
virDomainUSBAddressRelease(priv->usbaddrs, &disk->info);
virDomainDiskDefFree(disk);
return 0;
}
static int
qemuDomainRemoveControllerDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainControllerDefPtr controller)
{
virObjectEventPtr event;
size_t i;
VIR_DEBUG("Removing controller %s from domain %p %s",
controller->info.alias, vm, vm->def->name);
event = virDomainEventDeviceRemovedNewFromObj(vm, controller->info.alias);
qemuDomainEventQueue(driver, event);
for (i = 0; i < vm->def->ncontrollers; i++) {
if (vm->def->controllers[i] == controller) {
virDomainControllerRemove(vm->def, i);
break;
}
}
qemuDomainReleaseDeviceAddress(vm, &controller->info, NULL);
virDomainControllerDefFree(controller);
return 0;
}
static int
qemuDomainRemoveMemoryDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainMemoryDefPtr mem)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
unsigned long long newmem = oldmem - mem->size;
virObjectEventPtr event;
char *backendAlias = NULL;
int rc;
int idx;
VIR_DEBUG("Removing memory device %s from domain %p %s",
mem->info.alias, vm, vm->def->name);
event = virDomainEventDeviceRemovedNewFromObj(vm, mem->info.alias);
qemuDomainEventQueue(driver, event);
if (virAsprintf(&backendAlias, "mem%s", mem->info.alias) < 0)
return -1;
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorDelObject(priv->mon, backendAlias);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
rc = -1;
VIR_FREE(backendAlias);
virDomainAuditMemory(vm, oldmem, newmem, "update", rc == 0);
if (rc < 0)
return -1;
if ((idx = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
virDomainMemoryRemove(vm->def, idx);
virDomainMemoryDefFree(mem);
/* fix the balloon size */
ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));
/* decrease the mlock limit after memory unplug if necessary */
ignore_value(qemuDomainAdjustMaxMemLock(vm));
return 0;
}
static void
qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
}
static void
qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
}
static void
qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
}
static int
qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
virDomainNetDefPtr net = NULL;
virObjectEventPtr event;
size_t i;
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
char *drivestr = NULL;
bool is_vfio = false;
VIR_DEBUG("Removing host device %s from domain %p %s",
hostdev->info->alias, vm, vm->def->name);
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
int backend = hostdev->source.subsys.u.pci.backend;
is_vfio = backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
}
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
/* build the actual drive id string as generated during
* qemuBuildSCSIHostdevDrvStr that is passed to qemu */
if (virAsprintf(&drivestr, "%s-%s",
virDomainDeviceAddressTypeToString(hostdev->info->type),
hostdev->info->alias) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
qemuMonitorDriveDel(priv->mon, drivestr);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
}
event = virDomainEventDeviceRemovedNewFromObj(vm, hostdev->info->alias);
qemuDomainEventQueue(driver, event);
if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET) {
net = hostdev->parent.data.net;
for (i = 0; i < vm->def->nnets; i++) {
if (vm->def->nets[i] == net) {
virDomainNetRemove(vm->def, i);
break;
}
}
}
for (i = 0; i < vm->def->nhostdevs; i++) {
if (vm->def->hostdevs[i] == hostdev) {
virDomainHostdevRemove(vm->def, i);
break;
}
}
virDomainAuditHostdev(vm, hostdev, "detach", true);
if (!is_vfio &&
virSecurityManagerRestoreHostdevLabel(driver->securityManager,
vm->def, hostdev, NULL) < 0)
VIR_WARN("Failed to restore host device labelling");
if (qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Failed to remove host device cgroup ACL");
switch ((virDomainHostdevSubsysType) hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
qemuDomainRemovePCIHostDevice(driver, vm, hostdev);
/* QEMU might no longer need to lock as much memory, eg. we just
* detached the last VFIO device, so adjust the limit here */
if (qemuDomainAdjustMaxMemLock(vm) < 0)
VIR_WARN("Failed to adjust locked memory limit");
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
qemuDomainRemoveUSBHostDevice(driver, vm, hostdev);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
qemuDomainRemoveSCSIHostDevice(driver, vm, hostdev);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
break;
}
virDomainHostdevDefFree(hostdev);
if (net) {
networkReleaseActualDevice(vm->def, net);
virDomainNetDefFree(net);
}
ret = 0;
cleanup:
VIR_FREE(drivestr);
virObjectUnref(cfg);
return ret;
}
static int
qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainNetDefPtr net)
{
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
qemuDomainObjPrivatePtr priv = vm->privateData;
virNetDevVPortProfilePtr vport;
virObjectEventPtr event;
char *hostnet_name = NULL;
size_t i;
int ret = -1;
qemu: fix removal of <interface type='hostdev'> This patch (and the two patches that precede it) resolve: https://bugzilla.redhat.com/show_bug.cgi?id=1005682 When libvirt was changed to delay the final cleanup of device removal until the qemu process had signaled it with a DEVICE_DELETED event for that device, the hostdev removal function (qemuDomainRemoveHostDevice()) was written to properly handle the removal of a hostdev that was actually an SRIOV virtual function (defined with <interface type='hostdev'>). However, the function used to search for a device matching the alias name provided in the DEVICE_DELETED message (virDomainDefFindDevice()) would search through the list of netdevs before hostdevs, so qemuDomainRemoveHostDevice() was never called; instead the netdev function, qemuDomainRemoveNetDevice() (which *doesn't* properly cleanup after removal of <interface type='hostdev'>), was called. (As a reminder - each <interface type='hostdev'> results in a virDomainNetDef which contains a virDomainHostdevDef having a parent type of VIR_DOMAIN_DEVICE_NET, and parent.data.net pointing back to the virDomainNetDef; both Defs point to the same device info object (and the info contains the device's "alias", which is used by qemu to identify the device). The virDomainHostdevDef is added to the domain's hostdevs list *and* the virDomainNetDef is added to the domain's nets list, so searching either list for a particular alias will yield a positive result.) This function modifies the qemuDomainRemoveNetDevice() to short circuit itself and call qemu DomainRemoveHostDevice() instead when the actual device is a VIR_DOMAIN_NET_TYPE_HOSTDEV (similar logic to what is done in the higher level qemuDomainDetachNetDevice()) Note that even if virDomainDefFindDevice() changes in the future so that it finds the hostdev entry first, the current code will continue to work properly.
2013-10-18 09:34:53 +00:00
if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
/* this function handles all hostdev and netdev cleanup */
ret = qemuDomainRemoveHostDevice(driver, vm,
virDomainNetGetActualHostdev(net));
goto cleanup;
qemu: fix removal of <interface type='hostdev'> This patch (and the two patches that precede it) resolve: https://bugzilla.redhat.com/show_bug.cgi?id=1005682 When libvirt was changed to delay the final cleanup of device removal until the qemu process had signaled it with a DEVICE_DELETED event for that device, the hostdev removal function (qemuDomainRemoveHostDevice()) was written to properly handle the removal of a hostdev that was actually an SRIOV virtual function (defined with <interface type='hostdev'>). However, the function used to search for a device matching the alias name provided in the DEVICE_DELETED message (virDomainDefFindDevice()) would search through the list of netdevs before hostdevs, so qemuDomainRemoveHostDevice() was never called; instead the netdev function, qemuDomainRemoveNetDevice() (which *doesn't* properly cleanup after removal of <interface type='hostdev'>), was called. (As a reminder - each <interface type='hostdev'> results in a virDomainNetDef which contains a virDomainHostdevDef having a parent type of VIR_DOMAIN_DEVICE_NET, and parent.data.net pointing back to the virDomainNetDef; both Defs point to the same device info object (and the info contains the device's "alias", which is used by qemu to identify the device). The virDomainHostdevDef is added to the domain's hostdevs list *and* the virDomainNetDef is added to the domain's nets list, so searching either list for a particular alias will yield a positive result.) This function modifies the qemuDomainRemoveNetDevice() to short circuit itself and call qemu DomainRemoveHostDevice() instead when the actual device is a VIR_DOMAIN_NET_TYPE_HOSTDEV (similar logic to what is done in the higher level qemuDomainDetachNetDevice()) Note that even if virDomainDefFindDevice() changes in the future so that it finds the hostdev entry first, the current code will continue to work properly.
2013-10-18 09:34:53 +00:00
}
VIR_DEBUG("Removing network interface %s from domain %p %s",
net->info.alias, vm, vm->def->name);
if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditNet(vm, net, NULL, "detach", false);
goto cleanup;
}
} else {
int vlan;
if ((vlan = qemuDomainNetVLAN(net)) < 0 ||
qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
if (vlan < 0) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("unable to determine original VLAN"));
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditNet(vm, net, NULL, "detach", false);
goto cleanup;
}
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditNet(vm, net, NULL, "detach", true);
event = virDomainEventDeviceRemovedNewFromObj(vm, net->info.alias);
qemuDomainEventQueue(driver, event);
for (i = 0; i < vm->def->nnets; i++) {
if (vm->def->nets[i] == net) {
virDomainNetRemove(vm->def, i);
break;
}
}
qemuDomainReleaseDeviceAddress(vm, &net->info, NULL);
virDomainConfNWFilterTeardown(net);
if (cfg->macFilter && (net->ifname != NULL)) {
ignore_value(ebtablesRemoveForwardAllowIn(driver->ebtables,
net->ifname,
&net->mac));
}
if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
net->ifname, &net->mac,
virDomainNetGetActualDirectDev(net),
virDomainNetGetActualDirectMode(net),
virDomainNetGetActualVirtPortProfile(net),
cfg->stateDir));
}
vport = virDomainNetGetActualVirtPortProfile(net);
if (vport) {
if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_MIDONET) {
ignore_value(virNetDevMidonetUnbindPort(vport));
} else if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
ignore_value(virNetDevOpenvswitchRemovePort(
virDomainNetGetActualBridgeName(net),
net->ifname));
}
}
networkReleaseActualDevice(vm->def, net);
virDomainNetDefFree(net);
ret = 0;
cleanup:
virObjectUnref(cfg);
VIR_FREE(hostnet_name);
return ret;
}
static int
qemuDomainRemoveChrDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainChrDefPtr chr)
{
virObjectEventPtr event;
char *charAlias = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret = -1;
int rc;
VIR_DEBUG("Removing character device %s from domain %p %s",
chr->info.alias, vm, vm->def->name);
if (virAsprintf(&charAlias, "char%s", chr->info.alias) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorDetachCharDev(priv->mon, charAlias);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditChardev(vm, chr, NULL, "detach", rc == 0);
if (rc < 0)
goto cleanup;
event = virDomainEventDeviceRemovedNewFromObj(vm, chr->info.alias);
qemuDomainEventQueue(driver, event);
qemuDomainChrRemove(vm->def, chr);
virDomainChrDefFree(chr);
ret = 0;
cleanup:
VIR_FREE(charAlias);
return ret;
}
static int
qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainRNGDefPtr rng)
{
virObjectEventPtr event;
char *charAlias = NULL;
char *objAlias = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
ssize_t idx;
int ret = -1;
int rc;
VIR_DEBUG("Removing RNG device %s from domain %p %s",
rng->info.alias, vm, vm->def->name);
if (virAsprintf(&objAlias, "obj%s", rng->info.alias) < 0)
goto cleanup;
if (virAsprintf(&charAlias, "char%s", rng->info.alias) < 0)
goto cleanup;
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorDelObject(priv->mon, objAlias);
if (rc == 0 && rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD)
ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditRNG(vm, rng, NULL, "detach", rc == 0);
if (rc < 0)
goto cleanup;
event = virDomainEventDeviceRemovedNewFromObj(vm, rng->info.alias);
qemuDomainEventQueue(driver, event);
if ((idx = virDomainRNGFind(vm->def, rng)) >= 0)
virDomainRNGRemove(vm->def, idx);
qemuDomainReleaseDeviceAddress(vm, &rng->info, NULL);
virDomainRNGDefFree(rng);
ret = 0;
cleanup:
VIR_FREE(charAlias);
VIR_FREE(objAlias);
return ret;
}
int
qemuDomainRemoveDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
int ret = -1;
switch ((virDomainDeviceType) dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
ret = qemuDomainRemoveDiskDevice(driver, vm, dev->data.disk);
break;
case VIR_DOMAIN_DEVICE_CONTROLLER:
ret = qemuDomainRemoveControllerDevice(driver, vm, dev->data.controller);
break;
case VIR_DOMAIN_DEVICE_NET:
ret = qemuDomainRemoveNetDevice(driver, vm, dev->data.net);
break;
case VIR_DOMAIN_DEVICE_HOSTDEV:
ret = qemuDomainRemoveHostDevice(driver, vm, dev->data.hostdev);
break;
case VIR_DOMAIN_DEVICE_CHR:
ret = qemuDomainRemoveChrDevice(driver, vm, dev->data.chr);
break;
case VIR_DOMAIN_DEVICE_RNG:
ret = qemuDomainRemoveRNGDevice(driver, vm, dev->data.rng);
break;
case VIR_DOMAIN_DEVICE_MEMORY:
ret = qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory);
break;
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
case VIR_DOMAIN_DEVICE_VIDEO:
case VIR_DOMAIN_DEVICE_WATCHDOG:
case VIR_DOMAIN_DEVICE_GRAPHICS:
case VIR_DOMAIN_DEVICE_HUB:
case VIR_DOMAIN_DEVICE_REDIRDEV:
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("don't know how to remove a %s device"),
virDomainDeviceTypeToString(dev->type));
break;
}
return ret;
}
static void
qemuDomainMarkDeviceForRemoval(virDomainObjPtr vm,
virDomainDeviceInfoPtr info)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
memset(&priv->unplug, 0, sizeof(priv->unplug));
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
return;
priv->unplug.alias = info->alias;
}
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
priv->unplug.alias = NULL;
}
/* Returns:
* -1 Unplug of the device failed
*
* 0 DEVICE_DELETED event is supported and removal of the device did not
* finish in qemuDomainRemoveDeviceWaitTime
*
* 1 when the caller is responsible for finishing the device removal:
* - DEVICE_DELETED event is unsupported
* - DEVICE_DELETED event arrived before the timeout time
* - we failed to reliably wait for the event and thus use fallback behavior
*/
static int
qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
unsigned long long until;
int rc;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
return 1;
if (virTimeMillisNow(&until) < 0)
return 1;
until += qemuDomainRemoveDeviceWaitTime;
while (priv->unplug.alias) {
if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
return 0;
if (rc < 0) {
VIR_WARN("Failed to wait on unplug condition for domain '%s' "
"device '%s'", vm->def->name, priv->unplug.alias);
return 1;
}
}
if (priv->unplug.status == QEMU_DOMAIN_UNPLUGGING_DEVICE_STATUS_GUEST_REJECTED) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("unplug of device was rejected by the guest"));
return -1;
}
return 1;
}
/* Returns:
* true there was a thread waiting for devAlias to be removed and this
* thread will take care of finishing the removal
* false the thread that started the removal is already gone and delegate
* finishing the removal to a new thread
*/
bool
qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
const char *devAlias,
qemuDomainUnpluggingDeviceStatus status)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
if (STREQ_NULLABLE(priv->unplug.alias, devAlias)) {
qemuDomainResetDeviceRemoval(vm);
priv->unplug.status = status;
virDomainObjBroadcast(vm);
return true;
}
return false;
}
static int
qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr detach)
{
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("cannot hot unplug multifunction PCI device: %s"),
detach->dst);
goto cleanup;
}
if (qemuDomainMachineIsS390CCW(vm->def) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
if (!virDomainDeviceAddressIsValid(&detach->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("device cannot be detached without a valid CCW address"));
goto cleanup;
}
} else {
if (!virDomainDeviceAddressIsValid(&detach->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("device cannot be detached without a valid PCI address"));
goto cleanup;
}
}
if (!detach->info.alias) {
if (qemuAssignDeviceDiskAlias(vm->def, detach, priv->qemuCaps) < 0)
goto cleanup;
}
qemuDomainMarkDeviceForRemoval(vm, &detach->info);
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
goto cleanup;
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
ret = qemuDomainRemoveDiskDevice(driver, vm, detach);
cleanup:
qemuDomainResetDeviceRemoval(vm);
return ret;
}
static int
qemuDomainDetachDiskDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDiskDefPtr detach)
{
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
if (qemuDomainDiskBlockJobIsActive(detach))
blockjob: react to active block copy For now, disk migration via block copy job is not implemented in libvirt. But when we do implement it, we have to deal with the fact that qemu does not yet provide an easy way to re-start a qemu process with mirroring still intact. Paolo has proposed an idea for a persistent dirty bitmap that might make this possible, but until that design is complete, it's hard to say what changes libvirt would need. Even something like 'virDomainSave' becomes hairy, if you realize the implications that 'virDomainRestore' would be stuck with recreating the same mirror layout. But if we step back and look at the bigger picture, we realize that the initial client of live storage migration via disk mirroring is oVirt, which always uses transient domains, and that if a transient domain is destroyed while a mirror exists, oVirt can easily restart the storage migration by creating a new domain that visits just the source storage, with no loss in data. We can make life a lot easier by being cowards for now, forbidding certain operations on a domain. This patch guarantees that we never get in a state where we would have to restart a domain with a mirroring block copy, by preventing saves, snapshots, migration, hot unplug of a disk in use, and conversion to a persistent domain (thankfully, it is still relatively easy to 'virsh undefine' a running domain to temporarily make it transient, run tests on 'virsh blockcopy', then 'virsh define' to restore the persistence). Later, if the qemu design is enhanced, we can relax our code. The change to qemudDomainDefine looks a bit odd for undoing an assignment, rather than probing up front to avoid the assignment, but this is because of how virDomainAssignDef combines both a lookup and assignment into a single function call. * src/conf/domain_conf.h (virDomainHasDiskMirror): New prototype. * src/conf/domain_conf.c (virDomainHasDiskMirror): New function. * src/libvirt_private.syms (domain_conf.h): Export it. * src/qemu/qemu_driver.c (qemuDomainSaveInternal) (qemuDomainSnapshotCreateXML, qemuDomainRevertToSnapshot) (qemuDomainBlockJobImpl, qemudDomainDefine): Prevent dangerous actions while block copy is already in action. * src/qemu/qemu_hotplug.c (qemuDomainDetachDiskDevice): Likewise. * src/qemu/qemu_migration.c (qemuMigrationIsAllowed): Likewise.
2012-04-10 02:39:47 +00:00
goto cleanup;
qemuDomainMarkDeviceForRemoval(vm, &detach->info);
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
goto cleanup;
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
ret = qemuDomainRemoveDiskDevice(driver, vm, detach);
cleanup:
qemuDomainResetDeviceRemoval(vm);
return ret;
}
static int
qemuFindDisk(virDomainDefPtr def, const char *dst)
{
size_t i;
for (i = 0; i < def->ndisks; i++) {
if (STREQ(def->disks[i]->dst, dst))
return i;
}
return -1;
}
int
qemuDomainDetachDeviceDiskLive(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
virDomainDiskDefPtr disk;
int ret = -1;
int idx;
if ((idx = qemuFindDisk(vm->def, dev->data.disk->dst)) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("disk %s not found"), dev->data.disk->dst);
return -1;
}
disk = vm->def->disks[idx];
switch (disk->device) {
case VIR_DOMAIN_DISK_DEVICE_DISK:
case VIR_DOMAIN_DISK_DEVICE_LUN:
if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
ret = qemuDomainDetachVirtioDiskDevice(driver, vm, disk);
else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
disk->bus == VIR_DOMAIN_DISK_BUS_USB)
ret = qemuDomainDetachDiskDevice(driver, vm, disk);
else
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("This type of disk cannot be hot unplugged"));
break;
default:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("disk device type '%s' cannot be detached"),
virDomainDiskDeviceTypeToString(disk->device));
break;
}
return ret;
}
static bool qemuDomainDiskControllerIsBusy(virDomainObjPtr vm,
virDomainControllerDefPtr detach)
{
size_t i;
virDomainDiskDefPtr disk;
for (i = 0; i < vm->def->ndisks; i++) {
disk = vm->def->disks[i];
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
/* the disk does not use disk controller */
continue;
/* check whether the disk uses this type controller */
if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE &&
detach->type != VIR_DOMAIN_CONTROLLER_TYPE_IDE)
continue;
if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC &&
detach->type != VIR_DOMAIN_CONTROLLER_TYPE_FDC)
continue;
if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
detach->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
continue;
if (disk->info.addr.drive.controller == detach->idx)
return true;
}
return false;
}
static bool qemuDomainControllerIsBusy(virDomainObjPtr vm,
virDomainControllerDefPtr detach)
{
switch (detach->type) {
case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
return qemuDomainDiskControllerIsBusy(vm, detach);
case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
default:
/* libvirt does not support sata controller, and does not support to
* detach virtio and smart card controller.
*/
return true;
}
}
int qemuDomainDetachControllerDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
int idx, ret = -1;
virDomainControllerDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
if ((idx = virDomainControllerFind(vm->def,
dev->data.controller->type,
dev->data.controller->idx)) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("controller %s:%d not found"),
virDomainControllerTypeToString(dev->data.controller->type),
dev->data.controller->idx);
goto cleanup;
}
detach = vm->def->controllers[idx];
if (detach->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
detach->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
detach->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("device with '%s' address cannot be detached"),
virDomainDeviceAddressTypeToString(detach->info.type));
goto cleanup;
}
if (!virDomainDeviceAddressIsValid(&detach->info, detach->info.type)) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("device with invalid '%s' address cannot be detached"),
virDomainDeviceAddressTypeToString(detach->info.type));
goto cleanup;
}
if (detach->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("cannot hot unplug multifunction PCI device: %s"),
dev->data.disk->dst);
goto cleanup;
}
if (qemuDomainControllerIsBusy(vm, detach)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("device cannot be detached: device is busy"));
goto cleanup;
}
if (!detach->info.alias) {
if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, detach) < 0)
goto cleanup;
}
qemuDomainMarkDeviceForRemoval(vm, &detach->info);
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorDelDevice(priv->mon, detach->info.alias)) {
ignore_value(qemuDomainObjExitMonitor(driver, vm));
goto cleanup;
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
ret = qemuDomainRemoveControllerDevice(driver, vm, detach);
cleanup:
qemuDomainResetDeviceRemoval(vm);
return ret;
}
static int
qemuDomainDetachHostPCIDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr detach)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainHostdevSubsysPCIPtr pcisrc = &detach->source.subsys.u.pci;
int ret;
if (qemuIsMultiFunctionDevice(vm->def, detach->info)) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"),
pcisrc->addr.domain, pcisrc->addr.bus,
pcisrc->addr.slot, pcisrc->addr.function);
return -1;
}
if (!virDomainDeviceAddressIsValid(detach->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
virReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("device cannot be detached without a PCI address"));
return -1;
}
qemuDomainMarkDeviceForRemoval(vm, detach->info);
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
ret = -1;
return ret;
}
static int
qemuDomainDetachHostUSBDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr detach)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret;
if (!detach->info->alias) {
virReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("device cannot be detached without a device alias"));
return -1;
}
qemuDomainMarkDeviceForRemoval(vm, detach->info);
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
ret = -1;
return ret;
}
static int
qemuDomainDetachHostSCSIDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr detach)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret = -1;
if (!detach->info->alias) {
virReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("device cannot be detached without a device alias"));
return -1;
}
qemuDomainMarkDeviceForRemoval(vm, detach->info);
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
return -1;
return ret;
}
static int
qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr detach)
{
int ret = -1;
if (!detach->info->alias) {
if (qemuAssignDeviceHostdevAlias(vm->def, &detach->info->alias, -1) < 0)
return -1;
}
switch (detach->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
ret = qemuDomainDetachHostPCIDevice(driver, vm, detach);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
ret = qemuDomainDetachHostUSBDevice(driver, vm, detach);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
ret = qemuDomainDetachHostSCSIDevice(driver, vm, detach);
break;
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("hostdev subsys type '%s' not supported"),
virDomainHostdevSubsysTypeToString(detach->source.subsys.type));
return -1;
}
if (ret < 0) {
if (virDomainObjIsActive(vm))
virDomainAuditHostdev(vm, detach, "detach", false);
} else if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1) {
ret = qemuDomainRemoveHostDevice(driver, vm, detach);
}
qemuDomainResetDeviceRemoval(vm);
return ret;
}
/* search for a hostdev matching dev and detach it */
int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
virDomainHostdevDefPtr hostdev = dev->data.hostdev;
virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb;
virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
virDomainHostdevSubsysSCSIPtr scsisrc = &subsys->u.scsi;
virDomainHostdevDefPtr detach = NULL;
int idx;
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("hostdev mode '%s' not supported"),
virDomainHostdevModeTypeToString(hostdev->mode));
return -1;
}
idx = virDomainHostdevFind(vm->def, hostdev, &detach);
if (idx < 0) {
switch (subsys->type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
virReportError(VIR_ERR_OPERATION_FAILED,
_("host pci device %.4x:%.2x:%.2x.%.1x not found"),
pcisrc->addr.domain, pcisrc->addr.bus,
pcisrc->addr.slot, pcisrc->addr.function);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
if (usbsrc->bus && usbsrc->device) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("host usb device %03d.%03d not found"),
usbsrc->bus, usbsrc->device);
} else {
virReportError(VIR_ERR_OPERATION_FAILED,
_("host usb device vendor=0x%.4x product=0x%.4x not found"),
usbsrc->vendor, usbsrc->product);
}
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
if (scsisrc->protocol ==
VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
virReportError(VIR_ERR_OPERATION_FAILED,
_("host scsi iSCSI path %s not found"),
iscsisrc->path);
} else {
virDomainHostdevSubsysSCSIHostPtr scsihostsrc =
&scsisrc->u.host;
virReportError(VIR_ERR_OPERATION_FAILED,
_("host scsi device %s:%u:%u.%llu not found"),
scsihostsrc->adapter, scsihostsrc->bus,
scsihostsrc->target, scsihostsrc->unit);
}
break;
}
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected hostdev type %d"), subsys->type);
break;
}
return -1;
}
qemu: support type=hostdev network device live hotplug attach/detach qemuDomainAttachNetDevice - re-ordered some things at start of function because networkAllocateActualDevice should always be run and a slot in def->nets always allocated, but host_net_add isn't needed if the actual type is hostdev. - if actual type is hostdev, defer to qemuDomainAttachHostDevice (which will reach up to the NetDef for things like MAC address when necessary). After return from qemuDomainAttachHostDevice, slip directly to cleanup, since the rest of the function is specific to emulated net devices. - put assignment of new NetDef into expanded def->nets down below cleanup: (but only on success) since it is also needed for emulated and hostdev net devices. qemuDomainDetachHostDevice - after locating the exact device to detach, check if it's a network device and, if so, use toplevel qemuDomainDetachNetDevice instead so that the def->nets list is properly updated, and 'actual device' properly returned to network pool if appropriate. Otherwise, for normal hostdevs, call the lower level qemuDomainDetachThisDevice. qemuDomainDetachNetDevice - This is where it gets a bit tricky. After locating the device on the def->nets list, if the network device type == hostdev, call the *lower level* qemuDomainDetachThisDevice (which will reach back up to the parent net device for MAC address / virtualport when appropriate, then clear the device out of def->hostdevs) before skipping past all the emulated net-device-specific code to cleanup:, where the network device is removed from def->nets, and the network device object is freed. In short, any time a hostdev-type network device is detached, we must go through the toplevel virDomaineDetachNetDevice function first and last, to make sure 1) the def->nnets list is properly managed, and 2) any device allocated with networkAllocateActualDevice is properly freed. At the same time, in the middle we need to go through the lower-level vidDomainDetach*This*HostDevice to be sure that 1) the def->hostdevs list is properly managed, 2) the PCI device is properly detached from the guest and reattached to the host (if appropriate), and 3) any higher level teardown is called at the appropriate time, by reaching back up to the NetDef config (part (3) will be covered in a separate patch).
2012-02-27 19:20:17 +00:00
/* If this is a network hostdev, we need to use the higher-level detach
* function so that mac address / virtualport are reset
*/
if (detach->parent.type == VIR_DOMAIN_DEVICE_NET)
return qemuDomainDetachNetDevice(driver, vm, &detach->parent);
qemu: support type=hostdev network device live hotplug attach/detach qemuDomainAttachNetDevice - re-ordered some things at start of function because networkAllocateActualDevice should always be run and a slot in def->nets always allocated, but host_net_add isn't needed if the actual type is hostdev. - if actual type is hostdev, defer to qemuDomainAttachHostDevice (which will reach up to the NetDef for things like MAC address when necessary). After return from qemuDomainAttachHostDevice, slip directly to cleanup, since the rest of the function is specific to emulated net devices. - put assignment of new NetDef into expanded def->nets down below cleanup: (but only on success) since it is also needed for emulated and hostdev net devices. qemuDomainDetachHostDevice - after locating the exact device to detach, check if it's a network device and, if so, use toplevel qemuDomainDetachNetDevice instead so that the def->nets list is properly updated, and 'actual device' properly returned to network pool if appropriate. Otherwise, for normal hostdevs, call the lower level qemuDomainDetachThisDevice. qemuDomainDetachNetDevice - This is where it gets a bit tricky. After locating the device on the def->nets list, if the network device type == hostdev, call the *lower level* qemuDomainDetachThisDevice (which will reach back up to the parent net device for MAC address / virtualport when appropriate, then clear the device out of def->hostdevs) before skipping past all the emulated net-device-specific code to cleanup:, where the network device is removed from def->nets, and the network device object is freed. In short, any time a hostdev-type network device is detached, we must go through the toplevel virDomaineDetachNetDevice function first and last, to make sure 1) the def->nnets list is properly managed, and 2) any device allocated with networkAllocateActualDevice is properly freed. At the same time, in the middle we need to go through the lower-level vidDomainDetach*This*HostDevice to be sure that 1) the def->hostdevs list is properly managed, 2) the PCI device is properly detached from the guest and reattached to the host (if appropriate), and 3) any higher level teardown is called at the appropriate time, by reaching back up to the NetDef config (part (3) will be covered in a separate patch).
2012-02-27 19:20:17 +00:00
else
return qemuDomainDetachThisHostDevice(driver, vm, detach);
}
int
qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
qemu: fix attach/detach of netdevs with matching mac addrs This resolves: https://bugzilla.redhat.com/show_bug.cgi?id=862515 which describes inconsistencies in dealing with duplicate mac addresses on network devices in a domain. (at any rate, it resolves *almost* everything, and prints out an informative error message for the one problem that isn't solved, but has a workaround.) A synopsis of the problems: 1) you can't do a persistent attach-interface of a device with a mac address that matches an existing device. 2) you *can* do a live attach-interface of such a device. 3) you *can* directly edit a domain and put in two devices with matching mac addresses. 4) When running virsh detach-device (live or config), only MAC address is checked when matching the device to remove, so the first device with the desired mac address will be removed. This isn't always the one that's wanted. 5) when running virsh detach-interface (live or config), the only two items that can be specified to match against are mac address and model type (virtio, etc) - if multiple netdevs match both of those attributes, it again just finds the first one added and assumes that is the only match. Since it is completely valid to have multiple network devices with the same MAC address (although it can cause problems in many cases, there *are* valid use cases), what is needed is: 1) remove the restriction that prohibits doing a persistent add of a netdev with a duplicate mac address. 2) enhance the backend of virDomainDetachDeviceFlags to check for something that *is* guaranteed unique (but still work with just mac address, as long as it yields only a single results. This patch does three things: 1) removes the check for duplicate mac address during a persistent netdev attach. 2) unifies the searching for both live and config detach of netdevices in the subordinate functions of qemuDomainModifyDeviceFlags() to use the new function virDomainNetFindIdx (which matches mac address and PCI address if available, checking for duplicates if only mac address was specified). This function returns -2 if multiple matches are found, allowing the callers to print out an appropriate message. Steps 1 & 2 are enough to fully fix the problem when using virsh attach-device and detach-device (which require an XML description of the device rather than a bunch of commandline args) 3) modifies the virsh detach-interface command to check for multiple matches of mac address and show an error message suggesting use of the detach-device command in cases where there are multiple matching mac addresses. Later we should decide how we want to input a PCI address on the virsh commandline, and enhance detach-interface to take a --address option, eliminating the need to use detach-device * src/conf/domain_conf.c * src/conf/domain_conf.h * src/libvirt_private.syms * added new virDomainNetFindIdx function * removed now unused virDomainNetIndexByMac and virDomainNetRemoveByMac * src/qemu/qemu_driver.c * remove check for duplicate max from qemuDomainAttachDeviceConfig * use virDomainNetFindIdx/virDomainNetRemove instead of virDomainNetRemoveByMac in qemuDomainDetachDeviceConfig * use virDomainNetFindIdx instead of virDomainIndexByMac in qemuDomainUpdateDeviceConfig * src/qemu/qemu_hotplug.c * use virDomainNetFindIdx instead of a homespun loop in qemuDomainDetachNetDevice. * tools/virsh-domain.c: modified detach-interface command as described above
2012-10-25 20:03:35 +00:00
int detachidx, ret = -1;
virDomainNetDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
goto cleanup;
qemu: fix attach/detach of netdevs with matching mac addrs This resolves: https://bugzilla.redhat.com/show_bug.cgi?id=862515 which describes inconsistencies in dealing with duplicate mac addresses on network devices in a domain. (at any rate, it resolves *almost* everything, and prints out an informative error message for the one problem that isn't solved, but has a workaround.) A synopsis of the problems: 1) you can't do a persistent attach-interface of a device with a mac address that matches an existing device. 2) you *can* do a live attach-interface of such a device. 3) you *can* directly edit a domain and put in two devices with matching mac addresses. 4) When running virsh detach-device (live or config), only MAC address is checked when matching the device to remove, so the first device with the desired mac address will be removed. This isn't always the one that's wanted. 5) when running virsh detach-interface (live or config), the only two items that can be specified to match against are mac address and model type (virtio, etc) - if multiple netdevs match both of those attributes, it again just finds the first one added and assumes that is the only match. Since it is completely valid to have multiple network devices with the same MAC address (although it can cause problems in many cases, there *are* valid use cases), what is needed is: 1) remove the restriction that prohibits doing a persistent add of a netdev with a duplicate mac address. 2) enhance the backend of virDomainDetachDeviceFlags to check for something that *is* guaranteed unique (but still work with just mac address, as long as it yields only a single results. This patch does three things: 1) removes the check for duplicate mac address during a persistent netdev attach. 2) unifies the searching for both live and config detach of netdevices in the subordinate functions of qemuDomainModifyDeviceFlags() to use the new function virDomainNetFindIdx (which matches mac address and PCI address if available, checking for duplicates if only mac address was specified). This function returns -2 if multiple matches are found, allowing the callers to print out an appropriate message. Steps 1 & 2 are enough to fully fix the problem when using virsh attach-device and detach-device (which require an XML description of the device rather than a bunch of commandline args) 3) modifies the virsh detach-interface command to check for multiple matches of mac address and show an error message suggesting use of the detach-device command in cases where there are multiple matching mac addresses. Later we should decide how we want to input a PCI address on the virsh commandline, and enhance detach-interface to take a --address option, eliminating the need to use detach-device * src/conf/domain_conf.c * src/conf/domain_conf.h * src/libvirt_private.syms * added new virDomainNetFindIdx function * removed now unused virDomainNetIndexByMac and virDomainNetRemoveByMac * src/qemu/qemu_driver.c * remove check for duplicate max from qemuDomainAttachDeviceConfig * use virDomainNetFindIdx/virDomainNetRemove instead of virDomainNetRemoveByMac in qemuDomainDetachDeviceConfig * use virDomainNetFindIdx instead of virDomainIndexByMac in qemuDomainUpdateDeviceConfig * src/qemu/qemu_hotplug.c * use virDomainNetFindIdx instead of a homespun loop in qemuDomainDetachNetDevice. * tools/virsh-domain.c: modified detach-interface command as described above
2012-10-25 20:03:35 +00:00
detach = vm->def->nets[detachidx];
if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
/* coverity[negative_returns] */
ret = qemuDomainDetachThisHostDevice(driver, vm,
virDomainNetGetActualHostdev(detach));
goto cleanup;
}
if (qemuDomainMachineIsS390CCW(vm->def) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
if (!virDomainDeviceAddressIsValid(&detach->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
virReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("device cannot be detached without a CCW address"));
goto cleanup;
}
} else {
if (!virDomainDeviceAddressIsValid(&detach->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
virReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("device cannot be detached without a PCI address"));
goto cleanup;
}
if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("cannot hot unplug multifunction PCI device :%s"),
dev->data.disk->dst);
goto cleanup;
}
}
if (!detach->info.alias) {
if (qemuAssignDeviceNetAlias(vm->def, detach, -1) < 0)
goto cleanup;
}
if (virDomainNetGetActualBandwidth(detach) &&
virNetDevSupportBandwidth(virDomainNetGetActualType(detach)) &&
virNetDevBandwidthClear(detach->ifname) < 0)
VIR_WARN("cannot clear bandwidth setting for device : %s",
detach->ifname);
/* deactivate the tap/macvtap device on the host, which could also
* affect the parent device (e.g. macvtap passthrough mode sets
* the parent device offline)
*/
ignore_value(qemuInterfaceStopDevice(detach));
qemuDomainMarkDeviceForRemoval(vm, &detach->info);
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
virDomainAuditNet(vm, detach, NULL, "detach", false);
goto cleanup;
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
ret = qemuDomainRemoveNetDevice(driver, vm, detach);
cleanup:
qemuDomainResetDeviceRemoval(vm);
return ret;
}
int
qemuDomainChangeGraphicsPasswords(virQEMUDriverPtr driver,
virDomainObjPtr vm,
int type,
virDomainGraphicsAuthDefPtr auth,
const char *defaultPasswd,
int asyncJob)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
time_t now = time(NULL);
const char *expire;
char *validTo = NULL;
const char *connected = NULL;
const char *password;
int ret = -1;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
if (!auth->passwd && !defaultPasswd) {
ret = 0;
goto cleanup;
}
password = auth->passwd ? auth->passwd : defaultPasswd;
if (auth->connected)
connected = virDomainGraphicsAuthConnectedTypeToString(auth->connected);
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
goto cleanup;
ret = qemuMonitorSetPassword(priv->mon, type, password, connected);
if (ret == -2) {
if (type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Graphics password only supported for VNC"));
ret = -1;
} else {
ret = qemuMonitorSetVNCPassword(priv->mon, password);
}
}
if (ret != 0)
goto end_job;
if (password[0] == '\0' ||
(auth->expires && auth->validTo <= now)) {
expire = "now";
} else if (auth->expires) {
if (virAsprintf(&validTo, "%lu", (unsigned long) auth->validTo) < 0)
goto end_job;
expire = validTo;
} else {
expire = "never";
}
ret = qemuMonitorExpirePassword(priv->mon, type, expire);
if (ret == -2) {
/* XXX we could fake this with a timer */
if (auth->expires) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Expiry of passwords is not supported"));
ret = -1;
} else {
ret = 0;
}
}
end_job:
if (qemuDomainObjExitMonitor(driver, vm) < 0)
ret = -1;
cleanup:
VIR_FREE(validTo);
virObjectUnref(cfg);
return ret;
}
int qemuDomainAttachLease(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainLeaseDefPtr lease)
{
int ret = -1;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
if (virDomainLeaseInsertPreAlloc(vm->def) < 0)
goto cleanup;
if (virDomainLockLeaseAttach(driver->lockManager, cfg->uri,
vm, lease) < 0) {
virDomainLeaseInsertPreAlloced(vm->def, NULL);
goto cleanup;
}
virDomainLeaseInsertPreAlloced(vm->def, lease);
ret = 0;
cleanup:
virObjectUnref(cfg);
return ret;
}
int qemuDomainDetachLease(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainLeaseDefPtr lease)
{
2012-03-06 23:06:14 +00:00
virDomainLeaseDefPtr det_lease;
int idx;
if ((idx = virDomainLeaseIndex(vm->def, lease)) < 0) {
virReportError(VIR_ERR_INVALID_ARG,
_("Lease %s in lockspace %s does not exist"),
lease->key, NULLSTR(lease->lockspace));
return -1;
}
if (virDomainLockLeaseDetach(driver->lockManager, vm, lease) < 0)
return -1;
det_lease = virDomainLeaseRemoveAt(vm->def, idx);
2012-03-06 23:06:14 +00:00
virDomainLeaseDefFree(det_lease);
return 0;
}
int qemuDomainDetachChrDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainChrDefPtr chr)
{
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainDefPtr vmdef = vm->def;
virDomainChrDefPtr tmpChr;
char *devstr = NULL;
if (!(tmpChr = virDomainChrFind(vmdef, chr))) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("device not present in domain configuration"));
return ret;
}
if (!tmpChr->info.alias && qemuAssignDeviceChrAlias(vmdef, tmpChr, -1) < 0)
return ret;
sa_assert(tmpChr->info.alias);
if (qemuBuildChrDeviceStr(&devstr, vmdef, chr, priv->qemuCaps) < 0)
return ret;
qemuDomainMarkDeviceForRemoval(vm, &tmpChr->info);
qemuDomainObjEnterMonitor(driver, vm);
if (devstr && qemuMonitorDelDevice(priv->mon, tmpChr->info.alias) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm));
goto cleanup;
}
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1) {
qemuDomainReleaseDeviceAddress(vm, &tmpChr->info, NULL);
ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr);
}
cleanup:
qemuDomainResetDeviceRemoval(vm);
VIR_FREE(devstr);
return ret;
}
int
qemuDomainDetachRNGDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainRNGDefPtr rng)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
ssize_t idx;
virDomainRNGDefPtr tmpRNG;
int rc;
int ret = -1;
if ((idx = virDomainRNGFind(vm->def, rng) < 0)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("device not present in domain configuration"));
return -1;
}
tmpRNG = vm->def->rngs[idx];
if (!tmpRNG->info.alias) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("alias not set for RNG device"));
return -1;
}
qemuDomainMarkDeviceForRemoval(vm, &tmpRNG->info);
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorDelDevice(priv->mon, tmpRNG->info.alias);
if (qemuDomainObjExitMonitor(driver, vm) || rc < 0)
goto cleanup;
if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
ret = qemuDomainRemoveRNGDevice(driver, vm, tmpRNG);
cleanup:
qemuDomainResetDeviceRemoval(vm);
return ret;
}
int
qemuDomainDetachMemoryDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainMemoryDefPtr memdef)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainMemoryDefPtr mem;
int idx;
int rc;
int ret = -1;
qemuDomainMemoryDeviceAlignSize(vm->def, memdef);
if ((idx = virDomainMemoryFindByDef(vm->def, memdef)) < 0) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("device not present in domain configuration"));
return -1;
}
mem = vm->def->mems[idx];
if (!mem->info.alias) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("alias for the memory device was not found"));
return -1;
}
qemuDomainMarkDeviceForRemoval(vm, &mem->info);
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorDelDevice(priv->mon, mem->info.alias);
if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
goto cleanup;
if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
ret = qemuDomainRemoveMemoryDevice(driver, vm, mem);
cleanup:
qemuDomainResetDeviceRemoval(vm);
return ret;
}