[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] Support QEMU/KVM watchdog device



Time to brush off this old patch.  This adds simple support for the
QEMU/KVM emulated hardware watchdog device (qemu commit
9dd986ccf68f142aaafe543d80cf877716d91d4e).

Event notification isn't supported.  This just lets you configure a
domain with a <watchdog.../> device, select the model and action.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming blog: http://rwmj.wordpress.com
Fedora now supports 80 OCaml packages (the OPEN alternative to F#)
http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
>From e5e1afaa76fa1485ec8e9bd2d5dde19ac7ce6e12 Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones redhat com>
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 +++++++++++++++++++++++++
 src/conf/domain_conf.c    |  136 ++++++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h    |   30 ++++++++++
 src/libvirt_private.syms  |    4 +
 src/qemu/qemu_conf.c      |   40 +++++++++++++
 5 files changed, 284 insertions(+), 1 deletions(-)

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>
+      ...
+      &lt;watchdog model='i6300esb'/&gt;
+      ...</pre>
+
+    <pre>
+      ...
+      &lt;watchdog model='i6300esb' action='poweroff'/&gt;
+      ...</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' &mdash; the recommended device,
+	    emulating a PCI Intel 6300ESB </li>
+	  <li> 'ib700' &mdash; 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' &mdash; default, forcefully reset the guest</li>
+	  <li>'shutdown' &mdash; gracefully shutdown the guest
+	    (not recommended) </li>
+	  <li>'poweroff' &mdash; forcefully power off the guest</li>
+	  <li>'pause' &mdash; pause the guest</li>
+	  <li>'none' &mdash; 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/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);
-- 
1.6.5.rc2


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]