For vhost-user ports, Open vSwitch acts as the server and QEMU the client. When OVS crashes or restarts, the QEMU process should be reconnected to OVS. Signed-off-by: ZhiPeng Lu <lu.zhipeng@xxxxxxxxxx> Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- v1->v2: - modify xml format v2->v3: - fix commit message syntax - reimplemente functions and the struct about reconnect v3->v4: - revert reimplemente functions and the struct about reconnect docs/formatdomain.html.in | 7 +- docs/schemas/domaincommon.rng | 26 ++-- src/conf/domain_conf.c | 158 ++++++++++++--------- .../qemuxml2argv-net-vhostuser-multiq.args | 12 +- .../qemuxml2argv-net-vhostuser-multiq.xml | 11 +- 5 files changed, 127 insertions(+), 87 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 92e14a9..7ea72ed 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -5756,7 +5756,9 @@ qemu-kvm -net nic,model=? /dev/null </interface> <interface type='vhostuser'> <mac address='52:54:00:3b:83:1b'/> - <source type='unix' path='/tmp/vhost2.sock' mode='client'/> + <source type='unix' path='/tmp/vhost2.sock' mode='client'> + <reconnect enabled='yes' timeout='10'/> + </source> <model type='virtio'/> <driver queues='5'/> </interface> @@ -5772,6 +5774,9 @@ qemu-kvm -net nic,model=? /dev/null are supported. vhost-user requires the virtio model type, thus the <code><model></code> element is mandatory. + <span class="since">Since 3.10.0</span> the element has an optional + attribute <code>reconnect</code> which configures reconnect timeout + (in seconds) if the connection is lost. </p> <h5><a id="elementNwfilter">Traffic filtering with NWFilter</a></h5> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 9cec1a0..66b9758 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2399,6 +2399,18 @@ </attribute> </optional> </define> + <define name="reconnect"> + <element name="reconnect"> + <attribute name="enabled"> + <ref name="virYesNo"/> + </attribute> + <optional> + <attribute name="timeout"> + <ref name="unsignedInt"/> + </attribute> + </optional> + </element> + </define> <!-- An interface description can either be of type bridge in which case @@ -2460,6 +2472,9 @@ <value>client</value> </choice> </attribute> + <optional> + <ref name="reconnect"/> + </optional> <empty/> </element> <ref name="interface-options"/> @@ -3708,16 +3723,7 @@ </attribute> </optional> <optional> - <element name="reconnect"> - <attribute name="enabled"> - <ref name="virYesNo"/> - </attribute> - <optional> - <attribute name="timeout"> - <ref name="unsignedInt"/> - </attribute> - </optional> - </element> + <ref name="reconnect"/> </optional> <zeroOrMore> <ref name='devSeclabel'/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f9ae057..be3374d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -10584,6 +10584,56 @@ virDomainNetAppendIPAddress(virDomainNetDefPtr def, return -1; } +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 timeout 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; +} + /* Parse the XML definition for a network interface * @param node XML nodeset to parse for net definition * @return 0 on success, -1 on failure @@ -10638,6 +10688,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, virNWFilterHashTablePtr filterparams = NULL; virDomainActualNetDefPtr actual = NULL; xmlNodePtr oldnode = ctxt->node; + virDomainChrSourceReconnectDef reconnect = {0}; int rv, val; if (VIR_ALLOC(def) < 0) @@ -10719,11 +10770,14 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, goto error; } } else if (!vhostuser_path && !vhostuser_mode && !vhostuser_type - && def->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER && - virXMLNodeNameEqual(cur, "source")) { + && def->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER + && virXMLNodeNameEqual(cur, "source")) { vhostuser_type = virXMLPropString(cur, "type"); vhostuser_path = virXMLPropString(cur, "path"); vhostuser_mode = virXMLPropString(cur, "mode"); + if (virDomainChrSourceReconnectDefParseXML(&reconnect, cur, ctxt) < 0) + goto error; + } else if (!def->virtPortProfile && virXMLNodeNameEqual(cur, "virtualport")) { if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) { @@ -10945,8 +10999,16 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, if (STREQ(vhostuser_mode, "server")) { def->data.vhostuser->data.nix.listen = true; + if (reconnect.enabled != VIR_TRISTATE_BOOL_ABSENT) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("'reconnect' attribute unsupported " + "'server' mode for <interface type='vhostuser'>")); + goto error; + } } else if (STREQ(vhostuser_mode, "client")) { def->data.vhostuser->data.nix.listen = false; + def->data.vhostuser->data.nix.reconnect.enabled = reconnect.enabled; + def->data.vhostuser->data.nix.reconnect.timeout = reconnect.timeout; } else { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Wrong <source> 'mode' attribute " @@ -11608,57 +11670,6 @@ 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 timeout 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, VIR_DOMAIN_CHR_SOURCE_MODE_BIND, @@ -23399,6 +23410,21 @@ virDomainVirtioNetDriverFormat(char **outstr, 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"); +} int virDomainNetDefFormat(virBufferPtr buf, @@ -23493,6 +23519,14 @@ virDomainNetDefFormat(virBufferPtr buf, def->data.vhostuser->data.nix.listen ? "server" : "client"); sourceLines++; + if (def->data.vhostuser->data.nix.reconnect.enabled != VIR_TRISTATE_BOOL_ABSENT) { + virBufferAddLit(buf, ">\n"); + sourceLines++; + virBufferAdjustIndent(buf, 2); + virDomainChrSourceReconnectDefFormat(buf, &def->data.vhostuser->data.nix.reconnect); + virBufferAdjustIndent(buf, -2); + } + } break; @@ -23725,24 +23759,6 @@ 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, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-vhostuser-multiq.args b/tests/qemuxml2argvdata/qemuxml2argv-net-vhostuser-multiq.args index b69ebd8..f2aec7b 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-net-vhostuser-multiq.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-vhostuser-multiq.args @@ -32,7 +32,11 @@ addr=0x4 \ -netdev socket,listen=:2015,id=hostnet2 \ -device rtl8139,netdev=hostnet2,id=net2,mac=52:54:00:95:db:c0,bus=pci.0,\ addr=0x5 \ --chardev socket,id=charnet3,path=/tmp/vhost2.sock \ --netdev vhost-user,chardev=charnet3,queues=4,id=hostnet3 \ --device virtio-net-pci,mq=on,vectors=10,netdev=hostnet3,id=net3,\ -mac=52:54:00:ee:96:6d,bus=pci.0,addr=0x6 +-chardev socket,id=charnet3,path=/tmp/vhost2.sock,reconnect=10 \ +-netdev vhost-user,chardev=charnet3,id=hostnet3 \ +-device virtio-net-pci,netdev=hostnet3,id=net3,\ +mac=52:54:00:ee:96:6d,bus=pci.0,addr=0x6 \ +-chardev socket,id=charnet4,path=/tmp/vhost3.sock,reconnect=0 \ +-netdev vhost-user,chardev=charnet4,queues=4,id=hostnet4 \ +-device virtio-net-pci,mq=on,vectors=10,netdev=hostnet4,id=net4,\ +mac=52:54:00:ee:96:6e,bus=pci.0,addr=0x7 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-vhostuser-multiq.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-vhostuser-multiq.xml index d5c42fe..a30cce6 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-net-vhostuser-multiq.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-vhostuser-multiq.xml @@ -40,7 +40,16 @@ </interface> <interface type='vhostuser'> <mac address='52:54:00:ee:96:6d'/> - <source type='unix' path='/tmp/vhost2.sock' mode='client'/> + <source type='unix' path='/tmp/vhost2.sock' mode='client'> + <reconnect enabled='yes' timeout='10'/> + </source> + <model type='virtio'/> + </interface> + <interface type='vhostuser'> + <mac address='52:54:00:ee:96:6e'/> + <source type='unix' path='/tmp/vhost3.sock' mode='client'> + <reconnect enabled='no'/> + </source> <model type='virtio'/> <driver queues='4'/> </interface> -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list