This introduces a third option for clock offset synchronization, that allows an arbitrary / variable adjustment to be set. In essence the XML contains the time delta in seconds, relative to UTC. <clock offset='variable' adjustment='123465'/> The difference from 'utc' mode, is that management apps should track adjustments and preserve them at next reboot. * docs/schemas/domain.rng: Schema for new clock mode * src/conf/domain_conf.c, src/conf/domain_conf.h: Parse new clock time delta * src/libvirt_private.syms, src/util/xml.c, src/util/xml.h: Add virXPathLongLong() method --- docs/schemas/domain.rng | 25 +++++++++++++++++--- src/conf/domain_conf.c | 18 +++++++++++++- src/conf/domain_conf.h | 5 ++++ src/libvirt_private.syms | 1 + src/util/xml.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/xml.h | 5 +++- 6 files changed, 101 insertions(+), 7 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 1ff0944..d295bfe 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -297,12 +297,24 @@ <define name="clock"> <optional> <element name="clock"> - <attribute name="offset"> - <choice> + <choice> + <attribute name="offset"> <value>localtime</value> + </attribute> + <attribute name="offset"> <value>utc</value> - </choice> - </attribute> + </attribute> + <group> + <attribute name="offset"> + <value>variable</value> + </attribute> + <optional> + <attribute name="adjustment"> + <ref name="timeDelta"/> + </attribute> + </optional> + </group> + </choice> <empty/> </element> </optional> @@ -1567,4 +1579,9 @@ <param name='pattern'>[a-zA-Z0-9\-_]+</param> </data> </define> + <define name="timeDelta"> + <data type="string"> + <param name="pattern">(-|\+)?[0-9]+</param> + </data> + </define> </grammar> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f86b4eb..49d5d19 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -231,7 +231,8 @@ VIR_ENUM_IMPL(virDomainNetdevMacvtap, VIR_DOMAIN_NETDEV_MACVTAP_MODE_LAST, VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST, "utc", - "localtime"); + "localtime", + "variable"); #define virDomainReportError(code, fmt...) \ virReportErrorHelper(NULL, VIR_FROM_DOMAIN, code, __FILE__, \ @@ -3492,6 +3493,13 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, } else { def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; } + switch (def->clock.offset) { + case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: + if (virXPathLongLong("./clock/@adjustment", ctxt, + &def->clock.adjustment) < 0) + def->clock.adjustment = 0; + break; + } def->os.bootloader = virXPathString("string(./bootloader)", ctxt); def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt); @@ -5399,8 +5407,14 @@ char *virDomainDefFormat(virDomainDefPtr def, if (virCPUDefFormatBuf(&buf, def->cpu, " ", 0) < 0) goto cleanup; - virBufferVSprintf(&buf, " <clock offset='%s'/>\n", + virBufferVSprintf(&buf, " <clock offset='%s'", virDomainClockOffsetTypeToString(def->clock.offset)); + switch (def->clock.offset) { + case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: + virBufferVSprintf(&buf, " adjustment='%lld'", def->clock.adjustment); + break; + } + virBufferAddLit(&buf, "/>\n"); if (virDomainLifecycleDefFormat(&buf, def->onPoweroff, "on_poweroff") < 0) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index fbbe683..f5fe016 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -612,6 +612,7 @@ struct _virSecurityLabelDef { enum virDomainClockOffsetType { VIR_DOMAIN_CLOCK_OFFSET_UTC = 0, VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME = 1, + VIR_DOMAIN_CLOCK_OFFSET_VARIABLE = 2, VIR_DOMAIN_CLOCK_OFFSET_LAST, }; @@ -620,6 +621,10 @@ typedef struct _virDomainClockDef virDomainClockDef; typedef virDomainClockDef *virDomainClockDefPtr; struct _virDomainClockDef { int offset; + + /* Adjustment in seconds, relative to UTC, when + * offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE */ + long long adjustment; }; #define VIR_DOMAIN_CPUMASK_LEN 1024 diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1af34bd..41bde8e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -629,6 +629,7 @@ virXPathStringLimit; virXPathBoolean; virXPathNumber; virXPathULong; +virXPathLongLong; virXPathULongLong; virXPathLongHex; virXPathULongHex; diff --git a/src/util/xml.c b/src/util/xml.c index 46ea9aa..14c8345 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -364,6 +364,60 @@ virXPathULongLong(const char *xpath, return (ret); } +/** + * virXPathULongLong: + * @xpath: the XPath string to evaluate + * @ctxt: an XPath context + * @value: the returned long long value + * + * Convenience function to evaluate an XPath number + * + * Returns 0 in case of success in which case @value is set, + * or -1 if the XPath evaluation failed or -2 if the + * value doesn't have a long format. + */ +int +virXPathLongLong(const char *xpath, + xmlXPathContextPtr ctxt, + long long *value) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret = 0; + + if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { + virXMLError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathLongLong()")); + return (-1); + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + char *conv = NULL; + unsigned long long val; + + val = strtoll((const char *) obj->stringval, &conv, 10); + if (conv == (const char *) obj->stringval) { + ret = -2; + } else { + *value = val; + } + } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) && + (!(isnan(obj->floatval)))) { + *value = (long long) obj->floatval; + if (*value != obj->floatval) { + ret = -2; + } + } else { + ret = -1; + } + + xmlXPathFreeObject(obj); + return (ret); +} + char * virXMLPropString(xmlNodePtr node, const char *name) diff --git a/src/util/xml.h b/src/util/xml.h index 246672d..af721bb 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -30,7 +30,10 @@ int virXPathULong(const char *xpath, int virXPathULongLong(const char *xpath, xmlXPathContextPtr ctxt, unsigned long long *value); -int virXPathLongHex(const char *xpath, +int virXPathLongLong(const char *xpath, + xmlXPathContextPtr ctxt, + long long *value); +int virXPathLongHex (const char *xpath, xmlXPathContextPtr ctxt, long *value); int virXPathULongHex(const char *xpath, -- 1.6.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list