Implement XML parser/formatter for "timer" subelement of domain clock

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
This commit is contained in:
Laine Stump 2010-03-30 13:44:22 +02:00 committed by Daniel Veillard
parent 99123ba012
commit 92a9e5df63
3 changed files with 301 additions and 4 deletions

View File

@ -245,6 +245,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__)
@ -606,6 +629,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;
@ -675,8 +710,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);
@ -2512,6 +2546,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) {
@ -3643,7 +3778,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) {
@ -3672,6 +3806,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);
@ -5271,6 +5423,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,
@ -5569,7 +5790,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)

View File

@ -646,6 +646,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,
@ -669,6 +719,9 @@ struct _virDomainClockDef {
* offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME */
char *timezone;
} data;
int ntimers;
virDomainTimerDefPtr *timers;
};
# define VIR_DOMAIN_CPUMASK_LEN 1024
@ -975,4 +1028,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 */

View File

@ -197,6 +197,15 @@ virDomainDeviceInfoIterate;
virDomainClockOffsetTypeToString;
virDomainClockOffsetTypeFromString;
virDomainDiskErrorPolicyTypeToString;
virDomainTimerNameTypeToString;
virDomainTimerNameTypeFromString;
virDomainTimerWallclockTypeToString;
virDomainTimerWallclockTypeFromString;
virDomainTimerTickpolicyTypeToString;
virDomainTimerTickpolicyTypeFromString;
virDomainTimerModeTypeToString;
virDomainTimerModeTypeFromString;
# domain_event.h
virDomainEventCallbackListAdd;