[Libvirt-cim] [PATCH] Network QoS Patch2

Gareth S Bestor bestor at us.ibm.com
Fri Dec 30 12:54:38 UTC 2011


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;
                 }
-- 
1.7.1




More information about the Libvirt-cim mailing list