Devel
Threads by month
- ----- 2026 -----
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- 44 participants
- 40055 discussions
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
3
4
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
3
3
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
2
2
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],
2
1
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;
4
4
26 May '10
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
2
4
* 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
1
0
26 May '10
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
2
2
25 May '10
Reposting due to malformatted patch.
This patch builds on the work recently posted by Stefan Berger. It builds
on top of Stefan's three posted patches:
[PATCH v10] vepa: parsing for 802.1Qb{g|h} XML
[RFC][PATCH 1/3] vepa+vsi: Introduce dependency on libnl
[PATCH v3] Add host UUID (to libvirt capabilities)
Stefan's RFC patches 2/3 and 3/3 are incorporated into my patch.
V7:
- Addressing Jim Meyering's comments; this also touches existing
code for example for correcting indentation of break statements or
simplification of switch statements.
Changes from v5 to v6:
- Renamed occurrencvirVirtualPortProfileDef to
virVirtualPortProfileParamses
- 802.1Qbg part prepared for sending a RTM_SETLINK and getting
processing status back plus a subsequent RTM_GETLINK to
get IFLA_PORT_RESPONSE.
Note: This interface for 802.1Qbg may still change
Changes from v4 to v5:
- [David Allan] move getPhysfn inside IFLA_VF_PORT_MAX to avoid
compiler
warning when latest if_link.h isn't available
Changes from v3 to v4:
- move from Stefan's 802.1Qb{g|h} XML v8 to v9
- move hostuuid and vf index calcs to inside doPortProfileOp8021Qbh
Changes from v2 to v3:
- remove debug fprintfs
- use virGetHostUUID (thanks Stefan!)
- fix compile issue when latest if_link.h isn't available
- change poll timeout to 10s, at 1/8 intervals
- if polling times out, log msg and return -ETIMEDOUT
Changes from v1 to v2:
- Add Stefan's code for getPortProfileStatus
- Poll for up to 2 secs for port-profile status, at 1/8 sec intervals:
- if status indicates error, abort openMacvtapTap
- if status indicates success, exit polling
- if status is "in-progress" after 2 secs of polling, exit
polling loop silently, without error
My patch finishes out the 802.1Qbh parts, which Stefan had mostly complete.
I've tested using the recent kernel updates for VF_PORT netlink msgs and
enic for Cisco's 10G Ethernet NIC. I tested many VMs, each with several
direct interfaces, each configured with a port-profile per the XML. VM-to-VM,
and VM-to-external work as expected. VM-to-VM on same host (using same NIC)
works same as VM-to-VM where VMs are on diff hosts. I'm able to change
settings on the port-profile while the VM is running to change the virtual
port behaviour. For example, adjusting a QoS setting like rate limit. All
VMs with interfaces using that port-profile immediatly see the effect of the
change to the port-profile.
I don't have a SR-IOV device to test so source dev is a non-SR-IOV device,
but most of the code paths include support for specifing the source dev and
VF index. We'll need to complete this by discovering the PF given the VF
linkdev. Once we have the PF, we'll also have the VF index. All this info-
mation is available from sysfs.
Signed-off-by: Scott Feldman <scofeldm(a)cisco.com>
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
configure.ac | 16
src/qemu/qemu_conf.c | 2
src/qemu/qemu_driver.c | 4
src/util/macvtap.c | 837 +++++++++++++++++++++++++++++++++++++++++++++----
src/util/macvtap.h | 1
5 files changed, 788 insertions(+), 72 deletions(-)
Index: libvirt-acl/configure.ac
===================================================================
--- libvirt-acl.orig/configure.ac
+++ libvirt-acl/configure.ac
@@ -2005,13 +2005,26 @@ if test "$with_macvtap" != "no" ; then
fi
AM_CONDITIONAL([WITH_MACVTAP], [test "$with_macvtap" = "yes"])
+AC_TRY_COMPILE([ #include <sys/socket.h>
+ #include <linux/rtnetlink.h> ],
+ [ int x = IFLA_PORT_MAX; ],
+ [ with_virtualport=yes ],
+ [ with_virtualport=no ])
+if test "$with_virtualport" = "yes"; then
+ val=1
+else
+ val=0
+fi
+AC_DEFINE_UNQUOTED([WITH_VIRTUALPORT], $val, [whether vsi vepa support is enabled])
+AM_CONDITIONAL([WITH_VIRTUALPORT], [test "$with_virtualport" = "yes"])
+
dnl netlink library
LIBNL_CFLAGS=""
LIBNL_LIBS=""
-if test "$with_macvtap" = "yes"; then
+if test "$with_macvtap" = "yes" || test "$with_virtualport" = "yes"; then
PKG_CHECK_MODULES([LIBNL], [libnl-1 >= $LIBNL_REQUIRED], [
], [
AC_MSG_ERROR([libnl >= $LIBNL_REQUIRED is required for macvtap support])
@@ -2084,6 +2097,7 @@ AC_MSG_NOTICE([ Network: $with_network])
AC_MSG_NOTICE([Libvirtd: $with_libvirtd])
AC_MSG_NOTICE([ netcf: $with_netcf])
AC_MSG_NOTICE([ macvtap: $with_macvtap])
+AC_MSG_NOTICE([virtport: $with_virtualport])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Storage Drivers])
AC_MSG_NOTICE([])
Index: libvirt-acl/src/qemu/qemu_conf.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.c
+++ libvirt-acl/src/qemu/qemu_conf.c
@@ -1509,7 +1509,7 @@ qemudPhysIfaceConnect(virConnectPtr conn
if (err) {
close(rc);
rc = -1;
- delMacvtap(net->ifname,
+ delMacvtap(net->ifname, net->data.direct.linkdev,
&net->data.direct.virtPortProfile);
}
}
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -3709,7 +3709,7 @@ static void qemudShutdownVMDaemon(struct
for (i = 0; i < def->nnets; i++) {
virDomainNetDefPtr net = def->nets[i];
if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
- delMacvtap(net->ifname,
+ delMacvtap(net->ifname, net->data.direct.linkdev,
&net->data.direct.virtPortProfile);
}
#endif
@@ -8514,7 +8514,7 @@ qemudDomainDetachNetDevice(struct qemud_
#if WITH_MACVTAP
if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT)
- delMacvtap(detach->ifname,
+ delMacvtap(detach->ifname, detach->data.direct.linkdev,
&detach->data.direct.virtPortProfile);
#endif
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -27,7 +27,7 @@
#include <config.h>
-#if WITH_MACVTAP
+#if WITH_MACVTAP || WITH_VIRTUALPORT
# include <stdio.h>
# include <errno.h>
@@ -41,6 +41,8 @@
# include <linux/rtnetlink.h>
# include <linux/if_tun.h>
+# include <netlink/msg.h>
+
# include "util.h"
# include "memory.h"
# include "logging.h"
@@ -48,6 +50,7 @@
# include "interface.h"
# include "conf/domain_conf.h"
# include "virterror_internal.h"
+# include "uuid.h"
# define VIR_FROM_THIS VIR_FROM_NET
@@ -58,15 +61,30 @@
# define MACVTAP_NAME_PREFIX "macvtap"
# define MACVTAP_NAME_PATTERN "macvtap%d"
+# define MICROSEC_PER_SEC (1000 * 1000)
+
+# define NLMSGBUF_SIZE 256
+# define RATTBUF_SIZE 64
+
+
+# define STATUS_POLL_TIMEOUT_USEC (10 * MICROSEC_PER_SEC)
+# define STATUS_POLL_INTERVL_USEC (MICROSEC_PER_SEC / 8)
+
static int associatePortProfileId(const char *macvtap_ifname,
+ const char *linkdev,
const virVirtualPortProfileParamsPtr virtPort,
- int vf,
const unsigned char *vmuuid);
static int disassociatePortProfileId(const char *macvtap_ifname,
+ const char *linkdev,
const virVirtualPortProfileParamsPtr virtPort);
+enum virVirtualPortOp {
+ ASSOCIATE = 0x1,
+ DISASSOCIATE = 0x2,
+};
+
static int nlOpen(void)
{
@@ -97,7 +115,7 @@ static void nlClose(int fd)
*/
static
int nlComm(struct nlmsghdr *nlmsg,
- char **respbuf, int *respbuflen)
+ char **respbuf, unsigned int *respbuflen)
{
int rc = 0;
struct sockaddr_nl nladdr = {
@@ -159,6 +177,162 @@ err_exit:
}
+# ifdef IFLA_VF_PORT_MAX
+
+/**
+ * nlCommWaitSuccess:
+ *
+ * @nlmsg: pointer to netlink message
+ * @nl_grousp: the netlink multicast groups to send to
+ * @respbuf: pointer to pointer where response buffer will be allocated
+ * @respbuflen: pointer to integer holding the size of the response buffer
+ * on return of the function.
+ * @timeout_usecs: timeout in microseconds to wait for a success message
+ * to be returned
+ *
+ * Send the given message to the netlink multicast group and receive
+ * responses. Skip responses indicating an error and keep on receiving
+ * responses until a success response is returned.
+ * Returns 0 on success, -1 on error. In case of error, no response
+ * buffer will be returned.
+ */
+static int
+nlCommWaitSuccess(struct nlmsghdr *nlmsg, uint32_t nl_groups,
+ char **respbuf, unsigned int *respbuflen,
+ unsigned long long timeout_usecs)
+{
+ int rc = 0;
+ struct sockaddr_nl nladdr = {
+ .nl_family = AF_NETLINK,
+ .nl_pid = getpid(),
+ .nl_groups = nl_groups,
+ };
+ int rcvChunkSize = 1024; // expecting less than that
+ size_t rcv_offset = 0;
+ ssize_t nbytes;
+ struct timeval tv = {
+ .tv_sec = timeout_usecs / MICROSEC_PER_SEC,
+ .tv_usec = timeout_usecs % MICROSEC_PER_SEC,
+ };
+ bool got_valid = false;
+ int fd = nlOpen();
+ static uint32_t seq = 0x1234;
+ uint32_t myseq = seq++;
+ uint32_t mypid = getpid();
+
+ if (fd < 0)
+ return -1;
+
+ nlmsg->nlmsg_pid = mypid;
+ nlmsg->nlmsg_seq = myseq;
+ nlmsg->nlmsg_flags |= NLM_F_ACK;
+
+ nbytes = sendto(fd, (void *)nlmsg, nlmsg->nlmsg_len, 0,
+ (struct sockaddr *)&nladdr, sizeof(nladdr));
+ if (nbytes < 0) {
+ virReportSystemError(errno,
+ "%s", _("cannot send to netlink socket"));
+ rc = -1;
+ goto err_exit;
+ }
+
+ while (!got_valid) {
+
+ rcv_offset = 0;
+
+ while (1) {
+ int n;
+ fd_set rfds;
+ socklen_t addrlen = sizeof(nladdr);
+
+ if (VIR_REALLOC_N(*respbuf, rcv_offset + rcvChunkSize) < 0) {
+ virReportOOMError();
+ rc = -1;
+ goto err_exit;
+ }
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ n = select(fd + 1, &rfds, NULL, NULL, &tv);
+ if (n <= 0) {
+ if (n < 0)
+ virReportSystemError(errno, "%s",
+ _("error in select call"));
+ if (n == 0)
+ virReportSystemError(ETIMEDOUT, "%s",
+ _("no valid netlink response was received"));
+ rc = -1;
+ goto err_exit;
+ }
+
+ nbytes = recvfrom(fd, &((*respbuf)[rcv_offset]), rcvChunkSize, 0,
+ (struct sockaddr *)&nladdr, &addrlen);
+ if (nbytes < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ virReportSystemError(errno, "%s",
+ _("error receiving from netlink socket"));
+ rc = -1;
+ goto err_exit;
+ }
+ rcv_offset += nbytes;
+ break;
+ }
+ *respbuflen = rcv_offset;
+
+ /* check message for error */
+ if (*respbuflen > NLMSG_LENGTH(0) && *respbuf != NULL) {
+ struct nlmsghdr *resp = (struct nlmsghdr *)*respbuf;
+ struct nlmsgerr *err;
+
+ if (resp->nlmsg_pid != mypid ||
+ resp->nlmsg_seq != myseq)
+ continue;
+
+ /* skip reflected message */
+ if (resp->nlmsg_type & 0x10)
+ continue;
+
+ switch (resp->nlmsg_type) {
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(resp);
+ if (resp->nlmsg_len >= NLMSG_LENGTH(sizeof(*err))) {
+ if (err->error != -EOPNOTSUPP) {
+ /* assuming error msg from daemon */
+ got_valid = true;
+ break;
+ }
+ }
+ /* whatever this is, skip it */
+ VIR_FREE(*respbuf);
+ *respbuflen = 0;
+ break;
+
+ case NLMSG_DONE:
+ got_valid = true;
+ break;
+
+ default:
+ VIR_FREE(*respbuf);
+ *respbuflen = 0;
+ break;
+ }
+ }
+ }
+
+err_exit:
+ if (rc == -1) {
+ VIR_FREE(*respbuf);
+ *respbuflen = 0;
+ }
+
+ nlClose(fd);
+ return rc;
+}
+
+# endif
+
static struct rtattr *
rtattrCreate(char *buffer, int bufsize, int type,
const void *data, int datalen)
@@ -204,6 +378,8 @@ nlAppend(struct nlmsghdr *nlm, int totle
}
+# if WITH_MACVTAP
+
static int
link_add(const char *type,
const unsigned char *macaddress, int macaddrsize,
@@ -213,15 +389,15 @@ link_add(const char *type,
int *retry)
{
int rc = 0;
- char nlmsgbuf[256];
+ char nlmsgbuf[NLMSGBUF_SIZE];
struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
struct nlmsgerr *err;
- char rtattbuf[64];
+ char rtattbuf[RATTBUF_SIZE];
struct rtattr *rta, *rta1, *li;
- struct ifinfomsg i = { .ifi_family = AF_UNSPEC };
+ struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
int ifindex;
char *recvbuf = NULL;
- int recvbuflen;
+ unsigned int recvbuflen;
if (ifaceGetIndex(true, srcdev, &ifindex) != 0)
return -1;
@@ -232,65 +408,46 @@ link_add(const char *type,
nlInit(nlm, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, RTM_NEWLINK);
- if (!nlAppend(nlm, sizeof(nlmsgbuf), &i, sizeof(i)))
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), &ifinfo, sizeof(ifinfo)))
goto buffer_too_small;
rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_LINK,
&ifindex, sizeof(ifindex));
- if (!rta)
- goto buffer_too_small;
-
- if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
goto buffer_too_small;
rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_ADDRESS,
macaddress, macaddrsize);
- if (!rta)
- goto buffer_too_small;
-
- if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
goto buffer_too_small;
if (ifname) {
rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME,
ifname, strlen(ifname) + 1);
- if (!rta)
- goto buffer_too_small;
-
- if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
goto buffer_too_small;
}
rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_LINKINFO, NULL, 0);
- if (!rta)
- goto buffer_too_small;
-
- if (!(li = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
+ if (!rta ||
+ !(li = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
goto buffer_too_small;
rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_INFO_KIND,
type, strlen(type));
- if (!rta)
- goto buffer_too_small;
-
- if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
goto buffer_too_small;
if (macvlan_mode > 0) {
rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_INFO_DATA,
NULL, 0);
- if (!rta)
- goto buffer_too_small;
-
- if (!(rta1 = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
+ if (!rta ||
+ !(rta1 = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
goto buffer_too_small;
rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_MACVLAN_MODE,
&macvlan_mode, sizeof(macvlan_mode));
- if (!rta)
- goto buffer_too_small;
-
- if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
goto buffer_too_small;
rta1->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)rta1;
@@ -312,15 +469,15 @@ link_add(const char *type,
if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
goto malformed_resp;
- switch (-err->error) {
+ switch (err->error) {
case 0:
- break;
+ break;
- case EEXIST:
+ case -EEXIST:
*retry = 1;
rc = -1;
- break;
+ break;
default:
virReportSystemError(-err->error,
@@ -328,10 +485,10 @@ link_add(const char *type,
type);
rc = -1;
}
- break;
+ break;
case NLMSG_DONE:
- break;
+ break;
default:
goto malformed_resp;
@@ -358,14 +515,14 @@ static int
link_del(const char *name)
{
int rc = 0;
- char nlmsgbuf[256];
+ char nlmsgbuf[NLMSGBUF_SIZE];
struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
struct nlmsgerr *err;
- char rtattbuf[64];
+ char rtattbuf[RATTBUF_SIZE];
struct rtattr *rta;
struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
char *recvbuf = NULL;
- int recvbuflen;
+ unsigned int recvbuflen;
memset(&nlmsgbuf, 0, sizeof(nlmsgbuf));
@@ -376,10 +533,7 @@ link_del(const char *name)
rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_IFNAME,
name, strlen(name)+1);
- if (!rta)
- goto buffer_too_small;
-
- if (!nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
goto buffer_too_small;
if (nlComm(nlm, &recvbuf, &recvbuflen) < 0)
@@ -396,20 +550,16 @@ link_del(const char *name)
if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
goto malformed_resp;
- switch (-err->error) {
- case 0:
- break;
-
- default:
+ if (err->error) {
virReportSystemError(-err->error,
_("error destroying %s interface"),
name);
rc = -1;
}
- break;
+ break;
case NLMSG_DONE:
- break;
+ break;
default:
goto malformed_resp;
@@ -509,11 +659,9 @@ macvtapModeFromInt(enum virDomainNetdevM
switch (mode) {
case VIR_DOMAIN_NETDEV_MACVTAP_MODE_PRIVATE:
return MACVLAN_MODE_PRIVATE;
- break;
case VIR_DOMAIN_NETDEV_MACVTAP_MODE_BRIDGE:
return MACVLAN_MODE_BRIDGE;
- break;
case VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA:
default:
@@ -655,8 +803,8 @@ create_name:
}
if (associatePortProfileId(cr_ifname,
+ linkdev,
virtPortProfile,
- -1,
vmuuid) != 0) {
rc = -1;
goto link_del_exit;
@@ -689,6 +837,7 @@ create_name:
disassociate_exit:
disassociatePortProfileId(cr_ifname,
+ linkdev,
virtPortProfile);
link_del_exit:
@@ -701,6 +850,7 @@ link_del_exit:
/**
* delMacvtap:
* @ifname : The name of the macvtap interface
+ * @linkdev: The interface name of the NIC to connect to the external bridge
* @virtPortProfile: pointer to object holding the virtual port profile data
*
* Delete an interface given its name. Disassociate
@@ -709,24 +859,565 @@ link_del_exit:
*/
void
delMacvtap(const char *ifname,
+ const char *linkdev,
virVirtualPortProfileParamsPtr virtPortProfile)
{
if (ifname) {
disassociatePortProfileId(ifname,
+ linkdev,
virtPortProfile);
link_del(ifname);
}
}
-#endif
+# endif
+
+
+# ifdef IFLA_PORT_MAX
+
+static struct nla_policy ifla_policy[IFLA_MAX + 1] =
+{
+ [IFLA_VF_PORTS] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy ifla_vf_ports_policy[IFLA_VF_PORT_MAX + 1] =
+{
+ [IFLA_VF_PORT] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] =
+{
+ [IFLA_PORT_RESPONSE] = { .type = NLA_U16 },
+};
+
+
+static int
+link_dump(bool multicast, int ifindex, struct nlattr **tb, char **recvbuf)
+{
+ int rc = 0;
+ char nlmsgbuf[NLMSGBUF_SIZE] = { 0, };
+ struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
+ struct nlmsgerr *err;
+ struct ifinfomsg ifinfo = {
+ .ifi_family = AF_UNSPEC,
+ .ifi_index = ifindex
+ };
+ unsigned int recvbuflen;
+
+ *recvbuf = NULL;
+
+ nlInit(nlm, NLM_F_REQUEST, RTM_GETLINK);
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), &ifinfo, sizeof(ifinfo)))
+ goto buffer_too_small;
+
+ if (!multicast) {
+ if (nlComm(nlm, recvbuf, &recvbuflen) < 0)
+ return -1;
+ } else {
+ if (nlCommWaitSuccess(nlm, RTMGRP_LINK, recvbuf, &recvbuflen,
+ 5 * MICROSEC_PER_SEC) < 0)
+ return -1;
+ }
+
+ if (recvbuflen < NLMSG_LENGTH(0) || *recvbuf == NULL)
+ goto malformed_resp;
+
+ resp = (struct nlmsghdr *)*recvbuf;
+
+ switch (resp->nlmsg_type) {
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(resp);
+ if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
+ goto malformed_resp;
+
+ if (err->error) {
+ virReportSystemError(-err->error,
+ _("error dumping %d interface"),
+ ifindex);
+ rc = -1;
+ }
+ break;
+
+ case GENL_ID_CTRL:
+ case NLMSG_DONE:
+ if (nlmsg_parse(resp, sizeof(struct ifinfomsg),
+ tb, IFLA_MAX, ifla_policy)) {
+ goto malformed_resp;
+ }
+ break;
+
+ default:
+ goto malformed_resp;
+ }
+
+ if (rc != 0)
+ VIR_FREE(*recvbuf);
+
+ return rc;
+
+malformed_resp:
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed netlink response message"));
+ VIR_FREE(*recvbuf);
+ return -1;
+
+buffer_too_small:
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("internal buffer is too small"));
+ return -1;
+}
+
+
+static int
+getPortProfileStatus(struct nlattr **tb, int32_t vf, uint16_t *status)
+{
+ int rc = 1;
+ const char *msg = NULL;
+ struct nlattr *tb2[IFLA_VF_PORT_MAX + 1],
+ *tb3[IFLA_PORT_MAX+1];
+
+ if (vf == PORT_SELF_VF) {
+ if (tb[IFLA_PORT_SELF]) {
+ if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb[IFLA_PORT_SELF],
+ ifla_port_policy)) {
+ msg = _("error parsing nested IFLA_VF_PORT part");
+ goto err_exit;
+ }
+ }
+ } else {
+ if (tb[IFLA_VF_PORTS]) {
+ if (nla_parse_nested(tb2, IFLA_VF_PORT_MAX, tb[IFLA_VF_PORTS],
+ ifla_vf_ports_policy)) {
+ msg = _("error parsing nested IFLA_VF_PORTS part");
+ goto err_exit;
+ }
+ if (tb2[IFLA_VF_PORT]) {
+ if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb2[IFLA_VF_PORT],
+ ifla_port_policy)) {
+ msg = _("error parsing nested IFLA_VF_PORT part");
+ goto err_exit;
+ }
+ }
+ }
+ }
+
+ if (tb3[IFLA_PORT_RESPONSE]) {
+ *status = *(uint16_t *)RTA_DATA(tb3[IFLA_PORT_RESPONSE]);
+ rc = 0;
+ } else {
+ msg = _("no IFLA_PORT_RESPONSE found in netlink message");
+ goto err_exit;
+ }
+
+err_exit:
+ if (msg)
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s", msg);
+
+ return rc;
+}
+
+
+static int
+doPortProfileOpSetLink(bool multicast,
+ int ifindex,
+ const char *profileId,
+ struct ifla_port_vsi *portVsi,
+ const unsigned char *instanceId,
+ const unsigned char *hostUUID,
+ int32_t vf,
+ uint8_t op)
+{
+ int rc = 0;
+ char nlmsgbuf[NLMSGBUF_SIZE];
+ struct nlmsghdr *nlm = (struct nlmsghdr *)nlmsgbuf, *resp;
+ struct nlmsgerr *err;
+ char rtattbuf[RATTBUF_SIZE];
+ struct rtattr *rta, *vfports = NULL, *vfport;
+ struct ifinfomsg ifinfo = {
+ .ifi_family = AF_UNSPEC,
+ .ifi_index = ifindex,
+ };
+ char *recvbuf = NULL;
+ unsigned int recvbuflen = 0;
+
+ memset(&nlmsgbuf, 0, sizeof(nlmsgbuf));
+
+ nlInit(nlm, NLM_F_REQUEST, RTM_SETLINK);
+
+ if (!nlAppend(nlm, sizeof(nlmsgbuf), &ifinfo, sizeof(ifinfo)))
+ goto buffer_too_small;
+
+ if (vf == PORT_SELF_VF) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_SELF, NULL, 0);
+ } else {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_PORTS, NULL, 0);
+ if (!rta ||
+ !(vfports = nlAppend(nlm, sizeof(nlmsgbuf),
+ rtattbuf, rta->rta_len)))
+ goto buffer_too_small;
+
+ /* begin nesting vfports */
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_VF_PORT, NULL, 0);
+ }
+
+ if (!rta ||
+ !(vfport = nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len)))
+ goto buffer_too_small;
+
+ if (profileId) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_PROFILE,
+ profileId, strlen(profileId) + 1);
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ if (portVsi) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_VSI_TYPE,
+ portVsi, sizeof(*portVsi));
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ if (instanceId) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_INSTANCE_UUID,
+ instanceId, VIR_UUID_BUFLEN);
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ if (hostUUID) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_HOST_UUID,
+ hostUUID, VIR_UUID_BUFLEN);
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ if (vf != PORT_SELF_VF) {
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_VF,
+ &vf, sizeof(vf));
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+ }
+
+ rta = rtattrCreate(rtattbuf, sizeof(rtattbuf), IFLA_PORT_REQUEST,
+ &op, sizeof(op));
+ if (!rta || !nlAppend(nlm, sizeof(nlmsgbuf), rtattbuf, rta->rta_len))
+ goto buffer_too_small;
+
+ /* end nesting of vport */
+ vfport->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)vfport;
+
+ if (vf != PORT_SELF_VF) {
+ /* end nesting of vfports */
+ vfports->rta_len = (char *)nlm + nlm->nlmsg_len - (char *)vfports;
+ }
+
+ if (!multicast) {
+ if (nlComm(nlm, &recvbuf, &recvbuflen) < 0)
+ return -1;
+ } else {
+ if (nlCommWaitSuccess(nlm, RTMGRP_LINK, &recvbuf, &recvbuflen,
+ 5 * MICROSEC_PER_SEC) < 0)
+ return -1;
+ }
+
+ if (recvbuflen < NLMSG_LENGTH(0) || recvbuf == NULL)
+ goto malformed_resp;
+
+ resp = (struct nlmsghdr *)recvbuf;
+
+ switch (resp->nlmsg_type) {
+ case NLMSG_ERROR:
+ err = (struct nlmsgerr *)NLMSG_DATA(resp);
+ if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
+ goto malformed_resp;
+
+ if (err->error) {
+ virReportSystemError(-err->error,
+ _("error during virtual port configuration of ifindex %d"),
+ ifindex);
+ rc = -1;
+ }
+ break;
+
+ case NLMSG_DONE:
+ break;
+
+ default:
+ goto malformed_resp;
+ }
+
+ VIR_FREE(recvbuf);
+
+ return rc;
+
+malformed_resp:
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed netlink response message"));
+ VIR_FREE(recvbuf);
+ return -1;
+
+buffer_too_small:
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("internal buffer is too small"));
+ return -1;
+}
+
+
+static int
+doPortProfileOpCommon(bool multicast,
+ int ifindex,
+ const char *profileId,
+ struct ifla_port_vsi *portVsi,
+ const unsigned char *instanceId,
+ const unsigned char *hostUUID,
+ int32_t vf,
+ uint8_t op)
+{
+ int rc;
+ char *recvbuf = NULL;
+ struct nlattr *tb[IFLA_MAX + 1];
+ int repeats = STATUS_POLL_TIMEOUT_USEC / STATUS_POLL_INTERVL_USEC;
+ uint16_t status = 0;
+
+ rc = doPortProfileOpSetLink(multicast,
+ ifindex,
+ profileId,
+ portVsi,
+ instanceId,
+ hostUUID,
+ vf,
+ op);
+
+ if (rc != 0) {
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("sending of PortProfileRequest failed."));
+ return rc;
+ }
+
+ while (--repeats >= 0) {
+ rc = link_dump(multicast, ifindex, tb, &recvbuf);
+ if (rc)
+ goto err_exit;
+ rc = getPortProfileStatus(tb, vf, &status);
+ if (rc == 0) {
+ if (status == PORT_PROFILE_RESPONSE_SUCCESS ||
+ status == PORT_VDP_RESPONSE_SUCCESS) {
+ break;
+ } else if (status == PORT_PROFILE_RESPONSE_INPROGRESS) {
+ // keep trying...
+ } else {
+ virReportSystemError(EINVAL,
+ _("error %d during port-profile setlink on ifindex %d"),
+ status, ifindex);
+ rc = 1;
+ break;
+ }
+ } else
+ goto err_exit;
+ usleep(STATUS_POLL_INTERVL_USEC);
+
+ VIR_FREE(recvbuf);
+ }
+
+ if (status == PORT_PROFILE_RESPONSE_INPROGRESS) {
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("port-profile setlink timed out"));
+ rc = -ETIMEDOUT;
+ }
+
+err_exit:
+ VIR_FREE(recvbuf);
+
+ return rc;
+}
+
+# endif /* IFLA_PORT_MAX */
+
+static int
+doPortProfileOp8021Qbg(const char *ifname,
+ const virVirtualPortProfileParamsPtr virtPort,
+ enum virVirtualPortOp virtPortOp)
+{
+ int rc;
+
+# ifndef IFLA_VF_PORT_MAX
+
+ (void)ifname;
+ (void)virtPort;
+ (void)virtPortOp;
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Kernel VF Port support was missing at compile time."));
+ rc = 1;
+
+# else /* IFLA_VF_PORT_MAX */
+
+ int op = PORT_REQUEST_ASSOCIATE;
+ struct ifla_port_vsi portVsi = {
+ .vsi_mgr_id = virtPort->u.virtPort8021Qbg.managerID,
+ .vsi_type_version = virtPort->u.virtPort8021Qbg.typeIDVersion,
+ };
+ bool multicast = true;
+ int ifindex;
+
+ if (ifaceGetIndex(true, ifname, &ifindex) != 0) {
+ rc = 1;
+ goto err_exit;
+ }
+
+ portVsi.vsi_type_id[2] = virtPort->u.virtPort8021Qbg.typeID >> 16;
+ portVsi.vsi_type_id[1] = virtPort->u.virtPort8021Qbg.typeID >> 8;
+ portVsi.vsi_type_id[0] = virtPort->u.virtPort8021Qbg.typeID;
+
+ switch (virtPortOp) {
+ case ASSOCIATE:
+ op = PORT_REQUEST_ASSOCIATE;
+ break;
+ case DISASSOCIATE:
+ op = PORT_REQUEST_DISASSOCIATE;
+ break;
+ default:
+ macvtapError(VIR_ERR_INTERNAL_ERROR,
+ _("operation type %d not supported"), op);
+ rc = 1;
+ goto err_exit;
+ }
+
+ rc = doPortProfileOpCommon(multicast, ifindex,
+ NULL,
+ &portVsi,
+ virtPort->u.virtPort8021Qbg.instanceID,
+ NULL,
+ PORT_SELF_VF,
+ op);
+
+err_exit:
+
+# endif /* IFLA_VF_PORT_MAX */
+
+ return rc;
+}
+
+
+# ifdef IFLA_VF_PORT_MAX
+static int
+getPhysfn(const char *linkdev,
+ int32_t *vf,
+ char **physfndev)
+{
+ int rc = 0;
+ bool virtfn = false;
+
+ if (virtfn) {
+
+ // XXX: if linkdev is SR-IOV VF, then set vf = VF index
+ // XXX: and set linkdev = PF device
+ // XXX: need to use get_physical_function_linux() or
+ // XXX: something like that to get PF
+ // XXX: device and figure out VF index
+
+ rc = 1;
+
+ } else {
+
+ /* Not SR-IOV VF: physfndev is linkdev and VF index
+ * refers to linkdev self
+ */
+
+ *vf = PORT_SELF_VF;
+ *physfndev = (char *)linkdev;
+ }
+
+ return rc;
+}
+# endif /* IFLA_VF_PORT_MAX */
+
+static int
+doPortProfileOp8021Qbh(const char *ifname,
+ const virVirtualPortProfileParamsPtr virtPort,
+ const unsigned char *vm_uuid,
+ enum virVirtualPortOp virtPortOp)
+{
+ int rc;
+
+# ifndef IFLA_VF_PORT_MAX
+
+ (void)ifname;
+ (void)virtPort;
+ (void)vm_uuid;
+ (void)virtPortOp;
+ macvtapError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Kernel VF Port support was missing at compile time."));
+ rc = 1;
+
+# else /* IFLA_VF_PORT_MAX */
+
+ char *physfndev;
+ unsigned char hostuuid[VIR_UUID_BUFLEN];
+ int32_t vf;
+ int op = PORT_REQUEST_ASSOCIATE;
+ bool multicast = false;
+ int ifindex;
+
+ rc = virGetHostUUID(hostuuid);
+ if (rc)
+ goto err_exit;
+
+ rc = getPhysfn(ifname, &vf, &physfndev);
+ if (rc)
+ goto err_exit;
+
+ if (ifaceGetIndex(true, physfndev, &ifindex) != 0) {
+ rc = 1;
+ goto err_exit;
+ }
+
+ switch (virtPortOp) {
+ case ASSOCIATE:
+ op = PORT_REQUEST_ASSOCIATE;
+ break;
+ case DISASSOCIATE:
+ op = PORT_REQUEST_DISASSOCIATE;
+ break;
+ default:
+ macvtapError(VIR_ERR_INTERNAL_ERROR,
+ _("operation type %d not supported"), op);
+ rc = 1;
+ goto err_exit;
+ }
+
+ rc = doPortProfileOpCommon(multicast, ifindex,
+ virtPort->u.virtPort8021Qbh.profileID,
+ NULL,
+ vm_uuid,
+ hostuuid,
+ vf,
+ op);
+
+ switch (virtPortOp) {
+ case ASSOCIATE:
+ ifaceUp(ifname);
+ break;
+ case DISASSOCIATE:
+ ifaceDown(ifname);
+ break;
+ }
+
+err_exit:
+
+# endif /* IFLA_VF_PORT_MAX */
+
+ return rc;
+}
/**
* associatePortProfile
*
* @macvtap_ifname: The name of the macvtap device
+ * @linkdev: The link device in case of macvtap
* @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
@@ -740,15 +1431,14 @@ delMacvtap(const char *ifname,
*/
static int
associatePortProfileId(const char *macvtap_ifname,
+ const char *linkdev,
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:
@@ -756,11 +1446,14 @@ associatePortProfileId(const char *macvt
break;
case VIR_VIRTUALPORT_8021QBG:
-
+ rc = doPortProfileOp8021Qbg(macvtap_ifname, virtPort,
+ ASSOCIATE);
break;
case VIR_VIRTUALPORT_8021QBH:
-
+ rc = doPortProfileOp8021Qbh(linkdev, virtPort,
+ vmuuid,
+ ASSOCIATE);
break;
}
@@ -772,6 +1465,7 @@ associatePortProfileId(const char *macvt
* disassociatePortProfile
*
* @macvtap_ifname: The name of the macvtap device
+ * @linkdev: The link device in case of macvtap
* @virtPort: point to object holding port profile parameters
*
* Returns 0 in case of success, != 0 otherwise with error
@@ -779,9 +1473,11 @@ associatePortProfileId(const char *macvt
*/
static int
disassociatePortProfileId(const char *macvtap_ifname,
+ const char *linkdev,
const virVirtualPortProfileParamsPtr virtPort)
{
int rc = 0;
+
VIR_DEBUG("Disassociating port profile id '%p' on link device '%s' ",
virtPort, macvtap_ifname);
@@ -791,13 +1487,18 @@ disassociatePortProfileId(const char *ma
break;
case VIR_VIRTUALPORT_8021QBG:
-
+ rc = doPortProfileOp8021Qbg(macvtap_ifname, virtPort,
+ DISASSOCIATE);
break;
case VIR_VIRTUALPORT_8021QBH:
-
+ rc = doPortProfileOp8021Qbh(linkdev, virtPort,
+ NULL,
+ DISASSOCIATE);
break;
}
return rc;
}
+
+#endif
Index: libvirt-acl/src/util/macvtap.h
===================================================================
--- libvirt-acl.orig/src/util/macvtap.h
+++ libvirt-acl/src/util/macvtap.h
@@ -72,6 +72,7 @@ int openMacvtapTap(const char *ifname,
char **res_ifname);
void delMacvtap(const char *ifname,
+ const char *linkdev,
virVirtualPortProfileParamsPtr virtPortProfile);
# endif /* WITH_MACVTAP */
3
2
25 May '10
Currently all host audio backends are disabled if a VM is using VNC, in
favor of the QEMU VNC audio extension. Unfortunately no released VNC
client supports this extension, so users have no way of getting audio
to work if using VNC.
Add a new config option in qemu.conf which allows changing libvirt's
behavior, but keep the default intact.
Signed-off-by: Cole Robinson <crobinso(a)redhat.com>
---
src/qemu/qemu.conf | 10 ++++++++++
src/qemu/qemu_conf.c | 17 ++++++++++++-----
src/qemu/qemu_conf.h | 2 ++
3 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 3da332f..fec946d 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -168,3 +168,13 @@
# be assigned to guests.
#
# relaxed_acs_check = 1
+
+
+# QEMU implements anextension for providing audio over a VNC connection,
+# though if your VNC client does not support it, your only chance for getting
+# sound output is through regular audio backends. By default, libvirt will
+# disable all QEMU sound backends if using VNC, since they can cause
+# permissions issues. Enabling this option will make libvirtd honor the
+# QEMU_AUDIO_DRV environment variable when using VNC.
+#
+# vnc_enable_audio_backend = 0
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index d7bc798..5c30f48 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -351,6 +351,10 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
CHECK_TYPE ("relaxed_acs_check", VIR_CONF_LONG);
if (p) driver->relaxedACS = p->l;
+ p = virConfGetValue (conf, "vnc_enable_audio_backend");
+ CHECK_TYPE ("vnc_enable_audio_backend", VIR_CONF_LONG);
+ if (p) driver->vncEnableAudioBackend = p->l;
+
virConfFree (conf);
return 0;
}
@@ -4394,12 +4398,15 @@ int qemudBuildCommandLine(virConnectPtr conn,
ADD_ARG_LIT(def->graphics[0]->data.vnc.keymap);
}
- /* QEMU implements a VNC extension for providing audio, so we
- * set the audio backend to none, to prevent it opening the
- * host OS audio devices since that causes security issues
- * and is non-sensical when using VNC.
+ /* Unless user requested it, set the audio backend to none, to
+ * prevent it opening the host OS audio devices since that causes
+ * security issues and is may not work when using VNC.
*/
- ADD_ENV_LIT("QEMU_AUDIO_DRV=none");
+ if (driver->vncEnableAudioBackend) {
+ ADD_ENV_COPY("QEMU_AUDIO_DRV");
+ } else {
+ ADD_ENV_LIT("QEMU_AUDIO_DRV=none");
+ }
} else if ((def->ngraphics == 1) &&
def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
char *xauth = NULL;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 11f8dcd..aa6ed61 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -137,6 +137,8 @@ struct qemud_driver {
unsigned int relaxedACS : 1;
+ unsigned int vncEnableAudioBackend : 1;
+
virCapsPtr caps;
/* An array of callbacks */
--
1.6.6.1
3
7