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); +}
