[libvirt] [PATCH v5] network: Add network bandwidth support to ethernet interfaces

Anirban Chakraborty abchak at juniper.net
Wed Nov 12 23:07:43 UTC 2014


>From 7db513698bfcc30d2d0b020c3fcf9e0337c66ff4 Mon Sep 17 00:00:00 2001
From: Anirban Chakraborty <abchak at juniper.net>
Date: Wed, 12 Nov 2014 14:24:43 -0800
Subject: [PATCH] network: Add network bandwidth support to ethernet interfaces

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/conf/netdev_bandwidth_conf.c | 14 ++++++++++-
 src/conf/netdev_bandwidth_conf.h | 25 +++++++++++++++++++
 src/libvirt_private.syms         |  1 +
 src/lxc/lxc_driver.c             |  8 +++++++
 src/lxc/lxc_process.c            | 52 +++++++++++++++++++++++-----------------
 src/qemu/qemu_command.c          | 16 ++++++++-----
 src/qemu/qemu_hotplug.c          | 12 ++++++++++
 src/qemu/qemu_process.c          |  4 ++++
 src/util/virnetdevmacvlan.c      | 10 --------
 src/util/virnetdevmacvlan.h      |  1 -
 10 files changed, 104 insertions(+), 41 deletions(-)

diff --git a/src/conf/netdev_bandwidth_conf.c b/src/conf/netdev_bandwidth_conf.c
index 2e5b564..63a39e3 100644
--- a/src/conf/netdev_bandwidth_conf.c
+++ b/src/conf/netdev_bandwidth_conf.c
@@ -25,7 +25,6 @@
 #include "netdev_bandwidth_conf.h"
 #include "virerror.h"
 #include "viralloc.h"
-#include "domain_conf.h"
 #include "virstring.h"

 #define VIR_FROM_THIS VIR_FROM_NONE
@@ -269,3 +268,16 @@ virNetDevBandwidthFormat(virNetDevBandwidthPtr def, virBufferPtr buf)
  cleanup:
     return ret;
 }
+
+void
+virDomainClearNetBandwidth(virDomainObjPtr vm)
+{
+    size_t i;
+    virDomainNetType type;
+
+    for (i = 0; i < vm->def->nnets; i++) {
+        type = virDomainNetGetActualType(vm->def->nets[i]);
+        if (virNetDevSupportBandwidth(type))
+            virNetDevBandwidthClear(vm->def->nets[i]->ifname);
+    }
+}
diff --git a/src/conf/netdev_bandwidth_conf.h b/src/conf/netdev_bandwidth_conf.h
index 23aaaf3..60dacc6 100644
--- a/src/conf/netdev_bandwidth_conf.h
+++ b/src/conf/netdev_bandwidth_conf.h
@@ -27,6 +27,7 @@
 # include "virnetdevbandwidth.h"
 # include "virbuffer.h"
 # include "virxml.h"
+# include "domain_conf.h"

 virNetDevBandwidthPtr virNetDevBandwidthParse(xmlNodePtr node,
                                               int net_type)
@@ -35,4 +36,28 @@ int virNetDevBandwidthFormat(virNetDevBandwidthPtr def,
                              virBufferPtr buf)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);

+void virDomainClearNetBandwidth(virDomainObjPtr vm)
+    ATTRIBUTE_NONNULL(1);
+
+static inline bool virNetDevSupportBandwidth(virDomainNetType type)
+{
+    switch (type) {
+    case VIR_DOMAIN_NET_TYPE_BRIDGE:
+    case VIR_DOMAIN_NET_TYPE_NETWORK:
+    case VIR_DOMAIN_NET_TYPE_DIRECT:
+    case VIR_DOMAIN_NET_TYPE_ETHERNET:
+        return true;
+    case VIR_DOMAIN_NET_TYPE_USER:
+    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
+    case VIR_DOMAIN_NET_TYPE_SERVER:
+    case VIR_DOMAIN_NET_TYPE_CLIENT:
+    case VIR_DOMAIN_NET_TYPE_MCAST:
+    case VIR_DOMAIN_NET_TYPE_INTERNAL:
+    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+    case VIR_DOMAIN_NET_TYPE_LAST:
+        break;
+    }
+    return false;
+}
+
 #endif /* __VIR_NETDEV_BANDWIDTH_CONF_H__ */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0864618..1c0cfb1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -509,6 +509,7 @@ virInterfaceRemove;
 # conf/netdev_bandwidth_conf.h
 virNetDevBandwidthFormat;
 virNetDevBandwidthParse;
+virDomainClearNetBandwidth;


 # conf/netdev_vlan_conf.h
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 6a58d50..e418f8e 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -72,6 +72,7 @@
 #include "viraccessapicheck.h"
 #include "viraccessapichecklxc.h"
 #include "virhostdev.h"
+#include "netdev_bandwidth_conf.h"

 #define VIR_FROM_THIS VIR_FROM_LXC

@@ -4212,6 +4213,11 @@ lxcDomainAttachDeviceNetLive(virConnectPtr conn,
                        _("Network device type is not supported"));
         goto cleanup;
     }
+    /* set network bandwidth */
+    if (virNetDevSupportBandwidth(actualType) &&
+        virNetDevBandwidthSet(net->ifname,
+        virDomainNetGetActualBandwidth(net), false) < 0)
+        goto cleanup;

     if (virNetDevSetNamespace(veth, priv->initpid) < 0) {
         virDomainAuditNet(vm, NULL, net, "attach", false);
@@ -4643,6 +4649,8 @@ lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,

     detach = vm->def->nets[detachidx];

+    virDomainClearNetBandwidth(vm);
+
     switch (virDomainNetGetActualType(detach)) {
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
     case VIR_DOMAIN_NET_TYPE_NETWORK:
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index 6c83fdb..77069b9 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -51,6 +51,7 @@
 #include "viratomic.h"
 #include "virprocess.h"
 #include "virsystemd.h"
+#include "netdev_bandwidth_conf.h"

 #define VIR_FROM_THIS VIR_FROM_LXC

@@ -274,11 +275,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 +296,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,14 +326,13 @@ 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)
+            cfg->stateDir, 0) < 0)
         goto cleanup;

     ret = res_ifname;
@@ -368,6 +364,8 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
     int ret = -1;
     size_t i;
     size_t niface = 0;
+    virDomainNetDefPtr net;
+    virDomainNetType type;

     for (i = 0; i < def->nnets; i++) {
         char *veth = NULL;
@@ -375,13 +373,15 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
          * network's pool of devices, or resolve bridge device name
          * to the one defined in the network definition.
          */
-        if (networkAllocateActualDevice(def, def->nets[i]) < 0)
+        net = def->nets[i];
+        if (networkAllocateActualDevice(def, net) < 0)
             goto cleanup;

         if (VIR_EXPAND_N(*veths, *nveths, 1) < 0)
             goto cleanup;

-        switch (virDomainNetGetActualType(def->nets[i])) {
+        type = virDomainNetGetActualType(net);
+        switch (type) {
         case VIR_DOMAIN_NET_TYPE_NETWORK: {
             virNetworkPtr network;
             char *brname = NULL;
@@ -389,7 +389,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
             virErrorPtr errobj;

             if (!(network = virNetworkLookupByName(conn,
-                                                   def->nets[i]->data.network.name)))
+                                                   net->data.network.name)))
                 goto cleanup;
             if (!(brname = virNetworkGetBridgeName(network)))
                fail = true;
@@ -405,7 +405,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,

             if (!(veth = virLXCProcessSetupInterfaceBridged(conn,
                                                             def,
-                                                            def->nets[i],
+                                                            net,
                                                             brname))) {
                 VIR_FREE(brname);
                 goto cleanup;
@@ -414,7 +414,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
             break;
         }
         case VIR_DOMAIN_NET_TYPE_BRIDGE: {
-            const char *brname = virDomainNetGetActualBridgeName(def->nets[i]);
+            const char *brname = virDomainNetGetActualBridgeName(net);
             if (!brname) {
                 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("No bridge name specified"));
@@ -422,7 +422,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
             }
             if (!(veth = virLXCProcessSetupInterfaceBridged(conn,
                                                             def,
-                                                            def->nets[i],
+                                                            net,
                                                             brname)))
                 goto cleanup;
         }   break;
@@ -430,31 +430,39 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
         case VIR_DOMAIN_NET_TYPE_DIRECT:
             if (!(veth = virLXCProcessSetupInterfaceDirect(conn,
                                                            def,
-                                                           def->nets[i])))
+                                                           net)))
                 goto cleanup;
             break;

-        case VIR_DOMAIN_NET_TYPE_USER:
         case VIR_DOMAIN_NET_TYPE_ETHERNET:
+            break;
+
+        case VIR_DOMAIN_NET_TYPE_USER:
         case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
         case VIR_DOMAIN_NET_TYPE_SERVER:
         case VIR_DOMAIN_NET_TYPE_CLIENT:
         case VIR_DOMAIN_NET_TYPE_MCAST:
         case VIR_DOMAIN_NET_TYPE_INTERNAL:
         case VIR_DOMAIN_NET_TYPE_LAST:
+        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Unsupported network type %s"),
-                           virDomainNetTypeToString(
-                               virDomainNetGetActualType(def->nets[i])
-                               ));
+                           virDomainNetTypeToString(type));
             goto cleanup;
+
         }

+        /* set network bandwidth */
+        if (virNetDevSupportBandwidth(type) &&
+            virNetDevBandwidthSet(net->ifname,
+            virDomainNetGetActualBandwidth(net), false) < 0)
+            goto cleanup;
+
         (*veths)[(*nveths)-1] = veth;

         /* Make sure all net definitions will have a name in the container */
-        if (!def->nets[i]->ifname_guest) {
-            if (virAsprintf(&def->nets[i]->ifname_guest, "eth%zu", niface) < 0)
+        if (!net->ifname_guest) {
+            if (virAsprintf(&net->ifname_guest, "eth%zu", niface) < 0)
                 return -1;
             niface++;
         }
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index f674ba9..146f2e2 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -43,6 +43,7 @@
 #include "domain_addr.h"
 #include "domain_audit.h"
 #include "domain_conf.h"
+#include "netdev_bandwidth_conf.h"
 #include "snapshot_conf.h"
 #include "storage_conf.h"
 #include "secret_conf.h"
@@ -192,7 +193,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);
@@ -372,11 +372,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) {
         goto cleanup;
@@ -7499,6 +7494,15 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
             goto cleanup;
     }

+    /* Set Bandwidth */
+    if (net->ifname && strlen(net->ifname)) {
+        if (virNetDevSupportBandwidth(actualType) &&
+            virNetDevBandwidthSet(net->ifname,
+            virDomainNetGetActualBandwidth(net),
+            false) < 0)
+            goto cleanup;
+    }
+
     if ((actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
          actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 13bcd88..d17d860 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -31,6 +31,7 @@
 #include "qemu_command.h"
 #include "qemu_hostdev.h"
 #include "domain_audit.h"
+#include "netdev_bandwidth_conf.h"
 #include "domain_nwfilter.h"
 #include "virlog.h"
 #include "datatypes.h"
@@ -948,6 +949,12 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
             goto cleanup;
     }

+    /* Set Bandwidth */
+    if (virNetDevSupportBandwidth(actualType) &&
+        virNetDevBandwidthSet(net->ifname,
+        virDomainNetGetActualBandwidth(net), false) < 0)
+        goto cleanup;
+
     for (i = 0; i < tapfdSize; i++) {
         if (virSecurityManagerSetTapFDLabel(driver->securityManager,
                                             vm->def, tapfd[i]) < 0)
@@ -3547,6 +3554,11 @@ qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
             goto cleanup;
     }

+    if (virNetDevSupportBandwidth(virDomainNetGetActualType(detach)) &&
+        virNetDevBandwidthClear(detach->ifname) < 0)
+        VIR_WARN("cannot clear bandwidth setting for device : %s",
+                       detach->ifname);
+
     qemuDomainMarkDeviceForRemoval(vm, &detach->info);

     qemuDomainObjEnterMonitor(driver, vm);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 24e5f0f..9c1a417 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -68,6 +68,7 @@
 #include "virhostdev.h"
 #include "storage/storage_driver.h"
 #include "configmake.h"
+#include "netdev_bandwidth_conf.h"

 #define VIR_FROM_THIS VIR_FROM_QEMU

@@ -4842,6 +4843,9 @@ void qemuProcessStop(virQEMUDriverPtr driver,
                       virStrerror(errno, ebuf, sizeof(ebuf)));
     }

+    /* Clear network bandwidth */
+    virDomainClearNetBandwidth(vm);
+
     virDomainConfVMNWFilterTeardown(vm);

     if (cfg->macFilter) {
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;
-- 
1.8.2.3




More information about the libvir-list mailing list