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 9107753826a49c74b5639643f6e6c7c39ae22b4a
Author: Yongrong Wang <[email protected]>
AuthorDate: Tue Sep 23 16:14:37 2025 +0800

    vsock: support multi pkt chain in vsock vhost Tx
    
    vsock vhost tx transmission rate increased by about 61%.
    
    Signed-off-by: Yongrong Wang <[email protected]>
---
 net/vsock/vsock.h        |  12 +++---
 net/vsock/vsock_sockif.c |  87 ++++++++++++++++++++++-----------------
 net/vsock/vsock_vhost.c  | 104 +++++++++++++++++++++++++++++++++++++++--------
 net/vsock/vsock_virtio.c |   2 +
 4 files changed, 145 insertions(+), 60 deletions(-)

diff --git a/net/vsock/vsock.h b/net/vsock/vsock.h
index 9af83327209..60b8896128e 100644
--- a/net/vsock/vsock.h
+++ b/net/vsock/vsock.h
@@ -48,11 +48,13 @@
 
 struct vsock_pkt_s
 {
-  size_t                vbidx;
-  size_t                vboff;
-  size_t                vbcnt;
-  FAR void             *priv;
-  struct virtqueue_buf  vb[CONFIG_NET_VSOCK_PKT_BUFCOUNT];
+  size_t                  vbidx;
+  size_t                  vboff;
+  size_t                  vbcnt;
+  size_t                  len;
+  FAR void               *priv;
+  FAR struct vsock_pkt_s *next;
+  struct virtqueue_buf    vb[CONFIG_NET_VSOCK_PKT_BUFCOUNT];
 };
 
 struct vsock_transport_s;
diff --git a/net/vsock/vsock_sockif.c b/net/vsock/vsock_sockif.c
index 87405a80b1f..de1d7b3c854 100644
--- a/net/vsock/vsock_sockif.c
+++ b/net/vsock/vsock_sockif.c
@@ -916,27 +916,34 @@ static size_t vsock_copy_msg2pkt(FAR struct vsock_pkt_s 
*pkt,
   size_t ret = 0;
 
   DEBUGASSERT(total <= msg->uio.uio_resid);
-  while (total > 0 && pkt->vbidx < pkt->vbcnt &&
-         pkt->vboff <= pkt->vb[pkt->vbidx].len)
-    {
-      FAR void *buf = pkt->vb[pkt->vbidx].buf + pkt->vboff;
-      size_t len = pkt->vb[pkt->vbidx].len - pkt->vboff;
 
-      size_t copied = MIN(len, total);
-      uio_copyto(&msg->uio, 0, buf, copied);
-      uio_advance(&msg->uio, copied);
-      if (copied >= len)
-        {
-          pkt->vbidx++;
-          pkt->vboff = 0;
-        }
-      else
+  while (pkt != NULL)
+    {
+      while (total > 0 && pkt->vbidx < pkt->vbcnt &&
+             pkt->vboff <= pkt->vb[pkt->vbidx].len)
         {
-          pkt->vboff += copied;
+          FAR void *buf = pkt->vb[pkt->vbidx].buf + pkt->vboff;
+          size_t len = pkt->vb[pkt->vbidx].len - pkt->vboff;
+
+          size_t copied = MIN(len, total);
+
+          uio_copyto(&msg->uio, 0, buf, copied);
+          uio_advance(&msg->uio, copied);
+          if (copied >= len)
+            {
+              pkt->vbidx++;
+              pkt->vboff = 0;
+            }
+          else
+            {
+              pkt->vboff += copied;
+            }
+
+          total -= copied;
+          ret += copied;
         }
 
-      total -= copied;
-      ret += copied;
+      pkt = pkt->next;
     }
 
   return ret;
@@ -997,6 +1004,7 @@ static int vsock_send_pkt(FAR struct vsock_conn_s *conn,
                           uint16_t op, uint32_t hdrflags,
                           uint64_t dst_cid, uint32_t dst_port)
 {
+  FAR struct vsock_pkt_s *tmp;
   struct vsock_pkt_s pkt;
   struct vsock_hdr_s *hdr;
   unsigned int rxcount;
@@ -1033,30 +1041,33 @@ static int vsock_send_pkt(FAR struct vsock_conn_s *conn,
       vsock_alloc_tx_credit(conn, len);
     }
 
-  hdr = vsock_pkt2hdr(&pkt);
-  if (dst_cid == 0)
+  for (tmp = &pkt; tmp != NULL; tmp = tmp->next)
     {
-      hdr->dst_cid  = conn->remote_addr.svm_cid;
-      hdr->dst_port = conn->remote_addr.svm_port;
-    }
-  else
-    {
-      hdr->dst_cid  = dst_cid;
-      hdr->dst_port = dst_port;
-    }
+      hdr = vsock_pkt2hdr(tmp);
+      if (dst_cid == 0)
+        {
+          hdr->dst_cid  = conn->remote_addr.svm_cid;
+          hdr->dst_port = conn->remote_addr.svm_port;
+        }
+      else
+        {
+          hdr->dst_cid  = dst_cid;
+          hdr->dst_port = dst_port;
+        }
 
-  hdr->type     = VIRTIO_VSOCK_TYPE_STREAM;
-  hdr->op       = op;
-  hdr->src_cid  = VSOCK_GET_LOCALCID(conn->transport);
-  hdr->src_port = conn->local_addr.svm_port;
-  hdr->flags    = hdrflags;
-  hdr->len      = len;
+      hdr->type     = VIRTIO_VSOCK_TYPE_STREAM;
+      hdr->op       = op;
+      hdr->src_cid  = VSOCK_GET_LOCALCID(conn->transport);
+      hdr->src_port = conn->local_addr.svm_port;
+      hdr->flags    = hdrflags;
+      hdr->len      = tmp->len - VIRTIO_VSOCK_HDR_LEN;
 
-  flags = spin_lock_irqsave(&conn->cnt_lock);
-  conn->rx_last_fwd_cnt = conn->rx_fwd_cnt;
-  hdr->fwd_cnt = conn->rx_fwd_cnt;
-  hdr->buf_alloc = conn->rx_buf_alloc;
-  spin_unlock_irqrestore(&conn->cnt_lock, flags);
+      flags = spin_lock_irqsave(&conn->cnt_lock);
+      conn->rx_last_fwd_cnt = conn->rx_fwd_cnt;
+      hdr->fwd_cnt = conn->rx_fwd_cnt;
+      hdr->buf_alloc = conn->rx_buf_alloc;
+      spin_unlock_irqrestore(&conn->cnt_lock, flags);
+    }
 
   vsock_dump_pkt(&pkt, "Send", false);
   return VSOCK_SEND_PKT(conn->transport, &pkt);
diff --git a/net/vsock/vsock_vhost.c b/net/vsock/vsock_vhost.c
index cd642c9cdc2..3dc7b0bf3b2 100644
--- a/net/vsock/vsock_vhost.c
+++ b/net/vsock/vsock_vhost.c
@@ -60,6 +60,9 @@ struct vsock_vhost_priv_s
   sem_t                    tx_sem;
   struct work_s            rx_work;
 
+  struct list_node         tx_pkt_list;
+  FAR struct vsock_pkt_s  *tx_pkt_alloc;
+
   struct vsock_transport_s t;
 };
 
@@ -148,30 +151,43 @@ static int vsock_vhost_alloc_pkt(FAR struct 
vsock_transport_s *t,
   FAR struct vsock_vhost_priv_s *priv = vsock_vhost_trans2priv(t);
   FAR struct virtqueue *vq;
   irqstate_t flags;
-  size_t vbcnt;
+  size_t pktcnt;
   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);
+  pktcnt = data_len == 0 ? 1 :
+           div_round_up(data_len, CONFIG_NET_VSOCK_PKT_BUFSIZE);
+  pktcnt = MIN(pktcnt, CONFIG_NET_VSOCK_PKT_BUFCOUNT);
 
   vq = priv->hdev->vrings_info[VSOCK_VQ_TX].vq;
-  for (; ; )
+  flags = spin_lock_irqsave(&priv->tx_lock);
+  while (pktcnt > 0)
     {
-      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);
+      head = vhost_get_vq_buffers(vq, pkt->vb, 1, &pkt->vbcnt);
       if (head < 0)
         {
+          spin_unlock_irqrestore(&priv->tx_lock, flags);
           nxsem_wait(&priv->tx_sem);
+          flags = spin_lock_irqsave(&priv->tx_lock);
           continue;
         }
 
       pkt->vbidx = 0;
       pkt->vboff = VIRTIO_VSOCK_HDR_LEN;
       pkt->priv = (FAR void *)(uintptr_t)head;
-      return 0;
+      pkt->len  = MIN(data_len + VIRTIO_VSOCK_HDR_LEN, pkt->vb[0].len);
+      data_len -= pkt->len - VIRTIO_VSOCK_HDR_LEN;
+
+      if (--pktcnt > 0)
+        {
+          pkt->next = (FAR struct vsock_pkt_s *)
+                      list_remove_head(&priv->tx_pkt_list);
+          DEBUGASSERT(pkt->next != NULL);
+          pkt = pkt->next;
+        }
     }
+
+  spin_unlock_irqrestore(&priv->tx_lock, flags);
+  return 0;
 }
 
 /****************************************************************************
@@ -182,21 +198,38 @@ 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 vsock_pkt_s *next;
+  FAR struct vsock_hdr_s *hdr;
   FAR struct virtqueue *vq;
-  ssize_t len = hdr->len;
+  uint32_t data_len;
   irqstate_t flags;
+  ssize_t len = 0;
   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)
+  while (pkt != NULL)
     {
-      spin_unlock_irqrestore(&priv->tx_lock, flags);
-      vhosterr("Add buffer failed ret=%d\n", ret);
-      return ret;
+      hdr = vsock_pkt2hdr(pkt);
+      data_len = hdr->len;
+      ret = virtqueue_add_consumed_buffer(vq, (uint16_t)(uintptr_t)pkt->priv,
+                                          data_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;
+        }
+
+      next = pkt->next;
+      if (len != 0)
+        {
+          pkt->next = NULL;
+          list_add_head(&priv->tx_pkt_list, (FAR struct list_node *)pkt);
+        }
+
+      pkt = next;
+      len += data_len;
     }
 
   virtqueue_kick(vq);
@@ -273,6 +306,32 @@ static void vsock_vhost_handle_tx(FAR struct virtqueue *vq)
   vsock_post(&priv->tx_sem);
 }
 
+/****************************************************************************
+ * Name: vsock_vhost_tx_pkt_init
+ ****************************************************************************/
+
+static int vsock_vhost_tx_pkt_init(FAR struct vsock_vhost_priv_s *priv)
+{
+  FAR struct virtqueue *vq = priv->hdev->vrings_info[VSOCK_VQ_TX].vq;
+  uint16_t i;
+
+  list_initialize(&priv->tx_pkt_list);
+  priv->tx_pkt_alloc = kmm_zalloc(sizeof(struct vsock_pkt_s) *
+                                  vq->vq_nentries);
+  if (priv->tx_pkt_alloc == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  for (i = 0; i < vq->vq_nentries; i++)
+    {
+      list_add_tail(&priv->tx_pkt_list,
+                    (FAR struct list_node *)(&priv->tx_pkt_alloc[i]));
+    }
+
+  return 0;
+}
+
 /****************************************************************************
  * Name: vsock_vhost_probe
  ****************************************************************************/
@@ -327,6 +386,13 @@ static int vsock_vhost_probe(FAR struct vhost_device *hdev)
       priv->host_cid = VMADDR_CID_HOST;
     }
 
+  ret = vsock_vhost_tx_pkt_init(priv);
+  if (ret < 0)
+    {
+      vrterr("vsock_vhost_tx_pkt_init failed, ret=%d\n", ret);
+      goto err_with_tx;
+    }
+
   /* Register Virtual Socket H2G transport */
 
   priv->t.ops = &g_vsock_vhost_transport_ops;
@@ -336,7 +402,10 @@ static int vsock_vhost_probe(FAR struct vhost_device *hdev)
   virtqueue_enable_cb(hdev->vrings_info[VSOCK_VQ_TX].vq);
   return ret;
 
+err_with_tx:
+  vhost_delete_virtqueues(hdev);
 err:
+  nxsem_destroy(&priv->tx_sem);
   kmm_free(priv);
   return ret;
 }
@@ -351,6 +420,7 @@ static void vsock_vhost_remove(FAR struct vhost_device 
*hdev)
 
   virtqueue_disable_cb(hdev->vrings_info[VSOCK_VQ_RX].vq);
   virtqueue_disable_cb(hdev->vrings_info[VSOCK_VQ_TX].vq);
+  kmm_free(priv->tx_pkt_alloc);
   vhost_delete_virtqueues(hdev);
   nxsem_destroy(&priv->tx_sem);
   kmm_free(priv);
diff --git a/net/vsock/vsock_virtio.c b/net/vsock/vsock_virtio.c
index 2a8f6279b81..5ccc839d040 100644
--- a/net/vsock/vsock_virtio.c
+++ b/net/vsock/vsock_virtio.c
@@ -203,6 +203,8 @@ static int vsock_virtio_alloc_pkt(FAR struct 
vsock_transport_s *t,
                 {
                   pkt->vb[i].len = data_len;
                 }
+
+              pkt->len += pkt->vb[i].len;
             }
 
           priv->tx_buf_num -= vbcnt;

Reply via email to