mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-18 10:35:20 +00:00
vhost-user: add support reconnect for vhost-user ports
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@zte.com.cn> Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
6aba071560
commit
614be3b882
@ -5900,7 +5900,9 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
</interface>
|
</interface>
|
||||||
<interface type='vhostuser'>
|
<interface type='vhostuser'>
|
||||||
<mac address='52:54:00:3b:83:1b'/>
|
<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'/>
|
<model type='virtio'/>
|
||||||
<driver queues='5'/>
|
<driver queues='5'/>
|
||||||
</interface>
|
</interface>
|
||||||
@ -5916,6 +5918,13 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
are supported.
|
are supported.
|
||||||
vhost-user requires the virtio model type, thus the
|
vhost-user requires the virtio model type, thus the
|
||||||
<code><model></code> element is mandatory.
|
<code><model></code> element is mandatory.
|
||||||
|
<span class="since">Since 4.1.0</span> the element has an
|
||||||
|
optional child element <code>reconnect</code> which
|
||||||
|
configures reconnect timeout if the connection is lost. It
|
||||||
|
has two attributes <code>enabled</code> (which accepts
|
||||||
|
<code>yes</code> and <code>no</code>) and
|
||||||
|
<code>timeout</code> which specifies the amount of seconds
|
||||||
|
after which hypervisor tries to reconnect.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h5><a id="elementNwfilter">Traffic filtering with NWFilter</a></h5>
|
<h5><a id="elementNwfilter">Traffic filtering with NWFilter</a></h5>
|
||||||
|
@ -2431,6 +2431,18 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</optional>
|
</optional>
|
||||||
</define>
|
</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
|
An interface description can either be of type bridge in which case
|
||||||
@ -2492,6 +2504,9 @@
|
|||||||
<value>client</value>
|
<value>client</value>
|
||||||
</choice>
|
</choice>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
<optional>
|
||||||
|
<ref name="reconnect"/>
|
||||||
|
</optional>
|
||||||
<empty/>
|
<empty/>
|
||||||
</element>
|
</element>
|
||||||
<ref name="interface-options"/>
|
<ref name="interface-options"/>
|
||||||
@ -3760,16 +3775,7 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</optional>
|
</optional>
|
||||||
<optional>
|
<optional>
|
||||||
<element name="reconnect">
|
<ref name="reconnect"/>
|
||||||
<attribute name="enabled">
|
|
||||||
<ref name="virYesNo"/>
|
|
||||||
</attribute>
|
|
||||||
<optional>
|
|
||||||
<attribute name="timeout">
|
|
||||||
<ref name="unsignedInt"/>
|
|
||||||
</attribute>
|
|
||||||
</optional>
|
|
||||||
</element>
|
|
||||||
</optional>
|
</optional>
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
<ref name='devSeclabel'/>
|
<ref name='devSeclabel'/>
|
||||||
|
@ -10712,6 +10712,58 @@ virDomainNetAppendIPAddress(virDomainNetDefPtr def,
|
|||||||
return -1;
|
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
|
/* Parse the XML definition for a network interface
|
||||||
* @param node XML nodeset to parse for net definition
|
* @param node XML nodeset to parse for net definition
|
||||||
* @return 0 on success, -1 on failure
|
* @return 0 on success, -1 on failure
|
||||||
@ -10766,6 +10818,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
virNWFilterHashTablePtr filterparams = NULL;
|
virNWFilterHashTablePtr filterparams = NULL;
|
||||||
virDomainActualNetDefPtr actual = NULL;
|
virDomainActualNetDefPtr actual = NULL;
|
||||||
xmlNodePtr oldnode = ctxt->node;
|
xmlNodePtr oldnode = ctxt->node;
|
||||||
|
virDomainChrSourceReconnectDef reconnect = {0};
|
||||||
int rv, val;
|
int rv, val;
|
||||||
|
|
||||||
if (VIR_ALLOC(def) < 0)
|
if (VIR_ALLOC(def) < 0)
|
||||||
@ -10847,11 +10900,14 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else if (!vhostuser_path && !vhostuser_mode && !vhostuser_type
|
} else if (!vhostuser_path && !vhostuser_mode && !vhostuser_type
|
||||||
&& def->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER &&
|
&& def->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER
|
||||||
virXMLNodeNameEqual(cur, "source")) {
|
&& virXMLNodeNameEqual(cur, "source")) {
|
||||||
vhostuser_type = virXMLPropString(cur, "type");
|
vhostuser_type = virXMLPropString(cur, "type");
|
||||||
vhostuser_path = virXMLPropString(cur, "path");
|
vhostuser_path = virXMLPropString(cur, "path");
|
||||||
vhostuser_mode = virXMLPropString(cur, "mode");
|
vhostuser_mode = virXMLPropString(cur, "mode");
|
||||||
|
if (virDomainChrSourceReconnectDefParseXML(&reconnect, cur, ctxt) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
} else if (!def->virtPortProfile
|
} else if (!def->virtPortProfile
|
||||||
&& virXMLNodeNameEqual(cur, "virtualport")) {
|
&& virXMLNodeNameEqual(cur, "virtualport")) {
|
||||||
if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
|
||||||
@ -11073,8 +11129,15 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
|
|
||||||
if (STREQ(vhostuser_mode, "server")) {
|
if (STREQ(vhostuser_mode, "server")) {
|
||||||
def->data.vhostuser->data.nix.listen = true;
|
def->data.vhostuser->data.nix.listen = true;
|
||||||
|
if (reconnect.enabled == VIR_TRISTATE_BOOL_YES) {
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
|
_("'reconnect' attribute unsupported "
|
||||||
|
"'server' mode for <interface type='vhostuser'>"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
} else if (STREQ(vhostuser_mode, "client")) {
|
} else if (STREQ(vhostuser_mode, "client")) {
|
||||||
def->data.vhostuser->data.nix.listen = false;
|
def->data.vhostuser->data.nix.listen = false;
|
||||||
|
def->data.vhostuser->data.nix.reconnect = reconnect;
|
||||||
} else {
|
} else {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||||
_("Wrong <source> 'mode' attribute "
|
_("Wrong <source> 'mode' attribute "
|
||||||
@ -11780,57 +11843,6 @@ virDomainChrDefParseTargetXML(virDomainChrDefPtr def,
|
|||||||
return ret;
|
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 {
|
typedef enum {
|
||||||
VIR_DOMAIN_CHR_SOURCE_MODE_CONNECT,
|
VIR_DOMAIN_CHR_SOURCE_MODE_CONNECT,
|
||||||
VIR_DOMAIN_CHR_SOURCE_MODE_BIND,
|
VIR_DOMAIN_CHR_SOURCE_MODE_BIND,
|
||||||
@ -23899,6 +23911,23 @@ virDomainVirtioNetDriverFormat(char **outstr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
int
|
||||||
virDomainNetDefFormat(virBufferPtr buf,
|
virDomainNetDefFormat(virBufferPtr buf,
|
||||||
virDomainNetDefPtr def,
|
virDomainNetDefPtr def,
|
||||||
@ -23992,6 +24021,15 @@ virDomainNetDefFormat(virBufferPtr buf,
|
|||||||
def->data.vhostuser->data.nix.listen ?
|
def->data.vhostuser->data.nix.listen ?
|
||||||
"server" : "client");
|
"server" : "client");
|
||||||
sourceLines++;
|
sourceLines++;
|
||||||
|
if (def->data.vhostuser->data.nix.reconnect.enabled) {
|
||||||
|
virBufferAddLit(buf, ">\n");
|
||||||
|
sourceLines++;
|
||||||
|
virBufferAdjustIndent(buf, 2);
|
||||||
|
virDomainChrSourceReconnectDefFormat(buf,
|
||||||
|
&def->data.vhostuser->data.nix.reconnect);
|
||||||
|
virBufferAdjustIndent(buf, -2);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -24224,24 +24262,6 @@ virDomainChrAttrsDefFormat(virBufferPtr buf,
|
|||||||
return 0;
|
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
|
static int
|
||||||
virDomainChrSourceDefFormat(virBufferPtr buf,
|
virDomainChrSourceDefFormat(virBufferPtr buf,
|
||||||
virDomainChrSourceDefPtr def,
|
virDomainChrSourceDefPtr def,
|
||||||
|
@ -32,7 +32,11 @@ addr=0x4 \
|
|||||||
-netdev socket,listen=:2015,id=hostnet2 \
|
-netdev socket,listen=:2015,id=hostnet2 \
|
||||||
-device rtl8139,netdev=hostnet2,id=net2,mac=52:54:00:95:db:c0,bus=pci.0,\
|
-device rtl8139,netdev=hostnet2,id=net2,mac=52:54:00:95:db:c0,bus=pci.0,\
|
||||||
addr=0x5 \
|
addr=0x5 \
|
||||||
-chardev socket,id=charnet3,path=/tmp/vhost2.sock \
|
-chardev socket,id=charnet3,path=/tmp/vhost2.sock,reconnect=10 \
|
||||||
-netdev vhost-user,chardev=charnet3,queues=4,id=hostnet3 \
|
-netdev vhost-user,chardev=charnet3,id=hostnet3 \
|
||||||
-device virtio-net-pci,mq=on,vectors=10,netdev=hostnet3,id=net3,\
|
-device virtio-net-pci,netdev=hostnet3,id=net3,mac=52:54:00:ee:96:6d,bus=pci.0,\
|
||||||
mac=52:54:00:ee:96:6d,bus=pci.0,addr=0x6
|
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
|
||||||
|
@ -40,7 +40,16 @@
|
|||||||
</interface>
|
</interface>
|
||||||
<interface type='vhostuser'>
|
<interface type='vhostuser'>
|
||||||
<mac address='52:54:00:ee:96:6d'/>
|
<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'/>
|
<model type='virtio'/>
|
||||||
<driver queues='4'/>
|
<driver queues='4'/>
|
||||||
</interface>
|
</interface>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user