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 b2297be84e..4e446aaf40 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -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 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 9c05750d66..d03ddb0886 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" @@ -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) 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 d84e7832b5..2eb5653254 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -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: diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 5114a311fb..08430b67b9 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -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); 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 dba699a8a8..026e1ee5ad 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" @@ -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 index 0000000000..3355f7b2fa --- /dev/null +++ b/src/qemu/qemu_passt.c @@ -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 + * . + */ + +#include + +#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 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 + * . + */ + +#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 9fc7eada52..ee9f0784d3 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -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) 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..48e3e8ca8b --- /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/-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 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index c9e291c450..8c52feb83c 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; @@ -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");