/*
* libvirt.c: Main interfaces for the libvirt library to handle virtualization
* domains from a process running in domain 0
*
* Copyright (C) 2005-2006, 2008-2014 Red Hat, Inc.
*
* 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
* License along with this library. If not, see
* .
*
* Daniel Veillard
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "getpass.h"
#ifdef HAVE_WINSOCK2_H
# include
#endif
#ifdef WITH_CURL
# include
#endif
#include "virerror.h"
#include "virlog.h"
#include "datatypes.h"
#include "driver.h"
#include "viruuid.h"
#include "viralloc.h"
#include "configmake.h"
#include "virconf.h"
#if WITH_GNUTLS
# if WITH_GNUTLS_GCRYPT
# include
# endif
# include "rpc/virnettlscontext.h"
#endif
#include "vircommand.h"
#include "virfile.h"
#include "virrandom.h"
#include "viruri.h"
#include "virthread.h"
#include "virstring.h"
#include "virutil.h"
#include "virtypedparam.h"
#ifdef WITH_TEST
# include "test/test_driver.h"
#endif
#ifdef WITH_REMOTE
# include "remote/remote_driver.h"
#endif
#ifdef WITH_OPENVZ
# include "openvz/openvz_driver.h"
#endif
#ifdef WITH_VMWARE
# include "vmware/vmware_driver.h"
#endif
#ifdef WITH_PHYP
# include "phyp/phyp_driver.h"
#endif
#ifdef WITH_ESX
# include "esx/esx_driver.h"
#endif
#ifdef WITH_HYPERV
# include "hyperv/hyperv_driver.h"
#endif
#ifdef WITH_XENAPI
# include "xenapi/xenapi_driver.h"
#endif
#ifdef WITH_PARALLELS
# include "parallels/parallels_driver.h"
#endif
#ifdef WITH_BHYVE
# include "bhyve/bhyve_driver.h"
#endif
#define VIR_FROM_THIS VIR_FROM_NONE
VIR_LOG_INIT("libvirt");
/*
* TODO:
* - use lock to protect against concurrent accesses ?
* - use reference counting to guarantee coherent pointer state ?
*/
#define MAX_DRIVERS 20
#define virDriverCheckTabMaxReturn(count, ret) \
do { \
if ((count) >= MAX_DRIVERS) { \
virReportError(VIR_ERR_INTERNAL_ERROR, \
_("Too many drivers, cannot register %s"), \
driver->name); \
return ret; \
} \
} while (0)
static virHypervisorDriverPtr virHypervisorDriverTab[MAX_DRIVERS];
static int virHypervisorDriverTabCount = 0;
static virNetworkDriverPtr virNetworkDriverTab[MAX_DRIVERS];
static int virNetworkDriverTabCount = 0;
static virInterfaceDriverPtr virInterfaceDriverTab[MAX_DRIVERS];
static int virInterfaceDriverTabCount = 0;
static virStorageDriverPtr virStorageDriverTab[MAX_DRIVERS];
static int virStorageDriverTabCount = 0;
static virNodeDeviceDriverPtr virNodeDeviceDriverTab[MAX_DRIVERS];
static int virNodeDeviceDriverTabCount = 0;
static virSecretDriverPtr virSecretDriverTab[MAX_DRIVERS];
static int virSecretDriverTabCount = 0;
static virNWFilterDriverPtr virNWFilterDriverTab[MAX_DRIVERS];
static int virNWFilterDriverTabCount = 0;
#ifdef WITH_LIBVIRTD
static virStateDriverPtr virStateDriverTab[MAX_DRIVERS];
static int virStateDriverTabCount = 0;
#endif
#if defined(POLKIT_AUTH)
static int
virConnectAuthGainPolkit(const char *privilege)
{
virCommandPtr cmd;
int ret = -1;
if (geteuid() == 0)
return 0;
cmd = virCommandNewArgList(POLKIT_AUTH, "--obtain", privilege, NULL);
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
ret = 0;
cleanup:
virCommandFree(cmd);
return ret;
}
#endif
static int
virConnectAuthCallbackDefault(virConnectCredentialPtr cred,
unsigned int ncred,
void *cbdata ATTRIBUTE_UNUSED)
{
size_t i;
for (i = 0; i < ncred; i++) {
char buf[1024];
char *bufptr = buf;
size_t len;
switch (cred[i].type) {
case VIR_CRED_EXTERNAL: {
if (STRNEQ(cred[i].challenge, "PolicyKit"))
return -1;
#if defined(POLKIT_AUTH)
if (virConnectAuthGainPolkit(cred[i].prompt) < 0)
return -1;
#else
/*
* Ignore & carry on. Although we can't auth
* directly, the user may have authenticated
* themselves already outside context of libvirt
*/
#endif
break;
}
case VIR_CRED_USERNAME:
case VIR_CRED_AUTHNAME:
case VIR_CRED_ECHOPROMPT:
case VIR_CRED_REALM:
if (printf("%s: ", cred[i].prompt) < 0)
return -1;
if (fflush(stdout) != 0)
return -1;
if (!fgets(buf, sizeof(buf), stdin)) {
if (feof(stdin)) { /* Treat EOF as "" */
buf[0] = '\0';
break;
}
return -1;
}
len = strlen(buf);
if (len != 0 && buf[len-1] == '\n')
buf[len-1] = '\0';
break;
case VIR_CRED_PASSPHRASE:
case VIR_CRED_NOECHOPROMPT:
if (printf("%s: ", cred[i].prompt) < 0)
return -1;
if (fflush(stdout) != 0)
return -1;
bufptr = getpass("");
if (!bufptr)
return -1;
break;
default:
return -1;
}
if (cred[i].type != VIR_CRED_EXTERNAL) {
if (VIR_STRDUP(cred[i].result,
STREQ(bufptr, "") && cred[i].defresult ?
cred[i].defresult : bufptr) < 0)
return -1;
cred[i].resultlen = strlen(cred[i].result);
}
}
return 0;
}
/* Don't typically want VIR_CRED_USERNAME. It enables you to authenticate
* as one user, and act as another. It just results in annoying
* prompts for the username twice & is very rarely what you want
*/
static int virConnectCredTypeDefault[] = {
VIR_CRED_AUTHNAME,
VIR_CRED_ECHOPROMPT,
VIR_CRED_REALM,
VIR_CRED_PASSPHRASE,
VIR_CRED_NOECHOPROMPT,
VIR_CRED_EXTERNAL,
};
static virConnectAuth virConnectAuthDefault = {
virConnectCredTypeDefault,
sizeof(virConnectCredTypeDefault)/sizeof(int),
virConnectAuthCallbackDefault,
NULL,
};
/*
* virConnectAuthPtrDefault
*
* A default implementation of the authentication callbacks. This
* implementation is suitable for command line based tools. It will
* prompt for username, passwords, realm and one time keys as needed.
* It will print on STDOUT, and read from STDIN. If this is not
* suitable for the application's needs an alternative implementation
* should be provided.
*/
virConnectAuthPtr virConnectAuthPtrDefault = &virConnectAuthDefault;
#if HAVE_WINSOCK2_H
static int
winsock_init(void)
{
WORD winsock_version, err;
WSADATA winsock_data;
/* http://msdn2.microsoft.com/en-us/library/ms742213.aspx */
winsock_version = MAKEWORD (2, 2);
err = WSAStartup (winsock_version, &winsock_data);
return err == 0 ? 0 : -1;
}
#endif
#ifdef WITH_GNUTLS_GCRYPT
static int
virTLSMutexInit(void **priv)
{
virMutexPtr lock = NULL;
if (VIR_ALLOC_QUIET(lock) < 0)
return ENOMEM;
if (virMutexInit(lock) < 0) {
VIR_FREE(lock);
return errno;
}
*priv = lock;
return 0;
}
static int
virTLSMutexDestroy(void **priv)
{
virMutexPtr lock = *priv;
virMutexDestroy(lock);
VIR_FREE(lock);
return 0;
}
static int
virTLSMutexLock(void **priv)
{
virMutexPtr lock = *priv;
virMutexLock(lock);
return 0;
}
static int
virTLSMutexUnlock(void **priv)
{
virMutexPtr lock = *priv;
virMutexUnlock(lock);
return 0;
}
static struct gcry_thread_cbs virTLSThreadImpl = {
/* GCRY_THREAD_OPTION_VERSION was added in gcrypt 1.4.2 */
# ifdef GCRY_THREAD_OPTION_VERSION
(GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)),
# else
GCRY_THREAD_OPTION_PTHREAD,
# endif
NULL,
virTLSMutexInit,
virTLSMutexDestroy,
virTLSMutexLock,
virTLSMutexUnlock,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
#endif /* WITH_GNUTLS_GCRYPT */
static bool virGlobalError = false;
static virOnceControl virGlobalOnce = VIR_ONCE_CONTROL_INITIALIZER;
static void
virGlobalInit(void)
{
/* It would be nice if we could trace the use of this call, to
* help diagnose in log files if a user calls something other than
* virConnectOpen first. But we can't rely on VIR_DEBUG working
* until after initialization is complete, and since this is
* one-shot, we never get here again. */
if (virThreadInitialize() < 0 ||
virErrorInitialize() < 0)
goto error;
#ifndef LIBVIRT_SETUID_RPC_CLIENT
if (virIsSUID()) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("libvirt.so is not safe to use from setuid programs"));
goto error;
}
#endif
#ifdef WITH_GNUTLS_GCRYPT
/*
* This sequence of API calls it copied exactly from
* gnutls 2.12.23 source lib/gcrypt/init.c, with
* exception that GCRYCTL_ENABLE_QUICK_RANDOM, is
* dropped
*/
if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0) {
gcry_control(GCRYCTL_SET_THREAD_CBS, &virTLSThreadImpl);
gcry_check_version(NULL);
gcry_control(GCRYCTL_DISABLE_SECMEM, NULL, 0);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, NULL, 0);
}
#endif
virLogSetFromEnv();
#ifdef WITH_GNUTLS
virNetTLSInit();
#endif
#if WITH_CURL
curl_global_init(CURL_GLOBAL_DEFAULT);
#endif
VIR_DEBUG("register drivers");
#if HAVE_WINSOCK2_H
if (winsock_init() == -1)
goto error;
#endif
if (!bindtextdomain(PACKAGE, LOCALEDIR))
goto error;
/*
* Note we must avoid everything except 'remote' driver
* for virt-login-shell usage
*/
#ifndef LIBVIRT_SETUID_RPC_CLIENT
/*
* Note that the order is important: the first ones have a higher
* priority when calling virConnectOpen.
*/
# ifdef WITH_TEST
if (testRegister() == -1)
goto error;
# endif
# ifdef WITH_OPENVZ
if (openvzRegister() == -1)
goto error;
# endif
# ifdef WITH_VMWARE
if (vmwareRegister() == -1)
goto error;
# endif
# ifdef WITH_PHYP
if (phypRegister() == -1)
goto error;
# endif
# ifdef WITH_ESX
if (esxRegister() == -1)
goto error;
# endif
# ifdef WITH_HYPERV
if (hypervRegister() == -1)
goto error;
# endif
# ifdef WITH_XENAPI
if (xenapiRegister() == -1)
goto error;
# endif
# ifdef WITH_PARALLELS
if (parallelsRegister() == -1)
goto error;
# endif
#endif
#ifdef WITH_REMOTE
if (remoteRegister() == -1)
goto error;
#endif
return;
error:
virGlobalError = true;
}
/**
* virInitialize:
*
* Initialize the library.
*
* This method is invoked automatically by any of the virConnectOpen() API
* calls, and by virGetVersion(). Since release 1.0.0, there is no need to
* call this method even in a multithreaded application, since
* initialization is performed in a thread safe manner; but applications
* using an older version of the library should manually call this before
* setting up competing threads that attempt virConnectOpen in parallel.
*
* The only other time it would be necessary to call virInitialize is if the
* application did not invoke virConnectOpen as its first API call, such
* as when calling virEventRegisterImpl() before setting up connections,
* or when using virSetErrorFunc() to alter error reporting of the first
* connection attempt.
*
* Returns 0 in case of success, -1 in case of error
*/
int
virInitialize(void)
{
if (virOnce(&virGlobalOnce, virGlobalInit) < 0)
return -1;
if (virGlobalError)
return -1;
return 0;
}
#ifdef WIN32
BOOL WINAPI
DllMain(HINSTANCE instance, DWORD reason, LPVOID ignore);
BOOL WINAPI
DllMain(HINSTANCE instance ATTRIBUTE_UNUSED,
DWORD reason,
LPVOID ignore ATTRIBUTE_UNUSED)
{
switch (reason) {
case DLL_PROCESS_ATTACH:
virInitialize();
break;
case DLL_THREAD_ATTACH:
/* Nothing todo in libvirt yet */
break;
case DLL_THREAD_DETACH:
/* Release per-thread local data */
virThreadOnExit();
break;
case DLL_PROCESS_DETACH:
/* Don't bother releasing per-thread data
since (hopefully) windows cleans up
everything on process exit */
break;
}
return TRUE;
}
#endif
/**
* virRegisterNetworkDriver:
* @driver: pointer to a network driver block
*
* Register a network virtualization driver
*
* Returns the driver priority or -1 in case of error.
*/
int
virRegisterNetworkDriver(virNetworkDriverPtr driver)
{
virCheckNonNullArgReturn(driver, -1);
virDriverCheckTabMaxReturn(virNetworkDriverTabCount, -1);
VIR_DEBUG("registering %s as network driver %d",
driver->name, virNetworkDriverTabCount);
virNetworkDriverTab[virNetworkDriverTabCount] = driver;
return virNetworkDriverTabCount++;
}
/**
* virRegisterInterfaceDriver:
* @driver: pointer to an interface driver block
*
* Register an interface virtualization driver
*
* Returns the driver priority or -1 in case of error.
*/
int
virRegisterInterfaceDriver(virInterfaceDriverPtr driver)
{
virCheckNonNullArgReturn(driver, -1);
virDriverCheckTabMaxReturn(virInterfaceDriverTabCount, -1);
VIR_DEBUG("registering %s as interface driver %d",
driver->name, virInterfaceDriverTabCount);
virInterfaceDriverTab[virInterfaceDriverTabCount] = driver;
return virInterfaceDriverTabCount++;
}
/**
* virRegisterStorageDriver:
* @driver: pointer to a storage driver block
*
* Register a storage virtualization driver
*
* Returns the driver priority or -1 in case of error.
*/
int
virRegisterStorageDriver(virStorageDriverPtr driver)
{
virCheckNonNullArgReturn(driver, -1);
virDriverCheckTabMaxReturn(virStorageDriverTabCount, -1);
VIR_DEBUG("registering %s as storage driver %d",
driver->name, virStorageDriverTabCount);
virStorageDriverTab[virStorageDriverTabCount] = driver;
return virStorageDriverTabCount++;
}
/**
* virRegisterNodeDeviceDriver:
* @driver: pointer to a device monitor block
*
* Register a device monitor
*
* Returns the driver priority or -1 in case of error.
*/
int
virRegisterNodeDeviceDriver(virNodeDeviceDriverPtr driver)
{
virCheckNonNullArgReturn(driver, -1);
virDriverCheckTabMaxReturn(virNodeDeviceDriverTabCount, -1);
VIR_DEBUG("registering %s as device driver %d",
driver->name, virNodeDeviceDriverTabCount);
virNodeDeviceDriverTab[virNodeDeviceDriverTabCount] = driver;
return virNodeDeviceDriverTabCount++;
}
/**
* virRegisterSecretDriver:
* @driver: pointer to a secret driver block
*
* Register a secret driver
*
* Returns the driver priority or -1 in case of error.
*/
int
virRegisterSecretDriver(virSecretDriverPtr driver)
{
virCheckNonNullArgReturn(driver, -1);
virDriverCheckTabMaxReturn(virSecretDriverTabCount, -1);
VIR_DEBUG("registering %s as secret driver %d",
driver->name, virSecretDriverTabCount);
virSecretDriverTab[virSecretDriverTabCount] = driver;
return virSecretDriverTabCount++;
}
/**
* virRegisterNWFilterDriver:
* @driver: pointer to a network filter driver block
*
* Register a network filter virtualization driver
*
* Returns the driver priority or -1 in case of error.
*/
int
virRegisterNWFilterDriver(virNWFilterDriverPtr driver)
{
virCheckNonNullArgReturn(driver, -1);
virDriverCheckTabMaxReturn(virNWFilterDriverTabCount, -1);
VIR_DEBUG("registering %s as network filter driver %d",
driver->name, virNWFilterDriverTabCount);
virNWFilterDriverTab[virNWFilterDriverTabCount] = driver;
return virNWFilterDriverTabCount++;
}
/**
* virRegisterHypervisorDriver:
* @driver: pointer to a driver block
*
* Register a virtualization driver
*
* Returns the driver priority or -1 in case of error.
*/
int
virRegisterHypervisorDriver(virHypervisorDriverPtr driver)
{
VIR_DEBUG("driver=%p name=%s", driver,
driver ? NULLSTR(driver->name) : "(null)");
virCheckNonNullArgReturn(driver, -1);
virDriverCheckTabMaxReturn(virHypervisorDriverTabCount, -1);
VIR_DEBUG("registering %s as driver %d",
driver->name, virHypervisorDriverTabCount);
virHypervisorDriverTab[virHypervisorDriverTabCount] = driver;
return virHypervisorDriverTabCount++;
}
#ifdef WITH_LIBVIRTD
/**
* virRegisterStateDriver:
* @driver: pointer to a driver block
*
* Register a virtualization driver
*
* Returns the driver priority or -1 in case of error.
*/
int
virRegisterStateDriver(virStateDriverPtr driver)
{
virCheckNonNullArgReturn(driver, -1);
virDriverCheckTabMaxReturn(virStateDriverTabCount, -1);
virStateDriverTab[virStateDriverTabCount] = driver;
return virStateDriverTabCount++;
}
/**
* virStateInitialize:
* @privileged: set to true if running with root privilege, false otherwise
* @callback: callback to invoke to inhibit shutdown of the daemon
* @opaque: data to pass to @callback
*
* Initialize all virtualization drivers. Accomplished in two phases,
* the first being state and structure initialization followed by any
* auto start supported by the driver. This is done to ensure dependencies
* that some drivers may have on another driver having been initialized
* will exist, such as the storage driver's need to use the secret driver.
*
* Returns 0 if all succeed, -1 upon any failure.
*/
int
virStateInitialize(bool privileged,
virStateInhibitCallback callback,
void *opaque)
{
size_t i;
if (virInitialize() < 0)
return -1;
for (i = 0; i < virStateDriverTabCount; i++) {
if (virStateDriverTab[i]->stateInitialize) {
VIR_DEBUG("Running global init for %s state driver",
virStateDriverTab[i]->name);
if (virStateDriverTab[i]->stateInitialize(privileged,
callback,
opaque) < 0) {
virErrorPtr err = virGetLastError();
VIR_ERROR(_("Initialization of %s state driver failed: %s"),
virStateDriverTab[i]->name,
err && err->message ? err->message : _("Unknown problem"));
return -1;
}
}
}
for (i = 0; i < virStateDriverTabCount; i++) {
if (virStateDriverTab[i]->stateAutoStart) {
VIR_DEBUG("Running global auto start for %s state driver",
virStateDriverTab[i]->name);
virStateDriverTab[i]->stateAutoStart();
}
}
return 0;
}
/**
* virStateCleanup:
*
* Run each virtualization driver's cleanup method.
*
* Returns 0 if all succeed, -1 upon any failure.
*/
int
virStateCleanup(void)
{
size_t i;
int ret = 0;
for (i = 0; i < virStateDriverTabCount; i++) {
if (virStateDriverTab[i]->stateCleanup &&
virStateDriverTab[i]->stateCleanup() < 0)
ret = -1;
}
return ret;
}
/**
* virStateReload:
*
* Run each virtualization driver's reload method.
*
* Returns 0 if all succeed, -1 upon any failure.
*/
int
virStateReload(void)
{
size_t i;
int ret = 0;
for (i = 0; i < virStateDriverTabCount; i++) {
if (virStateDriverTab[i]->stateReload &&
virStateDriverTab[i]->stateReload() < 0)
ret = -1;
}
return ret;
}
/**
* virStateStop:
*
* Run each virtualization driver's "stop" method.
*
* Returns 0 if successful, -1 on failure
*/
int
virStateStop(void)
{
size_t i;
int ret = 0;
for (i = 0; i < virStateDriverTabCount; i++) {
if (virStateDriverTab[i]->stateStop &&
virStateDriverTab[i]->stateStop())
ret = 1;
}
return ret;
}
#endif /* WITH_LIBVIRTD */
/**
* virGetVersion:
* @libVer: return value for the library version (OUT)
* @type: ignored; pass NULL
* @typeVer: pass NULL; for historical purposes duplicates @libVer if
* non-NULL
*
* Provides version information. @libVer is the version of the
* library and will always be set unless an error occurs, in which case
* an error code will be returned. @typeVer exists for historical
* compatibility; if it is not NULL it will duplicate @libVer (it was
* originally intended to return hypervisor information based on @type,
* but due to the design of remote clients this is not reliable). To
* get the version of the running hypervisor use the virConnectGetVersion()
* function instead. To get the libvirt library version used by a
* connection use the virConnectGetLibVersion() instead.
*
* This function includes a call to virInitialize() when necessary.
*
* Returns -1 in case of failure, 0 otherwise, and values for @libVer and
* @typeVer have the format major * 1,000,000 + minor * 1,000 + release.
*/
int
virGetVersion(unsigned long *libVer, const char *type ATTRIBUTE_UNUSED,
unsigned long *typeVer)
{
if (virInitialize() < 0)
goto error;
VIR_DEBUG("libVir=%p, type=%s, typeVer=%p", libVer, type, typeVer);
virResetLastError();
if (libVer == NULL)
goto error;
*libVer = LIBVIR_VERSION_NUMBER;
if (typeVer != NULL)
*typeVer = LIBVIR_VERSION_NUMBER;
return 0;
error:
virDispatchError(NULL);
return -1;
}
static char *
virConnectGetConfigFilePath(void)
{
char *path;
if (geteuid() == 0) {
if (virAsprintf(&path, "%s/libvirt/libvirt.conf",
SYSCONFDIR) < 0)
return NULL;
} else {
char *userdir = virGetUserConfigDirectory();
if (!userdir)
return NULL;
if (virAsprintf(&path, "%s/libvirt.conf",
userdir) < 0) {
VIR_FREE(userdir);
return NULL;
}
VIR_FREE(userdir);
}
return path;
}
static int
virConnectGetConfigFile(virConfPtr *conf)
{
char *filename = NULL;
int ret = -1;
*conf = NULL;
if (!(filename = virConnectGetConfigFilePath()))
goto cleanup;
if (!virFileExists(filename)) {
ret = 0;
goto cleanup;
}
VIR_DEBUG("Loading config file '%s'", filename);
if (!(*conf = virConfReadFile(filename, 0)))
goto cleanup;
ret = 0;
cleanup:
VIR_FREE(filename);
return ret;
}
#define URI_ALIAS_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"
static int
virConnectOpenFindURIAliasMatch(virConfValuePtr value, const char *alias,
char **uri)
{
virConfValuePtr entry;
size_t alias_len;
if (value->type != VIR_CONF_LIST) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Expected a list for 'uri_aliases' config parameter"));
return -1;
}
entry = value->list;
alias_len = strlen(alias);
while (entry) {
char *offset;
size_t safe;
if (entry->type != VIR_CONF_STRING) {
virReportError(VIR_ERR_CONF_SYNTAX, "%s",
_("Expected a string for 'uri_aliases' config parameter list entry"));
return -1;
}
if (!(offset = strchr(entry->str, '='))) {
virReportError(VIR_ERR_CONF_SYNTAX,
_("Malformed 'uri_aliases' config entry '%s', expected 'alias=uri://host/path'"),
entry->str);
return -1;
}
safe = strspn(entry->str, URI_ALIAS_CHARS);
if (safe < (offset - entry->str)) {
virReportError(VIR_ERR_CONF_SYNTAX,
_("Malformed 'uri_aliases' config entry '%s', aliases may only contain 'a-Z, 0-9, _, -'"),
entry->str);
return -1;
}
if (alias_len == (offset - entry->str) &&
STREQLEN(entry->str, alias, alias_len)) {
VIR_DEBUG("Resolved alias '%s' to '%s'",
alias, offset+1);
return VIR_STRDUP(*uri, offset+1);
}
entry = entry->next;
}
VIR_DEBUG("No alias found for '%s', passing through to drivers",
alias);
return 0;
}
static int
virConnectOpenResolveURIAlias(virConfPtr conf,
const char *alias, char **uri)
{
int ret = -1;
virConfValuePtr value = NULL;
*uri = NULL;
if ((value = virConfGetValue(conf, "uri_aliases")))
ret = virConnectOpenFindURIAliasMatch(value, alias, uri);
else
ret = 0;
return ret;
}
static int
virConnectGetDefaultURI(virConfPtr conf,
const char **name)
{
int ret = -1;
virConfValuePtr value = NULL;
const char *defname = virGetEnvBlockSUID("LIBVIRT_DEFAULT_URI");
if (defname && *defname) {
VIR_DEBUG("Using LIBVIRT_DEFAULT_URI '%s'", defname);
*name = defname;
} else if ((value = virConfGetValue(conf, "uri_default"))) {
if (value->type != VIR_CONF_STRING) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Expected a string for 'uri_default' config parameter"));
goto cleanup;
}
VIR_DEBUG("Using config file uri '%s'", value->str);
*name = value->str;
}
ret = 0;
cleanup:
return ret;
}
static virConnectPtr
do_open(const char *name,
virConnectAuthPtr auth,
unsigned int flags)
{
size_t i;
int res;
virConnectPtr ret;
virConfPtr conf = NULL;
ret = virGetConnect();
if (ret == NULL)
return NULL;
if (virConnectGetConfigFile(&conf) < 0)
goto failed;
if (name && name[0] == '\0')
name = NULL;
if (!name && virIsSUID()) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("An explicit URI must be provided when setuid"));
goto failed;
}
/*
* If no URI is passed, then check for an environment string if not
* available probe the compiled in drivers to find a default hypervisor
* if detectable.
*/
if (!name &&
virConnectGetDefaultURI(conf, &name) < 0)
goto failed;
if (name) {
char *alias = NULL;
/* Convert xen -> xen:/// for back compat */
if (STRCASEEQ(name, "xen"))
name = "xen:///";
/* Convert xen:// -> xen:/// because xmlParseURI cannot parse the
* former. This allows URIs such as xen://localhost to work.
*/
if (STREQ(name, "xen://"))
name = "xen:///";
if (!(flags & VIR_CONNECT_NO_ALIASES) &&
virConnectOpenResolveURIAlias(conf, name, &alias) < 0)
goto failed;
if (!(ret->uri = virURIParse(alias ? alias : name))) {
VIR_FREE(alias);
goto failed;
}
VIR_DEBUG("name \"%s\" to URI components:\n"
" scheme %s\n"
" server %s\n"
" user %s\n"
" port %d\n"
" path %s\n",
alias ? alias : name,
NULLSTR(ret->uri->scheme), NULLSTR(ret->uri->server),
NULLSTR(ret->uri->user), ret->uri->port,
NULLSTR(ret->uri->path));
VIR_FREE(alias);
} else {
VIR_DEBUG("no name, allowing driver auto-select");
}
/* Cleansing flags */
ret->flags = flags & VIR_CONNECT_RO;
for (i = 0; i < virHypervisorDriverTabCount; i++) {
/* We're going to probe the remote driver next. So we have already
* probed all other client-side-only driver before, but none of them
* accepted the URI.
* If the scheme corresponds to a known but disabled client-side-only
* driver then report a useful error, instead of a cryptic one about
* not being able to connect to libvirtd or not being able to find
* certificates. */
if (virHypervisorDriverTab[i]->no == VIR_DRV_REMOTE &&
ret->uri != NULL && ret->uri->scheme != NULL &&
(
#ifndef WITH_PHYP
STRCASEEQ(ret->uri->scheme, "phyp") ||
#endif
#ifndef WITH_ESX
STRCASEEQ(ret->uri->scheme, "vpx") ||
STRCASEEQ(ret->uri->scheme, "esx") ||
STRCASEEQ(ret->uri->scheme, "gsx") ||
#endif
#ifndef WITH_HYPERV
STRCASEEQ(ret->uri->scheme, "hyperv") ||
#endif
#ifndef WITH_XENAPI
STRCASEEQ(ret->uri->scheme, "xenapi") ||
#endif
#ifndef WITH_PARALLELS
STRCASEEQ(ret->uri->scheme, "parallels") ||
#endif
false)) {
virReportErrorHelper(VIR_FROM_NONE, VIR_ERR_CONFIG_UNSUPPORTED,
__FILE__, __FUNCTION__, __LINE__,
_("libvirt was built without the '%s' driver"),
ret->uri->scheme);
goto failed;
}
VIR_DEBUG("trying driver %zu (%s) ...", i, virHypervisorDriverTab[i]->name);
ret->driver = virHypervisorDriverTab[i];
res = virHypervisorDriverTab[i]->connectOpen(ret, auth, flags);
VIR_DEBUG("driver %zu %s returned %s",
i, virHypervisorDriverTab[i]->name,
res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" :
(res == VIR_DRV_OPEN_DECLINED ? "DECLINED" :
(res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status")));
if (res == VIR_DRV_OPEN_SUCCESS) {
break;
} else if (res == VIR_DRV_OPEN_ERROR) {
ret->driver = NULL;
goto failed;
} else {
ret->driver = NULL;
}
}
if (!ret->driver) {
/* If we reach here, then all drivers declined the connection. */
virReportError(VIR_ERR_NO_CONNECT, "%s", NULLSTR(name));
goto failed;
}
for (i = 0; i < virNetworkDriverTabCount; i++) {
res = virNetworkDriverTab[i]->networkOpen(ret, auth, flags);
VIR_DEBUG("network driver %zu %s returned %s",
i, virNetworkDriverTab[i]->name,
res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" :
(res == VIR_DRV_OPEN_DECLINED ? "DECLINED" :
(res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status")));
if (res == VIR_DRV_OPEN_SUCCESS) {
ret->networkDriver = virNetworkDriverTab[i];
break;
} else if (res == VIR_DRV_OPEN_ERROR) {
break;
}
}
for (i = 0; i < virInterfaceDriverTabCount; i++) {
res = virInterfaceDriverTab[i]->interfaceOpen(ret, auth, flags);
VIR_DEBUG("interface driver %zu %s returned %s",
i, virInterfaceDriverTab[i]->name,
res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" :
(res == VIR_DRV_OPEN_DECLINED ? "DECLINED" :
(res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status")));
if (res == VIR_DRV_OPEN_SUCCESS) {
ret->interfaceDriver = virInterfaceDriverTab[i];
break;
} else if (res == VIR_DRV_OPEN_ERROR) {
break;
}
}
/* Secondary driver for storage. Optional */
for (i = 0; i < virStorageDriverTabCount; i++) {
res = virStorageDriverTab[i]->storageOpen(ret, auth, flags);
VIR_DEBUG("storage driver %zu %s returned %s",
i, virStorageDriverTab[i]->name,
res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" :
(res == VIR_DRV_OPEN_DECLINED ? "DECLINED" :
(res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status")));
if (res == VIR_DRV_OPEN_SUCCESS) {
ret->storageDriver = virStorageDriverTab[i];
break;
} else if (res == VIR_DRV_OPEN_ERROR) {
break;
}
}
/* Node driver (optional) */
for (i = 0; i < virNodeDeviceDriverTabCount; i++) {
res = virNodeDeviceDriverTab[i]->nodeDeviceOpen(ret, auth, flags);
VIR_DEBUG("node driver %zu %s returned %s",
i, virNodeDeviceDriverTab[i]->name,
res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" :
(res == VIR_DRV_OPEN_DECLINED ? "DECLINED" :
(res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status")));
if (res == VIR_DRV_OPEN_SUCCESS) {
ret->nodeDeviceDriver = virNodeDeviceDriverTab[i];
break;
} else if (res == VIR_DRV_OPEN_ERROR) {
break;
}
}
/* Secret manipulation driver. Optional */
for (i = 0; i < virSecretDriverTabCount; i++) {
res = virSecretDriverTab[i]->secretOpen(ret, auth, flags);
VIR_DEBUG("secret driver %zu %s returned %s",
i, virSecretDriverTab[i]->name,
res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" :
(res == VIR_DRV_OPEN_DECLINED ? "DECLINED" :
(res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status")));
if (res == VIR_DRV_OPEN_SUCCESS) {
ret->secretDriver = virSecretDriverTab[i];
break;
} else if (res == VIR_DRV_OPEN_ERROR) {
break;
}
}
/* Network filter driver. Optional */
for (i = 0; i < virNWFilterDriverTabCount; i++) {
res = virNWFilterDriverTab[i]->nwfilterOpen(ret, auth, flags);
VIR_DEBUG("nwfilter driver %zu %s returned %s",
i, virNWFilterDriverTab[i]->name,
res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" :
(res == VIR_DRV_OPEN_DECLINED ? "DECLINED" :
(res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status")));
if (res == VIR_DRV_OPEN_SUCCESS) {
ret->nwfilterDriver = virNWFilterDriverTab[i];
break;
} else if (res == VIR_DRV_OPEN_ERROR) {
break;
}
}
virConfFree(conf);
return ret;
failed:
virConfFree(conf);
virObjectUnref(ret);
return NULL;
}
/**
* virConnectOpen:
* @name: (optional) URI of the hypervisor
*
* This function should be called first to get a connection to the
* Hypervisor and xen store
*
* If @name is NULL, if the LIBVIRT_DEFAULT_URI environment variable is set,
* then it will be used. Otherwise if the client configuration file
* has the "uri_default" parameter set, then it will be used. Finally
* probing will be done to determine a suitable default driver to activate.
* This involves trying each hypervisor in turn until one successfully opens.
*
* If connecting to an unprivileged hypervisor driver which requires
* the libvirtd daemon to be active, it will automatically be launched
* if not already running. This can be prevented by setting the
* environment variable LIBVIRT_AUTOSTART=0
*
* URIs are documented at http://libvirt.org/uri.html
*
* virConnectClose should be used to release the resources after the connection
* is no longer needed.
*
* Returns a pointer to the hypervisor connection or NULL in case of error
*/
virConnectPtr
virConnectOpen(const char *name)
{
virConnectPtr ret = NULL;
if (virInitialize() < 0)
goto error;
VIR_DEBUG("name=%s", NULLSTR(name));
virResetLastError();
ret = do_open(name, NULL, 0);
if (!ret)
goto error;
return ret;
error:
virDispatchError(NULL);
return NULL;
}
/**
* virConnectOpenReadOnly:
* @name: (optional) URI of the hypervisor
*
* This function should be called first to get a restricted connection to the
* library functionalities. The set of APIs usable are then restricted
* on the available methods to control the domains.
*
* See virConnectOpen for notes about environment variables which can
* have an effect on opening drivers and freeing the connection resources
*
* URIs are documented at http://libvirt.org/uri.html
*
* Returns a pointer to the hypervisor connection or NULL in case of error
*/
virConnectPtr
virConnectOpenReadOnly(const char *name)
{
virConnectPtr ret = NULL;
if (virInitialize() < 0)
goto error;
VIR_DEBUG("name=%s", NULLSTR(name));
virResetLastError();
ret = do_open(name, NULL, VIR_CONNECT_RO);
if (!ret)
goto error;
return ret;
error:
virDispatchError(NULL);
return NULL;
}
/**
* virConnectOpenAuth:
* @name: (optional) URI of the hypervisor
* @auth: Authenticate callback parameters
* @flags: bitwise-OR of virConnectFlags
*
* This function should be called first to get a connection to the
* Hypervisor. If necessary, authentication will be performed fetching
* credentials via the callback
*
* See virConnectOpen for notes about environment variables which can
* have an effect on opening drivers and freeing the connection resources
*
* URIs are documented at http://libvirt.org/uri.html
*
* Returns a pointer to the hypervisor connection or NULL in case of error
*/
virConnectPtr
virConnectOpenAuth(const char *name,
virConnectAuthPtr auth,
unsigned int flags)
{
virConnectPtr ret = NULL;
if (virInitialize() < 0)
goto error;
VIR_DEBUG("name=%s, auth=%p, flags=%x", NULLSTR(name), auth, flags);
virResetLastError();
ret = do_open(name, auth, flags);
if (!ret)
goto error;
return ret;
error:
virDispatchError(NULL);
return NULL;
}
/**
* virConnectClose:
* @conn: pointer to the hypervisor connection
*
* This function closes the connection to the Hypervisor. This should
* not be called if further interaction with the Hypervisor are needed
* especially if there is running domain which need further monitoring by
* the application.
*
* Connections are reference counted; the count is explicitly
* increased by the initial open (virConnectOpen, virConnectOpenAuth,
* and the like) as well as virConnectRef; it is also temporarily
* increased by other API that depend on the connection remaining
* alive. The open and every virConnectRef call should have a
* matching virConnectClose, and all other references will be released
* after the corresponding operation completes.
*
* Returns a positive number if at least 1 reference remains on
* success. The returned value should not be assumed to be the total
* reference count. A return of 0 implies no references remain and
* the connection is closed and memory has been freed. A return of -1
* implies a failure.
*
* It is possible for the last virConnectClose to return a positive
* value if some other object still has a temporary reference to the
* connection, but the application should not try to further use a
* connection after the virConnectClose that matches the initial open.
*/
int
virConnectClose(virConnectPtr conn)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, -1);
if (!virObjectUnref(conn))
return 0;
return 1;
}
/**
* virConnectRef:
* @conn: the connection to hold a reference on
*
* Increment the reference count on the connection. For each
* additional call to this method, there shall be a corresponding
* call to virConnectClose to release the reference count, once
* the caller no longer needs the reference to this object.
*
* This method is typically useful for applications where multiple
* threads are using a connection, and it is required that the
* connection remain open until all threads have finished using
* it. ie, each new thread using a connection would increment
* the reference count.
*
* Returns 0 in case of success, -1 in case of failure
*/
int
virConnectRef(virConnectPtr conn)
{
VIR_DEBUG("conn=%p refs=%d", conn, conn ? conn->object.u.s.refs : 0);
virResetLastError();
virCheckConnectReturn(conn, -1);
virObjectRef(conn);
return 0;
}
/*
* Not for public use. This function is part of the internal
* implementation of driver features in the remote case.
*/
int
virConnectSupportsFeature(virConnectPtr conn, int feature)
{
int ret;
VIR_DEBUG("conn=%p, feature=%d", conn, feature);
virResetLastError();
virCheckConnectReturn(conn, -1);
if (!conn->driver->connectSupportsFeature)
ret = 0;
else
ret = conn->driver->connectSupportsFeature(conn, feature);
if (ret < 0)
virDispatchError(conn);
return ret;
}
/* Helper function called to validate incoming client array on any
* interface that sets typed parameters in the hypervisor. */
int
virTypedParameterValidateSet(virConnectPtr conn,
virTypedParameterPtr params,
int nparams)
{
bool string_okay;
size_t i;
string_okay = VIR_DRV_SUPPORTS_FEATURE(conn->driver,
conn,
VIR_DRV_FEATURE_TYPED_PARAM_STRING);
for (i = 0; i < nparams; i++) {
if (strnlen(params[i].field, VIR_TYPED_PARAM_FIELD_LENGTH) ==
VIR_TYPED_PARAM_FIELD_LENGTH) {
virReportInvalidArg(params,
_("string parameter name '%.*s' too long"),
VIR_TYPED_PARAM_FIELD_LENGTH,
params[i].field);
return -1;
}
if (params[i].type == VIR_TYPED_PARAM_STRING) {
if (string_okay) {
if (!params[i].value.s) {
virReportInvalidArg(params,
_("NULL string parameter '%s'"),
params[i].field);
return -1;
}
} else {
virReportInvalidArg(params,
_("string parameter '%s' unsupported"),
params[i].field);
return -1;
}
}
}
return 0;
}
/**
* virConnectGetType:
* @conn: pointer to the hypervisor connection
*
* Get the name of the Hypervisor driver used. This is merely the driver
* name; for example, both KVM and QEMU guests are serviced by the
* driver for the qemu:// URI, so a return of "QEMU" does not indicate
* whether KVM acceleration is present. For more details about the
* hypervisor, use virConnectGetCapabilities().
*
* Returns NULL in case of error, a static zero terminated string otherwise.
*
* See also:
* http://www.redhat.com/archives/libvir-list/2007-February/msg00096.html
*/
const char *
virConnectGetType(virConnectPtr conn)
{
const char *ret;
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, NULL);
if (conn->driver->connectGetType) {
ret = conn->driver->connectGetType(conn);
if (ret) return ret;
}
return conn->driver->name;
}
/**
* virConnectGetVersion:
* @conn: pointer to the hypervisor connection
* @hvVer: return value for the version of the running hypervisor (OUT)
*
* Get the version level of the Hypervisor running. This may work only with
* hypervisor call, i.e. with privileged access to the hypervisor, not
* with a Read-Only connection.
*
* Returns -1 in case of error, 0 otherwise. if the version can't be
* extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
* @hvVer value is major * 1,000,000 + minor * 1,000 + release
*/
int
virConnectGetVersion(virConnectPtr conn, unsigned long *hvVer)
{
VIR_DEBUG("conn=%p, hvVer=%p", conn, hvVer);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(hvVer, error);
if (conn->driver->connectGetVersion) {
int ret = conn->driver->connectGetVersion(conn, hvVer);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virConnectGetLibVersion:
* @conn: pointer to the hypervisor connection
* @libVer: returns the libvirt library version used on the connection (OUT)
*
* Provides @libVer, which is the version of libvirt used by the
* daemon running on the @conn host
*
* Returns -1 in case of failure, 0 otherwise, and values for @libVer have
* the format major * 1,000,000 + minor * 1,000 + release.
*/
int
virConnectGetLibVersion(virConnectPtr conn, unsigned long *libVer)
{
int ret = -1;
VIR_DEBUG("conn=%p, libVir=%p", conn, libVer);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(libVer, error);
if (conn->driver->connectGetLibVersion) {
ret = conn->driver->connectGetLibVersion(conn, libVer);
if (ret < 0)
goto error;
return ret;
}
*libVer = LIBVIR_VERSION_NUMBER;
return 0;
error:
virDispatchError(conn);
return ret;
}
/**
* virConnectGetHostname:
* @conn: pointer to a hypervisor connection
*
* This returns a system hostname on which the hypervisor is
* running (based on the result of the gethostname system call, but
* possibly expanded to a fully-qualified domain name via getaddrinfo).
* If we are connected to a remote system, then this returns the
* hostname of the remote system.
*
* Returns the hostname which must be freed by the caller, or
* NULL if there was an error.
*/
char *
virConnectGetHostname(virConnectPtr conn)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, NULL);
if (conn->driver->connectGetHostname) {
char *ret = conn->driver->connectGetHostname(conn);
if (!ret)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virConnectGetURI:
* @conn: pointer to a hypervisor connection
*
* This returns the URI (name) of the hypervisor connection.
* Normally this is the same as or similar to the string passed
* to the virConnectOpen/virConnectOpenReadOnly call, but
* the driver may make the URI canonical. If name == NULL
* was passed to virConnectOpen, then the driver will return
* a non-NULL URI which can be used to connect to the same
* hypervisor later.
*
* Returns the URI string which must be freed by the caller, or
* NULL if there was an error.
*/
char *
virConnectGetURI(virConnectPtr conn)
{
char *name;
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, NULL);
if (!(name = virURIFormat(conn->uri)))
goto error;
return name;
error:
virDispatchError(conn);
return NULL;
}
/**
* virConnectGetSysinfo:
* @conn: pointer to a hypervisor connection
* @flags: extra flags; not used yet, so callers should always pass 0
*
* This returns the XML description of the sysinfo details for the
* host on which the hypervisor is running, in the same format as the
* element of a domain XML. This information is generally
* available only for hypervisors running with root privileges.
*
* Returns the XML string which must be freed by the caller, or
* NULL if there was an error.
*/
char *
virConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
{
VIR_DEBUG("conn=%p, flags=%x", conn, flags);
virResetLastError();
virCheckConnectReturn(conn, NULL);
if (conn->driver->connectGetSysinfo) {
char *ret = conn->driver->connectGetSysinfo(conn, flags);
if (!ret)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virConnectGetMaxVcpus:
* @conn: pointer to the hypervisor connection
* @type: value of the 'type' attribute in the element
*
* Provides the maximum number of virtual CPUs supported for a guest VM of a
* specific type. The 'type' parameter here corresponds to the 'type'
* attribute in the element of the XML.
*
* Returns the maximum of virtual CPU or -1 in case of error.
*/
int
virConnectGetMaxVcpus(virConnectPtr conn,
const char *type)
{
VIR_DEBUG("conn=%p, type=%s", conn, type);
virResetLastError();
virCheckConnectReturn(conn, -1);
if (conn->driver->connectGetMaxVcpus) {
int ret = conn->driver->connectGetMaxVcpus(conn, type);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virNodeGetInfo:
* @conn: pointer to the hypervisor connection
* @info: pointer to a virNodeInfo structure allocated by the user
*
* Extract hardware information about the node.
*
* Returns 0 in case of success and -1 in case of failure.
*/
int
virNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
{
VIR_DEBUG("conn=%p, info=%p", conn, info);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(info, error);
if (conn->driver->nodeGetInfo) {
int ret;
ret = conn->driver->nodeGetInfo(conn, info);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virConnectGetCapabilities:
* @conn: pointer to the hypervisor connection
*
* Provides capabilities of the hypervisor / driver.
*
* Returns NULL in case of error, or an XML string
* defining the capabilities.
* The client must free the returned string after use.
*/
char *
virConnectGetCapabilities(virConnectPtr conn)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, NULL);
if (conn->driver->connectGetCapabilities) {
char *ret;
ret = conn->driver->connectGetCapabilities(conn);
if (!ret)
goto error;
VIR_DEBUG("conn=%p ret=%s", conn, ret);
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virNodeGetCPUStats:
* @conn: pointer to the hypervisor connection.
* @cpuNum: number of node cpu. (VIR_NODE_CPU_STATS_ALL_CPUS means total cpu
* statistics)
* @params: pointer to node cpu time parameter objects
* @nparams: number of node cpu time parameter (this value should be same or
* less than the number of parameters supported)
* @flags: extra flags; not used yet, so callers should always pass 0
*
* This function provides individual cpu statistics of the node.
* If you want to get total cpu statistics of the node, you must specify
* VIR_NODE_CPU_STATS_ALL_CPUS to @cpuNum.
* The @params array will be filled with the values equal to the number of
* parameters suggested by @nparams
*
* As the value of @nparams is dynamic, call the API setting @nparams to 0 and
* @params as NULL, the API returns the number of parameters supported by the
* HV by updating @nparams on SUCCESS. The caller should then allocate @params
* array, i.e. (sizeof(@virNodeCPUStats) * @nparams) bytes and call
* the API again.
*
* Here is a sample code snippet:
*
* if (virNodeGetCPUStats(conn, cpuNum, NULL, &nparams, 0) == 0 &&
* nparams != 0) {
* if ((params = malloc(sizeof(virNodeCPUStats) * nparams)) == NULL)
* goto error;
* memset(params, 0, sizeof(virNodeCPUStats) * nparams);
* if (virNodeGetCPUStats(conn, cpuNum, params, &nparams, 0))
* goto error;
* }
*
* This function doesn't require privileged access to the hypervisor.
* This function expects the caller to allocate the @params.
*
* CPU time Statistics:
*
* VIR_NODE_CPU_STATS_KERNEL:
* The cumulative CPU time which spends by kernel,
* when the node booting up.(nanoseconds)
* VIR_NODE_CPU_STATS_USER:
* The cumulative CPU time which spends by user processes,
* when the node booting up.(nanoseconds)
* VIR_NODE_CPU_STATS_IDLE:
* The cumulative idle CPU time, when the node booting up.(nanoseconds)
* VIR_NODE_CPU_STATS_IOWAIT:
* The cumulative I/O wait CPU time, when the node booting up.(nanoseconds)
* VIR_NODE_CPU_STATS_UTILIZATION:
* The CPU utilization. The usage value is in percent and 100%
* represents all CPUs on the server.
*
* Returns -1 in case of error, 0 in case of success.
*/
int
virNodeGetCPUStats(virConnectPtr conn,
int cpuNum,
virNodeCPUStatsPtr params,
int *nparams, unsigned int flags)
{
VIR_DEBUG("conn=%p, cpuNum=%d, params=%p, nparams=%d, flags=%x",
conn, cpuNum, params, nparams ? *nparams : -1, flags);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(nparams, error);
virCheckNonNegativeArgGoto(*nparams, error);
if (cpuNum < 0 && cpuNum != VIR_NODE_CPU_STATS_ALL_CPUS) {
virReportInvalidArg(cpuNum,
_("cpuNum in %s only accepts %d as a negative "
"value"),
__FUNCTION__, VIR_NODE_CPU_STATS_ALL_CPUS);
goto error;
}
if (conn->driver->nodeGetCPUStats) {
int ret;
ret = conn->driver->nodeGetCPUStats(conn, cpuNum, params, nparams, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virNodeGetMemoryStats:
* @conn: pointer to the hypervisor connection.
* @cellNum: number of node cell. (VIR_NODE_MEMORY_STATS_ALL_CELLS means total
* cell statistics)
* @params: pointer to node memory stats objects
* @nparams: number of node memory stats (this value should be same or
* less than the number of stats supported)
* @flags: extra flags; not used yet, so callers should always pass 0
*
* This function provides memory stats of the node.
* If you want to get total memory statistics of the node, you must specify
* VIR_NODE_MEMORY_STATS_ALL_CELLS to @cellNum.
* The @params array will be filled with the values equal to the number of
* stats suggested by @nparams
*
* As the value of @nparams is dynamic, call the API setting @nparams to 0 and
* @params as NULL, the API returns the number of parameters supported by the
* HV by updating @nparams on SUCCESS. The caller should then allocate @params
* array, i.e. (sizeof(@virNodeMemoryStats) * @nparams) bytes and call
* the API again.
*
* Here is the sample code snippet:
*
* if (virNodeGetMemoryStats(conn, cellNum, NULL, &nparams, 0) == 0 &&
* nparams != 0) {
* if ((params = malloc(sizeof(virNodeMemoryStats) * nparams)) == NULL)
* goto error;
* memset(params, cellNum, 0, sizeof(virNodeMemoryStats) * nparams);
* if (virNodeGetMemoryStats(conn, params, &nparams, 0))
* goto error;
* }
*
* This function doesn't require privileged access to the hypervisor.
* This function expects the caller to allocate the @params.
*
* Memory Stats:
*
* VIR_NODE_MEMORY_STATS_TOTAL:
* The total memory usage.(KB)
* VIR_NODE_MEMORY_STATS_FREE:
* The free memory usage.(KB)
* On linux, this usage includes buffers and cached.
* VIR_NODE_MEMORY_STATS_BUFFERS:
* The buffers memory usage.(KB)
* VIR_NODE_MEMORY_STATS_CACHED:
* The cached memory usage.(KB)
*
* Returns -1 in case of error, 0 in case of success.
*/
int
virNodeGetMemoryStats(virConnectPtr conn,
int cellNum,
virNodeMemoryStatsPtr params,
int *nparams, unsigned int flags)
{
VIR_DEBUG("conn=%p, cellNum=%d, params=%p, nparams=%d, flags=%x",
conn, cellNum, params, nparams ? *nparams : -1, flags);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(nparams, error);
virCheckNonNegativeArgGoto(*nparams, error);
if (cellNum < 0 && cellNum != VIR_NODE_MEMORY_STATS_ALL_CELLS) {
virReportInvalidArg(cpuNum,
_("cellNum in %s only accepts %d as a negative "
"value"),
__FUNCTION__, VIR_NODE_MEMORY_STATS_ALL_CELLS);
goto error;
}
if (conn->driver->nodeGetMemoryStats) {
int ret;
ret = conn->driver->nodeGetMemoryStats(conn, cellNum, params, nparams, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virNodeGetFreeMemory:
* @conn: pointer to the hypervisor connection
*
* provides the free memory available on the Node
* Note: most libvirt APIs provide memory sizes in kibibytes, but in this
* function the returned value is in bytes. Divide by 1024 as necessary.
*
* Returns the available free memory in bytes or 0 in case of error
*/
unsigned long long
virNodeGetFreeMemory(virConnectPtr conn)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, 0);
if (conn->driver->nodeGetFreeMemory) {
unsigned long long ret;
ret = conn->driver->nodeGetFreeMemory(conn);
if (ret == 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return 0;
}
/**
* virNodeSuspendForDuration:
* @conn: pointer to the hypervisor connection
* @target: the state to which the host must be suspended to,
* such as: VIR_NODE_SUSPEND_TARGET_MEM (Suspend-to-RAM)
* VIR_NODE_SUSPEND_TARGET_DISK (Suspend-to-Disk)
* VIR_NODE_SUSPEND_TARGET_HYBRID (Hybrid-Suspend,
* which is a combination of the former modes).
* @duration: the time duration in seconds for which the host
* has to be suspended
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Attempt to suspend the node (host machine) for the given duration of
* time in the specified state (Suspend-to-RAM, Suspend-to-Disk or
* Hybrid-Suspend). Schedule the node's Real-Time-Clock interrupt to
* resume the node after the duration is complete.
*
* Returns 0 on success (i.e., the node will be suspended after a short
* delay), -1 on failure (the operation is not supported, or an attempted
* suspend is already underway).
*/
int
virNodeSuspendForDuration(virConnectPtr conn,
unsigned int target,
unsigned long long duration,
unsigned int flags)
{
VIR_DEBUG("conn=%p, target=%d, duration=%lld, flags=%x",
conn, target, duration, flags);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckReadOnlyGoto(conn->flags, error);
if (conn->driver->nodeSuspendForDuration) {
int ret;
ret = conn->driver->nodeSuspendForDuration(conn, target,
duration, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/*
* virNodeGetMemoryParameters:
* @conn: pointer to the hypervisor connection
* @params: pointer to memory parameter object
* (return value, allocated by the caller)
* @nparams: pointer to number of memory parameters; input and output
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Get all node memory parameters (parameters unsupported by OS will be
* omitted). On input, @nparams gives the size of the @params array;
* on output, @nparams gives how many slots were filled with parameter
* information, which might be less but will not exceed the input value.
*
* As a special case, calling with @params as NULL and @nparams as 0 on
* input will cause @nparams on output to contain the number of parameters
* supported by the hypervisor. The caller should then allocate @params
* array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
* again. See virDomainGetMemoryParameters() for an equivalent usage
* example.
*
* Returns 0 in case of success, and -1 in case of failure.
*/
int
virNodeGetMemoryParameters(virConnectPtr conn,
virTypedParameterPtr params,
int *nparams,
unsigned int flags)
{
VIR_DEBUG("conn=%p, params=%p, nparams=%p, flags=%x",
conn, params, nparams, flags);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(nparams, error);
virCheckNonNegativeArgGoto(*nparams, error);
if (*nparams != 0)
virCheckNonNullArgGoto(params, error);
if (VIR_DRV_SUPPORTS_FEATURE(conn->driver, conn,
VIR_DRV_FEATURE_TYPED_PARAM_STRING))
flags |= VIR_TYPED_PARAM_STRING_OKAY;
if (conn->driver->nodeGetMemoryParameters) {
int ret;
ret = conn->driver->nodeGetMemoryParameters(conn, params,
nparams, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/*
* virNodeSetMemoryParameters:
* @conn: pointer to the hypervisor connection
* @params: pointer to scheduler parameter objects
* @nparams: number of scheduler parameter objects
* (this value can be the same or less than the returned
* value nparams of virDomainGetSchedulerType)
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Change all or a subset of the node memory tunables. The function
* fails if not all of the tunables are supported.
*
* Note that it's not recommended to use this function while the
* outside tuning program is running (such as ksmtuned under Linux),
* as they could change the tunables in parallel, which could cause
* conflicts.
*
* This function may require privileged access to the hypervisor.
*
* Returns 0 in case of success, -1 in case of failure.
*/
int
virNodeSetMemoryParameters(virConnectPtr conn,
virTypedParameterPtr params,
int nparams,
unsigned int flags)
{
VIR_DEBUG("conn=%p, params=%p, nparams=%d, flags=%x",
conn, params, nparams, flags);
VIR_TYPED_PARAMS_DEBUG(params, nparams);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckReadOnlyGoto(conn->flags, error);
virCheckNonNullArgGoto(params, error);
virCheckNonNegativeArgGoto(nparams, error);
if (virTypedParameterValidateSet(conn, params, nparams) < 0)
goto error;
if (conn->driver->nodeSetMemoryParameters) {
int ret;
ret = conn->driver->nodeSetMemoryParameters(conn, params,
nparams, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virNodeGetSecurityModel:
* @conn: a connection object
* @secmodel: pointer to a virSecurityModel structure
*
* Extract the security model of a hypervisor. The 'model' field
* in the @secmodel argument may be initialized to the empty
* string if the driver has not activated a security model.
*
* Returns 0 in case of success, -1 in case of failure
*/
int
virNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel)
{
VIR_DEBUG("conn=%p secmodel=%p", conn, secmodel);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(secmodel, error);
if (conn->driver->nodeGetSecurityModel) {
int ret;
ret = conn->driver->nodeGetSecurityModel(conn, secmodel);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virNodeGetCellsFreeMemory:
* @conn: pointer to the hypervisor connection
* @freeMems: pointer to the array of unsigned long long
* @startCell: index of first cell to return freeMems info on.
* @maxCells: Maximum number of cells for which freeMems information can
* be returned.
*
* This call returns the amount of free memory in one or more NUMA cells.
* The @freeMems array must be allocated by the caller and will be filled
* with the amount of free memory in bytes for each cell requested,
* starting with startCell (in freeMems[0]), up to either
* (startCell + maxCells), or the number of additional cells in the node,
* whichever is smaller.
*
* Returns the number of entries filled in freeMems, or -1 in case of error.
*/
int
virNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems,
int startCell, int maxCells)
{
VIR_DEBUG("conn=%p, freeMems=%p, startCell=%d, maxCells=%d",
conn, freeMems, startCell, maxCells);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(freeMems, error);
virCheckPositiveArgGoto(maxCells, error);
virCheckNonNegativeArgGoto(startCell, error);
if (conn->driver->nodeGetCellsFreeMemory) {
int ret;
ret = conn->driver->nodeGetCellsFreeMemory(conn, freeMems, startCell, maxCells);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virConnectIsEncrypted:
* @conn: pointer to the connection object
*
* Determine if the connection to the hypervisor is encrypted
*
* Returns 1 if encrypted, 0 if not encrypted, -1 on error
*/
int
virConnectIsEncrypted(virConnectPtr conn)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, -1);
if (conn->driver->connectIsEncrypted) {
int ret;
ret = conn->driver->connectIsEncrypted(conn);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virConnectIsSecure:
* @conn: pointer to the connection object
*
* Determine if the connection to the hypervisor is secure
*
* A connection will be classed as secure if it is either
* encrypted, or running over a channel which is not exposed
* to eavesdropping (eg a UNIX domain socket, or pipe)
*
* Returns 1 if secure, 0 if not secure, -1 on error
*/
int
virConnectIsSecure(virConnectPtr conn)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, -1);
if (conn->driver->connectIsSecure) {
int ret;
ret = conn->driver->connectIsSecure(conn);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virConnectCompareCPU:
* @conn: virConnect connection
* @xmlDesc: XML describing the CPU to compare with host CPU
* @flags: bitwise-OR of virConnectCompareCPUFlags
*
* Compares the given CPU description with the host CPU
*
* Returns comparison result according to enum virCPUCompareResult. If
* VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlDesc CPU is
* incompatible with host CPU, this function will return VIR_CPU_COMPARE_ERROR
* (instead of VIR_CPU_COMPARE_INCOMPATIBLE) and the error will use the
* VIR_ERR_CPU_INCOMPATIBLE code with a message providing more details about
* the incompatibility.
*/
int
virConnectCompareCPU(virConnectPtr conn,
const char *xmlDesc,
unsigned int flags)
{
VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, xmlDesc, flags);
virResetLastError();
virCheckConnectReturn(conn, VIR_CPU_COMPARE_ERROR);
virCheckNonNullArgGoto(xmlDesc, error);
if (conn->driver->connectCompareCPU) {
int ret;
ret = conn->driver->connectCompareCPU(conn, xmlDesc, flags);
if (ret == VIR_CPU_COMPARE_ERROR)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return VIR_CPU_COMPARE_ERROR;
}
/**
* virConnectGetCPUModelNames:
*
* @conn: virConnect connection
* @arch: Architecture
* @models: Pointer to a variable to store the NULL-terminated array of the
* CPU models supported for the specified architecture. Each element
* and the array itself must be freed by the caller with free. Pass
* NULL if only the list length is needed.
* @flags: extra flags; not used yet, so callers should always pass 0.
*
* Get the list of supported CPU models for a specific architecture.
*
* Returns -1 on error, number of elements in @models on success.
*/
int
virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char ***models,
unsigned int flags)
{
VIR_DEBUG("conn=%p, arch=%s, models=%p, flags=%x",
conn, arch, models, flags);
virResetLastError();
if (models)
*models = NULL;
virCheckConnectReturn(conn, -1);
virCheckNonNullArgGoto(arch, error);
if (conn->driver->connectGetCPUModelNames) {
int ret;
ret = conn->driver->connectGetCPUModelNames(conn, arch, models, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virConnectBaselineCPU:
*
* @conn: virConnect connection
* @xmlCPUs: array of XML descriptions of host CPUs
* @ncpus: number of CPUs in xmlCPUs
* @flags: bitwise-OR of virConnectBaselineCPUFlags
*
* Computes the most feature-rich CPU which is compatible with all given
* host CPUs.
*
* If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt
* will explicitly list all CPU features that are part of the host CPU,
* without this flag features that are part of the CPU model will not be
* listed.
*
* Returns XML description of the computed CPU (caller frees) or NULL on error.
*/
char *
virConnectBaselineCPU(virConnectPtr conn,
const char **xmlCPUs,
unsigned int ncpus,
unsigned int flags)
{
size_t i;
VIR_DEBUG("conn=%p, xmlCPUs=%p, ncpus=%u, flags=%x",
conn, xmlCPUs, ncpus, flags);
if (xmlCPUs) {
for (i = 0; i < ncpus; i++)
VIR_DEBUG("xmlCPUs[%zu]=%s", i, NULLSTR(xmlCPUs[i]));
}
virResetLastError();
virCheckConnectReturn(conn, NULL);
virCheckNonNullArgGoto(xmlCPUs, error);
if (conn->driver->connectBaselineCPU) {
char *cpu;
cpu = conn->driver->connectBaselineCPU(conn, xmlCPUs, ncpus, flags);
if (!cpu)
goto error;
return cpu;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return NULL;
}
/**
* virConnectSetKeepAlive:
* @conn: pointer to a hypervisor connection
* @interval: number of seconds of inactivity before a keepalive message is sent
* @count: number of messages that can be sent in a row
*
* Start sending keepalive messages after @interval seconds of inactivity and
* consider the connection to be broken when no response is received after
* @count keepalive messages sent in a row. In other words, sending count + 1
* keepalive message results in closing the connection. When @interval is
* <= 0, no keepalive messages will be sent. When @count is 0, the connection
* will be automatically closed after @interval seconds of inactivity without
* sending any keepalive messages.
*
* Note: The client has to implement and run an event loop with
* virEventRegisterImpl() or virEventRegisterDefaultImpl() to be able to
* use keepalive messages. Failure to do so may result in connections
* being closed unexpectedly.
*
* Note: This API function controls only keepalive messages sent by the client.
* If the server is configured to use keepalive you still need to run the event
* loop to respond to them, even if you disable keepalives by this function.
*
* Returns -1 on error, 0 on success, 1 when remote party doesn't support
* keepalive messages.
*/
int
virConnectSetKeepAlive(virConnectPtr conn,
int interval,
unsigned int count)
{
int ret = -1;
VIR_DEBUG("conn=%p, interval=%d, count=%u", conn, interval, count);
virResetLastError();
virCheckConnectReturn(conn, -1);
if (conn->driver->connectSetKeepAlive) {
ret = conn->driver->connectSetKeepAlive(conn, interval, count);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virConnectIsAlive:
* @conn: pointer to the connection object
*
* Determine if the connection to the hypervisor is still alive
*
* A connection will be classed as alive if it is either local, or running
* over a channel (TCP or UNIX socket) which is not closed.
*
* Returns 1 if alive, 0 if dead, -1 on error
*/
int
virConnectIsAlive(virConnectPtr conn)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, -1);
if (conn->driver->connectIsAlive) {
int ret;
ret = conn->driver->connectIsAlive(conn);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virConnectRegisterCloseCallback:
* @conn: pointer to connection object
* @cb: callback to invoke upon close
* @opaque: user data to pass to @cb
* @freecb: callback to free @opaque
*
* Registers a callback to be invoked when the connection
* is closed. This callback is invoked when there is any
* condition that causes the socket connection to the
* hypervisor to be closed.
*
* This function is only applicable to hypervisor drivers
* which maintain a persistent open connection. Drivers
* which open a new connection for every operation will
* not invoke this.
*
* The @freecb must not invoke any other libvirt public
* APIs, since it is not called from a re-entrant safe
* context.
*
* Returns 0 on success, -1 on error
*/
int
virConnectRegisterCloseCallback(virConnectPtr conn,
virConnectCloseFunc cb,
void *opaque,
virFreeCallback freecb)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, -1);
virObjectRef(conn);
virMutexLock(&conn->lock);
virObjectLock(conn->closeCallback);
virCheckNonNullArgGoto(cb, error);
if (conn->closeCallback->callback) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("A close callback is already registered"));
goto error;
}
conn->closeCallback->conn = conn;
conn->closeCallback->callback = cb;
conn->closeCallback->opaque = opaque;
conn->closeCallback->freeCallback = freecb;
virObjectUnlock(conn->closeCallback);
virMutexUnlock(&conn->lock);
return 0;
error:
virObjectUnlock(conn->closeCallback);
virMutexUnlock(&conn->lock);
virDispatchError(conn);
virObjectUnref(conn);
return -1;
}
/**
* virConnectUnregisterCloseCallback:
* @conn: pointer to connection object
* @cb: pointer to the current registered callback
*
* Unregisters the callback previously set with the
* virConnectRegisterCloseCallback method. The callback
* will no longer receive notifications when the connection
* closes. If a virFreeCallback was provided at time of
* registration, it will be invoked
*
* Returns 0 on success, -1 on error
*/
int
virConnectUnregisterCloseCallback(virConnectPtr conn,
virConnectCloseFunc cb)
{
VIR_DEBUG("conn=%p", conn);
virResetLastError();
virCheckConnectReturn(conn, -1);
virMutexLock(&conn->lock);
virObjectLock(conn->closeCallback);
virCheckNonNullArgGoto(cb, error);
if (conn->closeCallback->callback != cb) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("A different callback was requested"));
goto error;
}
conn->closeCallback->callback = NULL;
if (conn->closeCallback->freeCallback)
conn->closeCallback->freeCallback(conn->closeCallback->opaque);
conn->closeCallback->freeCallback = NULL;
virObjectUnref(conn);
virObjectUnlock(conn->closeCallback);
virMutexUnlock(&conn->lock);
return 0;
error:
virObjectUnlock(conn->closeCallback);
virMutexUnlock(&conn->lock);
virDispatchError(conn);
return -1;
}
/**
* virNodeGetCPUMap:
* @conn: pointer to the hypervisor connection
* @cpumap: optional pointer to a bit map of real CPUs on the host node
* (in 8-bit bytes) (OUT)
* In case of success each bit set to 1 means that corresponding
* CPU is online.
* Bytes are stored in little-endian order: CPU0-7, 8-15...
* In each byte, lowest CPU number is least significant bit.
* The bit map is allocated by virNodeGetCPUMap and needs
* to be released using free() by the caller.
* @online: optional number of online CPUs in cpumap (OUT)
* Contains the number of online CPUs if the call was successful.
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Get CPU map of host node CPUs.
*
* Returns number of CPUs present on the host node,
* or -1 if there was an error.
*/
int
virNodeGetCPUMap(virConnectPtr conn,
unsigned char **cpumap,
unsigned int *online,
unsigned int flags)
{
VIR_DEBUG("conn=%p, cpumap=%p, online=%p, flags=%x",
conn, cpumap, online, flags);
virResetLastError();
virCheckConnectReturn(conn, -1);
if (conn->driver->nodeGetCPUMap) {
int ret = conn->driver->nodeGetCPUMap(conn, cpumap, online, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virNodeGetFreePages:
* @conn: pointer to the hypervisor connection
* @npages: number of items in the @pages array
* @pages: page sizes to query
* @startCell: index of first cell to return free pages info on.
* @cellCount: maximum number of cells for which free pages
* information can be returned.
* @counts: returned counts of free pages
* @flags: extra flags; not used yet, so callers should always pass 0
*
* This calls queries the host system on free pages of
* specified size. For the input, @pages is expected to be
* filled with pages that caller is interested in (the size
* unit is kibibytes, so e.g. pass 2048 for 2MB), then @startcell
* refers to the first NUMA node that info should be collected
* from, and @cellcount tells how many consecutive nodes should
* be queried. On the function output, @counts is filled with
* desired information, where items are grouped by NUMA node.
* So from @counts[0] till @counts[@npages - 1] you'll find count
* for the first node (@startcell), then from @counts[@npages]
* till @count[2 * @npages - 1] you'll find info for the
* (@startcell + 1) node, and so on. It's callers responsibility
* to allocate the @counts array.
*
* Example how to use this API:
*
* unsigned int pages[] = { 4, 2048, 1048576}
* unsigned int npages = ARRAY_CARDINALITY(pages);
* int startcell = 0;
* unsigned int cellcount = 2;
*
* unsigned long long counts = malloc(sizeof(long long) * npages * cellcount);
*
* virNodeGetFreePages(conn, pages, npages,
* startcell, cellcount, counts, 0);
*
* for (i = 0 ; i < cellcount ; i++) {
* fprintf(stdout, "Cell %d\n", startcell + i);
* for (j = 0 ; j < npages ; j++) {
* fprintf(stdout, " Page size=%d count=%d bytes=%llu\n",
* pages[j], counts[(i * npages) + j],
* pages[j] * counts[(i * npages) + j]);
* }
* }
*
* This little code snippet will produce something like this:
* Cell 0
* Page size=4096 count=300 bytes=1228800
* Page size=2097152 count=0 bytes=0
* Page size=1073741824 count=1 bytes=1073741824
* Cell 1
* Page size=4096 count=0 bytes=0
* Page size=2097152 count=20 bytes=41943040
* Page size=1073741824 count=0 bytes=0
*
* Returns: the number of entries filled in @counts or -1 in case of error.
*/
int
virNodeGetFreePages(virConnectPtr conn,
unsigned int npages,
unsigned int *pages,
int startCell,
unsigned int cellCount,
unsigned long long *counts,
unsigned int flags)
{
VIR_DEBUG("conn=%p, npages=%u, pages=%p, startCell=%u, "
"cellCount=%u, counts=%p, flags=%x",
conn, npages, pages, startCell, cellCount, counts, flags);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckNonZeroArgGoto(npages, error);
virCheckNonNullArgGoto(pages, error);
virCheckNonZeroArgGoto(cellCount, error);
virCheckNonNullArgGoto(counts, error);
if (conn->driver->nodeGetFreePages) {
int ret;
ret = conn->driver->nodeGetFreePages(conn, npages, pages, startCell,
cellCount, counts, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}
/**
* virNodeAllocPages:
* @conn: pointer to the hypervisor connection
* @npages: number of items in the @pageSizes and
* @pageCounts arrays
* @pageSizes: which huge page sizes to allocate
* @pageCounts: how many pages should be allocated
* @startCell: index of first cell to allocate pages on
* @cellCount: number of consecutive cells to allocate pages on
* @flags: extra flags; binary-OR of virNodeAllocPagesFlags
*
* Sometimes, when trying to start a new domain, it may be
* necessary to reserve some huge pages in the system pool which
* can be then allocated by the domain. This API serves that
* purpose. On its input, @pageSizes and @pageCounts are arrays
* of the same cardinality of @npages. The @pageSizes contains
* page sizes which are to be allocated in the system (the size
* unit is kibibytes), and @pageCounts then contains the number
* of pages to reserve. If @flags is 0
* (VIR_NODE_ALLOC_PAGES_ADD), each pool corresponding to
* @pageSizes grows by the number of pages specified in the
* corresponding @pageCounts. If @flags contains
* VIR_NODE_ALLOC_PAGES_SET, each pool mentioned is resized to
* the given number of pages. The pages pool can be allocated
* over several NUMA nodes at once, just point at @startCell and
* tell how many subsequent NUMA nodes should be taken in. As a
* special case, if @startCell is equal to negative one, then
* kernel is instructed to allocate the pages over all NUMA nodes
* proportionally.
*
* Returns: the number of nodes successfully adjusted or -1 in
* case of an error.
*/
int
virNodeAllocPages(virConnectPtr conn,
unsigned int npages,
unsigned int *pageSizes,
unsigned long long *pageCounts,
int startCell,
unsigned int cellCount,
unsigned int flags)
{
VIR_DEBUG("conn=%p npages=%u pageSizes=%p pageCounts=%p "
"startCell=%d cellCount=%u flagx=%x",
conn, npages, pageSizes, pageCounts, startCell,
cellCount, flags);
virResetLastError();
virCheckConnectReturn(conn, -1);
virCheckReadOnlyGoto(conn->flags, error);
virCheckNonZeroArgGoto(npages, error);
virCheckNonNullArgGoto(pageSizes, error);
virCheckNonNullArgGoto(pageCounts, error);
virCheckNonZeroArgGoto(cellCount, error);
if (conn->driver->nodeAllocPages) {
int ret;
ret = conn->driver->nodeAllocPages(conn, npages, pageSizes,
pageCounts, startCell,
cellCount, flags);
if (ret < 0)
goto error;
return ret;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}