From 27050b094f6b3e64f1536ebca09f3476b308493b Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Wed, 26 Jan 2022 17:05:20 +0100 Subject: libvirt, qemu: Move patches to new directory, contrib I'm about to add a new adaptation carrying out-of-tree patches for a Kata Containers PoC -- move the existing out-of-tree patches to their own directory to keep things easy to find in the main one. Signed-off-by: Stefano Brivio --- ...uce-support-for-UNIX-domain-socket-as-qem.patch | 427 +++++++++++++++++++++ ...lso-UNIX-domain-sockets-to-be-used-as-net.patch | 171 +++++++++ ...ignore-EINVAL-on-netdev-socket-connection.patch | 37 ++ ...uce-support-for-UNIX-domain-socket-as-qem.patch | 427 --------------------- ...lso-UNIX-domain-sockets-to-be-used-as-net.patch | 171 --------- ...ignore-EINVAL-on-netdev-socket-connection.patch | 37 -- 6 files changed, 635 insertions(+), 635 deletions(-) create mode 100644 contrib/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch create mode 100644 contrib/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch create mode 100644 contrib/qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch delete mode 100644 libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch delete mode 100644 qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch delete mode 100644 qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch 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 +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 +--- +SPDX-FileCopyrightText: 2020-2021 Red Hat GmbH +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. + + ... + +-:anchor:`` ++:anchor:`` + +-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. + + ... + ++Named UNIX domain sockets can be specified as follows: ++:since:`Since 7.3.0, qemu` ++ ++:: ++ ++ ... ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ ++ ... ++ + :anchor:`` + + 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 @@ + + + +- +- mcast +- client +- ++ mcast + + + +@@ -3179,6 +3176,30 @@ + + + ++ ++ ++ client ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + udp +@@ -3210,14 +3231,21 @@ + + + +- +- +- ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +- +- +- +- ++ + + + +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, + " "), 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", ++ _(" '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 '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 '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 '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, "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, "data.socket.address, +- def->data.socket.port); ++ def->data.socket.net.address, ++ def->data.socket.net.port); + } else { + virBufferAsprintf(buf, "data.socket.port); ++ def->data.socket.net.port); + } + sourceLines++; + +@@ -25960,8 +25992,8 @@ virDomainNetDefFormat(virBuffer *buf, + virBufferAdjustIndent(buf, 2); + + virBufferAsprintf(buf, "\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 +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 +--- +SPDX-FileCopyrightText: 2020-2022 Red Hat GmbH +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: +In-Reply-To: +References: +From: Stefano Brivio +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 +--- +SPDX-FileCopyrightText: 2020-2021 Red Hat GmbH +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 + diff --git a/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch b/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch deleted file mode 100644 index 386cc4a..0000000 --- a/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch +++ /dev/null @@ -1,427 +0,0 @@ -From 7afbbab2ccada16c87e1095e85184bb21c028012 Mon Sep 17 00:00:00 2001 -Message-Id: <7afbbab2ccada16c87e1095e85184bb21c028012.1619091487.git.sbrivio@redhat.com> -From: Stefano Brivio -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 ---- -SPDX-FileCopyrightText: 2020-2021 Red Hat GmbH -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. - - ... - --:anchor:`` -+:anchor:`` - --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. - - ... - -+Named UNIX domain sockets can be specified as follows: -+:since:`Since 7.3.0, qemu` -+ -+:: -+ -+ ... -+ -+ -+ -+ -+ -+ ... -+ -+ -+ -+ -+ -+ ... -+ - :anchor:`` - - 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 @@ - - - -- -- mcast -- client -- -+ mcast - - - -@@ -3179,6 +3176,30 @@ - - - -+ -+ -+ client -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - udp -@@ -3210,14 +3231,21 @@ - - - -- -- -- -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - -- -- -- -- -+ - - - -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, - " "), 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", -+ _(" '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 '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 '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 '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, "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, "data.socket.address, -- def->data.socket.port); -+ def->data.socket.net.address, -+ def->data.socket.net.port); - } else { - virBufferAsprintf(buf, "data.socket.port); -+ def->data.socket.net.port); - } - sourceLines++; - -@@ -25960,8 +25992,8 @@ virDomainNetDefFormat(virBuffer *buf, - virBufferAdjustIndent(buf, 2); - - virBufferAsprintf(buf, "\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/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch b/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch deleted file mode 100644 index 9e71f88..0000000 --- a/qemu/0001-net-Allow-also-UNIX-domain-sockets-to-be-used-as-net.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 83c3f76b8fe6b4a6bb45dcf5cfad65ec6f98a10e Mon Sep 17 00:00:00 2001 -From: Stefano Brivio -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 ---- -SPDX-FileCopyrightText: 2020-2022 Red Hat GmbH -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/qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch b/qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch deleted file mode 100644 index 0e31a1b..0000000 --- a/qemu/0002-net-Don-t-ignore-EINVAL-on-netdev-socket-connection.patch +++ /dev/null @@ -1,37 +0,0 @@ -From a6d475147682de1fe3b14eb325f4247e013e8440 Mon Sep 17 00:00:00 2001 -Message-Id: -In-Reply-To: -References: -From: Stefano Brivio -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 ---- -SPDX-FileCopyrightText: 2020-2021 Red Hat GmbH -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 - -- cgit v1.2.3