2010-12-16 16:10:54 +00:00
|
|
|
/*
|
|
|
|
* qemu_hotplug.h: QEMU device hotplug management
|
|
|
|
*
|
domain_conf: split source data out from ChrDef
This opens up the possibility of reusing the smaller ChrSourceDef
for both qemu monitor and a passthrough smartcard device.
* src/conf/domain_conf.h (_virDomainChrDef): Factor host
details...
(_virDomainChrSourceDef): ...into new struct.
(virDomainChrSourceDefFree): New prototype.
* src/conf/domain_conf.c (virDomainChrDefFree)
(virDomainChrDefParseXML, virDomainChrDefFormat): Split...
(virDomainChrSourceDefClear, virDomainChrSourceDefFree)
(virDomainChrSourceDefParseXML, virDomainChrSourceDefFormat):
...into new functions.
(virDomainChrDefParseTargetXML): Update clients to reflect type
split.
* src/vmx/vmx.c (virVMXParseSerial, virVMXParseParallel)
(virVMXFormatSerial, virVMXFormatParallel): Likewise.
* src/xen/xen_driver.c (xenUnifiedDomainOpenConsole): Likewise.
* src/xen/xend_internal.c (xenDaemonParseSxprChar)
(xenDaemonFormatSxprChr): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxAttachSerial)
(vboxAttachParallel): Likewise.
* src/security/security_dac.c (virSecurityDACSetChardevLabel)
(virSecurityDACSetChardevCallback)
(virSecurityDACRestoreChardevLabel)
(virSecurityDACRestoreChardevCallback): Likewise.
* src/security/security_selinux.c (SELinuxSetSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback)
(SELinuxRestoreSecurityChardevLabel)
(SELinuxSetSecurityChardevCallback): Likewise.
* src/security/virt-aa-helper.c (get_files): Likewise.
* src/lxc/lxc_driver.c (lxcVmStart, lxcDomainOpenConsole):
Likewise.
* src/uml/uml_conf.c (umlBuildCommandLineChr): Likewise.
* src/uml/uml_driver.c (umlIdentifyOneChrPTY, umlIdentifyChrPTY)
(umlDomainOpenConsole): Likewise.
* src/qemu/qemu_command.c (qemuBuildChrChardevStr)
(qemuBuildChrArgStr, qemuBuildCommandLine)
(qemuParseCommandLineChr): Likewise.
* src/qemu/qemu_domain.c (qemuDomainObjPrivateXMLFormat)
(qemuDomainObjPrivateXMLParse): Likewise.
* src/qemu/qemu_cgroup.c (qemuSetupChardevCgroup): Likewise.
* src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise.
* src/qemu/qemu_driver.c (qemudFindCharDevicePTYsMonitor)
(qemudFindCharDevicePTYs, qemuPrepareChardevDevice)
(qemuPrepareMonitorChr, qemudShutdownVMDaemon)
(qemuDomainOpenConsole): Likewise.
* src/qemu/qemu_command.h (qemuBuildChrChardevStr)
(qemuBuildChrArgStr): Delete, now that they are static.
* src/libvirt_private.syms (domain_conf.h): New exports.
* cfg.mk (useless_free_options): Update list.
* tests/qemuxml2argvtest.c (testCompareXMLToArgvFiles): Update
tests.
2011-01-07 22:45:01 +00:00
|
|
|
* Copyright (C) 2006-2011 Red Hat, Inc.
|
2010-12-16 16:10:54 +00:00
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "qemu_hotplug.h"
|
|
|
|
#include "qemu_capabilities.h"
|
|
|
|
#include "qemu_domain.h"
|
|
|
|
#include "qemu_command.h"
|
|
|
|
#include "qemu_bridge_filter.h"
|
|
|
|
#include "qemu_audit.h"
|
|
|
|
#include "qemu_hostdev.h"
|
|
|
|
#include "domain_nwfilter.h"
|
|
|
|
#include "logging.h"
|
|
|
|
#include "virterror_internal.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "pci.h"
|
|
|
|
#include "files.h"
|
|
|
|
#include "qemu_cgroup.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
int qemuDomainChangeEjectableMedia(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
unsigned long long qemuCmdFlags,
|
|
|
|
bool force)
|
|
|
|
{
|
|
|
|
virDomainDiskDefPtr origdisk = NULL;
|
|
|
|
int i;
|
|
|
|
int ret;
|
|
|
|
char *driveAlias = NULL;
|
|
|
|
|
|
|
|
origdisk = NULL;
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (vm->def->disks[i]->bus == disk->bus &&
|
|
|
|
STREQ(vm->def->disks[i]->dst, disk->dst)) {
|
|
|
|
origdisk = vm->def->disks[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!origdisk) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("No device with bus '%s' and target '%s'"),
|
|
|
|
virDomainDiskBusTypeToString(disk->bus),
|
|
|
|
disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!origdisk->info.alias) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing disk device alias name for %s"), origdisk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
|
|
|
|
origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Removable media not supported for %s device"),
|
|
|
|
virDomainDiskDeviceTypeToString(disk->device));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetImageLabel(driver->securityManager,
|
|
|
|
vm, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(driveAlias = qemuDeviceDriveHostAlias(origdisk, qemuCmdFlags)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (disk->src) {
|
|
|
|
const char *format = NULL;
|
|
|
|
if (disk->type != VIR_DOMAIN_DISK_TYPE_DIR) {
|
|
|
|
if (disk->driverType)
|
|
|
|
format = disk->driverType;
|
|
|
|
else if (origdisk->driverType)
|
|
|
|
format = origdisk->driverType;
|
|
|
|
}
|
|
|
|
ret = qemuMonitorChangeMedia(priv->mon,
|
|
|
|
driveAlias,
|
|
|
|
disk->src, format);
|
|
|
|
} else {
|
|
|
|
ret = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
qemuDomainDiskAudit(vm, origdisk, disk, "update", ret >= 0);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
|
|
|
vm, origdisk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on ejected image %s", origdisk->src);
|
|
|
|
|
|
|
|
VIR_FREE(origdisk->src);
|
|
|
|
origdisk->src = disk->src;
|
|
|
|
disk->src = NULL;
|
|
|
|
origdisk->type = disk->type;
|
|
|
|
|
|
|
|
VIR_FREE(driveAlias);
|
|
|
|
|
|
|
|
virDomainDiskDefFree(disk);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(driveAlias);
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
|
|
|
vm, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on new media %s", disk->src);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachPciDiskDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int i, ret;
|
|
|
|
const char* type = virDomainDiskBusTypeToString(disk->bus);
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
char *devstr = NULL;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s already exists"), disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetImageLabel(driver->securityManager,
|
|
|
|
vm, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
|
|
|
|
goto error;
|
|
|
|
if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
|
|
|
|
goto error;
|
|
|
|
|
2011-01-12 10:33:34 +00:00
|
|
|
if (!(devstr = qemuBuildDriveDevStr(disk, qemuCmdFlags)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
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 */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virDomainDevicePCIAddress guestAddr;
|
|
|
|
ret = qemuMonitorAddPCIDisk(priv->mon,
|
|
|
|
disk->src,
|
|
|
|
type,
|
|
|
|
&guestAddr);
|
|
|
|
if (ret == 0) {
|
|
|
|
disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
memcpy(&disk->info.addr.pci, &guestAddr, sizeof(guestAddr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
qemuDomainDiskAudit(vm, NULL, disk, "attach", ret >= 0);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virDomainDiskInsertPreAlloced(vm->def, disk);
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
(disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
|
|
|
|
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &disk->info) < 0)
|
|
|
|
VIR_WARN("Unable to release PCI address on %s", disk->src);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
|
|
|
vm, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", disk->src);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachPciControllerDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainControllerDefPtr controller,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int ret = -1;
|
|
|
|
const char* type = virDomainControllerTypeToString(controller->type);
|
|
|
|
char *devstr = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ncontrollers ; i++) {
|
|
|
|
if ((vm->def->controllers[i]->type == controller->type) &&
|
|
|
|
(vm->def->controllers[i]->idx == controller->idx)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s:%d already exists"),
|
|
|
|
type, controller->idx);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (qemuAssignDeviceControllerAlias(controller) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!(devstr = qemuBuildControllerDevStr(controller))) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
} else {
|
|
|
|
ret = qemuMonitorAttachPCIDiskController(priv->mon,
|
|
|
|
type,
|
|
|
|
&controller->info.addr.pci);
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
virDomainControllerInsertPreAlloced(vm->def, controller);
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if ((ret != 0) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
(controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
|
|
|
|
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &controller->info) < 0)
|
|
|
|
VIR_WARN0("Unable to release PCI address on controller");
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virDomainControllerDefPtr
|
|
|
|
qemuDomainFindOrCreateSCSIDiskController(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
int controller,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int 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) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
|
|
|
|
cont->idx = 0;
|
|
|
|
cont->model = -1;
|
|
|
|
|
|
|
|
VIR_INFO0("No SCSI controller present, hotplugging one");
|
|
|
|
if (qemuDomainAttachPciControllerDevice(driver,
|
|
|
|
vm, cont, qemuCmdFlags) < 0) {
|
|
|
|
VIR_FREE(cont);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
qemuReportError(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachSCSIDisk(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virDomainControllerDefPtr cont = NULL;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
char *devstr = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s already exists"), disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetImageLabel(driver->securityManager,
|
|
|
|
vm, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* We should have an address already, so make sure */
|
|
|
|
if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected disk address type %s"),
|
|
|
|
virDomainDeviceAddressTypeToString(disk->info.type));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
|
|
|
|
goto error;
|
2011-01-12 10:33:34 +00:00
|
|
|
if (!(devstr = qemuBuildDriveDevStr(disk, qemuCmdFlags)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
for (i = 0 ; i <= disk->info.addr.drive.controller ; i++) {
|
|
|
|
cont = qemuDomainFindOrCreateSCSIDiskController(driver, vm, i, qemuCmdFlags);
|
|
|
|
if (!cont)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Tell clang that "cont" is non-NULL.
|
|
|
|
This is because disk->info.addr.driver.controller is unsigned,
|
|
|
|
and hence the above loop must iterate at least once. */
|
|
|
|
sa_assert (cont);
|
|
|
|
|
|
|
|
if (cont->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("SCSI controller %d was missing its PCI address"), cont->idx);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
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 */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
virDomainDeviceDriveAddress driveAddr;
|
|
|
|
ret = qemuMonitorAttachDrive(priv->mon,
|
|
|
|
drivestr,
|
|
|
|
&cont->info.addr.pci,
|
|
|
|
&driveAddr);
|
|
|
|
if (ret == 0) {
|
|
|
|
/* XXX we should probably validate that the addr matches
|
|
|
|
* our existing defined addr instead of overwriting */
|
|
|
|
disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
|
|
|
|
memcpy(&disk->info.addr.drive, &driveAddr, sizeof(driveAddr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
qemuDomainDiskAudit(vm, NULL, disk, "attach", ret >= 0);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virDomainDiskInsertPreAlloced(vm->def, disk);
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
|
|
|
vm, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", disk->src);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachUsbMassstorageDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int i, ret;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
char *devstr = NULL;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("target %s already exists"), disk->dst);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetImageLabel(driver->securityManager,
|
|
|
|
vm, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!disk->src) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("disk source path is missing"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
|
|
|
|
goto error;
|
|
|
|
if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
|
|
|
|
goto error;
|
2011-01-12 10:33:34 +00:00
|
|
|
if (!(devstr = qemuBuildDriveDevStr(disk, qemuCmdFlags)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
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 */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = qemuMonitorAddUSBDisk(priv->mon, disk->src);
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
qemuDomainDiskAudit(vm, NULL, disk, "attach", ret >= 0);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virDomainDiskInsertPreAlloced(vm->def, disk);
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
|
|
|
vm, disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", disk->src);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* XXX conn required for network -> bridge resolution */
|
|
|
|
int qemuDomainAttachNetDevice(virConnectPtr conn,
|
|
|
|
struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainNetDefPtr net,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
char *tapfd_name = NULL;
|
|
|
|
int tapfd = -1;
|
|
|
|
char *nicstr = NULL;
|
|
|
|
char *netstr = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
virDomainDevicePCIAddress guestAddr;
|
|
|
|
int vlan;
|
|
|
|
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("installed qemu version does not support host_net_add"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
|
|
|
|
net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
2011-01-07 23:36:25 +00:00
|
|
|
if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("network device type '%s' cannot be attached: "
|
|
|
|
"qemu is not using a unix socket monitor"),
|
|
|
|
virDomainNetTypeToString(net->type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tapfd = qemuNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
|
|
|
|
return -1;
|
|
|
|
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
2011-01-07 23:36:25 +00:00
|
|
|
if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
|
2010-12-16 16:10:54 +00:00
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("network device type '%s' cannot be attached: "
|
|
|
|
"qemu is not using a unix socket monitor"),
|
|
|
|
virDomainNetTypeToString(net->type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tapfd = qemuPhysIfaceConnect(conn, driver, net,
|
|
|
|
qemuCmdFlags,
|
|
|
|
vm->def->uuid,
|
|
|
|
VIR_VM_OP_CREATE)) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
vlan = -1;
|
|
|
|
} else {
|
|
|
|
vlan = qemuDomainNetVLAN(net);
|
|
|
|
|
|
|
|
if (vlan < 0) {
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Unable to attach network devices without vlan"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tapfd != -1) {
|
|
|
|
if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("guest unexpectedly quit"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME - need to support vhost-net here (5th arg) */
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
if (!(netstr = qemuBuildHostNetStr(net, ',',
|
|
|
|
-1, tapfd_name, 0)))
|
|
|
|
goto try_tapfd_close;
|
|
|
|
} else {
|
|
|
|
if (!(netstr = qemuBuildHostNetStr(net, ' ',
|
|
|
|
vlan, tapfd_name, 0)))
|
|
|
|
goto try_tapfd_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
if (qemuMonitorAddNetdev(priv->mon, netstr) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
qemuDomainNetAudit(vm, NULL, net, "attach", false);
|
|
|
|
goto try_tapfd_close;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
qemuDomainNetAudit(vm, NULL, net, "attach", false);
|
|
|
|
goto try_tapfd_close;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
VIR_FORCE_CLOSE(tapfd);
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("guest unexpectedly quit"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
2011-01-12 10:33:34 +00:00
|
|
|
if (!(nicstr = qemuBuildNicDevStr(net, vlan, qemuCmdFlags)))
|
2010-12-16 16:10:54 +00:00
|
|
|
goto try_remove;
|
|
|
|
} else {
|
|
|
|
if (!(nicstr = qemuBuildNicStr(net, NULL, vlan)))
|
|
|
|
goto try_remove;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
qemuDomainNetAudit(vm, NULL, net, "attach", false);
|
|
|
|
goto try_remove;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorAddPCINetwork(priv->mon, nicstr,
|
|
|
|
&guestAddr) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
qemuDomainNetAudit(vm, NULL, net, "attach", false);
|
|
|
|
goto try_remove;
|
|
|
|
}
|
|
|
|
net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
memcpy(&net->info.addr.pci, &guestAddr, sizeof(guestAddr));
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
qemuDomainNetAudit(vm, NULL, net, "attach", true);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
vm->def->nets[vm->def->nnets++] = net;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if ((ret != 0) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
(net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
|
|
|
|
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &net->info) < 0)
|
|
|
|
VIR_WARN0("Unable to release PCI address on NIC");
|
|
|
|
|
|
|
|
if (ret != 0)
|
|
|
|
virDomainConfNWFilterTeardown(net);
|
|
|
|
|
|
|
|
VIR_FREE(nicstr);
|
|
|
|
VIR_FREE(netstr);
|
|
|
|
VIR_FREE(tapfd_name);
|
|
|
|
VIR_FORCE_CLOSE(tapfd);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
try_remove:
|
|
|
|
if (!virDomainObjIsActive(vm))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (vlan < 0) {
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
char *netdev_name;
|
|
|
|
if (virAsprintf(&netdev_name, "host%s", net->info.alias) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
|
|
|
|
VIR_WARN("Failed to remove network backend for netdev %s",
|
|
|
|
netdev_name);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
VIR_FREE(netdev_name);
|
|
|
|
} else {
|
|
|
|
VIR_WARN0("Unable to remove network backend");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
char *hostnet_name;
|
|
|
|
if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(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);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
VIR_FREE(hostnet_name);
|
|
|
|
}
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
try_tapfd_close:
|
|
|
|
if (!virDomainObjIsActive(vm))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (tapfd_name) {
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
|
|
|
|
VIR_WARN("Failed to close tapfd with '%s'", tapfd_name);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
}
|
|
|
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachHostPciDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainHostdevDefPtr hostdev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int ret;
|
|
|
|
char *devstr = NULL;
|
|
|
|
int configfd = -1;
|
|
|
|
char *configfd_name = NULL;
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuPrepareHostdevPCIDevices(driver, &hostdev, 1) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
|
|
|
|
goto error;
|
|
|
|
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
|
|
|
|
goto error;
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_PCI_CONFIGFD) {
|
|
|
|
configfd = qemuOpenPCIConfig(hostdev);
|
|
|
|
if (configfd >= 0) {
|
|
|
|
if (virAsprintf(&configfd_name, "fd-%s",
|
|
|
|
hostdev->info.alias) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuMonitorSendFileHandle(priv->mon, configfd_name,
|
|
|
|
configfd) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("guest unexpectedly quit during hotplug"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
} else {
|
|
|
|
virDomainDevicePCIAddress guestAddr;
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
ret = qemuMonitorAddPCIHostDevice(priv->mon,
|
|
|
|
&hostdev->source.subsys.u.pci,
|
|
|
|
&guestAddr);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
hostdev->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
|
|
|
memcpy(&hostdev->info.addr.pci, &guestAddr, sizeof(guestAddr));
|
|
|
|
}
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(configfd_name);
|
|
|
|
VIR_FORCE_CLOSE(configfd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
(hostdev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
|
|
|
|
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &hostdev->info) < 0)
|
|
|
|
VIR_WARN0("Unable to release PCI address on host device");
|
|
|
|
|
|
|
|
qemuDomainReAttachHostdevDevices(driver, &hostdev, 1);
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
VIR_FREE(configfd_name);
|
|
|
|
VIR_FORCE_CLOSE(configfd);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainHostdevDefPtr hostdev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
char *devstr = NULL;
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
|
|
|
|
goto error;
|
|
|
|
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
usbDevice *usb;
|
|
|
|
|
|
|
|
if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-01-28 03:39:44 +00:00
|
|
|
_("Unable to find cgroup for %s"),
|
2010-12-16 16:10:54 +00:00
|
|
|
vm->def->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((usb = usbGetDevice(hostdev->source.subsys.u.usb.bus,
|
|
|
|
hostdev->source.subsys.u.usb.device)) == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (usbDeviceFileIterate(usb, qemuSetupHostUsbDeviceCgroup, cgroup) < 0 )
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
|
|
|
|
ret = qemuMonitorAddDevice(priv->mon, devstr);
|
|
|
|
else
|
|
|
|
ret = qemuMonitorAddUSBDeviceExact(priv->mon,
|
|
|
|
hostdev->source.subsys.u.usb.bus,
|
|
|
|
hostdev->source.subsys.u.usb.device);
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
if (ret < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
|
|
|
|
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(devstr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainAttachHostDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainHostdevDefPtr hostdev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hostdev mode '%s' not supported"),
|
|
|
|
virDomainHostdevModeTypeToString(hostdev->mode));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resolve USB product/vendor to bus/device */
|
|
|
|
if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
|
|
|
|
hostdev->source.subsys.u.usb.vendor) {
|
|
|
|
usbDevice *usb
|
|
|
|
= usbFindDevice(hostdev->source.subsys.u.usb.vendor,
|
|
|
|
hostdev->source.subsys.u.usb.product);
|
|
|
|
|
|
|
|
if (!usb)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
|
|
|
|
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
|
|
|
|
|
|
|
|
usbFreeDevice(usb);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerSetHostdevLabel(driver->securityManager,
|
|
|
|
vm, hostdev) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
switch (hostdev->source.subsys.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
|
|
|
if (qemuDomainAttachHostPciDevice(driver, vm,
|
|
|
|
hostdev, qemuCmdFlags) < 0)
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
|
|
|
if (qemuDomainAttachHostUsbDevice(driver, vm,
|
|
|
|
hostdev, qemuCmdFlags) < 0)
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hostdev subsys type '%s' not supported"),
|
|
|
|
virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreHostdevLabel(driver->securityManager,
|
|
|
|
vm, hostdev) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN0("Unable to restore host device labelling on hotplug fail");
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static virDomainGraphicsDefPtr qemuDomainFindGraphics(virDomainObjPtr vm,
|
|
|
|
virDomainGraphicsDefPtr dev)
|
|
|
|
{
|
|
|
|
int 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
|
|
|
|
qemuDomainChangeGraphics(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainGraphicsDefPtr dev)
|
|
|
|
{
|
|
|
|
virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!olddev) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot find existing graphics device to modify"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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))) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change port settings on vnc graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.vnc.listenAddr, dev->data.vnc.listenAddr)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change listen address setting on vnc graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change keymap setting on vnc graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
/* If a password lifetime was, or is set, then we must always run,
|
|
|
|
* even if new password matches old password */
|
|
|
|
if (olddev->data.vnc.auth.expires ||
|
|
|
|
dev->data.vnc.auth.expires ||
|
|
|
|
STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd, dev->data.vnc.auth.passwd)) {
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_DEBUG("Updating password on VNC server %p %p", dev->data.vnc.auth.passwd, driver->vncPassword);
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
ret = qemuDomainChangeGraphicsPasswords(driver, vm, VIR_DOMAIN_GRAPHICS_TYPE_VNC,
|
|
|
|
&dev->data.vnc.auth, driver->vncPassword);
|
2010-12-16 16:10:54 +00:00
|
|
|
|
|
|
|
/* 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;
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo;
|
|
|
|
olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires;
|
2010-12-16 16:10:54 +00:00
|
|
|
} else {
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
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))) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change port settings on spice graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.spice.listenAddr, dev->data.spice.listenAddr)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change listen address setting on spice graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (STRNEQ_NULLABLE(olddev->data.spice.keymap, dev->data.spice.keymap)) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot change keymap setting on spice graphics"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If a password lifetime was, or is set, then we must always run,
|
|
|
|
* even if new password matches old password */
|
|
|
|
if (olddev->data.spice.auth.expires ||
|
|
|
|
dev->data.spice.auth.expires ||
|
|
|
|
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, driver->spicePassword);
|
|
|
|
ret = qemuDomainChangeGraphicsPasswords(driver, vm, VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
|
|
|
|
&dev->data.spice.auth, driver->spicePassword);
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
} else {
|
|
|
|
VIR_DEBUG0("Not updating since password didn't change");
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
2010-12-16 16:10:54 +00:00
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unable to change config on '%s' graphics type"),
|
|
|
|
virDomainGraphicsTypeToString(dev->type));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline int qemuFindDisk(virDomainDefPtr def, const char *dst)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0 ; i < def->ndisks ; i++) {
|
|
|
|
if (STREQ(def->disks[i]->dst, dst)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int qemuDomainDetachPciDiskDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
virDomainDiskDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
|
|
|
|
i = qemuFindDisk(vm->def, dev->data.disk->dst);
|
|
|
|
|
|
|
|
if (i < 0) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("disk %s not found"), dev->data.disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
detach = vm->def->disks[i];
|
|
|
|
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
|
|
|
if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-01-28 03:39:44 +00:00
|
|
|
_("Unable to find cgroup for %s"),
|
2010-12-16 16:10:54 +00:00
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDeviceAddressIsValid(&detach->info,
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("device cannot be detached without a PCI address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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, detach->info.alias) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
|
|
|
|
qemuDomainObjExitMonitor(vm);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemovePCIDevice(priv->mon,
|
|
|
|
&detach->info.addr.pci) < 0) {
|
|
|
|
qemuDomainObjExitMonitor(vm);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disconnect guest from host device */
|
|
|
|
qemuMonitorDriveDel(priv->mon, drivestr);
|
|
|
|
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
qemuDomainDiskAudit(vm, detach, NULL, "detach", ret >= 0);
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
|
|
|
|
VIR_WARN("Unable to release PCI address on %s", dev->data.disk->src);
|
|
|
|
|
|
|
|
virDomainDiskRemove(vm->def, i);
|
|
|
|
|
|
|
|
virDomainDiskDefFree(detach);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
|
|
|
vm, dev->data.disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
|
|
|
|
|
|
|
|
if (cgroup != NULL) {
|
|
|
|
if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
|
|
|
|
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
|
|
|
NULLSTR(dev->data.disk->src));
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
virDomainDiskDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
virCgroupPtr cgroup = NULL;
|
|
|
|
char *drivestr = NULL;
|
|
|
|
|
|
|
|
i = qemuFindDisk(vm->def, dev->data.disk->dst);
|
|
|
|
|
|
|
|
if (i < 0) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("disk %s not found"), dev->data.disk->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("Underlying qemu does not support SCSI disk removal"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
detach = vm->def->disks[i];
|
|
|
|
|
|
|
|
if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
|
|
|
|
if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-01-28 03:39:44 +00:00
|
|
|
_("Unable to find cgroup for %s"),
|
2010-12-16 16:10:54 +00:00
|
|
|
vm->def->name);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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, detach->info.alias) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
|
|
|
|
qemuDomainObjExitMonitor(vm);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disconnect guest from host device */
|
|
|
|
qemuMonitorDriveDel(priv->mon, drivestr);
|
|
|
|
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
qemuDomainDiskAudit(vm, detach, NULL, "detach", ret >= 0);
|
|
|
|
|
|
|
|
virDomainDiskRemove(vm->def, i);
|
|
|
|
|
|
|
|
virDomainDiskDefFree(detach);
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreImageLabel(driver->securityManager,
|
|
|
|
vm, dev->data.disk) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);
|
|
|
|
|
|
|
|
if (cgroup != NULL) {
|
|
|
|
if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
|
|
|
|
VIR_WARN("Failed to teardown cgroup for disk path %s",
|
|
|
|
NULLSTR(dev->data.disk->src));
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(drivestr);
|
|
|
|
virCgroupFree(&cgroup);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainDetachPciControllerDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
virDomainControllerDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ncontrollers ; i++) {
|
|
|
|
if ((vm->def->controllers[i]->type == dev->data.controller->type) &&
|
|
|
|
(vm->def->controllers[i]->idx == dev->data.controller->idx)) {
|
|
|
|
detach = vm->def->controllers[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("disk controller %s:%d not found"),
|
|
|
|
virDomainControllerTypeToString(dev->data.controller->type),
|
|
|
|
dev->data.controller->idx);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDeviceAddressIsValid(&detach->info,
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
|
_("device cannot be detached without a PCI address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuAssignDeviceControllerAlias(detach) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias)) {
|
|
|
|
qemuDomainObjExitMonitor(vm);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemovePCIDevice(priv->mon,
|
|
|
|
&detach->info.addr.pci) < 0) {
|
|
|
|
qemuDomainObjExitMonitor(vm);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
if (vm->def->ncontrollers > 1) {
|
|
|
|
memmove(vm->def->controllers + i,
|
|
|
|
vm->def->controllers + i + 1,
|
|
|
|
sizeof(*vm->def->controllers) *
|
|
|
|
(vm->def->ncontrollers - (i + 1)));
|
|
|
|
vm->def->ncontrollers--;
|
|
|
|
if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers) < 0) {
|
|
|
|
/* ignore, harmless */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VIR_FREE(vm->def->controllers);
|
|
|
|
vm->def->ncontrollers = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
|
|
|
|
VIR_WARN0("Unable to release PCI address on controller");
|
|
|
|
|
|
|
|
virDomainControllerDefFree(detach);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainDetachNetDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
int i, ret = -1;
|
|
|
|
virDomainNetDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int vlan;
|
|
|
|
char *hostnet_name = NULL;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->nnets ; i++) {
|
|
|
|
virDomainNetDefPtr net = vm->def->nets[i];
|
|
|
|
|
|
|
|
if (!memcmp(net->mac, dev->data.net->mac, sizeof(net->mac))) {
|
|
|
|
detach = net;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("network device %02x:%02x:%02x:%02x:%02x:%02x not found"),
|
|
|
|
dev->data.net->mac[0], dev->data.net->mac[1],
|
|
|
|
dev->data.net->mac[2], dev->data.net->mac[3],
|
|
|
|
dev->data.net->mac[4], dev->data.net->mac[5]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDeviceAddressIsValid(&detach->info,
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("device cannot be detached without a PCI address"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("unable to determine original VLAN"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
|
|
|
|
qemuDomainObjExitMonitor(vm);
|
|
|
|
qemuDomainNetAudit(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemovePCIDevice(priv->mon,
|
|
|
|
&detach->info.addr.pci) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
qemuDomainNetAudit(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
|
|
|
|
(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
qemuDomainNetAudit(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
qemuDomainNetAudit(vm, detach, NULL, "detach", false);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
qemuDomainNetAudit(vm, detach, NULL, "detach", true);
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
|
|
|
|
VIR_WARN0("Unable to release PCI address on NIC");
|
|
|
|
|
|
|
|
virDomainConfNWFilterTeardown(detach);
|
|
|
|
|
|
|
|
#if WITH_MACVTAP
|
|
|
|
if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
|
|
|
delMacvtap(detach->ifname, detach->mac, detach->data.direct.linkdev,
|
|
|
|
&detach->data.direct.virtPortProfile);
|
|
|
|
VIR_FREE(detach->ifname);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ((driver->macFilter) && (detach->ifname != NULL)) {
|
|
|
|
if ((errno = networkDisallowMacOnPort(driver,
|
|
|
|
detach->ifname,
|
|
|
|
detach->mac))) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("failed to remove ebtables rule on '%s'"),
|
|
|
|
detach->ifname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vm->def->nnets > 1) {
|
|
|
|
memmove(vm->def->nets + i,
|
|
|
|
vm->def->nets + i + 1,
|
|
|
|
sizeof(*vm->def->nets) *
|
|
|
|
(vm->def->nnets - (i + 1)));
|
|
|
|
vm->def->nnets--;
|
|
|
|
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets) < 0) {
|
|
|
|
/* ignore, harmless */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VIR_FREE(vm->def->nets);
|
|
|
|
vm->def->nnets = 0;
|
|
|
|
}
|
|
|
|
virDomainNetDefFree(detach);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(hostnet_name);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
virDomainHostdevDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int i, ret;
|
|
|
|
pciDevice *pci;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->nhostdevs ; i++) {
|
|
|
|
if (vm->def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
|
|
|
|
vm->def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
unsigned domain = vm->def->hostdevs[i]->source.subsys.u.pci.domain;
|
|
|
|
unsigned bus = vm->def->hostdevs[i]->source.subsys.u.pci.bus;
|
|
|
|
unsigned slot = vm->def->hostdevs[i]->source.subsys.u.pci.slot;
|
|
|
|
unsigned function = vm->def->hostdevs[i]->source.subsys.u.pci.function;
|
|
|
|
|
|
|
|
if (dev->data.hostdev->source.subsys.u.pci.domain == domain &&
|
|
|
|
dev->data.hostdev->source.subsys.u.pci.bus == bus &&
|
|
|
|
dev->data.hostdev->source.subsys.u.pci.slot == slot &&
|
|
|
|
dev->data.hostdev->source.subsys.u.pci.function == function) {
|
|
|
|
detach = vm->def->hostdevs[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("host pci device %.4x:%.2x:%.2x.%.1x not found"),
|
|
|
|
dev->data.hostdev->source.subsys.u.pci.domain,
|
|
|
|
dev->data.hostdev->source.subsys.u.pci.bus,
|
|
|
|
dev->data.hostdev->source.subsys.u.pci.slot,
|
|
|
|
dev->data.hostdev->source.subsys.u.pci.function);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virDomainDeviceAddressIsValid(&detach->info,
|
|
|
|
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("device cannot be detached without a PCI address"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
|
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
|
|
|
|
qemuDomainObjExitMonitor(vm);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (qemuMonitorRemovePCIDevice(priv->mon,
|
|
|
|
&detach->info.addr.pci) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
pci = pciGetDevice(detach->source.subsys.u.pci.domain,
|
|
|
|
detach->source.subsys.u.pci.bus,
|
|
|
|
detach->source.subsys.u.pci.slot,
|
|
|
|
detach->source.subsys.u.pci.function);
|
|
|
|
if (!pci)
|
|
|
|
ret = -1;
|
|
|
|
else {
|
|
|
|
pciDeviceSetManaged(pci, detach->managed);
|
|
|
|
pciDeviceListDel(driver->activePciHostdevs, pci);
|
|
|
|
if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
|
|
|
|
ret = -1;
|
|
|
|
qemuReattachPciDevice(pci, driver);
|
|
|
|
pciFreeDevice(pci);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
|
|
|
|
qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
|
|
|
|
VIR_WARN0("Unable to release PCI address on host device");
|
|
|
|
|
|
|
|
if (vm->def->nhostdevs > 1) {
|
|
|
|
memmove(vm->def->hostdevs + i,
|
|
|
|
vm->def->hostdevs + i + 1,
|
|
|
|
sizeof(*vm->def->hostdevs) *
|
|
|
|
(vm->def->nhostdevs - (i + 1)));
|
|
|
|
vm->def->nhostdevs--;
|
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs) < 0) {
|
|
|
|
/* ignore, harmless */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VIR_FREE(vm->def->hostdevs);
|
|
|
|
vm->def->nhostdevs = 0;
|
|
|
|
}
|
|
|
|
virDomainHostdevDefFree(detach);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
virDomainHostdevDefPtr detach = NULL;
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->nhostdevs ; i++) {
|
|
|
|
if (vm->def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
|
|
|
|
vm->def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
unsigned bus = vm->def->hostdevs[i]->source.subsys.u.usb.bus;
|
|
|
|
unsigned device = vm->def->hostdevs[i]->source.subsys.u.usb.device;
|
|
|
|
unsigned product = vm->def->hostdevs[i]->source.subsys.u.usb.product;
|
|
|
|
unsigned vendor = vm->def->hostdevs[i]->source.subsys.u.usb.vendor;
|
|
|
|
|
|
|
|
if (dev->data.hostdev->source.subsys.u.usb.bus &&
|
|
|
|
dev->data.hostdev->source.subsys.u.usb.device) {
|
|
|
|
if (dev->data.hostdev->source.subsys.u.usb.bus == bus &&
|
|
|
|
dev->data.hostdev->source.subsys.u.usb.device == device) {
|
|
|
|
detach = vm->def->hostdevs[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (dev->data.hostdev->source.subsys.u.usb.product == product &&
|
|
|
|
dev->data.hostdev->source.subsys.u.usb.vendor == vendor) {
|
|
|
|
detach = vm->def->hostdevs[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("host usb device %03d.%03d not found"),
|
|
|
|
dev->data.hostdev->source.subsys.u.usb.bus,
|
|
|
|
dev->data.hostdev->source.subsys.u.usb.device);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!detach->info.alias) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("device cannot be detached without a device alias"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
|
|
|
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("device cannot be detached with this QEMU version"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
if (vm->def->nhostdevs > 1) {
|
|
|
|
memmove(vm->def->hostdevs + i,
|
|
|
|
vm->def->hostdevs + i + 1,
|
|
|
|
sizeof(*vm->def->hostdevs) *
|
|
|
|
(vm->def->nhostdevs - (i + 1)));
|
|
|
|
vm->def->nhostdevs--;
|
|
|
|
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs) < 0) {
|
|
|
|
/* ignore, harmless */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VIR_FREE(vm->def->hostdevs);
|
|
|
|
vm->def->nhostdevs = 0;
|
|
|
|
}
|
|
|
|
virDomainHostdevDefFree(detach);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemuDomainDetachHostDevice(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
virDomainDeviceDefPtr dev,
|
|
|
|
unsigned long long qemuCmdFlags)
|
|
|
|
{
|
|
|
|
virDomainHostdevDefPtr hostdev = dev->data.hostdev;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
|
|
|
|
qemuReportError(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:
|
|
|
|
ret = qemuDomainDetachHostPciDevice(driver, vm, dev, qemuCmdFlags);
|
|
|
|
break;
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
|
|
|
ret = qemuDomainDetachHostUsbDevice(driver, vm, dev, qemuCmdFlags);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("hostdev subsys type '%s' not supported"),
|
|
|
|
virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
Refactor the security drivers to simplify usage
The current security driver usage requires horrible code like
if (driver->securityDriver &&
driver->securityDriver->domainSetSecurityHostdevLabel &&
driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
This pair of checks for NULL clutters up the code, making the driver
calls 2 lines longer than they really need to be. The goal of the
patchset is to change the calling convention to simply
if (virSecurityManagerSetHostdevLabel(driver->securityDriver,
vm, hostdev) < 0)
The first check for 'driver->securityDriver' being NULL is removed
by introducing a 'no op' security driver that will always be present
if no real driver is enabled. This guarentees driver->securityDriver
!= NULL.
The second check for 'driver->securityDriver->domainSetSecurityHostdevLabel'
being non-NULL is hidden in a new abstraction called virSecurityManager.
This separates the driver callbacks, from main internal API. The addition
of a virSecurityManager object, that is separate from the virSecurityDriver
struct also allows for security drivers to carry state / configuration
information directly. Thus the DAC/Stack drivers from src/qemu which
used to pull config from 'struct qemud_driver' can now be moved into
the 'src/security' directory and store their config directly.
* src/qemu/qemu_conf.h, src/qemu/qemu_driver.c: Update to
use new virSecurityManager APIs
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_dac.h
src/qemu/qemu_security_stacked.c, src/qemu/qemu_security_stacked.h:
Move into src/security directory
* src/security/security_stack.c, src/security/security_stack.h,
src/security/security_dac.c, src/security/security_dac.h: Generic
versions of previous QEMU specific drivers
* src/security/security_apparmor.c, src/security/security_apparmor.h,
src/security/security_driver.c, src/security/security_driver.h,
src/security/security_selinux.c, src/security/security_selinux.h:
Update to take virSecurityManagerPtr object as the first param
in all callbacks
* src/security/security_nop.c, src/security/security_nop.h: Stub
implementation of all security driver APIs.
* src/security/security_manager.h, src/security/security_manager.c:
New internal API for invoking security drivers
* src/libvirt.c: Add missing debug for security APIs
2010-11-17 20:26:30 +00:00
|
|
|
if (virSecurityManagerRestoreHostdevLabel(driver->securityManager,
|
|
|
|
vm, dev->data.hostdev) < 0)
|
2010-12-16 16:10:54 +00:00
|
|
|
VIR_WARN0("Failed to restore host device labelling");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
qemuDomainChangeGraphicsPasswords(struct qemud_driver *driver,
|
|
|
|
virDomainObjPtr vm,
|
|
|
|
int type,
|
|
|
|
virDomainGraphicsAuthDefPtr auth,
|
|
|
|
const char *defaultPasswd)
|
|
|
|
{
|
|
|
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
|
time_t now = time(NULL);
|
|
|
|
char expire_time [64];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!auth->passwd && !driver->vncPassword)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
|
|
|
ret = qemuMonitorSetPassword(priv->mon,
|
|
|
|
type,
|
|
|
|
auth->passwd ? auth->passwd : defaultPasswd,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (ret == -2) {
|
|
|
|
if (type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Only VNC graphics are supported"));
|
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
ret = qemuMonitorSetVNCPassword(priv->mon,
|
|
|
|
auth->passwd ? auth->passwd : defaultPasswd);
|
|
|
|
}
|
|
|
|
}
|
2011-01-18 18:37:45 +00:00
|
|
|
if (ret != 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!virDomainObjIsActive(vm)) {
|
|
|
|
ret = -1;
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("guest unexpectedly quit"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
|
|
|
|
if (auth->expires) {
|
|
|
|
time_t lifetime = auth->validTo - now;
|
|
|
|
if (lifetime <= 0)
|
|
|
|
snprintf(expire_time, sizeof (expire_time), "now");
|
|
|
|
else
|
|
|
|
snprintf(expire_time, sizeof (expire_time), "%lu", (long unsigned)auth->validTo);
|
|
|
|
} else {
|
|
|
|
snprintf(expire_time, sizeof (expire_time), "never");
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = qemuMonitorExpirePassword(priv->mon, type, expire_time);
|
|
|
|
|
|
|
|
if (ret == -2) {
|
|
|
|
/* XXX we could fake this with a timer */
|
|
|
|
if (auth->expires) {
|
|
|
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Expiry of passwords is not supported"));
|
|
|
|
ret = -1;
|
2011-01-18 18:37:45 +00:00
|
|
|
} else {
|
|
|
|
ret = 0;
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-18 18:37:45 +00:00
|
|
|
cleanup:
|
Use the new set_password monitor command to set password.
We try to use that command first when setting a VNC/SPICE password. If
that doesn't work we fallback to the legacy VNC only password
Allow an expiry time to be set, if that doesn't work, throw an error
if they try to use SPICE.
Change since v1:
- moved qemuInitGraphicsPasswords to qemu_hotplug, renamed
to qemuDomainChangeGraphicsPasswords.
- updated what looks like a typo (that appears to work anyway) in
initial patch from Daniel:
- ret = qemuInitGraphicsPasswords(driver, vm,
- VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
- &vm->def->graphics[0]->data.vnc.auth,
- driver->vncPassword);
+ ret = qemuInitGraphicsPasswords(driver, vm,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ &vm->def->graphics[0]->data.spice.auth,
+ driver->spicePassword);
Based on patch by Daniel P. Berrange <berrange@redhat.com>.
2011-01-10 11:12:33 +00:00
|
|
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|