[libvirt] [PATCH] Fix integer overflow in hotplug methods
by Daniel P. Berrange
The hotplug methods still had the qemuCmdFlags variable declared
as an int, instead of unsigned long long. This caused flag checks
to be incorrect for flags > 31
* src/qemu/qemu_driver.c: Fix integer overflow in hotplug
---
src/qemu/qemu_driver.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 64dbf4a..ad99d59 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7019,7 +7019,7 @@ error:
static int qemudDomainAttachPciDiskDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk,
- int qemuCmdFlags)
+ unsigned long long qemuCmdFlags)
{
int i, ret;
const char* type = virDomainDiskBusTypeToString(disk->bus);
@@ -7114,7 +7114,7 @@ error:
static int qemudDomainAttachPciControllerDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainControllerDefPtr controller,
- int qemuCmdFlags)
+ unsigned long long qemuCmdFlags)
{
int i;
int ret = -1;
@@ -7180,7 +7180,7 @@ static virDomainControllerDefPtr
qemuDomainFindOrCreateSCSIDiskController(struct qemud_driver *driver,
virDomainObjPtr vm,
int controller,
- int qemuCmdFlags)
+ unsigned long long qemuCmdFlags)
{
int i;
virDomainControllerDefPtr cont;
@@ -7225,7 +7225,7 @@ qemuDomainFindOrCreateSCSIDiskController(struct qemud_driver *driver,
static int qemudDomainAttachSCSIDisk(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk,
- int qemuCmdFlags)
+ unsigned long long qemuCmdFlags)
{
int i;
qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -7341,7 +7341,7 @@ error:
static int qemudDomainAttachUsbMassstorageDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainDiskDefPtr disk,
- int qemuCmdFlags)
+ unsigned long long qemuCmdFlags)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
int i, ret;
@@ -7652,7 +7652,7 @@ no_memory:
static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev,
- int qemuCmdFlags)
+ unsigned long long qemuCmdFlags)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
pciDevice *pci;
@@ -7764,7 +7764,7 @@ error:
static int qemudDomainAttachHostUsbDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev,
- int qemuCmdFlags)
+ unsigned long long qemuCmdFlags)
{
int ret;
qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -7808,7 +7808,7 @@ error:
static int qemudDomainAttachHostDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev,
- int qemuCmdFlags)
+ unsigned long long qemuCmdFlags)
{
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
qemuReportError(VIR_ERR_NO_SUPPORT,
--
1.6.6.1
14 years, 7 months
[libvirt] [PATCH] Fix failing virGetHostname.
by Chris Lalancette
We've been running into a lot of situations where
virGetHostname() is returning "localhost", where a plain
gethostname() would have returned the correct thing. This
is because virGetHostname() is *always* trying to canonicalize
the name returned from gethostname(), even when it doesn't
have to.
This patch changes virGetHostname so that if the value returned
from gethostname() is already FQDN or localhost, it returns
that string directly. If the value returned from gethostname()
is a shortened hostname, then we try to canonicalize it. If
that succeeds, we returned the canonicalized hostname. If
that fails, and/or returns "localhost", then we just return
the original string we got from gethostname() and hope for
the best.
Note that after this patch it is up to clients to check whether
"localhost" is an allowed return value. The only place
where it's currently not is in qemu migration.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/libvirt_private.syms | 1 -
src/qemu/qemu_driver.c | 15 +++++--
src/util/util.c | 94 ++++++++++++++++++++++++---------------------
src/util/util.h | 1 -
4 files changed, 60 insertions(+), 51 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 104278f..130a2a1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -653,7 +653,6 @@ virExecDaemonize;
virSetCloseExec;
virSetNonBlock;
virFormatMacAddr;
-virGetHostnameLocalhost;
virGetHostname;
virParseMacAddr;
virFileDeletePid;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0af64c7..cfa5964 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10017,7 +10017,7 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
virDomainDefPtr def = NULL;
virDomainObjPtr vm = NULL;
int this_port;
- char *hostname;
+ char *hostname = NULL;
char migrateFrom [64];
const char *p;
virDomainEventPtr event = NULL;
@@ -10057,9 +10057,15 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
if (port == QEMUD_MIGRATION_NUM_PORTS) port = 0;
/* Get hostname */
- if ((hostname = virGetHostnameLocalhost(0)) == NULL)
+ if ((hostname = virGetHostname(NULL)) == NULL)
goto cleanup;
+ if (STRPREFIX(hostname, "localhost")) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("hostname on destination resolved to localhost, but migration requires an FQDN"));
+ goto cleanup;
+ }
+
/* XXX this really should have been a properly well-formed
* URI, but we can't add in tcp:// now without breaking
* compatability with old targets. We at least make the
@@ -10067,7 +10073,6 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
*/
/* Caller frees */
internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
- VIR_FREE(hostname);
if (internalret < 0) {
virReportOOMError();
goto cleanup;
@@ -10171,10 +10176,10 @@ endjob:
vm = NULL;
cleanup:
+ VIR_FREE(hostname);
virDomainDefFree(def);
- if (ret != 0) {
+ if (ret != 0)
VIR_FREE(*uri_out);
- }
if (vm)
virDomainObjUnlock(vm);
if (event)
diff --git a/src/util/util.c b/src/util/util.c
index e937d39..930bfac 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -2367,11 +2367,31 @@ char *virIndexToDiskName(int idx, const char *prefix)
# define AI_CANONIDN 0
#endif
-char *virGetHostnameLocalhost(int allow_localhost)
+/* Who knew getting a hostname could be so delicate. In Linux (and Unices
+ * in general), many things depend on "hostname" returning a value that will
+ * resolve one way or another. In the modern world where networks frequently
+ * come and go this is often being hard-coded to resolve to "localhost". If
+ * it *doesn't* resolve to localhost, then we would prefer to have the FQDN.
+ * That leads us to 3 possibilities:
+ *
+ * 1) gethostname() returns an FQDN (not localhost) - we return the string
+ * as-is, it's all of the information we want
+ * 2) gethostname() returns "localhost" - we return localhost; doing further
+ * work to try to resolve it is pointless
+ * 3) gethostname() returns a shortened hostname - in this case, we want to
+ * try to resolve this to a fully-qualified name. Therefore we pass it
+ * to getaddrinfo(). There are two possible responses:
+ * a) getaddrinfo() resolves to a FQDN - return the FQDN
+ * b) getaddrinfo() resolves to localhost - in this case, the data we got
+ * from gethostname() is actually more useful than what we got from
+ * getaddrinfo(). Return the value from gethostname() and hope for
+ * the best.
+ */
+char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
{
int r;
char hostname[HOST_NAME_MAX+1], *result;
- struct addrinfo hints, *info, *res;
+ struct addrinfo hints, *info;
r = gethostname (hostname, sizeof(hostname));
if (r == -1) {
@@ -2381,6 +2401,21 @@ char *virGetHostnameLocalhost(int allow_localhost)
}
NUL_TERMINATE(hostname);
+ if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) {
+ /* in this case, gethostname returned localhost (meaning we can't
+ * do any further canonicalization), or it returned an FQDN (and
+ * we don't need to do any further canonicalization). Return the
+ * string as-is; it's up to callers to check whether "localhost"
+ * is allowed.
+ */
+ result = strdup(hostname);
+ goto check_and_return;
+ }
+
+ /* otherwise, it's a shortened, non-localhost, hostname. Attempt to
+ * canonicalize the hostname by running it through getaddrinfo
+ */
+
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME|AI_CANONIDN;
hints.ai_family = AF_UNSPEC;
@@ -2395,54 +2430,25 @@ char *virGetHostnameLocalhost(int allow_localhost)
/* Tell static analyzers about getaddrinfo semantics. */
sa_assert (info);
- /* if we aren't allowing localhost, then we iterate through the
- * list and make sure none of the IPv4 addresses are 127.0.0.1 and
- * that none of the IPv6 addresses are ::1
- */
- if (!allow_localhost) {
- res = info;
- while (res) {
- if (res->ai_family == AF_INET) {
- if (htonl(((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr) == INADDR_LOOPBACK) {
- virUtilError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("canonical hostname pointed to localhost, but this is not allowed"));
- freeaddrinfo(info);
- return NULL;
- }
- }
- else if (res->ai_family == AF_INET6) {
- if (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)) {
- virUtilError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("canonical hostname pointed to localhost, but this is not allowed"));
- freeaddrinfo(info);
- return NULL;
- }
- }
- res = res->ai_next;
- }
- }
+ if (info->ai_canonname == NULL ||
+ STRPREFIX(info->ai_canonname, "localhost"))
+ /* in this case, we tried to canonicalize and we ended up back with
+ * localhost. Ignore the canonicalized name and just return the
+ * original hostname
+ */
+ result = strdup(hostname);
+ else
+ /* Caller frees this string. */
+ result = strdup (info->ai_canonname);
- if (info->ai_canonname == NULL) {
- virUtilError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("could not determine canonical host name"));
- freeaddrinfo(info);
- return NULL;
- }
+ freeaddrinfo(info);
- /* Caller frees this string. */
- result = strdup (info->ai_canonname);
- if (!result)
+check_and_return:
+ if (result == NULL)
virReportOOMError();
-
- freeaddrinfo(info);
return result;
}
-char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return virGetHostnameLocalhost(1);
-}
-
/* send signal to a single process */
int virKillProcess(pid_t pid, int sig)
{
diff --git a/src/util/util.h b/src/util/util.h
index 6bf6bcc..f8b64c2 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -252,7 +252,6 @@ static inline int getuid (void) { return 0; }
static inline int getgid (void) { return 0; }
# endif
-char *virGetHostnameLocalhost(int allow_localhost);
char *virGetHostname(virConnectPtr conn);
int virKillProcess(pid_t pid, int sig);
--
1.6.6.1
14 years, 7 months
[libvirt] [PATCH v3] Fix up basic migration.
by Chris Lalancette
Basic live migration was broken by the commit that added
non-shared block support in two ways:
1) It added a virCheckFlags() to doNativeMigrate(). Besides
the fact that typical usage of virCheckFlags() is in driver
entry points, and doNativeMigrate() is not an entry point,
it was missing important flags like VIR_MIGRATE_LIVE. Move
the virCheckFlags to the top-level qemuDomainMigratePrepare2
and friends.
2) It also added a memory leak in qemuMonitorTextMigrate()
by not freeing the memory used by virBufferContentAndReset().
This is fixed by storing the pointer in a temporary variable
and freeing it at the end.
With this patch in place, normal live migration works again.
v3: Instead of the churn for virCheckFlagsUI and UL, instead
always promote flags to an unsigned long and always use %lx
for the fprintf.
v2: Add back flags check, which required adding virCheckFlagsUI
and virCheckFlagsUL
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
src/internal.h | 7 ++++---
src/qemu/qemu_driver.c | 30 +++++++++++++++++++++++++++---
src/qemu/qemu_monitor_text.c | 10 +++++++---
3 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/src/internal.h b/src/internal.h
index c3c5311..fab3e11 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -212,15 +212,16 @@
*/
# define virCheckFlags(supported, retval) \
do { \
- if ((flags & ~(supported))) { \
+ unsigned long __unsuppflags = flags & ~(supported); \
+ if (__unsuppflags) { \
virReportErrorHelper(NULL, \
VIR_FROM_THIS, \
VIR_ERR_INVALID_ARG, \
__FILE__, \
__FUNCTION__, \
__LINE__, \
- _("%s: unsupported flags (0x%x)"), \
- __FUNCTION__, flags & ~(supported)); \
+ _("%s: unsupported flags (0x%lx)"), \
+ __FUNCTION__, __unsuppflags); \
return retval; \
} \
} while (0)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 77e71cc..941b482 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10175,6 +10175,15 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
int ret = -1;
int internalret;
+ virCheckFlags(VIR_MIGRATE_LIVE |
+ VIR_MIGRATE_PEER2PEER |
+ VIR_MIGRATE_TUNNELLED |
+ VIR_MIGRATE_PERSIST_DEST |
+ VIR_MIGRATE_UNDEFINE_SOURCE |
+ VIR_MIGRATE_PAUSED |
+ VIR_MIGRATE_NON_SHARED_DISK |
+ VIR_MIGRATE_NON_SHARED_INC, -1);
+
*uri_out = NULL;
qemuDriverLock(driver);
@@ -10356,9 +10365,6 @@ static int doNativeMigrate(struct qemud_driver *driver,
qemuDomainObjPrivatePtr priv = vm->privateData;
unsigned int background_flags = 0;
- virCheckFlags(VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
- -1);
-
/* Issue the migrate command. */
if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
/* HACK: source host generates bogus URIs, so fix them up */
@@ -10779,6 +10785,15 @@ qemudDomainMigratePerform (virDomainPtr dom,
int resume = 0;
qemuDomainObjPrivatePtr priv;
+ virCheckFlags(VIR_MIGRATE_LIVE |
+ VIR_MIGRATE_PEER2PEER |
+ VIR_MIGRATE_TUNNELLED |
+ VIR_MIGRATE_PERSIST_DEST |
+ VIR_MIGRATE_UNDEFINE_SOURCE |
+ VIR_MIGRATE_PAUSED |
+ VIR_MIGRATE_NON_SHARED_DISK |
+ VIR_MIGRATE_NON_SHARED_INC, -1);
+
qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
if (!vm) {
@@ -10882,6 +10897,15 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
virErrorPtr orig_err;
int newVM = 1;
+ virCheckFlags(VIR_MIGRATE_LIVE |
+ VIR_MIGRATE_PEER2PEER |
+ VIR_MIGRATE_TUNNELLED |
+ VIR_MIGRATE_PERSIST_DEST |
+ VIR_MIGRATE_UNDEFINE_SOURCE |
+ VIR_MIGRATE_PAUSED |
+ VIR_MIGRATE_NON_SHARED_DISK |
+ VIR_MIGRATE_NON_SHARED_INC, NULL);
+
/* Migration failed. Save the current error so nothing squashes it */
orig_err = virSaveLastError();
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 5511550..4b1e2ec 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -1144,6 +1144,7 @@ static int qemuMonitorTextMigrate(qemuMonitorPtr mon,
int ret = -1;
char *safedest = qemuMonitorEscapeArg(dest);
virBuffer extra = VIR_BUFFER_INITIALIZER;
+ char *extrastr = NULL;
if (!safedest) {
virReportOOMError();
@@ -1159,10 +1160,12 @@ static int qemuMonitorTextMigrate(qemuMonitorPtr mon,
if (virBufferError(&extra)) {
virBufferFreeAndReset(&extra);
virReportOOMError();
- free(safedest);
- return -1;
+ goto cleanup;
}
- if (virAsprintf(&cmd, "migrate %s\"%s\"", virBufferContentAndReset(&extra), safedest) < 0) {
+
+ extrastr = virBufferContentAndReset(&extra);
+ if (virAsprintf(&cmd, "migrate %s\"%s\"", extrastr ? extrastr : "",
+ safedest) < 0) {
virReportOOMError();
goto cleanup;
}
@@ -1191,6 +1194,7 @@ static int qemuMonitorTextMigrate(qemuMonitorPtr mon,
ret = 0;
cleanup:
+ VIR_FREE(extrastr);
VIR_FREE(safedest);
VIR_FREE(info);
VIR_FREE(cmd);
--
1.6.6.1
14 years, 7 months
[libvirt] xen-proxy build broken
by Eric Blake
Didn't have time to fix this today; virVirtualPortProfileFormat is
conditionally implemented based on PROXY, but unconditionally called.
Throwing it out there in case someone else wants to beat me to the fix.
cc1: warnings being treated as errors
../src/conf/domain_conf.c: In function 'virDomainNetDefFormat':
../src/conf/domain_conf.c:5343: error: implicit declaration of function
'virVirtualPortProfileFormat' [-Wimplicit-function-declaration]
../src/conf/domain_conf.c:5343: error: nested extern declaration of
'virVirtualPortProfileFormat' [-Wnested-externs]
--
Eric Blake eblake(a)redhat.com +1-801-349-2682
Libvirt virtualization library http://libvirt.org
14 years, 7 months
[libvirt] [PATCH v2] esx: Add read-only storage pool access
by Matthias Bolte
Allows listing existing pools and requesting information about them.
Alter the esxVI_ProductVersion enum in a way that allows to check for
product type by masking.
Changes in v2:
- split not directly related parts into separate patches
- simplify goto usage: don't jump backwards
- rework format of esxVI_ProductVersion values and explain the format
- expand a FIXME in esxStoragePoolGetXMLDesc
---
po/POTFILES.in | 1 +
src/esx/esx_storage_driver.c | 597 +++++++++++++++++++++++++++++++++++++++-
src/esx/esx_vi.c | 126 ++++++++-
src/esx/esx_vi.h | 33 ++-
src/esx/esx_vi_generator.input | 59 ++++
src/esx/esx_vi_generator.py | 7 +-
6 files changed, 794 insertions(+), 29 deletions(-)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 88218bd..e047b1b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -19,6 +19,7 @@ src/cpu/cpu_map.c
src/cpu/cpu_x86.c
src/datatypes.c
src/esx/esx_driver.c
+src/esx/esx_storage_driver.c
src/esx/esx_util.c
src/esx/esx_vi.c
src/esx/esx_vi_methods.c
diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c
index 97b92a5..0e2e1a3 100644
--- a/src/esx/esx_storage_driver.c
+++ b/src/esx/esx_storage_driver.c
@@ -29,6 +29,7 @@
#include "memory.h"
#include "logging.h"
#include "uuid.h"
+#include "storage_conf.h"
#include "esx_private.h"
#include "esx_storage_driver.h"
#include "esx_vi.h"
@@ -65,17 +66,587 @@ esxStorageClose(virConnectPtr conn)
+static int
+esxNumberOfStoragePools(virConnectPtr conn)
+{
+ int count = 0;
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_ObjectContent *datastoreList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+
+ if (esxVI_EnsureSession(priv->host) < 0) {
+ return -1;
+ }
+
+ if (esxVI_LookupObjectContentByType(priv->host, priv->host->datacenter,
+ "Datastore", NULL, esxVI_Boolean_True,
+ &datastoreList) < 0) {
+ return -1;
+ }
+
+ for (datastore = datastoreList; datastore != NULL;
+ datastore = datastore->_next) {
+ ++count;
+ }
+
+ esxVI_ObjectContent_Free(&datastoreList);
+
+ return count;
+}
+
+
+
+static int
+esxListStoragePools(virConnectPtr conn, char **const names, int maxnames)
+{
+ bool success = false;
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_ObjectContent *datastoreList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ int count = 0;
+ int i;
+
+ if (names == NULL || maxnames < 0) {
+ ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", _("Invalid argument"));
+ return -1;
+ }
+
+ if (maxnames == 0) {
+ return 0;
+ }
+
+ if (esxVI_EnsureSession(priv->host) < 0) {
+ return -1;
+ }
+
+ if (esxVI_String_AppendValueToList(&propertyNameList,
+ "summary.name") < 0 ||
+ esxVI_LookupObjectContentByType(priv->host, priv->host->datacenter,
+ "Datastore", propertyNameList,
+ esxVI_Boolean_True,
+ &datastoreList) < 0) {
+ goto cleanup;
+ }
+
+ for (datastore = datastoreList; datastore != NULL;
+ datastore = datastore->_next) {
+ for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "summary.name")) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_String) < 0) {
+ goto cleanup;
+ }
+
+ names[count] = strdup(dynamicProperty->val->string);
+
+ if (names[count] == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ++count;
+ break;
+ } else {
+ VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+ }
+ }
+ }
+
+ success = true;
+
+ cleanup:
+ if (! success) {
+ for (i = 0; i < count; ++i) {
+ VIR_FREE(names[i]);
+ }
+
+ count = -1;
+ }
+
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastoreList);
+
+ return count;
+}
+
+
+
+static int
+esxNumberOfDefinedStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ /* ESX storage pools are always active */
+ return 0;
+}
+
+
+
+static int
+esxListDefinedStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
+ char **const names ATTRIBUTE_UNUSED,
+ int maxnames ATTRIBUTE_UNUSED)
+{
+ /* ESX storage pools are always active */
+ return 0;
+}
+
+
+
+static virStoragePoolPtr
+esxStoragePoolLookupByName(virConnectPtr conn, const char *name)
+{
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+ char *summaryUrl = NULL;
+ char *suffix = NULL;
+ int suffixLength;
+ char uuid_string[VIR_UUID_STRING_BUFLEN] = "00000000-00000000-0000-000000000000";
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ char *realName = NULL;
+ virStoragePoolPtr pool = NULL;
+
+ if (esxVI_EnsureSession(priv->host) < 0) {
+ return NULL;
+ }
+
+ if (esxVI_String_AppendValueListToList(&propertyNameList,
+ "summary.accessible\0"
+ "summary.name\0"
+ "summary.url\0") < 0 ||
+ esxVI_LookupDatastoreByName(priv->host, name,
+ propertyNameList, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0 ||
+ esxVI_GetBoolean(datastore, "summary.accessible",
+ &accessible, esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ /*
+ * Datastores don't have a UUID. We can use the 'summary.url' property as
+ * source for a "UUID" on ESX, because the property value has this format:
+ *
+ * summary.url = /vmfs/volumes/4b0beca7-7fd401f3-1d7f-000ae484a6a3
+ * summary.url = /vmfs/volumes/b24b7a78-9d82b4f5 (short format)
+ *
+ * The 'summary.url' property comes in two forms, with a complete "UUID"
+ * and a short "UUID".
+ *
+ * But this trailing "UUID" is not guaranteed to be there. On the other
+ * hand we already rely on another implementation detail of the ESX server:
+ * The object name of virtual machine contains an integer, we use that as
+ * domain ID.
+ *
+ * The 'summary.url' property of an inaccessible datastore is invalid.
+ */
+ if (accessible == esxVI_Boolean_True &&
+ priv->host->productVersion & esxVI_ProductVersion_ESX) {
+ if (esxVI_GetStringValue(datastore, "summary.url", &summaryUrl,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ if ((suffix = STRSKIP(summaryUrl, "/vmfs/volumes/")) == NULL) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Datastore URL '%s' has unexpected prefix, "
+ "expecting '/vmfs/volumes/' prefix"), summaryUrl);
+ goto cleanup;
+ }
+
+ suffixLength = strlen(suffix);
+
+ if ((suffixLength == 35 && /* = strlen("4b0beca7-7fd401f3-1d7f-000ae484a6a3") */
+ suffix[8] == '-' && suffix[17] == '-' && suffix[22] == '-') ||
+ (suffixLength == 17 && /* = strlen("b24b7a78-9d82b4f5") */
+ suffix[8] == '-')) {
+ /*
+ * Intentionally use memcpy here, because we want to be able to
+ * replace a prefix of the initial Zero-UUID. virStrncpy would
+ * null-terminate the string in an unwanted place.
+ */
+ memcpy(uuid_string, suffix, suffixLength);
+ } else {
+ VIR_WARN("Datastore URL suffix '%s' has unexpected format, "
+ "cannot deduce a UUID from it", suffix);
+ }
+ }
+
+ if (virUUIDParse(uuid_string, uuid) < 0) {
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Could not parse UUID from string '%s'"),
+ uuid_string);
+ goto cleanup;
+ }
+
+ if (esxVI_GetStringValue(datastore, "summary.name", &realName,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ pool = virGetStoragePool(conn, realName, uuid);
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastore);
+
+ return pool;
+}
+
+
+
+static virStoragePoolPtr
+esxStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+ esxPrivate *priv = conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
+ char *name = NULL;
+ virStoragePoolPtr pool = NULL;
+
+ if (! (priv->host->productVersion & esxVI_ProductVersion_ESX)) {
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Lookup by UUID is supported on ESX only"));
+ return NULL;
+ }
+
+ if (esxVI_EnsureSession(priv->host) < 0) {
+ return NULL;
+ }
+
+ /*
+ * Convert from UUID to datastore URL form by stripping the second '-':
+ *
+ * <---- 14 ----><-------- 22 --------> <---- 13 ---><-------- 22 -------->
+ * 4b0beca7-7fd4-01f3-1d7f-000ae484a6a3 -> 4b0beca7-7fd401f3-1d7f-000ae484a6a3
+ */
+ virUUIDFormat(uuid, uuid_string);
+ memmove(uuid_string + 13, uuid_string + 14, 22 + 1);
+
+ /*
+ * Use esxVI_LookupDatastoreByName because it also does try to match "UUID"
+ * part of the 'summary.url' property if there is no name match.
+ */
+ if (esxVI_String_AppendValueToList(&propertyNameList, "summary.name") < 0 ||
+ esxVI_LookupDatastoreByName(priv->host, uuid_string,
+ propertyNameList, &datastore,
+ esxVI_Occurrence_OptionalItem) < 0) {
+ goto cleanup;
+ }
+
+ /*
+ * If the first try didn't succeed and the trailing 16 digits are zero then
+ * the "UUID" could be a short one. Strip the 16 zeros and try again:
+ *
+ * <------ 17 -----> <------ 17 ----->
+ * b24b7a78-9d82b4f5-0000-000000000000 -> b24b7a78-9d82b4f5
+ */
+ if (datastore == NULL && STREQ(uuid_string + 17, "-0000-000000000000")) {
+ uuid_string[17] = '\0';
+
+ if (esxVI_LookupDatastoreByName(priv->host, uuid_string,
+ propertyNameList, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+ }
+
+ if (datastore == NULL) {
+ virUUIDFormat(uuid, uuid_string);
+
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find datastore with UUID '%s'"),
+ uuid_string);
+
+ goto cleanup;
+ }
+
+ if (esxVI_GetStringValue(datastore, "summary.name", &name,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ pool = virGetStoragePool(conn, name, uuid);
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastore);
+
+ return pool;
+}
+
+
+
+static int
+esxStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
+{
+ int result = -1;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_ObjectContent *datastore = NULL;
+
+ virCheckFlags(0, -1);
+
+ if (esxVI_EnsureSession(priv->host) < 0) {
+ return -1;
+ }
+
+ if (esxVI_LookupDatastoreByName(priv->host, pool->name, NULL, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0 ||
+ esxVI_RefreshDatastore(priv->host, datastore->obj) < 0) {
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ esxVI_ObjectContent_Free(&datastore);
+
+ return result;
+}
+
+
+
+static int
+esxStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
+{
+ int result = -1;
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+
+ memset(info, 0, sizeof (*info));
+
+ if (esxVI_EnsureSession(priv->host) < 0) {
+ return -1;
+ }
+
+ if (esxVI_String_AppendValueListToList(&propertyNameList,
+ "summary.accessible\0"
+ "summary.capacity\0"
+ "summary.freeSpace\0") < 0 ||
+ esxVI_LookupDatastoreByName(priv->host, pool->name,
+ propertyNameList, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0 ||
+ esxVI_GetBoolean(datastore, "summary.accessible",
+ &accessible, esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ if (accessible == esxVI_Boolean_True) {
+ info->state = VIR_STORAGE_POOL_RUNNING;
+
+ for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "summary.capacity")) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_Long) < 0) {
+ goto cleanup;
+ }
+
+ info->capacity = dynamicProperty->val->int64;
+ } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_Long) < 0) {
+ goto cleanup;
+ }
+
+ info->available = dynamicProperty->val->int64;
+ }
+ }
+
+ info->allocation = info->capacity - info->available;
+ } else {
+ info->state = VIR_STORAGE_POOL_INACCESSIBLE;
+ }
+
+ result = 0;
+
+ cleanup:
+ if (result < 0) {
+ memset(info, 0, sizeof (*info));
+ }
+
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastore);
+
+ return result;
+}
+
+
+
+static char *
+esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
+{
+ esxPrivate *priv = pool->conn->storagePrivateData;
+ esxVI_String *propertyNameList = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_Boolean accessible = esxVI_Boolean_Undefined;
+ virStoragePoolDef def;
+ esxVI_DatastoreInfo *info = NULL;
+ esxVI_LocalDatastoreInfo *localInfo = NULL;
+ esxVI_NasDatastoreInfo *nasInfo = NULL;
+ esxVI_VmfsDatastoreInfo *vmfsInfo = NULL;
+ char *xml = NULL;
+
+ virCheckFlags(0, NULL);
+
+ memset(&def, 0, sizeof (def));
+
+ if (esxVI_EnsureSession(priv->host) < 0) {
+ return NULL;
+ }
+
+ if (esxVI_String_AppendValueListToList(&propertyNameList,
+ "summary.accessible\0"
+ "summary.capacity\0"
+ "summary.freeSpace\0"
+ "info\0") < 0 ||
+ esxVI_LookupDatastoreByName(priv->host, pool->name,
+ propertyNameList, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0 ||
+ esxVI_GetBoolean(datastore, "summary.accessible",
+ &accessible, esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ def.name = pool->name;
+ memcpy(def.uuid, pool->uuid, VIR_UUID_BUFLEN);
+
+ if (accessible == esxVI_Boolean_True) {
+ for (dynamicProperty = datastore->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "summary.capacity")) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_Long) < 0) {
+ goto cleanup;
+ }
+
+ def.capacity = dynamicProperty->val->int64;
+ } else if (STREQ(dynamicProperty->name, "summary.freeSpace")) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_Long) < 0) {
+ goto cleanup;
+ }
+
+ def.available = dynamicProperty->val->int64;
+ } else if (STREQ(dynamicProperty->name, "info")) {
+ if (esxVI_DatastoreInfo_CastFromAnyType(dynamicProperty->val,
+ &info) < 0) {
+ goto cleanup;
+ }
+ }
+ }
+
+ def.allocation = def.capacity - def.available;
+
+ /* See vSphere API documentation about HostDatastoreSystem for details */
+ if ((localInfo = esxVI_LocalDatastoreInfo_DynamicCast(info)) != NULL) {
+ def.type = VIR_STORAGE_POOL_DIR;
+ def.target.path = localInfo->path;
+ } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) {
+ def.type = VIR_STORAGE_POOL_NETFS;
+ def.source.host.name = nasInfo->nas->remoteHost;
+ def.source.dir = nasInfo->nas->remotePath;
+
+ if (STRCASEEQ(nasInfo->nas->type, "NFS")) {
+ def.source.format = VIR_STORAGE_POOL_NETFS_NFS;
+ } else if (STRCASEEQ(nasInfo->nas->type, "CIFS")) {
+ def.source.format = VIR_STORAGE_POOL_NETFS_CIFS;
+ } else {
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Datastore has unexpected type '%s'"),
+ nasInfo->nas->type);
+ goto cleanup;
+ }
+ } else if ((vmfsInfo = esxVI_VmfsDatastoreInfo_DynamicCast(info)) != NULL) {
+ def.type = VIR_STORAGE_POOL_FS;
+ /*
+ * FIXME: I'm not sure how to represent the source and target of a
+ * VMFS based datastore in libvirt terms
+ */
+ } else {
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("DatastoreInfo has unexpected type"));
+ goto cleanup;
+ }
+ }
+
+ xml = virStoragePoolDefFormat(&def);
+
+ cleanup:
+ esxVI_String_Free(&propertyNameList);
+ esxVI_ObjectContent_Free(&datastore);
+ esxVI_DatastoreInfo_Free(&info);
+
+ return xml;
+}
+
+
+
+static int
+esxStoragePoolGetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+ int *autostart)
+{
+ /* ESX storage pools are always active */
+ *autostart = 1;
+
+ return 0;
+}
+
+
+
+static int
+esxStoragePoolSetAutostart(virStoragePoolPtr pool ATTRIBUTE_UNUSED,
+ int autostart)
+{
+ /* Just accept autostart activation, but fail on autostart deactivation */
+ autostart = (autostart != 0);
+
+ if (! autostart) {
+ ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot deactivate storage pool autostart"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+static int
+esxStoragePoolIsActive(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
+{
+ /* ESX storage pools are always active */
+ return 1;
+}
+
+
+
+static int
+esxStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
+{
+ /* ESX has no concept of transient pools, so all of them are persistent */
+ return 1;
+}
+
+
static virStorageDriver esxStorageDriver = {
"ESX", /* name */
esxStorageOpen, /* open */
esxStorageClose, /* close */
- NULL, /* numOfPools */
- NULL, /* listPools */
- NULL, /* numOfDefinedPools */
- NULL, /* listDefinedPools */
+ esxNumberOfStoragePools, /* numOfPools */
+ esxListStoragePools, /* listPools */
+ esxNumberOfDefinedStoragePools, /* numOfDefinedPools */
+ esxListDefinedStoragePools, /* listDefinedPools */
NULL, /* findPoolSources */
- NULL, /* poolLookupByName */
- NULL, /* poolLookupByUUID */
+ esxStoragePoolLookupByName, /* poolLookupByName */
+ esxStoragePoolLookupByUUID, /* poolLookupByUUID */
NULL, /* poolLookupByVolume */
NULL, /* poolCreateXML */
NULL, /* poolDefineXML */
@@ -84,11 +655,11 @@ static virStorageDriver esxStorageDriver = {
NULL, /* poolCreate */
NULL, /* poolDestroy */
NULL, /* poolDelete */
- NULL, /* poolRefresh */
- NULL, /* poolGetInfo */
- NULL, /* poolGetXMLDesc */
- NULL, /* poolGetAutostart */
- NULL, /* poolSetAutostart */
+ esxStoragePoolRefresh, /* poolRefresh */
+ esxStoragePoolGetInfo, /* poolGetInfo */
+ esxStoragePoolGetXMLDesc, /* poolGetXMLDesc */
+ esxStoragePoolGetAutostart, /* poolGetAutostart */
+ esxStoragePoolSetAutostart, /* poolSetAutostart */
NULL, /* poolNumOfVolumes */
NULL, /* poolListVolumes */
NULL, /* volLookupByName */
@@ -101,8 +672,8 @@ static virStorageDriver esxStorageDriver = {
NULL, /* volGetInfo */
NULL, /* volGetXMLDesc */
NULL, /* volGetPath */
- NULL, /* poolIsActive */
- NULL, /* poolIsPersistent */
+ esxStoragePoolIsActive, /* poolIsActive */
+ esxStoragePoolIsPersistent, /* poolIsPersistent */
};
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 966ef85..100b9d2 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -1530,6 +1530,114 @@ esxVI_GetVirtualMachineQuestionInfo
int
+esxVI_GetBoolean(esxVI_ObjectContent *objectContent, const char *propertyName,
+ esxVI_Boolean *value, esxVI_Occurrence occurence)
+{
+ esxVI_DynamicProperty *dynamicProperty;
+
+ if (value == NULL || *value != esxVI_Boolean_Undefined) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+ return -1;
+ }
+
+ for (dynamicProperty = objectContent->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, propertyName)) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_Boolean) < 0) {
+ return -1;
+ }
+
+ *value = dynamicProperty->val->boolean;
+ break;
+ }
+ }
+
+ if (*value == esxVI_Boolean_Undefined &&
+ occurence == esxVI_Occurrence_RequiredItem) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Missing '%s' property"), propertyName);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+int
+esxVI_GetStringValue(esxVI_ObjectContent *objectContent,
+ const char *propertyName,
+ char **value, esxVI_Occurrence occurence)
+{
+ esxVI_DynamicProperty *dynamicProperty;
+
+ if (value == NULL || *value != NULL) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+ return -1;
+ }
+
+ for (dynamicProperty = objectContent->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, propertyName)) {
+ if (esxVI_AnyType_ExpectType(dynamicProperty->val,
+ esxVI_Type_String) < 0) {
+ return -1;
+ }
+
+ *value = dynamicProperty->val->string;
+ break;
+ }
+ }
+
+ if (*value == NULL && occurence == esxVI_Occurrence_RequiredItem) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Missing '%s' property"), propertyName);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+int
+esxVI_GetManagedObjectReference(esxVI_ObjectContent *objectContent,
+ const char *propertyName,
+ esxVI_ManagedObjectReference **value,
+ esxVI_Occurrence occurence)
+{
+ esxVI_DynamicProperty *dynamicProperty;
+
+ if (value == NULL || *value != NULL) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+ return -1;
+ }
+
+ for (dynamicProperty = objectContent->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, propertyName)) {
+ if (esxVI_ManagedObjectReference_CastFromAnyType
+ (dynamicProperty->val, value) < 0) {
+ return -1;
+ }
+
+ break;
+ }
+ }
+
+ if (*value == NULL && occurence == esxVI_Occurrence_RequiredItem) {
+ ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR,
+ _("Missing '%s' property"), propertyName);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+int
esxVI_LookupNumberOfDomainsByPowerState(esxVI_Context *ctx,
esxVI_VirtualMachinePowerState powerState,
esxVI_Boolean inverse)
@@ -2161,7 +2269,7 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
esxVI_ObjectContent *candidate = NULL;
esxVI_DynamicProperty *dynamicProperty = NULL;
esxVI_Boolean accessible = esxVI_Boolean_Undefined;
- size_t offset = strlen("/vmfs/volumes/");
+ size_t offset = 14; /* = strlen("/vmfs/volumes/") */
int numInaccessibleDatastores = 0;
if (datastore == NULL || *datastore != NULL) {
@@ -2227,9 +2335,7 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
for (dynamicProperty = candidate->propSet; dynamicProperty != NULL;
dynamicProperty = dynamicProperty->_next) {
- if (STREQ(dynamicProperty->name, "summary.accessible")) {
- /* Ignore it */
- } else if (STREQ(dynamicProperty->name, "summary.name")) {
+ if (STREQ(dynamicProperty->name, "summary.name")) {
if (esxVI_AnyType_ExpectType(dynamicProperty->val,
esxVI_Type_String) < 0) {
goto failure;
@@ -2244,7 +2350,8 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
/* Found datastore with matching name */
goto cleanup;
}
- } else if (STREQ(dynamicProperty->name, "summary.url")) {
+ } else if (STREQ(dynamicProperty->name, "summary.url") &&
+ ctx->productVersion & esxVI_ProductVersion_ESX) {
if (accessible == esxVI_Boolean_False) {
/*
* The 'summary.url' property of an inaccessible datastore
@@ -2276,8 +2383,6 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
/* Found datastore with matching URL suffix */
goto cleanup;
}
- } else {
- VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
}
}
}
@@ -2309,9 +2414,10 @@ esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
-int esxVI_LookupTaskInfoByTask(esxVI_Context *ctx,
- esxVI_ManagedObjectReference *task,
- esxVI_TaskInfo **taskInfo)
+int
+esxVI_LookupTaskInfoByTask(esxVI_Context *ctx,
+ esxVI_ManagedObjectReference *task,
+ esxVI_TaskInfo **taskInfo)
{
int result = 0;
esxVI_String *propertyNameList = NULL;
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index d581a59..e2687c4 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -96,13 +96,23 @@ enum _esxVI_APIVersion {
esxVI_APIVersion_40
};
+/*
+ * AAAABBBB: where AAAA0000 is the product and BBBB the version. this format
+ * allows simple bitmask testing for a product independent of the version
+ */
enum _esxVI_ProductVersion {
esxVI_ProductVersion_Undefined = 0,
- esxVI_ProductVersion_GSX20,
- esxVI_ProductVersion_ESX35,
- esxVI_ProductVersion_ESX40,
- esxVI_ProductVersion_VPX25,
- esxVI_ProductVersion_VPX40
+
+ esxVI_ProductVersion_GSX = (1 << 0) << 16,
+ esxVI_ProductVersion_GSX20 = esxVI_ProductVersion_GSX | 1,
+
+ esxVI_ProductVersion_ESX = (1 << 1) << 16,
+ esxVI_ProductVersion_ESX35 = esxVI_ProductVersion_ESX | 1,
+ esxVI_ProductVersion_ESX40 = esxVI_ProductVersion_ESX | 2,
+
+ esxVI_ProductVersion_VPX = (1 << 2) << 16,
+ esxVI_ProductVersion_VPX25 = esxVI_ProductVersion_VPX | 1,
+ esxVI_ProductVersion_VPX40 = esxVI_ProductVersion_VPX | 2
};
enum _esxVI_Occurrence {
@@ -272,6 +282,19 @@ int esxVI_GetVirtualMachineQuestionInfo
(esxVI_ObjectContent *virtualMachine,
esxVI_VirtualMachineQuestionInfo **questionInfo);
+int esxVI_GetBoolean(esxVI_ObjectContent *objectContent,
+ const char *propertyName,
+ esxVI_Boolean *value, esxVI_Occurrence occurence);
+
+int esxVI_GetStringValue(esxVI_ObjectContent *objectContent,
+ const char *propertyName,
+ char **value, esxVI_Occurrence occurence);
+
+int esxVI_GetManagedObjectReference(esxVI_ObjectContent *objectContent,
+ const char *propertyName,
+ esxVI_ManagedObjectReference **value,
+ esxVI_Occurrence occurence);
+
int esxVI_LookupNumberOfDomainsByPowerState
(esxVI_Context *ctx, esxVI_VirtualMachinePowerState powerState,
esxVI_Boolean inverse);
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 5e5e6ba..ff65178 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -146,6 +146,14 @@ object ChoiceOption extends OptionType
end
+object DatastoreInfo
+ String name r
+ String url r
+ Long freeSpace r
+ Long maxFileSize r
+end
+
+
object Description
String label r
String summary r
@@ -186,6 +194,47 @@ object HostCpuIdInfo
end
+object HostFileSystemVolume
+ String type r
+ String name r
+ Long capacity r
+end
+
+
+object HostNasVolume extends HostFileSystemVolume
+ String remoteHost r
+ String remotePath r
+ String userName o
+end
+
+
+object HostScsiDiskPartition
+ String diskName r
+ Int partition r
+end
+
+
+object HostVmfsVolume extends HostFileSystemVolume
+ Int blockSizeMb r
+ Int maxBlocks r
+ Int majorVersion r
+ String version r
+ String uuid r
+ HostScsiDiskPartition extent rl
+ Boolean vmfsUpgradable r
+end
+
+
+object LocalDatastoreInfo extends DatastoreInfo
+ String path o
+end
+
+
+object NasDatastoreInfo extends DatastoreInfo
+ HostNasVolume nas o
+end
+
+
object ObjectContent
ManagedObjectReference obj r
DynamicProperty propSet ol
@@ -453,6 +502,11 @@ object VirtualMachineSnapshotTree
end
+object VmfsDatastoreInfo extends DatastoreInfo
+ HostVmfsVolume vmfs o
+end
+
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Methods
#
@@ -571,6 +625,11 @@ method ReconfigVM_Task returns ManagedObjectReference r
end
+method RefreshDatastore
+ ManagedObjectReference _this r
+end
+
+
method RegisterVM_Task returns ManagedObjectReference r
ManagedObjectReference _this r
String path r
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index 6ae13c0..8df0e80 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -382,6 +382,9 @@ class Object:
self.properties = properties
self.extended_by = extended_by
+ if self.extended_by is not None:
+ self.extended_by.sort();
+
def generate_struct_members(self, add_banner = False, struct_gap = False):
global objects_by_name
@@ -1095,7 +1098,8 @@ additional_enum_features = { "ManagedEntityStatus" : Enum.FEATURE__ANY_TYPE
"VirtualMachinePowerState" : Enum.FEATURE__ANY_TYPE }
-additional_object_features = { "Event" : Object.FEATURE__LIST,
+additional_object_features = { "DatastoreInfo" : Object.FEATURE__ANY_TYPE | Object.FEATURE__DYNAMIC_CAST,
+ "Event" : Object.FEATURE__LIST,
"HostCpuIdInfo" : Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST,
"ManagedObjectReference" : Object.FEATURE__ANY_TYPE,
"ObjectContent" : Object.FEATURE__DEEP_COPY | Object.FEATURE__LIST,
@@ -1235,6 +1239,7 @@ for obj in objects_by_name.values():
extended_obj.extended_by = [obj.name]
else:
extended_obj.extended_by.append(obj.name)
+ extended_obj.extended_by.sort()
--
1.7.0.4
14 years, 7 months
[libvirt] Sys::Virt deps
by C.J. Adams-Collier
Hey folks,
I am poking at Sys::Virt a little. Here's a patch to help with
dependencies.
Cheers,
C.J.
$ diff -u Sys-Virt-0.2.4/Makefile.PL Sys-Virt-0.2.4-cjac/Makefile.PL
--- Sys-Virt-0.2.4/Makefile.PL 2010-05-19 11:56:18.000000000 +0000
+++ Sys-Virt-0.2.4-cjac/Makefile.PL 2010-05-26 00:55:05.000000000 +0000
@@ -16,6 +16,7 @@
'VERSION_FROM' => 'lib/Sys/Virt.pm',
'PREREQ_PM' => {
'Test::More' => 0,
+ 'XML::XPath' => 0,
},
'AUTHOR' => 'Daniel Berrange <dan(a)berrange.com>',
'LIBS' => [$LIBVIRT_LIBS],
14 years, 7 months
[libvirt] [PATCH v10] vepa: parsing for 802.1Qb{g|h} XML
by Stefan Berger
Below is David Alan's original patch with lots of changes.
In particular, it now parses the following two XML descriptions, one
for 802.1Qbg and 802.1Qbh and stored the data internally. The actual
triggering of the switch setup protocol has not been implemented
here but the relevant code to do that should go into the functions
associatePortProfileId() and disassociatePortProfileId().
<interface type='direct'>
<source dev='eth0.100' mode='vepa'/>
<model type='virtio'/>
<virtualport type='802.1Qbg'>
<parameters managerid='12' typeid='0x123456' typeidversion='1'
instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
</virtualport>
<filterref filter='clean-traffic'/>
</interface>
<interface type='direct'>
<source dev='eth0.100' mode='vepa'/>
<model type='virtio'/>
<virtualport type='802.1Qbh'>
<parameters profileid='my_profile'/>
</virtualport>
</interface>
I'd suggest to use this patch as a base for triggering the setup
protocol with the 802.1Qb{g|h} switch.
V10:
- Renamed structure virVirtualPortProfileDef to virVirtualPortProfileParams
as per Daniel Berrange's request
V9:
-Addressing Daniel Berrange's comments:
- removing macvtap.h's dependency on domain_conf.h by
moving the virVirtualPortProfileDef structure into macvtap.h
and not passing virtDomainNetDefPtr to any functions in
macvtap.c
Changes from V7 to V8:
- Addressed most of Chris Wright's comments:
- indicating error in case virtualport XML node cannot be parsed
properly
- parsing hex and decimal numbers using virStrToLong_ui() with
parameter '0' for base
- tgifname (target interface name) variable wasn't necessary
to pass to openMacvtapTap function anymore
- assigning the virtual port data structure to the virDomainNetDef
only if it was previously parsed
-> still leaving possibility to start a domain with macvtap but no profile
Changes from V6 to V7:
- make sure that the error code returned by openMacvtapTap() is a negative number
in case the associatePortProfileId() function failed.
Changes from V5 to V6:
- renaming vsi in the XML to virtualport
- replace all occurrences of vsi in the source as well
Changes from V4 to V5:
- removing mode and MAC address parameters from the functions that
will communicate with the hareware diretctly or indirectly
Changes from V3 to V4:
- moving the associate and disassociate functions to the end of the
file for subsequent patches to easier make them generally available
for export
- passing the macvtap interface name rather than the link device since
this otherwise gives funny side effects when using netlink messages
where IFLA_IFNAME and IFLA_ADDRESS are specified and the link dev
all of a sudden gets the MAC address of the macvtap interface.
- Removing rc = -1 error indications in the case of 802.1Qbg|h setup in case
we wanted to use hook scripts for the setup and so the setup doesn't fail
here.
Changes from V2 to V3:
- if instance ID UUID is not supplied it will automatically be generated
- adapted schema to make instance ID UUID optional
- added test case
Some of the changes from V1 to V2:
- parser and XML generator have been separated into their own
functions so they can be re-used elsewhere (passthrough case
for example)
- Adapted XML parser and generator support the above shown type
(802.1Qbg, 802.1Qbh).
- Adapted schema to above XML
- Adapted test XML to above XML
- Passing through the VM's UUID which seems to be necessary for
802.1Qbh -- sorry no host UUID
- adding virtual function ID to association function, in case it's
necessary to use (for SR-IOV)
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
>From a945107f047c7cd71f9c1b74fd74c47d8cdc3670 Mon Sep 17 00:00:00 2001
From: David Allan <dallan(a)redhat.com>
Date: Fri, 12 Mar 2010 13:25:04 -0500
Subject: [PATCH 1/1] POC of port profile id support
* Modified schema per DanPB's feedback
* Added test for modified schema
---
docs/schemas/domain.rng | 69 +++++++++++
src/conf/domain_conf.c | 202 +++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 2
src/qemu/qemu_conf.c | 21 +--
src/qemu/qemu_conf.h | 5
src/qemu/qemu_driver.c | 19 +--
src/util/macvtap.c | 137 ++++++++++++++++++++--
src/util/macvtap.h | 45 ++++++-
tests/domainschemadata/portprofile.xml | 36 +++++
9 files changed, 498 insertions(+), 38 deletions(-)
create mode 100644 tests/domainschemadata/portprofile.xml
Index: libvirt-acl/docs/schemas/domain.rng
===================================================================
--- libvirt-acl.orig/docs/schemas/domain.rng
+++ libvirt-acl/docs/schemas/domain.rng
@@ -817,6 +817,9 @@
</optional>
<empty/>
</element>
+ <optional>
+ <ref name="virtualPortProfile"/>
+ </optional>
<ref name="interface-options"/>
</interleave>
</group>
@@ -902,6 +905,45 @@
</optional>
</interleave>
</define>
+ <define name="virtualPortProfile">
+ <choice>
+ <group>
+ <element name="virtualport">
+ <attribute name="type">
+ <value>802.1Qbg</value>
+ </attribute>
+ <element name="parameters">
+ <attribute name="managerid">
+ <ref name="uint8range"/>
+ </attribute>
+ <attribute name="typeid">
+ <ref name="uint24range"/>
+ </attribute>
+ <attribute name="typeidversion">
+ <ref name="uint8range"/>
+ </attribute>
+ <optional>
+ <attribute name="instanceid">
+ <ref name="UUID"/>
+ </attribute>
+ </optional>
+ </element>
+ </element>
+ </group>
+ <group>
+ <element name="virtualport">
+ <attribute name="type">
+ <value>802.1Qbh</value>
+ </attribute>
+ <element name="parameters">
+ <attribute name="profileid">
+ <ref name="virtualPortProfileID"/>
+ </attribute>
+ </element>
+ </element>
+ </group>
+ </choice>
+ </define>
<!--
An emulator description is just a path to the binary used for the task
-->
@@ -1769,4 +1811,31 @@
<param name="pattern">[a-zA-Z0-9_\.:]+</param>
</data>
</define>
+ <define name="uint8range">
+ <choice>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,2}</param>
+ </data>
+ <data type="int">
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">255</param>
+ </data>
+ </choice>
+ </define>
+ <define name="uint24range">
+ <choice>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,6}</param>
+ </data>
+ <data type="int">
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">16777215</param>
+ </data>
+ </choice>
+ </define>
+ <define name="virtualPortProfileID">
+ <data type="string">
+ <param name="maxLength">39</param>
+ </data>
+ </define>
</grammar>
Index: libvirt-acl/src/conf/domain_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.c
+++ libvirt-acl/src/conf/domain_conf.c
@@ -242,6 +242,11 @@ VIR_ENUM_IMPL(virDomainNetdevMacvtap, VI
"private",
"bridge")
+VIR_ENUM_IMPL(virVirtualPort, VIR_VIRTUALPORT_TYPE_LAST,
+ "none",
+ "802.1Qbg",
+ "802.1Qbh")
+
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
"utc",
"localtime",
@@ -1807,6 +1812,190 @@ cleanup:
}
+static int
+virVirtualPortProfileParamsParseXML(xmlNodePtr node,
+ virVirtualPortProfileParamsPtr virtPort)
+{
+ int ret = -1;
+ char *virtPortType;
+ char *virtPortManagerID = NULL;
+ char *virtPortTypeID = NULL;
+ char *virtPortTypeIDVersion = NULL;
+ char *virtPortInstanceID = NULL;
+ char *virtPortProfileID = NULL;
+ xmlNodePtr cur = node->children;
+ const char *msg = NULL;
+
+ virtPortType = virXMLPropString(node, "type");
+ if (!virtPortType)
+ return -1;
+
+ while (cur != NULL) {
+ if (xmlStrEqual(cur->name, BAD_CAST "parameters")) {
+
+ virtPortManagerID = virXMLPropString(cur, "managerid");
+ virtPortTypeID = virXMLPropString(cur, "typeid");
+ virtPortTypeIDVersion = virXMLPropString(cur, "typeidversion");
+ virtPortInstanceID = virXMLPropString(cur, "instanceid");
+ virtPortProfileID = virXMLPropString(cur, "profileid");
+
+ break;
+ }
+
+ cur = cur->next;
+ }
+
+ virtPort->virtPortType = VIR_VIRTUALPORT_NONE;
+
+ switch (virVirtualPortTypeFromString(virtPortType)) {
+
+ case VIR_VIRTUALPORT_8021QBG:
+ if (virtPortManagerID != NULL && virtPortTypeID != NULL &&
+ virtPortTypeIDVersion != NULL) {
+ unsigned int val;
+
+ if (virStrToLong_ui(virtPortManagerID, NULL, 0, &val)) {
+ msg = _("cannot parse value of managerid parameter");
+ goto err_exit;
+ }
+
+ if (val > 0xff) {
+ msg = _("value of managerid out of range");
+ goto err_exit;
+ }
+
+ virtPort->u.virtPort8021Qbg.managerID = (uint8_t)val;
+
+ if (virStrToLong_ui(virtPortTypeID, NULL, 0, &val)) {
+ msg = _("cannot parse value of typeid parameter");
+ goto err_exit;
+ }
+
+ if (val > 0xffffff) {
+ msg = _("value for typeid out of range");
+ goto err_exit;
+ }
+
+ virtPort->u.virtPort8021Qbg.typeID = (uint32_t)val;
+
+ if (virStrToLong_ui(virtPortTypeIDVersion, NULL, 0, &val)) {
+ msg = _("cannot parse value of typeidversion parameter");
+ goto err_exit;
+ }
+
+ if (val > 0xff) {
+ msg = _("value of typeidversion out of range");
+ goto err_exit;
+ }
+
+ virtPort->u.virtPort8021Qbg.typeIDVersion = (uint8_t)val;
+
+ if (virtPortInstanceID != NULL) {
+ if (virUUIDParse(virtPortInstanceID,
+ virtPort->u.virtPort8021Qbg.instanceID)) {
+ msg = _("cannot parse instanceid parameter as a uuid");
+ goto err_exit;
+ }
+ } else {
+ if (virUUIDGenerate(virtPort->u.virtPort8021Qbg.instanceID)) {
+ msg = _("cannot generate a random uuid for instanceid");
+ goto err_exit;
+ }
+ }
+
+ virtPort->virtPortType = VIR_VIRTUALPORT_8021QBG;
+ ret = 0;
+ } else {
+ msg = _("a parameter is missing for 802.1Qbg description");
+ goto err_exit;
+ }
+ break;
+
+ case VIR_VIRTUALPORT_8021QBH:
+ if (virtPortProfileID != NULL) {
+ if (virStrcpyStatic(virtPort->u.virtPort8021Qbh.profileID,
+ virtPortProfileID) != NULL) {
+ virtPort->virtPortType = VIR_VIRTUALPORT_8021QBH;
+ ret = 0;
+ } else {
+ msg = _("profileid parameter too long");
+ goto err_exit;
+ }
+ } else {
+ msg = _("profileid parameter is missing for 802.1Qbh descripion");
+ goto err_exit;
+ }
+ break;
+
+
+ default:
+ case VIR_VIRTUALPORT_NONE:
+ case VIR_VIRTUALPORT_TYPE_LAST:
+ msg = _("unknown virtualport type");
+ goto err_exit;
+ break;
+ }
+
+err_exit:
+
+ if (msg)
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", msg);
+
+ VIR_FREE(virtPortManagerID);
+ VIR_FREE(virtPortTypeID);
+ VIR_FREE(virtPortTypeIDVersion);
+ VIR_FREE(virtPortInstanceID);
+ VIR_FREE(virtPortProfileID);
+ VIR_FREE(virtPortType);
+
+ return ret;
+}
+
+
+static void
+virVirtualPortProfileFormat(virBufferPtr buf,
+ virVirtualPortProfileParamsPtr virtPort,
+ const char *indent)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ if (virtPort->virtPortType == VIR_VIRTUALPORT_NONE)
+ return;
+
+ virBufferVSprintf(buf, "%s<virtualport type='%s'>\n",
+ indent,
+ virVirtualPortTypeToString(virtPort->virtPortType));
+
+ switch (virtPort->virtPortType) {
+ case VIR_VIRTUALPORT_NONE:
+ case VIR_VIRTUALPORT_TYPE_LAST:
+ break;
+
+ case VIR_VIRTUALPORT_8021QBG:
+ virUUIDFormat(virtPort->u.virtPort8021Qbg.instanceID,
+ uuidstr);
+ virBufferVSprintf(buf,
+ "%s <parameters managerid='%d' typeid='%d' "
+ "typeidversion='%d' instanceid='%s'/>\n",
+ indent,
+ virtPort->u.virtPort8021Qbg.managerID,
+ virtPort->u.virtPort8021Qbg.typeID,
+ virtPort->u.virtPort8021Qbg.typeIDVersion,
+ uuidstr);
+ break;
+
+ case VIR_VIRTUALPORT_8021QBH:
+ virBufferVSprintf(buf,
+ "%s <parameters profileid='%s'/>\n",
+ indent,
+ virtPort->u.virtPort8021Qbh.profileID);
+ break;
+ }
+
+ virBufferVSprintf(buf, "%s</virtualport>\n", indent);
+}
+
+
/* Parse the XML definition for a network interface
* @param node XML nodeset to parse for net definition
* @return 0 on success, -1 on failure
@@ -1832,6 +2021,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *devaddr = NULL;
char *mode = NULL;
virNWFilterHashTablePtr filterparams = NULL;
+ virVirtualPortProfileParams virtPort;
+ bool virtPortParsed = false;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
@@ -1873,6 +2064,12 @@ virDomainNetDefParseXML(virCapsPtr caps,
xmlStrEqual(cur->name, BAD_CAST "source")) {
dev = virXMLPropString(cur, "dev");
mode = virXMLPropString(cur, "mode");
+ } else if ((virtPortParsed == false) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
+ xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
+ if (virVirtualPortProfileParamsParseXML(cur, &virtPort))
+ goto error;
+ virtPortParsed = true;
} else if ((network == NULL) &&
((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
(def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -2048,6 +2245,9 @@ virDomainNetDefParseXML(virCapsPtr caps,
} else
def->data.direct.mode = VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;
+ if (virtPortParsed)
+ def->data.direct.virtPortProfile = virtPort;
+
def->data.direct.linkdev = dev;
dev = NULL;
@@ -5140,6 +5340,8 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferVSprintf(buf, " mode='%s'",
virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
virBufferAddLit(buf, "/>\n");
+ virVirtualPortProfileFormat(buf, &def->data.direct.virtPortProfile,
+ " ");
break;
case VIR_DOMAIN_NET_TYPE_USER:
Index: libvirt-acl/src/conf/domain_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.h
+++ libvirt-acl/src/conf/domain_conf.h
@@ -38,6 +38,7 @@
# include "network.h"
# include "nwfilter_params.h"
# include "nwfilter_conf.h"
+# include "macvtap.h"
/* Private component of virDomainXMLFlags */
typedef enum {
@@ -290,6 +291,7 @@ struct _virDomainNetDef {
struct {
char *linkdev;
int mode;
+ virVirtualPortProfileParams virtPortProfile;
} direct;
} data;
char *ifname;
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -43,6 +43,7 @@
# include "util.h"
# include "memory.h"
+# include "logging.h"
# include "macvtap.h"
# include "interface.h"
# include "conf/domain_conf.h"
@@ -57,6 +58,16 @@
# define MACVTAP_NAME_PREFIX "macvtap"
# define MACVTAP_NAME_PATTERN "macvtap%d"
+
+static int associatePortProfileId(const char *macvtap_ifname,
+ const virVirtualPortProfileParamsPtr virtPort,
+ int vf,
+ const unsigned char *vmuuid);
+
+static int disassociatePortProfileId(const char *macvtap_ifname,
+ const virVirtualPortProfileParamsPtr virtPort);
+
+
static int nlOpen(void)
{
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
@@ -577,8 +588,10 @@ configMacvtapTap(int tapfd, int vnet_hdr
* be NULL if this function is supposed to choose a name
* @macaddress: The MAC address for the macvtap device
* @linkdev: The interface name of the NIC to connect to the external bridge
- * @mode_str: String describing the mode. Valid are 'bridge', 'vepa' and
- * 'private'.
+ * @mode: int describing the mode for 'bridge', 'vepa' or 'private'.
+ * @vnet_hdr: 1 to enable IFF_VNET_HDR, 0 to disable it
+ * @vmuuid: The UUID of the VM the macvtap belongs to
+ * @virtPortProfile: pointer to object holding the virtual port profile data
* @res_ifname: Pointer to a string pointer where the actual name of the
* interface will be stored into if everything succeeded. It is up
* to the caller to free the string.
@@ -592,8 +605,10 @@ openMacvtapTap(const char *tgifname,
const unsigned char *macaddress,
const char *linkdev,
int mode,
- char **res_ifname,
- int vnet_hdr)
+ int vnet_hdr,
+ const unsigned char *vmuuid,
+ virVirtualPortProfileParamsPtr virtPortProfile,
+ char **res_ifname)
{
const char *type = "macvtap";
int c, rc;
@@ -639,6 +654,14 @@ create_name:
cr_ifname = ifname;
}
+ if (associatePortProfileId(cr_ifname,
+ virtPortProfile,
+ -1,
+ vmuuid) != 0) {
+ rc = -1;
+ goto link_del_exit;
+ }
+
rc = ifaceUp(cr_ifname);
if (rc != 0) {
virReportSystemError(errno,
@@ -647,7 +670,7 @@ create_name:
"MAC address"),
cr_ifname);
rc = -1;
- goto link_del_exit;
+ goto disassociate_exit;
}
rc = openTap(cr_ifname, 10);
@@ -656,14 +679,18 @@ create_name:
if (configMacvtapTap(rc, vnet_hdr) < 0) {
close(rc);
rc = -1;
- goto link_del_exit;
+ goto disassociate_exit;
}
*res_ifname = strdup(cr_ifname);
} else
- goto link_del_exit;
+ goto disassociate_exit;
return rc;
+disassociate_exit:
+ disassociatePortProfileId(cr_ifname,
+ virtPortProfile);
+
link_del_exit:
link_del(cr_ifname);
@@ -674,13 +701,103 @@ link_del_exit:
/**
* delMacvtap:
* @ifname : The name of the macvtap interface
+ * @virtPortProfile: pointer to object holding the virtual port profile data
*
- * Delete an interface given its name.
+ * Delete an interface given its name. Disassociate
+ * it with the switch if port profile parameters
+ * were provided.
*/
void
-delMacvtap(const char *ifname)
+delMacvtap(const char *ifname,
+ virVirtualPortProfileParamsPtr virtPortProfile)
{
- link_del(ifname);
+ if (ifname) {
+ disassociatePortProfileId(ifname,
+ virtPortProfile);
+ link_del(ifname);
+ }
}
#endif
+
+
+/**
+ * associatePortProfile
+ *
+ * @macvtap_ifname: The name of the macvtap device
+ * @virtPort: pointer to the object holding port profile parameters
+ * @vf: virtual function number, -1 if to be ignored
+ * @vmuuid : the UUID of the virtual machine
+ *
+ * Associate a port on a swtich with a profile. This function
+ * may notify a kernel driver or an external daemon to run
+ * the setup protocol. If profile parameters were not supplied
+ * by the user, then this function returns without doing
+ * anything.
+ *
+ * Returns 0 in case of success, != 0 otherwise with error
+ * having been reported.
+ */
+static int
+associatePortProfileId(const char *macvtap_ifname,
+ const virVirtualPortProfileParamsPtr virtPort,
+ int vf,
+ const unsigned char *vmuuid)
+{
+ int rc = 0;
+ VIR_DEBUG("Associating port profile '%p' on link device '%s'",
+ virtPort, macvtap_ifname);
+ (void)vf;
+ (void)vmuuid;
+
+ switch (virtPort->virtPortType) {
+ case VIR_VIRTUALPORT_NONE:
+ case VIR_VIRTUALPORT_TYPE_LAST:
+ break;
+
+ case VIR_VIRTUALPORT_8021QBG:
+
+ break;
+
+ case VIR_VIRTUALPORT_8021QBH:
+
+ break;
+ }
+
+ return rc;
+}
+
+
+/**
+ * disassociatePortProfile
+ *
+ * @macvtap_ifname: The name of the macvtap device
+ * @virtPort: point to object holding port profile parameters
+ *
+ * Returns 0 in case of success, != 0 otherwise with error
+ * having been reported.
+ */
+static int
+disassociatePortProfileId(const char *macvtap_ifname,
+ const virVirtualPortProfileParamsPtr virtPort)
+{
+ int rc = 0;
+ VIR_DEBUG("Disassociating port profile id '%p' on link device '%s' ",
+ virtPort, macvtap_ifname);
+
+ switch (virtPort->virtPortType) {
+ case VIR_VIRTUALPORT_NONE:
+ case VIR_VIRTUALPORT_TYPE_LAST:
+ break;
+
+ case VIR_VIRTUALPORT_8021QBG:
+
+ break;
+
+ case VIR_VIRTUALPORT_8021QBH:
+
+ break;
+ }
+
+ return rc;
+}
Index: libvirt-acl/src/util/macvtap.h
===================================================================
--- libvirt-acl.orig/src/util/macvtap.h
+++ libvirt-acl/src/util/macvtap.h
@@ -24,6 +24,40 @@
# include <config.h>
+
+enum virVirtualPortType {
+ VIR_VIRTUALPORT_NONE,
+ VIR_VIRTUALPORT_8021QBG,
+ VIR_VIRTUALPORT_8021QBH,
+
+ VIR_VIRTUALPORT_TYPE_LAST,
+};
+
+# ifdef IFLA_VF_PORT_PROFILE_MAX
+# define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX IFLA_VF_PORT_PROFILE_MAX
+# else
+# define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX 40
+# endif
+
+/* profile data for macvtap (VEPA) */
+typedef struct _virVirtualPortProfileParams virVirtualPortProfileParams;
+typedef virVirtualPortProfileParams *virVirtualPortProfileParamsPtr;
+struct _virVirtualPortProfileParams {
+ enum virVirtualPortType virtPortType;
+ union {
+ struct {
+ uint8_t managerID;
+ uint32_t typeID; // 24 bit valid
+ uint8_t typeIDVersion;
+ unsigned char instanceID[VIR_UUID_BUFLEN];
+ } virtPort8021Qbg;
+ struct {
+ char profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX];
+ } virtPort8021Qbh;
+ } u;
+};
+
+
# if defined(WITH_MACVTAP)
# include "internal.h"
@@ -32,10 +66,13 @@ int openMacvtapTap(const char *ifname,
const unsigned char *macaddress,
const char *linkdev,
int mode,
- char **res_ifname,
- int vnet_hdr);
+ int vnet_hdr,
+ const unsigned char *vmuuid,
+ virVirtualPortProfileParamsPtr virtPortProfile,
+ char **res_ifname);
-void delMacvtap(const char *ifname);
+void delMacvtap(const char *ifname,
+ virVirtualPortProfileParamsPtr virtPortProfile);
# endif /* WITH_MACVTAP */
@@ -44,4 +81,6 @@ void delMacvtap(const char *ifname);
# define MACVTAP_MODE_BRIDGE_STR "bridge"
+VIR_ENUM_DECL(virVirtualPort)
+
#endif /* __UTIL_MACVTAP_H__ */
Index: libvirt-acl/tests/domainschemadata/portprofile.xml
===================================================================
--- /dev/null
+++ libvirt-acl/tests/domainschemadata/portprofile.xml
@@ -0,0 +1,36 @@
+<domain type='lxc'>
+ <name>portprofile</name>
+ <uuid>00000000-0000-0000-0000-000000000000</uuid>
+ <memory>1048576</memory>
+ <os>
+ <type>exe</type>
+ <init>/sh</init>
+ </os>
+ <devices>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <virtualport type='802.1Qbg'>
+ <parameters managerid='12' typeid='1193046' typeidversion='1'
+ instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
+ </virtualport>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <virtualport type='802.1Qbg'>
+ <parameters managerid='12' typeid='1193046' typeidversion='1'/>
+ </virtualport>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <virtualport type='802.1Qbh'>
+ <parameters profileid='my_profile'/>
+ </virtualport>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ </interface>
+ </devices>
+</domain>
Index: libvirt-acl/src/qemu/qemu_conf.h
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.h
+++ libvirt-acl/src/qemu/qemu_conf.h
@@ -274,9 +274,8 @@ qemudOpenVhostNet(virDomainNetDefPtr net
int qemudPhysIfaceConnect(virConnectPtr conn,
struct qemud_driver *driver,
virDomainNetDefPtr net,
- char *linkdev,
- int brmode,
- unsigned long long qemuCmdFlags);
+ unsigned long long qemuCmdFlags,
+ const unsigned char *vmuuid);
int qemudProbeMachineTypes (const char *binary,
virCapsGuestMachinePtr **machines,
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -3708,10 +3708,9 @@ static void qemudShutdownVMDaemon(struct
def = vm->def;
for (i = 0; i < def->nnets; i++) {
virDomainNetDefPtr net = def->nets[i];
- if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (net->ifname)
- delMacvtap(net->ifname);
- }
+ if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
+ delMacvtap(net->ifname,
+ &net->data.direct.virtPortProfile);
}
#endif
@@ -7466,9 +7465,8 @@ static int qemudDomainAttachNetDevice(vi
}
if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
- net->data.direct.linkdev,
- net->data.direct.mode,
- qemuCmdFlags)) < 0)
+ qemuCmdFlags,
+ vm->def->uuid)) < 0)
return -1;
}
@@ -8514,10 +8512,9 @@ qemudDomainDetachNetDevice(struct qemud_
virNWFilterTearNWFilter(detach);
#if WITH_MACVTAP
- if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
- if (detach->ifname)
- delMacvtap(detach->ifname);
- }
+ if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT)
+ delMacvtap(detach->ifname,
+ &detach->data.direct.virtPortProfile);
#endif
if ((driver->macFilter) && (detach->ifname != NULL)) {
Index: libvirt-acl/src/qemu/qemu_conf.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.c
+++ libvirt-acl/src/qemu/qemu_conf.c
@@ -1470,9 +1470,8 @@ int
qemudPhysIfaceConnect(virConnectPtr conn,
struct qemud_driver *driver,
virDomainNetDefPtr net,
- char *linkdev,
- int brmode,
- unsigned long long qemuCmdFlags)
+ unsigned long long qemuCmdFlags,
+ const unsigned char *vmuuid)
{
int rc;
#if WITH_MACVTAP
@@ -1484,8 +1483,9 @@ qemudPhysIfaceConnect(virConnectPtr conn
net->model && STREQ(net->model, "virtio"))
vnet_hdr = 1;
- rc = openMacvtapTap(net->ifname, net->mac, linkdev, brmode,
- &res_ifname, vnet_hdr);
+ rc = openMacvtapTap(net->ifname, net->mac, net->data.direct.linkdev,
+ net->data.direct.mode, vnet_hdr, vmuuid,
+ &net->data.direct.virtPortProfile, &res_ifname);
if (rc >= 0) {
VIR_FREE(net->ifname);
net->ifname = res_ifname;
@@ -1505,17 +1505,17 @@ qemudPhysIfaceConnect(virConnectPtr conn
if (err) {
close(rc);
rc = -1;
- delMacvtap(net->ifname);
+ delMacvtap(net->ifname,
+ &net->data.direct.virtPortProfile);
}
}
}
#else
(void)conn;
(void)net;
- (void)linkdev;
- (void)brmode;
(void)qemuCmdFlags;
(void)driver;
+ (void)vmuuid;
qemuReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("No support for macvtap device"));
rc = -1;
@@ -4135,9 +4135,8 @@ int qemudBuildCommandLine(virConnectPtr
goto no_memory;
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
int tapfd = qemudPhysIfaceConnect(conn, driver, net,
- net->data.direct.linkdev,
- net->data.direct.mode,
- qemuCmdFlags);
+ qemuCmdFlags,
+ def->uuid);
if (tapfd < 0)
goto error;
14 years, 7 months
[libvirt] [PATCH] phyp: first part of storage management driver
by Eduardo Otubo
Hello all,
This is the first patch about storage management driver on IBM Power
Hypervisor. I reviewd a couple of times but perhaps I might be missing
something. Any comments are welcome.
[]'s
--
Eduardo Otubo
Software Engineer
Linux Technology Center
IBM Systems & Technology Group
Mobile: +55 19 8135 0885
eotubo(a)linux.vnet.ibm.com
14 years, 7 months
[libvirt] [PATCH] build: fix compilation without macvtap
by Eric Blake
* src/util/macvtap.c: (associatePortProfileId)
(disassociatePortProfileId): Move inside HAVE_MACVTAP
conditional.
Reported by Eduardo Otubo
---
Pushing as trivial, to fix the build.
src/util/macvtap.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/util/macvtap.c b/src/util/macvtap.c
index 715f329..4f8c95a 100644
--- a/src/util/macvtap.c
+++ b/src/util/macvtap.c
@@ -718,8 +718,6 @@ delMacvtap(const char *ifname,
}
}
-#endif
-
/**
* associatePortProfile
@@ -801,3 +799,5 @@ disassociatePortProfileId(const char *macvtap_ifname,
return rc;
}
+
+#endif /* WITH_MACVTAP */
--
1.7.0.1
14 years, 7 months
[libvirt] avoid new "make check" failure and fix a related bug
by Jim Meyering
In reviewing/testing some incoming patches, I noticed a new
"make check" failure.
There were two problems:
- not diagnosing an invalid host UUID. The lack of this diagnostic
made it slightly more challenging to track down the next problem:
- not accommodating the fact that our template now contains
an invalid line; before the addition of "host_uuid", each
commented-out sample line was valid.
Here are the fixes.
>From 11228f4b2dba1b43a9de97a575d1121eba2e8cf4 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Tue, 25 May 2010 20:56:18 +0200
Subject: [PATCH 1/2] libvirtd: diagnose invalid host UUID
* daemon/libvirtd.c (remoteReadConfigFile): Diagnose an invalid
host UUID rather than silently exiting with status 7.
---
daemon/libvirtd.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 8fa78b8..e86f78d 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -2843,8 +2843,10 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename)
GET_CONF_INT (conf, filename, max_client_requests);
GET_CONF_STR (conf, filename, host_uuid);
- if (virSetHostUUIDStr(host_uuid))
+ if (virSetHostUUIDStr(host_uuid)) {
+ VIR_ERROR(_("invalid host UUID: %s"), host_uuid);
goto free_and_fail;
+ }
VIR_FREE(host_uuid);
--
1.7.1.342.g1c280
>From 6d20ae23fe5a5e64a0cf1be1f0b9cebce49625c1 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Tue, 25 May 2010 21:08:37 +0200
Subject: [PATCH 2/2] tests: avoid new failure of the daemon-conf test
* tests/daemon-conf: Accommodate the fact that out template,
daemon/libvirtd.conf now contains an invalid host_uuid.
Convert it to a valid one before the final libvirtd-running
test that must terminate normally.
---
tests/daemon-conf | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/tests/daemon-conf b/tests/daemon-conf
index 14d4ced..0e756d4 100755
--- a/tests/daemon-conf
+++ b/tests/daemon-conf
@@ -83,7 +83,11 @@ if test 108 -lt `echo $SOCKPATH | wc -c`; then
skip_test_ "CWD too long"
fi
-$abs_top_builddir/daemon/libvirtd --pid-file=pid-file --config=tmp.conf > log 2>&1 & pid=$!
+# Replace the invalid host_uuid with one that is valid:
+sed 's/^\(host_uuid =.*\)0"$/\11"/' tmp.conf > k; mv k tmp.conf
+
+$abs_top_builddir/daemon/libvirtd --pid-file=pid-file --config=tmp.conf \
+ > log 2>&1 & pid=$!
sleep $sleep_secs
kill $pid
--
1.7.1.342.g1c280
14 years, 7 months