[libvirt PATCH v2 00/15] Support for VFIO variant drivers, Part 2

(Thisis "V2 of Part 2". "V1 of Part 2" is here: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/5GF4N... ) Part 1 (which simply made it possible to use virsh nodedev-detach to bind a device to a manually-specified variant driver, and at guest runtime allowed libvirt to ignore the fact that the driver found to the device was something other than exactly "vfio-pci") was here: https://listman.redhat.com/archives/libvir-list/2023-August/241338.html and pushed upstream as of commit v9.6.0-153-g24beaffec3 Part 2 adds two new pieces of functionality: 1) It is possible to manually specify a VFIO variant driver (or force the generic vfio-pci driver) for a device in the domain XML with, e.g.: <driver name='mlx5_vfio_pci'/> (for the former) or: <driver name='vfio-pci'/> (for the latter). 2) By default libvirt will now find the "best match" VFIO or VFIO variant driver by comparing the device's modalias file contents (in sysfs) with vfio drivers found in the running kernel's modules.alias file. This means that "virsh nodedev-detach" of a host device will bind it to its appropriate VFIO variant driver (if one is available), and also if a <hostdev> decice in a domain config has "managed='yes'", libvirt will bind it to a variant driver if possible (in order to force binding to the basic vfio-pci driver instead, you just need to add the <driver> element mentioned above). The first 12 patches are all just getting (1) going (a lot of it is refactoring code to use common code for the four places that use the hostdev <driver> element), and the final 3 patches implement (2). More details are spread along the way. Differences from V1: I squashed together a couple of the patches, and fixed some things that caused CI jobs to fail (I'd forgotten to push the branch to gitlab and trigger CI). Laine Stump (15): util: properly deal with module vs. driver when binding device to driver schema: consolidate RNG for all hostdev <driver> elements conf: move/rename hostdev PCI driver type enum to device_conf.h conf: normalize hostdev <driver> parsing to simplify adding new attr conf: put hostdev PCI backend into a struct conf: use virDeviceHostdevPCIDriverInfo in network and networkport objects conf: split out hostdev <driver> parse/format to their own functions conf: use new common parser/formatter for hostdev driver in network XML tests: remove explicit <driver name='vfio'/> from hostdev test cases xen: explicitly set hostdev driver.type at runtime, not in postparse conf: replace virHostdevIsVFIODevice with virHostdevIsPCIDevice conf: support manually specifying VFIO variant driver in <hostdev> XML util: new function virStringSkipToSpace() tests: mock virPCIDevice(BindTo|UnbindFrom)Stub with nop functions qemu: automatically bind to a vfio variant driver, if available docs/formatdomain.rst | 55 ++- src/conf/device_conf.c | 75 +++ src/conf/device_conf.h | 27 ++ src/conf/domain_capabilities.c | 2 +- src/conf/domain_capabilities.h | 2 +- src/conf/domain_conf.c | 98 +--- src/conf/domain_conf.h | 18 +- src/conf/network_conf.c | 43 +- src/conf/network_conf.h | 17 +- src/conf/schemas/basictypes.rng | 20 + src/conf/schemas/domaincommon.rng | 173 ++++--- src/conf/schemas/network.rng | 10 +- src/conf/schemas/networkport.rng | 10 +- src/conf/virconftypes.h | 2 + src/conf/virnetworkportdef.c | 22 +- src/conf/virnetworkportdef.h | 4 +- src/hypervisor/virhostdev.c | 16 +- src/hypervisor/virhostdev.h | 2 - src/libvirt_private.syms | 10 +- src/libxl/libxl_capabilities.c | 2 +- src/libxl/libxl_domain.c | 65 ++- src/libxl/libxl_driver.c | 25 +- src/network/bridge_driver.c | 2 +- src/qemu/qemu_capabilities.c | 4 +- src/qemu/qemu_command.c | 14 +- src/qemu/qemu_domain.c | 29 +- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_validate.c | 6 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 4 +- src/security/security_selinux.c | 4 +- src/security/virt-aa-helper.c | 8 +- src/util/virpci.c | 438 ++++++++++++++++-- src/util/virpci.h | 3 + src/util/virstring.c | 17 + src/util/virstring.h | 1 + tests/domaincapstest.c | 4 +- tests/libxlxml2domconfigdata/moredevs-hvm.xml | 1 - tests/networkxml2xmlin/hostdev-pf-old.xml | 8 + tests/networkxml2xmlin/hostdev-pf.xml | 2 +- tests/networkxml2xmlout/hostdev-pf-old.xml | 8 + tests/networkxml2xmlout/hostdev-pf.xml | 2 +- tests/networkxml2xmltest.c | 6 + tests/qemuhotplugmock.c | 15 + .../qemuhotplug-hostdev-pci.xml | 1 - .../qemuhotplug-base-live+hostdev-pci.xml | 2 +- ...uhotplug-pseries-base-live+hostdev-pci.xml | 2 +- tests/qemustatusxml2xmldata/modern-in.xml | 2 +- .../hostdev-pci-address-unassigned.xml | 4 - .../hostdev-pci-multifunction.xml | 7 - .../hostdev-vfio-multidomain.xml | 1 - .../hostdev-vfio-zpci-autogenerate-fids.xml | 2 - .../hostdev-vfio-zpci-autogenerate-uids.xml | 2 - .../hostdev-vfio-zpci-autogenerate.xml | 1 - .../hostdev-vfio-zpci-boundaries.xml | 2 - .../hostdev-vfio-zpci-ccw-memballoon.xml | 1 - .../hostdev-vfio-zpci-duplicate.xml | 2 - ...ostdev-vfio-zpci-invalid-uid-valid-fid.xml | 1 - .../hostdev-vfio-zpci-multidomain-many.xml | 8 - .../hostdev-vfio-zpci-set-zero.xml | 1 - .../hostdev-vfio-zpci-uid-set-zero.xml | 1 - .../hostdev-vfio-zpci-wrong-arch.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio-zpci.xml | 1 - .../hostdev-vfio.x86_64-latest.args | 5 +- tests/qemuxml2argvdata/hostdev-vfio.xml | 19 +- .../net-hostdev-vfio-multidomain.xml | 1 - tests/qemuxml2argvdata/net-hostdev-vfio.xml | 1 - tests/qemuxml2argvdata/pseries-hostdevs-1.xml | 3 - tests/qemuxml2argvdata/pseries-hostdevs-2.xml | 2 - tests/qemuxml2argvdata/pseries-hostdevs-3.xml | 2 - ...v-pci-address-unassigned.x86_64-latest.xml | 4 - ...ostdev-pci-multifunction.x86_64-latest.xml | 7 - ...io-zpci-autogenerate-fids.s390x-latest.xml | 2 - ...io-zpci-autogenerate-uids.s390x-latest.xml | 2 - ...ev-vfio-zpci-autogenerate.s390x-latest.xml | 1 - ...tdev-vfio-zpci-boundaries.s390x-latest.xml | 2 - ...-vfio-zpci-ccw-memballoon.s390x-latest.xml | 1 - ...fio-zpci-multidomain-many.s390x-latest.xml | 8 - .../hostdev-vfio-zpci.s390x-latest.xml | 1 - .../hostdev-vfio.x86_64-latest.xml | 24 +- .../net-hostdev-vfio.x86_64-latest.xml | 1 - .../pseries-hostdevs-1.ppc64-latest.xml | 3 - .../pseries-hostdevs-2.ppc64-latest.xml | 2 - .../pseries-hostdevs-3.ppc64-latest.xml | 2 - tests/virhostdevtest.c | 2 +- .../plug-hostdev-pci-unmanaged.xml | 2 +- .../plug-hostdev-pci.xml | 2 +- tests/xlconfigdata/test-fullvirt-pci.xml | 2 - tests/xmconfigdata/test-pci-dev-syntax.xml | 2 - tests/xmconfigdata/test-pci-devs.xml | 2 - tools/virsh-completer-nodedev.c | 4 +- 92 files changed, 933 insertions(+), 498 deletions(-) create mode 100644 tests/networkxml2xmlin/hostdev-pf-old.xml create mode 100644 tests/networkxml2xmlout/hostdev-pf-old.xml -- 2.41.0

Historically libvirt has treated the concept of "loadable kernel module" and "device driver" as being effectively the same (at least in the case of the vfio-pci driver used for VFIO device assignment). The code assumed that a module named "vfio-pci" implemented a driver named "vfio-pci". In reality, the module is named "vfio_pci", and it implements a device driver named "vfio-pci" (note the difference in separator characters), and our code worked only because the modprobe utility we use to load the module will always "normalize" the module name it's given by replacing all "-" (dash) with "_" (underscore) (this has been verified in the modprobe source, which is in the kmod package - there are 3 separate functions that perform this same operation!). So even though we asked modprobe to load the "vfio-pci" module, it would actually load the "vfio_pci" module. After loading the module with modprobe, libvirt then looks for the desired *driver* to be present in sysfs, by looking for the directory /sys/bus/pci/drivers/${driverName}, which would succeed because we were still looking for the original "dash version" of the name ("vfio-pci"). When we recently gained the ability to manually specify a driver to bind to with virsh nodedev-detach, the fragility of this system became apparent - if a user gives the driver name as "vfio_pci", then we would modprobe the module, but then erroneously believe it hadn't been loaded because /sys/bus/pci/drivers/vfio_pci didn't exist. For manual specification of the driver name, this could be dealt with by telling the user "always use the correct name for the driver, don't assume that it is the same as the modulename", but it would still end up confusing people, especially since some drivers do use underscore in their name (e.g. the mlx5_vfio_pci driver/module). More more importantly, when we begin looking in the modules.alias file for the "best" VFIO variant driver for a particular device (in an upcoming patch), that lookup will provide us with the name of a *module*, not a driver, and 3 of the 4 examples of vfio-pci/variant drivers I have access to use underscore in the module name and dash in the driver, while the 4th uses underscore in both, so 3 out of 4 fail with the current code. To make the current code more forgiving (and yet more correct!), as well as to make the upcoming variant auto-selection actually useful, this patch follows the following steps: 1) if the requested driver (${driverName}) is present in sysfs drivers list (/sys/bus/pci/drivers/${driverName}) then use ${driverName} - DONE 2) if underscored(${driverName}) (call it ${underName} for short) is in sysfs drivers list then use ${underName} - DONE 3) if ${underName} *isn't* in the sysfs modules list (/sys/module/${underName}) then "modprobe ${underName}" to load it. 4) look for the PCI driver implemented by this module, it will be at /sys/module/${underName}/driver/pci:${newName}. 5) use ${newName} - DONE. A few notes: a) This will *always* replace dash with underscore in the name used to load the module, which seems it could be problematic, but I have verified this is what modprobe itself does, so I don't think there will ever be a module with "-" in its name as modprobe would be unable to load it (the same can't be said for drivers though!) b) The one case where the above steps wouldn't work would be if someone implemented a driver within a module where the driver and module had names that differed other than dash vs. underscore. I haven't seen an example of this, so the convention seems to be that they will "match" (modulo - & _). If this mismatch were to ever occur, though, it could be worked around by simply loading the module out-of-band during the host system startup, and then using the driver's name in the config. c) All of this is conveniently ignoring the possibility of a VFIO variant driver that is statically linked in the kernel. The entire design of variant driver auto-detection is based on doing a lookup in modules.alias, and that only lists *loadable modules* (not drivers), so unless I'm missing something, it would be impossible to auto-detect a VFIO variant driver that was statically linked. This is beyond libvirt's ability to fix; the best that could be done would be to manually specify the driver name in the libvirt config, which I suppose is better than nothing :-) Signed-off-by: Laine Stump <laine@redhat.com> --- src/util/virpci.c | 194 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 164 insertions(+), 30 deletions(-) diff --git a/src/util/virpci.c b/src/util/virpci.c index baacde4c14..dfc97dc981 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -221,6 +221,13 @@ virPCIDriverDir(const char *driver) } +static char * +virPCIModuleDir(const char *module) +{ + return g_strdup_printf("/sys/module/%s", module); +} + + static char * virPCIFile(const char *device, const char *file) { @@ -1153,44 +1160,167 @@ virPCIDeviceReset(virPCIDevice *dev, } +/** + * virPCINameDashToUnderscore: + * @path: the module/driver name or path - will be directly modified + * + * Replace all occurences of "-" with "_" in the name + * part of the path (everything after final "/" + * + * return true if any change was made, otherwise false. + */ static int -virPCIProbeDriver(const char *driverName) +virPCINameDashToUnderscore(char *path) { - g_autofree char *drvpath = NULL; + bool changed = false; + char *tmp = strrchr(path, '/'); + + if (!tmp) + tmp = path; + + while (*tmp) { + if (*tmp == '-') { + *tmp = '_'; + changed = true; + } + tmp++; + } + + return changed; +} + + +static int +virPCIProbeModule(const char *moduleName) +{ + g_autofree char *modulePath = NULL; g_autofree char *errbuf = NULL; - drvpath = virPCIDriverDir(driverName); + modulePath = virPCIModuleDir(moduleName); /* driver previously loaded, return */ - if (virFileExists(drvpath)) + if (virFileExists(modulePath)) return 0; - if ((errbuf = virKModLoad(driverName))) { - VIR_WARN("failed to load driver %s: %s", driverName, errbuf); - goto cleanup; + if ((errbuf = virKModLoad(moduleName))) { + /* If we know failure was because of admin config, let's report that; + * otherwise, report a more generic failure message + */ + if (virKModIsProhibited(moduleName)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to load PCI driver module %1$s: administratively prohibited"), + moduleName); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to load PCI driver module %1$s: %2$s"), + moduleName, errbuf); + } + return -1; } /* driver loaded after probing */ - if (virFileExists(drvpath)) + if (virFileExists(modulePath)) return 0; - cleanup: - /* If we know failure was because of admin config, let's report that; - * otherwise, report a more generic failure message + virReportError(VIR_ERR_INTERNAL_ERROR, + _("modprobe reported success loading module '%1$s', but module is missing from /sys/module"), + moduleName); + return -1; +} + +/** + * virPCIDeviceFindDriver: + * @dev: initialized virPCIDevice, including desired stubDriverName + * + * Checks if there is a driver named @dev->stubDriverName already + * loaded. If there is, we're done. If not, look for a driver with + * that same name, except with dashes replaced with underscores. + + * If neither of the above is found, then look for/load the module of + * the underscored version of the name, and follow the links from + * /sys/module/$name/drivers/pci:* to the PCI driver associated with that + * module, and update @dev->stubDriverName with that name. + * + * On a successful return, @dev->stubDriverName will be updated with + * the proper name for the driver, and that driver will be loaded. + * + * returns 0 on success, -1 on failure + */ +static int +virPCIDeviceFindDriver(virPCIDevice *dev) +{ + g_autofree char *driverPath = virPCIDriverDir(dev->stubDriverName); + g_autofree char *moduleName = NULL; + g_autofree char *moduleDriversDir = NULL; + g_autoptr(DIR) dir = NULL; + struct dirent *ent; + int direrr; + + /* unchanged stubDriverName */ + if (virFileExists(driverPath)) + return 0; + + /* try replacing "-" with "_" */ + if (virPCINameDashToUnderscore(driverPath) + && virFileExists(driverPath)) { + + /* update original name in dev */ + virPCINameDashToUnderscore(dev->stubDriverName); + return 0; + } + + /* look for a module with this name (but always replacing + * "-" with "_", since that's what modprobe does) */ - if (virKModIsProhibited(driverName)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to load PCI driver module %1$s: administratively prohibited"), - driverName); - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to load PCI driver module %1$s"), - driverName); + + moduleName = g_strdup(dev->stubDriverName); + virPCINameDashToUnderscore(moduleName); + + if (virPCIProbeModule(moduleName) < 0) + return -1; + + /* module was found/loaded. Now find the PCI driver it implements, + * linked to by /sys/module/$moduleName/drivers/pci:$driverName + */ + + moduleDriversDir = g_strdup_printf("/sys/module/%s/drivers", moduleName); + + if (virDirOpen(&dir, moduleDriversDir) < 0) + return -1; + + while ((direrr = virDirRead(dir, &ent, moduleDriversDir))) { + + if (STRPREFIX(ent->d_name, "pci:")) { + /* this is the link to the driver we want */ + + g_autofree char *drvName = NULL; + g_autofree char *drvPath = NULL; + + /* extract the driver name from the link name */ + drvName = g_strdup(ent->d_name + strlen("pci:")); + + /* make sure that driver is actually loaded */ + drvPath = virPCIDriverDir(drvName); + if (!virFileExists(drvPath)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("pci driver '%1$s' supposedly loaded by module '%2$s' not found in sysfs"), + drvName, moduleName); + return -1; + } + + g_free(dev->stubDriverName); + dev->stubDriverName = g_steal_pointer(&drvName); + return 0; + } } + virReportError(VIR_ERR_INTERNAL_ERROR, + _("module '%1$s' does not implement any pci driver"), + moduleName); return -1; } + int virPCIDeviceUnbind(virPCIDevice *dev) { @@ -1290,7 +1420,6 @@ virPCIDeviceUnbindFromStub(virPCIDevice *dev) static int virPCIDeviceBindToStub(virPCIDevice *dev) { - const char *stubDriverName = dev->stubDriverName; g_autofree char *stubDriverPath = NULL; g_autofree char *driverLink = NULL; @@ -1302,30 +1431,35 @@ virPCIDeviceBindToStub(virPCIDevice *dev) return -1; } - if (!stubDriverName - && !(stubDriverName = virPCIStubDriverTypeToString(dev->stubDriverType))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown stub driver configured for PCI device %1$s"), - dev->name); - return -1; + if (!dev->stubDriverName) { + + const char *stubDriverName = NULL; + + if (!(stubDriverName = virPCIStubDriverTypeToString(dev->stubDriverType))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown stub driver configured for PCI device %1$s"), + dev->name); + return -1; + } + dev->stubDriverName = g_strdup(stubDriverName); } - if (virPCIProbeDriver(stubDriverName) < 0) + if (virPCIDeviceFindDriver(dev) < 0) return -1; - stubDriverPath = virPCIDriverDir(stubDriverName); + stubDriverPath = virPCIDriverDir(dev->stubDriverName); driverLink = virPCIFile(dev->name, "driver"); if (virFileExists(driverLink)) { if (virFileLinkPointsTo(driverLink, stubDriverPath)) { /* The device is already bound to the correct driver */ VIR_DEBUG("Device %s is already bound to %s", - dev->name, stubDriverName); + dev->name, dev->stubDriverName); return 0; } } - if (virPCIDeviceBindWithDriverOverride(dev, stubDriverName) < 0) + if (virPCIDeviceBindWithDriverOverride(dev, dev->stubDriverName) < 0) return -1; dev->unbind_from_stub = true; -- 2.41.0

The commit message is longer than it needs to be and the long explanation actually made it harder to comprehend for me. On a Monday in 2023, Laine Stump wrote:
Historically libvirt has treated the concept of "loadable kernel module" and "device driver" as being effectively the same (at least in the case of the vfio-pci driver used for VFIO device assignment). The code assumed that a module named "vfio-pci" implemented a driver named "vfio-pci".
In reality, the module is named "vfio_pci", and it implements a device driver named "vfio-pci" (note the difference in separator characters),
The note about the difference in characters is not needed if you mention them explicitly below.
and our code worked only because the modprobe utility we use to load the module will always "normalize" the module name it's given by replacing all "-" (dash) with "_" (underscore) (this has been verified in the modprobe source, which is in the kmod package - there are 3 separate functions that perform this same operation!).
My package manager can tell me which package modprobe is in and I don't need to know the number of functions.
So even though we asked modprobe to load the "vfio-pci" module, it would actually load the "vfio_pci" module.
After loading the module with modprobe, libvirt then looks for the desired *driver* to be present in sysfs, by looking for the directory /sys/bus/pci/drivers/${driverName}, which would succeed because we were still looking for the original "dash version" of the name ("vfio-pci").
When we recently gained the ability to manually specify a driver to bind to with virsh nodedev-detach, the fragility of this system became apparent - if a user gives the driver name as "vfio_pci", then we would modprobe the module, but then erroneously believe it hadn't been loaded because /sys/bus/pci/drivers/vfio_pci didn't exist. For manual specification of the driver name, this could be dealt with by telling the user "always use the correct name for the driver, don't assume that it is the same as the modulename", but it would still end up confusing people, especially since some drivers do use underscore in their name (e.g. the mlx5_vfio_pci driver/module).
More more importantly, when we begin looking in the modules.alias file for the "best" VFIO variant driver for a particular device (in an upcoming patch), that lookup will provide us with the name of a *module*, not a driver, and 3 of the 4 examples of vfio-pci/variant drivers I have access to use underscore in the module name and dash in the driver, while the 4th uses underscore in both, so 3 out of 4 fail with the current code.
To make the current code more forgiving (and yet more correct!), as well as to make the upcoming variant auto-selection actually useful, this patch follows the following steps:
1) if the requested driver (${driverName}) is present in sysfs drivers list (/sys/bus/pci/drivers/${driverName}) then use ${driverName} - DONE
I did not see any response to Jason's points in v1: https://listman.redhat.com/archives/libvir-list/2023-October/242780.html I think we can safely assume that modprobe will accept a dashed name and that module names are using underscores. Is the problem here that you cannot figure out the driver the module provides until after it's loaded? Jano
2) if underscored(${driverName}) (call it ${underName} for short) is in sysfs drivers list then use ${underName} - DONE
3) if ${underName} *isn't* in the sysfs modules list (/sys/module/${underName}) then "modprobe ${underName}" to load it.
4) look for the PCI driver implemented by this module, it will be at /sys/module/${underName}/driver/pci:${newName}.
5) use ${newName} - DONE.
A few notes:
a) This will *always* replace dash with underscore in the name used to load the module, which seems it could be problematic, but I have verified this is what modprobe itself does, so I don't think there will ever be a module with "-" in its name as modprobe would be unable to load it (the same can't be said for drivers though!)
b) The one case where the above steps wouldn't work would be if someone implemented a driver within a module where the driver and module had names that differed other than dash vs. underscore. I haven't seen an example of this, so the convention seems to be that they will "match" (modulo - & _). If this mismatch were to ever occur, though, it could be worked around by simply loading the module out-of-band during the host system startup, and then using the driver's name in the config.
c) All of this is conveniently ignoring the possibility of a VFIO variant driver that is statically linked in the kernel. The entire design of variant driver auto-detection is based on doing a lookup in modules.alias, and that only lists *loadable modules* (not drivers), so unless I'm missing something, it would be impossible to auto-detect a VFIO variant driver that was statically linked. This is beyond libvirt's ability to fix; the best that could be done would be to manually specify the driver name in the libvirt config, which I suppose is better than nothing :-)
Signed-off-by: Laine Stump <laine@redhat.com> --- src/util/virpci.c | 194 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 164 insertions(+), 30 deletions(-)

On 11/28/23 8:21 AM, Ján Tomko wrote:
The commit message is longer than it needs to be and the long explanation actually made it harder to comprehend for me.
Well, without *enough* explanation, it all seems like pointlessly pushing bits around :-). I guess my extra explanation failed though, since people have had issues with the patch twice now).
On a Monday in 2023, Laine Stump wrote:
Historically libvirt has treated the concept of "loadable kernel module" and "device driver" as being effectively the same (at least in the case of the vfio-pci driver used for VFIO device assignment). The code assumed that a module named "vfio-pci" implemented a driver named "vfio-pci".
In reality, the module is named "vfio_pci", and it implements a device driver named "vfio-pci" (note the difference in separator characters),
The note about the difference in characters is not needed if you mention them explicitly below.
I suppose I can remove it. Reading the paragraph by itself, though, it sounds like 'His name is "Bob", not "*Bob*"'.
and our code worked only because the modprobe utility we use to load the module will always "normalize" the module name it's given by replacing all "-" (dash) with "_" (underscore) (this has been verified in the modprobe source, which is in the kmod package - there are 3 separate functions that perform this same operation!).
My package manager can tell me which package modprobe is in and I don't need to know the number of functions.
My spidey senses tell me someone is getting fed up with my verbose explanations :-). I'll try to be more brief.
So even though we asked modprobe to load the "vfio-pci" module, it would actually load the "vfio_pci" module.
After loading the module with modprobe, libvirt then looks for the desired *driver* to be present in sysfs, by looking for the directory /sys/bus/pci/drivers/${driverName}, which would succeed because we were still looking for the original "dash version" of the name ("vfio-pci").
When we recently gained the ability to manually specify a driver to bind to with virsh nodedev-detach, the fragility of this system became apparent - if a user gives the driver name as "vfio_pci", then we would modprobe the module, but then erroneously believe it hadn't been loaded because /sys/bus/pci/drivers/vfio_pci didn't exist. For manual specification of the driver name, this could be dealt with by telling the user "always use the correct name for the driver, don't assume that it is the same as the modulename", but it would still end up confusing people, especially since some drivers do use underscore in their name (e.g. the mlx5_vfio_pci driver/module).
More more importantly, when we begin looking in the modules.alias file for the "best" VFIO variant driver for a particular device (in an upcoming patch), that lookup will provide us with the name of a *module*, not a driver, and 3 of the 4 examples of vfio-pci/variant drivers I have access to use underscore in the module name and dash in the driver, while the 4th uses underscore in both, so 3 out of 4 fail with the current code.
To make the current code more forgiving (and yet more correct!), as well as to make the upcoming variant auto-selection actually useful, this patch follows the following steps:
1) if the requested driver (${driverName}) is present in sysfs drivers list (/sys/bus/pci/drivers/${driverName}) then use ${driverName} - DONE
I did not see any response to Jason's points in v1: https://listman.redhat.com/archives/libvir-list/2023-October/242780.html
I did send a response, but I sent it after the list switched to the new server, so you won't find it in the old archives (actually when I originally replied I forgot to change the list address, and then had to resend): https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/WSWE...
I think we can safely assume that modprobe will accept a dashed name and that module names are using underscores.
Yes. But you can't assume that the driver name will use dashes, nor even that the driver name will resemble the module name in any programmatically derivable way - although it is common convention that the module name be underscored(drivername), driver name is *not* dashed(modulename). (Technically it is even possible (although I've not seen it) that the driver and module names might be completely unrelated - e.g. module "foo" implementing driver "bar". Sure, we could assume that will never happen, but then in 5 years someone will do that and libvirt 15.2.0 will break because of this assumption made 5 years prior, and some poor soul will have to spend a bunch of time figuring out why.)
Is the problem here that you cannot figure out the driver the module provides until after it's loaded?
Yes, that is true. But also: 1) users may know the driver name or the module name, and usually don't know the difference between the two, or even that there are two different names. This blurring between the two has been exacerbated by modprobe always converting "-" into "_", so someone using "vfio-pci" will still automatically get the proper module loaded (because the module just happens to be "vfio_pci"), and binding the new driver will also work properly, but if they use the module name (vfio_pci), then the module will be loaded, but the driver bind will fail. We could just log an error, but "driver 'vfio_pci' not found" is pretty uninformative, and "driver 'vfio_pci' not found - maybe try 'vfio-pci' instead" is kind of pointless - if we already know how to fix the problem, why not just fix it and continue on? (you can bet that if we don't, there will be bug reports saying "Why don't you just automatically fix this instead of just telling me exactly how to fix it?!?!?". As a matter of fact, I'd already had bugs filed because "vfio_pci" wasn't accepted "even though mlx5_vfio_pci is", which is at least part of the origin story of this patch) 2) modules.alias deals only with *module* names, while each device's driver_override file in sysfs only understands *driver* names. And even if we insist that the user specify the driver name, libvirt's own code (see patch 14/15) will be retrieving the *module* name from the modules.alias file, and there will need to be code in libvirt to convert that to driver name in order for the bind operation to be successful. I'm just fixing that in this patch in order to simplify the later patch, and also make user-specified <driver name="blah"/> more foolproof. In the end, all I'm doing is: 1) Making it more clear in libvirt's code where we are using a module name and where we are using a driver name. 1.5) explicitly performing the "dash to underscore" transformation to derive a modulename from the user-provided "driver-module name", but only because we need to follow links in sysfs, and those links *don't* benefit from modprobe's automatic replacement of dash with underscore (i.e. even though we can assume that modprobe will always replace dash with underscore, modprobe isn't the only place that we need the underscore version of the name) 2) following links in sysfs to derive a driver name from a module name, rather than making the *incorrect* assumption that we can get that with dashed(modulename) (which already doesn't work, e.g. for mlx5_vfio_pci/mlx5_vfio_pci) (with current functionality this just automatically fixes a common user error, but beginning with patch 14/15 it will actually be essential to proper functioning of variant driver auto-detect) There is really nothing controversial going on here. Maybe I just spent so much time explaining that everyone *thinks* there must be something fishy.
Jano
2) if underscored(${driverName}) (call it ${underName} for short) is in sysfs drivers list then use ${underName} - DONE
3) if ${underName} *isn't* in the sysfs modules list (/sys/module/${underName}) then "modprobe ${underName}" to load it.
4) look for the PCI driver implemented by this module, it will be at /sys/module/${underName}/driver/pci:${newName}.
5) use ${newName} - DONE.
A few notes:
a) This will *always* replace dash with underscore in the name used to load the module, which seems it could be problematic, but I have verified this is what modprobe itself does, so I don't think there will ever be a module with "-" in its name as modprobe would be unable to load it (the same can't be said for drivers though!)
b) The one case where the above steps wouldn't work would be if someone implemented a driver within a module where the driver and module had names that differed other than dash vs. underscore. I haven't seen an example of this, so the convention seems to be that they will "match" (modulo - & _). If this mismatch were to ever occur, though, it could be worked around by simply loading the module out-of-band during the host system startup, and then using the driver's name in the config.
c) All of this is conveniently ignoring the possibility of a VFIO variant driver that is statically linked in the kernel. The entire design of variant driver auto-detection is based on doing a lookup in modules.alias, and that only lists *loadable modules* (not drivers), so unless I'm missing something, it would be impossible to auto-detect a VFIO variant driver that was statically linked. This is beyond libvirt's ability to fix; the best that could be done would be to manually specify the driver name in the libvirt config, which I suppose is better than nothing :-)
Signed-off-by: Laine Stump <laine@redhat.com> --- src/util/virpci.c | 194 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 164 insertions(+), 30 deletions(-)
_______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org

The exact same element can appear in <hostdev> and <interface type='hostdev'>, and nearly identical in <network> and <networkport> (these latter two don't include "xen" as a possible driver, but that's coincidental - there's no reason Xen couldn't also use the VF pools in virtual networks, it just doesn't). This patch modifies all 4 to use the same <ref name="hostdevDriver"/> so that it is simpler to add something new. A side effect of this patch is that the grammar for the <interface> element in domain XML has been tightened up a bit - previously it was accepted by the schema (but nonsensical) to have virtio and network interface options specified; as a part of making the two different <driver> choices each a complete element (rather than each being a collection of attributes and subelements) these extra attributes/subelements that were irrelevant to the hostdev-type <driver> were made to be valid only for an emulated interface's <driver>. Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/schemas/basictypes.rng | 13 +++ src/conf/schemas/domaincommon.rng | 173 ++++++++++++++---------------- src/conf/schemas/network.rng | 10 +- src/conf/schemas/networkport.rng | 10 +- 4 files changed, 94 insertions(+), 112 deletions(-) diff --git a/src/conf/schemas/basictypes.rng b/src/conf/schemas/basictypes.rng index 26eb538077..8d5f4475ca 100644 --- a/src/conf/schemas/basictypes.rng +++ b/src/conf/schemas/basictypes.rng @@ -656,4 +656,17 @@ </choice> </define> + <define name="hostdevDriver"> + <element name="driver"> + <attribute name="name"> + <choice> + <value>kvm</value> + <value>vfio</value> + <value>xen</value> + </choice> + </attribute> + <empty/> + </element> + </define> + </grammar> diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index a26986b5ce..002587db58 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -3759,18 +3759,12 @@ </element> </optional> <optional> - <element name="driver"> - <choice> - <group> - <attribute name="name"> - <choice> - <value>kvm</value> - <value>vfio</value> - <value>xen</value> - </choice> - </attribute> - </group> - <group> + <choice> + <group> + <ref name="hostdevDriver"/> + </group> + <group> + <element name="driver"> <optional> <attribute name="name"> <choice> @@ -3808,90 +3802,90 @@ <optional> <ref name="event_idx"/> </optional> - </group> - </choice> - <ref name="virtioOptions"/> - <interleave> - <optional> - <element name="host"> - <optional> - <attribute name="csum"> - <ref name="virOnOff"/> - </attribute> - </optional> - <optional> - <attribute name="gso"> - <ref name="virOnOff"/> - </attribute> - </optional> - <optional> - <attribute name="tso4"> - <ref name="virOnOff"/> - </attribute> - </optional> - <optional> - <attribute name="tso6"> - <ref name="virOnOff"/> - </attribute> - </optional> - <optional> - <attribute name="ecn"> - <ref name="virOnOff"/> - </attribute> - </optional> - <optional> - <attribute name="ufo"> - <ref name="virOnOff"/> - </attribute> - </optional> - <optional> - <attribute name="mrg_rxbuf"> - <ref name="virOnOff"/> - </attribute> - </optional> - </element> - </optional> - <optional> - <element name="guest"> - <optional> - <attribute name="csum"> - <ref name="virOnOff"/> - </attribute> - </optional> + <ref name="virtioOptions"/> + <interleave> <optional> - <attribute name="tso4"> - <ref name="virOnOff"/> - </attribute> + <element name="host"> + <optional> + <attribute name="csum"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="gso"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="tso4"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="tso6"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="ecn"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="ufo"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="mrg_rxbuf"> + <ref name="virOnOff"/> + </attribute> + </optional> + </element> </optional> <optional> - <attribute name="tso6"> - <ref name="virOnOff"/> - </attribute> + <element name="guest"> + <optional> + <attribute name="csum"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="tso4"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="tso6"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="ecn"> + <ref name="virOnOff"/> + </attribute> + </optional> + <optional> + <attribute name="ufo"> + <ref name="virOnOff"/> + </attribute> + </optional> + </element> </optional> <optional> - <attribute name="ecn"> + <attribute name="rss"> <ref name="virOnOff"/> </attribute> </optional> <optional> - <attribute name="ufo"> + <attribute name="rss_hash_report"> <ref name="virOnOff"/> </attribute> </optional> - </element> - </optional> - <optional> - <attribute name="rss"> - <ref name="virOnOff"/> - </attribute> - </optional> - <optional> - <attribute name="rss_hash_report"> - <ref name="virOnOff"/> - </attribute> - </optional> - </interleave> - </element> + </interleave> + </element> + </group> + </choice> </optional> <optional> <ref name="alias"/> @@ -6182,16 +6176,7 @@ </attribute> <interleave> <optional> - <element name="driver"> - <attribute name="name"> - <choice> - <value>kvm</value> - <value>vfio</value> - <value>xen</value> - </choice> - </attribute> - <empty/> - </element> + <ref name="hostdevDriver"/> </optional> <optional> <ref name="teaming"/> diff --git a/src/conf/schemas/network.rng b/src/conf/schemas/network.rng index cda174ab4b..e56e07d130 100644 --- a/src/conf/schemas/network.rng +++ b/src/conf/schemas/network.rng @@ -179,15 +179,7 @@ </element> </optional> <optional> - <element name="driver"> - <attribute name="name"> - <choice> - <value>kvm</value> - <value>vfio</value> - </choice> - </attribute> - <empty/> - </element> + <ref name="hostdevDriver"/> </optional> <optional> <element name="nat"> diff --git a/src/conf/schemas/networkport.rng b/src/conf/schemas/networkport.rng index 14db949578..50995559e8 100644 --- a/src/conf/schemas/networkport.rng +++ b/src/conf/schemas/networkport.rng @@ -145,15 +145,7 @@ </optional> <interleave> <optional> - <element name="driver"> - <attribute name="name"> - <choice> - <value>kvm</value> - <value>vfio</value> - </choice> - </attribute> - <empty/> - </element> + <ref name="hostdevDriver"/> </optional> <element name="address"> <ref name="pciaddress"/> -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:47 -0500, Laine Stump wrote:
The exact same element can appear in <hostdev> and <interface type='hostdev'>, and nearly identical in <network> and <networkport> (these latter two don't include "xen" as a possible driver, but that's coincidental - there's no reason Xen couldn't also use the VF pools in virtual networks, it just doesn't).
This patch modifies all 4 to use the same <ref name="hostdevDriver"/> so that it is simpler to add something new.
A side effect of this patch is that the grammar for the <interface> element in domain XML has been tightened up a bit - previously it was accepted by the schema (but nonsensical) to have virtio and network interface options specified; as a part of making the two different <driver> choices each a complete element (rather than each being a collection of attributes and subelements) these extra attributes/subelements that were irrelevant to the hostdev-type <driver> were made to be valid only for an emulated interface's <driver>.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/schemas/basictypes.rng | 13 +++ src/conf/schemas/domaincommon.rng | 173 ++++++++++++++---------------- src/conf/schemas/network.rng | 10 +- src/conf/schemas/networkport.rng | 10 +- 4 files changed, 94 insertions(+), 112 deletions(-)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

Currently this enum is defined in domain_conf.h and named virDomainHostdevSubsysPCIDriverType. I want to use it in parts of the network and networkport config, so am moving its definition to device_conf.h which is / can be included by all interested parties, and renaming it to be less specific to its old usage (all the other parts still apply, at least functionally, to the new usage). The name change (which includes enum values) does cause a lot of churn, but it's all mechanical. Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/device_conf.c | 9 +++++++++ src/conf/device_conf.h | 12 +++++++++++ src/conf/domain_capabilities.c | 2 +- src/conf/domain_capabilities.h | 2 +- src/conf/domain_conf.c | 34 +++++++++++++------------------- src/conf/domain_conf.h | 14 +------------ src/hypervisor/virhostdev.c | 8 ++++---- src/libvirt_private.syms | 2 +- src/libxl/libxl_capabilities.c | 2 +- src/libxl/libxl_domain.c | 6 +++--- src/libxl/libxl_driver.c | 4 ++-- src/qemu/qemu_capabilities.c | 4 ++-- src/qemu/qemu_command.c | 12 +++++------ src/qemu/qemu_domain.c | 23 ++++++++++----------- src/qemu/qemu_validate.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 4 ++-- src/security/security_selinux.c | 4 ++-- src/security/virt-aa-helper.c | 8 +++++--- tests/domaincapstest.c | 4 ++-- tests/virhostdevtest.c | 2 +- tools/virsh-completer-nodedev.c | 4 ++-- 22 files changed, 85 insertions(+), 79 deletions(-) diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index f3d977f2b7..25a522671e 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -29,6 +29,15 @@ #define VIR_FROM_THIS VIR_FROM_DEVICE +VIR_ENUM_IMPL(virDeviceHostdevPCIDriver, + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST, + "default", + "kvm", + "vfio", + "xen", +); + + VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, "none", diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index a83377417a..7513beb5e1 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -31,6 +31,18 @@ #include "virnetdev.h" #include "virenum.h" +/* the backend driver used for PCI hostdev devices */ +typedef enum { + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT = 0, /* detect automatically, prefer VFIO */ + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM, /* force legacy kvm style */ + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO, /* force vfio */ + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN, /* force legacy xen style, use pciback */ + + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST +} virDeviceHostdevPCIDriverType; + +VIR_ENUM_DECL(virDeviceHostdevPCIDriver); + typedef enum { VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE = 0, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI, diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index f6e09dc584..6c1ccb2370 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -524,7 +524,7 @@ virDomainCapsDeviceHostdevFormat(virBuffer *buf, ENUM_PROCESS(hostdev, startupPolicy, virDomainStartupPolicyTypeToString); ENUM_PROCESS(hostdev, subsysType, virDomainHostdevSubsysTypeToString); ENUM_PROCESS(hostdev, capsType, virDomainHostdevCapsTypeToString); - ENUM_PROCESS(hostdev, pciBackend, virDomainHostdevSubsysPCIBackendTypeToString); + ENUM_PROCESS(hostdev, pciBackend, virDeviceHostdevPCIDriverTypeToString); FORMAT_EPILOGUE(hostdev); } diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 01bcfa2e39..25d3672b18 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -99,7 +99,7 @@ STATIC_ASSERT_ENUM(VIR_DOMAIN_HOSTDEV_MODE_LAST); STATIC_ASSERT_ENUM(VIR_DOMAIN_STARTUP_POLICY_LAST); STATIC_ASSERT_ENUM(VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST); STATIC_ASSERT_ENUM(VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST); -STATIC_ASSERT_ENUM(VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST); +STATIC_ASSERT_ENUM(VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST); typedef struct _virDomainCapsDeviceHostdev virDomainCapsDeviceHostdev; struct _virDomainCapsDeviceHostdev { virTristateBool supported; diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index fa97def9f7..4a3de08efa 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1053,13 +1053,6 @@ VIR_ENUM_IMPL(virDomainHostdevSubsys, "mdev", ); -VIR_ENUM_IMPL(virDomainHostdevSubsysPCIBackend, - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST, - "default", - "kvm", - "vfio", - "xen", -); VIR_ENUM_IMPL(virDomainHostdevSubsysSCSIProtocol, VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_LAST, @@ -6276,7 +6269,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, driver_node = virXPathNode("./driver", ctxt); if (virXMLPropEnum(driver_node, "name", - virDomainHostdevSubsysPCIBackendTypeFromString, + virDeviceHostdevPCIDriverTypeFromString, VIR_XML_PROP_NONZERO, &pcisrc->backend) < 0) return -1; @@ -23342,8 +23335,9 @@ virDomainHostdevDefFormatSubsysPCI(virBuffer *buf, virBufferAsprintf(&sourceAttrBuf, " writeFiltering='%s'", virTristateBoolTypeToString(def->writeFiltering)); - if (pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) { - const char *backend = virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend); + if (pcisrc->backend != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { + const char *backend + = virDeviceHostdevPCIDriverTypeToString(pcisrc->backend); if (!backend) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -29841,17 +29835,17 @@ virDomainNetDefActualFromNetworkPort(virDomainNetDef *iface, switch ((virNetworkForwardDriverNameType)port->plug.hostdevpci.driver) { case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT: actual->data.hostdev.def.source.subsys.u.pci.backend = - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT; + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT; break; case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM: actual->data.hostdev.def.source.subsys.u.pci.backend = - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM; + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM; break; case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO: actual->data.hostdev.def.source.subsys.u.pci.backend = - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO; + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; break; case VIR_NETWORK_FORWARD_DRIVER_NAME_LAST: @@ -29962,26 +29956,26 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, port->plug.hostdevpci.managed = virTristateBoolFromBool(actual->data.hostdev.def.managed); port->plug.hostdevpci.addr = actual->data.hostdev.def.source.subsys.u.pci.addr; switch (actual->data.hostdev.def.source.subsys.u.pci.backend) { - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT: port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT; break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM: port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_KVM; break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO: port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO; break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Unexpected PCI backend 'xen'")); break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST: default: - virReportEnumRangeError(virDomainHostdevSubsysPCIBackendType, + virReportEnumRangeError(virDeviceHostdevPCIDriverType, actual->data.hostdev.def.source.subsys.u.pci.backend); return NULL; } @@ -30926,7 +30920,7 @@ virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev) { return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO; + hostdev->source.subsys.u.pci.backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7c0e017038..57e06dd935 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -201,18 +201,6 @@ typedef enum { VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST } virDomainHostdevSubsysType; -/* the backend driver used for PCI hostdev devices */ -typedef enum { - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT = 0, /* detect automatically, prefer VFIO */ - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM, /* force legacy kvm style */ - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO, /* force vfio */ - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN, /* force legacy xen style, use pciback */ - - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST -} virDomainHostdevSubsysPCIBackendType; - -VIR_ENUM_DECL(virDomainHostdevSubsysPCIBackend); - typedef enum { VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_NONE, VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI, @@ -247,7 +235,7 @@ struct _virDomainHostdevSubsysUSB { struct _virDomainHostdevSubsysPCI { virPCIDeviceAddress addr; /* host address */ - virDomainHostdevSubsysPCIBackendType backend; + virDeviceHostdevPCIDriverType backend; virBitmap *origstates; }; diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c index 4672bd8785..ce7189ffcd 100644 --- a/src/hypervisor/virhostdev.c +++ b/src/hypervisor/virhostdev.c @@ -243,14 +243,14 @@ virHostdevGetPCIHostDevice(const virDomainHostdevDef *hostdev, virPCIDeviceSetManaged(actual, hostdev->managed); - if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { virPCIDeviceSetStubDriverType(actual, VIR_PCI_STUB_DRIVER_VFIO); - } else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN) { + } else if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN) { virPCIDeviceSetStubDriverType(actual, VIR_PCI_STUB_DRIVER_XEN); } else { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("pci backend driver '%1$s' is not supported"), - virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend)); + _("pci backend driver type '%1$s' is not supported"), + virDeviceHostdevPCIDriverTypeToString(pcisrc->backend)); return -1; } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 553b01b8c0..479a69ed0b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -126,6 +126,7 @@ virCPUModeTypeToString; # conf/device_conf.h virCCWDeviceAddressParseXML; +virDeviceHostdevPCIDriverTypeToString; virDeviceInfoPCIAddressExtensionIsPresent; virDeviceInfoPCIAddressExtensionIsWanted; virDeviceInfoPCIAddressIsPresent; @@ -467,7 +468,6 @@ virDomainHostdevInsert; virDomainHostdevMatch; virDomainHostdevModeTypeToString; virDomainHostdevRemove; -virDomainHostdevSubsysPCIBackendTypeToString; virDomainHostdevSubsysSCSIVHostModelTypeFromString; virDomainHostdevSubsysSCSIVHostModelTypeToString; virDomainHostdevSubsysTypeToString; diff --git a/src/libxl/libxl_capabilities.c b/src/libxl/libxl_capabilities.c index 177e8b988e..28330c4d36 100644 --- a/src/libxl/libxl_capabilities.c +++ b/src/libxl/libxl_capabilities.c @@ -631,7 +631,7 @@ libxlMakeDomainDeviceHostdevCaps(virDomainCapsDeviceHostdev *dev) virDomainCapsEnumClear(&dev->pciBackend); VIR_DOMAIN_CAPS_ENUM_SET(dev->pciBackend, - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN); + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN); return 0; } diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 0c4beffd6a..904f40914c 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -160,8 +160,8 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev, if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) - pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN; + pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) + pcisrc->backend = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; } if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) { @@ -997,7 +997,7 @@ libxlNetworkPrepareDevices(virDomainDef *def) if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN; + pcisrc->backend = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; if (virDomainHostdevInsert(def, hostdev) < 0) return -1; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index c98d2d737a..d04ec7f6ea 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3398,12 +3398,12 @@ libxlDomainAttachNetDevice(libxlDriverPrivate *driver, virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; /* For those just allocated from a network pool whose backend is - * still VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, we need to set + * still VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT, we need to set * backend correctly. */ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN; + pcisrc->backend = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; /* This is really a "smart hostdev", so it should be attached * as a hostdev (the hostdev code will reach over into the diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 83119e871a..a5e2681ea1 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -6352,8 +6352,8 @@ virQEMUCapsFillDomainDeviceHostdevCaps(virQEMUCaps *qemuCaps, if (supportsPassthroughVFIO && virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) { VIR_DOMAIN_CAPS_ENUM_SET(hostdev->pciBackend, - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO); + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT, + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO); } } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2674dd6959..3bcd0d3aa8 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4712,16 +4712,16 @@ qemuBuildPCIHostdevDevProps(const virDomainDef *def, /* caller has to assign proper passthrough backend type */ switch (pcisrc->backend) { - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO: break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM: - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT: - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN: - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST: virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid PCI passthrough type '%1$s'"), - virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend)); + virDeviceHostdevPCIDriverTypeToString(pcisrc->backend)); return NULL; } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index ae19ce884b..cf95b2cce3 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -10568,7 +10568,7 @@ qemuDomainGetHostdevPath(virDomainHostdevDef *dev, case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: - if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { if (!(tmpPath = virPCIDeviceAddressGetIOMMUGroupDev(&pcisrc->addr))) return -1; @@ -11332,14 +11332,15 @@ qemuDomainPrepareHostdevPCI(virDomainHostdevDef *hostdev, virQEMUCaps *qemuCaps) { bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO(); - virDomainHostdevSubsysPCIBackendType *backend = &hostdev->source.subsys.u.pci.backend; + virDeviceHostdevPCIDriverType *driverType + = &hostdev->source.subsys.u.pci.backend; /* assign defaults for hostdev passthrough */ - switch (*backend) { - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT: + switch (*driverType) { + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT: if (supportsPassthroughVFIO) { if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) { - *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO; + *driverType = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; } else { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("VFIO PCI device assignment is not supported by this version of QEMU")); @@ -11352,7 +11353,7 @@ qemuDomainPrepareHostdevPCI(virDomainHostdevDef *hostdev, } break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO: if (!supportsPassthroughVFIO) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("host doesn't support VFIO PCI passthrough")); @@ -11360,20 +11361,20 @@ qemuDomainPrepareHostdevPCI(virDomainHostdevDef *hostdev, } break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("host doesn't support legacy PCI passthrough")); return false; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN: + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("QEMU does not support device assignment mode '%1$s'"), - virDomainHostdevSubsysPCIBackendTypeToString(*backend)); + virDeviceHostdevPCIDriverTypeToString(*driverType)); return false; default: - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST: - virReportEnumRangeError(virDomainHostdevSubsysPCIBackendType, *backend); + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST: + virReportEnumRangeError(virDeviceHostdevPCIDriverType, *driverType); break; } diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 93df9e4c8e..83365f6685 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -2464,7 +2464,7 @@ qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev, case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: backend = hostdev->source.subsys.u.pci.backend; - if (backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("VFIO PCI device assignment is not supported by this version of qemu")); diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 6fd0aedacf..515d68ec6b 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -869,7 +869,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, if (!pci) goto done; - if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) { diff --git a/src/security/security_dac.c b/src/security/security_dac.c index c07e488db7..ff28e17136 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -1257,7 +1257,7 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, if (!pci) return -1; - if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) @@ -1418,7 +1418,7 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, if (!pci) return -1; - if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 84c5ce75ed..89ceaf48d7 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -2201,7 +2201,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, if (!pci) return -1; - if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) @@ -2437,7 +2437,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, if (!pci) return -1; - if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index be13979cef..ac4225a783 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -1092,9 +1092,11 @@ get_files(vahControl * ctl) case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: { virPCIDevice *pci = virPCIDeviceNew(&dev->source.subsys.u.pci.addr); - virDomainHostdevSubsysPCIBackendType backend = dev->source.subsys.u.pci.backend; - if (backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO || - backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) { + virDeviceHostdevPCIDriverType driverType + = dev->source.subsys.u.pci.backend; + + if (driverType == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO || + driverType == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { needsVfio = true; } diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index c4a4508430..3d86bdb9c7 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -109,8 +109,8 @@ fillQemuCaps(virDomainCaps *domCaps, * successfully mocked as they are not exposed as internal APIs. Therefore, * instead of mocking set the expected values here by hand. */ VIR_DOMAIN_CAPS_ENUM_SET(domCaps->hostdev.pciBackend, - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO); + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT, + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO); /* As of f05b6a918e28 we are expecting to see OVMF_CODE.fd file which * may not exists everywhere. */ diff --git a/tests/virhostdevtest.c b/tests/virhostdevtest.c index 04e6c00908..d9ff992e91 100644 --- a/tests/virhostdevtest.c +++ b/tests/virhostdevtest.c @@ -134,7 +134,7 @@ myInit(void) subsys->u.pci.addr.bus = 0; subsys->u.pci.addr.slot = i + 1; subsys->u.pci.addr.function = 0; - subsys->u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO; + subsys->u.pci.backend = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; } for (i = 0; i < nhostdevs; i++) { diff --git a/tools/virsh-completer-nodedev.c b/tools/virsh-completer-nodedev.c index d743df460e..1518395a1e 100644 --- a/tools/virsh-completer-nodedev.c +++ b/tools/virsh-completer-nodedev.c @@ -110,6 +110,6 @@ virshNodeDevicePCIBackendCompleter(vshControl *ctl G_GNUC_UNUSED, { virCheckFlags(0, NULL); - return virshEnumComplete(VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST, - virDomainHostdevSubsysPCIBackendTypeToString); + return virshEnumComplete(VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST, + virDeviceHostdevPCIDriverTypeToString); } -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:48 -0500, Laine Stump wrote:
Currently this enum is defined in domain_conf.h and named virDomainHostdevSubsysPCIDriverType. I want to use it in parts of the network and networkport config, so am moving its definition to device_conf.h which is / can be included by all interested parties, and renaming it to be less specific to its old usage (all the other parts still apply, at least functionally, to the new usage). The name change (which includes enum values) does cause a lot of churn, but it's all mechanical.
Signed-off-by: Laine Stump <laine@redhat.com> ---
[...]
@@ -23342,8 +23335,9 @@ virDomainHostdevDefFormatSubsysPCI(virBuffer *buf, virBufferAsprintf(&sourceAttrBuf, " writeFiltering='%s'", virTristateBoolTypeToString(def->writeFiltering));
- if (pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) { - const char *backend = virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend); + if (pcisrc->backend != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { + const char *backend + = virDeviceHostdevPCIDriverTypeToString(pcisrc->backend);
Please no pointless linebreaks. The times of max 80 colums are gone.
if (!backend) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -29841,17 +29835,17 @@ virDomainNetDefActualFromNetworkPort(virDomainNetDef *iface, switch ((virNetworkForwardDriverNameType)port->plug.hostdevpci.driver) { case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT: actual->data.hostdev.def.source.subsys.u.pci.backend = - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT; + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT; break;
case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM: actual->data.hostdev.def.source.subsys.u.pci.backend = - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM; + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM; break;
case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO: actual->data.hostdev.def.source.subsys.u.pci.backend = - VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO; + VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; break;
I'd argue that the above is in the same category now that you are changing it. [...]
@@ -11332,14 +11332,15 @@ qemuDomainPrepareHostdevPCI(virDomainHostdevDef *hostdev, virQEMUCaps *qemuCaps) { bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO(); - virDomainHostdevSubsysPCIBackendType *backend = &hostdev->source.subsys.u.pci.backend; + virDeviceHostdevPCIDriverType *driverType + = &hostdev->source.subsys.u.pci.backend;
Same.
/* assign defaults for hostdev passthrough */ - switch (*backend) { - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT: + switch (*driverType) { + case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT: if (supportsPassthroughVFIO) { if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) { - *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO; + *driverType = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; } else { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("VFIO PCI device assignment is not supported by this version of QEMU"));
[...]
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index be13979cef..ac4225a783 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -1092,9 +1092,11 @@ get_files(vahControl * ctl) case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: { virPCIDevice *pci = virPCIDeviceNew(&dev->source.subsys.u.pci.addr);
- virDomainHostdevSubsysPCIBackendType backend = dev->source.subsys.u.pci.backend; - if (backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO || - backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) { + virDeviceHostdevPCIDriverType driverType + = dev->source.subsys.u.pci.backend;
ditto
+ + if (driverType == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO || + driverType == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { needsVfio = true; }
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

On 11/27/23 9:41 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:38:48 -0500, Laine Stump wrote:
Currently this enum is defined in domain_conf.h and named virDomainHostdevSubsysPCIDriverType. I want to use it in parts of the network and networkport config, so am moving its definition to device_conf.h which is / can be included by all interested parties, and renaming it to be less specific to its old usage (all the other parts still apply, at least functionally, to the new usage). The name change (which includes enum values) does cause a lot of churn, but it's all mechanical.
Signed-off-by: Laine Stump <laine@redhat.com> ---
[...]
@@ -23342,8 +23335,9 @@ virDomainHostdevDefFormatSubsysPCI(virBuffer *buf, virBufferAsprintf(&sourceAttrBuf, " writeFiltering='%s'", virTristateBoolTypeToString(def->writeFiltering));
- if (pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) { - const char *backend = virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend); + if (pcisrc->backend != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { + const char *backend + = virDeviceHostdevPCIDriverTypeToString(pcisrc->backend);
Please no pointless linebreaks. The times of max 80 colums are gone.
But what about this onion on my belt? Old habits die hard, but I'll fix all of these. Are you okay with the currently listed 100 character limit? Or do you think there should be *no* line length limit?

On Fri, Dec 08, 2023 at 13:32:31 -0500, Laine Stump wrote:
On 11/27/23 9:41 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:38:48 -0500, Laine Stump wrote:
Currently this enum is defined in domain_conf.h and named virDomainHostdevSubsysPCIDriverType. I want to use it in parts of the network and networkport config, so am moving its definition to device_conf.h which is / can be included by all interested parties, and renaming it to be less specific to its old usage (all the other parts still apply, at least functionally, to the new usage). The name change (which includes enum values) does cause a lot of churn, but it's all mechanical.
Signed-off-by: Laine Stump <laine@redhat.com> ---
[...]
@@ -23342,8 +23335,9 @@ virDomainHostdevDefFormatSubsysPCI(virBuffer *buf, virBufferAsprintf(&sourceAttrBuf, " writeFiltering='%s'", virTristateBoolTypeToString(def->writeFiltering)); - if (pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) { - const char *backend = virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend); + if (pcisrc->backend != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { + const char *backend + = virDeviceHostdevPCIDriverTypeToString(pcisrc->backend);
Please no pointless linebreaks. The times of max 80 colums are gone.
But what about this onion on my belt?
Old habits die hard, but I'll fix all of these. Are you okay with the currently listed 100 character limit? Or do you think there should be *no* line length limit?
Having a specific number leads to stuff like this. I'd prefer we stay at just stating that lines should be reasonably long without breaking coding style while maintaining readability. Once the line gets ridiculously long it's usually obvious to many that it's not a good idea.

The hostdev version of the <driver> subelement appears in four places: * The domain XML in the <hostdev> and <interface type='hostdev'> elements (that's 2) * The network XML inside <forward> when the network is a pool of SRIOV VFs * the <networkport> XML, which is used to communicate between the hypervisor driver and network driver. In order to make the pending addition of a new attribute to <driver> in all these cases simpler, this patch refactors the parsing of <driver> in all four places to use virXMLProp*() and virXMLFormatElement(). Making all of the different instances of the separate parse/format for <driver> look nearly identical will make it easier to see that the upcoming patch that converges all four to use a common parser/formatter is a functional NOP. Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/domain_conf.c | 28 ++++++++++++++++------------ src/conf/network_conf.c | 26 ++++++++++++-------------- src/conf/network_conf.h | 2 +- src/conf/virnetworkportdef.c | 28 ++++++++++++++++++---------- src/conf/virnetworkportdef.h | 2 +- 5 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4a3de08efa..1d3e46604a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -6267,13 +6267,14 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, if (virDomainHostdevSubsysPCIDefParseXML(sourcenode, ctxt, def, flags) < 0) return -1; - driver_node = virXPathNode("./driver", ctxt); - if (virXMLPropEnum(driver_node, "name", - virDeviceHostdevPCIDriverTypeFromString, - VIR_XML_PROP_NONZERO, - &pcisrc->backend) < 0) - return -1; - + if ((driver_node = virXPathNode("./driver", ctxt))) { + if (virXMLPropEnum(driver_node, "name", + virDeviceHostdevPCIDriverTypeFromString, + VIR_XML_PROP_NONZERO, + &pcisrc->backend) < 0) { + return -1; + } + } break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: @@ -23327,14 +23328,11 @@ virDomainHostdevDefFormatSubsysPCI(virBuffer *buf, unsigned int flags, bool includeTypeInAddr) { + g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) sourceAttrBuf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) sourceChildBuf = VIR_BUFFER_INIT_CHILD(buf); virDomainHostdevSubsysPCI *pcisrc = &def->source.subsys.u.pci; - if (def->writeFiltering != VIR_TRISTATE_BOOL_ABSENT) - virBufferAsprintf(&sourceAttrBuf, " writeFiltering='%s'", - virTristateBoolTypeToString(def->writeFiltering)); - if (pcisrc->backend != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { const char *backend = virDeviceHostdevPCIDriverTypeToString(pcisrc->backend); @@ -23346,9 +23344,15 @@ virDomainHostdevDefFormatSubsysPCI(virBuffer *buf, return -1; } - virBufferAsprintf(buf, "<driver name='%s'/>\n", backend); + virBufferAsprintf(&driverAttrBuf, " name='%s'", backend); } + virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); + + if (def->writeFiltering != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(&sourceAttrBuf, " writeFiltering='%s'", + virTristateBoolTypeToString(def->writeFiltering)); + virPCIDeviceAddressFormat(&sourceChildBuf, pcisrc->addr, includeTypeInAddr); if (pcisrc->origstates && diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 1a6fd86180..b9601cb307 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1334,8 +1334,8 @@ virNetworkForwardDefParseXML(const char *networkName, g_autofree xmlNodePtr *forwardNatNodes = NULL; g_autofree char *forwardDev = NULL; g_autofree char *forwardManaged = NULL; - g_autofree char *forwardDriverName = NULL; g_autofree char *type = NULL; + xmlNodePtr driverNode = NULL; VIR_XPATH_NODE_AUTORESTORE(ctxt) ctxt->node = node; @@ -1356,18 +1356,13 @@ virNetworkForwardDefParseXML(const char *networkName, def->managed = true; } - forwardDriverName = virXPathString("string(./driver/@name)", ctxt); - if (forwardDriverName) { - int driverName - = virNetworkForwardDriverNameTypeFromString(forwardDriverName); - - if (driverName <= 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unknown forward <driver name='%1$s'/> in network %2$s"), - forwardDriverName, networkName); + if ((driverNode = virXPathNode("./driver", ctxt))) { + if (virXMLPropEnum(driverNode, "name", + virNetworkForwardDriverNameTypeFromString, + VIR_XML_PROP_NONZERO, + &def->driverName) < 0) { return -1; } - def->driverName = driverName; } /* bridge and hostdev modes can use a pool of physical interfaces */ @@ -2331,6 +2326,7 @@ virNetworkDefFormatBuf(virBuffer *buf, if (def->forward.type != VIR_NETWORK_FORWARD_NONE) { const char *dev = NULL; const char *mode = virNetworkForwardTypeToString(def->forward.type); + g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; if (!def->forward.npfs) dev = virNetworkDefForwardIf(def, 0); @@ -2361,8 +2357,7 @@ virNetworkDefFormatBuf(virBuffer *buf, virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : ""); virBufferAdjustIndent(buf, 2); - if (def->forward.driverName - != VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT) { + if (def->forward.driverName) { const char *driverName = virNetworkForwardDriverNameTypeToString(def->forward.driverName); if (!driverName) { @@ -2371,8 +2366,11 @@ virNetworkDefFormatBuf(virBuffer *buf, def->forward.driverName); return -1; } - virBufferAsprintf(buf, "<driver name='%s'/>\n", driverName); + virBufferAsprintf(&driverAttrBuf, " name='%s'", driverName); } + + virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); + if (def->forward.type == VIR_NETWORK_FORWARD_NAT) { if (virNetworkForwardNatDefFormat(buf, &def->forward) < 0) return -1; diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 5a1bdb1284..497ae765f2 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -216,7 +216,7 @@ typedef struct _virNetworkForwardDef virNetworkForwardDef; struct _virNetworkForwardDef { int type; /* One of virNetworkForwardType constants */ bool managed; /* managed attribute for hostdev mode */ - int driverName; /* enum virNetworkForwardDriverNameType */ + virNetworkForwardDriverNameType driverName; /* If there are multiple forward devices (i.e. a pool of * interfaces), they will be listed here. diff --git a/src/conf/virnetworkportdef.c b/src/conf/virnetworkportdef.c index fc06ef41d5..402c0051ec 100644 --- a/src/conf/virnetworkportdef.c +++ b/src/conf/virnetworkportdef.c @@ -87,10 +87,10 @@ virNetworkPortDefParseXML(xmlXPathContextPtr ctxt) xmlNodePtr addressNode; xmlNodePtr rxfiltersNode = NULL; xmlNodePtr plugNode = NULL; + xmlNodePtr driverNode = NULL; g_autofree char *mac = NULL; g_autofree char *macmgr = NULL; g_autofree char *mode = NULL; - g_autofree char *driver = NULL; def = g_new0(virNetworkPortDef, 1); @@ -223,14 +223,16 @@ virNetworkPortDefParseXML(xmlXPathContextPtr ctxt) VIR_XML_PROP_NONE, &def->plug.hostdevpci.managed) < 0) return NULL; - driver = virXPathString("string(./plug/driver/@name)", ctxt); - if (driver && - (def->plug.hostdevpci.driver = - virNetworkForwardDriverNameTypeFromString(driver)) <= 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("Missing network port driver name")); - return NULL; + + if ((driverNode = virXPathNode("./plug/driver", ctxt))) { + if (virXMLPropEnum(driverNode, "name", + virNetworkForwardDriverNameTypeFromString, + VIR_XML_PROP_NONZERO, + &def->plug.hostdevpci.driver) < 0) { + return NULL; + } } + if (!(addressNode = virXPathNode("./plug/address", ctxt))) { virReportError(VIR_ERR_XML_ERROR, "%s", _("Missing network port PCI address")); @@ -319,6 +321,8 @@ virNetworkPortDefFormatBuf(virBuffer *buf, virTristateBoolTypeToString(def->trustGuestRxFilters)); if (def->plugtype != VIR_NETWORK_PORT_PLUG_TYPE_NONE) { + g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; + virBufferAsprintf(buf, "<plug type='%s'", virNetworkPortPlugTypeToString(def->plugtype)); @@ -351,10 +355,14 @@ virNetworkPortDefFormatBuf(virBuffer *buf, } virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); - if (def->plug.hostdevpci.driver) - virBufferEscapeString(buf, "<driver name='%s'/>\n", + + if (def->plug.hostdevpci.driver) { + virBufferEscapeString(&driverAttrBuf, " name='%s'", virNetworkForwardDriverNameTypeToString( def->plug.hostdevpci.driver)); + } + + virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); virPCIDeviceAddressFormat(buf, def->plug.hostdevpci.addr, false); virBufferAdjustIndent(buf, -2); diff --git a/src/conf/virnetworkportdef.h b/src/conf/virnetworkportdef.h index 48e73dbefd..bfe1dae9ea 100644 --- a/src/conf/virnetworkportdef.h +++ b/src/conf/virnetworkportdef.h @@ -69,7 +69,7 @@ struct _virNetworkPortDef { } direct; struct { virPCIDeviceAddress addr; /* PCI Address of device */ - int driver; /* virNetworkForwardDriverNameType */ + unsigned int driver; /* virNetworkForwardDriverNameType */ virTristateBool managed; } hostdevpci; } plug; -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:49 -0500, Laine Stump wrote:
The hostdev version of the <driver> subelement appears in four places:
* The domain XML in the <hostdev> and <interface type='hostdev'> elements (that's 2)
* The network XML inside <forward> when the network is a pool of SRIOV VFs
* the <networkport> XML, which is used to communicate between the hypervisor driver and network driver.
In order to make the pending addition of a new attribute to <driver> in all these cases simpler, this patch refactors the parsing of <driver> in all four places to use virXMLProp*() and virXMLFormatElement().
Making all of the different instances of the separate parse/format for <driver> look nearly identical will make it easier to see that the upcoming patch that converges all four to use a common parser/formatter is a functional NOP.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/domain_conf.c | 28 ++++++++++++++++------------ src/conf/network_conf.c | 26 ++++++++++++-------------- src/conf/network_conf.h | 2 +- src/conf/virnetworkportdef.c | 28 ++++++++++++++++++---------- src/conf/virnetworkportdef.h | 2 +- 5 files changed, 48 insertions(+), 38 deletions(-)
[...]
@@ -351,10 +355,14 @@ virNetworkPortDefFormatBuf(virBuffer *buf, } virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); - if (def->plug.hostdevpci.driver) - virBufferEscapeString(buf, "<driver name='%s'/>\n", + + if (def->plug.hostdevpci.driver) { + virBufferEscapeString(&driverAttrBuf, " name='%s'", virNetworkForwardDriverNameTypeToString( def->plug.hostdevpci.driver));
Please remove the linebreak;
+ } + + virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL);
virPCIDeviceAddressFormat(buf, def->plug.hostdevpci.addr, false); virBufferAdjustIndent(buf, -2); diff --git a/src/conf/virnetworkportdef.h b/src/conf/virnetworkportdef.h index 48e73dbefd..bfe1dae9ea 100644 --- a/src/conf/virnetworkportdef.h +++ b/src/conf/virnetworkportdef.h @@ -69,7 +69,7 @@ struct _virNetworkPortDef { } direct; struct { virPCIDeviceAddress addr; /* PCI Address of device */ - int driver; /* virNetworkForwardDriverNameType */ + unsigned int driver; /* virNetworkForwardDriverNameType */
Use the proper enum type here. Reviewed-by: Peter Krempa <pkrempa@redhat.com>

The new struct is virDeviceHostdevPCIDriverInfo, and the "backend" enum in the hostdevDef will be replaced with a virDeviceHostdevPCIDriverInfo named "driver'. Since the enum value in this new struct is called "type", it means that all references to "backend" will become "driver.type". This will allow easily adding other items for new attributes in the <driver> element / C struct, which will be useful once we are using this new struct in multiple places. Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/device_conf.h | 4 ++++ src/conf/domain_conf.c | 32 ++++++++++++++------------------ src/conf/domain_conf.h | 2 +- src/conf/virconftypes.h | 2 ++ src/hypervisor/virhostdev.c | 6 +++--- src/libxl/libxl_domain.c | 6 +++--- src/libxl/libxl_driver.c | 6 +++--- src/qemu/qemu_command.c | 4 ++-- src/qemu/qemu_domain.c | 4 ++-- src/qemu/qemu_validate.c | 6 +++--- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 4 ++-- src/security/security_selinux.c | 4 ++-- src/security/virt-aa-helper.c | 2 +- tests/virhostdevtest.c | 2 +- 15 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 7513beb5e1..3a7a6c3f99 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -43,6 +43,10 @@ typedef enum { VIR_ENUM_DECL(virDeviceHostdevPCIDriver); +struct _virDeviceHostdevPCIDriverInfo { + virDeviceHostdevPCIDriverType type; +}; + typedef enum { VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE = 0, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI, diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 1d3e46604a..e322f1ffa7 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -6271,7 +6271,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, if (virXMLPropEnum(driver_node, "name", virDeviceHostdevPCIDriverTypeFromString, VIR_XML_PROP_NONZERO, - &pcisrc->backend) < 0) { + &pcisrc->driver.type) < 0) { return -1; } } @@ -23333,18 +23333,18 @@ virDomainHostdevDefFormatSubsysPCI(virBuffer *buf, g_auto(virBuffer) sourceChildBuf = VIR_BUFFER_INIT_CHILD(buf); virDomainHostdevSubsysPCI *pcisrc = &def->source.subsys.u.pci; - if (pcisrc->backend != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { - const char *backend - = virDeviceHostdevPCIDriverTypeToString(pcisrc->backend); + if (pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { + const char *driverType + = virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type); - if (!backend) { + if (!driverType) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected pci hostdev driver name type %1$d"), - pcisrc->backend); + _("unexpected pci hostdev driver type %1$d"), + pcisrc->driver.type); return -1; } - virBufferAsprintf(&driverAttrBuf, " name='%s'", backend); + virBufferAsprintf(&driverAttrBuf, " name='%s'", driverType); } virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); @@ -29838,17 +29838,17 @@ virDomainNetDefActualFromNetworkPort(virDomainNetDef *iface, actual->data.hostdev.def.source.subsys.u.pci.addr = port->plug.hostdevpci.addr; switch ((virNetworkForwardDriverNameType)port->plug.hostdevpci.driver) { case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT: - actual->data.hostdev.def.source.subsys.u.pci.backend = + actual->data.hostdev.def.source.subsys.u.pci.driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT; break; case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM: - actual->data.hostdev.def.source.subsys.u.pci.backend = + actual->data.hostdev.def.source.subsys.u.pci.driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM; break; case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO: - actual->data.hostdev.def.source.subsys.u.pci.backend = + actual->data.hostdev.def.source.subsys.u.pci.driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; break; @@ -29959,7 +29959,7 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, } port->plug.hostdevpci.managed = virTristateBoolFromBool(actual->data.hostdev.def.managed); port->plug.hostdevpci.addr = actual->data.hostdev.def.source.subsys.u.pci.addr; - switch (actual->data.hostdev.def.source.subsys.u.pci.backend) { + switch (actual->data.hostdev.def.source.subsys.u.pci.driver.type) { case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT: port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT; break; @@ -29973,14 +29973,10 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, break; case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unexpected PCI backend 'xen'")); - break; - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST: default: virReportEnumRangeError(virDeviceHostdevPCIDriverType, - actual->data.hostdev.def.source.subsys.u.pci.backend); + actual->data.hostdev.def.source.subsys.u.pci.driver.type); return NULL; } @@ -30924,7 +30920,7 @@ virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev) { return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - hostdev->source.subsys.u.pci.backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; + hostdev->source.subsys.u.pci.driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 57e06dd935..855e09d236 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -235,7 +235,7 @@ struct _virDomainHostdevSubsysUSB { struct _virDomainHostdevSubsysPCI { virPCIDeviceAddress addr; /* host address */ - virDeviceHostdevPCIDriverType backend; + virDeviceHostdevPCIDriverInfo driver; virBitmap *origstates; }; diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index 26cb966194..0779bc224b 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -66,6 +66,8 @@ typedef struct _virCapsHostSecModelLabel virCapsHostSecModelLabel; typedef struct _virCapsStoragePool virCapsStoragePool; +typedef struct _virDeviceHostdevPCIDriverInfo virDeviceHostdevPCIDriverInfo; + typedef struct _virDomainABIStability virDomainABIStability; typedef struct _virDomainActualNetDef virDomainActualNetDef; diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c index ce7189ffcd..a33b3b604f 100644 --- a/src/hypervisor/virhostdev.c +++ b/src/hypervisor/virhostdev.c @@ -243,14 +243,14 @@ virHostdevGetPCIHostDevice(const virDomainHostdevDef *hostdev, virPCIDeviceSetManaged(actual, hostdev->managed); - if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { + if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { virPCIDeviceSetStubDriverType(actual, VIR_PCI_STUB_DRIVER_VFIO); - } else if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN) { + } else if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN) { virPCIDeviceSetStubDriverType(actual, VIR_PCI_STUB_DRIVER_XEN); } else { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("pci backend driver type '%1$s' is not supported"), - virDeviceHostdevPCIDriverTypeToString(pcisrc->backend)); + virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type)); return -1; } diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 904f40914c..22482adfa6 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -160,8 +160,8 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev, if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) - pcisrc->backend = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) + pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; } if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) { @@ -997,7 +997,7 @@ libxlNetworkPrepareDevices(virDomainDef *def) if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->backend = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; if (virDomainHostdevInsert(def, hostdev) < 0) return -1; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index d04ec7f6ea..7f12b11b8d 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3397,13 +3397,13 @@ libxlDomainAttachNetDevice(libxlDriverPrivate *driver, virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net); virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; - /* For those just allocated from a network pool whose backend is + /* For those just allocated from a network pool whose driver type is * still VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT, we need to set - * backend correctly. + * driver type correctly. */ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->backend = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; /* This is really a "smart hostdev", so it should be attached * as a hostdev (the hostdev code will reach over into the diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 3bcd0d3aa8..5847d5549d 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4711,7 +4711,7 @@ qemuBuildPCIHostdevDevProps(const virDomainDef *def, const char *failover_pair_id = NULL; /* caller has to assign proper passthrough backend type */ - switch (pcisrc->backend) { + switch (pcisrc->driver.type) { case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO: break; @@ -4721,7 +4721,7 @@ qemuBuildPCIHostdevDevProps(const virDomainDef *def, case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST: virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid PCI passthrough type '%1$s'"), - virDeviceHostdevPCIDriverTypeToString(pcisrc->backend)); + virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type)); return NULL; } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index cf95b2cce3..09735ba710 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -10568,7 +10568,7 @@ qemuDomainGetHostdevPath(virDomainHostdevDef *dev, case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: switch (dev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: - if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { + if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { if (!(tmpPath = virPCIDeviceAddressGetIOMMUGroupDev(&pcisrc->addr))) return -1; @@ -11333,7 +11333,7 @@ qemuDomainPrepareHostdevPCI(virDomainHostdevDef *hostdev, { bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO(); virDeviceHostdevPCIDriverType *driverType - = &hostdev->source.subsys.u.pci.backend; + = &hostdev->source.subsys.u.pci.driver.type; /* assign defaults for hostdev passthrough */ switch (*driverType) { diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 83365f6685..d958d01638 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -2437,7 +2437,7 @@ qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev, const virDomainDef *def, virQEMUCaps *qemuCaps) { - int backend; + virDeviceHostdevPCIDriverType driverType; /* forbid capabilities mode hostdev in this kind of hypervisor */ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) { @@ -2462,9 +2462,9 @@ qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev, break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: - backend = hostdev->source.subsys.u.pci.backend; + driverType = hostdev->source.subsys.u.pci.driver.type; - if (backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { + if (driverType == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("VFIO PCI device assignment is not supported by this version of qemu")); diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 515d68ec6b..5ccc294773 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -869,7 +869,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManager *mgr, if (!pci) goto done; - if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { + if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) { diff --git a/src/security/security_dac.c b/src/security/security_dac.c index ff28e17136..31997474a4 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -1257,7 +1257,7 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr, if (!pci) return -1; - if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { + if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) @@ -1418,7 +1418,7 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr, if (!pci) return -1; - if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { + if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 89ceaf48d7..9a65c3a9f1 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -2201,7 +2201,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr, if (!pci) return -1; - if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { + if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) @@ -2437,7 +2437,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr, if (!pci) return -1; - if (pcisrc->backend == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { + if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO) { g_autofree char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); if (!vfioGroupDev) diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index ac4225a783..dab181de47 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -1093,7 +1093,7 @@ get_files(vahControl * ctl) virPCIDevice *pci = virPCIDeviceNew(&dev->source.subsys.u.pci.addr); virDeviceHostdevPCIDriverType driverType - = dev->source.subsys.u.pci.backend; + = dev->source.subsys.u.pci.driver.type; if (driverType == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO || driverType == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { diff --git a/tests/virhostdevtest.c b/tests/virhostdevtest.c index d9ff992e91..e375fb2833 100644 --- a/tests/virhostdevtest.c +++ b/tests/virhostdevtest.c @@ -134,7 +134,7 @@ myInit(void) subsys->u.pci.addr.bus = 0; subsys->u.pci.addr.slot = i + 1; subsys->u.pci.addr.function = 0; - subsys->u.pci.backend = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; + subsys->u.pci.driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; } for (i = 0; i < nhostdevs; i++) { -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:50 -0500, Laine Stump wrote:
The new struct is virDeviceHostdevPCIDriverInfo, and the "backend" enum in the hostdevDef will be replaced with a virDeviceHostdevPCIDriverInfo named "driver'. Since the enum value in this new struct is called "type", it means that all references to "backend" will become "driver.type".
This will allow easily adding other items for new attributes in the <driver> element / C struct, which will be useful once we are using this new struct in multiple places.
Signed-off-by: Laine Stump <laine@redhat.com> ---
[...] I will not repeat the comment about unneeded linebreaks.
@@ -29973,14 +29973,10 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, break;
case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unexpected PCI backend 'xen'")); - break; -
Falling through to virReportEnumRangeError from such cases isn't something we normally do as virReportEnumRangeError is usually meant for cases when the value is unknown. Reviewed-by: Peter Krempa <pkrempa@redhat.com>

On 11/27/23 9:53 AM, Peter Krempa wrote:
@@ -29973,14 +29973,10 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, break;
case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unexpected PCI backend 'xen'")); - break; -
Falling through to virReportEnumRangeError from such cases isn't something we normally do as virReportEnumRangeError is usually meant for cases when the value is unknown.
(Finally going through all of these) the ..._XEN value does exist in the enum for the value in the NetDef object, but there's no equivalent for it in the virNetworkForwardDriverNameType enum that's used on the NetworkPort object being converted *to*, so this actually *is* a range error (although you're correct that it's not the normal case of a completely unknown value). So I would take the time to make a separate case / error message for this particular value, however the patch immediately after this patch completely removes all this code anyway (it switches to using the same enum for both objects), so I'm just leaving it as it is.

On Sun, Dec 17, 2023 at 21:28:46 -0500, Laine Stump wrote:
On 11/27/23 9:53 AM, Peter Krempa wrote:
@@ -29973,14 +29973,10 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, break; case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unexpected PCI backend 'xen'")); - break; -
Falling through to virReportEnumRangeError from such cases isn't something we normally do as virReportEnumRangeError is usually meant for cases when the value is unknown.
(Finally going through all of these)
the ..._XEN value does exist in the enum for the value in the NetDef object, but there's no equivalent for it in the virNetworkForwardDriverNameType enum that's used on the NetworkPort object being converted *to*, so this actually *is* a range error (although you're correct that it's not the normal case of a completely unknown value).
The virReportEnumRangeError error reporting macro is in all other cases used to report values out of range of the enum, the 'switch' statement uses as an argument. Whatever it's then doing with the value is IMO out of scope as it is in range of the enum being tested for values. If it doesn't have any mapping where it is being converted *to*, it's either an UNSUPORTED_CONFIG or INTERNAL_ERROR, but clearly the value is in range of the source enum.
So I would take the time to make a separate case / error message for this particular value, however the patch immediately after this patch completely removes all this code anyway (it switches to using the same enum for both objects), so I'm just leaving it as it is.
Fair enough in this case, I just don't want to keep wrong examples in the repo, so if you remove it it's okay. I was just reviewing these chronologically.

The next step in consolidating parsing/formatting of the <driver> element of these objects using a common struct and common code. This eliminates the virNetworkForwardDriverNameType enum which is nearly identical to virDeviceHostdevPCIDriverType (the only non-identical bit was just because they'd gotten out of sync over time) and replaces its uses with a virDeviceHostdevPCIDriverInfo (which is a struct that contains a virDeviceHostdevPCIDriverType). Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/domain_conf.c | 48 +++--------------------------------- src/conf/network_conf.c | 21 ++++++---------- src/conf/network_conf.h | 17 ++----------- src/conf/virnetworkportdef.c | 10 ++++---- src/conf/virnetworkportdef.h | 4 ++- src/network/bridge_driver.c | 2 +- 6 files changed, 22 insertions(+), 80 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e322f1ffa7..82c1287986 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -29836,29 +29836,8 @@ virDomainNetDefActualFromNetworkPort(virDomainNetDef *iface, } actual->data.hostdev.def.source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; actual->data.hostdev.def.source.subsys.u.pci.addr = port->plug.hostdevpci.addr; - switch ((virNetworkForwardDriverNameType)port->plug.hostdevpci.driver) { - case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT: - actual->data.hostdev.def.source.subsys.u.pci.driver.type = - VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT; - break; - - case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM: - actual->data.hostdev.def.source.subsys.u.pci.driver.type = - VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM; - break; - - case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO: - actual->data.hostdev.def.source.subsys.u.pci.driver.type = - VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; - break; - - case VIR_NETWORK_FORWARD_DRIVER_NAME_LAST: - default: - virReportEnumRangeError(virNetworkForwardDriverNameType, - port->plug.hostdevpci.driver); - goto error; - } - + actual->data.hostdev.def.source.subsys.u.pci.driver.type + = port->plug.hostdevpci.driver.type; break; case VIR_NETWORK_PORT_PLUG_TYPE_LAST: @@ -29959,27 +29938,8 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, } port->plug.hostdevpci.managed = virTristateBoolFromBool(actual->data.hostdev.def.managed); port->plug.hostdevpci.addr = actual->data.hostdev.def.source.subsys.u.pci.addr; - switch (actual->data.hostdev.def.source.subsys.u.pci.driver.type) { - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT: - port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT; - break; - - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM: - port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_KVM; - break; - - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO: - port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO; - break; - - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST: - default: - virReportEnumRangeError(virDeviceHostdevPCIDriverType, - actual->data.hostdev.def.source.subsys.u.pci.driver.type); - return NULL; - } - + port->plug.hostdevpci.driver.type + = actual->data.hostdev.def.source.subsys.u.pci.driver.type; break; case VIR_DOMAIN_NET_TYPE_CLIENT: diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index b9601cb307..e3ad4c7340 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -56,13 +56,6 @@ VIR_ENUM_IMPL(virNetworkForwardHostdevDevice, "none", "pci", "netdev", ); -VIR_ENUM_IMPL(virNetworkForwardDriverName, - VIR_NETWORK_FORWARD_DRIVER_NAME_LAST, - "default", - "kvm", - "vfio", -); - VIR_ENUM_IMPL(virNetworkTaint, VIR_NETWORK_TAINT_LAST, "hook-script", @@ -1358,9 +1351,9 @@ virNetworkForwardDefParseXML(const char *networkName, if ((driverNode = virXPathNode("./driver", ctxt))) { if (virXMLPropEnum(driverNode, "name", - virNetworkForwardDriverNameTypeFromString, + virDeviceHostdevPCIDriverTypeFromString, VIR_XML_PROP_NONZERO, - &def->driverName) < 0) { + &def->driver.type) < 0) { return -1; } } @@ -2351,19 +2344,19 @@ virNetworkDefFormatBuf(virBuffer *buf, || VIR_SOCKET_ADDR_VALID(&def->forward.addr.end) || def->forward.port.start || def->forward.port.end - || (def->forward.driverName - != VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT) + || (def->forward.driver.type + != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) || def->forward.natIPv6); virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : ""); virBufferAdjustIndent(buf, 2); - if (def->forward.driverName) { + if (def->forward.driver.type) { const char *driverName - = virNetworkForwardDriverNameTypeToString(def->forward.driverName); + = virDeviceHostdevPCIDriverTypeToString(def->forward.driver.type); if (!driverName) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected hostdev driver name type %1$d "), - def->forward.driverName); + def->forward.driver.type); return -1; } virBufferAsprintf(&driverAttrBuf, " name='%s'", driverName); diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 497ae765f2..1d7fd3ab6a 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -24,6 +24,7 @@ #define DNS_RECORD_LENGTH_SRV (512 - 30) /* Limit minus overhead as mentioned in RFC-2782 */ #include "internal.h" +#include "virconftypes.h" #include "virsocketaddr.h" #include "virnetdevbandwidth.h" #include "virnetdevvportprofile.h" @@ -88,20 +89,6 @@ typedef enum { VIR_ENUM_DECL(virNetworkDHCPLeaseTimeUnit); -/* The backend driver used for devices from the pool. Currently used - * only for PCI devices (vfio vs. kvm), but could be used for other - * device types in the future. - */ -typedef enum { - VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT, /* kvm now, could change */ - VIR_NETWORK_FORWARD_DRIVER_NAME_KVM, /* force legacy kvm style */ - VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO, /* force vfio */ - - VIR_NETWORK_FORWARD_DRIVER_NAME_LAST -} virNetworkForwardDriverNameType; - -VIR_ENUM_DECL(virNetworkForwardDriverName); - typedef struct _virNetworkDHCPLeaseTimeDef virNetworkDHCPLeaseTimeDef; struct _virNetworkDHCPLeaseTimeDef { unsigned long long expiry; @@ -216,7 +203,7 @@ typedef struct _virNetworkForwardDef virNetworkForwardDef; struct _virNetworkForwardDef { int type; /* One of virNetworkForwardType constants */ bool managed; /* managed attribute for hostdev mode */ - virNetworkForwardDriverNameType driverName; + virDeviceHostdevPCIDriverInfo driver; /* If there are multiple forward devices (i.e. a pool of * interfaces), they will be listed here. diff --git a/src/conf/virnetworkportdef.c b/src/conf/virnetworkportdef.c index 402c0051ec..77ef705e18 100644 --- a/src/conf/virnetworkportdef.c +++ b/src/conf/virnetworkportdef.c @@ -226,9 +226,9 @@ virNetworkPortDefParseXML(xmlXPathContextPtr ctxt) if ((driverNode = virXPathNode("./plug/driver", ctxt))) { if (virXMLPropEnum(driverNode, "name", - virNetworkForwardDriverNameTypeFromString, + virDeviceHostdevPCIDriverTypeFromString, VIR_XML_PROP_NONZERO, - &def->plug.hostdevpci.driver) < 0) { + &def->plug.hostdevpci.driver.type) < 0) { return NULL; } } @@ -356,10 +356,10 @@ virNetworkPortDefFormatBuf(virBuffer *buf, virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); - if (def->plug.hostdevpci.driver) { + if (def->plug.hostdevpci.driver.type) { virBufferEscapeString(&driverAttrBuf, " name='%s'", - virNetworkForwardDriverNameTypeToString( - def->plug.hostdevpci.driver)); + virDeviceHostdevPCIDriverTypeToString( + def->plug.hostdevpci.driver.type)); } virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); diff --git a/src/conf/virnetworkportdef.h b/src/conf/virnetworkportdef.h index bfe1dae9ea..9e51ab1a8b 100644 --- a/src/conf/virnetworkportdef.h +++ b/src/conf/virnetworkportdef.h @@ -22,6 +22,8 @@ #pragma once #include "internal.h" +#include "virconftypes.h" +#include "device_conf.h" #include "virnetdevvlan.h" #include "virnetdevvportprofile.h" #include "virnetdevbandwidth.h" @@ -69,7 +71,7 @@ struct _virNetworkPortDef { } direct; struct { virPCIDeviceAddress addr; /* PCI Address of device */ - unsigned int driver; /* virNetworkForwardDriverNameType */ + virDeviceHostdevPCIDriverInfo driver; virTristateBool managed; } hostdevpci; } plug; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 4be740de2c..a9188c2436 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -3930,7 +3930,7 @@ networkAllocatePort(virNetworkObj *obj, return -1; } port->plug.hostdevpci.addr = dev->device.pci; - port->plug.hostdevpci.driver = netdef->forward.driverName; + port->plug.hostdevpci.driver.type = netdef->forward.driver.type; port->plug.hostdevpci.managed = virTristateBoolFromBool(netdef->forward.managed); if (port->virtPortProfile) { -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:51 -0500, Laine Stump wrote:
The next step in consolidating parsing/formatting of the <driver> element of these objects using a common struct and common code. This eliminates the virNetworkForwardDriverNameType enum which is nearly identical to virDeviceHostdevPCIDriverType (the only non-identical bit was just because they'd gotten out of sync over time) and replaces its uses with a virDeviceHostdevPCIDriverInfo (which is a struct that contains a virDeviceHostdevPCIDriverType).
Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/domain_conf.c | 48 +++--------------------------------- src/conf/network_conf.c | 21 ++++++---------- src/conf/network_conf.h | 17 ++----------- src/conf/virnetworkportdef.c | 10 ++++---- src/conf/virnetworkportdef.h | 4 ++- src/network/bridge_driver.c | 2 +- 6 files changed, 22 insertions(+), 80 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e322f1ffa7..82c1287986 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -29836,29 +29836,8 @@ virDomainNetDefActualFromNetworkPort(virDomainNetDef *iface, } actual->data.hostdev.def.source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; actual->data.hostdev.def.source.subsys.u.pci.addr = port->plug.hostdevpci.addr; - switch ((virNetworkForwardDriverNameType)port->plug.hostdevpci.driver) { - case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT: - actual->data.hostdev.def.source.subsys.u.pci.driver.type = - VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT; - break; - - case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM: - actual->data.hostdev.def.source.subsys.u.pci.driver.type = - VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM; - break; - - case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO: - actual->data.hostdev.def.source.subsys.u.pci.driver.type = - VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; - break; - - case VIR_NETWORK_FORWARD_DRIVER_NAME_LAST: - default: - virReportEnumRangeError(virNetworkForwardDriverNameType, - port->plug.hostdevpci.driver); - goto error; - } - + actual->data.hostdev.def.source.subsys.u.pci.driver.type + = port->plug.hostdevpci.driver.type; break;
case VIR_NETWORK_PORT_PLUG_TYPE_LAST: @@ -29959,27 +29938,8 @@ virDomainNetDefActualToNetworkPort(virDomainDef *dom, } port->plug.hostdevpci.managed = virTristateBoolFromBool(actual->data.hostdev.def.managed); port->plug.hostdevpci.addr = actual->data.hostdev.def.source.subsys.u.pci.addr; - switch (actual->data.hostdev.def.source.subsys.u.pci.driver.type) { - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT: - port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT; - break; - - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM: - port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_KVM; - break; - - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO: - port->plug.hostdevpci.driver = VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO; - break; - - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN: - case VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_LAST: - default: - virReportEnumRangeError(virDeviceHostdevPCIDriverType, - actual->data.hostdev.def.source.subsys.u.pci.driver.type); - return NULL; - } - + port->plug.hostdevpci.driver.type + = actual->data.hostdev.def.source.subsys.u.pci.driver.type;
It's okay if you un-break the line here. Don't need to create conflicts in previous patches.
break;
case VIR_DOMAIN_NET_TYPE_CLIENT: diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index b9601cb307..e3ad4c7340 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -56,13 +56,6 @@ VIR_ENUM_IMPL(virNetworkForwardHostdevDevice, "none", "pci", "netdev", );
-VIR_ENUM_IMPL(virNetworkForwardDriverName, - VIR_NETWORK_FORWARD_DRIVER_NAME_LAST, - "default", - "kvm", - "vfio", -); - VIR_ENUM_IMPL(virNetworkTaint, VIR_NETWORK_TAINT_LAST, "hook-script", @@ -1358,9 +1351,9 @@ virNetworkForwardDefParseXML(const char *networkName,
if ((driverNode = virXPathNode("./driver", ctxt))) { if (virXMLPropEnum(driverNode, "name", - virNetworkForwardDriverNameTypeFromString, + virDeviceHostdevPCIDriverTypeFromString, VIR_XML_PROP_NONZERO, - &def->driverName) < 0) { + &def->driver.type) < 0) { return -1; } } @@ -2351,19 +2344,19 @@ virNetworkDefFormatBuf(virBuffer *buf, || VIR_SOCKET_ADDR_VALID(&def->forward.addr.end) || def->forward.port.start || def->forward.port.end - || (def->forward.driverName - != VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT) + || (def->forward.driver.type + != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) || def->forward.natIPv6); virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : ""); virBufferAdjustIndent(buf, 2);
- if (def->forward.driverName) { + if (def->forward.driver.type) { const char *driverName - = virNetworkForwardDriverNameTypeToString(def->forward.driverName); + = virDeviceHostdevPCIDriverTypeToString(def->forward.driver.type); if (!driverName) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected hostdev driver name type %1$d "), - def->forward.driverName); + def->forward.driver.type); return -1; } virBufferAsprintf(&driverAttrBuf, " name='%s'", driverName); diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 497ae765f2..1d7fd3ab6a 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -24,6 +24,7 @@ #define DNS_RECORD_LENGTH_SRV (512 - 30) /* Limit minus overhead as mentioned in RFC-2782 */
#include "internal.h" +#include "virconftypes.h" #include "virsocketaddr.h" #include "virnetdevbandwidth.h" #include "virnetdevvportprofile.h" @@ -88,20 +89,6 @@ typedef enum {
VIR_ENUM_DECL(virNetworkDHCPLeaseTimeUnit);
-/* The backend driver used for devices from the pool. Currently used - * only for PCI devices (vfio vs. kvm), but could be used for other - * device types in the future. - */ -typedef enum { - VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT, /* kvm now, could change */ - VIR_NETWORK_FORWARD_DRIVER_NAME_KVM, /* force legacy kvm style */ - VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO, /* force vfio */ - - VIR_NETWORK_FORWARD_DRIVER_NAME_LAST -} virNetworkForwardDriverNameType; - -VIR_ENUM_DECL(virNetworkForwardDriverName); - typedef struct _virNetworkDHCPLeaseTimeDef virNetworkDHCPLeaseTimeDef; struct _virNetworkDHCPLeaseTimeDef { unsigned long long expiry; @@ -216,7 +203,7 @@ typedef struct _virNetworkForwardDef virNetworkForwardDef; struct _virNetworkForwardDef { int type; /* One of virNetworkForwardType constants */ bool managed; /* managed attribute for hostdev mode */ - virNetworkForwardDriverNameType driverName; + virDeviceHostdevPCIDriverInfo driver;
/* If there are multiple forward devices (i.e. a pool of * interfaces), they will be listed here. diff --git a/src/conf/virnetworkportdef.c b/src/conf/virnetworkportdef.c index 402c0051ec..77ef705e18 100644 --- a/src/conf/virnetworkportdef.c +++ b/src/conf/virnetworkportdef.c @@ -226,9 +226,9 @@ virNetworkPortDefParseXML(xmlXPathContextPtr ctxt)
if ((driverNode = virXPathNode("./plug/driver", ctxt))) { if (virXMLPropEnum(driverNode, "name", - virNetworkForwardDriverNameTypeFromString, + virDeviceHostdevPCIDriverTypeFromString, VIR_XML_PROP_NONZERO, - &def->plug.hostdevpci.driver) < 0) { + &def->plug.hostdevpci.driver.type) < 0) { return NULL; } } @@ -356,10 +356,10 @@ virNetworkPortDefFormatBuf(virBuffer *buf, virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2);
- if (def->plug.hostdevpci.driver) { + if (def->plug.hostdevpci.driver.type) { virBufferEscapeString(&driverAttrBuf, " name='%s'", - virNetworkForwardDriverNameTypeToString( - def->plug.hostdevpci.driver)); + virDeviceHostdevPCIDriverTypeToString( + def->plug.hostdevpci.driver.type)); }
virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); diff --git a/src/conf/virnetworkportdef.h b/src/conf/virnetworkportdef.h index bfe1dae9ea..9e51ab1a8b 100644 --- a/src/conf/virnetworkportdef.h +++ b/src/conf/virnetworkportdef.h @@ -22,6 +22,8 @@ #pragma once
#include "internal.h" +#include "virconftypes.h" +#include "device_conf.h" #include "virnetdevvlan.h" #include "virnetdevvportprofile.h" #include "virnetdevbandwidth.h" @@ -69,7 +71,7 @@ struct _virNetworkPortDef { } direct; struct { virPCIDeviceAddress addr; /* PCI Address of device */ - unsigned int driver; /* virNetworkForwardDriverNameType */ + virDeviceHostdevPCIDriverInfo driver;
You can ignore my earlier comment about this. Reviewed-by: Peter Krempa <pkrempa@redhat.com>

This is done so that we can re-use the same parser/formatter for <network> and <networkport> Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/device_conf.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/conf/device_conf.h | 7 +++++++ src/conf/domain_conf.c | 28 +++++----------------------- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 25a522671e..e022783816 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -55,6 +55,47 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, "unassigned", ); + +int +virDeviceHostdevPCIDriverInfoParseXML(xmlNodePtr node, + virDeviceHostdevPCIDriverInfo *driver) +{ + if (virXMLPropEnum(node, "name", + virDeviceHostdevPCIDriverTypeFromString, + VIR_XML_PROP_NONZERO, + &driver->type) < 0) { + return -1; + } + + return 0; +} + + +int +virDeviceHostdevPCIDriverInfoFormat(virBuffer *buf, + const virDeviceHostdevPCIDriverInfo *driver) +{ + g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; + + if (driver->type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { + const char *driverType + = virDeviceHostdevPCIDriverTypeToString(driver->type); + + if (!driverType) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected pci hostdev driver type %1$d"), + driver->type); + return -1; + } + + virBufferAsprintf(&driverAttrBuf, " name='%s'", driverType); + } + + virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); + return 0; +} + + static int virZPCIDeviceAddressParseXML(xmlNodePtr node, virPCIDeviceAddress *addr) diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 3a7a6c3f99..9f4b9f5375 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -25,6 +25,7 @@ #include <libxml/xpath.h> #include "internal.h" +#include "virconftypes.h" #include "virbuffer.h" #include "virccw.h" #include "virpci.h" @@ -185,6 +186,12 @@ struct _virDomainDeviceInfo { bool isolationGroupLocked; }; +int virDeviceHostdevPCIDriverInfoParseXML(xmlNodePtr node, + virDeviceHostdevPCIDriverInfo *driver); + +int virDeviceHostdevPCIDriverInfoFormat(virBuffer *buf, + const virDeviceHostdevPCIDriverInfo *driver); + void virDomainDeviceInfoClear(virDomainDeviceInfo *info); void virDomainDeviceInfoFree(virDomainDeviceInfo *info); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 82c1287986..d87ead291c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -6267,13 +6267,9 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, if (virDomainHostdevSubsysPCIDefParseXML(sourcenode, ctxt, def, flags) < 0) return -1; - if ((driver_node = virXPathNode("./driver", ctxt))) { - if (virXMLPropEnum(driver_node, "name", - virDeviceHostdevPCIDriverTypeFromString, - VIR_XML_PROP_NONZERO, - &pcisrc->driver.type) < 0) { - return -1; - } + if ((driver_node = virXPathNode("./driver", ctxt)) && + virDeviceHostdevPCIDriverInfoParseXML(driver_node, &pcisrc->driver) < 0) { + return -1; } break; @@ -23328,26 +23324,12 @@ virDomainHostdevDefFormatSubsysPCI(virBuffer *buf, unsigned int flags, bool includeTypeInAddr) { - g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) sourceAttrBuf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) sourceChildBuf = VIR_BUFFER_INIT_CHILD(buf); virDomainHostdevSubsysPCI *pcisrc = &def->source.subsys.u.pci; - if (pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { - const char *driverType - = virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type); - - if (!driverType) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected pci hostdev driver type %1$d"), - pcisrc->driver.type); - return -1; - } - - virBufferAsprintf(&driverAttrBuf, " name='%s'", driverType); - } - - virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); + if (virDeviceHostdevPCIDriverInfoFormat(buf, &pcisrc->driver) < 0) + return -1; if (def->writeFiltering != VIR_TRISTATE_BOOL_ABSENT) virBufferAsprintf(&sourceAttrBuf, " writeFiltering='%s'", -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:52 -0500, Laine Stump wrote:
This is done so that we can re-use the same parser/formatter for <network> and <networkport>
Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/device_conf.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/conf/device_conf.h | 7 +++++++ src/conf/domain_conf.c | 28 +++++----------------------- 3 files changed, 53 insertions(+), 23 deletions(-)
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 25a522671e..e022783816 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -55,6 +55,47 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, "unassigned", );
[...]
+int +virDeviceHostdevPCIDriverInfoFormat(virBuffer *buf, + const virDeviceHostdevPCIDriverInfo *driver) +{ + g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; + + if (driver->type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { + const char *driverType + = virDeviceHostdevPCIDriverTypeToString(driver->type);
-||- Reviewed-by: Peter Krempa <pkrempa@redhat.com>

Now if a new attribute is added to <driver>, we only need to update the formatting/parsing in one place. Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/network_conf.c | 24 ++++-------------------- src/conf/virnetworkportdef.c | 21 ++++++--------------- 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index e3ad4c7340..2d78d588aa 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1349,13 +1349,9 @@ virNetworkForwardDefParseXML(const char *networkName, def->managed = true; } - if ((driverNode = virXPathNode("./driver", ctxt))) { - if (virXMLPropEnum(driverNode, "name", - virDeviceHostdevPCIDriverTypeFromString, - VIR_XML_PROP_NONZERO, - &def->driver.type) < 0) { + if ((driverNode = virXPathNode("./driver", ctxt)) && + virDeviceHostdevPCIDriverInfoParseXML(driverNode, &def->driver) < 0) { return -1; - } } /* bridge and hostdev modes can use a pool of physical interfaces */ @@ -2319,7 +2315,6 @@ virNetworkDefFormatBuf(virBuffer *buf, if (def->forward.type != VIR_NETWORK_FORWARD_NONE) { const char *dev = NULL; const char *mode = virNetworkForwardTypeToString(def->forward.type); - g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; if (!def->forward.npfs) dev = virNetworkDefForwardIf(def, 0); @@ -2350,19 +2345,8 @@ virNetworkDefFormatBuf(virBuffer *buf, virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : ""); virBufferAdjustIndent(buf, 2); - if (def->forward.driver.type) { - const char *driverName - = virDeviceHostdevPCIDriverTypeToString(def->forward.driver.type); - if (!driverName) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected hostdev driver name type %1$d "), - def->forward.driver.type); - return -1; - } - virBufferAsprintf(&driverAttrBuf, " name='%s'", driverName); - } - - virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); + if (virDeviceHostdevPCIDriverInfoFormat(buf, &def->forward.driver) < 0) + return -1; if (def->forward.type == VIR_NETWORK_FORWARD_NAT) { if (virNetworkForwardNatDefFormat(buf, &def->forward) < 0) diff --git a/src/conf/virnetworkportdef.c b/src/conf/virnetworkportdef.c index 77ef705e18..49d00b2ea6 100644 --- a/src/conf/virnetworkportdef.c +++ b/src/conf/virnetworkportdef.c @@ -224,13 +224,10 @@ virNetworkPortDefParseXML(xmlXPathContextPtr ctxt) &def->plug.hostdevpci.managed) < 0) return NULL; - if ((driverNode = virXPathNode("./plug/driver", ctxt))) { - if (virXMLPropEnum(driverNode, "name", - virDeviceHostdevPCIDriverTypeFromString, - VIR_XML_PROP_NONZERO, - &def->plug.hostdevpci.driver.type) < 0) { - return NULL; - } + if ((driverNode = virXPathNode("./plug/driver", ctxt)) && + virDeviceHostdevPCIDriverInfoParseXML(driverNode, + &def->plug.hostdevpci.driver) < 0) { + return NULL; } if (!(addressNode = virXPathNode("./plug/address", ctxt))) { @@ -321,7 +318,6 @@ virNetworkPortDefFormatBuf(virBuffer *buf, virTristateBoolTypeToString(def->trustGuestRxFilters)); if (def->plugtype != VIR_NETWORK_PORT_PLUG_TYPE_NONE) { - g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER; virBufferAsprintf(buf, "<plug type='%s'", virNetworkPortPlugTypeToString(def->plugtype)); @@ -356,13 +352,8 @@ virNetworkPortDefFormatBuf(virBuffer *buf, virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 2); - if (def->plug.hostdevpci.driver.type) { - virBufferEscapeString(&driverAttrBuf, " name='%s'", - virDeviceHostdevPCIDriverTypeToString( - def->plug.hostdevpci.driver.type)); - } - - virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); + if (virDeviceHostdevPCIDriverInfoFormat(buf, &def->plug.hostdevpci.driver) < 0) + return -1; virPCIDeviceAddressFormat(buf, def->plug.hostdevpci.addr, false); virBufferAdjustIndent(buf, -2); -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:53 -0500, Laine Stump wrote:
Now if a new attribute is added to <driver>, we only need to update the formatting/parsing in one place.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/network_conf.c | 24 ++++-------------------- src/conf/virnetworkportdef.c | 21 ++++++--------------- 2 files changed, 10 insertions(+), 35 deletions(-)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

The long-deprecated use of <driver name='vfio|xen|kvm'/> in domain xml for <hostdev> devices was only ever necessary during the period when libvirt (and the Linux kernel) supported both VFIO and "legacy KVM" styles of hostdev device assignment for QEMU. This became pointless many years ago when legacy KVM device assignment was removed from the kernel, and support for that style of device assignment was completely disabled in the libvirt source in 2019 (commit v5.6.0-316-g2e7225ea8c). Nevertheless, there were instances of <driver name='vfio'/> in the unit test data that were then (unnecessarily) propagated to several more tests over the years. This patch cleans out those unnecessary explicit settings of driver name='vfio' in all QEMU unit test data, proving that the attribute is no longer (externally) needed while also making it simpler to properly test when a later patch "re-animates" the driver name attribute for a slightly different (but related) use. Signed-off-by: Laine Stump <laine@redhat.com> --- tests/qemuxml2argvdata/hostdev-pci-address-unassigned.xml | 4 ---- tests/qemuxml2argvdata/hostdev-pci-multifunction.xml | 7 ------- tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml | 1 - .../hostdev-vfio-zpci-autogenerate-fids.xml | 2 -- .../hostdev-vfio-zpci-autogenerate-uids.xml | 2 -- tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio-zpci-boundaries.xml | 2 -- .../qemuxml2argvdata/hostdev-vfio-zpci-ccw-memballoon.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio-zpci-duplicate.xml | 2 -- .../hostdev-vfio-zpci-invalid-uid-valid-fid.xml | 1 - .../hostdev-vfio-zpci-multidomain-many.xml | 8 -------- tests/qemuxml2argvdata/hostdev-vfio-zpci-set-zero.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio-zpci-uid-set-zero.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio-zpci-wrong-arch.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio-zpci.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio.xml | 1 - tests/qemuxml2argvdata/net-hostdev-vfio-multidomain.xml | 1 - tests/qemuxml2argvdata/net-hostdev-vfio.xml | 1 - tests/qemuxml2argvdata/pseries-hostdevs-1.xml | 3 --- tests/qemuxml2argvdata/pseries-hostdevs-2.xml | 2 -- tests/qemuxml2argvdata/pseries-hostdevs-3.xml | 2 -- .../hostdev-pci-address-unassigned.x86_64-latest.xml | 4 ---- .../hostdev-pci-multifunction.x86_64-latest.xml | 7 ------- .../hostdev-vfio-zpci-autogenerate-fids.s390x-latest.xml | 2 -- .../hostdev-vfio-zpci-autogenerate-uids.s390x-latest.xml | 2 -- .../hostdev-vfio-zpci-autogenerate.s390x-latest.xml | 1 - .../hostdev-vfio-zpci-boundaries.s390x-latest.xml | 2 -- .../hostdev-vfio-zpci-ccw-memballoon.s390x-latest.xml | 1 - .../hostdev-vfio-zpci-multidomain-many.s390x-latest.xml | 8 -------- .../qemuxml2xmloutdata/hostdev-vfio-zpci.s390x-latest.xml | 1 - tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml | 1 - .../qemuxml2xmloutdata/net-hostdev-vfio.x86_64-latest.xml | 1 - .../pseries-hostdevs-1.ppc64-latest.xml | 3 --- .../pseries-hostdevs-2.ppc64-latest.xml | 2 -- .../pseries-hostdevs-3.ppc64-latest.xml | 2 -- 35 files changed, 82 deletions(-) diff --git a/tests/qemuxml2argvdata/hostdev-pci-address-unassigned.xml b/tests/qemuxml2argvdata/hostdev-pci-address-unassigned.xml index 9a2685ca0e..864ef303c0 100644 --- a/tests/qemuxml2argvdata/hostdev-pci-address-unassigned.xml +++ b/tests/qemuxml2argvdata/hostdev-pci-address-unassigned.xml @@ -14,26 +14,22 @@ <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x1'/> </source> <address type='unassigned'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x3'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml b/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml index 06c889c64d..ba0a593628 100644 --- a/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml +++ b/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml @@ -14,43 +14,36 @@ <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x3'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml b/tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml index b720883913..7afe18b24e 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml @@ -23,7 +23,6 @@ <controller type='ide' index='0'/> <controller type='pci' index='0' model='pci-root'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0021' bus='222' slot='31' function='1'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate-fids.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate-fids.xml index 49c26e2434..e72c524a98 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate-fids.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate-fids.xml @@ -8,7 +8,6 @@ <devices> <emulator>/usr/bin/qemu-system-s390x</emulator> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -17,7 +16,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate-uids.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate-uids.xml index e74e0116c7..1ed75aae48 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate-uids.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate-uids.xml @@ -8,7 +8,6 @@ <devices> <emulator>/usr/bin/qemu-system-s390x</emulator> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -17,7 +16,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate.xml index 36161006ab..b4b1ce315f 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-autogenerate.xml @@ -8,7 +8,6 @@ <devices> <emulator>/usr/bin/qemu-system-s390x</emulator> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-boundaries.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-boundaries.xml index 1e6060345b..fe005af488 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-boundaries.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-boundaries.xml @@ -9,7 +9,6 @@ <emulator>/usr/bin/qemu-system-s390x</emulator> <controller type='pci' index='0' model='pci-root'/> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0xffff' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -18,7 +17,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-ccw-memballoon.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-ccw-memballoon.xml index ef5e97fc9c..bb6861f103 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-ccw-memballoon.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-ccw-memballoon.xml @@ -8,7 +8,6 @@ <devices> <emulator>/usr/bin/qemu-system-s390x</emulator> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-duplicate.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-duplicate.xml index 6062ae4940..53cf48ea6a 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-duplicate.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-duplicate.xml @@ -9,7 +9,6 @@ <emulator>/usr/bin/qemu-system-s390x</emulator> <controller type='pci' index='0' model='pci-root'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -18,7 +17,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-invalid-uid-valid-fid.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-invalid-uid-valid-fid.xml index 6e7101489e..1026661730 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-invalid-uid-valid-fid.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-invalid-uid-valid-fid.xml @@ -9,7 +9,6 @@ <emulator>/usr/bin/qemu-system-s390x</emulator> <controller type='pci' index='0' model='pci-root'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-multidomain-many.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-multidomain-many.xml index da8305dd6d..36c11a8311 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-multidomain-many.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-multidomain-many.xml @@ -9,7 +9,6 @@ <emulator>/usr/bin/qemu-system-s390x</emulator> <controller type='pci' index='0' model='pci-root'/> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -18,7 +17,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0002' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -27,20 +25,17 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0003' bus='0x00' slot='0x00' function='0x0'/> </source> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0004' bus='0x00' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -49,7 +44,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0006' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -58,7 +52,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0007' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -67,7 +60,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0008' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-set-zero.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-set-zero.xml index fd3d1193f1..eefe05de39 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-set-zero.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-set-zero.xml @@ -9,7 +9,6 @@ <emulator>/usr/bin/qemu-system-s390x</emulator> <controller type='pci' index='0' model='pci-root'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-uid-set-zero.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-uid-set-zero.xml index 6bfbfe611b..fb0e680b55 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-uid-set-zero.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-uid-set-zero.xml @@ -8,7 +8,6 @@ <devices> <emulator>/usr/bin/qemu-system-s390x</emulator> <hostdev mode='subsystem' type='pci'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci-wrong-arch.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci-wrong-arch.xml index a9a5afd6dd..8b3cc45ddf 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci-wrong-arch.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci-wrong-arch.xml @@ -21,7 +21,6 @@ </disk> <controller type='pci' index='0' model='pci-root'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='00' slot='00' function='0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio-zpci.xml b/tests/qemuxml2argvdata/hostdev-vfio-zpci.xml index 002b99c52d..5f439eff73 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-zpci.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-zpci.xml @@ -9,7 +9,6 @@ <emulator>/usr/bin/qemu-system-s390x</emulator> <controller type='pci' index='0' model='pci-root'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/hostdev-vfio.xml b/tests/qemuxml2argvdata/hostdev-vfio.xml index 1b438a2eef..a03870f6e0 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio.xml @@ -25,7 +25,6 @@ <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> diff --git a/tests/qemuxml2argvdata/net-hostdev-vfio-multidomain.xml b/tests/qemuxml2argvdata/net-hostdev-vfio-multidomain.xml index ae8c4e7e80..cdadf4f2cb 100644 --- a/tests/qemuxml2argvdata/net-hostdev-vfio-multidomain.xml +++ b/tests/qemuxml2argvdata/net-hostdev-vfio-multidomain.xml @@ -24,7 +24,6 @@ <controller type='pci' index='0' model='pci-root'/> <interface type='hostdev' managed='yes'> <mac address='00:11:22:33:44:55'/> - <driver name='vfio'/> <source> <address type='pci' domain='0x0021' bus='0xde' slot='0x1f' function='0x1'/> </source> diff --git a/tests/qemuxml2argvdata/net-hostdev-vfio.xml b/tests/qemuxml2argvdata/net-hostdev-vfio.xml index e6e6b6e5d3..9cdb8a602d 100644 --- a/tests/qemuxml2argvdata/net-hostdev-vfio.xml +++ b/tests/qemuxml2argvdata/net-hostdev-vfio.xml @@ -24,7 +24,6 @@ <controller type='pci' index='0' model='pci-root'/> <interface type='hostdev' managed='yes'> <mac address='00:11:22:33:44:55'/> - <driver name='vfio'/> <source> <address type='pci' domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> diff --git a/tests/qemuxml2argvdata/pseries-hostdevs-1.xml b/tests/qemuxml2argvdata/pseries-hostdevs-1.xml index 04f3ec4759..5d09413a98 100644 --- a/tests/qemuxml2argvdata/pseries-hostdevs-1.xml +++ b/tests/qemuxml2argvdata/pseries-hostdevs-1.xml @@ -11,7 +11,6 @@ <!-- This hostdev will cause a new PHB to be created because its isolation group is 1 (IOMMU group 0) --> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> @@ -19,7 +18,6 @@ <!-- This hostdev can't share the PHB that was just created, because its isolation group is 2 (IOMMU group 1) --> <interface type='hostdev' managed='yes'> - <driver name='vfio'/> <source> <address type='pci' domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> @@ -28,7 +26,6 @@ <!-- This hostdev will be placed on the first PHB, since its isolation group is 1 (IOMMU group 0) just like the first hostdev --> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> </source> diff --git a/tests/qemuxml2argvdata/pseries-hostdevs-2.xml b/tests/qemuxml2argvdata/pseries-hostdevs-2.xml index 6568475c72..00d4228499 100644 --- a/tests/qemuxml2argvdata/pseries-hostdevs-2.xml +++ b/tests/qemuxml2argvdata/pseries-hostdevs-2.xml @@ -17,7 +17,6 @@ despite being in the separate isolation group 1 (IOMMU group 0), because the address has been requested explicitly by the user --> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> @@ -26,7 +25,6 @@ <!-- This hostdev can use neither the PHB that was just created, nor the default one, because it's in isolation group 2 (IOMMU group 1) --> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> diff --git a/tests/qemuxml2argvdata/pseries-hostdevs-3.xml b/tests/qemuxml2argvdata/pseries-hostdevs-3.xml index 4f51f48c90..64ba95ca30 100644 --- a/tests/qemuxml2argvdata/pseries-hostdevs-3.xml +++ b/tests/qemuxml2argvdata/pseries-hostdevs-3.xml @@ -11,7 +11,6 @@ <!-- This hostdev will cause a new PHB to be created because its isolation group is 1 (IOMMU group 0). It will be PHB 2 due to the address --> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> @@ -20,7 +19,6 @@ <!-- This hostdev will be placed on the same PHB, since its isolation group is also 1 (IOMMU group 0) --> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-pci-address-unassigned.x86_64-latest.xml b/tests/qemuxml2xmloutdata/hostdev-pci-address-unassigned.x86_64-latest.xml index 480d2f8363..9da9a8a07e 100644 --- a/tests/qemuxml2xmloutdata/hostdev-pci-address-unassigned.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-pci-address-unassigned.x86_64-latest.xml @@ -28,28 +28,24 @@ <input type='keyboard' bus='ps2'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x1'/> </source> <address type='unassigned'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x3'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.x86_64-latest.xml b/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.x86_64-latest.xml index a29a27e85b..9530c28e14 100644 --- a/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.x86_64-latest.xml @@ -28,49 +28,42 @@ <input type='keyboard' bus='ps2'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x3'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate-fids.s390x-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate-fids.s390x-latest.xml index dd1dea4e99..f23ad5b90c 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate-fids.s390x-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate-fids.s390x-latest.xml @@ -20,7 +20,6 @@ <controller type='pci' index='0' model='pci-root'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -29,7 +28,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate-uids.s390x-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate-uids.s390x-latest.xml index 1a52487692..9bf2ce32be 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate-uids.s390x-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate-uids.s390x-latest.xml @@ -20,7 +20,6 @@ <controller type='pci' index='0' model='pci-root'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -29,7 +28,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate.s390x-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate.s390x-latest.xml index 670f8c68b4..94f3c04b9a 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate.s390x-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-autogenerate.s390x-latest.xml @@ -20,7 +20,6 @@ <controller type='pci' index='0' model='pci-root'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-boundaries.s390x-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-boundaries.s390x-latest.xml index df55f79501..8b0044af1c 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-boundaries.s390x-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-boundaries.s390x-latest.xml @@ -25,7 +25,6 @@ </controller> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0xffff' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -34,7 +33,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-ccw-memballoon.s390x-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-ccw-memballoon.s390x-latest.xml index 7df6491b68..e0ff360553 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-ccw-memballoon.s390x-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-ccw-memballoon.s390x-latest.xml @@ -18,7 +18,6 @@ <controller type='pci' index='0' model='pci-root'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-multidomain-many.s390x-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-multidomain-many.s390x-latest.xml index e64d7de561..70d592f2df 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-multidomain-many.s390x-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci-multidomain-many.s390x-latest.xml @@ -20,7 +20,6 @@ <controller type='pci' index='0' model='pci-root'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -29,7 +28,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0002' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -38,7 +36,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0003' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -47,7 +44,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0004' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -56,7 +52,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -65,7 +60,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0006' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -74,7 +68,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0007' bus='0x00' slot='0x00' function='0x0'/> </source> @@ -83,7 +76,6 @@ </address> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0008' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci.s390x-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci.s390x-latest.xml index 5e14a63810..c8a1407427 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio-zpci.s390x-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio-zpci.s390x-latest.xml @@ -20,7 +20,6 @@ <controller type='pci' index='0' model='pci-root'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x00' slot='0x00' function='0x0'/> </source> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml index b660d245a1..3915b515f2 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml @@ -34,7 +34,6 @@ <input type='keyboard' bus='ps2'/> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> diff --git a/tests/qemuxml2xmloutdata/net-hostdev-vfio.x86_64-latest.xml b/tests/qemuxml2xmloutdata/net-hostdev-vfio.x86_64-latest.xml index 167e1b1fea..1eee425593 100644 --- a/tests/qemuxml2xmloutdata/net-hostdev-vfio.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/net-hostdev-vfio.x86_64-latest.xml @@ -32,7 +32,6 @@ <controller type='pci' index='0' model='pci-root'/> <interface type='hostdev' managed='yes'> <mac address='00:11:22:33:44:55'/> - <driver name='vfio'/> <source> <address type='pci' domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> diff --git a/tests/qemuxml2xmloutdata/pseries-hostdevs-1.ppc64-latest.xml b/tests/qemuxml2xmloutdata/pseries-hostdevs-1.ppc64-latest.xml index db369a1fc7..d0ad114d34 100644 --- a/tests/qemuxml2xmloutdata/pseries-hostdevs-1.ppc64-latest.xml +++ b/tests/qemuxml2xmloutdata/pseries-hostdevs-1.ppc64-latest.xml @@ -32,7 +32,6 @@ </controller> <interface type='hostdev' managed='yes'> <mac address='52:54:00:6d:90:02'/> - <driver name='vfio'/> <source> <address type='pci' domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> @@ -40,14 +39,12 @@ </interface> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> </source> diff --git a/tests/qemuxml2xmloutdata/pseries-hostdevs-2.ppc64-latest.xml b/tests/qemuxml2xmloutdata/pseries-hostdevs-2.ppc64-latest.xml index 09b657698d..4ffcae80b8 100644 --- a/tests/qemuxml2xmloutdata/pseries-hostdevs-2.ppc64-latest.xml +++ b/tests/qemuxml2xmloutdata/pseries-hostdevs-2.ppc64-latest.xml @@ -35,14 +35,12 @@ </controller> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x01' slot='0x02' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> diff --git a/tests/qemuxml2xmloutdata/pseries-hostdevs-3.ppc64-latest.xml b/tests/qemuxml2xmloutdata/pseries-hostdevs-3.ppc64-latest.xml index 58ffb09c3b..e06901a9a4 100644 --- a/tests/qemuxml2xmloutdata/pseries-hostdevs-3.ppc64-latest.xml +++ b/tests/qemuxml2xmloutdata/pseries-hostdevs-3.ppc64-latest.xml @@ -32,14 +32,12 @@ </controller> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> </source> -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:54 -0500, Laine Stump wrote:
The long-deprecated use of <driver name='vfio|xen|kvm'/> in domain xml for <hostdev> devices was only ever necessary during the period when libvirt (and the Linux kernel) supported both VFIO and "legacy KVM" styles of hostdev device assignment for QEMU. This became pointless many years ago when legacy KVM device assignment was removed from the kernel, and support for that style of device assignment was completely disabled in the libvirt source in 2019 (commit v5.6.0-316-g2e7225ea8c).
Nevertheless, there were instances of <driver name='vfio'/> in the unit test data that were then (unnecessarily) propagated to several more tests over the years. This patch cleans out those unnecessary explicit settings of driver name='vfio' in all QEMU unit test data, proving that the attribute is no longer (externally) needed while also making it simpler to properly test when a later patch "re-animates" the driver name attribute for a slightly different (but related) use.
Signed-off-by: Laine Stump <laine@redhat.com> ---
Few issues: 1) There are few bits with domain XML bits that seem to mention it: tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml: <driver name='vfio'/> tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml: <driver name='vfio'/> tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-hostdev-nvme.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml: <driver name='vfio'/> tests/qemustatusxml2xmldata/modern-in.xml: <driver name='vfio'/> 2) There's documentation that seems to mention it: docs/formatdomain.rst: <driver name='vfio'/> docs/formatnetwork.rst: <driver name='vfio'/> docs/formatnetworkport.rst: <driver name='vfio'/> docs/pci-addresses.rst: <driver name='vfio'/> 3) You are not leaving any example with the existing syntax. To prevent regression, either keep some in or create a specific new test case to cover this now-corner-case. With at least 2 & 3 addressed: Reviewed-by: Peter Krempa <pkrempa@redhat.com>

On 11/27/23 10:03 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:38:54 -0500, Laine Stump wrote:
The long-deprecated use of <driver name='vfio|xen|kvm'/> in domain xml for <hostdev> devices was only ever necessary during the period when libvirt (and the Linux kernel) supported both VFIO and "legacy KVM" styles of hostdev device assignment for QEMU. This became pointless many years ago when legacy KVM device assignment was removed from the kernel, and support for that style of device assignment was completely disabled in the libvirt source in 2019 (commit v5.6.0-316-g2e7225ea8c).
Nevertheless, there were instances of <driver name='vfio'/> in the unit test data that were then (unnecessarily) propagated to several more tests over the years. This patch cleans out those unnecessary explicit settings of driver name='vfio' in all QEMU unit test data, proving that the attribute is no longer (externally) needed while also making it simpler to properly test when a later patch "re-animates" the driver name attribute for a slightly different (but related) use.
Signed-off-by: Laine Stump <laine@redhat.com> ---
Few issues: 1) There are few bits with domain XML bits that seem to mention it:
tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml: <driver name='vfio'/> tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml: <driver name='vfio'/> tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml: <driver name='vfio'/>
I *thought* that I needed to keep those for now (until patch 12/15), but it turns out I didn't, so I removed them too.
tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-hostdev-nvme.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml: <driver name='vfio'/> tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml: <driver name='vfio'/>
I had previously also left these in because the test was failing when I removed them, then I forgot to go back and investiate why. Now that you've reminded me to look back at it, I see this failure was due to the patch 11/15 - "conf: replace virHostdevIsVFIODevice with virHostdevIsPCIDevice" - not yet being applied. I've switched the order of the patches and now am able to remove these as well.
tests/qemustatusxml2xmldata/modern-in.xml: <driver name='vfio'/>
This is status XML generated by
2) There's documentation that seems to mention it:
docs/formatdomain.rst: <driver name='vfio'/> docs/formatnetwork.rst: <driver name='vfio'/> docs/formatnetworkport.rst: <driver name='vfio'/> docs/pci-addresses.rst: <driver name='vfio'/>
removed (I forgot to search in docs)
3) You are not leaving any example with the existing syntax. To prevent regression, either keep some in or create a specific new test case to cover this now-corner-case.
One of the test cases added in patch 12/15 covers the "legacy" case of "driver name='vfio'" along with the new "driver type='vfio'", and the new usage of "driver name='vfio-pci-igbvf'".
With at least 2 & 3 addressed:
Reviewed-by: Peter Krempa <pkrempa@redhat.com> _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org

Xen only supports a single type of PCI hostdev assignment, so it is superfluous to have <driver name='xen'/> peppered throughout the config. It *is* necessary to have the driver type explicitly set in the hosdev object before calling into the hypervisor-agnostic "hostdev manager" though (otherwise the hostdev manager doesn't know whether it should do Xen-specific setup, or VFIO-specific setup). Historically, the Xen driver has checked for "default" driver type (i.e. not set in the XML), and set it to "xen', during the XML postparse, thus guaranteeing that it will be set by the time the object is sent to the hostdev manager at runtime, but also setting it so early that a simple round-trip of parse-format results in the XML always containing an explicit <driver name='xen'/>, even if that wasn't specified in the original XML. The QEMU driver *doesn't* set driver.type during postparse though; instead, it waits until domain startup time (or device attach time for hotplug), and sets the driver.type then. The result is that a parse-format round trip of the XML in the QEMU driver *doesn't* add in the <driver name='vfio'/>. This patch modifies the Xen code to behave similarly to the QEMU code - the PostParse just checks for a driver.type that isn't supported by the Xen driver, and any explicit setting to "xen" is deferred until domain runtime rather than during the postparse. This delayed setting of driver.type of course results in slightly different xml2xml parse-format results, so the unit test data is modified accordingly. Signed-off-by: Laine Stump <laine@redhat.com> --- src/libxl/libxl_domain.c | 65 +++++++++++++++---- src/libxl/libxl_driver.c | 25 ++++--- tests/libxlxml2domconfigdata/moredevs-hvm.xml | 1 - tests/xlconfigdata/test-fullvirt-pci.xml | 2 - tests/xmconfigdata/test-pci-dev-syntax.xml | 2 - tests/xmconfigdata/test-pci-devs.xml | 2 - 6 files changed, 69 insertions(+), 28 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 22482adfa6..ecdf57e655 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -160,8 +160,15 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev, if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT && + pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN) { + + /* Xen only supports "Xen" style of hostdev, of course! */ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("XEN does not support device assignment mode '%1$s'"), + virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type)); + return -1; + } } if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) { @@ -986,18 +993,9 @@ libxlNetworkPrepareDevices(virDomainDef *def) if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV && net->type == VIR_DOMAIN_NET_TYPE_NETWORK) { /* Each type='hostdev' network device must also have a - * corresponding entry in the hostdevs array. For netdevs - * that are hardcoded as type='hostdev', this is already - * done by the parser, but for those allocated from a - * network / determined at runtime, we need to do it - * separately. + * corresponding entry in the hostdevs array. */ virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net); - virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; - - if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; if (virDomainHostdevInsert(def, hostdev) < 0) return -1; @@ -1007,6 +1005,46 @@ libxlNetworkPrepareDevices(virDomainDef *def) return 0; } + +static int +libxlHostdevPrepareDevices(virDomainDef *def) +{ + size_t i; + + for (i = 0; i < def->nhostdevs; i++) { + virDomainHostdevDef *hostdev = def->hostdevs[i]; + virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; + + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && + pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { + + + pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + + /* Q: Why do we set an explicit driverType here even + * though Xen (currently) only supports one driverType for + * PCI hostdev assignment? + * + * A: Setting the driver type *in the domain XML config* + * is optional (and actually pointless at the time of + * writing, since each hypervisor only supports a single + * type of PCI hostdev device assignment). But the + * hypervisor-agnostic virHostdevPrepareDomainDevices(), + * which is called immediately after this function in + * order to do any driver-related setup (e.g. bind the + * host device to a driver kernel driver), requires that + * the driverType be explicitly set (otherwise it wouldn't + * know whether to bind to the Xen driver or VFIO driver, + * for example). + */ + } + } + + return 0; +} + + static void libxlConsoleCallback(libxl_ctx *ctx, libxl_event *ev, void *for_callback) { @@ -1174,6 +1212,9 @@ libxlDomainStartPrepare(libxlDriverPrivate *driver, if (libxlNetworkPrepareDevices(vm->def) < 0) goto error; + if (libxlHostdevPrepareDevices(vm->def) < 0) + goto error; + if (virHostdevPrepareDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME, vm->def, hostdev_flags) < 0) goto error; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 7f12b11b8d..1636233346 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -3087,6 +3087,22 @@ libxlDomainAttachHostPCIDevice(libxlDriverPrivate *driver, VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1); + /* The only supported driverType for Xen is + * VIR_DOMAIN_HOSTDEV_PCI_DRIVER_TYPE_XEN, which normally isn't + * set in the config (because it doesn't need to be), but it does + * need to be set for the impending call to + * virHostdevPreparePCIDevices() + */ + if (pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) + pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + + if (pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("XEN does not support device assignment mode '%1$s'"), + virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type)); + goto cleanup; + } + if (virHostdevPreparePCIDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME, vm->def->name, vm->def->uuid, &hostdev, 1, 0) < 0) @@ -3395,15 +3411,6 @@ libxlDomainAttachNetDevice(libxlDriverPrivate *driver, if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) { virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net); - virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; - - /* For those just allocated from a network pool whose driver type is - * still VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT, we need to set - * driver type correctly. - */ - if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; /* This is really a "smart hostdev", so it should be attached * as a hostdev (the hostdev code will reach over into the diff --git a/tests/libxlxml2domconfigdata/moredevs-hvm.xml b/tests/libxlxml2domconfigdata/moredevs-hvm.xml index 89ad80631d..64eeeff889 100644 --- a/tests/libxlxml2domconfigdata/moredevs-hvm.xml +++ b/tests/libxlxml2domconfigdata/moredevs-hvm.xml @@ -43,7 +43,6 @@ </interface> <interface type='hostdev' managed='yes'> <mac address='00:16:3e:2e:e7:fc'/> - <driver name='xen'/> <source> <address type='pci' domain='0x0000' bus='0x0a' slot='0x10' function='0x0'/> </source> diff --git a/tests/xlconfigdata/test-fullvirt-pci.xml b/tests/xlconfigdata/test-fullvirt-pci.xml index 75aa6ac25b..6826d14b9e 100644 --- a/tests/xlconfigdata/test-fullvirt-pci.xml +++ b/tests/xlconfigdata/test-fullvirt-pci.xml @@ -37,13 +37,11 @@ <model type='cirrus' vram='8192' heads='1' primary='yes'/> </video> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='xen'/> <source> <address domain='0x0000' bus='0x01' slot='0x1a' function='0x1'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='xen'/> <source writeFiltering='no'> <address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> </source> diff --git a/tests/xmconfigdata/test-pci-dev-syntax.xml b/tests/xmconfigdata/test-pci-dev-syntax.xml index 5d5d29c61c..1d5d857072 100644 --- a/tests/xmconfigdata/test-pci-dev-syntax.xml +++ b/tests/xmconfigdata/test-pci-dev-syntax.xml @@ -55,13 +55,11 @@ <model type='cirrus' vram='8192' heads='1' primary='yes'/> </video> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='xen'/> <source> <address domain='0x0001' bus='0x0c' slot='0x1b' function='0x2'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='xen'/> <source> <address domain='0x0000' bus='0x01' slot='0x13' function='0x0'/> </source> diff --git a/tests/xmconfigdata/test-pci-devs.xml b/tests/xmconfigdata/test-pci-devs.xml index 5d5d29c61c..1d5d857072 100644 --- a/tests/xmconfigdata/test-pci-devs.xml +++ b/tests/xmconfigdata/test-pci-devs.xml @@ -55,13 +55,11 @@ <model type='cirrus' vram='8192' heads='1' primary='yes'/> </video> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='xen'/> <source> <address domain='0x0001' bus='0x0c' slot='0x1b' function='0x2'/> </source> </hostdev> <hostdev mode='subsystem' type='pci' managed='no'> - <driver name='xen'/> <source> <address domain='0x0000' bus='0x01' slot='0x13' function='0x0'/> </source> -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:55 -0500, Laine Stump wrote:
Xen only supports a single type of PCI hostdev assignment, so it is superfluous to have <driver name='xen'/> peppered throughout the config. It *is* necessary to have the driver type explicitly set in the hosdev object before calling into the hypervisor-agnostic "hostdev manager" though (otherwise the hostdev manager doesn't know whether it should do Xen-specific setup, or VFIO-specific setup).
Historically, the Xen driver has checked for "default" driver type (i.e. not set in the XML), and set it to "xen', during the XML postparse, thus guaranteeing that it will be set by the time the object is sent to the hostdev manager at runtime, but also setting it so early that a simple round-trip of parse-format results in the XML always containing an explicit <driver name='xen'/>, even if that wasn't specified in the original XML.
Generally stuff that is written to the definition at parse time is done so that it doesn't change in the future, thus preserving ABI of machines created with a config where the default was not entered yet. This commit message doesn't make an argument why the change is needed, so I'm a bit reluctant...
The QEMU driver *doesn't* set driver.type during postparse though; instead, it waits until domain startup time (or device attach time for hotplug), and sets the driver.type then. The result is that a parse-format round trip of the XML in the QEMU driver *doesn't* add in the <driver name='vfio'/>.
This patch modifies the Xen code to behave similarly to the QEMU code - the PostParse just checks for a driver.type that isn't supported by the Xen driver, and any explicit setting to "xen" is deferred until domain runtime rather than during the postparse.
This delayed setting of driver.type of course results in slightly different xml2xml parse-format results, so the unit test data is modified accordingly.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/libxl/libxl_domain.c | 65 +++++++++++++++---- src/libxl/libxl_driver.c | 25 ++++--- tests/libxlxml2domconfigdata/moredevs-hvm.xml | 1 - tests/xlconfigdata/test-fullvirt-pci.xml | 2 - tests/xmconfigdata/test-pci-dev-syntax.xml | 2 - tests/xmconfigdata/test-pci-devs.xml | 2 - 6 files changed, 69 insertions(+), 28 deletions(-)
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 22482adfa6..ecdf57e655 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -160,8 +160,15 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev,
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT && + pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN) { + + /* Xen only supports "Xen" style of hostdev, of course! */ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("XEN does not support device assignment mode '%1$s'"), + virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type)); + return -1; + } }
if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) { @@ -986,18 +993,9 @@ libxlNetworkPrepareDevices(virDomainDef *def) if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV && net->type == VIR_DOMAIN_NET_TYPE_NETWORK) { /* Each type='hostdev' network device must also have a - * corresponding entry in the hostdevs array. For netdevs - * that are hardcoded as type='hostdev', this is already - * done by the parser, but for those allocated from a - * network / determined at runtime, we need to do it - * separately. + * corresponding entry in the hostdevs array. */ virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net); - virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; - - if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN;
if (virDomainHostdevInsert(def, hostdev) < 0) return -1; @@ -1007,6 +1005,46 @@ libxlNetworkPrepareDevices(virDomainDef *def) return 0; }
+ +static int +libxlHostdevPrepareDevices(virDomainDef *def) +{ + size_t i; + + for (i = 0; i < def->nhostdevs; i++) { + virDomainHostdevDef *hostdev = def->hostdevs[i]; + virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; + + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && + pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { +
... and here I don't think it's obvious enough that the default must never change.

On 11/27/23 10:12 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:38:55 -0500, Laine Stump wrote:
Xen only supports a single type of PCI hostdev assignment, so it is superfluous to have <driver name='xen'/> peppered throughout the config. It *is* necessary to have the driver type explicitly set in the hosdev object before calling into the hypervisor-agnostic "hostdev manager" though (otherwise the hostdev manager doesn't know whether it should do Xen-specific setup, or VFIO-specific setup).
Historically, the Xen driver has checked for "default" driver type (i.e. not set in the XML), and set it to "xen', during the XML postparse, thus guaranteeing that it will be set by the time the object is sent to the hostdev manager at runtime, but also setting it so early that a simple round-trip of parse-format results in the XML always containing an explicit <driver name='xen'/>, even if that wasn't specified in the original XML.
Generally stuff that is written to the definition at parse time is done so that it doesn't change in the future, thus preserving ABI of machines created with a config where the default was not entered yet.
I don't think there was any intentional "lock in the default setting in the config to preserve ABI" in this case - it all seems to just be convenience/serendipity. From what I can see in the original code adding "PCI passthrough" to the libxl driver, they were just filling in the driver name in the xml because 1) it was there, and 2) they had just split out some of the code from qemu into "common code" to be used by both libxl and QEMU, needed a way to specify which driver was calling into this common code, saw the driver name as a convenient way to do it, and noticed that lots of other values that weren't set by the user were being set in the postparse, so that's where they set it in their code. (BTW, there was code in the original commit adding PCI passthrough to libxl (commit 6225cb3df5a5732868719462f0a602ef11f7fa03) that logged an error if the driver name was anything other than empty (in which case it was set to "xen") or "xen". That code is still there today (see libxlNodeDeviceDetachFlags), so the Xen driver definiteoy only supports the one type of PCI device assignment.)
This commit message doesn't make an argument why the change is needed, so I'm a bit reluctant...
Well... the less use of the old usage of <driver name> there is, the better, and preventing it from being written into every single new config file with a <hostdev> means less use. Also this change makes the libxl driver more consistent with the behavior of the qemu driver (which has never set an explicit default in the postparse - it waits until the devices are being initialized for domain startup/hotplug before it sets the driver type (and it also always sets it to the same value). I suppose I could omit this patch, but I think it's just perpetuating unintentional code that is inconsistent with the other driver (qemu) which serves to make it more difficult for a newcomer to understand what's going on with the <driver name/type> and what is the proper way to handle it in the case of some new hypervisor driver that decides to support <hostdev>.
The QEMU driver *doesn't* set driver.type during postparse though; instead, it waits until domain startup time (or device attach time for hotplug), and sets the driver.type then. The result is that a parse-format round trip of the XML in the QEMU driver *doesn't* add in the <driver name='vfio'/>.
This patch modifies the Xen code to behave similarly to the QEMU code - the PostParse just checks for a driver.type that isn't supported by the Xen driver, and any explicit setting to "xen" is deferred until domain runtime rather than during the postparse.
This delayed setting of driver.type of course results in slightly different xml2xml parse-format results, so the unit test data is modified accordingly.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/libxl/libxl_domain.c | 65 +++++++++++++++---- src/libxl/libxl_driver.c | 25 ++++--- tests/libxlxml2domconfigdata/moredevs-hvm.xml | 1 - tests/xlconfigdata/test-fullvirt-pci.xml | 2 - tests/xmconfigdata/test-pci-dev-syntax.xml | 2 - tests/xmconfigdata/test-pci-devs.xml | 2 - 6 files changed, 69 insertions(+), 28 deletions(-)
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 22482adfa6..ecdf57e655 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -160,8 +160,15 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev,
if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT && + pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN) { + + /* Xen only supports "Xen" style of hostdev, of course! */ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("XEN does not support device assignment mode '%1$s'"), + virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type)); + return -1; + } }
if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) { @@ -986,18 +993,9 @@ libxlNetworkPrepareDevices(virDomainDef *def) if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV && net->type == VIR_DOMAIN_NET_TYPE_NETWORK) { /* Each type='hostdev' network device must also have a - * corresponding entry in the hostdevs array. For netdevs - * that are hardcoded as type='hostdev', this is already - * done by the parser, but for those allocated from a - * network / determined at runtime, we need to do it - * separately. + * corresponding entry in the hostdevs array. */ virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net); - virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; - - if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN;
if (virDomainHostdevInsert(def, hostdev) < 0) return -1; @@ -1007,6 +1005,46 @@ libxlNetworkPrepareDevices(virDomainDef *def) return 0; }
+ +static int +libxlHostdevPrepareDevices(virDomainDef *def) +{ + size_t i; + + for (i = 0; i < def->nhostdevs; i++) { + virDomainHostdevDef *hostdev = def->hostdevs[i]; + virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; + + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && + pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { +
... and here I don't think it's obvious enough that the default must never change.
But is that the case? (that the default must never change, I mean) It's only going to make a difference if libxl adds support for some other type of PCI device assignment *and* there is something in that new type of device assignment that changes the guest ABI in an incompatible way. (I'm not certain, but I'm guessing that Xen doesn't live migration of domains with an assigned PCI device, so likely any guest would need to be fully shut down to move from the existing type of device assignment to some hypothetical new type that may exist at some time in the future. At the time that VFIO device assignment first became available, there was no <driver name='kvm'/> in any existing config, and no existing management app had a setting for the type of device assignment. This turned out to be a very *good* thing, because it meant that everyone began using VFIO device assignment by default immediately even on existing configs (and the newly-introduced <driver name='kvm|vfio'/> was only used if someone found a problem in VFIO and needed to temporarily switch back to KVM; fortunately I don't think anyone ever did). If we had instead required an explicit change to config for anyone to switch to using VFIO device assignment instead of legacy KVM device assignment (in addition to also requiring the management applications to add a knob to turn it on) it surely would have taken *years* longer for VFIO to be fully accepted/adopted, and it would have been a correspondingly longer time before the legacy KVM device assignment code could be deprecated and then finally removed from the kernel and qemu. Anyway, I don't see an advantage to explicitly writing into the config the value of a knob that only has one valid setting. If, at some point in the future, it turns out that libxl adds some new type of device assignment, and that new type of device assignement is incompatible with the current device assignment in such a way that they don't want users to automatically begin using it, then at that time it can just be explicitly stated that "not having the driver type set in the config means that the type is "legacy xen". But maybe that *won't* be needed, and it will be totally okay for everyone to just automatically start using this hypothetical "new type of device assignment for libxl"; why make the decision now that we shouldn't allow that? So have I convinced you, or should I drop it?

On Mon, Dec 18, 2023 at 01:14:55 -0500, Laine Stump wrote:
On 11/27/23 10:12 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:38:55 -0500, Laine Stump wrote:
Xen only supports a single type of PCI hostdev assignment, so it is superfluous to have <driver name='xen'/> peppered throughout the config. It *is* necessary to have the driver type explicitly set in the hosdev object before calling into the hypervisor-agnostic "hostdev manager" though (otherwise the hostdev manager doesn't know whether it should do Xen-specific setup, or VFIO-specific setup).
Historically, the Xen driver has checked for "default" driver type (i.e. not set in the XML), and set it to "xen', during the XML postparse, thus guaranteeing that it will be set by the time the object is sent to the hostdev manager at runtime, but also setting it so early that a simple round-trip of parse-format results in the XML always containing an explicit <driver name='xen'/>, even if that wasn't specified in the original XML.
Generally stuff that is written to the definition at parse time is done so that it doesn't change in the future, thus preserving ABI of machines created with a config where the default was not entered yet.
I don't think there was any intentional "lock in the default setting in the config to preserve ABI" in this case - it all seems to just be convenience/serendipity. From what I can see in the original code adding "PCI passthrough" to the libxl driver, they were just filling in the driver name in the xml because 1) it was there, and 2) they had just split out some of the code from qemu into "common code" to be used by both libxl and QEMU, needed a way to specify which driver was calling into this common code, saw the driver name as a convenient way to do it, and noticed that lots of other values that weren't set by the user were being set in the postparse, so that's where they set it in their code.
(BTW, there was code in the original commit adding PCI passthrough to libxl (commit 6225cb3df5a5732868719462f0a602ef11f7fa03) that logged an error if the driver name was anything other than empty (in which case it was set to "xen") or "xen". That code is still there today (see libxlNodeDeviceDetachFlags), so the Xen driver definiteoy only supports the one type of PCI device assignment.)
This commit message doesn't make an argument why the change is needed, so I'm a bit reluctant...
Well... the less use of the old usage of <driver name> there is, the better, and preventing it from being written into every single new config file with a <hostdev> means less use. Also this change makes the libxl driver more consistent with the behavior of the qemu driver (which has never set an explicit default in the postparse - it waits until the devices are being initialized for domain startup/hotplug before it sets the driver type (and it also always sets it to the same value).
I suppose I could omit this patch, but I think it's just perpetuating unintentional code that is inconsistent with the other driver (qemu) which serves to make it more difficult for a newcomer to understand what's going on with the <driver name/type> and what is the proper way to handle it in the case of some new hypervisor driver that decides to support <hostdev>.
The QEMU driver *doesn't* set driver.type during postparse though; instead, it waits until domain startup time (or device attach time for hotplug), and sets the driver.type then. The result is that a parse-format round trip of the XML in the QEMU driver *doesn't* add in the <driver name='vfio'/>.
This patch modifies the Xen code to behave similarly to the QEMU code - the PostParse just checks for a driver.type that isn't supported by the Xen driver, and any explicit setting to "xen" is deferred until domain runtime rather than during the postparse.
This delayed setting of driver.type of course results in slightly different xml2xml parse-format results, so the unit test data is modified accordingly.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/libxl/libxl_domain.c | 65 +++++++++++++++---- src/libxl/libxl_driver.c | 25 ++++--- tests/libxlxml2domconfigdata/moredevs-hvm.xml | 1 - tests/xlconfigdata/test-fullvirt-pci.xml | 2 - tests/xmconfigdata/test-pci-dev-syntax.xml | 2 - tests/xmconfigdata/test-pci-devs.xml | 2 - 6 files changed, 69 insertions(+), 28 deletions(-)
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 22482adfa6..ecdf57e655 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -160,8 +160,15 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev, if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT && + pcisrc->driver.type != VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN) { + + /* Xen only supports "Xen" style of hostdev, of course! */ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("XEN does not support device assignment mode '%1$s'"), + virDeviceHostdevPCIDriverTypeToString(pcisrc->driver.type)); + return -1; + } } if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) { @@ -986,18 +993,9 @@ libxlNetworkPrepareDevices(virDomainDef *def) if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV && net->type == VIR_DOMAIN_NET_TYPE_NETWORK) { /* Each type='hostdev' network device must also have a - * corresponding entry in the hostdevs array. For netdevs - * that are hardcoded as type='hostdev', this is already - * done by the parser, but for those allocated from a - * network / determined at runtime, we need to do it - * separately. + * corresponding entry in the hostdevs array. */ virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net); - virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; - - if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - pcisrc->driver.type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; if (virDomainHostdevInsert(def, hostdev) < 0) return -1; @@ -1007,6 +1005,46 @@ libxlNetworkPrepareDevices(virDomainDef *def) return 0; } + +static int +libxlHostdevPrepareDevices(virDomainDef *def) +{ + size_t i; + + for (i = 0; i < def->nhostdevs; i++) { + virDomainHostdevDef *hostdev = def->hostdevs[i]; + virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci; + + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && + pcisrc->driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_DEFAULT) { +
... and here I don't think it's obvious enough that the default must never change.
But is that the case? (that the default must never change, I mean) It's only going to make a difference if libxl adds support for some other type of PCI device assignment *and* there is something in that new type of device assignment that changes the guest ABI in an incompatible way. (I'm not certain, but I'm guessing that Xen doesn't live migration of domains with an assigned PCI device, so likely any guest would need to be fully shut down to move from the existing type of device assignment to some hypothetical new type that may exist at some time in the future.
At the time that VFIO device assignment first became available, there was no <driver name='kvm'/> in any existing config, and no existing management app had a setting for the type of device assignment. This turned out to be a very *good* thing, because it meant that everyone began using VFIO device assignment by default immediately even on existing configs (and the newly-introduced <driver name='kvm|vfio'/> was only used if someone found a problem in VFIO and needed to temporarily switch back to KVM; fortunately I don't think anyone ever did).
If we had instead required an explicit change to config for anyone to switch to using VFIO device assignment instead of legacy KVM device assignment (in addition to also requiring the management applications to add a knob to turn it on) it surely would have taken *years* longer for VFIO to be fully accepted/adopted, and it would have been a correspondingly longer time before the legacy KVM device assignment code could be deprecated and then finally removed from the kernel and qemu.
Anyway, I don't see an advantage to explicitly writing into the config the value of a knob that only has one valid setting. If, at some point in the future, it turns out that libxl adds some new type of device assignment, and that new type of device assignement is incompatible with the current device assignment in such a way that they don't want users to automatically begin using it, then at that time it can just be explicitly stated that "not having the driver type set in the config means that the type is "legacy xen". But maybe that *won't* be needed, and it will be totally okay for everyone to just automatically start using this hypothetical "new type of device assignment for libxl"; why make the decision now that we shouldn't allow that?
So have I convinced you, or should I drop it?
The explanation makes sense. You can mention in the commit message that this is mostly a backend thing so it's likely that it can be upgraded in the future in a compatible way. Ideally add a comment to the xen function stating that it can change if it's ABI compatible.

virHostdevIsVFIODevice() and virDomainDefHasVFIOHostdev() are only ever called from the QEMU driver, and in the case of the QEMU driver, any PCI hostdev by definition uses VFIO, so really all these callers only need to know if the device is a PCI hostdev. (It turned out that the less specific virHostdevIsPCIDevice() already existed in hypervisor/virhostdev.c, so I had to remove one of them; since conf is a lower level directory than hypervisor, and the function is called from conf, keeping the copy in hypervisor would have required moving its caller (virDomainDefHasPCIHostdev()) into hypervisor as well, so I just removed the copy in hypervisor.) Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/domain_conf.c | 13 ++++++------- src/conf/domain_conf.h | 4 ++-- src/hypervisor/virhostdev.c | 8 -------- src/hypervisor/virhostdev.h | 2 -- src/libvirt_private.syms | 5 ++--- src/qemu/qemu_domain.c | 6 +++--- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- 8 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d87ead291c..04d9de7f32 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30576,12 +30576,12 @@ virDomainDefHasNVMeDisk(const virDomainDef *def) bool -virDomainDefHasVFIOHostdev(const virDomainDef *def) +virDomainDefHasPCIHostdev(const virDomainDef *def) { size_t i; for (i = 0; i < def->nhostdevs; i++) { - if (virHostdevIsVFIODevice(def->hostdevs[i])) + if (virHostdevIsPCIDevice(def->hostdevs[i])) return true; } @@ -30852,17 +30852,16 @@ virHostdevIsMdevDevice(const virDomainHostdevDef *hostdev) /** - * virHostdevIsVFIODevice: + * virHostdevIsPCIDevice: * @hostdev: host device to check * - * Returns true if @hostdev is a PCI device with VFIO backend, false otherwise. + * Returns true if @hostdev is a PCI device, false otherwise. */ bool -virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev) +virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev) { return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - hostdev->source.subsys.u.pci.driver.type == VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 855e09d236..3ff02ec636 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -4405,7 +4405,7 @@ bool virDomainDefHasNVMeDisk(const virDomainDef *def); bool -virDomainDefHasVFIOHostdev(const virDomainDef *def); +virDomainDefHasPCIHostdev(const virDomainDef *def); bool virDomainDefHasMdevHostdev(const virDomainDef *def); @@ -4463,7 +4463,7 @@ bool virHostdevIsMdevDevice(const virDomainHostdevDef *hostdev) ATTRIBUTE_NONNULL(1); bool -virHostdevIsVFIODevice(const virDomainHostdevDef *hostdev) +virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev) ATTRIBUTE_NONNULL(1); int diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c index a33b3b604f..e0ad1371c2 100644 --- a/src/hypervisor/virhostdev.c +++ b/src/hypervisor/virhostdev.c @@ -344,14 +344,6 @@ virHostdevNetDevice(virDomainHostdevDef *hostdev, } -bool -virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev) -{ - return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && - hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; -} - - static bool virHostdevIsPCINetDevice(const virDomainHostdevDef *hostdev) { diff --git a/src/hypervisor/virhostdev.h b/src/hypervisor/virhostdev.h index 642d753ffb..22ec3068db 100644 --- a/src/hypervisor/virhostdev.h +++ b/src/hypervisor/virhostdev.h @@ -232,5 +232,3 @@ virHostdevUpdateActiveNVMeDevices(virHostdevManager *hostdev_mgr, const char *dom_name, virDomainDiskDef **disks, size_t ndisks); - -bool virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 479a69ed0b..a943a79e01 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -340,11 +340,11 @@ virDomainDefHasMemoryHotplug; virDomainDefHasNVMeDisk; virDomainDefHasOldStyleROUEFI; virDomainDefHasOldStyleUEFI; +virDomainDefHasPCIHostdev; virDomainDefHasSpiceGraphics; virDomainDefHasUSB; virDomainDefHasVcpusOffline; virDomainDefHasVDPANet; -virDomainDefHasVFIOHostdev; virDomainDefLifecycleActionAllowed; virDomainDefMaybeAddController; virDomainDefMaybeAddInput; @@ -777,8 +777,8 @@ virDomainEventWatchdogNewFromObj; virDomainQemuMonitorEventNew; virDomainQemuMonitorEventStateRegisterID; virHostdevIsMdevDevice; +virHostdevIsPCIDevice; virHostdevIsSCSIDevice; -virHostdevIsVFIODevice; # conf/domain_nwfilter.h @@ -1641,7 +1641,6 @@ virCloseCallbacksDomainRunForConn; # hypervisor/virhostdev.h virHostdevFindUSBDevice; -virHostdevIsPCIDevice; virHostdevManagerGetDefault; virHostdevPCINodeDeviceDetach; virHostdevPCINodeDeviceReAttach; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 09735ba710..37055fd6be 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -9380,7 +9380,7 @@ getPPC64MemLockLimitBytes(virDomainDef *def) for (i = 0; i < def->nhostdevs; i++) { virDomainHostdevDef *dev = def->hostdevs[i]; - if (virHostdevIsVFIODevice(dev)) { + if (virHostdevIsPCIDevice(dev)) { pciAddr = &dev->source.subsys.u.pci.addr; if (virPCIDeviceAddressIsValid(pciAddr, false)) { @@ -9485,7 +9485,7 @@ qemuDomainGetNumVFIOHostdevs(const virDomainDef *def) int n = 0; for (i = 0; i < def->nhostdevs; i++) { - if (virHostdevIsVFIODevice(def->hostdevs[i]) || + if (virHostdevIsPCIDevice(def->hostdevs[i]) || virHostdevIsMdevDevice(def->hostdevs[i])) n++; } @@ -10526,7 +10526,7 @@ qemuDomainSupportsVideoVga(const virDomainVideoDef *video, bool qemuDomainNeedsVFIO(const virDomainDef *def) { - return virDomainDefHasVFIOHostdev(def) || + return virDomainDefHasPCIHostdev(def) || virDomainDefHasMdevHostdev(def) || virDomainDefHasNVMeDisk(def); } diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 4992c23ee0..15b543dbff 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -133,7 +133,7 @@ qemuHostdevUpdateActiveDomainDevices(virQEMUDriver *driver, bool qemuHostdevNeedsVFIO(const virDomainHostdevDef *hostdev) { - return virHostdevIsVFIODevice(hostdev) || + return virHostdevIsPCIDevice(hostdev) || virHostdevIsMdevDevice(hostdev); } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index fec7c4be4e..dd2062a05b 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -4681,7 +4681,7 @@ qemuDomainRemoveHostDevice(virQEMUDriver *driver, virDomainAuditHostdev(vm, hostdev, "detach", true); - if (!virHostdevIsVFIODevice(hostdev) && + if (!virHostdevIsPCIDevice(hostdev) && qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0) VIR_WARN("Failed to restore host device labelling"); -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:56 -0500, Laine Stump wrote:
virHostdevIsVFIODevice() and virDomainDefHasVFIOHostdev() are only ever called from the QEMU driver, and in the case of the QEMU driver, any PCI hostdev by definition uses VFIO, so really all these callers only need to know if the device is a PCI hostdev.
(It turned out that the less specific virHostdevIsPCIDevice() already existed in hypervisor/virhostdev.c, so I had to remove one of them; since conf is a lower level directory than hypervisor, and the function is called from conf, keeping the copy in hypervisor would have required moving its caller (virDomainDefHasPCIHostdev()) into hypervisor as well, so I just removed the copy in hypervisor.)
Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/domain_conf.c | 13 ++++++------- src/conf/domain_conf.h | 4 ++-- src/hypervisor/virhostdev.c | 8 -------- src/hypervisor/virhostdev.h | 2 -- src/libvirt_private.syms | 5 ++--- src/qemu/qemu_domain.c | 6 +++--- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- 8 files changed, 15 insertions(+), 27 deletions(-)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

This patch makes it possible to manually specify which VFIO variant driver to use for PCI hostdev device assignment, so that, e.g. you could force use of the generic vfio-pci driver with <driver name='vfio-pci'/> when libvirt would have normally (after applying a subsequent patch) found a "better match" for a device in the active kernel's modules.alias file. (The main use of this manual override would be to work around a bug in a new VFIO variant driver by temporarily not using that driver). This sounds like a simple addition to XML parsing/formatting, but of course it's messier than that, since the attribute we want to use was previously used in config for a now non-existent purpose (choosing a type of device assignment that was removed from the kernel nearly a decade ago), and continues to be used *internal to the C code*. Background: Beginning when VFIO device assignment support was added to <hostdev> or <interface type='hostdev'/>) in libvirt's QEMU driver, it was possible to specify which device assignment backend to use with "<driver name='vfio|kvm'/>". This was only useful for a couple of years in the early 2010's when VFIO device assignment was newly introduced, but "legacy KVM" device assignment was still possible (in reality "<driver name='blah'/>" was only intended to be used (1) in the *very* early days of VFIO when "kvm" was still the default, or (2) when the host kernel was too old to have VFIO support (meaning it was e.g. pre-RHEL7) or (3) some bug was encountered with the then-new VFIO code that could have been avoided by switching back to the older style of device assignment (I don't recall anyone ever needing to set it for this reason, but that is one of the main reasons we added the knob). Later, when the libxl (Xen) driver in libvirt began supporting "device passthrough" with <hostdev>, they added <driver name='xen'/> to indicate that mode of operation. But in practice this was also never necessary in any config, since Xen only supports one type of device assignment, and so the attribute was anyway set in the C object by the libxl driver code prior to calling any hypervisor-common code (i.e. the stuff in hypervisor/hostdev.c and util/virpci.c) that needs to know which type of device assignment is being used - setting it in the XML config was superfluous (kind of like me saying "I am now describing this patch in a human language", ref: Perd Hapley on "Parks and Recreation"). So the setting was available in the XML, but never needed to be set by the user. Because it was automatically set in the C code though, sometimes libvirt-generated XML would contain the option even though the user hadn't included it in the original input XML (e.g. the libxl driver sets it in the PostParse, so all saved configs with a PCI <hostdev> device will have <driver name='xen'/>; also status XML from the QEMU and libxl drivers will contain <driver name='vfio|xen'/> - in both cases completely unnecessary and redundant information). When adding support for specifying a variant driver for VFIO device assignment, from the beginning I have wanted to use <driver name='blah'/> to force a specific variant driver (e.g. <driver name='mlx5_vfio_pci'/>), with the assumption that the name attribute could be easily repurposed because it had been *completely* unused for so long. What I discovered though, was that 1) the field in the C object corresponding to driver name was an enum value rather than a string (so parser and formatter need to be changed, not just the driver code looking at a string in the C object), and 2) even though the XML attribute was effectively unused (except in some output), the field in the C object was *always* being set internally as a way for the hypervisor driver code to inform the hypervisor-common hostdev manager (in src/hypervisor) which method of device assignment to use. So re-use wasn't as simple as I'd wished. However. What I have hit upon that permits us to use <driver name='mlx5_vfio_pci'/> is to do the following: 1) rename the existing driver name attribute to driver *type* - this will now be the enum that is set internally by the hypervisor driver prior to calling the hostdev manager (and also is what will show up in status XML; the libxl driver was modified in a previous patch so that the setting isn't done until domain runtime (rather than during PostParse), so it will no longer show up in regurgitated libxml config) 2) add a new attribute with the now-newly-unused name "name" - this will be a string that can be used to communicate a specific host kernel driver to the hostdev manager. 3) In the parsing code for <driver>, if <driver name='vfio|xen|kvm'/> is encountered, set the driver *type* to the appropriate enum instead, and clear our the name string. (since the four places that use the hostdev <driver> element now all call a common parser function, this check is only needed in a single place) I could alternately just leave "name" as-is, and create a new attribute with a never-before-used name within driver. I suppose instead of "type" and "name", we could instead have "name and "model" (where "model" would be the string that could be set to "mlx5_vfio_pci"). I just prefer type/name to name/model, and think it's been long enough since <driver name='blah'/> has had a useful purpose (and the fixup for backward compatibility is limited to a few lines in one function) that this change is safe. (another alternate would be to add an extra parameter to the C API that calls into the hostdev manager rather than keeping/adding the publicly visible "type" attribute, but it seems at least possible that sometime in the future another alternate "type" of device assignment could be introduced for either Xen or QEMU, and we would then need to add back the XML attribute anyway) I'd be fine with doing it one of the other ways, but decided to post this way first, since it's the one that I find the most aesthetically pleasing :-) Note that a few test cases have been modified - places where an existing "name='vfio'" was changed to "type='vfio'" were in in status XML or only the *output* XML for a test (except the case of the virnetworkportxml2xmltest, which doesn't have a separate directory for the XML result; fortunately the converged parsing of <driver> between domain/network/networkport means that the test cases for network and domain XML are already testing the same code that would convert "name" to "type" in thte networkport XML) Signed-off-by: Laine Stump <laine@redhat.com> --- docs/formatdomain.rst | 55 +++++++++++++------ src/conf/device_conf.c | 29 +++++++++- src/conf/device_conf.h | 4 ++ src/conf/domain_conf.c | 1 + src/conf/network_conf.c | 2 + src/conf/schemas/basictypes.rng | 21 ++++--- src/conf/virnetworkportdef.c | 1 + tests/networkxml2xmlin/hostdev-pf-old.xml | 8 +++ tests/networkxml2xmlin/hostdev-pf.xml | 2 +- tests/networkxml2xmlout/hostdev-pf-old.xml | 8 +++ tests/networkxml2xmlout/hostdev-pf.xml | 2 +- tests/networkxml2xmltest.c | 6 ++ .../qemuhotplug-hostdev-pci.xml | 1 - .../qemuhotplug-base-live+hostdev-pci.xml | 2 +- ...uhotplug-pseries-base-live+hostdev-pci.xml | 2 +- tests/qemustatusxml2xmldata/modern-in.xml | 2 +- .../hostdev-vfio.x86_64-latest.args | 5 +- tests/qemuxml2argvdata/hostdev-vfio.xml | 18 ++++++ .../hostdev-vfio.x86_64-latest.xml | 23 +++++++- .../plug-hostdev-pci-unmanaged.xml | 2 +- .../plug-hostdev-pci.xml | 2 +- 21 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 tests/networkxml2xmlin/hostdev-pf-old.xml create mode 100644 tests/networkxml2xmlout/hostdev-pf-old.xml diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 459815d2b5..d67421a054 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -4500,24 +4500,47 @@ or: an error. See the `Device Addresses`_ section for more details on the address element. ``driver`` - PCI devices can have an optional ``driver`` subelement that specifies which - backend driver to use for PCI device assignment. Use the ``name`` attribute - to select either "vfio" (for the new VFIO device assignment backend, which is - compatible with UEFI SecureBoot) or "kvm" (the legacy device assignment - handled directly by the KVM kernel module) :since:`Since 1.0.5 (QEMU and KVM - only, requires kernel 3.6 or newer)` . When specified, device assignment will - fail if the requested method of device assignment isn't available on the - host. When not specified, the default is "vfio" on systems where the VFIO - driver is available and loaded, and "kvm" on older systems, or those where - the VFIO driver hasn't been loaded :since:`Since 1.1.3` (prior to that the - default was always "kvm"). + PCI hostdev devices can have an optional ``driver`` subelement that + specifies which host driver to bind to the device when preparing it + for assignment to a guest. :since:`Since 9.10.0 (useful for QEMU and + KVM only)`. This is done by setting the ``<driver>`` element's ``name`` + attribute, for example:: + + ... + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio-pci-igb'/> + ... + + tells libvirt to bind the driver "vfio-pci-igb" to the device on + the host before handing it off to QEMU for assignment to the + guest. Normally libvirt will bind the device to the "best match" + VFIO-type driver that it finds in the kernel's modules.alias file + (based on matching the corresponding fields of the device's + modalias file in sysfs) or to the generic "vfio-pci" driver if no + better match is found (vfio-pci is always used prior to libvirt + 9.10.0), but in cases when the correct driver isn't listed in + modules.alias then the desired device-specific driver can be forced + by setting driver name, or if the device-specific driver that is + found is "problematic" in some way, the generic vfio-pci driver + similarly be forced. + + (Note: in versions of libvirt prior to 9.10.0 (:since:`Since + 1.0.5), the ``name`` attribute was described to be used to select + the type of device assignment ("vfio", "kvm", or "xen"), but those + values have been mostly useless, since the type of device + assignment is actually determined by which hypservisor is in + use. This means that you may occasionally see ``<driver + name='vfio'/>`` or ``<driver name='xen'/>`` in a domain's status + XML, or more rarely in config, but those specific values are + essentially ignored.) + ``readonly`` - Indicates that the device is readonly, only supported by SCSI host device - now. :since:`Since 1.0.6 (QEMU and KVM only)` + Indicates that the device is readonly, only supported by SCSI host + device now. :since:`Since 1.0.6 (QEMU and KVM only)` ``shareable`` - If present, this indicates the device is expected to be shared between - domains (assuming the hypervisor and OS support this). Only supported by SCSI - host device. :since:`Since 1.0.6` + If present, this indicates the device is expected to be shared + between domains (assuming the hypervisor and OS support this). Only + supported by SCSI host device. :since:`Since 1.0.6` Note: Although ``shareable`` was introduced :since:`in 1.0.6` , it did not work as as expected until :since:`1.2.2` . diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index e022783816..2ad7232678 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -60,13 +60,29 @@ int virDeviceHostdevPCIDriverInfoParseXML(xmlNodePtr node, virDeviceHostdevPCIDriverInfo *driver) { - if (virXMLPropEnum(node, "name", + if (virXMLPropEnum(node, "type", virDeviceHostdevPCIDriverTypeFromString, VIR_XML_PROP_NONZERO, &driver->type) < 0) { return -1; } + driver->name = virXMLPropString(node, "name"); + + /* translate special case of <driver name='vfio|xen|kvm'/> to + * <driver type='vfio|xen|kvm'/> for backward compatibility + */ + if (STREQ_NULLABLE(driver->name, "vfio")) { + driver->type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_VFIO; + VIR_FREE(driver->name); + } else if (STREQ_NULLABLE(driver->name, "xen")) { + driver->type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_XEN; + VIR_FREE(driver->name); + } else if (STREQ_NULLABLE(driver->name, "kvm")) { + driver->type = VIR_DEVICE_HOSTDEV_PCI_DRIVER_TYPE_KVM; + VIR_FREE(driver->name); + } + return 0; } @@ -88,14 +104,23 @@ virDeviceHostdevPCIDriverInfoFormat(virBuffer *buf, return -1; } - virBufferAsprintf(&driverAttrBuf, " name='%s'", driverType); + virBufferAsprintf(&driverAttrBuf, " type='%s'", driverType); } + virBufferEscapeString(&driverAttrBuf, " name='%s'", driver->name); + virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL); return 0; } +void +virDeviceHostdevPCIDriverInfoClear(virDeviceHostdevPCIDriverInfo *driver) +{ + VIR_FREE(driver->name); +} + + static int virZPCIDeviceAddressParseXML(xmlNodePtr node, virPCIDeviceAddress *addr) diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 9f4b9f5375..cccc60cb29 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -46,6 +46,7 @@ VIR_ENUM_DECL(virDeviceHostdevPCIDriver); struct _virDeviceHostdevPCIDriverInfo { virDeviceHostdevPCIDriverType type; + char *name; }; typedef enum { @@ -192,6 +193,9 @@ int virDeviceHostdevPCIDriverInfoParseXML(xmlNodePtr node, int virDeviceHostdevPCIDriverInfoFormat(virBuffer *buf, const virDeviceHostdevPCIDriverInfo *driver); +void virDeviceHostdevPCIDriverInfoPostParse(virDeviceHostdevPCIDriverInfo *driver); +void virDeviceHostdevPCIDriverInfoClear(virDeviceHostdevPCIDriverInfo *driver); + void virDomainDeviceInfoClear(virDomainDeviceInfo *info); void virDomainDeviceInfoFree(virDomainDeviceInfo *info); diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 04d9de7f32..3b11b927b5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2635,6 +2635,7 @@ virDomainHostdevDefClear(virDomainHostdevDef *def) VIR_FREE(def->source.subsys.u.scsi_host.wwpn); break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + virDeviceHostdevPCIDriverInfoClear(&def->source.subsys.u.pci.driver); g_clear_pointer(&def->source.subsys.u.pci.origstates, virBitmapFree); break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 2d78d588aa..c8ced95af6 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -229,6 +229,8 @@ virNetworkForwardDefClear(virNetworkForwardDef *def) { size_t i; + virDeviceHostdevPCIDriverInfoClear(&def->driver); + for (i = 0; i < def->npfs && def->pfs; i++) virNetworkForwardPfDefClear(&def->pfs[i]); VIR_FREE(def->pfs); diff --git a/src/conf/schemas/basictypes.rng b/src/conf/schemas/basictypes.rng index 8d5f4475ca..46e8a493f7 100644 --- a/src/conf/schemas/basictypes.rng +++ b/src/conf/schemas/basictypes.rng @@ -658,13 +658,20 @@ <define name="hostdevDriver"> <element name="driver"> - <attribute name="name"> - <choice> - <value>kvm</value> - <value>vfio</value> - <value>xen</value> - </choice> - </attribute> + <optional> + <attribute name="type"> + <choice> + <value>kvm</value> + <value>vfio</value> + <value>xen</value> + </choice> + </attribute> + </optional> + <optional> + <attribute name="name"> + <ref name="genericName"/> + </attribute> + </optional> <empty/> </element> </define> diff --git a/src/conf/virnetworkportdef.c b/src/conf/virnetworkportdef.c index 49d00b2ea6..64db63ae66 100644 --- a/src/conf/virnetworkportdef.c +++ b/src/conf/virnetworkportdef.c @@ -64,6 +64,7 @@ virNetworkPortDefFree(virNetworkPortDef *def) break; case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI: + virDeviceHostdevPCIDriverInfoClear(&def->plug.hostdevpci.driver); break; case VIR_NETWORK_PORT_PLUG_TYPE_LAST: diff --git a/tests/networkxml2xmlin/hostdev-pf-old.xml b/tests/networkxml2xmlin/hostdev-pf-old.xml new file mode 100644 index 0000000000..5b8f59858c --- /dev/null +++ b/tests/networkxml2xmlin/hostdev-pf-old.xml @@ -0,0 +1,8 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode='hostdev' managed='yes'> + <driver name='vfio'/> + <pf dev='eth2'/> + </forward> +</network> diff --git a/tests/networkxml2xmlin/hostdev-pf.xml b/tests/networkxml2xmlin/hostdev-pf.xml index 5b8f59858c..72a3049800 100644 --- a/tests/networkxml2xmlin/hostdev-pf.xml +++ b/tests/networkxml2xmlin/hostdev-pf.xml @@ -2,7 +2,7 @@ <name>hostdev</name> <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> <forward mode='hostdev' managed='yes'> - <driver name='vfio'/> + <driver type='vfio'/> <pf dev='eth2'/> </forward> </network> diff --git a/tests/networkxml2xmlout/hostdev-pf-old.xml b/tests/networkxml2xmlout/hostdev-pf-old.xml new file mode 100644 index 0000000000..72a3049800 --- /dev/null +++ b/tests/networkxml2xmlout/hostdev-pf-old.xml @@ -0,0 +1,8 @@ +<network> + <name>hostdev</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward mode='hostdev' managed='yes'> + <driver type='vfio'/> + <pf dev='eth2'/> + </forward> +</network> diff --git a/tests/networkxml2xmlout/hostdev-pf.xml b/tests/networkxml2xmlout/hostdev-pf.xml index 5b8f59858c..72a3049800 100644 --- a/tests/networkxml2xmlout/hostdev-pf.xml +++ b/tests/networkxml2xmlout/hostdev-pf.xml @@ -2,7 +2,7 @@ <name>hostdev</name> <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> <forward mode='hostdev' managed='yes'> - <driver name='vfio'/> + <driver type='vfio'/> <pf dev='eth2'/> </forward> </network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index b0814c7529..928f28b579 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -146,6 +146,12 @@ mymain(void) DO_TEST_FLAGS("passthrough-pf", VIR_NETWORK_XML_INACTIVE); DO_TEST("hostdev"); DO_TEST_FLAGS("hostdev-pf", VIR_NETWORK_XML_INACTIVE); + + /* libvirt pre-9.9.0 used "name='vfio'" which should be + * automatically translated to "type='vfio'" by new parser + */ + DO_TEST_FLAGS("hostdev-pf-old", VIR_NETWORK_XML_INACTIVE); + DO_TEST("passthrough-address-crash"); DO_TEST("nat-network-explicit-flood"); DO_TEST("host-bridge-no-flood"); diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml b/tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml index 6f7c99c943..0d6dec9d26 100644 --- a/tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml +++ b/tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml @@ -1,5 +1,4 @@ <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> </source> diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml index e49e21c53e..b14f184044 100644 --- a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml +++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml @@ -49,7 +49,7 @@ </input> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> + <driver type='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> </source> diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml index 13d10e57aa..02b66a3590 100644 --- a/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml +++ b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml @@ -41,7 +41,7 @@ </input> <audio id='1' type='none'/> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> + <driver type='vfio'/> <source> <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> </source> diff --git a/tests/qemustatusxml2xmldata/modern-in.xml b/tests/qemustatusxml2xmldata/modern-in.xml index 67e0aa4952..299046331e 100644 --- a/tests/qemustatusxml2xmldata/modern-in.xml +++ b/tests/qemustatusxml2xmldata/modern-in.xml @@ -502,7 +502,7 @@ <address type='drive' controller='0' bus='0' target='2' unit='4'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> - <driver name='vfio'/> + <driver type='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/> <origstates> diff --git a/tests/qemuxml2argvdata/hostdev-vfio.x86_64-latest.args b/tests/qemuxml2argvdata/hostdev-vfio.x86_64-latest.args index c1f9258844..8529cde269 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio.x86_64-latest.args +++ b/tests/qemuxml2argvdata/hostdev-vfio.x86_64-latest.args @@ -32,6 +32,9 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest2/.config \ -device '{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-format","id":"ide0-0-0","bootindex":1}' \ -audiodev '{"id":"audio1","driver":"none"}' \ -device '{"driver":"vfio-pci","host":"0000:06:12.1","id":"hostdev0","bus":"pci.0","addr":"0x2"}' \ --device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x3"}' \ +-device '{"driver":"vfio-pci","host":"0000:06:12.2","id":"hostdev1","bus":"pci.0","addr":"0x3"}' \ +-device '{"driver":"vfio-pci","host":"0000:06:12.3","id":"hostdev2","bus":"pci.0","addr":"0x4"}' \ +-device '{"driver":"vfio-pci","host":"0000:06:12.4","id":"hostdev3","bus":"pci.0","addr":"0x5"}' \ +-device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x6"}' \ -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ -msg timestamp=on diff --git a/tests/qemuxml2argvdata/hostdev-vfio.xml b/tests/qemuxml2argvdata/hostdev-vfio.xml index a03870f6e0..609714ab06 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio.xml @@ -29,6 +29,24 @@ <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver type='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x3'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio-pci-igb'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x4'/> + </source> + </hostdev> <memballoon model='virtio'/> </devices> </domain> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml b/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml index 3915b515f2..bae07de8d2 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio.x86_64-latest.xml @@ -39,8 +39,29 @@ </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </hostdev> - <memballoon model='virtio'> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver type='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver type='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x3'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio-pci-igb'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x4'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </hostdev> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> </devices> </domain> diff --git a/tests/virnetworkportxml2xmldata/plug-hostdev-pci-unmanaged.xml b/tests/virnetworkportxml2xmldata/plug-hostdev-pci-unmanaged.xml index da5f568031..5d9f7cae73 100644 --- a/tests/virnetworkportxml2xmldata/plug-hostdev-pci-unmanaged.xml +++ b/tests/virnetworkportxml2xmldata/plug-hostdev-pci-unmanaged.xml @@ -6,7 +6,7 @@ </owner> <mac address='52:54:00:7b:35:93'/> <plug type='hostdev-pci' managed='no'> - <driver name='vfio'/> + <driver type='vfio'/> <address domain='0x0001' bus='0x02' slot='0x03' function='0x4'/> </plug> </networkport> diff --git a/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml b/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml index cc4419f3fd..d216fc916e 100644 --- a/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml +++ b/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml @@ -6,7 +6,7 @@ </owner> <mac address='52:54:00:7b:35:93'/> <plug type='hostdev-pci' managed='yes'> - <driver name='vfio'/> + <driver type='vfio'/> <address domain='0x0001' bus='0x02' slot='0x03' function='0x4'/> </plug> </networkport> -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:57 -0500, Laine Stump wrote:
This patch makes it possible to manually specify which VFIO variant driver to use for PCI hostdev device assignment, so that, e.g. you could force use of the generic vfio-pci driver with
<driver name='vfio-pci'/>
when libvirt would have normally (after applying a subsequent patch) found a "better match" for a device in the active kernel's modules.alias file. (The main use of this manual override would be to work around a bug in a new VFIO variant driver by temporarily not using that driver).
This sounds like a simple addition to XML parsing/formatting, but of course it's messier than that, since the attribute we want to use was previously used in config for a now non-existent purpose (choosing a type of device assignment that was removed from the kernel nearly a decade ago), and continues to be used *internal to the C code*.
Background:
Beginning when VFIO device assignment support was added to <hostdev> or <interface type='hostdev'/>) in libvirt's QEMU driver, it was possible to specify which device assignment backend to use with "<driver name='vfio|kvm'/>". This was only useful for a couple of years in the early 2010's when VFIO device assignment was newly introduced, but "legacy KVM" device assignment was still possible (in reality "<driver name='blah'/>" was only intended to be used (1) in the *very* early days of VFIO when "kvm" was still the default, or (2) when the host kernel was too old to have VFIO support (meaning it was e.g. pre-RHEL7) or (3) some bug was encountered with the then-new VFIO code that could have been avoided by switching back to the older style of device assignment (I don't recall anyone ever needing to set it for this reason, but that is one of the main reasons we added the knob).
Later, when the libxl (Xen) driver in libvirt began supporting "device passthrough" with <hostdev>, they added <driver name='xen'/> to indicate that mode of operation. But in practice this was also never necessary in any config, since Xen only supports one type of device assignment, and so the attribute was anyway set in the C object by the libxl driver code prior to calling any hypervisor-common code (i.e. the stuff in hypervisor/hostdev.c and util/virpci.c) that needs to know which type of device assignment is being used - setting it in the XML config was superfluous (kind of like me saying "I am now describing this patch in a human language", ref: Perd Hapley on "Parks and Recreation").
So the setting was available in the XML, but never needed to be set by the user. Because it was automatically set in the C code though, sometimes libvirt-generated XML would contain the option even though the user hadn't included it in the original input XML (e.g. the libxl driver sets it in the PostParse, so all saved configs with a PCI <hostdev> device will have <driver name='xen'/>; also status XML from the QEMU and libxl drivers will contain <driver name='vfio|xen'/> - in both cases completely unnecessary and redundant information).
When adding support for specifying a variant driver for VFIO device assignment, from the beginning I have wanted to use <driver name='blah'/> to force a specific variant driver (e.g. <driver name='mlx5_vfio_pci'/>), with the assumption that the name attribute could be easily repurposed because it had been *completely* unused for so long. What I discovered though, was that 1) the field in the C object corresponding to driver name was an enum value rather than a string (so parser and formatter need to be changed, not just the driver code looking at a string in the C object), and 2) even though the XML attribute was effectively unused (except in some output), the field in the C object was *always* being set internally as a way for the hypervisor driver code to inform the hypervisor-common hostdev manager (in src/hypervisor) which method of device assignment to use. So re-use wasn't as simple as I'd wished.
However.
What I have hit upon that permits us to use <driver name='mlx5_vfio_pci'/> is to do the following:
1) rename the existing driver name attribute to driver *type* - this will now be the enum that is set internally by the hypervisor driver prior to calling the hostdev manager (and also is what will show up in status XML; the libxl driver was modified in a previous patch so that the setting isn't done until domain runtime (rather than during PostParse), so it will no longer show up in regurgitated libxml config)
2) add a new attribute with the now-newly-unused name "name" - this will be a string that can be used to communicate a specific host kernel driver to the hostdev manager.
3) In the parsing code for <driver>, if <driver name='vfio|xen|kvm'/> is encountered, set the driver *type* to the appropriate enum instead, and clear our the name string. (since the four places that use the hostdev <driver> element now all call a common parser function, this check is only needed in a single place)
I could alternately just leave "name" as-is, and create a new attribute with a never-before-used name within driver. I suppose instead of "type" and "name", we could instead have "name and "model" (where "model" would be the string that could be set to "mlx5_vfio_pci"). I just prefer type/name to name/model, and think it's been long enough since <driver name='blah'/> has had a useful purpose (and the fixup for backward compatibility is limited to a few lines in one function) that this change is safe.
I'm not entirely sold on the reusing of the 'name' attribute and this paragraph seems to confirm that it's just for optics. I'm a bit worried that some tool may be checking the output here however useless it is and that tool might then need changing just because we wanted "better looking" attribute names.
(another alternate would be to add an extra parameter to the C API that calls into the hostdev manager rather than keeping/adding the publicly visible "type" attribute, but it seems at least possible that sometime in the future another alternate "type" of device assignment could be introduced for either Xen or QEMU, and we would then need to add back the XML attribute anyway)
I'd be fine with doing it one of the other ways, but decided to post this way first, since it's the one that I find the most aesthetically pleasing :-)
Okay this paragraph is a bit too much of discussion for a commit message. Please put stuff like this under the lines or as a RFC question.
Note that a few test cases have been modified - places where an existing "name='vfio'" was changed to "type='vfio'" were in in status XML or only the *output* XML for a test (except the case of the virnetworkportxml2xmltest, which doesn't have a separate directory for the XML result; fortunately the converged parsing of <driver> between domain/network/networkport means that the test cases for network and domain XML are already testing the same code that would convert "name" to "type" in thte networkport XML)
Signed-off-by: Laine Stump <laine@redhat.com> ---
The code looks okay but I'm not a fan of the rename for cosmetical reasons. Especially if we fiddle with the value in the field with original name and display it back to the user/management sw.

On 11/28/23 9:58 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:38:57 -0500, Laine Stump wrote:
This patch makes it possible to manually specify which VFIO variant driver to use for PCI hostdev device assignment, so that, e.g. you could force use of the generic vfio-pci driver with
<driver name='vfio-pci'/>
when libvirt would have normally (after applying a subsequent patch) found a "better match" for a device in the active kernel's modules.alias file. (The main use of this manual override would be to work around a bug in a new VFIO variant driver by temporarily not using that driver).
This sounds like a simple addition to XML parsing/formatting, but of course it's messier than that, since the attribute we want to use was previously used in config for a now non-existent purpose (choosing a type of device assignment that was removed from the kernel nearly a decade ago), and continues to be used *internal to the C code*.
Background:
Beginning when VFIO device assignment support was added to <hostdev> or <interface type='hostdev'/>) in libvirt's QEMU driver, it was possible to specify which device assignment backend to use with "<driver name='vfio|kvm'/>". This was only useful for a couple of years in the early 2010's when VFIO device assignment was newly introduced, but "legacy KVM" device assignment was still possible (in reality "<driver name='blah'/>" was only intended to be used (1) in the *very* early days of VFIO when "kvm" was still the default, or (2) when the host kernel was too old to have VFIO support (meaning it was e.g. pre-RHEL7) or (3) some bug was encountered with the then-new VFIO code that could have been avoided by switching back to the older style of device assignment (I don't recall anyone ever needing to set it for this reason, but that is one of the main reasons we added the knob).
Later, when the libxl (Xen) driver in libvirt began supporting "device passthrough" with <hostdev>, they added <driver name='xen'/> to indicate that mode of operation. But in practice this was also never necessary in any config, since Xen only supports one type of device assignment, and so the attribute was anyway set in the C object by the libxl driver code prior to calling any hypervisor-common code (i.e. the stuff in hypervisor/hostdev.c and util/virpci.c) that needs to know which type of device assignment is being used - setting it in the XML config was superfluous (kind of like me saying "I am now describing this patch in a human language", ref: Perd Hapley on "Parks and Recreation").
So the setting was available in the XML, but never needed to be set by the user. Because it was automatically set in the C code though, sometimes libvirt-generated XML would contain the option even though the user hadn't included it in the original input XML (e.g. the libxl driver sets it in the PostParse, so all saved configs with a PCI <hostdev> device will have <driver name='xen'/>; also status XML from the QEMU and libxl drivers will contain <driver name='vfio|xen'/> - in both cases completely unnecessary and redundant information).
When adding support for specifying a variant driver for VFIO device assignment, from the beginning I have wanted to use <driver name='blah'/> to force a specific variant driver (e.g. <driver name='mlx5_vfio_pci'/>), with the assumption that the name attribute could be easily repurposed because it had been *completely* unused for so long. What I discovered though, was that 1) the field in the C object corresponding to driver name was an enum value rather than a string (so parser and formatter need to be changed, not just the driver code looking at a string in the C object), and 2) even though the XML attribute was effectively unused (except in some output), the field in the C object was *always* being set internally as a way for the hypervisor driver code to inform the hypervisor-common hostdev manager (in src/hypervisor) which method of device assignment to use. So re-use wasn't as simple as I'd wished.
However.
What I have hit upon that permits us to use <driver name='mlx5_vfio_pci'/> is to do the following:
1) rename the existing driver name attribute to driver *type* - this will now be the enum that is set internally by the hypervisor driver prior to calling the hostdev manager (and also is what will show up in status XML; the libxl driver was modified in a previous patch so that the setting isn't done until domain runtime (rather than during PostParse), so it will no longer show up in regurgitated libxml config)
2) add a new attribute with the now-newly-unused name "name" - this will be a string that can be used to communicate a specific host kernel driver to the hostdev manager.
3) In the parsing code for <driver>, if <driver name='vfio|xen|kvm'/> is encountered, set the driver *type* to the appropriate enum instead, and clear our the name string. (since the four places that use the hostdev <driver> element now all call a common parser function, this check is only needed in a single place)
I could alternately just leave "name" as-is, and create a new attribute with a never-before-used name within driver. I suppose instead of "type" and "name", we could instead have "name and "model" (where "model" would be the string that could be set to "mlx5_vfio_pci"). I just prefer type/name to name/model, and think it's been long enough since <driver name='blah'/> has had a useful purpose (and the fixup for backward compatibility is limited to a few lines in one function) that this change is safe.
I'm not entirely sold on the reusing of the 'name' attribute and this paragraph seems to confirm that it's just for optics.
I'm a bit worried that some tool may be checking the output here however useless it is and that tool might then need changing just because we wanted "better looking" attribute names.
Sigh. Yeah, you're probably right. Okay, so how about keeping <driver name='vfio|xen'> (but still minimizing its auto-generation as much as possible), and using <driver model='blah'/> when we want to specify a particular driver?
(another alternate would be to add an extra parameter to the C API that calls into the hostdev manager rather than keeping/adding the publicly visible "type" attribute, but it seems at least possible that sometime in the future another alternate "type" of device assignment could be introduced for either Xen or QEMU, and we would then need to add back the XML attribute anyway)
I'd be fine with doing it one of the other ways, but decided to post this way first, since it's the one that I find the most aesthetically pleasing :-)
Okay this paragraph is a bit too much of discussion for a commit message. Please put stuff like this under the lines or as a RFC question.
Yeah, I meant to do that but forgot.
Note that a few test cases have been modified - places where an existing "name='vfio'" was changed to "type='vfio'" were in in status XML or only the *output* XML for a test (except the case of the virnetworkportxml2xmltest, which doesn't have a separate directory for the XML result; fortunately the converged parsing of <driver> between domain/network/networkport means that the test cases for network and domain XML are already testing the same code that would convert "name" to "type" in thte networkport XML)
Signed-off-by: Laine Stump <laine@redhat.com> ---
The code looks okay but I'm not a fan of the rename for cosmetical reasons. Especially if we fiddle with the value in the field with original name and display it back to the user/management sw.
I'll redo everything to use <driver model> and try to get it posted in the next day or two. If you or anyone else thinks of a better name let me know.

On Mon, Dec 18, 2023 at 01:25:02 -0500, Laine Stump wrote:
On 11/28/23 9:58 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:38:57 -0500, Laine Stump wrote:
This patch makes it possible to manually specify which VFIO variant driver to use for PCI hostdev device assignment, so that, e.g. you could force use of the generic vfio-pci driver with
<driver name='vfio-pci'/>
when libvirt would have normally (after applying a subsequent patch) found a "better match" for a device in the active kernel's modules.alias file. (The main use of this manual override would be to work around a bug in a new VFIO variant driver by temporarily not using that driver).
This sounds like a simple addition to XML parsing/formatting, but of course it's messier than that, since the attribute we want to use was previously used in config for a now non-existent purpose (choosing a type of device assignment that was removed from the kernel nearly a decade ago), and continues to be used *internal to the C code*.
Background:
Beginning when VFIO device assignment support was added to <hostdev> or <interface type='hostdev'/>) in libvirt's QEMU driver, it was possible to specify which device assignment backend to use with "<driver name='vfio|kvm'/>". This was only useful for a couple of years in the early 2010's when VFIO device assignment was newly introduced, but "legacy KVM" device assignment was still possible (in reality "<driver name='blah'/>" was only intended to be used (1) in the *very* early days of VFIO when "kvm" was still the default, or (2) when the host kernel was too old to have VFIO support (meaning it was e.g. pre-RHEL7) or (3) some bug was encountered with the then-new VFIO code that could have been avoided by switching back to the older style of device assignment (I don't recall anyone ever needing to set it for this reason, but that is one of the main reasons we added the knob).
Later, when the libxl (Xen) driver in libvirt began supporting "device passthrough" with <hostdev>, they added <driver name='xen'/> to indicate that mode of operation. But in practice this was also never necessary in any config, since Xen only supports one type of device assignment, and so the attribute was anyway set in the C object by the libxl driver code prior to calling any hypervisor-common code (i.e. the stuff in hypervisor/hostdev.c and util/virpci.c) that needs to know which type of device assignment is being used - setting it in the XML config was superfluous (kind of like me saying "I am now describing this patch in a human language", ref: Perd Hapley on "Parks and Recreation").
So the setting was available in the XML, but never needed to be set by the user. Because it was automatically set in the C code though, sometimes libvirt-generated XML would contain the option even though the user hadn't included it in the original input XML (e.g. the libxl driver sets it in the PostParse, so all saved configs with a PCI <hostdev> device will have <driver name='xen'/>; also status XML from the QEMU and libxl drivers will contain <driver name='vfio|xen'/> - in both cases completely unnecessary and redundant information).
When adding support for specifying a variant driver for VFIO device assignment, from the beginning I have wanted to use <driver name='blah'/> to force a specific variant driver (e.g. <driver name='mlx5_vfio_pci'/>), with the assumption that the name attribute could be easily repurposed because it had been *completely* unused for so long. What I discovered though, was that 1) the field in the C object corresponding to driver name was an enum value rather than a string (so parser and formatter need to be changed, not just the driver code looking at a string in the C object), and 2) even though the XML attribute was effectively unused (except in some output), the field in the C object was *always* being set internally as a way for the hypervisor driver code to inform the hypervisor-common hostdev manager (in src/hypervisor) which method of device assignment to use. So re-use wasn't as simple as I'd wished.
However.
What I have hit upon that permits us to use <driver name='mlx5_vfio_pci'/> is to do the following:
1) rename the existing driver name attribute to driver *type* - this will now be the enum that is set internally by the hypervisor driver prior to calling the hostdev manager (and also is what will show up in status XML; the libxl driver was modified in a previous patch so that the setting isn't done until domain runtime (rather than during PostParse), so it will no longer show up in regurgitated libxml config)
2) add a new attribute with the now-newly-unused name "name" - this will be a string that can be used to communicate a specific host kernel driver to the hostdev manager.
3) In the parsing code for <driver>, if <driver name='vfio|xen|kvm'/> is encountered, set the driver *type* to the appropriate enum instead, and clear our the name string. (since the four places that use the hostdev <driver> element now all call a common parser function, this check is only needed in a single place)
I could alternately just leave "name" as-is, and create a new attribute with a never-before-used name within driver. I suppose instead of "type" and "name", we could instead have "name and "model" (where "model" would be the string that could be set to "mlx5_vfio_pci"). I just prefer type/name to name/model, and think it's been long enough since <driver name='blah'/> has had a useful purpose (and the fixup for backward compatibility is limited to a few lines in one function) that this change is safe.
I'm not entirely sold on the reusing of the 'name' attribute and this paragraph seems to confirm that it's just for optics.
I'm a bit worried that some tool may be checking the output here however useless it is and that tool might then need changing just because we wanted "better looking" attribute names.
Sigh. Yeah, you're probably right.
Okay, so how about keeping <driver name='vfio|xen'> (but still minimizing its auto-generation as much as possible), and using <driver model='blah'/> when we want to specify a particular driver?
That sounds good. The 'name=' attribute should be present in the runtime XML when it was selected, but based on your previous explanation we don't need to keep putting it into the config at post-parse time. If it was specified though, don't remove it.
(another alternate would be to add an extra parameter to the C API that calls into the hostdev manager rather than keeping/adding the publicly visible "type" attribute, but it seems at least possible that sometime in the future another alternate "type" of device assignment could be introduced for either Xen or QEMU, and we would then need to add back the XML attribute anyway)
I'd be fine with doing it one of the other ways, but decided to post this way first, since it's the one that I find the most aesthetically pleasing :-)
Okay this paragraph is a bit too much of discussion for a commit message. Please put stuff like this under the lines or as a RFC question.
Yeah, I meant to do that but forgot.
Note that a few test cases have been modified - places where an existing "name='vfio'" was changed to "type='vfio'" were in in status XML or only the *output* XML for a test (except the case of the virnetworkportxml2xmltest, which doesn't have a separate directory for the XML result; fortunately the converged parsing of <driver> between domain/network/networkport means that the test cases for network and domain XML are already testing the same code that would convert "name" to "type" in thte networkport XML)
Signed-off-by: Laine Stump <laine@redhat.com> ---
The code looks okay but I'm not a fan of the rename for cosmetical reasons. Especially if we fiddle with the value in the field with original name and display it back to the user/management sw.
I'll redo everything to use <driver model> and try to get it posted in the next day or two. If you or anyone else thinks of a better name let me know.

Add a surprisingly missing simple function to the arsenal. Signed-off-by: Laine Stump <laine@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virstring.c | 17 +++++++++++++++++ src/util/virstring.h | 1 + 3 files changed, 19 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a943a79e01..3e8eded81e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3409,6 +3409,7 @@ virSkipSpaces; virSkipSpacesAndBackslash; virSkipSpacesBackwards; virSkipToDigit; +virSkipToSpace; virStrcpy; virStringBufferIsPrintable; virStringFilterChars; diff --git a/src/util/virstring.c b/src/util/virstring.c index 6b728ff047..4a732de5dc 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -441,6 +441,23 @@ virSkipToDigit(const char **str) } +/** + * virSkipToSApace: + * @str: pointer to the char pointer used + * + * Skip over any character that is not whitespace + */ +void +virSkipToSpace(const char **str) +{ + const char *cur = *str; + + while (*cur && !g_ascii_isspace(*cur)) + cur++; + *str = cur; +} + + /** * virTrimSpaces: * @str: string to modify to remove all trailing spaces diff --git a/src/util/virstring.h b/src/util/virstring.h index 16dcce98f4..9fd8be44cf 100644 --- a/src/util/virstring.h +++ b/src/util/virstring.h @@ -74,6 +74,7 @@ int virDoubleToStr(char **strp, double number) void virSkipSpaces(const char **str) ATTRIBUTE_NONNULL(1); void virSkipSpacesAndBackslash(const char **str) ATTRIBUTE_NONNULL(1); void virSkipToDigit(const char **str) ATTRIBUTE_NONNULL(1); +void virSkipToSpace(const char **str) ATTRIBUTE_NONNULL(1); void virTrimSpaces(char *str, char **endp) ATTRIBUTE_NONNULL(1); void virSkipSpacesBackwards(const char *str, char **endp) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:58 -0500, Laine Stump wrote:
Add a surprisingly missing simple function to the arsenal.
I'd almost prefer to have this simply inlined into the only user.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virstring.c | 17 +++++++++++++++++ src/util/virstring.h | 1 + 3 files changed, 19 insertions(+)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

Only in qemuhotplug test, in order to not fail when running the test on macOS. This is a temporary measure until I decice how best to make a mock environment that allows virPCIDeviceFindBestVariant() to succeed on non-Linux platforms (which is a bit nonsensical, since none of that code will ever run on non-Linux anyway). Signed-off-by: Laine Stump <laine@redhat.com> --- src/libvirt_private.syms | 2 ++ src/util/virpci.c | 4 ++-- src/util/virpci.h | 3 +++ tests/qemuhotplugmock.c | 15 +++++++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3e8eded81e..0e8353cc22 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3072,6 +3072,7 @@ virPCIDeviceAddressIOMMUGroupIterate; virPCIDeviceAddressIsEmpty; virPCIDeviceAddressIsValid; virPCIDeviceAddressParse; +virPCIDeviceBindToStub; virPCIDeviceCopy; virPCIDeviceDetach; virPCIDeviceExists; @@ -3120,6 +3121,7 @@ virPCIDeviceSetStubDriverType; virPCIDeviceSetUnbindFromStub; virPCIDeviceSetUsedBy; virPCIDeviceUnbind; +virPCIDeviceUnbindFromStub; virPCIEDeviceInfoFree; virPCIELinkSpeedTypeFromString; virPCIELinkSpeedTypeToString; diff --git a/src/util/virpci.c b/src/util/virpci.c index dfc97dc981..885958eb99 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -1406,7 +1406,7 @@ virPCIDeviceBindWithDriverOverride(virPCIDevice *dev, return 0; } -static int +int virPCIDeviceUnbindFromStub(virPCIDevice *dev) { if (!dev->unbind_from_stub) { @@ -1417,7 +1417,7 @@ virPCIDeviceUnbindFromStub(virPCIDevice *dev) return virPCIDeviceBindWithDriverOverride(dev, "\n"); } -static int +int virPCIDeviceBindToStub(virPCIDevice *dev) { g_autofree char *stubDriverPath = NULL; diff --git a/src/util/virpci.h b/src/util/virpci.h index faca6cf6f9..4fbace7f67 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -131,6 +131,9 @@ int virPCIDeviceReset(virPCIDevice *dev, virPCIDeviceList *activeDevs, virPCIDeviceList *inactiveDevs); +int virPCIDeviceUnbindFromStub(virPCIDevice *dev); +int virPCIDeviceBindToStub(virPCIDevice *dev); + void virPCIDeviceSetManaged(virPCIDevice *dev, bool managed); bool virPCIDeviceGetManaged(virPCIDevice *dev); diff --git a/tests/qemuhotplugmock.c b/tests/qemuhotplugmock.c index dd7e2c67e0..e578046e0d 100644 --- a/tests/qemuhotplugmock.c +++ b/tests/qemuhotplugmock.c @@ -25,6 +25,7 @@ #include "conf/domain_conf.h" #include "virdevmapper.h" #include "virmock.h" +#include "virpci.h" #include <fcntl.h> #define LIBVIRT_QEMU_MONITOR_PRIV_H_ALLOW @@ -81,6 +82,20 @@ virFileExists(const char *path) } +int +virPCIDeviceBindToStub(virPCIDevice *dev G_GNUC_UNUSED) +{ + return 0; +} + + +int +virPCIDeviceUnbindFromStub(virPCIDevice *dev G_GNUC_UNUSED) +{ + return 0; +} + + int qemuProcessStartManagedPRDaemon(virDomainObj *vm G_GNUC_UNUSED) { -- 2.41.0

On Mon, Nov 06, 2023 at 02:38:59 -0500, Laine Stump wrote:
Only in qemuhotplug test, in order to not fail when running the test on macOS.
This is a temporary measure until I decice how best to make a mock environment that allows virPCIDeviceFindBestVariant() to succeed on non-Linux platforms (which is a bit nonsensical, since none of that code will ever run on non-Linux anyway).
Signed-off-by: Laine Stump <laine@redhat.com> ---
[...]
diff --git a/src/util/virpci.h b/src/util/virpci.h index faca6cf6f9..4fbace7f67 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -131,6 +131,9 @@ int virPCIDeviceReset(virPCIDevice *dev, virPCIDeviceList *activeDevs, virPCIDeviceList *inactiveDevs);
+int virPCIDeviceUnbindFromStub(virPCIDevice *dev); +int virPCIDeviceBindToStub(virPCIDevice *dev); +
You need to use G_NO_INLINE with any function to be mocked
void virPCIDeviceSetManaged(virPCIDevice *dev, bool managed); bool virPCIDeviceGetManaged(virPCIDevice *dev);
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

Rather than always binding to the vfio-pci driver, use the new function virPCIDeviceFindBestVFIOVariant() to see if the running kernel has a VFIO variant driver available that is a better match for the device, and if one is found, use that instead. virPCIDeviceFindBestVFIOVariant() function reads the modalias file for the given device from sysfs, then looks through /lib/modules/${kernel_release}/modules.alias for the vfio_pci alias that matches with the least number of wildcard ('*') fields. The appropriate "VFIO variant" driver for a device will be the PCI driver implemented by the discovered module - these drivers are compatible with (and provide the entire API of) the standard vfio-pci driver, but have additional device-specific APIs that can be useful for, e.g., saving/restoring state for migration. If a specific driver is named, that will still be used rather than searching modules.alias; this makes it possible to force binding of vfio-pci if there is an issue with the auto-selected variant driver. Signed-off-by: Laine Stump <laine@redhat.com> --- src/util/virpci.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) diff --git a/src/util/virpci.c b/src/util/virpci.c index 885958eb99..40831a5294 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -30,6 +30,10 @@ #include <sys/stat.h> #include <unistd.h> +#ifndef WIN32 +# include <sys/utsname.h> +#endif + #include "virlog.h" #include "virerror.h" #include "virfile.h" @@ -1321,6 +1325,225 @@ virPCIDeviceFindDriver(virPCIDevice *dev) } +#ifdef __linux__ +typedef struct { + /* this is the decomposed version of a string like: + * + * vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN + * + * (followed by a space or newline). The "NNNN" are always of the + * length in the example unless replaced with a wildcard ("*"), + * but we make no assumptions about length. + * + * Rather than name each field, we just put them + * all in an array of 6 elements, so that we + * can write a simple loop to compare them + */ + char *fields[7]; /* v, d, sv, sd, bc, sc, i */ +} virPCIDeviceAliasInfo; + + +/* NULL in last position makes parsing loop simpler */ +static const char *fieldnames[] = { "v", "d", "sv", "sd", "bc", "sc", "i", NULL }; + + +static void +virPCIDeviceAliasInfoFree(virPCIDeviceAliasInfo *info) +{ + if (info) { + size_t i; + + for (i = 0; i < G_N_ELEMENTS(info->fields); i++) + g_free(info->fields[i]); + + g_free(info); + } +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virPCIDeviceAliasInfo, virPCIDeviceAliasInfoFree); + + +static virPCIDeviceAliasInfo * +virPCIDeviceAliasInfoNew(const char *str) +{ + const char *field = str; + + size_t i; + g_autoptr(virPCIDeviceAliasInfo) ret = g_new0(virPCIDeviceAliasInfo, 1); + + if (!str) + return g_steal_pointer(&ret); + + /* initialize from str */ + for (i = 0; i < G_N_ELEMENTS(ret->fields); i++) { + int len = strlen(fieldnames[i]); + const char *next; + + if (strncmp(field, fieldnames[i], len)) + return NULL; + + field += len; + if (fieldnames[i + 1]) { + if (!(next = strstr(field, fieldnames[i + 1]))) + return NULL; + } else { + next = field; + virSkipToSpace(&next); + } + + ret->fields[i] = g_strndup(field, next - field); + field = next; + } + + return g_steal_pointer(&ret); +} + + +static void +virPCIDeviceAliasInfoPrint(virPCIDeviceAliasInfo *info) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(info->fields); i++) + VIR_DEBUG("%s: '%s'", fieldnames[i], info->fields[i]); +} + + +static bool +virPCIDeviceAliasInfoMatch(virPCIDeviceAliasInfo *orig, + virPCIDeviceAliasInfo *match, + int *wildCardCt) +{ + size_t i; + + *wildCardCt = 0; + + for (i = 0; i < G_N_ELEMENTS(orig->fields); i++) { + if (STREQ(match->fields[i], "*")) + (*wildCardCt)++; + else if (STRNEQ(orig->fields[i], match->fields[i])) + return false; + } + return true; +} + + +/* virPCIDeviceFindBestVFIOVariant: + * + * Find the "best" match of all vfio_pci aliases for @dev in the host + * modules.alias file. This uses the algorithm of finding every + * modules.alias line that begins with "vfio_pci:", then picking the + * one that matches the device's own modalias value (from the file of + * that name in the device's sysfs directory) with the fewest + * "wildcards" (* character, meaning "match any value for this + * attribute"). + */ +static int +virPCIDeviceFindBestVFIOVariant(virPCIDevice *dev, + char **moduleName) +{ + g_autofree char *devModAliasPath = NULL; + g_autofree char *devModAliasContent = NULL; + const char *devModAlias; + g_autoptr(virPCIDeviceAliasInfo) devModAliasInfo = NULL; + struct utsname unameInfo; + g_autofree char *modulesAliasPath = NULL; + g_autofree char *modulesAliasContent = NULL; + const char *line; + int currentBestWildcardCt = INT_MAX; + + *moduleName = NULL; + + /* get the modalias values for the device from sysfs */ + devModAliasPath = virPCIFile(dev->name, "modalias"); + if (virFileReadAll(devModAliasPath, 100, &devModAliasContent) < 0) + return 0; + + VIR_DEBUG("modalias path: '%s' contents: '%s'", + devModAliasPath, devModAliasContent); + + /* "pci:vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN\n" */ + if ((devModAlias = STRSKIP(devModAliasContent, "pci:")) == NULL || + !(devModAliasInfo = virPCIDeviceAliasInfoNew(devModAlias))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("device modalias file %1$s content has improper format"), + devModAliasPath); + return -1; + } + + virPCIDeviceAliasInfoPrint(devModAliasInfo); + + uname(&unameInfo); + modulesAliasPath = g_strdup_printf("/lib/modules/%s/modules.alias", + unameInfo.release); + if (virFileReadAll(modulesAliasPath, + 4 * 1024 * 1024, &modulesAliasContent) < 0) { + return -1; + } + + /* Look for all lines that are aliases for vfio_pci drivers. + * (The first line is always a comment, so we can be sure "alias" + * is preceded by a newline) + */ + line = modulesAliasContent; + + while ((line = strstr(line, "\nalias vfio_pci:"))) { + g_autoptr(virPCIDeviceAliasInfo) fileModAliasInfo = NULL; + int wildCardCt; + + /* "alias vfio_pci:vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN XXXX\n" */ + line += strlen("\nalias vfio_pci:"); + if (!(fileModAliasInfo = virPCIDeviceAliasInfoNew(line))) + continue; + + virPCIDeviceAliasInfoPrint(fileModAliasInfo); + + if (virPCIDeviceAliasInfoMatch(devModAliasInfo, + fileModAliasInfo, &wildCardCt)) { + + const char *aliasStart = strchr(line, ' '); + const char *aliasEnd = NULL; + g_autofree char *aliasName = NULL; + + if (!aliasStart) { + VIR_WARN("malformed modules.alias vfio_pci: line"); + continue; + } + + aliasStart++; + line = aliasEnd = strchrnul(aliasStart, '\n'); + aliasName = g_strndup(aliasStart, aliasEnd - aliasStart); + + VIR_DEBUG("matching alias '%s' found, %d wildcards", + aliasName, wildCardCt); + + if (wildCardCt < currentBestWildcardCt) { + + /* this is a better match than previous */ + currentBestWildcardCt = wildCardCt; + g_free(*moduleName); + *moduleName = g_steal_pointer(&aliasName); + } + } + } + return 0; +} + + +#else /* __linux__ */ + + +static int +virPCIDeviceFindBestVFIOVariant(virPCIDevice *dev G_GNUC_UNUSED, + char **moduleName G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("VFIO device assignment is not available on this platform")); + return -1; +} +#endif /* __linux__ */ + + int virPCIDeviceUnbind(virPCIDevice *dev) { @@ -1431,6 +1654,22 @@ virPCIDeviceBindToStub(virPCIDevice *dev) return -1; } + if (dev->stubDriverType == VIR_PCI_STUB_DRIVER_VFIO + && !dev->stubDriverName) { + g_autofree char *autodetectModuleName = NULL; + + /* automatically use a VFIO variant driver if available for + * this device. + */ + + if (virPCIDeviceFindBestVFIOVariant(dev, &autodetectModuleName) < 0) + return -1; + + g_free(dev->stubDriverName); + dev->stubDriverName = g_steal_pointer(&autodetectModuleName); + } + + /* if a driver name hasn't been decided by now, use default for this type */ if (!dev->stubDriverName) { const char *stubDriverName = NULL; @@ -1538,6 +1777,9 @@ virPCIDeviceReattach(virPCIDevice *dev, return 0; } + + + static char * virPCIDeviceReadID(virPCIDevice *dev, const char *id_name) { -- 2.41.0

On Mon, Nov 06, 2023 at 02:39:00 -0500, Laine Stump wrote:
Rather than always binding to the vfio-pci driver, use the new function virPCIDeviceFindBestVFIOVariant() to see if the running kernel has a VFIO variant driver available that is a better match for the device, and if one is found, use that instead.
virPCIDeviceFindBestVFIOVariant() function reads the modalias file for the given device from sysfs, then looks through /lib/modules/${kernel_release}/modules.alias for the vfio_pci alias that matches with the least number of wildcard ('*') fields.
The appropriate "VFIO variant" driver for a device will be the PCI driver implemented by the discovered module - these drivers are compatible with (and provide the entire API of) the standard vfio-pci driver, but have additional device-specific APIs that can be useful for, e.g., saving/restoring state for migration.
If a specific driver is named, that will still be used rather than searching modules.alias; this makes it possible to force binding of vfio-pci if there is an issue with the auto-selected variant driver.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/util/virpci.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+)
diff --git a/src/util/virpci.c b/src/util/virpci.c index 885958eb99..40831a5294 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -30,6 +30,10 @@ #include <sys/stat.h> #include <unistd.h>
+#ifndef WIN32 +# include <sys/utsname.h> +#endif + #include "virlog.h" #include "virerror.h" #include "virfile.h" @@ -1321,6 +1325,225 @@ virPCIDeviceFindDriver(virPCIDevice *dev) }
+#ifdef __linux__ +typedef struct { + /* this is the decomposed version of a string like: + * + * vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN + * + * (followed by a space or newline). The "NNNN" are always of the + * length in the example unless replaced with a wildcard ("*"), + * but we make no assumptions about length. + * + * Rather than name each field, we just put them + * all in an array of 6 elements, so that we
^^^
+ * can write a simple loop to compare them + */ + char *fields[7]; /* v, d, sv, sd, bc, sc, i */
^^^ ...
+} virPCIDeviceAliasInfo; + + +/* NULL in last position makes parsing loop simpler */ +static const char *fieldnames[] = { "v", "d", "sv", "sd", "bc", "sc", "i", NULL }; + + +static void +virPCIDeviceAliasInfoFree(virPCIDeviceAliasInfo *info) +{ + if (info) { + size_t i; + + for (i = 0; i < G_N_ELEMENTS(info->fields); i++) + g_free(info->fields[i]); + + g_free(info); + } +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virPCIDeviceAliasInfo, virPCIDeviceAliasInfoFree); + + +static virPCIDeviceAliasInfo * +virPCIDeviceAliasInfoNew(const char *str) +{ + const char *field = str; + + size_t i; + g_autoptr(virPCIDeviceAliasInfo) ret = g_new0(virPCIDeviceAliasInfo, 1); + + if (!str) + return g_steal_pointer(&ret);
So here you return an empty array as "success" if the input string is empty, but note that neither virPCIDeviceAliasInfoMatch nor virPCIDeviceAliasInfoPrint properly handle the fields being NULL. None of the callers use this scenario so it should be removed.
+ + /* initialize from str */ + for (i = 0; i < G_N_ELEMENTS(ret->fields); i++) { + int len = strlen(fieldnames[i]); + const char *next; + + if (strncmp(field, fieldnames[i], len)) + return NULL; + + field += len; + if (fieldnames[i + 1]) { + if (!(next = strstr(field, fieldnames[i + 1]))) + return NULL; + } else { + next = field; + virSkipToSpace(&next); + } + + ret->fields[i] = g_strndup(field, next - field); + field = next; + } + + return g_steal_pointer(&ret); +} + + +static void +virPCIDeviceAliasInfoPrint(virPCIDeviceAliasInfo *info) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(info->fields); i++) + VIR_DEBUG("%s: '%s'", fieldnames[i], info->fields[i]); +} + + +static bool +virPCIDeviceAliasInfoMatch(virPCIDeviceAliasInfo *orig, + virPCIDeviceAliasInfo *match, + int *wildCardCt)
unsigned, negative values don't seem to make sense.
+{ + size_t i; + + *wildCardCt = 0; + + for (i = 0; i < G_N_ELEMENTS(orig->fields); i++) { + if (STREQ(match->fields[i], "*")) + (*wildCardCt)++; + else if (STRNEQ(orig->fields[i], match->fields[i])) + return false; + } + return true; +} + + +/* virPCIDeviceFindBestVFIOVariant: + * + * Find the "best" match of all vfio_pci aliases for @dev in the host + * modules.alias file. This uses the algorithm of finding every + * modules.alias line that begins with "vfio_pci:", then picking the + * one that matches the device's own modalias value (from the file of + * that name in the device's sysfs directory) with the fewest + * "wildcards" (* character, meaning "match any value for this + * attribute"). + */ +static int +virPCIDeviceFindBestVFIOVariant(virPCIDevice *dev, + char **moduleName) +{ + g_autofree char *devModAliasPath = NULL; + g_autofree char *devModAliasContent = NULL; + const char *devModAlias; + g_autoptr(virPCIDeviceAliasInfo) devModAliasInfo = NULL; + struct utsname unameInfo; + g_autofree char *modulesAliasPath = NULL; + g_autofree char *modulesAliasContent = NULL; + const char *line; + int currentBestWildcardCt = INT_MAX;
Unsigned.
+ + *moduleName = NULL; + + /* get the modalias values for the device from sysfs */ + devModAliasPath = virPCIFile(dev->name, "modalias");
If you expect this file to be missing ...
+ if (virFileReadAll(devModAliasPath, 100, &devModAliasContent) < 0)
... then you need to check whether it exists, as this will spam logs. And also we most likely should reset the local instance of error in this code path as virFileReadAll sets it.
+ return 0; + + VIR_DEBUG("modalias path: '%s' contents: '%s'", + devModAliasPath, devModAliasContent); + + /* "pci:vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN\n" */ + if ((devModAlias = STRSKIP(devModAliasContent, "pci:")) == NULL || + !(devModAliasInfo = virPCIDeviceAliasInfoNew(devModAlias))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("device modalias file %1$s content has improper format"), + devModAliasPath); + return -1; + } + + virPCIDeviceAliasInfoPrint(devModAliasInfo);
Since this logs 7 lines into the debug log I don't think it's a great idea to have it in production. If you need to be sure that the parser processes teh modalias correctly, then please add unit tests instead. Logging the raw string, which happens above should be sufficient for debugging.
+ + uname(&unameInfo); + modulesAliasPath = g_strdup_printf("/lib/modules/%s/modules.alias", + unameInfo.release); + if (virFileReadAll(modulesAliasPath, + 4 * 1024 * 1024, &modulesAliasContent) < 0) {
Note that the file currently has 1.3MiB already, I'm not sure what the potenital for growth is though, but this leaves less than an order of magnitude in reserve. Additionally the code below only currently looks at 2 of the 25k lines in the file. Maybe it's worth caching the relevant lines?
+ return -1; + } + + /* Look for all lines that are aliases for vfio_pci drivers. + * (The first line is always a comment, so we can be sure "alias" + * is preceded by a newline) + */ + line = modulesAliasContent; + + while ((line = strstr(line, "\nalias vfio_pci:"))) { + g_autoptr(virPCIDeviceAliasInfo) fileModAliasInfo = NULL; + int wildCardCt; + + /* "alias vfio_pci:vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN XXXX\n" */ + line += strlen("\nalias vfio_pci:"); + if (!(fileModAliasInfo = virPCIDeviceAliasInfoNew(line))) + continue; + + virPCIDeviceAliasInfoPrint(fileModAliasInfo);
Logging the matched line should be sufficient. Please remove the overly verbose virPCIDeviceAliasInfoPrint.
+ + if (virPCIDeviceAliasInfoMatch(devModAliasInfo, + fileModAliasInfo, &wildCardCt)) { + + const char *aliasStart = strchr(line, ' '); + const char *aliasEnd = NULL; + g_autofree char *aliasName = NULL; + + if (!aliasStart) { + VIR_WARN("malformed modules.alias vfio_pci: line"); + continue; + } + + aliasStart++; + line = aliasEnd = strchrnul(aliasStart, '\n'); + aliasName = g_strndup(aliasStart, aliasEnd - aliasStart); + + VIR_DEBUG("matching alias '%s' found, %d wildcards", + aliasName, wildCardCt);
Possibly worth logging currentBestWildcardCt too?
+ + if (wildCardCt < currentBestWildcardCt) { + + /* this is a better match than previous */ + currentBestWildcardCt = wildCardCt; + g_free(*moduleName); + *moduleName = g_steal_pointer(&aliasName); + } + } + } + return 0; +} + + +#else /* __linux__ */ + + +static int +virPCIDeviceFindBestVFIOVariant(virPCIDevice *dev G_GNUC_UNUSED, + char **moduleName G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("VFIO device assignment is not available on this platform")); + return -1; +} +#endif /* __linux__ */ + + int virPCIDeviceUnbind(virPCIDevice *dev) { @@ -1431,6 +1654,22 @@ virPCIDeviceBindToStub(virPCIDevice *dev) return -1; }
+ if (dev->stubDriverType == VIR_PCI_STUB_DRIVER_VFIO + && !dev->stubDriverName) {
Logic operators are commonly placed at the end of the line before.
+ g_autofree char *autodetectModuleName = NULL; + + /* automatically use a VFIO variant driver if available for + * this device. + */ + + if (virPCIDeviceFindBestVFIOVariant(dev, &autodetectModuleName) < 0) + return -1; + + g_free(dev->stubDriverName); + dev->stubDriverName = g_steal_pointer(&autodetectModuleName); + } + + /* if a driver name hasn't been decided by now, use default for this type */ if (!dev->stubDriverName) {
const char *stubDriverName = NULL; @@ -1538,6 +1777,9 @@ virPCIDeviceReattach(virPCIDevice *dev, return 0; }
+ + +
Spurious whitespace change.
static char * virPCIDeviceReadID(virPCIDevice *dev, const char *id_name) {
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

On 11/28/23 10:39 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:39:00 -0500, Laine Stump wrote:
Rather than always binding to the vfio-pci driver, use the new function virPCIDeviceFindBestVFIOVariant() to see if the running kernel has a VFIO variant driver available that is a better match for the device, and if one is found, use that instead.
virPCIDeviceFindBestVFIOVariant() function reads the modalias file for the given device from sysfs, then looks through /lib/modules/${kernel_release}/modules.alias for the vfio_pci alias that matches with the least number of wildcard ('*') fields.
The appropriate "VFIO variant" driver for a device will be the PCI driver implemented by the discovered module - these drivers are compatible with (and provide the entire API of) the standard vfio-pci driver, but have additional device-specific APIs that can be useful for, e.g., saving/restoring state for migration.
If a specific driver is named, that will still be used rather than searching modules.alias; this makes it possible to force binding of vfio-pci if there is an issue with the auto-selected variant driver.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/util/virpci.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+)
diff --git a/src/util/virpci.c b/src/util/virpci.c index 885958eb99..40831a5294 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -30,6 +30,10 @@ #include <sys/stat.h> #include <unistd.h>
+#ifndef WIN32 +# include <sys/utsname.h> +#endif + #include "virlog.h" #include "virerror.h" #include "virfile.h" @@ -1321,6 +1325,225 @@ virPCIDeviceFindDriver(virPCIDevice *dev) }
+#ifdef __linux__ +typedef struct { + /* this is the decomposed version of a string like: + * + * vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN + * + * (followed by a space or newline). The "NNNN" are always of the + * length in the example unless replaced with a wildcard ("*"), + * but we make no assumptions about length. + * + * Rather than name each field, we just put them + * all in an array of 6 elements, so that we
^^^
+ * can write a simple loop to compare them + */ + char *fields[7]; /* v, d, sv, sd, bc, sc, i */
^^^ ...
+} virPCIDeviceAliasInfo; + + +/* NULL in last position makes parsing loop simpler */ +static const char *fieldnames[] = { "v", "d", "sv", "sd", "bc", "sc", "i", NULL }; + + +static void +virPCIDeviceAliasInfoFree(virPCIDeviceAliasInfo *info) +{ + if (info) { + size_t i; + + for (i = 0; i < G_N_ELEMENTS(info->fields); i++) + g_free(info->fields[i]); + + g_free(info); + } +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virPCIDeviceAliasInfo, virPCIDeviceAliasInfoFree); + + +static virPCIDeviceAliasInfo * +virPCIDeviceAliasInfoNew(const char *str) +{ + const char *field = str; + + size_t i; + g_autoptr(virPCIDeviceAliasInfo) ret = g_new0(virPCIDeviceAliasInfo, 1); + + if (!str) + return g_steal_pointer(&ret);
So here you return an empty array as "success" if the input string is empty, but note that neither virPCIDeviceAliasInfoMatch nor virPCIDeviceAliasInfoPrint properly handle the fields being NULL.
None of the callers use this scenario so it should be removed.
Done.
+ + /* initialize from str */ + for (i = 0; i < G_N_ELEMENTS(ret->fields); i++) { + int len = strlen(fieldnames[i]); + const char *next; + + if (strncmp(field, fieldnames[i], len)) + return NULL; + + field += len; + if (fieldnames[i + 1]) { + if (!(next = strstr(field, fieldnames[i + 1]))) + return NULL; + } else { + next = field; + virSkipToSpace(&next); + } + + ret->fields[i] = g_strndup(field, next - field); + field = next; + } + + return g_steal_pointer(&ret); +} + + +static void +virPCIDeviceAliasInfoPrint(virPCIDeviceAliasInfo *info) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(info->fields); i++) + VIR_DEBUG("%s: '%s'", fieldnames[i], info->fields[i]); +} + + +static bool +virPCIDeviceAliasInfoMatch(virPCIDeviceAliasInfo *orig, + virPCIDeviceAliasInfo *match, + int *wildCardCt)
unsigned, negative values don't seem to make sense.
Okay, I've made them all unsigned.
+{ + size_t i; + + *wildCardCt = 0; + + for (i = 0; i < G_N_ELEMENTS(orig->fields); i++) { + if (STREQ(match->fields[i], "*")) + (*wildCardCt)++; + else if (STRNEQ(orig->fields[i], match->fields[i])) + return false; + } + return true; +} + + +/* virPCIDeviceFindBestVFIOVariant: + * + * Find the "best" match of all vfio_pci aliases for @dev in the host + * modules.alias file. This uses the algorithm of finding every + * modules.alias line that begins with "vfio_pci:", then picking the + * one that matches the device's own modalias value (from the file of + * that name in the device's sysfs directory) with the fewest + * "wildcards" (* character, meaning "match any value for this + * attribute"). + */ +static int +virPCIDeviceFindBestVFIOVariant(virPCIDevice *dev, + char **moduleName) +{ + g_autofree char *devModAliasPath = NULL; + g_autofree char *devModAliasContent = NULL; + const char *devModAlias; + g_autoptr(virPCIDeviceAliasInfo) devModAliasInfo = NULL; + struct utsname unameInfo; + g_autofree char *modulesAliasPath = NULL; + g_autofree char *modulesAliasContent = NULL; + const char *line; + int currentBestWildcardCt = INT_MAX;
Unsigned.
+ + *moduleName = NULL; + + /* get the modalias values for the device from sysfs */ + devModAliasPath = virPCIFile(dev->name, "modalias");
If you expect this file to be missing ...
+ if (virFileReadAll(devModAliasPath, 100, &devModAliasContent) < 0)
... then you need to check whether it exists, as this will spam logs.
It should never be missing. *Every* pci device should have a modalias file, so if it's missing that's something that everyone should know about. Just in case that *did* happen, I was reluctant to have the entire operation fail (just because it would mean that something that previously worked would no longer work), but after talking to Alex (Williamson) I've decided that if the modalias file is missing, that is enough indication that something is broken that we *should* log an error and fail. I changed it to return -1
And also we most likely should reset the local instance of error in this code path as virFileReadAll sets it.
+ return 0; + + VIR_DEBUG("modalias path: '%s' contents: '%s'", + devModAliasPath, devModAliasContent); + + /* "pci:vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN\n" */ + if ((devModAlias = STRSKIP(devModAliasContent, "pci:")) == NULL || + !(devModAliasInfo = virPCIDeviceAliasInfoNew(devModAlias))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("device modalias file %1$s content has improper format"), + devModAliasPath); + return -1; + } + + virPCIDeviceAliasInfoPrint(devModAliasInfo);
Since this logs 7 lines into the debug log I don't think it's a great idea to have it in production. If you need to be sure that the parser processes teh modalias correctly, then please add unit tests instead. Logging the raw string, which happens above should be sufficient for debugging.
Agreed. I had that in there when I was writing the code, and should have removed it before I posted - it really is too verbose and the "parsing" is so simplistic that it doesn't need a test case. I removed all trace of virPCIDeiceAliasInfoPrint().
+ + uname(&unameInfo); + modulesAliasPath = g_strdup_printf("/lib/modules/%s/modules.alias", + unameInfo.release); + if (virFileReadAll(modulesAliasPath, + 4 * 1024 * 1024, &modulesAliasContent) < 0) {
Note that the file currently has 1.3MiB already, I'm not sure what the potenital for growth is though, but this leaves less than an order of magnitude in reserve.
How about increasing it to 8MB? Still too small?
Additionally the code below only currently looks at 2 of the 25k lines in the file. Maybe it's worth caching the relevant lines?
Yes, I agree with this. I suppose the "proper" way to do that is to use virfilecache (code re-use and all that), but it will take me some time to understand that, as I've never looked at it until just now :-P. How about a promise to do a followup "soon" that caches the useful lines and re-uses them?
+ return -1; + } + + /* Look for all lines that are aliases for vfio_pci drivers. + * (The first line is always a comment, so we can be sure "alias" + * is preceded by a newline) + */ + line = modulesAliasContent; + + while ((line = strstr(line, "\nalias vfio_pci:"))) { + g_autoptr(virPCIDeviceAliasInfo) fileModAliasInfo = NULL; + int wildCardCt; + + /* "alias vfio_pci:vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN XXXX\n" */ + line += strlen("\nalias vfio_pci:"); + if (!(fileModAliasInfo = virPCIDeviceAliasInfoNew(line))) + continue; + + virPCIDeviceAliasInfoPrint(fileModAliasInfo);
Logging the matched line should be sufficient. Please remove the overly verbose virPCIDeviceAliasInfoPrint.
It's gone. It's over. </frodo>
+ + if (virPCIDeviceAliasInfoMatch(devModAliasInfo, + fileModAliasInfo, &wildCardCt)) { + + const char *aliasStart = strchr(line, ' '); + const char *aliasEnd = NULL; + g_autofree char *aliasName = NULL; + + if (!aliasStart) { + VIR_WARN("malformed modules.alias vfio_pci: line"); + continue; + } + + aliasStart++; + line = aliasEnd = strchrnul(aliasStart, '\n'); + aliasName = g_strndup(aliasStart, aliasEnd - aliasStart); + + VIR_DEBUG("matching alias '%s' found, %d wildcards", + aliasName, wildCardCt);
Possibly worth logging currentBestWildcardCt too?
Sure, why not - doesn't add any extra lines.
+ + if (wildCardCt < currentBestWildcardCt) { + + /* this is a better match than previous */ + currentBestWildcardCt = wildCardCt; + g_free(*moduleName); + *moduleName = g_steal_pointer(&aliasName); + } + } + } + return 0; +} + + +#else /* __linux__ */ + + +static int +virPCIDeviceFindBestVFIOVariant(virPCIDevice *dev G_GNUC_UNUSED, + char **moduleName G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("VFIO device assignment is not available on this platform")); + return -1; +} +#endif /* __linux__ */ + + int virPCIDeviceUnbind(virPCIDevice *dev) { @@ -1431,6 +1654,22 @@ virPCIDeviceBindToStub(virPCIDevice *dev) return -1; }
+ if (dev->stubDriverType == VIR_PCI_STUB_DRIVER_VFIO + && !dev->stubDriverName) {
Logic operators are commonly placed at the end of the line before.
It's been 15 years, and I *still* remember this backwards half the time!!
+ g_autofree char *autodetectModuleName = NULL; + + /* automatically use a VFIO variant driver if available for + * this device. + */ + + if (virPCIDeviceFindBestVFIOVariant(dev, &autodetectModuleName) < 0) + return -1; + + g_free(dev->stubDriverName); + dev->stubDriverName = g_steal_pointer(&autodetectModuleName); + } + + /* if a driver name hasn't been decided by now, use default for this type */ if (!dev->stubDriverName) {
const char *stubDriverName = NULL; @@ -1538,6 +1777,9 @@ virPCIDeviceReattach(virPCIDevice *dev, return 0; }
+ + +
Spurious whitespace change.
static char * virPCIDeviceReadID(virPCIDevice *dev, const char *id_name) {
Reviewed-by: Peter Krempa <pkrempa@redhat.com> _______________________________________________ Devel mailing list -- devel@lists.libvirt.org To unsubscribe send an email to devel-leave@lists.libvirt.org

On Thu, Jan 04, 2024 at 20:01:44 -0500, Laine Stump wrote:
On 11/28/23 10:39 AM, Peter Krempa wrote:
On Mon, Nov 06, 2023 at 02:39:00 -0500, Laine Stump wrote:
Rather than always binding to the vfio-pci driver, use the new function virPCIDeviceFindBestVFIOVariant() to see if the running kernel has a VFIO variant driver available that is a better match for the device, and if one is found, use that instead.
virPCIDeviceFindBestVFIOVariant() function reads the modalias file for the given device from sysfs, then looks through /lib/modules/${kernel_release}/modules.alias for the vfio_pci alias that matches with the least number of wildcard ('*') fields.
The appropriate "VFIO variant" driver for a device will be the PCI driver implemented by the discovered module - these drivers are compatible with (and provide the entire API of) the standard vfio-pci driver, but have additional device-specific APIs that can be useful for, e.g., saving/restoring state for migration.
If a specific driver is named, that will still be used rather than searching modules.alias; this makes it possible to force binding of vfio-pci if there is an issue with the auto-selected variant driver.
Signed-off-by: Laine Stump <laine@redhat.com> --- src/util/virpci.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+)
[...]
+ + uname(&unameInfo); + modulesAliasPath = g_strdup_printf("/lib/modules/%s/modules.alias", + unameInfo.release); + if (virFileReadAll(modulesAliasPath, + 4 * 1024 * 1024, &modulesAliasContent) < 0) {
Note that the file currently has 1.3MiB already, I'm not sure what the potenital for growth is though, but this leaves less than an order of magnitude in reserve.
How about increasing it to 8MB? Still too small?
Ideally we'd stream-process the file, since the code looks at single lines at time, I'm not sure whether we have some prior art in this regard.
Additionally the code below only currently looks at 2 of the 25k lines in the file. Maybe it's worth caching the relevant lines?
Yes, I agree with this. I suppose the "proper" way to do that is to use virfilecache (code re-use and all that), but it will take me some time to understand that, as I've never looked at it until just now :-P.
How about a promise to do a followup "soon" that caches the useful lines and re-uses them?
Honestly I don't think there's too much value in caching it on disk. A runtime cache would be fine. It's fine from my side if it's done later. If you keep reading of the contents into a buffer and processing that add a comment stating that it might not be enough. The code will break once the file size exceeds the buffer size.

ping On 11/6/23 2:38 AM, Laine Stump wrote:
(Thisis "V2 of Part 2". "V1 of Part 2" is here: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/5GF4N... )
Part 1 (which simply made it possible to use virsh nodedev-detach to bind a device to a manually-specified variant driver, and at guest runtime allowed libvirt to ignore the fact that the driver found to the device was something other than exactly "vfio-pci") was here:
https://listman.redhat.com/archives/libvir-list/2023-August/241338.html
and pushed upstream as of commit v9.6.0-153-g24beaffec3
Part 2 adds two new pieces of functionality:
1) It is possible to manually specify a VFIO variant driver (or force the generic vfio-pci driver) for a device in the domain XML with, e.g.:
<driver name='mlx5_vfio_pci'/>
(for the former) or:
<driver name='vfio-pci'/>
(for the latter).
2) By default libvirt will now find the "best match" VFIO or VFIO variant driver by comparing the device's modalias file contents (in sysfs) with vfio drivers found in the running kernel's modules.alias file. This means that "virsh nodedev-detach" of a host device will bind it to its appropriate VFIO variant driver (if one is available), and also if a <hostdev> decice in a domain config has "managed='yes'", libvirt will bind it to a variant driver if possible (in order to force binding to the basic vfio-pci driver instead, you just need to add the <driver> element mentioned above).
The first 12 patches are all just getting (1) going (a lot of it is refactoring code to use common code for the four places that use the hostdev <driver> element), and the final 3 patches implement (2).
More details are spread along the way.
Differences from V1:
I squashed together a couple of the patches, and fixed some things that caused CI jobs to fail (I'd forgotten to push the branch to gitlab and trigger CI).
Laine Stump (15): util: properly deal with module vs. driver when binding device to driver schema: consolidate RNG for all hostdev <driver> elements conf: move/rename hostdev PCI driver type enum to device_conf.h conf: normalize hostdev <driver> parsing to simplify adding new attr conf: put hostdev PCI backend into a struct conf: use virDeviceHostdevPCIDriverInfo in network and networkport objects conf: split out hostdev <driver> parse/format to their own functions conf: use new common parser/formatter for hostdev driver in network XML tests: remove explicit <driver name='vfio'/> from hostdev test cases xen: explicitly set hostdev driver.type at runtime, not in postparse conf: replace virHostdevIsVFIODevice with virHostdevIsPCIDevice conf: support manually specifying VFIO variant driver in <hostdev> XML util: new function virStringSkipToSpace() tests: mock virPCIDevice(BindTo|UnbindFrom)Stub with nop functions qemu: automatically bind to a vfio variant driver, if available
docs/formatdomain.rst | 55 ++- src/conf/device_conf.c | 75 +++ src/conf/device_conf.h | 27 ++ src/conf/domain_capabilities.c | 2 +- src/conf/domain_capabilities.h | 2 +- src/conf/domain_conf.c | 98 +--- src/conf/domain_conf.h | 18 +- src/conf/network_conf.c | 43 +- src/conf/network_conf.h | 17 +- src/conf/schemas/basictypes.rng | 20 + src/conf/schemas/domaincommon.rng | 173 ++++--- src/conf/schemas/network.rng | 10 +- src/conf/schemas/networkport.rng | 10 +- src/conf/virconftypes.h | 2 + src/conf/virnetworkportdef.c | 22 +- src/conf/virnetworkportdef.h | 4 +- src/hypervisor/virhostdev.c | 16 +- src/hypervisor/virhostdev.h | 2 - src/libvirt_private.syms | 10 +- src/libxl/libxl_capabilities.c | 2 +- src/libxl/libxl_domain.c | 65 ++- src/libxl/libxl_driver.c | 25 +- src/network/bridge_driver.c | 2 +- src/qemu/qemu_capabilities.c | 4 +- src/qemu/qemu_command.c | 14 +- src/qemu/qemu_domain.c | 29 +- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_validate.c | 6 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 4 +- src/security/security_selinux.c | 4 +- src/security/virt-aa-helper.c | 8 +- src/util/virpci.c | 438 ++++++++++++++++-- src/util/virpci.h | 3 + src/util/virstring.c | 17 + src/util/virstring.h | 1 + tests/domaincapstest.c | 4 +- tests/libxlxml2domconfigdata/moredevs-hvm.xml | 1 - tests/networkxml2xmlin/hostdev-pf-old.xml | 8 + tests/networkxml2xmlin/hostdev-pf.xml | 2 +- tests/networkxml2xmlout/hostdev-pf-old.xml | 8 + tests/networkxml2xmlout/hostdev-pf.xml | 2 +- tests/networkxml2xmltest.c | 6 + tests/qemuhotplugmock.c | 15 + .../qemuhotplug-hostdev-pci.xml | 1 - .../qemuhotplug-base-live+hostdev-pci.xml | 2 +- ...uhotplug-pseries-base-live+hostdev-pci.xml | 2 +- tests/qemustatusxml2xmldata/modern-in.xml | 2 +- .../hostdev-pci-address-unassigned.xml | 4 - .../hostdev-pci-multifunction.xml | 7 - .../hostdev-vfio-multidomain.xml | 1 - .../hostdev-vfio-zpci-autogenerate-fids.xml | 2 - .../hostdev-vfio-zpci-autogenerate-uids.xml | 2 - .../hostdev-vfio-zpci-autogenerate.xml | 1 - .../hostdev-vfio-zpci-boundaries.xml | 2 - .../hostdev-vfio-zpci-ccw-memballoon.xml | 1 - .../hostdev-vfio-zpci-duplicate.xml | 2 - ...ostdev-vfio-zpci-invalid-uid-valid-fid.xml | 1 - .../hostdev-vfio-zpci-multidomain-many.xml | 8 - .../hostdev-vfio-zpci-set-zero.xml | 1 - .../hostdev-vfio-zpci-uid-set-zero.xml | 1 - .../hostdev-vfio-zpci-wrong-arch.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio-zpci.xml | 1 - .../hostdev-vfio.x86_64-latest.args | 5 +- tests/qemuxml2argvdata/hostdev-vfio.xml | 19 +- .../net-hostdev-vfio-multidomain.xml | 1 - tests/qemuxml2argvdata/net-hostdev-vfio.xml | 1 - tests/qemuxml2argvdata/pseries-hostdevs-1.xml | 3 - tests/qemuxml2argvdata/pseries-hostdevs-2.xml | 2 - tests/qemuxml2argvdata/pseries-hostdevs-3.xml | 2 - ...v-pci-address-unassigned.x86_64-latest.xml | 4 - ...ostdev-pci-multifunction.x86_64-latest.xml | 7 - ...io-zpci-autogenerate-fids.s390x-latest.xml | 2 - ...io-zpci-autogenerate-uids.s390x-latest.xml | 2 - ...ev-vfio-zpci-autogenerate.s390x-latest.xml | 1 - ...tdev-vfio-zpci-boundaries.s390x-latest.xml | 2 - ...-vfio-zpci-ccw-memballoon.s390x-latest.xml | 1 - ...fio-zpci-multidomain-many.s390x-latest.xml | 8 - .../hostdev-vfio-zpci.s390x-latest.xml | 1 - .../hostdev-vfio.x86_64-latest.xml | 24 +- .../net-hostdev-vfio.x86_64-latest.xml | 1 - .../pseries-hostdevs-1.ppc64-latest.xml | 3 - .../pseries-hostdevs-2.ppc64-latest.xml | 2 - .../pseries-hostdevs-3.ppc64-latest.xml | 2 - tests/virhostdevtest.c | 2 +- .../plug-hostdev-pci-unmanaged.xml | 2 +- .../plug-hostdev-pci.xml | 2 +- tests/xlconfigdata/test-fullvirt-pci.xml | 2 - tests/xmconfigdata/test-pci-dev-syntax.xml | 2 - tests/xmconfigdata/test-pci-devs.xml | 2 - tools/virsh-completer-nodedev.c | 4 +- 92 files changed, 933 insertions(+), 498 deletions(-) create mode 100644 tests/networkxml2xmlin/hostdev-pf-old.xml create mode 100644 tests/networkxml2xmlout/hostdev-pf-old.xml

Re-ping :-) On 11/6/23 2:38 AM, Laine Stump wrote:
(Thisis "V2 of Part 2". "V1 of Part 2" is here: https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/5GF4N... )
Part 1 (which simply made it possible to use virsh nodedev-detach to bind a device to a manually-specified variant driver, and at guest runtime allowed libvirt to ignore the fact that the driver found to the device was something other than exactly "vfio-pci") was here:
https://listman.redhat.com/archives/libvir-list/2023-August/241338.html
and pushed upstream as of commit v9.6.0-153-g24beaffec3
Part 2 adds two new pieces of functionality:
1) It is possible to manually specify a VFIO variant driver (or force the generic vfio-pci driver) for a device in the domain XML with, e.g.:
<driver name='mlx5_vfio_pci'/>
(for the former) or:
<driver name='vfio-pci'/>
(for the latter).
2) By default libvirt will now find the "best match" VFIO or VFIO variant driver by comparing the device's modalias file contents (in sysfs) with vfio drivers found in the running kernel's modules.alias file. This means that "virsh nodedev-detach" of a host device will bind it to its appropriate VFIO variant driver (if one is available), and also if a <hostdev> decice in a domain config has "managed='yes'", libvirt will bind it to a variant driver if possible (in order to force binding to the basic vfio-pci driver instead, you just need to add the <driver> element mentioned above).
The first 12 patches are all just getting (1) going (a lot of it is refactoring code to use common code for the four places that use the hostdev <driver> element), and the final 3 patches implement (2).
More details are spread along the way.
Differences from V1:
I squashed together a couple of the patches, and fixed some things that caused CI jobs to fail (I'd forgotten to push the branch to gitlab and trigger CI).
Laine Stump (15): util: properly deal with module vs. driver when binding device to driver schema: consolidate RNG for all hostdev <driver> elements conf: move/rename hostdev PCI driver type enum to device_conf.h conf: normalize hostdev <driver> parsing to simplify adding new attr conf: put hostdev PCI backend into a struct conf: use virDeviceHostdevPCIDriverInfo in network and networkport objects conf: split out hostdev <driver> parse/format to their own functions conf: use new common parser/formatter for hostdev driver in network XML tests: remove explicit <driver name='vfio'/> from hostdev test cases xen: explicitly set hostdev driver.type at runtime, not in postparse conf: replace virHostdevIsVFIODevice with virHostdevIsPCIDevice conf: support manually specifying VFIO variant driver in <hostdev> XML util: new function virStringSkipToSpace() tests: mock virPCIDevice(BindTo|UnbindFrom)Stub with nop functions qemu: automatically bind to a vfio variant driver, if available
docs/formatdomain.rst | 55 ++- src/conf/device_conf.c | 75 +++ src/conf/device_conf.h | 27 ++ src/conf/domain_capabilities.c | 2 +- src/conf/domain_capabilities.h | 2 +- src/conf/domain_conf.c | 98 +--- src/conf/domain_conf.h | 18 +- src/conf/network_conf.c | 43 +- src/conf/network_conf.h | 17 +- src/conf/schemas/basictypes.rng | 20 + src/conf/schemas/domaincommon.rng | 173 ++++--- src/conf/schemas/network.rng | 10 +- src/conf/schemas/networkport.rng | 10 +- src/conf/virconftypes.h | 2 + src/conf/virnetworkportdef.c | 22 +- src/conf/virnetworkportdef.h | 4 +- src/hypervisor/virhostdev.c | 16 +- src/hypervisor/virhostdev.h | 2 - src/libvirt_private.syms | 10 +- src/libxl/libxl_capabilities.c | 2 +- src/libxl/libxl_domain.c | 65 ++- src/libxl/libxl_driver.c | 25 +- src/network/bridge_driver.c | 2 +- src/qemu/qemu_capabilities.c | 4 +- src/qemu/qemu_command.c | 14 +- src/qemu/qemu_domain.c | 29 +- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_validate.c | 6 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 4 +- src/security/security_selinux.c | 4 +- src/security/virt-aa-helper.c | 8 +- src/util/virpci.c | 438 ++++++++++++++++-- src/util/virpci.h | 3 + src/util/virstring.c | 17 + src/util/virstring.h | 1 + tests/domaincapstest.c | 4 +- tests/libxlxml2domconfigdata/moredevs-hvm.xml | 1 - tests/networkxml2xmlin/hostdev-pf-old.xml | 8 + tests/networkxml2xmlin/hostdev-pf.xml | 2 +- tests/networkxml2xmlout/hostdev-pf-old.xml | 8 + tests/networkxml2xmlout/hostdev-pf.xml | 2 +- tests/networkxml2xmltest.c | 6 + tests/qemuhotplugmock.c | 15 + .../qemuhotplug-hostdev-pci.xml | 1 - .../qemuhotplug-base-live+hostdev-pci.xml | 2 +- ...uhotplug-pseries-base-live+hostdev-pci.xml | 2 +- tests/qemustatusxml2xmldata/modern-in.xml | 2 +- .../hostdev-pci-address-unassigned.xml | 4 - .../hostdev-pci-multifunction.xml | 7 - .../hostdev-vfio-multidomain.xml | 1 - .../hostdev-vfio-zpci-autogenerate-fids.xml | 2 - .../hostdev-vfio-zpci-autogenerate-uids.xml | 2 - .../hostdev-vfio-zpci-autogenerate.xml | 1 - .../hostdev-vfio-zpci-boundaries.xml | 2 - .../hostdev-vfio-zpci-ccw-memballoon.xml | 1 - .../hostdev-vfio-zpci-duplicate.xml | 2 - ...ostdev-vfio-zpci-invalid-uid-valid-fid.xml | 1 - .../hostdev-vfio-zpci-multidomain-many.xml | 8 - .../hostdev-vfio-zpci-set-zero.xml | 1 - .../hostdev-vfio-zpci-uid-set-zero.xml | 1 - .../hostdev-vfio-zpci-wrong-arch.xml | 1 - tests/qemuxml2argvdata/hostdev-vfio-zpci.xml | 1 - .../hostdev-vfio.x86_64-latest.args | 5 +- tests/qemuxml2argvdata/hostdev-vfio.xml | 19 +- .../net-hostdev-vfio-multidomain.xml | 1 - tests/qemuxml2argvdata/net-hostdev-vfio.xml | 1 - tests/qemuxml2argvdata/pseries-hostdevs-1.xml | 3 - tests/qemuxml2argvdata/pseries-hostdevs-2.xml | 2 - tests/qemuxml2argvdata/pseries-hostdevs-3.xml | 2 - ...v-pci-address-unassigned.x86_64-latest.xml | 4 - ...ostdev-pci-multifunction.x86_64-latest.xml | 7 - ...io-zpci-autogenerate-fids.s390x-latest.xml | 2 - ...io-zpci-autogenerate-uids.s390x-latest.xml | 2 - ...ev-vfio-zpci-autogenerate.s390x-latest.xml | 1 - ...tdev-vfio-zpci-boundaries.s390x-latest.xml | 2 - ...-vfio-zpci-ccw-memballoon.s390x-latest.xml | 1 - ...fio-zpci-multidomain-many.s390x-latest.xml | 8 - .../hostdev-vfio-zpci.s390x-latest.xml | 1 - .../hostdev-vfio.x86_64-latest.xml | 24 +- .../net-hostdev-vfio.x86_64-latest.xml | 1 - .../pseries-hostdevs-1.ppc64-latest.xml | 3 - .../pseries-hostdevs-2.ppc64-latest.xml | 2 - .../pseries-hostdevs-3.ppc64-latest.xml | 2 - tests/virhostdevtest.c | 2 +- .../plug-hostdev-pci-unmanaged.xml | 2 +- .../plug-hostdev-pci.xml | 2 +- tests/xlconfigdata/test-fullvirt-pci.xml | 2 - tests/xmconfigdata/test-pci-dev-syntax.xml | 2 - tests/xmconfigdata/test-pci-devs.xml | 2 - tools/virsh-completer-nodedev.c | 4 +- 92 files changed, 933 insertions(+), 498 deletions(-) create mode 100644 tests/networkxml2xmlin/hostdev-pf-old.xml create mode 100644 tests/networkxml2xmlout/hostdev-pf-old.xml
participants (3)
-
Ján Tomko
-
Laine Stump
-
Peter Krempa