
On Wed, Apr 26, 2017 at 04:55:31PM +0200, Erik Skultety wrote:
The parent device needs to report the generic stuff about the supported mediated devices types, like device API, available instances, type name, etc. Therefore this patch introduces a new nested capability element of type 'mdev_types' with the resulting XML of the following format:
<device> ... <capability type='pci'> ... <capability type='mdev_types'> <type id='vendor_supplied_id'> <name>optional_vendor_supplied_codename</name> <deviceAPI>vfio-pci</deviceAPI> <availableInstances>NUM</availableInstances> </type> ... <type> ...
It's a commit message so it doesn't matter but I would indent the place-holder dots :).
</type> </capability> </capability> ... </device>
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- docs/schemas/nodedev.rng | 26 +++++ src/conf/node_device_conf.c | 104 ++++++++++++++++++ src/conf/node_device_conf.h | 15 +++ src/conf/virnodedeviceobj.c | 7 ++ src/libvirt_private.syms | 1 + src/node_device/node_device_udev.c | 119 +++++++++++++++++++++ .../pci_0000_02_10_7_mdev_types.xml | 32 ++++++ tests/nodedevxml2xmltest.c | 1 + 8 files changed, 305 insertions(+) create mode 100644 tests/nodedevschemadata/pci_0000_02_10_7_mdev_types.xml
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng index 0f90a73c8..e0a2c5032 100644 --- a/docs/schemas/nodedev.rng +++ b/docs/schemas/nodedev.rng @@ -205,6 +205,32 @@ </optional>
<optional> + <element name='capability'> + <attribute name='type'> + <value>mdev_types</value> + </attribute> + <oneOrMore> + <element name='type'> + <attribute name='id'> + <data type='string'/> + </attribute> + <optional> + <element name='name'><text/></element> + </optional> + <element name='deviceAPI'> + <choice> + <value>vfio-pci</value> + </choice> + </element> + <element name='availableInstances'> + <ref name='unsignedInt'/> + </element> + </element> + </oneOrMore> + </element> + </optional> + + <optional> <element name='iommuGroup'> <attribute name='number'> <ref name='unsignedInt'/> diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 24cb6d66f..b3012821a 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -88,6 +88,26 @@ virNodeDevCapsDefParseString(const char *xpath, }
+static void +virNodeDevCapMdevTypeClear(virNodeDevCapMdevTypePtr type) +{ + VIR_FREE(type->id); + VIR_FREE(type->name); + VIR_FREE(type->device_api); +}
There is no need for the extra Clear function since it's static and used only by the Free function.
+ + +void +virNodeDevCapMdevTypeFree(virNodeDevCapMdevTypePtr type) +{ + if (!type) + return; + + virNodeDevCapMdevTypeClear(type); + VIR_FREE(type); +} + + void virNodeDeviceDefFree(virNodeDeviceDefPtr def) { @@ -265,6 +285,27 @@ virNodeDeviceCapPCIDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "<capability type='%s'/>\n", virPCIHeaderTypeToString(data->pci_dev.hdrType)); } + if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) { + virBufferAddLit(buf, "<capability type='mdev_types'>\n"); + virBufferAdjustIndent(buf, 2); + for (i = 0; i < data->pci_dev.nmdev_types; i++) { + virNodeDevCapMdevTypePtr type = data->pci_dev.mdev_types[i]; + virBufferEscapeString(buf, "<type id='%s'>\n", type->id); + virBufferAdjustIndent(buf, 2); + if (type->name) + virBufferAsprintf(buf, "<name>%s</name>\n", + type->name); + virBufferAsprintf(buf, "<deviceAPI>%s</deviceAPI>\n", + type->device_api);
We should use virBufferEscapeString for <name> and <deviceAPI> as well, the data stored in these variables are loaded from sysfs.
+ virBufferAsprintf(buf, + "<availableInstances>%u</availableInstances>\n", + type->available_instances); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</type>\n"); + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</capability>\n"); + } if (data->pci_dev.nIommuGroupDevices) { virBufferAsprintf(buf, "<iommuGroup number='%d'>\n", data->pci_dev.iommuGroupNumber); @@ -1365,6 +1406,63 @@ virNodeDevPCICapSRIOVVirtualParseXML(xmlXPathContextPtr ctxt,
static int +virNodeDevPCICapMdevTypesParseXML(xmlXPathContextPtr ctxt, + virNodeDevCapPCIDevPtr pci_dev) +{ + int ret = -1; + xmlNodePtr orignode = NULL; + xmlNodePtr *nodes = NULL; + int nmdev_types = virXPathNodeSet("./type", ctxt, &nodes); + virNodeDevCapMdevTypePtr type = NULL; + size_t i; + + orignode = ctxt->node; + for (i = 0; i < nmdev_types; i++) { + ctxt->node = nodes[i]; + + if (VIR_ALLOC(type) < 0) + goto cleanup; + + if (!(type->id = virXPathString("string(./@id[1])", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing 'id' attribute for mediated device's " + "<type> element")); + goto cleanup; + } + + if (!(type->device_api = virXPathString("string(./deviceAPI[1])", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, + _("missing device API for mediated device type '%s'"), + type->id); + goto cleanup; + } + + if (virXPathUInt("number(./availableInstances)", ctxt, + &type->available_instances) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("missing number of available instances for " + "mediated device type '%s'"), + type->id); + goto cleanup; + } + + type->name = virXPathString("string(./name)", ctxt); + + if (VIR_APPEND_ELEMENT(pci_dev->mdev_types, + pci_dev->nmdev_types, type) < 0) + goto cleanup; + } + + pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV; + ret = 0; + cleanup: + virNodeDevCapMdevTypeFree(type); + ctxt->node = orignode; + return ret; +} + + +static int virNodeDevPCICapabilityParseXML(xmlXPathContextPtr ctxt, xmlNodePtr node, virNodeDevCapPCIDevPtr pci_dev) @@ -1386,6 +1484,9 @@ virNodeDevPCICapabilityParseXML(xmlXPathContextPtr ctxt, } else if (STREQ(type, "virt_functions") && virNodeDevPCICapSRIOVVirtualParseXML(ctxt, pci_dev) < 0) { goto cleanup; + } if (STREQ(type, "mdev_types") &&
s/if/else if/
+ virNodeDevPCICapMdevTypesParseXML(ctxt, pci_dev)) {
there should be " < 0 " comparison.
+ goto cleanup; } else { int hdrType = virPCIHeaderTypeFromString(type);
Pavel