2008-02-27 04:35:08 +00:00
|
|
|
/*
|
|
|
|
* capabilities.c: hypervisor capabilities
|
|
|
|
*
|
2015-09-17 08:46:55 +00:00
|
|
|
* Copyright (C) 2006-2015 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
|
|
|
*/
|
|
|
|
|
2008-02-27 14:40:19 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
2017-03-07 09:40:15 +00:00
|
|
|
#include <unistd.h>
|
2011-11-22 09:45:47 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
#include "capabilities.h"
|
2009-12-18 13:44:55 +00:00
|
|
|
#include "cpu_conf.h"
|
2017-03-07 09:40:15 +00:00
|
|
|
#include "domain_conf.h"
|
|
|
|
#include "physmem.h"
|
2019-01-10 12:19:35 +00:00
|
|
|
#include "storage_conf.h"
|
2017-03-07 09:40:15 +00:00
|
|
|
#include "viralloc.h"
|
|
|
|
#include "virarch.h"
|
|
|
|
#include "virbuffer.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2017-03-07 09:40:15 +00:00
|
|
|
#include "virfile.h"
|
|
|
|
#include "virhostcpu.h"
|
|
|
|
#include "virhostmem.h"
|
|
|
|
#include "virlog.h"
|
|
|
|
#include "virnuma.h"
|
2013-05-03 12:40:46 +00:00
|
|
|
#include "virstring.h"
|
2017-03-07 09:40:15 +00:00
|
|
|
#include "virtypedparam.h"
|
|
|
|
#include "viruuid.h"
|
2019-04-01 10:14:26 +00:00
|
|
|
#include "virenum.h"
|
2011-11-22 03:31:22 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_CAPABILITIES
|
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
#define SYSFS_SYSTEM_PATH "/sys/devices/system"
|
|
|
|
|
2019-01-20 16:32:42 +00:00
|
|
|
VIR_LOG_INIT("conf.capabilities");
|
2017-03-07 09:40:15 +00:00
|
|
|
|
2019-01-20 16:04:56 +00:00
|
|
|
VIR_ENUM_DECL(virCapsHostPMTarget);
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_ENUM_IMPL(virCapsHostPMTarget,
|
|
|
|
VIR_NODE_SUSPEND_TARGET_LAST,
|
2019-01-20 16:30:15 +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;
|
2018-04-13 12:56:40 +00:00
|
|
|
static void virCapsDispose(void *obj);
|
2013-02-01 12:26:18 +00:00
|
|
|
|
|
|
|
static int virCapabilitiesOnceInit(void)
|
|
|
|
{
|
2018-04-17 15:42:33 +00:00
|
|
|
if (!VIR_CLASS_NEW(virCaps, virClassForObject()))
|
2013-02-01 12:26:18 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:23:29 +00:00
|
|
|
VIR_ONCE_GLOBAL_INIT(virCapabilities);
|
2013-02-01 12:26:18 +00:00
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
/**
|
|
|
|
* virCapabilitiesNew:
|
2012-12-10 22:28:09 +00:00
|
|
|
* @hostarch: host machine architecture
|
2014-07-14 12:56:13 +00:00
|
|
|
* @offlineMigrate: true if offline migration is available
|
|
|
|
* @liveMigrate: true 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,
|
2014-07-14 12:56:13 +00:00
|
|
|
bool offlineMigrate,
|
|
|
|
bool liveMigrate)
|
2008-02-27 04:35:08 +00:00
|
|
|
{
|
|
|
|
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);
|
2014-06-03 13:18:27 +00:00
|
|
|
VIR_FREE(cell->siblings);
|
2014-06-06 16:12:51 +00:00
|
|
|
VIR_FREE(cell->pageinfo);
|
2008-04-28 21:44:54 +00:00
|
|
|
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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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);
|
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
|
|
|
}
|
|
|
|
|
2017-03-15 12:01:13 +00:00
|
|
|
void
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesFreeGuest(virCapsGuestPtr guest)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-05-29 15:28:28 +00:00
|
|
|
if (guest == NULL)
|
|
|
|
return;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-01-10 12:19:35 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
virCapabilitiesFreeStoragePool(virCapsStoragePoolPtr pool)
|
|
|
|
{
|
|
|
|
if (!pool)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(pool);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-29 10:41:56 +00:00
|
|
|
void
|
|
|
|
virCapabilitiesFreeNUMAInfo(virCapsPtr caps)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2009-06-29 10:41:56 +00:00
|
|
|
|
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
|
|
|
|
2018-07-30 03:12:41 +00:00
|
|
|
static void
|
|
|
|
virCapsHostMemBWNodeFree(virCapsHostMemBWNodePtr ptr)
|
|
|
|
{
|
|
|
|
if (!ptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virBitmapFree(ptr->cpus);
|
|
|
|
VIR_FREE(ptr);
|
|
|
|
}
|
|
|
|
|
2013-10-18 12:13:21 +00:00
|
|
|
static void
|
|
|
|
virCapabilitiesClearSecModel(virCapsHostSecModelPtr secmodel)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < secmodel->nlabels; i++) {
|
|
|
|
VIR_FREE(secmodel->labels[i].type);
|
|
|
|
VIR_FREE(secmodel->labels[i].label);
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(secmodel->labels);
|
|
|
|
VIR_FREE(secmodel->model);
|
|
|
|
VIR_FREE(secmodel->doi);
|
|
|
|
}
|
|
|
|
|
2013-02-01 12:26:18 +00:00
|
|
|
static void
|
2018-04-13 12:56:40 +00:00
|
|
|
virCapsDispose(void *object)
|
2013-02-01 12:26:18 +00:00
|
|
|
{
|
|
|
|
virCapsPtr caps = object;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2019-01-10 12:19:35 +00:00
|
|
|
for (i = 0; i < caps->npools; i++)
|
|
|
|
virCapabilitiesFreeStoragePool(caps->pools[i]);
|
|
|
|
VIR_FREE(caps->pools);
|
|
|
|
|
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
|
|
|
|
2014-11-13 14:23:27 +00:00
|
|
|
for (i = 0; i < caps->host.nsecModels; i++)
|
2013-10-18 12:13:21 +00:00
|
|
|
virCapabilitiesClearSecModel(&caps->host.secModels[i]);
|
2012-08-15 22:10:35 +00:00
|
|
|
VIR_FREE(caps->host.secModels);
|
|
|
|
|
2018-09-20 10:10:48 +00:00
|
|
|
for (i = 0; i < caps->host.cache.nbanks; i++)
|
|
|
|
virCapsHostCacheBankFree(caps->host.cache.banks[i]);
|
2018-09-20 10:10:50 +00:00
|
|
|
virResctrlInfoMonFree(caps->host.cache.monitor);
|
2018-09-20 10:10:48 +00:00
|
|
|
VIR_FREE(caps->host.cache.banks);
|
2017-03-30 13:01:27 +00:00
|
|
|
|
2018-09-20 10:10:49 +00:00
|
|
|
for (i = 0; i < caps->host.memBW.nnodes; i++)
|
|
|
|
virCapsHostMemBWNodeFree(caps->host.memBW.nodes[i]);
|
2018-09-20 10:10:50 +00:00
|
|
|
virResctrlInfoMonFree(caps->host.memBW.monitor);
|
2018-09-20 10:10:49 +00:00
|
|
|
VIR_FREE(caps->host.memBW.nodes);
|
2018-07-30 03:12:41 +00:00
|
|
|
|
2016-02-03 21:40:33 +00:00
|
|
|
VIR_FREE(caps->host.netprefix);
|
2014-06-06 16:12:51 +00:00
|
|
|
VIR_FREE(caps->host.pagesSize);
|
2009-12-18 13:44:55 +00:00
|
|
|
virCPUDefFree(caps->host.cpu);
|
2017-11-20 12:43:30 +00:00
|
|
|
virObjectUnref(caps->host.resctrl);
|
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;
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
caps->host.features[caps->host.nfeatures] = g_strdup(name);
|
2008-02-27 04:35:08 +00:00
|
|
|
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;
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
caps->host.migrateTrans[caps->host.nmigrateTrans] = g_strdup(name);
|
2008-02-27 04:35:08 +00:00
|
|
|
caps->host.nmigrateTrans++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-03 21:40:33 +00:00
|
|
|
/**
|
|
|
|
* virCapabilitiesSetNetPrefix:
|
|
|
|
* @caps: capabilities to extend
|
|
|
|
* @name: prefix for host generated network interfaces
|
|
|
|
*
|
|
|
|
* Registers the prefix that is used for generated network interfaces
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virCapabilitiesSetNetPrefix(virCapsPtr caps,
|
|
|
|
const char *prefix)
|
|
|
|
{
|
2019-10-20 11:49:46 +00:00
|
|
|
caps->host.netprefix = g_strdup(prefix);
|
2016-02-03 21:40:33 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-27 04:35:08 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesAddHostNUMACell:
|
|
|
|
* @caps: capabilities to extend
|
|
|
|
* @num: ID number of NUMA cell
|
2013-10-18 12:53:49 +00:00
|
|
|
* @mem: Total size of memory in the NUMA node (in KiB)
|
2014-06-03 13:18:27 +00:00
|
|
|
* @ncpus: number of CPUs in cell
|
2013-01-22 17:42:08 +00:00
|
|
|
* @cpus: array of CPU definition structures, the pointer is stolen
|
2014-06-03 13:18:27 +00:00
|
|
|
* @nsiblings: number of sibling NUMA nodes
|
|
|
|
* @siblings: info on sibling NUMA nodes
|
2014-06-06 16:12:51 +00:00
|
|
|
* @npageinfo: number of pages at node @num
|
|
|
|
* @pageinfo: info on each single memory page
|
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,
|
2013-03-07 16:03:36 +00:00
|
|
|
unsigned long long mem,
|
2014-06-03 13:18:27 +00:00
|
|
|
int ncpus,
|
|
|
|
virCapsHostNUMACellCPUPtr cpus,
|
|
|
|
int nsiblings,
|
2014-06-06 16:12:51 +00:00
|
|
|
virCapsHostNUMACellSiblingInfoPtr siblings,
|
|
|
|
int npageinfo,
|
|
|
|
virCapsHostNUMACellPageInfoPtr pageinfo)
|
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->num = num;
|
2013-03-07 16:03:36 +00:00
|
|
|
cell->mem = mem;
|
2014-06-06 16:12:51 +00:00
|
|
|
cell->ncpus = ncpus;
|
2013-01-22 17:42:08 +00:00
|
|
|
cell->cpus = cpus;
|
2014-06-03 13:18:27 +00:00
|
|
|
cell->nsiblings = nsiblings;
|
2014-06-06 16:12:51 +00:00
|
|
|
cell->siblings = siblings;
|
|
|
|
cell->npageinfo = npageinfo;
|
|
|
|
cell->pageinfo = pageinfo;
|
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;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2009-07-23 17:31:34 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC_N(machines, nnames) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < nnames; i++) {
|
2019-10-20 11:49:46 +00:00
|
|
|
if (VIR_ALLOC(machines[i]) < 0) {
|
2009-07-23 17:31:34 +00:00
|
|
|
virCapabilitiesFreeMachines(machines, nnames);
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-10-20 11:49:46 +00:00
|
|
|
machines[i]->name = g_strdup(names[i]);
|
2009-07-23 17:31:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return machines;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesFreeMachines:
|
|
|
|
* @machines: table of vircapsGuestMachinePtr
|
|
|
|
*
|
|
|
|
* Free a table of virCapsGuestMachinePtr
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virCapabilitiesFreeMachines(virCapsGuestMachinePtr *machines,
|
|
|
|
int nmachines)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2009-07-23 17:31:34 +00:00
|
|
|
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
|
2015-04-17 22:09:16 +00:00
|
|
|
* @ostype: guest operating system type, of enum VIR_DOMAIN_OSTYPE
|
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,
|
2015-04-17 22:09:16 +00:00
|
|
|
int 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)
|
2013-05-03 12:40:46 +00:00
|
|
|
goto error;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2015-04-16 23:18:32 +00:00
|
|
|
guest->ostype = ostype;
|
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
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
guest->arch.defaultInfo.emulator = g_strdup(emulator);
|
|
|
|
guest->arch.defaultInfo.loader = g_strdup(loader);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2010-08-17 21:41:51 +00:00
|
|
|
if (VIR_RESIZE_N(caps->guests, caps->nguests_max,
|
|
|
|
caps->nguests, 1) < 0)
|
2013-05-03 12:40:46 +00:00
|
|
|
goto error;
|
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;
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
error:
|
2008-02-27 04:35:08 +00:00
|
|
|
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,
|
2015-04-17 22:38:10 +00:00
|
|
|
int hvtype,
|
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
|
|
|
virCapsGuestDomainPtr dom;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2008-04-28 21:44:54 +00:00
|
|
|
if (VIR_ALLOC(dom) < 0)
|
2013-05-03 12:40:46 +00:00
|
|
|
goto error;
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2015-04-17 22:38:10 +00:00
|
|
|
dom->type = hvtype;
|
2019-10-20 11:49:46 +00:00
|
|
|
dom->info.emulator = g_strdup(emulator);
|
|
|
|
dom->info.loader = g_strdup(loader);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2010-08-17 21:41:51 +00:00
|
|
|
if (VIR_RESIZE_N(guest->arch.domains, guest->arch.ndomains_max,
|
|
|
|
guest->arch.ndomains, 1) < 0)
|
2013-05-03 12:40:46 +00:00
|
|
|
goto error;
|
2008-02-27 04:35:08 +00:00
|
|
|
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;
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
error:
|
2008-02-27 04:35:08 +00:00
|
|
|
virCapabilitiesFreeGuestDomain(dom);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virCapabilitiesAddGuestFeature:
|
|
|
|
* @guest: guest to associate feature with
|
|
|
|
* @name: name of feature ('pae', 'acpi', 'apic')
|
2014-07-14 12:56:13 +00:00
|
|
|
* @defaultOn: true if it defaults to on
|
|
|
|
* @toggle: true if its state can be toggled
|
2008-02-27 04:35:08 +00:00
|
|
|
*
|
2014-07-14 12:56:13 +00:00
|
|
|
* Registers a feature for a guest domain.
|
2008-02-27 04:35:08 +00:00
|
|
|
*/
|
|
|
|
virCapsGuestFeaturePtr
|
|
|
|
virCapabilitiesAddGuestFeature(virCapsGuestPtr guest,
|
|
|
|
const char *name,
|
2014-07-14 12:56:13 +00:00
|
|
|
bool defaultOn,
|
|
|
|
bool toggle)
|
2008-02-27 04:35:08 +00:00
|
|
|
{
|
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;
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
feature->name = g_strdup(name);
|
2008-02-27 04:35:08 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-10-18 12:13:21 +00:00
|
|
|
/**
|
|
|
|
* virCapabilitiesHostSecModelAddBaseLabel
|
|
|
|
* @secmodel: Security model to add a base label for
|
|
|
|
* @type: virtualization type
|
|
|
|
* @label: base label
|
|
|
|
*
|
|
|
|
* Returns non-zero on error.
|
|
|
|
*/
|
|
|
|
extern int
|
|
|
|
virCapabilitiesHostSecModelAddBaseLabel(virCapsHostSecModelPtr secmodel,
|
|
|
|
const char *type,
|
|
|
|
const char *label)
|
|
|
|
{
|
|
|
|
char *t = NULL, *l = NULL;
|
|
|
|
|
|
|
|
if (type == NULL || label == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2019-10-20 11:49:46 +00:00
|
|
|
t = g_strdup(type);
|
|
|
|
l = g_strdup(label);
|
2013-10-18 12:13:21 +00:00
|
|
|
|
|
|
|
if (VIR_EXPAND_N(secmodel->labels, secmodel->nlabels, 1) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
secmodel->labels[secmodel->nlabels - 1].type = t;
|
|
|
|
secmodel->labels[secmodel->nlabels - 1].label = l;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
no_memory:
|
2013-10-18 12:13:21 +00:00
|
|
|
VIR_FREE(l);
|
|
|
|
VIR_FREE(t);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-04-17 16:38:55 +00:00
|
|
|
|
2015-05-06 22:32:05 +00:00
|
|
|
static virCapsDomainDataPtr
|
|
|
|
virCapabilitiesDomainDataLookupInternal(virCapsPtr caps,
|
|
|
|
int ostype,
|
|
|
|
virArch arch,
|
2015-09-17 08:46:55 +00:00
|
|
|
virDomainVirtType domaintype,
|
2015-05-06 22:32:05 +00:00
|
|
|
const char *emulator,
|
|
|
|
const char *machinetype)
|
2015-04-17 16:38:55 +00:00
|
|
|
{
|
|
|
|
virCapsGuestPtr foundguest = NULL;
|
|
|
|
virCapsGuestDomainPtr founddomain = NULL;
|
|
|
|
virCapsGuestMachinePtr foundmachine = NULL;
|
|
|
|
virCapsDomainDataPtr ret = NULL;
|
|
|
|
size_t i, j, k;
|
|
|
|
|
2018-08-02 16:12:58 +00:00
|
|
|
VIR_DEBUG("Lookup ostype=%d arch=%d domaintype=%d emulator=%s machine=%s",
|
|
|
|
ostype, arch, domaintype, NULLSTR(emulator), NULLSTR(machinetype));
|
2015-04-17 16:38:55 +00:00
|
|
|
for (i = 0; i < caps->nguests; i++) {
|
|
|
|
virCapsGuestPtr guest = caps->guests[i];
|
|
|
|
|
2018-08-02 16:12:58 +00:00
|
|
|
if (ostype != -1 && guest->ostype != ostype) {
|
|
|
|
VIR_DEBUG("Skip os type want=%d vs got=%d", ostype, guest->ostype);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Match os type %d", ostype);
|
|
|
|
|
|
|
|
if ((arch != VIR_ARCH_NONE) && (guest->arch.id != arch)) {
|
|
|
|
VIR_DEBUG("Skip arch want=%d vs got=%d", arch, guest->arch.id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Match arch %d", arch);
|
|
|
|
|
2015-04-17 16:38:55 +00:00
|
|
|
for (j = 0; j < guest->arch.ndomains; j++) {
|
|
|
|
virCapsGuestDomainPtr domain = guest->arch.domains[j];
|
|
|
|
virCapsGuestMachinePtr *machinelist;
|
|
|
|
int nmachines;
|
2018-08-02 16:12:58 +00:00
|
|
|
const char *check_emulator = NULL;
|
|
|
|
|
|
|
|
if (domaintype != VIR_DOMAIN_VIRT_NONE &&
|
|
|
|
(domain->type != domaintype)) {
|
|
|
|
VIR_DEBUG("Skip domain type want=%d vs got=%d", domaintype, domain->type);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Match domain type %d", domaintype);
|
|
|
|
|
|
|
|
check_emulator = domain->info.emulator;
|
|
|
|
if (!check_emulator)
|
|
|
|
check_emulator = guest->arch.defaultInfo.emulator;
|
|
|
|
if (emulator && STRNEQ_NULLABLE(check_emulator, emulator)) {
|
|
|
|
VIR_DEBUG("Skip emulator got=%s vs want=%s",
|
|
|
|
emulator, NULLSTR(check_emulator));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Match emulator %s", NULLSTR(emulator));
|
2015-04-17 16:38:55 +00:00
|
|
|
|
|
|
|
if (domain->info.nmachines) {
|
|
|
|
nmachines = domain->info.nmachines;
|
|
|
|
machinelist = domain->info.machines;
|
|
|
|
} else {
|
|
|
|
nmachines = guest->arch.defaultInfo.nmachines;
|
|
|
|
machinelist = guest->arch.defaultInfo.machines;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (k = 0; k < nmachines; k++) {
|
|
|
|
virCapsGuestMachinePtr machine = machinelist[k];
|
2018-08-02 16:12:58 +00:00
|
|
|
|
|
|
|
if (machinetype &&
|
|
|
|
STRNEQ(machine->name, machinetype) &&
|
|
|
|
STRNEQ_NULLABLE(machine->canonical, machinetype)) {
|
|
|
|
VIR_DEBUG("Skip machine type want=%s vs got=%s got=%s",
|
|
|
|
machinetype, machine->name, NULLSTR(machine->canonical));
|
2015-04-17 16:38:55 +00:00
|
|
|
continue;
|
2018-08-02 16:12:58 +00:00
|
|
|
}
|
2018-09-17 15:06:30 +00:00
|
|
|
VIR_DEBUG("Match machine type machine %s", NULLSTR(machinetype));
|
2015-04-17 16:38:55 +00:00
|
|
|
|
|
|
|
foundmachine = machine;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-08-02 16:12:58 +00:00
|
|
|
if (!foundmachine && nmachines)
|
|
|
|
continue;
|
2015-04-17 16:38:55 +00:00
|
|
|
|
|
|
|
founddomain = domain;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-08-02 16:12:58 +00:00
|
|
|
if (!founddomain)
|
|
|
|
continue;
|
2015-04-17 16:38:55 +00:00
|
|
|
|
|
|
|
foundguest = guest;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX check default_emulator, see how it uses this */
|
|
|
|
if (!foundguest) {
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
if (ostype)
|
|
|
|
virBufferAsprintf(&buf, "ostype=%s ",
|
|
|
|
virDomainOSTypeToString(ostype));
|
|
|
|
if (arch)
|
|
|
|
virBufferAsprintf(&buf, "arch=%s ", virArchToString(arch));
|
2015-09-17 08:46:55 +00:00
|
|
|
if (domaintype > VIR_DOMAIN_VIRT_NONE)
|
2015-04-17 16:38:55 +00:00
|
|
|
virBufferAsprintf(&buf, "domaintype=%s ",
|
|
|
|
virDomainVirtTypeToString(domaintype));
|
|
|
|
if (emulator)
|
2015-05-05 14:52:46 +00:00
|
|
|
virBufferEscapeString(&buf, "emulator=%s ", emulator);
|
2015-04-17 16:38:55 +00:00
|
|
|
if (machinetype)
|
2015-05-05 14:52:46 +00:00
|
|
|
virBufferEscapeString(&buf, "machine=%s ", machinetype);
|
2015-04-17 16:38:55 +00:00
|
|
|
if (virBufferCurrentContent(&buf) &&
|
|
|
|
!virBufferCurrentContent(&buf)[0])
|
|
|
|
virBufferAsprintf(&buf, "%s", _("any configuration"));
|
|
|
|
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
|
|
_("could not find capabilities for %s"),
|
2015-04-27 06:41:43 +00:00
|
|
|
virBufferCurrentContent(&buf));
|
|
|
|
virBufferFreeAndReset(&buf);
|
2015-04-17 16:38:55 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(ret) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ret->ostype = foundguest->ostype;
|
|
|
|
ret->arch = foundguest->arch.id;
|
|
|
|
if (founddomain) {
|
|
|
|
ret->domaintype = founddomain->type;
|
|
|
|
ret->emulator = founddomain->info.emulator;
|
|
|
|
}
|
|
|
|
if (!ret->emulator)
|
|
|
|
ret->emulator = foundguest->arch.defaultInfo.emulator;
|
|
|
|
if (foundmachine)
|
|
|
|
ret->machinetype = foundmachine->name;
|
|
|
|
|
|
|
|
error:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-05-06 22:32:05 +00:00
|
|
|
/**
|
|
|
|
* virCapabilitiesDomainDataLookup:
|
|
|
|
* @caps: capabilities to query
|
|
|
|
* @ostype: guest operating system type, of enum VIR_DOMAIN_OSTYPE
|
|
|
|
* @arch: Architecture to search for
|
2015-09-17 08:46:55 +00:00
|
|
|
* @domaintype: domain type to search for, of enum virDomainVirtType
|
2015-05-06 22:32:05 +00:00
|
|
|
* @emulator: Emulator path to search for
|
|
|
|
* @machinetype: Machine type to search for
|
|
|
|
*
|
|
|
|
* Search capabilities for the passed values, and if found return
|
|
|
|
* virCapabilitiesDomainDataLookup filled in with the default values
|
|
|
|
*/
|
|
|
|
virCapsDomainDataPtr
|
|
|
|
virCapabilitiesDomainDataLookup(virCapsPtr caps,
|
|
|
|
int ostype,
|
|
|
|
virArch arch,
|
|
|
|
int domaintype,
|
|
|
|
const char *emulator,
|
|
|
|
const char *machinetype)
|
|
|
|
{
|
|
|
|
virCapsDomainDataPtr ret;
|
|
|
|
|
|
|
|
if (arch == VIR_ARCH_NONE) {
|
|
|
|
/* Prefer host arch if its available */
|
|
|
|
ret = virCapabilitiesDomainDataLookupInternal(caps, ostype,
|
|
|
|
caps->host.arch,
|
|
|
|
domaintype,
|
|
|
|
emulator, machinetype);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virCapabilitiesDomainDataLookupInternal(caps, ostype,
|
|
|
|
arch, domaintype,
|
|
|
|
emulator, machinetype);
|
|
|
|
}
|
|
|
|
|
2019-01-10 12:19:35 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virCapabilitiesAddStoragePool(virCapsPtr caps,
|
|
|
|
int poolType)
|
|
|
|
{
|
|
|
|
virCapsStoragePoolPtr pool;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(pool) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
pool->type = poolType;
|
|
|
|
|
|
|
|
if (VIR_RESIZE_N(caps->pools, caps->npools_max, caps->npools, 1) < 0)
|
|
|
|
goto error;
|
|
|
|
caps->pools[caps->npools++] = pool;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virCapabilitiesFreeStoragePool(pool);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-01-18 22:06:55 +00:00
|
|
|
static int
|
2014-03-06 14:50:15 +00:00
|
|
|
virCapabilitiesFormatNUMATopology(virBufferPtr buf,
|
2013-01-18 19:39:00 +00:00
|
|
|
size_t ncells,
|
|
|
|
virCapsHostNUMACellPtr *cells)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
|
|
|
size_t j;
|
2013-01-18 22:06:55 +00:00
|
|
|
char *siblings;
|
2013-01-18 19:39:00 +00:00
|
|
|
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAddLit(buf, "<topology>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAsprintf(buf, "<cells num='%zu'>\n", ncells);
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2013-01-18 19:39:00 +00:00
|
|
|
for (i = 0; i < ncells; i++) {
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAsprintf(buf, "<cell id='%d'>\n", cells[i]->num);
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2013-03-07 16:03:36 +00:00
|
|
|
|
|
|
|
/* Print out the numacell memory total if it is available */
|
|
|
|
if (cells[i]->mem)
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAsprintf(buf, "<memory unit='KiB'>%llu</memory>\n",
|
2013-03-07 16:03:36 +00:00
|
|
|
cells[i]->mem);
|
|
|
|
|
2014-06-06 16:12:51 +00:00
|
|
|
for (j = 0; j < cells[i]->npageinfo; j++) {
|
2018-04-23 14:36:53 +00:00
|
|
|
virBufferAsprintf(buf, "<pages unit='KiB' size='%u'>%llu</pages>\n",
|
2014-06-06 16:12:51 +00:00
|
|
|
cells[i]->pageinfo[j].size,
|
|
|
|
cells[i]->pageinfo[j].avail);
|
|
|
|
}
|
|
|
|
|
2014-06-03 13:18:27 +00:00
|
|
|
if (cells[i]->nsiblings) {
|
|
|
|
virBufferAddLit(buf, "<distances>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
for (j = 0; j < cells[i]->nsiblings; j++) {
|
|
|
|
virBufferAsprintf(buf, "<sibling id='%d' value='%d'/>\n",
|
|
|
|
cells[i]->siblings[j].node,
|
|
|
|
cells[i]->siblings[j].distance);
|
|
|
|
}
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</distances>\n");
|
|
|
|
}
|
|
|
|
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAsprintf(buf, "<cpus num='%d'>\n", cells[i]->ncpus);
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2013-01-18 22:06:55 +00:00
|
|
|
for (j = 0; j < cells[i]->ncpus; j++) {
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAsprintf(buf, "<cpu id='%d'", cells[i]->cpus[j].id);
|
2013-01-18 22:06:55 +00:00
|
|
|
|
|
|
|
if (cells[i]->cpus[j].siblings) {
|
2014-06-05 09:24:24 +00:00
|
|
|
if (!(siblings = virBitmapFormat(cells[i]->cpus[j].siblings)))
|
2013-01-18 22:06:55 +00:00
|
|
|
return -1;
|
|
|
|
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAsprintf(buf,
|
2013-01-18 22:06:55 +00:00
|
|
|
" socket_id='%d' core_id='%d' siblings='%s'",
|
|
|
|
cells[i]->cpus[j].socket_id,
|
|
|
|
cells[i]->cpus[j].core_id,
|
|
|
|
siblings);
|
|
|
|
VIR_FREE(siblings);
|
|
|
|
}
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAddLit(buf, "/>\n");
|
2013-01-18 22:06:55 +00:00
|
|
|
}
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</cpus>\n");
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</cell>\n");
|
2013-01-18 19:39:00 +00:00
|
|
|
}
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</cells>\n");
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</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
|
|
|
|
2018-09-20 10:10:50 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virCapabilitiesFormatResctrlMonitor(virBufferPtr buf,
|
|
|
|
virResctrlInfoMonPtr monitor)
|
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
/* monitor not supported, no capability */
|
|
|
|
if (!monitor)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* no feature found in monitor means no capability, return */
|
|
|
|
if (monitor->nfeatures == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<monitor ");
|
|
|
|
|
|
|
|
/* CMT might not enabled, if enabled show related attributes. */
|
|
|
|
if (monitor->type == VIR_RESCTRL_MONITOR_TYPE_CACHE)
|
|
|
|
virBufferAsprintf(buf,
|
|
|
|
"level='%u' reuseThreshold='%u' ",
|
|
|
|
monitor->cache_level,
|
|
|
|
monitor->cache_reuse_threshold);
|
|
|
|
virBufferAsprintf(buf,
|
|
|
|
"maxMonitors='%u'>\n",
|
|
|
|
monitor->max_monitor);
|
|
|
|
|
|
|
|
virBufferSetChildIndent(&childrenBuf, buf);
|
|
|
|
for (i = 0; i < monitor->nfeatures; i++) {
|
|
|
|
virBufferAsprintf(&childrenBuf,
|
|
|
|
"<feature name='%s'/>\n",
|
|
|
|
monitor->features[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddBuffer(buf, &childrenBuf);
|
|
|
|
virBufferAddLit(buf, "</monitor>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
static int
|
|
|
|
virCapabilitiesFormatCaches(virBufferPtr buf,
|
2018-09-20 10:10:48 +00:00
|
|
|
virCapsHostCachePtr cache)
|
2017-03-30 13:01:27 +00:00
|
|
|
{
|
|
|
|
size_t i = 0;
|
2017-05-17 09:08:33 +00:00
|
|
|
size_t j = 0;
|
2017-03-30 13:01:27 +00:00
|
|
|
|
2018-09-20 10:10:48 +00:00
|
|
|
if (!cache->nbanks)
|
2017-03-30 13:01:27 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<cache>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
2018-09-20 10:10:48 +00:00
|
|
|
for (i = 0; i < cache->nbanks; i++) {
|
2019-10-25 14:16:41 +00:00
|
|
|
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
|
|
|
|
g_auto(virBuffer) childrenBuf = VIR_BUFFER_INITIALIZER;
|
2018-09-20 10:10:48 +00:00
|
|
|
virCapsHostCacheBankPtr bank = cache->banks[i];
|
2019-10-25 14:11:34 +00:00
|
|
|
g_autofree char *cpus_str = virBitmapFormat(bank->cpus);
|
2017-11-10 12:19:53 +00:00
|
|
|
const char *unit = NULL;
|
|
|
|
unsigned long long short_size = virFormatIntPretty(bank->size, &unit);
|
2017-03-30 13:01:27 +00:00
|
|
|
|
|
|
|
if (!cpus_str)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let's just *hope* the size is aligned to KiBs so that it does not
|
|
|
|
* bite is back in the future
|
|
|
|
*/
|
2019-10-25 14:16:41 +00:00
|
|
|
virBufferAsprintf(&attrBuf,
|
|
|
|
" id='%u' level='%u' type='%s' "
|
2017-05-17 09:08:33 +00:00
|
|
|
"size='%llu' unit='%s' cpus='%s'",
|
2017-03-30 13:01:27 +00:00
|
|
|
bank->id, bank->level,
|
|
|
|
virCacheTypeToString(bank->type),
|
2017-11-10 12:19:53 +00:00
|
|
|
short_size, unit, cpus_str);
|
2017-03-30 13:01:27 +00:00
|
|
|
|
2018-08-27 11:23:04 +00:00
|
|
|
virBufferSetChildIndent(&childrenBuf, buf);
|
2017-05-17 09:08:33 +00:00
|
|
|
for (j = 0; j < bank->ncontrols; j++) {
|
2017-11-10 12:19:53 +00:00
|
|
|
const char *min_unit;
|
2017-11-20 09:23:04 +00:00
|
|
|
virResctrlInfoPerCachePtr controls = bank->controls[j];
|
2017-11-10 12:19:53 +00:00
|
|
|
unsigned long long gran_short_size = controls->granularity;
|
|
|
|
unsigned long long min_short_size = controls->min;
|
|
|
|
|
|
|
|
gran_short_size = virFormatIntPretty(gran_short_size, &unit);
|
|
|
|
min_short_size = virFormatIntPretty(min_short_size, &min_unit);
|
|
|
|
|
|
|
|
/* Only use the smaller unit if they are different */
|
|
|
|
if (min_short_size) {
|
|
|
|
unsigned long long gran_div;
|
|
|
|
unsigned long long min_div;
|
|
|
|
|
|
|
|
gran_div = controls->granularity / gran_short_size;
|
|
|
|
min_div = controls->min / min_short_size;
|
|
|
|
|
|
|
|
if (min_div > gran_div) {
|
|
|
|
min_short_size *= min_div / gran_div;
|
|
|
|
} else if (min_div < gran_div) {
|
|
|
|
unit = min_unit;
|
|
|
|
gran_short_size *= gran_div / min_div;
|
|
|
|
}
|
|
|
|
}
|
2017-06-05 12:00:45 +00:00
|
|
|
|
2018-08-27 11:23:04 +00:00
|
|
|
virBufferAsprintf(&childrenBuf,
|
2017-06-05 12:00:45 +00:00
|
|
|
"<control granularity='%llu'",
|
2017-11-10 12:19:53 +00:00
|
|
|
gran_short_size);
|
2017-06-05 12:00:45 +00:00
|
|
|
|
2017-11-10 12:19:53 +00:00
|
|
|
if (min_short_size)
|
2018-08-27 11:23:04 +00:00
|
|
|
virBufferAsprintf(&childrenBuf, " min='%llu'", min_short_size);
|
2017-06-05 12:00:45 +00:00
|
|
|
|
2018-08-27 11:23:04 +00:00
|
|
|
virBufferAsprintf(&childrenBuf,
|
2017-06-05 12:00:45 +00:00
|
|
|
" unit='%s' type='%s' maxAllocs='%u'/>\n",
|
2017-11-10 12:19:53 +00:00
|
|
|
unit,
|
|
|
|
virCacheTypeToString(controls->scope),
|
|
|
|
controls->max_allocation);
|
2017-05-17 09:08:33 +00:00
|
|
|
}
|
|
|
|
|
2019-10-25 14:16:41 +00:00
|
|
|
virXMLFormatElement(buf, "bank", &attrBuf, &childrenBuf);
|
2017-03-30 13:01:27 +00:00
|
|
|
}
|
|
|
|
|
2018-09-20 10:10:50 +00:00
|
|
|
if (virCapabilitiesFormatResctrlMonitor(buf, cache->monitor) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</cache>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-30 03:12:41 +00:00
|
|
|
static int
|
|
|
|
virCapabilitiesFormatMemoryBandwidth(virBufferPtr buf,
|
2018-09-20 10:10:49 +00:00
|
|
|
virCapsHostMemBWPtr memBW)
|
2018-07-30 03:12:41 +00:00
|
|
|
{
|
|
|
|
size_t i = 0;
|
2018-08-27 11:23:04 +00:00
|
|
|
virBuffer childrenBuf = VIR_BUFFER_INITIALIZER;
|
2018-07-30 03:12:41 +00:00
|
|
|
|
2018-09-20 10:10:49 +00:00
|
|
|
if (!memBW->nnodes)
|
2018-07-30 03:12:41 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<memory_bandwidth>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
2018-09-20 10:10:49 +00:00
|
|
|
for (i = 0; i < memBW->nnodes; i++) {
|
|
|
|
virCapsHostMemBWNodePtr node = memBW->nodes[i];
|
2018-07-30 03:12:41 +00:00
|
|
|
virResctrlInfoMemBWPerNodePtr control = &node->control;
|
|
|
|
char *cpus_str = virBitmapFormat(node->cpus);
|
|
|
|
|
|
|
|
if (!cpus_str)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
virBufferAsprintf(buf,
|
|
|
|
"<node id='%u' cpus='%s'",
|
|
|
|
node->id, cpus_str);
|
|
|
|
VIR_FREE(cpus_str);
|
|
|
|
|
2018-08-27 11:23:04 +00:00
|
|
|
virBufferSetChildIndent(&childrenBuf, buf);
|
|
|
|
virBufferAsprintf(&childrenBuf,
|
2018-07-30 03:12:41 +00:00
|
|
|
"<control granularity='%u' min ='%u' "
|
|
|
|
"maxAllocs='%u'/>\n",
|
|
|
|
control->granularity, control->min,
|
|
|
|
control->max_allocation);
|
|
|
|
|
2018-08-27 11:23:04 +00:00
|
|
|
if (virBufferUse(&childrenBuf)) {
|
2018-07-30 03:12:41 +00:00
|
|
|
virBufferAddLit(buf, ">\n");
|
2018-08-27 11:23:04 +00:00
|
|
|
virBufferAddBuffer(buf, &childrenBuf);
|
2018-07-30 03:12:41 +00:00
|
|
|
virBufferAddLit(buf, "</node>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-20 10:10:50 +00:00
|
|
|
if (virCapabilitiesFormatResctrlMonitor(buf, memBW->monitor) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2018-07-30 03:12:41 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</memory_bandwidth>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-09 16:51:17 +00:00
|
|
|
|
|
|
|
static int
|
2019-01-09 17:10:59 +00:00
|
|
|
virCapabilitiesFormatHostXML(virCapsHostPtr host,
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferPtr buf)
|
2008-02-27 04:35:08 +00:00
|
|
|
{
|
2019-01-09 16:51:17 +00:00
|
|
|
size_t i, j;
|
2010-05-25 14:33:51 +00:00
|
|
|
char host_uuid[VIR_UUID_STRING_BUFLEN];
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2019-01-10 12:19:35 +00:00
|
|
|
/* The lack of some data means we have nothing
|
|
|
|
* minimally to format, so just return. */
|
|
|
|
if (!virUUIDIsValid(host->host_uuid) &&
|
|
|
|
!host->arch && !host->powerMgmt && !host->iommu)
|
|
|
|
return 0;
|
|
|
|
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<host>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2019-01-09 17:10:59 +00:00
|
|
|
if (virUUIDIsValid(host->host_uuid)) {
|
|
|
|
virUUIDFormat(host->host_uuid, host_uuid);
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<uuid>%s</uuid>\n", host_uuid);
|
2010-05-25 14:33:51 +00:00
|
|
|
}
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<cpu>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2014-03-06 14:50:15 +00:00
|
|
|
|
2019-01-09 17:10:59 +00:00
|
|
|
if (host->arch)
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<arch>%s</arch>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
virArchToString(host->arch));
|
|
|
|
if (host->nfeatures) {
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<features>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2019-01-09 17:10:59 +00:00
|
|
|
for (i = 0; i < host->nfeatures; i++) {
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<%s/>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
host->features[i]);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</features>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2019-01-09 17:10:59 +00:00
|
|
|
virCPUDefFormatBuf(buf, host->cpu);
|
2009-12-18 13:44:55 +00:00
|
|
|
|
2019-01-09 17:10:59 +00:00
|
|
|
for (i = 0; i < host->nPagesSize; i++) {
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<pages unit='KiB' size='%u'/>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
host->pagesSize[i]);
|
2014-06-06 16:12:51 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</cpu>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2011-11-29 14:50:04 +00:00
|
|
|
/* The PM query was successful. */
|
2019-01-09 17:10:59 +00:00
|
|
|
if (host->powerMgmt) {
|
2011-11-29 14:50:04 +00:00
|
|
|
/* The host supports some PM features. */
|
2019-01-09 17:10:59 +00:00
|
|
|
unsigned int pm = host->powerMgmt;
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<power_management>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2011-11-29 14:50:04 +00:00
|
|
|
while (pm) {
|
2019-10-03 14:51:30 +00:00
|
|
|
int bit = __builtin_ffs(pm) - 1;
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<%s/>\n",
|
2011-11-29 14:50:04 +00:00
|
|
|
virCapsHostPMTargetTypeToString(bit));
|
|
|
|
pm &= ~(1U << bit);
|
2011-11-22 03:31:22 +00:00
|
|
|
}
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</power_management>\n");
|
2011-11-29 14:50:04 +00:00
|
|
|
} else {
|
|
|
|
/* The host does not support any PM feature. */
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<power_management/>\n");
|
2011-11-22 03:31:22 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<iommu support='%s'/>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
host->iommu ? "yes" : "no");
|
2018-06-01 08:15:59 +00:00
|
|
|
|
2019-01-09 17:10:59 +00:00
|
|
|
if (host->offlineMigrate) {
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<migration_features>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2019-01-09 17:10:59 +00:00
|
|
|
if (host->liveMigrate)
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<live/>\n");
|
2019-01-09 17:10:59 +00:00
|
|
|
if (host->nmigrateTrans) {
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<uri_transports>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2019-01-09 17:10:59 +00:00
|
|
|
for (i = 0; i < host->nmigrateTrans; i++) {
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<uri_transport>%s</uri_transport>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
host->migrateTrans[i]);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</uri_transports>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</migration_features>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 17:10:59 +00:00
|
|
|
if (host->netprefix)
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<netprefix>%s</netprefix>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
host->netprefix);
|
2016-02-03 21:40:33 +00:00
|
|
|
|
2019-01-09 17:10:59 +00:00
|
|
|
if (host->nnumaCell &&
|
|
|
|
virCapabilitiesFormatNUMATopology(buf, host->nnumaCell,
|
|
|
|
host->numaCell) < 0)
|
2017-03-29 11:36:15 +00:00
|
|
|
goto error;
|
2009-03-03 09:44:41 +00:00
|
|
|
|
2019-01-09 17:10:59 +00:00
|
|
|
if (virCapabilitiesFormatCaches(buf, &host->cache) < 0)
|
2017-03-30 13:01:27 +00:00
|
|
|
goto error;
|
|
|
|
|
2019-01-09 17:10:59 +00:00
|
|
|
if (virCapabilitiesFormatMemoryBandwidth(buf, &host->memBW) < 0)
|
2018-07-30 03:12:41 +00:00
|
|
|
goto error;
|
|
|
|
|
2019-01-09 17:10:59 +00:00
|
|
|
for (i = 0; i < host->nsecModels; i++) {
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAddLit(buf, "<secmodel>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAsprintf(buf, "<model>%s</model>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
host->secModels[i].model);
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<doi>%s</doi>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
host->secModels[i].doi);
|
|
|
|
for (j = 0; j < host->secModels[i].nlabels; j++) {
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAsprintf(buf, "<baselabel type='%s'>%s</baselabel>\n",
|
2019-01-09 17:10:59 +00:00
|
|
|
host->secModels[i].labels[j].type,
|
|
|
|
host->secModels[i].labels[j].label);
|
2013-10-18 12:13:21 +00:00
|
|
|
}
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</secmodel>\n");
|
2009-03-03 09:44:41 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 16:51:17 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</host>\n\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-09 17:00:28 +00:00
|
|
|
static void
|
2019-01-09 18:31:50 +00:00
|
|
|
virCapabilitiesFormatGuestXML(virCapsGuestPtr *guests,
|
|
|
|
size_t nguests,
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferPtr buf)
|
2019-01-09 16:51:17 +00:00
|
|
|
{
|
|
|
|
size_t i, j, k;
|
|
|
|
|
2019-01-09 18:31:50 +00:00
|
|
|
for (i = 0; i < nguests; i++) {
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAddLit(buf, "<guest>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAsprintf(buf, "<os_type>%s</os_type>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
virDomainOSTypeToString(guests[i]->ostype));
|
|
|
|
if (guests[i]->arch.id)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, "<arch name='%s'>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
virArchToString(guests[i]->arch.id));
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAsprintf(buf, "<wordsize>%d</wordsize>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
guests[i]->arch.wordsize);
|
|
|
|
if (guests[i]->arch.defaultInfo.emulator)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, "<emulator>%s</emulator>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
guests[i]->arch.defaultInfo.emulator);
|
|
|
|
if (guests[i]->arch.defaultInfo.loader)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, "<loader>%s</loader>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
guests[i]->arch.defaultInfo.loader);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2019-01-09 18:31:50 +00:00
|
|
|
for (j = 0; j < guests[i]->arch.defaultInfo.nmachines; j++) {
|
|
|
|
virCapsGuestMachinePtr machine = guests[i]->arch.defaultInfo.machines[j];
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAddLit(buf, "<machine");
|
2009-07-23 17:31:35 +00:00
|
|
|
if (machine->canonical)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, " canonical='%s'", machine->canonical);
|
2013-06-26 15:46:35 +00:00
|
|
|
if (machine->maxCpus > 0)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, " maxCpus='%d'", machine->maxCpus);
|
|
|
|
virBufferAsprintf(buf, ">%s</machine>\n", machine->name);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 18:31:50 +00:00
|
|
|
for (j = 0; j < guests[i]->arch.ndomains; j++) {
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, "<domain type='%s'",
|
2019-01-09 18:31:50 +00:00
|
|
|
virDomainVirtTypeToString(guests[i]->arch.domains[j]->type));
|
|
|
|
if (!guests[i]->arch.domains[j]->info.emulator &&
|
|
|
|
!guests[i]->arch.domains[j]->info.loader &&
|
|
|
|
!guests[i]->arch.domains[j]->info.nmachines) {
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAddLit(buf, "/>\n");
|
2014-12-11 15:11:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAddLit(buf, ">\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2019-01-09 18:31:50 +00:00
|
|
|
if (guests[i]->arch.domains[j]->info.emulator)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, "<emulator>%s</emulator>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
guests[i]->arch.domains[j]->info.emulator);
|
|
|
|
if (guests[i]->arch.domains[j]->info.loader)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, "<loader>%s</loader>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
guests[i]->arch.domains[j]->info.loader);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2019-01-09 18:31:50 +00:00
|
|
|
for (k = 0; k < guests[i]->arch.domains[j]->info.nmachines; k++) {
|
|
|
|
virCapsGuestMachinePtr machine = guests[i]->arch.domains[j]->info.machines[k];
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAddLit(buf, "<machine");
|
2009-07-23 17:31:35 +00:00
|
|
|
if (machine->canonical)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, " canonical='%s'", machine->canonical);
|
2013-06-26 15:46:35 +00:00
|
|
|
if (machine->maxCpus > 0)
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, " maxCpus='%d'", machine->maxCpus);
|
|
|
|
virBufferAsprintf(buf, ">%s</machine>\n", machine->name);
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</domain>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</arch>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2019-01-09 18:31:50 +00:00
|
|
|
if (guests[i]->nfeatures) {
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAddLit(buf, "<features>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2019-01-09 18:31:50 +00:00
|
|
|
for (j = 0; j < guests[i]->nfeatures; j++) {
|
|
|
|
if (STREQ(guests[i]->features[j]->name, "pae") ||
|
|
|
|
STREQ(guests[i]->features[j]->name, "nonpae") ||
|
|
|
|
STREQ(guests[i]->features[j]->name, "ia64_be") ||
|
|
|
|
STREQ(guests[i]->features[j]->name, "cpuselection") ||
|
|
|
|
STREQ(guests[i]->features[j]->name, "deviceboot")) {
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, "<%s/>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
guests[i]->features[j]->name);
|
2008-02-27 04:35:08 +00:00
|
|
|
} else {
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAsprintf(buf, "<%s default='%s' toggle='%s'/>\n",
|
2019-01-09 18:31:50 +00:00
|
|
|
guests[i]->features[j]->name,
|
|
|
|
guests[i]->features[j]->defaultOn ? "on" : "off",
|
|
|
|
guests[i]->features[j]->toggle ? "yes" : "no");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</features>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2019-01-09 17:00:28 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</guest>\n\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2019-01-09 17:00:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-10 12:19:35 +00:00
|
|
|
static void
|
|
|
|
virCapabilitiesFormatStoragePoolXML(virCapsStoragePoolPtr *pools,
|
|
|
|
size_t npools,
|
|
|
|
virBufferPtr buf)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (npools == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<pool>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "<enum name='type'>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
for (i = 0; i < npools; i++)
|
|
|
|
virBufferAsprintf(buf, "<value>%s</value>\n",
|
|
|
|
virStoragePoolTypeToString(pools[i]->type));
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</enum>\n");
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</pool>\n\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-09 17:00:28 +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)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<capabilities>\n\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
|
|
|
|
if (virCapabilitiesFormatHostXML(&caps->host, &buf) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2019-01-09 18:31:50 +00:00
|
|
|
virCapabilitiesFormatGuestXML(caps->guests, caps->nguests, &buf);
|
2019-01-09 17:00:28 +00:00
|
|
|
|
2019-01-10 12:19:35 +00:00
|
|
|
virCapabilitiesFormatStoragePoolXML(caps->pools, caps->npools, &buf);
|
|
|
|
|
2014-03-06 14:50:15 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</capabilities>\n");
|
2008-02-27 04:35:08 +00:00
|
|
|
|
2014-03-06 14:50:15 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2017-03-29 11:36:15 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
return NULL;
|
2008-02-27 04:35:08 +00:00
|
|
|
}
|
2013-07-18 09:21:48 +00:00
|
|
|
|
|
|
|
/* get the maximum ID of cpus in the host */
|
|
|
|
static unsigned int
|
|
|
|
virCapabilitiesGetHostMaxcpu(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
unsigned int maxcpu = 0;
|
|
|
|
size_t node;
|
|
|
|
size_t cpu;
|
|
|
|
|
|
|
|
for (node = 0; node < caps->host.nnumaCell; node++) {
|
|
|
|
virCapsHostNUMACellPtr cell = caps->host.numaCell[node];
|
|
|
|
|
|
|
|
for (cpu = 0; cpu < cell->ncpus; cpu++) {
|
|
|
|
if (cell->cpus[cpu].id > maxcpu)
|
|
|
|
maxcpu = cell->cpus[cpu].id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return maxcpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set cpus of a numa node in the bitmask */
|
|
|
|
static int
|
|
|
|
virCapabilitiesGetCpusForNode(virCapsPtr caps,
|
|
|
|
size_t node,
|
|
|
|
virBitmapPtr cpumask)
|
|
|
|
{
|
2014-02-11 14:32:50 +00:00
|
|
|
virCapsHostNUMACellPtr cell = NULL;
|
2013-07-18 09:21:48 +00:00
|
|
|
size_t cpu;
|
2014-02-11 15:35:33 +00:00
|
|
|
size_t i;
|
2014-02-11 14:32:50 +00:00
|
|
|
/* The numa node numbers can be non-contiguous. Ex: 0,1,16,17. */
|
2014-02-11 15:35:33 +00:00
|
|
|
for (i = 0; i < caps->host.nnumaCell; i++) {
|
|
|
|
if (caps->host.numaCell[i]->num == node) {
|
|
|
|
cell = caps->host.numaCell[i];
|
2014-02-11 14:32:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-07-18 09:21:48 +00:00
|
|
|
|
2014-02-11 14:32:50 +00:00
|
|
|
for (cpu = 0; cell && cpu < cell->ncpus; cpu++) {
|
2013-07-18 09:21:48 +00:00
|
|
|
if (virBitmapSetBit(cpumask, cell->cpus[cpu].id) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cpu '%u' in node '%zu' is out of range "
|
|
|
|
"of the provided bitmap"),
|
|
|
|
cell->cpus[cpu].id, node);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBitmapPtr
|
|
|
|
virCapabilitiesGetCpusForNodemask(virCapsPtr caps,
|
|
|
|
virBitmapPtr nodemask)
|
|
|
|
{
|
|
|
|
virBitmapPtr ret = NULL;
|
|
|
|
unsigned int maxcpu = virCapabilitiesGetHostMaxcpu(caps);
|
|
|
|
ssize_t node = -1;
|
|
|
|
|
|
|
|
if (!(ret = virBitmapNew(maxcpu + 1)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
while ((node = virBitmapNextSetBit(nodemask, node)) >= 0) {
|
|
|
|
if (virCapabilitiesGetCpusForNode(caps, node, ret) < 0) {
|
|
|
|
virBitmapFree(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2017-03-07 09:40:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virCapabilitiesGetNodeInfo(virNodeInfoPtr nodeinfo)
|
|
|
|
{
|
|
|
|
virArch hostarch = virArchFromHost();
|
|
|
|
unsigned long long memorybytes;
|
|
|
|
|
|
|
|
memset(nodeinfo, 0, sizeof(*nodeinfo));
|
|
|
|
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpyStatic(nodeinfo->model, virArchToString(hostarch)) < 0)
|
2017-03-07 09:40:15 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virHostMemGetInfo(&memorybytes, NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
nodeinfo->memory = memorybytes / 1024;
|
|
|
|
|
|
|
|
if (virHostCPUGetInfo(hostarch,
|
|
|
|
&nodeinfo->cpus, &nodeinfo->mhz,
|
|
|
|
&nodeinfo->nodes, &nodeinfo->sockets,
|
|
|
|
&nodeinfo->cores, &nodeinfo->threads) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns 1 on success, 0 if the detection failed and -1 on hard error */
|
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
virCapabilitiesFillCPUInfo(int cpu_id G_GNUC_UNUSED,
|
|
|
|
virCapsHostNUMACellCPUPtr cpu G_GNUC_UNUSED)
|
2017-03-07 09:40:15 +00:00
|
|
|
{
|
|
|
|
#ifdef __linux__
|
|
|
|
cpu->id = cpu_id;
|
|
|
|
|
|
|
|
if (virHostCPUGetSocket(cpu_id, &cpu->socket_id) < 0 ||
|
|
|
|
virHostCPUGetCore(cpu_id, &cpu->core_id) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(cpu->siblings = virHostCPUGetSiblingsList(cpu_id)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("node cpu info not implemented on this platform"));
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virCapabilitiesGetNUMASiblingInfo(int node,
|
|
|
|
virCapsHostNUMACellSiblingInfoPtr *siblings,
|
|
|
|
int *nsiblings)
|
|
|
|
{
|
|
|
|
virCapsHostNUMACellSiblingInfoPtr tmp = NULL;
|
|
|
|
int tmp_size = 0;
|
|
|
|
int ret = -1;
|
|
|
|
int *distances = NULL;
|
|
|
|
int ndistances = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (virNumaGetDistances(node, &distances, &ndistances) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!distances) {
|
|
|
|
*siblings = NULL;
|
|
|
|
*nsiblings = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(tmp, ndistances) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < ndistances; i++) {
|
|
|
|
if (!distances[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tmp[tmp_size].node = i;
|
|
|
|
tmp[tmp_size].distance = distances[i];
|
|
|
|
tmp_size++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(tmp, tmp_size) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
*siblings = tmp;
|
|
|
|
*nsiblings = tmp_size;
|
|
|
|
tmp = NULL;
|
|
|
|
tmp_size = 0;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(distances);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virCapabilitiesGetNUMAPagesInfo(int node,
|
|
|
|
virCapsHostNUMACellPageInfoPtr *pageinfo,
|
|
|
|
int *npageinfo)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
2018-04-23 14:36:53 +00:00
|
|
|
unsigned int *pages_size = NULL;
|
|
|
|
unsigned long long *pages_avail = NULL;
|
2017-03-07 09:40:15 +00:00
|
|
|
size_t npages, i;
|
|
|
|
|
|
|
|
if (virNumaGetPages(node, &pages_size, &pages_avail, NULL, &npages) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(*pageinfo, npages) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
*npageinfo = npages;
|
|
|
|
|
|
|
|
for (i = 0; i < npages; i++) {
|
|
|
|
(*pageinfo)[i].size = pages_size[i];
|
|
|
|
(*pageinfo)[i].avail = pages_avail[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(pages_avail);
|
|
|
|
VIR_FREE(pages_size);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virCapabilitiesInitNUMAFake(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
virNodeInfo nodeinfo;
|
|
|
|
virCapsHostNUMACellCPUPtr cpus;
|
|
|
|
int ncpus;
|
|
|
|
int s, c, t;
|
|
|
|
int id, cid;
|
2019-10-14 12:45:33 +00:00
|
|
|
int onlinecpus G_GNUC_UNUSED;
|
2017-03-07 09:40:15 +00:00
|
|
|
bool tmp;
|
|
|
|
|
|
|
|
if (virCapabilitiesGetNodeInfo(&nodeinfo) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ncpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
|
|
|
|
onlinecpus = nodeinfo.cpus;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(cpus, ncpus) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
id = cid = 0;
|
|
|
|
for (s = 0; s < nodeinfo.sockets; s++) {
|
|
|
|
for (c = 0; c < nodeinfo.cores; c++) {
|
|
|
|
for (t = 0; t < nodeinfo.threads; t++) {
|
|
|
|
if (virHostCPUGetOnline(id, &tmp) < 0)
|
|
|
|
goto error;
|
|
|
|
if (tmp) {
|
|
|
|
cpus[cid].id = id;
|
|
|
|
cpus[cid].socket_id = s;
|
|
|
|
cpus[cid].core_id = c;
|
|
|
|
if (!(cpus[cid].siblings = virBitmapNew(ncpus)))
|
|
|
|
goto error;
|
|
|
|
ignore_value(virBitmapSetBit(cpus[cid].siblings, id));
|
|
|
|
cid++;
|
|
|
|
}
|
|
|
|
|
|
|
|
id++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virCapabilitiesAddHostNUMACell(caps, 0,
|
|
|
|
nodeinfo.memory,
|
|
|
|
#ifdef __linux__
|
|
|
|
onlinecpus, cpus,
|
|
|
|
#else
|
|
|
|
ncpus, cpus,
|
|
|
|
#endif
|
|
|
|
0, NULL,
|
|
|
|
0, NULL) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
for (; id >= 0; id--)
|
|
|
|
virBitmapFree(cpus[id].siblings);
|
|
|
|
VIR_FREE(cpus);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
virCapabilitiesInitNUMA(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
unsigned long long memory;
|
|
|
|
virCapsHostNUMACellCPUPtr cpus = NULL;
|
|
|
|
virBitmapPtr cpumap = NULL;
|
|
|
|
virCapsHostNUMACellSiblingInfoPtr siblings = NULL;
|
|
|
|
int nsiblings = 0;
|
|
|
|
virCapsHostNUMACellPageInfoPtr pageinfo = NULL;
|
|
|
|
int npageinfo;
|
|
|
|
int ret = -1;
|
|
|
|
int ncpus = 0;
|
|
|
|
int cpu;
|
|
|
|
bool topology_failed = false;
|
|
|
|
int max_node;
|
|
|
|
|
|
|
|
if (!virNumaIsAvailable())
|
|
|
|
return virCapabilitiesInitNUMAFake(caps);
|
|
|
|
|
|
|
|
if ((max_node = virNumaGetMaxNode()) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (n = 0; n <= max_node; n++) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if ((ncpus = virNumaGetNodeCPUs(n, &cpumap)) < 0) {
|
|
|
|
if (ncpus == -2)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(cpus, ncpus) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
cpu = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < virBitmapSize(cpumap); i++) {
|
|
|
|
if (virBitmapIsBitSet(cpumap, i)) {
|
|
|
|
if (virCapabilitiesFillCPUInfo(i, cpus + cpu++) < 0) {
|
|
|
|
topology_failed = true;
|
|
|
|
virResetLastError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virCapabilitiesGetNUMASiblingInfo(n, &siblings, &nsiblings) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virCapabilitiesGetNUMAPagesInfo(n, &pageinfo, &npageinfo) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/* Detect the amount of memory in the numa cell in KiB */
|
|
|
|
virNumaGetNodeMemory(n, &memory, NULL);
|
|
|
|
memory >>= 10;
|
|
|
|
|
|
|
|
if (virCapabilitiesAddHostNUMACell(caps, n, memory,
|
|
|
|
ncpus, cpus,
|
|
|
|
nsiblings, siblings,
|
|
|
|
npageinfo, pageinfo) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
cpus = NULL;
|
|
|
|
siblings = NULL;
|
|
|
|
pageinfo = NULL;
|
|
|
|
virBitmapFree(cpumap);
|
|
|
|
cpumap = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if ((topology_failed || ret < 0) && cpus)
|
|
|
|
virCapabilitiesClearHostNUMACellCPUTopology(cpus, ncpus);
|
|
|
|
|
|
|
|
virBitmapFree(cpumap);
|
|
|
|
VIR_FREE(cpus);
|
|
|
|
VIR_FREE(siblings);
|
|
|
|
VIR_FREE(pageinfo);
|
|
|
|
return ret;
|
|
|
|
}
|
2017-03-11 15:32:13 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
virCapabilitiesInitPages(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
unsigned int *pages_size = NULL;
|
|
|
|
size_t npages;
|
|
|
|
|
|
|
|
if (virNumaGetPages(-1 /* Magic constant for overall info */,
|
|
|
|
&pages_size, NULL, NULL, &npages) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
caps->host.pagesSize = pages_size;
|
|
|
|
pages_size = NULL;
|
|
|
|
caps->host.nPagesSize = npages;
|
|
|
|
npages = 0;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(pages_size);
|
|
|
|
return ret;
|
|
|
|
}
|
2017-03-30 13:01:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
virCapsHostCacheBankEquals(virCapsHostCacheBankPtr a,
|
|
|
|
virCapsHostCacheBankPtr b)
|
|
|
|
{
|
|
|
|
return (a->id == b->id &&
|
|
|
|
a->level == b->level &&
|
|
|
|
a->type == b->type &&
|
|
|
|
a->size == b->size &&
|
|
|
|
virBitmapEqual(a->cpus, b->cpus));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
virCapsHostCacheBankFree(virCapsHostCacheBankPtr ptr)
|
|
|
|
{
|
2017-05-17 09:08:33 +00:00
|
|
|
size_t i;
|
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
if (!ptr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virBitmapFree(ptr->cpus);
|
2017-05-17 09:08:33 +00:00
|
|
|
for (i = 0; i < ptr->ncontrols; i++)
|
|
|
|
VIR_FREE(ptr->controls[i]);
|
|
|
|
VIR_FREE(ptr->controls);
|
2017-03-30 13:01:27 +00:00
|
|
|
VIR_FREE(ptr);
|
|
|
|
}
|
|
|
|
|
2017-11-10 12:19:31 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virCapsHostCacheBankSorter(const void *a,
|
|
|
|
const void *b)
|
|
|
|
{
|
|
|
|
virCapsHostCacheBankPtr ca = *(virCapsHostCacheBankPtr *)a;
|
|
|
|
virCapsHostCacheBankPtr cb = *(virCapsHostCacheBankPtr *)b;
|
|
|
|
|
|
|
|
if (ca->level < cb->level)
|
|
|
|
return -1;
|
|
|
|
if (ca->level > cb->level)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return ca->id - cb->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-20 12:43:30 +00:00
|
|
|
static int
|
|
|
|
virCapabilitiesInitResctrl(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
if (caps->host.resctrl)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
caps->host.resctrl = virResctrlInfoNew();
|
|
|
|
if (!caps->host.resctrl)
|
|
|
|
return -1;
|
|
|
|
|
2018-02-08 14:47:46 +00:00
|
|
|
return 0;
|
2017-11-20 12:43:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-30 03:12:41 +00:00
|
|
|
static int
|
|
|
|
virCapabilitiesInitResctrlMemory(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
virCapsHostMemBWNodePtr node = NULL;
|
|
|
|
size_t i = 0;
|
|
|
|
int ret = -1;
|
2018-09-20 10:10:50 +00:00
|
|
|
const virResctrlMonitorType montype = VIR_RESCTRL_MONITOR_TYPE_MEMBW;
|
|
|
|
const char *prefix = virResctrlMonitorPrefixTypeToString(montype);
|
2018-07-30 03:12:41 +00:00
|
|
|
|
2018-09-20 10:10:48 +00:00
|
|
|
for (i = 0; i < caps->host.cache.nbanks; i++) {
|
|
|
|
virCapsHostCacheBankPtr bank = caps->host.cache.banks[i];
|
2018-07-30 03:12:41 +00:00
|
|
|
if (VIR_ALLOC(node) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virResctrlInfoGetMemoryBandwidth(caps->host.resctrl,
|
|
|
|
bank->level, &node->control) > 0) {
|
|
|
|
node->id = bank->id;
|
|
|
|
if (!(node->cpus = virBitmapNewCopy(bank->cpus)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-09-20 10:10:49 +00:00
|
|
|
if (VIR_APPEND_ELEMENT(caps->host.memBW.nodes,
|
|
|
|
caps->host.memBW.nnodes, node) < 0) {
|
2018-07-30 03:12:41 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virCapsHostMemBWNodeFree(node);
|
|
|
|
node = NULL;
|
|
|
|
}
|
|
|
|
|
2018-09-20 10:10:50 +00:00
|
|
|
if (virResctrlInfoGetMonitorPrefix(caps->host.resctrl, prefix,
|
|
|
|
&caps->host.memBW.monitor) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-07-30 03:12:41 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virCapsHostMemBWNodeFree(node);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
int
|
|
|
|
virCapabilitiesInitCaches(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
size_t i = 0;
|
|
|
|
virBitmapPtr cpus = NULL;
|
|
|
|
ssize_t pos = -1;
|
|
|
|
DIR *dirp = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
char *path = NULL;
|
|
|
|
char *type = NULL;
|
|
|
|
struct dirent *ent = NULL;
|
|
|
|
virCapsHostCacheBankPtr bank = NULL;
|
2018-09-20 10:10:50 +00:00
|
|
|
const virResctrlMonitorType montype = VIR_RESCTRL_MONITOR_TYPE_CACHE;
|
|
|
|
const char *prefix = virResctrlMonitorPrefixTypeToString(montype);
|
2017-03-30 13:01:27 +00:00
|
|
|
|
|
|
|
/* Minimum level to expose in capabilities. Can be lowered or removed (with
|
|
|
|
* the appropriate code below), but should not be increased, because we'd
|
|
|
|
* lose information. */
|
|
|
|
const int cache_min_level = 3;
|
|
|
|
|
2017-11-20 12:43:30 +00:00
|
|
|
if (virCapabilitiesInitResctrl(caps) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
/* offline CPUs don't provide cache info */
|
|
|
|
if (virFileReadValueBitmap(&cpus, "%s/cpu/online", SYSFS_SYSTEM_PATH) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while ((pos = virBitmapNextSetBit(cpus, pos)) >= 0) {
|
|
|
|
int rv = -1;
|
|
|
|
|
|
|
|
VIR_FREE(path);
|
|
|
|
if (virAsprintf(&path, "%s/cpu/cpu%zd/cache/", SYSFS_SYSTEM_PATH, pos) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2017-05-22 10:07:19 +00:00
|
|
|
VIR_DIR_CLOSE(dirp);
|
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
rv = virDirOpenIfExists(&dirp, path);
|
|
|
|
if (rv < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!dirp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
while ((rv = virDirRead(dirp, &ent, path)) > 0) {
|
|
|
|
int kernel_type;
|
|
|
|
unsigned int level;
|
|
|
|
|
|
|
|
if (!STRPREFIX(ent->d_name, "index"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (virFileReadValueUint(&level,
|
|
|
|
"%s/cpu/cpu%zd/cache/%s/level",
|
|
|
|
SYSFS_SYSTEM_PATH, pos, ent->d_name) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (level < cache_min_level)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(bank) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
bank->level = level;
|
|
|
|
|
|
|
|
if (virFileReadValueUint(&bank->id,
|
|
|
|
"%s/cpu/cpu%zd/cache/%s/id",
|
|
|
|
SYSFS_SYSTEM_PATH, pos, ent->d_name) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virFileReadValueUint(&bank->level,
|
|
|
|
"%s/cpu/cpu%zd/cache/%s/level",
|
|
|
|
SYSFS_SYSTEM_PATH, pos, ent->d_name) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virFileReadValueString(&type,
|
|
|
|
"%s/cpu/cpu%zd/cache/%s/type",
|
|
|
|
SYSFS_SYSTEM_PATH, pos, ent->d_name) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virFileReadValueScaledInt(&bank->size,
|
|
|
|
"%s/cpu/cpu%zd/cache/%s/size",
|
|
|
|
SYSFS_SYSTEM_PATH, pos, ent->d_name) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virFileReadValueBitmap(&bank->cpus,
|
|
|
|
"%s/cpu/cpu%zd/cache/%s/shared_cpu_list",
|
|
|
|
SYSFS_SYSTEM_PATH, pos, ent->d_name) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
kernel_type = virCacheKernelTypeFromString(type);
|
|
|
|
if (kernel_type < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unknown cache type '%s'"), type);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2017-05-17 09:08:33 +00:00
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
bank->type = kernel_type;
|
2017-05-12 10:46:20 +00:00
|
|
|
VIR_FREE(type);
|
2017-03-30 13:01:27 +00:00
|
|
|
|
2018-09-20 10:10:48 +00:00
|
|
|
for (i = 0; i < caps->host.cache.nbanks; i++) {
|
|
|
|
if (virCapsHostCacheBankEquals(bank, caps->host.cache.banks[i]))
|
2017-03-30 13:01:27 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-09-20 10:10:48 +00:00
|
|
|
if (i == caps->host.cache.nbanks) {
|
2017-11-20 12:43:30 +00:00
|
|
|
/* If it is a new cache, then update its resctrl information. */
|
|
|
|
if (virResctrlInfoGetCache(caps->host.resctrl,
|
|
|
|
bank->level,
|
|
|
|
bank->size,
|
|
|
|
&bank->ncontrols,
|
|
|
|
&bank->controls) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-09-20 10:10:48 +00:00
|
|
|
if (VIR_APPEND_ELEMENT(caps->host.cache.banks,
|
|
|
|
caps->host.cache.nbanks,
|
2017-03-30 13:01:27 +00:00
|
|
|
bank) < 0) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virCapsHostCacheBankFree(bank);
|
|
|
|
bank = NULL;
|
|
|
|
}
|
|
|
|
if (rv < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-11-10 12:19:31 +00:00
|
|
|
/* Sort the array in order for the tests to be predictable. This way we can
|
|
|
|
* still traverse the directory instead of guessing names (in case there is
|
|
|
|
* 'index1' and 'index3' but no 'index2'). */
|
2018-09-20 10:10:48 +00:00
|
|
|
qsort(caps->host.cache.banks, caps->host.cache.nbanks,
|
|
|
|
sizeof(*caps->host.cache.banks), virCapsHostCacheBankSorter);
|
2017-11-10 12:19:31 +00:00
|
|
|
|
2018-07-30 03:12:41 +00:00
|
|
|
if (virCapabilitiesInitResctrlMemory(caps) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-09-20 10:10:50 +00:00
|
|
|
if (virResctrlInfoGetMonitorPrefix(caps->host.resctrl, prefix,
|
|
|
|
&caps->host.cache.monitor) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2017-03-30 13:01:27 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
2017-05-12 10:46:20 +00:00
|
|
|
VIR_FREE(type);
|
2017-03-30 13:01:27 +00:00
|
|
|
VIR_FREE(path);
|
2017-05-22 10:07:19 +00:00
|
|
|
VIR_DIR_CLOSE(dirp);
|
2017-03-30 13:01:27 +00:00
|
|
|
virCapsHostCacheBankFree(bank);
|
2017-05-29 08:04:36 +00:00
|
|
|
virBitmapFree(cpus);
|
2017-03-30 13:01:27 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2018-06-01 08:15:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virCapabilitiesHostInitIOMMU(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
caps->host.iommu = virHostHasIOMMU();
|
|
|
|
}
|