passt/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch
Stefano Brivio 087b5f4dbb LICENSES: Add license text files, add missing notices, fix SPDX tags
SPDX tags don't replace license files. Some notices were missing and
some tags were not according to the SPDX specification, too.

Now reuse --lint from the REUSE tool (https://reuse.software/) passes.

Reported-by: Martin Hauke <mardnh@gmx.de>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
2021-10-20 08:29:30 +02:00

427 lines
17 KiB
Diff

From 7afbbab2ccada16c87e1095e85184bb21c028012 Mon Sep 17 00:00:00 2001
Message-Id: <7afbbab2ccada16c87e1095e85184bb21c028012.1619091487.git.sbrivio@redhat.com>
From: Stefano Brivio <sbrivio@redhat.com>
Date: Wed, 21 Apr 2021 19:29:31 +0200
Subject: [PATCH] conf: Introduce support for UNIX domain socket as qemu netdev
back-end
Since qemu [TODO], named UNIX domain sockets can be used instead of
TCP to establish a virtual network between VMs.
The obvious difference compared with TCP is that we need pass a path
instead of address and port.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
SPDX-FileCopyrightText: 2020-2021 Red Hat GmbH <sbrivio@redhat.com>
SPDX-License-Identifier: AGPL-3.0-or-later
docs/formatdomain.rst | 41 +++++++++++++++++++------
docs/schemas/domaincommon.rng | 50 +++++++++++++++++++++++-------
src/conf/domain_conf.c | 58 +++++++++++++++++++++++++++--------
src/conf/domain_conf.h | 13 +++++---
src/qemu/qemu_command.c | 46 ++++++++++++++++++---------
src/qemu/qemu_hotplug.c | 8 +++--
6 files changed, 160 insertions(+), 56 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 1b9b2216111c..87c3c956fa23 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -5010,18 +5010,20 @@ must be from the multicast address block.
</devices>
...
-:anchor:`<a id="elementsNICSTCP"/>`
+:anchor:`<a id="elementsNICSStream"/>`
-TCP tunnel
-^^^^^^^^^^
+TCP or UNIX domain socket tunnel
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A stream-oriented client/server architecture provides a virtual network. One VM
+provides the server end of the network, all other VMS are configured as clients.
+All network traffic is routed between the VMs via the server. This mode is also
+available to unprivileged users. There is no default DNS or DHCP support and no
+outgoing network access. To provide outgoing network access, one of the VMs
+should have a 2nd NIC which is connected to one of the first 4 network types and
+do the appropriate routing.
-A TCP client/server architecture provides a virtual network. One VM provides the
-server end of the network, all other VMS are configured as clients. All network
-traffic is routed between the VMs via the server. This mode is also available to
-unprivileged users. There is no default DNS or DHCP support and no outgoing
-network access. To provide outgoing network access, one of the VMs should have a
-2nd NIC which is connected to one of the first 4 network types and do the
-appropriate routing.
+TCP endpoints can be specified as follows:
::
@@ -5039,6 +5041,25 @@ appropriate routing.
</devices>
...
+Named UNIX domain sockets can be specified as follows:
+:since:`Since 7.3.0, qemu`
+
+::
+
+ ...
+ <devices>
+ <interface type='server'>
+ <mac address='52:54:00:22:c9:42'/>
+ <source path='/tmp/qemu.socket'/>
+ </interface>
+ ...
+ <interface type='client'>
+ <mac address='52:54:00:8b:c9:51'/>
+ <source path='/tmp/qemu.socket'/>
+ </interface>
+ </devices>
+ ...
+
:anchor:`<a id="elementsNICSUDP"/>`
UDP unicast tunnel
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index a2e5c50c1d77..7c0a90ba199b 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3161,10 +3161,7 @@
</group>
<group>
<attribute name="type">
- <choice>
- <value>mcast</value>
- <value>client</value>
- </choice>
+ <value>mcast</value>
</attribute>
<interleave>
<element name="source">
@@ -3179,6 +3176,30 @@
<ref name="interface-options"/>
</interleave>
</group>
+ <group>
+ <attribute name="type">
+ <value>client</value>
+ </attribute>
+ <interleave>
+ <element name="source">
+ <choice>
+ <group>
+ <attribute name="address">
+ <ref name="ipv4Addr"/>
+ </attribute>
+ <attribute name="port">
+ <ref name="PortNumber"/>
+ </attribute>
+ </group>
+ <attribute name="path">
+ <ref name="absFilePath"/>
+ </attribute>
+ </choice>
+ <empty/>
+ </element>
+ <ref name="interface-options"/>
+ </interleave>
+ </group>
<group>
<attribute name="type">
<value>udp</value>
@@ -3210,14 +3231,21 @@
</attribute>
<interleave>
<element name="source">
- <optional>
- <attribute name="address">
- <ref name="ipv4Addr"/>
+ <choice>
+ <group>
+ <optional>
+ <attribute name="address">
+ <ref name="ipv4Addr"/>
+ </attribute>
+ </optional>
+ <attribute name="port">
+ <ref name="PortNumber"/>
+ </attribute>
+ </group>
+ <attribute name="path">
+ <ref name="absFilePath"/>
</attribute>
- </optional>
- <attribute name="port">
- <ref name="PortNumber"/>
- </attribute>
+ </choice>
<empty/>
</element>
<ref name="interface-options"/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index f8a462fb3b99..8c6a5d4f974e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2562,8 +2562,9 @@ virDomainNetDefFree(virDomainNetDef *def)
case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_UDP:
- g_free(def->data.socket.address);
- g_free(def->data.socket.localaddr);
+ g_free(def->data.socket.net.address);
+ g_free(def->data.socket.net.localaddr);
+ g_free(def->data.socket.path);
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
@@ -10555,6 +10556,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
g_autofree char *downscript = NULL;
g_autofree char *address = NULL;
g_autofree char *port = NULL;
+ g_autofree char *path = NULL;
g_autofree char *localaddr = NULL;
g_autofree char *localport = NULL;
g_autofree char *model = NULL;
@@ -10699,7 +10701,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
" <interface type='%s'>"), type);
goto error;
}
- } else if (!address &&
+ } else if (!address && !path &&
(def->type == VIR_DOMAIN_NET_TYPE_SERVER ||
def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
def->type == VIR_DOMAIN_NET_TYPE_MCAST ||
@@ -10707,6 +10709,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
virXMLNodeNameEqual(cur, "source")) {
address = virXMLPropString(cur, "address");
port = virXMLPropString(cur, "port");
+ path = virXMLPropString(cur, "path");
if (!localaddr && def->type == VIR_DOMAIN_NET_TYPE_UDP) {
xmlNodePtr tmpnode = ctxt->node;
ctxt->node = cur;
@@ -10950,6 +10953,27 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_SERVER:
+ if (path != NULL) {
+ if (port != NULL || address != NULL ||
+ localport != NULL || localaddr != NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("<source> 'path' attribute "
+ "for socket interface cannot be specified "
+ "together with other attributes"));
+ goto error;
+ }
+ def->data.socket.path = g_steal_pointer(&path);
+ break;
+ }
+
+ if (port == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Neither <source> 'port' nor 'path' attribute "
+ "specified with socket interface"));
+ goto error;
+ }
+
+ G_GNUC_FALLTHROUGH;
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_UDP:
if (port == NULL) {
@@ -10958,7 +10982,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
"specified with socket interface"));
goto error;
}
- if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) {
+ if (virStrToLong_i(port, NULL, 10, &def->data.socket.net.port) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot parse <source> 'port' attribute "
"with socket interface"));
@@ -10975,7 +10999,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
goto error;
}
} else {
- def->data.socket.address = g_steal_pointer(&address);
+ def->data.socket.net.address = g_steal_pointer(&address);
}
if (def->type != VIR_DOMAIN_NET_TYPE_UDP)
@@ -10987,7 +11011,8 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
"specified with socket interface"));
goto error;
}
- if (virStrToLong_i(localport, NULL, 10, &def->data.socket.localport) < 0) {
+ if (virStrToLong_i(localport, NULL, 10,
+ &def->data.socket.net.localport) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot parse <local> 'port' attribute "
"with socket interface"));
@@ -11000,7 +11025,7 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
"specified with socket interface"));
goto error;
} else {
- def->data.socket.localaddr = g_steal_pointer(&localaddr);
+ def->data.socket.net.localaddr = g_steal_pointer(&localaddr);
}
break;
@@ -25940,15 +25965,22 @@ virDomainNetDefFormat(virBuffer *buf,
case VIR_DOMAIN_NET_TYPE_SERVER:
case VIR_DOMAIN_NET_TYPE_CLIENT:
+ if (def->data.socket.path) {
+ virBufferAsprintf(buf, "<source path='%s'",
+ def->data.socket.path);
+ sourceLines++;
+ break;
+ }
+ G_GNUC_FALLTHROUGH;
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_UDP:
- if (def->data.socket.address) {
+ if (def->data.socket.net.address) {
virBufferAsprintf(buf, "<source address='%s' port='%d'",
- def->data.socket.address,
- def->data.socket.port);
+ def->data.socket.net.address,
+ def->data.socket.net.port);
} else {
virBufferAsprintf(buf, "<source port='%d'",
- def->data.socket.port);
+ def->data.socket.net.port);
}
sourceLines++;
@@ -25960,8 +25992,8 @@ virDomainNetDefFormat(virBuffer *buf,
virBufferAdjustIndent(buf, 2);
virBufferAsprintf(buf, "<local address='%s' port='%d'/>\n",
- def->data.socket.localaddr,
- def->data.socket.localport);
+ def->data.socket.net.localaddr,
+ def->data.socket.net.localport);
virBufferAdjustIndent(buf, -2);
break;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 7688f17b18cd..054b08330c8c 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1055,11 +1055,14 @@ struct _virDomainNetDef {
virDomainNetTeamingInfo *teaming;
union {
virDomainChrSourceDef *vhostuser;
- struct {
- char *address;
- int port;
- char *localaddr;
- int localport;
+ union {
+ struct {
+ char *address;
+ int port;
+ char *localaddr;
+ int localport;
+ } net;
+ char *path;
} socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */
struct {
char *name;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 2ceff155124e..dbef58f37879 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3713,37 +3713,55 @@ qemuBuildHostNetStr(virDomainNetDef *net,
break;
case VIR_DOMAIN_NET_TYPE_CLIENT:
- if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
- virJSONValueObjectAppendStringPrintf(netprops, "connect", "%s:%d",
- net->data.socket.address,
- net->data.socket.port) < 0)
+ if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0)
+ return NULL;
+
+ if (net->data.socket.path != NULL) {
+ if (virJSONValueObjectAppendStringPrintf(netprops, "connect", "%s",
+ net->data.socket.path) < 0)
+ return NULL;
+ break;
+ }
+
+ if (virJSONValueObjectAppendStringPrintf(netprops, "connect", "%s:%d",
+ net->data.socket.net.address,
+ net->data.socket.net.port) < 0)
return NULL;
break;
case VIR_DOMAIN_NET_TYPE_SERVER:
- if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
- virJSONValueObjectAppendStringPrintf(netprops, "listen", "%s:%d",
- NULLSTR_EMPTY(net->data.socket.address),
- net->data.socket.port) < 0)
+ if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0)
+ return NULL;
+
+ if (net->data.socket.path != NULL) {
+ if (virJSONValueObjectAppendStringPrintf(netprops, "listen", "%s",
+ net->data.socket.path) < 0)
+ return NULL;
+ break;
+ }
+
+ if (virJSONValueObjectAppendStringPrintf(netprops, "listen", "%s:%d",
+ NULLSTR_EMPTY(net->data.socket.net.address),
+ net->data.socket.net.port) < 0)
return NULL;
break;
case VIR_DOMAIN_NET_TYPE_MCAST:
if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
virJSONValueObjectAppendStringPrintf(netprops, "mcast", "%s:%d",
- net->data.socket.address,
- net->data.socket.port) < 0)
+ net->data.socket.net.address,
+ net->data.socket.net.port) < 0)
return NULL;
break;
case VIR_DOMAIN_NET_TYPE_UDP:
if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) < 0 ||
virJSONValueObjectAppendStringPrintf(netprops, "udp", "%s:%d",
- net->data.socket.address,
- net->data.socket.port) < 0 ||
+ net->data.socket.net.address,
+ net->data.socket.net.port) < 0 ||
virJSONValueObjectAppendStringPrintf(netprops, "localaddr", "%s:%d",
- net->data.socket.localaddr,
- net->data.socket.localport) < 0)
+ net->data.socket.net.localaddr,
+ net->data.socket.net.localport) < 0)
return NULL;
break;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 4344edc75b80..69ef7abd0ee2 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -3741,9 +3741,11 @@ qemuDomainChangeNet(virQEMUDriver *driver,
case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_MCAST:
case VIR_DOMAIN_NET_TYPE_UDP:
- if (STRNEQ_NULLABLE(olddev->data.socket.address,
- newdev->data.socket.address) ||
- olddev->data.socket.port != newdev->data.socket.port) {
+ if (STRNEQ_NULLABLE(olddev->data.socket.path,
+ newdev->data.socket.path) ||
+ STRNEQ_NULLABLE(olddev->data.socket.net.address,
+ newdev->data.socket.net.address) ||
+ olddev->data.socket.net.port != newdev->data.socket.net.port) {
needReconnect = true;
}
break;
--
2.29.2