[libvirt] [PATCH libvirt 1/6] errcode is typedef by mingw, rename an argument name
by Marc-André Lureau
Fixes the following warning:
util/virterror.c:1242:31: warning: declaration of 'errcode' shadows a global declaration [-Wshadow]
---
src/util/virterror.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/util/virterror.c b/src/util/virterror.c
index ff44a57..85eec8d 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -1228,7 +1228,7 @@ virErrorMsg(virErrorNumber error, const char *info)
* virReportErrorHelper:
*
* @domcode: the virErrorDomain indicating where it's coming from
- * @errcode: the virErrorNumber code for the error
+ * @errorcode: the virErrorNumber code for the error
* @filename: Source file error is dispatched from
* @funcname: Function error is dispatched from
* @linenr: Line number error is dispatched from
@@ -1239,7 +1239,7 @@ virErrorMsg(virErrorNumber error, const char *info)
* ReportError
*/
void virReportErrorHelper(int domcode,
- int errcode,
+ int errorcode,
const char *filename,
const char *funcname,
size_t linenr,
@@ -1258,9 +1258,9 @@ void virReportErrorHelper(int domcode,
errorMessage[0] = '\0';
}
- virerr = virErrorMsg(errcode, (errorMessage[0] ? errorMessage : NULL));
+ virerr = virErrorMsg(errorcode, (errorMessage[0] ? errorMessage : NULL));
virRaiseErrorFull(filename, funcname, linenr,
- domcode, errcode, VIR_ERR_ERROR,
+ domcode, errorcode, VIR_ERR_ERROR,
virerr, errorMessage, NULL,
-1, -1, virerr, errorMessage);
errno = save_errno;
--
1.7.7.5
12 years, 9 months
[libvirt] [RFC PATCH V2] Add proxy FS support to libvirt
by M. Mohan Kumar
From: "M. Mohan Kumar" <mohan(a)in.ibm.com>
A new FS driver type 'proxy' is added to QEMU 9p server. This patch adds
support for using proxy FS driver from libvirt.
QEMU proxy FS driver uses socket for communicating between helper and qemu
proxy FS driver. Proxy helper (a stand alone binary part of qemu) is invoked
with one of the descriptors created using socketpair call and the share path.
Similarly QEMU is invoked with another descriptor created using the same
socketpair system call and with other required FS driver parameters.
Need for proxy FS driver
========================
Pass through security model in QEMU 9p server has following issues:
1) TOCTTOU vulnerability: Following symbolic links in the server could
provide access to files beyond 9p export path.
2) Running QEMU with root privilege could be a security issue (pass
through security model needs root privilege).
Proxy FS driver is implemented to solve these issues.
Proxy FS uses chroot + socket combination for securing the vulnerability
known with following symbolic links. Intention of adding a new filesystem
type is to allow qemu to run in non-root mode, but doing privileged
operations in a chroot environment using socket IO.
Proxy helper is invoked with root privileges and chroots into 9p export path.
QEMU proxy fs driver sends filesystem request to proxy helper and receives the
response from it.
Proxy helper is designed such a way that it needs only few capabilities related
to filesystem operations (such as CAP_DAC_OVERRIDE, CAP_FOWNER, etc) and all
other capabilities are dropped (CAP_SYS_CHROOT, etc)
Proxy patches
http://permalink.gmane.org/gmane.comp.emulators.qemu/128735
Signed-off-by: M. Mohan Kumar <mohan(a)in.ibm.com>
---
Changes from previous version
* Remove the xml node for specifying the virtfs-proxy-helper, now it is
determined from qemu binary.
docs/formatdomain.html.in | 3 +-
src/conf/domain_conf.c | 3 +-
src/conf/domain_conf.h | 2 +-
src/qemu/qemu_capabilities.c | 3 ++
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 71 ++++++++++++++++++++++++++++++++++++++++--
src/qemu/qemu_command.h | 3 +-
tests/qemuhelptest.c | 3 +-
8 files changed, 81 insertions(+), 8 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 18b7e22..e398779 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1336,7 +1336,8 @@
This mode also has an optional
sub-element <code>driver</code>, with an
attribute <code>type='path'</code>
- or <code>type='handle'</code> <span class="since">(since
+ or <code>type='handle'</code>
+ or <code>type='proxy'</code> <span class="since">(since
0.9.7)</span>.
</dd>
<dt><code>type='template'</code></dt>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0190a81..2d45324 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -250,7 +250,8 @@ VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
VIR_ENUM_IMPL(virDomainFSDriverType, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
"default",
"path",
- "handle")
+ "handle",
+ "proxy")
VIR_ENUM_IMPL(virDomainFSAccessMode, VIR_DOMAIN_FS_ACCESSMODE_LAST,
"passthrough",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 03aa5b6..3796da4 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -466,6 +466,7 @@ enum virDomainFSDriverType {
VIR_DOMAIN_FS_DRIVER_TYPE_DEFAULT = 0,
VIR_DOMAIN_FS_DRIVER_TYPE_PATH,
VIR_DOMAIN_FS_DRIVER_TYPE_HANDLE,
+ VIR_DOMAIN_FS_DRIVER_TYPE_PROXY,
VIR_DOMAIN_FS_DRIVER_TYPE_LAST
};
@@ -491,7 +492,6 @@ struct _virDomainFSDef {
virDomainDeviceInfo info;
};
-
/* 5 different types of networking config */
enum virDomainNetType {
VIR_DOMAIN_NET_TYPE_USER,
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 43c7578..9c01a3b 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -144,6 +144,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"ich9-ahci",
"no-acpi",
"fsdev-readonly",
+ "fsdev-proxy",
);
struct qemu_feature_flags {
@@ -1083,6 +1084,8 @@ qemuCapsComputeCmdFlags(const char *help,
qemuCapsSet(flags, QEMU_CAPS_FSDEV);
if (strstr(fsdev, "readonly"))
qemuCapsSet(flags, QEMU_CAPS_FSDEV_READONLY);
+ if (strstr(fsdev, "sock_fd"))
+ qemuCapsSet(flags, QEMU_CAPS_FSDEV_PROXY);
}
if (strstr(help, "-smbios type"))
qemuCapsSet(flags, QEMU_CAPS_SMBIOS_TYPE);
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index c759baf..e129e35 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -117,6 +117,7 @@ enum qemuCapsFlags {
QEMU_CAPS_ICH9_AHCI = 77, /* -device ich9-ahci */
QEMU_CAPS_NO_ACPI = 78, /* -no-acpi */
QEMU_CAPS_FSDEV_READONLY =79, /* -fsdev readonly supported */
+ QEMU_CAPS_FSDEV_PROXY = 80, /* -fsdev proxy supported */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index f2e9cfa..0c79340 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -44,6 +44,7 @@
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <libgen.h>
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -106,7 +107,8 @@ VIR_ENUM_DECL(qemuDomainFSDriver)
VIR_ENUM_IMPL(qemuDomainFSDriver, VIR_DOMAIN_FS_DRIVER_TYPE_LAST,
"local",
"local",
- "handle");
+ "handle",
+ "proxy");
static void
@@ -2080,9 +2082,43 @@ error:
return NULL;
}
+/*
+ * Invokes the Proxy Helper with one of the socketpair as its parameter
+ *
+ */
+static int qemuInvokeProxyHelper(const char *emulator, int sock, const char *path)
+{
+#define HELPER "virtfs-proxy-helper"
+ int ret_val, status;
+ virCommandPtr cmd;
+ char *helper, *dname;
+
+ dname = dirname(strdup(emulator));
+ if (virAsprintf(&helper, "%s/%s", dname, HELPER) < 0) {
+ VIR_FREE(dname);
+ virReportOOMError();
+ return -1;
+ }
+
+ cmd = virCommandNewArgList(helper, NULL);
+ virCommandAddArg(cmd, "-f");
+ virCommandAddArgFormat(cmd, "%d", sock);
+ virCommandAddArg(cmd, "-p");
+ virCommandAddArgFormat(cmd, "%s", path);
+ virCommandTransferFD(cmd, sock);
+ virCommandDaemonize(cmd);
+ ret_val = virCommandRun(cmd, &status);
+ if (ret_val < 0)
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("%s can't execute"), helper);
+ virCommandFree(cmd);
+ VIR_FREE(helper);
+ VIR_FREE(dname);
+ return ret_val;
+}
char *qemuBuildFSStr(virDomainFSDefPtr fs,
- virBitmapPtr qemuCaps ATTRIBUTE_UNUSED)
+ virBitmapPtr qemuCaps ATTRIBUTE_UNUSED, int qemuSocket)
{
virBuffer opt = VIR_BUFFER_INITIALIZER;
const char *driver = qemuDomainFSDriverTypeToString(fs->fsdriver);
@@ -2108,6 +2144,10 @@ char *qemuBuildFSStr(virDomainFSDefPtr fs,
virBufferAddLit(&opt, ",security_model=none");
}
virBufferAsprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
+
+ if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PROXY)
+ virBufferAsprintf(&opt, ",sock_fd=%d", qemuSocket);
+
virBufferAsprintf(&opt, ",path=%s", fs->src);
if (fs->readonly) {
@@ -4426,10 +4466,35 @@ qemuBuildCommandLine(virConnectPtr conn,
if (qemuCapsGet(qemuCaps, QEMU_CAPS_FSDEV)) {
for (i = 0 ; i < def->nfss ; i++) {
char *optstr;
+ int sockets[2] = {-1, -1};
virDomainFSDefPtr fs = def->fss[i];
+ /*
+ * If its a proxy FS, we need to create a socket pair
+ * and invoke proxy_helper
+ */
+ if (fs->fsdriver == VIR_DOMAIN_FS_DRIVER_TYPE_PROXY) {
+ if (qemuCapsGet(qemuCaps, QEMU_CAPS_FSDEV_PROXY) < 0) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("proxy helper not supported"));
+ goto error;
+ }
+ /* create a socket pair */
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("socketpair failed"));
+ goto error;
+ }
+ virCommandTransferFD(cmd, sockets[1]);
+ if (qemuInvokeProxyHelper(def->emulator, sockets[0],
+ fs->src) < 0) {
+ VIR_FORCE_CLOSE(sockets[0]);
+ VIR_FORCE_CLOSE(sockets[1]);
+ goto error;
+ }
+ }
virCommandAddArg(cmd, "-fsdev");
- if (!(optstr = qemuBuildFSStr(fs, qemuCaps)))
+ if (!(optstr = qemuBuildFSStr(fs, qemuCaps, sockets[1])))
goto error;
virCommandAddArg(cmd, optstr);
VIR_FREE(optstr);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index de61cf3..8e4f335 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -87,7 +87,8 @@ char *qemuBuildDriveStr(virConnectPtr conn,
bool bootable,
virBitmapPtr qemuCaps);
char *qemuBuildFSStr(virDomainFSDefPtr fs,
- virBitmapPtr qemuCaps);
+ virBitmapPtr qemuCaps,
+ int qemuSocket);
/* Current, best practice */
char * qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index 60155e7..455a7e1 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -648,7 +648,8 @@ mymain(void)
QEMU_CAPS_PCI_ROMBAR,
QEMU_CAPS_ICH9_AHCI,
QEMU_CAPS_NO_ACPI,
- QEMU_CAPS_FSDEV_READONLY);
+ QEMU_CAPS_FSDEV_READONLY,
+ QEMU_CAPS_FSDEV_PROXY);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
1.7.6
12 years, 9 months
[libvirt] [PATCH 1/4] add a qemu-specific event register API, to passthough the new events come from qemu
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
Basically, this feature can go along with qemu monitor passthrough.
That way, if we use new commands in the monitor that generate new events, we want some way to receive those new events too.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
include/libvirt/libvirt-qemu.h | 27 ++++
include/libvirt/libvirt.h.in | 2 +-
src/conf/domain_event.c | 293 ++++++++++++++++++++++++++++++++++++++--
src/conf/domain_event.h | 50 ++++++-
src/driver.h | 14 ++
src/libvirt-qemu.c | 189 ++++++++++++++++++++++++++
src/libvirt_private.syms | 6 +
src/libvirt_qemu.syms | 5 +
8 files changed, 571 insertions(+), 15 deletions(-)
diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h
index 7f12e4f..3aa944a 100644
--- a/include/libvirt/libvirt-qemu.h
+++ b/include/libvirt/libvirt-qemu.h
@@ -32,6 +32,33 @@ virDomainPtr virDomainQemuAttach(virConnectPtr domain,
unsigned int pid,
unsigned int flags);
+/**
+ * virConnectDomainQemuEventCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @eventName : the name of the unknow or un-implementation event
+ * @eventArgs: the content of the unknow or un-implementation event
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN with virConnectDomainQemuEventRegister()
+ */
+typedef void (*virConnectDomainQemuEventCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *eventName, /* The JSON event name */
+ const char *eventArgs, /* The JSON string of args */
+ void *opaque);
+
+int
+virConnectDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom, /* option to filter */
+ const char *eventName, /* JSON event name */
+ virConnectDomainQemuEventCallback cb,
+ void *opaque,
+ virFreeCallback freecb);
+int
+virConnectDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID);
+
# ifdef __cplusplus
}
# endif
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 2480add..9fcb400 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3207,7 +3207,6 @@ typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
int type,
int status,
void *opaque);
-
/**
* virConnectDomainEventDiskChangeReason:
*
@@ -3263,6 +3262,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_CONTROL_ERROR = 7, /* virConnectDomainEventGenericCallback */
VIR_DOMAIN_EVENT_ID_BLOCK_JOB = 8, /* virConnectDomainEventBlockJobCallback */
VIR_DOMAIN_EVENT_ID_DISK_CHANGE = 9, /* virConnectDomainEventDiskChangeCallback */
+ VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN = 10, /* virConnectDomainEventDefaultCallback */
/*
* NB: this enum value will increase over time as new events are
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 614ab97..0388a66 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -45,7 +45,9 @@ typedef virDomainMeta *virDomainMetaPtr;
struct _virDomainEventCallback {
int callbackID;
+ int qemuCallbackID;
int eventID;
+ char *eventName;
virConnectPtr conn;
virDomainMetaPtr dom;
virConnectDomainEventGenericCallback cb;
@@ -94,6 +96,10 @@ struct _virDomainEvent {
char *devAlias;
int reason;
} diskChange;
+ struct {
+ char *eventName;
+ char *eventArgs;
+ }qemuUnknownEvent;
} data;
};
@@ -112,6 +118,7 @@ virDomainEventCallbackListFree(virDomainEventCallbackListPtr list)
for (i=0; i<list->count; i++) {
virFreeCallback freecb = list->callbacks[i]->freecb;
+ VIR_FREE(list->callbacks[i]->eventName);
if (freecb)
(*freecb)(list->callbacks[i]->opaque);
VIR_FREE(list->callbacks[i]);
@@ -187,8 +194,10 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn,
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -231,6 +240,9 @@ virDomainEventCallbackListRemoveConn(virConnectPtr conn,
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
if (i < (cbList->count - 1))
@@ -299,6 +311,9 @@ int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList)
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
if (i < (cbList->count - 1))
@@ -404,7 +419,98 @@ virDomainEventCallbackListAddID(virConnectPtr conn,
cbList->callbacks[cbList->count] = event;
cbList->count++;
+ event->callbackID = cbList->nextID++;
+
+ return event->callbackID;
+
+no_memory:
+ virReportOOMError();
+
+ if (event) {
+ if (event->dom)
+ VIR_FREE(event->dom->name);
+ VIR_FREE(event->dom);
+ }
+ VIR_FREE(event);
+ return -1;
+}
+
+
+
+/**
+ * virDomainEventCallbackListAddName:
+ * @conn: pointer to the connection
+ * @cbList: the list
+ * @eventName: the event eventName
+ * @callback: the callback to add
+ * @eventID: the specific eventID
+ * @opaque: opaque data tio pass to callback
+ *
+ * Internal function to add a callback from a virDomainEventCallbackListPtr
+ */
+int
+virDomainEventCallbackListAddName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ virDomainPtr dom,
+ const char* eventName,
+ int eventID,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ virDomainEventCallbackPtr event;
+ int i;
+
+ /* Check incoming */
+ if ( !cbList ) {
+ return -1;
+ }
+
+ /* check if we already have this callback on our list */
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->cb == VIR_DOMAIN_EVENT_CALLBACK(callback) &&
+ STREQ(cbList->callbacks[i]->eventName, eventName) &&
+ cbList->callbacks[i]->eventID == eventID &&
+ cbList->callbacks[i]->conn == conn) {
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("event callback already tracked"));
+ return -1;
+ }
+ }
+ if (eventID > VIR_DOMAIN_EVENT_ID_LAST || eventID < VIR_DOMAIN_EVENT_ID_LIFECYCLE) {
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("not suport this kind of eventID: %d"), eventID);
+ }
+ /* Allocate new event */
+ if (VIR_ALLOC(event) < 0)
+ goto no_memory;
+ event->conn = conn;
+ event->cb = callback;
+ if (eventName == NULL)
+ goto no_memory;
+ event->eventName = strdup(eventName);
+ if ( event->eventName == NULL)
+ goto no_memory;
+ event->opaque = opaque;
+ event->freecb = freecb;
+ event->eventID = eventID;
+ if (dom) {
+ if (VIR_ALLOC(event->dom) < 0)
+ goto no_memory;
+ if (!(event->dom->name = strdup(dom->name)))
+ goto no_memory;
+ memcpy(event->dom->uuid, dom->uuid, VIR_UUID_BUFLEN);
+ event->dom->id = dom->id;
+ }
+ /* Make space on list */
+ if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0)
+ goto no_memory;
+
+ event->conn->refs++;
+
+ cbList->callbacks[cbList->count] = event;
+ cbList->count++;
event->callbackID = cbList->nextID++;
return event->callbackID;
@@ -416,11 +522,40 @@ no_memory:
if (event->dom)
VIR_FREE(event->dom->name);
VIR_FREE(event->dom);
+ VIR_FREE(event->eventName);
}
VIR_FREE(event);
return -1;
}
+/**
+ * virDomainEventCallbackListAddQemuCallbackID:
+ * @conn: pointer to the connection
+ * @cbList: the list
+ * @callbackID: the libvirt callback ID
+ * @qemuCallbackID: the libvirtd callback ID to add
+ *
+ * Internal function to add a Daemon libvirtd callbackID
+ */
+int
+virDomainEventCallbackListAddQemuCallbackID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID,
+ int qemuCallbackID)
+{
+ int i;
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn) {
+ cbList->callbacks[i]->qemuCallbackID = qemuCallbackID;
+ return 0;
+ }
+ }
+
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("could not find event callback for deletion"));
+ return -1;
+}
int virDomainEventCallbackListCountID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -442,6 +577,27 @@ int virDomainEventCallbackListCountID(virConnectPtr conn,
}
+int
+virDomainEventCallbackListCountName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ const char *eventName)
+{
+ int i;
+ int count = 0;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (STREQ(cbList->callbacks[i]->eventName,eventName) &&
+ cbList->callbacks[i]->conn == conn)
+ count++;
+ }
+
+ return count;
+}
+
+
int virDomainEventCallbackListEventID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
int callbackID)
@@ -461,6 +617,44 @@ int virDomainEventCallbackListEventID(virConnectPtr conn,
}
+const char*
+virDomainEventCallbackListEventName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+{
+ int i;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn)
+ return cbList->callbacks[i]->eventName;
+ }
+
+ return NULL;
+}
+
+int
+virDomainEventCallbackListEventQemuCallbackID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+{
+ int i;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn)
+ return cbList->callbacks[i]->qemuCallbackID;
+ }
+
+ return -1;
+}
+
int virDomainEventCallbackListCount(virDomainEventCallbackListPtr cbList)
{
int i;
@@ -521,6 +715,11 @@ void virDomainEventFree(virDomainEventPtr event)
VIR_FREE(event->data.diskChange.newSrcPath);
VIR_FREE(event->data.diskChange.devAlias);
break;
+
+ case VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN:
+ VIR_FREE(event->data.qemuUnknownEvent.eventName);
+ VIR_FREE(event->data.qemuUnknownEvent.eventArgs);
+ break;
}
VIR_FREE(event->dom.name);
@@ -956,6 +1155,51 @@ virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
path, type, status);
}
+static virDomainEventPtr
+virDomainEventUnknownNew(int id, const char *name, unsigned char *uuid,
+ const char *eventName, const char *eventArgs)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
+ id, name, uuid);
+ if (ev) {
+ if (!(ev->data.qemuUnknownEvent.eventName = strdup(eventName))) {
+ virReportOOMError();
+ VIR_FREE(ev->dom.name);
+ VIR_FREE(ev);
+ return NULL;
+ }
+ if (eventArgs) {
+ if (!(ev->data.qemuUnknownEvent.eventArgs = strdup(eventArgs))) {
+ virReportOOMError();
+ VIR_FREE(ev->data.qemuUnknownEvent.eventName);
+ VIR_FREE(ev->dom.name);
+ VIR_FREE(ev);
+ return NULL;
+ }
+ }
+ }
+
+ return ev;
+}
+
+virDomainEventPtr virDomainEventUnknownNewFromObj(virDomainObjPtr obj,
+ const char *eventName,
+ const char *eventArgs)
+{
+
+ return virDomainEventUnknownNew(obj->def->id, obj->def->name,
+ obj->def->uuid, eventName, eventArgs);
+}
+
+virDomainEventPtr virDomainEventUnknownNewFromDom(virDomainPtr dom,
+ const char *eventName,
+ const char *eventArgs)
+{
+ return virDomainEventUnknownNew(dom->id, dom->name, dom->uuid,
+ eventName, eventArgs);
+}
+
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom)
{
virDomainEventPtr ev =
@@ -1095,11 +1339,12 @@ virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
}
-void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
- virDomainEventPtr event,
- virConnectDomainEventGenericCallback cb,
- void *cbopaque,
- void *opaque ATTRIBUTE_UNUSED)
+void
+virDomainEventDispatchDefaultFunc(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventGenericCallback cb,
+ void *cbopaque,
+ void *opaque ATTRIBUTE_UNUSED)
{
virDomainPtr dom = virGetDomain(conn, event->dom.name, event->dom.uuid);
if (!dom)
@@ -1180,6 +1425,13 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
+ case VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN:
+ ((virConnectDomainQemuEventCallback)cb)(conn, dom,
+ event->data.qemuUnknownEvent.eventName,
+ event->data.qemuUnknownEvent.eventArgs,
+ cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
@@ -1189,8 +1441,9 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
}
-static int virDomainEventDispatchMatchCallback(virDomainEventPtr event,
- virDomainEventCallbackPtr cb)
+static int
+virDomainEventDispatchMatchCallback(virDomainEventPtr event,
+ virDomainEventCallbackPtr cb)
{
if (!cb)
return 0;
@@ -1198,7 +1451,12 @@ static int virDomainEventDispatchMatchCallback(virDomainEventPtr event,
return 0;
if (cb->eventID != event->eventID)
return 0;
-
+ if (event->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if (event->data.qemuUnknownEvent.eventName == NULL ||
+ cb->eventName == NULL ||
+ STRNEQ(cb->eventName, event->data.qemuUnknownEvent.eventName))
+ return 0;
+ }
if (cb->dom) {
/* Deliberately ignoring 'id' for matching, since that
* will cause problems when a domain switches between
@@ -1341,3 +1599,20 @@ virDomainEventStateDeregisterAny(virConnectPtr conn,
virDomainEventStateUnlock(state);
return ret;
}
+int
+virDomainQemuEventStateDeregister(virConnectPtr conn,
+ virDomainEventStatePtr state,
+ int callbackID)
+{
+ int ret;
+
+ virDomainEventStateLock(state);
+ if (state->isDispatching)
+ ret = virDomainEventCallbackListMarkDeleteID(conn,
+ state->callbacks, callbackID);
+ else
+ ret = virDomainEventCallbackListRemoveID(conn,
+ state->callbacks, callbackID);
+ virDomainEventStateUnlock(state);
+ return ret;
+}
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 3ba418e..f2fe847 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -83,14 +83,23 @@ int virDomainEventCallbackListAddID(virConnectPtr conn,
virFreeCallback freecb)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(5);
+int virDomainEventCallbackListAddName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ virDomainPtr dom,
+ const char* eventName,
+ int eventID,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(6);
int virDomainEventCallbackListRemove(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
virConnectDomainEventCallback callback)
ATTRIBUTE_NONNULL(1);
-int virDomainEventCallbackListRemoveID(virConnectPtr conn,
- virDomainEventCallbackListPtr cbList,
- int callbackID)
+int virDomainQemuEventCallbackListRemoveID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
ATTRIBUTE_NONNULL(1);
int virDomainEventCallbackListRemoveConn(virConnectPtr conn,
virDomainEventCallbackListPtr cbList)
@@ -106,9 +115,14 @@ int virDomainEventCallbackListMarkDeleteID(virConnectPtr conn,
int callbackID)
ATTRIBUTE_NONNULL(1);
-
int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList);
+int virDomainEventCallbackListAddQemuCallbackID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID,
+ int qemuCallbackID)
+ ATTRIBUTE_NONNULL(1);
+
int virDomainEventCallbackListCount(virDomainEventCallbackListPtr cbList);
int virDomainEventCallbackListCountID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -119,6 +133,21 @@ int virDomainEventCallbackListEventID(virConnectPtr conn,
int callbackID)
ATTRIBUTE_NONNULL(1);
+int virDomainEventCallbackListCountName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ const char *eventName)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
+
+int virDomainEventCallbackListEventQemuCallbackID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1);
+
+const char* virDomainEventCallbackListEventName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1);
+
virDomainEventQueuePtr virDomainEventQueueNew(void);
virDomainEventPtr virDomainEventNew(int id, const char *name, const unsigned char *uuid, int type, int detail);
@@ -190,6 +219,13 @@ virDomainEventPtr virDomainEventDiskChangeNewFromDom(virDomainPtr dom,
const char *devAlias,
int reason);
+virDomainEventPtr virDomainEventUnknownNewFromObj(virDomainObjPtr obj,
+ const char *eventName,
+ const char *eventArgs);
+virDomainEventPtr virDomainEventUnknownNewFromDom(virDomainPtr dom,
+ const char *eventName,
+ const char *eventArgs);
+
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);
@@ -246,5 +282,9 @@ virDomainEventStateDeregisterAny(virConnectPtr conn,
virDomainEventStatePtr state,
int callbackID)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-
+int
+virDomainQemuEventStateDeregister(virConnectPtr conn,
+ virDomainEventStatePtr state,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
#endif
diff --git a/src/driver.h b/src/driver.h
index 941ff51..51164a9 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -635,6 +635,18 @@ typedef virDomainPtr
unsigned int flags);
typedef int
+ (*virDrvDomainQemuEventRegister)(virConnectPtr conn,
+ virDomainPtr dom, /* option to filter */
+ const char *eventName, /* JSON event name */
+ virConnectDomainEventGenericCallback cb,
+ void *opaque,
+ virFreeCallback freecb);
+
+typedef int
+ (*virDrvDomainQemuEventDeregister)(virConnectPtr conn,
+ int callbackID);
+
+typedef int
(*virDrvDomainOpenConsole)(virDomainPtr dom,
const char *dev_name,
virStreamPtr st,
@@ -915,6 +927,8 @@ struct _virDriver {
virDrvDomainSnapshotDelete domainSnapshotDelete;
virDrvDomainQemuMonitorCommand qemuDomainMonitorCommand;
virDrvDomainQemuAttach qemuDomainAttach;
+ virDrvDomainQemuEventRegister qemuDomainQemuEventRegister;
+ virDrvDomainQemuEventDeregister qemuDomainQemuEventDeregister;
virDrvDomainOpenConsole domainOpenConsole;
virDrvDomainOpenGraphics domainOpenGraphics;
virDrvDomainInjectNMI domainInjectNMI;
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c
index 248cc33..7722b7b 100644
--- a/src/libvirt-qemu.c
+++ b/src/libvirt-qemu.c
@@ -36,6 +36,77 @@
virReportErrorHelper(VIR_FROM_DOM, error, NULL, __FUNCTION__, \
__LINE__, info)
+/* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This
+ * assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but
+ * can easily be expanded if needed.
+ *
+ * Note that gcc provides extensions of "define a(b...) b" or
+ * "define a(b,...) b,##__VA_ARGS__" as a means of eliding a comma
+ * when no var-args are present, but we don't want to require gcc.
+ */
+#define VIR_ARG15(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
+#define VIR_HAS_COMMA(...) VIR_ARG15(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
+
+/* Form the name VIR_DOMAIN_DEBUG_[01], then call that macro,
+ * according to how many arguments are present. Two-phase due to
+ * macro expansion rules. */
+#define VIR_DOMAIN_DEBUG_EXPAND(a, b, ...) \
+ VIR_DOMAIN_DEBUG_PASTE(a, b, __VA_ARGS__)
+#define VIR_DOMAIN_DEBUG_PASTE(a, b, ...) \
+ a##b(__VA_ARGS__)
+
+/* Internal use only, when VIR_DOMAIN_DEBUG has one argument. */
+#define VIR_DOMAIN_DEBUG_0(dom) \
+ VIR_DOMAIN_DEBUG_2(dom, "%s", "")
+
+/* Internal use only, when VIR_DOMAIN_DEBUG has three or more arguments. */
+#define VIR_DOMAIN_DEBUG_1(dom, fmt, ...) \
+ VIR_DOMAIN_DEBUG_2(dom, ", " fmt, __VA_ARGS__)
+
+/* Internal use only, with final format. */
+#define VIR_DOMAIN_DEBUG_2(dom, fmt, ...) \
+ do { \
+ char _uuidstr[VIR_UUID_STRING_BUFLEN]; \
+ const char *_domname = NULL; \
+ \
+ if (!VIR_IS_DOMAIN(dom)) { \
+ memset(_uuidstr, 0, sizeof(_uuidstr)); \
+ } else { \
+ virUUIDFormat((dom)->uuid, _uuidstr); \
+ _domname = (dom)->name; \
+ } \
+ \
+ VIR_DEBUG("dom=%p, (VM: name=%s, uuid=%s)" fmt, \
+ dom, NULLSTR(_domname), _uuidstr, __VA_ARGS__); \
+ } while (0)
+
+/**
+ * VIR_DOMAIN_DEBUG:
+ * @dom: domain
+ * @fmt: optional format for additional information
+ * @...: optional arguments corresponding to @fmt.
+ */
+#define VIR_DOMAIN_DEBUG(...) \
+ VIR_DOMAIN_DEBUG_EXPAND(VIR_DOMAIN_DEBUG_, \
+ VIR_HAS_COMMA(__VA_ARGS__), \
+ __VA_ARGS__)
+
+/**
+ * VIR_UUID_DEBUG:
+ * @conn: connection
+ * @uuid: possibly null UUID array
+ */
+#define VIR_UUID_DEBUG(conn, uuid) \
+ do { \
+ if (uuid) { \
+ char _uuidstr[VIR_UUID_STRING_BUFLEN]; \
+ virUUIDFormat(uuid, _uuidstr); \
+ VIR_DEBUG("conn=%p, uuid=%s", conn, _uuidstr); \
+ } else { \
+ VIR_DEBUG("conn=%p, uuid=(null)", conn); \
+ } \
+ } while (0)
+
/**
* virDomainQemuMonitorCommand:
* @domain: a domain object
@@ -178,3 +249,121 @@ error:
virDispatchError(conn);
return NULL;
}
+
+/**
+ * virConnectDomainQemuEventRegister:
+ * @conn: pointer to the connection
+ * @dom: pointer to the domain
+ * @eventName: the event Name to receive
+ * @cb: callback to the function handling domain events
+ * @opaque: opaque data to pass on to the callback
+ * @freecb: optional function to deallocate opaque when not used anymore
+ *
+ * Adds a callback to receive notifications of arbitrary qemu domain events
+ * occurring on a domain.
+ *
+ * If dom is NULL, then events will be monitored for any domain. If dom
+ * is non-NULL, then only the specific domain will be monitored
+ *
+ * Most types of event have a callback providing a custom set of parameters
+ * for the event. When registering an event, it is thus neccessary to use
+ * the VIR_DOMAIN_EVENT_CALLBACK() macro to cast the supplied function pointer
+ * to match the signature of this method.
+ *
+ * The virDomainPtr object handle passed into the callback upon delivery
+ * of an event is only valid for the duration of execution of the callback.
+ * If the callback wishes to keep the domain object after the callback returns,
+ * it shall take a reference to it, by calling virDomainRef.
+ * The reference can be released once the object is no longer required
+ * by calling virDomainFree.
+ *
+ * The return value from this method is a positive integer identifier
+ * for the callback. To unregister a callback, this callback ID should
+ * be passed to the virConnectDomainQemuEventDeregister method
+ *
+ * Returns a callback identifier on success, -1 on failure
+ */
+int
+virConnectDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom, /* option to filter */
+ const char *eventName, /* JSON event name */
+ virConnectDomainQemuEventCallback cb,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ VIR_DOMAIN_DEBUG(dom, "conn=%p, eventName=%s, cb=%p, opaque=%p, freecb=%p",
+ conn, eventName, cb, opaque, freecb);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (dom != NULL &&
+ !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(conn);
+ return -1;
+ }
+ if (eventName == NULL || cb == NULL) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if ((conn->driver) && (conn->driver->qemuDomainQemuEventRegister)) {
+ int ret;
+ ret = conn->driver->qemuDomainQemuEventRegister(conn, dom, eventName, cb, opaque, freecb);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+ virDispatchError(conn);
+ return -1;
+}
+
+/**
+ * virConnectDomainQemuEventDeregister:
+ * @conn: pointer to the connection
+ * @callbackID: the callback identifier
+ *
+ * Removes an event callback. The callbackID parameter should be the
+ * vaule obtained from a previous virConnectDomainQemuEventDeregister method.
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int
+virConnectDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID)
+{
+
+ VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (callbackID < 0) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ if ((conn->driver) && (conn->driver->qemuDomainQemuEventDeregister)) {
+ int ret;
+ ret = conn->driver->qemuDomainQemuEventDeregister(conn, callbackID);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+ virDispatchError(conn);
+ return -1;
+}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 48ffdf2..75e544a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -471,11 +471,16 @@ virDomainWatchdogModelTypeToString;
# domain_event.h
virDomainEventBlockJobNewFromObj;
virDomainEventBlockJobNewFromDom;
+virDomainEventUnknownNewFromObj;
+virDomainEventunknownNewFromDom;
virDomainEventCallbackListAdd;
virDomainEventCallbackListAddID;
+virDomainEventCallbackListAddName;
virDomainEventCallbackListCount;
virDomainEventCallbackListCountID;
+virDomainEventCallbackListCountName;
virDomainEventCallbackListEventID;
+virDomainEventCallbackListEventName;
virDomainEventCallbackListFree;
virDomainEventCallbackListMarkDelete;
virDomainEventCallbackListMarkDeleteID;
@@ -512,6 +517,7 @@ virDomainEventRebootNewFromDom;
virDomainEventRebootNewFromObj;
virDomainEventStateDeregister;
virDomainEventStateDeregisterAny;
+virDomainQemuEventStateDeregister;
virDomainEventStateFlush;
virDomainEventStateFree;
virDomainEventStateNew;
diff --git a/src/libvirt_qemu.syms b/src/libvirt_qemu.syms
index 8447730..a17e387 100644
--- a/src/libvirt_qemu.syms
+++ b/src/libvirt_qemu.syms
@@ -19,3 +19,8 @@ LIBVIRT_QEMU_0.9.4 {
global:
virDomainQemuAttach;
} LIBVIRT_QEMU_0.8.3;
+LIBVIRT_QEMU_0.9.9 {
+ global:
+ virConnectDomainQemuEventRegister;
+ virConnectDomainQemuEventDeregister;
+} LIBVIRT_QEMU_0.9.4;
--
1.7.5.4
12 years, 9 months
[libvirt] [PATCH 1/2 v3] Python: Refactoring virTypedParameter conversion for NUMA tuning APIs
by Guannan Ren
*virDomainSetNumaParameters
*virDomainGetNumaParameters
---
python/Makefile.am | 4 +-
python/libvirt-override-api.xml | 13 ++
python/libvirt-override.c | 314 +++++++++++++++++++++++++++++++++++++++
3 files changed, 330 insertions(+), 1 deletions(-)
diff --git a/python/Makefile.am b/python/Makefile.am
index 3068eee..4302fa5 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -8,6 +8,8 @@ SUBDIRS= . tests
INCLUDES = \
$(PYTHON_INCLUDES) \
-I$(top_srcdir)/include \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/gnulib/lib \
-I$(top_builddir)/include \
-I$(top_builddir)/$(subdir) \
$(GETTEXT_CPPFLAGS)
@@ -42,7 +44,7 @@ all-local: libvirt.py libvirt_qemu.py
pyexec_LTLIBRARIES = libvirtmod.la libvirtmod_qemu.la
-libvirtmod_la_SOURCES = libvirt-override.c typewrappers.c
+libvirtmod_la_SOURCES = libvirt-override.c typewrappers.c ../src/util/virtypedparam.c
nodist_libvirtmod_la_SOURCES = libvirt.c libvirt.h
# Python <= 2.4 header files contain a redundant decl, hence we
# need extra flags here
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
index 704fee9..748aa17 100644
--- a/python/libvirt-override-api.xml
+++ b/python/libvirt-override-api.xml
@@ -248,6 +248,19 @@
<arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
<arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/>
</function>
+ <function name='virDomainSetNumaParameters' file='python'>
+ <info>Change the NUMA tunables</info>
+ <return type='int' info='-1 in case of error, 0 in case of success.'/>
+ <arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
+ <arg name='params' type='virTypedParameterPtr' info='pointer to numa tunable objects'/>
+ <arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/>
+ </function>
+ <function name='virDomainGetNumaParameters' file='python'>
+ <info>Get the NUMA parameters</info>
+ <return type='int' info='returns a dictionary of params in case of success, -1 in case of error'/>
+ <arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
+ <arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/>
+ </function>
<function name='virConnectListStoragePools' file='python'>
<info>list the storage pools, stores the pointers to the names in @names</info>
<arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/>
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index d2aad0f..5f9d83e 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -21,6 +21,7 @@
#include "libvirt/virterror.h"
#include "typewrappers.h"
#include "libvirt.h"
+#include "util/virtypedparam.h"
#ifndef __CYGWIN__
extern void initlibvirtmod(void);
@@ -61,6 +62,208 @@ static char *py_str(PyObject *obj)
return PyString_AsString(str);
}
+/* Two helper functions to help the conversions between C to Python
+ * for the virTypedParameter used in the following APIs. */
+static PyObject *
+getPyVirTypedParameter(virTypedParameterPtr params, int nparams)
+{
+ PyObject *info;
+ PyObject *key, *val;
+ PyObject *ret = NULL;
+ int i;
+
+ if (!params)
+ return ret;
+
+ /* convert to a Python tuple of long objects */
+ if ((info = PyDict_New()) == NULL) {
+ return ret;
+ }
+
+ for (i = 0 ; i < nparams ; i++) {
+ switch (params[i].type) {
+ case VIR_TYPED_PARAM_INT:
+ val = PyInt_FromLong((long)params[i].value.i);
+ break;
+
+ case VIR_TYPED_PARAM_UINT:
+ val = PyInt_FromLong((unsigned long)params[i].value.ui);
+ break;
+
+ case VIR_TYPED_PARAM_LLONG:
+ val = PyLong_FromLongLong((long long)params[i].value.l);
+ break;
+
+ case VIR_TYPED_PARAM_ULLONG:
+ val = PyLong_FromUnsignedLongLong((unsigned long long)params[i].value.ul);
+ break;
+
+ case VIR_TYPED_PARAM_DOUBLE:
+ val = PyFloat_FromDouble((double)params[i].value.d);
+ break;
+
+ case VIR_TYPED_PARAM_BOOLEAN:
+ val = PyBool_FromLong((long)params[i].value.b);
+ break;
+
+ case VIR_TYPED_PARAM_STRING:
+ val = libvirt_constcharPtrWrap(params[i].value.s);
+ break;
+
+ default:
+ Py_DECREF(info);
+ return ret;
+ }
+
+ key = libvirt_constcharPtrWrap(params[i].field);
+ if (!key || !val)
+ goto fail;
+
+ if (PyDict_SetItem(info, key, val) < 0)
+ goto fail;
+
+ Py_DECREF(key);
+ Py_DECREF(val);
+ }
+ return info;
+fail:
+ Py_XDECREF(info);
+ Py_XDECREF(key);
+ Py_XDECREF(val);
+ return ret;
+}
+
+static PyObject *
+setPyVirTypedParameter(PyObject *info, virTypedParameterPtr params, int nparams)
+{
+ PyObject *key, *val;
+ PyObject *ret = NULL;
+ int i;
+
+ if (!info || !params)
+ return ret;
+
+ /* convert to a Python tuple of long objects */
+ for (i = 0; i < nparams; i++) {
+ key = libvirt_constcharPtrWrap(params[i].field);
+ val = PyDict_GetItem(info, key);
+ Py_DECREF(key);
+
+ if (val == NULL)
+ continue;
+
+ switch (params[i].type) {
+ case VIR_TYPED_PARAM_INT:
+ {
+ long long_val;
+ if (PyInt_Check(val)) {
+ long_val = PyInt_AsLong(val);
+ if ((long_val == -1) && PyErr_Occurred())
+ return ret;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Attribute value type must be int");
+ return ret;
+ }
+ params[i].value.i = (int)long_val;
+ }
+ break;
+ case VIR_TYPED_PARAM_UINT:
+ {
+ long long_val;
+ if (PyInt_Check(val)) {
+ long_val = PyInt_AsLong(val);
+ if ((long_val == -1) && PyErr_Occurred())
+ return ret;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Attribute value type must be int");
+ return ret;
+ }
+ params[i].value.ui = (unsigned int)long_val;
+ }
+ break;
+ case VIR_TYPED_PARAM_LLONG:
+ {
+ long long llong_val;
+ if (PyLong_Check(val)) {
+ llong_val = PyLong_AsLongLong(val);
+ if ((llong_val == -1) && PyErr_Occurred())
+ return ret;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Attribute value type must be long");
+ return ret;
+ }
+ params[i].value.l = llong_val;
+ }
+ break;
+ case VIR_TYPED_PARAM_ULLONG:
+ {
+ unsigned long long ullong_val;
+ if (PyLong_Check(val)) {
+ ullong_val = PyLong_AsUnsignedLongLong(val);
+ if ((ullong_val == -1) && PyErr_Occurred())
+ return ret;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Attribute value type must be long");
+ return ret;
+
+ }
+ params[i].value.ul = ullong_val;
+ }
+ break;
+ case VIR_TYPED_PARAM_DOUBLE:
+ {
+ double double_val;
+ if (PyFloat_Check(val)) {
+ double_val = PyFloat_AsDouble(val);
+ if ((double_val == -1) && PyErr_Occurred())
+ return ret;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Attribute value type must be float");
+ return ret;
+ }
+ params[i].value.d = double_val;
+ }
+ break;
+ case VIR_TYPED_PARAM_BOOLEAN:
+ {
+ /* Hack - Python's definition of Py_True breaks strict
+ * aliasing rules, so can't directly compare
+ */
+ if (PyBool_Check(val)) {
+ PyObject *hacktrue = PyBool_FromLong(1);
+ params[i].value.b = hacktrue == val ? 1: 0;
+ Py_DECREF(hacktrue);
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Attribute value type must be bool");
+ return ret;
+ }
+ }
+ break;
+ case VIR_TYPED_PARAM_STRING:
+ {
+ if (PyString_Check(val)) {
+ free(params[i].value.s);
+ params[i].value.s = PyString_AsString(val);
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "Attribute value type must be string");
+ return ret;
+ }
+ }
+ break;
+ default:
+ return ret;
+ }
+ }
+ return VIR_PY_NONE;
+}
+
/************************************************************************
* *
* Statistics *
@@ -1000,6 +1203,115 @@ libvirt_virDomainGetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED,
}
static PyObject *
+libvirt_virDomainSetNumaParameters(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *info;
+ PyObject *ret = NULL;
+ int i_retval;
+ int nparams = 0;
+ unsigned int flags;
+ virTypedParameterPtr params;
+
+ if (!PyArg_ParseTuple(args,
+ (char *)"OOi:virDomainSetNumaParameters",
+ &pyobj_domain, &info, &flags))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ i_retval = virDomainGetNumaParameters(domain, NULL, &nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (i_retval < 0)
+ return VIR_PY_INT_FAIL;
+
+ if ((params = malloc(sizeof(*params)*nparams)) == NULL)
+ return PyErr_NoMemory();
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ i_retval = virDomainGetNumaParameters(domain, params, &nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (i_retval < 0) {
+ ret = VIR_PY_INT_FAIL;
+ goto fail;
+ }
+
+ if (!setPyVirTypedParameter(info, params, nparams))
+ goto fail;
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ i_retval = virDomainSetNumaParameters(domain, params, nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (i_retval < 0) {
+ ret = VIR_PY_INT_FAIL;
+ goto fail;
+ }
+
+ /* The string generated by PyString_AsString
+ * must not be deallocated */
+ free(params);
+ return VIR_PY_INT_SUCCESS;
+fail:
+ /*same as above*/
+ free(params);
+ return ret;
+}
+
+static PyObject *
+libvirt_virDomainGetNumaParameters(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *info;
+ PyObject *ret = NULL;
+ int i_retval;
+ int nparams = 0;
+ unsigned int flags;
+ virTypedParameterPtr params;
+
+ if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetNumaParameters",
+ &pyobj_domain, &flags))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ i_retval = virDomainGetNumaParameters(domain, NULL, &nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (i_retval < 0)
+ return VIR_PY_INT_FAIL;
+
+ if ((params = malloc(sizeof(*params)*nparams)) == NULL)
+ return PyErr_NoMemory();
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ i_retval = virDomainGetNumaParameters(domain, params, &nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (i_retval < 0) {
+ ret = VIR_PY_INT_FAIL;
+ goto fail;
+ }
+
+ info = getPyVirTypedParameter(params, nparams);
+ if (!info)
+ goto fail;
+
+ virTypedParameterArrayClear(params, nparams);
+ free(params);
+ return info;
+
+fail:
+ virTypedParameterArrayClear(params, nparams);
+ free(params);
+ return ret;
+}
+
+static PyObject *
libvirt_virDomainGetVcpus(PyObject *self ATTRIBUTE_UNUSED,
PyObject *args) {
virDomainPtr domain;
@@ -5162,6 +5474,8 @@ static PyMethodDef libvirtMethods[] = {
{(char *) "virDomainGetBlkioParameters", libvirt_virDomainGetBlkioParameters, METH_VARARGS, NULL},
{(char *) "virDomainSetMemoryParameters", libvirt_virDomainSetMemoryParameters, METH_VARARGS, NULL},
{(char *) "virDomainGetMemoryParameters", libvirt_virDomainGetMemoryParameters, METH_VARARGS, NULL},
+ {(char *) "virDomainSetNumaParameters", libvirt_virDomainSetNumaParameters, METH_VARARGS, NULL},
+ {(char *) "virDomainGetNumaParameters", libvirt_virDomainGetNumaParameters, METH_VARARGS, NULL},
{(char *) "virDomainGetVcpus", libvirt_virDomainGetVcpus, METH_VARARGS, NULL},
{(char *) "virDomainPinVcpu", libvirt_virDomainPinVcpu, METH_VARARGS, NULL},
{(char *) "virDomainPinVcpuFlags", libvirt_virDomainPinVcpuFlags, METH_VARARGS, NULL},
--
1.7.7.5
12 years, 9 months
[libvirt] [RFC Incomplete Patch] Libvirt + Openvswitch
by Dan Wendlandt
Hello all,
I know of many people who want to spin up VMs using libvirt + kvm/qemu and
attach those VMs to an openvswitch bridge (see: http://www.openvswitch.org).
However, the only way I know of to get this working is a kludge that uses
to tap devices along with <interface type="ethernet"> while running
ovs-vsctl outside of libvirt. Even worse, doing this on RHEL/Fedora seems
to require privilege tweaks (e.g., running qemu as root, not dropping
capabilities), which may not be acceptable for production deployments
(see:
http://fedoraproject.org/wiki/How_to_debug_Virtualization_problems#Errors...).
So I would like to start taking steps toward better libvirt/openvswitch
integration. My initial step has the fairly limit goal of enabling
kvm/qemu VM NICs to attach to an openvswitch bridge in much the same way VM
NIC can already attached to the linux bridge. For example, specifying:
<interface type="openvswitch">
<source bridge="br0"/>
<mac address="ca:fe:de;ad:be:ef"/>
</interface>
I also wanted to add a new child element of <interface> that can be used to
specify some OVS specific configuration. To start, I just want to expose a
single 'interfaceid' value (this parameter is specific to openvswitch).
Extending the previous example:
<interface type="openvswitch">
<source bridge="br0"/>
<mac address="ca:fe:de;ad:be:ef"/>
<openvswitchport interfaceid="interface-xyz"/>
</interface>
For this first step (see attached patch), I am only targeting the model
where the OVS bridge has been created externally ahead of time. I am not
tackling any of the "network" logic that actually creates/destroys bridges,
as it is not needed for my target use case.
A couple notes about the attached patch:
- I haven't actually run this code. I was just poking around the libvirt
code to learn about it and figured that a diff was the most concrete way to
propose what I was thinking of doing. I would be curious for pointers
about big chunks of work that I may have missed (for example, I haven't
added any tests yet).
- the code was modeled on the network interface "bandwidth" code, that
calls out to 'tc' to configure bandwidth rates. Ideally we would be able
to make direct C calls to OVS (and we plan to make that possible in the
future), but calling an external utility right now is the only viable
path.
- no attention was paid to style guidelines. Will do that before any real
submission.
- I wasn't very clear on the notion of an "actual" net def, as opposed to a
normal net def. What's the best place to look for documentation on this?
Anyway, I'm primarily looking for feedback about whether I'm barking up the
right tree before I spend time debugging or polishing the patch, so I would
appreciate thoughts, advice, etc. Thanks,
Dan
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dan Wendlandt
Nicira Networks: www.nicira.com
twitter: danwendlandt
~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 years, 9 months
[libvirt] [PATCH 0/2] Added RSS reporting for qemu
by Martin Kletzander
This patch enables reporting of Resident Set Size for qemu process. It
is available through qemudDomainMemoryStats and qemudGetProcessInfo. The
reporting is also added into "virsh dommemstat" command.
Martin Kletzander (2):
Added RSS information gathering into qemudGetProcessInfo
Added RSS reporting
include/libvirt/libvirt.h.in | 7 +++++-
src/qemu/qemu_driver.c | 46 +++++++++++++++++++++++++++++++----------
tools/virsh.c | 2 +
3 files changed, 43 insertions(+), 12 deletions(-)
--
1.7.3.4
12 years, 9 months
[libvirt] [PATCH] tests: avoid test failure on rawhide gnutls
by Eric Blake
I hit a VERY weird testsuite failure on rawhide, which included
_binary_ output to stderr, followed by a hang waiting for me
to type something! (Here, using ^@ for NUL):
$ ./commandtest
TEST: commandtest
WARNING: gnome-keyring:: couldn't send data: Bad file descriptor
.WARNING: gnome-keyring:: couldn't send data: Bad file descriptor
.WARNING: gnome-keyring:: couldn't send data: Bad file descriptor
WARNING: gnome-keyring:: couldn't send data: Bad file descriptor
.8^@^@^@8^@^@^@^A^@^@^@^Bay^A^@^@^@)PRIVATE-GNOME-KEYRING-PKCS11-PROTOCOL-V-1
I finally traced it to the fact that gnome-keyring, called via
gnutls_global_init which is turn called by virNetTLSInit, opens
an internal fd that it expects to communicate to via a
pthread_atfork handler (never mind that it violates POSIX by
using non-async-signal-safe functions in that handler:
https://bugzilla.redhat.com/show_bug.cgi?id=772320).
Our problem stems from the fact that we pulled the rug out from
under the library's expectations by closing an fd that it had
just opened. While we aren't responsible for fixing the bugs
in that pthread_atfork handler, we can at least avoid the bugs
by not closing the fd in the first place.
* tests/commandtest.c (mymain): Avoid closing fds that were opened
by virInitialize.
---
Pushing under the build-breaker rule. It cost me the better part of
a morning to track this one down, so I left a super-long comment
to help the next person to read the file understand what we're
fighting against.
tests/commandtest.c | 20 ++++++++++++++++++--
1 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/tests/commandtest.c b/tests/commandtest.c
index efc48fe..b4b6044 100644
--- a/tests/commandtest.c
+++ b/tests/commandtest.c
@@ -784,6 +784,22 @@ mymain(void)
setpgid(0, 0);
setsid();
+ /* Our test expects particular fd values; to get that, we must not
+ * leak fds that we inherited from a lazy parent. At the same
+ * time, virInitialize may open some fds (perhaps via third-party
+ * libraries that it uses), and we must not kill off an fd that
+ * this process opens as it might break expectations of a
+ * pthread_atfork handler, as well as interfering with our tests
+ * trying to ensure we aren't leaking to our children. The
+ * solution is to do things in two phases - reserve the fds we
+ * want by overwriting any externally inherited fds, then
+ * initialize, then clear the slots for testing. */
+ if ((fd = open("/dev/null", O_RDONLY)) < 0 ||
+ dup2(fd, 3) < 0 ||
+ dup2(fd, 4) < 0 ||
+ dup2(fd, 5) < 0 ||
+ (fd > 5 && VIR_CLOSE(fd) < 0))
+ return EXIT_FAILURE;
/* Prime the debug/verbose settings from the env vars,
* since we're about to reset 'environ' */
@@ -791,8 +807,8 @@ mymain(void)
virTestGetVerbose();
virInitialize();
- /* Kill off any inherited fds that might interfere with our
- * testing. */
+
+ /* Phase two of killing interfering fds; see above. */
fd = 3;
VIR_FORCE_CLOSE(fd);
fd = 4;
--
1.7.7.5
12 years, 9 months
[libvirt] [PATCH v3 0/7] Console corruption patchset
by Peter Krempa
This is the third version of this patchset, rebased, polisehd and
tweaked after Eric's review.
This series contains one new patch that enables reuse of code in
patches later on.
The qemu driver implementation of console handling is very similar to
LXC's implementation, so porting this functionality to LXC should be
trivial and I'll post a follow-up patch when the qemu's driver will be
ok.
Peter Krempa (7):
pidfile: Make checking binary path in virPidFileRead optional
Add flags for virDomainOpenConsole
virsh: add support for VIR_DOMAIN_CONSOLE_* flags
fdstream: Emit stream abort callback even if poll() doesnt.
fdstream: Add internal callback on stream close
util: Add helpers for safe domain console operations
qemu: Add ability to abort existing console while creating new one
configure.ac | 39 ++++-
include/libvirt/libvirt.h.in | 12 ++
po/POTFILES.in | 1 +
src/Makefile.am | 6 +-
src/conf/virconsole.c | 396 ++++++++++++++++++++++++++++++++++++++++++
src/conf/virconsole.h | 36 ++++
src/fdstream.c | 89 +++++++++-
src/fdstream.h | 11 ++
src/libvirt.c | 11 +-
src/libvirt_private.syms | 6 +
src/qemu/qemu_domain.c | 5 +
src/qemu/qemu_domain.h | 3 +
src/qemu/qemu_driver.c | 21 ++-
src/util/virpidfile.c | 21 ++-
tools/console.c | 5 +-
tools/console.h | 3 +-
tools/virsh.c | 24 ++-
tools/virsh.pod | 8 +-
18 files changed, 660 insertions(+), 37 deletions(-)
create mode 100644 src/conf/virconsole.c
create mode 100644 src/conf/virconsole.h
--
1.7.3.4
12 years, 9 months
[libvirt] oVirt Live Snapshots
by Federico Simoncelli
Hi,
oVirt, and more specifically VDSM, is currently implementing the live
snapshot feature using the API/commands provided by libvirt and qemu.
It would be great if you could review the design and the current open
issues at:
http://ovirt.org/wiki/Live_Snapshots
Thank you,
--
Federico
12 years, 9 months