public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Laine Stump <laine@redhat.com>
To: libvir-list@redhat.com
Cc: sbrivio@redhat.com, passt-dev@passt.top
Subject: [libvirt PATCH 8/9] qemu: hook up passt config to qemu domains
Date: Sun,  8 Jan 2023 23:11:11 -0500	[thread overview]
Message-ID: <20230109041112.368790-9-laine@redhat.com> (raw)
In-Reply-To: <20230109041112.368790-1-laine@redhat.com>

This consists of (1) adding the necessary args to the qemu commandline
netdev option, and (2) starting a passt process prior to starting
qemu, and making sure that it is terminated when it's no longer
needed. Under normal circumstances, passt will terminate itself as
soon as qemu closes its socket, but in case of some error where qemu
is never started, or fails to startup completely, we need to terminate
passt manually.

Signed-off-by: Laine Stump <laine@redhat.com>
---
 meson.build                                   |   1 +
 po/POTFILES                                   |   1 +
 src/qemu/meson.build                          |   2 +
 src/qemu/qemu_command.c                       |  11 +-
 src/qemu/qemu_command.h                       |   3 +-
 src/qemu/qemu_domain.c                        |   5 +-
 src/qemu/qemu_domain.h                        |   3 +-
 src/qemu/qemu_extdevice.c                     |  25 +-
 src/qemu/qemu_hotplug.c                       |  26 +-
 src/qemu/qemu_passt.c                         | 284 ++++++++++++++++++
 src/qemu/qemu_passt.h                         |  38 +++
 src/qemu/qemu_process.c                       |   1 +
 src/qemu/qemu_validate.c                      |   9 +-
 tests/qemuxml2argvdata/net-user-passt.args    |  34 +++
 .../net-user-passt.x86_64-latest.args         |  37 +++
 tests/qemuxml2argvtest.c                      |   2 +
 16 files changed, 470 insertions(+), 12 deletions(-)
 create mode 100644 src/qemu/qemu_passt.c
 create mode 100644 src/qemu/qemu_passt.h
 create mode 100644 tests/qemuxml2argvdata/net-user-passt.args
 create mode 100644 tests/qemuxml2argvdata/net-user-passt.x86_64-latest.args

diff --git a/meson.build b/meson.build
index 177009c44d..6604ba20c8 100644
--- a/meson.build
+++ b/meson.build
@@ -780,6 +780,7 @@ optional_programs = [
   'mm-ctl',
   'modprobe',
   'ovs-vsctl',
+  'passt',
   'pdwtags',
   'rmmod',
   'scrub',
diff --git a/po/POTFILES b/po/POTFILES
index 169e2a41dc..f979c9c4bc 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -180,6 +180,7 @@ src/qemu/qemu_monitor.c
 src/qemu/qemu_monitor_json.c
 src/qemu/qemu_monitor_text.c
 src/qemu/qemu_namespace.c
+src/qemu/qemu_passt.c
 src/qemu/qemu_process.c
 src/qemu/qemu_qapi.c
 src/qemu/qemu_saveimage.c
diff --git a/src/qemu/meson.build b/src/qemu/meson.build
index 96952cc52d..c8806bbc36 100644
--- a/src/qemu/meson.build
+++ b/src/qemu/meson.build
@@ -28,6 +28,7 @@ qemu_driver_sources = [
   'qemu_monitor_json.c',
   'qemu_monitor_text.c',
   'qemu_namespace.c',
+  'qemu_passt.c',
   'qemu_process.c',
   'qemu_qapi.c',
   'qemu_saveimage.c',
@@ -216,6 +217,7 @@ if conf.has('WITH_QEMU')
     localstatedir / 'log' / 'swtpm' / 'libvirt' / 'qemu',
     runstatedir / 'libvirt' / 'qemu',
     runstatedir / 'libvirt' / 'qemu' / 'dbus',
+    runstatedir / 'libvirt' / 'qemu' / 'passt',
     runstatedir / 'libvirt' / 'qemu' / 'slirp',
     runstatedir / 'libvirt' / 'qemu' / 'swtpm',
   ]
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 42bd7cb99f..89af798a31 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -27,6 +27,7 @@
 #include "qemu_interface.h"
 #include "qemu_alias.h"
 #include "qemu_security.h"
+#include "qemu_passt.h"
 #include "qemu_slirp.h"
 #include "qemu_block.h"
 #include "qemu_fd.h"
@@ -3793,7 +3794,8 @@ qemuBuildNicDevProps(virDomainDef *def,
 
 
 virJSONValue *
-qemuBuildHostNetProps(virDomainNetDef *net)
+qemuBuildHostNetProps(virDomainObj *vm,
+                      virDomainNetDef *net)
 {
     virDomainNetType netType = virDomainNetGetActualType(net);
     size_t i;
@@ -3908,7 +3910,10 @@ qemuBuildHostNetProps(virDomainNetDef *net)
         break;
 
     case VIR_DOMAIN_NET_TYPE_USER:
-        if (netpriv->slirpfd) {
+        if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
+            if (qemuPasstAddNetProps(vm, net, &netprops) < 0)
+                return NULL;
+        } else if (netpriv->slirpfd) {
             if (virJSONValueObjectAdd(&netprops,
                                       "s:type", "socket",
                                       "s:fd", qemuFDPassDirectGetPath(netpriv->slirpfd),
@@ -8452,7 +8457,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver,
     qemuFDPassDirectTransferCommand(netpriv->slirpfd, cmd);
     qemuFDPassTransferCommand(netpriv->vdpafd, cmd);
 
-    if (!(hostnetprops = qemuBuildHostNetProps(net)))
+    if (!(hostnetprops = qemuBuildHostNetProps(vm, net)))
         goto cleanup;
 
     if (qemuBuildNetdevCommandlineFromJSON(cmd, hostnetprops, qemuCaps) < 0)
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 761cc5d865..c49096a057 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -78,7 +78,8 @@ virJSONValue *
 qemuBuildChannelGuestfwdNetdevProps(virDomainChrDef *chr);
 
 virJSONValue *
-qemuBuildHostNetProps(virDomainNetDef *net);
+qemuBuildHostNetProps(virDomainObj *vm,
+                      virDomainNetDef *net);
 
 int
 qemuBuildInterfaceConnect(virDomainObj *vm,
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 8892f28fce..ec55bc47c4 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -2351,6 +2351,7 @@ qemuDomainGetSlirpHelperOk(virDomainObj *vm)
 
         /* if there is a builtin slirp, prevent slirp-helper */
         if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
+            net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT &&
             !QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
             return false;
     }
@@ -9906,7 +9907,8 @@ qemuDomainSupportsNicdev(virDomainDef *def,
 }
 
 bool
-qemuDomainNetSupportsMTU(virDomainNetType type)
+qemuDomainNetSupportsMTU(virDomainNetType type,
+                         virDomainNetBackendType backend)
 {
     switch (type) {
     case VIR_DOMAIN_NET_TYPE_NETWORK:
@@ -9915,6 +9917,7 @@ qemuDomainNetSupportsMTU(virDomainNetType type)
     case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
         return true;
     case VIR_DOMAIN_NET_TYPE_USER:
+        return backend == VIR_DOMAIN_NET_BACKEND_PASST;
     case VIR_DOMAIN_NET_TYPE_SERVER:
     case VIR_DOMAIN_NET_TYPE_CLIENT:
     case VIR_DOMAIN_NET_TYPE_MCAST:
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 2f027fad87..c82d56191d 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -883,7 +883,8 @@ int qemuDomainRefreshVcpuHalted(virDomainObj *vm,
 bool qemuDomainSupportsNicdev(virDomainDef *def,
                               virDomainNetDef *net);
 
-bool qemuDomainNetSupportsMTU(virDomainNetType type);
+bool qemuDomainNetSupportsMTU(virDomainNetType type,
+                              virDomainNetBackendType backend);
 
 int qemuDomainSetPrivatePaths(virQEMUDriver *driver,
                               virDomainObj *vm);
diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c
index d5c3e8ed71..f7b2e2e653 100644
--- a/src/qemu/qemu_extdevice.c
+++ b/src/qemu/qemu_extdevice.c
@@ -25,6 +25,7 @@
 #include "qemu_dbus.h"
 #include "qemu_domain.h"
 #include "qemu_tpm.h"
+#include "qemu_passt.h"
 #include "qemu_slirp.h"
 #include "qemu_virtiofs.h"
 
@@ -194,8 +195,16 @@ qemuExtDevicesStart(virQEMUDriver *driver,
     for (i = 0; i < def->nnets; i++) {
         virDomainNetDef *net = def->nets[i];
 
-        if (qemuSlirpStart(vm, net, incomingMigration) < 0)
-            return -1;
+        if (net->type != VIR_DOMAIN_NET_TYPE_USER)
+            continue;
+
+        if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
+            if (qemuPasstStart(vm, net) < 0)
+                return -1;
+        } else {
+            if (qemuSlirpStart(vm, net, incomingMigration) < 0)
+                return -1;
+        }
     }
 
     for (i = 0; i < def->nfss; i++) {
@@ -254,6 +263,12 @@ qemuExtDevicesStop(virQEMUDriver *driver,
 
         if (slirp)
             qemuSlirpStop(slirp, vm, driver, net);
+
+        if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
+            net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
+            qemuPasstStop(vm, net);
+        }
+
         if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET && net->downscript)
             virNetDevRunEthernetScript(net->ifname, net->downscript);
     }
@@ -319,6 +334,12 @@ qemuExtDevicesSetupCgroup(virQEMUDriver *driver,
 
         if (slirp && qemuSlirpSetupCgroup(slirp, cgroup) < 0)
             return -1;
+
+        if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
+            net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST &&
+            qemuPasstSetupCgroup(vm, net, cgroup) < 0) {
+            return -1;
+        }
     }
 
     for (i = 0; i < def->ntpms; i++) {
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 6e300f547c..217230f845 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -31,6 +31,7 @@
 #include "qemu_command.h"
 #include "qemu_hostdev.h"
 #include "qemu_interface.h"
+#include "qemu_passt.h"
 #include "qemu_process.h"
 #include "qemu_security.h"
 #include "qemu_block.h"
@@ -1201,8 +1202,16 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
         break;
 
     case VIR_DOMAIN_NET_TYPE_USER:
-        if (!priv->disableSlirp &&
-            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
+        if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
+
+            if (qemuPasstStart(vm, net) < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               "%s", _("Failed to start passt"));
+                goto cleanup;
+            }
+
+        } else if (!priv->disableSlirp &&
+                   virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
 
             if (qemuInterfacePrepareSlirp(driver, net) < 0)
                 goto cleanup;
@@ -1269,7 +1278,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
         virNetDevSetMTU(net->ifname, net->mtu) < 0)
         goto cleanup;
 
-    if (!(netprops = qemuBuildHostNetProps(net)))
+    if (!(netprops = qemuBuildHostNetProps(vm, net)))
         goto cleanup;
 
     qemuDomainObjEnterMonitor(vm);
@@ -1417,6 +1426,12 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
     netdev_name = g_strdup_printf("host%s", net->info.alias);
     if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
         qemuSlirpStop(QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp, vm, driver, net);
+
+    if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
+        net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
+        qemuPasstStop(vm, net);
+    }
+
     qemuDomainObjEnterMonitor(vm);
     if (charDevPlugged &&
         qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0)
@@ -4618,6 +4633,11 @@ qemuDomainRemoveNetDevice(virQEMUDriver *driver,
     if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
         qemuSlirpStop(QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp, vm, driver, net);
 
+    if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
+        net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
+        qemuPasstStop(vm, net);
+    }
+
     virDomainAuditNet(vm, net, NULL, "detach", true);
 
     for (i = 0; i < vm->def->nnets; i++) {
diff --git a/src/qemu/qemu_passt.c b/src/qemu/qemu_passt.c
new file mode 100644
index 0000000000..5941594811
--- /dev/null
+++ b/src/qemu/qemu_passt.c
@@ -0,0 +1,284 @@
+/*
+ * qemu_passt.c: QEMU passt support
+ *
+ * Copyright (C) 2022 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 "qemu_dbus.h"
+#include "qemu_extdevice.h"
+#include "qemu_security.h"
+#include "qemu_passt.h"
+#include "virenum.h"
+#include "virerror.h"
+#include "virjson.h"
+#include "virlog.h"
+#include "virpidfile.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+VIR_LOG_INIT("qemu.passt");
+
+
+static char *
+qemuPasstCreatePidFilename(virDomainObj *vm,
+                           virDomainNetDef *net)
+{
+    qemuDomainObjPrivate *priv = vm->privateData;
+    virQEMUDriver *driver = priv->driver;
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+    g_autofree char *name = NULL;
+
+    name = g_strdup_printf("%s-%s-passt", vm->def->name, net->info.alias);
+
+    return virPidFileBuildPath(cfg->passtStateDir, name);
+}
+
+
+static char *
+qemuPasstCreateSocketPath(virDomainObj *vm,
+                          virDomainNetDef *net)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    qemuDomainObjPrivate *priv = vm->privateData;
+    virQEMUDriver *driver = priv->driver;
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+
+    return g_strdup_printf("%s/%s-%s.socket",
+                           cfg->passtStateDir,
+                           virUUIDFormat(vm->def->uuid, uuidstr),
+                           net->info.alias);
+}
+
+
+static int
+qemuPasstGetPid(virDomainObj *vm,
+                virDomainNetDef *net,
+                pid_t *pid)
+{
+    g_autofree char *pidfile = qemuPasstCreatePidFilename(vm, net);
+
+    return virPidFileReadPathIfLocked(pidfile, pid);
+}
+
+
+int
+qemuPasstAddNetProps(virDomainObj *vm,
+                     virDomainNetDef *net,
+                     virJSONValue **netprops)
+{
+    g_autofree char *passtSocketName = qemuPasstCreateSocketPath(vm, net);
+    g_autoptr(virJSONValue) addrprops = NULL;
+
+    if (virJSONValueObjectAdd(&addrprops,
+                              "s:type", "unix",
+                              "s:path", passtSocketName,
+                              NULL) < 0) {
+        return -1;
+    }
+
+    if (virJSONValueObjectAdd(netprops,
+                              "s:type", "stream",
+                              "a:addr", &addrprops,
+                              "b:server", false,
+                              /*  "u:reconnect", 5, */
+                              NULL) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+
+void
+qemuPasstStop(virDomainObj *vm,
+              virDomainNetDef *net)
+{
+    g_autofree char *pidfile = qemuPasstCreatePidFilename(vm, net);
+    virErrorPtr orig_err;
+
+    virErrorPreserveLast(&orig_err);
+
+
+    if (virPidFileForceCleanupPath(pidfile) < 0)
+        VIR_WARN("Unable to kill passt process");
+
+    virErrorRestore(&orig_err);
+}
+
+
+int
+qemuPasstSetupCgroup(virDomainObj *vm,
+                     virDomainNetDef *net,
+                     virCgroup *cgroup)
+{
+    pid_t pid = (pid_t) -1;
+
+    if (qemuPasstGetPid(vm, net, &pid) < 0 || pid <= 0)
+        return -1;
+
+    return virCgroupAddProcess(cgroup, pid);
+}
+
+
+int
+qemuPasstStart(virDomainObj *vm,
+               virDomainNetDef *net)
+{
+    qemuDomainObjPrivate *priv = vm->privateData;
+    virQEMUDriver *driver = priv->driver;
+    g_autofree char *passtSocketName = qemuPasstCreateSocketPath(vm, net);
+    g_autoptr(virCommand) cmd = NULL;
+    g_autofree char *pidfile = qemuPasstCreatePidFilename(vm, net);
+    char macaddr[VIR_MAC_STRING_BUFLEN];
+    size_t i;
+    pid_t pid = (pid_t) -1;
+    int exitstatus = 0;
+    int cmdret = 0;
+    VIR_AUTOCLOSE errfd = -1;
+
+    cmd = virCommandNew(PASST);
+
+    virCommandClearCaps(cmd);
+    virCommandSetPidFile(cmd, pidfile);
+    virCommandSetErrorFD(cmd, &errfd);
+    virCommandDaemonize(cmd);
+
+    virCommandAddArgList(cmd,
+                         "--one-off",
+                         "--socket", passtSocketName,
+                         "--mac-addr", virMacAddrFormat(&net->mac, macaddr),
+                         NULL);
+
+    if (net->mtu) {
+        virCommandAddArg(cmd, "--mtu");
+        virCommandAddArgFormat(cmd, "%u", net->mtu);
+    }
+
+    if (net->backend.upstream)
+        virCommandAddArgList(cmd, "--interface", net->backend.upstream, NULL);
+
+    if (net->backend.logFile)
+        virCommandAddArgList(cmd, "--log-file", net->backend.logFile, NULL);
+
+    /* Add IP address info */
+    for (i = 0; i < net->guestIP.nips; i++) {
+        const virNetDevIPAddr *ip = net->guestIP.ips[i];
+        g_autofree char *addr = NULL;
+
+        /* validation has already limited us to
+         * a single IPv4 and single IPv6 address
+         */
+        if (!(addr = virSocketAddrFormat(&ip->address)))
+            return -1;
+
+        virCommandAddArgList(cmd, "--address", addr, NULL);
+
+        if (ip->prefix && VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET)) {
+            /* validation already made sure no prefix is
+             * specified for IPv6 (not allowed by passt)
+             */
+            virCommandAddArg(cmd, "--netmask");
+            virCommandAddArgFormat(cmd, "%u", ip->prefix);
+        }
+    }
+
+    /* Add port forwarding info */
+
+    for (i = 0; i < net->nPortForwards; i++) {
+        virDomainNetPortForward *pf = net->portForwards[i];
+        g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+        if (pf->proto == VIR_DOMAIN_NET_PROTO_TCP) {
+            virCommandAddArg(cmd, "--tcp-ports");
+        } else if (pf->proto == VIR_DOMAIN_NET_PROTO_UDP) {
+            virCommandAddArg(cmd, "--udp-ports");
+        } else {
+            /* validation guarantees this will never happen */
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Invalid portForward proto value %u"), pf->proto);
+            goto error;
+        }
+
+        if (VIR_SOCKET_ADDR_VALID(&pf->address)) {
+            g_autofree char *addr = NULL;
+
+            if (!(addr = virSocketAddrFormat(&pf->address)))
+                goto error;
+
+            virBufferAddStr(&buf, addr);
+
+            if (pf->dev)
+                virBufferAsprintf(&buf, "%%%s", pf->dev);
+
+            virBufferAddChar(&buf, '/');
+        }
+
+        if (!pf->nRanges) {
+            virBufferAddLit(&buf, "all");
+        } else {
+            size_t r;
+
+            for (r = 0; r < pf->nRanges; r++) {
+                virDomainNetPortForwardRange *range = pf->ranges[r];
+
+                if (r > 0)
+                    virBufferAddChar(&buf, ',');
+
+                if (range->exclude == VIR_TRISTATE_BOOL_YES)
+                    virBufferAddChar(&buf, '~');
+
+                virBufferAsprintf(&buf, "%u", range->start);
+
+                if (range->end)
+                    virBufferAsprintf(&buf, "-%u", range->end);
+                if (range->to) {
+                    virBufferAsprintf(&buf, ":%u", range->to);
+                    if (range->end) {
+                        virBufferAsprintf(&buf, "-%u",
+                                          range->end + range->to - range->start);
+                    }
+                }
+            }
+        }
+        virCommandAddArg(cmd, virBufferCurrentContent(&buf));
+    }
+
+
+    if (qemuExtDeviceLogCommand(driver, vm, cmd, "passt") < 0)
+        goto error;
+
+    if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, &exitstatus, &cmdret) < 0)
+        goto error;
+
+    if (cmdret < 0 || exitstatus != 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not start 'passt'. exitstatus: %d"), exitstatus);
+        goto error;
+    }
+
+    return 0;
+
+ error:
+    ignore_value(virPidFileReadPathIfLocked(pidfile, &pid));
+    if (pid != -1)
+        virProcessKillPainfully(pid, true);
+    if (pidfile)
+        unlink(pidfile);
+
+    return -1;
+}
diff --git a/src/qemu/qemu_passt.h b/src/qemu/qemu_passt.h
new file mode 100644
index 0000000000..623b494b7a
--- /dev/null
+++ b/src/qemu/qemu_passt.h
@@ -0,0 +1,38 @@
+/*
+ * qemu_passt.h: QEMU passt support
+ *
+ * Copyright (C) 2022 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/>.
+ */
+
+#pragma once
+
+#include "qemu_conf.h"
+
+int
+qemuPasstAddNetProps(virDomainObj *vm,
+                     virDomainNetDef *net,
+                     virJSONValue **netprops);
+
+int qemuPasstStart(virDomainObj *vm,
+                   virDomainNetDef *net);
+
+void qemuPasstStop(virDomainObj *vm,
+                   virDomainNetDef *net);
+
+int qemuPasstSetupCgroup(virDomainObj *vm,
+                         virDomainNetDef *net,
+                         virCgroup *cgroup);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index b6adcf2f2a..b5f1bcf557 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -5794,6 +5794,7 @@ qemuProcessNetworkPrepareDevices(virQEMUDriver *driver,
             if (virDomainHostdevInsert(def, hostdev) < 0)
                 return -1;
         } else if (actualType == VIR_DOMAIN_NET_TYPE_USER &&
+                   net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT &&
                    !priv->disableSlirp &&
                    virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
             if (qemuInterfacePrepareSlirp(driver, net) < 0)
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index c687df0bfc..6e04b22da4 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -1830,6 +1830,13 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net,
                 }
                 hasIPv6 = true;
 
+                if (ip->prefix && ip->prefix != 64) {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                   _("unsupported IPv6 address prefix='%u' - must be 64"),
+                                   ip->prefix);
+                    return -1;
+                }
+
                 if (ip->prefix > 120) {
                     virReportError(VIR_ERR_XML_ERROR, "%s",
                                    _("prefix too long"));
@@ -1892,7 +1899,7 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net,
     }
 
     if (net->mtu &&
-        !qemuDomainNetSupportsMTU(net->type)) {
+        !qemuDomainNetSupportsMTU(net->type, net->backend.type)) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("setting MTU on interface type %s is not supported yet"),
                        virDomainNetTypeToString(net->type));
diff --git a/tests/qemuxml2argvdata/net-user-passt.args b/tests/qemuxml2argvdata/net-user-passt.args
new file mode 100644
index 0000000000..8c887ca210
--- /dev/null
+++ b/tests/qemuxml2argvdata/net-user-passt.args
@@ -0,0 +1,34 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
+/usr/bin/qemu-system-x86_64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
+-machine pc,usb=off,dump-guest-core=off \
+-accel tcg \
+-m 214 \
+-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 \
+-no-acpi \
+-boot strict=on \
+-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \
+-blockdev '{"node-name":"libvirt-1-format","read-only":false,"driver":"raw","file":"libvirt-1-storage"}' \
+-device ide-hd,bus=ide.0,unit=0,drive=libvirt-1-format,id=ide0-0-0,bootindex=1 \
+-netdev stream,addr.path=/var/run/libvirt/qemu/passt/UUID-net0.socket,server=off,reconnect=5,id=hostnet0 \
+-device rtl8139,netdev=hostnet0,id=net0,mac=00:11:22:33:44:55,bus=pci.0,addr=0x2 \
+-audiodev '{"id":"audio1","driver":"none"}' \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/net-user-passt.x86_64-latest.args b/tests/qemuxml2argvdata/net-user-passt.x86_64-latest.args
new file mode 100644
index 0000000000..69194a2cfc
--- /dev/null
+++ b/tests/qemuxml2argvdata/net-user-passt.x86_64-latest.args
@@ -0,0 +1,37 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/tmp/lib/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":"/tmp/lib/domain--1-QEMUGuest1/master-key.aes"}' \
+-machine pc,usb=off,dump-guest-core=off,memory-backend=pc.ram \
+-accel tcg \
+-cpu qemu64 \
+-m 214 \
+-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 \
+-no-acpi \
+-boot strict=on \
+-blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest1","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \
+-blockdev '{"node-name":"libvirt-1-format","read-only":false,"driver":"raw","file":"libvirt-1-storage"}' \
+-device '{"driver":"ide-hd","bus":"ide.0","unit":0,"drive":"libvirt-1-format","id":"ide0-0-0","bootindex":1}' \
+-netdev '{"type":"stream","addr":{"type":"unix","path":"/bad-test-used-env-xdg-runtime-dir/libvirt/qemu/run/passt/c7a5fdbd-edaf-9455-926a-d65c16db1809-net0.socket"},"server":false,"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/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 4d563d3a09..a8b4a8d18c 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -471,6 +471,7 @@ testCompareXMLToArgvCreateArgs(virQEMUDriver *drv,
             virDomainNetDef *net = vm->def->nets[i];
 
             if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
+                net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT &&
                 virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
                 qemuSlirp *slirp = qemuSlirpNew();
                 slirp->fd[0] = 42;
@@ -1460,6 +1461,7 @@ mymain(void)
     DO_TEST_NOCAPS("net-user");
     DO_TEST_CAPS_ARCH_LATEST_FULL("net-user", "x86_64", ARG_FLAGS, FLAG_SLIRP_HELPER);
     DO_TEST_NOCAPS("net-user-addr");
+    DO_TEST_CAPS_LATEST("net-user-passt");
     DO_TEST_NOCAPS("net-virtio");
     DO_TEST_NOCAPS("net-virtio-device");
     DO_TEST_NOCAPS("net-virtio-disable-offloads");
-- 
@@ -471,6 +471,7 @@ testCompareXMLToArgvCreateArgs(virQEMUDriver *drv,
             virDomainNetDef *net = vm->def->nets[i];
 
             if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
+                net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT &&
                 virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
                 qemuSlirp *slirp = qemuSlirpNew();
                 slirp->fd[0] = 42;
@@ -1460,6 +1461,7 @@ mymain(void)
     DO_TEST_NOCAPS("net-user");
     DO_TEST_CAPS_ARCH_LATEST_FULL("net-user", "x86_64", ARG_FLAGS, FLAG_SLIRP_HELPER);
     DO_TEST_NOCAPS("net-user-addr");
+    DO_TEST_CAPS_LATEST("net-user-passt");
     DO_TEST_NOCAPS("net-virtio");
     DO_TEST_NOCAPS("net-virtio-device");
     DO_TEST_NOCAPS("net-virtio-disable-offloads");
-- 
2.38.1


  parent reply	other threads:[~2023-01-09  4:11 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-09  4:11 [libvirt PATCH 0/9] Support libvirt-managed QEMU domain <interface> backed by a passt process Laine Stump
2023-01-09  4:11 ` [libvirt PATCH 1/9] conf: rename virDomainNetBackend* to virDomainNetDriver* Laine Stump
2023-01-09  5:40   ` Ján Tomko
2023-01-09  4:11 ` [libvirt PATCH 2/9] conf: move anonymous backend struct from virDomainNetDef into its own struct Laine Stump
2023-01-09  5:41   ` Ján Tomko
2023-01-09  4:11 ` [libvirt PATCH 3/9] conf: put interface <backend> parsing/formatting separate functions Laine Stump
2023-01-09  5:47   ` Ján Tomko
2023-01-09  7:04     ` Laine Stump
2023-01-09  4:11 ` [libvirt PATCH 4/9] conf: add passt XML additions to schema Laine Stump
2023-01-09  5:48   ` Ján Tomko
2023-01-11 18:33   ` Daniel P. Berrangé
2023-01-12 14:45     ` Laine Stump
2023-01-12 17:28       ` Stefano Brivio
2023-01-12 18:12       ` Jiri Denemark
2023-01-09  4:11 ` [libvirt PATCH 5/9] conf: parse/format passt-related XML additions Laine Stump
2023-01-09  6:18   ` Ján Tomko
2023-01-09  4:11 ` [libvirt PATCH 6/9] qemu: new capability QEMU_CAPS_NETDEV_STREAM Laine Stump
2023-01-09  6:20   ` Ján Tomko
2023-01-09  4:11 ` [libvirt PATCH 7/9] qemu: add passtStateDir to qemu driver config Laine Stump
2023-01-09  6:23   ` Ján Tomko
2023-01-09 14:02     ` Laine Stump
2023-01-09  4:11 ` Laine Stump [this message]
2023-01-09  6:31   ` [libvirt PATCH 8/9] qemu: hook up passt config to qemu domains Ján Tomko
2023-01-09 14:14     ` Laine Stump
2023-01-09 14:51       ` Ján Tomko
2023-01-09 16:05         ` Laine Stump
2023-01-09  4:11 ` [libvirt PATCH 9/9] specfile: require passt for the build if fedora >= 36 or rhel >= 9 Laine Stump
2023-01-09  6:32   ` Ján Tomko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230109041112.368790-9-laine@redhat.com \
    --to=laine@redhat.com \
    --cc=libvir-list@redhat.com \
    --cc=passt-dev@passt.top \
    --cc=sbrivio@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).