From e653f9b3ed1b60037e3bc661d53b3f9407243fc2 Mon Sep 17 00:00:00 2001
From: Stefano Brivio <sbrivio@redhat.com>
Date: Sat, 20 Mar 2021 07:22:09 +0100
Subject: passt: Add libvirt patch for qemu UNIX socket domain back-end

...and mention it in the README.

While at it, remove useless escaping in the README, and fix
indentation in the syslog message with the qemu command line
example.

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
 ...uce-support-for-UNIX-domain-socket-as-qem.patch | 423 +++++++++++++++++++++
 1 file changed, 423 insertions(+)
 create mode 100644 libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch

(limited to 'libvirt')

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
new file mode 100644
index 0000000..c0e3337
--- /dev/null
+++ b/libvirt/0001-conf-Introduce-support-for-UNIX-domain-socket-as-qem.patch
@@ -0,0 +1,423 @@
+From 62e95cb4b5708eca7860139dffef22e65b29514c Mon Sep 17 00:00:00 2001
+From: Stefano Brivio <sbrivio@redhat.com>
+Date: Sat, 20 Mar 2021 07:16:15 +0100
+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>
+---
+ 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 9392c80113..b5b642e91a 100644
+--- a/docs/formatdomain.rst
++++ b/docs/formatdomain.rst
+@@ -4995,18 +4995,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:
+ 
+ ::
+ 
+@@ -5024,6 +5026,25 @@ appropriate routing.
+    </devices>
+    ...
+ 
++Named UNIX domain sockets can be specified as follows:
++:since:`Since 7.2.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 1dbfc68f18..350d6969c0 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -3125,10 +3125,7 @@
+         </group>
+         <group>
+           <attribute name="type">
+-            <choice>
+-              <value>mcast</value>
+-              <value>client</value>
+-            </choice>
++            <value>mcast</value>
+           </attribute>
+           <interleave>
+             <element name="source">
+@@ -3143,6 +3140,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>
+@@ -3174,14 +3195,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 7671050134..55543c47ce 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -2569,8 +2569,9 @@ virDomainNetDefFree(virDomainNetDefPtr 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:
+@@ -10792,6 +10793,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr 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;
+@@ -10935,7 +10937,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr 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 ||
+@@ -10943,6 +10945,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr 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;
+@@ -11186,6 +11189,27 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr 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) {
+@@ -11194,7 +11218,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr 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"));
+@@ -11211,7 +11235,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr 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)
+@@ -11223,7 +11247,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr 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"));
+@@ -11236,7 +11261,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr 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;
+ 
+@@ -26219,15 +26244,22 @@ virDomainNetDefFormat(virBufferPtr 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++;
+ 
+@@ -26239,8 +26271,8 @@ virDomainNetDefFormat(virBufferPtr 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 87bc7e8625..3cc0842eed 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -1042,11 +1042,14 @@ struct _virDomainNetDef {
+     virDomainNetTeamingInfoPtr teaming;
+     union {
+         virDomainChrSourceDefPtr 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 5717f7b98d..c1687e582e 100644
+--- a/src/qemu/qemu_command.c
++++ b/src/qemu/qemu_command.c
+@@ -3639,37 +3639,55 @@ qemuBuildHostNetStr(virDomainNetDefPtr 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 a66354426d..8ca86f9c53 100644
+--- a/src/qemu/qemu_hotplug.c
++++ b/src/qemu/qemu_hotplug.c
+@@ -3752,9 +3752,11 @@ qemuDomainChangeNet(virQEMUDriverPtr 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.28.0
+
-- 
cgit v1.2.3