On Thu, Jul 10, 2025 at 12:04 PM Peter Krempa <pkre...@redhat.com> wrote:
>
> On Wed, Jul 09, 2025 at 13:38:12 +0200, Enrique Llorente via Devel wrote:
> > 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>
>
> Based on the discussion on v2 of this patch, since you used AI to
> generate (at least parts of) this patch I don't think you can claim
> conformance with D-c-o.
>
> I'm also unwiling to jeopardize the project by knowingly allowing any
> form of code with unclear licensing so I will not be able to give R-b
> nor merge this patch.
>
> https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/PHRHCEDTRDHSR3MY6YWPD3J3NC47LHAI/
> https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/VAAJFYGHEK4CTS6FOFEWBCDAAUIZYIFT/

Make sense, let's disregard this change, I will create a non assisted
AI v4 and send it.

>
>
> > ---
> > 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::
>
> Our "styling engine" doesn't support the warning tag yet.
>
> While it's possible to make this work with a bit of CSS that will
> certainly be a separate patch.
>
> > +
> > +   **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.**
>
> I thought about this and I think this docs should go into
> docs/drvqemu.rst in the sub-section where we generate other overrides.
>
> I don't think we want it in the main documentation
>
> > +
> >  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;
>
> Spurious whitespace change.
>
> >  }
> >
>
> [...]
>
> > 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.
>
> 2025?
>
> > + *
> > + * 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);
>
>
> So this parses the definition ...
>
> > +
> > +    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;
>
> ... and just checks if the parsr parsed these elements?
>
> The same is done by qemuxmlconftest which parses and formats back the
> XML. If the output contains them it's fine.
>
> I originally expected that the purpose of this test is to actually check
> the generated commandline.
>


--
Quique Llorente

CNV networking Senior Software Engineer

Red Hat EMEA

ellor...@redhat.com

@RedHat   Red Hat  Red Hat

Reply via email to