This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 9736fefb3bb00730608c9ce701953a890b6753a8
Author: Yongrong Wang <[email protected]>
AuthorDate: Wed Sep 25 00:03:52 2024 +0800

    net/vsock: add vsock vhost transport support
    
    Add the vhost (host side) transport layer for vsock, letting a host serve
    guest vsock connections.
    
    Signed-off-by: Bowen Wang <[email protected]>
    Signed-off-by: Yongrong Wang <[email protected]>
---
 net/vsock/CMakeLists.txt |   9 ++
 net/vsock/Kconfig        |  16 +++
 net/vsock/Make.defs      |   8 ++
 net/vsock/vsock.h        |   8 ++
 net/vsock/vsock_sockif.c |  20 ++-
 net/vsock/vsock_vhost.c  | 368 +++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 428 insertions(+), 1 deletion(-)

diff --git a/net/vsock/CMakeLists.txt b/net/vsock/CMakeLists.txt
index 839d7ff9898..5895c124a2d 100644
--- a/net/vsock/CMakeLists.txt
+++ b/net/vsock/CMakeLists.txt
@@ -22,5 +22,14 @@
 
 if(CONFIG_NET_VSOCK)
   set(SRCS vsock_sockif.c vsock_addr.c)
+
+  if(CONFIG_NET_VSOCK_VIRTIO)
+    list(APPEND SRCS vsock_virtio.c)
+  endif()
+
+  if(CONFIG_NET_VSOCK_VHOST)
+    list(APPEND SRCS vsock_vhost.c)
+  endif()
+
   target_sources(net PRIVATE ${SRCS})
 endif()
diff --git a/net/vsock/Kconfig b/net/vsock/Kconfig
index 58ee4af8807..f94cccf7fd6 100644
--- a/net/vsock/Kconfig
+++ b/net/vsock/Kconfig
@@ -34,6 +34,22 @@ config NET_VSOCK_WORK_STACKSIZE
        int "Virtual Socket work stack size"
        default DEFAULT_TASK_STACKSIZE
 
+config NET_VSOCK_VQ_BUFCOUNT
+       int "Virtual Socket virtqueue max number"
+       default 64
+
 endif # NET_VSOCK
 
+config NET_VSOCK_VIRTIO
+       bool "Virtual Socket Virtio Transport Layer Support"
+       default n
+       select DRIVERS_VIRTIO
+       select NET_VSOCK
+
+config NET_VSOCK_VHOST
+       bool "Virtual Socket Vhost Transport Layer Support"
+       default n
+       select DRIVERS_VHOST
+       select NET_VSOCK
+
 endmenu # Virtual Socket networking stack API
diff --git a/net/vsock/Make.defs b/net/vsock/Make.defs
index db599d61ed3..03b06e052de 100644
--- a/net/vsock/Make.defs
+++ b/net/vsock/Make.defs
@@ -24,6 +24,14 @@ ifeq ($(CONFIG_NET_VSOCK),y)
 
 SOCK_CSRCS += vsock_sockif.c vsock_addr.c
 
+ifeq ($(CONFIG_NET_VSOCK_VIRTIO),y)
+  SOCK_CSRCS += vsock_virtio.c
+endif
+
+ifeq ($(CONFIG_NET_VSOCK_VHOST),y)
+  SOCK_CSRCS += vsock_vhost.c
+endif
+
 # Include Virtio Socket build support
 
 DEPPATH += --dep-path vsock
diff --git a/net/vsock/vsock.h b/net/vsock/vsock.h
index 773a9e36bd3..ca6f21f73a1 100644
--- a/net/vsock/vsock.h
+++ b/net/vsock/vsock.h
@@ -128,6 +128,14 @@ bool vsock_addr_equal(FAR const struct sockaddr_vm *addr1,
 
 int vsock_initialize(void);
 
+#ifdef CONFIG_NET_VSOCK_VIRTIO
+int vsock_virtio_initialize(void);
+#endif
+
+#ifdef CONFIG_NET_VSOCK_VHOST
+int vsock_vhost_initialize(void);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/net/vsock/vsock_sockif.c b/net/vsock/vsock_sockif.c
index 714878a558a..eaca2df23c8 100644
--- a/net/vsock/vsock_sockif.c
+++ b/net/vsock/vsock_sockif.c
@@ -2434,6 +2434,8 @@ void vsock_transport_register(FAR struct 
vsock_transport_s *t)
 
 int vsock_initialize(void)
 {
+  int ret = OK;
+
   g_vsock_wqueue = work_queue_create("vsock_work",
                                      CONFIG_NET_VSOCK_WORK_PRIORITY,
                                      NULL,
@@ -2444,5 +2446,21 @@ int vsock_initialize(void)
       return -ENOMEM;
     }
 
-  return OK;
+#ifdef CONFIG_NET_VSOCK_VIRTIO
+  ret = vsock_virtio_initialize();
+  if (ret < 0)
+    {
+      vrterr("ERROR: vsock_virtio_initialize failed: %d\n", ret);
+    }
+#endif
+
+#ifdef CONFIG_NET_VSOCK_VHOST
+  ret = vsock_vhost_initialize();
+  if (ret < 0)
+    {
+      vhosterr("ERROR: vsock_vhost_initialize failed, ret=%d\n", ret);
+    }
+#endif
+
+  return ret;
 }
diff --git a/net/vsock/vsock_vhost.c b/net/vsock/vsock_vhost.c
new file mode 100644
index 00000000000..545688224fd
--- /dev/null
+++ b/net/vsock/vsock_vhost.c
@@ -0,0 +1,368 @@
+/****************************************************************************
+ * net/vsock/vsock_vhost.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/param.h>
+
+#include <nuttx/nuttx.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/vhost/vhost.h>
+
+#include "vsock/vsock.h"
+#include "vsock/vsock_virtio.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define VSOCK_VQ_TX              0
+#define VSOCK_VQ_RX              1
+#define VSOCK_VQ_EVENT           2
+#define VSOCK_VQ_NUM             3
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct vsock_vhost_priv_s
+{
+  FAR struct vhost_device *hdev;
+  uint64_t                 guest_cid;
+  uint64_t                 host_cid;
+
+  spinlock_t               tx_lock;
+  sem_t                    tx_sem;
+  struct work_s            rx_work;
+
+  struct vsock_transport_s t;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Vhost driver functions */
+
+static int vsock_vhost_probe(FAR struct vhost_device *hdev);
+static void vsock_vhost_remove(FAR struct vhost_device *hdev);
+
+static uint64_t vsock_vhost_get_localcid(FAR struct vsock_transport_s *t);
+static uint64_t vsock_vhost_get_remotecid(FAR struct vsock_transport_s *t);
+static int vsock_vhost_alloc_pkt(FAR struct vsock_transport_s *t,
+                                 FAR struct vsock_pkt_s *pkt,
+                                 size_t data_len);
+static ssize_t vsock_vhost_send_pkt(FAR struct vsock_transport_s *t,
+                                    FAR struct vsock_pkt_s *pkt);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct vhost_driver g_vsock_vhost_driver =
+{
+  LIST_INITIAL_VALUE(g_vsock_vhost_driver.node), /* Node */
+  VIRTIO_ID_VSOCK,                               /* Device id */
+  vsock_vhost_probe,                             /* Probe */
+  vsock_vhost_remove,                            /* Remove */
+};
+
+static const struct vsock_transport_ops_s g_vsock_vhost_transport_ops =
+{
+  .get_localcid  = vsock_vhost_get_localcid,
+  .get_remotecid = vsock_vhost_get_remotecid,
+  .alloc_pkt     = vsock_vhost_alloc_pkt,
+  .send_pkt      = vsock_vhost_send_pkt,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: vsock_vhost_trans2priv
+ ****************************************************************************/
+
+static FAR struct vsock_vhost_priv_s *
+vsock_vhost_trans2priv(FAR struct vsock_transport_s *t)
+{
+  return container_of(t, struct vsock_vhost_priv_s, t);
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_get_localcid
+ ****************************************************************************/
+
+static uint64_t vsock_vhost_get_localcid(FAR struct vsock_transport_s *t)
+{
+  FAR struct vsock_vhost_priv_s *priv = vsock_vhost_trans2priv(t);
+
+  return priv->host_cid;
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_get_remotecid
+ ****************************************************************************/
+
+static uint64_t vsock_vhost_get_remotecid(FAR struct vsock_transport_s *t)
+{
+  FAR struct vsock_vhost_priv_s *priv =
+    container_of(t, struct vsock_vhost_priv_s, t);
+
+  return priv->guest_cid;
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_alloc_pkt
+ ****************************************************************************/
+
+static int vsock_vhost_alloc_pkt(FAR struct vsock_transport_s *t,
+                                 FAR struct vsock_pkt_s *pkt,
+                                 size_t data_len)
+{
+  FAR struct vsock_vhost_priv_s *priv = vsock_vhost_trans2priv(t);
+  FAR struct virtqueue *vq;
+  irqstate_t flags;
+  size_t vbcnt;
+  int head;
+
+  data_len += VIRTIO_VSOCK_HDR_LEN;
+  vbcnt = div_round_up(data_len, CONFIG_NET_VSOCK_PKT_BUFSIZE);
+  vbcnt = MIN(vbcnt, CONFIG_NET_VSOCK_PKT_BUFCOUNT);
+
+  vq = priv->hdev->vrings_info[VSOCK_VQ_TX].vq;
+  for (; ; )
+    {
+      flags = spin_lock_irqsave(&priv->tx_lock);
+      head = vhost_get_vq_buffers(vq, pkt->vb, vbcnt, &pkt->vbcnt);
+      spin_unlock_irqrestore(&priv->tx_lock, flags);
+      if (head < 0)
+        {
+          nxsem_wait(&priv->tx_sem);
+          continue;
+        }
+
+      pkt->vbidx = 0;
+      pkt->vboff = VIRTIO_VSOCK_HDR_LEN;
+      pkt->priv = (FAR void *)(uintptr_t)head;
+      return 0;
+    }
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_send_pkt
+ ****************************************************************************/
+
+static ssize_t vsock_vhost_send_pkt(FAR struct vsock_transport_s *t,
+                                    FAR struct vsock_pkt_s *pkt)
+{
+  FAR struct vsock_vhost_priv_s *priv = vsock_vhost_trans2priv(t);
+  FAR struct vsock_hdr_s *hdr = vsock_pkt2hdr(pkt);
+  FAR struct virtqueue *vq;
+  ssize_t len = hdr->len;
+  irqstate_t flags;
+  int ret;
+
+  vq = priv->hdev->vrings_info[VSOCK_VQ_TX].vq;
+  flags = spin_lock_irqsave(&priv->tx_lock);
+  ret = virtqueue_add_consumed_buffer(vq, (uint16_t)(uintptr_t)pkt->priv,
+                                      hdr->len + VIRTIO_VSOCK_HDR_LEN);
+  if (ret < 0)
+    {
+      spin_unlock_irqrestore(&priv->tx_lock, flags);
+      vhosterr("Add buffer failed ret=%d\n", ret);
+      return ret;
+    }
+
+  virtqueue_kick(vq);
+
+  spin_unlock_irqrestore(&priv->tx_lock, flags);
+  return len;
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_rx_work
+ ****************************************************************************/
+
+static void vsock_vhost_rx_work(FAR void *arg)
+{
+  FAR struct vsock_vhost_priv_s *priv = arg;
+  FAR struct virtqueue *vq;
+  struct vsock_pkt_s pkt;
+  bool added = false;
+  int head;
+
+  vq = priv->hdev->vrings_info[VSOCK_VQ_RX].vq;
+  memset(&pkt, 0, sizeof(struct vsock_pkt_s));
+
+  do
+    {
+      virtqueue_disable_cb(vq);
+      for (; ; )
+        {
+          head = vhost_get_vq_buffers(vq, pkt.vb,
+                                      CONFIG_NET_VSOCK_PKT_BUFCOUNT,
+                                      &pkt.vbcnt);
+          if (head < 0)
+            {
+              break;
+            }
+
+          pkt.vbidx = 0;
+          pkt.vboff = VIRTIO_VSOCK_HDR_LEN;
+          vsock_recv_pkt(&priv->t, &pkt);
+          virtqueue_add_consumed_buffer(vq, head, 0);
+          added = true;
+        }
+    }
+  while (virtqueue_enable_cb(vq));
+
+  if (added)
+    {
+      virtqueue_kick(vq);
+    }
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_handle_rx
+ ****************************************************************************/
+
+static void vsock_vhost_handle_rx(FAR struct virtqueue *vq)
+{
+  FAR struct vsock_vhost_priv_s *priv = vq->vq_dev->priv;
+
+  if (work_available(&priv->rx_work))
+    {
+      vsock_queue_work(&priv->rx_work, vsock_vhost_rx_work, priv, 0);
+    }
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_handle_tx
+ ****************************************************************************/
+
+static void vsock_vhost_handle_tx(FAR struct virtqueue *vq)
+{
+  FAR struct vsock_vhost_priv_s *priv = vq->vq_dev->priv;
+
+  vsock_post(&priv->tx_sem);
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_probe
+ ****************************************************************************/
+
+static int vsock_vhost_probe(FAR struct vhost_device *hdev)
+{
+  FAR struct vsock_vhost_priv_s *priv;
+  FAR const char *vqnames[VSOCK_VQ_NUM];
+  vq_callback callbacks[VSOCK_VQ_NUM];
+  int ret;
+
+  priv = kmm_zalloc(sizeof(*priv));
+  if (priv == NULL)
+    {
+      vhosterr("No enough memory\n");
+      return -ENOMEM;
+    }
+
+  priv->hdev = hdev;
+  hdev->priv = priv;
+  spin_lock_init(&priv->tx_lock);
+  nxsem_init(&priv->tx_sem, 0, 0);
+
+  /* Create the virtqueues */
+
+  vqnames[VSOCK_VQ_RX]      = "vsock_vhost_handle_rx";
+  vqnames[VSOCK_VQ_TX]      = "vsock_vhost_handle_tx";
+  vqnames[VSOCK_VQ_EVENT]   = "vsock_vhost_handle_event";
+  callbacks[VSOCK_VQ_RX]    = vsock_vhost_handle_rx;
+  callbacks[VSOCK_VQ_TX]    = vsock_vhost_handle_tx;
+  callbacks[VSOCK_VQ_EVENT] = NULL;
+  ret = vhost_create_virtqueues(hdev, 0, VSOCK_VQ_NUM, vqnames, callbacks,
+                                NULL);
+  if (ret < 0)
+    {
+      vhosterr("virtio_device_create_virtqueue failed, ret=%d\n", ret);
+      goto err;
+    }
+
+  virtio_read_config_member(priv->hdev, struct virtio_vsock_config_s,
+                            guest_cid, &priv->guest_cid);
+
+  if (virtio_has_feature(hdev, VIRTIO_VSOCK_F_HOST_CID))
+    {
+      virtio_read_config_member(priv->hdev, struct virtio_vsock_config_s,
+                                host_cid, &priv->host_cid);
+    }
+  else
+    {
+      priv->host_cid = VMADDR_CID_HOST;
+    }
+
+  /* Register Virtual Socket H2G transport */
+
+  priv->t.ops = &g_vsock_vhost_transport_ops;
+  vsock_transport_register(&priv->t);
+
+  virtqueue_enable_cb(hdev->vrings_info[VSOCK_VQ_RX].vq);
+  virtqueue_enable_cb(hdev->vrings_info[VSOCK_VQ_TX].vq);
+  return ret;
+
+err:
+  kmm_free(priv);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: vsock_vhost_remove
+ ****************************************************************************/
+
+static void vsock_vhost_remove(FAR struct vhost_device *hdev)
+{
+  FAR struct vsock_vhost_priv_s *priv = hdev->priv;
+
+  virtqueue_disable_cb(hdev->vrings_info[VSOCK_VQ_RX].vq);
+  virtqueue_disable_cb(hdev->vrings_info[VSOCK_VQ_TX].vq);
+  vhost_delete_virtqueues(hdev);
+  nxsem_destroy(&priv->tx_sem);
+  kmm_free(priv);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: vsock_vhost_initialize
+ ****************************************************************************/
+
+int vsock_vhost_initialize(void)
+{
+  return vhost_register_driver(&g_vsock_vhost_driver);
+}

Reply via email to