aboutgitcodebugslistschat
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch427
-rw-r--r--contrib/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch171
-rw-r--r--contrib/qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch37
3 files changed, 635 insertions, 0 deletions
diff --git a/contrib/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch b/contrib/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch
new file mode 100644
index 0000000..386cc4a
--- /dev/null
+++ b/contrib/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch
@@ -0,0 +1,427 @@
+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
+
diff --git a/contrib/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch b/contrib/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch
new file mode 100644
index 0000000..9e71f88
--- /dev/null
+++ b/contrib/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch
@@ -0,0 +1,171 @@
+From 83c3f76b8fe6b4a6bb45dcf5cfad65ec6f98a10e Mon Sep 17 00:00:00 2001
+From: Stefano Brivio <sbrivio@redhat.com>
+Date: Wed, 26 Jan 2022 16:45:15 +0100
+Subject: [PATCH 1/2] net: Allow also UNIX domain sockets to be used as -netdev
+ socket
+
+It has lower overhead compared to TCP, doesn't need a free port
+and the adaptation is trivial.
+
+Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
+---
+SPDX-FileCopyrightText: 2020-2022 Red Hat GmbH <sbrivio@redhat.com>
+SPDX-License-Identifier: AGPL-3.0-or-later
+
+ net/socket.c | 106 ++++++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 87 insertions(+), 19 deletions(-)
+
+diff --git a/net/socket.c b/net/socket.c
+index 2e5f3ac923..b901e22836 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -511,26 +511,59 @@ static int net_socket_listen_init(NetClientState *peer,
+ {
+ NetClientState *nc;
+ NetSocketState *s;
+- struct sockaddr_in saddr;
+- int fd, ret;
++ struct sockaddr_storage saddr;
++ struct sockaddr_in *saddr_in = (struct sockaddr_in *)&saddr;
++ struct sockaddr_un *saddr_un = (struct sockaddr_un *)&saddr;
++ size_t saddr_size;
++ int fd, ret, pf;
++
++#ifndef WIN32
++ if (strchr(host_str, ':')) {
++#endif
++ if (parse_host_port(saddr_in, host_str, errp) < 0)
++ return -1;
+
+- if (parse_host_port(&saddr, host_str, errp) < 0) {
+- return -1;
+- }
++ pf = PF_INET;
++ saddr_size = sizeof(*saddr_in);
++#ifndef WIN32
++ } else {
++ struct stat sb;
++
++ if (stat(host_str, &sb) == -1) {
++ error_setg_errno(errp, errno, "can't stat socket path");
++ return -1;
++ }
++
++ if ((sb.st_mode & S_IFMT) != S_IFSOCK) {
++ error_setg_errno(errp, errno, "path provided is not a socket");
++ return -1;
++ }
+
+- fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
++ saddr_un->sun_family = PF_UNIX;
++ strncpy(saddr_un->sun_path, host_str, sizeof(saddr_un->sun_path));
++
++ pf = PF_UNIX;
++ saddr_size = sizeof(*saddr_un);
++ }
++#endif /* !WIN32 */
++ fd = qemu_socket(pf, SOCK_STREAM, 0);
+ if (fd < 0) {
+ error_setg_errno(errp, errno, "can't create stream socket");
+ return -1;
+ }
+ qemu_set_nonblock(fd);
+
+- socket_set_fast_reuse(fd);
++ if (pf == PF_INET)
++ socket_set_fast_reuse(fd);
+
+- ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
++ ret = bind(fd, (struct sockaddr *)&saddr, saddr_size);
+ if (ret < 0) {
+- error_setg_errno(errp, errno, "can't bind ip=%s to socket",
+- inet_ntoa(saddr.sin_addr));
++ if (pf == PF_INET)
++ error_setg_errno(errp, errno, "can't bind ip=%s to socket",
++ inet_ntoa(saddr_in->sin_addr));
++ else if (pf == PF_UNIX)
++ error_setg_errno(errp, errno, "can't create socket with path: %s",
++ host_str);
+ closesocket(fd);
+ return -1;
+ }
+@@ -559,14 +592,43 @@ static int net_socket_connect_init(NetClientState *peer,
+ Error **errp)
+ {
+ NetSocketState *s;
+- int fd, connected, ret;
+- struct sockaddr_in saddr;
++ int fd, connected, ret, pf;
++ struct sockaddr_storage saddr;
++ size_t saddr_size;
++ struct sockaddr_in *saddr_in = (struct sockaddr_in *)&saddr;
++#ifndef WIN32
++ struct sockaddr_un *saddr_un = (struct sockaddr_un *)&saddr;
++
++ if (strchr(host_str, ':')) {
++#endif
++ if (parse_host_port(saddr_in, host_str, errp) < 0)
++ return -1;
+
+- if (parse_host_port(&saddr, host_str, errp) < 0) {
+- return -1;
++ pf = PF_INET;
++ saddr_size = sizeof(*saddr_in);
++#ifndef WIN32
++ } else {
++ struct stat sb;
++
++ if (stat(host_str, &sb) == -1) {
++ error_setg_errno(errp, errno, "can't stat socket path");
++ return -1;
++ }
++
++ if ((sb.st_mode & S_IFMT) != S_IFSOCK) {
++ error_setg_errno(errp, errno, "provided path is not a socket");
++ return -1;
++ }
++
++ saddr_un->sun_family = PF_UNIX;
++ strncpy(saddr_un->sun_path, host_str, sizeof(saddr_un->sun_path));
++
++ pf = PF_UNIX;
++ saddr_size = sizeof(*saddr_un);
+ }
++#endif /* !WIN32 */
+
+- fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
++ fd = qemu_socket(pf, SOCK_STREAM, 0);
+ if (fd < 0) {
+ error_setg_errno(errp, errno, "can't create stream socket");
+ return -1;
+@@ -575,7 +637,7 @@ static int net_socket_connect_init(NetClientState *peer,
+
+ connected = 0;
+ for(;;) {
+- ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
++ ret = connect(fd, (struct sockaddr *)&saddr, saddr_size);
+ if (ret < 0) {
+ if (errno == EINTR || errno == EWOULDBLOCK) {
+ /* continue */
+@@ -597,9 +659,15 @@ static int net_socket_connect_init(NetClientState *peer,
+ return -1;
+ }
+
+- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
+- "socket: connect to %s:%d",
+- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
++ if (pf == PF_INET) {
++ snprintf(s->nc.info_str, sizeof(s->nc.info_str),
++ "socket: connect to %s:%d",
++ inet_ntoa(saddr_in->sin_addr), ntohs(saddr_in->sin_port));
++ } else if (pf == PF_UNIX) {
++ snprintf(s->nc.info_str, sizeof(s->nc.info_str),
++ "socket: connect to %s", saddr_un->sun_path);
++ }
++
+ return 0;
+ }
+
+--
+2.28.0
+
diff --git a/contrib/qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch b/contrib/qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch
new file mode 100644
index 0000000..0e31a1b
--- /dev/null
+++ b/contrib/qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch
@@ -0,0 +1,37 @@
+From a6d475147682de1fe3b14eb325f4247e013e8440 Mon Sep 17 00:00:00 2001
+Message-Id: <a6d475147682de1fe3b14eb325f4247e013e8440.1619091389.git.sbrivio@redhat.com>
+In-Reply-To: <ba51349d353f11e05c6341a7e065f2ade3874c68.1619091389.git.sbrivio@redhat.com>
+References: <ba51349d353f11e05c6341a7e065f2ade3874c68.1619091389.git.sbrivio@redhat.com>
+From: Stefano Brivio <sbrivio@redhat.com>
+Date: Wed, 21 Apr 2021 18:52:16 +0200
+Subject: [PATCH 2/2] net: Don't ignore EINVAL on netdev socket connection
+
+Other errors are treated as failure by net_socket_connect_init(),
+but if connect() returns EINVAL, we'll fail silently. Remove the
+related exception.
+
+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
+
+ net/socket.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/socket.c b/net/socket.c
+index aadd11dae2b3..d3293ac12e82 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -644,8 +644,7 @@ static int net_socket_connect_init(NetClientState *peer,
+ if (errno == EINTR || errno == EWOULDBLOCK) {
+ /* continue */
+ } else if (errno == EINPROGRESS ||
+- errno == EALREADY ||
+- errno == EINVAL) {
++ errno == EALREADY) {
+ break;
+ } else {
+ error_setg_errno(errp, errno, "can't connect socket");
+--
+2.29.2
+