render / rpms / libvirt

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