From 3ee7cf6c9b2996f1b58cf6e67f3f450c3d51a66f Mon Sep 17 00:00:00 2001 From: Michal Novotny Date: Fri, 25 Feb 2011 15:41:12 +0100 Subject: [PATCH] Add support for multiple serial ports into the Xen driver this is the patch to add support for multiple serial ports to the libvirt Xen driver. It support both old style (serial = "pty") and new style (serial = [ "/dev/ttyS0", "/dev/ttyS1" ]) definition and tests for xml2sexpr, sexpr2xml and xmconfig have been added as well. Written and tested on RHEL-5 Xen dom0 and working as designed but the Xen version have to have patch for RHBZ #614004 but this patch is for upstream version of libvirt. Also, this patch is addressing issue described in RHBZ #670789. Signed-off-by: Michal Novotny --- src/xenxs/xen_sxpr.c | 99 +++++++++-- src/xenxs/xen_xm.c | 161 +++++++++++++++--- .../sexpr2xml-fv-serial-dev-2-ports.sexpr | 1 + .../sexpr2xml-fv-serial-dev-2-ports.xml | 53 ++++++ .../sexpr2xml-fv-serial-dev-2nd-port.sexpr | 1 + .../sexpr2xml-fv-serial-dev-2nd-port.xml | 49 ++++++ tests/sexpr2xmltest.c | 2 + .../test-fullvirt-serial-dev-2-ports.cfg | 25 +++ .../test-fullvirt-serial-dev-2-ports.xml | 55 ++++++ .../test-fullvirt-serial-dev-2nd-port.cfg | 25 +++ .../test-fullvirt-serial-dev-2nd-port.xml | 51 ++++++ tests/xmconfigtest.c | 2 + .../xml2sexpr-fv-serial-dev-2-ports.sexpr | 1 + .../xml2sexpr-fv-serial-dev-2-ports.xml | 44 +++++ .../xml2sexpr-fv-serial-dev-2nd-port.sexpr | 1 + .../xml2sexpr-fv-serial-dev-2nd-port.xml | 40 +++++ tests/xml2sexprtest.c | 2 + 17 files changed, 575 insertions(+), 37 deletions(-) create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2nd-port.sexpr create mode 100644 tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2nd-port.xml create mode 100644 tests/xmconfigdata/test-fullvirt-serial-dev-2-ports.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-dev-2-ports.xml create mode 100644 tests/xmconfigdata/test-fullvirt-serial-dev-2nd-port.cfg create mode 100644 tests/xmconfigdata/test-fullvirt-serial-dev-2nd-port.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-dev-2-ports.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-dev-2-ports.xml create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-dev-2nd-port.sexpr create mode 100644 tests/xml2sexprdata/xml2sexpr-fv-serial-dev-2nd-port.xml diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index aac2585b3a..3a412a68e8 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -177,6 +177,9 @@ xenParseSxprChar(const char *value, if (value[0] == '/') { def->source.type = VIR_DOMAIN_CHR_TYPE_DEV; + def->source.data.file.path = strdup(value); + if (!def->source.data.file.path) + goto no_memory; } else { if ((tmp = strchr(value, ':')) != NULL) { *tmp = '\0'; @@ -1280,18 +1283,55 @@ xenParseSxpr(const struct sexpr *root, /* Character device config */ if (hvm) { - tmp = sexpr_node(root, "domain/image/hvm/serial"); - if (tmp && STRNEQ(tmp, "none")) { - virDomainChrDefPtr chr; - if ((chr = xenParseSxprChar(tmp, tty)) == NULL) - goto error; - if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) { - virDomainChrDefFree(chr); - goto no_memory; + const struct sexpr *serial_root; + bool have_multiple_serials = false; + + serial_root = sexpr_lookup(root, "domain/image/hvm/serial"); + if (serial_root) { + const struct sexpr *cur, *node, *cur2; + int ports_skipped = 0; + + for (cur = serial_root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) { + node = cur->u.s.car; + + for (cur2 = node; cur2->kind == SEXPR_CONS; cur2 = cur2->u.s.cdr) { + tmp = cur2->u.s.car->u.value; + + if (tmp && STRNEQ(tmp, "none")) { + virDomainChrDefPtr chr; + if ((chr = xenParseSxprChar(tmp, tty)) == NULL) + goto error; + if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) { + virDomainChrDefFree(chr); + goto no_memory; + } + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + chr->target.port = def->nserials + ports_skipped; + def->serials[def->nserials++] = chr; + } + else + ports_skipped++; + + have_multiple_serials = true; + } } - chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; - def->serials[def->nserials++] = chr; } + + if (!have_multiple_serials) { + tmp = sexpr_node(root, "domain/image/hvm/serial"); + if (tmp && STRNEQ(tmp, "none")) { + virDomainChrDefPtr chr; + if ((chr = xenParseSxprChar(tmp, tty)) == NULL) + goto error; + if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) { + virDomainChrDefFree(chr); + goto no_memory; + } + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + def->serials[def->nserials++] = chr; + } + } + tmp = sexpr_node(root, "domain/image/hvm/parallel"); if (tmp && STRNEQ(tmp, "none")) { virDomainChrDefPtr chr; @@ -2121,10 +2161,41 @@ xenFormatSxpr(virConnectPtr conn, virBufferAddLit(&buf, "(parallel none)"); } if (def->serials) { - virBufferAddLit(&buf, "(serial "); - if (xenFormatSxprChr(def->serials[0], &buf) < 0) - goto error; - virBufferAddLit(&buf, ")"); + if ((def->nserials > 1) || (def->serials[0]->target.port != 0)) { + int maxport = -1; + int j = 0; + + virBufferAddLit(&buf, "(serial ("); + for (i = 0; i < def->nserials; i++) + if (def->serials[i]->target.port > maxport) + maxport = def->serials[i]->target.port; + + for (i = 0; i <= maxport; i++) { + virDomainChrDefPtr chr = NULL; + + if (i) + virBufferAddLit(&buf, " "); + for (j = 0; j < def->nserials; j++) { + if (def->serials[j]->target.port == i) { + chr = def->serials[j]; + break; + } + } + if (chr) { + if (xenFormatSxprChr(chr, &buf) < 0) + goto error; + } else { + virBufferAddLit(&buf, "none"); + } + } + virBufferAddLit(&buf, "))"); + } + else { + virBufferAddLit(&buf, "(serial "); + if (xenFormatSxprChr(def->serials[0], &buf) < 0) + goto error; + virBufferAddLit(&buf, ")"); + } } else { virBufferAddLit(&buf, "(serial none)"); } diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index ce590b9493..0acd12016b 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -965,20 +965,57 @@ xenParseXM(virConfPtr conf, int xendConfigVersion, chr = NULL; } - if (xenXMConfigGetString(conf, "serial", &str, NULL) < 0) - goto cleanup; - if (str && STRNEQ(str, "none") && - !(chr = xenParseSxprChar(str, NULL))) - goto cleanup; + /* Try to get the list of values to support multiple serial ports */ + list = virConfGetValue(conf, "serial"); + if (list && list->type == VIR_CONF_LIST) { + int portnum = -1; - if (chr) { - if (VIR_ALLOC_N(def->serials, 1) < 0) { - virDomainChrDefFree(chr); - goto no_memory; + list = list->list; + while (list) { + char *port = NULL; + + if ((list->type != VIR_CONF_STRING) || (list->str == NULL)) + goto cleanup; + + port = list->str; + portnum++; + if (STREQ(port, "none")) { + list = list->next; + continue; + } + + if (VIR_ALLOC(chr) < 0) + goto no_memory; + if (!(chr = xenParseSxprChar(port, NULL))) + goto cleanup; + + if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) + goto no_memory; + + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + chr->target.port = portnum; + + def->serials[def->nserials++] = chr; + chr = NULL; + + list = list->next; + } + } else { + /* If domain is not using multiple serial ports we parse data old way */ + if (xenXMConfigGetString(conf, "serial", &str, NULL) < 0) + goto cleanup; + if (str && STRNEQ(str, "none") && + !(chr = xenParseSxprChar(str, NULL))) + goto cleanup; + if (chr) { + if (VIR_ALLOC_N(def->serials, 1) < 0) { + virDomainChrDefFree(chr); + goto no_memory; + } + chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; + def->serials[0] = chr; + def->nserials++; } - chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL; - def->serials[0] = chr; - def->nserials++; } } else { if (!(def->console = xenParseSxprChar("pty", NULL))) @@ -1120,6 +1157,49 @@ cleanup: return -1; } +static int xenFormatXMSerial(virConfValuePtr list, + virDomainChrDefPtr serial) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + virConfValuePtr val, tmp; + int ret; + + if (serial) { + ret = xenFormatSxprChr(serial, &buf); + if (ret < 0) { + virReportOOMError(); + goto cleanup; + } + } else { + virBufferAddLit(&buf, "none"); + } + if (virBufferError(&buf)) { + virReportOOMError(); + goto cleanup; + } + + if (VIR_ALLOC(val) < 0) { + virReportOOMError(); + goto cleanup; + } + + val->type = VIR_CONF_STRING; + val->str = virBufferContentAndReset(&buf); + tmp = list->list; + while (tmp && tmp->next) + tmp = tmp->next; + if (tmp) + tmp->next = val; + else + list->list = val; + + return 0; + +cleanup: + virBufferFreeAndReset(&buf); + return -1; +} + static int xenFormatXMNet(virConnectPtr conn, virConfValuePtr list, virDomainNetDefPtr net, @@ -1678,17 +1758,52 @@ virConfPtr xenFormatXM(virConnectPtr conn, } if (def->nserials) { - virBuffer buf = VIR_BUFFER_INITIALIZER; - char *str; - int ret; + if ((def->nserials == 1) && (def->serials[0]->target.port == 0)) { + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *str; + int ret; - ret = xenFormatSxprChr(def->serials[0], &buf); - str = virBufferContentAndReset(&buf); - if (ret == 0) - ret = xenXMConfigSetString(conf, "serial", str); - VIR_FREE(str); - if (ret < 0) - goto no_memory; + ret = xenFormatSxprChr(def->serials[0], &buf); + str = virBufferContentAndReset(&buf); + if (ret == 0) + ret = xenXMConfigSetString(conf, "serial", str); + VIR_FREE(str); + if (ret < 0) + goto no_memory; + } else { + int j = 0; + int maxport = -1; + virConfValuePtr serialVal = NULL; + + if (VIR_ALLOC(serialVal) < 0) + goto no_memory; + serialVal->type = VIR_CONF_LIST; + serialVal->list = NULL; + + for (i = 0; i < def->nserials; i++) + if (def->serials[i]->target.port > maxport) + maxport = def->serials[i]->target.port; + + for (i = 0; i <= maxport; i++) { + virDomainChrDefPtr chr = NULL; + for (j = 0; j < def->nserials; j++) { + if (def->serials[j]->target.port == i) { + chr = def->serials[j]; + break; + } + } + if (xenFormatXMSerial(serialVal, chr) < 0) + goto cleanup; + } + + if (serialVal->list != NULL) { + int ret = virConfSetValue(conf, "serial", serialVal); + serialVal = NULL; + if (ret < 0) + goto no_memory; + } + VIR_FREE(serialVal); + } } else { if (xenXMConfigSetString(conf, "serial", "none") < 0) goto no_memory; @@ -1721,4 +1836,4 @@ cleanup: if (conf) virConfFree(conf); return (NULL); -} \ No newline at end of file +} diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.sexpr b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.sexpr new file mode 100644 index 0000000000..e709eb0c9e --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.sexpr @@ -0,0 +1 @@ +(domain (domid 1)(name 'fvtest')(memory 400)(maxmem 400)(vcpus 1)(uuid 'b5d70dd275cdaca517769660b059d8ff')(on_poweroff 'destroy')(on_reboot 'restart')(on_crash 'restart')(image (hvm (kernel '/usr/lib/xen/boot/hvmloader')(vcpus 1)(boot c)(cdrom '/root/boot.iso')(acpi 1)(usb 1)(parallel none)(serial (/dev/ttyS0 /dev/ttyS1))(device_model '/usr/lib64/xen/bin/qemu-dm')(vnc 1)))(device (vbd (dev 'ioemu:hda')(uname 'file:/root/foo.img')(mode 'w')))(device (vif (mac '00:16:3e:1b:b1:47')(bridge 'xenbr0')(script 'vif-bridge')(type ioemu)))) diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml new file mode 100644 index 0000000000..5e085f96c9 --- /dev/null +++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml @@ -0,0 +1,53 @@ + + fvtest + b5d70dd2-75cd-aca5-1776-9660b059d8ff + 409600 + 409600 + 1 + + hvm + /usr/lib/xen/boot/hvmloader + + + + + + + destroy + restart + restart + + /usr/lib64/xen/bin/qemu-dm + + + + + + + + + + + + + + +