[Libvirt-cim] [PATCH] Network QoS Patch2

Chip Vincent cvincent at linux.vnet.ibm.com
Fri Dec 30 20:39:27 UTC 2011


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 at 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 at 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 at linux.vnet.ibm.com




More information about the Libvirt-cim mailing list