[libvirt] [PATCH] virsh: trim aliases from -h output
by Eric Blake
Commit af3f9aab taught 'virsh help' to ignore command aliases,
but forgot 'virsh -h'.
* tools/virsh.c (vshUsage): Handle aliases.
---
tools/virsh.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 19f9bbe..e48c56a 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -19721,8 +19721,11 @@ vshUsage(void)
fprintf(stdout, _(" %s (help keyword '%s')\n"), grp->name, grp->keyword);
for (cmd = grp->commands; cmd->name; cmd++)
+ if (cmd->flags & VSH_CMD_FLAG_ALIAS)
+ continue;
fprintf(stdout,
- " %-30s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help")));
+ " %-30s %s\n", cmd->name,
+ _(vshCmddefGetInfo(cmd, "help")));
fprintf(stdout, "\n");
}
--
1.7.7.6
12 years, 9 months
[libvirt] QEMU was not selected for Google Summer of Code this year
by Stefan Hajnoczi
Sad news - QEMU was not accepted for Google Summer of Code 2012.
Students can consider other organizations in the accepted
organizations list here:
http://www.google-melange.com/gsoc/accepted_orgs/google/gsoc2012
The list is currently not complete but should be finalized over the
next few days as organizations complete their profiles.
Students and mentors who wanted to participate with QEMU will be
disappointed. I am too but there are many factors that organizations
are considered against, we have not received information why QEMU was
rejected this year.
QEMU will try again for sure next year because Google Summer of Code
is a great program both for students and for QEMU.
Stefan
12 years, 9 months
[libvirt] Storage pool support for large scale deployments
by Jesse J. Cook
I am using libvirt for large scale deployment of virtual machines. I ran into
an issue where virConnectListStoragePools and virConnectListDefinedStoragePools
return an error if there are more than 256 pools. The following patch increases
this limitation. Currently, I am only using in the neighborhood of 500 pools,
but this is likely to grow into the tens of thousands.
This patch did not cause any test failures. I wrote some test code to verify
the fix worked. The test code and the results follow.
TEST CODE:
/* pool-test src code */
#include <libvirt.h>
#include <stdlib.h>
#include <stdio.h>
static int get_active_pools(virConnectPtr vir_conn)
{
int ret_code = -1;
int rc = -1;
int num_pools = -1;
char** pools = NULL;
printf("Before virConnectNumOfStoragePools\n");
num_pools = virConnectNumOfStoragePools(vir_conn);
printf("After virConnectNumOfStoragePools\n");
if(0 >= num_pools) goto cleanup;
pools = malloc(sizeof(*pools) * num_pools);
printf("Before virConnectListStoragePools\n");
rc = virConnectListStoragePools(vir_conn, pools, num_pools);
printf("After virConnectListStoragePools\n");
if(-1 == rc) goto cleanup;
for(int i = 0; i < num_pools; ++i) {
if(NULL != pools[i]) free(pools[i]);
}
ret_code = num_pools;
cleanup:
if(NULL != pools) free(pools);
return ret_code;
}
static int get_inactive_pools(virConnectPtr vir_conn)
{
int ret_code = -1;
int rc = -1;
int num_pools = -1;
char** pools = NULL;
printf("Before virConnectNumOfDefinedStoragePools\n");
num_pools = virConnectNumOfDefinedStoragePools(vir_conn);
printf("After virConnectNumOfDefinedStoragePools\n");
if(0 >= num_pools) goto cleanup;
pools = malloc(sizeof(*pools) * num_pools);
printf("Before virConnectListDefinedStoragePools\n");
rc = virConnectListDefinedStoragePools(vir_conn, pools, num_pools);
printf("After virConnectListDefinedStoragePools\n");
if(-1 == rc) goto cleanup;
for(int i = 0; i < num_pools; ++i) {
if(NULL != pools[i]) free(pools[i]);
}
ret_code = num_pools;
cleanup:
if(NULL != pools) free(pools);
return ret_code;
}
int main(int argc, char** argv)
{
virConnectPtr conn = virConnectOpen("qemu:///system");
printf("Active: %d\n" , get_active_pools(conn ));
printf("Inactive: %d\n", get_inactive_pools(conn));
virConnectClose(conn);
return 0;
}
TEST RESULTS PRE-PATCH:
# for i in `ls -1 /etc/libvirt/storage/*`; do virsh pool-start $(basename $i .xml); done &>/dev/null
# ~/pool-test
Before virConnectNumOfStoragePools
After virConnectNumOfStoragePools
Before virConnectListStoragePools
libvir: Remote error : too many remote undefineds: 407 > 256
After virConnectListStoragePools
Active: -1
Before virConnectNumOfDefinedStoragePools
After virConnectNumOfDefinedStoragePools
Inactive: -1
# for i in `ls -1 /etc/libvirt/storage/*`; do virsh pool-destroy $(basename $i .xml); done &>/dev/null
# ~/pool-test
Before virConnectNumOfStoragePools
After virConnectNumOfStoragePools
Active: -1
Before virConnectNumOfDefinedStoragePools
After virConnectNumOfDefinedStoragePools
Before virConnectListDefinedStoragePools
libvir: Remote error : too many remote undefineds: 407 > 256
After virConnectListDefinedStoragePools
Inactive: -1
TEST RESULTS POST-PATCH:
# for i in `ls -1 /etc/libvirt/storage/*`; do virsh pool-start $(basename $i .xml); done &>/dev/null
# ~/pool-test
Before virConnectNumOfStoragePools
After virConnectNumOfStoragePools
Before virConnectListStoragePools
After virConnectListStoragePools
Active: 407
Before virConnectNumOfDefinedStoragePools
After virConnectNumOfDefinedStoragePools
Inactive: -1
# for i in `ls -1 /etc/libvirt/storage/*`; do virsh pool-destroy $(basename $i .xml); done &>/dev/null
# ~/pool-test
Before virConnectNumOfStoragePools
After virConnectNumOfStoragePools
Active: -1
Before virConnectNumOfDefinedStoragePools
After virConnectNumOfDefinedStoragePools
Before virConnectListDefinedStoragePools
After virConnectListDefinedStoragePools
Inactive: 407
12 years, 9 months
[libvirt] [PATCH] Add migration APIs for libxl driver
by Chunyan Liu
Add migration APIs for libxl driver.
Implemented in migration version 3. Based on xen 4.1.
Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
src/libxl/libxl_driver.c | 617 ++++++++++++++++++++++++++++++++++++++++++++++
src/libxl/libxl_driver.h | 17 ++-
2 files changed, 632 insertions(+), 2 deletions(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index d5fa64a..4037635 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -30,6 +30,12 @@
#include <math.h>
#include <libxl.h>
#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
#include "internal.h"
#include "logging.h"
@@ -60,6 +66,13 @@
#define XEN_SCHED_CREDIT_NPARAM 2
static libxlDriverPrivatePtr libxl_driver = NULL;
+static virThread migrate_receive_thread;
+
+typedef struct migrate_receive_args {
+ virConnectPtr conn;
+ virDomainObjPtr vm;
+ int sockfd;
+} migrate_receive_args;
/* Function declarations */
static int
@@ -1095,6 +1108,17 @@ libxlClose(virConnectPtr conn ATTRIBUTE_UNUSED)
return 0;
}
+static int
+libxlSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
+{
+ switch (feature) {
+ case VIR_DRV_FEATURE_MIGRATION_V3:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static const char *
libxlGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
{
@@ -3842,12 +3866,600 @@ libxlIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
return 1;
}
+static int libxlReadFixedMessage(int fd, const void *msg, int msgsz)
+{
+ char buf[msgsz];
+
+ if (saferead(fd, buf, msgsz) != msgsz || memcmp(buf, msg, msgsz)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int doParseURI(const char *uri, char **p_hostname, int *p_port)
+{
+ char *p, *hostname;
+ char port[16] = "0";
+
+ if (strstr (uri, "//")) { /* Full URI. */
+ virURIPtr uriptr = virURIParse(uri);
+ if (!uriptr) {
+ libxlError(VIR_ERR_INVALID_ARG,
+ _("Invalid URI"));
+ return -1;
+ }
+ if (uriptr->scheme && STRCASENEQ(uriptr->scheme, "xlmigr")) {
+ libxlError(VIR_ERR_INVALID_ARG,
+ _("Only xlmigr://"
+ " migrations are supported by Xen"));
+ xmlFreeURI(uriptr);
+ return -1;
+ }
+ if (!uriptr->server) {
+ libxlError(VIR_ERR_INVALID_ARG,
+ _("A hostname must be"
+ " specified in the URI"));
+ xmlFreeURI(uriptr);
+ return -1;
+ }
+ hostname = strdup(uriptr->server);
+ if (!hostname) {
+ virReportOOMError();
+ xmlFreeURI(uriptr);
+ return -1;
+ }
+ if (uriptr->port)
+ snprintf(port, sizeof(port), "%d", uriptr->port);
+ xmlFreeURI(uriptr);
+ }
+ else if ((p = strrchr(uri, ':')) != NULL) { /* "hostname:port" */
+ int port_nr, n;
+
+ if (virStrToLong_i(p+1, NULL, 10, &port_nr) < 0) {
+ libxlError(VIR_ERR_INVALID_ARG,
+ _("Invalid port number"));
+ return -1;
+ }
+ snprintf(port, sizeof(port), "%d", port_nr);
+
+ /* Get the hostname. */
+ n = p - uri; /* n = Length of hostname in bytes. */
+ hostname = strdup(uri);
+ if (!hostname) {
+ virReportOOMError();
+ return -1;
+ }
+ hostname[n] = '\0';
+ }
+ else {/* "hostname" (or IP address) */
+ hostname = strdup(uri);
+ if (!hostname) {
+ virReportOOMError();
+ return -1;
+ }
+ }
+ *p_hostname = hostname;
+ *p_port = atoi(port);
+ return 0;
+}
+
+static bool libxlMigrationFromIsAllowed(libxlDriverPrivatePtr driver, virDomainObjPtr vm)
+{
+ /* to be extended */
+ VIR_DEBUG("driver=%p, vm=%p", driver, vm);
+ return true;
+}
+
+static bool libxlMigrationToIsAllowed(libxlDriverPrivatePtr driver, virDomainDefPtr def)
+{
+ /* to be extended */
+ VIR_DEBUG("driver=%p, def=%p", driver, def);
+ return true;
+}
+
+static char *
+libxlDomainMigrateBegin3(virDomainPtr domain,
+ const char *xmlin,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ unsigned long flags,
+ const char *dname ATTRIBUTE_UNUSED,
+ unsigned long resource ATTRIBUTE_UNUSED)
+{
+ libxlDriverPrivatePtr driver = domain->conn->privateData;
+ virDomainObjPtr vm;
+ virDomainDefPtr def = NULL;
+ char *xml = NULL;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, domain->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(domain->uuid, uuidstr);
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (!libxlMigrationFromIsAllowed(driver, vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("domain cannot do migration"));
+ goto cleanup;
+ }
+
+ if (xmlin) {
+ if (!(def = virDomainDefParseString(driver->caps, xml,
+ 1 << VIR_DOMAIN_VIRT_XEN,
+ VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ xml = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE);
+ } else {
+ xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
+ }
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return xml;
+}
+
+static void doMigrateReceive(void *opaque)
+{
+ migrate_receive_args *data = opaque;
+ virConnectPtr conn = data->conn;
+ int sockfd = data->sockfd;
+ virDomainObjPtr vm = data->vm;
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int recv_fd;
+ struct sockaddr_in new_addr;
+ socklen_t socklen = sizeof(new_addr);
+ int len;
+
+ do {
+ recv_fd = accept(sockfd, (struct sockaddr *)&new_addr, &socklen);
+ } while(recv_fd < 0 && errno == EINTR);
+
+ VIR_DEBUG("Accepted migration\n");
+ if (recv_fd < 0) {
+ VIR_DEBUG("Could not accept migration connection\n");
+ goto cleanup;
+ }
+
+ len = sizeof(migrate_receiver_banner);
+ if (safewrite(recv_fd, migrate_receiver_banner, len) != len) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to write migrate_receiver_banner"));
+ goto cleanup;
+ }
+
+ if (libxlVmStart(driver, vm, false, recv_fd) < 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to restore domain with libxenlight"));
+ if (!vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+ goto cleanup;
+ }
+
+ len = sizeof(migrate_receiver_ready);
+ if (safewrite(recv_fd, migrate_receiver_ready, len) != len) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to write migrate_receiver_ready"));
+ }
+
+cleanup:
+ if (VIR_CLOSE(recv_fd) < 0)
+ virReportSystemError(errno, "%s", _("cannot close recv_fd"));
+ if (VIR_CLOSE(sockfd) < 0)
+ virReportSystemError(errno, "%s", _("cannot close sockfd"));
+ if (vm)
+ virDomainObjUnlock(vm);
+ VIR_FREE(opaque);
+ return;
+}
+
+static int doMigrateSend(virDomainPtr dom, unsigned long flags, int sockfd)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ libxlDomainObjPrivatePtr priv;
+ libxl_domain_suspend_info suspinfo;
+ virDomainEventPtr event = NULL;
+ int live = 0;
+ int ret = -1;
+
+ if (flags & VIR_MIGRATE_LIVE)
+ live = 1;
+
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+
+ /* read fixed message from dest (ready to receive) */
+ if (libxlReadFixedMessage(sockfd, migrate_receiver_banner,
+ sizeof(migrate_receiver_banner))) {
+ goto cleanup;
+ }
+
+ /* send suspend data */
+ memset(&suspinfo, 0, sizeof(suspinfo));
+ if (live == 1)
+ suspinfo.flags |= XL_SUSPEND_LIVE;
+ if (libxl_domain_suspend(&priv->ctx, &suspinfo, vm->def->id, sockfd) != 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to save domain '%d' with libxenlight"),
+ vm->def->id);
+ goto cleanup;
+ }
+
+ /* read fixed message from dest (receive completed) */
+ if (libxlReadFixedMessage(sockfd, migrate_receiver_ready,
+ sizeof(migrate_receiver_ready))) {
+ /* Src side should be resumed, but for ret < 0, virsh won't call Src side
+ * Confirm3, handle it here.
+ */
+ libxl_domain_resume(&priv->ctx, vm->def->id);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ if (event)
+ libxlDomainEventQueue(driver, event);
+ return ret;
+}
+
+static int
+libxlDomainMigratePrepare3(virConnectPtr dconn,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource ATTRIBUTE_UNUSED,
+ const char *dom_xml)
+{
+ libxlDriverPrivatePtr driver = dconn->privateData;
+ virDomainDefPtr def = NULL;
+ virDomainObjPtr vm = NULL;
+ int port = 0;
+ int sockfd = -1;
+ struct sockaddr_in addr;
+ migrate_receive_args *args;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ libxlDriverLock(driver);
+ if (!dom_xml) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("no domain XML passed"));
+ goto cleanup;
+ }
+
+ def = virDomainDefParseString(driver->caps, dom_xml,
+ 1 << VIR_DOMAIN_VIRT_XEN,
+ VIR_DOMAIN_XML_INACTIVE);
+
+ if (!libxlMigrationToIsAllowed(driver, def)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("cannot migrate domain to this host"));
+ goto cleanup;
+ }
+
+ /* Target domain name, maybe renamed. */
+ if (dname) {
+ def->name = strdup(dname);
+ if (def->name == NULL)
+ goto cleanup;
+ }
+
+ if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
+ goto cleanup;
+
+ if (!(vm = virDomainAssignDef(driver->caps, &driver->domains, def, true)))
+ goto cleanup;
+
+ def = NULL;
+
+ /* Create socket connection to receive migration data */
+ if (!uri_in) {
+ *uri_out = virGetHostname(dconn);
+ if (*uri_out == NULL)
+ goto cleanup;
+ } else {
+ char *hostname = NULL;
+ doParseURI(uri_in, &hostname, &port);
+ VIR_FREE (hostname);
+ }
+
+ if (port <= 0)
+ port = DEFAULT_MIGRATION_PORT;
+
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ _("Failed to create socket"));
+ goto cleanup;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Bind error"));
+ goto cleanup;
+ }
+
+ if (listen(sockfd, MAXCONN_NUM) < 0){
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Listen error"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC(args) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ args->conn = dconn;
+ args->vm = vm;
+ args->sockfd = sockfd;
+ if (virThreadCreate(&migrate_receive_thread,
+ true,
+ doMigrateReceive, args) < 0 ) {
+ virReportSystemError(errno, "%s",
+ _("Unable to create migration thread"));
+ VIR_FREE(args);
+ goto cleanup;
+ }
+
+ ret = 0;
+ goto end;
+
+cleanup:
+ if (VIR_CLOSE(sockfd) < 0)
+ virReportSystemError(errno, "%s", _("cannot close sockfd"));
+ if (vm)
+ virDomainObjUnlock(vm);
+
+end:
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainMigratePerform3(virDomainPtr dom,
+ const char *xmlin ATTRIBUTE_UNUSED,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ const char *dconnuri ATTRIBUTE_UNUSED,
+ const char *uri,
+ unsigned long flags,
+ const char *dname ATTRIBUTE_UNUSED,
+ unsigned long resource ATTRIBUTE_UNUSED)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ char *hostname = NULL;
+ int port;
+ char *servname = NULL;
+ struct addrinfo hints, *res;
+ int sockfd = -1;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ libxlDriverLock(driver);
+
+ if (doParseURI(uri, &hostname, &port))
+ goto cleanup;
+
+ VIR_DEBUG("hostname = %s, port = %d", hostname, port);
+
+ if (virAsprintf(&servname, "%d", port ? port : DEFAULT_MIGRATION_PORT) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ){
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to create socket"));
+ goto cleanup;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(hostname, servname, &hints, &res) || res == NULL) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("IP address lookup failed"));
+ goto cleanup;
+ }
+
+ if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Connect error"));
+ goto cleanup;
+ }
+
+ ret = doMigrateSend(dom, flags, sockfd);
+
+cleanup:
+ if (VIR_CLOSE(sockfd) < 0)
+ virReportSystemError(errno, "%s", _("cannot close sockfd"));
+ VIR_FREE (hostname);
+ VIR_FREE(servname);
+ freeaddrinfo(res);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static virDomainPtr
+libxlDomainMigrateFinish3(virConnectPtr dconn,
+ const char *dname,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ const char *dconnuri ATTRIBUTE_UNUSED,
+ const char *uri ATTRIBUTE_UNUSED,
+ unsigned long flags,
+ int cancelled)
+{
+ libxlDriverPrivatePtr driver = dconn->privateData;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+ libxlDomainObjPrivatePtr priv;
+ virDomainEventPtr event = NULL;
+ int rc;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
+ virThreadJoin(&migrate_receive_thread);
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByName(&driver->domains, dname);
+ if (!vm)
+ goto cleanup;
+
+ if (!cancelled) {
+ if (!(flags & VIR_MIGRATE_PAUSED)) {
+ priv = vm->privateData;
+ rc = libxl_domain_unpause(&priv->ctx, vm->def->id);
+ if (rc) {
+ libxlError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to unpause domain"));
+ goto error;
+ }
+
+ virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
+ goto error;
+ }
+
+ dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
+ goto cleanup;
+ }
+
+error:
+ if (libxlVmReap(driver, vm, 1, VIR_DOMAIN_SHUTOFF_SAVED)) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to destroy domain '%d'"), vm->def->id);
+ goto cleanup;
+ }
+ event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
+ if (!vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ if (event)
+ libxlDomainEventQueue(driver, event);
+ libxlDriverUnlock(driver);
+ return dom;
+}
+
+static int
+libxlDomainMigrateConfirm3(virDomainPtr domain,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ unsigned long flags,
+ int cancelled)
+{
+ libxlDriverPrivatePtr driver = domain->conn->privateData;
+ virDomainObjPtr vm;
+ libxlDomainObjPrivatePtr priv;
+ virDomainEventPtr event = NULL;
+ int ret = -1;
+
+ virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, domain->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(domain->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (cancelled) {
+ priv = vm->privateData;
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("migration failed, try to resume on our end"));
+ if (!libxl_domain_resume(&priv->ctx, vm->def->id))
+ ret = 0;
+
+ goto cleanup;
+ }
+
+ if (libxlVmReap(driver, vm, 1, VIR_DOMAIN_SHUTOFF_SAVED)) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to destroy domain '%d'"), vm->def->id);
+ goto cleanup;
+ }
+
+ event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
+
+ if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
+ virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm);
+
+ if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+
+ VIR_DEBUG("Migration successful.\n");
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
static virDriver libxlDriver = {
.no = VIR_DRV_LIBXL,
.name = "xenlight",
.open = libxlOpen, /* 0.9.0 */
.close = libxlClose, /* 0.9.0 */
+ .supports_feature = libxlSupportsFeature, /* 0.9.9 */
.type = libxlGetType, /* 0.9.0 */
.version = libxlGetVersion, /* 0.9.0 */
.getHostname = virGetHostname, /* 0.9.0 */
@@ -3906,6 +4518,11 @@ static virDriver libxlDriver = {
.domainGetSchedulerParametersFlags = libxlDomainGetSchedulerParametersFlags, /* 0.9.2 */
.domainSetSchedulerParameters = libxlDomainSetSchedulerParameters, /* 0.9.0 */
.domainSetSchedulerParametersFlags = libxlDomainSetSchedulerParametersFlags, /* 0.9.2 */
+ .domainMigrateBegin3 = libxlDomainMigrateBegin3, /* 0.9.9 */
+ .domainMigratePrepare3 = libxlDomainMigratePrepare3, /* 0.9.0 */
+ .domainMigratePerform3 = libxlDomainMigratePerform3, /* 0.9.9 */
+ .domainMigrateFinish3 = libxlDomainMigrateFinish3, /* 0.9.9 */
+ .domainMigrateConfirm3 = libxlDomainMigrateConfirm3, /* 0.9.9 */
.nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
.domainEventRegister = libxlDomainEventRegister, /* 0.9.0 */
.domainEventDeregister = libxlDomainEventDeregister, /* 0.9.0 */
diff --git a/src/libxl/libxl_driver.h b/src/libxl/libxl_driver.h
index 4632d33..8a5fa6b 100644
--- a/src/libxl/libxl_driver.h
+++ b/src/libxl/libxl_driver.h
@@ -21,9 +21,22 @@
/*---------------------------------------------------------------------------*/
#ifndef LIBXL_DRIVER_H
-# define LIBXL_DRIVER_H
+#define LIBXL_DRIVER_H
-# include <config.h>
+#include <config.h>
+
+#define LIBXL_MIGRATION_FLAGS \
+ (VIR_MIGRATE_LIVE | \
+ VIR_MIGRATE_UNDEFINE_SOURCE | \
+ VIR_MIGRATE_PAUSED)
+
+#define DEFAULT_MIGRATION_PORT 8002
+#define MAXCONN_NUM 10
+
+static const char migrate_receiver_banner[]=
+ "xl migration receiver ready, send binary domain data";
+static const char migrate_receiver_ready[]=
+ "domain received, ready to unpause";
int libxlRegister(void);
--
1.7.3.4
12 years, 9 months
[libvirt] [PATCH] Fix handling of blkio deviceWeight empty string
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
A common coding pattern for changing blkio parameters is
1. virDomainGetBlkioParameters
2. change one or more params
3. virDomainSetBlkioParameters
For this to work, it must be possible to roundtrip through
the methods without error. Unforuntelty virDomainGetBlkioParameters
will return "" for the deviceWeight parameter for guests by default,
which virDomainSetBlkioParameters will then reject as invalid.
This fixes the handling of "" to be a no-op, and also improves the
error message to tell you what was invalid
---
src/qemu/qemu_driver.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b20b3e9..2c467ab 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5959,6 +5959,12 @@ qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
int i;
virBlkioDeviceWeightPtr result = NULL;
+ *dw = NULL;
+ *size = 0;
+
+ if (STREQ(deviceWeightStr, ""))
+ return 0;
+
temp = deviceWeightStr;
while (temp) {
temp = strchr(temp, ',');
@@ -6021,7 +6027,7 @@ qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
error:
qemuReportError(VIR_ERR_INVALID_ARG,
- _("unable to parse %s"), deviceWeightStr);
+ _("unable to parse device weight '%s'"), deviceWeightStr);
cleanup:
virBlkioDeviceWeightArrayClear(result, ndevices);
VIR_FREE(result);
--
1.7.7.6
12 years, 9 months
[libvirt] [PATCH] remote: Fix migration leaks
by Osier Yang
How to reproduce:
% valgrind -v --leak-check=full virsh migrate mig \
qemu+ssh://$dest/system --unsafe
== 8 bytes in 1 blocks are definitely lost in loss record 1 of 28
== at 0x4A04A28: calloc (vg_replace_malloc.c:467)
== by 0x3EB7115FB8: xdr_reference (in /lib64/libc-2.12.so)
== by 0x3EB7115F10: xdr_pointer (in /lib64/libc-2.12.so)
== by 0x4D1EA84: xdr_remote_string (remote_protocol.c:40)
== by 0x4D1EAD8: xdr_remote_domain_migrate_prepare3_ret (remote_protocol.c:4772)
== by 0x4D2FFD2: virNetMessageDecodePayload (virnetmessage.c:382)
== by 0x4D2789C: virNetClientProgramCall (virnetclientprogram.c:382)
== by 0x4D0707D: callWithFD (remote_driver.c:4549)
== by 0x4D070FB: call (remote_driver.c:4570)
== by 0x4D12AEE: remoteDomainMigratePrepare3 (remote_driver.c:4138)
== by 0x4CF7BE9: virDomainMigrateVersion3 (libvirt.c:4815)
== by 0x4CF9432: virDomainMigrate2 (libvirt.c:5454)
==
== LEAK SUMMARY:
== definitely lost: 8 bytes in 1 blocks
== indirectly lost: 0 bytes in 0 blocks
== possibly lost: 0 bytes in 0 blocks
== still reachable: 126,995 bytes in 1,343 blocks
== suppressed: 0 bytes in 0 blocks
This patch also fixes the leaks in remoteDomainMigratePrepare and
remoteDomainMigratePrepare2.
---
src/remote/remote_driver.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 031167a..4ddebcb 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -1963,6 +1963,7 @@ remoteDomainMigratePrepare (virConnectPtr dconn,
if (ret.uri_out)
*uri_out = *ret.uri_out; /* Caller frees. */
+ VIR_FREE(ret.uri_out);
rv = 0;
done:
@@ -2018,6 +2019,7 @@ remoteDomainMigratePrepare2 (virConnectPtr dconn,
rv = 0;
done:
+ VIR_FREE(ret.uri_out);
remoteDriverUnlock(priv);
return rv;
error:
@@ -4161,6 +4163,7 @@ remoteDomainMigratePrepare3(virConnectPtr dconn,
rv = 0;
done:
+ VIR_FREE(ret.uri_out);
remoteDriverUnlock(priv);
return rv;
error:
--
1.7.1
12 years, 9 months
[libvirt] [PATCH] libvirt: fix comment typo
by Alex Jia
* src/libvirt.c (virStorageVolResize): correct comment typo according to
virStorageVolResizeFlags enum define.
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
src/libvirt.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c
index d0b1b28..7f8d42c 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -13324,15 +13324,15 @@ error:
* capacity; this may make the operation take noticeably longer.
*
* Normally, the operation treats @capacity as the new size in bytes;
- * but if @flags contains VIR_STORAGE_RESIZE_DELTA, then @capacity
+ * but if @flags contains VIR_STORAGE_VOL_RESIZE_DELTA, then @capacity
* represents the size difference to add to the current size. It is
* up to the storage pool implementation whether unaligned requests are
* rounded up to the next valid boundary, or rejected.
*
* Normally, this operation should only be used to enlarge capacity;
- * but if @flags contains VIR_STORAGE_RESIZE_SHRINK, it is possible to
+ * but if @flags contains VIR_STORAGE_VOL_RESIZE_SHRINK, it is possible to
* attempt a reduction in capacity even though it might cause data loss.
- * If VIR_STORAGE_RESIZE_DELTA is also present, then @capacity is
+ * If VIR_STORAGE_VOL_RESIZE_DELTA is also present, then @capacity is
* subtracted from the current size; without it, @capacity represents
* the absolute new size regardless of whether it is larger or smaller
* than the current size.
--
1.7.1
12 years, 9 months
[libvirt] [PATCH v2 0/5] Allow hibernation on guests
by Michal Privoznik
As we've added guest agent recently, the whole world
of new functionality has opened. As this patch set,
which allows domains to enter S4 state.
What is needed for this?
Patched qemu. As this is not in qemu git, but patches
are await to be pushed in very short future. They can
be found here:
http://lists.gnu.org/archive/html/qemu-devel/2012-01/msg03261.html
Despite that, if anybody is willing to give me review
if I am going the right way, I'd appreciate it.
One thing, that you'll probably notice is this
'set-support-level' command. Basically, it tells GA what qemu version
is it running on. Ideally, this should be done as soon as
GA starts up. However, that cannot be determined from outside
world as GA doesn't emit any events yet.
Ideally^2 this command should be left out as it should be qemu
who tells its own agent this kind of information.
Anyway, I was going to call this command in qemuProcess{Startup,
Reconnect,Attach}, but it won't work. We need to un-pause guest CPUs
so guest can boot and start GA, but that implies returning from qemuProcess*.
So I am setting this just before 'guest-suspend' command, as
there is one more thing about GA. It is unable to remember anything
upon its restart (GA process). Which has BTW show flaw
in our current code with FS freeze & thaw. If we freeze guest
FS, and somebody restart GA, the simple FS Thaw will not succeed as
GA thinks FS are not frozen. But that's a different cup of tea.
Because of what written above, we need to call set-level
on every suspend.
diff to v1:
-move from misusing virDomainSuspend to brand new
virDomainSuspendForDuration API
Michal Privoznik (5):
qemu-agent: Allow setting supported level
qemu-agent: Create suspend function
Introduce virDomainSuspendForDuration API
qemu: Wire up virDomainSuspendForDuration API
virsh: Expose new virDomainSuspendForDuration API
include/libvirt/libvirt.h.in | 5 ++-
src/driver.h | 6 ++
src/libvirt.c | 58 +++++++++++++++++++++++
src/libvirt_public.syms | 1 +
src/qemu/qemu_agent.c | 105 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_agent.h | 13 +++++
src/qemu/qemu_driver.c | 93 +++++++++++++++++++++++++++++++++++++
src/qemu/qemu_process.c | 45 +++++++++++++++++-
src/remote/remote_driver.c | 1 +
src/remote/remote_protocol.x | 11 ++++-
src/remote_protocol-structs | 7 +++
tools/virsh.c | 67 +++++++++++++++++++++++++++
tools/virsh.pod | 8 +++
13 files changed, 415 insertions(+), 5 deletions(-)
--
1.7.3.4
12 years, 9 months
Re: [libvirt] Using Libvirt to change the bridge a virtual network card of a running vm is connected to
by Hendrik Schwartke
I wrote a patch to change the mapping between a virtual bridge interface
and the host bridge while the host is up. It's based on commit
6fba577e505611e6c25c68e322942eab7754de7e. The host and the interface
definition I used for testing are also attached.
I would be glad if the patch could be added to the repo.
Patch:
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 4b60839..f791795 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -40,6 +40,7 @@
#include "qemu_cgroup.h"
#include "locking/domain_lock.h"
#include "network/bridge_driver.h"
+#include "util/virnetdevbridge.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -1163,6 +1164,28 @@ static virDomainNetDefPtr
qemuDomainFindNet(virDomainObjPtr vm,
return NULL;
}
+int qemuDomainChangeNetBridge(virDomainNetDefPtr olddev,
+ virDomainNetDefPtr newdev)
+{
+ const char *oldbridge=olddev->data.bridge.brname;
+ const char *newbridge=newdev->data.bridge.brname;
+ VIR_DEBUG("Change bridge for interface %s: %s -> %s",
olddev->ifname, oldbridge, newbridge);
+ if(virNetDevBridgeRemovePort(oldbridge, olddev->ifname)<0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("unable to remove port from bridge"));
+ return -1;
+ }
+ if(virNetDevBridgeAddPort(newbridge, newdev->ifname)<0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("unable to add port to bridge"));
+ return -1;
+ }
+ VIR_FREE(olddev->data.bridge.brname);
+ olddev->data.bridge.brname=strdup(newbridge);
+ return 0;
+}
+
+
int qemuDomainChangeNetLinkState(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainNetDefPtr dev,
@@ -1293,6 +1316,12 @@ int qemuDomainChangeNet(struct qemud_driver *driver,
return -1;
}
+ if(olddev->type==VIR_DOMAIN_NET_TYPE_BRIDGE
+ && dev->type==VIR_DOMAIN_NET_TYPE_BRIDGE
+ && STRNEQ(olddev->data.bridge.brname, dev->data.bridge.brname)) {
+ qemuDomainChangeNetBridge(olddev, dev);
+ }
+
if (olddev->linkstate != dev->linkstate) {
if ((ret = qemuDomainChangeNetLinkState(driver, vm, olddev,
dev->linkstate)) < 0)
return ret;
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 0310361..1e1f75c 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -80,6 +80,8 @@ int qemuDomainChangeNetLinkState(struct qemud_driver
*driver,
virDomainObjPtr vm,
virDomainNetDefPtr dev,
int linkstate);
+int qemuDomainChangeNetBridge(virDomainNetDefPtr olddev,
+ virDomainNetDefPtr newdev);
int qemuDomainDetachPciDiskDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev);
Host definition:
<domain type='kvm'>
<name>test</name>
<memory>32768</memory>
<currentMemory>32768</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='x86_64' machine='pc-0.12'>hvm</type>
<boot dev='cdrom'/>
<bootmenu enable='no'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/kvm</emulator>
<controller type='ide' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<interface type='bridge'>
<mac address='52:54:00:ab:cd:02'/>
<source bridge='br0'/>
<target dev='testif'/>
<link state='up'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<target port='0'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='tablet' bus='usb'/>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes'/>
<video>
<model type='cirrus' vram='9216' heads='1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</memballoon>
</devices>
</domain>
Interface definition:
<interface type="bridge">
<mac address="52:54:00:ab:cd:02"/>
<source bridge="br1"/>
<target dev="testif"/>
<link state="up"/>
<alias name="net0"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x0"/>
</interface>
Best regards
Hendrik Schwartke
12 years, 9 months