[libvirt] [PATCH v2] network: Add network bandwidth support for ethernet interfaces

Anirban Chakraborty abchak at juniper.net
Fri Sep 26 17:52:57 UTC 2014


V2:
Addressed comments raised in review of V1.
Consolidate calls to virNetDevBandwidthSet.
Clear bandwidth settings when the interface is detached or domain
destroyed.

V1:
Ethernet interfaces in libvirt currently do not support bandwidth setting.
For example, following xml file for an interface will not apply these
settings to corresponding qdiscs.

    <interface type="ethernet">
      <mac address="02:36:1d:18:2a:e4"/>
      <model type="virtio"/>
      <script path=""/>
      <target dev="tap361d182a-e4"/>
      <bandwidth>
        <inbound average="984" peak="1024" burst="64"/>
        <outbound average="2000" peak="2048" burst="128"/>
      </bandwidth>
    </interface>

Signed-off-by: Anirban Chakraborty <abchak at juniper.net>

---
 src/lxc/lxc_process.c          | 26 +++++++++++++-------------
 src/network/bridge_driver.c    |  7 ++++---
 src/qemu/qemu_command.c        |  9 ++++-----
 src/qemu/qemu_driver.c         | 22 +++++++++++++++++++++-
 src/qemu/qemu_hotplug.c        | 14 +++++++++++++-
 src/util/virnetdevbandwidth.c  | 23 ++++++++++++++++++++---
 src/util/virnetdevbandwidth.h  |  7 ++++---
 src/util/virnetdevmacvlan.c    | 10 ----------
 src/util/virnetdevmacvlan.h    |  1 -
 tests/virnetdevbandwidthtest.c |  3 ++-
 10 files changed, 81 insertions(+), 41 deletions(-)

diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index ed30c37..7f7e4ad 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -274,11 +274,6 @@ char *virLXCProcessSetupInterfaceBridged(virConnectPtr conn,
     if (virNetDevSetOnline(parentVeth, true) < 0)
         goto cleanup;

-    if (virNetDevBandwidthSet(net->ifname,
-                              virDomainNetGetActualBandwidth(net),
-                              false) < 0)
-        goto cleanup;
-
     if (net->filter &&
         virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0)
         goto cleanup;
@@ -300,6 +295,7 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn,
     virNetDevBandwidthPtr bw;
     virNetDevVPortProfilePtr prof;
     virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver);
+    const char *linkdev = virDomainNetGetActualDirectDev(net);

     /* XXX how todo bandwidth controls ?
      * Since the 'net-ifname' is about to be moved to a different
@@ -329,16 +325,15 @@ char *virLXCProcessSetupInterfaceDirect(virConnectPtr conn,

     if (virNetDevMacVLanCreateWithVPortProfile(
             net->ifname, &net->mac,
-            virDomainNetGetActualDirectDev(net),
+            linkdev,
             virDomainNetGetActualDirectMode(net),
             false, def->uuid,
-            virDomainNetGetActualVirtPortProfile(net),
+            prof,
             &res_ifname,
             VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
             cfg->stateDir,
-            virDomainNetGetActualBandwidth(net), 0) < 0)
+            0) < 0)
         goto cleanup;
-
     ret = res_ifname;

  cleanup:
@@ -368,6 +363,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
     int ret = -1;
     size_t i;
     size_t niface = 0;
+    int actualType;

     for (i = 0; i < def->nnets; i++) {
         char *veth = NULL;
@@ -381,7 +377,8 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
         if (VIR_EXPAND_N(*veths, *nveths, 1) < 0)
             goto cleanup;

-        switch (virDomainNetGetActualType(def->nets[i])) {
+        actualType = virDomainNetGetActualType(def->nets[i]);
+        switch (actualType) {
         case VIR_DOMAIN_NET_TYPE_NETWORK: {
             virNetworkPtr network;
             char *brname = NULL;
@@ -444,11 +441,14 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
         case VIR_DOMAIN_NET_TYPE_LAST:
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Unsupported network type %s"),
-                           virDomainNetTypeToString(
-                               virDomainNetGetActualType(def->nets[i])
-                               ));
+                           virDomainNetTypeToString(actualType));
             goto cleanup;
         }
+        /* set network bandwidth */
+        if (virNetDevBandwidthSet(def->nets[i]->ifname,
+                virDomainNetGetActualBandwidth(def->nets[i]), false,
+                actualType) < 0)
+           goto cleanup;

         (*veths)[(*nveths)-1] = veth;

diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 979fb13..2e1f821 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2082,7 +2082,8 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
     }

     if (virNetDevBandwidthSet(network->def->bridge,
-                              network->def->bandwidth, true) < 0)
+                              network->def->bandwidth, true,
+                              VIR_DOMAIN_NET_TYPE_BRIDGE) < 0)
         goto err5;

     VIR_FREE(macTapIfName);
@@ -2090,7 +2091,7 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
     return 0;

  err5:
-    virNetDevBandwidthClear(network->def->bridge);
+    virNetDevBandwidthClear(network->def->bridge, VIR_DOMAIN_NET_TYPE_BRIDGE);

  err4:
     if (!save_err)
@@ -2137,7 +2138,7 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
 static int networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
                                          virNetworkObjPtr network)
 {
-    virNetDevBandwidthClear(network->def->bridge);
+    virNetDevBandwidthClear(network->def->bridge, VIR_DOMAIN_NET_TYPE_BRIDGE);

     if (network->radvdPid > 0) {
         char *radvdpidbase;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index eb72451..a92fb29 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -191,7 +191,6 @@ qemuPhysIfaceConnect(virDomainDefPtr def,
         virDomainNetGetActualVirtPortProfile(net),
         &res_ifname,
         vmop, cfg->stateDir,
-        virDomainNetGetActualBandwidth(net),
         macvlan_create_flags);
     if (rc >= 0) {
         virDomainAuditNetDevice(def, net, res_ifname, true);
@@ -371,10 +370,6 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
                                   &net->mac) < 0)
         goto cleanup;

-    if (virNetDevBandwidthSet(net->ifname,
-                              virDomainNetGetActualBandwidth(net),
-                              false) < 0)
-        goto cleanup;

     if (net->filter &&
         virDomainConfNWFilterInstantiate(conn, def->uuid, net) < 0) {
@@ -7392,6 +7387,10 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
         if (tapfd[0] < 0)
             goto cleanup;
     }
+    /* Set bandwidth  */
+    if (virNetDevBandwidthSet(net->ifname, virDomainNetGetActualBandwidth(net),
+           false, actualType) < 0)
+        goto cleanup;

     if ((actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 117138a..02eb680 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -186,6 +186,9 @@ qemuVMFilterRebuild(virDomainObjListIterator iter, void *data)
     return virDomainObjListForEach(qemu_driver->domains, iter, data);
 }

+static void
+qemuDomainClearNetBandwidth(virDomainObjPtr vm);
+
 static virNWFilterCallbackDriver qemuCallbackDriver = {
     .name = QEMU_DRIVER_NAME,
     .vmFilterRebuild = qemuVMFilterRebuild,
@@ -2196,6 +2199,9 @@ qemuDomainDestroyFlags(virDomainPtr dom,
     if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
         goto cleanup;

+    /* Clear network bandwidth settings */
+    qemuDomainClearNetBandwidth(vm);
+
     qemuDomainSetFakeReboot(driver, vm, false);


@@ -10205,7 +10211,8 @@ qemuDomainSetInterfaceParameters(virDomainPtr dom,
                    sizeof(*newBandwidth->out));
         }

-        if (virNetDevBandwidthSet(net->ifname, newBandwidth, false) < 0)
+        if (virNetDevBandwidthSet(net->ifname, newBandwidth, false,
+                virDomainNetGetActualType(net)) < 0)
             goto cleanup;

         virNetDevBandwidthFree(net->bandwidth);
@@ -18216,6 +18223,19 @@ qemuNodeAllocPages(virConnectPtr conn,
                           startCell, cellCount, add);
 }

+/* Clear the bandwidth setting of all the network interfaces of a vm */
+static void
+qemuDomainClearNetBandwidth(virDomainObjPtr vm)
+{
+    size_t i;
+    int type;
+
+    for (i = 0; i < vm->def->nnets; i++) {
+        type = virDomainNetGetActualType(vm->def->nets[i]);
+        virNetDevBandwidthClear(vm->def->nets[i]->ifname, type);
+    }
+}
+

 static virDriver qemuDriver = {
     .no = VIR_DRV_QEMU,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index d631887..4002afb 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -947,6 +947,10 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
         if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)
             goto cleanup;
     }
+    /* Set bandwidth  */
+    if (virNetDevBandwidthSet(net->ifname, virDomainNetGetActualBandwidth(net),
+            false, actualType) < 0)
+        goto cleanup;

     for (i = 0; i < tapfdSize; i++) {
         if (virSecurityManagerSetTapFDLabel(driver->securityManager,
@@ -2214,7 +2218,7 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
     if (needBandwidthSet) {
         if (virNetDevBandwidthSet(newdev->ifname,
                                   virDomainNetGetActualBandwidth(newdev),
-                                  false) < 0)
+                                  false, newType) < 0)
             goto cleanup;
         needReplaceDevDef = true;
     }
@@ -3481,6 +3485,7 @@ qemuDomainDetachNetDevice(virConnectPtr conn,
     virDomainNetDefPtr detach = NULL;
     qemuDomainObjPrivatePtr priv = vm->privateData;
     int rc;
+    int actualType;

     if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
         goto cleanup;
@@ -3517,6 +3522,13 @@ qemuDomainDetachNetDevice(virConnectPtr conn,
         }
     }

+    actualType = virDomainNetGetActualType(detach);
+    if (virNetDevBandwidthClear(detach->ifname, actualType) < 0) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("cannot clear bandwidth setting for device : %s"),
+                       detach->ifname);
+        goto cleanup;
+    }
     qemuDomainMarkDeviceForRemoval(vm, &detach->info);

     qemuDomainObjEnterMonitor(driver, vm);
diff --git a/src/util/virnetdevbandwidth.c b/src/util/virnetdevbandwidth.c
index 5fa231a..34a224e 100644
--- a/src/util/virnetdevbandwidth.c
+++ b/src/util/virnetdevbandwidth.c
@@ -27,6 +27,7 @@
 #include "viralloc.h"
 #include "virerror.h"
 #include "virstring.h"
+#include "domain_conf.h"

 #define VIR_FROM_THIS VIR_FROM_NONE

@@ -47,6 +48,7 @@ virNetDevBandwidthFree(virNetDevBandwidthPtr def)
  * @ifname: on which interface
  * @bandwidth: rates to set (may be NULL)
  * @hierarchical_class: whether to create hierarchical class
+ * @type: interface type
  *
  * This function enables QoS on specified interface
  * and set given traffic limits for both, incoming
@@ -60,7 +62,8 @@ virNetDevBandwidthFree(virNetDevBandwidthPtr def)
 int
 virNetDevBandwidthSet(const char *ifname,
                       virNetDevBandwidthPtr bandwidth,
-                      bool hierarchical_class)
+                      bool hierarchical_class,
+                      int type)
 {
     int ret = -1;
     virCommandPtr cmd = NULL;
@@ -74,7 +77,14 @@ virNetDevBandwidthSet(const char *ifname,
         goto cleanup;
     }

-    virNetDevBandwidthClear(ifname);
+    if (type != VIR_DOMAIN_NET_TYPE_ETHERNET &&
+            type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
+            type != VIR_DOMAIN_NET_TYPE_NETWORK &&
+            type != VIR_DOMAIN_NET_TYPE_DIRECT)
+        /* bandwidth not set for interfaces other than the above */
+        return 0;
+
+    virNetDevBandwidthClear(ifname, type);

     if (bandwidth->in && bandwidth->in->average) {
         if (virAsprintf(&average, "%llukbps", bandwidth->in->average) < 0)
@@ -245,6 +255,7 @@ virNetDevBandwidthSet(const char *ifname,
 /**
  * virNetDevBandwidthClear:
  * @ifname: on which interface
+ * @type: interface tyoe
  *
  * This function tries to disable QoS on specified interface
  * by deleting root and ingress qdisc. However, this may fail
@@ -253,12 +264,18 @@ virNetDevBandwidthSet(const char *ifname,
  * Return 0 on success, -1 otherwise.
  */
 int
-virNetDevBandwidthClear(const char *ifname)
+virNetDevBandwidthClear(const char *ifname, int type)
 {
     int ret = 0;
     int dummy; /* for ignoring the exit status */
     virCommandPtr cmd = NULL;

+    if (type != VIR_DOMAIN_NET_TYPE_ETHERNET &&
+            type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
+            type != VIR_DOMAIN_NET_TYPE_NETWORK &&
+            type != VIR_DOMAIN_NET_TYPE_DIRECT)
+        return ret;
+
     cmd = virCommandNew(TC);
     virCommandAddArgList(cmd, "qdisc", "del", "dev", ifname, "root", NULL);

diff --git a/src/util/virnetdevbandwidth.h b/src/util/virnetdevbandwidth.h
index 4606a07..cc43444 100644
--- a/src/util/virnetdevbandwidth.h
+++ b/src/util/virnetdevbandwidth.h
@@ -43,11 +43,12 @@ struct _virNetDevBandwidth {

 void virNetDevBandwidthFree(virNetDevBandwidthPtr def);

-int virNetDevBandwidthSet(const char *ifname,
+int virNetDevBandwidthSet(const char *name,
                           virNetDevBandwidthPtr bandwidth,
-                          bool hierarchical_class)
+                          bool hierarchical_class,
+                          int type)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
-int virNetDevBandwidthClear(const char *ifname)
+int virNetDevBandwidthClear(const char *name, int type)
     ATTRIBUTE_NONNULL(1);
 int virNetDevBandwidthCopy(virNetDevBandwidthPtr *dest,
                            const virNetDevBandwidth *src)
diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c
index c83341c..956a96b 100644
--- a/src/util/virnetdevmacvlan.c
+++ b/src/util/virnetdevmacvlan.c
@@ -811,7 +811,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
                                            char **res_ifname,
                                            virNetDevVPortProfileOp vmOp,
                                            char *stateDir,
-                                           virNetDevBandwidthPtr bandwidth,
                                            unsigned int flags)
 {
     const char *type = (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP) ?
@@ -925,14 +924,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *tgifname,
         rc = 0;
     }

-    if (virNetDevBandwidthSet(cr_ifname, bandwidth, false) < 0) {
-        if (flags & VIR_NETDEV_MACVLAN_CREATE_WITH_TAP)
-            VIR_FORCE_CLOSE(rc); /* sets rc to -1 */
-        else
-            rc = -1;
-        goto disassociate_exit;
-    }
-
     if (vmOp == VIR_NETDEV_VPORT_PROFILE_OP_CREATE ||
         vmOp == VIR_NETDEV_VPORT_PROFILE_OP_RESTORE) {
         /* Only directly register upon a create or restore (restarting
@@ -1076,7 +1067,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname ATTRIBUTE_UNUSED,
                                            char **res_ifname ATTRIBUTE_UNUSED,
                                            virNetDevVPortProfileOp vmop ATTRIBUTE_UNUSED,
                                            char *stateDir ATTRIBUTE_UNUSED,
-                                           virNetDevBandwidthPtr bandwidth ATTRIBUTE_UNUSED,
                                            unsigned int flags)
 {
     virCheckFlags(0, -1);
diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h
index 41aa4e2..f08d32b 100644
--- a/src/util/virnetdevmacvlan.h
+++ b/src/util/virnetdevmacvlan.h
@@ -68,7 +68,6 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname,
                                            char **res_ifname,
                                            virNetDevVPortProfileOp vmop,
                                            char *stateDir,
-                                           virNetDevBandwidthPtr bandwidth,
                                            unsigned int flags)
     ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(6)
     ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(10) ATTRIBUTE_RETURN_CHECK;
diff --git a/tests/virnetdevbandwidthtest.c b/tests/virnetdevbandwidthtest.c
index 384991e..db1f557 100644
--- a/tests/virnetdevbandwidthtest.c
+++ b/tests/virnetdevbandwidthtest.c
@@ -79,7 +79,8 @@ testVirNetDevBandwidthSet(const void *data)

     virCommandSetDryRun(&buf, NULL, NULL);

-    if (virNetDevBandwidthSet(iface, band, info->hierarchical_class) < 0)
+    if (virNetDevBandwidthSet(iface, band, info->hierarchical_class,
+           VIR_DOMAIN_NET_TYPE_ETHERNET) < 0)
         goto cleanup;

     if (!(actual_cmd = virBufferContentAndReset(&buf))) {
-- 
1.9.1




More information about the libvir-list mailing list