On Wed, Oct 21, 2009 at 04:42:06PM +0200, Daniel Veillard wrote: > On Wed, Oct 21, 2009 at 01:32:49PM +0100, Richard W.M. Jones wrote: > > + if ((n = virXPathNodeSet(conn, "./devices/watchdog", ctxt, &nodes)) < 0) { > > + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, > > + "%s", _("cannot extract watchdog devices")); > > + goto error; > > + } > > Hum, I'm afraid this will lead to errros for any defintition without a > watchdog ! Since that's completely optional we really should not error > there IMHO and just skip it. Trouble is, the code preceeding this would fail first. It seems to be a generic problem with all those calls to virXPathNodeSet in that case. > As well as extending the domain.rng as you raised on IRC :-) The attached patch includes changes to the domain.rng and adds XML <-> qemu command line tests. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/
>From ae4ec398d9cc229d4d2ea8cb537d30572d58a61b Mon Sep 17 00:00:00 2001 From: Richard Jones <rjones@xxxxxxxxxx> Date: Wed, 21 Oct 2009 13:26:38 +0100 Subject: [PATCH] Support QEMU watchdog device. This adds simple support for configuring a guest with a QEMU/KVM virtual hardware watchdog device. --- docs/formatdomain.html.in | 75 +++++++++++ docs/schemas/domain.rng | 24 ++++ src/conf/domain_conf.c | 136 ++++++++++++++++++++- src/conf/domain_conf.h | 30 +++++ src/libvirt_private.syms | 4 + src/qemu/qemu_conf.c | 40 ++++++ tests/qemuargv2xmltest.c | 1 + tests/qemuxml2argvdata/qemuxml2argv-watchdog.args | 1 + tests/qemuxml2argvdata/qemuxml2argv-watchdog.xml | 23 ++++ 9 files changed, 333 insertions(+), 1 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-watchdog.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-watchdog.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 829adef..53cd960 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1028,6 +1028,81 @@ qemu-kvm -net nic,model=? /dev/null </dd> </dl> + <h4><a name="elementsWatchdog">Watchdog device</a></h4> + + <p> + A virtual hardware watchdog device can be added to the guest via + the <code>watchdog</code> element. + <span class="since">Since 0.7.3, QEMU and KVM only</span> + </p> + + <p> + The watchdog device requires an additional driver and management + daemon in the guest. Just enabling the watchdog in the libvirt + configuration does not do anything useful on its own. + </p> + + <p> + Currently libvirt does not support notification when the + watchdog fires. This feature is planned for a future version of + libvirt. + </p> + + <pre> + ... + <watchdog model='i6300esb'/> + ...</pre> + + <pre> + ... + <watchdog model='i6300esb' action='poweroff'/> + ...</pre> + + <dl> + <dt><code>model</code></dt> + <dd> + <p> + The required <code>model</code> attribute specifies what real + watchdog device is emulated. Valid values are specific to the + underlying hypervisor. + </p> + <p> + QEMU and KVM support: + </p> + <ul> + <li> 'i6300esb' — the recommended device, + emulating a PCI Intel 6300ESB </li> + <li> 'ib700' — emulating an ISA iBase IB700 </li> + </ul> + </dd> + <dt><code>action</code></dt> + <dd> + <p> + The optional <code>action</code> attribute describes what + action to take when the watchdog expires. Valid values are + specific to the underlying hypervisor. + </p> + <p> + QEMU and KVM support: + </p> + <ul> + <li>'reset' — default, forcefully reset the guest</li> + <li>'shutdown' — gracefully shutdown the guest + (not recommended) </li> + <li>'poweroff' — forcefully power off the guest</li> + <li>'pause' — pause the guest</li> + <li>'none' — do nothing</li> + </ul> + <p> + Note that the 'shutdown' action requires that the guest + is responsive to ACPI signals. In the sort of situations + where the watchdog has expired, guests are usually unable + to respond to ACPI signals. Therefore using 'shutdown' + is not recommended. + </p> + </dd> + </dl> + <h2><a name="examples">Example configs</a></h2> <p> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 1935f15..bb2db1d 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -1013,6 +1013,27 @@ </attribute> </element> </define> + <define name="watchdog"> + <element name="watchdog"> + <attribute name="model"> + <choice> + <value>i6300esb</value> + <value>ib700</value> + </choice> + </attribute> + <optional> + <attribute name="action"> + <choice> + <value>reset</value> + <value>shutdown</value> + <value>poweroff</value> + <value>pause</value> + <value>none</value> + </choice> + </attribute> + </optional> + </element> + </define> <define name="parallel"> <element name="parallel"> <ref name="qemucdev"/> @@ -1139,6 +1160,9 @@ <ref name="serial"/> </choice> </zeroOrMore> + <optional> + <ref name="watchdog"/> + </optional> </interleave> </element> </define> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f50a8ef..7d558e8 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -84,7 +84,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, "input", "sound", "video", - "hostdev") + "hostdev", + "watchdog") VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST, "block", @@ -144,6 +145,17 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST, "pcspk", "ac97") +VIR_ENUM_IMPL(virDomainWatchdogModel, VIR_DOMAIN_WATCHDOG_MODEL_LAST, + "i6300esb", + "ib700") + +VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST, + "reset", + "shutdown", + "poweroff", + "pause", + "none") + VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST, "vga", "cirrus", @@ -387,6 +399,14 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def) VIR_FREE(def); } +void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def); +} + void virDomainVideoDefFree(virDomainVideoDefPtr def) { if (!def) @@ -429,6 +449,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_HOSTDEV: virDomainHostdevDefFree(def->data.hostdev); break; + case VIR_DOMAIN_DEVICE_WATCHDOG: + virDomainWatchdogDefFree(def->data.watchdog); + break; } VIR_FREE(def); @@ -508,6 +531,8 @@ void virDomainDefFree(virDomainDefPtr def) VIR_FREE(def->emulator); VIR_FREE(def->description); + virDomainWatchdogDefFree(def->watchdog); + virSecurityLabelDefFree(def); VIR_FREE(def); @@ -1739,6 +1764,58 @@ error: } +static virDomainWatchdogDefPtr +virDomainWatchdogDefParseXML(virConnectPtr conn, + const xmlNodePtr node, + int flags ATTRIBUTE_UNUSED) { + + char *model = NULL; + char *action = NULL; + virDomainWatchdogDefPtr def; + + if (VIR_ALLOC (def) < 0) { + virReportOOMError (conn); + return NULL; + } + + model = virXMLPropString (node, "model"); + if (model == NULL) { + virDomainReportError (conn, VIR_ERR_INTERNAL_ERROR, + _("watchdog must contain model name")); + goto error; + } + def->model = virDomainWatchdogModelTypeFromString (model); + if (def->model < 0) { + virDomainReportError (conn, VIR_ERR_INTERNAL_ERROR, + _("unknown watchdog model '%s'"), model); + goto error; + } + + action = virXMLPropString (node, "action"); + if (action == NULL) + def->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET; + else { + def->action = virDomainWatchdogActionTypeFromString (action); + if (def->action < 0) { + virDomainReportError (conn, VIR_ERR_INTERNAL_ERROR, + _("unknown watchdog action '%s'"), action); + goto error; + } + } + +cleanup: + VIR_FREE (action); + VIR_FREE (model); + + return def; + +error: + virDomainWatchdogDefFree (def); + def = NULL; + goto cleanup; +} + + int virDomainVideoDefaultRAM(virDomainDefPtr def, int type) @@ -2365,6 +2442,11 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn, dev->type = VIR_DOMAIN_DEVICE_SOUND; if (!(dev->data.sound = virDomainSoundDefParseXML(conn, node, flags))) goto error; + } else if (xmlStrEqual(node->name, BAD_CAST "watchdog")) { + dev->type = VIR_DOMAIN_DEVICE_WATCHDOG; + if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(conn, node, + flags))) + goto error; } else if (xmlStrEqual(node->name, BAD_CAST "video")) { dev->type = VIR_DOMAIN_DEVICE_VIDEO; if (!(dev->data.video = virDomainVideoDefParseXML(conn, node, def, flags))) @@ -3039,6 +3121,28 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn, } VIR_FREE(nodes); + /* analysis of the watchdog devices */ + def->watchdog = NULL; + if ((n = virXPathNodeSet(conn, "./devices/watchdog", ctxt, &nodes)) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot extract watchdog devices")); + goto error; + } + if (n > 1) { + virDomainReportError (conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("only a single watchdog device is supported")); + goto error; + } + if (n > 0) { + virDomainWatchdogDefPtr watchdog = + virDomainWatchdogDefParseXML (conn, nodes[0], flags); + if (!watchdog) + goto error; + + def->watchdog = watchdog; + VIR_FREE(nodes); + } + /* analysis of security label */ if (virSecurityLabelDefParseXML(conn, def, ctxt, flags) == -1) goto error; @@ -3946,6 +4050,33 @@ virDomainSoundDefFormat(virConnectPtr conn, } +static int +virDomainWatchdogDefFormat(virConnectPtr conn, + virBufferPtr buf, + virDomainWatchdogDefPtr def) +{ + const char *model = virDomainWatchdogModelTypeToString (def->model); + const char *action = virDomainWatchdogActionTypeToString (def->action); + + if (!model) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unexpected watchdog model %d"), def->model); + return -1; + } + + if (!action) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unexpected watchdog action %d"), def->action); + return -1; + } + + virBufferVSprintf(buf, " <watchdog model='%s' action='%s'/>\n", + model, action); + + return 0; +} + + static void virDomainVideoAccelDefFormat(virBufferPtr buf, virDomainVideoAccelDefPtr def) @@ -4392,6 +4523,9 @@ char *virDomainDefFormat(virConnectPtr conn, if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n], flags) < 0) goto cleanup; + if (def->watchdog) + virDomainWatchdogDefFormat (conn, &buf, def->watchdog); + virBufferAddLit(&buf, " </devices>\n"); if (def->seclabel.model) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4b3646e..ff1b0cf 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -298,6 +298,30 @@ struct _virDomainSoundDef { int model; }; +enum virDomainWatchdogModel { + VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB, + VIR_DOMAIN_WATCHDOG_MODEL_IB700, + + VIR_DOMAIN_WATCHDOG_MODEL_LAST +}; + +enum virDomainWatchdogAction { + VIR_DOMAIN_WATCHDOG_ACTION_RESET, + VIR_DOMAIN_WATCHDOG_ACTION_SHUTDOWN, + VIR_DOMAIN_WATCHDOG_ACTION_POWEROFF, + VIR_DOMAIN_WATCHDOG_ACTION_PAUSE, + VIR_DOMAIN_WATCHDOG_ACTION_NONE, + + VIR_DOMAIN_WATCHDOG_ACTION_LAST +}; + +typedef struct _virDomainWatchdogDef virDomainWatchdogDef; +typedef virDomainWatchdogDef *virDomainWatchdogDefPtr; +struct _virDomainWatchdogDef { + int model; + int action; +}; + enum virDomainVideoType { VIR_DOMAIN_VIDEO_TYPE_VGA, @@ -438,6 +462,7 @@ enum virDomainDeviceType { VIR_DOMAIN_DEVICE_SOUND, VIR_DOMAIN_DEVICE_VIDEO, VIR_DOMAIN_DEVICE_HOSTDEV, + VIR_DOMAIN_DEVICE_WATCHDOG, VIR_DOMAIN_DEVICE_LAST, }; @@ -454,6 +479,7 @@ struct _virDomainDeviceDef { virDomainSoundDefPtr sound; virDomainVideoDefPtr video; virDomainHostdevDefPtr hostdev; + virDomainWatchdogDefPtr watchdog; } data; }; @@ -586,6 +612,7 @@ struct _virDomainDef { /* Only 1 */ virDomainChrDefPtr console; virSecurityLabelDef seclabel; + virDomainWatchdogDefPtr watchdog; }; /* Guest VM runtime state */ @@ -639,6 +666,7 @@ void virDomainFSDefFree(virDomainFSDefPtr def); void virDomainNetDefFree(virDomainNetDefPtr def); void virDomainChrDefFree(virDomainChrDefPtr def); void virDomainSoundDefFree(virDomainSoundDefPtr def); +void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def); void virDomainVideoDefFree(virDomainVideoDefPtr def); void virDomainHostdevDefFree(virDomainHostdevDefPtr def); void virDomainDeviceDefFree(virDomainDeviceDefPtr def); @@ -769,6 +797,8 @@ VIR_ENUM_DECL(virDomainFS) VIR_ENUM_DECL(virDomainNet) VIR_ENUM_DECL(virDomainChr) VIR_ENUM_DECL(virDomainSoundModel) +VIR_ENUM_DECL(virDomainWatchdogModel) +VIR_ENUM_DECL(virDomainWatchdogAction) VIR_ENUM_DECL(virDomainVideo) VIR_ENUM_DECL(virDomainHostdevMode) VIR_ENUM_DECL(virDomainHostdevSubsys) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 45d1069..98ea7f8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -132,6 +132,10 @@ virDomainSaveStatus; virDomainSoundDefFree; virDomainSoundModelTypeFromString; virDomainSoundModelTypeToString; +virDomainWatchdogModelTypeFromString; +virDomainWatchdogModelTypeToString; +virDomainWatchdogActionTypeFromString; +virDomainWatchdogActionTypeToString; virDomainVideoDefFree; virDomainVideoTypeToString; virDomainVideoTypeFromString; diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index b881f1e..158e9a3 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -2233,6 +2233,28 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG(modstr); } + /* Add watchdog hardware */ + if (def->watchdog) { + virDomainWatchdogDefPtr watchdog = def->watchdog; + const char *model = virDomainWatchdogModelTypeToString(watchdog->model); + if (!model) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("invalid watchdog model")); + goto error; + } + ADD_ARG_LIT("-watchdog"); + ADD_ARG_LIT(model); + + const char *action = virDomainWatchdogActionTypeToString(watchdog->action); + if (!action) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("invalid watchdog action")); + goto error; + } + ADD_ARG_LIT("-watchdog-action"); + ADD_ARG_LIT(action); + } + /* Add host passthrough hardware */ for (i = 0 ; i < def->nhostdevs ; i++) { int ret; @@ -3482,6 +3504,24 @@ virDomainDefPtr qemuParseCommandLine(virConnectPtr conn, start = tmp ? tmp + 1 : NULL; } + } else if (STREQ(arg, "-watchdog")) { + WANT_VALUE(); + int model = virDomainWatchdogModelTypeFromString (val); + + if (model != -1) { + virDomainWatchdogDefPtr wd; + if (VIR_ALLOC(wd) < 0) + goto no_memory; + wd->model = model; + wd->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET; + def->watchdog = wd; + } + } else if (STREQ(arg, "-watchdog-action") && def->watchdog) { + WANT_VALUE(); + int action = virDomainWatchdogActionTypeFromString (val); + + if (action != -1) + def->watchdog->action = action; } else if (STREQ(arg, "-bootloader")) { WANT_VALUE(); def->os.bootloader = strdup(val); diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 65d4d14..1b16aa9 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -212,6 +212,7 @@ mymain(int argc, char **argv) DO_TEST("parallel-tcp", 0); DO_TEST("console-compat", 0); DO_TEST("sound", 0); + DO_TEST("watchdog", 0); DO_TEST("hostdev-usb-product", 0); DO_TEST("hostdev-usb-address", 0); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-watchdog.args b/tests/qemuxml2argvdata/qemuxml2argv-watchdog.args new file mode 100644 index 0000000..40a656b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-watchdog.args @@ -0,0 +1 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb -watchdog ib700 -watchdog-action poweroff diff --git a/tests/qemuxml2argvdata/qemuxml2argv-watchdog.xml b/tests/qemuxml2argvdata/qemuxml2argv-watchdog.xml new file mode 100644 index 0000000..9b2ffdf --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-watchdog.xml @@ -0,0 +1,23 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <watchdog model='ib700' action='poweroff'/> + </devices> +</domain> -- 1.6.5.rc2
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list