]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
bandwidth: Implement functions to enable and disable QoS
authorMichal Privoznik <mprivozn@redhat.com>
Fri, 22 Jul 2011 14:07:27 +0000 (16:07 +0200)
committerDaniel Veillard <veillard@redhat.com>
Mon, 25 Jul 2011 05:49:55 +0000 (13:49 +0800)
These function executes 'tc' with appropriate arguments to set
desired QoS setting on interface or bridge during its creation.

configure.ac
libvirt.spec.in
src/libvirt_private.syms
src/network/bridge_driver.c
src/qemu/qemu_command.c
src/util/macvtap.c
src/util/macvtap.h
src/util/network.c
src/util/network.h

index 4e04950f4a239687e4209dc8f5ec31b02aa77f36..ac34efc4f1c28d2b5d9becb5d215e983f4ea363a 100644 (file)
@@ -170,6 +170,8 @@ AC_PATH_PROG([RADVD], [radvd], [radvd],
        [/sbin:/usr/sbin:/usr/local/sbin:$PATH])
 AC_PATH_PROG([BRCTL], [brctl], [brctl],
        [/sbin:/usr/sbin:/usr/local/sbin:$PATH])
+AC_PATH_PROG([TC], [tc], [tc],
+    [/sbin:/usr/sbin:/usr/local/sbin:$PATH])
 AC_PATH_PROG([UDEVADM], [udevadm], [],
        [/sbin:/usr/sbin:/usr/local/sbin:$PATH])
 AC_PATH_PROG([UDEVSETTLE], [udevsettle], [],
@@ -183,6 +185,8 @@ AC_DEFINE_UNQUOTED([RADVD],["$RADVD"],
         [Location or name of the radvd program])
 AC_DEFINE_UNQUOTED([BRCTL],["$BRCTL"],
         [Location or name of the brctl program (see bridge-utils)])
+AC_DEFINE_UNQUOTED([TC],["$TC"],
+        [Location or name of the tc profram (see iproute2)])
 if test -n "$UDEVADM"; then
   AC_DEFINE_UNQUOTED([UDEVADM],["$UDEVADM"],
         [Location or name of the udevadm program])
index 7c8b2ec6354f626a8d9826e13e047670fc426aa9..002239c043330e84ddc47d7434a6974e7c4ff017 100644 (file)
@@ -250,7 +250,7 @@ Requires: %{name}-client = %{version}-%{release}
 Requires: bridge-utils
 # for modprobe of pci devices
 Requires: module-init-tools
-# for /sbin/ip
+# for /sbin/ip & /sbin/tc
 Requires: iproute
 %endif
 %if %{with_network}
index 2efe9412c506e8b60fb426807d1b19d4b0ded4eb..853ee628f11af2ad27a6d2bf6f4c5647fd66f1c5 100644 (file)
@@ -713,6 +713,8 @@ nlComm;
 virBandwidthDefFormat;
 virBandwidthDefFree;
 virBandwidthDefParseNode;
+virBandwidthDisable;
+virBandwidthEnable;
 virSocketAddrBroadcast;
 virSocketAddrBroadcastByPrefix;
 virSocketAddrIsNetmask;
index 4a274086e477cf4ddff16429396eff634b236f7a..f242db8c052542d09fd896f0bfff599236ee349a 100644 (file)
@@ -1822,10 +1822,23 @@ networkStartNetworkVirtual(struct network_driver *driver,
     if (v6present && networkStartRadvd(network) < 0)
         goto err4;
 
+    if (virBandwidthEnable(network->def->bandwidth, network->def->bridge) < 0) {
+        networkReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("cannot set bandwidth limits on %s"),
+                           network->def->bridge);
+        goto err5;
+    }
+
     VIR_FREE(macTapIfName);
 
     return 0;
 
+ err5:
+    if (virBandwidthDisable(network->def->bridge, true) < 0) {
+        VIR_WARN("Failed to disable QoS on %s",
+                 network->def->bridge);
+    }
+
  err4:
     if (!save_err)
         save_err = virSaveLastError();
@@ -1883,6 +1896,11 @@ static int networkShutdownNetworkVirtual(struct network_driver *driver,
     int err;
     char ebuf[1024];
 
+    if (virBandwidthDisable(network->def->bridge, true) < 0) {
+        VIR_WARN("Failed to disable QoS on %s",
+                 network->def->name);
+    }
+
     if (network->radvdPid > 0) {
         char *radvdpidbase;
 
index e785f001728dd9bc336cd59076520ab524e58026..f8fd4eee9afdded36cba5d9fd892bcaa80680e74 100644 (file)
@@ -132,7 +132,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def,
                         vnet_hdr, def->uuid,
                         virDomainNetGetActualDirectVirtPortProfile(net),
                         &res_ifname,
-                        vmop, driver->stateDir);
+                        vmop, driver->stateDir, net->bandwidth);
     if (rc >= 0) {
         virDomainAuditNetDevice(def, net, res_ifname, true);
         VIR_FREE(net->ifname);
@@ -298,6 +298,15 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
         }
     }
 
+    if (tapfd >= 0 &&
+        virBandwidthEnable(net->bandwidth, net->ifname) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot set bandwidth limits on %s"),
+                        net->ifname);
+        VIR_FORCE_CLOSE(tapfd);
+        goto cleanup;
+    }
+
     if (tapfd >= 0) {
         if ((net->filter) && (net->ifname)) {
             err = virDomainConfNWFilterInstantiate(conn, net);
index 86e52fa26c4cdc10c82292ba3cda61280cc95b47..0b00776695a705c56cbe9b623361e84d1dae62e4 100644 (file)
@@ -267,7 +267,8 @@ openMacvtapTap(const char *tgifname,
                virVirtualPortProfileParamsPtr virtPortProfile,
                char **res_ifname,
                enum virVMOperationType vmOp,
-               char *stateDir)
+               char *stateDir,
+               virBandwidthPtr bandwidth)
 {
     const char *type = "macvtap";
     int c, rc;
@@ -361,6 +362,15 @@ create_name:
     } else
         goto disassociate_exit;
 
+    if (virBandwidthEnable(bandwidth, cr_ifname) < 0) {
+        macvtapError(VIR_ERR_INTERNAL_ERROR,
+                     _("cannot set bandwidth limits on %s"),
+                     cr_ifname);
+        rc = -1;
+        goto disassociate_exit;
+    }
+
+
     return rc;
 
 disassociate_exit:
index 8e8613d619bd2dc785b1b5430bc8c883e67a3469..2b2d835479614263cba8ca7ae2e22abe196ed058 100644 (file)
@@ -62,7 +62,8 @@ int openMacvtapTap(const char *ifname,
                    virVirtualPortProfileParamsPtr virtPortProfile,
                    char **res_ifname,
                    enum virVMOperationType vmop,
-                   char *stateDir);
+                   char *stateDir,
+                   virBandwidthPtr bandwidth);
 
 void delMacvtap(const char *ifname,
                 const unsigned char *macaddress,
index 563921981675f3edfbde942a4d3069f4d79aff59..5561012ada61b8f41ce381fad28784d31dca6a82 100644 (file)
@@ -16,6 +16,7 @@
 #include "network.h"
 #include "util.h"
 #include "virterror_internal.h"
+#include "command.h"
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 #define virSocketError(code, ...)                                       \
@@ -1102,3 +1103,163 @@ virBandwidthDefFormat(virBufferPtr buf,
 cleanup:
     return ret;
 }
+
+/**
+ * virBandwidthEnable:
+ * @bandwidth: rates to set
+ * @iface: on which interface
+ *
+ * This function enables QoS on specified interface
+ * and set given traffic limits for both, incoming
+ * and outgoing traffic. Any previous setting get
+ * overwritten.
+ *
+ * Return 0 on success, -1 otherwise.
+ */
+int
+virBandwidthEnable(virBandwidthPtr bandwidth,
+                   const char *iface)
+{
+    int ret = -1;
+    virCommandPtr cmd = NULL;
+    char *average = NULL;
+    char *peak = NULL;
+    char *burst = NULL;
+
+    if (!iface)
+        return -1;
+
+    if (!bandwidth) {
+        /* nothing to be enabled */
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (virBandwidthDisable(iface, true) < 0)
+        goto cleanup;
+
+    if (bandwidth->in) {
+        if (virAsprintf(&average, "%llukbps", bandwidth->in->average) < 0)
+            goto cleanup;
+        if (bandwidth->in->peak &&
+            (virAsprintf(&peak, "%llukbps", bandwidth->in->peak) < 0))
+            goto cleanup;
+        if (bandwidth->in->burst &&
+            (virAsprintf(&burst, "%llukb", bandwidth->in->burst) < 0))
+            goto cleanup;
+
+        cmd = virCommandNew(TC);
+        virCommandAddArgList(cmd, "qdisc", "add", "dev", iface, "root",
+                             "handle", "1:", "htb", "default", "1", NULL);
+        if (virCommandRun(cmd, NULL) < 0)
+            goto cleanup;
+
+        virCommandFree(cmd);
+        cmd = virCommandNew(TC);
+            virCommandAddArgList(cmd,"class", "add", "dev", iface, "parent",
+                                 "1:", "classid", "1:1", "htb", NULL);
+        virCommandAddArgList(cmd, "rate", average, NULL);
+
+        if (peak)
+            virCommandAddArgList(cmd, "ceil", peak, NULL);
+        if (burst)
+            virCommandAddArgList(cmd, "burst", burst, NULL);
+
+        if (virCommandRun(cmd, NULL) < 0)
+            goto cleanup;
+
+        virCommandFree(cmd);
+        cmd = virCommandNew(TC);
+            virCommandAddArgList(cmd,"filter", "add", "dev", iface, "parent",
+                                 "1:0", "protocol", "ip", "handle", "1", "fw",
+                                 "flowid", "1", NULL);
+
+        if (virCommandRun(cmd, NULL) < 0)
+            goto cleanup;
+
+        VIR_FREE(average);
+        VIR_FREE(peak);
+        VIR_FREE(burst);
+    }
+
+    if (bandwidth->out) {
+        if (virAsprintf(&average, "%llukbps", bandwidth->out->average) < 0)
+            goto cleanup;
+        if (virAsprintf(&burst, "%llukb", bandwidth->out->burst ?
+                        bandwidth->out->burst : bandwidth->out->average) < 0)
+            goto cleanup;
+
+        virCommandFree(cmd);
+        cmd = virCommandNew(TC);
+            virCommandAddArgList(cmd, "qdisc", "add", "dev", iface,
+                                 "ingress", NULL);
+
+        if (virCommandRun(cmd, NULL) < 0)
+            goto cleanup;
+
+        virCommandFree(cmd);
+        cmd = virCommandNew(TC);
+        virCommandAddArgList(cmd, "filter", "add", "dev", iface, "parent",
+                             "ffff:", "protocol", "ip", "u32", "match", "ip",
+                             "src", "0.0.0.0/0", "police", "rate", average,
+                             "burst", burst, "mtu", burst, "drop", "flowid",
+                             ":1", NULL);
+
+        if (virCommandRun(cmd, NULL) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    virCommandFree(cmd);
+    VIR_FREE(average);
+    VIR_FREE(peak);
+    VIR_FREE(burst);
+    return ret;
+}
+
+/**
+ * virBandwidthDisable:
+ * @iface: on which interface
+ * @may_fail: should be unsuccessful disable considered fatal?
+ *
+ * This function tries to disable QoS on specified interface
+ * by deleting root and ingress qdisc. However, this may fail
+ * if we try to remove the default one.
+ *
+ * Return 0 on success, -1 otherwise.
+ */
+int
+virBandwidthDisable(const char *iface,
+                    bool may_fail)
+{
+    int ret = -1;
+    int status;
+    virCommandPtr cmd = NULL;
+
+    if (!iface)
+        return -1;
+
+    cmd = virCommandNew(TC);
+    virCommandAddArgList(cmd, "qdisc", "del", "dev", iface, "root", NULL);
+
+    if ((virCommandRun(cmd, &status) < 0) ||
+        (!may_fail && status))
+        goto cleanup;
+
+    virCommandFree(cmd);
+
+    cmd = virCommandNew(TC);
+    virCommandAddArgList(cmd, "qdisc",  "del", "dev", iface, "ingress", NULL);
+
+    if ((virCommandRun(cmd, &status) < 0) ||
+        (!may_fail && status))
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virCommandFree(cmd);
+    return ret;
+}
index d0181fddfa3c103189633dd72eca3dd184827cfb..139f6ccb8bef9b5368a1431cf8e20f4c14635baa 100644 (file)
@@ -155,4 +155,7 @@ void virBandwidthDefFree(virBandwidthPtr def);
 int virBandwidthDefFormat(virBufferPtr buf,
                           virBandwidthPtr def,
                           const char *indent);
+
+int virBandwidthEnable(virBandwidthPtr bandwidth, const char *iface);
+int virBandwidthDisable(const char *iface, bool may_fail);
 #endif /* __VIR_NETWORK_H__ */