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.
This commit is contained in:
Michal Privoznik 2012-11-16 10:37:15 +01:00
parent 7e5040bd20
commit ec6474b245
7 changed files with 90 additions and 19 deletions

View 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>

View File

@ -148,6 +148,11 @@
<ref name="speed"/>
</attribute>
</optional>
<optional>
<attribute name="floor">
<ref name="speed"/>
</attribute>
</optional>
<optional>
<attribute name='burst'>
<ref name="BurstSize"/>

View 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)

View 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");

View 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)

View 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);

View 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 */
};