提交 ec6474b2 编写于 作者: M Michal Privoznik

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.
上级 7e5040bd
......@@ -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>
......
......@@ -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"/>
......
......@@ -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)
......
......@@ -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");
......
......@@ -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)
......
......@@ -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);
......
......@@ -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 */
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册