The idea of having an attribute that declares that a hostdev is not to be assigned to the guest seems counterintuitive, but it has a niche use with multifunction PCI devices. The current use of this kind of device in Libvirt is to declare all of the functions in the XML. This is not ideal though - some devices might have functions that are security sensitive to be shared to guests, but at the same time the user might want to passthrough the other functions to a guest. This is what we call 'partial assignment'. Libvirt does not have proper support for this scenario: when using managed='yes', this partial assignment will cause the code inside virhostdev.c to not detach all the IOMMU devices - given that we do not want all of them in the guest - and then we face a QEMU error because we didn't detached the whole IOMMU. An idea was discussed in [1] where Libvirt would automatically detach all the IOMMU devices in case any multifunction PCI hostdev is used in the guest, but this idea was discarded because removing user agency in this case is undesirable. The user must be aware of all the functions that are going to be detached from the host, even if they're not being assigned to the guest, to avoid scenarios in which Libvirt "all of a sudden" detaches something that the user didn't want to. This patch implements a new attribute called 'assigned' that indicates whether a hostdev is going to be assigned to the guest or not. To keep its use less intrusive for every other hostdev that does not need such control, the attribute can only be set by PCI multifunction devices. For existing domains prior to this change, assign='yes' will be implied. If the user decides not to assign a specific function to the guest using assign='no', the <address> field becomes unavailable and throws a parsing error if used. In the next patch we'll use this attribute to avoid assigning an assigned='no' device to QEMU at boot. Signed-off-by: Daniel Henrique Barboza <danielhb413@xxxxxxxxx> --- Note: the changes in the .config files were done because the existing .config data files weren't being recognized as multifunction PCI devices after we started reading the PCI header. docs/schemas/domaincommon.rng | 5 +++ src/conf/domain_conf.c | 36 +++++++++++++++++- src/conf/domain_conf.h | 1 + .../hostdev-pci-multifunction.args | 7 ++-- .../hostdev-pci-multifunction.xml | 6 +++ .../hostdev-pci-multifunction.xml | 23 +++++++---- .../qemuxml2xmloutdata/pseries-hostdevs-1.xml | 4 +- .../qemuxml2xmloutdata/pseries-hostdevs-2.xml | 4 +- .../qemuxml2xmloutdata/pseries-hostdevs-3.xml | 4 +- tests/virpcitestdata/0005-90-01.1.config | Bin 256 -> 256 bytes tests/virpcitestdata/0005-90-01.2.config | Bin 256 -> 256 bytes tests/virpcitestdata/0005-90-01.3.config | Bin 0 -> 256 bytes tools/virsh-domain.c | 5 +++ 13 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 tests/virpcitestdata/0005-90-01.3.config diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 40eb4a2d75..d1a5c051e3 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4629,6 +4629,11 @@ <attribute name="type"> <value>pci</value> </attribute> + <optional> + <attribute name="assigned"> + <ref name="virYesNo"/> + </attribute> + </optional> <interleave> <optional> <element name="driver"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a53cd6a725..8d80824a0a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -7755,7 +7755,6 @@ virDomainHostdevSubsysPCIDefParseXML(xmlNodePtr node, if (virXMLNodeNameEqual(cur, "address")) { virPCIDeviceAddressPtr addr = &def->source.subsys.u.pci.addr; - if (virPCIDeviceAddressParseXML(cur, addr) < 0) goto out; } else if ((flags & VIR_DOMAIN_DEF_PARSE_STATUS) && @@ -8147,7 +8146,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, virDomainHostdevDefPtr def, unsigned int flags) { - xmlNodePtr sourcenode; + xmlNodePtr sourcenode, addressnode; int backend; virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci; virDomainHostdevSubsysSCSIPtr scsisrc = &def->source.subsys.u.scsi; @@ -8159,6 +8158,8 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, VIR_AUTOFREE(char *) backendStr = NULL; VIR_AUTOFREE(char *) model = NULL; VIR_AUTOFREE(char *) display = NULL; + VIR_AUTOFREE(char *) assigned = NULL; + /* @managed can be read from the xml document - it is always an * attribute of the toplevel element, no matter what type of @@ -8289,6 +8290,32 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, if (virDomainHostdevSubsysPCIDefParseXML(sourcenode, def, flags) < 0) return -1; + /* @assigned can only be set for multifunction PCI devices. + * In case the attribute is missing, always assume + * assigned = true. + */ + def->assigned = true; + + if ((assigned = virXMLPropString(node, "assigned")) != NULL) { + if (!virHostdevIsPCIMultifunctionDevice(def)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("'assigned' can only be set for multifunction " + "PCI devices")); + return -1; + } + + if (STREQ(assigned, "no")) + def->assigned = false; + + if ((addressnode = virXPathNode("./address", ctxt)) && + !def->assigned) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("unable to set <address> element " + "for assign='no' hostdev")); + return -1; + } + } + backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT; if ((backendStr = virXPathString("string(./driver/@name)", ctxt)) && (((backend = virDomainHostdevSubsysPCIBackendTypeFromString(backendStr)) < 0) || @@ -27254,6 +27281,11 @@ virDomainHostdevDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " managed='%s'", def->managed ? "yes" : "no"); + if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && + virHostdevIsPCIMultifunctionDevice(def)) + virBufferAsprintf(buf, " assigned='%s'", + def->assigned ? "yes" : "no"); + if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI && scsisrc->sgio) virBufferAsprintf(buf, " sgio='%s'", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 2884af49d8..e2f6f640b9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -343,6 +343,7 @@ struct _virDomainHostdevDef { bool missing; bool readonly; bool shareable; + bool assigned; union { virDomainHostdevSubsys subsys; virDomainHostdevCaps caps; diff --git a/tests/qemuxml2argvdata/hostdev-pci-multifunction.args b/tests/qemuxml2argvdata/hostdev-pci-multifunction.args index d8690c010b..3cef177c00 100644 --- a/tests/qemuxml2argvdata/hostdev-pci-multifunction.args +++ b/tests/qemuxml2argvdata/hostdev-pci-multifunction.args @@ -30,6 +30,7 @@ server,nowait \ -device vfio-pci,host=0001:01:00.0,id=hostdev2,bus=pci.0,addr=0x5 \ -device vfio-pci,host=0005:90:01.2,id=hostdev3,bus=pci.0,addr=0x6 \ -device vfio-pci,host=0005:90:01.3,id=hostdev4,bus=pci.0,addr=0x7 \ --device vfio-pci,host=0000:06:12.1,id=hostdev5,bus=pci.0,addr=0x8 \ --device vfio-pci,host=0000:06:12.2,id=hostdev6,bus=pci.0,addr=0x9 \ --device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0xa +-device vfio-pci,host=0000:06:12.0,id=hostdev5,bus=pci.0,addr=0x8 \ +-device vfio-pci,host=0000:06:12.1,id=hostdev6,bus=pci.0,addr=0x9 \ +-device vfio-pci,host=0000:06:12.2,id=hostdev7,bus=pci.0,addr=0xa \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0xb diff --git a/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml b/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml index 06c889c64d..f4813961b3 100644 --- a/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml +++ b/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml @@ -43,6 +43,12 @@ <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='0x0'/> + </source> + </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> diff --git a/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml b/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml index 52ed86e305..079e0513c1 100644 --- a/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml +++ b/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml @@ -23,35 +23,35 @@ <controller type='pci' index='0' model='pci-root'/> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='yes'> <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </hostdev> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='yes'> <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </hostdev> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='yes'> <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </hostdev> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='yes'> <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </hostdev> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='yes'> <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x3'/> @@ -61,19 +61,26 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> </hostdev> - <memballoon model='virtio'> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </hostdev> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> </memballoon> </devices> </domain> diff --git a/tests/qemuxml2xmloutdata/pseries-hostdevs-1.xml b/tests/qemuxml2xmloutdata/pseries-hostdevs-1.xml index e77a060a38..94472b38e4 100644 --- a/tests/qemuxml2xmloutdata/pseries-hostdevs-1.xml +++ b/tests/qemuxml2xmloutdata/pseries-hostdevs-1.xml @@ -35,14 +35,14 @@ </source> <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> </interface> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='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'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='yes'> <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> diff --git a/tests/qemuxml2xmloutdata/pseries-hostdevs-2.xml b/tests/qemuxml2xmloutdata/pseries-hostdevs-2.xml index cfa395b001..f2fe94d2fb 100644 --- a/tests/qemuxml2xmloutdata/pseries-hostdevs-2.xml +++ b/tests/qemuxml2xmloutdata/pseries-hostdevs-2.xml @@ -30,14 +30,14 @@ <model name='spapr-pci-host-bridge'/> <target index='2'/> </controller> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='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'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='yes'> <driver name='vfio'/> <source> <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> diff --git a/tests/qemuxml2xmloutdata/pseries-hostdevs-3.xml b/tests/qemuxml2xmloutdata/pseries-hostdevs-3.xml index f91959b805..0893ecd887 100644 --- a/tests/qemuxml2xmloutdata/pseries-hostdevs-3.xml +++ b/tests/qemuxml2xmloutdata/pseries-hostdevs-3.xml @@ -27,14 +27,14 @@ <model name='spapr-pci-host-bridge'/> <target index='2'/> </controller> - <hostdev mode='subsystem' type='pci' managed='yes'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='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'> + <hostdev mode='subsystem' type='pci' managed='yes' assigned='yes'> <driver name='vfio'/> <source> <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> diff --git a/tests/virpcitestdata/0005-90-01.1.config b/tests/virpcitestdata/0005-90-01.1.config index beee76534041a7020c08ae9ac03d9a349c6ea12e..a60599bd342d3ebcdc7b8367ca36ad337f602fde 100644 GIT binary patch delta 44 ycmZo*YG4vE7BFRCV-R3+7GUOK;Amg~f~JXq5)*X<85t+qEn;Cc-jFjfPzC^<7YL>R delta 39 ucmZo*YG4vE7BFRCV-R3+7GUOK;9y{25MXGU7$`AON05<eqTQm22?_viD+cla diff --git a/tests/virpcitestdata/0005-90-01.2.config b/tests/virpcitestdata/0005-90-01.2.config index cfd72e4d7165bff2751ecbdc570ce7f1e0646226..a60599bd342d3ebcdc7b8367ca36ad337f602fde 100644 GIT binary patch literal 256 zcmXpOFlAt45MXi^VCG@qXkY+>CJ=!Q7z5RUfCHEW5{!&mj0{Y5Fz#TaS&cX3;ByxM DCDjDB literal 256 zcmXpOc)-BMAi%_;z|6zo!oa|wz|aIFu>xbDS`csmlR$!5K#7rosSd`)Mk^@TV-u#E T7_0Gy9FS#<5E~CbC<F-rZiWW} diff --git a/tests/virpcitestdata/0005-90-01.3.config b/tests/virpcitestdata/0005-90-01.3.config new file mode 100644 index 0000000000000000000000000000000000000000..a60599bd342d3ebcdc7b8367ca36ad337f602fde GIT binary patch literal 256 zcmXpOFlAt45MXi^VCG@qXkY+>CJ=!Q7z5RUfCHEW5{!&mj0{Y5Fz#TaS&cX3;ByxM DCDjDB literal 0 HcmV?d00001 diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index fbfdc09c0d..1453d7f024 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -858,6 +858,11 @@ static const vshCmdOptDef opts_attach_interface[] = { .type = VSH_OT_BOOL, .help = N_("libvirt will automatically detach/attach the device from/to host") }, + {.name = "assigned", + .type = VSH_OT_BOOL, + .help = N_("hostdev virtual function will be assigned to the guest " + "(multifunction PCI device only)") + }, {.name = NULL} }; -- 2.21.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list