2008-02-27 04:35:08 +00:00
|
|
|
/*
|
|
|
|
* capabilities.c: hypervisor capabilities
|
|
|
|
*
|
2013-03-07 16:03:36 +00:00
|
|
|
* Copyright (C) 2006-2008, 2010-2011, 2013 Red Hat, Inc.
|
2008-02-27 04:35:08 +00:00
|
|
|
* Copyright (C) 2006-2008 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2008-02-27 04:35:08 +00:00
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2008-02-27 14:40:19 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
2011-11-22 09:45:47 +00:00
|
|
|
#include <strings.h>
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
#include "capabilities.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2009-12-18 13:44:55 +00:00
|
|
|
#include "cpu_conf.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2011-11-22 03:31:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_CAPABILITIES
|
|
|
|
|
2011-11-29 14:22:21 +00:00
|
|
|
VIR_ENUM_DECL(virCapsHostPMTarget)
|
|
|
|
VIR_ENUM_IMPL(virCapsHostPMTarget, VIR_NODE_SUSPEND_TARGET_LAST,
|
2011-11-29 14:14:03 +00:00
|
|
|
"suspend_mem", "suspend_disk", "suspend_hybrid");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-02-01 12:26:18 +00:00
|
|
|
static virClassPtr virCapsClass;
|
|
|
|
static void virCapabilitiesDispose(void *obj);
|
|
|
|
|
|
|
|
static int virCapabilitiesOnceInit(void)
|
|
|
|
{
|
|
|
|
if (!(virCapsClass = virClassNew(virClassForObject(),
|
|
|
|
"virCaps",
|
|
|
|
sizeof(virCaps),
|
|
|
|
virCapabilitiesDispose)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_ONCE_GLOBAL_INIT(virCapabilities)
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
/**
|
|
|
|
* virCapabilitiesNew:
|
2012-12-10 22:28:09 +00:00
|
|
|
* @hostarch: host machine architecture
|
2008-02-27 04:35:08 +00:00
|
|
|
* @offlineMigrate: non-zero if offline migration is available
|
|
|
|
* @liveMigrate: non-zero if live migration is available
|
2008-02-27 14:40:19 +00:00
|
|
|
*
|
2008-02-27 04:35:08 +00:00
|
|
|
* Allocate a new capabilities object
|
|
|
|
*/
|
|
|
|
virCapsPtr
|
2012-12-10 22:28:09 +00:00
|
|
|
virCapabilitiesNew(virArch hostarch,
|
2008-02-27 04:35:08 +00:00
|
|
|
int offlineMigrate,
|
|
|
|
int liveMigrate)
|
|
|
|
{
|
|
|
|
virCapsPtr caps;
|
|
|
|
|
2013-02-01 12:26:18 +00:00
|
|
|
if (virCapabilitiesInitialize() < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(caps = virObjectNew(virCapsClass)))
|
2008-05-29 15:28:28 +00:00
|
|
|
return NULL;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2012-12-10 22:28:09 +00:00
|
|
|
caps->host.arch = hostarch;
|
2008-02-27 04:35:08 +00:00
|
|
|
caps->host.offlineMigrate = offlineMigrate;
|
|
|
|
caps->host.liveMigrate = liveMigrate;
|
|
|
|
|
|
|
|
return caps;
|
|
|
|
}
|
|
|
|
|
2013-01-22 17:42:08 +00:00
|
|
|
void
|
|
|
|
virCapabilitiesClearHostNUMACellCPUTopology(virCapsHostNUMACellCPUPtr cpus,
|
|
|
|
size_t ncpus)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!cpus)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < ncpus; i++) {
|
|
|
|
virBitmapFree(cpus[i].siblings);
|
|
|
|
cpus[i].siblings = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
static void
|
|
|
|
virCapabilitiesFreeHostNUMACell(virCapsHostNUMACellPtr cell)
|
|
|
|
{
|
2008-05-29 15:28:28 +00:00
|
|
|
if (cell == NULL)
|
|
|
|
return;
|
|
|
|
|
2013-01-22 17:42:08 +00:00
|
|
|
virCapabilitiesClearHostNUMACellCPUTopology(cell->cpus, cell->ncpus);
|
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(cell->cpus);
|
|
|
|
VIR_FREE(cell);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
static void
|
|
|
|
virCapabilitiesFreeGuestMachine(virCapsGuestMachinePtr machine)
|
|
|
|
{
|
|
|
|
if (machine == NULL)
|
|
|
|
return;
|
|
|
|
VIR_FREE(machine->name);
|
|
|
|
VIR_FREE(machine->canonical);
|
|
|
|
VIR_FREE(machine);
|
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
static void
|
|
|
|
virCapabilitiesFreeGuestDomain(virCapsGuestDomainPtr dom)
|
|
|
|
{
|
|
|
|
int i;
|
2008-05-29 15:28:28 +00:00
|
|
|
if (dom == NULL)
|
|
|
|
return;
|
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(dom->info.emulator);
|
|
|
|
VIR_FREE(dom->info.loader);
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < dom->info.nmachines; i++)
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapabilitiesFreeGuestMachine(dom->info.machines[i]);
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(dom->info.machines);
|
|
|
|
VIR_FREE(dom->type);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(dom);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
virCapabilitiesFreeGuestFeature(virCapsGuestFeaturePtr feature)
|
|
|
|
{
|
2008-05-29 15:28:28 +00:00
|
|
|
if (feature == NULL)
|
|
|
|
return;
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(feature->name);
|
|
|
|
VIR_FREE(feature);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
virCapabilitiesFreeGuest(virCapsGuestPtr guest)
|
|
|
|
{
|
|
|
|
int i;
|
2008-05-29 15:28:28 +00:00
|
|
|
if (guest == NULL)
|
|
|
|
return;
|
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(guest->ostype);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(guest->arch.defaultInfo.emulator);
|
|
|
|
VIR_FREE(guest->arch.defaultInfo.loader);
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < guest->arch.defaultInfo.nmachines; i++)
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapabilitiesFreeGuestMachine(guest->arch.defaultInfo.machines[i]);
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(guest->arch.defaultInfo.machines);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < guest->arch.ndomains; i++)
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesFreeGuestDomain(guest->arch.domains[i]);
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(guest->arch.domains);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < guest->nfeatures; i++)
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesFreeGuestFeature(guest->features[i]);
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(guest->features);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(guest);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2009-06-29 10:41:56 +00:00
|
|
|
void
|
|
|
|
virCapabilitiesFreeNUMAInfo(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->host.nnumaCell; i++)
|
2009-06-29 10:41:56 +00:00
|
|
|
virCapabilitiesFreeHostNUMACell(caps->host.numaCell[i]);
|
|
|
|
VIR_FREE(caps->host.numaCell);
|
2009-08-13 10:56:31 +00:00
|
|
|
caps->host.nnumaCell = 0;
|
2009-06-29 10:41:56 +00:00
|
|
|
}
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-02-01 12:26:18 +00:00
|
|
|
static void
|
|
|
|
virCapabilitiesDispose(void *object)
|
|
|
|
{
|
|
|
|
virCapsPtr caps = object;
|
2008-02-27 04:35:08 +00:00
|
|
|
int i;
|
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++)
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesFreeGuest(caps->guests[i]);
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(caps->guests);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->host.nfeatures; i++)
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(caps->host.features[i]);
|
|
|
|
VIR_FREE(caps->host.features);
|
2009-06-29 10:41:56 +00:00
|
|
|
|
|
|
|
virCapabilitiesFreeNUMAInfo(caps);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->host.nmigrateTrans; i++)
|
2008-04-28 21:44:54 +00:00
|
|
|
VIR_FREE(caps->host.migrateTrans[i]);
|
|
|
|
VIR_FREE(caps->host.migrateTrans);
|
2008-03-03 13:15:14 +00:00
|
|
|
|
2012-08-15 22:10:35 +00:00
|
|
|
for (i = 0; i < caps->host.nsecModels; i++) {
|
|
|
|
VIR_FREE(caps->host.secModels[i].model);
|
|
|
|
VIR_FREE(caps->host.secModels[i].doi);
|
|
|
|
}
|
|
|
|
VIR_FREE(caps->host.secModels);
|
|
|
|
|
2009-12-18 13:44:55 +00:00
|
|
|
virCPUDefFree(caps->host.cpu);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesAddHostFeature:
|
|
|
|
* @caps: capabilities to extend
|
|
|
|
* @name: name of new feature
|
|
|
|
*
|
|
|
|
* Registers a new host CPU feature, eg 'pae', or 'vmx'
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCapabilitiesAddHostFeature(virCapsPtr caps,
|
|
|
|
const char *name)
|
|
|
|
{
|
2010-08-17 21:41:51 +00:00
|
|
|
if (VIR_RESIZE_N(caps->host.features, caps->host.nfeatures_max,
|
|
|
|
caps->host.nfeatures, 1) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ((caps->host.features[caps->host.nfeatures] = strdup(name)) == NULL)
|
|
|
|
return -1;
|
|
|
|
caps->host.nfeatures++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesAddHostMigrateTransport:
|
|
|
|
* @caps: capabilities to extend
|
|
|
|
* @name: name of migration transport
|
|
|
|
*
|
|
|
|
* Registers a new domain migration transport URI
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCapabilitiesAddHostMigrateTransport(virCapsPtr caps,
|
|
|
|
const char *name)
|
|
|
|
{
|
2010-08-17 21:41:51 +00:00
|
|
|
if (VIR_RESIZE_N(caps->host.migrateTrans, caps->host.nmigrateTrans_max,
|
|
|
|
caps->host.nmigrateTrans, 1) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ((caps->host.migrateTrans[caps->host.nmigrateTrans] = strdup(name)) == NULL)
|
|
|
|
return -1;
|
|
|
|
caps->host.nmigrateTrans++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesAddHostNUMACell:
|
|
|
|
* @caps: capabilities to extend
|
|
|
|
* @num: ID number of NUMA cell
|
|
|
|
* @ncpus: number of CPUs in cell
|
2013-01-22 17:42:08 +00:00
|
|
|
* @cpus: array of CPU definition structures, the pointer is stolen
|
2008-02-27 04:35:08 +00:00
|
|
|
*
|
|
|
|
* Registers a new NUMA cell for a host, passing in a
|
|
|
|
* array of CPU IDs belonging to the cell
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCapabilitiesAddHostNUMACell(virCapsPtr caps,
|
|
|
|
int num,
|
|
|
|
int ncpus,
|
2013-03-07 16:03:36 +00:00
|
|
|
unsigned long long mem,
|
2013-01-22 17:42:08 +00:00
|
|
|
virCapsHostNUMACellCPUPtr cpus)
|
2008-02-27 04:35:08 +00:00
|
|
|
{
|
2008-04-28 21:44:54 +00:00
|
|
|
virCapsHostNUMACellPtr cell;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2010-08-17 21:41:51 +00:00
|
|
|
if (VIR_RESIZE_N(caps->host.numaCell, caps->host.nnumaCell_max,
|
|
|
|
caps->host.nnumaCell, 1) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
return -1;
|
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
if (VIR_ALLOC(cell) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
return -1;
|
|
|
|
|
2008-07-07 09:52:26 +00:00
|
|
|
cell->ncpus = ncpus;
|
|
|
|
cell->num = num;
|
2013-03-07 16:03:36 +00:00
|
|
|
cell->mem = mem;
|
2013-01-22 17:42:08 +00:00
|
|
|
cell->cpus = cpus;
|
2008-07-07 09:52:26 +00:00
|
|
|
|
2010-08-17 21:41:51 +00:00
|
|
|
caps->host.numaCell[caps->host.nnumaCell++] = cell;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-18 13:44:55 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesSetHostCPU:
|
|
|
|
* @caps: capabilities to extend
|
|
|
|
* @cpu: CPU definition
|
|
|
|
*
|
|
|
|
* Sets host CPU specification
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCapabilitiesSetHostCPU(virCapsPtr caps,
|
|
|
|
virCPUDefPtr cpu)
|
|
|
|
{
|
|
|
|
if (cpu == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
caps->host.cpu = cpu;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-23 17:31:34 +00:00
|
|
|
/**
|
|
|
|
* virCapabilitiesAllocMachines:
|
|
|
|
* @machines: machine variants for emulator ('pc', or 'isapc', etc)
|
|
|
|
* @nmachines: number of machine variants for emulator
|
|
|
|
*
|
|
|
|
* Allocate a table of virCapsGuestMachinePtr from the supplied table
|
|
|
|
* of machine names.
|
|
|
|
*/
|
|
|
|
virCapsGuestMachinePtr *
|
|
|
|
virCapabilitiesAllocMachines(const char *const *names, int nnames)
|
|
|
|
{
|
|
|
|
virCapsGuestMachinePtr *machines;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(machines, nnames) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < nnames; i++) {
|
|
|
|
if (VIR_ALLOC(machines[i]) < 0 ||
|
|
|
|
!(machines[i]->name = strdup(names[i]))) {
|
|
|
|
virCapabilitiesFreeMachines(machines, nnames);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return machines;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesFreeMachines:
|
|
|
|
* @machines: table of vircapsGuestMachinePtr
|
|
|
|
*
|
|
|
|
* Free a table of virCapsGuestMachinePtr
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virCapabilitiesFreeMachines(virCapsGuestMachinePtr *machines,
|
|
|
|
int nmachines)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (!machines)
|
|
|
|
return;
|
|
|
|
for (i = 0; i < nmachines && machines[i]; i++) {
|
|
|
|
virCapabilitiesFreeGuestMachine(machines[i]);
|
|
|
|
machines[i] = NULL;
|
|
|
|
}
|
|
|
|
VIR_FREE(machines);
|
|
|
|
}
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesAddGuest:
|
|
|
|
* @caps: capabilities to extend
|
|
|
|
* @ostype: guest operating system type ('hvm' or 'xen')
|
2012-12-10 22:28:09 +00:00
|
|
|
* @arch: guest CPU architecture
|
2008-02-27 04:35:08 +00:00
|
|
|
* @wordsize: number of bits in CPU word
|
|
|
|
* @emulator: path to default device emulator for arch/ostype
|
|
|
|
* @loader: path to default BIOS loader for arch/ostype
|
|
|
|
* @nmachines: number of machine variants for emulator
|
|
|
|
* @machines: machine variants for emulator ('pc', or 'isapc', etc)
|
|
|
|
*
|
|
|
|
* Registers a new guest operating system. This should be
|
|
|
|
* followed by registration of at least one domain for
|
|
|
|
* running the guest
|
|
|
|
*/
|
|
|
|
virCapsGuestPtr
|
|
|
|
virCapabilitiesAddGuest(virCapsPtr caps,
|
|
|
|
const char *ostype,
|
2012-12-10 22:28:09 +00:00
|
|
|
virArch arch,
|
2008-02-27 04:35:08 +00:00
|
|
|
const char *emulator,
|
|
|
|
const char *loader,
|
|
|
|
int nmachines,
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapsGuestMachinePtr *machines)
|
2008-02-27 04:35:08 +00:00
|
|
|
{
|
2008-04-28 21:44:54 +00:00
|
|
|
virCapsGuestPtr guest;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
if (VIR_ALLOC(guest) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if ((guest->ostype = strdup(ostype)) == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
|
2012-12-10 22:28:09 +00:00
|
|
|
guest->arch.id = arch;
|
|
|
|
guest->arch.wordsize = virArchGetWordSize(arch);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
if (emulator &&
|
|
|
|
(guest->arch.defaultInfo.emulator = strdup(emulator)) == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
if (loader &&
|
|
|
|
(guest->arch.defaultInfo.loader = strdup(loader)) == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
|
2010-08-17 21:41:51 +00:00
|
|
|
if (VIR_RESIZE_N(caps->guests, caps->nguests_max,
|
|
|
|
caps->nguests, 1) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
goto no_memory;
|
2010-08-17 21:41:51 +00:00
|
|
|
caps->guests[caps->nguests++] = guest;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2009-09-02 14:09:04 +00:00
|
|
|
if (nmachines) {
|
|
|
|
guest->arch.defaultInfo.nmachines = nmachines;
|
|
|
|
guest->arch.defaultInfo.machines = machines;
|
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
return guest;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virCapabilitiesFreeGuest(guest);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesAddGuestDomain:
|
|
|
|
* @guest: guest to support
|
|
|
|
* @hvtype: hypervisor type ('xen', 'qemu', 'kvm')
|
|
|
|
* @emulator: specialized device emulator for domain
|
|
|
|
* @loader: specialized BIOS loader for domain
|
|
|
|
* @nmachines: number of machine variants for emulator
|
|
|
|
* @machines: specialized machine variants for emulator
|
|
|
|
*
|
|
|
|
* Registers a virtual domain capable of running a
|
|
|
|
* guest operating system
|
|
|
|
*/
|
|
|
|
virCapsGuestDomainPtr
|
|
|
|
virCapabilitiesAddGuestDomain(virCapsGuestPtr guest,
|
|
|
|
const char *hvtype,
|
|
|
|
const char *emulator,
|
|
|
|
const char *loader,
|
|
|
|
int nmachines,
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapsGuestMachinePtr *machines)
|
2008-02-27 04:35:08 +00:00
|
|
|
{
|
2008-04-28 21:44:54 +00:00
|
|
|
virCapsGuestDomainPtr dom;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
if (VIR_ALLOC(dom) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if ((dom->type = strdup(hvtype)) == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if (emulator &&
|
|
|
|
(dom->info.emulator = strdup(emulator)) == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
if (loader &&
|
|
|
|
(dom->info.loader = strdup(loader)) == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
|
2010-08-17 21:41:51 +00:00
|
|
|
if (VIR_RESIZE_N(guest->arch.domains, guest->arch.ndomains_max,
|
|
|
|
guest->arch.ndomains, 1) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
goto no_memory;
|
|
|
|
guest->arch.domains[guest->arch.ndomains] = dom;
|
|
|
|
guest->arch.ndomains++;
|
|
|
|
|
2009-09-02 14:09:04 +00:00
|
|
|
if (nmachines) {
|
|
|
|
dom->info.nmachines = nmachines;
|
|
|
|
dom->info.machines = machines;
|
|
|
|
}
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
return dom;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virCapabilitiesFreeGuestDomain(dom);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesAddGuestFeature:
|
|
|
|
* @guest: guest to associate feature with
|
|
|
|
* @name: name of feature ('pae', 'acpi', 'apic')
|
|
|
|
* @defaultOn: non-zero if it defaults to on
|
|
|
|
* @toggle: non-zero if its state can be toggled
|
|
|
|
*
|
|
|
|
* Registers a feature for a guest domain
|
|
|
|
*/
|
|
|
|
virCapsGuestFeaturePtr
|
|
|
|
virCapabilitiesAddGuestFeature(virCapsGuestPtr guest,
|
|
|
|
const char *name,
|
|
|
|
int defaultOn,
|
|
|
|
int toggle)
|
|
|
|
{
|
2008-04-28 21:44:54 +00:00
|
|
|
virCapsGuestFeaturePtr feature;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
if (VIR_ALLOC(feature) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
if ((feature->name = strdup(name)) == NULL)
|
|
|
|
goto no_memory;
|
|
|
|
feature->defaultOn = defaultOn;
|
|
|
|
feature->toggle = toggle;
|
|
|
|
|
2010-08-17 21:41:51 +00:00
|
|
|
if (VIR_RESIZE_N(guest->features, guest->nfeatures_max,
|
|
|
|
guest->nfeatures, 1) < 0)
|
2008-02-27 04:35:08 +00:00
|
|
|
goto no_memory;
|
2010-08-17 21:41:51 +00:00
|
|
|
guest->features[guest->nfeatures++] = feature;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
return feature;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virCapabilitiesFreeGuestFeature(feature);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-02-20 18:40:30 +00:00
|
|
|
/**
|
|
|
|
* virCapabilitiesSupportsGuestArch:
|
|
|
|
* @caps: capabilities to query
|
2012-12-10 22:28:09 +00:00
|
|
|
* @arch: Architecture to search for
|
2012-02-20 18:40:30 +00:00
|
|
|
*
|
|
|
|
* Returns non-zero if the capabilities support the
|
|
|
|
* requested architecture
|
|
|
|
*/
|
|
|
|
extern int
|
|
|
|
virCapabilitiesSupportsGuestArch(virCapsPtr caps,
|
2012-12-10 22:28:09 +00:00
|
|
|
virArch arch)
|
2012-02-20 18:40:30 +00:00
|
|
|
{
|
|
|
|
int i;
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
2012-12-10 22:28:09 +00:00
|
|
|
if (caps->guests[i]->arch.id == arch)
|
2012-02-20 18:40:30 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesSupportsGuestOSType:
|
|
|
|
* @caps: capabilities to query
|
|
|
|
* @ostype: OS type to search for (eg 'hvm', 'xen')
|
|
|
|
*
|
|
|
|
* Returns non-zero if the capabilities support the
|
|
|
|
* requested operating system type
|
|
|
|
*/
|
|
|
|
extern int
|
|
|
|
virCapabilitiesSupportsGuestOSType(virCapsPtr caps,
|
|
|
|
const char *ostype)
|
|
|
|
{
|
|
|
|
int i;
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
2008-02-27 04:35:08 +00:00
|
|
|
if (STREQ(caps->guests[i]->ostype, ostype))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-30 17:12:28 +00:00
|
|
|
/**
|
2012-02-20 18:40:30 +00:00
|
|
|
* virCapabilitiesSupportsGuestOSTypeArch:
|
2009-01-30 17:12:28 +00:00
|
|
|
* @caps: capabilities to query
|
|
|
|
* @ostype: OS type to search for (eg 'hvm', 'xen')
|
2012-12-10 22:28:09 +00:00
|
|
|
* @arch: Architecture to search for
|
2009-01-30 17:12:28 +00:00
|
|
|
*
|
|
|
|
* Returns non-zero if the capabilities support the
|
|
|
|
* requested operating system type
|
|
|
|
*/
|
|
|
|
extern int
|
2012-02-20 18:40:30 +00:00
|
|
|
virCapabilitiesSupportsGuestOSTypeArch(virCapsPtr caps,
|
|
|
|
const char *ostype,
|
2012-12-10 22:28:09 +00:00
|
|
|
virArch arch)
|
2009-01-30 17:12:28 +00:00
|
|
|
{
|
|
|
|
int i;
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
2009-01-30 17:12:28 +00:00
|
|
|
if (STREQ(caps->guests[i]->ostype, ostype) &&
|
2012-12-10 22:28:09 +00:00
|
|
|
caps->guests[i]->arch.id == arch)
|
2009-01-30 17:12:28 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
/**
|
|
|
|
* virCapabilitiesDefaultGuestArch:
|
|
|
|
* @caps: capabilities to query
|
|
|
|
* @ostype: OS type to search for
|
|
|
|
*
|
|
|
|
* Returns the first architecture able to run the
|
|
|
|
* requested operating system type
|
|
|
|
*/
|
2012-12-10 22:28:09 +00:00
|
|
|
extern virArch
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesDefaultGuestArch(virCapsPtr caps,
|
2009-03-24 11:16:29 +00:00
|
|
|
const char *ostype,
|
|
|
|
const char *domain)
|
2008-02-27 04:35:08 +00:00
|
|
|
{
|
2009-03-24 11:16:29 +00:00
|
|
|
int i, j;
|
2012-12-10 22:28:09 +00:00
|
|
|
|
|
|
|
/* First try to find one matching host arch */
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
2009-03-24 11:16:29 +00:00
|
|
|
if (STREQ(caps->guests[i]->ostype, ostype)) {
|
2013-05-21 07:21:17 +00:00
|
|
|
for (j = 0; j < caps->guests[i]->arch.ndomains; j++) {
|
2012-12-10 22:28:09 +00:00
|
|
|
if (STREQ(caps->guests[i]->arch.domains[j]->type, domain) &&
|
|
|
|
caps->guests[i]->arch.id == caps->host.arch)
|
|
|
|
return caps->guests[i]->arch.id;
|
2009-03-24 11:16:29 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2012-12-10 22:28:09 +00:00
|
|
|
|
|
|
|
/* Otherwise find the first match */
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
2012-12-10 22:28:09 +00:00
|
|
|
if (STREQ(caps->guests[i]->ostype, ostype)) {
|
2013-05-21 07:21:17 +00:00
|
|
|
for (j = 0; j < caps->guests[i]->arch.ndomains; j++) {
|
2012-12-10 22:28:09 +00:00
|
|
|
if (STREQ(caps->guests[i]->arch.domains[j]->type, domain))
|
|
|
|
return caps->guests[i]->arch.id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return VIR_ARCH_NONE;
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesDefaultGuestMachine:
|
|
|
|
* @caps: capabilities to query
|
|
|
|
* @ostype: OS type to search for
|
|
|
|
* @arch: architecture to search for
|
2009-10-12 09:52:13 +00:00
|
|
|
* @domain: domain type to search for
|
2008-02-27 04:35:08 +00:00
|
|
|
*
|
|
|
|
* Returns the first machine variant associated with
|
2009-10-12 09:52:13 +00:00
|
|
|
* the requested operating system type, architecture
|
|
|
|
* and domain type
|
2008-02-27 04:35:08 +00:00
|
|
|
*/
|
|
|
|
extern const char *
|
|
|
|
virCapabilitiesDefaultGuestMachine(virCapsPtr caps,
|
|
|
|
const char *ostype,
|
2012-12-10 22:28:09 +00:00
|
|
|
virArch arch,
|
2009-10-12 09:52:13 +00:00
|
|
|
const char *domain)
|
2008-02-27 04:35:08 +00:00
|
|
|
{
|
|
|
|
int i;
|
2009-10-12 09:52:13 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
2009-10-12 09:52:13 +00:00
|
|
|
virCapsGuestPtr guest = caps->guests[i];
|
|
|
|
int j;
|
|
|
|
|
2012-12-10 22:28:09 +00:00
|
|
|
if (!STREQ(guest->ostype, ostype) ||
|
|
|
|
guest->arch.id != arch)
|
2009-10-12 09:52:13 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < guest->arch.ndomains; j++) {
|
2012-12-10 22:28:09 +00:00
|
|
|
virCapsGuestDomainPtr dom = guest->arch.domains[j];
|
2009-10-12 09:52:13 +00:00
|
|
|
|
|
|
|
if (!STREQ(dom->type, domain))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!dom->info.nmachines)
|
|
|
|
break;
|
|
|
|
|
|
|
|
return dom->info.machines[0]->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (guest->arch.defaultInfo.nmachines)
|
2009-07-23 17:31:34 +00:00
|
|
|
return caps->guests[i]->arch.defaultInfo.machines[0]->name;
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2009-10-12 09:52:13 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-07-30 14:31:41 +00:00
|
|
|
* virCapabilitiesDefaultGuestEmulator:
|
2008-02-27 04:35:08 +00:00
|
|
|
* @caps: capabilities to query
|
|
|
|
* @ostype: OS type to search for ('xen', 'hvm')
|
|
|
|
* @arch: architecture to search for
|
|
|
|
* @domain: domain type ('xen', 'qemu', 'kvm')
|
|
|
|
*
|
|
|
|
* Returns the first emulator path associated with
|
|
|
|
* the requested operating system type, architecture
|
|
|
|
* and domain type
|
|
|
|
*/
|
|
|
|
extern const char *
|
|
|
|
virCapabilitiesDefaultGuestEmulator(virCapsPtr caps,
|
|
|
|
const char *ostype,
|
2012-12-10 22:28:09 +00:00
|
|
|
virArch arch,
|
2008-02-27 04:35:08 +00:00
|
|
|
const char *domain)
|
|
|
|
{
|
|
|
|
int i, j;
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
2008-02-27 04:35:08 +00:00
|
|
|
char *emulator;
|
|
|
|
if (STREQ(caps->guests[i]->ostype, ostype) &&
|
2012-12-10 22:28:09 +00:00
|
|
|
caps->guests[i]->arch.id == arch) {
|
2008-02-27 04:35:08 +00:00
|
|
|
emulator = caps->guests[i]->arch.defaultInfo.emulator;
|
2013-05-21 07:21:17 +00:00
|
|
|
for (j = 0; j < caps->guests[i]->arch.ndomains; j++) {
|
2008-02-27 04:35:08 +00:00
|
|
|
if (STREQ(caps->guests[i]->arch.domains[j]->type, domain)) {
|
|
|
|
if (caps->guests[i]->arch.domains[j]->info.emulator)
|
|
|
|
emulator = caps->guests[i]->arch.domains[j]->info.emulator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return emulator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-18 22:06:55 +00:00
|
|
|
static int
|
2013-01-18 19:39:00 +00:00
|
|
|
virCapabilitiesFormatNUMATopology(virBufferPtr xml,
|
|
|
|
size_t ncells,
|
|
|
|
virCapsHostNUMACellPtr *cells)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int j;
|
2013-01-18 22:06:55 +00:00
|
|
|
char *siblings;
|
2013-01-18 19:39:00 +00:00
|
|
|
|
|
|
|
virBufferAddLit(xml, " <topology>\n");
|
|
|
|
virBufferAsprintf(xml, " <cells num='%zu'>\n", ncells);
|
|
|
|
for (i = 0; i < ncells; i++) {
|
|
|
|
virBufferAsprintf(xml, " <cell id='%d'>\n", cells[i]->num);
|
2013-03-07 16:03:36 +00:00
|
|
|
|
|
|
|
/* Print out the numacell memory total if it is available */
|
|
|
|
if (cells[i]->mem)
|
|
|
|
virBufferAsprintf(xml,
|
|
|
|
" <memory unit='KiB'>%llu</memory>\n",
|
|
|
|
cells[i]->mem);
|
|
|
|
|
2013-01-18 19:39:00 +00:00
|
|
|
virBufferAsprintf(xml, " <cpus num='%d'>\n", cells[i]->ncpus);
|
2013-01-18 22:06:55 +00:00
|
|
|
for (j = 0; j < cells[i]->ncpus; j++) {
|
|
|
|
virBufferAsprintf(xml, " <cpu id='%d'",
|
2013-01-22 17:42:08 +00:00
|
|
|
cells[i]->cpus[j].id);
|
2013-01-18 22:06:55 +00:00
|
|
|
|
|
|
|
if (cells[i]->cpus[j].siblings) {
|
|
|
|
if (!(siblings = virBitmapFormat(cells[i]->cpus[j].siblings))) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAsprintf(xml,
|
|
|
|
" socket_id='%d' core_id='%d' siblings='%s'",
|
|
|
|
cells[i]->cpus[j].socket_id,
|
|
|
|
cells[i]->cpus[j].core_id,
|
|
|
|
siblings);
|
|
|
|
VIR_FREE(siblings);
|
|
|
|
}
|
|
|
|
virBufferAddLit(xml, "/>\n");
|
|
|
|
}
|
|
|
|
|
2013-01-18 19:39:00 +00:00
|
|
|
virBufferAddLit(xml, " </cpus>\n");
|
|
|
|
virBufferAddLit(xml, " </cell>\n");
|
|
|
|
}
|
|
|
|
virBufferAddLit(xml, " </cells>\n");
|
|
|
|
virBufferAddLit(xml, " </topology>\n");
|
2013-01-18 22:06:55 +00:00
|
|
|
|
|
|
|
return 0;
|
2013-01-18 19:39:00 +00:00
|
|
|
}
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesFormatXML:
|
|
|
|
* @caps: capabilities to format
|
|
|
|
*
|
|
|
|
* Convert the capabilities object into an XML representation
|
|
|
|
*
|
|
|
|
* Returns the XML document as a string
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
virCapabilitiesFormatXML(virCapsPtr caps)
|
|
|
|
{
|
2008-04-28 15:14:59 +00:00
|
|
|
virBuffer xml = VIR_BUFFER_INITIALIZER;
|
2008-02-27 04:35:08 +00:00
|
|
|
int i, j, k;
|
2010-05-25 14:33:51 +00:00
|
|
|
char host_uuid[VIR_UUID_STRING_BUFLEN];
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, "<capabilities>\n\n");
|
|
|
|
virBufferAddLit(&xml, " <host>\n");
|
2010-05-25 14:33:51 +00:00
|
|
|
if (virUUIDIsValid(caps->host.host_uuid)) {
|
|
|
|
virUUIDFormat(caps->host.host_uuid, host_uuid);
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml," <uuid>%s</uuid>\n", host_uuid);
|
2010-05-25 14:33:51 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " <cpu>\n");
|
2012-12-10 22:28:09 +00:00
|
|
|
if (caps->host.arch)
|
|
|
|
virBufferAsprintf(&xml, " <arch>%s</arch>\n",
|
|
|
|
virArchToString(caps->host.arch));
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
if (caps->host.nfeatures) {
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " <features>\n");
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->host.nfeatures; i++) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <%s/>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->host.features[i]);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </features>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2009-12-18 13:44:55 +00:00
|
|
|
|
2011-09-21 23:42:07 +00:00
|
|
|
virBufferAdjustIndent(&xml, 6);
|
2011-08-18 10:14:36 +00:00
|
|
|
virCPUDefFormatBuf(&xml, caps->host.cpu, 0);
|
2011-09-21 23:42:07 +00:00
|
|
|
virBufferAdjustIndent(&xml, -6);
|
2009-12-18 13:44:55 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </cpu>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2011-11-29 14:50:04 +00:00
|
|
|
/* The PM query was successful. */
|
|
|
|
if (caps->host.powerMgmt) {
|
|
|
|
/* The host supports some PM features. */
|
|
|
|
unsigned int pm = caps->host.powerMgmt;
|
|
|
|
virBufferAddLit(&xml, " <power_management>\n");
|
|
|
|
while (pm) {
|
|
|
|
int bit = ffs(pm) - 1;
|
|
|
|
virBufferAsprintf(&xml, " <%s/>\n",
|
|
|
|
virCapsHostPMTargetTypeToString(bit));
|
|
|
|
pm &= ~(1U << bit);
|
2011-11-22 03:31:22 +00:00
|
|
|
}
|
2011-11-29 14:50:04 +00:00
|
|
|
virBufferAddLit(&xml, " </power_management>\n");
|
|
|
|
} else {
|
|
|
|
/* The host does not support any PM feature. */
|
|
|
|
virBufferAddLit(&xml, " <power_management/>\n");
|
2011-11-22 03:31:22 +00:00
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
if (caps->host.offlineMigrate) {
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " <migration_features>\n");
|
|
|
|
if (caps->host.liveMigrate)
|
|
|
|
virBufferAddLit(&xml, " <live/>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
if (caps->host.nmigrateTrans) {
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " <uri_transports>\n");
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->host.nmigrateTrans; i++) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <uri_transport>%s</uri_transport>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->host.migrateTrans[i]);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </uri_transports>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </migration_features>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2013-01-18 22:06:55 +00:00
|
|
|
if (caps->host.nnumaCell &&
|
2013-01-18 19:39:00 +00:00
|
|
|
virCapabilitiesFormatNUMATopology(&xml, caps->host.nnumaCell,
|
2013-01-18 22:06:55 +00:00
|
|
|
caps->host.numaCell) < 0)
|
|
|
|
return NULL;
|
2009-03-03 09:44:41 +00:00
|
|
|
|
2012-08-15 22:10:36 +00:00
|
|
|
for (i = 0; i < caps->host.nsecModels; i++) {
|
2009-03-03 09:44:41 +00:00
|
|
|
virBufferAddLit(&xml, " <secmodel>\n");
|
2012-08-15 22:10:35 +00:00
|
|
|
virBufferAsprintf(&xml, " <model>%s</model>\n",
|
2012-08-15 22:10:36 +00:00
|
|
|
caps->host.secModels[i].model);
|
2012-08-15 22:10:35 +00:00
|
|
|
virBufferAsprintf(&xml, " <doi>%s</doi>\n",
|
2012-08-15 22:10:36 +00:00
|
|
|
caps->host.secModels[i].doi);
|
2009-03-03 09:44:41 +00:00
|
|
|
virBufferAddLit(&xml, " </secmodel>\n");
|
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </host>\n\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " <guest>\n");
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <os_type>%s</os_type>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->ostype);
|
2012-12-10 22:28:09 +00:00
|
|
|
if (caps->guests[i]->arch.id)
|
|
|
|
virBufferAsprintf(&xml, " <arch name='%s'>\n",
|
|
|
|
virArchToString(caps->guests[i]->arch.id));
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <wordsize>%d</wordsize>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->arch.wordsize);
|
|
|
|
if (caps->guests[i]->arch.defaultInfo.emulator)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <emulator>%s</emulator>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->arch.defaultInfo.emulator);
|
|
|
|
if (caps->guests[i]->arch.defaultInfo.loader)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <loader>%s</loader>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->arch.defaultInfo.loader);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (j = 0; j < caps->guests[i]->arch.defaultInfo.nmachines; j++) {
|
2009-07-23 17:31:35 +00:00
|
|
|
virCapsGuestMachinePtr machine = caps->guests[i]->arch.defaultInfo.machines[j];
|
|
|
|
virBufferAddLit(&xml, " <machine");
|
|
|
|
if (machine->canonical)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " canonical='%s'", machine->canonical);
|
|
|
|
virBufferAsprintf(&xml, ">%s</machine>\n", machine->name);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (j = 0; j < caps->guests[i]->arch.ndomains; j++) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <domain type='%s'>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->arch.domains[j]->type);
|
|
|
|
if (caps->guests[i]->arch.domains[j]->info.emulator)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <emulator>%s</emulator>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->arch.domains[j]->info.emulator);
|
|
|
|
if (caps->guests[i]->arch.domains[j]->info.loader)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <loader>%s</loader>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->arch.domains[j]->info.loader);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (k = 0; k < caps->guests[i]->arch.domains[j]->info.nmachines; k++) {
|
2009-07-23 17:31:35 +00:00
|
|
|
virCapsGuestMachinePtr machine = caps->guests[i]->arch.domains[j]->info.machines[k];
|
2009-09-07 13:11:43 +00:00
|
|
|
virBufferAddLit(&xml, " <machine");
|
2009-07-23 17:31:35 +00:00
|
|
|
if (machine->canonical)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " canonical='%s'", machine->canonical);
|
|
|
|
virBufferAsprintf(&xml, ">%s</machine>\n", machine->name);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </domain>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </arch>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
if (caps->guests[i]->nfeatures) {
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " <features>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (j = 0; j < caps->guests[i]->nfeatures; j++) {
|
2008-02-27 04:35:08 +00:00
|
|
|
if (STREQ(caps->guests[i]->features[j]->name, "pae") ||
|
|
|
|
STREQ(caps->guests[i]->features[j]->name, "nonpae") ||
|
2009-12-18 13:44:55 +00:00
|
|
|
STREQ(caps->guests[i]->features[j]->name, "ia64_be") ||
|
2011-01-12 14:19:34 +00:00
|
|
|
STREQ(caps->guests[i]->features[j]->name, "cpuselection") ||
|
|
|
|
STREQ(caps->guests[i]->features[j]->name, "deviceboot")) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <%s/>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->features[j]->name);
|
2008-02-27 04:35:08 +00:00
|
|
|
} else {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&xml, " <%s default='%s' toggle='%s'/>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
caps->guests[i]->features[j]->name,
|
|
|
|
caps->guests[i]->features[j]->defaultOn ? "on" : "off",
|
|
|
|
caps->guests[i]->features[j]->toggle ? "yes" : "no");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </features>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, " </guest>\n\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&xml, "</capabilities>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2009-12-09 23:00:50 +00:00
|
|
|
if (virBufferError(&xml)) {
|
|
|
|
virBufferFreeAndReset(&xml);
|
2008-04-28 15:14:59 +00:00
|
|
|
return NULL;
|
2009-12-09 23:00:50 +00:00
|
|
|
}
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return virBufferContentAndReset(&xml);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|