[libvirt] [PATCH] Don't reset user/group/security label on shared filesystems during migrate
by Daniel P. Berrange
When QEMU runs with its disk on NFS, and as a non-root user, the
disk is chownd to that non-root user. When migration completes
the last step is shutting down the QEMU on the source host. THis
normally resets user/group/security label. This is bad when the
VM was just migrated because the file is still in use on the dest
host. It is thus neccessary to skip the reset step for any files
found to be on a shared filesystem
* src/libvirt_private.syms: Export virStorageFileIsSharedFS
* src/util/storage_file.c, src/util/storage_file.h: Add a new
method virStorageFileIsSharedFS() to determine if a file is
on a shared filesystem (NFS, GFS, OCFS2, etc)
* src/qemu/qemu_driver.c: Tell security driver not to reset
disk labels on migration completion
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c,
src/security/security_selinux.c, src/security/security_driver.h,
src/security/security_apparmor.c: Add ability to skip disk
restore step for files on shared filesystems.
---
src/libvirt_private.syms | 1 +
src/qemu/qemu_driver.c | 34 ++++++++++++++-----------
src/qemu/qemu_security_dac.c | 40 +++++++++++++++++++++++++----
src/qemu/qemu_security_stacked.c | 7 +++--
src/security/security_apparmor.c | 3 +-
src/security/security_driver.h | 3 +-
src/security/security_selinux.c | 38 +++++++++++++++++++++++++----
src/util/storage_file.c | 50 ++++++++++++++++++++++++++++++++++++++
src/util/storage_file.h | 2 +
9 files changed, 147 insertions(+), 31 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5713b2c..7d7ee14 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -617,6 +617,7 @@ virStorageFileFormatTypeToString;
virStorageFileFormatTypeFromString;
virStorageFileGetMetadata;
virStorageFileGetMetadataFromFD;
+virStorageFileIsSharedFS;
# threads.h
virMutexInit;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b478464..702a652 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -174,7 +174,8 @@ static int qemudStartVMDaemon(virConnectPtr conn,
int stdin_fd);
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
- virDomainObjPtr vm);
+ virDomainObjPtr vm,
+ int migrated);
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
@@ -1105,7 +1106,7 @@ qemuHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
VIR_DOMAIN_EVENT_STOPPED_FAILED :
VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
- qemudShutdownVMDaemon(driver, vm);
+ qemudShutdownVMDaemon(driver, vm, 0);
if (!vm->persistent)
virDomainRemoveInactive(&driver->domains, vm);
else
@@ -1636,7 +1637,7 @@ error:
/* We can't get the monitor back, so must kill the VM
* to remove danger of it ending up running twice if
* user tries to start it again later */
- qemudShutdownVMDaemon(driver, obj);
+ qemudShutdownVMDaemon(driver, obj, 0);
if (!obj->persistent)
virDomainRemoveInactive(&driver->domains, obj);
else
@@ -4009,7 +4010,7 @@ cleanup:
if (driver->securityDriver &&
driver->securityDriver->domainRestoreSecurityAllLabel)
- driver->securityDriver->domainRestoreSecurityAllLabel(vm);
+ driver->securityDriver->domainRestoreSecurityAllLabel(vm, 0);
if (driver->securityDriver &&
driver->securityDriver->domainReleaseSecurityLabel)
driver->securityDriver->domainReleaseSecurityLabel(vm);
@@ -4032,7 +4033,7 @@ cleanup:
abort:
/* We jump here if we failed to initialize the now running VM
* killing it off and pretend we never started it */
- qemudShutdownVMDaemon(driver, vm);
+ qemudShutdownVMDaemon(driver, vm, 0);
if (logfile != -1)
close(logfile);
@@ -4042,7 +4043,8 @@ abort:
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
- virDomainObjPtr vm) {
+ virDomainObjPtr vm,
+ int migrated) {
int ret;
int retries = 0;
qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -4053,7 +4055,7 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver,
if (!virDomainObjIsActive(vm))
return;
- VIR_DEBUG("Shutting down VM '%s'", vm->def->name);
+ VIR_DEBUG("Shutting down VM '%s' migrated=%d", vm->def->name, migrated);
/* This method is routinely used in clean up paths. Disable error
* reporting so we don't squash a legit error. */
@@ -4111,7 +4113,7 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver,
/* Reset Security Labels */
if (driver->securityDriver &&
driver->securityDriver->domainRestoreSecurityAllLabel)
- driver->securityDriver->domainRestoreSecurityAllLabel(vm);
+ driver->securityDriver->domainRestoreSecurityAllLabel(vm, migrated);
if (driver->securityDriver &&
driver->securityDriver->domainReleaseSecurityLabel)
driver->securityDriver->domainReleaseSecurityLabel(vm);
@@ -4835,7 +4837,7 @@ static int qemudDomainDestroy(virDomainPtr dom) {
goto endjob;
}
- qemudShutdownVMDaemon(driver, vm);
+ qemudShutdownVMDaemon(driver, vm, 0);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
@@ -5546,7 +5548,7 @@ static int qemudDomainSaveFlag(virDomainPtr dom, const char *path,
ret = 0;
/* Shut it down */
- qemudShutdownVMDaemon(driver, vm);
+ qemudShutdownVMDaemon(driver, vm, 0);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_SAVED);
@@ -5856,7 +5858,7 @@ static int qemudDomainCoreDump(virDomainPtr dom,
endjob:
if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
- qemudShutdownVMDaemon(driver, vm);
+ qemudShutdownVMDaemon(driver, vm, 0);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_CRASHED);
@@ -10365,7 +10367,7 @@ qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
qemust = qemuStreamMigOpen(st, unixfile);
if (qemust == NULL) {
- qemudShutdownVMDaemon(driver, vm);
+ qemudShutdownVMDaemon(driver, vm, 0);
if (!vm->persistent) {
if (qemuDomainObjEndJob(vm) > 0)
virDomainRemoveInactive(&driver->domains, vm);
@@ -11093,7 +11095,9 @@ qemudDomainMigratePerform (virDomainPtr dom,
}
/* Clean up the source domain. */
- qemudShutdownVMDaemon(driver, vm);
+ fprintf(stderr, "******************* MIG \n");
+ qemudShutdownVMDaemon(driver, vm, 1);
+ fprintf(stderr, "******************* YEEHAAA\n");
resume = 0;
event = virDomainEventNewFromObj(vm,
@@ -11235,7 +11239,7 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
}
virDomainSaveStatus(driver->caps, driver->stateDir, vm);
} else {
- qemudShutdownVMDaemon(driver, vm);
+ qemudShutdownVMDaemon(driver, vm, 0);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_FAILED);
@@ -12081,7 +12085,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
*/
if (virDomainObjIsActive(vm)) {
- qemudShutdownVMDaemon(driver, vm);
+ qemudShutdownVMDaemon(driver, vm, 0);
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
index e408dbf..2d42ce2 100644
--- a/src/qemu/qemu_security_dac.c
+++ b/src/qemu/qemu_security_dac.c
@@ -142,8 +142,9 @@ qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
static int
-qemuSecurityDACRestoreSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
- virDomainDiskDefPtr disk)
+qemuSecurityDACRestoreSecurityImageLabelInt(virDomainObjPtr vm ATTRIBUTE_UNUSED,
+ virDomainDiskDefPtr disk,
+ int migrated)
{
if (!driver->privileged || !driver->dynamicOwnership)
return 0;
@@ -162,11 +163,35 @@ qemuSecurityDACRestoreSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
if (!disk->src)
return 0;
+ /* If we have a shared FS & doing migrated, we must not
+ * change ownership, because that kills access on the
+ * destination host which is sub-optimal for the guest
+ * VM's I/O attempts :-)
+ */
+ if (migrated) {
+ int rc = virStorageFileIsSharedFS(disk->src);
+ if (rc < 0)
+ return -1;
+ if (rc == 1) {
+ VIR_DEBUG("Skipping image label restore on %s because FS is shared",
+ disk->src);
+ return 0;
+ }
+ }
+
return qemuSecurityDACRestoreSecurityFileLabel(disk->src);
}
static int
+qemuSecurityDACRestoreSecurityImageLabel(virDomainObjPtr vm,
+ virDomainDiskDefPtr disk)
+{
+ return qemuSecurityDACRestoreSecurityImageLabelInt(vm, disk, 0);
+}
+
+
+static int
qemuSecurityDACSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
const char *file,
void *opaque ATTRIBUTE_UNUSED)
@@ -306,7 +331,8 @@ done:
static int
-qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm)
+qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
+ int migrated)
{
int i;
int rc = 0;
@@ -314,7 +340,8 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm)
if (!driver->privileged || !driver->dynamicOwnership)
return 0;
- VIR_DEBUG("Restoring security label on %s", vm->def->name);
+ VIR_DEBUG("Restoring security label on %s migrated=%d",
+ vm->def->name, migrated);
for (i = 0 ; i < vm->def->nhostdevs ; i++) {
if (qemuSecurityDACRestoreSecurityHostdevLabel(vm,
@@ -322,8 +349,9 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm)
rc = -1;
}
for (i = 0 ; i < vm->def->ndisks ; i++) {
- if (qemuSecurityDACRestoreSecurityImageLabel(vm,
- vm->def->disks[i]) < 0)
+ if (qemuSecurityDACRestoreSecurityImageLabelInt(vm,
+ vm->def->disks[i],
+ migrated) < 0)
rc = -1;
}
diff --git a/src/qemu/qemu_security_stacked.c b/src/qemu/qemu_security_stacked.c
index c0258ce..04c1f10 100644
--- a/src/qemu/qemu_security_stacked.c
+++ b/src/qemu/qemu_security_stacked.c
@@ -215,18 +215,19 @@ qemuSecurityStackedSetSecurityAllLabel(virDomainObjPtr vm)
static int
-qemuSecurityStackedRestoreSecurityAllLabel(virDomainObjPtr vm)
+qemuSecurityStackedRestoreSecurityAllLabel(virDomainObjPtr vm,
+ int migrated)
{
int rc = 0;
if (driver->securitySecondaryDriver &&
driver->securitySecondaryDriver->domainRestoreSecurityAllLabel &&
- driver->securitySecondaryDriver->domainRestoreSecurityAllLabel(vm) < 0)
+ driver->securitySecondaryDriver->domainRestoreSecurityAllLabel(vm, migrated) < 0)
rc = -1;
if (driver->securityPrimaryDriver &&
driver->securityPrimaryDriver->domainRestoreSecurityAllLabel &&
- driver->securityPrimaryDriver->domainRestoreSecurityAllLabel(vm) < 0)
+ driver->securityPrimaryDriver->domainRestoreSecurityAllLabel(vm, migrated) < 0)
rc = -1;
return rc;
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index c0c91cc..87f8a1b 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -444,7 +444,8 @@ AppArmorReleaseSecurityLabel(virDomainObjPtr vm)
static int
-AppArmorRestoreSecurityAllLabel(virDomainObjPtr vm)
+AppArmorRestoreSecurityAllLabel(virDomainObjPtr vm,
+ int migrated ATTRIBUTE_UNUSED)
{
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
int rc = 0;
diff --git a/src/security/security_driver.h b/src/security/security_driver.h
index 3de234a..39edc6d 100644
--- a/src/security/security_driver.h
+++ b/src/security/security_driver.h
@@ -46,7 +46,8 @@ typedef int (*virSecurityDomainGenLabel) (virDomainObjPtr sec);
typedef int (*virSecurityDomainReserveLabel) (virDomainObjPtr sec);
typedef int (*virSecurityDomainReleaseLabel) (virDomainObjPtr sec);
typedef int (*virSecurityDomainSetAllLabel) (virDomainObjPtr sec);
-typedef int (*virSecurityDomainRestoreAllLabel) (virDomainObjPtr vm);
+typedef int (*virSecurityDomainRestoreAllLabel) (virDomainObjPtr vm,
+ int migrated);
typedef int (*virSecurityDomainGetProcessLabel) (virDomainObjPtr vm,
virSecurityLabelPtr sec);
typedef int (*virSecurityDomainSetProcessLabel) (virSecurityDriverPtr drv,
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 1aabb20..47534df 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -385,8 +385,9 @@ err:
}
static int
-SELinuxRestoreSecurityImageLabel(virDomainObjPtr vm,
- virDomainDiskDefPtr disk)
+SELinuxRestoreSecurityImageLabelInt(virDomainObjPtr vm,
+ virDomainDiskDefPtr disk,
+ int migrated)
{
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
@@ -407,9 +408,34 @@ SELinuxRestoreSecurityImageLabel(virDomainObjPtr vm,
if (!disk->src)
return 0;
+ /* If we have a shared FS & doing migrated, we must not
+ * change ownership, because that kills access on the
+ * destination host which is sub-optimal for the guest
+ * VM's I/O attempts :-)
+ */
+ if (migrated) {
+ int rc = virStorageFileIsSharedFS(disk->src);
+ if (rc < 0)
+ return -1;
+ if (rc == 1) {
+ VIR_DEBUG("Skipping image label restore on %s because FS is shared",
+ disk->src);
+ return 0;
+ }
+ }
+
return SELinuxRestoreSecurityFileLabel(disk->src);
}
+
+static int
+SELinuxRestoreSecurityImageLabel(virDomainObjPtr vm,
+ virDomainDiskDefPtr disk)
+{
+ return SELinuxRestoreSecurityImageLabelInt(vm, disk, 0);
+}
+
+
static int
SELinuxSetSecurityImageLabel(virDomainObjPtr vm,
virDomainDiskDefPtr disk)
@@ -603,7 +629,8 @@ done:
}
static int
-SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm)
+SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm,
+ int migrated ATTRIBUTE_UNUSED)
{
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
int i;
@@ -619,8 +646,9 @@ SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm)
rc = -1;
}
for (i = 0 ; i < vm->def->ndisks ; i++) {
- if (SELinuxRestoreSecurityImageLabel(vm,
- vm->def->disks[i]) < 0)
+ if (SELinuxRestoreSecurityImageLabelInt(vm,
+ vm->def->disks[i],
+ migrated) < 0)
rc = -1;
}
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index 76ebb98..d4aad86 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -26,9 +26,14 @@
#include <unistd.h>
#include <fcntl.h>
+#ifdef __linux__
+#include <linux/magic.h>
+#include <sys/statfs.h>
+#endif
#include "dirname.h"
#include "memory.h"
#include "virterror_internal.h"
+#include "logging.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -407,3 +412,48 @@ virStorageFileGetMetadata(const char *path,
return ret;
}
+
+
+#ifdef __linux__
+
+#ifndef OCFS2_SUPER_MAGIC
+#define OCFS2_SUPER_MAGIC 0x7461636f
+#endif
+#ifndef GFS2_MAGIC
+#define GFS2_MAGIC 0x01161970
+#endif
+#ifndef AFS_FS_MAGIC
+#define AFS_FS_MAGIC 0x6B414653
+#endif
+
+
+int virStorageFileIsSharedFS(const char *path)
+{
+ struct statfs sb;
+
+ if (statfs(path, &sb) < 0) {
+ virReportSystemError(errno,
+ _("cannot determine filesystem for '%s'"),
+ path);
+ return -1;
+ }
+
+ VIR_DEBUG("Check if path %s with FS magic %lld is shared",
+ path, (long long int)sb.f_type);
+
+ if (sb.f_type == NFS_SUPER_MAGIC ||
+ sb.f_type == GFS2_MAGIC ||
+ sb.f_type == OCFS2_SUPER_MAGIC ||
+ sb.f_type == AFS_FS_MAGIC) {
+ return 1;
+ }
+
+ return 0;
+}
+#else
+int virStorageFileIsSharedFS(const char *path ATTRIBUTE_UNUSED)
+{
+ /* XXX implement me :-) */
+ return 0;
+}
+#endif
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
index c761dc6..58533ee 100644
--- a/src/util/storage_file.h
+++ b/src/util/storage_file.h
@@ -61,4 +61,6 @@ int virStorageFileGetMetadataFromFD(const char *path,
int fd,
virStorageFileMetadata *meta);
+int virStorageFileIsSharedFS(const char *path);
+
#endif /* __VIR_STORAGE_FILE_H__ */
--
1.6.6.1
14 years, 7 months
[libvirt] [PATCH] nwfilter: Add missing driver lock in qemu driver
by Stefan Berger
This adds a missing driver lock in the qemu driver to protect
the list of domains.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
src/qemu/qemu_driver.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -11869,11 +11869,15 @@ static virStateDriver qemuStateDriver =
};
static int
-qemudVMFilterRebuild(virConnectPtr conn,
+qemudVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
virHashIterator iter, void *data)
{
- (void)conn;
+ struct qemud_driver *driver = qemu_driver;
+
+ qemuDriverLock(driver);
virHashForEach(qemu_driver->domains.objs, iter, data);
+ qemuDriverUnlock(driver);
+
return 0;
}
14 years, 7 months
[libvirt] [PATCH] qemudDomainSetVcpus: avoid NULL-deref
by Jim Meyering
Here's a patch for a coverity-spotted bug:
>From 12160fa54bc948e5de3fecff6a9552995e9595b0 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering(a)redhat.com>
Date: Fri, 14 May 2010 12:38:43 +0200
Subject: [PATCH] qemudDomainSetVcpus: avoid NULL-deref
* src/qemu/qemu_driver.c (qemudDomainSetVcpus): Avoid NULL-deref
upon unknown UUID. Call qemuDomainObjBeginJob(vm) only after
ensuring that vm != NULL, not before. This potential NULL-deref
was introduced by commit 2c555d87b0041e0d1ec4742386d2161d1b2f0600.
---
src/qemu/qemu_driver.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index bb1079e..cbddb96 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5410,9 +5410,6 @@ static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
qemuDriverUnlock(driver);
- if (qemuDomainObjBeginJob(vm) < 0)
- goto cleanup;
-
if (!vm) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(dom->uuid, uuidstr);
@@ -5421,6 +5418,9 @@ static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
goto endjob;
}
+ if (qemuDomainObjBeginJob(vm) < 0)
+ goto cleanup;
+
if (!virDomainObjIsActive(vm)) {
qemuReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("domain is not running"));
--
1.7.1.460.gf3c4c
14 years, 7 months
[libvirt] [PATCH] Fix a misuse of virAsprintf in qemudDomainMemoryPeek
by Ryota Ozaki
The code specifies driver->cacheDir as the format string,
but it usually doesn't contain '%s', so the subsequent
argument, "/qemu.mem.XXXXXX", is always ignored.
The patch fixes the misuse.
---
src/qemu/qemu_driver.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index bb1079e..843f827 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9033,7 +9033,7 @@ qemudDomainMemoryPeek (virDomainPtr dom,
goto endjob;
}
- if (virAsprintf(&tmp, driver->cacheDir, "/qemu.mem.XXXXXX") < 0) {
+ if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", driver->cacheDir) < 0) {
virReportOOMError();
goto endjob;
}
--
1.6.5.2
14 years, 7 months
[libvirt] [PATCH] Query block allocation extent from QEMU monitor
by Daniel P. Berrange
The virDomainGetBlockInfo API allows query physical block
extent and allocated block extent. These are normally the
same value unless storing a special format like qcow2
inside a block device. In this scenario we can query QEMU
to get the actual allocated extent.
* src/qemu/qemu_driver.c: Fill in block aloction extent when VM
is running
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h,
src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h: Add
API to query the highest block extent via info blockstats
---
src/qemu/qemu_driver.c | 32 +++++++++++---
src/qemu/qemu_monitor.c | 16 +++++++
src/qemu/qemu_monitor.h | 4 ++
src/qemu/qemu_monitor_json.c | 97 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 3 +
src/qemu/qemu_monitor_text.c | 12 +++++
src/qemu/qemu_monitor_text.h | 4 +-
7 files changed, 160 insertions(+), 8 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5089129..4251a66 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9651,6 +9651,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
int fd = -1;
off_t end;
virStorageFileMetadata meta;
+ virDomainDiskDefPtr disk = NULL;
struct stat sb;
int i;
@@ -9677,19 +9678,17 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
for (i = 0 ; i < vm->def->ndisks ; i++) {
if (vm->def->disks[i]->src != NULL &&
STREQ (vm->def->disks[i]->src, path)) {
- ret = 0;
+ disk = vm->def->disks[i];
break;
}
}
- if (ret != 0) {
+ if (!disk) {
qemuReportError(VIR_ERR_INVALID_ARG,
_("invalid path %s not assigned to domain"), path);
goto cleanup;
}
- ret = -1;
-
/* The path is correct, now try to open it and get its size. */
fd = open (path, O_RDONLY);
if (fd == -1) {
@@ -9740,11 +9739,30 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
if (meta.capacity)
info->capacity = meta.capacity;
- /* XXX allocation will need to be pulled from QEMU for
- * the qcow inside LVM case */
+ /* Set default value .. */
info->allocation = info->physical;
- ret = 0;
+ /* ..but if guest is running & not using raw
+ disk format and on a block device, then query
+ highest allocated extent from QEMU */
+ if (virDomainObjIsActive(vm) &&
+ meta.format != VIR_STORAGE_FILE_RAW &&
+ S_ISBLK(sb.st_mode)) {
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ if (qemuDomainObjBeginJob(vm) < 0)
+ goto cleanup;
+
+ qemuDomainObjEnterMonitor(vm);
+ ret = qemuMonitorGetBlockExtent(priv->mon,
+ disk->info.alias,
+ &info->allocation);
+ qemuDomainObjExitMonitor(vm);
+
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
+ } else {
+ ret = 0;
+ }
cleanup:
if (fd != -1)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index f77ec44..4a77f39 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1000,6 +1000,22 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorGetBlockExtent(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned long long *extent)
+{
+ int ret;
+ DEBUG("mon=%p, fd=%d, devname=%p",
+ mon, mon->fd, devname);
+
+ if (mon->json)
+ ret = qemuMonitorJSONGetBlockExtent(mon, devname, extent);
+ else
+ ret = qemuMonitorTextGetBlockExtent(mon, devname, extent);
+
+ return ret;
+}
+
int qemuMonitorSetVNCPassword(qemuMonitorPtr mon,
const char *password)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 7b1589e..adfb3bc 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -185,6 +185,10 @@ int qemuMonitorGetBlockStatsInfo(qemuMonitorPtr mon,
long long *wr_bytes,
long long *errs);
+int qemuMonitorGetBlockExtent(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned long long *extent);
+
int qemuMonitorSetVNCPassword(qemuMonitorPtr mon,
const char *password);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 6d8f328..a15609c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1186,6 +1186,103 @@ cleanup:
}
+int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned long long *extent)
+{
+ int ret;
+ int i;
+ int found = 0;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-blockstats",
+ NULL);
+ virJSONValuePtr reply = NULL;
+ virJSONValuePtr devices;
+
+ *extent = 0;
+
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0) {
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+ if (ret < 0)
+ goto cleanup;
+ }
+ ret = -1;
+
+ devices = virJSONValueObjectGet(reply, "return");
+ if (!devices || devices->type != VIR_JSON_TYPE_ARRAY) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats reply was missing device list"));
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < virJSONValueArraySize(devices) ; i++) {
+ virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
+ virJSONValuePtr stats;
+ virJSONValuePtr parent;
+ const char *thisdev;
+ if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats device entry was not in expected format"));
+ goto cleanup;
+ }
+
+ if ((thisdev = virJSONValueObjectGetString(dev, "device")) == NULL) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats device entry was not in expected format"));
+ goto cleanup;
+ }
+
+ /* New QEMU has separate names for host & guest side of the disk
+ * and libvirt gives the host side a 'drive-' prefix. The passed
+ * in devname is the guest side though
+ */
+ if (STRPREFIX(thisdev, QEMU_DRIVE_HOST_PREFIX))
+ thisdev += strlen(QEMU_DRIVE_HOST_PREFIX);
+
+ if (STRNEQ(thisdev, devname))
+ continue;
+
+ found = 1;
+ if ((parent = virJSONValueObjectGet(dev, "parent")) == NULL ||
+ parent->type != VIR_JSON_TYPE_OBJECT) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats parent entry was not in expected format"));
+ goto cleanup;
+ }
+
+ if ((stats = virJSONValueObjectGet(parent, "stats")) == NULL ||
+ stats->type != VIR_JSON_TYPE_OBJECT) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("blockstats stats entry was not in expected format"));
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectGetNumberUlong(stats, "wr_highest_offset", extent) < 0) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s statistic"),
+ "wr_highest_offset");
+ goto cleanup;
+ }
+ }
+
+ if (!found) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot find statistics for device '%s'"), devname);
+ goto cleanup;
+ }
+ ret = 0;
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
const char *password)
{
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 26fc865..14597f4 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -56,6 +56,9 @@ int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
long long *wr_req,
long long *wr_bytes,
long long *errs);
+int qemuMonitorJSONGetBlockExtent(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned long long *extent);
int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index d725d6d..19038d1 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -711,6 +711,18 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
}
+int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ const char *devname ATTRIBUTE_UNUSED,
+ unsigned long long *extent)
+{
+ /* Not supported in text monitor, but we don't want to
+ * cause an error in callers in this scenario, just
+ * fallback to marking the data unavailable */
+ *extent = 0;
+ return 0;
+}
+
+
static int
qemuMonitorSendVNCPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
qemuMonitorMessagePtr msg,
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 2a62c7e..6fb7d7a 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -55,7 +55,9 @@ int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
long long *wr_req,
long long *wr_bytes,
long long *errs);
-
+int qemuMonitorTextGetBlockExtent(qemuMonitorPtr mon,
+ const char *devname,
+ unsigned long long *extent);
int qemuMonitorTextSetVNCPassword(qemuMonitorPtr mon,
const char *password);
--
1.6.6.1
14 years, 7 months
[libvirt] CAP_SYS_RAWIO missing for qemu-kvm device passthrough
by Gerd v. Egidy
Hi,
I'm running current git libvirt on Fedora 13 beta. I enabled the use of
libcap-ng as it is done in the regular F13 .spec.
When I now pass a pci card through to a qemu-kvm guest using vt-d I get this
error from qemu-kvm:
Failed to assign irq for "hostdev0": Operation not permitted
Perhaps you are assigning a device that shares an IRQ with another device?
I'm running qemu-kvm as root. But that doesn't seem to be enough:
I traced the issue down to a missing CAP_SYS_RAWIO.The kvm kernel module
requires CAP_SYS_RAWIO to use the KVM_ASSIGN_DEV_IRQ ioctl.
When I remove the capability-dropping from libvirt like this everything works
as expected:
--- libvirt/src/qemu/qemu_driver.c 2010-05-13 22:50:13.000000000 +0200
+++ libvirt.new/src/qemu/qemu_driver.c 2010-05-13 23:18:49.286311290 +0200
@@ -3359,7 +3359,7 @@
ret = virExecDaemonize(argv, progenv, &keepfd, &child,
stdin_fd, &logfile, &logfile,
- VIR_EXEC_NONBLOCK | VIR_EXEC_CLEAR_CAPS,
+ VIR_EXEC_NONBLOCK,
qemudSecurityHook, &hookData,
pidfile);
VIR_FREE(pidfile);
Is there a better solution to get device passthrough to work?
Kind regards,
Gerd
14 years, 7 months
[libvirt] libvirt-java
by Stephen Shaw
I was wondering how long it usually takes for the java bindings to be
updated to the latest version of libvirt. I'm interested in the newer
kvm snapshotting features specifically.
Thanks,
Stephen
14 years, 7 months
[libvirt] [PATCH] Make domain save work when dynamic_ownership=0
by Daniel P. Berrange
Setting dynamic_ownership=0 in /etc/libvirt/qemu.conf prevents
libvirt's DAC security driver from setting uid/gid on disk
files when starting/stopping QEMU, allowing the admin to manage
this manually. As a side effect it also stopped setting of
uid/gid when saving guests to a file, which completely breaks
save when QEMU is running non-root. Thus saved state labelling
code must ignore the dynamic_ownership parameter
* src/qemu/qemu_security_dac.c: Ignore dynamic_ownership=0 when
doing save/restore image labelling
---
src/qemu/qemu_security_dac.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
index 2d42ce2..364227d 100644
--- a/src/qemu/qemu_security_dac.c
+++ b/src/qemu/qemu_security_dac.c
@@ -407,7 +407,7 @@ static int
qemuSecurityDACSetSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
const char *savefile)
{
- if (!driver->privileged || !driver->dynamicOwnership)
+ if (!driver->privileged)
return 0;
return qemuSecurityDACSetOwnership(savefile, driver->user, driver->group);
@@ -418,7 +418,7 @@ static int
qemuSecurityDACRestoreSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
const char *savefile)
{
- if (!driver->privileged || !driver->dynamicOwnership)
+ if (!driver->privileged)
return 0;
return qemuSecurityDACRestoreSecurityFileLabel(savefile);
--
1.6.6.1
14 years, 7 months
[libvirt] [PATCH v3] vepa: parsing for 802.1Qb{g|h} XML
by Stefan Berger
Below is David Alan's original patch with lots of changes.
In particular, it now parses the following two XML descriptions, one
for 802.1Qbg and 802.1Qbh and stored the data internally. The actual
triggering of the switch setup protocol has not been implemented
here but the relevant code to do that should go into the functions
associatePortProfileId() and disassociatePortProfileId().
<interface type='direct'>
<source dev='static' mode='vepa'/>
<model type='virtio'/>
<vsi type='802.1Qbg'>
<parameters managerid='12' typeid='0x123456' typeidversion='1'
instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
</vsi>
<filterref filter='clean-traffic'/>
</interface>
<interface type='direct'>
<source dev='static' mode='vepa'/>
<model type='virtio'/>
<vsi type='802.1Qbh'>
<parameters profileid='my_profile'/>
</vsi>
</interface>
I'd suggest to use this patch as a base for triggering the setup
protocol with the 802.1Qb{g|h} switch.
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 | 155 +++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 35 +++++++
src/qemu/qemu_conf.c | 17 +--
src/qemu/qemu_conf.h | 5 -
src/qemu/qemu_driver.c | 17 +--
src/util/macvtap.c | 150 ++++++++++++++++++++++++++++---
src/util/macvtap.h | 10 +-
tests/domainschemadata/portprofile.xml | 36 +++++++
9 files changed, 446 insertions(+), 48 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="vsiProfile"/>
+ </optional>
<ref name="interface-options"/>
</interleave>
</group>
@@ -902,6 +905,45 @@
</optional>
</interleave>
</define>
+ <define name="vsiProfile">
+ <choice>
+ <group>
+ <element name="vsi">
+ <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="vsi">
+ <attribute name="type">
+ <value>802.1Qbh</value>
+ </attribute>
+ <element name="parameters">
+ <attribute name="profileid">
+ <ref name="vsiProfileID"/>
+ </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="vsiProfileID">
+ <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(virVSI, VIR_VSI_TYPE_LAST,
+ "none",
+ "802.1Qbg",
+ "802.1Qbh")
+
VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
"utc",
"localtime",
@@ -1807,6 +1812,145 @@ isValidIfname(const char *ifname) {
}
+static void
+virVSIProfileDefParseXML(xmlNodePtr node,
+ virVSIProfileDefPtr vsi)
+{
+ char *vsiType;
+ char *vsiManagerID = NULL;
+ char *vsiTypeID = NULL;
+ char *vsiTypeIDVersion = NULL;
+ char *vsiInstanceID = NULL;
+ char *vsiProfileID = NULL;
+ xmlNodePtr cur = node->children;
+
+ vsiType = virXMLPropString(node, "type");
+ if (!vsiType)
+ return;
+
+ while (cur != NULL) {
+ if (xmlStrEqual(cur->name, BAD_CAST "parameters")) {
+
+ vsiManagerID = virXMLPropString(cur, "managerid");
+ vsiTypeID = virXMLPropString(cur, "typeid");
+ vsiTypeIDVersion = virXMLPropString(cur, "typeidversion");
+ vsiInstanceID = virXMLPropString(cur, "instanceid");
+ vsiProfileID = virXMLPropString(cur, "profileid");
+
+ break;
+ }
+
+ cur = cur->next;
+ }
+
+ vsi->vsiType = VIR_VSI_NONE;
+
+ switch (virVSITypeFromString(vsiType)) {
+
+ case VIR_VSI_8021QBG:
+ if (vsiManagerID != NULL && vsiTypeID != NULL &&
+ vsiTypeIDVersion != NULL) {
+ unsigned int val;
+
+ if ((virStrToLong_ui(vsiManagerID, NULL, 10, &val) &&
+ virStrToLong_ui(vsiManagerID, NULL, 16, &val) ) ||
+ val > 0xff)
+ break;
+
+ vsi->u.vsi8021Qbg.managerID = (uint8_t)val;
+
+ if ((virStrToLong_ui(vsiTypeID, NULL, 10, &val) &&
+ virStrToLong_ui(vsiTypeID, NULL, 16, &val) ) ||
+ val > 0xffffff)
+ break;
+
+ vsi->u.vsi8021Qbg.typeID = (uint32_t)val;
+
+ if ((virStrToLong_ui(vsiTypeIDVersion, NULL, 10, &val) &&
+ virStrToLong_ui(vsiTypeIDVersion, NULL, 16, &val) ) ||
+ val > 0xff)
+ break;
+
+ vsi->u.vsi8021Qbg.typeIDVersion = (uint8_t)val;
+
+ if (vsiInstanceID != NULL) {
+ if (virUUIDParse(vsiInstanceID, vsi->u.vsi8021Qbg.instanceID))
+ break;
+ } else {
+ if (virUUIDGenerate(vsi->u.vsi8021Qbg.instanceID))
+ break;
+ }
+
+ vsi->vsiType = VIR_VSI_8021QBG;
+ }
+ break;
+
+ case VIR_VSI_8021QBH:
+ if (vsiProfileID != NULL) {
+ if (virStrcpyStatic(vsi->u.vsi8021Qbh.profileID,
+ vsiProfileID) != NULL)
+ vsi->vsiType = VIR_VSI_8021QBH;
+ }
+ break;
+
+
+ default:
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+ }
+
+ VIR_FREE(vsiManagerID);
+ VIR_FREE(vsiTypeID);
+ VIR_FREE(vsiTypeIDVersion);
+ VIR_FREE(vsiInstanceID);
+ VIR_FREE(vsiProfileID);
+ VIR_FREE(vsiType);
+}
+
+
+static void
+virVSIProfileFormat(virBufferPtr buf, virVSIProfileDefPtr vsi,
+ const char *indent)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ if (vsi->vsiType == VIR_VSI_NONE)
+ return;
+
+ virBufferVSprintf(buf, "%s<vsi type='%s'>\n",
+ indent, virVSITypeToString(vsi->vsiType));
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ virUUIDFormat(vsi->u.vsi8021Qbg.instanceID,
+ uuidstr);
+ virBufferVSprintf(buf,
+ "%s <parameters managerid='%d' typeid='%d' "
+ "typeidversion='%d' instanceid='%s'/>\n",
+ indent,
+ vsi->u.vsi8021Qbg.managerID,
+ vsi->u.vsi8021Qbg.typeID,
+ vsi->u.vsi8021Qbg.typeIDVersion,
+ uuidstr);
+ break;
+
+ case VIR_VSI_8021QBH:
+ virBufferVSprintf(buf,
+ "%s <parameters profileid='%s'/>\n",
+ indent,
+ vsi->u.vsi8021Qbh.profileID);
+ break;
+ }
+
+ virBufferVSprintf(buf, "%s</vsi>\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 +1976,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *devaddr = NULL;
char *mode = NULL;
virNWFilterHashTablePtr filterparams = NULL;
+ virVSIProfileDef vsi;
+ bool vsiParsed = false;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
@@ -1873,6 +2019,11 @@ virDomainNetDefParseXML(virCapsPtr caps,
xmlStrEqual(cur->name, BAD_CAST "source")) {
dev = virXMLPropString(cur, "dev");
mode = virXMLPropString(cur, "mode");
+ } else if ((vsiParsed == false) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
+ xmlStrEqual(cur->name, BAD_CAST "vsi")) {
+ virVSIProfileDefParseXML(cur, &vsi);
+ vsiParsed = true;
} else if ((network == NULL) &&
((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
(def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -2049,6 +2200,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
} else
def->data.direct.mode = VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;
+ def->data.direct.vsiProfile = vsi;
+
def->data.direct.linkdev = dev;
dev = NULL;
@@ -5141,6 +5294,8 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferVSprintf(buf, " mode='%s'",
virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
virBufferAddLit(buf, "/>\n");
+ virVSIProfileFormat(buf, &def->data.direct.vsiProfile,
+ " ");
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
@@ -259,6 +259,39 @@ enum virDomainNetdevMacvtapType {
};
+enum virVSIType {
+ VIR_VSI_NONE,
+ VIR_VSI_8021QBG,
+ VIR_VSI_8021QBH,
+
+ VIR_VSI_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 _virVSIProfileDef virVSIProfileDef;
+typedef virVSIProfileDef *virVSIProfileDefPtr;
+struct _virVSIProfileDef {
+ enum virVSIType vsiType;
+ union {
+ struct {
+ uint8_t managerID;
+ uint32_t typeID; // 24 bit valid
+ uint8_t typeIDVersion;
+ unsigned char instanceID[VIR_UUID_BUFLEN];
+ } vsi8021Qbg;
+ struct {
+ char profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX];
+ } vsi8021Qbh;
+ } u;
+};
+
+
/* Stores the virtual network interface configuration */
typedef struct _virDomainNetDef virDomainNetDef;
typedef virDomainNetDef *virDomainNetDefPtr;
@@ -290,6 +323,7 @@ struct _virDomainNetDef {
struct {
char *linkdev;
int mode;
+ virVSIProfileDef vsiProfile;
} direct;
} data;
char *ifname;
@@ -1089,6 +1123,7 @@ VIR_ENUM_DECL(virDomainSeclabel)
VIR_ENUM_DECL(virDomainClockOffset)
VIR_ENUM_DECL(virDomainNetdevMacvtap)
+VIR_ENUM_DECL(virVSI)
VIR_ENUM_DECL(virDomainTimerName)
VIR_ENUM_DECL(virDomainTimerTrack)
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"
@@ -570,36 +571,127 @@ configMacvtapTap(int tapfd, int vnet_hdr
/**
+ * associatePortProfile
+ *
+ * @linkdev: the link dev in case of macvtap
+ * @mac: the MAC address of the interface
+ * @mode: The vepa mode (private, bridge or vepa)
+ * @vsi: 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 *linkdev,
+ const unsigned char *mac,
+ int mode,
+ const virVSIProfileDefPtr vsi,
+ int vf,
+ const unsigned char *vmuuid)
+{
+ int rc = 0;
+ VIR_DEBUG("Associating port profile '%p' on link device '%s' mode %d ",
+ vsi, linkdev, mode);
+ (void)mac;
+ (void)vf;
+ (void)vmuuid;
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ rc = -1;
+ break;
+
+ case VIR_VSI_8021QBH:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+
+/**
+ * disassociatePortProfile
+ *
+ * @linkdev: The link dev in case of a macvtap device
+ * @mac: The MAC address of the interface
+ * @vsi: 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 *linkdev,
+ const unsigned char *mac,
+ const virVSIProfileDefPtr vsi)
+{
+ int rc = 0;
+ VIR_DEBUG("Disassociating port profile id '%p' on link device '%s' ",
+ vsi, linkdev);
+ (void)mac;
+
+ switch (vsi->vsiType) {
+ case VIR_VSI_NONE:
+ case VIR_VSI_TYPE_LAST:
+ break;
+
+ case VIR_VSI_8021QBG:
+ rc = -1;
+ break;
+
+ case VIR_VSI_8021QBH:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+
+/**
* openMacvtapTap:
* Create an instance of a macvtap device and open its tap character
* device.
* @tgifname: Interface name that the macvtap is supposed to have. May
* 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'.
+ * @net: pointer to the virDomainNetDef object describing the direct
+ * type if an interface
* @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.
+ * @vnet_hdr: Whether to enable IFF_VNET_HDR on the interface
+ * @vmuuid: The (raw) UUID of the VM
*
* Returns file descriptor of the tap device in case of success,
* negative value otherwise with error reported.
*
+ * Open a macvtap device and trigger the switch setup protocol
+ * if valid port profile parameters were provided.
*/
int
openMacvtapTap(const char *tgifname,
- const unsigned char *macaddress,
- const char *linkdev,
- int mode,
+ virDomainNetDefPtr net,
char **res_ifname,
- int vnet_hdr)
+ int vnet_hdr,
+ const unsigned char *vmuuid)
{
const char *type = "macvtap";
int c, rc;
char ifname[IFNAMSIZ];
int retries, do_retry = 0;
- uint32_t macvtapMode = macvtapModeFromInt(mode);
+ uint32_t macvtapMode = macvtapModeFromInt(net->data.direct.mode);
const char *cr_ifname;
int ifindex;
@@ -616,7 +708,7 @@ openMacvtapTap(const char *tgifname,
return -1;
}
cr_ifname = tgifname;
- rc = link_add(type, macaddress, 6, tgifname, linkdev,
+ rc = link_add(type, net->mac, 6, tgifname, net->data.direct.linkdev,
macvtapMode, &do_retry);
if (rc)
return -1;
@@ -626,7 +718,8 @@ create_name:
for (c = 0; c < 8192; c++) {
snprintf(ifname, sizeof(ifname), MACVTAP_NAME_PATTERN, c);
if (ifaceGetIndex(false, ifname, &ifindex) == ENODEV) {
- rc = link_add(type, macaddress, 6, ifname, linkdev,
+ rc = link_add(type, net->mac, 6, ifname,
+ net->data.direct.linkdev,
macvtapMode, &do_retry);
if (rc == 0)
break;
@@ -639,6 +732,15 @@ create_name:
cr_ifname = ifname;
}
+ rc = associatePortProfileId(net->data.direct.linkdev,
+ net->mac,
+ net->data.direct.mode,
+ &net->data.direct.vsiProfile,
+ -1,
+ vmuuid);
+ if (rc != 0)
+ goto link_del_exit;
+
rc = ifaceUp(cr_ifname);
if (rc != 0) {
virReportSystemError(errno,
@@ -647,7 +749,7 @@ create_name:
"MAC address"),
cr_ifname);
rc = -1;
- goto link_del_exit;
+ goto disassociate_exit;
}
rc = openTap(cr_ifname, 10);
@@ -656,14 +758,19 @@ 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(net->data.direct.linkdev,
+ net->mac,
+ &net->data.direct.vsiProfile);
+
link_del_exit:
link_del(cr_ifname);
@@ -673,14 +780,21 @@ link_del_exit:
/**
* delMacvtap:
- * @ifname : The name of the macvtap interface
+ * @net: pointer to virDomainNetDef object
*
- * 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(virDomainNetDefPtr net)
{
- link_del(ifname);
+ if (net->ifname) {
+ disassociatePortProfileId(net->data.direct.linkdev,
+ net->mac,
+ &net->data.direct.vsiProfile);
+ link_del(net->ifname);
+ }
}
#endif
Index: libvirt-acl/src/util/macvtap.h
===================================================================
--- libvirt-acl.orig/src/util/macvtap.h
+++ libvirt-acl/src/util/macvtap.h
@@ -27,15 +27,15 @@
# if defined(WITH_MACVTAP)
# include "internal.h"
+# include "conf/domain_conf.h"
int openMacvtapTap(const char *ifname,
- const unsigned char *macaddress,
- const char *linkdev,
- int mode,
+ virDomainNetDefPtr net,
char **res_ifname,
- int vnet_hdr);
+ int vnet_hdr,
+ const unsigned char *vmuuid);
-void delMacvtap(const char *ifname);
+void delMacvtap(virDomainNetDefPtr net);
# endif /* WITH_MACVTAP */
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'/>
+ <vsi type='802.1Qbg'>
+ <parameters managerid='12' typeid='1193046' typeidversion='1'
+ instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
+ </vsi>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <vsi type='802.1Qbg'>
+ <parameters managerid='12' typeid='1193046' typeidversion='1'/>
+ </vsi>
+ </interface>
+ <interface type='direct'>
+ <source dev='eth0' mode='vepa'/>
+ <vsi type='802.1Qbh'>
+ <parameters profileid='my_profile'/>
+ </vsi>
+ </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
@@ -271,9 +271,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
@@ -3585,10 +3585,8 @@ 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);
}
#endif
@@ -7175,9 +7173,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;
}
@@ -8146,10 +8143,8 @@ 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);
#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
@@ -1465,9 +1465,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
@@ -1479,8 +1478,7 @@ 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, &res_ifname, vnet_hdr, vmuuid);
if (rc >= 0) {
VIR_FREE(net->ifname);
net->ifname = res_ifname;
@@ -1500,15 +1498,13 @@ qemudPhysIfaceConnect(virConnectPtr conn
if (err) {
close(rc);
rc = -1;
- delMacvtap(net->ifname);
+ delMacvtap(net);
}
}
}
#else
(void)conn;
(void)net;
- (void)linkdev;
- (void)brmode;
(void)qemuCmdFlags;
(void)driver;
qemuReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4130,9 +4126,8 @@ int qemudBuildCommandLine(virConnectPtr
goto no_memory;
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
int tapfd = qemudPhysIfaceConnect(conn, driver, net,
- net->data.direct.linkdev,
- net->data.direct.mode,
- qemuCmdFlags);
+ qemuCmdFlags,
+ def->uuid);
if (tapfd < 0)
goto error;
14 years, 7 months