From e87e3f86bfb8b19449c9492285d09167ddcb9d07 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 5 Feb 2008 16:21:25 +0000 Subject: [PATCH] Added support for booting off kenrel+initrd with HVM guests --- ChangeLog | 9 + src/xend_internal.c | 122 +++++++----- src/xml.c | 186 ++++++++---------- tests/sexpr2xmldata/sexpr2xml-fv-kernel.sexpr | 1 + tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml | 26 +++ .../sexpr2xml-fv-legacy-vfb.sexpr | 70 +++++++ .../sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml | 33 ++++ tests/sexpr2xmltest.c | 20 ++ tests/xml2sexprdata/xml2sexpr-fv-kernel.sexpr | 1 + tests/xml2sexprdata/xml2sexpr-fv-kernel.xml | 24 +++ .../xml2sexpr-fv-localtime.sexpr | 2 +- .../xml2sexprdata/xml2sexpr-fv-usbmouse.sexpr | 2 +- .../xml2sexpr-fv-usbtablet.sexpr | 2 +- tests/xml2sexprdata/xml2sexpr-fv-utc.sexpr | 2 +- tests/xml2sexprdata/xml2sexpr-fv-v2.sexpr | 2 +- .../xml2sexpr-fv-vncunused.sexpr | 2 +- tests/xml2sexprdata/xml2sexpr-fv.sexpr | 2 +- .../xml2sexpr-no-source-cdrom.sexpr | 2 +- tests/xml2sexprtest.c | 11 ++ 19 files changed, 357 insertions(+), 162 deletions(-) create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-kernel.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-kernel.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-kernel.xml diff --git a/ChangeLog b/ChangeLog index 59c21561f8..1a62dbadaa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Tue Feb 3 11:21:45 EST 2008 Daniel P. Berrange + + * src/xml.c, src/xend_internal.c: Allow use of kernel+initrd + in HVM guests as well as PV + * tests/xml2sexprdata/*, tests/sexpr2xmldata/*: Updated for + slight changes in SXPR element ordering + * tests/xml2sexprtest.c, tests/sexpr2xmltest.c: Add test + case for new HVM kernel+initrd ability + Tue Feb 3 15:21:45 CET 2008 Jim Meyering Eliminate all uses of virBufferAdd with string literals. diff --git a/src/xend_internal.c b/src/xend_internal.c index 9a79591891..50cd6a4feb 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -1280,65 +1280,84 @@ xend_log(virConnectPtr xend, char *buffer, size_t n_buffer) static int xend_parse_sexp_desc_os(virConnectPtr xend, struct sexpr *node, virBufferPtr buf, int hvm, int bootloader) { - const char *tmp; + const char *loader = NULL; + const char *kernel = NULL; + const char *initrd = NULL; + const char *cmdline = NULL; + const char *root = NULL; if (node == NULL || buf == NULL) { return(-1); } virBufferAddLit(buf, " \n"); + if (hvm) + virBufferAddLit(buf, " hvm\n"); + else + virBufferAddLit(buf, " linux\n"); + if (hvm) { - virBufferVSprintf(buf, " hvm\n"); - tmp = sexpr_node(node, "domain/image/hvm/kernel"); - if (tmp == NULL) - tmp = sexpr_node(node, "domain/image/hvm/loader"); - if (tmp == NULL && !bootloader) { - virXendError(xend, VIR_ERR_INTERNAL_ERROR, - _("domain information incomplete, missing kernel & bootloader")); - return(-1); - } - if (tmp) - virBufferVSprintf(buf, " %s\n", tmp); - tmp = sexpr_node(node, "domain/image/hvm/boot"); - if ((tmp != NULL) && (tmp[0] != 0)) { - while (*tmp) { - if (*tmp == 'a') - /* XXX no way to deal with boot from 2nd floppy */ - virBufferAddLit(buf, " \n"); - else if (*tmp == 'c') - /* - * Don't know what to put here. Say the vm has been given 3 - * disks - hda, hdb, hdc. How does one identify the boot disk? - * We're going to assume that first disk is the boot disk since - * this is most common practice - */ - virBufferAddLit(buf, " \n"); - else if (*tmp == 'd') - virBufferAddLit(buf, " \n"); - else if (*tmp == 'n') - virBufferAddLit(buf, " \n"); - tmp++; + loader = sexpr_node(node, "domain/image/hvm/loader"); + if (loader == NULL) { + loader = sexpr_node(node, "domain/image/hvm/kernel"); + + if (loader == NULL) { + virXendError(xend, VIR_ERR_INTERNAL_ERROR, + _("domain information incomplete, missing HVM loader")); + return(-1); } + } else { + kernel = sexpr_node(node, "domain/image/hvm/kernel"); + initrd = sexpr_node(node, "domain/image/hvm/ramdisk"); + cmdline = sexpr_node(node, "domain/image/hvm/args"); + root = sexpr_node(node, "domain/image/hvm/root"); } } else { - virBufferVSprintf(buf, " linux\n"); - tmp = sexpr_node(node, "domain/image/linux/kernel"); - if (tmp == NULL && !bootloader) { + kernel = sexpr_node(node, "domain/image/linux/kernel"); + initrd = sexpr_node(node, "domain/image/linux/ramdisk"); + cmdline = sexpr_node(node, "domain/image/linux/args"); + root = sexpr_node(node, "domain/image/linux/root"); + } + + if (hvm) + virBufferVSprintf(buf, " %s\n", loader); + + if (kernel) { + virBufferVSprintf(buf, " %s\n", kernel); + if (initrd && initrd[0]) + virBufferVSprintf(buf, " %s\n", initrd); + if (root && root[0]) + virBufferVSprintf(buf, " %s\n", root); + if (cmdline && cmdline[0]) + virBufferEscapeString(buf, " %s\n", cmdline); + } else { + if (hvm) { + const char *boot = sexpr_node(node, "domain/image/hvm/boot"); + if ((boot != NULL) && (boot[0] != 0)) { + while (*boot) { + if (*boot == 'a') + /* XXX no way to deal with boot from 2nd floppy */ + virBufferAddLit(buf, " \n"); + else if (*boot == 'c') + /* + * Don't know what to put here. Say the vm has been given 3 + * disks - hda, hdb, hdc. How does one identify the boot disk? + * We're going to assume that first disk is the boot disk since + * this is most common practice + */ + virBufferAddLit(buf, " \n"); + else if (*boot == 'd') + virBufferAddLit(buf, " \n"); + else if (*boot == 'n') + virBufferAddLit(buf, " \n"); + boot++; + } + } + } else if (!bootloader) { virXendError(xend, VIR_ERR_INTERNAL_ERROR, _("domain information incomplete, missing kernel & bootloader")); return(-1); } - if (tmp) - virBufferVSprintf(buf, " %s\n", tmp); - tmp = sexpr_node(node, "domain/image/linux/ramdisk"); - if ((tmp != NULL) && (tmp[0] != 0)) - virBufferVSprintf(buf, " %s\n", tmp); - tmp = sexpr_node(node, "domain/image/linux/root"); - if ((tmp != NULL) && (tmp[0] != 0)) - virBufferVSprintf(buf, " %s\n", tmp); - tmp = sexpr_node(node, "domain/image/linux/args"); - if ((tmp != NULL) && (tmp[0] != 0)) - virBufferEscapeString(buf, " %s\n", tmp); } virBufferAddLit(buf, " \n"); @@ -1367,7 +1386,7 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, const char *tmp; char *tty; virBuffer buf; - int hvm = 0, bootloader = 0; + int hvm = 0, bootloader = 0, vfb = 0; int domid = -1; int max_mem, cur_mem; unsigned char uuid[VIR_UUID_BUFLEN]; @@ -1487,8 +1506,10 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, virBufferAddLit(&buf, " \n"); - /* in case of HVM we have devices emulation */ - tmp = sexpr_node(root, "domain/image/hvm/device_model"); + if (hvm) + tmp = sexpr_node(root, "domain/image/hvm/device_model"); + else + tmp = sexpr_node(root, "domain/image/linux/device_model"); if ((tmp != NULL) && (tmp[0] != 0)) virBufferVSprintf(&buf, " %s\n", tmp); @@ -1681,6 +1702,7 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, tmp = sexpr_node(node, "device/vfb/type"); if (tmp && !strcmp(tmp, "sdl")) { + vfb = 1; virBufferVSprintf(&buf, " \n", hvm ? "ps2": "xen"); virBufferAddLit(&buf, " \n"); } else if (tmp && !strcmp(tmp, "vnc")) { @@ -1688,6 +1710,7 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten"); const char *vncPasswd = NULL; const char *keymap = sexpr_node(node, "device/vfb/keymap"); + vfb = 1; virBufferVSprintf(&buf, " \n", hvm ? "ps2": "xen"); virBufferVSprintf(&buf, " children; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { - if ((type == NULL) && - (xmlStrEqual(cur->name, BAD_CAST "type"))) { - txt = cur->children; - if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && - (txt->next == NULL)) - type = txt->content; - } else if ((loader == NULL) && - (xmlStrEqual(cur->name, BAD_CAST "loader"))) { + if ((loader == NULL) && + (xmlStrEqual(cur->name, BAD_CAST "loader"))) { txt = cur->children; if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && (txt->next == NULL)) @@ -904,28 +897,31 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, } cur = cur->next; } + /* + * XenD always needs boot order defined for HVM, even if + * booting off a kernel + initrd, so force to 'c' if nothing + * else is specified + */ + if (nbootorder == 0) + bootorder[nbootorder++] = 'c'; bootorder[nbootorder] = '\0'; - if ((type == NULL) || (!xmlStrEqual(type, BAD_CAST "hvm"))) { - /* VIR_ERR_OS_TYPE */ - virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0); - return (-1); - } - virBufferAddLit(buf, "(image (hvm "); + if (loader == NULL) { - virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0); - goto error; - } else { - virBufferVSprintf(buf, "(kernel '%s')", (const char *) loader); + virXMLError(conn, VIR_ERR_INTERNAL_ERROR, "no HVM domain loader", 0); + return -1; } - /* get the device emulation model */ - str = virXPathString("string(/domain/devices/emulator[1])", ctxt); - if (str == NULL) { - virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0); /* TODO: error */ - goto error; + /* + * Originally XenD abused the 'kernel' parameter for the HVM + * firmware. New XenD allows HVM guests to boot from a kernel + * and if this is enabled, the HVM firmware must use the new + * 'loader' parameter + */ + if (hasKernel) { + virBufferVSprintf(buf, "(loader '%s')", (const char *) loader); + } else { + virBufferVSprintf(buf, "(kernel '%s')", (const char *) loader); } - virBufferVSprintf(buf, "(device_model '%s')", str); - xmlFree(str); virBufferVSprintf(buf, "(vcpus %d)", vcpus); @@ -1049,27 +1045,12 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferAddLit(buf, "(serial pty)"); } - /* HVM graphics for xen <= 3.0.5 */ - if (xendConfigVersion < 4) { - /* Is a graphics device specified? */ - cur = virXPathNode("/domain/devices/graphics[1]", ctxt); - if (cur != NULL) { - res = virDomainParseXMLGraphicsDescImage(conn, cur, buf, - xendConfigVersion); - if (res != 0) { - goto error; - } - } - } - str = virXPathString("string(/domain/clock/@offset)", ctxt); if (str != NULL && !strcmp(str, "localtime")) { virBufferAddLit(buf, "(localtime 1)"); } free(str); - virBufferAddLit(buf, "))"); - return (0); error: @@ -1077,45 +1058,34 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, return (-1); } + /** - * virDomainParseXMLOSDescPV: + * virDomainParseXMLOSDescKernel: * @conn: pointer to the hypervisor connection * @node: node containing PV OS description * @buf: a buffer for the result S-Expr - * @ctxt: a path context representing the XML description - * @xendConfigVersion: xend configuration file format * - * Parse the OS part of the XML description for a paravirtualized domain - * and add it to the S-Expr in buf. This is a temporary interface as the - * S-Expr interface will be replaced by XML-RPC in the future. However - * the XML format should stay valid over time. + * Parse the OS part of the XML description for a domain using a direct + * kernel and initrd to boot. * * Returns 0 in case of success, -1 in case of error. */ static int -virDomainParseXMLOSDescPV(virConnectPtr conn, xmlNodePtr node, - virBufferPtr buf, xmlXPathContextPtr ctxt, - int xendConfigVersion) +virDomainParseXMLOSDescKernel(virConnectPtr conn ATTRIBUTE_UNUSED, + xmlNodePtr node, + virBufferPtr buf) { xmlNodePtr cur, txt; - const xmlChar *type = NULL; const xmlChar *root = NULL; const xmlChar *kernel = NULL; const xmlChar *initrd = NULL; const xmlChar *cmdline = NULL; - int res; cur = node->children; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { - if ((type == NULL) - && (xmlStrEqual(cur->name, BAD_CAST "type"))) { - txt = cur->children; - if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && - (txt->next == NULL)) - type = txt->content; - } else if ((kernel == NULL) && - (xmlStrEqual(cur->name, BAD_CAST "kernel"))) { + if ((kernel == NULL) && + (xmlStrEqual(cur->name, BAD_CAST "kernel"))) { txt = cur->children; if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && (txt->next == NULL)) @@ -1142,18 +1112,9 @@ virDomainParseXMLOSDescPV(virConnectPtr conn, xmlNodePtr node, } cur = cur->next; } - if ((type != NULL) && (!xmlStrEqual(type, BAD_CAST "linux"))) { - /* VIR_ERR_OS_TYPE */ - virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0); - return (-1); - } - virBufferAddLit(buf, "(image (linux "); - if (kernel == NULL) { - virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0); - return (-1); - } else { - virBufferVSprintf(buf, "(kernel '%s')", (const char *) kernel); - } + + virBufferVSprintf(buf, "(kernel '%s')", (const char *) kernel); + if (initrd != NULL) virBufferVSprintf(buf, "(ramdisk '%s')", (const char *) initrd); if (root != NULL) @@ -1161,20 +1122,6 @@ virDomainParseXMLOSDescPV(virConnectPtr conn, xmlNodePtr node, if (cmdline != NULL) virBufferVSprintf(buf, "(args '%s')", (const char *) cmdline); - /* PV graphics for xen <= 3.0.4 */ - if (xendConfigVersion < 3) { - cur = virXPathNode("/domain/devices/graphics[1]", ctxt); - if (cur != NULL) { - res = virDomainParseXMLGraphicsDescImage(conn, cur, buf, - xendConfigVersion); - if (res != 0) { - goto error; - } - } - } - - error: - virBufferAddLit(buf, "))"); return (0); } @@ -1708,23 +1655,54 @@ virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, if (!bootloader) { if ((node = virXPathNode("/domain/os[1]", ctxt)) != NULL) { + int has_kernel = 0; + /* Analyze of the os description, based on HVM or PV. */ str = virXPathString("string(/domain/os/type[1])", ctxt); - - if ((str == NULL) || (strcmp(str, "hvm"))) { - res = virDomainParseXMLOSDescPV(conn, node, - &buf, ctxt, - xendConfigVersion); - } else { + if ((str != NULL) && STREQ(str, "hvm")) hvm = 1; - res = virDomainParseXMLOSDescHVM(conn, node, &buf, ctxt, - vcpus, xendConfigVersion); - } + xmlFree(str); + str = NULL; - free(str); + if (hvm) + virBufferAddLit(&buf, "(image (hvm "); + else + virBufferAddLit(&buf, "(image (linux "); - if (res != 0) + if (virXPathBoolean("count(/domain/os/kernel) > 0", ctxt)) { + if (virDomainParseXMLOSDescKernel(conn, node, + &buf) != 0) + goto error; + has_kernel = 1; + } + + if (hvm && + virDomainParseXMLOSDescHVM(conn, node, + &buf, ctxt, vcpus, + xendConfigVersion, + has_kernel) != 0) goto error; + + /* get the device emulation model */ + str = virXPathString("string(/domain/devices/emulator[1])", ctxt); + if (str != NULL) { + virBufferVSprintf(&buf, "(device_model '%s')", str); + xmlFree(str); + str = NULL; + } + + /* PV graphics for xen <= 3.0.4, or HVM graphics for xen <= 3.1.0 */ + if ((!hvm && xendConfigVersion < 3) || + (hvm && xendConfigVersion < 4)) { + xmlNodePtr cur; + cur = virXPathNode("/domain/devices/graphics[1]", ctxt); + if (cur != NULL && + virDomainParseXMLGraphicsDescImage(conn, cur, &buf, + xendConfigVersion) != 0) + goto error; + } + + virBufferAddLit(&buf, "))"); } else { virXMLError(conn, VIR_ERR_NO_OS, nam, 0); goto error; diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-kernel.sexpr b/tests/sexpr2xmldata/sexpr2xml-fv-kernel.sexpr new file mode 100644 index 0000000000..96f699cf4b --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-kernel.sexpr @@ -0,0 +1 @@ +(domain (domid 15)(name 'fvtest')(memory 420)(maxmem 420)(vcpus 2)(uuid '596a5d2171f48fb2e068e2386a5c413e')(on_poweroff 'destroy')(on_reboot 'destroy')(on_crash 'destroy')(image (hvm (kernel '/var/lib/xen/vmlinuz.2Dn2YT')(ramdisk '/var/lib/xen/initrd.img.0u-Vhq')(args ' method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os ')(loader '/usr/lib/xen/boot/hvmloader')(vcpus 2)(usb 1)(serial pty)))(device (vbd (dev 'ioemu:xvda')(uname 'file:/root/some.img')(mode 'w')))) \ No newline at end of file diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml b/tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml new file mode 100644 index 0000000000..7faeeff823 --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml @@ -0,0 +1,26 @@ + + fvtest + 596a5d21-71f4-8fb2-e068-e2386a5c413e + + hvm + /usr/lib/xen/boot/hvmloader + /var/lib/xen/vmlinuz.2Dn2YT + /var/lib/xen/initrd.img.0u-Vhq + method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os + + 430080 + 2 + destroy + destroy + destroy + + + + + + + + + + + diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.sexpr b/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.sexpr new file mode 100644 index 0000000000..549b2800c3 --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.sexpr @@ -0,0 +1,70 @@ +(domain + (domid 1) + (on_crash restart) + (uuid fde0533d-d043-88c6-dfba-4822fa32f309) + (bootloader_args ) + (vcpus 1) + (name s10u4) + (on_poweroff destroy) + (on_reboot restart) + (bootloader ) + (maxmem 1024) + (memory 1024) + (shadow_memory 9) + (cpu_weight 256) + (cpu_cap 0) + (features ) + (on_xend_start ignore) + (on_xend_stop shutdown) + (start_time 1201894394.0) + (cpu_time 17.253230349) + (online_vcpus 1) + (image + (hvm + (kernel /usr/lib/xen/boot/hvmloader) + (boot c) + (device_model /usr/lib/xen/bin/qemu-dm) + (keymap en-us) + (localtime 0) + (pae 1) + (vnc 1) + (vncunused 1) + (notes (SUSPEND_CANCEL 1)) + ) + ) + (status 2) + (state -b----) + (store_mfn 262142) + (device + (vif + (mac 00:16:3e:3b:b9:d7) + (script vif-vnic) + (uuid 33b87cce-c187-4bdd-8301-6411a48be129) + (backend 0) + ) + ) + (device + (vbd + (uname phy:/dev/zvol/dsk/export/s10u4-root) + (uuid b1d5196f-aae7-74bb-43dc-b4aae943b9bd) + (mode w) + (dev hda:disk) + (backend 0) + (bootable 1) + ) + ) + (device + (vfb + (vncunused 1) + (uuid d45dfd90-c0e0-8851-8f14-f16ba9512d2d) + (location localhost:5900) + ) + ) + (device + (console + (protocol vt100) + (location 3) + (uuid 0248d3f7-f3ae-78e8-4829-ad51a6f94efd) + ) + ) +) diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml b/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml new file mode 100644 index 0000000000..62a8d0a185 --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml @@ -0,0 +1,33 @@ + + s10u4 + fde0533d-d043-88c6-dfba-4822fa32f309 + + hvm + /usr/lib/xen/boot/hvmloader + + + 1048576 + 1 + destroy + restart + restart + + + + + + /usr/lib/xen/bin/qemu-dm + + + +