1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-22 17:34:18 +03:00

domcaps: Add support for listing supported CPU models

The patch adds <cpu> element to domain capabilities XML:

    <cpu>
        <mode name='host-passthrough' supported='yes'/>
        <mode name='host-model' supported='yes'/>
        <mode name='custom' supported='yes'>
            <model>Broadwell</model>
            <model>Broadwell-noTSX</model>
            ...
        </mode>
    </cpu>

Applications can use it to inspect what CPU configuration modes are
supported for a specific combination of domain type, emulator binary,
guest architecture and machine type.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
This commit is contained in:
Jiri Denemark 2016-04-22 11:08:57 +02:00
parent 350e3fee0e
commit 167280e7f6
18 changed files with 346 additions and 0 deletions

View File

@ -142,6 +142,50 @@
&lt;loader/&gt; element.</dd>
</dl>
<h3><a name="elementsCPU">CPU configuration</a></h3>
<p>
The <code>cpu</code> element exposes options usable for configuring
<a href="formatdomain.html#elementsCPU">guest CPUs</a>.
</p>
<pre>
&lt;domainCapabilities&gt;
...
&lt;cpu&gt;
&lt;mode name='host-passthrough' supported='yes'/&gt;
&lt;mode name='host-model' supported='yes'/&gt;
&lt;mode name='custom' supported='yes'&gt;
&lt;model&gt;Broadwell&lt;/model&gt;
&lt;model&gt;Broadwell-noTSX&lt;/model&gt;
&lt;model&gt;Haswell&lt;/model&gt;
...
&lt;/mode&gt;
&lt;/cpu&gt;
...
&lt;domainCapabilities&gt;
</pre>
<p>
Each CPU mode understood by libvirt is described with a
<code>mode</code> element which tells whether the particular mode
is supported and provides (when applicable) more details about it:
</p>
<dl>
<dt><code>host-passthrough</code></dt>
<dd>No mode specific details are provided.</dd>
<dt><code>host-model</code></dt>
<dd>No mode specific details are provided yet.</dd>
<dt><code>custom</code></dt>
<dd>
The <code>mode</code> element contains a list of supported CPU
models, each described by a dedicated <code>model</code> element.
</dd>
</dl>
<h3><a name="elementsDevices">Devices</a></h3>
<p>

View File

@ -28,6 +28,9 @@
<optional>
<ref name='os'/>
</optional>
<optional>
<ref name='cpu'/>
</optional>
<optional>
<ref name='devices'/>
</optional>
@ -68,6 +71,46 @@
</element>
</define>
<define name='cpu'>
<element name='cpu'>
<ref name='cpuHost'/>
<ref name='cpuHostModel'/>
<ref name='cpuCustom'/>
</element>
</define>
<define name='cpuHost'>
<element name='mode'>
<attribute name='name'>
<value>host-passthrough</value>
</attribute>
<ref name='supported'/>
</element>
</define>
<define name='cpuHostModel'>
<element name='mode'>
<attribute name='name'>
<value>host-model</value>
</attribute>
<ref name='supported'/>
</element>
</define>
<define name='cpuCustom'>
<element name='mode'>
<attribute name='name'>
<value>custom</value>
</attribute>
<ref name='supported'/>
<zeroOrMore>
<element name='model'>
<text/>
</element>
</zeroOrMore>
</element>
</define>
<define name='devices'>
<element name='devices'>
<interleave>

View File

@ -30,8 +30,10 @@
#define VIR_FROM_THIS VIR_FROM_CAPABILITIES
static virClassPtr virDomainCapsClass;
static virClassPtr virDomainCapsCPUModelsClass;
static void virDomainCapsDispose(void *obj);
static void virDomainCapsCPUModelsDispose(void *obj);
static int virDomainCapsOnceInit(void)
{
@ -40,6 +42,14 @@ static int virDomainCapsOnceInit(void)
sizeof(virDomainCaps),
virDomainCapsDispose)))
return -1;
virDomainCapsCPUModelsClass = virClassNew(virClassForObject(),
"virDomainCapsCPUModelsClass",
sizeof(virDomainCapsCPUModels),
virDomainCapsCPUModelsDispose);
if (!virDomainCapsCPUModelsClass)
return -1;
return 0;
}
@ -68,11 +78,25 @@ virDomainCapsDispose(void *obj)
VIR_FREE(caps->path);
VIR_FREE(caps->machine);
virObjectUnref(caps->cpu.custom);
virDomainCapsStringValuesFree(&caps->os.loader.values);
}
static void
virDomainCapsCPUModelsDispose(void *obj)
{
virDomainCapsCPUModelsPtr cpuModels = obj;
size_t i;
for (i = 0; i < cpuModels->nmodels; i++)
VIR_FREE(cpuModels->models[i].name);
VIR_FREE(cpuModels->models);
}
virDomainCapsPtr
virDomainCapsNew(const char *path,
const char *machine,
@ -100,6 +124,85 @@ virDomainCapsNew(const char *path,
}
virDomainCapsCPUModelsPtr
virDomainCapsCPUModelsNew(size_t nmodels)
{
virDomainCapsCPUModelsPtr cpuModels = NULL;
if (virDomainCapsInitialize() < 0)
return NULL;
if (!(cpuModels = virObjectNew(virDomainCapsCPUModelsClass)))
return NULL;
if (VIR_ALLOC_N(cpuModels->models, nmodels) < 0)
goto error;
cpuModels->nmodels_max = nmodels;
return cpuModels;
error:
virObjectUnref(cpuModels);
return NULL;
}
virDomainCapsCPUModelsPtr
virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old)
{
virDomainCapsCPUModelsPtr cpuModels;
size_t i;
if (!(cpuModels = virDomainCapsCPUModelsNew(old->nmodels)))
return NULL;
for (i = 0; i < old->nmodels; i++) {
if (virDomainCapsCPUModelsAdd(cpuModels, old->models[i].name, -1) < 0)
goto error;
}
return cpuModels;
error:
virObjectUnref(cpuModels);
return NULL;
}
int
virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels,
char **name)
{
if (VIR_RESIZE_N(cpuModels->models, cpuModels->nmodels_max,
cpuModels->nmodels, 1) < 0)
return -1;
VIR_STEAL_PTR(cpuModels->models[cpuModels->nmodels++].name, *name);
return 0;
}
int
virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels,
const char *name,
ssize_t nameLen)
{
char *copy = NULL;
if (VIR_STRNDUP(copy, name, nameLen) < 0)
goto error;
if (virDomainCapsCPUModelsAddSteal(cpuModels, &copy) < 0)
goto error;
return 0;
error:
VIR_FREE(copy);
return -1;
}
int
virDomainCapsEnumSet(virDomainCapsEnumPtr capsEnum,
const char *capsEnumName,
@ -233,6 +336,51 @@ virDomainCapsOSFormat(virBufferPtr buf,
FORMAT_EPILOGUE(os);
}
static void
virDomainCapsCPUCustomFormat(virBufferPtr buf,
virDomainCapsCPUModelsPtr custom)
{
size_t i;
virBufferAdjustIndent(buf, 2);
for (i = 0; i < custom->nmodels; i++) {
virBufferAsprintf(buf, "<model>%s</model>\n",
custom->models[i].name);
}
virBufferAdjustIndent(buf, -2);
}
static void
virDomainCapsCPUFormat(virBufferPtr buf,
virDomainCapsCPUPtr cpu)
{
virBufferAddLit(buf, "<cpu>\n");
virBufferAdjustIndent(buf, 2);
virBufferAsprintf(buf, "<mode name='%s' supported='%s'/>\n",
virCPUModeTypeToString(VIR_CPU_MODE_HOST_PASSTHROUGH),
cpu->hostPassthrough ? "yes" : "no");
virBufferAsprintf(buf, "<mode name='%s' supported='%s'/>\n",
virCPUModeTypeToString(VIR_CPU_MODE_HOST_MODEL),
cpu->hostModel ? "yes" : "no");
virBufferAsprintf(buf, "<mode name='%s' ",
virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM));
if (cpu->custom && cpu->custom->nmodels) {
virBufferAddLit(buf, "supported='yes'>\n");
virDomainCapsCPUCustomFormat(buf, cpu->custom);
virBufferAddLit(buf, "</mode>\n");
} else {
virBufferAddLit(buf, "supported='no'/>\n");
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</cpu>\n");
}
static void
virDomainCapsDeviceDiskFormat(virBufferPtr buf,
virDomainCapsDeviceDiskPtr const disk)
@ -333,6 +481,7 @@ virDomainCapsFormatInternal(virBufferPtr buf,
virBufferAsprintf(buf, "<vcpu max='%d'/>\n", caps->maxvcpus);
virDomainCapsOSFormat(buf, &caps->os);
virDomainCapsCPUFormat(buf, &caps->cpu);
virBufferAddLit(buf, "<devices>\n");
virBufferAdjustIndent(buf, 2);

View File

@ -102,6 +102,30 @@ struct _virDomainCapsFeatureGIC {
virDomainCapsEnum version; /* Info about virGICVersion */
};
typedef struct _virDomainCapsCPUModel virDomainCapsCPUModel;
typedef virDomainCapsCPUModel *virDomainCapsCPUModelPtr;
struct _virDomainCapsCPUModel {
char *name;
};
typedef struct _virDomainCapsCPUModels virDomainCapsCPUModels;
typedef virDomainCapsCPUModels *virDomainCapsCPUModelsPtr;
struct _virDomainCapsCPUModels {
virObject parent;
size_t nmodels_max;
size_t nmodels;
virDomainCapsCPUModelPtr models;
};
typedef struct _virDomainCapsCPU virDomainCapsCPU;
typedef virDomainCapsCPU *virDomainCapsCPUPtr;
struct _virDomainCapsCPU {
bool hostPassthrough;
bool hostModel;
virDomainCapsCPUModelsPtr custom;
};
struct _virDomainCaps {
virObjectLockable parent;
@ -114,6 +138,7 @@ struct _virDomainCaps {
int maxvcpus;
virDomainCapsOS os;
virDomainCapsCPU cpu;
virDomainCapsDeviceDisk disk;
virDomainCapsDeviceGraphics graphics;
virDomainCapsDeviceVideo video;
@ -129,6 +154,14 @@ virDomainCapsPtr virDomainCapsNew(const char *path,
virArch arch,
virDomainVirtType virttype);
virDomainCapsCPUModelsPtr virDomainCapsCPUModelsNew(size_t nmodels);
virDomainCapsCPUModelsPtr virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old);
int virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels,
char **name);
int virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels,
const char *name,
ssize_t nameLen);
# define VIR_DOMAIN_CAPS_ENUM_SET(capsEnum, ...) \
do { \
unsigned int __values[] = {__VA_ARGS__}; \

View File

@ -153,6 +153,10 @@ virDomainAuditVcpu;
# conf/domain_capabilities.h
virDomainCapsCPUModelsAdd;
virDomainCapsCPUModelsAddSteal;
virDomainCapsCPUModelsCopy;
virDomainCapsCPUModelsNew;
virDomainCapsEnumClear;
virDomainCapsEnumSet;
virDomainCapsFormat;

View File

@ -4,6 +4,11 @@
<machine>my-machine-type</machine>
<arch>x86_64</arch>
<os supported='no'/>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='no'/>
<graphics supported='no'/>

View File

@ -19,6 +19,15 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='yes'/>
<mode name='host-model' supported='yes'/>
<mode name='custom' supported='yes'>
<model>Model1</model>
<model>Model2</model>
<model>Model3</model>
</mode>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -17,6 +17,11 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -17,6 +17,11 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -7,6 +7,11 @@
<os supported='yes'>
<loader supported='no'/>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -7,6 +7,11 @@
<os supported='yes'>
<loader supported='no'/>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -18,6 +18,11 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -18,6 +18,11 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -18,6 +18,11 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -18,6 +18,11 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -18,6 +18,11 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -18,6 +18,11 @@
</enum>
</loader>
</os>
<cpu>
<mode name='host-passthrough' supported='no'/>
<mode name='host-model' supported='no'/>
<mode name='custom' supported='no'/>
</cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>

View File

@ -60,6 +60,7 @@ fillAllCaps(virDomainCapsPtr domCaps)
{
virDomainCapsOSPtr os = &domCaps->os;
virDomainCapsLoaderPtr loader = &os->loader;
virDomainCapsCPUPtr cpu = &domCaps->cpu;
virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
virDomainCapsDeviceGraphicsPtr graphics = &domCaps->graphics;
virDomainCapsDeviceVideoPtr video = &domCaps->video;
@ -77,6 +78,14 @@ fillAllCaps(virDomainCapsPtr domCaps)
NULL) < 0)
return -1;
cpu->hostPassthrough = true;
cpu->hostModel = true;
if (!(cpu->custom = virDomainCapsCPUModelsNew(3)) ||
virDomainCapsCPUModelsAdd(cpu->custom, "Model1", -1) < 0 ||
virDomainCapsCPUModelsAdd(cpu->custom, "Model2", -1) < 0 ||
virDomainCapsCPUModelsAdd(cpu->custom, "Model3", -1) < 0)
return -1;
disk->supported = true;
SET_ALL_BITS(disk->diskDevice);
SET_ALL_BITS(disk->bus);