[libvirt] [PATCH 4/5] hyperv: Add basic driver for Microsoft Hyper-V

Matthias Bolte matthias.bolte at googlemail.com
Wed Jul 13 19:01:35 UTC 2011


Domain listing, basic information retrieval and domain life cycle
management is implemented. But currently the domian XML output
lacks the complete devices section.

The driver uses OpenWSMAN to directly communicate with an Hyper-V
server over its WS-Management interface exposed via Microsoft WinRM.

The driver is based on the work of Michael Sievers. This started in
the same master program project group at the University of Paderborn
as the ESX driver.

See Michael's blog for details: http://hyperv4libvirt.wordpress.com/
---
 po/POTFILES.in              |    1 +
 src/Makefile.am             |    1 +
 src/hyperv/hyperv_driver.c  | 1172 ++++++++++++++++++++++++++++++++++++++++++-
 src/hyperv/hyperv_private.h |    2 +
 src/hyperv/hyperv_util.c    |  129 +++++
 src/hyperv/hyperv_util.h    |   40 ++
 6 files changed, 1343 insertions(+), 2 deletions(-)
 create mode 100644 src/hyperv/hyperv_util.c
 create mode 100644 src/hyperv/hyperv_util.h

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 848d581..809ace6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -29,6 +29,7 @@ src/esx/esx_vi_methods.c
 src/esx/esx_vi_types.c
 src/fdstream.c
 src/hyperv/hyperv_driver.c
+src/hyperv/hyperv_util.c
 src/hyperv/hyperv_wmi.c
 src/interface/netcf_driver.c
 src/internal.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 9971a90..6707181 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -388,6 +388,7 @@ HYPERV_DRIVER_SOURCES =								\
 		hyperv/hyperv_device_monitor.c hyperv/hyperv_device_monitor.h		\
 		hyperv/hyperv_secret_driver.c hyperv/hyperv_secret_driver.h		\
 		hyperv/hyperv_nwfilter_driver.c hyperv/hyperv_nwfilter_driver.h		\
+		hyperv/hyperv_util.c hyperv/hyperv_util.h				\
 		hyperv/hyperv_wmi.c hyperv/hyperv_wmi.h					\
 		hyperv/hyperv_wmi_classes.c hyperv/hyperv_wmi_classes.h			\
 		hyperv/openwsman.h
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index eb01bac..32d360b 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -39,14 +39,42 @@
 #include "hyperv_secret_driver.h"
 #include "hyperv_nwfilter_driver.h"
 #include "hyperv_private.h"
+#include "hyperv_util.h"
+#include "hyperv_wmi.h"
+#include "openwsman.h"
 
 #define VIR_FROM_THIS VIR_FROM_HYPERV
 
 
 
+static void
+hypervFreePrivate(hypervPrivate **priv)
+{
+    if (priv == NULL || *priv == NULL) {
+        return;
+    }
+
+    if ((*priv)->client != NULL) {
+        /* FIXME: This leaks memory due to bugs in openwsman <= 2.2.6 */
+        wsmc_release((*priv)->client);
+    }
+
+    hypervFreeParsedUri(&(*priv)->parsedUri);
+    VIR_FREE(*priv);
+}
+
+
+
 static virDrvOpenStatus
 hypervOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags)
 {
+    virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
+    hypervPrivate *priv = NULL;
+    char *username = NULL;
+    char *password = NULL;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
 
     /* Decline if the URI is NULL or the scheme is not hyperv */
@@ -69,28 +97,1165 @@ hypervOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags)
         return VIR_DRV_OPEN_ERROR;
     }
 
-    return VIR_DRV_OPEN_SUCCESS;
+    /* Allocate per-connection private data */
+    if (VIR_ALLOC(priv) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (hypervParseUri(&priv->parsedUri, conn->uri) < 0) {
+        goto cleanup;
+    }
+
+    /* Set the port dependent on the transport protocol if no port is
+     * specified. This allows us to rely on the port parameter being
+     * correctly set when building URIs later on, without the need to
+     * distinguish between the situations port == 0 and port != 0 */
+    if (conn->uri->port == 0) {
+        if (STRCASEEQ(priv->parsedUri->transport, "https")) {
+            conn->uri->port = 5986;
+        } else {
+            conn->uri->port = 5985;
+        }
+    }
+
+    /* Request credentials */
+    if (conn->uri->user != NULL) {
+        username = strdup(conn->uri->user);
+
+        if (username == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    } else {
+        username = virRequestUsername(auth, "administrator", conn->uri->server);
+
+        if (username == NULL) {
+            HYPERV_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
+            goto cleanup;
+        }
+    }
+
+    password = virRequestPassword(auth, username, conn->uri->server);
+
+    if (password == NULL) {
+        HYPERV_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
+        goto cleanup;
+    }
+
+    /* Initialize the openwsman connection */
+    priv->client = wsmc_create(conn->uri->server, conn->uri->port, "/wsman",
+                               priv->parsedUri->transport, username, password);
+
+    if (priv->client == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Could not create openwsman client"));
+        goto cleanup;
+    }
+
+    if (wsmc_transport_init(priv->client, NULL) != 0) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Could not initialize openwsman transport"));
+        goto cleanup;
+    }
+
+    /* FIXME: Currently only basic authentication is supported  */
+    wsman_transport_set_auth_method(priv->client, "basic");
+
+    /* Check if the connection can be established and if the server has the
+     * Hyper-V role installed. If the call to hypervGetMsvmComputerSystemList
+     * succeeds than the connection has be established. If the returned list
+     * is empty than the server isn't a Hyper-V server. */
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("%s is not a Hyper-V server"), conn->uri->server);
+        goto cleanup;
+    }
+
+    conn->privateData = priv;
+
+    result = VIR_DRV_OPEN_SUCCESS;
+
+  cleanup:
+    if (result == VIR_DRV_OPEN_ERROR) {
+        hypervFreePrivate(&priv);
+    }
+
+    VIR_FREE(username);
+    VIR_FREE(password);
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervClose(virConnectPtr conn)
+{
+    hypervPrivate *priv = conn->privateData;
+
+    hypervFreePrivate(&priv);
+
+    conn->privateData = NULL;
+
+    return 0;
+}
+
+
+
+static const char *
+hypervGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return "Hyper-V";
+}
+
+
+
+static char *
+hypervGetHostname(virConnectPtr conn)
+{
+    char *hostname = NULL;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Win32_ComputerSystem *computerSystem = NULL;
+
+    virBufferAddLit(&query, WIN32_COMPUTERSYSTEM_WQL_SELECT);
+
+    if (hypervGetWin32ComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s"),
+                     "Win32_ComputerSystem");
+        goto cleanup;
+    }
+
+    hostname = strdup(computerSystem->data->DNSHostName);
+
+    if (hostname == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return hostname;
+}
+
+
+
+static int
+hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
+{
+    int result = -1;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Win32_ComputerSystem *computerSystem = NULL;
+    Win32_Processor *processorList = NULL;
+    Win32_Processor *processor = NULL;
+    char *tmp;
+
+    memset(info, 0, sizeof (*info));
+
+    virBufferAddLit(&query, WIN32_COMPUTERSYSTEM_WQL_SELECT);
+
+    /* Get Win32_ComputerSystem */
+    if (hypervGetWin32ComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s"),
+                     "Win32_ComputerSystem");
+        goto cleanup;
+    }
+
+    /* Get Win32_Processor list */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Win32_ComputerSystem.Name=\"%s\"} "
+                      "where AssocClass = Win32_ComputerSystemProcessor "
+                      "ResultClass = Win32_Processor",
+                      computerSystem->data->Name);
+
+    if (hypervGetWin32ProcessorList(priv, &query, &processorList) < 0) {
+        goto cleanup;
+    }
+
+    if (processorList == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s"),
+                     "Win32_Processor");
+        goto cleanup;
+    }
+
+    /* Strip the string to fit more relevant information in 32 chars */
+    tmp = processorList->data->Name;
+
+    while (*tmp != '\0') {
+        if (STRPREFIX(tmp, "  ")) {
+            memmove(tmp, tmp + 1, strlen(tmp + 1) + 1);
+            continue;
+        } else if (STRPREFIX(tmp, "(R)") || STRPREFIX(tmp, "(C)")) {
+            memmove(tmp, tmp + 3, strlen(tmp + 3) + 1);
+            continue;
+        } else if (STRPREFIX(tmp, "(TM)")) {
+            memmove(tmp, tmp + 4, strlen(tmp + 4) + 1);
+            continue;
+        }
+
+        ++tmp;
+    }
+
+    /* Fill struct */
+    if (virStrncpy(info->model, processorList->data->Name,
+                   sizeof (info->model) - 1, sizeof (info->model)) == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("CPU model %s too long for destination"),
+                     processorList->data->Name);
+        goto cleanup;
+    }
+
+    info->memory = computerSystem->data->TotalPhysicalMemory / 1024; /* byte to kilobyte */
+    info->mhz = processorList->data->MaxClockSpeed;
+    info->nodes = 1;
+    info->sockets = 0;
+
+    for (processor = processorList; processor != NULL;
+         processor = processor->next) {
+        ++info->sockets;
+    }
+
+    info->cores = processorList->data->NumberOfCores;
+    info->threads = info->cores / processorList->data->NumberOfLogicalProcessors;
+    info->cpus = info->sockets * info->cores;
+
+    result = 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+    hypervFreeObject(priv, (hypervObject *)processorList);
+
+    return result;
+}
+
+
+
+static int
+hypervListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+    bool success = false;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystemList = NULL;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    int count = 0;
+
+    if (maxids == 0) {
+        return 0;
+    }
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAddLit(&query, "and ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_ACTIVE);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query,
+                                        &computerSystemList) < 0) {
+        goto cleanup;
+    }
+
+    for (computerSystem = computerSystemList; computerSystem != NULL;
+         computerSystem = computerSystem->next) {
+        ids[count++] = computerSystem->data->ProcessID;
+
+        if (count >= maxids) {
+            break;
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystemList);
+
+    return success ? count : -1;
+}
+
+
+
+static int
+hypervNumberOfDomains(virConnectPtr conn)
+{
+    bool success = false;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystemList = NULL;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    int count = 0;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAddLit(&query, "and ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_ACTIVE);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query,
+                                        &computerSystemList) < 0) {
+        goto cleanup;
+    }
+
+    for (computerSystem = computerSystemList; computerSystem != NULL;
+         computerSystem = computerSystem->next) {
+        ++count;
+    }
+
+    success = true;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystemList);
+
+    return success ? count : -1;
+}
+
+
+
+static virDomainPtr
+hypervDomainLookupByID(virConnectPtr conn, int id)
+{
+    virDomainPtr domain = NULL;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAsprintf(&query, "and ProcessID = %d", id);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
+        goto cleanup;
+    }
+
+    hypervMsvmComputerSystemToDomain(conn, computerSystem, &domain);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return domain;
+}
+
+
+
+static virDomainPtr
+hypervDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+    virDomainPtr domain = NULL;
+    hypervPrivate *priv = conn->privateData;
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    virUUIDFormat(uuid, uuid_string);
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAsprintf(&query, "and Name = \"%s\"", uuid_string);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_NO_DOMAIN,
+                     _("No domain with UUID %s"), uuid_string);
+        goto cleanup;
+    }
+
+    hypervMsvmComputerSystemToDomain(conn, computerSystem, &domain);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return domain;
+}
+
+
+
+static virDomainPtr
+hypervDomainLookupByName(virConnectPtr conn, const char *name)
+{
+    virDomainPtr domain = NULL;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAsprintf(&query, "and ElementName = \"%s\"", name);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_NO_DOMAIN,
+                     _("No domain with name %s"), name);
+        goto cleanup;
+    }
+
+    hypervMsvmComputerSystemToDomain(conn, computerSystem, &domain);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return domain;
+}
+
+
+
+static int
+hypervDomainSuspend(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem->data->EnabledState !=
+        MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is not active"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainResume(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem->data->EnabledState !=
+        MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is not paused"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainDestroy(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    bool in_transition = false;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (!hypervIsMsvmComputerSystemActive(computerSystem, &in_transition) ||
+        in_transition) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is not active or is in state transition"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static char *
+hypervDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
+{
+    char *osType = strdup("hvm");
+
+    if (osType == NULL) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return osType;
+}
+
+
+
+static int
+hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL;
+    Msvm_ProcessorSettingData *processorSettingData = NULL;
+    Msvm_MemorySettingData *memorySettingData = NULL;
+
+    memset(info, 0, sizeof (*info));
+
+    virUUIDFormat(domain->uuid, uuid_string);
+
+    /* Get Msvm_ComputerSystem */
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    /* Get Msvm_VirtualSystemSettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\","
+                      "Name=\"%s\"} "
+                      "where AssocClass = Msvm_SettingsDefineState "
+                      "ResultClass = Msvm_VirtualSystemSettingData",
+                      uuid_string);
+
+    if (hypervGetMsvmVirtualSystemSettingDataList(priv, &query,
+                                                  &virtualSystemSettingData) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualSystemSettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_VirtualSystemSettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Get Msvm_ProcessorSettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
+                      "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
+                      "ResultClass = Msvm_ProcessorSettingData",
+                      virtualSystemSettingData->data->InstanceID);
+
+    if (hypervGetMsvmProcessorSettingDataList(priv, &query,
+                                              &processorSettingData) < 0) {
+        goto cleanup;
+    }
+
+    if (processorSettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_ProcessorSettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Get Msvm_MemorySettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
+                      "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
+                      "ResultClass = Msvm_MemorySettingData",
+                      virtualSystemSettingData->data->InstanceID);
+
+    if (hypervGetMsvmMemorySettingDataList(priv, &query,
+                                           &memorySettingData) < 0) {
+        goto cleanup;
+    }
+
+
+    if (memorySettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_MemorySettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Fill struct */
+    info->state = hypervMsvmComputerSystemEnabledStateToDomainState(computerSystem);
+    info->maxMem = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */
+    info->memory = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */
+    info->nrVirtCpu = processorSettingData->data->VirtualQuantity;
+    info->cpuTime = 0;
+
+    result = 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+    hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData);
+    hypervFreeObject(priv, (hypervObject *)processorSettingData);
+    hypervFreeObject(priv, (hypervObject *)memorySettingData);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainGetState(virDomainPtr domain, int *state, int *reason,
+                     unsigned int flags)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    *state = hypervMsvmComputerSystemEnabledStateToDomainState(computerSystem);
+
+    if (reason != NULL) {
+        *reason = 0;
+    }
+
+    result = 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static char *
+hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+    char *xml = NULL;
+    hypervPrivate *priv = domain->conn->privateData;
+    virDomainDefPtr def = NULL;
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL;
+    Msvm_ProcessorSettingData *processorSettingData = NULL;
+    Msvm_MemorySettingData *memorySettingData = NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    virUUIDFormat(domain->uuid, uuid_string);
+
+    /* Get Msvm_ComputerSystem */
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    /* Get Msvm_VirtualSystemSettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\","
+                      "Name=\"%s\"} "
+                      "where AssocClass = Msvm_SettingsDefineState "
+                      "ResultClass = Msvm_VirtualSystemSettingData",
+                      uuid_string);
+
+    if (hypervGetMsvmVirtualSystemSettingDataList(priv, &query,
+                                                  &virtualSystemSettingData) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualSystemSettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_VirtualSystemSettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Get Msvm_ProcessorSettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
+                      "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
+                      "ResultClass = Msvm_ProcessorSettingData",
+                      virtualSystemSettingData->data->InstanceID);
+
+    if (hypervGetMsvmProcessorSettingDataList(priv, &query,
+                                              &processorSettingData) < 0) {
+        goto cleanup;
+    }
+
+    if (processorSettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_ProcessorSettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Get Msvm_MemorySettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
+                      "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
+                      "ResultClass = Msvm_MemorySettingData",
+                      virtualSystemSettingData->data->InstanceID);
+
+    if (hypervGetMsvmMemorySettingDataList(priv, &query,
+                                           &memorySettingData) < 0) {
+        goto cleanup;
+    }
+
+
+    if (memorySettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_MemorySettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Fill struct */
+    def->virtType = VIR_DOMAIN_VIRT_HYPERV;
+
+    if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) {
+        def->id = computerSystem->data->ProcessID;
+    } else {
+        def->id = -1;
+    }
+
+    if (virUUIDParse(computerSystem->data->Name, def->uuid) < 0) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not parse UUID from string '%s'"),
+                     computerSystem->data->Name);
+        return NULL;
+    }
+
+    def->name = strdup(computerSystem->data->ElementName);
+
+    if (def->name == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virtualSystemSettingData->data->Notes != NULL) {
+        def->description = strdup(virtualSystemSettingData->data->Notes);
+
+        if (def->description == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    def->mem.max_balloon = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */
+    def->mem.cur_balloon = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */
+
+    def->vcpus = processorSettingData->data->VirtualQuantity;
+    def->maxvcpus = processorSettingData->data->VirtualQuantity;
+
+    def->os.type = strdup("hvm");
+
+    if (def->os.type == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* FIXME: devices section is totally missing */
+
+    xml = virDomainDefFormat(def, flags);
+
+  cleanup:
+    virDomainDefFree(def);
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+    hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData);
+    hypervFreeObject(priv, (hypervObject *)processorSettingData);
+    hypervFreeObject(priv, (hypervObject *)memorySettingData);
+
+    return xml;
+}
+
+
+
+static int
+hypervListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
+{
+    bool success = false;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystemList = NULL;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    int count = 0;
+    int i;
+
+    if (maxnames == 0) {
+        return 0;
+    }
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAddLit(&query, "and ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_INACTIVE);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query,
+                                        &computerSystemList) < 0) {
+        goto cleanup;
+    }
+
+    for (computerSystem = computerSystemList; computerSystem != NULL;
+         computerSystem = computerSystem->next) {
+        names[count] = strdup(computerSystem->data->ElementName);
+
+        if (names[count] == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        ++count;
+
+        if (count >= maxnames) {
+            break;
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    if (!success) {
+        for (i = 0; i < count; ++i) {
+            VIR_FREE(names[i]);
+        }
+
+        count = -1;
+    }
+
+    hypervFreeObject(priv, (hypervObject *)computerSystemList);
+
+    return count;
+}
+
+
+
+static int
+hypervNumberOfDefinedDomains(virConnectPtr conn)
+{
+    bool success = false;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystemList = NULL;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    int count = 0;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAddLit(&query, "and ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_INACTIVE);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query,
+                                        &computerSystemList) < 0) {
+        goto cleanup;
+    }
+
+    for (computerSystem = computerSystemList; computerSystem != NULL;
+         computerSystem = computerSystem->next) {
+        ++count;
+    }
+
+    success = true;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystemList);
+
+    return success ? count : -1;
 }
 
 
 
 static int
-hypervClose(virConnectPtr conn ATTRIBUTE_UNUSED)
+hypervDomainCreate(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is already active or is in state transition"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervIsEncrypted(virConnectPtr conn)
+{
+    hypervPrivate *priv = conn->privateData;
+
+    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+
+
+static int
+hypervIsSecure(virConnectPtr conn)
+{
+    hypervPrivate *priv = conn->privateData;
+
+    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+
+
+static int
+hypervDomainIsActive(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    result = hypervIsMsvmComputerSystemActive(computerSystem, NULL) ? 1 : 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainIsPersistent(virDomainPtr domain ATTRIBUTE_UNUSED)
+{
+    /* Hyper-V has no concept of transient domains, so all of them are persistent */
+    return 1;
+}
+
+
+
+static int
+hypervDomainIsUpdated(virDomainPtr domain ATTRIBUTE_UNUSED)
 {
     return 0;
 }
 
 
 
+static int
+hypervDomainManagedSave(virDomainPtr domain,
+                        unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    bool in_transition = false;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (!hypervIsMsvmComputerSystemActive(computerSystem, &in_transition) ||
+        in_transition) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is not active or is in state transition"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_SUSPENDED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainHasManagedSaveImage(virDomainPtr domain,
+                                unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    result = computerSystem->data->EnabledState ==
+             MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED ? 1 : 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainManagedSaveRemove(virDomainPtr domain,
+                              unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem->data->EnabledState !=
+        MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain has no managed save image"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
 static virDriver hypervDriver = {
     .no = VIR_DRV_HYPERV,
     .name = "Hyper-V",
     .open = hypervOpen, /* 0.9.4 */
     .close = hypervClose, /* 0.9.4 */
+    .type = hypervGetType, /* 0.9.4 */
+    .getHostname = hypervGetHostname, /* 0.9.4 */
+    .nodeGetInfo = hypervNodeGetInfo, /* 0.9.4 */
+    .listDomains = hypervListDomains, /* 0.9.4 */
+    .numOfDomains = hypervNumberOfDomains, /* 0.9.4 */
+    .domainLookupByID = hypervDomainLookupByID, /* 0.9.4 */
+    .domainLookupByUUID = hypervDomainLookupByUUID, /* 0.9.4 */
+    .domainLookupByName = hypervDomainLookupByName, /* 0.9.4 */
+    .domainSuspend = hypervDomainSuspend, /* 0.9.4 */
+    .domainResume = hypervDomainResume, /* 0.9.4 */
+    .domainDestroy = hypervDomainDestroy, /* 0.9.4 */
+    .domainGetOSType = hypervDomainGetOSType, /* 0.9.4 */
+    .domainGetInfo = hypervDomainGetInfo, /* 0.9.4 */
+    .domainGetState = hypervDomainGetState, /* 0.9.4 */
+    .domainGetXMLDesc = hypervDomainGetXMLDesc, /* 0.9.4 */
+    .listDefinedDomains = hypervListDefinedDomains, /* 0.9.4 */
+    .numOfDefinedDomains = hypervNumberOfDefinedDomains, /* 0.9.4 */
+    .domainCreate = hypervDomainCreate, /* 0.9.4 */
+    .isEncrypted = hypervIsEncrypted, /* 0.9.4 */
+    .isSecure = hypervIsSecure, /* 0.9.4 */
+    .domainIsActive = hypervDomainIsActive, /* 0.9.4 */
+    .domainIsPersistent = hypervDomainIsPersistent, /* 0.9.4 */
+    .domainIsUpdated = hypervDomainIsUpdated, /* 0.9.4 */
+    .domainManagedSave = hypervDomainManagedSave, /* 0.9.4 */
+    .domainHasManagedSaveImage = hypervDomainHasManagedSaveImage, /* 0.9.4 */
+    .domainManagedSaveRemove = hypervDomainManagedSaveRemove, /* 0.9.4 */
 };
 
 
 
+static void
+hypervDebugHandler(const char *message, debug_level_e level,
+                   void *user_data ATTRIBUTE_UNUSED)
+{
+    switch (level) {
+      case DEBUG_LEVEL_ERROR:
+      case DEBUG_LEVEL_CRITICAL:
+        VIR_ERROR(_("openwsman error: %s"), message);
+        break;
+
+      case DEBUG_LEVEL_WARNING:
+        VIR_WARN("openwsman warning: %s", message);
+        break;
+
+      default:
+        /* Ignore the rest */
+        break;
+    }
+}
+
+
+
 int
 hypervRegister(void)
 {
@@ -104,5 +1269,8 @@ hypervRegister(void)
         return -1;
     }
 
+    /* Forward openwsman errors and warnings to libvirt's logging */
+    debug_add_handler(hypervDebugHandler, DEBUG_LEVEL_WARNING, NULL);
+
     return 0;
 }
diff --git a/src/hyperv/hyperv_private.h b/src/hyperv/hyperv_private.h
index 0d5370e..ebddf5d 100644
--- a/src/hyperv/hyperv_private.h
+++ b/src/hyperv/hyperv_private.h
@@ -26,6 +26,7 @@
 
 # include "internal.h"
 # include "virterror_internal.h"
+# include "hyperv_util.h"
 # include "openwsman.h"
 
 # define HYPERV_ERROR(code, ...)                                              \
@@ -35,6 +36,7 @@
 typedef struct _hypervPrivate hypervPrivate;
 
 struct _hypervPrivate {
+    hypervParsedUri *parsedUri;
     WsManClient *client;
 };
 
diff --git a/src/hyperv/hyperv_util.c b/src/hyperv/hyperv_util.c
new file mode 100644
index 0000000..298cfe0
--- /dev/null
+++ b/src/hyperv/hyperv_util.c
@@ -0,0 +1,129 @@
+
+/*
+ * hyperv_util.c: utility functions for the Microsoft Hyper-V driver
+ *
+ * Copyright (C) 2011 Matthias Bolte <matthias.bolte at googlemail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "qparams.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "hyperv_private.h"
+#include "hyperv_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_HYPERV
+
+
+
+int
+hypervParseUri(hypervParsedUri **parsedUri, xmlURIPtr uri)
+{
+    int result = -1;
+    struct qparam_set *queryParamSet = NULL;
+    struct qparam *queryParam = NULL;
+    int i;
+
+    if (parsedUri == NULL || *parsedUri != NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (VIR_ALLOC(*parsedUri) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+#ifdef HAVE_XMLURI_QUERY_RAW
+    queryParamSet = qparam_query_parse(uri->query_raw);
+#else
+    queryParamSet = qparam_query_parse(uri->query);
+#endif
+
+    if (queryParamSet == NULL) {
+        goto cleanup;
+    }
+
+    for (i = 0; i < queryParamSet->n; i++) {
+        queryParam = &queryParamSet->p[i];
+
+        if (STRCASEEQ(queryParam->name, "transport")) {
+            VIR_FREE((*parsedUri)->transport);
+
+            (*parsedUri)->transport = strdup(queryParam->value);
+
+            if ((*parsedUri)->transport == NULL) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            if (STRNEQ((*parsedUri)->transport, "http") &&
+                STRNEQ((*parsedUri)->transport, "https")) {
+                HYPERV_ERROR(VIR_ERR_INVALID_ARG,
+                             _("Query parameter 'transport' has unexpected value "
+                               "'%s' (should be http|https)"),
+                             (*parsedUri)->transport);
+                goto cleanup;
+            }
+        } else {
+            VIR_WARN("Ignoring unexpected query parameter '%s'",
+                     queryParam->name);
+        }
+    }
+
+    if ((*parsedUri)->transport == NULL) {
+        (*parsedUri)->transport = strdup("https");
+
+        if ((*parsedUri)->transport == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    result = 0;
+
+  cleanup:
+    if (result < 0) {
+        hypervFreeParsedUri(parsedUri);
+    }
+
+    if (queryParamSet != NULL) {
+        free_qparam_set(queryParamSet);
+    }
+
+    return result;
+}
+
+
+
+void
+hypervFreeParsedUri(hypervParsedUri **parsedUri)
+{
+    if (parsedUri == NULL || *parsedUri == NULL) {
+        return;
+    }
+
+    VIR_FREE((*parsedUri)->transport);
+
+    VIR_FREE(*parsedUri);
+}
diff --git a/src/hyperv/hyperv_util.h b/src/hyperv/hyperv_util.h
new file mode 100644
index 0000000..9057f55
--- /dev/null
+++ b/src/hyperv/hyperv_util.h
@@ -0,0 +1,40 @@
+
+/*
+ * hyperv_util.h: utility functions for the Microsoft Hyper-V driver
+ *
+ * Copyright (C) 2011 Matthias Bolte <matthias.bolte at googlemail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ */
+
+#ifndef __HYPERV_UTIL_H__
+# define __HYPERV_UTIL_H__
+
+# include <libxml/uri.h>
+
+# include "internal.h"
+
+typedef struct _hypervParsedUri hypervParsedUri;
+
+struct _hypervParsedUri {
+    char *transport;
+};
+
+int hypervParseUri(hypervParsedUri **parsedUri, xmlURIPtr uri);
+
+void hypervFreeParsedUri(hypervParsedUri **parsedUri);
+
+#endif /* __HYPERV_UTIL_H__ */
-- 
1.7.4.1




More information about the libvir-list mailing list