1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-23 21:34:54 +03:00

Support QEMU watchdog device.

This adds simple support for configuring a guest with a QEMU/KVM
virtual hardware watchdog device.
This commit is contained in:
Richard Jones 2009-10-21 13:26:38 +01:00
parent b03fe2d0ae
commit 08bed02515
9 changed files with 342 additions and 10 deletions

View File

@ -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>

View File

@ -275,13 +275,13 @@
</element>
</optional>
<optional>
<element name="memoryBacking">
<optional>
<element name="hugepages">
<empty/>
</element>
</optional>
</element>
<element name="memoryBacking">
<optional>
<element name="hugepages">
<empty/>
</element>
</optional>
</element>
</optional>
<optional>
<element name="vcpu">
@ -842,7 +842,7 @@
<define name="video">
<element name="video">
<optional>
<element name="model">
<element name="model">
<attribute name="type">
<choice>
<value>vga</value>
@ -882,7 +882,7 @@
</optional>
</element>
</optional>
</element>
</element>
</optional>
</element>
</define>
@ -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>

View File

@ -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) {

View File

@ -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)

View File

@ -132,6 +132,10 @@ virDomainSaveStatus;
virDomainSoundDefFree;
virDomainSoundModelTypeFromString;
virDomainSoundModelTypeToString;
virDomainWatchdogModelTypeFromString;
virDomainWatchdogModelTypeToString;
virDomainWatchdogActionTypeFromString;
virDomainWatchdogActionTypeToString;
virDomainVideoDefFree;
virDomainVideoTypeToString;
virDomainVideoTypeFromString;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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>