[PATCH 0/5] Some parsing functions refactor
by Kirill Shchetiniuk
This patch series is supposed to refactor the existing logic of
some parsing functions, changing the previous approach of getting
the string fisrt and then parsing the string itself. Now the
parsing logic is implemented by using the appropriate virXMLProp*
functions.
In some places the error reporter was changed along with the reported
error message and this change was also reflected in exsiting test cases.
Kirill Shchetiniuk (5):
conf: virNetDevVPortProfileParse refactor
conf: virDomainHostdevSubsysMediatedDevDefParseXML refactor
util: virSecretLookupParseSecret refactor
conf: virDomainChrDefParseTargetXML refactor
qemu: qemuDomainObjPrivateXMLParseVcpu refactor
src/conf/domain_conf.c | 28 +---
src/conf/netdev_vport_profile_conf.c | 120 +++++++-----------
src/qemu/qemu_domain.c | 16 +--
src/util/virsecret.c | 19 +--
...mdev-src-address-invalid.x86_64-latest.err | 2 +-
5 files changed, 60 insertions(+), 125 deletions(-)
--
2.49.0
1 week, 4 days
[PATCH 0/3] bhyve: TCP console support
by Roman Bogorodskiy
Roman Bogorodskiy (3):
bhyve: support serial type 'tcp'
bhyve: increase number of supported consoles to 4
docs: drvbhyve: document TCP console support
docs/drvbhyve.rst | 19 ++++++
src/bhyve/bhyve_capabilities.c | 3 +-
src/bhyve/bhyve_command.c | 42 +++++++++-----
.../bhyvexml2argv-4-consoles.args | 15 +++++
.../bhyvexml2argv-4-consoles.ldargs | 4 ++
.../bhyvexml2argv-4-consoles.xml | 35 +++++++++++
.../bhyvexml2argv-serial-invalid-port.args | 12 ++++
.../bhyvexml2argv-serial-invalid-port.ldargs | 4 ++
.../bhyvexml2argv-serial-invalid-port.xml | 28 +++++++++
.../bhyvexml2argv-serial-tcp.args | 12 ++++
.../bhyvexml2argv-serial-tcp.ldargs | 4 ++
.../bhyvexml2argv-serial-tcp.xml | 27 +++++++++
tests/bhyvexml2argvtest.c | 3 +
.../bhyvexml2xmlout-4-consoles.xml | 58 +++++++++++++++++++
.../bhyvexml2xmlout-serial-tcp.xml | 46 +++++++++++++++
tests/bhyvexml2xmltest.c | 2 +
tests/domaincapsdata/bhyve_basic.x86_64.xml | 1 +
tests/domaincapsdata/bhyve_fbuf.x86_64.xml | 1 +
tests/domaincapsdata/bhyve_uefi.x86_64.xml | 1 +
19 files changed, 301 insertions(+), 16 deletions(-)
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-4-consoles.args
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-4-consoles.ldargs
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-4-consoles.xml
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-serial-invalid-port.args
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-serial-invalid-port.ldargs
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-serial-invalid-port.xml
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-serial-tcp.args
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-serial-tcp.ldargs
create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-serial-tcp.xml
create mode 100644 tests/bhyvexml2xmloutdata/bhyvexml2xmlout-4-consoles.xml
create mode 100644 tests/bhyvexml2xmloutdata/bhyvexml2xmlout-serial-tcp.xml
--
2.49.0
1 week, 4 days
[PATCH 0/3] sysinfotest: rename output XMLs with .xml suffix and introduce schema testing
by Peter Krempa
As noticed in:
https://gitlab.com/libvirt/libvirt-go-xml-module/-/issues/10#note_2608097257
This series:
- renames the output files with .xml suffix
- refactors the schema for the domain <sysinfo> to be reusable
- introduces schema to validate the host sysinfo document and tests the
output files in virschematest
Peter Krempa (3):
sysinfotest: Use '.xml' suffix for output files
conf: schemas: Split out common parts of 'sysinfo' schema
schema: Schema validate host '<sysinfo>' XML test documents
src/conf/schemas/domaincommon.rng | 126 +----------
src/conf/schemas/sysinfo.rng | 34 +++
src/conf/schemas/sysinfocommon.rng | 204 ++++++++++++++++++
...nfo.expect => aarch64-gigabytesysinfo.xml} | 0
...o.expect => aarch64-hpe-apollosysinfo.xml} | 0
...nfo.expect => aarch64-moonshotsysinfo.xml} | 0
...rch64sysinfo.expect => aarch64sysinfo.xml} | 0
...rpi2sysinfo.expect => arm-rpi2sysinfo.xml} | 0
.../{armsysinfo.expect => armsysinfo.xml} | 0
.../{ppcsysinfo.expect => ppcsysinfo.xml} | 0
...reqsysinfo.expect => s390-freqsysinfo.xml} | 0
.../{s390sysinfo.expect => s390sysinfo.xml} | 0
.../{x86sysinfo.expect => x86sysinfo.xml} | 0
tests/sysinfotest.c | 2 +-
tests/virschematest.c | 5 +
15 files changed, 251 insertions(+), 120 deletions(-)
create mode 100644 src/conf/schemas/sysinfo.rng
create mode 100644 src/conf/schemas/sysinfocommon.rng
rename tests/sysinfodata/{aarch64-gigabytesysinfo.expect => aarch64-gigabytesysinfo.xml} (100%)
rename tests/sysinfodata/{aarch64-hpe-apollosysinfo.expect => aarch64-hpe-apollosysinfo.xml} (100%)
rename tests/sysinfodata/{aarch64-moonshotsysinfo.expect => aarch64-moonshotsysinfo.xml} (100%)
rename tests/sysinfodata/{aarch64sysinfo.expect => aarch64sysinfo.xml} (100%)
rename tests/sysinfodata/{arm-rpi2sysinfo.expect => arm-rpi2sysinfo.xml} (100%)
rename tests/sysinfodata/{armsysinfo.expect => armsysinfo.xml} (100%)
rename tests/sysinfodata/{ppcsysinfo.expect => ppcsysinfo.xml} (100%)
rename tests/sysinfodata/{s390-freqsysinfo.expect => s390-freqsysinfo.xml} (100%)
rename tests/sysinfodata/{s390sysinfo.expect => s390sysinfo.xml} (100%)
rename tests/sysinfodata/{x86sysinfo.expect => x86sysinfo.xml} (100%)
--
2.50.0
1 week, 4 days
[RFC 0/4] Implement automatic attachment of the vhostuser port
by yong.huang@smartx.com
From: Hyman Huang <yong.huang(a)smartx.com>
This series offer an automated method to configure a vhostuser interface
in server mode, simplifying integration with DPDK-enabled Open vSwitch
bridges.
To ensure simplicity and forward compatibility, we introduce openvswitch
backend support for vhostuser interfaces in XML configuration, with an
optional 'autoiface' attribute.
Here is an example of the config for a vhostuser interface that attached
to bridge automatically:
<interface type='vhostuser'>
<mac address='52:54:00:3b:83:1b'/>
<source type='unix' path='/tmp/vhost2.sock' mode='server'/>
<virtualport type='openvswitch'>
<parameters interfaceid='9317d6b7-5fae-4464-a7e9-87d90eff2204'/>
</virtualport>
<backend type='openvswitch' autoiface='yes'>
<parameters bridge='ovsbr-ddpbxnhaq'/>
</backend>
<model type='virtio'/>
<driver queues='5'/>
</interface>
The backend element specifies the backend implementation of the vhostuser
interface type. The type attribute is required and currently supports
supports openvswitch and passt.
If type is openvswitch, the autoiface attribute may be specified (yes
or no), if autoiface is yes, the parameters element bridge attribute
is mandatory. Libvirt will derive the interface name by extracting the
substring after the '/' character in the vhostuser server path, and
attach it to the bridge specified by the bridge attribute.
Please review. Thanks.
Yong
Hyman Huang (4):
qemu_passt: Make logFile backend-specific
conf: Introduce autoiface attribute for vhostuser interface
util: Add iface argument to virNetDevOpenvswitchAddPort
qemu: Implement automatic attachment of the vhostuser port
docs/formatdomain.rst | 37 ++++++++-
src/conf/domain_conf.c | 75 +++++++++++++++++--
src/conf/domain_conf.h | 13 +++-
src/conf/domain_postparse.c | 46 ++++++++++++
src/conf/domain_validate.c | 24 ++++++
src/conf/schemas/domaincommon.rng | 20 +++++
src/lxc/lxc_process.c | 3 +-
src/qemu/qemu_command.c | 3 +
src/qemu/qemu_hotplug.c | 4 +
src/qemu/qemu_interface.c | 46 ++++++++++++
src/qemu/qemu_interface.h | 3 +
src/qemu/qemu_passt.c | 4 +-
src/qemu/qemu_process.c | 4 +
src/util/virnetdevopenvswitch.c | 36 ++++++++-
src/util/virnetdevopenvswitch.h | 10 ++-
src/util/virnetdevtap.c | 3 +-
.../net-vhostuser.x86_64-latest.xml | 10 +++
tests/qemuxmlconfdata/net-vhostuser.xml | 10 +++
18 files changed, 336 insertions(+), 15 deletions(-)
--
2.27.0
1 week, 4 days
Support cloning of VMs - part 2
by Mark Cave-Ayland
Hi all,
I'm currently looking at how libvirt can be used to clone a saved VM,
and have been focusing on the previous thread on this topic at
https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/YX....
My understanding from reading the thread is that the best way to
approach this is 1) add uuid properties to the relevant objects/devices
in QEMU where the UUID is user-visible, and 2) update libvirt to handle
these properties via XML.
Does this sound correct, or is there any more recent thinking about the
best approach to take?
ATB,
Mark.
2 weeks
[PATCH] build: prohibit realpath() by syntax-check
by Michal Privoznik
From: Michal Privoznik <mprivozn(a)redhat.com>
We have virFileCanonicalizePath() which calls realpath() but
also is present in our mocks (in contrast to realpath()).
Introduce a syntax-check rule to enforce use of our wrapper.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
build-aux/syntax-check.mk | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk
index 1303a0ce7e..27eabe6565 100644
--- a/build-aux/syntax-check.mk
+++ b/build-aux/syntax-check.mk
@@ -247,6 +247,12 @@ sc_prohibit_canonicalize_file_name:
halt='use virFileCanonicalizePath() instead of canonicalize_file_name()' \
$(_sc_search_regexp)
+sc_prohibit_realpath:
+ @prohibit='\<realpath\(' \
+ exclude='exempt from syntax-check' \
+ halt='use virFileCanonicalizePath() instead of realpath()' \
+ $(_sc_search_regexp)
+
# qsort from glibc has unstable sort ordering for "equal" members
sc_prohibit_qsort:
@prohibit='\<(qsort|qsort_r) *\(' \
@@ -1420,6 +1426,9 @@ exclude_file_name_regexp--sc_prohibit_nonreentrant = \
exclude_file_name_regexp--sc_prohibit_canonicalize_file_name = \
^(build-aux/syntax-check\.mk|tests/virfilemock\.c)$$
+exclude_file_name_regexp--sc_prohibit_realpath = \
+ ^(build-aux/syntax-check\.mk|src/cpu_map/sync_qemu_features_i386\.py|tests/virfilemock\.c)$$
+
exclude_file_name_regexp--sc_prohibit_raw_allocation = \
^(docs/advanced-tests\.rst|src/util/viralloc\.[ch]|examples/.*|tests/(securityselinuxhelper|(vircgroup|nss)mock|commandhelper)\.c|tools/wireshark/src/packet-libvirt\.c|tools/nss/libvirt_nss(_leases|_macs)?\.[ch])$$
--
2.49.0
2 weeks
[libvirt PATCH] docs: hacking: Define policy forbidding use of AI code generators
by Pavel Hrdina
This policy is a copy of what QEMU project is using [1] as there is no
reason to use different policy, only modification is changing the
project name and link to DCO.
[1] <https://www.qemu.org/docs/master/devel/code-provenance.html#use-of-ai-con...>
Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
docs/hacking.rst | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/docs/hacking.rst b/docs/hacking.rst
index 825b8b83d2..5f0f867b9f 100644
--- a/docs/hacking.rst
+++ b/docs/hacking.rst
@@ -90,6 +90,58 @@ formal ID documents, but should not be anonymous, nor misrepresent
who you are. The presence of this line attests that the contributor
has read the above linked DCO and agrees with its statements.
+Use of AI content generators
+============================
+
+TL;DR:
+
+ **Current libvirt project policy is to DECLINE any contributions which are
+ believed to include or derive from AI generated content. This includes
+ ChatGPT, Claude, Copilot, Llama and similar tools.**
+
+The increasing prevalence of AI-assisted software development results in a
+number of difficult legal questions and risks for software projects, including
+libvirt. Of particular concern is content generated by `Large Language Models
+<https://en.wikipedia.org/wiki/Large_language_model>`__ (LLMs).
+
+The libvirt community requires that contributors certify their patch submissions
+are made in accordance with the rules of the `Developer Certificate of
+Origin`_.
+
+To satisfy the DCO, the patch contributor has to fully understand the
+copyright and license status of content they are contributing to libvirt. With
+AI content generators, the copyright and license status of the output is
+ill-defined with no generally accepted, settled legal foundation.
+
+Where the training material is known, it is common for it to include large
+volumes of material under restrictive licensing/copyright terms. Even where
+the training material is all known to be under open source licenses, it is
+likely to be under a variety of terms, not all of which will be compatible
+with libvirt's licensing requirements.
+
+How contributors could comply with DCO terms (b) or (c) for the output of AI
+content generators commonly available today is unclear. The libvirt project is
+not willing or able to accept the legal risks of non-compliance.
+
+The libvirt project thus requires that contributors refrain from using AI
+content generators on patches intended to be submitted to the project, and
+will decline any contribution if use of AI is either known or suspected.
+
+This policy does not apply to other uses of AI, such as researching APIs or
+algorithms, static analysis, or debugging, provided their output is not to be
+included in contributions.
+
+Examples of tools impacted by this policy includes GitHub's CoPilot, OpenAI's
+ChatGPT, Anthropic's Claude, and Meta's Code Llama, and code/content
+generation agents which are built on top of such tools.
+
+This policy may evolve as AI tools mature and the legal situation is
+clarified. In the meanwhile, requests for exceptions to this policy will be
+evaluated by the libvirt project on a case by case basis. To be granted an
+exception, a contributor will need to demonstrate clarity of the license and
+copyright status for the tool's output in relation to its training model and
+code, to the satisfaction of the project maintainers.
+
Further reading
===============
--
2.49.0
2 weeks, 1 day
[PATCH] NEWS: Mention switch to virtio-scsi on ARM
by Jim Fehlig
From: Jim Fehlig <jfehlig(a)suse.com>
Signed-off-by: Jim Fehlig <jfehlig(a)suse.com>
---
NEWS.rst | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/NEWS.rst b/NEWS.rst
index d8bd2559f4..59494cb380 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -19,6 +19,12 @@ v11.6.0 (unreleased)
* **Improvements**
+ * qemu: Change default SCSI controller model to ``virtio-scsi`` for ARM
+
+ The previous default of ``lsilogic`` is unsupported by modern operating
+ systems. ``virtio-scsi`` is a more suitable default for ARM ``virt``
+ machine types.
+
* **Bug fixes**
--
2.43.0
2 weeks, 1 day
How to process after sending a patch assisted with AI
by Enrique Llorente Pastora
Hi,
How should I process after sending a patch that has code generated by AI [1] ?
Is creating a new AI free version with some explanation enough to
prevent the submission from being suspicious ?
Possible example for explanation would be "I am using how
qemu:commandline is implemented as inspiration for the feature and not
AI was used to generate code or tests as opposed to v3".
BR.
[1] https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/Z...
--
Quique Llorente
CNV networking Senior Software Engineer
Red Hat EMEA
ellorent(a)redhat.com
@RedHat Red Hat Red Hat
2 weeks, 1 day
[PATCH v3] qemu: passt: add support for custom command line arguments
by Enrique Llorente
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 <ellorent(a)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
2 weeks, 1 day