On 12/11/2012 11:09 AM, Michal Privoznik wrote: > 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 c81af8a..8e234fd 100644 > --- a/docs/formatdomain.html.in > +++ b/docs/formatdomain.html.in > @@ -3080,7 +3080,7 @@ qemu-kvm -net nic,model=? /dev/null > <source network='default'/> > <target dev='vnet0'/> > <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'/> > </bandwidth></b> > </interface> > @@ -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><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> > > <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 6aa5f79..18e65ca 100644 > --- a/src/conf/domain_conf.c > +++ b/src/conf/domain_conf.c > @@ -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) > 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 7220659..3093418 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; > } > > @@ -1285,7 +1285,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 */ > }; > ACK. -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list