]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Set noqueue qdisc for TAP devices
authorMichal Privoznik <mprivozn@redhat.com>
Thu, 8 Oct 2020 14:22:50 +0000 (16:22 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 13 Oct 2020 14:31:29 +0000 (16:31 +0200)
By default, pfifo_fast queueing discipline (qdisc) is set on
newly created interfaces (including TAPs). This qdisc has three
queues and packets that want to be sent through given NIC are
placed into one of the queues based on TOS field. Queues are then
emptied based on their priority allowing interactive sessions
stay interactive whilst something else is downloading a large
file.

Obviously, this means that kernel has to be involved and some
locking has to happen (when placing packets into queues). If
virtualization is taken into account then the above algorithm
happens twice - once in the guest and the second time in the
host.

This is arguably not optimal as it burns host CPU cycles
needlessly. Guest already made it choice and sent packets in the
order it wants.

To resolve this, Linux kernel offers 'noqueue' qdisc which can be
applied on virtual interfaces and in fact for 'lo' it is by
default:

  lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue

Set it for other TAP devices we create for domains too. With this
change I was able to squeeze 1Mbps more from a macvtap attached
to a guest and to my 1Gbps LAN (as measured by iperf3).

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1329644
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
src/qemu/qemu_command.c
src/qemu/qemu_domain.c
src/qemu/qemu_domain.h
src/qemu/qemu_hotplug.c
src/util/virnetdev.h
tests/qemuxml2argvmock.c

index 9519861e924a9cd78ed597290c3cae0f0d5b18e7..eec860382c3bda214b729932520a1935060e8866 100644 (file)
@@ -8267,6 +8267,8 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
         }
     }
 
+    qemuDomainInterfaceSetDefaultQDisc(driver, net);
+
     if (net->mtu &&
         virNetDevSetMTU(net->ifname, net->mtu) < 0)
         goto cleanup;
index 2d7f61f5e9eb9fb458e7d69d208c05e7bd35926e..5e603284be8fe38822d636498a79a2d56ab973a5 100644 (file)
@@ -11049,3 +11049,39 @@ qemuDomainFileWrapperFDClose(virDomainObjPtr vm,
     }
     return ret;
 }
+
+
+/**
+ * qemuDomainInterfaceSetDefaultQDisc:
+ * @driver: QEMU driver
+ * @net: domain interface
+ *
+ * Set the noqueue qdisc on @net if running as privileged. The
+ * noqueue qdisc is a lockless transmit and thus faster than the
+ * default pfifo_fast (at least in theory). But we can modify
+ * root qdisc only if we have CAP_NET_ADMIN.
+ *
+ * Returns: 0 on success,
+ *         -1 otherwise.
+ */
+int
+qemuDomainInterfaceSetDefaultQDisc(virQEMUDriverPtr driver,
+                                   virDomainNetDefPtr net)
+{
+    virDomainNetType actualType = virDomainNetGetActualType(net);
+
+    if (!driver->privileged || !net->ifname)
+        return 0;
+
+    /* We want only those types which are represented as TAP
+     * devices in the host. */
+    if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
+        actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
+        actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+        actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
+        if (virNetDevSetRootQDisc(net->ifname, "noqueue") < 0)
+            return -1;
+    }
+
+    return 0;
+}
index 9bf32e16c9af3a90f8faacf49de0e956022f27d5..91b3b67cb66496f875f44a9d465b0b95477b20aa 100644 (file)
@@ -1046,3 +1046,7 @@ qemuDomainOpenFile(virQEMUDriverPtr driver,
 int
 qemuDomainFileWrapperFDClose(virDomainObjPtr vm,
                              virFileWrapperFdPtr fd);
+
+int
+qemuDomainInterfaceSetDefaultQDisc(virQEMUDriverPtr driver,
+                                   virDomainNetDefPtr net);
index 7a54fcb221c72a941fb1c42a53e25c82300e8a80..2c184b9ba0b96eb0bccc53084fd715b84b08507b 100644 (file)
@@ -1368,6 +1368,8 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
         virNetDevSetMTU(net->ifname, net->mtu) < 0)
         goto cleanup;
 
+    qemuDomainInterfaceSetDefaultQDisc(driver, net);
+
     for (i = 0; i < tapfdSize; i++) {
         if (qemuSecuritySetTapFDLabel(driver->securityManager,
                                       vm->def, tapfd[i]) < 0)
index 82943b8e08ff608055c655ac66baf00a1a1fc147..dfef49938f33fe58c6778e131e83ec426ea705c4 100644 (file)
@@ -313,6 +313,7 @@ int virNetDevRunEthernetScript(const char *ifname, const char *script)
     G_GNUC_NO_INLINE;
 
 int virNetDevSetRootQDisc(const char *ifname,
-                          const char *qdisc);
+                          const char *qdisc)
+    G_GNUC_NO_INLINE;
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virNetDevRxFilter, virNetDevRxFilterFree);
index 9bf4357b66fc5d4e75a87b9325dca5278a6e8023..b9322f4f2aa7beba24f0d2657db5c009fbbedde8 100644 (file)
@@ -286,3 +286,11 @@ qemuBuildTPMOpenBackendFDs(const char *tpmdev G_GNUC_UNUSED,
     *cancelfd = 1731;
     return 0;
 }
+
+
+int
+virNetDevSetRootQDisc(const char *ifname G_GNUC_UNUSED,
+                      const char *qdisc G_GNUC_UNUSED)
+{
+    return 0;
+}