diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 829adef26e..53cd96030f 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1028,6 +1028,81 @@ qemu-kvm -net nic,model=? /dev/null
+
+
+
+ A virtual hardware watchdog device can be added to the guest via
+ the watchdog
element.
+ Since 0.7.3, QEMU and KVM only
+
+
+
+ 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.
+
+
+
+ Currently libvirt does not support notification when the
+ watchdog fires. This feature is planned for a future version of
+ libvirt.
+
+
+
+ ...
+ <watchdog model='i6300esb'/>
+ ...
+
+
+ ...
+ <watchdog model='i6300esb' action='poweroff'/>
+ ...
+
+
+ model
+
+
+ The required model
attribute specifies what real
+ watchdog device is emulated. Valid values are specific to the
+ underlying hypervisor.
+
+
+ QEMU and KVM support:
+
+
+ 'i6300esb' — the recommended device,
+ emulating a PCI Intel 6300ESB
+ 'ib700' — emulating an ISA iBase IB700
+
+
+ action
+
+
+ The optional action
attribute describes what
+ action to take when the watchdog expires. Valid values are
+ specific to the underlying hypervisor.
+
+
+ QEMU and KVM support:
+
+
+ 'reset' — default, forcefully reset the guest
+ 'shutdown' — gracefully shutdown the guest
+ (not recommended)
+ 'poweroff' — forcefully power off the guest
+ 'pause' — pause the guest
+ 'none' — do nothing
+
+
+ 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.
+
+
+
+
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 1935f1530a..0a6ab61561 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -275,13 +275,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -842,7 +842,7 @@
-
+
vga
@@ -882,7 +882,7 @@
-
+
@@ -1013,6 +1013,27 @@
+
+
+
+
+ i6300esb
+ ib700
+
+
+
+
+
+ reset
+ shutdown
+ poweroff
+ pause
+ none
+
+
+
+
+
@@ -1139,6 +1160,9 @@
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index f50a8ef4a4..7d558e8d3b 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, " \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, " \n");
if (def->seclabel.model) {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 4b3646ee8c..ff1b0cfa1c 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 45d106900a..98ea7f885e 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 b881f1e4d1..158e9a3250 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 65d4d147c5..1b16aa91b5 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 0000000000..40a656b3ab
--- /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 0000000000..9b2ffdf8b2
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-watchdog.xml
@@ -0,0 +1,23 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219200
+ 219200
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+
+
+