qemu: hook up passt config to qemu domains

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>
This commit is contained in:
Laine Stump 2022-12-15 14:19:16 -05:00
parent 98a24813c8
commit a56f0168d5
16 changed files with 468 additions and 12 deletions

View File

@ -780,6 +780,7 @@ optional_programs = [
'mm-ctl', 'mm-ctl',
'modprobe', 'modprobe',
'ovs-vsctl', 'ovs-vsctl',
'passt',
'pdwtags', 'pdwtags',
'rmmod', 'rmmod',
'scrub', 'scrub',

View File

@ -179,6 +179,7 @@ src/qemu/qemu_monitor.c
src/qemu/qemu_monitor_json.c src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_text.c src/qemu/qemu_monitor_text.c
src/qemu/qemu_namespace.c src/qemu/qemu_namespace.c
src/qemu/qemu_passt.c
src/qemu/qemu_process.c src/qemu/qemu_process.c
src/qemu/qemu_qapi.c src/qemu/qemu_qapi.c
src/qemu/qemu_saveimage.c src/qemu/qemu_saveimage.c

View File

@ -28,6 +28,7 @@ qemu_driver_sources = [
'qemu_monitor_json.c', 'qemu_monitor_json.c',
'qemu_monitor_text.c', 'qemu_monitor_text.c',
'qemu_namespace.c', 'qemu_namespace.c',
'qemu_passt.c',
'qemu_process.c', 'qemu_process.c',
'qemu_qapi.c', 'qemu_qapi.c',
'qemu_saveimage.c', 'qemu_saveimage.c',
@ -216,6 +217,7 @@ if conf.has('WITH_QEMU')
localstatedir / 'log' / 'swtpm' / 'libvirt' / 'qemu', localstatedir / 'log' / 'swtpm' / 'libvirt' / 'qemu',
runstatedir / 'libvirt' / 'qemu', runstatedir / 'libvirt' / 'qemu',
runstatedir / 'libvirt' / 'qemu' / 'dbus', runstatedir / 'libvirt' / 'qemu' / 'dbus',
runstatedir / 'libvirt' / 'qemu' / 'passt',
runstatedir / 'libvirt' / 'qemu' / 'slirp', runstatedir / 'libvirt' / 'qemu' / 'slirp',
runstatedir / 'libvirt' / 'qemu' / 'swtpm', runstatedir / 'libvirt' / 'qemu' / 'swtpm',
] ]

View File

@ -27,6 +27,7 @@
#include "qemu_interface.h" #include "qemu_interface.h"
#include "qemu_alias.h" #include "qemu_alias.h"
#include "qemu_security.h" #include "qemu_security.h"
#include "qemu_passt.h"
#include "qemu_slirp.h" #include "qemu_slirp.h"
#include "qemu_block.h" #include "qemu_block.h"
#include "qemu_fd.h" #include "qemu_fd.h"
@ -3817,7 +3818,8 @@ qemuBuildNicDevProps(virDomainDef *def,
virJSONValue * virJSONValue *
qemuBuildHostNetProps(virDomainNetDef *net) qemuBuildHostNetProps(virDomainObj *vm,
virDomainNetDef *net)
{ {
virDomainNetType netType = virDomainNetGetActualType(net); virDomainNetType netType = virDomainNetGetActualType(net);
size_t i; size_t i;
@ -3932,7 +3934,10 @@ qemuBuildHostNetProps(virDomainNetDef *net)
break; break;
case VIR_DOMAIN_NET_TYPE_USER: 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, if (virJSONValueObjectAdd(&netprops,
"s:type", "socket", "s:type", "socket",
"s:fd", qemuFDPassDirectGetPath(netpriv->slirpfd), "s:fd", qemuFDPassDirectGetPath(netpriv->slirpfd),
@ -8503,7 +8508,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver,
qemuFDPassDirectTransferCommand(netpriv->slirpfd, cmd); qemuFDPassDirectTransferCommand(netpriv->slirpfd, cmd);
qemuFDPassTransferCommand(netpriv->vdpafd, cmd); qemuFDPassTransferCommand(netpriv->vdpafd, cmd);
if (!(hostnetprops = qemuBuildHostNetProps(net))) if (!(hostnetprops = qemuBuildHostNetProps(vm, net)))
goto cleanup; goto cleanup;
if (qemuBuildNetdevCommandlineFromJSON(cmd, hostnetprops, qemuCaps) < 0) if (qemuBuildNetdevCommandlineFromJSON(cmd, hostnetprops, qemuCaps) < 0)

View File

@ -78,7 +78,8 @@ virJSONValue *
qemuBuildChannelGuestfwdNetdevProps(virDomainChrDef *chr); qemuBuildChannelGuestfwdNetdevProps(virDomainChrDef *chr);
virJSONValue * virJSONValue *
qemuBuildHostNetProps(virDomainNetDef *net); qemuBuildHostNetProps(virDomainObj *vm,
virDomainNetDef *net);
int int
qemuBuildInterfaceConnect(virDomainObj *vm, qemuBuildInterfaceConnect(virDomainObj *vm,

View File

@ -2379,6 +2379,7 @@ qemuDomainGetSlirpHelperOk(virDomainObj *vm)
/* if there is a builtin slirp, prevent slirp-helper */ /* if there is a builtin slirp, prevent slirp-helper */
if (net->type == VIR_DOMAIN_NET_TYPE_USER && if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT &&
!QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp) !QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
return false; return false;
} }
@ -9848,7 +9849,8 @@ qemuDomainSupportsNicdev(virDomainDef *def,
} }
bool bool
qemuDomainNetSupportsMTU(virDomainNetType type) qemuDomainNetSupportsMTU(virDomainNetType type,
virDomainNetBackendType backend)
{ {
switch (type) { switch (type) {
case VIR_DOMAIN_NET_TYPE_NETWORK: case VIR_DOMAIN_NET_TYPE_NETWORK:
@ -9857,6 +9859,7 @@ qemuDomainNetSupportsMTU(virDomainNetType type)
case VIR_DOMAIN_NET_TYPE_VHOSTUSER: case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
return true; return true;
case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_USER:
return backend == VIR_DOMAIN_NET_BACKEND_PASST;
case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_SERVER:
case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_MCAST: case VIR_DOMAIN_NET_TYPE_MCAST:

View File

@ -882,7 +882,8 @@ int qemuDomainRefreshVcpuHalted(virDomainObj *vm,
bool qemuDomainSupportsNicdev(virDomainDef *def, bool qemuDomainSupportsNicdev(virDomainDef *def,
virDomainNetDef *net); virDomainNetDef *net);
bool qemuDomainNetSupportsMTU(virDomainNetType type); bool qemuDomainNetSupportsMTU(virDomainNetType type,
virDomainNetBackendType backend);
int qemuDomainSetPrivatePaths(virQEMUDriver *driver, int qemuDomainSetPrivatePaths(virQEMUDriver *driver,
virDomainObj *vm); virDomainObj *vm);

View File

@ -25,6 +25,7 @@
#include "qemu_dbus.h" #include "qemu_dbus.h"
#include "qemu_domain.h" #include "qemu_domain.h"
#include "qemu_tpm.h" #include "qemu_tpm.h"
#include "qemu_passt.h"
#include "qemu_slirp.h" #include "qemu_slirp.h"
#include "qemu_virtiofs.h" #include "qemu_virtiofs.h"
@ -194,9 +195,17 @@ qemuExtDevicesStart(virQEMUDriver *driver,
for (i = 0; i < def->nnets; i++) { for (i = 0; i < def->nnets; i++) {
virDomainNetDef *net = def->nets[i]; virDomainNetDef *net = def->nets[i];
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) if (qemuSlirpStart(vm, net, incomingMigration) < 0)
return -1; return -1;
} }
}
for (i = 0; i < def->nfss; i++) { for (i = 0; i < def->nfss; i++) {
virDomainFSDef *fs = def->fss[i]; virDomainFSDef *fs = def->fss[i];
@ -254,6 +263,12 @@ qemuExtDevicesStop(virQEMUDriver *driver,
if (slirp) if (slirp)
qemuSlirpStop(slirp, vm, driver, net); 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) if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET && net->downscript)
virNetDevRunEthernetScript(net->ifname, net->downscript); virNetDevRunEthernetScript(net->ifname, net->downscript);
} }
@ -319,6 +334,12 @@ qemuExtDevicesSetupCgroup(virQEMUDriver *driver,
if (slirp && qemuSlirpSetupCgroup(slirp, cgroup) < 0) if (slirp && qemuSlirpSetupCgroup(slirp, cgroup) < 0)
return -1; 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++) { for (i = 0; i < def->ntpms; i++) {

View File

@ -31,6 +31,7 @@
#include "qemu_command.h" #include "qemu_command.h"
#include "qemu_hostdev.h" #include "qemu_hostdev.h"
#include "qemu_interface.h" #include "qemu_interface.h"
#include "qemu_passt.h"
#include "qemu_process.h" #include "qemu_process.h"
#include "qemu_security.h" #include "qemu_security.h"
#include "qemu_block.h" #include "qemu_block.h"
@ -1202,7 +1203,15 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
break; break;
case VIR_DOMAIN_NET_TYPE_USER: case VIR_DOMAIN_NET_TYPE_USER:
if (!priv->disableSlirp && 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)) { virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
if (qemuInterfacePrepareSlirp(driver, net) < 0) if (qemuInterfacePrepareSlirp(driver, net) < 0)
@ -1270,7 +1279,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
virNetDevSetMTU(net->ifname, net->mtu) < 0) virNetDevSetMTU(net->ifname, net->mtu) < 0)
goto cleanup; goto cleanup;
if (!(netprops = qemuBuildHostNetProps(net))) if (!(netprops = qemuBuildHostNetProps(vm, net)))
goto cleanup; goto cleanup;
qemuDomainObjEnterMonitor(vm); qemuDomainObjEnterMonitor(vm);
@ -1418,6 +1427,12 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
netdev_name = g_strdup_printf("host%s", net->info.alias); netdev_name = g_strdup_printf("host%s", net->info.alias);
if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp) if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
qemuSlirpStop(QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp, vm, driver, net); 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); qemuDomainObjEnterMonitor(vm);
if (charDevPlugged && if (charDevPlugged &&
qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0) qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0)
@ -4619,6 +4634,11 @@ qemuDomainRemoveNetDevice(virQEMUDriver *driver,
if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp) if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
qemuSlirpStop(QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp, vm, driver, net); 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); virDomainAuditNet(vm, net, NULL, "detach", true);
for (i = 0; i < vm->def->nnets; i++) { for (i = 0; i < vm->def->nnets; i++) {

282
src/qemu/qemu_passt.c Normal file
View File

@ -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;
}

38
src/qemu/qemu_passt.h Normal file
View File

@ -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);

View File

@ -5846,6 +5846,7 @@ qemuProcessNetworkPrepareDevices(virQEMUDriver *driver,
if (virDomainHostdevInsert(def, hostdev) < 0) if (virDomainHostdevInsert(def, hostdev) < 0)
return -1; return -1;
} else if (actualType == VIR_DOMAIN_NET_TYPE_USER && } else if (actualType == VIR_DOMAIN_NET_TYPE_USER &&
net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT &&
!priv->disableSlirp && !priv->disableSlirp &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) { virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
if (qemuInterfacePrepareSlirp(driver, net) < 0) if (qemuInterfacePrepareSlirp(driver, net) < 0)

View File

@ -1830,6 +1830,13 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net,
} }
hasIPv6 = true; 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) { if (ip->prefix > 120) {
virReportError(VIR_ERR_XML_ERROR, "%s", virReportError(VIR_ERR_XML_ERROR, "%s",
_("prefix too long")); _("prefix too long"));
@ -1892,7 +1899,7 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net,
} }
if (net->mtu && if (net->mtu &&
!qemuDomainNetSupportsMTU(net->type)) { !qemuDomainNetSupportsMTU(net->type, net->backend.type)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("setting MTU on interface type %s is not supported yet"), _("setting MTU on interface type %s is not supported yet"),
virDomainNetTypeToString(net->type)); virDomainNetTypeToString(net->type));

View File

@ -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

View File

@ -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

View File

@ -471,6 +471,7 @@ testCompareXMLToArgvCreateArgs(virQEMUDriver *drv,
virDomainNetDef *net = vm->def->nets[i]; virDomainNetDef *net = vm->def->nets[i];
if (net->type == VIR_DOMAIN_NET_TYPE_USER && if (net->type == VIR_DOMAIN_NET_TYPE_USER &&
net->backend.type == VIR_DOMAIN_NET_BACKEND_DEFAULT &&
virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) { virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
qemuSlirp *slirp = qemuSlirpNew(); qemuSlirp *slirp = qemuSlirpNew();
slirp->fd[0] = 42; slirp->fd[0] = 42;
@ -1469,6 +1470,7 @@ mymain(void)
DO_TEST_NOCAPS("net-user"); DO_TEST_NOCAPS("net-user");
DO_TEST_CAPS_ARCH_LATEST_FULL("net-user", "x86_64", ARG_FLAGS, FLAG_SLIRP_HELPER); DO_TEST_CAPS_ARCH_LATEST_FULL("net-user", "x86_64", ARG_FLAGS, FLAG_SLIRP_HELPER);
DO_TEST_NOCAPS("net-user-addr"); DO_TEST_NOCAPS("net-user-addr");
DO_TEST_CAPS_LATEST("net-user-passt");
DO_TEST_NOCAPS("net-virtio"); DO_TEST_NOCAPS("net-virtio");
DO_TEST_NOCAPS("net-virtio-device"); DO_TEST_NOCAPS("net-virtio-device");
DO_TEST_NOCAPS("net-virtio-disable-offloads"); DO_TEST_NOCAPS("net-virtio-disable-offloads");