[libvirt] [PATCH 1/4] Implement XML parser/formatter for "timer" subelement of domain clock.

Laine Stump laine at laine.org
Fri Mar 26 18:21:37 UTC 2010


This extension is described in

  http://www.redhat.com/archives/libvir-list/2010-March/msg00304.html

Currently all attributes are optional, except name.

* src/conf/domain_conf.h: add data definition for virDomainTimerDef
                          and add a list of them to virDomainClockDef
* src/conf/domain_conf.c: XML parser and formatter for a timer inside a clock
* src/libvirt_private.syms: add new Timer enum helper functions to symbols
---
 src/conf/domain_conf.c   |  238 +++++++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h   |   58 +++++++++++
 src/libvirt_private.syms |    9 ++-
 3 files changed, 300 insertions(+), 5 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 651dd04..e864417 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -239,6 +239,29 @@ VIR_ENUM_IMPL(virDomainClockOffset, VIR_DOMAIN_CLOCK_OFFSET_LAST,
               "variable",
               "timezone");
 
+VIR_ENUM_IMPL(virDomainTimerName, VIR_DOMAIN_TIMER_NAME_LAST,
+              "platform",
+              "pit",
+              "rtc",
+              "hpet",
+              "tsc");
+
+VIR_ENUM_IMPL(virDomainTimerWallclock, VIR_DOMAIN_TIMER_WALLCLOCK_LAST,
+              "host",
+              "guest");
+
+VIR_ENUM_IMPL(virDomainTimerTickpolicy, VIR_DOMAIN_TIMER_TICKPOLICY_LAST,
+              "delay",
+              "catchup",
+              "merge",
+              "discard");
+
+VIR_ENUM_IMPL(virDomainTimerMode, VIR_DOMAIN_TIMER_MODE_LAST,
+              "auto",
+              "native",
+              "emulate",
+              "paravirt");
+
 #define virDomainReportError(code, ...)                              \
     virReportErrorHelper(NULL, VIR_FROM_DOMAIN, code, __FILE__,      \
                          __FUNCTION__, __LINE__, __VA_ARGS__)
@@ -597,6 +620,18 @@ void virSecurityLabelDefFree(virDomainDefPtr def)
     VIR_FREE(def->seclabel.imagelabel);
 }
 
+static void
+virDomainClockDefClear(virDomainClockDefPtr def)
+{
+    if (def->offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE)
+        VIR_FREE(def->data.timezone);
+
+    int i;
+    for (i = 0; i < def->ntimers; i++)
+        VIR_FREE(def->timers[i]);
+    VIR_FREE(def->timers);
+}
+
 void virDomainDefFree(virDomainDefPtr def)
 {
     unsigned int i;
@@ -666,8 +701,7 @@ void virDomainDefFree(virDomainDefPtr def)
     VIR_FREE(def->os.bootloader);
     VIR_FREE(def->os.bootloaderArgs);
 
-    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE)
-        VIR_FREE(def->clock.data.timezone);
+    virDomainClockDefClear(&def->clock);
 
     VIR_FREE(def->name);
     VIR_FREE(def->cpumask);
@@ -2462,6 +2496,107 @@ error:
 }
 
 
+/* Parse the XML definition for a clock timer */
+static virDomainTimerDefPtr
+virDomainTimerDefParseXML(const xmlNodePtr node,
+                          xmlXPathContextPtr ctxt,
+                          int flags ATTRIBUTE_UNUSED)
+{
+    char *name = NULL;
+    char *present = NULL;
+    char *tickpolicy = NULL;
+    char *wallclock = NULL;
+    char *mode = NULL;
+
+    virDomainTimerDefPtr def;
+    xmlNodePtr oldnode = ctxt->node;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    ctxt->node = node;
+
+    name = virXMLPropString(node, "name");
+    if (name == NULL) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("missing timer name"));
+        goto error;
+    }
+    if ((def->name = virDomainTimerNameTypeFromString(name)) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             _("unknown timer name '%s'"), name);
+        goto error;
+    }
+
+    def->present = -1; /* unspecified */
+    if ((present = virXMLPropString(node, "present")) != NULL) {
+        if (STREQ(present, "yes")) {
+            def->present = 1;
+        } else if (STREQ(present, "no")) {
+            def->present = 0;
+        } else {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("unknown timer present value '%s'"), present);
+            goto error;
+        }
+    }
+
+    def->tickpolicy = -1;
+    tickpolicy = virXMLPropString(node, "tickpolicy");
+    if (tickpolicy != NULL) {
+        if ((def->tickpolicy = virDomainTimerTickpolicyTypeFromString(tickpolicy)) < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("unknown timer tickpolicy '%s'"), tickpolicy);
+            goto error;
+        }
+    }
+
+    def->wallclock = -1;
+    wallclock = virXMLPropString(node, "wallclock");
+    if (wallclock != NULL) {
+        if ((def->wallclock = virDomainTimerWallclockTypeFromString(wallclock)) < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("unknown timer wallclock '%s'"), wallclock);
+            goto error;
+        }
+    }
+
+    int ret = virXPathULong("string(./frequency)", ctxt, &def->frequency);
+    if (ret == -1) {
+        def->frequency = 0;
+    } else if (ret <= 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("invalid timer frequency"));
+        goto error;
+    }
+
+    def->mode = -1;
+    mode = virXMLPropString(node, "mode");
+    if (mode != NULL) {
+        if ((def->mode = virDomainTimerModeTypeFromString(mode)) < 0) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("unknown timer mode '%s'"), mode);
+            goto error;
+        }
+    }
+
+cleanup:
+    VIR_FREE(name);
+    VIR_FREE(present);
+    VIR_FREE(tickpolicy);
+    VIR_FREE(wallclock);
+    VIR_FREE(mode);
+    ctxt->node = oldnode;
+
+    return def;
+
+error:
+    VIR_FREE(def);
+    goto cleanup;
+}
+
 /* Parse the XML definition for a graphics device */
 static virDomainGraphicsDefPtr
 virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) {
@@ -3593,7 +3728,6 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
                                    &def->onCrash, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
         goto error;
 
-
     tmp = virXPathString("string(./clock/@offset)", ctxt);
     if (tmp) {
         if ((def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
@@ -3622,6 +3756,24 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
         break;
     }
 
+    if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("failed to parse timers"));
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->clock.timers, n) < 0)
+        goto no_memory;
+    for (i = 0 ; i < n ; i++) {
+        virDomainTimerDefPtr timer = virDomainTimerDefParseXML(nodes[i],
+                                                               ctxt,
+                                                               flags);
+        if (!timer)
+            goto error;
+
+        def->clock.timers[def->clock.ntimers++] = timer;
+    }
+    VIR_FREE(nodes);
+
     def->os.bootloader = virXPathString("string(./bootloader)", ctxt);
     def->os.bootloaderArgs = virXPathString("string(./bootloader_args)", ctxt);
 
@@ -5207,6 +5359,75 @@ virDomainInputDefFormat(virBufferPtr buf,
 
 
 static int
+virDomainTimerDefFormat(virBufferPtr buf,
+                        virDomainTimerDefPtr def)
+{
+    const char *name = virDomainTimerNameTypeToString(def->name);
+
+    if (!name) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected timer name %d"), def->name);
+        return -1;
+    }
+    virBufferVSprintf(buf, "    <timer name='%s'", name);
+
+    if (def->present == 0) {
+        virBufferAddLit(buf, " present='no'");
+    } else if (def->present == 1) {
+        virBufferAddLit(buf, " present='yes'");
+    }
+
+    if (def->tickpolicy != -1) {
+        const char *tickpolicy
+            = virDomainTimerTickpolicyTypeToString(def->tickpolicy);
+        if (!tickpolicy) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 _("unexpected timer tickpolicy %d"),
+                                 def->tickpolicy);
+            return -1;
+        }
+        virBufferVSprintf(buf, " tickpolicy='%s'", tickpolicy);
+    }
+
+    if ((def->name == VIR_DOMAIN_TIMER_NAME_PLATFORM)
+        || (def->name == VIR_DOMAIN_TIMER_NAME_RTC)) {
+        if (def->wallclock != -1) {
+            const char *wallclock
+                = virDomainTimerWallclockTypeToString(def->wallclock);
+            if (!wallclock) {
+                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                     _("unexpected timer wallclock %d"),
+                                     def->wallclock);
+                return -1;
+            }
+            virBufferVSprintf(buf, " wallclock='%s'", wallclock);
+        }
+    }
+
+    if (def->name == VIR_DOMAIN_TIMER_NAME_TSC) {
+        if (def->frequency > 0) {
+            virBufferVSprintf(buf, " frequency='%lu'", def->frequency);
+        }
+
+        if (def->mode != -1) {
+            const char *mode
+                = virDomainTimerModeTypeToString(def->mode);
+            if (!mode) {
+                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                     _("unexpected timer mode %d"),
+                                     def->mode);
+                return -1;
+            }
+            virBufferVSprintf(buf, " mode='%s'", mode);
+        }
+    }
+
+    virBufferAddLit(buf, "/>\n");
+
+    return 0;
+}
+
+static int
 virDomainGraphicsDefFormat(virBufferPtr buf,
                            virDomainGraphicsDefPtr def,
                            int flags)
@@ -5504,7 +5725,16 @@ char *virDomainDefFormat(virDomainDefPtr def,
         virBufferEscapeString(&buf, " timezone='%s'", def->clock.data.timezone);
         break;
     }
-    virBufferAddLit(&buf, "/>\n");
+    if (def->clock.ntimers == 0) {
+        virBufferAddLit(&buf, "/>\n");
+    } else {
+        virBufferAddLit(&buf, ">\n");
+        for (n = 0; n < def->clock.ntimers; n++) {
+            if (virDomainTimerDefFormat(&buf, def->clock.timers[n]) < 0)
+                goto cleanup;
+        }
+        virBufferAddLit(&buf, "  </clock>\n");
+    }
 
     if (virDomainLifecycleDefFormat(&buf, def->onPoweroff,
                                     "on_poweroff") < 0)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 218e0a7..d5c0637 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -633,6 +633,56 @@ struct _virSecurityLabelDef {
     int type;
 };
 
+enum virDomainTimerNameType {
+    VIR_DOMAIN_TIMER_NAME_PLATFORM = 0,
+    VIR_DOMAIN_TIMER_NAME_PIT,
+    VIR_DOMAIN_TIMER_NAME_RTC,
+    VIR_DOMAIN_TIMER_NAME_HPET,
+    VIR_DOMAIN_TIMER_NAME_TSC,
+
+    VIR_DOMAIN_TIMER_NAME_LAST,
+};
+
+enum virDomainTimerWallclockType {
+    VIR_DOMAIN_TIMER_WALLCLOCK_HOST = 0,
+    VIR_DOMAIN_TIMER_WALLCLOCK_GUEST,
+
+    VIR_DOMAIN_TIMER_WALLCLOCK_LAST,
+};
+
+enum virDomainTimerTickpolicyType {
+    VIR_DOMAIN_TIMER_TICKPOLICY_DELAY = 0,
+    VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP,
+    VIR_DOMAIN_TIMER_TICKPOLICY_MERGE,
+    VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD,
+
+    VIR_DOMAIN_TIMER_TICKPOLICY_LAST,
+};
+
+enum virDomainTimerModeType {
+    VIR_DOMAIN_TIMER_MODE_AUTO = 0,
+    VIR_DOMAIN_TIMER_MODE_NATIVE,
+    VIR_DOMAIN_TIMER_MODE_EMULATE,
+    VIR_DOMAIN_TIMER_MODE_PARAVIRT,
+
+    VIR_DOMAIN_TIMER_MODE_LAST,
+};
+
+typedef struct _virDomainTimerDef virDomainTimerDef;
+typedef virDomainTimerDef *virDomainTimerDefPtr;
+struct _virDomainTimerDef {
+    int name;
+    int present;    /* unspecified = -1, no = 0, yes = 1 */
+    int tickpolicy; /* none|catchup|merge|discard */
+
+    /* wallclock is only valid for name='platform|rtc' */
+    int wallclock;  /* host|guest */
+
+    /* frequency & mode are only valid for name='tsc' */
+    unsigned long frequency; /* in Hz, unspecified = 0 */
+    int mode;       /* auto|native|emulate|paravirt */
+};
+
 enum virDomainClockOffsetType {
     VIR_DOMAIN_CLOCK_OFFSET_UTC = 0,
     VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME = 1,
@@ -656,6 +706,9 @@ struct _virDomainClockDef {
          * offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME */
         char *timezone;
     } data;
+
+    int ntimers;
+    virDomainTimerDefPtr *timers;
 };
 
 # define VIR_DOMAIN_CPUMASK_LEN 1024
@@ -958,4 +1011,9 @@ VIR_ENUM_DECL(virDomainClockOffset)
 
 VIR_ENUM_DECL(virDomainNetdevMacvtap)
 
+VIR_ENUM_DECL(virDomainTimerName)
+VIR_ENUM_DECL(virDomainTimerWallclock)
+VIR_ENUM_DECL(virDomainTimerTickpolicy)
+VIR_ENUM_DECL(virDomainTimerMode)
+
 #endif /* __DOMAIN_CONF_H */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0033d2a..83059ad 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -192,7 +192,14 @@ virDomainDefClearDeviceAliases;
 virDomainDeviceInfoIterate;
 virDomainClockOffsetTypeToString;
 virDomainClockOffsetTypeFromString;
-
+virDomainTimerNameTypeToString;
+virDomainTimerNameTypeFromString;
+virDomainTimerWallclockTypeToString;
+virDomainTimerWallclockTypeFromString;
+virDomainTimerTickpolicyTypeToString;
+virDomainTimerTickpolicyTypeFromString;
+virDomainTimerModeTypeToString;
+virDomainTimerModeTypeFromString;
 
 # domain_event.h
 virDomainEventCallbackListAdd;
-- 
1.6.6.1




More information about the libvir-list mailing list