This adds support for custom command line arguments for the passt
backend, similar to qemu:commandline. The feature allows passing
additional arguments to the passt process for development and testing
purposes.

The implementation:
- Adds a passt XML namespace for custom arguments
- Properly taints the domain when custom args are used
- Includes comprehensive test coverage
- Adds documentation for the new feature

Usage example:
  <interface type='user'>
    <backend type='passt' 
xmlns:passt='http://libvirt.org/schemas/domain/passt/1.0'>
      <passt:commandline>
        <passt:arg value='--debug'/>
        <passt:arg value='--verbose'/>
      </passt:commandline>
    </backend>
  </interface>

Signed-off-by: Enrique Llorente <ellor...@redhat.com>
---
v3:
 - Fix all test problems
 - Refactor domain_conf.c to use libvirt xml constructs to have proper
   indent
 - Rework documentation and make it more concise
 - Add domainpassttest.c to check that arguments are passed to passt

 docs/formatdomain.rst                         |  38 ++++
 src/conf/domain_conf.c                        |  61 ++++++-
 src/conf/domain_conf.h                        |   6 +
 src/conf/schemas/domaincommon.rng             |  15 ++
 src/qemu/qemu_passt.c                         |   9 +
 tests/meson.build                             |   1 +
 tests/qemupassttest.c                         | 162 ++++++++++++++++++
 ...-user-passt-custom-args.x86_64-latest.args |  35 ++++
 ...t-user-passt-custom-args.x86_64-latest.xml |  67 ++++++++
 .../net-user-passt-custom-args.xml            |  64 +++++++
 tests/qemuxmlconftest.c                       |   1 +
 11 files changed, 458 insertions(+), 1 deletion(-)
 create mode 100644 tests/qemupassttest.c
 create mode 100644 
tests/qemuxmlconfdata/net-user-passt-custom-args.x86_64-latest.args
 create mode 100644 
tests/qemuxmlconfdata/net-user-passt-custom-args.x86_64-latest.xml
 create mode 100644 tests/qemuxmlconfdata/net-user-passt-custom-args.xml

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 9a2f065590..4c01a07135 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -5464,6 +5464,44 @@ ports **with the exception of some subset**.
    </devices>
    ...
 
+Custom passt commandline arguments
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. warning::
+
+   **This is an unsupported feature for development and testing only.**
+   Using it will taint the domain. Users are strongly advised to use the
+   proper libvirt XML elements for configuring passt instead.
+
+
+:since:`Since 11.7.0` For development and testing purposes, it is
+sometimes useful to be able to pass additional command-line arguments
+directly to the passt process. This can be accomplished using a
+special passt namespace in the domain XML that is similar to the qemu
+commandline namespace:
+
+::
+
+   ...
+   <devices>
+     ...
+     <interface type='user'>
+       <backend type='passt'>
+         <passt:commandline 
xmlns:passt='http://libvirt.org/schemas/domain/passt/1.0'>
+           <passt:arg value='--debug'/>
+           <passt:arg value='--verbose'/>
+         </passt:commandline>
+       </backend>
+     </interface>
+   </devices>
+   ...
+
+Any arguments provided using this method will be appended to the passt
+command line, and will therefore override any default options set by
+libvirt in the case of conflicts. **This can lead to unexpected behavior
+and libvirt cannot guarantee functionality when its default configuration
+is overridden.**
+
 Generic ethernet connection
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 1e24e41a48..9721763622 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2918,6 +2918,10 @@ virDomainNetDefFree(virDomainNetDef *def)
     g_free(def->backend.tap);
     g_free(def->backend.vhost);
     g_free(def->backend.logFile);
+    if (def->backend.passtCommandline) {
+        g_strfreev(def->backend.passtCommandline->args);
+        g_free(def->backend.passtCommandline);
+    }
     virDomainNetTeamingInfoFree(def->teaming);
     g_free(def->virtPortProfile);
     g_free(def->script);
@@ -9772,6 +9776,7 @@ virDomainNetBackendParseXML(xmlNodePtr node,
 {
     g_autofree char *tap = virXMLPropString(node, "tap");
     g_autofree char *vhost = virXMLPropString(node, "vhost");
+    xmlNodePtr cur;
 
     /* In the case of NET_TYPE_USER, backend type can be unspecified
      * (i.e. VIR_DOMAIN_NET_BACKEND_DEFAULT) and that means 'use
@@ -9808,6 +9813,38 @@ virDomainNetBackendParseXML(xmlNodePtr node,
         def->backend.vhost = virFileSanitizePath(vhost);
     }
 
+    /* Parse passt namespace commandline */
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if (cur->ns &&
+                STREQ((const char *)cur->ns->href, 
"http://libvirt.org/schemas/domain/passt/1.0";) &&
+                STREQ((const char *)cur->name, "commandline")) {
+                xmlNodePtr arg_node = cur->children;
+                g_autoptr(GPtrArray) args = g_ptr_array_new();
+
+                while (arg_node != NULL) {
+                    if (arg_node->type == XML_ELEMENT_NODE &&
+                        arg_node->ns &&
+                        STREQ((const char *)arg_node->ns->href, 
"http://libvirt.org/schemas/domain/passt/1.0";) &&
+                        STREQ((const char *)arg_node->name, "arg")) {
+                        g_autofree char *value = virXMLPropString(arg_node, 
"value");
+                        if (value)
+                            g_ptr_array_add(args, g_strdup(value));
+                    }
+                    arg_node = arg_node->next;
+                }
+
+                if (args->len > 0) {
+                    def->backend.passtCommandline = 
g_new0(virDomainNetBackendPasstCommandline, 1);
+                    g_ptr_array_add(args, NULL); /* NULL-terminate */
+                    def->backend.passtCommandline->args = (char 
**)g_ptr_array_steal(args, NULL);
+                }
+            }
+        }
+        cur = cur->next;
+    }
+
     return 0;
 }
 
@@ -20802,6 +20839,7 @@ virDomainNetBackendIsEqual(virDomainNetBackend *src,
         STRNEQ_NULLABLE(src->logFile, dst->logFile)) {
         return false;
     }
+
     return true;
 }
 
@@ -24921,11 +24959,29 @@ virDomainNetTeamingInfoFormat(virDomainNetTeamingInfo 
*teaming,
 }
 
 
+static void
+virDomainNetBackendPasstCommandLineFormat(virBuffer *buf,
+                                           virDomainNetBackend *backend)
+{
+    g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
+    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+    GStrv n;
+
+    if (backend->passtCommandline && backend->passtCommandline->args) {
+        for (n = backend->passtCommandline->args; n && *n; n++)
+            virBufferEscapeString(&childBuf, "<passt:arg value='%s'/>\n", *n);
+        virBufferAddLit(&attrBuf, " 
xmlns:passt='http://libvirt.org/schemas/domain/passt/1.0'");
+        virXMLFormatElement(buf, "passt:commandline", &attrBuf, &childBuf);
+    }
+
+}
+
 static void
 virDomainNetBackendFormat(virBuffer *buf,
                           virDomainNetBackend *backend)
 {
     g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
+    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
 
     if (backend->type) {
         virBufferAsprintf(&attrBuf, " type='%s'",
@@ -24934,7 +24990,10 @@ virDomainNetBackendFormat(virBuffer *buf,
     virBufferEscapeString(&attrBuf, " tap='%s'", backend->tap);
     virBufferEscapeString(&attrBuf, " vhost='%s'", backend->vhost);
     virBufferEscapeString(&attrBuf, " logFile='%s'", backend->logFile);
-    virXMLFormatElement(buf, "backend", &attrBuf, NULL);
+
+    virDomainNetBackendPasstCommandLineFormat(&childBuf, backend);
+
+    virXMLFormatElement(buf, "backend", &attrBuf, &childBuf);
 }
 
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6997cf7c09..1f51bad546 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1070,12 +1070,18 @@ struct _virDomainActualNetDef {
     unsigned int class_id; /* class ID for bandwidth 'floor' */
 };
 
+typedef struct _virDomainNetBackendPasstCommandline 
virDomainNetBackendPasstCommandline;
+struct _virDomainNetBackendPasstCommandline {
+    char **args;  /* NULL-terminated array of arguments */
+};
+
 struct _virDomainNetBackend {
     virDomainNetBackendType type;
     char *tap;
     char *vhost;
     /* The following are currently only valid/used when backend type='passt' */
     char *logFile;  /* path to logfile used by passt process */
+    virDomainNetBackendPasstCommandline *passtCommandline;  /* for passt 
overrides */
 };
 
 struct _virDomainNetPortForwardRange {
diff --git a/src/conf/schemas/domaincommon.rng 
b/src/conf/schemas/domaincommon.rng
index 183dd5db5e..e176073c6a 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -3908,6 +3908,9 @@
       </optional>
       <optional>
         <element name="backend">
+          <optional>
+            <ref name="passtcmdline"/>
+          </optional>
           <optional>
             <attribute name="type">
               <choice>
@@ -8877,6 +8880,18 @@
     </attribute>
   </define>
 
+  <define name="passtcmdline">
+    <element name="commandline" 
ns="http://libvirt.org/schemas/domain/passt/1.0";>
+      <interleave>
+        <zeroOrMore>
+          <element name="arg">
+            <attribute name="value"/>
+          </element>
+        </zeroOrMore>
+      </interleave>
+    </element>
+  </define>
+
   <define name="coalesce">
     <element name="coalesce">
       <interleave>
diff --git a/src/qemu/qemu_passt.c b/src/qemu/qemu_passt.c
index fcc34de384..0163553cee 100644
--- a/src/qemu/qemu_passt.c
+++ b/src/qemu/qemu_passt.c
@@ -317,6 +317,15 @@ qemuPasstStart(virDomainObj *vm,
         virCommandAddArg(cmd, virBufferCurrentContent(&buf));
     }
 
+    /* Add custom passt arguments from namespace */
+    if (net->backend.passtCommandline && net->backend.passtCommandline->args) {
+        for (i = 0; net->backend.passtCommandline->args[i]; i++) {
+            virCommandAddArg(cmd, net->backend.passtCommandline->args[i]);
+        }
+
+        /* Taint the domain when using custom passt arguments */
+        qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_ARGV, NULL);
+    }
 
     if (qemuExtDeviceLogCommand(driver, vm, cmd, "passt") < 0)
         return -1;
diff --git a/tests/meson.build b/tests/meson.build
index 0d76d37959..fe9013b600 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -269,6 +269,7 @@ tests += [
   { 'name': 'networkxml2xmlupdatetest' },
   { 'name': 'nodedevxml2xmltest' },
   { 'name': 'nwfilterxml2xmltest' },
+  { 'name': 'qemupassttest' },
   { 'name': 'seclabeltest' },
   { 'name': 'secretxml2xmltest' },
   { 'name': 'sockettest' },
diff --git a/tests/qemupassttest.c b/tests/qemupassttest.c
new file mode 100644
index 0000000000..84f4c1510a
--- /dev/null
+++ b/tests/qemupassttest.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "testutils.h"
+#include "conf/domain_conf.h"
+#include "viralloc.h"
+#include "virstring.h"
+#include "virlog.h"
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+VIR_LOG_INIT("tests.qemupassttest");
+
+struct testPasstData {
+    const char *name;
+    const char *xmlfile;
+    const char * const *expectedArgs;
+    size_t nExpectedArgs;
+    bool expectCustomArgs;
+};
+
+static virDomainDef *
+testParseDomainXML(const char *xmlfile)
+{
+    g_autofree char *xmlpath = NULL;
+    g_autofree char *xmldata = NULL;
+    virDomainDef *def = NULL;
+    g_autoptr(virDomainXMLOption) xmlopt = NULL;
+
+    xmlpath = g_strdup_printf("%s/qemuxmlconfdata/%s", abs_srcdir, xmlfile);
+
+    if (virTestLoadFile(xmlpath, &xmldata) < 0)
+        return NULL;
+
+    if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL, NULL)))
+        return NULL;
+
+    def = virDomainDefParseString(xmldata, xmlopt, NULL,
+                                  VIR_DOMAIN_DEF_PARSE_INACTIVE);
+
+    return def;
+}
+
+static int
+testPasstParseCustomArgs(const void *opaque)
+{
+    const struct testPasstData *data = opaque;
+    g_autoptr(virDomainDef) def = NULL;
+    virDomainNetDef *net = NULL;
+    size_t i;
+
+    if (!(def = testParseDomainXML(data->xmlfile))) {
+        VIR_TEST_DEBUG("Failed to parse domain XML");
+        return -1;
+    }
+
+    /* Find the interface with passt backend */
+    for (i = 0; i < def->nnets; i++) {
+        if (def->nets[i]->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
+            net = def->nets[i];
+            break;
+        }
+    }
+
+    if (!net) {
+        VIR_TEST_DEBUG("No passt interface found in domain XML");
+        return -1;
+    }
+
+    /* Check if we have custom arguments */
+    if (data->expectCustomArgs) {
+        char **args;
+
+        if (!net->backend.passtCommandline || 
!net->backend.passtCommandline->args) {
+            VIR_TEST_DEBUG("Expected custom args but none found");
+            return -1;
+        }
+
+        args = net->backend.passtCommandline->args;
+
+        if (g_strv_length(args) != data->nExpectedArgs) {
+            VIR_TEST_DEBUG("Expected %zu arguments but found %u",
+                          data->nExpectedArgs, g_strv_length(args));
+            return -1;
+        }
+
+        /* Verify all expected arguments are present */
+        for (i = 0; i < data->nExpectedArgs; i++) {
+            if (!g_strv_contains((const char * const *)args, 
data->expectedArgs[i])) {
+                VIR_TEST_DEBUG("Missing expected argument: %s", 
data->expectedArgs[i]);
+                return -1;
+            }
+        }
+    } else {
+        /* Should not have custom arguments */
+        if (net->backend.passtCommandline &&
+            net->backend.passtCommandline->args &&
+            *net->backend.passtCommandline->args) {
+            VIR_TEST_DEBUG("Found custom args but none expected");
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int
+mymain(void)
+{
+    int ret = 0;
+
+    static const char * const customArgsExpected[] = {
+        "--debug",
+        "--verbose",
+        "--socket=/tmp/foo.socket"
+    };
+
+    struct testPasstData customArgsData = {
+        .name = "custom-args",
+        .xmlfile = "net-user-passt-custom-args.xml",
+        .expectedArgs = customArgsExpected,
+        .nExpectedArgs = G_N_ELEMENTS(customArgsExpected),
+        .expectCustomArgs = true,
+    };
+
+    struct testPasstData noCustomArgsData = {
+        .name = "no-custom-args",
+        .xmlfile = "net-user-passt.xml",
+        .expectedArgs = NULL,
+        .nExpectedArgs = 0,
+        .expectCustomArgs = false,
+    };
+
+    if (virTestRun("passt XML parsing with custom args",
+                   testPasstParseCustomArgs, &customArgsData) < 0)
+        ret = -1;
+
+    if (virTestRun("passt XML parsing without custom args",
+                   testPasstParseCustomArgs, &noCustomArgsData) < 0)
+        ret = -1;
+
+    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIR_TEST_MAIN(mymain)
diff --git 
a/tests/qemuxmlconfdata/net-user-passt-custom-args.x86_64-latest.args 
b/tests/qemuxmlconfdata/net-user-passt-custom-args.x86_64-latest.args
new file mode 100644
index 0000000000..48d2596594
--- /dev/null
+++ b/tests/qemuxmlconfdata/net-user-passt-custom-args.x86_64-latest.args
@@ -0,0 +1,35 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
+/usr/bin/qemu-system-x86_64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object 
'{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-QEMUGuest1/master-key.aes"}'
 \
+-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \
+-accel tcg \
+-cpu qemu64 \
+-m size=219136k \
+-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}' \
+-overcommit mem-lock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-boot strict=on \
+-blockdev 
'{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","read-only":false}'
 \
+-device 
'{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-storage","id":"ide0-0-0","bootindex":1}'
 \
+-netdev 
'{"type":"stream","addr":{"type":"unix","path":"/var/run/libvirt/qemu/passt/-1-QEMUGuest1-net0.socket"},"server":false,"reconnect-ms":5000,"id":"hostnet0"}'
 \
+-device 
'{"driver":"rtl8139","netdev":"hostnet0","id":"net0","mac":"00:11:22:33:44:55","bus":"pci.0","addr":"0x2"}'
 \
+-audiodev '{"id":"audio1","driver":"none"}' \
+-sandbox 
on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxmlconfdata/net-user-passt-custom-args.x86_64-latest.xml 
b/tests/qemuxmlconfdata/net-user-passt-custom-args.x86_64-latest.xml
new file mode 100644
index 0000000000..6718893a52
--- /dev/null
+++ b/tests/qemuxmlconfdata/net-user-passt-custom-args.x86_64-latest.xml
@@ -0,0 +1,67 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu mode='custom' match='exact' check='none'>
+    <model fallback='forbid'>qemu64</model>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <disk type='block' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <controller type='usb' index='0' model='none'/>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' 
function='0x1'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <interface type='user'>
+      <mac address='00:11:22:33:44:55'/>
+      <source dev='eth42'/>
+      <ip address='172.17.2.0' family='ipv4' prefix='24'/>
+      <ip address='2001:db8:ac10:fd01::feed' family='ipv6'/>
+      <portForward proto='tcp' address='2001:db8:ac10:fd01::1:10'>
+        <range start='22' to='2022'/>
+        <range start='1000' end='1050'/>
+        <range start='1020' exclude='yes'/>
+        <range start='1030' end='1040' exclude='yes'/>
+      </portForward>
+      <portForward proto='udp' address='1.2.3.4' dev='eth0'>
+        <range start='5000' end='5020' to='6000'/>
+        <range start='5010' end='5015' exclude='yes'/>
+      </portForward>
+      <portForward proto='tcp'>
+        <range start='80'/>
+      </portForward>
+      <portForward proto='tcp'>
+        <range start='443' to='344'/>
+      </portForward>
+      <model type='rtl8139'/>
+      <backend type='passt' logFile='/var/log/loglaw.blog'>
+        <passt:commandline 
xmlns:passt='http://libvirt.org/schemas/domain/passt/1.0'>
+          <passt:arg value='--debug'/>
+          <passt:arg value='--verbose'/>
+          <passt:arg value='--socket=/tmp/foo.socket'/>
+        </passt:commandline>
+      </backend>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' 
function='0x0'/>
+    </interface>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <audio id='1' type='none'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxmlconfdata/net-user-passt-custom-args.xml 
b/tests/qemuxmlconfdata/net-user-passt-custom-args.xml
new file mode 100644
index 0000000000..a2a0f4c245
--- /dev/null
+++ b/tests/qemuxmlconfdata/net-user-passt-custom-args.xml
@@ -0,0 +1,64 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <disk type='block' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <controller type='usb' index='0' model='none'/>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' 
function='0x1'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <interface type='user'>
+      <mac address='00:11:22:33:44:55'/>
+      <source dev='eth42'/>
+      <ip address='172.17.2.0' family='ipv4' prefix='24'/>
+      <ip address='2001:db8:ac10:fd01::feed' family='ipv6'/>
+      <portForward proto='tcp' address='2001:db8:ac10:fd01::1:10'>
+        <range start='22' to='2022'/>
+        <range start='1000' end='1050'/>
+        <range start='1020' exclude='yes'/>
+        <range start='1030' end='1040' exclude='yes'/>
+      </portForward>
+      <portForward proto='udp' address='1.2.3.4' dev='eth0'>
+        <range start='5000' end='5020' to='6000'/>
+        <range start='5010' end='5015' exclude='yes'/>
+      </portForward>
+      <portForward proto='tcp'>
+        <range start='80'/>
+      </portForward>
+      <portForward proto='tcp'>
+        <range start='443' to='344'/>
+      </portForward>
+      <model type='rtl8139'/>
+      <backend type='passt' logFile='/var/log/loglaw.blog'>
+        <passt:commandline 
xmlns:passt='http://libvirt.org/schemas/domain/passt/1.0'>
+          <passt:arg value='--debug'/>
+          <passt:arg value='--verbose'/>
+          <passt:arg value='--socket=/tmp/foo.socket'/>
+        </passt:commandline>
+      </backend>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' 
function='0x0'/>
+    </interface>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <audio id='1' type='none'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
index 9fba984290..839ae49ed4 100644
--- a/tests/qemuxmlconftest.c
+++ b/tests/qemuxmlconftest.c
@@ -1805,6 +1805,7 @@ mymain(void)
     DO_TEST_CAPS_LATEST("net-user-addr");
     DO_TEST_CAPS_LATEST("net-user-passt");
     DO_TEST_CAPS_VER("net-user-passt", "7.2.0");
+    DO_TEST_CAPS_LATEST("net-user-passt-custom-args");
     DO_TEST_CAPS_LATEST_PARSE_ERROR("net-user-slirp-portforward");
     DO_TEST_CAPS_LATEST("net-vhostuser-passt");
     DO_TEST_CAPS_LATEST_PARSE_ERROR("net-vhostuser-passt-no-shmem");
-- 
2.50.0

Reply via email to