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(a)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