Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
docs/formatdomain.html.in | 11 ++++
docs/schemas/domaincommon.rng | 12 +++++
src/conf/domain_conf.c | 119 +++++++++++++++++++++++++++++++++++++++---
src/conf/domain_conf.h | 11 ++++
4 files changed, 145 insertions(+), 8 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index fba8cfc6f3..205122f28e 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -6298,6 +6298,17 @@ qemu-kvm -net nic,model=? /dev/null
slot.
</p>
+ <p>
+ For character device with type <code>unix</code> or
<code>tcp</code>
+ the <code>source</code> has an optional element
<code>reconnect</code>
+ which configures reconnect timeout if the connection is lost.
+ There are two attributes, <code>enabled</code> where possible
+ values are <code>yes</code> and <code>no</code> and
<code>timeout</code>
+ which is in seconds. The <code>reconnect</code> attribute is valid
only
+ for <code>connect</code> mode.
+ <span class="since">Since 3.7.0 (QEMU driver only)</span>.
+ </p>
+
<h5><a id="elementsCharGuestInterface">Guest
interface</a></h5>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 3f56d8f45b..06c5a91b3d 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3634,6 +3634,18 @@
<ref name="virYesNo"/>
</attribute>
</optional>
+ <optional>
+ <element name="reconnect">
+ <attribute name="enabled">
+ <ref name="virYesNo"/>
+ </attribute>
+ <optional>
+ <attribute name="timeout">
+ <ref name="unsignedInt"/>
+ </attribute>
+ </optional>
+ </element>
+ </optional>
<zeroOrMore>
<ref name='devSeclabel'/>
</zeroOrMore>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5bad3976cf..e291d13ac5 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -5130,6 +5130,12 @@ virDomainChrSourceDefValidate(const virDomainChrSourceDef *def,
_("Missing source service attribute for char
device"));
return -1;
}
+
+ if (def->data.tcp.listen && def->data.tcp.reconnect.enabled) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("chardev reconnect is possible only for connect
mode"));
+ return -1;
+ }
break;
case VIR_DOMAIN_CHR_TYPE_UDP:
@@ -5150,6 +5156,12 @@ virDomainChrSourceDefValidate(const virDomainChrSourceDef *def,
_("Missing source path attribute for char
device"));
return -1;
}
+
+ if (def->data.nix.listen && def->data.nix.reconnect.enabled) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("chardev reconnect is possible only for connect
mode"));
+ return -1;
+ }
break;
case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
@@ -11115,6 +11127,56 @@ virDomainChrDefParseTargetXML(virDomainChrDefPtr def,
return ret;
}
+static int
+virDomainChrSourceReconnectDefParseXML(virDomainChrSourceReconnectDefPtr def,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
+{
+ int ret = -1;
+ int tmpVal;
+ char *tmp = NULL;
+ xmlNodePtr saveNode = ctxt->node;
+ xmlNodePtr cur;
+
+ ctxt->node = node;
+
+ if ((cur = virXPathNode("./reconnect", ctxt))) {
+ if ((tmp = virXMLPropString(cur, "enabled"))) {
+ if ((tmpVal = virTristateBoolTypeFromString(tmp)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid reconnect enabled value:
'%s'"),
+ tmp);
+ goto cleanup;
+ }
+ def->enabled = tmpVal;
+ VIR_FREE(tmp);
+ }
+
+ if (def->enabled == VIR_TRISTATE_BOOL_YES) {
+ if ((tmp = virXMLPropString(cur, "timeout"))) {
+ if (virStrToLong_ui(tmp, NULL, 10, &def->timeout) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid reconnect enabled value:
'%s'"),
+ tmp);
+ goto cleanup;
+ }
+ VIR_FREE(tmp);
+ } else {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing timeout for chardev with "
+ "reconnect enabled"));
+ goto cleanup;
+ }
+ }
+ }
+
+ ret = 0;
+ cleanup:
+ ctxt->node = saveNode;
+ VIR_FREE(tmp);
+ return ret;
+}
+
typedef enum {
VIR_DOMAIN_CHR_SOURCE_MODE_CONNECT,
@@ -11152,6 +11214,7 @@ virDomainChrSourceDefParseMode(xmlNodePtr source)
static int
virDomainChrSourceDefParseTCP(virDomainChrSourceDefPtr def,
xmlNodePtr source,
+ xmlXPathContextPtr ctxt,
unsigned int flags)
{
int mode;
@@ -11187,6 +11250,12 @@ virDomainChrSourceDefParseTCP(virDomainChrSourceDefPtr def,
VIR_FREE(tmp);
}
+ if (virDomainChrSourceReconnectDefParseXML(&def->data.tcp.reconnect,
+ source,
+ ctxt) < 0) {
+ goto error;
+ }
+
return 0;
error:
@@ -11220,7 +11289,8 @@ virDomainChrSourceDefParseUDP(virDomainChrSourceDefPtr def,
static int
virDomainChrSourceDefParseUnix(virDomainChrSourceDefPtr def,
- xmlNodePtr source)
+ xmlNodePtr source,
+ xmlXPathContextPtr ctxt)
{
int mode;
@@ -11231,6 +11301,12 @@ virDomainChrSourceDefParseUnix(virDomainChrSourceDefPtr def,
def->data.nix.listen = mode == VIR_DOMAIN_CHR_SOURCE_MODE_BIND;
def->data.nix.path = virXMLPropString(source, "path");
+ if (virDomainChrSourceReconnectDefParseXML(&def->data.nix.reconnect,
+ source,
+ ctxt) < 0) {
+ return -1;
+ }
+
return 0;
}
@@ -11359,7 +11435,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
break;
case VIR_DOMAIN_CHR_TYPE_UNIX:
- if (virDomainChrSourceDefParseUnix(def, cur) < 0)
+ if (virDomainChrSourceDefParseUnix(def, cur, ctxt) < 0)
goto error;
break;
@@ -11369,7 +11445,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
break;
case VIR_DOMAIN_CHR_TYPE_TCP:
- if (virDomainChrSourceDefParseTCP(def, cur, flags) < 0)
+ if (virDomainChrSourceDefParseTCP(def, cur, ctxt, flags) < 0)
goto error;
break;
@@ -11613,6 +11689,7 @@ virDomainChrDefParseXML(virDomainXMLOptionPtr xmlopt,
static virDomainSmartcardDefPtr
virDomainSmartcardDefParseXML(virDomainXMLOptionPtr xmlopt,
xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
unsigned int flags)
{
xmlNodePtr cur;
@@ -11705,7 +11782,7 @@ virDomainSmartcardDefParseXML(virDomainXMLOptionPtr xmlopt,
cur = node->children;
if (virDomainChrSourceDefParseXML(def->data.passthru, cur, flags,
- NULL, NULL, NULL, 0) < 0)
+ NULL, ctxt, NULL, 0) < 0)
goto error;
if (def->data.passthru->type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
@@ -14183,6 +14260,7 @@ virDomainHostdevDefParseXML(virDomainXMLOptionPtr xmlopt,
static virDomainRedirdevDefPtr
virDomainRedirdevDefParseXML(virDomainXMLOptionPtr xmlopt,
xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
virHashTablePtr bootHash,
unsigned int flags)
{
@@ -14224,7 +14302,7 @@ virDomainRedirdevDefParseXML(virDomainXMLOptionPtr xmlopt,
/* boot gets parsed in virDomainDeviceInfoParseXML
* source gets parsed in virDomainChrSourceDefParseXML */
if (virDomainChrSourceDefParseXML(def->source, cur, flags,
- NULL, NULL, NULL, 0) < 0)
+ NULL, ctxt, NULL, 0) < 0)
goto error;
if (def->source->type == VIR_DOMAIN_CHR_TYPE_SPICEVMC)
@@ -14883,7 +14961,7 @@ virDomainDeviceDefParse(const char *xmlStr,
break;
case VIR_DOMAIN_DEVICE_REDIRDEV:
if (!(dev->data.redirdev = virDomainRedirdevDefParseXML(xmlopt, node,
- NULL, flags)))
+ ctxt, NULL, flags)))
goto error;
break;
case VIR_DOMAIN_DEVICE_RNG:
@@ -14902,7 +14980,7 @@ virDomainDeviceDefParse(const char *xmlStr,
break;
case VIR_DOMAIN_DEVICE_SMARTCARD:
if (!(dev->data.smartcard = virDomainSmartcardDefParseXML(xmlopt, node,
- flags)))
+ ctxt, flags)))
goto error;
break;
case VIR_DOMAIN_DEVICE_MEMBALLOON:
@@ -18600,6 +18678,7 @@ virDomainDefParseXML(xmlDocPtr xml,
for (i = 0; i < n; i++) {
virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(xmlopt,
nodes[i],
+ ctxt,
flags);
if (!card)
goto error;
@@ -18949,7 +19028,7 @@ virDomainDefParseXML(xmlDocPtr xml,
goto error;
for (i = 0; i < n; i++) {
virDomainRedirdevDefPtr redirdev =
- virDomainRedirdevDefParseXML(xmlopt, nodes[i], bootHash, flags);
+ virDomainRedirdevDefParseXML(xmlopt, nodes[i], ctxt, bootHash, flags);
if (!redirdev)
goto error;
@@ -23070,6 +23149,24 @@ virDomainChrAttrsDefFormat(virBufferPtr buf,
return 0;
}
+
+static void
+virDomainChrSourceReconnectDefFormat(virBufferPtr buf,
+ virDomainChrSourceReconnectDefPtr def)
+{
+ if (def->enabled == VIR_TRISTATE_BOOL_ABSENT)
+ return;
+
+ virBufferAsprintf(buf, "<reconnect enabled='%s'",
+ virTristateBoolTypeToString(def->enabled));
+
+ if (def->enabled == VIR_TRISTATE_BOOL_YES)
+ virBufferAsprintf(buf, " timeout='%u'", def->timeout);
+
+ virBufferAddLit(buf, "/>\n");
+}
+
+
static int
virDomainChrSourceDefFormat(virBufferPtr buf,
virDomainChrSourceDefPtr def,
@@ -23150,6 +23247,9 @@ virDomainChrSourceDefFormat(virBufferPtr buf,
virBufferAsprintf(&attrBuf, " tlsFromConfig='%d'",
def->data.tcp.tlsFromConfig);
+ virDomainChrSourceReconnectDefFormat(&childBuf,
+ &def->data.tcp.reconnect);
+
if (virXMLFormatElement(buf, "source", &attrBuf, &childBuf)
< 0)
goto error;
@@ -23166,6 +23266,9 @@ virDomainChrSourceDefFormat(virBufferPtr buf,
virDomainSourceDefFormatSeclabel(&childBuf, def->nseclabels,
def->seclabels, flags);
+ virDomainChrSourceReconnectDefFormat(&childBuf,
+ &def->data.nix.reconnect);
+
if (virXMLFormatElement(buf, "source", &attrBuf, &childBuf)
< 0)
goto error;
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index c3d6845032..e2d0bb1b50 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1137,6 +1137,15 @@ typedef enum {
VIR_DOMAIN_CHR_SPICEVMC_LAST
} virDomainChrSpicevmcName;
+
+struct _virDomainChrSourceReconnectDef {
+ virTristateBool enabled;
+ unsigned int timeout;
+};
+typedef struct _virDomainChrSourceReconnectDef virDomainChrSourceReconnectDef;
+typedef virDomainChrSourceReconnectDef *virDomainChrSourceReconnectDefPtr;
+
+
/* The host side information for a character device. */
struct _virDomainChrSourceDef {
int type; /* virDomainChrType */
@@ -1159,6 +1168,7 @@ struct _virDomainChrSourceDef {
bool tlscreds;
int haveTLS; /* enum virTristateBool */
bool tlsFromConfig;
+ virDomainChrSourceReconnectDef reconnect;
} tcp;
struct {
char *bindHost;
@@ -1169,6 +1179,7 @@ struct _virDomainChrSourceDef {
struct {
char *path;
bool listen;
+ virDomainChrSourceReconnectDef reconnect;
} nix;
int spicevmc;
struct {
--
2.13.5