]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
bandwidth: add new 'floor' attribute
authorMichal Privoznik <mprivozn@redhat.com>
Fri, 16 Nov 2012 09:37:15 +0000 (10:37 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 11 Dec 2012 17:35:12 +0000 (18:35 +0100)
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
docs/schemas/networkcommon.rng
src/conf/domain_conf.c
src/conf/netdev_bandwidth_conf.c
src/conf/netdev_bandwidth_conf.h
src/conf/network_conf.c
src/util/virnetdevbandwidth.h

index c81af8a892e71e55cfbe9318df3fc4565f73b93f..8e234fd885e3a0bede73270dde8ccda907a4fabe 100644 (file)
@@ -3080,7 +3080,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;
@@ -3095,14 +3095,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>
index c7749e71863922137271f85ea476207857b7d225..51ff7592ea0e6eb97ca203df75d505a4b7db0a76 100644 (file)
         <ref name="speed"/>
       </attribute>
     </optional>
+    <optional>
+      <attribute name="floor">
+        <ref name="speed"/>
+      </attribute>
+    </optional>
     <optional>
       <attribute name='burst'>
         <ref name="BurstSize"/>
index 6aa5f79ca3d908f95fc7850d11ab383cfedd7af1..18e65ca834b2b44adc081a165d74a3f4de289ed1 100644 (file)
@@ -4823,7 +4823,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);
@@ -5011,7 +5012,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)
index 5802eba1225d7db671b4474ffd297e7efb25acb3..15840b92d163c48d65a9c51cd16e9f7579c91e23 100644 (file)
@@ -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");
index bca5c50c7b595501414dd6bf224e4dfc9eaaf9eb..00801652329e9ae986442b3a5205d379cdac41ad 100644 (file)
@@ -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)
index f9bc37138b02d52fc183cf90e7b92ef6b00b04ea..ab148926e93aff2c54d33bbd70be093aece9c43d 100644 (file)
@@ -1286,7 +1286,7 @@ virNetworkPortGroupParseXML(virPortGroupDefPtr def,
 
     bandwidth_node = virXPathNode("./bandwidth", ctxt);
     if (bandwidth_node &&
-        !(def->bandwidth = virNetDevBandwidthParse(bandwidth_node))) {
+        !(def->bandwidth = virNetDevBandwidthParse(bandwidth_node, -1))) {
         goto cleanup;
     }
 
@@ -1578,7 +1578,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);
index e0462309f4462e0293e2d04768b761522c55f671..35f8b89cb2e80bc6135c6e213fdf423f913428a8 100644 (file)
@@ -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 */
 };