mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-10 14:57:42 +00:00
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:
parent
7e5040bd20
commit
ec6474b245
@ -3080,7 +3080,7 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
<source network='default'/>
|
<source network='default'/>
|
||||||
<target dev='vnet0'/>
|
<target dev='vnet0'/>
|
||||||
<b><bandwidth>
|
<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'/>
|
<outbound average='128' peak='256' burst='256'/>
|
||||||
</bandwidth></b>
|
</bandwidth></b>
|
||||||
</interface>
|
</interface>
|
||||||
@ -3095,14 +3095,29 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
children element out result in no QoS applied on that traffic direction.
|
children element out result in no QoS applied on that traffic direction.
|
||||||
So, when you want to shape only domain's incoming traffic, use
|
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
|
<code>inbound</code> only, and vice versa. Each of these elements have one
|
||||||
mandatory attribute <code>average</code>. It specifies average bit rate on
|
mandatory attribute <code>average</code> (or <code>floor</code> as
|
||||||
interface being shaped. Then there are two optional attributes:
|
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
|
<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
|
data, and <code>burst</code>, amount of bytes that can be burst at
|
||||||
<code>peak</code> speed. Accepted values for attributes are integer
|
<code>peak</code> speed. Accepted values for attributes are integer
|
||||||
numbers. The units for <code>average</code> and <code>peak</code> attributes
|
numbers. The units for <code>average</code> and <code>peak</code> attributes
|
||||||
are kilobytes per second, and for the <code>burst</code> just kilobytes.
|
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><interface type='network'/></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>
|
</p>
|
||||||
|
|
||||||
<h5><a name="elementVlanTag">Setting VLAN tag (on supported network types only)</a></h5>
|
<h5><a name="elementVlanTag">Setting VLAN tag (on supported network types only)</a></h5>
|
||||||
|
@ -148,6 +148,11 @@
|
|||||||
<ref name="speed"/>
|
<ref name="speed"/>
|
||||||
</attribute>
|
</attribute>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<attribute name="floor">
|
||||||
|
<ref name="speed"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
<optional>
|
<optional>
|
||||||
<attribute name='burst'>
|
<attribute name='burst'>
|
||||||
<ref name="BurstSize"/>
|
<ref name="BurstSize"/>
|
||||||
|
@ -4823,7 +4823,8 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
|
|||||||
|
|
||||||
bandwidth_node = virXPathNode("./bandwidth", ctxt);
|
bandwidth_node = virXPathNode("./bandwidth", ctxt);
|
||||||
if (bandwidth_node &&
|
if (bandwidth_node &&
|
||||||
!(actual->bandwidth = virNetDevBandwidthParse(bandwidth_node)))
|
!(actual->bandwidth = virNetDevBandwidthParse(bandwidth_node,
|
||||||
|
actual->type)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
vlanNode = virXPathNode("./vlan", ctxt);
|
vlanNode = virXPathNode("./vlan", ctxt);
|
||||||
@ -5011,7 +5012,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
|
} else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
|
||||||
if (!(def->bandwidth = virNetDevBandwidthParse(cur)))
|
if (!(def->bandwidth = virNetDevBandwidthParse(cur,
|
||||||
|
def->type)))
|
||||||
goto error;
|
goto error;
|
||||||
} else if (xmlStrEqual(cur->name, BAD_CAST "vlan")) {
|
} else if (xmlStrEqual(cur->name, BAD_CAST "vlan")) {
|
||||||
if (virNetDevVlanParse(cur, ctxt, &def->vlan) < 0)
|
if (virNetDevVlanParse(cur, ctxt, &def->vlan) < 0)
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "virterror_internal.h"
|
#include "virterror_internal.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "domain_conf.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
|
|||||||
char *average = NULL;
|
char *average = NULL;
|
||||||
char *peak = NULL;
|
char *peak = NULL;
|
||||||
char *burst = NULL;
|
char *burst = NULL;
|
||||||
|
char *floor = NULL;
|
||||||
|
|
||||||
if (!node || !rate) {
|
if (!node || !rate) {
|
||||||
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||||
@ -46,40 +48,55 @@ virNetDevBandwidthParseRate(xmlNodePtr node, virNetDevBandwidthRatePtr rate)
|
|||||||
average = virXMLPropString(node, "average");
|
average = virXMLPropString(node, "average");
|
||||||
peak = virXMLPropString(node, "peak");
|
peak = virXMLPropString(node, "peak");
|
||||||
burst = virXMLPropString(node, "burst");
|
burst = virXMLPropString(node, "burst");
|
||||||
|
floor = virXMLPropString(node, "floor");
|
||||||
|
|
||||||
if (average) {
|
if (average) {
|
||||||
if (virStrToLong_ull(average, NULL, 10, &rate->average) < 0) {
|
if (virStrToLong_ull(average, NULL, 10, &rate->average) < 0) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("could not convert %s"),
|
_("could not convert bandwidth average value '%s'"),
|
||||||
average);
|
average);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!floor) {
|
||||||
virReportError(VIR_ERR_XML_DETAIL, "%s",
|
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;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peak && virStrToLong_ull(peak, NULL, 10, &rate->peak) < 0) {
|
if (peak && virStrToLong_ull(peak, NULL, 10, &rate->peak) < 0) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("could not convert %s"),
|
_("could not convert bandwidth peak value '%s'"),
|
||||||
peak);
|
peak);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (burst && virStrToLong_ull(burst, NULL, 10, &rate->burst) < 0) {
|
if (burst && virStrToLong_ull(burst, NULL, 10, &rate->burst) < 0) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("could not convert %s"),
|
_("could not convert bandwidth burst value '%s'"),
|
||||||
burst);
|
burst);
|
||||||
goto cleanup;
|
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;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(average);
|
VIR_FREE(average);
|
||||||
VIR_FREE(peak);
|
VIR_FREE(peak);
|
||||||
VIR_FREE(burst);
|
VIR_FREE(burst);
|
||||||
|
VIR_FREE(floor);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -87,13 +104,17 @@ cleanup:
|
|||||||
/**
|
/**
|
||||||
* virNetDevBandwidthParse:
|
* virNetDevBandwidthParse:
|
||||||
* @node: XML node
|
* @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.
|
* Returns !NULL on success, NULL on error.
|
||||||
*/
|
*/
|
||||||
virNetDevBandwidthPtr
|
virNetDevBandwidthPtr
|
||||||
virNetDevBandwidthParse(xmlNodePtr node)
|
virNetDevBandwidthParse(xmlNodePtr node,
|
||||||
|
int net_type)
|
||||||
{
|
{
|
||||||
virNetDevBandwidthPtr def = NULL;
|
virNetDevBandwidthPtr def = NULL;
|
||||||
xmlNodePtr cur;
|
xmlNodePtr cur;
|
||||||
@ -146,6 +167,20 @@ virNetDevBandwidthParse(xmlNodePtr node)
|
|||||||
/* helper reported error for us */
|
/* helper reported error for us */
|
||||||
goto error;
|
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) {
|
if (out) {
|
||||||
@ -158,6 +193,13 @@ virNetDevBandwidthParse(xmlNodePtr node)
|
|||||||
/* helper reported error for us */
|
/* helper reported error for us */
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (def->out->floor) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("'floor' attribute allowed "
|
||||||
|
"only in <inbound> element"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return def;
|
return def;
|
||||||
@ -177,13 +219,18 @@ virNetDevBandwidthRateFormat(virNetDevBandwidthRatePtr def,
|
|||||||
if (!def)
|
if (!def)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (def->average) {
|
if (def->average || def->floor) {
|
||||||
virBufferAsprintf(buf, " <%s average='%llu'", elem_name,
|
virBufferAsprintf(buf, " <%s", elem_name);
|
||||||
def->average);
|
|
||||||
|
if (def->average)
|
||||||
|
virBufferAsprintf(buf, " average='%llu'", def->average);
|
||||||
|
|
||||||
if (def->peak)
|
if (def->peak)
|
||||||
virBufferAsprintf(buf, " peak='%llu'", def->peak);
|
virBufferAsprintf(buf, " peak='%llu'", def->peak);
|
||||||
|
|
||||||
|
if (def->floor)
|
||||||
|
virBufferAsprintf(buf, " floor='%llu'", def->floor);
|
||||||
|
|
||||||
if (def->burst)
|
if (def->burst)
|
||||||
virBufferAsprintf(buf, " burst='%llu'", def->burst);
|
virBufferAsprintf(buf, " burst='%llu'", def->burst);
|
||||||
virBufferAddLit(buf, "/>\n");
|
virBufferAddLit(buf, "/>\n");
|
||||||
|
@ -28,7 +28,8 @@
|
|||||||
# include "buf.h"
|
# include "buf.h"
|
||||||
# include "xml.h"
|
# include "xml.h"
|
||||||
|
|
||||||
virNetDevBandwidthPtr virNetDevBandwidthParse(xmlNodePtr node)
|
virNetDevBandwidthPtr virNetDevBandwidthParse(xmlNodePtr node,
|
||||||
|
int net_type)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||||
int virNetDevBandwidthFormat(virNetDevBandwidthPtr def,
|
int virNetDevBandwidthFormat(virNetDevBandwidthPtr def,
|
||||||
virBufferPtr buf)
|
virBufferPtr buf)
|
||||||
|
@ -1286,7 +1286,7 @@ virNetworkPortGroupParseXML(virPortGroupDefPtr def,
|
|||||||
|
|
||||||
bandwidth_node = virXPathNode("./bandwidth", ctxt);
|
bandwidth_node = virXPathNode("./bandwidth", ctxt);
|
||||||
if (bandwidth_node &&
|
if (bandwidth_node &&
|
||||||
!(def->bandwidth = virNetDevBandwidthParse(bandwidth_node))) {
|
!(def->bandwidth = virNetDevBandwidthParse(bandwidth_node, -1))) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1578,7 +1578,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
|
|||||||
def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
|
def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
|
||||||
|
|
||||||
if ((bandwidthNode = virXPathNode("./bandwidth", ctxt)) != NULL &&
|
if ((bandwidthNode = virXPathNode("./bandwidth", ctxt)) != NULL &&
|
||||||
(def->bandwidth = virNetDevBandwidthParse(bandwidthNode)) == NULL)
|
(def->bandwidth = virNetDevBandwidthParse(bandwidthNode, -1)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
vlanNode = virXPathNode("./vlan", ctxt);
|
vlanNode = virXPathNode("./vlan", ctxt);
|
||||||
|
@ -30,6 +30,7 @@ typedef virNetDevBandwidthRate *virNetDevBandwidthRatePtr;
|
|||||||
struct _virNetDevBandwidthRate {
|
struct _virNetDevBandwidthRate {
|
||||||
unsigned long long average; /* kbytes/s */
|
unsigned long long average; /* kbytes/s */
|
||||||
unsigned long long peak; /* kbytes/s */
|
unsigned long long peak; /* kbytes/s */
|
||||||
|
unsigned long long floor; /* kbytes/s */
|
||||||
unsigned long long burst; /* kbytes */
|
unsigned long long burst; /* kbytes */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user