Isolation groups will eventually allow us to make sure certain
devices, eg. PCI hostdevs, are assigned to guest PCI buses in
a way that guarantees improved isolation, error detection and
recovery for machine types and hypervisors that support it,
eg. pSeries guest on QEMU.
---
src/bhyve/bhyve_device.c | 4 ++--
src/conf/device_conf.h | 4 ++++
src/conf/domain_addr.c | 33 +++++++++++++++++++++++++--------
src/conf/domain_addr.h | 7 ++++++-
src/conf/domain_conf.h | 4 ++++
src/qemu/qemu_domain_address.c | 34 +++++++++++++++++-----------------
6 files changed, 58 insertions(+), 28 deletions(-)
diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c
index fdfd512..03aa6c9 100644
--- a/src/bhyve/bhyve_device.c
+++ b/src/bhyve/bhyve_device.c
@@ -57,7 +57,7 @@ bhyveCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
}
if (virDomainPCIAddressReserveAddr(addrs, addr,
- VIR_PCI_CONNECT_TYPE_PCI_DEVICE) < 0) {
+ VIR_PCI_CONNECT_TYPE_PCI_DEVICE, 0) < 0) {
goto cleanup;
}
@@ -100,7 +100,7 @@ bhyveAssignDevicePCISlots(virDomainDefPtr def,
lpc_addr.slot = 0x1;
if (virDomainPCIAddressReserveAddr(addrs, &lpc_addr,
- VIR_PCI_CONNECT_TYPE_PCI_DEVICE) < 0) {
+ VIR_PCI_CONNECT_TYPE_PCI_DEVICE, 0) < 0) {
goto error;
}
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
index 58b2c9c..4b1377c 100644
--- a/src/conf/device_conf.h
+++ b/src/conf/device_conf.h
@@ -163,6 +163,10 @@ struct _virDomainDeviceInfo {
* assignment, never saved and never reported.
*/
int pciConnectFlags; /* enum virDomainPCIConnectFlags */
+
+ /* PCI devices will only be automatically placed on a PCI bus
+ * that shares the same isolation group */
+ int isolationGroup;
};
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
index e6a6399..cd26b21 100644
--- a/src/conf/domain_addr.c
+++ b/src/conf/domain_addr.c
@@ -365,7 +365,8 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
static int
virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr,
- virDomainPCIConnectFlags flags)
+ virDomainPCIConnectFlags flags,
+ int isolationGroup)
{
int add;
size_t i;
@@ -492,6 +493,9 @@ virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs,
for (; i < addrs->nbuses; i++) {
if (virDomainPCIAddressBusSetModel(&addrs->buses[i], model) < 0)
return -1;
+
+ /* Set isolation group for the new bus */
+ addrs->buses[i].isolationGroup = isolationGroup;
}
return add;
@@ -534,6 +538,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr,
virDomainPCIConnectFlags flags,
+ int isolationGroup,
bool fromConfig)
{
int ret = -1;
@@ -546,8 +551,10 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr
addrs,
goto cleanup;
/* Add an extra bus if necessary */
- if (addrs->dryRun && virDomainPCIAddressSetGrow(addrs, addr, flags) <
0)
+ if (addrs->dryRun &&
+ virDomainPCIAddressSetGrow(addrs, addr, flags, isolationGroup) < 0) {
goto cleanup;
+ }
/* Check that the requested bus exists, is the correct type, and we
* are asking for a valid slot
*/
@@ -586,9 +593,11 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr
addrs,
int
virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr,
- virDomainPCIConnectFlags flags)
+ virDomainPCIConnectFlags flags,
+ int isolationGroup)
{
- return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags, true);
+ return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags,
+ isolationGroup, true);
}
int
@@ -624,7 +633,8 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
goto cleanup;
ret = virDomainPCIAddressReserveAddrInternal(addrs, &dev->addr.pci,
- flags, true);
+ flags, dev->isolationGroup,
+ true);
} else {
ret = virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1);
}
@@ -745,6 +755,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr next_addr,
virDomainPCIConnectFlags flags,
+ int isolationGroup,
int function)
{
virPCIDeviceAddress a = { 0 };
@@ -765,6 +776,10 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) {
bool found = false;
+ /* Isolation groups for bus and device must match */
+ if (addrs->buses[a.bus].isolationGroup != isolationGroup)
+ continue;
+
a.slot = addrs->buses[a.bus].minSlot;
if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus],
@@ -780,7 +795,7 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
/* There were no free slots after the last used one */
if (addrs->dryRun) {
/* a is already set to the first new bus */
- if (virDomainPCIAddressSetGrow(addrs, &a, flags) < 0)
+ if (virDomainPCIAddressSetGrow(addrs, &a, flags, isolationGroup) < 0)
goto error;
/* this device will use the first slot of the new bus */
a.slot = addrs->buses[a.bus].minSlot;
@@ -825,10 +840,12 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
{
virPCIDeviceAddress addr;
- if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, function) < 0)
+ if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags,
+ dev->isolationGroup, function) < 0)
return -1;
- if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0)
+ if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags,
+ dev->isolationGroup, false) < 0)
return -1;
if (!addrs->dryRun) {
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
index 1849d2b..23c7900 100644
--- a/src/conf/domain_addr.h
+++ b/src/conf/domain_addr.h
@@ -100,6 +100,10 @@ typedef struct {
* bit is set, that function is in use by a device.
*/
virDomainPCIAddressSlot slot[VIR_PCI_ADDRESS_SLOT_LAST + 1];
+
+ /* PCI devices will only be automatically placed on a PCI bus
+ * that shares the same isolation group */
+ int isolationGroup;
} virDomainPCIAddressBus;
typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr;
@@ -147,7 +151,8 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
virPCIDeviceAddressPtr addr,
- virDomainPCIConnectFlags flags)
+ virDomainPCIConnectFlags flags,
+ int isolationGroup)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 244977a..507891a 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -786,6 +786,10 @@ struct _virDomainPCIControllerOpts {
* item in memory target config) -1 == unspecified
*/
int numaNode;
+
+ /* PCI devices will only be automatically placed on a PCI bus
+ * that shares the same isolation group */
+ int isolationGroup;
};
typedef struct _virDomainUSBControllerOpts virDomainUSBControllerOpts;
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 08773c0..384d6fd 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -1032,7 +1032,8 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
}
if (virDomainPCIAddressReserveAddr(addrs, addr,
- info->pciConnectFlags) < 0) {
+ info->pciConnectFlags,
+ info->isolationGroup) < 0) {
goto cleanup;
}
@@ -1077,6 +1078,8 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model)
< 0)
goto error;
+ addrs->buses[idx].isolationGroup = cont->opts.pciopts.isolationGroup;
+
if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT)
hasPCIeRoot = true;
}
@@ -1193,7 +1196,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
if (addrs->nbuses) {
memset(&tmp_addr, 0, sizeof(tmp_addr));
tmp_addr.slot = 1;
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
goto cleanup;
}
@@ -1228,7 +1231,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
goto cleanup;
}
} else {
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) <
0)
goto cleanup;
primaryVideo->info.addr.pci = tmp_addr;
primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -1253,7 +1256,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
VIR_DEBUG("PCI address 0:0:2.0 in use, future addition of a video"
" device will not be possible without manual"
" intervention");
- } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) {
+ } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
{
goto cleanup;
}
}
@@ -1329,10 +1332,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
assign = true;
}
if (assign) {
- if (virDomainPCIAddressReserveAddr(addrs,
- &tmp_addr, flags) < 0) {
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0)
< 0)
goto cleanup;
- }
cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
cont->info.addr.pci.domain = 0;
@@ -1354,10 +1355,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
memset(&tmp_addr, 0, sizeof(tmp_addr));
tmp_addr.slot = 0x1E;
if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
- if (virDomainPCIAddressReserveAddr(addrs,
- &tmp_addr, flags) < 0) {
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0)
< 0)
goto cleanup;
- }
cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
cont->info.addr.pci.domain = 0;
@@ -1380,12 +1379,12 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
tmp_addr.slot = 0x1F;
tmp_addr.function = 0;
tmp_addr.multi = VIR_TRISTATE_SWITCH_ON;
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
goto cleanup;
tmp_addr.function = 3;
tmp_addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
goto cleanup;
}
@@ -1419,7 +1418,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
goto cleanup;
}
} else {
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) <
0)
goto cleanup;
primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
primaryVideo->info.addr.pci = tmp_addr;
@@ -1445,8 +1444,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
" device will not be possible without manual"
" intervention");
virResetLastError();
- } else if (virDomainPCIAddressReserveAddr(addrs,
- &tmp_addr, flags) < 0) {
+ } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
{
goto cleanup;
}
}
@@ -1467,7 +1465,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
!virDeviceInfoPCIAddressWanted(&sound->info)) {
continue;
}
- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
+ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
goto cleanup;
sound->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
@@ -1684,7 +1682,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def,
if (foundAddr) {
/* Reserve this function on the slot we found */
if (virDomainPCIAddressReserveAddr(addrs, &addr,
- cont->info.pciConnectFlags) < 0)
{
+ cont->info.pciConnectFlags,
+ cont->info.isolationGroup) < 0)
{
goto error;
}
@@ -2150,6 +2149,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
}
dev.type = VIR_DOMAIN_DEVICE_CONTROLLER;
dev.data.controller = def->controllers[contIndex];
+ dev.data.controller->opts.pciopts.isolationGroup =
bus->isolationGroup;
/* set connect flags so it will be properly addressed */
qemuDomainFillDevicePCIConnectFlags(def, &dev, qemuCaps, driver);
--
2.7.5