[libvirt] PATCH: 3/5: The easy Xen and QEMU implementations

Daniel P. Berrange berrange at redhat.com
Wed May 13 14:38:57 UTC 2009


This patches provides an implenmentation of the new APIs for Xen which
can convert to/from both XM config format (/etc/xen files), and the
SEXPR format used by XenD.  The former is most useful to end users, but
it was easy to add the latter too, so I did. It can be a useful debugging
aid sometimes. For QEMU, it implemnets export of  domain XML into the
QEMU argv format.

 qemu_conf.c   |   25 +++++-------
 qemu_conf.h   |    3 +
 qemu_driver.c |  119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 xen_unified.c |   95 +++++++++++++++++++++++++++++++++++++++++++++-
 xen_unified.h |    3 +
 5 files changed, 228 insertions(+), 17 deletions(-)


Daniel

diff -r f55fa9b69d85 src/qemu_conf.c
--- a/src/qemu_conf.c	Wed May 13 13:13:18 2009 +0100
+++ b/src/qemu_conf.c	Wed May 13 13:16:50 2009 +0100
@@ -1248,21 +1248,18 @@ int qemudBuildCommandLine(virConnectPtr 
 
             case VIR_DOMAIN_NET_TYPE_ETHERNET:
                 {
-                    char arg[PATH_MAX];
-                    if (net->ifname) {
-                        if (snprintf(arg, PATH_MAX-1, "tap,ifname=%s,script=%s,vlan=%d",
-                                     net->ifname,
-                                     net->data.ethernet.script,
-                                     vlan) >= (PATH_MAX-1))
-                            goto error;
-                    } else {
-                        if (snprintf(arg, PATH_MAX-1, "tap,script=%s,vlan=%d",
-                                     net->data.ethernet.script,
-                                     vlan) >= (PATH_MAX-1))
-                            goto error;
-                    }
+                    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
-                    ADD_ARG_LIT(arg);
+                    virBufferAddLit(&buf, "tap");
+                    if (net->ifname)
+                        virBufferVSprintf(&buf, ",ifname=%s", net->ifname);
+                    if (net->data.ethernet.script)
+                        virBufferVSprintf(&buf, ",script=%s", net->data.ethernet.script);
+                    virBufferVSprintf(&buf, ",vlan=%d", vlan);
+                    if (virBufferError(&buf))
+                        goto error;
+
+                    ADD_ARG(virBufferContentAndReset(&buf));
                 }
                 break;
 
diff -r f55fa9b69d85 src/qemu_conf.h
--- a/src/qemu_conf.h	Wed May 13 13:13:18 2009 +0100
+++ b/src/qemu_conf.h	Wed May 13 13:16:50 2009 +0100
@@ -106,6 +106,9 @@ struct _qemudDomainStatus {
 #define QEMUD_MIGRATION_FIRST_PORT 49152
 #define QEMUD_MIGRATION_NUM_PORTS 64
 
+/* Config type for XML import/export conversions */
+#define QEMU_CONFIG_FORMAT_ARGV "qemu-argv"
+
 #define qemudReportError(conn, dom, net, code, fmt...)                       \
         virReportErrorHelper(conn, VIR_FROM_QEMU, code, __FILE__,          \
                                __FUNCTION__, __LINE__, fmt)
diff -r f55fa9b69d85 src/qemu_driver.c
--- a/src/qemu_driver.c	Wed May 13 13:13:18 2009 +0100
+++ b/src/qemu_driver.c	Wed May 13 13:16:50 2009 +0100
@@ -3423,6 +3423,123 @@ cleanup:
 }
 
 
+static char *qemuDomainXMLToNative(virConnectPtr conn,
+                                   const char *format,
+                                   const char *xmlData,
+                                   unsigned int flags ATTRIBUTE_UNUSED) {
+    struct qemud_driver *driver = conn->privateData;
+    virDomainDefPtr def = NULL;
+    const char *emulator;
+    unsigned int qemuCmdFlags;
+    struct stat sb;
+    const char **retargv = NULL;
+    const char **retenv = NULL;
+    const char **tmp;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *ret = NULL;
+    int i;
+
+    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
+                         _("unsupported config type %s"), format);
+        goto cleanup;
+    }
+
+    def = virDomainDefParseString(conn, driver->caps, xmlData, 0);
+    if (!def)
+        goto cleanup;
+
+    /* Since we're just exporting args, we can't do bridge/network
+     * setups, since libvirt will normally create TAP devices
+     * directly. We convert those configs into generic 'ethernet'
+     * config and assume the user has suitable 'ifup-qemu' scripts
+     */
+    for (i = 0 ; i < def->nnets ; i++) {
+        virDomainNetDefPtr net = def->nets[i];
+        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
+            VIR_FREE(net->data.network.name);
+            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+            net->data.ethernet.dev = NULL;
+            net->data.ethernet.script = NULL;
+            net->data.ethernet.ipaddr = NULL;
+        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+            /* Rely on fact that the 'ethernet' and 'bridge'
+             * union structs have members in same place */
+        }
+    }
+    for (i = 0 ; i < def->ngraphics ; i++) {
+        if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
+            def->graphics[i]->data.vnc.autoport)
+            def->graphics[i]->data.vnc.port = 5900;
+    }
+    emulator = def->emulator;
+    if (!emulator)
+        emulator = virDomainDefDefaultEmulator(conn, def, driver->caps);
+    if (!emulator)
+        goto cleanup;
+
+    /* Make sure the binary we are about to try exec'ing exists.
+     * Technically we could catch the exec() failure, but that's
+     * in a sub-process so its hard to feed back a useful error
+     */
+    if (stat(emulator, &sb) < 0) {
+        virReportSystemError(conn, errno,
+                             _("Cannot find QEMU binary %s"),
+                             emulator);
+        goto cleanup;
+    }
+
+    if (qemudExtractVersionInfo(emulator,
+                                NULL,
+                                &qemuCmdFlags) < 0) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("Cannot determine QEMU argv syntax %s"),
+                         emulator);
+        goto cleanup;
+    }
+
+
+    if (qemudBuildCommandLine(conn, driver, def,
+                              qemuCmdFlags,
+                              &retargv, &retenv,
+                              NULL, NULL, /* Don't want it to create TAP devices */
+                              NULL) < 0) {
+        goto cleanup;
+    }
+
+    tmp = retenv;
+    while (*tmp) {
+        virBufferAdd(&buf, *tmp, strlen(*tmp));
+        virBufferAddLit(&buf, " ");
+        tmp++;
+    }
+    tmp = retargv;
+    while (*tmp) {
+        virBufferAdd(&buf, *tmp, strlen(*tmp));
+        virBufferAddLit(&buf, " ");
+        tmp++;
+    }
+
+    if (virBufferError(&buf))
+        goto cleanup;
+
+    ret = virBufferContentAndReset(&buf);
+
+cleanup:
+    for (tmp = retargv ; tmp && *tmp ; tmp++)
+        VIR_FREE(*tmp);
+    VIR_FREE(retargv);
+
+    for (tmp = retenv ; tmp && *tmp ; tmp++)
+        VIR_FREE(*tmp);
+    VIR_FREE(retenv);
+
+    virDomainDefFree(def);
+    return ret;
+}
+
+
 static int qemudListDefinedDomains(virConnectPtr conn,
                             char **const names, int nnames) {
     struct qemud_driver *driver = conn->privateData;
@@ -5232,7 +5349,7 @@ static virDriver qemuDriver = {
     qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
     qemudDomainDumpXML, /* domainDumpXML */
     NULL, /* domainXmlFromNative */
-    NULL, /* domainXmlToNative */
+    qemuDomainXMLToNative, /* domainXMLToNative */
     qemudListDefinedDomains, /* listDefinedDomains */
     qemudNumDefinedDomains, /* numOfDefinedDomains */
     qemudDomainStart, /* domainCreate */
diff -r f55fa9b69d85 src/xen_unified.c
--- a/src/xen_unified.c	Wed May 13 13:13:18 2009 +0100
+++ b/src/xen_unified.c	Wed May 13 13:16:50 2009 +0100
@@ -1043,6 +1043,97 @@ xenUnifiedDomainDumpXML (virDomainPtr do
     return NULL;
 }
 
+
+static char *
+xenUnifiedDomainXMLFromNative(virConnectPtr conn,
+                              const char *format,
+                              const char *config,
+                              unsigned int flags ATTRIBUTE_UNUSED)
+{
+    virDomainDefPtr def = NULL;
+    char *ret = NULL;
+    virConfPtr conf = NULL;
+    GET_PRIVATE(conn);
+
+    if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) &&
+        STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+        xenUnifiedError(conn, VIR_ERR_INVALID_ARG,
+                        _("unsupported config type %s"), format);
+        return NULL;
+    }
+
+    if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
+        conf = virConfReadMem(config, strlen(config));
+        if (!conf)
+            goto cleanup;
+
+        def = xenXMDomainConfigParse(conn, conf);
+    } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+        def = xenDaemonParseSxprString(conn, config, priv->xendConfigVersion);
+    }
+    if (!def)
+        goto cleanup;
+
+    ret = virDomainDefFormat(conn, def, 0);
+
+cleanup:
+    virDomainDefFree(def);
+    return ret;
+}
+
+
+#define MAX_CONFIG_SIZE (1024 * 65)
+static char *
+xenUnifiedDomainXMLToNative(virConnectPtr conn,
+                            const char *format,
+                            const char *xmlData,
+                            unsigned int flags ATTRIBUTE_UNUSED)
+{
+    virDomainDefPtr def = NULL;
+    char *ret = NULL;
+    virConfPtr conf = NULL;
+    GET_PRIVATE(conn);
+
+    if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) &&
+        STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+        xenUnifiedError(conn, VIR_ERR_INVALID_ARG,
+                        _("unsupported config type %s"), format);
+        goto cleanup;
+    }
+
+    if (!(def = virDomainDefParseString(conn,
+                                        priv->caps,
+                                        xmlData,
+                                        0)))
+        goto cleanup;
+
+    if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
+        int len = MAX_CONFIG_SIZE;
+        conf = xenXMDomainConfigFormat(conn, def);
+        if (!conf)
+            goto cleanup;
+
+        if (VIR_ALLOC_N(ret, len) < 0) {
+            virReportOOMError(conn);
+            goto cleanup;
+        }
+
+        if (virConfWriteMem(ret, &len, conf) < 0) {
+            VIR_FREE(ret);
+            goto cleanup;
+        }
+    } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+        ret = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion);
+    }
+
+cleanup:
+    virDomainDefFree(def);
+    if (conf)
+        virConfFree(conf);
+    return ret;
+}
+
+
 static int
 xenUnifiedDomainMigratePrepare (virConnectPtr dconn,
                                 char **cookie,
@@ -1580,8 +1671,8 @@ static virDriver xenUnifiedDriver = {
     NULL, /* domainGetSecurityLabel */
     NULL, /* nodeGetSecurityModel */
     xenUnifiedDomainDumpXML, /* domainDumpXML */
-    NULL, /* domainXmlFromNative */
-    NULL, /* domainXmlToNative */
+    xenUnifiedDomainXMLFromNative, /* domainXmlFromNative */
+    xenUnifiedDomainXMLToNative, /* domainXmlToNative */
     xenUnifiedListDefinedDomains, /* listDefinedDomains */
     xenUnifiedNumOfDefinedDomains, /* numOfDefinedDomains */
     xenUnifiedDomainCreate, /* domainCreate */
diff -r f55fa9b69d85 src/xen_unified.h
--- a/src/xen_unified.h	Wed May 13 13:13:18 2009 +0100
+++ b/src/xen_unified.h	Wed May 13 13:16:50 2009 +0100
@@ -46,6 +46,9 @@ extern int xenRegister (void);
 
 #define MIN_XEN_GUEST_SIZE 64  /* 64 megabytes */
 
+#define XEN_CONFIG_FORMAT_XM    "xen-xm"
+#define XEN_CONFIG_FORMAT_SEXPR "xen-sxpr"
+
 /* _xenUnifiedDriver:
  *
  * Entry points into the underlying Xen drivers.  This structure


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list