commit b0cad42ef24ad379e2d7bc47cd8cd39dba5f35fa
Author: Jim Fehlig <jfehlig@suse.com>
Date:   Thu Jul 30 13:25:20 2020 -0600

    Xen: Add support for qemu command-line passthrough
    
    Xen supports passing arbitrary arguments to the QEMU device model via
    the 'extra' member of the public libxl_domain_build_info structure.
    This patch adds a 'xen' namespace extension, similar to the QEMU and
    bhyve drivers, to map arbitrary arguments to the 'extra' member. Only
    passthrough of arguments is supported. Passthrough of environment
    variables or capabilities adjustments is not supported.
    
    Signed-off-by: Jim Fehlig <jfehlig@suse.com>
    Reviewed-by: Michal Privoznik <mprivozn@redhat.com>

Index: libvirt-6.0.0/docs/drvxen.html.in
===================================================================
--- libvirt-6.0.0.orig/docs/drvxen.html.in
+++ libvirt-6.0.0/docs/drvxen.html.in
@@ -141,6 +141,35 @@ vnclisten = "0.0.0.0"
 disk = [ "tap:aio:/var/lib/xen/images/rhel5pv.img,xvda,w", "tap:qcow:/root/qcow1-xen.img,xvdd,w" ]
 vif = [ "mac=00:16:3e:60:36:ba,bridge=virbr0,script=vif-bridge,vifname=vif5.0" ]</pre>
 
+    <h2><a id="xencommand">Pass-through of arbitrary command-line arguments
+    to the qemu device model</a></h2>
+
+    <p><span class="since">Since 6.7.0</span>, the Xen driver supports passing
+      arbitrary command-line arguments to the qemu device model used by Xen with
+      the <code>&lt;xen:commandline&gt;</code> element under <code>domain</code>.
+      In order to use command-line pass-through, an XML namespace request must be
+      issued that pulls in <code>http://libvirt.org/schemas/domain/xen/1.0</code>.
+      With the namespace in place, it is then possible to add
+      <code>&lt;xen:arg&gt;</code>sub-elements to
+      <code>&lt;xen:commandline&gt;</code> describing each argument passed to
+      the device model when starting the domain.
+    </p>
+    <p>The following example illustrates passing agruments to the QEMU device
+      model that define a floppy drive, which Xen does not support through its
+      public APIs:
+    </p>
+    <pre>
+&lt;domain type="xen" xmlns:xen="http://libvirt.org/schemas/domain/xen/1.0"&gt;
+  ...
+  &lt;xen:commandline&gt;
+    &lt;xen:arg value='-drive'/&gt;
+    &lt;xen:arg value='file=/path/to/image,format=raw,if=none,id=drive-fdc0-0-0'/&gt;
+    &lt;xen:arg value='-global'/&gt;
+    &lt;xen:arg value='isa-fdc.driveA=drive-fdc0-0-0'/&gt;
+  &lt;/xen:commandline&gt;
+&lt;/domain&gt;
+    </pre>
+
     <h2><a id="xmlconfig">Example domain XML config</a></h2>
 
     <p>
Index: libvirt-6.0.0/docs/schemas/domaincommon.rng
===================================================================
--- libvirt-6.0.0.orig/docs/schemas/domaincommon.rng
+++ libvirt-6.0.0/docs/schemas/domaincommon.rng
@@ -87,6 +87,9 @@
         <optional>
           <ref name='bhyvecmdline'/>
         </optional>
+        <optional>
+          <ref name='xencmdline'/>
+        </optional>
       </interleave>
     </element>
   </define>
@@ -6417,6 +6420,20 @@
       <zeroOrMore>
         <element name="arg">
           <attribute name='value'/>
+        </element>
+      </zeroOrMore>
+    </element>
+  </define>
+
+  <!--
+       Optional hypervisor extensions in their own namespace:
+         Xen
+    -->
+  <define name="xencmdline">
+    <element name="commandline" ns="http://libvirt.org/schemas/domain/xen/1.0">
+      <zeroOrMore>
+        <element name="arg">
+          <attribute name='value'/>
         </element>
       </zeroOrMore>
     </element>
Index: libvirt-6.0.0/src/libxl/libxl_conf.c
===================================================================
--- libvirt-6.0.0.orig/src/libxl/libxl_conf.c
+++ libvirt-6.0.0/src/libxl/libxl_conf.c
@@ -761,6 +761,13 @@ libxlMakeDomBuildInfo(virDomainDefPtr de
         libxl_get_required_shadow_memory(b_info->max_memkb,
                                          b_info->max_vcpus);
 
+    if (def->namespaceData) {
+        libxlDomainXmlNsDefPtr nsdata = def->namespaceData;
+
+        if (nsdata->num_args > 0)
+            b_info->extra = g_strdupv(nsdata->args);
+    }
+
     return 0;
 }
 
@@ -2512,5 +2519,6 @@ libxlCreateXMLConf(libxlDriverPrivatePtr
     libxlDomainDefParserConfig.priv = driver;
     return virDomainXMLOptionNew(&libxlDomainDefParserConfig,
                                  &libxlDomainXMLPrivateDataCallbacks,
-                                 NULL, NULL, NULL);
+                                 &libxlDriverDomainXMLNamespace,
+                                 NULL, NULL);
 }
Index: libvirt-6.0.0/src/libxl/libxl_conf.h
===================================================================
--- libvirt-6.0.0.orig/src/libxl/libxl_conf.h
+++ libvirt-6.0.0/src/libxl/libxl_conf.h
@@ -162,6 +162,14 @@ struct _libxlSavefileHeader {
     uint32_t unused[10];
 };
 
+
+typedef struct _libxlDomainXmlNsDef libxlDomainXmlNsDef;
+typedef libxlDomainXmlNsDef *libxlDomainXmlNsDefPtr;
+struct _libxlDomainXmlNsDef {
+    size_t num_args;
+    char **args;
+};
+
 libxlDriverConfigPtr
 libxlDriverConfigNew(void);
 
Index: libvirt-6.0.0/src/libxl/libxl_domain.c
===================================================================
--- libvirt-6.0.0.orig/src/libxl/libxl_domain.c
+++ libvirt-6.0.0/src/libxl/libxl_domain.c
@@ -1562,3 +1562,85 @@ libxlDomainDefCheckABIStability(libxlDri
     virDomainDefFree(migratableDefDst);
     return ret;
 }
+
+
+static void
+libxlDomainDefNamespaceFree(void *nsdata)
+{
+    libxlDomainXmlNsDefPtr def = nsdata;
+
+    if (!def)
+        return;
+
+    g_strfreev(def->args);
+    g_free(def);
+}
+
+
+static int
+libxlDomainDefNamespaceParse(xmlXPathContextPtr ctxt,
+                             void **data)
+{
+    libxlDomainXmlNsDefPtr nsdata = NULL;
+    g_autofree xmlNodePtr *nodes = NULL;
+    ssize_t nnodes;
+    size_t i;
+    int ret = -1;
+
+    if ((nnodes = virXPathNodeSet("./xen:commandline/xen:arg", ctxt, &nodes)) < 0)
+        return -1;
+
+    if (nnodes == 0)
+        return 0;
+
+    nsdata = g_new0(libxlDomainXmlNsDef, 1);
+    nsdata->args = g_new0(char *, nnodes + 1);
+
+    for (i = 0; i < nnodes; i++) {
+        if (!(nsdata->args[nsdata->num_args++] = virXMLPropString(nodes[i], "value"))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("No device model command-line argument specified"));
+            goto cleanup;
+        }
+    }
+
+    *data = g_steal_pointer(&nsdata);
+    ret = 0;
+
+ cleanup:
+    libxlDomainDefNamespaceFree(nsdata);
+    return ret;
+}
+
+
+static int
+libxlDomainDefNamespaceFormatXML(virBufferPtr buf,
+                                 void *nsdata)
+{
+    libxlDomainXmlNsDefPtr cmd = nsdata;
+    size_t i;
+
+    if (!cmd->num_args)
+        return 0;
+
+    virBufferAddLit(buf, "<xen:commandline>\n");
+    virBufferAdjustIndent(buf, 2);
+
+    for (i = 0; i < cmd->num_args; i++)
+        virBufferEscapeString(buf, "<xen:arg value='%s'/>\n",
+                              cmd->args[i]);
+
+    virBufferAdjustIndent(buf, -2);
+    virBufferAddLit(buf, "</xen:commandline>\n");
+
+    return 0;
+}
+
+
+virXMLNamespace libxlDriverDomainXMLNamespace = {
+    .parse = libxlDomainDefNamespaceParse,
+    .free = libxlDomainDefNamespaceFree,
+    .format = libxlDomainDefNamespaceFormatXML,
+    .prefix = "xen",
+    .uri = "http://libvirt.org/schemas/domain/xen/1.0",
+};
Index: libvirt-6.0.0/src/libxl/libxl_domain.h
===================================================================
--- libvirt-6.0.0.orig/src/libxl/libxl_domain.h
+++ libvirt-6.0.0/src/libxl/libxl_domain.h
@@ -77,6 +77,7 @@ struct _libxlDomainObjPrivate {
 
 extern virDomainXMLPrivateDataCallbacks libxlDomainXMLPrivateDataCallbacks;
 extern virDomainDefParserConfig libxlDomainDefParserConfig;
+extern virXMLNamespace libxlDriverDomainXMLNamespace;
 extern const struct libxl_event_hooks ev_hooks;
 
 int
