]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: hook up passt config to qemu domains
authorLaine Stump <laine@redhat.com>
Thu, 15 Dec 2022 19:19:16 +0000 (14:19 -0500)
committerLaine Stump <laine@redhat.com>
Tue, 10 Jan 2023 06:19:25 +0000 (01:19 -0500)
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>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
16 files changed:
meson.build
po/POTFILES
src/qemu/meson.build
src/qemu/qemu_command.c
src/qemu/qemu_command.h
src/qemu/qemu_domain.c
src/qemu/qemu_domain.h
src/qemu/qemu_extdevice.c
src/qemu/qemu_hotplug.c
src/qemu/qemu_passt.c [new file with mode: 0644]
src/qemu/qemu_passt.h [new file with mode: 0644]
src/qemu/qemu_process.c
src/qemu/qemu_validate.c
tests/qemuxml2argvdata/net-user-passt.args [new file with mode: 0644]
tests/qemuxml2argvdata/net-user-passt.x86_64-latest.args [new file with mode: 0644]
tests/qemuxml2argvtest.c

index 177009c44d4763ec58c9b0a188ffbb13082a719f..6604ba20c8a1b2266f2ca689109f7a2f30056d9a 100644 (file)
@@ -780,6 +780,7 @@ optional_programs = [
   'mm-ctl',
   'modprobe',
   'ovs-vsctl',
+  'passt',
   'pdwtags',
   'rmmod',
   'scrub',
index b2297be84eb84a5ccbcab8d195d4f8d7ef554870..4e446aaf40cb8d182ac0490590532344bff886ff 100644 (file)
@@ -179,6 +179,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
index 96952cc52db5caeb53fc92e599b68ba304fc938c..c8806bbc36a9266110d67cb98dfb9ebe8d4f0851 100644 (file)
@@ -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',
   ]
index 9c05750d6620fc2e6ce9e3a95486a677d7ad0afd..d03ddb08868655c1b2ad3dbdd284840e98628154 100644 (file)
@@ -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"
@@ -3817,7 +3818,8 @@ qemuBuildNicDevProps(virDomainDef *def,
 
 
 virJSONValue *
-qemuBuildHostNetProps(virDomainNetDef *net)
+qemuBuildHostNetProps(virDomainObj *vm,
+                      virDomainNetDef *net)
 {
     virDomainNetType netType = virDomainNetGetActualType(net);
     size_t i;
@@ -3932,7 +3934,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),
@@ -8503,7 +8508,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)
index 761cc5d8650d544891d10929d7015e99739bf877..c49096a057a462bea77aa292b6c2bd6096eeb129 100644 (file)
@@ -78,7 +78,8 @@ virJSONValue *
 qemuBuildChannelGuestfwdNetdevProps(virDomainChrDef *chr);
 
 virJSONValue *
-qemuBuildHostNetProps(virDomainNetDef *net);
+qemuBuildHostNetProps(virDomainObj *vm,
+                      virDomainNetDef *net);
 
 int
 qemuBuildInterfaceConnect(virDomainObj *vm,
index d84e7832b534d7b45694f2918178db211dfc03b6..2eb5653254e130503c74d8b5f6e98a3bb621aa2a 100644 (file)
@@ -2379,6 +2379,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;
     }
@@ -9848,7 +9849,8 @@ qemuDomainSupportsNicdev(virDomainDef *def,
 }
 
 bool
-qemuDomainNetSupportsMTU(virDomainNetType type)
+qemuDomainNetSupportsMTU(virDomainNetType type,
+                         virDomainNetBackendType backend)
 {
     switch (type) {
     case VIR_DOMAIN_NET_TYPE_NETWORK:
@@ -9857,6 +9859,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:
index 5114a311fb21eb8fdb5667c29bd67be614d75a35..08430b67b90d6df352ad174feb7c8151535085e9 100644 (file)
@@ -882,7 +882,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);
index d5c3e8ed71f17a00a84f55828b47c905ffabae4e..f7b2e2e65389c73d54335df44e2c270509447780 100644 (file)
@@ -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++) {
index dba699a8a8d8fc3ac128ba6a5b8e087ccfa57353..026e1ee5add75c5ddbbe1428c14835d50189e1d5 100644 (file)
@@ -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"
@@ -1202,8 +1203,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;
@@ -1270,7 +1279,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);
@@ -1418,6 +1427,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)
@@ -4619,6 +4634,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 (file)
index 0000000..3355f7b
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * 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_autofree char *shortName = virDomainDefGetShortName(vm->def);
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+    g_autofree char *name = NULL;
+
+    name = g_strdup_printf("%s-%s-passt", shortName, net->info.alias);
+
+    return virPidFileBuildPath(cfg->passtStateDir, name);
+}
+
+
+static char *
+qemuPasstCreateSocketPath(virDomainObj *vm,
+                          virDomainNetDef *net)
+{
+    qemuDomainObjPrivate *priv = vm->privateData;
+    virQEMUDriver *driver = priv->driver;
+    g_autofree char *shortName = virDomainDefGetShortName(vm->def);
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+
+    return g_strdup_printf("%s/%s-%s.socket", cfg->passtStateDir,
+                           shortName, 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 (file)
index 0000000..623b494
--- /dev/null
@@ -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);
index 9fc7eada5220ae901132af93d56d0f2fc5fc320b..ee9f0784d3a38400faeff11481150bac3afa5f89 100644 (file)
@@ -5846,6 +5846,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)
index c687df0bfc6d46286cde232f217025a230f2daed..6e04b22da43f25cf57046fbf2c30e4eb56fdfbc0 100644 (file)
@@ -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 (file)
index 0000000..8c887ca
--- /dev/null
@@ -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 (file)
index 0000000..48e3e8c
--- /dev/null
@@ -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/-1-QEMUGuest1-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
index c9e291c450009b69527bea1bee0ab980f920fb68..8c52feb83c3cebc565b26629fa4e4f1b8fc39319 100644 (file)
@@ -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;
@@ -1469,6 +1470,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");