From 3d90a9c86de916450b6bb022ddb21e48dc71c953 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Mon, 10 Jul 2006 11:21:24 +0000 Subject: [PATCH] * src/xend_internal.c src/xml.c: patches from Jim Fehlig for HVM guests, plus XML format changes and merge from Mark McLoughlin Daniel --- ChangeLog | 7 +- src/xend_internal.c | 127 +++++++++++++++++++++++++++------- src/xml.c | 165 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 259 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5020d7dd83..79cd78bdc3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,14 @@ +Mon Jul 10 12:27:17 CEST 2006 Daniel Veillard + + * src/xend_internal.c src/xml.c: patches from Jim Fehlig for HVM + guests, plus XML format changes and merge from Mark McLoughlin + Fri Jul 7 09:47:14 EDT 2006 Daniel Berrange + * src/xend_internal.c: changed xenDaemonLookupByID to simply do an sexpr GET on /xend/domain/[ID] instead of listing all names and iterating over /xend/domain/[NAME]. Reduces the running time and number of GETs from O(n^2) to O(n). - * src/xend_internal.c: fixed xenDaemonOpen() to try both unix and Wed Jul 5 17:11:32 IST 2006 Mark McLoughlin diff --git a/src/xend_internal.c b/src/xend_internal.c index e7aa3bf2a7..6e9c32bf9d 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -1350,10 +1350,77 @@ xend_log(virConnectPtr xend, char *buffer, size_t n_buffer) ****** *****************************************************************/ #ifndef XEN_RO + +/** + * xend_parse_sexp_desc_os: + * @node: the root of the parsed S-Expression + * @buf: output buffer object + * @hvm: true or 1 if no contains HVM S-Expression + * + * Parse the xend sexp for description of os and append it to buf. + * + * Returns 0 in case of success and -1 in case of error + */ +static int +xend_parse_sexp_desc_os(struct sexpr *node, virBufferPtr buf, int hvm) +{ + const char *tmp; + + if (node == NULL || buf == NULL) { + return(-1); + } + + virBufferAdd(buf, " \n", 7); + if (hvm) { + virBufferVSprintf(buf, " hvm\n"); + tmp = sexpr_node(node, "domain/image/hvm/kernel"); + if (tmp == NULL) { + virXendError(NULL, VIR_ERR_INTERNAL_ERROR, + "domain informations incomplete, missing kernel"); + return(-1); + } + virBufferVSprintf(buf, " %s\n", tmp); + tmp = sexpr_node(node, "domain/image/hvm/boot"); + if ((tmp != NULL) && (tmp[0] != 0)) { + // FIXME: + // Figure out how to map the 'a', 'b', 'c' nonsense to a + // device. + if (tmp[0] == 'a') + virBufferAdd(buf, " \n", 25 ); + else if (tmp[0] == '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? + virBufferAdd(buf, " \n", 22 ); + else if (strcmp(tmp, "d") == 0) + virBufferAdd(buf, " \n", 24 ); + } + } else { + virBufferVSprintf(buf, " linux\n"); + tmp = sexpr_node(node, "domain/image/linux/kernel"); + if (tmp == NULL) { + virXendError(NULL, VIR_ERR_INTERNAL_ERROR, + "domain informations incomplete, missing kernel"); + return(-1); + } + 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)) + virBufferVSprintf(buf, " %s\n", tmp); + } + + virBufferAdd(buf, " \n", 8); + return(0); +} + /** * xend_parse_sexp_desc: * @root: the root of the parsed S-Expression - * @name: output name of the domain * * Parse the xend sexp description and turn it into the XML format similar * to the one unsed for creation. @@ -1368,6 +1435,7 @@ xend_parse_sexp_desc(struct sexpr *root) struct sexpr *cur, *node; const char *tmp; virBuffer buf; + int hvm; if (root == NULL) { /* ERROR */ @@ -1407,30 +1475,12 @@ xend_parse_sexp_desc(struct sexpr *root) tmp = sexpr_node(root, "domain/bootloader"); if (tmp != NULL) virBufferVSprintf(&buf, " %s\n", tmp); + if (sexpr_lookup(root, "domain/image")) { - tmp = sexpr_node(root, "domain/image/linux/kernel"); - if (tmp == NULL) { - /* - * TODO: we will need some fallback here for other guest OSes - */ - virXendError(NULL, VIR_ERR_INTERNAL_ERROR, - "domain informations incomplete, missing kernel"); - goto error; - } - virBufferAdd(&buf, " \n", 7); - virBufferVSprintf(&buf, " linux\n"); - virBufferVSprintf(&buf, " %s\n", tmp); - tmp = sexpr_node(root, "domain/image/linux/ramdisk"); - if ((tmp != NULL) && (tmp[0] != 0)) - virBufferVSprintf(&buf, " %s\n", tmp); - tmp = sexpr_node(root, "domain/image/linux/root"); - if ((tmp != NULL) && (tmp[0] != 0)) - virBufferVSprintf(&buf, " %s\n", tmp); - tmp = sexpr_node(root, "domain/image/linux/args"); - if ((tmp != NULL) && (tmp[0] != 0)) - virBufferVSprintf(&buf, " %s\n", tmp); - virBufferAdd(&buf, " \n", 8); + hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0; + xend_parse_sexp_desc_os(root, &buf, hvm); } + virBufferVSprintf(&buf, " %d\n", (int) (sexpr_u64(root, "domain/maxmem") << 10)); virBufferVSprintf(&buf, " %d\n", @@ -1446,6 +1496,12 @@ xend_parse_sexp_desc(struct sexpr *root) virBufferVSprintf(&buf, " %s\n", tmp); virBufferAdd(&buf, " \n", 12); + + /* in case of HVM we have devices emulation */ + tmp = sexpr_node(root, "domain/image/hvm/device_model"); + if ((tmp != NULL) && (tmp[0] != 0)) + virBufferVSprintf(&buf, " %s\n", tmp); + for (cur = root; cur->kind == SEXPR_CONS; cur = cur->cdr) { node = cur->car; if (sexpr_lookup(node, "device/vbd")) { @@ -1523,9 +1579,32 @@ xend_parse_sexp_desc(struct sexpr *root) virBufferVSprintf(&buf, "\n", serial); } - } } + + if (hvm) { + /* Graphics device */ + /* TODO: + * Support for some additional attributes for graphics device? + */ + tmp = sexpr_node(root, "domain/image/hvm/vnc"); + if (tmp != NULL) { + if (tmp[0] == '1') + virBufferAdd(&buf, " \n", 27 ); + } + + tmp = sexpr_node(root, "domain/image/hvm/sdl"); + if (tmp != NULL) { + if (tmp[0] == '1') + virBufferAdd(&buf, " \n", 27 ); + } + + /* + * TODO: + * Device for cdrom + */ + } + virBufferAdd(&buf, " \n", 13); virBufferAdd(&buf, "\n", 10); diff --git a/src/xml.c b/src/xml.c index 44ea2ee66d..b30c00d292 100644 --- a/src/xml.c +++ b/src/xml.c @@ -563,19 +563,141 @@ virDomainGetXMLDesc(virDomainPtr domain, int flags) #endif /** - * virDomainParseXMLOSDesc: - * @xmldesc: string with the XML description + * virDomainParseXMLOSDescHVM: + * @node: node containing HVM OS description * @buf: a buffer for the result S-Expr + * @ctxt: a path context representing the XML description * - * Parse the OS part of the XML description and add it to the S-Expr in buf - * This is a temporary interface as the S-Expr interface + * Parse the OS part of the XML description for an HVM 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. * * Returns 0 in case of success, -1 in case of error. */ static int -virDomainParseXMLOSDesc(xmlNodePtr node, virBufferPtr buf) +virDomainParseXMLOSDescHVM(xmlNodePtr node, virBufferPtr buf, xmlXPathContextPtr ctxt) +{ + xmlXPathObjectPtr obj = NULL; + xmlNodePtr cur, txt; + const xmlChar *type = NULL; + const xmlChar *loader = NULL; + const xmlChar *dev_model = NULL; + const xmlChar *boot_dev = NULL; + xmlChar *graphics_type = NULL; + + 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 ((loader == NULL) && + (xmlStrEqual(cur->name, BAD_CAST "loader"))) { + txt = cur->children; + if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && + (txt->next == NULL)) + loader = txt->content; + } else if ((boot_dev == NULL) && + (xmlStrEqual(cur->name, BAD_CAST "boot"))) { + boot_dev = xmlGetProp(cur, BAD_CAST "dev"); + } + } + cur = cur->next; + } + if ((type == NULL) || (!xmlStrEqual(type, BAD_CAST "hvm"))) { + /* VIR_ERR_OS_TYPE */ + virXMLError(VIR_ERR_OS_TYPE, (const char *) type, 0); + return (-1); + } + virBufferAdd(buf, "(image (hvm ", 12); + if (loader == NULL) { + virXMLError(VIR_ERR_NO_KERNEL, NULL, 0); + goto error; + } else { + virBufferVSprintf(buf, "(kernel '%s')", (const char *) loader); + } + + /* get the device emulation model */ + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/emulator[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + virXMLError(VIR_ERR_NO_KERNEL, NULL, 0); /* TODO: error */ + goto error; + } + virBufferVSprintf(buf, "(device_model '%s')", + (const char *) obj->stringval); + xmlXPathFreeObject(obj); + obj = NULL; + + if (boot_dev) { + /* TODO: + * Have to figure out the naming used here. + */ + if (xmlStrEqual(type, BAD_CAST "hda")) { + virBufferVSprintf(buf, "(boot a)", (const char *) boot_dev); + } else if (xmlStrEqual(type, BAD_CAST "hdd")) { + virBufferVSprintf(buf, "(boot d)", (const char *) boot_dev); + } else { + /* Force hd[b|c] if boot_dev specified but not floppy or cdrom? */ + virBufferVSprintf(buf, "(boot c)", (const char *) boot_dev); + } + } + /* TODO: + * Is a cdrom disk device specified? + * Kind of ugly since it is buried in the devices/diskk node. + */ + + /* Is a graphics device specified? */ + obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics[1]", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr = 0)) { + virXMLError(VIR_ERR_NO_OS, "", 0); /* TODO: error */ + goto error; + } + + graphics_type = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "type"); + if (graphics_type != NULL) { + if (xmlStrEqual(graphics_type, BAD_CAST "sdl")) { + virBufferAdd(buf, "(sdl 1)", 7); + // TODO: + // Need to understand sdl options + // + //virBufferAdd(buf, "(display localhost:10.0)", 24); + //virBufferAdd(buf, "(xauthority /root/.Xauthority)", 30); + } + else if (xmlStrEqual(graphics_type, BAD_CAST "vnc")) + virBufferAdd(buf, "(vnc 1)", 7); + xmlFree(graphics_type); + } + xmlXPathFreeObject(obj); + + virBufferAdd(buf, "))", 2); + + return (0); +error: + if (obj != NULL) + xmlXPathFreeObject(obj); + return(-1); +} + +/** + * virDomainParseXMLOSDescPV: + * @node: node containing PV OS description + * @buf: a buffer for the result S-Expr + * + * 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. + * + * Returns 0 in case of success, -1 in case of error. + */ +static int +virDomainParseXMLOSDescPV(xmlNodePtr node, virBufferPtr buf) { xmlNodePtr cur, txt; const xmlChar *type = NULL; @@ -645,7 +767,7 @@ virDomainParseXMLOSDesc(xmlNodePtr node, virBufferPtr buf) /** * virDomainParseXMLDiskDesc: - * @xmldesc: string with the XML description + * @node: node containing disk description * @buf: a buffer for the result S-Expr * * Parse the one disk in the XML description and add it to the S-Expr in buf @@ -707,10 +829,7 @@ virDomainParseXMLDiskDesc(xmlNodePtr node, virBufferPtr buf) return (-1); } virBufferAdd(buf, "(vbd ", 5); - if (target[0] == '/') - virBufferVSprintf(buf, "(dev '%s')", (const char *) target); - else - virBufferVSprintf(buf, "(dev '/dev/%s')", (const char *) target); + virBufferVSprintf(buf, "(dev '%s')", (const char *) target); if (typ == 0) virBufferVSprintf(buf, "(uname 'file:%s')", source); else if (typ == 1) { @@ -732,7 +851,7 @@ virDomainParseXMLDiskDesc(xmlNodePtr node, virBufferPtr buf) /** * virDomainParseXMLIfDesc: - * @xmldesc: string with the XML description + * @node: node containing the interface description * @buf: a buffer for the result S-Expr * * Parse the one interface the XML description and add it to the S-Expr in buf @@ -824,6 +943,7 @@ virDomainParseXMLDesc(const char *xmldesc, char **name) virBuffer buf; xmlChar *prop; xmlXPathObjectPtr obj = NULL; + xmlXPathObjectPtr tmpobj = NULL; xmlXPathContextPtr ctxt = NULL; int i, res; int bootloader = 0; @@ -861,7 +981,7 @@ virDomainParseXMLDesc(const char *xmldesc, char **name) goto error; } /* - * extract soem of the basics, name, memory, cpus ... + * extract some of the basics, name, memory, cpus ... */ obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || @@ -928,14 +1048,29 @@ virDomainParseXMLDesc(const char *xmldesc, char **name) } xmlXPathFreeObject(obj); - /* analyze of the os description */ obj = xmlXPathEval(BAD_CAST "/domain/os[1]", ctxt); if ((obj != NULL) && (obj->type == XPATH_NODESET) && (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { - res = virDomainParseXMLOSDesc(obj->nodesetval->nodeTab[0], &buf); - if (res != 0) { + /* Analyze of the os description, based on HVM or PV. */ + tmpobj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1])", ctxt); + if ((tmpobj != NULL) && + ((tmpobj->type != XPATH_STRING) || (tmpobj->stringval == NULL) || + (tmpobj->stringval[0] == 0))) { + xmlXPathFreeObject(tmpobj); + virXMLError(VIR_ERR_OS_TYPE, nam, 0); goto error; } + + if ((tmpobj == NULL) || !xmlStrEqual(tmpobj->stringval, BAD_CAST "hvm")) { + res = virDomainParseXMLOSDescPV(obj->nodesetval->nodeTab[0], &buf); + } else { + res = virDomainParseXMLOSDescHVM(obj->nodesetval->nodeTab[0], &buf, ctxt); + } + + xmlXPathFreeObject(tmpobj); + + if (res != 0) + goto error; } else if (bootloader == 0) { virXMLError(VIR_ERR_NO_OS, nam, 0); goto error;