Pushed. NOTE: I squashed out some trailing whitespace in the files touched by
this patch.
On 12/30/2011 03:35 PM, Chip Vincent wrote:
Looks good. +1.
On 12/30/2011 07:54 AM, Gareth S Bestor wrote:
> From: Gareth S. Bestor<bestor(a)us.ibm.com>
>
> This patch updates the earlier patch to libvirt-cim for network bandwidth QOS
> support. Previous patch had to perform all external host 'tc' (traffic
control)
> commands from within libvirt-cim providers, because earlier versions of
> libvirt lacked native QoS support. libvirt 0.9.4 added native QoS support;
> this new patch for libvirt-cim removes earlier QoS hacks in favor of directly
> exploiting libvirt equivalent QoS function and configuration. Note, libvirt
> supports three tunables for network bandwidth QoS: average, peak and burst,
> for both inbound and outbound traffic independently.
> This revised libvirt-cim patch only exposes - as previously - inbound traffic
> QoS, but adds peak to previous average tunable support.
> Selection of earlier (libvirt-cim QoS hack) vs latter (native libvirt QoS)
> is done at compile-time based on libvirt version being built against.
> As previously, QoS capabilites are exposed on the virtual network pool, and
> the QoS setting for a specific guest's NIC are exposed on the associated
> network device RASD. QoS settings may be specified during guest creation
> (DefineSystem) or guest modification (ModifyResourceSettings).
>
> Signed-off-by: Gareth S. Bestor<bestor(a)us.ibm.com>
> ---
> libxkutil/device_parsing.c | 34 +++++++++++++++++++++
> libxkutil/device_parsing.h | 2 +
> libxkutil/xmlgen.c | 39 ++++++++++++++++++++++++
> src/Virt_RASD.c | 33 ++++++++++++++++++--
> src/Virt_SettingsDefineCapabilities.c | 47 +++++++++++++++++++++++++----
> src/Virt_VirtualSystemManagementService.c | 22 +++++++++++++-
> 6 files changed, 166 insertions(+), 11 deletions(-)
>
> diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c
> index 371838f..7eaa63e 100644
> --- a/libxkutil/device_parsing.c
> +++ b/libxkutil/device_parsing.c
> @@ -444,7 +444,39 @@ static int parse_net_device(xmlNode *inode, struct
> virt_device **vdevs)
> ndev->filter_ref = get_attr_value(child,
"filter");
> } else if (XSTREQ(child->name, "virtualport")) {
> parse_vsi_device(child, ndev);
> +#if LIBVIR_VERSION_NUMBER>= 9000
> + } else if (XSTREQ(child->name, "bandwidth")) {
> + /* Network QoS bandwidth support */
> + xmlNode *grandchild = NULL;
> + for (grandchild = child->children;
> + grandchild != NULL;
> + grandchild = grandchild->next) {
> + if (XSTREQ(grandchild->name,
"inbound")) {
> + /* Only expose inbound bandwidth */
> + char *val;
> +
> + val = get_attr_value(grandchild,
> +
"average");
> + if (val != NULL) {
> + sscanf(val, "%" PRIu64,
> +&ndev->reservation);
> + free(val);
> + } else
> + ndev->reservation = 0;
> +
> + val = get_attr_value(grandchild,
> + "peak");
> + if (val != NULL) {
> + sscanf(val, "%" PRIu64,
> +&ndev->limit);
> + free(val);
> + } else
> + ndev->limit = 0;
> + break;
> + }
> + }
> }
> +#endif
>
> }
>
> @@ -861,6 +893,8 @@ struct virt_device *virt_device_dup(struct virt_device
> *_dev)
> DUP_FIELD(dev, _dev, dev.net.vsi.instance_id);
> DUP_FIELD(dev, _dev, dev.net.vsi.filter_ref);
> DUP_FIELD(dev, _dev, dev.net.vsi.profile_id);
> + dev->dev.net.reservation = _dev->dev.net.reservation;
> + dev->dev.net.limit = _dev->dev.net.limit;
> } else if (dev->type == CIM_RES_TYPE_DISK) {
> DUP_FIELD(dev, _dev, dev.disk.type);
> DUP_FIELD(dev, _dev, dev.disk.device);
> diff --git a/libxkutil/device_parsing.h b/libxkutil/device_parsing.h
> index ab104d9..f24268b 100644
> --- a/libxkutil/device_parsing.h
> +++ b/libxkutil/device_parsing.h
> @@ -66,6 +66,8 @@ struct net_device {
> char *device;
> char *net_mode;
> char *filter_ref;
> + uint64_t reservation;
> + uint64_t limit;
> struct vsi_device vsi;
> };
>
> diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c
> index aae1e51..638cffe 100644
> --- a/libxkutil/xmlgen.c
> +++ b/libxkutil/xmlgen.c
> @@ -320,6 +320,45 @@ static const char *net_xml(xmlNodePtr root, struct
> domain *dominfo)
> BAD_CAST net->filter_ref);
> }
>
> +#if LIBVIR_VERSION_NUMBER>= 9000
> + /* Network QoS settings saved under<bandwidth> XML section
*/
> + if (net->reservation || net->limit) {
> + int ret;
> + char *string = NULL;
> +
> + tmp = xmlNewChild(nic, NULL,
> + BAD_CAST "bandwidth", NULL);
> + if (tmp == NULL)
> + return XML_ERROR;
> +
> + /* Set inbound bandwidth from Reservation& Limit */
> + tmp = xmlNewChild(tmp, NULL,
> + BAD_CAST "inbound", NULL);
> + if (tmp == NULL)
> + return XML_ERROR;
> +
> + if (net->reservation) {
> + ret = asprintf(&string, "%" PRIu64,
> + net->reservation);
> + if (ret == -1)
> + return XML_ERROR;
> + xmlNewProp(tmp, BAD_CAST "average",
> + BAD_CAST string);
> + free(string);
> + }
> +
> + if (net->limit) {
> + ret = asprintf(&string, "%" PRIu64,
> + net->limit);
> + if (ret == -1)
> + return XML_ERROR;
> + xmlNewProp(tmp, BAD_CAST "peak",
> + BAD_CAST string);
> + free(string);
> + }
> + }
> +#endif
> +
> if (STREQ(dev->dev.net.type, "network"))
> msg = set_net_source(nic, net, "network");
> else if (STREQ(dev->dev.net.type, "bridge"))
> diff --git a/src/Virt_RASD.c b/src/Virt_RASD.c
> index e148674..a868c21 100644
> --- a/src/Virt_RASD.c
> +++ b/src/Virt_RASD.c
> @@ -39,6 +39,7 @@
> #include "svpc_types.h"
> #include "Virt_Device.h"
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> /* Network QoS support */
> #define QOSCMD_MAC2BANDWIDTH "_ROOT=$(tc class show dev %s | awk
> '($4==\"root\")\
> {print $3}')\n _ID=$(tc filter show dev %s | awk 'BEGIN
{RS=\"\\nfilter\"}
> (NR>2)\
> @@ -48,6 +49,7 @@ m1,m2,m3,m4,m5,m6,$18)}' | awk -v mm=%s '($1==mm){print
> $2}')\n \
> if [[ -n \"$_ID\" ]]; then\n tc class show dev %s | awk -v rr=$_ROOT -v
> id=$_ID \
> '($4==\"parent\"&& $5==rr&& $3==id){print \
> substr($13,1,(index($13,\"Kbit\")-1))}'\n fi\n"
> +#endif
>
> const static CMPIBroker *_BROKER;
>
> @@ -463,11 +465,7 @@ static CMPIStatus set_net_rasd_params(const CMPIBroker
> *broker,
> const struct virt_device *dev,
> CMPIInstance *inst)
> {
> - FILE *pipe = NULL;
> - char *cmd = NULL;
> - uint64_t val = 0;
> CMPIStatus s = {CMPI_RC_OK, NULL};
> - int i;
>
> CMSetProperty(inst,
> "NetworkType",
> @@ -485,8 +483,14 @@ static CMPIStatus set_net_rasd_params(const CMPIBroker
> *broker,
> (CMPIValue *)dev->dev.net.source,
> CMPI_chars);
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> /* Network QoS support */
> if ((dev->dev.net.mac != NULL)&& (dev->dev.net.source !=
NULL)) {
> + FILE *pipe = NULL;
> + char *cmd = NULL;
> + uint64_t val = 0;
> + int i;
> +
> /* Get tc performance class bandwidth for this MAC addr */
> i = asprintf(&cmd, QOSCMD_MAC2BANDWIDTH,
dev->dev.net.source,
> dev->dev.net.source,
> @@ -511,6 +515,25 @@ static CMPIStatus set_net_rasd_params(const CMPIBroker
> *broker,
> }
> free(cmd);
> }
> +#else
> + if (dev->dev.net.reservation) {
> + CMSetProperty(inst,
> + "Reservation",
> + (CMPIValue *)&(dev->dev.net.reservation),
> + CMPI_uint64);
> +
> + if (dev->dev.net.limit)
> + CMSetProperty(inst,
> + "Limit",
> + (CMPIValue *)&(dev->dev.net.limit),
> + CMPI_uint64);
> +
> + CMSetProperty(inst,
> + "AllocationUnits",
> + (CMPIValue *)"KiloBytes per Second",
> + CMPI_chars);
> + }
> +#endif
>
> if ((dev->dev.net.source != NULL)&&
> (STREQ(dev->dev.net.type, "direct")))
> @@ -543,7 +566,9 @@ static CMPIStatus set_net_rasd_params(const CMPIBroker
> *broker,
> (CMPIValue *)dev->dev.net.poolid,
> CMPI_chars);
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> out:
> +#endif
> return s;
> }
>
> diff --git a/src/Virt_SettingsDefineCapabilities.c
> b/src/Virt_SettingsDefineCapabilities.c
> index 129749e..660103a 100644
> --- a/src/Virt_SettingsDefineCapabilities.c
> +++ b/src/Virt_SettingsDefineCapabilities.c
> @@ -74,9 +74,11 @@ const static CMPIBroker *_BROKER;
> #define NEW_VOL_RASD 2
>
> /* QoS Network support */
> +#if LIBVIR_VERSION_NUMBER< 9000
> #define QOSCMD_LISTCLASSES "_ROOT=$(tc class show dev %s | awk
> '($4==\"root\")\
> {print $3}')\n tc class show dev %s | awk -v rr=$_ROOT \
> '($4==\"parent\"&& $5==rr){print $3\"
\"$13}'\n"
> +#endif
>
> static bool system_has_vt(virConnectPtr conn)
> {
> @@ -567,6 +569,8 @@ static CMPIStatus set_net_props(int type,
> const char *net_type,
> const char *net_name,
> uint64_t num_nics,
> + uint64_t reservation,
> + uint64_t limit,
> const char *device,
> const char *src_dev,
> const char *net_mode,
> @@ -594,6 +598,21 @@ static CMPIStatus set_net_props(int type,
> CMSetProperty(inst, "VirtualQuantity",
> (CMPIValue *)&num_nics, CMPI_uint64);
>
> +#if LIBVIR_VERSION_NUMBER>= 9000
> + /* Network QoS support for later libvirt versions */
> + if (reservation)
> + CMSetProperty(inst, "Reservation",
> + (CMPIValue *)&reservation, CMPI_uint64);
> +
> + if (limit)
> + CMSetProperty(inst, "Limit",
> + (CMPIValue *)&reservation, CMPI_uint64);
> +
> + if (reservation || limit)
> + CMSetProperty(inst, "AllocationUnits",
> + (CMPIValue *)"KiloBytes per Second", CMPI_chars);
> +#endif
> +
> if (device != NULL)
> CMSetProperty(inst, "VirtualDevice",
> (CMPIValue *)device, CMPI_chars);
> @@ -647,6 +666,8 @@ static CMPIStatus net_template(const CMPIObjectPath *ref,
> {
> bool ret;
> uint64_t num_nics;
> + uint64_t reservation = 0;
> + uint64_t limit = 0;
> const char *id;
> CMPIStatus s = {CMPI_RC_OK, NULL};
> int i,j;
> @@ -658,16 +679,21 @@ static CMPIStatus net_template(const CMPIObjectPath *ref,
> switch (template_type) {
> case SDC_RASD_MIN:
> num_nics = 0;
> + reservation = 1;
> + limit = 1;
> id = "Minimum";
> break;
> case SDC_RASD_MAX:
> ret = get_max_nics(ref,&num_nics,&s);
> if (!ret)
> goto out;
> + /* No apparant maximum reservation or limit QoS setting in
> libvirt! */
> id = "Maximum";
> break;
> case SDC_RASD_INC:
> num_nics = 1;
> + reservation = 1;
> + limit = 1;
> id = "Increment";
> break;
> case SDC_RASD_DEF:
> @@ -689,7 +715,9 @@ static CMPIStatus net_template(const CMPIObjectPath *ref,
> id,
> type[i],
> name[i],
> - num_nics,
> + num_nics,
> + reservation,
> + limit,
> device[j],
> NULL,
> NULL,
> @@ -707,22 +735,26 @@ static CMPIStatus net_template(const CMPIObjectPath *ref,
> }
>
> s = set_net_props(template_type, ref, id, "direct", NULL,
> - num_nics, NULL, "eth1", "vepa", NULL,
> + num_nics, reservation, limit,
> + NULL, "eth1", "vepa", NULL,
> NULL, NULL, NULL, NULL, NULL, NULL, list);
> /* profile id*/
> s = set_net_props(template_type, ref, id, "direct", NULL,
> - num_nics, NULL, "eth1", "vepa",
NULL,
> + num_nics, reservation, limit,
> + NULL, "eth1", "vepa", NULL,
> "802.1Qbh", NULL, NULL, NULL,
> NULL, "my_profile", list);
> /* no profile id but with instance id*/
> s = set_net_props(template_type, ref, id, "direct", NULL,
> - num_nics, NULL, "eth1", "vepa",
NULL,
> + num_nics, reservation, limit,
> + NULL, "eth1", "vepa", NULL,
> "802.1Qbg", "managerid",
"typeid",
> "typeidversion", "instanceid",
NULL,
> list);
> /* no profile id and no instance id*/
> s = set_net_props(template_type, ref, id, "direct", NULL,
> - num_nics, NULL, "eth1", "vepa",
NULL,
> + num_nics, reservation, limit,
> + NULL, "eth1", "vepa", NULL,
> "802.1Qbg", "managerid",
"typeid",
> "typeidversion", "NULL",
"NULL", list);
>
> @@ -814,6 +846,7 @@ static CMPIStatus set_net_pool_props(const CMPIObjectPath
> *ref,
> return s;
> }
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> static char * get_bridge_name(virConnectPtr conn, const char *name)
> {
> char *bridge = NULL;
> @@ -913,7 +946,7 @@ static CMPIStatus qos_hack(
>
> return s;
> }
> -
> +#endif
>
> static CMPIStatus net_pool_template(const CMPIObjectPath *ref,
> int template_type,
> @@ -2086,8 +2119,10 @@ static CMPIStatus sdc_rasds_for_type(const
> CMPIObjectPath *ref,
> }
> }
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> if (type == CIM_RES_TYPE_NET)
> s = qos_hack(ref, list);
> +#endif
>
> out:
> return s;
> diff --git a/src/Virt_VirtualSystemManagementService.c
> b/src/Virt_VirtualSystemManagementService.c
> index 0141515..4e16b81 100644
> --- a/src/Virt_VirtualSystemManagementService.c
> +++ b/src/Virt_VirtualSystemManagementService.c
> @@ -68,6 +68,7 @@
> #define RASD_IND_DELETED
"ResourceAllocationSettingDataDeletedIndication"
> #define RASD_IND_MODIFIED
"ResourceAllocationSettingDataModifiedIndication"
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> /* Network QoS support */
> #define QOSCMD_BANDWIDTH2ID "_ROOT=$(tc class show dev %s | awk
> '($4==\"root\")\
> {print $3}')\n tc class show dev %s | awk -v rr=$_ROOT -v bw=%uKbit \
> @@ -96,6 +97,7 @@ $U32 match u16 0x0800 0xFFFF at -2 match u16 0x$ME2 0xFFFF
> at -4 match u32 \
> ffff: prio 50 u32\"; $U32 match u16 0x0800 0xFFFF at -2 match u32 0x$MI2 \
> 0xFFFFFFFF at -12 match u16 0x$MI1 0xFFFF at -14 police rate %uKbit burst
> 15k \
> drop\n"
> +#endif
>
> const static CMPIBroker *_BROKER;
>
> @@ -105,6 +107,7 @@ enum ResourceAction {
> RESOURCE_MOD,
> };
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> /* Network QoS support */
> static CMPIStatus add_qos_for_mac(const uint64_t qos,
> const char *mac,
> @@ -202,6 +205,7 @@ static CMPIStatus remove_qos_for_mac(const uint64_t qos,
> free(cmd);
> return s;
> }
> +#endif
>
> static CMPIStatus check_uuid_in_use(const CMPIObjectPath *ref,
> struct domain *domain)
> @@ -973,6 +977,15 @@ static const char *net_rasd_to_vdev(CMPIInstance *inst,
> dev->dev.net.model = NULL;
> else
> dev->dev.net.model = strdup(val);
> +
> + if (cu_get_u64_prop(inst, "Reservation",
> +&dev->dev.net.reservation) != CMPI_RC_OK)
> + dev->dev.net.reservation = 0;
> +
> + if (cu_get_u64_prop(inst, "Limit",
> +&dev->dev.net.limit) != CMPI_RC_OK)
> + dev->dev.net.limit = 0;
> +
> out:
> free(network);
> return msg;
> @@ -1645,8 +1658,10 @@ static const char *classify_resources(CMPIArray
> *resources,
> } else if (type == CIM_RES_TYPE_NET) {
> struct virt_device dev;
> int ncount = count + domain->dev_net_ct;
> +#if LIBVIR_VERSION_NUMBER< 9000
> uint64_t qos_val = 0;
> const char *qos_unitstr;
> +#endif
>
> memset(&dev, 0, sizeof(dev));
> msg = rasd_to_vdev(inst,
> @@ -1659,6 +1674,7 @@ static const char *classify_resources(CMPIArray
> *resources,
> ncount,
> &domain->dev_net_ct);
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> /* Network QoS support */
> if (((&dev)->dev.net.mac != NULL)&&
> ((&dev)->dev.net.source != NULL)&&
> @@ -1672,6 +1688,7 @@ static const char *classify_resources(CMPIArray
> *resources,
> (&dev)->dev.net.mac,
> (&dev)->dev.net.source);
> }
> +#endif
> } else if (type == CIM_RES_TYPE_GRAPHICS) {
> struct virt_device dev;
> int gcount = count + domain->dev_graphics_ct;
> @@ -2763,14 +2780,16 @@ static CMPIStatus resource_mod(struct domain *dominfo,
> (type == CIM_RES_TYPE_INPUT))
> cu_statusf(_BROKER,&s, CMPI_RC_OK,
"");
> else {
> +#if LIBVIR_VERSION_NUMBER< 9000
> uint64_t qos_val = 0;
> const char *qos_unitstr;
> -
> +#endif
> s = _resource_dynamic(dominfo,
> dev,
> RESOURCE_MOD,
> CLASSNAME(op));
>
> +#if LIBVIR_VERSION_NUMBER< 9000
> /* Network QoS support */
> if ((type == CIM_RES_TYPE_NET)&&
> (dev->dev.net.mac != NULL)&&
> @@ -2785,6 +2804,7 @@ static CMPIStatus resource_mod(struct domain *dominfo,
> dev->dev.net.mac,
>
> dev->dev.net.source);
> }
> +#endif
> }
> break;
> }
--
Chip Vincent
Open Virtualization
IBM Linux Technology Center
cvincent(a)linux.vnet.ibm.com