From 696cd69752032e55ef301f3eb4f7ad42693137ab Mon Sep 17 00:00:00 2001
From: hantwofish <hankangkang5@huawei.com>
Date: Mon, 17 Jun 2024 14:33:50 +0800
Subject: [PATCH] [virtio]: create and init virtio_port

---
 src/lstack/core/dir.mk               |   2 +-
 src/lstack/core/lstack_dpdk.c        |   6 +-
 src/lstack/core/lstack_port_map.c    |  43 ++++++
 src/lstack/core/lstack_virtio.c      | 201 +++++++++++++++++++++++++++
 src/lstack/include/lstack_port_map.h |  20 +++
 src/lstack/include/lstack_virtio.h   |  36 +++++
 6 files changed, 306 insertions(+), 2 deletions(-)
 create mode 100644 src/lstack/core/lstack_port_map.c
 create mode 100644 src/lstack/core/lstack_virtio.c
 create mode 100644 src/lstack/include/lstack_port_map.h
 create mode 100644 src/lstack/include/lstack_virtio.h

diff --git a/src/lstack/core/dir.mk b/src/lstack/core/dir.mk
index e2d10a5..21b0d22 100644
--- a/src/lstack/core/dir.mk
+++ b/src/lstack/core/dir.mk
@@ -8,6 +8,6 @@
 # PURPOSE.
 # See the Mulan PSL v2 for more details.
 
-SRC = lstack_preload.c lstack_init.c lstack_cfg.c lstack_dpdk.c lstack_control_plane.c lstack_stack_stat.c lstack_lwip.c lstack_protocol_stack.c lstack_thread_rpc.c
+SRC = lstack_preload.c lstack_init.c lstack_cfg.c lstack_dpdk.c lstack_control_plane.c lstack_stack_stat.c lstack_lwip.c lstack_protocol_stack.c lstack_thread_rpc.c lstack_virtio.c lstack_port_map.c
 $(eval $(call register_dir, core, $(SRC)))
 
diff --git a/src/lstack/core/lstack_dpdk.c b/src/lstack/core/lstack_dpdk.c
index 785431f..b0d76bf 100644
--- a/src/lstack/core/lstack_dpdk.c
+++ b/src/lstack/core/lstack_dpdk.c
@@ -49,6 +49,7 @@
 #include "lstack_thread_rpc.h"
 #include "lstack_lwip.h"
 #include "lstack_cfg.h"
+#include "lstack_virtio.h"
 #include "lstack_dpdk.h"
 
 struct eth_params {
@@ -771,7 +772,7 @@ int32_t init_dpdk_ethdev(void)
 {
     int32_t ret;
     int slave_port_id[GAZELLE_MAX_BOND_NUM] = {-1};
-    int port_id;
+    int port_id = 0;
     struct cfg_params *cfg = get_global_cfg_params();
     int i;
 
@@ -813,6 +814,9 @@ int32_t init_dpdk_ethdev(void)
         }
     }
 #endif
+    if (get_global_cfg_params()->flow_bifurcation && virtio_port_create(port_id) != 0) {
+        return -1;
+    }
 
     return 0;
 }
diff --git a/src/lstack/core/lstack_port_map.c b/src/lstack/core/lstack_port_map.c
new file mode 100644
index 0000000..e5008b3
--- /dev/null
+++ b/src/lstack/core/lstack_port_map.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
+ * gazelle is licensed under the Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *     http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+ * PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+#include <pthread.h>
+#include <stdint.h>
+#include "lstack_port_map.h"
+
+#define PORT_MAP_UNIX_TCP_PORT_MAX 65535
+#define PORT_MAP_EIGHT_BIT 8
+
+static uint8_t g_rule_port[(PORT_MAP_UNIX_TCP_PORT_MAX + 1) / PORT_MAP_EIGHT_BIT]; // 8k byte
+static pthread_mutex_t g_rule_map_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void port_map_set(uint32_t modBit, int setVal)
+{
+    pthread_mutex_lock(&g_rule_map_mutex);
+    g_rule_port[modBit / PORT_MAP_EIGHT_BIT] &= ~(1 << (modBit % PORT_MAP_EIGHT_BIT));
+    g_rule_port[modBit / PORT_MAP_EIGHT_BIT] |= (setVal << (modBit % PORT_MAP_EIGHT_BIT));
+    pthread_mutex_unlock(&g_rule_map_mutex);
+}
+
+int port_map_get(int bit_index)
+{
+    int bit_val = 0;
+    int byte_index = bit_index / PORT_MAP_EIGHT_BIT;
+    int bit_offset = bit_index % PORT_MAP_EIGHT_BIT;
+    uint8_t mask = 1 << bit_offset;
+    pthread_mutex_lock(&g_rule_map_mutex);
+    if ((g_rule_port[byte_index] & mask) != 0) {
+        bit_val = 1;
+    }
+    pthread_mutex_unlock(&g_rule_map_mutex);
+    return bit_val;
+}
\ No newline at end of file
diff --git a/src/lstack/core/lstack_virtio.c b/src/lstack/core/lstack_virtio.c
new file mode 100644
index 0000000..810e343
--- /dev/null
+++ b/src/lstack/core/lstack_virtio.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
+ * gazelle is licensed under the Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *     http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+ * PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+#include <rte_ethdev.h>
+#include "lstack_cfg.h"
+#include "lstack_log.h"
+#include "lstack_port_map.h"
+#include "lstack_virtio.h"
+
+#define VIRTIO_USER_NAME "virtio_user0"
+#define VIRTIO_DPDK_PARA_LEN 256
+#define VIRTIO_TX_RX_RING_SIZE 1024
+
+static struct virtio_instance g_virtio_instance = {0};
+
+struct virtio_instance* virtio_instance_get(void)
+{
+    return &g_virtio_instance;
+}
+
+static int virtio_set_ipv6_addr(void)
+{
+    return 0;
+}
+
+static int virtio_cfg_ip(void)
+{
+    // set ipv4 adr()
+
+    // set ipv6 addr
+    virtio_set_ipv6_addr();
+    return 0;
+}
+
+void virtio_tap_process_rx(uint16_t port, uint32_t queue_id)
+{
+    struct rte_mbuf *pkts_burst[VIRTIO_TX_RX_RING_SIZE];
+    uint16_t lstack_net_port = port;
+    uint32_t pkg_num;
+
+    pkg_num = rte_eth_rx_burst(g_virtio_instance.virtio_port_id, queue_id, pkts_burst, VIRTIO_TX_RX_RING_SIZE);
+    if (pkg_num > 0) {
+        g_virtio_instance.rx_pkg[queue_id] += pkg_num;
+        uint16_t nb_rx = rte_eth_tx_burst(lstack_net_port, queue_id, pkts_burst, pkg_num);
+        for (uint16_t i = nb_rx; i < pkg_num; ++i) {
+            rte_pktmbuf_free(pkts_burst[i]);
+            g_virtio_instance.rx_drop[queue_id]++;
+        }
+    }
+}
+
+void virtio_tap_process_tx(uint16_t queue_id, struct rte_mbuf *mbuf_copy)
+{
+    int tx_num = rte_eth_tx_burst(g_virtio_instance.virtio_port_id, queue_id, &(mbuf_copy), 1);
+    if (tx_num < 0) {
+        rte_pktmbuf_free(mbuf_copy);
+        g_virtio_instance.tx_drop[queue_id]++;
+        LSTACK_LOG(ERR, LSTACK, "virtio_tap_process_tx failed %d, %d\n", queue_id, tx_num);
+    }
+    g_virtio_instance.tx_pkg[queue_id]++;
+}
+
+static int virtio_port_init(uint16_t port)
+{
+    int retval;
+    uint16_t rx_queue_num = g_virtio_instance.rx_queue_num;
+    uint16_t tx_queue_num = g_virtio_instance.tx_queue_num;
+
+    LSTACK_LOG(INFO, LSTACK, "virtio_port_init port= %u rx_queue_num=%u tx_queue_num=%u \n",
+               port, rx_queue_num, tx_queue_num);
+
+    struct rte_eth_conf port_conf;
+    memset(&port_conf, 0, sizeof(struct rte_eth_conf));
+
+    struct rte_eth_dev_info dev_info;
+    retval = rte_eth_dev_info_get(port, &dev_info);
+    if (retval != 0) {
+        LSTACK_LOG(ERR, LSTACK, "rte_eth_dev_info_get failed(port %u) info: %d\n", port, retval);
+        return retval;
+    }
+
+    retval = rte_eth_dev_configure(port, rx_queue_num, tx_queue_num, &port_conf);
+    if (retval != 0) {
+        LSTACK_LOG(ERR, LSTACK, "rte_eth_dev_configure failed retval=%d\n", retval);
+        return retval;
+    }
+
+    for (uint16_t q = 0; q < tx_queue_num; q++) {
+        retval = rte_eth_tx_queue_setup(port, q, VIRTIO_TX_RX_RING_SIZE, rte_eth_dev_socket_id(port), NULL);
+        if (retval < 0) {
+            LSTACK_LOG(ERR, LSTACK, "rte_eth_tx_queue_setup failed (queue %u) retval=%d \n", q, retval);
+            return retval;
+        }
+    }
+
+    for (uint16_t q = 0; q < rx_queue_num; q++) {
+        struct rte_mempool *rxtx_mbuf_pool = get_protocol_stack_group()->total_rxtx_pktmbuf_pool[q];
+        retval = rte_eth_rx_queue_setup(port, q, VIRTIO_TX_RX_RING_SIZE, rte_eth_dev_socket_id(port),
+                                        NULL, rxtx_mbuf_pool);
+        if (retval < 0) {
+            LSTACK_LOG(ERR, LSTACK, "rte_eth_rx_queue_setup failed (queue %u) retval=%d \n", q, retval);
+            return retval;
+        }
+    }
+    return 0;
+}
+
+static int32_t virtio_port_start(uint16_t virtio_port)
+{
+    int retval = 0;
+    if (virtio_port_init(virtio_port) < 0) {
+        LSTACK_LOG(ERR, LSTACK, "virtio_port_init failed \n");
+        return -1;
+    }
+
+    retval = rte_eth_dev_start(virtio_port);
+    if (retval < 0) {
+        LSTACK_LOG(ERR, LSTACK, "rte_eth_dev_start failed retval=%d\n", retval);
+        return retval;
+    }
+
+    if (virtio_cfg_ip() != 0) {
+        LSTACK_LOG(ERR, LSTACK, "virtio_cfg_ip_mac failed\n");
+        return -1;
+    }
+    LSTACK_LOG(INFO, LSTACK, "virtio_user lstack_net_port=%u virtio_port=%u rx_queue_num = %u tx_queue_num = %u\n",
+               g_virtio_instance.lstack_port_id, g_virtio_instance.virtio_port_id,
+               g_virtio_instance.rx_queue_num, g_virtio_instance.tx_queue_num);
+    return 0;
+}
+int virtio_port_create(int lstack_net_port)
+{
+    char portargs[VIRTIO_DPDK_PARA_LEN] = {0};
+
+    struct rte_ether_addr addr;
+    uint16_t virtio_port_id = 0xffff; // invalid val
+
+    struct rte_eth_dev_info dev_info;
+    int ret = rte_eth_dev_info_get(lstack_net_port, &dev_info);
+    if (ret != 0) {
+        LSTACK_LOG(ERR, LSTACK, "get dev info ret=%d\n", ret);
+        return ret;
+    }
+
+    g_virtio_instance.rx_queue_num = dev_info.nb_rx_queues;
+    g_virtio_instance.tx_queue_num = dev_info.nb_tx_queues;
+
+    if (g_virtio_instance.rx_queue_num > VIRTIO_MAX_QUEUE_NUM ||
+        g_virtio_instance.tx_queue_num > VIRTIO_MAX_QUEUE_NUM) {
+        LSTACK_LOG(ERR, LSTACK, "virtio_port_create failed queue_num (%u %u) is bigger than %u\n",
+                   g_virtio_instance.rx_queue_num, g_virtio_instance.tx_queue_num, VIRTIO_MAX_QUEUE_NUM);
+        return -1;
+    }
+
+    int retval = rte_eth_macaddr_get(lstack_net_port, &addr); // virtio_user0'mac is same with lstack.conf MAC addr
+    if (retval != 0) {
+        LSTACK_LOG(ERR, LSTACK, " rte_eth_macaddr_get failed ret = %d\n", retval);
+        return retval;
+    }
+
+    retval = snprintf(portargs, sizeof(portargs),
+                      "path=/dev/vhost-net,queues=%u,queue_size=%u,iface=%s,mac=" RTE_ETHER_ADDR_PRT_FMT,
+                      VIRTIO_MAX_QUEUE_NUM, VIRTIO_TX_RX_RING_SIZE, VIRTIO_USER_NAME, RTE_ETHER_ADDR_BYTES(&addr));
+    if (retval < 0) {
+        LSTACK_LOG(ERR, LSTACK, "virtio portargs snprintf failed ret=%d \n", retval);
+        return retval;
+    }
+    LSTACK_LOG(INFO, LSTACK, "virtio portargs=%s \n", portargs);
+
+    retval = rte_eal_hotplug_add("vdev", VIRTIO_USER_NAME, portargs);
+    if (retval < 0) {
+        LSTACK_LOG(ERR, LSTACK, "rte_eal_hotplug_add failed retval=%d : %s\n", retval, strerror(-retval));
+        return retval;
+    }
+
+    retval = rte_eth_dev_get_port_by_name(VIRTIO_USER_NAME, &virtio_port_id);
+    if (retval != 0) {
+        rte_eal_hotplug_remove("vdev", VIRTIO_USER_NAME);
+        LSTACK_LOG(ERR, LSTACK, "virtio_user0 not found\n");
+        return -1;
+    }
+
+    g_virtio_instance.virtio_port_id = virtio_port_id;
+    g_virtio_instance.lstack_port_id = lstack_net_port;
+
+    retval = virtio_port_start(virtio_port_id);
+    if (retval != 0) {
+        LSTACK_LOG(ERR, LSTACK, "virtio_port_start failed ret=%d\n", retval);
+        rte_eal_hotplug_remove("vdev", VIRTIO_USER_NAME);
+        return retval;
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/src/lstack/include/lstack_port_map.h b/src/lstack/include/lstack_port_map.h
new file mode 100644
index 0000000..24ef53a
--- /dev/null
+++ b/src/lstack/include/lstack_port_map.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
+ * gazelle is licensed under the Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *     http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+ * PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+#ifndef __LSTACK_PORT_MAP_H__
+#define __LSTACK_PORT_MAP_H__
+
+#include <stdint.h>
+
+void port_map_set(uint32_t modBit, int setVal);
+int port_map_get(int bit_index);
+
+#endif
\ No newline at end of file
diff --git a/src/lstack/include/lstack_virtio.h b/src/lstack/include/lstack_virtio.h
new file mode 100644
index 0000000..5e001ca
--- /dev/null
+++ b/src/lstack/include/lstack_virtio.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
+ * gazelle is licensed under the Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ *     http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+ * PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+#ifndef __LSTACK_VIRTIO_H__
+#define __LSTACK_VIRTIO_H__
+
+#include <stdint.h>
+
+#define VIRTIO_MAX_QUEUE_NUM 8
+struct virtio_instance {
+    uint16_t lstack_port_id;
+    uint16_t virtio_port_id;
+    uint16_t rx_queue_num;
+    uint16_t tx_queue_num;
+
+    uint64_t rx_pkg[VIRTIO_MAX_QUEUE_NUM];
+    uint64_t rx_drop[VIRTIO_MAX_QUEUE_NUM];
+    uint64_t tx_pkg[VIRTIO_MAX_QUEUE_NUM];
+    uint64_t tx_drop[VIRTIO_MAX_QUEUE_NUM];
+};
+
+void virtio_tap_process_rx(uint16_t port, uint32_t queue_id);
+void virtio_tap_process_tx(uint16_t queue_id, struct rte_mbuf *mbuf_copy);
+
+int virtio_port_create(int lstack_net_port);
+
+struct virtio_instance* virtio_instance_get(void);
+#endif
\ No newline at end of file
-- 
2.33.0

