forked from rpms/libvirt
223 lines
9.3 KiB
Diff
223 lines
9.3 KiB
Diff
|
From 16ba1d0258765d9c3b5e2da666ed6d4d933e26d9 Mon Sep 17 00:00:00 2001
|
||
|
Message-Id: <16ba1d0258765d9c3b5e2da666ed6d4d933e26d9@dist-git>
|
||
|
From: Laine Stump <laine@redhat.com>
|
||
|
Date: Thu, 30 Jan 2020 14:12:41 -0500
|
||
|
Subject: [PATCH] qemu: support interface <teaming> functionality
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
The QEMU driver uses the <teaming type='persistent|transient'
|
||
|
persistent='blah'/> element to setup a "failover" pair of devices -
|
||
|
the persistent device must be a virtio emulated NIC, with the only
|
||
|
extra configuration being the addition of ",failover=on" to the device
|
||
|
commandline, and the transient device must be a hostdev NIC
|
||
|
(<interface type='hostdev'> or <interface type='network'> with a
|
||
|
network that is a pool of SRIOV VFs) where the extra configuration is
|
||
|
the addition of ",failover_pair_id=$aliasOfVirtio" to the device
|
||
|
commandline. These new options are supported in QEMU 4.2.0 and later.
|
||
|
|
||
|
Extra qemu-specific validation is added to ensure that the device
|
||
|
type/model is appropriate and that the qemu binary supports these
|
||
|
commandline options.
|
||
|
|
||
|
The result of this will be:
|
||
|
|
||
|
1) The virtio device presented to the guest will have an extra bit set
|
||
|
in its PCI capabilities indicating that it can be used as a failover
|
||
|
backup device. The virtio guest driver will need to be equipped to do
|
||
|
something with this information - this is included in the Linux
|
||
|
virtio-net driver in kernel 4.18 and above (and also backported to
|
||
|
some older distro kernels). Unfortunately there is no way for libvirt
|
||
|
to learn whether or not the guest driver supports failover - if it
|
||
|
doesn't then the extra PCI capability will be ignored and the guest OS
|
||
|
will just see two independent devices. (NB: the current virtio guest
|
||
|
driver also requires that the MAC addresses of the two NICs match in
|
||
|
order to pair them into a bond).
|
||
|
|
||
|
2) When a migration is requested, QEMu will automatically unplug the
|
||
|
transient/hostdev NIC from the guest on the source host before
|
||
|
starting migration, and automatically re-plug a similar device after
|
||
|
restarting the guest CPUs on the destination host. While the transient
|
||
|
NIC is unplugged, all network traffic will go through the
|
||
|
persistent/virtio device, but when the hostdev NIC is plugged in, it
|
||
|
will get all the traffic. This means that in normal circumstances the
|
||
|
guest gets the performance advantage of vfio-assigned "real hardware"
|
||
|
networking, but it can still be migrated with the only downside being
|
||
|
a performance penalty (due to using an emulated NIC) during the
|
||
|
migration.
|
||
|
|
||
|
Signed-off-by: Laine Stump <laine@redhat.com>
|
||
|
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||
|
(cherry picked from commit eb9f6cc4b3464707cf689fda9812e5129003bf27)
|
||
|
|
||
|
https://bugzilla.redhat.com/1693587
|
||
|
Signed-off-by: Laine Stump <laine@redhat.com>
|
||
|
Message-Id: <20200130191244.24174-4-laine@redhat.com>
|
||
|
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
|
||
|
---
|
||
|
src/qemu/qemu_command.c | 9 +++++
|
||
|
src/qemu/qemu_domain.c | 36 +++++++++++++++--
|
||
|
.../qemuxml2argvdata/net-virtio-teaming.args | 40 +++++++++++++++++++
|
||
|
tests/qemuxml2argvtest.c | 4 ++
|
||
|
4 files changed, 86 insertions(+), 3 deletions(-)
|
||
|
create mode 100644 tests/qemuxml2argvdata/net-virtio-teaming.args
|
||
|
|
||
|
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
|
||
|
index 7a184c229e..d144855b0d 100644
|
||
|
--- a/src/qemu/qemu_command.c
|
||
|
+++ b/src/qemu/qemu_command.c
|
||
|
@@ -3833,6 +3833,8 @@ qemuBuildNicDevStr(virDomainDefPtr def,
|
||
|
}
|
||
|
virBufferAsprintf(&buf, ",host_mtu=%u", net->mtu);
|
||
|
}
|
||
|
+ if (usingVirtio && net->teaming.type == VIR_DOMAIN_NET_TEAMING_TYPE_PERSISTENT)
|
||
|
+ virBufferAddLit(&buf, ",failover=on");
|
||
|
|
||
|
virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias);
|
||
|
virBufferAsprintf(&buf, ",id=%s", net->info.alias);
|
||
|
@@ -4704,6 +4706,13 @@ qemuBuildPCIHostdevDevStr(const virDomainDef *def,
|
||
|
if (qemuBuildRomStr(&buf, dev->info) < 0)
|
||
|
return NULL;
|
||
|
|
||
|
+ if (dev->parentnet &&
|
||
|
+ dev->parentnet->teaming.type == VIR_DOMAIN_NET_TEAMING_TYPE_TRANSIENT &&
|
||
|
+ dev->parentnet->teaming.persistent) {
|
||
|
+ virBufferAsprintf(&buf, ",failover_pair_id=%s",
|
||
|
+ dev->parentnet->teaming.persistent);
|
||
|
+ }
|
||
|
+
|
||
|
return virBufferContentAndReset(&buf);
|
||
|
}
|
||
|
|
||
|
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
||
|
index 91a9f0481b..e37404340f 100644
|
||
|
--- a/src/qemu/qemu_domain.c
|
||
|
+++ b/src/qemu/qemu_domain.c
|
||
|
@@ -6391,12 +6391,20 @@ qemuDomainValidateActualNetDef(const virDomainNetDef *net,
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
+ if (net->teaming.type == VIR_DOMAIN_NET_TEAMING_TYPE_TRANSIENT &&
|
||
|
+ actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
||
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||
|
+ _("interface %s - teaming transient device must be type='hostdev', not '%s'"),
|
||
|
+ macstr, virDomainNetTypeToString(actualType));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int
|
||
|
-qemuDomainDeviceDefValidateNetwork(const virDomainNetDef *net)
|
||
|
+qemuDomainDeviceDefValidateNetwork(const virDomainNetDef *net,
|
||
|
+ virQEMUCapsPtr qemuCaps)
|
||
|
{
|
||
|
bool hasIPv4 = false;
|
||
|
bool hasIPv6 = false;
|
||
|
@@ -6481,7 +6489,29 @@ qemuDomainDeviceDefValidateNetwork(const virDomainNetDef *net)
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
- if (net->coalesce && !qemuDomainNetSupportsCoalesce(net->type)) {
|
||
|
+ if (net->teaming.type != VIR_DOMAIN_NET_TEAMING_TYPE_NONE &&
|
||
|
+ !virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_FAILOVER)) {
|
||
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||
|
+ _("virtio-net failover (teaming) is not supported with this QEMU binary"));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ if (net->teaming.type == VIR_DOMAIN_NET_TEAMING_TYPE_PERSISTENT
|
||
|
+ && !virDomainNetIsVirtioModel(net)) {
|
||
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||
|
+ _("virtio-net teaming persistent interface must be <model type='virtio'/>, not '%s'"),
|
||
|
+ virDomainNetGetModelString(net));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ if (net->teaming.type == VIR_DOMAIN_NET_TEAMING_TYPE_TRANSIENT &&
|
||
|
+ net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
|
||
|
+ net->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
|
||
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||
|
+ _("virtio-net teaming transient interface must be type='hostdev', not '%s'"),
|
||
|
+ virDomainNetTypeToString(net->type));
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (net->coalesce && !qemuDomainNetSupportsCoalesce(net->type)) {
|
||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||
|
_("coalesce settings on interface type %s are not supported"),
|
||
|
virDomainNetTypeToString(net->type));
|
||
|
@@ -8377,7 +8407,7 @@ qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev,
|
||
|
|
||
|
switch ((virDomainDeviceType)dev->type) {
|
||
|
case VIR_DOMAIN_DEVICE_NET:
|
||
|
- ret = qemuDomainDeviceDefValidateNetwork(dev->data.net);
|
||
|
+ ret = qemuDomainDeviceDefValidateNetwork(dev->data.net, qemuCaps);
|
||
|
break;
|
||
|
|
||
|
case VIR_DOMAIN_DEVICE_CHR:
|
||
|
diff --git a/tests/qemuxml2argvdata/net-virtio-teaming.args b/tests/qemuxml2argvdata/net-virtio-teaming.args
|
||
|
new file mode 100644
|
||
|
index 0000000000..19e7260843
|
||
|
--- /dev/null
|
||
|
+++ b/tests/qemuxml2argvdata/net-virtio-teaming.args
|
||
|
@@ -0,0 +1,40 @@
|
||
|
+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 \
|
||
|
+QEMU_AUDIO_DRV=none \
|
||
|
+/usr/bin/qemu-system-i386 \
|
||
|
+-name QEMUGuest1 \
|
||
|
+-S \
|
||
|
+-machine pc,accel=tcg,usb=off,dump-guest-core=off \
|
||
|
+-m 214 \
|
||
|
+-realtime mlock=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,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
|
||
|
+server,nowait \
|
||
|
+-mon chardev=charmonitor,id=monitor,mode=control \
|
||
|
+-rtc base=utc \
|
||
|
+-no-shutdown \
|
||
|
+-no-acpi \
|
||
|
+-usb \
|
||
|
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
|
||
|
+-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \
|
||
|
+-netdev user,id=hostua-backup0 \
|
||
|
+-device virtio-net-pci,failover=on,netdev=hostua-backup0,id=ua-backup0,\
|
||
|
+mac=00:11:22:33:44:55,bus=pci.0,addr=0x3 \
|
||
|
+-netdev user,id=hostua-backup1 \
|
||
|
+-device virtio-net-pci,failover=on,netdev=hostua-backup1,id=ua-backup1,\
|
||
|
+mac=66:44:33:22:11:00,bus=pci.0,addr=0x4 \
|
||
|
+-device vfio-pci,host=0000:03:07.1,id=hostdev0,bus=pci.0,addr=0x5,\
|
||
|
+failover_pair_id=ua-backup0 \
|
||
|
+-device vfio-pci,host=0000:03:07.2,id=hostdev1,bus=pci.0,addr=0x6,\
|
||
|
+failover_pair_id=ua-backup1 \
|
||
|
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7
|
||
|
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
|
||
|
index b923590930..4d26fe0b55 100644
|
||
|
--- a/tests/qemuxml2argvtest.c
|
||
|
+++ b/tests/qemuxml2argvtest.c
|
||
|
@@ -1308,6 +1308,10 @@ mymain(void)
|
||
|
QEMU_CAPS_VIRTIO_NET_RX_QUEUE_SIZE,
|
||
|
QEMU_CAPS_VIRTIO_NET_TX_QUEUE_SIZE);
|
||
|
DO_TEST_PARSE_ERROR("net-virtio-rxqueuesize-invalid-size", NONE);
|
||
|
+ DO_TEST("net-virtio-teaming",
|
||
|
+ QEMU_CAPS_VIRTIO_NET_FAILOVER,
|
||
|
+ QEMU_CAPS_DEVICE_VFIO_PCI);
|
||
|
+ DO_TEST_PARSE_ERROR("net-virtio-teaming", NONE);
|
||
|
DO_TEST("net-eth", NONE);
|
||
|
DO_TEST("net-eth-ifname", NONE);
|
||
|
DO_TEST("net-eth-names", NONE);
|
||
|
--
|
||
|
2.25.0
|
||
|
|