[libvirt] [PATCH 1/6] bandwidth: add new 'floor' attribute

Michal Privoznik mprivozn at redhat.com
Fri Dec 9 18:29:46 UTC 2011


This is however supported only on domain interfaces with
type='network'. Moreover, target network needs to have at least
inbound QoS set. This is required by hierarchical traffic shaping.
---
 docs/formatdomain.html.in        |   21 ++++++++--
 docs/schemas/networkcommon.rng   |    5 ++
 src/conf/domain_conf.c           |    6 ++-
 src/conf/netdev_bandwidth_conf.c |   81 ++++++++++++++++++++++++++++++--------
 src/conf/netdev_bandwidth_conf.h |    3 +-
 src/conf/network_conf.c          |    4 +-
 src/util/virnetdevbandwidth.c    |    2 +-
 src/util/virnetdevbandwidth.h    |    1 +
 8 files changed, 96 insertions(+), 27 deletions(-)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index f9dbcda..2e9a8e2 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2311,7 +2311,7 @@ qemu-kvm -net nic,model=? /dev/null
       <source network='default'/>
       <target dev='vnet0'/>
       <b><bandwidth>
-        <inbound average='1000' peak='5000' burst='1024'/>
+        <inbound average='1000' peak='5000' floor='200' burst='1024'/>
         <outbound average='128' peak='256' burst='256'/>
       </bandwidth></b>
     </interface>
@@ -2325,15 +2325,28 @@ qemu-kvm -net nic,model=? /dev/null
       and at most one <code>outbound</code> child elements. Leaving any of these
       children element out result in no QoS applied on that traffic direction.
       So, when you want to shape only domain's incoming traffic, use
-      <code>inbound</code> only, and vice versa. Each of these elements have one
-      mandatory attribute <code>average</code>. It specifies average bit rate on
-      interface being shaped. Then there are two optional attributes:
+      <code>inbound</code> only, and vice versa. For <code>outbound</code>
+      element <code>average</code> is mandatory. However, <code>inbound</code>
+      can satisfied with <code>floor</code> (iff interface's type='network' and
+      source network has inbound shaping set) or <code>average</code> (if you
+      want to set at least one of <code>peak</code>, <code>burst</code>).
+      <code>average</code> specifies average bit rate on interface being shaped.
+      Then there are two optional attributes:
       <code>peak</code>, which specifies maximum rate at which interface can send
       data, and <code>burst</code>, amount of bytes that can be burst at
       <code>peak</code> speed. Accepted values for attributes are integer
       numbers. The units for <code>average</code> and <code>peak</code> attributes
       are kilobytes per second, and for the <code>burst</code> just kilobytes.
       <span class="since">Since 0.9.4</span>
+      <code>floor</code> attribute tells libvirt to set hierarchical classes,
+      so interfaces can share unused bandwidth and have guaranteed rate at
+      the same time. But to be able to do this, we need traffic to go through
+      one point which can then borrow unused bandwidth to all currently
+      transmitting interfaces. Therefore, it required that interface is 'network'
+      type and source network have inbound QoS set. Be aware, libvirt does
+      not check if sum of <code>floor</code> on interfaces connected to a network
+      does not exceed network <code>peak</code>.
+      <span class="since">Since 0.9.9</span>
     </p>
 
     <h5><a name="elementLink">Modyfing virtual link state</a></h5>
diff --git a/docs/schemas/networkcommon.rng b/docs/schemas/networkcommon.rng
index 3a168c3..cc1732c 100644
--- a/docs/schemas/networkcommon.rng
+++ b/docs/schemas/networkcommon.rng
@@ -77,6 +77,11 @@
       </attribute>
     </optional>
     <optional>
+      <attribute name="floor">
+          <ref name="speed"/>
+      </attribute>
+    </optional>
+    <optional>
       <attribute name='burst'>
         <ref name="BurstSize"/>
       </attribute>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 75e51a0..ebd0473 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -3370,7 +3370,8 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
 
     bandwidth_node = virXPathNode("./bandwidth", ctxt);
     if (bandwidth_node &&
-        !(actual->bandwidth = virNetDevBandwidthParse(bandwidth_node)))
+        !(actual->bandwidth = virNetDevBandwidthParse(bandwidth_node,
+                                                      actual->type)))
         goto error;
 
     *def = actual;
@@ -3528,7 +3529,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
                 if (virDomainActualNetDefParseXML(cur, ctxt, &actual) < 0)
                     goto error;
             } else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
-                if (!(def->bandwidth = virNetDevBandwidthParse(cur)))
+                if (!(def->bandwidth = virNetDevBandwidthParse(cur,
+                                                               def->type)))
                     goto error;
             }
         }
diff --git a/src/conf/netdev_bandwidth_conf.c b/src/conf/netdev_bandwidth_conf.c
index 24cd13d..21e5ac6 100644
--- a/src/conf/netdev_bandwidth_conf.c
+++ b/src/conf/netdev_bandwidth_conf.c
@@ -26,19 +26,28 @@
 #include "virterror_internal.h"
 #include "util.h"
 #include "memory.h"
+#include "domain_conf.h"
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 #define virNetDevError(code, ...)                                   \
     virReportErrorHelper(VIR_FROM_THIS, code, __FILE__,             \
                          __FUNCTION__, __LINE__, __VA_ARGS__)
 
+enum virNetDevBandwidthElem {
+    VIR_NET_DEV_BANDWIDTH_ELEM_INBOUND,
+    VIR_NET_DEV_BANDWIDTH_ELEM_OUTBOUND
+};
 
 static int
-virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
+virNetDevBandwidthParseRate(xmlNodePtr node,
+                            virNetDevBandwidthRatePtr rate,
+                            int elem_type,
+                            int net_type)
 {
     int ret = -1;
     char *average = NULL;
     char *peak = NULL;
+    char *floor = NULL;
     char *burst = NULL;
 
     if (!node || !rate) {
@@ -49,18 +58,32 @@ virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
 
     average = virXMLPropString(node, "average");
     peak = virXMLPropString(node, "peak");
+    floor = virXMLPropString(node, "floor");
     burst = virXMLPropString(node, "burst");
 
-    if (average) {
-        if (virStrToLong_ull(average, NULL, 10, &rate->average) < 0) {
-            virNetDevError(VIR_ERR_CONFIG_UNSUPPORTED,
-                           _("could not convert %s"),
-                           average);
-            goto cleanup;
-        }
-    } else {
+    if (!average && !floor) {
+        virNetDevError(VIR_ERR_XML_DETAIL, "%s",
+                       _("Missing 'average' or 'floor' attribute"));
+        goto cleanup;
+    }
+
+    if (!average && (peak || burst)) {
         virNetDevError(VIR_ERR_XML_DETAIL, "%s",
-                       _("Missing mandatory average attribute"));
+                       _("'peak' and 'burst' require 'average' attribute"));
+        goto cleanup;
+    }
+
+    if (floor && elem_type != VIR_NET_DEV_BANDWIDTH_ELEM_INBOUND &&
+        net_type != VIR_DOMAIN_NET_TYPE_NETWORK) {
+        virNetDevError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("'floor' is not supported in this context"));
+        goto cleanup;
+    }
+
+    if (average && virStrToLong_ull(average, NULL, 10, &rate->average) < 0) {
+        virNetDevError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("could not convert %s"),
+                       average);
         goto cleanup;
     }
 
@@ -71,6 +94,13 @@ virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
         goto cleanup;
     }
 
+    if (floor && virStrToLong_ull(floor, NULL, 10, &rate->floor) < 0) {
+        virNetDevError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("could not convert %s"),
+                       floor);
+        goto cleanup;
+    }
+
     if (burst && virStrToLong_ull(burst, NULL, 10, &rate->burst) < 0) {
         virNetDevError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("could not convert %s"),
@@ -83,6 +113,7 @@ virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
 cleanup:
     VIR_FREE(average);
     VIR_FREE(peak);
+    VIR_FREE(floor);
     VIR_FREE(burst);
 
     return ret;
@@ -91,13 +122,21 @@ cleanup:
 /**
  * virNetDevBandwidthParse:
  * @node: XML node
+ * @net_type: type of network interface is connected to
  *
- * Parse bandwidth XML and return pointer to structure
+ * Parse bandwidth XML and return pointer to structure.
+ * If interface is not connected to any network (e.g.
+ * it is a bridge), -1 must be passed. This is needed as
+ * some attributes are available only in some contexts,
+ * e.g. 'floor' only in
+ * "/domain/devices/interface[@type='network']/
+ * bandwidth/inbound"
  *
  * Returns !NULL on success, NULL on error.
  */
 virNetDevBandwidthPtr
-virNetDevBandwidthParse(xmlNodePtr node)
+virNetDevBandwidthParse(xmlNodePtr node,
+                        int net_type)
 {
     virNetDevBandwidthPtr def = NULL;
     xmlNodePtr cur = node->children;
@@ -144,7 +183,9 @@ virNetDevBandwidthParse(xmlNodePtr node)
             goto error;
         }
 
-        if (virNetDevBandwidthParseRate(in, def->in) < 0) {
+        if (virNetDevBandwidthParseRate(in, def->in,
+                                        VIR_NET_DEV_BANDWIDTH_ELEM_INBOUND,
+                                        net_type) < 0) {
             /* helper reported error for us */
             goto error;
         }
@@ -156,7 +197,9 @@ virNetDevBandwidthParse(xmlNodePtr node)
             goto error;
         }
 
-        if (virNetDevBandwidthParseRate(out, def->out) < 0) {
+        if (virNetDevBandwidthParseRate(out, def->out,
+                                        VIR_NET_DEV_BANDWIDTH_ELEM_OUTBOUND,
+                                        net_type) < 0) {
             /* helper reported error for us */
             goto error;
         }
@@ -179,13 +222,17 @@ virNetDevBandwidthRateFormat(virNetDevBandwidthRatePtr def,
     if (!def)
         return 0;
 
-    if (def->average) {
-        virBufferAsprintf(buf, "  <%s average='%llu'", elem_name,
-                          def->average);
+    if (def->average || def->floor) {
+        virBufferAsprintf(buf, "  <%s", elem_name);
+        if (def->average)
+            virBufferAsprintf(buf, " average='%llu'", def->average);
 
         if (def->peak)
             virBufferAsprintf(buf, " peak='%llu'", def->peak);
 
+        if (def->floor)
+            virBufferAsprintf(buf, " floor='%llu'", def->floor);
+
         if (def->burst)
             virBufferAsprintf(buf, " burst='%llu'", def->burst);
         virBufferAddLit(buf, "/>\n");
diff --git a/src/conf/netdev_bandwidth_conf.h b/src/conf/netdev_bandwidth_conf.h
index 4bb7def..8ad6176 100644
--- a/src/conf/netdev_bandwidth_conf.h
+++ b/src/conf/netdev_bandwidth_conf.h
@@ -28,7 +28,8 @@
 # include "buf.h"
 # include "xml.h"
 
-virNetDevBandwidthPtr virNetDevBandwidthParse(xmlNodePtr node)
+virNetDevBandwidthPtr virNetDevBandwidthParse(xmlNodePtr node,
+                                              int net_type)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
 int virNetDevBandwidthFormat(virNetDevBandwidthPtr def,
                              virBufferPtr buf)
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 1058b07..949cea8 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -796,7 +796,7 @@ virNetworkPortGroupParseXML(virPortGroupDefPtr def,
 
     bandwidth_node = virXPathNode("./bandwidth", ctxt);
     if (bandwidth_node &&
-        !(def->bandwidth = virNetDevBandwidthParse(bandwidth_node))) {
+        !(def->bandwidth = virNetDevBandwidthParse(bandwidth_node, -1))) {
         goto error;
     }
 
@@ -862,7 +862,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
     def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
 
     if ((bandwidthNode = virXPathNode("./bandwidth", ctxt)) != NULL &&
-        (def->bandwidth = virNetDevBandwidthParse(bandwidthNode)) == NULL)
+        (def->bandwidth = virNetDevBandwidthParse(bandwidthNode, -1)) == NULL)
         goto error;
 
     /* Parse bridge information */
diff --git a/src/util/virnetdevbandwidth.c b/src/util/virnetdevbandwidth.c
index b9bd2e3..d23d600 100644
--- a/src/util/virnetdevbandwidth.c
+++ b/src/util/virnetdevbandwidth.c
@@ -72,7 +72,7 @@ virNetDevBandwidthSet(const char *ifname,
 
     ignore_value(virNetDevBandwidthClear(ifname));
 
-    if (bandwidth->in) {
+    if (bandwidth->in && bandwidth->in->average) {
         if (virAsprintf(&average, "%llukbps", bandwidth->in->average) < 0)
             goto cleanup;
         if (bandwidth->in->peak &&
diff --git a/src/util/virnetdevbandwidth.h b/src/util/virnetdevbandwidth.h
index 58decff..8551caa 100644
--- a/src/util/virnetdevbandwidth.h
+++ b/src/util/virnetdevbandwidth.h
@@ -30,6 +30,7 @@ typedef virNetDevBandwidthRate *virNetDevBandwidthRatePtr;
 struct _virNetDevBandwidthRate {
     unsigned long long average;  /* kbytes/s */
     unsigned long long peak;     /* kbytes/s */
+    unsigned long long floor;    /* kbytes/s */
     unsigned long long burst;    /* kbytes */
 };
 
-- 
1.7.3.4




More information about the libvir-list mailing list