<qemu:env name='QEMU_ENV' value='VAL'/>
</qemu:commandline>
</domain>
+</pre>
+
+ <h2><a id="xmlnsfeatures">QEMU feature configuration for testing</a></h2>
+
+ <p>
+ In some cases e.g. when developing a new feature or for testing it may
+ be required to control a given qemu feature (or qemu capability) to test
+ it before it's complete or disable it for debugging purposes.
+ <span class="since">Since 5.5.0</span> it's possible to use the same
+ special qemu namespace as above
+ (<code>http://libvirt.org/schemas/domain/qemu/1.0</code>) and use
+ <code><qemu:capabilities></code> element to add
+ (<code><qemu:add capability="capname"/></code>) or remove
+ (<code><qemu:del capability="capname"/></code>) capability bits.
+ The naming of the feature bits is the same libvirt uses in the status
+ XML. Note that this feature is meant for experiments only and should
+ _not_ be used in production.
+ </p>
+
+ <p>Example:</p><pre>
+<domain type='qemu' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
+ <name>testvm</name>
+
+ [...]
+
+ <qemu:capabilities>
+ <qemu:add capability='blockdev'/>
+ <qemu:del capability='drive'/>
+ </qemu:capabilities>
+</domain>
</pre>
<h2><a id="xmlconfig">Example domain XML config</a></h2>
virStringListFreeCount(def->args, def->num_args);
virStringListFreeCount(def->env_name, def->num_env);
virStringListFreeCount(def->env_value, def->num_env);
+ virStringListFreeCount(def->capsadd, def->ncapsadd);
+ virStringListFreeCount(def->capsdel, def->ncapsdel);
VIR_FREE(def);
}
}
+static int
+qemuDomainDefNamespaceParseCaps(qemuDomainXmlNsDefPtr nsdef,
+ xmlXPathContextPtr ctxt)
+{
+ VIR_AUTOFREE(xmlNodePtr *) nodesadd = NULL;
+ ssize_t nnodesadd;
+ VIR_AUTOFREE(xmlNodePtr *) nodesdel = NULL;
+ ssize_t nnodesdel;
+ size_t i;
+
+ if ((nnodesadd = virXPathNodeSet("./qemu:capabilities/qemu:add", ctxt, &nodesadd)) < 0 ||
+ (nnodesdel = virXPathNodeSet("./qemu:capabilities/qemu:del", ctxt, &nodesdel)) < 0)
+ return -1;
+
+ if (nnodesadd > 0) {
+ if (VIR_ALLOC_N(nsdef->capsadd, nnodesadd) < 0)
+ return -1;
+
+ for (i = 0; i < nnodesadd; i++) {
+ if (!(nsdef->capsadd[nsdef->ncapsadd++] = virXMLPropString(nodesadd[i], "capability"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing capability name"));
+ return -1;
+ }
+ }
+ }
+
+ if (nnodesdel > 0) {
+ if (VIR_ALLOC_N(nsdef->capsdel, nnodesdel) < 0)
+ return -1;
+
+ for (i = 0; i < nnodesdel; i++) {
+ if (!(nsdef->capsdel[nsdef->ncapsdel++] = virXMLPropString(nodesdel[i], "capability"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing capability name"));
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
static int
qemuDomainDefNamespaceParse(xmlDocPtr xml ATTRIBUTE_UNUSED,
xmlNodePtr root ATTRIBUTE_UNUSED,
return -1;
if (qemuDomainDefNamespaceParseCommandlineArgs(nsdata, ctxt) < 0 ||
- qemuDomainDefNamespaceParseCommandlineEnv(nsdata, ctxt) < 0)
+ qemuDomainDefNamespaceParseCommandlineEnv(nsdata, ctxt) < 0 ||
+ qemuDomainDefNamespaceParseCaps(nsdata, ctxt) < 0)
goto cleanup;
- if (nsdata->num_args > 0 || nsdata->num_env > 0)
+ if (nsdata->num_args > 0 || nsdata->num_env > 0 ||
+ nsdata->ncapsadd > 0 || nsdata->ncapsdel > 0)
VIR_STEAL_PTR(*data, nsdata);
ret = 0;
}
+static void
+qemuDomainDefNamespaceFormatXMLCaps(virBufferPtr buf,
+ qemuDomainXmlNsDefPtr xmlns)
+{
+ size_t i;
+
+ if (!xmlns->ncapsadd && !xmlns->ncapsdel)
+ return;
+
+ virBufferAddLit(buf, "<qemu:capabilities>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ for (i = 0; i < xmlns->ncapsadd; i++)
+ virBufferEscapeString(buf, "<qemu:add capability='%s'/>\n", xmlns->capsadd[i]);
+
+ for (i = 0; i < xmlns->ncapsdel; i++)
+ virBufferEscapeString(buf, "<qemu:del capability='%s'/>\n", xmlns->capsdel[i]);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</qemu:capabilities>\n");
+}
+
+
static int
qemuDomainDefNamespaceFormatXML(virBufferPtr buf,
void *nsdata)
qemuDomainXmlNsDefPtr cmd = nsdata;
qemuDomainDefNamespaceFormatXMLCommandline(buf, cmd);
+ qemuDomainDefNamespaceFormatXMLCaps(buf, cmd);
return 0;
}