]> xenbits.xensource.com Git - libvirt.git/commitdiff
conf: Add XML for individual vCPU hotplug
authorPeter Krempa <pkrempa@redhat.com>
Tue, 2 Aug 2016 15:58:43 +0000 (17:58 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Wed, 24 Aug 2016 19:44:47 +0000 (15:44 -0400)
Individual vCPU hotplug requires us to track the state of any vCPU. To
allow this add the following XML:

<domain>
  ...
  <vcpu current='2'>3</vcpu>
  <vcpus>
    <vcpu id='0' enabled='yes' hotpluggable='no' order='1'/>
    <vcpu id='1' enabled='yes' hotpluggable='yes' order='2'/>
    <vcpu id='1' enabled='no' hotpluggable='yes'/>
  </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
docs/schemas/domaincommon.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/qemu/qemu_domain.c
tests/genericxml2xmlindata/generic-vcpus-individual.xml [new file with mode: 0644]
tests/genericxml2xmltest.c
tests/testutils.c

index bfbb0f2834c1f78396a33ab1c30a0f0d2fb5a3c0..062045b0feb1dcfc18ef776b0e89716149b80a52 100644 (file)
 &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>
          </dd>
         </dl>
       </dd>
+      <dt><code>vcpus</code></dt>
+      <dd>
+        The vcpus element allows to control state of individual vcpus.
+
+        The <code>id</code> attribute specifies the vCPU id as used by libvirt
+        in other places such as vcpu pinning, scheduler information and NUMA
+        assignment. Note that the vcpu ID as seen in the guest may differ from
+        libvirt ID in certain cases. Valid IDs are from 0 to the maximum vcpu
+        count as set by the <code>vcpu</code> element minus 1.
+
+        The <code>enabled</code> attribute allows to control the state of the
+        vcpu. Valid values are <code>yes</code> and <code>no</code>.
+
+        <code>hotpluggable</code> controls whether given vcpu can be hotplugged
+        and hotunplugged in cases when the cpu is enabled at boot. Note that
+        all disabled vcpus must be hotpluggable. Valid values are
+        <code>yes</code> and <code>no</code>.
+
+        <code>order</code> allows to specify the order to add the vcpus. For
+        hypervisors/platforms that require to insert multiple vcpus at once
+        the order may be be duplicated accross all vcpus that need to be
+        enabled at once. Specifying order is not necessary, vcpus are then
+        added in an arbitrary order.
+
+        Note that hypervisors may create hotpluggable vcpus differently from
+        boot vcpus thus special initialization may be necessary.
+
+        Hypervisors may require that vcpus enabled on boot which are not
+        hotpluggable are clustered at the beginning starting with ID 0. It may
+        be also required that vcpu 0 is always present and non-hotpluggable.
+
+        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 (QEMU only)</span>
+      </dd>
     </dl>
 
     <h3><a name="elementsIOThreadsAllocation">IOThreads Allocation</a></h3>
index 052f28c867f15924594dc32c37275997f54f4f73..9a7d03ed94fee427c72085fba4637328d6745b9a 100644 (file)
         </element>
       </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"/>
index 14d4f7df9c54ee9545f33c0eb2578df28063c91b..17c2f5396608304e6809194b4353c923be606a52 100644 (file)
@@ -4332,6 +4332,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;
 }
 
@@ -4405,6 +4412,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)
@@ -4416,6 +4460,9 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
         return -1;
     }
 
+    if (virDomainVcpuDefPostParse(def) < 0)
+        return -1;
+
     if (virDomainDefPostParseMemory(def, data->parseFlags) < 0)
         return -1;
 
@@ -15521,6 +15568,8 @@ virDomainVcpuParse(virDomainDefPtr def,
                    virDomainXMLOptionPtr xmlopt)
 {
     int n;
+    xmlNodePtr *nodes = NULL;
+    size_t i;
     char *tmp = NULL;
     unsigned int maxvcpus;
     unsigned int vcpus;
@@ -15549,8 +15598,6 @@ virDomainVcpuParse(virDomainDefPtr def,
         vcpus = maxvcpus;
     }
 
-    if (virDomainDefSetVcpus(def, vcpus) < 0)
-        goto cleanup;
 
     tmp = virXPathString("string(./vcpu[1]/@placement)", ctxt);
     if (tmp) {
@@ -15582,9 +15629,82 @@ 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"))) {
+                int hotpluggable;
+                if ((hotpluggable = virTristateBoolTypeFromString(tmp)) < 0) {
+                    virReportError(VIR_ERR_XML_ERROR,
+                                   _("invalid vcpu 'hotpluggable' value '%s'"), tmp);
+                    goto cleanup;
+                }
+                vcpu->hotpluggable = hotpluggable;
+                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;
+                VIR_FREE(tmp);
+            }
+        }
+    } else {
+        if (virDomainDefSetVcpus(def, vcpus) < 0)
+            goto cleanup;
+    }
+
     ret = 0;
 
  cleanup:
+    VIR_FREE(nodes);
     VIR_FREE(tmp);
 
     return ret;
@@ -18642,6 +18762,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;
@@ -22946,6 +23073,8 @@ static int
 virDomainCpuDefFormat(virBufferPtr buf,
                       const virDomainDef *def)
 {
+    virDomainVcpuDefPtr vcpu;
+    size_t i;
     char *cpumask = NULL;
     int ret = -1;
 
@@ -22962,6 +23091,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:
index 8b2672487dae60db2962af557b44134337c77061..b88912508b05cb488a3a1f3f37b8d92cc52f625a 100644 (file)
@@ -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;
 
 
index d4f472ba282cedf1068488fe43bedd37190d3e2b..5f4c642143752c47e8498eb7c1bfe9cb70f1f886 100644 (file)
@@ -5846,8 +5846,17 @@ qemuDomainRefreshVcpuInfo(virQEMUDriverPtr driver,
         VIR_STEAL_PTR(vcpupriv->alias, info[i].alias);
         vcpupriv->enable_id = info[i].id;
 
-        if (hotplug && state)
+        if (hotplug && state) {
             vcpu->online = !!info[i].qom_path;
+
+            /* mark cpus that don't have an alias as non-hotpluggable */
+            if (vcpu->online) {
+                if (vcpupriv->alias)
+                    vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
+                else
+                    vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO;
+            }
+        }
     }
 
     ret = 0;
diff --git a/tests/genericxml2xmlindata/generic-vcpus-individual.xml b/tests/genericxml2xmlindata/generic-vcpus-individual.xml
new file mode 100644 (file)
index 0000000..cbcf8fd
--- /dev/null
@@ -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>
index a487727a015110910a26386e46f18813ebafc1c9..2ea23964804543aedcf7d81664d41768cfedcd5d 100644 (file)
@@ -97,6 +97,8 @@ mymain(void)
 
     DO_TEST("perf");
 
+    DO_TEST("vcpus-individual");
+
     virObjectUnref(caps);
     virObjectUnref(xmlopt);
 
index 8af8707fab21e8fde1ae93aabdaac2b3e4ba555d..8ea6ab82ad5abb12de9cfe2363e0f539a47525fe 100644 (file)
@@ -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)