[PATCH 19/27] conf: Add XML for individual vCPU hotplug

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Individual vCPU hotplug requires us to track the state of any vCPU. To
allow this add the following XML:

<domain>
  ...
  <vcpu current='1'>2</vcpu>
  <vcpus>
    <vcpu id='0' enabled='no' hotpluggable='yes'/>
    <vcpu id='1' enabled='yes' hotpluggable='no' order='1'/>
  </vcpus>
  ...

The 'enabled' attribute allows to control the state of the vcpu.
'hotpluggable' controls whether given vcpu can be hotplugged and 'order'
allows to specify the order to add the vcpus.
---
 docs/formatdomain.html.in                          |  18 +++
 docs/schemas/domaincommon.rng                      |  25 ++++
 src/conf/domain_conf.c                             | 151 ++++++++++++++++++++-
 src/conf/domain_conf.h                             |   6 +
 .../generic-vcpus-individual.xml                   |  23 ++++
 tests/genericxml2xmltest.c                         |   2 +
 tests/testutils.c                                  |   4 +-
 7 files changed, 226 insertions(+), 3 deletions(-)
 create mode 100644 tests/genericxml2xmlindata/generic-vcpus-individual.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 5acb3b9..2d70f56 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -489,6 +489,10 @@
 &lt;domain&gt;
   ...
   &lt;vcpu placement='static' cpuset="1-4,^3,6" current="1"&gt;2&lt;/vcpu&gt;
+  &lt;vcpus&gt;
+    &lt;vcpu id='0' enabled='yes' hotpluggable='no' order='1'/&gt;
+    &lt;vcpu id='1' enabled='no' hotpluggable='yes'/&gt;
+  &lt;/vcpus&gt;
   ...
 &lt;/domain&gt;
 </pre>
@@ -542,6 +546,20 @@
          </dd>
         </dl>
       </dd>
+      <dt><code>vcpus</code></dt>
+      <dd>
+        The vcpus element allows to specify state of individual vcpu.
+
+        Note that providing state for individual cpus may be necessary to enable
+        support of addressable vCPU hotplug and this feature may not be
+        supported by all hypervisors.
+        <span class="since">Since 2.2.0</span>
+
+        The <code>enabled</code> attribute allows to control the state of the
+        vcpu. <code>hotpluggable</code> controls whether given vcpu can be
+        hotplugged and hotunplugged in cases when the cpu is enabled at boot.
+        <code>order</code> allows to specify the order to add the vcpus.
+      </dd>
     </dl>

     <h3><a name="elementsIOThreadsAllocation">IOThreads Allocation</a></h3>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 052f28c..5b3d652 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -583,6 +583,31 @@
       </optional>

       <optional>
+        <element name="vcpus">
+          <zeroOrMore>
+            <element name="vcpu">
+              <attribute name="id">
+                <ref name="unsignedInt"/>
+              </attribute>
+              <attribute name="enabled">
+                <ref name="virYesNo"/>
+              </attribute>
+              <optional>
+                  <attribute name="hotpluggable">
+                    <ref name="virYesNo"/>
+                  </attribute>
+              </optional>
+              <optional>
+                  <attribute name="order">
+                    <ref name="unsignedInt"/>
+                  </attribute>
+              </optional>
+            </element>
+          </zeroOrMore>
+        </element>
+      </optional>
+
+      <optional>
         <element name="iothreads">
           <ref name="unsignedInt"/>
         </element>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 2500058..51b8b78 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -4328,6 +4328,13 @@ virDomainDefPostParseCheckFeatures(virDomainDefPtr def,
         }
     }

+    if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS) &&
+        def->individualvcpus) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("individual CPU state configuration is not supported"));
+        return -1;
+    }
+
     return 0;
 }

@@ -4402,6 +4409,43 @@ virDomainDefPostParseDeviceIterator(virDomainDefPtr def,


 static int
+virDomainVcpuDefPostParse(virDomainDefPtr def)
+{
+    virDomainVcpuDefPtr vcpu;
+    size_t maxvcpus = virDomainDefGetVcpusMax(def);
+    size_t i;
+
+    for (i = 0; i < maxvcpus; i++) {
+        vcpu = virDomainDefGetVcpu(def, i);
+
+        switch (vcpu->hotpluggable) {
+        case VIR_TRISTATE_BOOL_ABSENT:
+            if (vcpu->online)
+                vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO;
+            else
+                vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
+            break;
+
+        case VIR_TRISTATE_BOOL_NO:
+            if (!vcpu->online) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("vcpu '%zu' is both offline and not "
+                                 "hotpluggable"), i);
+                return -1;
+            }
+            break;
+
+        case VIR_TRISTATE_BOOL_YES:
+        case VIR_TRISTATE_BOOL_LAST:
+            break;
+        }
+    }
+
+    return 0;
+}
+
+
+static int
 virDomainDefPostParseInternal(virDomainDefPtr def,
                               struct virDomainDefPostParseDeviceIteratorData *data)
 {
@@ -4412,6 +4456,9 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
         return -1;
     }

+    if (virDomainVcpuDefPostParse(def) < 0)
+        return -1;
+
     if (virDomainDefPostParseMemory(def, data->parseFlags) < 0)
         return -1;

@@ -15513,6 +15560,8 @@ virDomainVcpuParse(virDomainDefPtr def,
                    virDomainXMLOptionPtr xmlopt)
 {
     int n;
+    xmlNodePtr *nodes = NULL;
+    size_t i;
     char *tmp = NULL;
     unsigned int maxvcpus;
     unsigned int vcpus;
@@ -15541,8 +15590,6 @@ virDomainVcpuParse(virDomainDefPtr def,
         vcpus = maxvcpus;
     }

-    if (virDomainDefSetVcpus(def, vcpus) < 0)
-        goto cleanup;

     tmp = virXPathString("string(./vcpu[1]/@placement)", ctxt);
     if (tmp) {
@@ -15574,9 +15621,79 @@ virDomainVcpuParse(virDomainDefPtr def,
         }
     }

+    if ((n = virXPathNodeSet("./vcpus/vcpu", ctxt, &nodes)) < 0)
+        goto cleanup;
+
+    if (n) {
+        /* if individual vcpu states are provided take them as master */
+        def->individualvcpus = true;
+
+        for (i = 0; i < n; i++) {
+            virDomainVcpuDefPtr vcpu;
+            int state;
+            unsigned int id;
+            unsigned int order;
+
+            if (!(tmp = virXMLPropString(nodes[i], "id")) ||
+                virStrToLong_uip(tmp, NULL, 10, &id) < 0) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("missing or invalid vcpu id"));
+                goto cleanup;
+            }
+
+            VIR_FREE(tmp);
+
+            if (id >= def->maxvcpus) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("vcpu id '%u' is out of range of maximum "
+                                 "vcpu count"), id);
+                goto cleanup;
+            }
+
+            vcpu = virDomainDefGetVcpu(def, id);
+
+            if (!(tmp = virXMLPropString(nodes[i], "enabled"))) {
+                virReportError(VIR_ERR_XML_ERROR, "%s",
+                               _("missing vcpu enabled state"));
+                goto cleanup;
+            }
+
+            if ((state = virTristateBoolTypeFromString(tmp)) < 0) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("invalid vcpu 'enabled' value '%s'"), tmp);
+                goto cleanup;
+            }
+            VIR_FREE(tmp);
+
+            vcpu->online = state == VIR_TRISTATE_BOOL_YES;
+
+            if ((tmp = virXMLPropString(nodes[i], "hotpluggable"))) {
+                if ((vcpu->hotpluggable = virTristateBoolTypeFromString(tmp)) < 0) {
+                    virReportError(VIR_ERR_XML_ERROR,
+                                   _("invalid vcpu 'hotpluggable' value '%s'"), tmp);
+                    goto cleanup;
+                }
+                VIR_FREE(tmp);
+            }
+
+            if ((tmp = virXMLPropString(nodes[i], "order"))) {
+                if (virStrToLong_uip(tmp, NULL, 10, &order) < 0) {
+                    virReportError(VIR_ERR_XML_ERROR, "%s",
+                                   _("invalid vcpu order"));
+                    goto cleanup;
+                }
+                vcpu->order = order;
+            }
+        }
+    } else {
+        if (virDomainDefSetVcpus(def, vcpus) < 0)
+            goto cleanup;
+    }
+
     ret = 0;

  cleanup:
+    VIR_FREE(nodes);
     VIR_FREE(tmp);

     return ret;
@@ -18634,6 +18751,13 @@ virDomainDefVcpuCheckAbiStability(virDomainDefPtr src,
                              "destination definitions"), i);
             return false;
         }
+
+        if (svcpu->order != dvcpu->order) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("vcpu enable order of vCPU '%zu' differs between "
+                             "source and destination definitions"), i);
+            return false;
+        }
     }

     return true;
@@ -22938,6 +23062,8 @@ static int
 virDomainCpuDefFormat(virBufferPtr buf,
                       const virDomainDef *def)
 {
+    virDomainVcpuDefPtr vcpu;
+    size_t i;
     char *cpumask = NULL;
     int ret = -1;

@@ -22954,6 +23080,27 @@ virDomainCpuDefFormat(virBufferPtr buf,
         virBufferAsprintf(buf, " current='%u'", virDomainDefGetVcpus(def));
     virBufferAsprintf(buf, ">%u</vcpu>\n", virDomainDefGetVcpusMax(def));

+    if (def->individualvcpus) {
+        virBufferAddLit(buf, "<vcpus>\n");
+        virBufferAdjustIndent(buf, 2);
+        for (i = 0; i < def->maxvcpus; i++) {
+            vcpu = def->vcpus[i];
+
+            virBufferAsprintf(buf, "<vcpu id='%zu' enabled='%s'",
+                              i, vcpu->online ? "yes" : "no");
+            if (vcpu->hotpluggable)
+                virBufferAsprintf(buf, " hotpluggable='%s'",
+                                  virTristateBoolTypeToString(vcpu->hotpluggable));
+
+            if (vcpu->order != 0)
+                virBufferAsprintf(buf, " order='%d'", vcpu->order);
+
+            virBufferAddLit(buf, "/>\n");
+        }
+        virBufferAdjustIndent(buf, -2);
+        virBufferAddLit(buf, "</vcpus>\n");
+    }
+
     ret = 0;

  cleanup:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 8b26724..b889125 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2046,6 +2046,9 @@ typedef virDomainVcpuDef *virDomainVcpuDefPtr;

 struct _virDomainVcpuDef {
     bool online;
+    virTristateBool hotpluggable;
+    unsigned int order;
+
     virBitmapPtr cpumask;

     virDomainThreadSchedParam sched;
@@ -2142,6 +2145,8 @@ struct _virDomainDef {

     virDomainVcpuDefPtr *vcpus;
     size_t maxvcpus;
+    /* set if the vcpu definition was specified individually */
+    bool individualvcpus;
     int placement_mode;
     virBitmapPtr cpumask;

@@ -2344,6 +2349,7 @@ typedef enum {
     VIR_DOMAIN_DEF_FEATURE_MEMORY_HOTPLUG = (1 << 1),
     VIR_DOMAIN_DEF_FEATURE_OFFLINE_VCPUPIN = (1 << 2),
     VIR_DOMAIN_DEF_FEATURE_NAME_SLASH = (1 << 3),
+    VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS = (1 << 4),
 } virDomainDefFeatures;


diff --git a/tests/genericxml2xmlindata/generic-vcpus-individual.xml b/tests/genericxml2xmlindata/generic-vcpus-individual.xml
new file mode 100644
index 0000000..cbcf8fd
--- /dev/null
+++ b/tests/genericxml2xmlindata/generic-vcpus-individual.xml
@@ -0,0 +1,23 @@
+<domain type='qemu'>
+  <name>foobar</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static' current='2'>4</vcpu>
+  <vcpus>
+    <vcpu id='0' enabled='no' hotpluggable='yes' order='1'/>
+    <vcpu id='1' enabled='yes' hotpluggable='no'/>
+    <vcpu id='2' enabled='no' hotpluggable='yes' order='2'/>
+    <vcpu id='3' enabled='yes' hotpluggable='no'/>
+  </vcpus>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+  </devices>
+</domain>
diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c
index a487727..2ea2396 100644
--- a/tests/genericxml2xmltest.c
+++ b/tests/genericxml2xmltest.c
@@ -97,6 +97,8 @@ mymain(void)

     DO_TEST("perf");

+    DO_TEST("vcpus-individual");
+
     virObjectUnref(caps);
     virObjectUnref(xmlopt);

diff --git a/tests/testutils.c b/tests/testutils.c
index 8af8707..8ea6ab8 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -1089,7 +1089,9 @@ virCapsPtr virTestGenericCapsInit(void)
     return NULL;
 }

-static virDomainDefParserConfig virTestGenericDomainDefParserConfig;
+static virDomainDefParserConfig virTestGenericDomainDefParserConfig = {
+    .features = VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS,
+};
 static virDomainXMLPrivateDataCallbacks virTestGenericPrivateDataCallbacks;

 virDomainXMLOptionPtr virTestGenericDomainXMLConfInit(void)
-- 
2.9.2

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]