[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v2 2/8] bandwidth: add new 'floor' attribute



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.

>From now on, the required attribute for <inbound/> is either 'average'
(old) or 'floor' (new). This new attribute can be used just for
interfaces type of network (<interface type='network'/>) currently.
---
 docs/formatdomain.html.in        |   23 +++++++++++--
 docs/schemas/networkcommon.rng   |    5 +++
 src/conf/domain_conf.c           |    6 ++-
 src/conf/netdev_bandwidth_conf.c |   67 ++++++++++++++++++++++++++++++++------
 src/conf/netdev_bandwidth_conf.h |    3 +-
 src/conf/network_conf.c          |    4 +-
 src/util/virnetdevbandwidth.h    |    1 +
 7 files changed, 90 insertions(+), 19 deletions(-)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 0574e68..c5baf27 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3068,7 +3068,7 @@ qemu-kvm -net nic,model=? /dev/null
       &lt;source network='default'/&gt;
       &lt;target dev='vnet0'/&gt;
       <b>&lt;bandwidth&gt;
-        &lt;inbound average='1000' peak='5000' burst='1024'/&gt;
+        &lt;inbound average='1000' peak='5000' floor='200' burst='1024'/&gt;
         &lt;outbound average='128' peak='256' burst='256'/&gt;
       &lt;/bandwidth&gt;</b>
     &lt;/interface&gt;
@@ -3083,14 +3083,29 @@ qemu-kvm -net nic,model=? /dev/null
       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:
+      mandatory attribute <code>average</code> (or <code>floor</code> as
+      described below). <code>average</code> specifies average bit rate on
+      the 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>
+      <span class="since">Since 0.9.4</span> The <code>inbound</code> can
+      optionally have <code>floor</code> attribute. This is there for
+      guaranteeing minimal throughput for shaped interfaces. This, however,
+      requires that all traffic goes through one point where QoS decisions can
+      take place. That's why this attribute works only for virtual networks for
+      now (that is <code>&lt;interface type='network'/&gt;</code> with a
+      forward type of route, nat, or no forward at all). Moreover, the
+      virtual network the interface is connected to is required to have at least
+      inbound QoS set (<code>average</code> at least). Moreover, with
+      <code>floor<code> attribute users don't need to specify
+      <code>average</code>. However, <code>peak</code> and <code>burst</code>
+      attributes still require <code>average</code>. Currently, linux kernel
+      doesn't allow ingress qdiscs to have any classes therefore
+      <code>floor</code> can be applied only on <code>inbound</code> and not
+      </code>outbound</code>. <span class="since">Since 1.0.1</span>
     </p>
 
     <h5><a name="elementVlanTag">Setting VLAN tag (on supported network types only)</a></h5>
diff --git a/docs/schemas/networkcommon.rng b/docs/schemas/networkcommon.rng
index c7749e7..51ff759 100644
--- a/docs/schemas/networkcommon.rng
+++ b/docs/schemas/networkcommon.rng
@@ -149,6 +149,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 4ffb39d..99aa08d 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -4781,7 +4781,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;
 
     vlanNode = virXPathNode("./vlan", ctxt);
@@ -4969,7 +4970,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
                     goto error;
                 }
             } else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
-                if (!(def->bandwidth = virNetDevBandwidthParse(cur)))
+                if (!(def->bandwidth = virNetDevBandwidthParse(cur,
+                                                               def->type)))
                     goto error;
             } else if (xmlStrEqual(cur->name, BAD_CAST "vlan")) {
                 if (virNetDevVlanParse(cur, ctxt, &def->vlan) < 0)
diff --git a/src/conf/netdev_bandwidth_conf.c b/src/conf/netdev_bandwidth_conf.c
index 5802eba..15840b9 100644
--- a/src/conf/netdev_bandwidth_conf.c
+++ b/src/conf/netdev_bandwidth_conf.c
@@ -26,6 +26,7 @@
 #include "virterror_internal.h"
 #include "util.h"
 #include "memory.h"
+#include "domain_conf.h"
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 
@@ -36,6 +37,7 @@ virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
     char *average = NULL;
     char *peak = NULL;
     char *burst = NULL;
+    char *floor = NULL;
 
     if (!node || !rate) {
         virReportError(VIR_ERR_INVALID_ARG, "%s",
@@ -46,40 +48,55 @@ virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
     average = virXMLPropString(node, "average");
     peak = virXMLPropString(node, "peak");
     burst = virXMLPropString(node, "burst");
+    floor = virXMLPropString(node, "floor");
 
     if (average) {
         if (virStrToLong_ull(average, NULL, 10, &rate->average) < 0) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                           _("could not convert %s"),
+                           _("could not convert bandwidth average value '%s'"),
                            average);
             goto cleanup;
         }
-    } else {
+    } else if (!floor) {
         virReportError(VIR_ERR_XML_DETAIL, "%s",
-                       _("Missing mandatory average attribute"));
+                       _("Missing mandatory average or floor attributes"));
+        goto cleanup;
+    }
+
+    if ((peak || burst) && !average) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("'peak' and 'burst' require 'average' attribute"));
         goto cleanup;
     }
 
     if (peak && virStrToLong_ull(peak, NULL, 10, &rate->peak) < 0) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("could not convert %s"),
+                       _("could not convert bandwidth peak value '%s'"),
                        peak);
         goto cleanup;
     }
 
     if (burst && virStrToLong_ull(burst, NULL, 10, &rate->burst) < 0) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("could not convert %s"),
+                       _("could not convert bandwidth burst value '%s'"),
                        burst);
         goto cleanup;
     }
 
+    if (floor && virStrToLong_ull(floor, NULL, 10, &rate->floor) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("could not convert bandwidth floor value '%s'"),
+                       floor);
+        goto cleanup;
+    }
+
     ret = 0;
 
 cleanup:
     VIR_FREE(average);
     VIR_FREE(peak);
     VIR_FREE(burst);
+    VIR_FREE(floor);
 
     return ret;
 }
@@ -87,13 +104,17 @@ cleanup:
 /**
  * virNetDevBandwidthParse:
  * @node: XML node
+ * @net_type: one of virDomainNetType
  *
- * Parse bandwidth XML and return pointer to structure
+ * Parse bandwidth XML and return pointer to structure.
+ * @net_type tell to which type will/is interface connected to.
+ * Pass -1 if this is not called on interface.
  *
  * Returns !NULL on success, NULL on error.
  */
 virNetDevBandwidthPtr
-virNetDevBandwidthParse(xmlNodePtr node)
+virNetDevBandwidthParse(xmlNodePtr node,
+                        int net_type)
 {
     virNetDevBandwidthPtr def = NULL;
     xmlNodePtr cur;
@@ -146,6 +167,20 @@ virNetDevBandwidthParse(xmlNodePtr node)
             /* helper reported error for us */
             goto error;
         }
+
+        if (def->in->floor && net_type != VIR_DOMAIN_NET_TYPE_NETWORK) {
+            if (net_type == -1) {
+                /* 'floor' on network isn't supported */
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("floor attribute isn't supported for "
+                                 "network's bandwidth yet"));
+            } else {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("floor attribute is supported only for "
+                                 "interfaces of type network"));
+            }
+            goto error;
+        }
     }
 
     if (out) {
@@ -158,6 +193,13 @@ virNetDevBandwidthParse(xmlNodePtr node)
             /* helper reported error for us */
             goto error;
         }
+
+        if (def->out->floor) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("'floor' attribute allowed "
+                             "only in <inbound> element"));
+            goto error;
+        }
     }
 
     return def;
@@ -177,13 +219,18 @@ 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 bca5c50..0080165 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 6ce2e63..2cb9e81 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1192,7 +1192,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;
     }
 
@@ -1268,7 +1268,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;
 
     vlanNode = virXPathNode("./vlan", ctxt);
diff --git a/src/util/virnetdevbandwidth.h b/src/util/virnetdevbandwidth.h
index e046230..35f8b89 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.8.6


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]