2016-02-16 15:24:35 +00:00
|
|
|
/*
|
|
|
|
* qemu_alias.c: QEMU alias manipulation
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006-2016 Red Hat, Inc.
|
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "qemu_alias.h"
|
|
|
|
#include "viralloc.h"
|
|
|
|
#include "virlog.h"
|
|
|
|
#include "virstring.h"
|
|
|
|
|
2016-06-29 17:34:00 +00:00
|
|
|
#define QEMU_DRIVE_HOST_PREFIX "drive-"
|
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
VIR_LOG_INIT("qemu.qemu_alias");
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuDomainDeviceAliasIndex(const virDomainDeviceInfo *info,
|
|
|
|
const char *prefix)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
if (!info->alias)
|
|
|
|
return -1;
|
|
|
|
if (!STRPREFIX(info->alias, prefix))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virStrToLong_i(info->alias + strlen(prefix), NULL, 10, &idx) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
qemuGetNextChrDevIndex(virDomainDefPtr def,
|
|
|
|
virDomainChrDefPtr chr,
|
|
|
|
const char *prefix)
|
|
|
|
{
|
|
|
|
const virDomainChrDef **arrPtr;
|
|
|
|
size_t cnt;
|
|
|
|
size_t i;
|
|
|
|
ssize_t idx = 0;
|
|
|
|
const char *prefix2 = NULL;
|
|
|
|
|
|
|
|
if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)
|
|
|
|
prefix2 = "serial";
|
|
|
|
|
|
|
|
virDomainChrGetDomainPtrs(def, chr->deviceType, &arrPtr, &cnt);
|
|
|
|
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
|
|
ssize_t thisidx;
|
|
|
|
if (((thisidx = qemuDomainDeviceAliasIndex(&arrPtr[i]->info, prefix)) < 0) &&
|
|
|
|
(prefix2 &&
|
2017-10-20 11:24:41 +00:00
|
|
|
(thisidx = qemuDomainDeviceAliasIndex(&arrPtr[i]->info, prefix2)) < 0))
|
|
|
|
continue;
|
2016-02-16 15:24:35 +00:00
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceChrAlias(virDomainDefPtr def,
|
|
|
|
virDomainChrDefPtr chr,
|
|
|
|
ssize_t idx)
|
|
|
|
{
|
|
|
|
const char *prefix = NULL;
|
|
|
|
|
2017-10-14 17:16:20 +00:00
|
|
|
if (chr->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2018-04-25 12:42:34 +00:00
|
|
|
switch ((virDomainChrDeviceType)chr->deviceType) {
|
2016-02-16 15:24:35 +00:00
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL:
|
|
|
|
prefix = "parallel";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL:
|
|
|
|
prefix = "serial";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE:
|
|
|
|
prefix = "console";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL:
|
|
|
|
prefix = "channel";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CHR_DEVICE_TYPE_LAST:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx == -1 && (idx = qemuGetNextChrDevIndex(def, chr, prefix)) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virAsprintf(&chr->info.alias, "%s%zd", prefix, idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceControllerAlias(virDomainDefPtr domainDef,
|
|
|
|
virQEMUCapsPtr qemuCaps,
|
|
|
|
virDomainControllerDefPtr controller)
|
|
|
|
{
|
|
|
|
const char *prefix = virDomainControllerTypeToString(controller->type);
|
|
|
|
|
2017-10-14 17:16:20 +00:00
|
|
|
if (controller->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
|
|
|
|
if (!virQEMUCapsHasPCIMultiBus(qemuCaps, domainDef)) {
|
|
|
|
/* qemus that don't support multiple PCI buses have
|
|
|
|
* hardcoded the name of their single PCI controller as
|
|
|
|
* "pci".
|
|
|
|
*/
|
|
|
|
return VIR_STRDUP(controller->info.alias, "pci");
|
|
|
|
} else if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
|
|
|
|
/* The pcie-root controller on Q35 machinetypes uses a
|
|
|
|
* different naming convention ("pcie.0"), because it is
|
|
|
|
* hardcoded that way in qemu.
|
|
|
|
*/
|
|
|
|
return virAsprintf(&controller->info.alias, "pcie.%d", controller->idx);
|
|
|
|
}
|
|
|
|
/* All other PCI controllers use the consistent "pci.%u"
|
|
|
|
* (including the hardcoded pci-root controller on
|
|
|
|
* multibus-capable qemus).
|
|
|
|
*/
|
|
|
|
return virAsprintf(&controller->info.alias, "pci.%d", controller->idx);
|
|
|
|
} else if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE) {
|
|
|
|
/* for any machine based on e.g. I440FX or G3Beige, the
|
|
|
|
* first (and currently only) IDE controller is an integrated
|
|
|
|
* controller hardcoded with id "ide"
|
|
|
|
*/
|
2017-04-18 10:43:58 +00:00
|
|
|
if (qemuDomainHasBuiltinIDE(domainDef) &&
|
2016-02-16 15:24:35 +00:00
|
|
|
controller->idx == 0)
|
|
|
|
return VIR_STRDUP(controller->info.alias, "ide");
|
|
|
|
} else if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA) {
|
|
|
|
/* for any Q35 machine, the first SATA controller is the
|
|
|
|
* integrated one, and it too is hardcoded with id "ide"
|
|
|
|
*/
|
2017-04-18 10:43:58 +00:00
|
|
|
if (qemuDomainIsQ35(domainDef) && controller->idx == 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return VIR_STRDUP(controller->info.alias, "ide");
|
|
|
|
} else if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
|
|
|
|
/* first USB device is "usb", others are normal "usb%d" */
|
|
|
|
if (controller->idx == 0)
|
|
|
|
return VIR_STRDUP(controller->info.alias, "usb");
|
|
|
|
}
|
|
|
|
/* all other controllers use the default ${type}${index} naming
|
|
|
|
* scheme for alias/id.
|
|
|
|
*/
|
|
|
|
return virAsprintf(&controller->info.alias, "%s%d", prefix, controller->idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-15 21:24:54 +00:00
|
|
|
int
|
|
|
|
qemuAssignDeviceDiskAlias(virDomainDefPtr def,
|
2018-06-26 14:55:19 +00:00
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
virQEMUCapsPtr qemuCaps)
|
2016-02-16 15:24:35 +00:00
|
|
|
{
|
2018-06-26 14:55:19 +00:00
|
|
|
qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
|
2016-02-16 15:24:35 +00:00
|
|
|
const char *prefix = virDomainDiskBusTypeToString(disk->bus);
|
|
|
|
int controllerModel = -1;
|
|
|
|
|
2017-10-14 17:16:20 +00:00
|
|
|
if (disk->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2018-06-26 14:55:19 +00:00
|
|
|
if (!disk->info.alias) {
|
|
|
|
if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
|
|
|
|
if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
|
|
|
|
controllerModel = qemuDomainFindSCSIControllerModel(def,
|
|
|
|
&disk->info);
|
|
|
|
if (controllerModel < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI ||
|
|
|
|
controllerModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) {
|
|
|
|
if (virAsprintf(&disk->info.alias, "%s%d-%d-%d", prefix,
|
|
|
|
disk->info.addr.drive.controller,
|
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.unit) < 0)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (virAsprintf(&disk->info.alias, "%s%d-%d-%d-%d", prefix,
|
|
|
|
disk->info.addr.drive.controller,
|
|
|
|
disk->info.addr.drive.bus,
|
|
|
|
disk->info.addr.drive.target,
|
|
|
|
disk->info.addr.drive.unit) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int idx = virDiskNameToIndex(disk->dst);
|
|
|
|
if (virAsprintf(&disk->info.alias, "%s-disk%d", prefix, idx) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2018-06-26 14:55:19 +00:00
|
|
|
}
|
2016-02-16 15:24:35 +00:00
|
|
|
|
2018-06-26 14:55:19 +00:00
|
|
|
/* For -blockdev we need to know the qom names of the disk which are based
|
|
|
|
* on the alias in qemu. While certain disk types use just the alias, some
|
|
|
|
* need the full path into /machine/peripheral as a historical artifact.
|
|
|
|
*/
|
|
|
|
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) {
|
|
|
|
switch ((virDomainDiskBus) disk->bus) {
|
|
|
|
case VIR_DOMAIN_DISK_BUS_FDC:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_IDE:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SATA:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SCSI:
|
|
|
|
if (VIR_STRDUP(diskPriv->qomName, disk->info.alias) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
2018-06-26 14:55:19 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
|
|
|
if (virAsprintf(&diskPriv->qomName,
|
|
|
|
"/machine/peripheral/%s/virtio-backend",
|
|
|
|
disk->info.alias) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
2018-06-26 14:55:19 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_USB:
|
|
|
|
if (virAsprintf(&diskPriv->qomName,
|
|
|
|
"/machine/peripheral/%s/%s.0/legacy[0]",
|
|
|
|
disk->info.alias, disk->info.alias) < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_DISK_BUS_XEN:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_UML:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_SD:
|
|
|
|
case VIR_DOMAIN_DISK_BUS_LAST:
|
|
|
|
break;
|
2016-02-16 15:24:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceHostdevAlias(virDomainDefPtr def,
|
2016-04-01 14:40:23 +00:00
|
|
|
char **alias,
|
2016-02-16 15:24:35 +00:00
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (*alias)
|
|
|
|
return 0;
|
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
if (idx == -1) {
|
|
|
|
size_t i;
|
qemu: fix alias name for <interface type='hostdev'>
Starting with commit f8e712fe, if you start a domain that has an
<interface type='hostdev' (or that has <interface type='network'>
where the network is a pool of devices for hostdev assignment), when
you later try to add *another* interface (of any kind) with hotplug,
the function qemuAssignDeviceNetAlias() fails as soon as it sees a
"hostdevN" alias in the list of interfaces), causing the attach to
fail.
This is because (starting with f8e712fe) the device alias names are
assigned during the new function qemuProcessPrepareDomain(), which is
called *before* networkAllocateActualDevice() (which is called from
qemuProcessPrepareHost(), which is called from
qemuProcessLaunch()). Prior to that commit,
networkAllocateActualDevice() was called first.
The problem with this is that the alias for interfaces that are really
a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just
like other hostdevs), while other interfaces are "netN". But if you
don't know that the interface is going to be a hostdev at the time you
assign the alias name, you can't name it differently. (As far as I've
seen so far, the change in name by itself wouldn't have been a problem
(other than just an outwardly noticeable change in behavior) except
for the abovementioned failure to attach/detach new interfaces.
Rather than take the chance that there may be other not-yet-revealed
problems associated with changing the alias name, this patch changes
the way that aliases are assigned to restore the old behavior.
Old: In the past, assigning an alias to an interface was skipped if it
was seen that the interface was type='hostdev' - we knew that the
hostdev part of the interface was also in the list of hostdevs (that's
part of what happens in networkAllocateActualDevice()) and it would be
assigned when all the other hostdev aliases were assigned.
New: When assigning an alias to an interface, we haven't yet called
networkAllocateActualDevice() to construct the hostdev part of the
interface, so we can't just wait for the loop that creates aliases for
all the hostdevs (there's nothing on that list for this device
yet!). Instead we handle it immediately in the loop creating interface
aliases, by calling the new function networkGetActualType() to
determine if it is going to be hostdev, and if so calling
qemuAssignDeviceHostdevAlias() instead.
Some adjustments have to be made to both
qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to
accommodate this. In both of them, an error return from
qemuDomainDeviceAliasIndex() is no longer considered an error; instead
it's just ignored (because it almost certainly means that the alias
string for the device was "net" when we expected "hostdev" or vice
versa). in qemuAssignDeviceHostdevAlias() we have to look at all
interface aliases for hostdevN in addition to looking at all hostdev
aliases (this wasn't necessary in the past, because both the interface
entry and the hostdev entry for the device already pointed at the
device info; no longer the case since the hostdev entry hasn't yet
been setup).
Fortunately the buggy behavior hasn't yet been in any official release
of libvirt.
2016-04-01 17:18:57 +00:00
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
idx = 0;
|
|
|
|
for (i = 0; i < def->nhostdevs; i++) {
|
|
|
|
int thisidx;
|
qemu: fix alias name for <interface type='hostdev'>
Starting with commit f8e712fe, if you start a domain that has an
<interface type='hostdev' (or that has <interface type='network'>
where the network is a pool of devices for hostdev assignment), when
you later try to add *another* interface (of any kind) with hotplug,
the function qemuAssignDeviceNetAlias() fails as soon as it sees a
"hostdevN" alias in the list of interfaces), causing the attach to
fail.
This is because (starting with f8e712fe) the device alias names are
assigned during the new function qemuProcessPrepareDomain(), which is
called *before* networkAllocateActualDevice() (which is called from
qemuProcessPrepareHost(), which is called from
qemuProcessLaunch()). Prior to that commit,
networkAllocateActualDevice() was called first.
The problem with this is that the alias for interfaces that are really
a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just
like other hostdevs), while other interfaces are "netN". But if you
don't know that the interface is going to be a hostdev at the time you
assign the alias name, you can't name it differently. (As far as I've
seen so far, the change in name by itself wouldn't have been a problem
(other than just an outwardly noticeable change in behavior) except
for the abovementioned failure to attach/detach new interfaces.
Rather than take the chance that there may be other not-yet-revealed
problems associated with changing the alias name, this patch changes
the way that aliases are assigned to restore the old behavior.
Old: In the past, assigning an alias to an interface was skipped if it
was seen that the interface was type='hostdev' - we knew that the
hostdev part of the interface was also in the list of hostdevs (that's
part of what happens in networkAllocateActualDevice()) and it would be
assigned when all the other hostdev aliases were assigned.
New: When assigning an alias to an interface, we haven't yet called
networkAllocateActualDevice() to construct the hostdev part of the
interface, so we can't just wait for the loop that creates aliases for
all the hostdevs (there's nothing on that list for this device
yet!). Instead we handle it immediately in the loop creating interface
aliases, by calling the new function networkGetActualType() to
determine if it is going to be hostdev, and if so calling
qemuAssignDeviceHostdevAlias() instead.
Some adjustments have to be made to both
qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to
accommodate this. In both of them, an error return from
qemuDomainDeviceAliasIndex() is no longer considered an error; instead
it's just ignored (because it almost certainly means that the alias
string for the device was "net" when we expected "hostdev" or vice
versa). in qemuAssignDeviceHostdevAlias() we have to look at all
interface aliases for hostdevN in addition to looking at all hostdev
aliases (this wasn't necessary in the past, because both the interface
entry and the hostdev entry for the device already pointed at the
device info; no longer the case since the hostdev entry hasn't yet
been setup).
Fortunately the buggy behavior hasn't yet been in any official release
of libvirt.
2016-04-01 17:18:57 +00:00
|
|
|
|
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(def->hostdevs[i]->info, "hostdev")) < 0)
|
|
|
|
continue; /* error just means the alias wasn't "hostdevN", but something else */
|
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
/* network interfaces can also have a hostdevN alias */
|
|
|
|
for (i = 0; i < def->nnets; i++) {
|
|
|
|
int thisidx;
|
|
|
|
|
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "hostdev")) < 0)
|
|
|
|
continue;
|
2016-02-16 15:24:35 +00:00
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-01 14:40:23 +00:00
|
|
|
if (virAsprintf(alias, "hostdev%d", idx) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceNetAlias(virDomainDefPtr def,
|
|
|
|
virDomainNetDefPtr net,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (net->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
qemu: fix alias name for <interface type='hostdev'>
Starting with commit f8e712fe, if you start a domain that has an
<interface type='hostdev' (or that has <interface type='network'>
where the network is a pool of devices for hostdev assignment), when
you later try to add *another* interface (of any kind) with hotplug,
the function qemuAssignDeviceNetAlias() fails as soon as it sees a
"hostdevN" alias in the list of interfaces), causing the attach to
fail.
This is because (starting with f8e712fe) the device alias names are
assigned during the new function qemuProcessPrepareDomain(), which is
called *before* networkAllocateActualDevice() (which is called from
qemuProcessPrepareHost(), which is called from
qemuProcessLaunch()). Prior to that commit,
networkAllocateActualDevice() was called first.
The problem with this is that the alias for interfaces that are really
a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just
like other hostdevs), while other interfaces are "netN". But if you
don't know that the interface is going to be a hostdev at the time you
assign the alias name, you can't name it differently. (As far as I've
seen so far, the change in name by itself wouldn't have been a problem
(other than just an outwardly noticeable change in behavior) except
for the abovementioned failure to attach/detach new interfaces.
Rather than take the chance that there may be other not-yet-revealed
problems associated with changing the alias name, this patch changes
the way that aliases are assigned to restore the old behavior.
Old: In the past, assigning an alias to an interface was skipped if it
was seen that the interface was type='hostdev' - we knew that the
hostdev part of the interface was also in the list of hostdevs (that's
part of what happens in networkAllocateActualDevice()) and it would be
assigned when all the other hostdev aliases were assigned.
New: When assigning an alias to an interface, we haven't yet called
networkAllocateActualDevice() to construct the hostdev part of the
interface, so we can't just wait for the loop that creates aliases for
all the hostdevs (there's nothing on that list for this device
yet!). Instead we handle it immediately in the loop creating interface
aliases, by calling the new function networkGetActualType() to
determine if it is going to be hostdev, and if so calling
qemuAssignDeviceHostdevAlias() instead.
Some adjustments have to be made to both
qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to
accommodate this. In both of them, an error return from
qemuDomainDeviceAliasIndex() is no longer considered an error; instead
it's just ignored (because it almost certainly means that the alias
string for the device was "net" when we expected "hostdev" or vice
versa). in qemuAssignDeviceHostdevAlias() we have to look at all
interface aliases for hostdevN in addition to looking at all hostdev
aliases (this wasn't necessary in the past, because both the interface
entry and the hostdev entry for the device already pointed at the
device info; no longer the case since the hostdev entry hasn't yet
been setup).
Fortunately the buggy behavior hasn't yet been in any official release
of libvirt.
2016-04-01 17:18:57 +00:00
|
|
|
/* <interface type='hostdev'> uses "hostdevN" as the alias
|
|
|
|
* We must use "-1" as the index because the caller doesn't know
|
|
|
|
* that we're now looking for a unique hostdevN rather than netN
|
|
|
|
*/
|
2018-01-25 09:35:50 +00:00
|
|
|
if (virDomainNetResolveActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV)
|
qemu: fix alias name for <interface type='hostdev'>
Starting with commit f8e712fe, if you start a domain that has an
<interface type='hostdev' (or that has <interface type='network'>
where the network is a pool of devices for hostdev assignment), when
you later try to add *another* interface (of any kind) with hotplug,
the function qemuAssignDeviceNetAlias() fails as soon as it sees a
"hostdevN" alias in the list of interfaces), causing the attach to
fail.
This is because (starting with f8e712fe) the device alias names are
assigned during the new function qemuProcessPrepareDomain(), which is
called *before* networkAllocateActualDevice() (which is called from
qemuProcessPrepareHost(), which is called from
qemuProcessLaunch()). Prior to that commit,
networkAllocateActualDevice() was called first.
The problem with this is that the alias for interfaces that are really
a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just
like other hostdevs), while other interfaces are "netN". But if you
don't know that the interface is going to be a hostdev at the time you
assign the alias name, you can't name it differently. (As far as I've
seen so far, the change in name by itself wouldn't have been a problem
(other than just an outwardly noticeable change in behavior) except
for the abovementioned failure to attach/detach new interfaces.
Rather than take the chance that there may be other not-yet-revealed
problems associated with changing the alias name, this patch changes
the way that aliases are assigned to restore the old behavior.
Old: In the past, assigning an alias to an interface was skipped if it
was seen that the interface was type='hostdev' - we knew that the
hostdev part of the interface was also in the list of hostdevs (that's
part of what happens in networkAllocateActualDevice()) and it would be
assigned when all the other hostdev aliases were assigned.
New: When assigning an alias to an interface, we haven't yet called
networkAllocateActualDevice() to construct the hostdev part of the
interface, so we can't just wait for the loop that creates aliases for
all the hostdevs (there's nothing on that list for this device
yet!). Instead we handle it immediately in the loop creating interface
aliases, by calling the new function networkGetActualType() to
determine if it is going to be hostdev, and if so calling
qemuAssignDeviceHostdevAlias() instead.
Some adjustments have to be made to both
qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to
accommodate this. In both of them, an error return from
qemuDomainDeviceAliasIndex() is no longer considered an error; instead
it's just ignored (because it almost certainly means that the alias
string for the device was "net" when we expected "hostdev" or vice
versa). in qemuAssignDeviceHostdevAlias() we have to look at all
interface aliases for hostdevN in addition to looking at all hostdev
aliases (this wasn't necessary in the past, because both the interface
entry and the hostdev entry for the device already pointed at the
device info; no longer the case since the hostdev entry hasn't yet
been setup).
Fortunately the buggy behavior hasn't yet been in any official release
of libvirt.
2016-04-01 17:18:57 +00:00
|
|
|
return qemuAssignDeviceHostdevAlias(def, &net->info.alias, -1);
|
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
if (idx == -1) {
|
|
|
|
size_t i;
|
qemu: fix alias name for <interface type='hostdev'>
Starting with commit f8e712fe, if you start a domain that has an
<interface type='hostdev' (or that has <interface type='network'>
where the network is a pool of devices for hostdev assignment), when
you later try to add *another* interface (of any kind) with hotplug,
the function qemuAssignDeviceNetAlias() fails as soon as it sees a
"hostdevN" alias in the list of interfaces), causing the attach to
fail.
This is because (starting with f8e712fe) the device alias names are
assigned during the new function qemuProcessPrepareDomain(), which is
called *before* networkAllocateActualDevice() (which is called from
qemuProcessPrepareHost(), which is called from
qemuProcessLaunch()). Prior to that commit,
networkAllocateActualDevice() was called first.
The problem with this is that the alias for interfaces that are really
a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just
like other hostdevs), while other interfaces are "netN". But if you
don't know that the interface is going to be a hostdev at the time you
assign the alias name, you can't name it differently. (As far as I've
seen so far, the change in name by itself wouldn't have been a problem
(other than just an outwardly noticeable change in behavior) except
for the abovementioned failure to attach/detach new interfaces.
Rather than take the chance that there may be other not-yet-revealed
problems associated with changing the alias name, this patch changes
the way that aliases are assigned to restore the old behavior.
Old: In the past, assigning an alias to an interface was skipped if it
was seen that the interface was type='hostdev' - we knew that the
hostdev part of the interface was also in the list of hostdevs (that's
part of what happens in networkAllocateActualDevice()) and it would be
assigned when all the other hostdev aliases were assigned.
New: When assigning an alias to an interface, we haven't yet called
networkAllocateActualDevice() to construct the hostdev part of the
interface, so we can't just wait for the loop that creates aliases for
all the hostdevs (there's nothing on that list for this device
yet!). Instead we handle it immediately in the loop creating interface
aliases, by calling the new function networkGetActualType() to
determine if it is going to be hostdev, and if so calling
qemuAssignDeviceHostdevAlias() instead.
Some adjustments have to be made to both
qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to
accommodate this. In both of them, an error return from
qemuDomainDeviceAliasIndex() is no longer considered an error; instead
it's just ignored (because it almost certainly means that the alias
string for the device was "net" when we expected "hostdev" or vice
versa). in qemuAssignDeviceHostdevAlias() we have to look at all
interface aliases for hostdevN in addition to looking at all hostdev
aliases (this wasn't necessary in the past, because both the interface
entry and the hostdev entry for the device already pointed at the
device info; no longer the case since the hostdev entry hasn't yet
been setup).
Fortunately the buggy behavior hasn't yet been in any official release
of libvirt.
2016-04-01 17:18:57 +00:00
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
idx = 0;
|
|
|
|
for (i = 0; i < def->nnets; i++) {
|
|
|
|
int thisidx;
|
|
|
|
|
qemu: fix alias name for <interface type='hostdev'>
Starting with commit f8e712fe, if you start a domain that has an
<interface type='hostdev' (or that has <interface type='network'>
where the network is a pool of devices for hostdev assignment), when
you later try to add *another* interface (of any kind) with hotplug,
the function qemuAssignDeviceNetAlias() fails as soon as it sees a
"hostdevN" alias in the list of interfaces), causing the attach to
fail.
This is because (starting with f8e712fe) the device alias names are
assigned during the new function qemuProcessPrepareDomain(), which is
called *before* networkAllocateActualDevice() (which is called from
qemuProcessPrepareHost(), which is called from
qemuProcessLaunch()). Prior to that commit,
networkAllocateActualDevice() was called first.
The problem with this is that the alias for interfaces that are really
a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just
like other hostdevs), while other interfaces are "netN". But if you
don't know that the interface is going to be a hostdev at the time you
assign the alias name, you can't name it differently. (As far as I've
seen so far, the change in name by itself wouldn't have been a problem
(other than just an outwardly noticeable change in behavior) except
for the abovementioned failure to attach/detach new interfaces.
Rather than take the chance that there may be other not-yet-revealed
problems associated with changing the alias name, this patch changes
the way that aliases are assigned to restore the old behavior.
Old: In the past, assigning an alias to an interface was skipped if it
was seen that the interface was type='hostdev' - we knew that the
hostdev part of the interface was also in the list of hostdevs (that's
part of what happens in networkAllocateActualDevice()) and it would be
assigned when all the other hostdev aliases were assigned.
New: When assigning an alias to an interface, we haven't yet called
networkAllocateActualDevice() to construct the hostdev part of the
interface, so we can't just wait for the loop that creates aliases for
all the hostdevs (there's nothing on that list for this device
yet!). Instead we handle it immediately in the loop creating interface
aliases, by calling the new function networkGetActualType() to
determine if it is going to be hostdev, and if so calling
qemuAssignDeviceHostdevAlias() instead.
Some adjustments have to be made to both
qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to
accommodate this. In both of them, an error return from
qemuDomainDeviceAliasIndex() is no longer considered an error; instead
it's just ignored (because it almost certainly means that the alias
string for the device was "net" when we expected "hostdev" or vice
versa). in qemuAssignDeviceHostdevAlias() we have to look at all
interface aliases for hostdevN in addition to looking at all hostdev
aliases (this wasn't necessary in the past, because both the interface
entry and the hostdev entry for the device already pointed at the
device info; no longer the case since the hostdev entry hasn't yet
been setup).
Fortunately the buggy behavior hasn't yet been in any official release
of libvirt.
2016-04-01 17:18:57 +00:00
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "net")) < 0)
|
|
|
|
continue; /* failure could be due to "hostdevN" */
|
2016-02-16 15:24:35 +00:00
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&net->info.alias, "net%d", idx) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-20 16:17:32 +00:00
|
|
|
static int
|
|
|
|
qemuAssignDeviceFSAlias(virDomainFSDefPtr fss,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (fss->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-20 16:17:32 +00:00
|
|
|
return virAsprintf(&fss->info.alias, "fs%d", idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuAssignDeviceSoundAlias(virDomainSoundDefPtr sound,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (sound->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-20 16:17:32 +00:00
|
|
|
return virAsprintf(&sound->info.alias, "sound%d", idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuAssignDeviceVideoAlias(virDomainVideoDefPtr video,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (video->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-20 16:17:32 +00:00
|
|
|
return virAsprintf(&video->info.alias, "video%d", idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuAssignDeviceHubAlias(virDomainHubDefPtr hub,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (hub->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-20 16:17:32 +00:00
|
|
|
return virAsprintf(&hub->info.alias, "hub%d", idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuAssignDeviceSmartcardAlias(virDomainSmartcardDefPtr smartcard,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (smartcard->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-20 16:17:32 +00:00
|
|
|
return virAsprintf(&smartcard->info.alias, "smartcard%d", idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuAssingDeviceMemballoonAlias(virDomainMemballoonDefPtr memballoon,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (memballoon->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-20 16:17:32 +00:00
|
|
|
return virAsprintf(&memballoon->info.alias, "balloon%d", idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuAssignDeviceTPMAlias(virDomainTPMDefPtr tpm,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (tpm->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-20 16:17:32 +00:00
|
|
|
return virAsprintf(&tpm->info.alias, "tpm%d", idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
int
|
|
|
|
qemuAssignDeviceRedirdevAlias(virDomainDefPtr def,
|
|
|
|
virDomainRedirdevDefPtr redirdev,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (redirdev->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
if (idx == -1) {
|
|
|
|
size_t i;
|
|
|
|
idx = 0;
|
|
|
|
for (i = 0; i < def->nredirdevs; i++) {
|
|
|
|
int thisidx;
|
2017-10-20 11:24:41 +00:00
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->redirdevs[i]->info, "redir")) < 0)
|
|
|
|
continue;
|
2016-02-16 15:24:35 +00:00
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&redirdev->info.alias, "redir%d", idx) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2016-04-06 15:32:12 +00:00
|
|
|
qemuAssignDeviceRNGAlias(virDomainDefPtr def,
|
|
|
|
virDomainRNGDefPtr rng)
|
2016-02-16 15:24:35 +00:00
|
|
|
{
|
2016-04-06 15:32:12 +00:00
|
|
|
size_t i;
|
|
|
|
int maxidx = 0;
|
|
|
|
int idx;
|
|
|
|
|
2017-10-14 17:16:20 +00:00
|
|
|
if (rng->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2016-04-06 15:32:12 +00:00
|
|
|
for (i = 0; i < def->nrngs; i++) {
|
|
|
|
if ((idx = qemuDomainDeviceAliasIndex(&def->rngs[i]->info, "rng")) >= maxidx)
|
|
|
|
maxidx = idx + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&rng->info.alias, "rng%d", maxidx) < 0)
|
2016-04-06 15:32:12 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-01 05:21:36 +00:00
|
|
|
/**
|
|
|
|
* qemuAssignDeviceMemoryAlias:
|
|
|
|
* @def: domain definition. Necessary only if @oldAlias is true.
|
|
|
|
* @mem: memory device definition
|
|
|
|
* @oldAlias: Generate the alias according to the order of the device in @def
|
|
|
|
* rather than according to the slot number for legacy reasons.
|
|
|
|
*
|
|
|
|
* Generates alias for a memory device according to slot number if @oldAlias is
|
|
|
|
* false or according to order in @def->mems otherwise.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on error.
|
|
|
|
*/
|
2016-04-06 15:32:12 +00:00
|
|
|
int
|
|
|
|
qemuAssignDeviceMemoryAlias(virDomainDefPtr def,
|
2016-11-01 05:21:36 +00:00
|
|
|
virDomainMemoryDefPtr mem,
|
|
|
|
bool oldAlias)
|
2016-04-06 15:32:12 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
int maxidx = 0;
|
|
|
|
int idx;
|
2016-07-29 09:02:25 +00:00
|
|
|
const char *prefix;
|
|
|
|
|
2017-10-14 17:16:20 +00:00
|
|
|
if (mem->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2016-07-29 09:02:25 +00:00
|
|
|
if (mem->model == VIR_DOMAIN_MEMORY_MODEL_DIMM)
|
|
|
|
prefix = "dimm";
|
|
|
|
else
|
|
|
|
prefix = "nvdimm";
|
2016-04-06 15:32:12 +00:00
|
|
|
|
2016-11-01 05:21:36 +00:00
|
|
|
if (oldAlias) {
|
|
|
|
for (i = 0; i < def->nmems; i++) {
|
2016-07-29 09:02:25 +00:00
|
|
|
if ((idx = qemuDomainDeviceAliasIndex(&def->mems[i]->info, prefix)) >= maxidx)
|
2016-11-01 05:21:36 +00:00
|
|
|
maxidx = idx + 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
maxidx = mem->info.addr.dimm.slot;
|
2016-04-06 15:32:12 +00:00
|
|
|
}
|
|
|
|
|
2016-07-29 09:02:25 +00:00
|
|
|
if (virAsprintf(&mem->info.alias, "%s%d", prefix, maxidx) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-12 13:48:41 +00:00
|
|
|
int
|
|
|
|
qemuAssignDeviceShmemAlias(virDomainDefPtr def,
|
|
|
|
virDomainShmemDefPtr shmem,
|
|
|
|
int idx)
|
|
|
|
{
|
2017-10-14 17:16:20 +00:00
|
|
|
if (shmem->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2016-09-12 13:48:41 +00:00
|
|
|
if (idx == -1) {
|
|
|
|
size_t i;
|
|
|
|
idx = 0;
|
|
|
|
for (i = 0; i < def->nshmems; i++) {
|
|
|
|
int thisidx;
|
|
|
|
|
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->shmems[i]->info,
|
2017-10-20 11:24:41 +00:00
|
|
|
"shmem")) < 0)
|
|
|
|
continue;
|
2016-09-12 13:48:41 +00:00
|
|
|
|
|
|
|
if (thisidx >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&shmem->info.alias, "shmem%d", idx) < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-01 11:39:15 +00:00
|
|
|
int
|
|
|
|
qemuAssignDeviceWatchdogAlias(virDomainWatchdogDefPtr watchdog)
|
|
|
|
{
|
|
|
|
/* Currently, there's just one watchdog per domain */
|
|
|
|
|
2017-10-14 17:16:20 +00:00
|
|
|
if (watchdog->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-09-01 11:39:15 +00:00
|
|
|
if (VIR_STRDUP(watchdog->info.alias, "watchdog0") < 0)
|
|
|
|
return -1;
|
2017-10-04 09:09:22 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuAssignDeviceInputAlias(virDomainDefPtr def,
|
|
|
|
virDomainInputDefPtr input,
|
|
|
|
int idx)
|
|
|
|
{
|
2018-03-13 12:01:11 +00:00
|
|
|
if (input->info.alias)
|
|
|
|
return 0;
|
|
|
|
|
2017-10-04 09:09:22 +00:00
|
|
|
if (idx == -1) {
|
|
|
|
int thisidx;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->ninputs; i++) {
|
|
|
|
if ((thisidx = qemuDomainDeviceAliasIndex(&def->inputs[i]->info, "input")) >= idx)
|
|
|
|
idx = thisidx + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&input->info.alias, "input%d", idx) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-09-01 11:39:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-30 11:53:52 +00:00
|
|
|
int
|
2018-05-22 13:57:47 +00:00
|
|
|
qemuAssignDeviceVsockAlias(virDomainVsockDefPtr vsock)
|
|
|
|
{
|
|
|
|
if (vsock->info.alias)
|
|
|
|
return 0;
|
|
|
|
if (VIR_STRDUP(vsock->info.alias, "vsock0") < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-16 15:24:35 +00:00
|
|
|
int
|
|
|
|
qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < def->ndisks; i++) {
|
2018-06-26 14:55:19 +00:00
|
|
|
if (qemuAssignDeviceDiskAlias(def, def->disks[i], qemuCaps) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nnets; i++) {
|
qemu: fix alias name for <interface type='hostdev'>
Starting with commit f8e712fe, if you start a domain that has an
<interface type='hostdev' (or that has <interface type='network'>
where the network is a pool of devices for hostdev assignment), when
you later try to add *another* interface (of any kind) with hotplug,
the function qemuAssignDeviceNetAlias() fails as soon as it sees a
"hostdevN" alias in the list of interfaces), causing the attach to
fail.
This is because (starting with f8e712fe) the device alias names are
assigned during the new function qemuProcessPrepareDomain(), which is
called *before* networkAllocateActualDevice() (which is called from
qemuProcessPrepareHost(), which is called from
qemuProcessLaunch()). Prior to that commit,
networkAllocateActualDevice() was called first.
The problem with this is that the alias for interfaces that are really
a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just
like other hostdevs), while other interfaces are "netN". But if you
don't know that the interface is going to be a hostdev at the time you
assign the alias name, you can't name it differently. (As far as I've
seen so far, the change in name by itself wouldn't have been a problem
(other than just an outwardly noticeable change in behavior) except
for the abovementioned failure to attach/detach new interfaces.
Rather than take the chance that there may be other not-yet-revealed
problems associated with changing the alias name, this patch changes
the way that aliases are assigned to restore the old behavior.
Old: In the past, assigning an alias to an interface was skipped if it
was seen that the interface was type='hostdev' - we knew that the
hostdev part of the interface was also in the list of hostdevs (that's
part of what happens in networkAllocateActualDevice()) and it would be
assigned when all the other hostdev aliases were assigned.
New: When assigning an alias to an interface, we haven't yet called
networkAllocateActualDevice() to construct the hostdev part of the
interface, so we can't just wait for the loop that creates aliases for
all the hostdevs (there's nothing on that list for this device
yet!). Instead we handle it immediately in the loop creating interface
aliases, by calling the new function networkGetActualType() to
determine if it is going to be hostdev, and if so calling
qemuAssignDeviceHostdevAlias() instead.
Some adjustments have to be made to both
qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to
accommodate this. In both of them, an error return from
qemuDomainDeviceAliasIndex() is no longer considered an error; instead
it's just ignored (because it almost certainly means that the alias
string for the device was "net" when we expected "hostdev" or vice
versa). in qemuAssignDeviceHostdevAlias() we have to look at all
interface aliases for hostdevN in addition to looking at all hostdev
aliases (this wasn't necessary in the past, because both the interface
entry and the hostdev entry for the device already pointed at the
device info; no longer the case since the hostdev entry hasn't yet
been setup).
Fortunately the buggy behavior hasn't yet been in any official release
of libvirt.
2016-04-01 17:18:57 +00:00
|
|
|
if (qemuAssignDeviceNetAlias(def, def->nets[i], -1) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < def->nfss; i++) {
|
2017-09-20 16:17:32 +00:00
|
|
|
if (qemuAssignDeviceFSAlias(def->fss[i], i) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nsounds; i++) {
|
2017-09-20 16:17:32 +00:00
|
|
|
if (qemuAssignDeviceSoundAlias(def->sounds[i], i) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nhostdevs; i++) {
|
qemu: fix alias name for <interface type='hostdev'>
Starting with commit f8e712fe, if you start a domain that has an
<interface type='hostdev' (or that has <interface type='network'>
where the network is a pool of devices for hostdev assignment), when
you later try to add *another* interface (of any kind) with hotplug,
the function qemuAssignDeviceNetAlias() fails as soon as it sees a
"hostdevN" alias in the list of interfaces), causing the attach to
fail.
This is because (starting with f8e712fe) the device alias names are
assigned during the new function qemuProcessPrepareDomain(), which is
called *before* networkAllocateActualDevice() (which is called from
qemuProcessPrepareHost(), which is called from
qemuProcessLaunch()). Prior to that commit,
networkAllocateActualDevice() was called first.
The problem with this is that the alias for interfaces that are really
a hostdev (<interface type='hostdev'>) is of the form "hostdevN" (just
like other hostdevs), while other interfaces are "netN". But if you
don't know that the interface is going to be a hostdev at the time you
assign the alias name, you can't name it differently. (As far as I've
seen so far, the change in name by itself wouldn't have been a problem
(other than just an outwardly noticeable change in behavior) except
for the abovementioned failure to attach/detach new interfaces.
Rather than take the chance that there may be other not-yet-revealed
problems associated with changing the alias name, this patch changes
the way that aliases are assigned to restore the old behavior.
Old: In the past, assigning an alias to an interface was skipped if it
was seen that the interface was type='hostdev' - we knew that the
hostdev part of the interface was also in the list of hostdevs (that's
part of what happens in networkAllocateActualDevice()) and it would be
assigned when all the other hostdev aliases were assigned.
New: When assigning an alias to an interface, we haven't yet called
networkAllocateActualDevice() to construct the hostdev part of the
interface, so we can't just wait for the loop that creates aliases for
all the hostdevs (there's nothing on that list for this device
yet!). Instead we handle it immediately in the loop creating interface
aliases, by calling the new function networkGetActualType() to
determine if it is going to be hostdev, and if so calling
qemuAssignDeviceHostdevAlias() instead.
Some adjustments have to be made to both
qemuAssignDeviceHostdevAlias() and to qemuAssignDeviceNetAlias() to
accommodate this. In both of them, an error return from
qemuDomainDeviceAliasIndex() is no longer considered an error; instead
it's just ignored (because it almost certainly means that the alias
string for the device was "net" when we expected "hostdev" or vice
versa). in qemuAssignDeviceHostdevAlias() we have to look at all
interface aliases for hostdevN in addition to looking at all hostdev
aliases (this wasn't necessary in the past, because both the interface
entry and the hostdev entry for the device already pointed at the
device info; no longer the case since the hostdev entry hasn't yet
been setup).
Fortunately the buggy behavior hasn't yet been in any official release
of libvirt.
2016-04-01 17:18:57 +00:00
|
|
|
/* we can't start assigning at 0, since netdevs may have used
|
|
|
|
* up some hostdevN entries already. Also if the HostdevDef is
|
|
|
|
* linked to a NetDef, they will share an info and the alias
|
|
|
|
* will already be set, so don't try to set it again.
|
|
|
|
*/
|
2017-10-14 17:16:20 +00:00
|
|
|
if (qemuAssignDeviceHostdevAlias(def, &def->hostdevs[i]->info->alias, -1) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nredirdevs; i++) {
|
|
|
|
if (qemuAssignDeviceRedirdevAlias(def, def->redirdevs[i], i) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nvideos; i++) {
|
2017-09-20 16:17:32 +00:00
|
|
|
if (qemuAssignDeviceVideoAlias(def->videos[i], i) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->ncontrollers; i++) {
|
|
|
|
if (qemuAssignDeviceControllerAlias(def, qemuCaps, def->controllers[i]) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->ninputs; i++) {
|
2017-10-04 09:09:22 +00:00
|
|
|
if (qemuAssignDeviceInputAlias(def, def->inputs[i], i) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nparallels; i++) {
|
|
|
|
if (qemuAssignDeviceChrAlias(def, def->parallels[i], i) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nserials; i++) {
|
|
|
|
if (qemuAssignDeviceChrAlias(def, def->serials[i], i) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nchannels; i++) {
|
|
|
|
if (qemuAssignDeviceChrAlias(def, def->channels[i], i) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nconsoles; i++) {
|
|
|
|
if (qemuAssignDeviceChrAlias(def, def->consoles[i], i) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nhubs; i++) {
|
2017-09-20 16:17:32 +00:00
|
|
|
if (qemuAssignDeviceHubAlias(def->hubs[i], i) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nshmems; i++) {
|
2016-09-12 13:48:41 +00:00
|
|
|
if (qemuAssignDeviceShmemAlias(def, def->shmems[i], i) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nsmartcards; i++) {
|
2017-09-20 16:17:32 +00:00
|
|
|
if (qemuAssignDeviceSmartcardAlias(def->smartcards[i], i) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (def->watchdog) {
|
2017-09-01 11:39:15 +00:00
|
|
|
if (qemuAssignDeviceWatchdogAlias(def->watchdog) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2018-03-19 17:14:52 +00:00
|
|
|
if (def->memballoon &&
|
|
|
|
def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) {
|
2017-09-20 16:17:32 +00:00
|
|
|
if (qemuAssingDeviceMemballoonAlias(def->memballoon, 0) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nrngs; i++) {
|
2017-10-14 17:53:03 +00:00
|
|
|
if (qemuAssignDeviceRNGAlias(def, def->rngs[i]) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (def->tpm) {
|
2017-09-20 16:17:32 +00:00
|
|
|
if (qemuAssignDeviceTPMAlias(def->tpm, 0) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < def->nmems; i++) {
|
2016-11-01 05:21:36 +00:00
|
|
|
if (qemuAssignDeviceMemoryAlias(NULL, def->mems[i], false) < 0)
|
2016-02-16 15:24:35 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2018-05-22 13:57:47 +00:00
|
|
|
if (def->vsock) {
|
|
|
|
if (qemuAssignDeviceVsockAlias(def->vsock) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2016-02-16 15:24:35 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-02-26 15:29:58 +00:00
|
|
|
|
|
|
|
|
2018-05-31 09:55:24 +00:00
|
|
|
/* qemuAliasDiskDriveFromDisk
|
2016-06-29 16:37:39 +00:00
|
|
|
* @disk: Pointer to a disk definition
|
|
|
|
*
|
|
|
|
* Generate and return an alias for the device disk '-drive'
|
|
|
|
*
|
|
|
|
* Returns NULL with error or a string containing the alias
|
|
|
|
*/
|
2016-02-26 15:29:58 +00:00
|
|
|
char *
|
2018-05-31 09:55:24 +00:00
|
|
|
qemuAliasDiskDriveFromDisk(const virDomainDiskDef *disk)
|
2016-02-26 15:29:58 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
if (!disk->info.alias) {
|
2016-06-29 16:37:39 +00:00
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("disk does not have an alias"));
|
2016-02-26 15:29:58 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-29 16:37:39 +00:00
|
|
|
ignore_value(virAsprintf(&ret, "%s%s", QEMU_DRIVE_HOST_PREFIX,
|
|
|
|
disk->info.alias));
|
2016-02-26 15:29:58 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2016-03-29 22:23:02 +00:00
|
|
|
|
|
|
|
|
2016-06-29 17:34:00 +00:00
|
|
|
/* qemuAliasDiskDriveSkipPrefix:
|
|
|
|
* @dev_name: Pointer to a const char string
|
|
|
|
*
|
|
|
|
* If the QEMU_DRIVE_HOST_PREFIX exists in the input string, then
|
|
|
|
* increment the pointer and return it
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
qemuAliasDiskDriveSkipPrefix(const char *dev_name)
|
|
|
|
{
|
|
|
|
if (STRPREFIX(dev_name, QEMU_DRIVE_HOST_PREFIX))
|
|
|
|
dev_name += strlen(QEMU_DRIVE_HOST_PREFIX);
|
|
|
|
return dev_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-18 17:19:02 +00:00
|
|
|
/* qemuAliasFromHostdev
|
|
|
|
* @hostdev: Pointer to host device
|
|
|
|
*
|
|
|
|
* Generate and return a string containing a drive alias
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
qemuAliasFromHostdev(const virDomainHostdevDef *hostdev)
|
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
if (!hostdev->info->alias) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("hostdev does not have an alias"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ignore_value(virAsprintf(&ret, "%s-%s",
|
|
|
|
virDomainDeviceAddressTypeToString(hostdev->info->type),
|
|
|
|
hostdev->info->alias));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-29 22:23:02 +00:00
|
|
|
/* qemuDomainGetMasterKeyAlias:
|
|
|
|
*
|
|
|
|
* Generate and return the masterKey alias
|
|
|
|
*
|
|
|
|
* Returns NULL or a string containing the master key alias
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
qemuDomainGetMasterKeyAlias(void)
|
|
|
|
{
|
|
|
|
char *alias;
|
|
|
|
|
|
|
|
ignore_value(VIR_STRDUP(alias, "masterKey0"));
|
|
|
|
|
|
|
|
return alias;
|
|
|
|
}
|
qemu: Utilize qemu secret objects for RBD auth/secret
https://bugzilla.redhat.com/show_bug.cgi?id=1182074
If they're available and we need to pass secrets to qemu, then use the
qemu domain secret object in order to pass the secrets for RBD volumes
instead of passing the base64 encoded secret on the command line.
The goal is to make AES secrets the default and have no user interaction
required in order to allow using the AES mechanism. If the mechanism
is not available, then fall back to the current plain mechanism using
a base64 encoded secret.
New APIs:
qemu_domain.c:
qemuDomainGetSecretAESAlias:
Generate/return the secret object alias for an AES Secret Info type.
This will be called from qemuDomainSecretAESSetup.
qemuDomainSecretAESSetup: (private)
This API handles the details of the generation of the AES secret
and saves the pieces that need to be passed to qemu in order for
the secret to be decrypted. The encrypted secret based upon the
domain master key, an initialization vector (16 byte random value),
and the stored secret. Finally, the requirement from qemu is the IV
and encrypted secret are to be base64 encoded.
qemu_command.c:
qemuBuildSecretInfoProps: (private)
Generate/return a JSON properties object for the AES secret to
be used by both the command building and eventually the hotplug
code in order to add the secret object. Code was designed so that
in the future perhaps hotplug could use it if it made sense.
qemuBuildObjectSecretCommandLine (private)
Generate and add to the command line the -object secret for the
secret. This will be required for the subsequent RBD reference
to the object.
qemuBuildDiskSecinfoCommandLine (private)
Handle adding the AES secret object.
Adjustments:
qemu_domain.c:
The qemuDomainSecretSetup was altered to call either the AES or Plain
Setup functions based upon whether AES secrets are possible (we have
the encryption API) or not, we have secrets, and of course if the
protocol source is RBD.
qemu_command.c:
Adjust the qemuBuildRBDSecinfoURI API's in order to generate the
specific command options for an AES secret, such as:
-object secret,id=$alias,keyid=$masterKey,data=$base64encodedencrypted,
format=base64
-drive file=rbd:pool/image:id=myname:auth_supported=cephx\;none:\
mon_host=mon1.example.org\:6321,password-secret=$alias,...
where the 'id=' value is the secret object alias generated by
concatenating the disk alias and "-aesKey0". The 'keyid= $masterKey'
is the master key shared with qemu, and the -drive syntax will
reference that alias as the 'password-secret'. For the -drive
syntax, the 'id=myname' is kept to define the username, while the
'key=$base64 encoded secret' is removed.
While according to the syntax described for qemu commit '60390a21'
or as seen in the email archive:
https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg04083.html
it is possible to pass a plaintext password via a file, the qemu
commit 'ac1d8878' describes the more feature rich 'keyid=' option
based upon the shared masterKey.
Add tests for checking/comparing output.
NB: For hotplug, since the hotplug code doesn't add command line
arguments, passing the encoded secret directly to the monitor
will suffice.
2016-04-11 15:26:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* qemuDomainGetSecretAESAlias:
|
2016-06-24 19:31:57 +00:00
|
|
|
* @srcalias: Source alias used to generate the secret alias
|
|
|
|
* @isLuks: True when we are generating a secret for LUKS encrypt/decrypt
|
qemu: Utilize qemu secret objects for RBD auth/secret
https://bugzilla.redhat.com/show_bug.cgi?id=1182074
If they're available and we need to pass secrets to qemu, then use the
qemu domain secret object in order to pass the secrets for RBD volumes
instead of passing the base64 encoded secret on the command line.
The goal is to make AES secrets the default and have no user interaction
required in order to allow using the AES mechanism. If the mechanism
is not available, then fall back to the current plain mechanism using
a base64 encoded secret.
New APIs:
qemu_domain.c:
qemuDomainGetSecretAESAlias:
Generate/return the secret object alias for an AES Secret Info type.
This will be called from qemuDomainSecretAESSetup.
qemuDomainSecretAESSetup: (private)
This API handles the details of the generation of the AES secret
and saves the pieces that need to be passed to qemu in order for
the secret to be decrypted. The encrypted secret based upon the
domain master key, an initialization vector (16 byte random value),
and the stored secret. Finally, the requirement from qemu is the IV
and encrypted secret are to be base64 encoded.
qemu_command.c:
qemuBuildSecretInfoProps: (private)
Generate/return a JSON properties object for the AES secret to
be used by both the command building and eventually the hotplug
code in order to add the secret object. Code was designed so that
in the future perhaps hotplug could use it if it made sense.
qemuBuildObjectSecretCommandLine (private)
Generate and add to the command line the -object secret for the
secret. This will be required for the subsequent RBD reference
to the object.
qemuBuildDiskSecinfoCommandLine (private)
Handle adding the AES secret object.
Adjustments:
qemu_domain.c:
The qemuDomainSecretSetup was altered to call either the AES or Plain
Setup functions based upon whether AES secrets are possible (we have
the encryption API) or not, we have secrets, and of course if the
protocol source is RBD.
qemu_command.c:
Adjust the qemuBuildRBDSecinfoURI API's in order to generate the
specific command options for an AES secret, such as:
-object secret,id=$alias,keyid=$masterKey,data=$base64encodedencrypted,
format=base64
-drive file=rbd:pool/image:id=myname:auth_supported=cephx\;none:\
mon_host=mon1.example.org\:6321,password-secret=$alias,...
where the 'id=' value is the secret object alias generated by
concatenating the disk alias and "-aesKey0". The 'keyid= $masterKey'
is the master key shared with qemu, and the -drive syntax will
reference that alias as the 'password-secret'. For the -drive
syntax, the 'id=myname' is kept to define the username, while the
'key=$base64 encoded secret' is removed.
While according to the syntax described for qemu commit '60390a21'
or as seen in the email archive:
https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg04083.html
it is possible to pass a plaintext password via a file, the qemu
commit 'ac1d8878' describes the more feature rich 'keyid=' option
based upon the shared masterKey.
Add tests for checking/comparing output.
NB: For hotplug, since the hotplug code doesn't add command line
arguments, passing the encoded secret directly to the monitor
will suffice.
2016-04-11 15:26:14 +00:00
|
|
|
*
|
|
|
|
* Generate and return an alias for the encrypted secret
|
|
|
|
*
|
|
|
|
* Returns NULL or a string containing the alias
|
|
|
|
*/
|
|
|
|
char *
|
2016-06-24 19:31:57 +00:00
|
|
|
qemuDomainGetSecretAESAlias(const char *srcalias,
|
|
|
|
bool isLuks)
|
qemu: Utilize qemu secret objects for RBD auth/secret
https://bugzilla.redhat.com/show_bug.cgi?id=1182074
If they're available and we need to pass secrets to qemu, then use the
qemu domain secret object in order to pass the secrets for RBD volumes
instead of passing the base64 encoded secret on the command line.
The goal is to make AES secrets the default and have no user interaction
required in order to allow using the AES mechanism. If the mechanism
is not available, then fall back to the current plain mechanism using
a base64 encoded secret.
New APIs:
qemu_domain.c:
qemuDomainGetSecretAESAlias:
Generate/return the secret object alias for an AES Secret Info type.
This will be called from qemuDomainSecretAESSetup.
qemuDomainSecretAESSetup: (private)
This API handles the details of the generation of the AES secret
and saves the pieces that need to be passed to qemu in order for
the secret to be decrypted. The encrypted secret based upon the
domain master key, an initialization vector (16 byte random value),
and the stored secret. Finally, the requirement from qemu is the IV
and encrypted secret are to be base64 encoded.
qemu_command.c:
qemuBuildSecretInfoProps: (private)
Generate/return a JSON properties object for the AES secret to
be used by both the command building and eventually the hotplug
code in order to add the secret object. Code was designed so that
in the future perhaps hotplug could use it if it made sense.
qemuBuildObjectSecretCommandLine (private)
Generate and add to the command line the -object secret for the
secret. This will be required for the subsequent RBD reference
to the object.
qemuBuildDiskSecinfoCommandLine (private)
Handle adding the AES secret object.
Adjustments:
qemu_domain.c:
The qemuDomainSecretSetup was altered to call either the AES or Plain
Setup functions based upon whether AES secrets are possible (we have
the encryption API) or not, we have secrets, and of course if the
protocol source is RBD.
qemu_command.c:
Adjust the qemuBuildRBDSecinfoURI API's in order to generate the
specific command options for an AES secret, such as:
-object secret,id=$alias,keyid=$masterKey,data=$base64encodedencrypted,
format=base64
-drive file=rbd:pool/image:id=myname:auth_supported=cephx\;none:\
mon_host=mon1.example.org\:6321,password-secret=$alias,...
where the 'id=' value is the secret object alias generated by
concatenating the disk alias and "-aesKey0". The 'keyid= $masterKey'
is the master key shared with qemu, and the -drive syntax will
reference that alias as the 'password-secret'. For the -drive
syntax, the 'id=myname' is kept to define the username, while the
'key=$base64 encoded secret' is removed.
While according to the syntax described for qemu commit '60390a21'
or as seen in the email archive:
https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg04083.html
it is possible to pass a plaintext password via a file, the qemu
commit 'ac1d8878' describes the more feature rich 'keyid=' option
based upon the shared masterKey.
Add tests for checking/comparing output.
NB: For hotplug, since the hotplug code doesn't add command line
arguments, passing the encoded secret directly to the monitor
will suffice.
2016-04-11 15:26:14 +00:00
|
|
|
{
|
|
|
|
char *alias;
|
|
|
|
|
|
|
|
if (!srcalias) {
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
|
|
_("encrypted secret alias requires valid source alias"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-24 19:31:57 +00:00
|
|
|
if (isLuks)
|
|
|
|
ignore_value(virAsprintf(&alias, "%s-luks-secret0", srcalias));
|
|
|
|
else
|
|
|
|
ignore_value(virAsprintf(&alias, "%s-secret0", srcalias));
|
qemu: Utilize qemu secret objects for RBD auth/secret
https://bugzilla.redhat.com/show_bug.cgi?id=1182074
If they're available and we need to pass secrets to qemu, then use the
qemu domain secret object in order to pass the secrets for RBD volumes
instead of passing the base64 encoded secret on the command line.
The goal is to make AES secrets the default and have no user interaction
required in order to allow using the AES mechanism. If the mechanism
is not available, then fall back to the current plain mechanism using
a base64 encoded secret.
New APIs:
qemu_domain.c:
qemuDomainGetSecretAESAlias:
Generate/return the secret object alias for an AES Secret Info type.
This will be called from qemuDomainSecretAESSetup.
qemuDomainSecretAESSetup: (private)
This API handles the details of the generation of the AES secret
and saves the pieces that need to be passed to qemu in order for
the secret to be decrypted. The encrypted secret based upon the
domain master key, an initialization vector (16 byte random value),
and the stored secret. Finally, the requirement from qemu is the IV
and encrypted secret are to be base64 encoded.
qemu_command.c:
qemuBuildSecretInfoProps: (private)
Generate/return a JSON properties object for the AES secret to
be used by both the command building and eventually the hotplug
code in order to add the secret object. Code was designed so that
in the future perhaps hotplug could use it if it made sense.
qemuBuildObjectSecretCommandLine (private)
Generate and add to the command line the -object secret for the
secret. This will be required for the subsequent RBD reference
to the object.
qemuBuildDiskSecinfoCommandLine (private)
Handle adding the AES secret object.
Adjustments:
qemu_domain.c:
The qemuDomainSecretSetup was altered to call either the AES or Plain
Setup functions based upon whether AES secrets are possible (we have
the encryption API) or not, we have secrets, and of course if the
protocol source is RBD.
qemu_command.c:
Adjust the qemuBuildRBDSecinfoURI API's in order to generate the
specific command options for an AES secret, such as:
-object secret,id=$alias,keyid=$masterKey,data=$base64encodedencrypted,
format=base64
-drive file=rbd:pool/image:id=myname:auth_supported=cephx\;none:\
mon_host=mon1.example.org\:6321,password-secret=$alias,...
where the 'id=' value is the secret object alias generated by
concatenating the disk alias and "-aesKey0". The 'keyid= $masterKey'
is the master key shared with qemu, and the -drive syntax will
reference that alias as the 'password-secret'. For the -drive
syntax, the 'id=myname' is kept to define the username, while the
'key=$base64 encoded secret' is removed.
While according to the syntax described for qemu commit '60390a21'
or as seen in the email archive:
https://lists.gnu.org/archive/html/qemu-devel/2016-01/msg04083.html
it is possible to pass a plaintext password via a file, the qemu
commit 'ac1d8878' describes the more feature rich 'keyid=' option
based upon the shared masterKey.
Add tests for checking/comparing output.
NB: For hotplug, since the hotplug code doesn't add command line
arguments, passing the encoded secret directly to the monitor
will suffice.
2016-04-11 15:26:14 +00:00
|
|
|
|
|
|
|
return alias;
|
|
|
|
}
|
2016-06-09 22:30:55 +00:00
|
|
|
|
|
|
|
|
2017-02-16 19:59:06 +00:00
|
|
|
/* qemuAliasTLSObjFromSrcAlias
|
|
|
|
* @srcAlias: Pointer to a source alias string
|
2016-06-09 22:30:55 +00:00
|
|
|
*
|
|
|
|
* Generate and return a string to be used as the TLS object alias
|
|
|
|
*/
|
|
|
|
char *
|
2017-02-16 19:59:06 +00:00
|
|
|
qemuAliasTLSObjFromSrcAlias(const char *srcAlias)
|
2016-06-09 22:30:55 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
2017-02-16 19:59:06 +00:00
|
|
|
ignore_value(virAsprintf(&ret, "obj%s_tls0", srcAlias));
|
2016-06-09 22:30:55 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2016-10-18 14:37:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* qemuAliasChardevFromDevAlias:
|
|
|
|
* @devAlias: pointer do device alias
|
|
|
|
*
|
|
|
|
* Generate and return a string to be used as chardev alias.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
qemuAliasChardevFromDevAlias(const char *devAlias)
|
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
ignore_value(virAsprintf(&ret, "char%s", devAlias));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2018-04-18 14:55:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
qemuDomainGetManagedPRAlias(void)
|
|
|
|
{
|
|
|
|
return "pr-helper0";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
2018-05-11 12:11:36 +00:00
|
|
|
qemuDomainGetUnmanagedPRAlias(const char *parentalias)
|
2018-04-18 14:55:14 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
2018-05-11 12:11:36 +00:00
|
|
|
ignore_value(virAsprintf(&ret, "pr-helper-%s", parentalias));
|
2018-04-18 14:55:14 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|