diff --git a/0132-add-observable-method-of-data-aggregation.patch b/0132-add-observable-method-of-data-aggregation.patch new file mode 100644 index 0000000..b46fc91 --- /dev/null +++ b/0132-add-observable-method-of-data-aggregation.patch @@ -0,0 +1,62 @@ +From 36d2ddc58cd0f467d6d7682689cc10947a8a1973 Mon Sep 17 00:00:00 2001 +From: yangchen +Date: Tue, 6 Feb 2024 11:29:26 +0800 +Subject: [PATCH] add observable method of data aggregation + +--- + src/common/gazelle_dfx_msg.h | 2 ++ + src/lstack/core/lstack_lwip.c | 2 ++ + src/ltran/ltran_dfx.c | 4 +++- + 3 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/common/gazelle_dfx_msg.h b/src/common/gazelle_dfx_msg.h +index d465efa..1ca210b 100644 +--- a/src/common/gazelle_dfx_msg.h ++++ b/src/common/gazelle_dfx_msg.h +@@ -73,6 +73,8 @@ struct gazelle_stack_stat { + uint64_t tx; + uint64_t tx_prepare_fail; + uint64_t accept_fail; ++ uint64_t sock_rx_drop; ++ uint64_t sock_tx_merge; + }; + + struct gazelle_wakeup_stat { +diff --git a/src/lstack/core/lstack_lwip.c b/src/lstack/core/lstack_lwip.c +index 63044c2..4523907 100644 +--- a/src/lstack/core/lstack_lwip.c ++++ b/src/lstack/core/lstack_lwip.c +@@ -541,6 +541,7 @@ static ssize_t do_lwip_fill_sendring(struct lwip_sock *sock, const void *buf, si + + /* merge data into last pbuf */ + if (!NETCONN_IS_UDP(sock) && sock->remain_len) { ++ sock->stack->stats.sock_tx_merge++; + send_len = merge_data_lastpbuf(sock, (char *)buf, len); + if (send_len >= len) { + send_len = len; +@@ -1039,6 +1040,7 @@ ssize_t do_lwip_read_from_stack(int32_t fd, void *buf, size_t len, int32_t flags + + /* in udp, if pbuf remaining len less than copy_len, discard these packets */ + if (recvd > 0 && NETCONN_IS_UDP(sock)) { ++ sock->stack->stats.sock_rx_drop++; + break; + } + } +diff --git a/src/ltran/ltran_dfx.c b/src/ltran/ltran_dfx.c +index 4b246a1..9f12096 100644 +--- a/src/ltran/ltran_dfx.c ++++ b/src/ltran/ltran_dfx.c +@@ -648,7 +648,9 @@ static void show_lstack_stats(struct gazelle_stack_dfx_data *lstack_stat) + printf("send_pkts_fail: %-13"PRIu64" ", lstack_stat->data.pkts.stack_stat.send_pkts_fail); + printf("mbuf_pool_freecnt: %-10"PRIu32" ", lstack_stat->data.pkts.mbufpool_avail_cnt); + printf("rpc_pool_freecnt: %-12"PRIu32" \n", lstack_stat->data.pkts.rpcpool_avail_cnt); +- printf("accpet_fail: %-12"PRIu64" \n", lstack_stat->data.pkts.stack_stat.accept_fail); ++ printf("accpet_fail: %-16"PRIu64" ", lstack_stat->data.pkts.stack_stat.accept_fail); ++ printf("sock_rx_drop: %-15"PRIu64" ", lstack_stat->data.pkts.stack_stat.sock_rx_drop); ++ printf("sock_tx_merge: %-16"PRIu64" \n", lstack_stat->data.pkts.stack_stat.sock_tx_merge); + } + + static void gazelle_print_lstack_stat_detail(struct gazelle_stack_dfx_data *lstack_stat, +-- +2.27.0 + diff --git a/0133-try-to-ensure-arp-packet-can-be-sent.patch b/0133-try-to-ensure-arp-packet-can-be-sent.patch new file mode 100644 index 0000000..ef48dd5 --- /dev/null +++ b/0133-try-to-ensure-arp-packet-can-be-sent.patch @@ -0,0 +1,191 @@ +From 1a7bb2f60a459c2cca6646ccbe04a52fcd8272f6 Mon Sep 17 00:00:00 2001 +From: jiangheng +Date: Wed, 31 Jan 2024 14:49:40 +0800 +Subject: [PATCH] try to ensure arp packet can be sent + +--- + src/lstack/core/lstack_dpdk.c | 18 ++++++++++-------- + src/lstack/core/lstack_lwip.c | 13 ++++++++++--- + src/lstack/core/lstack_protocol_stack.c | 4 ++-- + src/lstack/include/lstack_dpdk.h | 2 +- + src/lstack/include/lstack_protocol_stack.h | 2 +- + src/lstack/netif/lstack_ethdev.c | 8 ++++---- + src/lstack/netif/lstack_vdev.c | 2 +- + 7 files changed, 29 insertions(+), 20 deletions(-) + +diff --git a/src/lstack/core/lstack_dpdk.c b/src/lstack/core/lstack_dpdk.c +index e352850..74e033b 100644 +--- a/src/lstack/core/lstack_dpdk.c ++++ b/src/lstack/core/lstack_dpdk.c +@@ -280,14 +280,16 @@ int32_t create_shared_ring(struct protocol_stack *stack) + return 0; + } + +-int32_t dpdk_alloc_pktmbuf(struct rte_mempool *pool, struct rte_mbuf **mbufs, uint32_t num) ++int32_t dpdk_alloc_pktmbuf(struct rte_mempool *pool, struct rte_mbuf **mbufs, uint32_t num, bool reserve) + { +- /* +- * don't use rte_mempool_avail_count, it traverse cpu local cache, +- * when RTE_MAX_LCORE is too large, it's time-consuming +- */ +- if (rte_ring_count(pool->pool_data) < MBUFPOOL_RESERVE_NUM + num) { +- return -ENOMEM; ++ if (reserve) { ++ /* ++ * don't use rte_mempool_avail_count, it traverse cpu local cache, ++ * when RTE_MAX_LCORE is too large, it's time-consuming ++ */ ++ if (rte_ring_count(pool->pool_data) < MBUFPOOL_RESERVE_NUM + num) { ++ return -ENOMEM; ++ } + } + + int32_t ret = rte_pktmbuf_alloc_bulk(pool, mbufs, num); +@@ -310,7 +312,7 @@ int32_t fill_mbuf_to_ring(struct rte_mempool *mempool, struct rte_ring *ring, ui + while (remain > 0) { + batch = LWIP_MIN(remain, RING_SIZE(FREE_RX_QUEUE_SZ)); + +- ret = dpdk_alloc_pktmbuf(mempool, free_buf, batch); ++ ret = dpdk_alloc_pktmbuf(mempool, free_buf, batch, true); + if (ret != 0) { + LSTACK_LOG(ERR, LSTACK, "cannot alloc mbuf for ring, count: %u ret=%d\n", batch, ret); + return -1; +diff --git a/src/lstack/core/lstack_lwip.c b/src/lstack/core/lstack_lwip.c +index 3f76424..da50fec 100644 +--- a/src/lstack/core/lstack_lwip.c ++++ b/src/lstack/core/lstack_lwip.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -101,7 +102,6 @@ static struct pbuf *init_mbuf_to_pbuf(struct rte_mbuf *mbuf, pbuf_layer layer, u + struct pbuf *pbuf = pbuf_alloced_custom(layer, length, type, pbuf_custom, data, MAX_PACKET_SZ); + if (pbuf) { + pbuf->allow_in = 1; +- pbuf->last = pbuf; + pbuf->addr = *IP_ANY_TYPE; + pbuf->port = 0; + pthread_spin_init(&pbuf->pbuf_lock, PTHREAD_PROCESS_SHARED); +@@ -122,7 +122,7 @@ static bool replenish_send_idlembuf(struct protocol_stack *stack, struct lwip_so + return false; + } + +- if (dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, (struct rte_mbuf **)pbuf, replenish_cnt) != 0) { ++ if (dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, (struct rte_mbuf **)pbuf, replenish_cnt, true) != 0) { + stack->stats.tx_allocmbuf_fail++; + return true; + } +@@ -209,10 +209,17 @@ void do_lwip_free_pbuf(struct pbuf *pbuf) + + struct pbuf *do_lwip_alloc_pbuf(pbuf_layer layer, uint16_t length, pbuf_type type) + { ++ int ret; + struct rte_mbuf *mbuf; + struct protocol_stack *stack = get_protocol_stack(); + +- if (dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf, 1) != 0) { ++ /* ensure arp packet can be sent */ ++ if (layer == PBUF_LINK && length == SIZEOF_ETHARP_HDR) { ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf, 1, false); ++ } else { ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf, 1, true); ++ } ++ if (ret != 0) { + stack->stats.tx_allocmbuf_fail++; + return NULL; + } +diff --git a/src/lstack/core/lstack_protocol_stack.c b/src/lstack/core/lstack_protocol_stack.c +index 8b99e82..cb39928 100644 +--- a/src/lstack/core/lstack_protocol_stack.c ++++ b/src/lstack/core/lstack_protocol_stack.c +@@ -940,7 +940,7 @@ void stack_broadcast_arp(struct rte_mbuf *mbuf, struct protocol_stack *cur_stack + continue; + } + +- ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1); ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); + if (ret != 0) { + stack->stats.rx_allocmbuf_fail++; + return; +@@ -952,7 +952,7 @@ void stack_broadcast_arp(struct rte_mbuf *mbuf, struct protocol_stack *cur_stack + return; + } + } +- ret = dpdk_alloc_pktmbuf(cur_stack->rxtx_mbuf_pool, &mbuf_copy, 1); ++ ret = dpdk_alloc_pktmbuf(cur_stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); + if (ret != 0) { + cur_stack->stats.rx_allocmbuf_fail++; + return; +diff --git a/src/lstack/include/lstack_dpdk.h b/src/lstack/include/lstack_dpdk.h +index b39d199..c40f3c0 100644 +--- a/src/lstack/include/lstack_dpdk.h ++++ b/src/lstack/include/lstack_dpdk.h +@@ -56,6 +56,6 @@ struct rte_mempool *create_pktmbuf_mempool(const char *name, uint32_t nb_mbuf, + uint32_t mbuf_cache_size, uint16_t queue_id, unsigned numa_id); + + void dpdk_nic_xstats_get(struct gazelle_stack_dfx_data *dfx, uint16_t port_id); +-int32_t dpdk_alloc_pktmbuf(struct rte_mempool *pool, struct rte_mbuf **mbufs, uint32_t num); ++int32_t dpdk_alloc_pktmbuf(struct rte_mempool *pool, struct rte_mbuf **mbufs, uint32_t num, bool reserve); + void dpdk_nic_features_get(struct gazelle_stack_dfx_data *dfx, uint16_t port_id); + #endif /* GAZELLE_DPDK_H */ +diff --git a/src/lstack/include/lstack_protocol_stack.h b/src/lstack/include/lstack_protocol_stack.h +index c681547..0a523b7 100644 +--- a/src/lstack/include/lstack_protocol_stack.h ++++ b/src/lstack/include/lstack_protocol_stack.h +@@ -31,7 +31,7 @@ + #define SOCK_SEND_REPLENISH_THRES (16) + #define WAKEUP_MAX_NUM (32) + +-#define MBUFPOOL_RESERVE_NUM 5000 ++#define MBUFPOOL_RESERVE_NUM (get_global_cfg_params()->nic.rxqueue_size + 1024) + + struct rte_mempool; + struct rte_ring; +diff --git a/src/lstack/netif/lstack_ethdev.c b/src/lstack/netif/lstack_ethdev.c +index 4d6f620..acf3c10 100644 +--- a/src/lstack/netif/lstack_ethdev.c ++++ b/src/lstack/netif/lstack_ethdev.c +@@ -543,9 +543,9 @@ void parse_arp_and_transefer(char* buf) + int32_t ret; + for (int32_t i = 0; i < stack_group->stack_num; i++) { + stack = stack_group->stacks[i]; +- ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1); ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); + while (ret != 0) { +- ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1); ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); + stack->stats.rx_allocmbuf_fail++; + } + copy_mbuf(mbuf_copy, mbuf); +@@ -572,9 +572,9 @@ void parse_tcp_and_transefer(char* buf) + struct rte_mbuf *mbuf_copy = NULL; + struct protocol_stack *stack = stack_group->stacks[stk_index]; + +- int32_t ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1); ++ int32_t ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); + while (ret != 0) { +- ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1); ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); + stack->stats.rx_allocmbuf_fail++; + } + +diff --git a/src/lstack/netif/lstack_vdev.c b/src/lstack/netif/lstack_vdev.c +index fe17f59..f78e48a 100644 +--- a/src/lstack/netif/lstack_vdev.c ++++ b/src/lstack/netif/lstack_vdev.c +@@ -59,7 +59,7 @@ static uint32_t ltran_rx_poll(struct protocol_stack *stack, struct rte_mbuf **pk + stack->rx_ring_used += rcvd_pkts; + if (unlikely(stack->rx_ring_used >= USED_RX_PKTS_WATERMARK)) { + uint32_t free_cnt = LWIP_MIN(stack->rx_ring_used, RING_SIZE(DPDK_PKT_BURST_SIZE)); +- int32_t ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, (struct rte_mbuf **)free_buf, free_cnt); ++ int32_t ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, (struct rte_mbuf **)free_buf, free_cnt, true); + if (likely(ret == 0)) { + nr_pkts = gazelle_ring_sp_enqueue(stack->rx_ring, (void **)free_buf, free_cnt); + stack->rx_ring_used -= nr_pkts; +-- +2.27.0 + diff --git a/0134-gazellectl-support-send-latency-show.patch b/0134-gazellectl-support-send-latency-show.patch new file mode 100644 index 0000000..5950ca7 --- /dev/null +++ b/0134-gazellectl-support-send-latency-show.patch @@ -0,0 +1,345 @@ +From 03eabf12b7d486278598ad44d2b7d8e310ff0abf Mon Sep 17 00:00:00 2001 +From: yangchen +Date: Sun, 4 Feb 2024 13:29:15 +0800 +Subject: [PATCH] gazellectl: support send latency show + +--- + src/common/dpdk_common.h | 10 +++ + src/common/gazelle_dfx_msg.h | 20 ++++- + src/lstack/core/lstack_lwip.c | 14 +++- + src/lstack/core/lstack_stack_stat.c | 15 ++-- + src/lstack/netif/lstack_ethdev.c | 4 + + src/ltran/ltran_dfx.c | 110 +++++++++++++++------------- + 6 files changed, 111 insertions(+), 62 deletions(-) + +diff --git a/src/common/dpdk_common.h b/src/common/dpdk_common.h +index 38f09ae..a79a0f2 100644 +--- a/src/common/dpdk_common.h ++++ b/src/common/dpdk_common.h +@@ -95,6 +95,16 @@ static __rte_always_inline void time_stamp_into_mbuf(uint32_t rx_count, struct r + } + } + ++static __rte_always_inline void time_stamp_into_pbuf(uint32_t tx_count, struct pbuf *buf[], uint64_t time_stamp) ++{ ++ struct latency_timestamp *lt; ++ for (uint32_t i = 0; i < tx_count; i++) { ++ lt = &pbuf_to_private(buf[i])->lt; ++ lt->stamp = time_stamp; ++ lt->check = ~(time_stamp); ++ } ++} ++ + bool get_kni_started(void); + struct rte_kni* get_gazelle_kni(void); + int32_t dpdk_kni_init(uint16_t port, struct rte_mempool *pool); +diff --git a/src/common/gazelle_dfx_msg.h b/src/common/gazelle_dfx_msg.h +index d465efa..d47ed9a 100644 +--- a/src/common/gazelle_dfx_msg.h ++++ b/src/common/gazelle_dfx_msg.h +@@ -24,6 +24,10 @@ + /* maybe it should be consistent with MEMP_NUM_TCP_PCB */ + #define GAZELLE_LSTACK_MAX_CONN (20000 + 2000) // same as MAX_CLIENTS + RESERVED_CLIENTS in lwipopts.h + ++#define GAZELLE_RESULT_LEN 4096 ++#define GAZELLE_MAX_LATENCY_TIME 1800 // max latency time 30mins ++#define GAZELLE_RESULT_LINE_LEN 80 // for a single row, the max len of result is 80 ++ + enum GAZELLE_STAT_MODE { + GAZELLE_STAT_LTRAN_SHOW = 0, + GAZELLE_STAT_LTRAN_SHOW_RATE, +@@ -54,8 +58,11 @@ enum GAZELLE_STAT_MODE { + }; + + enum GAZELLE_LATENCY_TYPE { +- GAZELLE_LATENCY_LWIP, +- GAZELLE_LATENCY_READ, ++ GAZELLE_LATENCY_READ_LWIP, ++ GAZELLE_LATENCY_READ_LSTACK, ++ GAZELLE_LATENCY_WRITE_LWIP, ++ GAZELLE_LATENCY_WRITE_LSTACK, ++ GAZELLE_LATENCY_MAX, + }; + + struct gazelle_stack_stat { +@@ -216,9 +223,14 @@ struct stack_latency { + uint64_t latency_total; + }; + ++struct gazelle_latency_result { ++ int latency_stat_index; ++ struct stack_latency latency_stat_record; ++ char latency_stat_result[GAZELLE_RESULT_LEN]; ++}; ++ + struct gazelle_stack_latency { +- struct stack_latency read_latency; +- struct stack_latency lwip_latency; ++ struct stack_latency latency[GAZELLE_LATENCY_MAX]; + uint64_t start_time; + uint64_t g_cycles_per_us; + }; +diff --git a/src/lstack/core/lstack_lwip.c b/src/lstack/core/lstack_lwip.c +index 22605dd..be2c6de 100644 +--- a/src/lstack/core/lstack_lwip.c ++++ b/src/lstack/core/lstack_lwip.c +@@ -244,6 +244,11 @@ struct pbuf *do_lwip_get_from_sendring(struct lwip_sock *sock, uint16_t remain_s + if (pbuf == NULL) { + return NULL; + } ++ ++ if (get_protocol_stack_group()->latency_start) { ++ calculate_lstack_latency(&sock->stack->latency, pbuf, GAZELLE_LATENCY_WRITE_LWIP); ++ } ++ + sock->send_pre_del = pbuf; + + if (!gazelle_ring_readover_count(sock->send_ring)) { +@@ -303,6 +308,11 @@ static inline ssize_t app_buff_write(struct lwip_sock *sock, void *buf, size_t l + + (void)gazelle_ring_read(sock->send_ring, (void **)pbufs, write_num); + ++ if (get_protocol_stack_group()->latency_start) { ++ uint64_t time_stamp = get_current_time(); ++ time_stamp_into_pbuf(write_num, pbufs, time_stamp); ++ } ++ + ssize_t send_len = do_app_write(pbufs, buf, len, write_num); + + if (addr) { +@@ -573,7 +583,7 @@ ssize_t do_lwip_read_from_lwip(struct lwip_sock *sock, int32_t flags, u8_t apifl + + for (uint32_t i = 0; get_protocol_stack_group()->latency_start && i < read_count; i++) { + if (pbufs[i] != NULL) { +- calculate_lstack_latency(&sock->stack->latency, pbufs[i], GAZELLE_LATENCY_LWIP); ++ calculate_lstack_latency(&sock->stack->latency, pbufs[i], GAZELLE_LATENCY_READ_LWIP); + } + } + +@@ -895,7 +905,7 @@ ssize_t do_lwip_read_from_stack(int32_t fd, void *buf, size_t len, int32_t flags + sock->wakeup->stat.app_read_cnt += 1; + } + if (latency_enable) { +- calculate_lstack_latency(&sock->stack->latency, pbuf, GAZELLE_LATENCY_READ); ++ calculate_lstack_latency(&sock->stack->latency, pbuf, GAZELLE_LATENCY_READ_LSTACK); + } + gazelle_ring_read_over(sock->recv_ring); + +diff --git a/src/lstack/core/lstack_stack_stat.c b/src/lstack/core/lstack_stack_stat.c +index 23571b4..cb11dc3 100644 +--- a/src/lstack/core/lstack_stack_stat.c ++++ b/src/lstack/core/lstack_stack_stat.c +@@ -53,8 +53,9 @@ void calculate_lstack_latency(struct gazelle_stack_latency *stack_latency, const + { + uint64_t latency; + const struct latency_timestamp *lt; ++ struct stack_latency *latency_stat; + +- if (pbuf == NULL) { ++ if (pbuf == NULL || type >= GAZELLE_LATENCY_MAX) { + return; + } + +@@ -62,10 +63,9 @@ void calculate_lstack_latency(struct gazelle_stack_latency *stack_latency, const + if (lt->stamp != ~(lt->check) || lt->stamp < stack_latency->start_time) { + return; + } +- latency = get_current_time() - lt->stamp; + +- struct stack_latency *latency_stat = (type == GAZELLE_LATENCY_LWIP) ? +- &stack_latency->lwip_latency : &stack_latency->read_latency; ++ latency = get_current_time() - lt->stamp; ++ latency_stat = &stack_latency->latency[type]; + + latency_stat->latency_total += latency; + latency_stat->latency_max = (latency_stat->latency_max > latency) ? latency_stat->latency_max : latency; +@@ -118,8 +118,11 @@ static void set_latency_start_flag(bool start) + LSTACK_LOG(ERR, LSTACK, "memset_s faile\n"); + } + stack->latency.start_time = get_current_time(); +- stack->latency.lwip_latency.latency_min = ~((uint64_t)0); +- stack->latency.read_latency.latency_min = ~((uint64_t)0); ++ ++ for (uint32_t j = 0; j < GAZELLE_LATENCY_MAX; j++) { ++ stack->latency.latency[j].latency_min = ~((uint64_t)0); ++ } ++ + memset_s(&stack->aggregate_stats, sizeof(struct gazelle_stack_aggregate_stats), + 0, sizeof(stack->aggregate_stats)); + } +diff --git a/src/lstack/netif/lstack_ethdev.c b/src/lstack/netif/lstack_ethdev.c +index 4d6f620..94ecffc 100644 +--- a/src/lstack/netif/lstack_ethdev.c ++++ b/src/lstack/netif/lstack_ethdev.c +@@ -889,6 +889,10 @@ static err_t eth_dev_output(struct netif *netif, struct pbuf *pbuf) + + pre_mbuf = mbuf; + rte_mbuf_refcnt_update(mbuf, 1); ++ ++ if (get_protocol_stack_group()->latency_start) { ++ calculate_lstack_latency(&stack->latency, pbuf, GAZELLE_LATENCY_WRITE_LSTACK); ++ } + pbuf = pbuf->next; + } + +diff --git a/src/ltran/ltran_dfx.c b/src/ltran/ltran_dfx.c +index 4b246a1..ecdb5f9 100644 +--- a/src/ltran/ltran_dfx.c ++++ b/src/ltran/ltran_dfx.c +@@ -50,9 +50,6 @@ + #define GAZELLE_CMD_MAX 5 + #define CMD_WAIT_TIME 1 // sec + +-#define GAZELLE_RESULT_LEN 8291 +-#define GAZELLE_MAX_LATENCY_TIME 1800 // max latency time 30mins +- + #define GAZELLE_DECIMAL 10 + #define GAZELLE_KEEPALIVE_STR_LEN 35 + #define GAZELLE_TIME_STR_LEN 25 +@@ -702,8 +699,8 @@ static void parse_thread_latency_result(const struct stack_latency *latency, cha + { + if (latency->latency_pkts > 0) { + *pos += sprintf_s(result + *pos, max_len, "%-8"PRIu64" ", latency->latency_pkts); +- *pos += sprintf_s(result + *pos, max_len, "%-6"PRIu64" ", latency->latency_min); +- *pos += sprintf_s(result + *pos, max_len, "%-6"PRIu64" ", latency->latency_max); ++ *pos += sprintf_s(result + *pos, max_len, "%-8"PRIu64" ", latency->latency_min); ++ *pos += sprintf_s(result + *pos, max_len, "%-8"PRIu64" ", latency->latency_max); + *pos += sprintf_s(result + *pos, max_len, "%-6.2f \n", + (double)latency->latency_total / latency->latency_pkts); + } else { +@@ -719,52 +716,53 @@ static void parse_thread_latency_result(const struct stack_latency *latency, cha + static void parse_latency_total_result(char *result, size_t max_len, int32_t *pos, + const struct stack_latency *record) + { ++ if (max_len < GAZELLE_RESULT_LINE_LEN) { ++ printf("total latency result show failed, out of memory bounds\n"); ++ return; ++ } ++ + if (record->latency_pkts > 0) { +- *pos += sprintf_s(result + *pos, max_len, " total: "); ++ *pos += sprintf_s(result + *pos, max_len, " total: "); + *pos += sprintf_s(result + *pos, max_len, "%-8"PRIu64" ", record->latency_pkts); +- *pos += sprintf_s(result + *pos, max_len, "%-6"PRIu64" ", record->latency_min); +- *pos += sprintf_s(result + *pos, max_len, "%-6"PRIu64" ", record->latency_max); +- *pos += sprintf_s(result + *pos, max_len, "%-6.2f \n\n\n", ++ *pos += sprintf_s(result + *pos, max_len, "%-8"PRIu64" ", record->latency_min); ++ *pos += sprintf_s(result + *pos, max_len, "%-8"PRIu64" ", record->latency_max); ++ *pos += sprintf_s(result + *pos, max_len, "%-6.2f \n\n", + (double)record->latency_total / record->latency_pkts); + } else { +- *pos += sprintf_s(result + *pos, max_len, " total: 0\n\n\n"); ++ *pos += sprintf_s(result + *pos, max_len, " total: 0\n\n"); + } + } + +-static void gazelle_print_lstack_stat_latency(void *buf, const struct gazelle_stat_msg_request *req_msg) ++static void gazelle_show_latency_result(const struct gazelle_stat_msg_request *req_msg, ++ struct gazelle_stack_dfx_data *stat, struct stack_latency *latency, ++ struct gazelle_latency_result *res) + { +- struct gazelle_stack_dfx_data *stat = (struct gazelle_stack_dfx_data *)buf; +- struct gazelle_stack_latency *latency = &stat->data.latency; +- int32_t ret = GAZELLE_OK; +- int32_t lwip_index = 0; +- int32_t read_index = 0; +- struct stack_latency lwip_record = {0}; +- struct stack_latency read_record = {0}; +- char str_ip[GAZELLE_SUBNET_LENGTH_MAX] = {0}; ++ char str_ip[GAZELLE_SUBNET_LENGTH_MAX] = { 0 }; + +- read_record.latency_min = ~((uint64_t)0); +- lwip_record.latency_min = ~((uint64_t)0); +- +- char *lwip_result = calloc(GAZELLE_RESULT_LEN, sizeof(char)); +- if (lwip_result == NULL) { +- return; +- } +- char *read_result = calloc(GAZELLE_RESULT_LEN, sizeof(char)); +- if (read_result == NULL) { +- free(lwip_result); ++ if (GAZELLE_RESULT_LEN - res->latency_stat_index < GAZELLE_RESULT_LINE_LEN) { ++ printf("too many threads show latency result, out of memory bounds\n"); + return; + } + +- do { +- lwip_index += sprintf_s(lwip_result + lwip_index, (size_t)(GAZELLE_RESULT_LEN - lwip_index), +- "ip: %-15s tid: %-8u ", inet_ntop(AF_INET, &req_msg->ip, str_ip, sizeof(str_ip)), stat->tid); +- parse_thread_latency_result(&latency->lwip_latency, lwip_result, (size_t)(GAZELLE_RESULT_LEN - lwip_index), +- &lwip_index, &lwip_record); ++ res->latency_stat_index += sprintf_s(res->latency_stat_result + res->latency_stat_index, ++ (size_t)(GAZELLE_RESULT_LEN - res->latency_stat_index), "ip: %-15s tid: %-8u ", ++ inet_ntop(AF_INET, &req_msg->ip, str_ip, sizeof(str_ip)), stat->tid); + +- read_index += sprintf_s(read_result + read_index, (size_t)(GAZELLE_RESULT_LEN - read_index), +- "ip: %-15s tid: %-8u ", inet_ntop(AF_INET, &req_msg->ip, str_ip, sizeof(str_ip)), stat->tid); +- parse_thread_latency_result(&latency->read_latency, read_result, (size_t)(GAZELLE_RESULT_LEN - read_index), +- &read_index, &read_record); ++ parse_thread_latency_result(latency, res->latency_stat_result, ++ (size_t)(GAZELLE_RESULT_LEN - res->latency_stat_index), &res->latency_stat_index, &res->latency_stat_record); ++} ++ ++static void gazelle_show_latency_result_total(void *buf, const struct gazelle_stat_msg_request *req_msg, ++ struct gazelle_latency_result *res) ++{ ++ int ret = GAZELLE_OK; ++ struct gazelle_stack_dfx_data *stat = (struct gazelle_stack_dfx_data *)buf; ++ struct gazelle_stack_latency *latency = &stat->data.latency; ++ ++ do { ++ for (int i = 0; i < GAZELLE_LATENCY_MAX; i++) { ++ gazelle_show_latency_result(req_msg, stat, &latency->latency[i], &res[i]); ++ } + + if ((stat->eof != 0) || (ret != GAZELLE_OK)) { + break; +@@ -772,21 +770,33 @@ static void gazelle_print_lstack_stat_latency(void *buf, const struct gazelle_st + ret = dfx_stat_read_from_ltran(buf, sizeof(struct gazelle_stack_dfx_data), req_msg->stat_mode); + } while (true); + +- parse_latency_total_result(lwip_result, (size_t)(GAZELLE_RESULT_LEN - lwip_index), &lwip_index, &lwip_record); +- parse_latency_total_result(read_result, (size_t)(GAZELLE_RESULT_LEN - read_index), &read_index, &read_record); ++ for (int i = 0; i < GAZELLE_LATENCY_MAX; i++) { ++ parse_latency_total_result(res[i].latency_stat_result, (size_t)(GAZELLE_RESULT_LEN - res[i].latency_stat_index), ++ &res[i].latency_stat_index, &res[i].latency_stat_record); ++ } ++} ++ ++static void gazelle_print_lstack_stat_latency(void *buf, const struct gazelle_stat_msg_request *req_msg) ++{ ++ struct gazelle_latency_result *res = calloc(GAZELLE_LATENCY_MAX, sizeof(struct gazelle_latency_result)); ++ if (res == NULL) { ++ return; ++ } ++ ++ for (int i = 0; i < GAZELLE_LATENCY_MAX; i++) { ++ res[i].latency_stat_record.latency_min = ~((uint64_t)0); ++ } + +- printf("Statistics of lstack latency: t0--->t3 \ +- (t0:read form nic t1:into lstask queue t2:into app queue t3:app read)\n"); +- printf(" pkts min(us) max(us) average(us)\n%s", +- read_result); ++ gazelle_show_latency_result_total(buf, req_msg, res); + +- printf("Statistics of lstack latency: t0--->t2 \ +- (t0:read form nic t1:into lstask queue t2:into app queue t3:app read)\n"); +- printf(" pkts min(us) max(us) average(us)\n%s", +- lwip_result); ++ printf("Statistics of lstack latency pkts min(us) max(us) average(us)\n"); ++ printf("range: t0--->t3\n%s", res[GAZELLE_LATENCY_READ_LSTACK].latency_stat_result); ++ printf("range: t0--->t2\n%s", res[GAZELLE_LATENCY_READ_LWIP].latency_stat_result); ++ printf("range: t3--->t0\n%s", res[GAZELLE_LATENCY_WRITE_LSTACK].latency_stat_result); ++ printf("range: t2--->t0\n%s", res[GAZELLE_LATENCY_WRITE_LWIP].latency_stat_result); ++ printf("t0:read form/send to nic t1:into/out of lstask queue t2:into/out of app queue t3:app read/send\n"); + +- free(read_result); +- free(lwip_result); ++ free(res); + } + + static void gazelle_print_lstack_stat_lpm(void *buf, const struct gazelle_stat_msg_request *req_msg) +-- +2.27.0 + diff --git a/0135-rpc-function-does-not-depend-on-protocol-stack.patch b/0135-rpc-function-does-not-depend-on-protocol-stack.patch new file mode 100644 index 0000000..1ca8ca5 --- /dev/null +++ b/0135-rpc-function-does-not-depend-on-protocol-stack.patch @@ -0,0 +1,1336 @@ +From fe39b43f897be7d29f9b51e79d51395e43b83e23 Mon Sep 17 00:00:00 2001 +From: jiangheng +Date: Sun, 4 Feb 2024 19:46:17 +0800 +Subject: [PATCH] rpc function does not depend on protocol stack diff rpc queue + and dfx rpc queue + +--- + src/common/gazelle_dfx_msg.h | 1 - + src/lstack/api/lstack_rtw_api.c | 36 ++- + src/lstack/core/lstack_control_plane.c | 10 +- + src/lstack/core/lstack_dpdk.c | 4 +- + src/lstack/core/lstack_lwip.c | 2 +- + src/lstack/core/lstack_protocol_stack.c | 92 ++++---- + src/lstack/core/lstack_stack_stat.c | 18 +- + src/lstack/core/lstack_thread_rpc.c | 241 ++++++++------------- + src/lstack/include/lstack_control_plane.h | 3 - + src/lstack/include/lstack_protocol_stack.h | 36 +-- + src/lstack/include/lstack_rpc_proc.h | 46 ++++ + src/lstack/include/lstack_thread_rpc.h | 79 +++---- + src/lstack/netif/lstack_ethdev.c | 6 +- + src/ltran/ltran_dfx.c | 3 +- + 14 files changed, 292 insertions(+), 285 deletions(-) + create mode 100644 src/lstack/include/lstack_rpc_proc.h + +diff --git a/src/common/gazelle_dfx_msg.h b/src/common/gazelle_dfx_msg.h +index 1ca210b..a91a30f 100644 +--- a/src/common/gazelle_dfx_msg.h ++++ b/src/common/gazelle_dfx_msg.h +@@ -101,7 +101,6 @@ struct gazelle_stack_aggregate_stats { + struct gazelle_stat_pkts { + uint16_t conn_num; + uint32_t mbufpool_avail_cnt; +- uint32_t rpcpool_avail_cnt; + uint64_t call_msg_cnt; + uint64_t recv_list_cnt; + uint64_t call_alloc_fail; +diff --git a/src/lstack/api/lstack_rtw_api.c b/src/lstack/api/lstack_rtw_api.c +index 10bc613..8498b8e 100644 +--- a/src/lstack/api/lstack_rtw_api.c ++++ b/src/lstack/api/lstack_rtw_api.c +@@ -28,7 +28,11 @@ + + int rtw_socket(int domain, int type, int protocol) + { +- return rpc_call_socket(domain, type, protocol); ++ struct protocol_stack *stack = get_bind_protocol_stack(); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EINVAL); ++ } ++ return rpc_call_socket(&stack->rpc_queue, domain, type, protocol); + } + + int rtw_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +@@ -64,27 +68,47 @@ int rtw_listen(int s, int backlog) + + int rtw_connect(int s, const struct sockaddr *name, socklen_t namelen) + { +- return rpc_call_connect(s, name, namelen); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(s); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EBADF); ++ } ++ return rpc_call_connect(&stack->rpc_queue, s, name, namelen); + } + + int rtw_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) + { +- return rpc_call_setsockopt(s, level, optname, optval, optlen); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(s); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EBADF); ++ } ++ return rpc_call_setsockopt(&stack->rpc_queue, s, level, optname, optval, optlen); + } + + int rtw_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) + { +- return rpc_call_getsockopt(s, level, optname, optval, optlen); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(s); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EBADF); ++ } ++ return rpc_call_getsockopt(&stack->rpc_queue, s, level, optname, optval, optlen); + } + + int rtw_getpeername(int s, struct sockaddr *name, socklen_t *namelen) + { +- return rpc_call_getpeername(s, name, namelen); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(s); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EBADF); ++ } ++ return rpc_call_getpeername(&stack->rpc_queue, s, name, namelen); + } + + int rtw_getsockname(int s, struct sockaddr *name, socklen_t *namelen) + { +- return rpc_call_getsockname(s, name, namelen); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(s); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EBADF); ++ } ++ return rpc_call_getsockname(&stack->rpc_queue, s, name, namelen); + } + + ssize_t rtw_read(int s, void *mem, size_t len) +diff --git a/src/lstack/core/lstack_control_plane.c b/src/lstack/core/lstack_control_plane.c +index a9a3814..025291d 100644 +--- a/src/lstack/core/lstack_control_plane.c ++++ b/src/lstack/core/lstack_control_plane.c +@@ -611,9 +611,10 @@ static int32_t thread_register(void) + /* register all connected conn before listen conn, avoid creating new conn */ + struct protocol_stack_group *stack_group = get_protocol_stack_group(); + for (int32_t i = 0; i < stack_group->stack_num; i++) { +- conn->conn_num = rpc_call_conntable(stack_group->stacks[i], conn->conn_list, GAZELLE_LSTACK_MAX_CONN); ++ conn->conn_num = rpc_call_conntable(&stack_group->stacks[i]->rpc_queue, ++ conn->conn_list, GAZELLE_LSTACK_MAX_CONN); + +- ret = rpc_call_thread_regphase1(stack_group->stacks[i], conn); ++ ret = rpc_call_thread_regphase1(&stack_group->stacks[i]->rpc_queue, conn); + if (ret != 0) { + LSTACK_LOG(ERR, LSTACK, "thread_register_phase1 failed ret=%d!\n", ret); + free(conn); +@@ -622,9 +623,10 @@ static int32_t thread_register(void) + } + + for (int32_t i = 0; i < stack_group->stack_num; i++) { +- conn->conn_num = rpc_call_conntable(stack_group->stacks[i], conn->conn_list, GAZELLE_LSTACK_MAX_CONN); ++ conn->conn_num = rpc_call_conntable(&stack_group->stacks[i]->rpc_queue, ++ conn->conn_list, GAZELLE_LSTACK_MAX_CONN); + +- ret = rpc_call_thread_regphase2(stack_group->stacks[i], conn); ++ ret = rpc_call_thread_regphase2(&stack_group->stacks[i]->rpc_queue, conn); + if (ret != 0) { + LSTACK_LOG(ERR, LSTACK, "thread_register_phase2 failed ret=%d!\n", ret); + free(conn); +diff --git a/src/lstack/core/lstack_dpdk.c b/src/lstack/core/lstack_dpdk.c +index e352850..985f1a5 100644 +--- a/src/lstack/core/lstack_dpdk.c ++++ b/src/lstack/core/lstack_dpdk.c +@@ -45,7 +45,6 @@ + + #include "lstack_log.h" + #include "dpdk_common.h" +-#include "lstack_lockless_queue.h" + #include "lstack_protocol_stack.h" + #include "lstack_thread_rpc.h" + #include "lstack_lwip.h" +@@ -258,7 +257,8 @@ struct rte_mempool *create_mempool(const char *name, uint32_t count, uint32_t si + + int32_t create_shared_ring(struct protocol_stack *stack) + { +- lockless_queue_init(&stack->rpc_queue); ++ rpc_queue_init(&stack->rpc_queue); ++ rpc_queue_init(&stack->dfx_rpc_queue); + + if (use_ltran()) { + stack->rx_ring = gazelle_ring_create_fast("RING_RX", VDEV_RX_QUEUE_SZ, RING_F_SP_ENQ | RING_F_SC_DEQ); +diff --git a/src/lstack/core/lstack_lwip.c b/src/lstack/core/lstack_lwip.c +index 3f76424..b79cdef 100644 +--- a/src/lstack/core/lstack_lwip.c ++++ b/src/lstack/core/lstack_lwip.c +@@ -636,7 +636,7 @@ static inline void notice_stack_send(struct lwip_sock *sock, int32_t fd, int32_t + { + // 2: call_num >= 2, don't need add new rpc send + if (__atomic_load_n(&sock->call_num, __ATOMIC_ACQUIRE) < 2) { +- while (rpc_call_send(fd, NULL, len, flags) < 0) { ++ while (rpc_call_send(&sock->stack->rpc_queue, fd, NULL, len, flags) < 0) { + usleep(1000); // 1000: wait 1ms to exec again + } + __sync_fetch_and_add(&sock->call_num, 1); +diff --git a/src/lstack/core/lstack_protocol_stack.c b/src/lstack/core/lstack_protocol_stack.c +index 8b99e82..f63fcb0 100644 +--- a/src/lstack/core/lstack_protocol_stack.c ++++ b/src/lstack/core/lstack_protocol_stack.c +@@ -465,7 +465,10 @@ int stack_polling(uint32_t wakeup_tick) + uint32_t read_connect_number = cfg->read_connect_number; + struct protocol_stack *stack = get_protocol_stack(); + +- force_quit = poll_rpc_msg(stack, rpc_number); ++ /* 2: one dfx consumes two rpc */ ++ rpc_poll_msg(&stack->dfx_rpc_queue, 2); ++ force_quit = rpc_poll_msg(&stack->rpc_queue, rpc_number); ++ + gazelle_eth_dev_poll(stack, use_ltran_flag, nic_read_number); + sys_timer_run(); + if (cfg->low_power_mod != 0) { +@@ -715,7 +718,7 @@ OUT2: + void stack_arp(struct rpc_msg *msg) + { + struct rte_mbuf *mbuf = (struct rte_mbuf *)msg->args[MSG_ARG_0].p; +- struct protocol_stack *stack = (struct protocol_stack*)msg->args[MSG_ARG_1].p; ++ struct protocol_stack *stack = get_protocol_stack(); + + eth_dev_recv(mbuf, stack); + } +@@ -893,7 +896,7 @@ void stack_send(struct rpc_msg *msg) + { + int32_t fd = msg->args[MSG_ARG_0].i; + size_t len = msg->args[MSG_ARG_1].size; +- struct protocol_stack *stack = (struct protocol_stack *)msg->args[MSG_ARG_3].p; ++ struct protocol_stack *stack = get_protocol_stack(); + int replenish_again; + + struct lwip_sock *sock = get_socket(fd); +@@ -947,7 +950,7 @@ void stack_broadcast_arp(struct rte_mbuf *mbuf, struct protocol_stack *cur_stack + } + copy_mbuf(mbuf_copy, mbuf); + +- ret = rpc_call_arp(stack, mbuf_copy); ++ ret = rpc_call_arp(&stack->rpc_queue, mbuf_copy); + if (ret != 0) { + return; + } +@@ -971,7 +974,7 @@ void stack_broadcast_clean_epoll(struct wakeup_poll *wakeup) + + for (int32_t i = 0; i < stack_group->stack_num; i++) { + stack = stack_group->stacks[i]; +- rpc_call_clean_epoll(stack, wakeup); ++ rpc_call_clean_epoll(&stack->rpc_queue, wakeup); + } + } + +@@ -985,17 +988,11 @@ void stack_clean_epoll(struct rpc_msg *msg) + + void stack_mempool_size(struct rpc_msg *msg) + { +- struct protocol_stack *stack = (struct protocol_stack*)msg->args[MSG_ARG_0].p; ++ struct protocol_stack *stack = get_protocol_stack(); + + msg->result = rte_mempool_avail_count(stack->rxtx_mbuf_pool); + } + +-void stack_rpcpool_size(struct rpc_msg *msg) +-{ +- struct rpc_msg_pool *rpc_mem_pool = (struct rpc_msg_pool*)msg->args[MSG_ARG_0].p; +- msg->result = rte_mempool_avail_count(rpc_mem_pool->mempool); +-} +- + void stack_create_shadow_fd(struct rpc_msg *msg) + { + int32_t fd = msg->args[MSG_ARG_0].i; +@@ -1049,8 +1046,8 @@ void stack_create_shadow_fd(struct rpc_msg *msg) + + void stack_replenish_sendring(struct rpc_msg *msg) + { +- struct protocol_stack *stack = (struct protocol_stack *)msg->args[MSG_ARG_0].p; +- struct lwip_sock *sock = (struct lwip_sock *)msg->args[MSG_ARG_1].p; ++ struct protocol_stack *stack = get_protocol_stack(); ++ struct lwip_sock *sock = (struct lwip_sock *)msg->args[MSG_ARG_0].p; + + msg->result = do_lwip_replenish_sendring(stack, sock); + } +@@ -1070,7 +1067,7 @@ void stack_get_connnum(struct rpc_msg *msg) + + void stack_recvlist_count(struct rpc_msg *msg) + { +- struct protocol_stack *stack = (struct protocol_stack *)msg->args[MSG_ARG_0].p; ++ struct protocol_stack *stack = get_protocol_stack(); + struct list_node *list = &stack->recv_list; + uint32_t count = 0; + struct list_node *node; +@@ -1086,16 +1083,16 @@ void stack_recvlist_count(struct rpc_msg *msg) + /* when fd is listenfd, listenfd of all protocol stack thread will be closed */ + int32_t stack_broadcast_close(int32_t fd) + { +- struct lwip_sock *sock = get_socket(fd); + int32_t ret = 0; +- ++ struct lwip_sock *sock = get_socket(fd); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(fd); + if (sock == NULL) { +- return -1; ++ GAZELLE_RETURN(EBADF); + } + + do { + sock = sock->listen_next; +- if (rpc_call_close(fd)) { ++ if (stack == NULL || rpc_call_close(&stack->rpc_queue, fd)) { + ret = -1; + } + +@@ -1103,7 +1100,8 @@ int32_t stack_broadcast_close(int32_t fd) + break; + } + fd = sock->conn->callback_arg.socket; +- } while (sock); ++ stack = get_protocol_stack_by_fd(fd); ++ } while (1); + + return ret; + } +@@ -1112,13 +1110,14 @@ int stack_broadcast_shutdown(int fd, int how) + { + int32_t ret = 0; + struct lwip_sock *sock = get_socket(fd); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(fd); + if (sock == NULL) { +- return -1; ++ GAZELLE_RETURN(EBADF); + } + + do { + sock = sock->listen_next; +- if (rpc_call_shutdown(fd, how)) { ++ if (stack == NULL || rpc_call_shutdown(&stack->rpc_queue, fd, how)) { + ret = -1; + } + +@@ -1126,7 +1125,8 @@ int stack_broadcast_shutdown(int fd, int how) + break; + } + fd = sock->conn->callback_arg.socket; +- } while (sock); ++ stack = get_protocol_stack_by_fd(fd); ++ } while (1); + + return ret; + } +@@ -1134,7 +1134,11 @@ int stack_broadcast_shutdown(int fd, int how) + /* choice one stack listen */ + int32_t stack_single_listen(int32_t fd, int32_t backlog) + { +- return rpc_call_listen(fd, backlog); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(fd); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EBADF); ++ } ++ return rpc_call_listen(&stack->rpc_queue, fd, backlog); + } + + /* listen sync to all protocol stack thread, so that any protocol stack thread can build connect */ +@@ -1153,12 +1157,12 @@ int32_t stack_broadcast_listen(int32_t fd, int32_t backlog) + int32_t ret, clone_fd; + + struct lwip_sock *sock = get_socket(fd); +- if (sock == NULL) { +- LSTACK_LOG(ERR, LSTACK, "tid %ld, %d get sock null\n", get_stack_tid(), fd); +- GAZELLE_RETURN(EINVAL); ++ if (sock == NULL || cur_stack == NULL) { ++ LSTACK_LOG(ERR, LSTACK, "tid %ld, %d get sock null or stack null\n", get_stack_tid(), fd); ++ GAZELLE_RETURN(EBADF); + } + +- ret = rpc_call_getsockname(fd, (struct sockaddr *)&addr, &addr_len); ++ ret = rpc_call_getsockname(&cur_stack->rpc_queue, fd, (struct sockaddr *)&addr, &addr_len); + if (ret != 0) { + return ret; + } +@@ -1172,7 +1176,7 @@ int32_t stack_broadcast_listen(int32_t fd, int32_t backlog) + continue; + } + if (stack != cur_stack) { +- clone_fd = rpc_call_shadow_fd(stack, fd, (struct sockaddr *)&addr, addr_len); ++ clone_fd = rpc_call_shadow_fd(&stack->rpc_queue, fd, (struct sockaddr *)&addr, addr_len); + if (clone_fd < 0) { + stack_broadcast_close(fd); + return clone_fd; +@@ -1187,7 +1191,7 @@ int32_t stack_broadcast_listen(int32_t fd, int32_t backlog) + get_socket_by_fd(clone_fd)->conn->is_master_fd = 0; + } + +- ret = rpc_call_listen(clone_fd, backlog); ++ ret = rpc_call_listen(&stack->rpc_queue, clone_fd, backlog); + if (ret < 0) { + stack_broadcast_close(fd); + return ret; +@@ -1234,7 +1238,11 @@ static void inline del_accept_in_event(struct lwip_sock *sock) + /* choice one stack bind */ + int32_t stack_single_bind(int32_t fd, const struct sockaddr *name, socklen_t namelen) + { +- return rpc_call_bind(fd, name, namelen); ++ struct protocol_stack *stack = get_protocol_stack_by_fd(fd); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EBADF); ++ } ++ return rpc_call_bind(&stack->rpc_queue, fd, name, namelen); + } + + /* bind sync to all protocol stack thread, so that any protocol stack thread can build connect */ +@@ -1245,12 +1253,12 @@ int32_t stack_broadcast_bind(int32_t fd, const struct sockaddr *name, socklen_t + int32_t ret, clone_fd; + + struct lwip_sock *sock = get_socket(fd); +- if (sock == NULL) { +- LSTACK_LOG(ERR, LSTACK, "tid %ld, %d get sock null\n", get_stack_tid(), fd); +- GAZELLE_RETURN(EINVAL); ++ if (sock == NULL || cur_stack == NULL) { ++ LSTACK_LOG(ERR, LSTACK, "tid %ld, %d get sock null or stack null\n", get_stack_tid(), fd); ++ GAZELLE_RETURN(EBADF); + } + +- ret = rpc_call_bind(fd, name, namelen); ++ ret = rpc_call_bind(&cur_stack->rpc_queue, fd, name, namelen); + if (ret < 0) { + close(fd); + return ret; +@@ -1260,7 +1268,7 @@ int32_t stack_broadcast_bind(int32_t fd, const struct sockaddr *name, socklen_t + for (int32_t i = 0; i < stack_group->stack_num; ++i) { + stack = stack_group->stacks[i]; + if (stack != cur_stack) { +- clone_fd = rpc_call_shadow_fd(stack, fd, name, namelen); ++ clone_fd = rpc_call_shadow_fd(&stack->rpc_queue, fd, name, namelen); + if (clone_fd < 0) { + stack_broadcast_close(fd); + return clone_fd; +@@ -1276,9 +1284,9 @@ int32_t stack_broadcast_accept4(int32_t fd, struct sockaddr *addr, socklen_t *ad + int32_t ret = -1; + struct lwip_sock *min_sock = NULL; + struct lwip_sock *sock = get_socket(fd); ++ struct protocol_stack *stack = NULL; + if (sock == NULL) { +- errno = EINVAL; +- return -1; ++ GAZELLE_RETURN(EBADF); + } + + if (netconn_is_nonblocking(sock->conn)) { +@@ -1290,7 +1298,11 @@ int32_t stack_broadcast_accept4(int32_t fd, struct sockaddr *addr, socklen_t *ad + } + + if (min_sock && min_sock->conn) { +- ret = rpc_call_accept(min_sock->conn->callback_arg.socket, addr, addrlen, flags); ++ stack = get_protocol_stack_by_fd(min_sock->conn->callback_arg.socket); ++ if (stack == NULL) { ++ GAZELLE_RETURN(EBADF); ++ } ++ ret = rpc_call_accept(&stack->rpc_queue, min_sock->conn->callback_arg.socket, addr, addrlen, flags); + } + + if (min_sock && min_sock->wakeup && min_sock->wakeup->type == WAKEUP_EPOLL) { +@@ -1344,7 +1356,7 @@ void stack_group_exit(void) + } + + if (stack != stack_group->stacks[i]) { +- rpc_call_stack_exit(stack_group->stacks[i]); ++ rpc_call_stack_exit(&stack_group->stacks[i]->rpc_queue); + } + } + +diff --git a/src/lstack/core/lstack_stack_stat.c b/src/lstack/core/lstack_stack_stat.c +index 23571b4..01ac6fb 100644 +--- a/src/lstack/core/lstack_stack_stat.c ++++ b/src/lstack/core/lstack_stack_stat.c +@@ -175,20 +175,17 @@ static void get_stack_stats(struct gazelle_stack_dfx_data *dfx, struct protocol_ + + get_wakeup_stat(stack_group, stack, &dfx->data.pkts.wakeup_stat); + +- dfx->data.pkts.call_alloc_fail = stack_group->call_alloc_fail; ++ dfx->data.pkts.call_alloc_fail = rpc_stats_get()->call_alloc_fail; + +- int32_t rpc_call_result = rpc_call_msgcnt(stack); ++ int32_t rpc_call_result = rpc_msgcnt(&stack->rpc_queue); + dfx->data.pkts.call_msg_cnt = (rpc_call_result < 0) ? 0 : rpc_call_result; + +- rpc_call_result = rpc_call_mbufpoolsize(stack); ++ rpc_call_result = rpc_call_mbufpoolsize(&stack->dfx_rpc_queue); + dfx->data.pkts.mbufpool_avail_cnt = (rpc_call_result < 0) ? 0 : rpc_call_result; + +- rpc_call_result = rpc_call_recvlistcnt(stack); ++ rpc_call_result = rpc_call_recvlistcnt(&stack->dfx_rpc_queue); + dfx->data.pkts.recv_list_cnt = (rpc_call_result < 0) ? 0 : rpc_call_result; + +- rpc_call_result = rpc_call_rpcpool_size(stack); +- dfx->data.pkts.rpcpool_avail_cnt = (rpc_call_result < 0) ? 0 : rpc_call_result; +- + dfx->data.pkts.conn_num = stack->conn_num; + } + +@@ -219,9 +216,10 @@ static void get_stack_dfx_data(struct gazelle_stack_dfx_data *dfx, struct protoc + } + break; + case GAZELLE_STAT_LSTACK_SHOW_CONN: +- rpc_call_result = rpc_call_conntable(stack, dfx->data.conn.conn_list, GAZELLE_LSTACK_MAX_CONN); ++ rpc_call_result = rpc_call_conntable(&stack->dfx_rpc_queue, dfx->data.conn.conn_list, ++ GAZELLE_LSTACK_MAX_CONN); + dfx->data.conn.conn_num = (rpc_call_result < 0) ? 0 : rpc_call_result; +- rpc_call_result = rpc_call_connnum(stack); ++ rpc_call_result = rpc_call_connnum(&stack->dfx_rpc_queue); + dfx->data.conn.total_conn_num = (rpc_call_result < 0) ? 0 : rpc_call_result; + break; + case GAZELLE_STAT_LSTACK_SHOW_LATENCY: +@@ -296,7 +294,7 @@ int handle_stack_cmd(int fd, enum GAZELLE_STAT_MODE stat_mode) + } + + dfx.tid = stack->tid; +- dfx.stack_id = i; ++ dfx.stack_id = i; + if (i == stack_group->stack_num - 1) { + dfx.eof = 1; + } +diff --git a/src/lstack/core/lstack_thread_rpc.c b/src/lstack/core/lstack_thread_rpc.c +index 2af30d7..1fdb037 100644 +--- a/src/lstack/core/lstack_thread_rpc.c ++++ b/src/lstack/core/lstack_thread_rpc.c +@@ -9,21 +9,20 @@ + * PURPOSE. + * See the Mulan PSL v2 for more details. + */ +-#include +-#include + #include +-#include + #include + + #include "lstack_log.h" +-#include "lstack_lwip.h" +-#include "lstack_protocol_stack.h" +-#include "lstack_control_plane.h" +-#include "gazelle_base_func.h" + #include "lstack_dpdk.h" ++#include "lstack_rpc_proc.h" + #include "lstack_thread_rpc.h" + + static PER_THREAD struct rpc_msg_pool *g_rpc_pool = NULL; ++static struct rpc_stats g_rpc_stats; ++struct rpc_stats *rpc_stats_get(void) ++{ ++ return &g_rpc_stats; ++} + + static inline __attribute__((always_inline)) struct rpc_msg *get_rpc_msg(struct rpc_msg_pool *rpc_pool) + { +@@ -37,33 +36,29 @@ static inline __attribute__((always_inline)) struct rpc_msg *get_rpc_msg(struct + return msg; + } + +-static struct rpc_msg *rpc_msg_alloc(struct protocol_stack *stack, rpc_msg_func func) ++static struct rpc_msg *rpc_msg_alloc(rpc_msg_func func) + { + struct rpc_msg *msg = NULL; + +- if (stack == NULL) { +- return NULL; +- } +- + if (g_rpc_pool == NULL) { + g_rpc_pool = calloc(1, sizeof(struct rpc_msg_pool)); + if (g_rpc_pool == NULL) { + LSTACK_LOG(INFO, LSTACK, "g_rpc_pool calloc failed\n"); +- get_protocol_stack_group()->call_alloc_fail++; ++ g_rpc_stats.call_alloc_fail++; + return NULL; + } + + g_rpc_pool->mempool = create_mempool("rpc_pool", RPC_MSG_MAX, sizeof(struct rpc_msg), + 0, rte_gettid()); + if (g_rpc_pool->mempool == NULL) { +- get_protocol_stack_group()->call_alloc_fail++; ++ g_rpc_stats.call_alloc_fail++; + return NULL; + } + } + + msg = get_rpc_msg(g_rpc_pool); + if (msg == NULL) { +- get_protocol_stack_group()->call_alloc_fail++; ++ g_rpc_stats.call_alloc_fail++; + return NULL; + } + msg->rpcpool = g_rpc_pool; +@@ -75,7 +70,7 @@ static struct rpc_msg *rpc_msg_alloc(struct protocol_stack *stack, rpc_msg_func + return msg; + } + +-static inline __attribute__((always_inline)) int32_t rpc_sync_call(lockless_queue *queue, struct rpc_msg *msg) ++static inline __attribute__((always_inline)) int32_t rpc_sync_call(rpc_queue *queue, struct rpc_msg *msg) + { + int32_t ret; + +@@ -90,13 +85,18 @@ static inline __attribute__((always_inline)) int32_t rpc_sync_call(lockless_queu + return ret; + } + +-int poll_rpc_msg(struct protocol_stack *stack, uint32_t max_num) ++int32_t rpc_msgcnt(rpc_queue *queue) ++{ ++ return lockless_queue_count(queue); ++} ++ ++int rpc_poll_msg(rpc_queue *queue, uint32_t max_num) + { + int force_quit = 0; + struct rpc_msg *msg = NULL; + + while (max_num--) { +- lockless_queue_node *node = lockless_queue_mpsc_pop(&stack->rpc_queue); ++ lockless_queue_node *node = lockless_queue_mpsc_pop(queue); + if (node == NULL) { + break; + } +@@ -106,7 +106,7 @@ int poll_rpc_msg(struct protocol_stack *stack, uint32_t max_num) + if (msg->func) { + msg->func(msg); + } else { +- stack->stats.call_null++; ++ g_rpc_stats.call_null++; + } + + if (msg->func == stack_exit_by_rpc) { +@@ -127,9 +127,9 @@ int poll_rpc_msg(struct protocol_stack *stack, uint32_t max_num) + return force_quit; + } + +-int32_t rpc_call_conntable(struct protocol_stack *stack, void *conn_table, uint32_t max_conn) ++int32_t rpc_call_conntable(rpc_queue *queue, void *conn_table, uint32_t max_conn) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_get_conntable); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_get_conntable); + if (msg == NULL) { + return -1; + } +@@ -137,22 +137,22 @@ int32_t rpc_call_conntable(struct protocol_stack *stack, void *conn_table, uint3 + msg->args[MSG_ARG_0].p = conn_table; + msg->args[MSG_ARG_1].u = max_conn; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_connnum(struct protocol_stack *stack) ++int32_t rpc_call_connnum(rpc_queue *queue) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_get_connnum); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_get_connnum); + if (msg == NULL) { + return -1; + } + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_shadow_fd(struct protocol_stack *stack, int32_t fd, const struct sockaddr *addr, socklen_t addrlen) ++int32_t rpc_call_shadow_fd(rpc_queue *queue, int32_t fd, const struct sockaddr *addr, socklen_t addrlen) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_create_shadow_fd); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_create_shadow_fd); + if (msg == NULL) { + return -1; + } +@@ -161,100 +161,67 @@ int32_t rpc_call_shadow_fd(struct protocol_stack *stack, int32_t fd, const struc + msg->args[MSG_ARG_1].cp = addr; + msg->args[MSG_ARG_2].socklen = addrlen; + +- return rpc_sync_call(&stack->rpc_queue, msg); +-} +- +-static void rpc_msgcnt(struct rpc_msg *msg) +-{ +- struct protocol_stack *stack = get_protocol_stack(); +- msg->result = lockless_queue_count(&stack->rpc_queue); +-} +- +-int32_t rpc_call_msgcnt(struct protocol_stack *stack) +-{ +- struct rpc_msg *msg = rpc_msg_alloc(stack, rpc_msgcnt); +- if (msg == NULL) { +- return -1; +- } +- +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_thread_regphase1(struct protocol_stack *stack, void *conn) ++int32_t rpc_call_thread_regphase1(rpc_queue *queue, void *conn) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, thread_register_phase1); ++ struct rpc_msg *msg = rpc_msg_alloc(thread_register_phase1); + if (msg == NULL) { + return -1; + } + msg->args[MSG_ARG_0].p = conn; +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_thread_regphase2(struct protocol_stack *stack, void *conn) ++int32_t rpc_call_thread_regphase2(rpc_queue *queue, void *conn) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, thread_register_phase2); ++ struct rpc_msg *msg = rpc_msg_alloc(thread_register_phase2); + if (msg == NULL) { + return -1; + } + msg->args[MSG_ARG_0].p = conn; +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_mbufpoolsize(struct protocol_stack *stack) ++int32_t rpc_call_mbufpoolsize(rpc_queue *queue) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_mempool_size); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_mempool_size); + if (msg == NULL) { + return -1; + } + +- msg->args[MSG_ARG_0].p = stack; +- +- return rpc_sync_call(&stack->rpc_queue, msg); +-} +- +-int32_t rpc_call_rpcpool_size(struct protocol_stack *stack) +-{ +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_rpcpool_size); +- if (msg == NULL) { +- return -1; +- } +- msg->args[MSG_ARG_0].p = g_rpc_pool; +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_recvlistcnt(struct protocol_stack *stack) ++int32_t rpc_call_recvlistcnt(rpc_queue *queue) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_recvlist_count); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_recvlist_count); + if (msg == NULL) { + return -1; + } + +- msg->args[MSG_ARG_0].p = stack; +- +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_arp(struct protocol_stack *stack, struct rte_mbuf *mbuf) ++int32_t rpc_call_arp(rpc_queue *queue, void *mbuf) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_arp); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_arp); + if (msg == NULL) { + return -1; + } + + msg->sync_flag = 0; + msg->args[MSG_ARG_0].p = mbuf; +- msg->args[MSG_ARG_1].p = stack; + +- rpc_call(&stack->rpc_queue, msg); ++ rpc_call(queue, msg); + + return 0; + } + +-int32_t rpc_call_socket(int32_t domain, int32_t type, int32_t protocol) ++int32_t rpc_call_socket(rpc_queue *queue, int32_t domain, int32_t type, int32_t protocol) + { +- struct protocol_stack *stack = get_bind_protocol_stack(); +- +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_socket); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_socket); + if (msg == NULL) { + return -1; + } +@@ -263,39 +230,35 @@ int32_t rpc_call_socket(int32_t domain, int32_t type, int32_t protocol) + msg->args[MSG_ARG_1].i = type; + msg->args[MSG_ARG_2].i = protocol; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_close(int fd) ++int32_t rpc_call_close(rpc_queue *queue, int fd) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_close); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_close); + if (msg == NULL) { + return -1; + } + + msg->args[MSG_ARG_0].i = fd; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_stack_exit(struct protocol_stack *stack) ++int32_t rpc_call_stack_exit(rpc_queue *queue) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_exit_by_rpc); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_exit_by_rpc); + if (msg == NULL) { +- LSTACK_LOG(INFO, LSTACK, "rpc msg alloc failed\n"); + return -1; + } + +- rpc_call(&stack->rpc_queue, msg); ++ rpc_call(queue, msg); + return 0; + } + +-int32_t rpc_call_shutdown(int fd, int how) ++int32_t rpc_call_shutdown(rpc_queue *queue, int fd, int how) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_shutdown); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_shutdown); + if (msg == NULL) { + return -1; + } +@@ -303,25 +266,24 @@ int32_t rpc_call_shutdown(int fd, int how) + msg->args[MSG_ARG_0].i = fd; + msg->args[MSG_ARG_1].i = how; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-void rpc_call_clean_epoll(struct protocol_stack *stack, struct wakeup_poll *wakeup) ++void rpc_call_clean_epoll(rpc_queue *queue, void *wakeup) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_clean_epoll); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_clean_epoll); + if (msg == NULL) { + return; + } + + msg->args[MSG_ARG_0].p = wakeup; + +- rpc_sync_call(&stack->rpc_queue, msg); ++ rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_bind(int32_t fd, const struct sockaddr *addr, socklen_t addrlen) ++int32_t rpc_call_bind(rpc_queue *queue, int32_t fd, const struct sockaddr *addr, socklen_t addrlen) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_bind); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_bind); + if (msg == NULL) { + return -1; + } +@@ -330,13 +292,12 @@ int32_t rpc_call_bind(int32_t fd, const struct sockaddr *addr, socklen_t addrlen + msg->args[MSG_ARG_1].cp = addr; + msg->args[MSG_ARG_2].socklen = addrlen; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_listen(int s, int backlog) ++int32_t rpc_call_listen(rpc_queue *queue, int s, int backlog) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(s); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_listen); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_listen); + if (msg == NULL) { + return -1; + } +@@ -344,13 +305,12 @@ int32_t rpc_call_listen(int s, int backlog) + msg->args[MSG_ARG_0].i = s; + msg->args[MSG_ARG_1].i = backlog; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_accept(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags) ++int32_t rpc_call_accept(rpc_queue *queue, int fd, struct sockaddr *addr, socklen_t *addrlen, int flags) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_accept); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_accept); + if (msg == NULL) { + return -1; + } +@@ -360,13 +320,12 @@ int32_t rpc_call_accept(int fd, struct sockaddr *addr, socklen_t *addrlen, int f + msg->args[MSG_ARG_2].p = addrlen; + msg->args[MSG_ARG_3].i = flags; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) ++int32_t rpc_call_connect(rpc_queue *queue, int fd, const struct sockaddr *addr, socklen_t addrlen) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_connect); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_connect); + if (msg == NULL) { + return -1; + } +@@ -375,7 +334,7 @@ int32_t rpc_call_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) + msg->args[MSG_ARG_1].cp = addr; + msg->args[MSG_ARG_2].socklen = addrlen; + +- int32_t ret = rpc_sync_call(&stack->rpc_queue, msg); ++ int32_t ret = rpc_sync_call(queue, msg); + if (ret < 0) { + errno = -ret; + return -1; +@@ -383,10 +342,9 @@ int32_t rpc_call_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) + return ret; + } + +-int32_t rpc_call_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen) ++int32_t rpc_call_getpeername(rpc_queue *queue, int fd, struct sockaddr *addr, socklen_t *addrlen) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_getpeername); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_getpeername); + if (msg == NULL) { + return -1; + } +@@ -395,13 +353,12 @@ int32_t rpc_call_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen) + msg->args[MSG_ARG_1].p = addr; + msg->args[MSG_ARG_2].p = addrlen; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen) ++int32_t rpc_call_getsockname(rpc_queue *queue, int fd, struct sockaddr *addr, socklen_t *addrlen) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_getsockname); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_getsockname); + if (msg == NULL) { + return -1; + } +@@ -410,13 +367,12 @@ int32_t rpc_call_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen) + msg->args[MSG_ARG_1].p = addr; + msg->args[MSG_ARG_2].p = addrlen; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) ++int32_t rpc_call_getsockopt(rpc_queue *queue, int fd, int level, int optname, void *optval, socklen_t *optlen) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_getsockopt); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_getsockopt); + if (msg == NULL) { + return -1; + } +@@ -427,13 +383,12 @@ int32_t rpc_call_getsockopt(int fd, int level, int optname, void *optval, sockle + msg->args[MSG_ARG_3].p = optval; + msg->args[MSG_ARG_4].p = optlen; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) ++int32_t rpc_call_setsockopt(rpc_queue *queue, int fd, int level, int optname, const void *optval, socklen_t optlen) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_setsockopt); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_setsockopt); + if (msg == NULL) { + return -1; + } +@@ -444,13 +399,12 @@ int32_t rpc_call_setsockopt(int fd, int level, int optname, const void *optval, + msg->args[MSG_ARG_3].cp = optval; + msg->args[MSG_ARG_4].socklen = optlen; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_fcntl(int fd, int cmd, long val) ++int32_t rpc_call_fcntl(rpc_queue *queue, int fd, int cmd, long val) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_fcntl); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_fcntl); + if (msg == NULL) { + return -1; + } +@@ -459,13 +413,12 @@ int32_t rpc_call_fcntl(int fd, int cmd, long val) + msg->args[MSG_ARG_1].i = cmd; + msg->args[MSG_ARG_2].l = val; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_ioctl(int fd, long cmd, void *argp) ++int32_t rpc_call_ioctl(rpc_queue *queue, int fd, long cmd, void *argp) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_ioctl); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_ioctl); + if (msg == NULL) { + return -1; + } +@@ -474,27 +427,24 @@ int32_t rpc_call_ioctl(int fd, long cmd, void *argp) + msg->args[MSG_ARG_1].l = cmd; + msg->args[MSG_ARG_2].p = argp; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_replenish(struct protocol_stack *stack, struct lwip_sock *sock) ++int32_t rpc_call_replenish(rpc_queue *queue, void *sock) + { +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_replenish_sendring); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_replenish_sendring); + if (msg == NULL) { + return -1; + } + +- msg->args[MSG_ARG_0].p = stack; +- msg->args[MSG_ARG_1].p = sock; ++ msg->args[MSG_ARG_0].p = sock; + +- return rpc_sync_call(&stack->rpc_queue, msg); ++ return rpc_sync_call(queue, msg); + } + +-int32_t rpc_call_send(int fd, const void *buf, size_t len, int flags) ++int32_t rpc_call_send(rpc_queue *queue, int fd, const void *buf, size_t len, int flags) + { +- struct protocol_stack *stack = get_protocol_stack_by_fd(fd); +- +- struct rpc_msg *msg = rpc_msg_alloc(stack, stack_send); ++ struct rpc_msg *msg = rpc_msg_alloc(stack_send); + if (msg == NULL) { + return -1; + } +@@ -502,10 +452,9 @@ int32_t rpc_call_send(int fd, const void *buf, size_t len, int flags) + msg->args[MSG_ARG_0].i = fd; + msg->args[MSG_ARG_1].size = len; + msg->args[MSG_ARG_2].i = flags; +- msg->args[MSG_ARG_3].p = stack; + msg->sync_flag = 0; + +- rpc_call(&stack->rpc_queue, msg); ++ rpc_call(queue, msg); + + return 0; + } +diff --git a/src/lstack/include/lstack_control_plane.h b/src/lstack/include/lstack_control_plane.h +index aed5443..548d725 100644 +--- a/src/lstack/include/lstack_control_plane.h ++++ b/src/lstack/include/lstack_control_plane.h +@@ -23,14 +23,11 @@ enum vdev_request { + VDEV_NONE, + }; + +-struct rpc_msg; + int client_reg_thrd_ring(void); + int32_t control_init_client(bool is_reconnect); + void control_client_thread(void *arg); + void control_server_thread(void *arg); + bool get_register_state(void); +-void thread_register_phase1(struct rpc_msg *msg); +-void thread_register_phase2(struct rpc_msg *msg); + void control_fd_close(void); + void delete_primary_path(void); + +diff --git a/src/lstack/include/lstack_protocol_stack.h b/src/lstack/include/lstack_protocol_stack.h +index c681547..7489f2a 100644 +--- a/src/lstack/include/lstack_protocol_stack.h ++++ b/src/lstack/include/lstack_protocol_stack.h +@@ -21,7 +21,7 @@ + #include + + #include "gazelle_dfx_msg.h" +-#include "lstack_lockless_queue.h" ++#include "lstack_thread_rpc.h" + #include "lstack_ethdev.h" + #include "gazelle_opt.h" + +@@ -59,13 +59,15 @@ struct protocol_stack { + volatile bool low_power; + bool is_send_thread; + +- lockless_queue rpc_queue __rte_cache_aligned; +- char pad __rte_cache_aligned; ++ char pad1 __rte_cache_aligned; ++ rpc_queue dfx_rpc_queue; ++ rpc_queue rpc_queue; ++ char pad2 __rte_cache_aligned; + + /* kernel event thread read/write frequently */ + struct epoll_event kernel_events[KERNEL_EPOLL_MAX]; + int32_t kernel_event_num; +- char pad1 __rte_cache_aligned; ++ char pad3 __rte_cache_aligned; + + struct netif netif; + struct lstack_dev_ops dev_ops; +@@ -149,36 +151,10 @@ void stack_broadcast_clean_epoll(struct wakeup_poll *wakeup); + + void stack_send_pkts(struct protocol_stack *stack); + +-struct rpc_msg; + struct thread_params { + uint16_t queue_id; + uint16_t idx; + }; +-void stack_clean_epoll(struct rpc_msg *msg); +-void stack_arp(struct rpc_msg *msg); +-void stack_socket(struct rpc_msg *msg); +-void stack_close(struct rpc_msg *msg); +-void stack_shutdown(struct rpc_msg *msg); +-void stack_bind(struct rpc_msg *msg); +-void stack_listen(struct rpc_msg *msg); +-void stack_accept(struct rpc_msg *msg); +-void stack_connect(struct rpc_msg *msg); +-void stack_recv(struct rpc_msg *msg); +-void stack_getpeername(struct rpc_msg *msg); +-void stack_getsockname(struct rpc_msg *msg); +-void stack_getsockopt(struct rpc_msg *msg); +-void stack_setsockopt(struct rpc_msg *msg); +-void stack_fcntl(struct rpc_msg *msg); +-void stack_ioctl(struct rpc_msg *msg); +-void stack_send(struct rpc_msg *msg); +-void stack_mempool_size(struct rpc_msg *msg); +-void stack_rpcpool_size(struct rpc_msg *msg); +-void stack_create_shadow_fd(struct rpc_msg *msg); +-void stack_replenish_sendring(struct rpc_msg *msg); +-void stack_get_conntable(struct rpc_msg *msg); +-void stack_get_connnum(struct rpc_msg *msg); +-void stack_recvlist_count(struct rpc_msg *msg); +-void stack_exit_by_rpc(struct rpc_msg *msg); + + int stack_polling(uint32_t wakeup_tick); + #endif +diff --git a/src/lstack/include/lstack_rpc_proc.h b/src/lstack/include/lstack_rpc_proc.h +new file mode 100644 +index 0000000..71f0c58 +--- /dev/null ++++ b/src/lstack/include/lstack_rpc_proc.h +@@ -0,0 +1,46 @@ ++/* ++* 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 __GAZELLE_RPC_PROC_H__ ++#define __GAZELLE_RPC_PROC_H__ ++#include "lstack_thread_rpc.h" ++ ++void stack_clean_epoll(struct rpc_msg *msg); ++void stack_arp(struct rpc_msg *msg); ++void stack_socket(struct rpc_msg *msg); ++void stack_close(struct rpc_msg *msg); ++void stack_shutdown(struct rpc_msg *msg); ++void stack_bind(struct rpc_msg *msg); ++void stack_listen(struct rpc_msg *msg); ++void stack_accept(struct rpc_msg *msg); ++void stack_connect(struct rpc_msg *msg); ++void stack_recv(struct rpc_msg *msg); ++void stack_getpeername(struct rpc_msg *msg); ++void stack_getsockname(struct rpc_msg *msg); ++void stack_getsockopt(struct rpc_msg *msg); ++void stack_setsockopt(struct rpc_msg *msg); ++void stack_fcntl(struct rpc_msg *msg); ++void stack_ioctl(struct rpc_msg *msg); ++void stack_send(struct rpc_msg *msg); ++void stack_mempool_size(struct rpc_msg *msg); ++void stack_rpcpool_size(struct rpc_msg *msg); ++void stack_create_shadow_fd(struct rpc_msg *msg); ++void stack_replenish_sendring(struct rpc_msg *msg); ++void stack_get_conntable(struct rpc_msg *msg); ++void stack_get_connnum(struct rpc_msg *msg); ++void stack_recvlist_count(struct rpc_msg *msg); ++void stack_exit_by_rpc(struct rpc_msg *msg); ++ ++void thread_register_phase1(struct rpc_msg *msg); ++void thread_register_phase2(struct rpc_msg *msg); ++ ++#endif +diff --git a/src/lstack/include/lstack_thread_rpc.h b/src/lstack/include/lstack_thread_rpc.h +index 633ef93..30caa66 100644 +--- a/src/lstack/include/lstack_thread_rpc.h ++++ b/src/lstack/include/lstack_thread_rpc.h +@@ -28,6 +28,12 @@ + + #define RPC_MSG_MAX 4096 + #define RPC_MSG_MASK (RPC_MSG_MAX - 1) ++typedef struct lockless_queue rpc_queue; ++ ++struct rpc_stats { ++ uint16_t call_null; ++ uint64_t call_alloc_fail; ++}; + + struct rpc_msg; + typedef void (*rpc_msg_func)(struct rpc_msg *msg); +@@ -41,7 +47,9 @@ union rpc_msg_arg { + socklen_t socklen; + size_t size; + }; +-struct rpc_msg_pool; ++struct rpc_msg_pool { ++ struct rte_mempool *mempool; ++}; + struct rpc_msg { + pthread_spinlock_t lock; /* msg handler unlock notice sender msg process done */ + int8_t sync_flag : 1; +@@ -54,44 +62,41 @@ struct rpc_msg { + union rpc_msg_arg args[RPM_MSG_ARG_SIZE]; /* resolve by type */ + }; + +-struct rpc_msg_pool { +- struct rte_mempool *mempool; +-}; ++static inline void rpc_queue_init(rpc_queue *queue) ++{ ++ lockless_queue_init(queue); ++} + +-struct protocol_stack; +-struct rte_mbuf; +-struct wakeup_poll; +-struct lwip_sock; +-int poll_rpc_msg(struct protocol_stack *stack, uint32_t max_num); +-void rpc_call_clean_epoll(struct protocol_stack *stack, struct wakeup_poll *wakeup); +-int32_t rpc_call_msgcnt(struct protocol_stack *stack); +-int32_t rpc_call_shadow_fd(struct protocol_stack *stack, int32_t fd, const struct sockaddr *addr, socklen_t addrlen); +-int32_t rpc_call_recvlistcnt(struct protocol_stack *stack); +-int32_t rpc_call_thread_regphase1(struct protocol_stack *stack, void *conn); +-int32_t rpc_call_thread_regphase2(struct protocol_stack *stack, void *conn); +-int32_t rpc_call_conntable(struct protocol_stack *stack, void *conn_table, uint32_t max_conn); +-int32_t rpc_call_connnum(struct protocol_stack *stack); +-int32_t rpc_call_arp(struct protocol_stack *stack, struct rte_mbuf *mbuf); +-int32_t rpc_call_socket(int32_t domain, int32_t type, int32_t protocol); +-int32_t rpc_call_close(int32_t fd); +-int32_t rpc_call_shutdown(int fd, int how); +-int32_t rpc_call_bind(int32_t fd, const struct sockaddr *addr, socklen_t addrlen); +-int32_t rpc_call_listen(int s, int backlog); +-int32_t rpc_call_accept(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags); +-int32_t rpc_call_connect(int fd, const struct sockaddr *addr, socklen_t addrlen); +-int32_t rpc_call_send(int fd, const void *buf, size_t len, int flags); +-int32_t rpc_call_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen); +-int32_t rpc_call_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen); +-int32_t rpc_call_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen); +-int32_t rpc_call_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen); +-int32_t rpc_call_fcntl(int fd, int cmd, long val); +-int32_t rpc_call_ioctl(int fd, long cmd, void *argp); +-int32_t rpc_call_replenish(struct protocol_stack *stack, struct lwip_sock *sock); +-int32_t rpc_call_mbufpoolsize(struct protocol_stack *stack); +-int32_t rpc_call_rpcpool_size(struct protocol_stack *stack); +-int32_t rpc_call_stack_exit(struct protocol_stack *stack); ++struct rpc_stats *rpc_stats_get(void); ++int32_t rpc_msgcnt(rpc_queue *queue); ++int rpc_poll_msg(rpc_queue *queue, uint32_t max_num); ++void rpc_call_clean_epoll(rpc_queue *queue, void *wakeup); ++int32_t rpc_call_shadow_fd(rpc_queue *queue, int32_t fd, const struct sockaddr *addr, socklen_t addrlen); ++int32_t rpc_call_recvlistcnt(rpc_queue *queue); ++int32_t rpc_call_thread_regphase1(rpc_queue *queue, void *conn); ++int32_t rpc_call_thread_regphase2(rpc_queue *queue, void *conn); ++int32_t rpc_call_conntable(rpc_queue *queue, void *conn_table, uint32_t max_conn); ++int32_t rpc_call_connnum(rpc_queue *queue); ++int32_t rpc_call_arp(rpc_queue *queue, void *mbuf); ++int32_t rpc_call_socket(rpc_queue *queue, int32_t domain, int32_t type, int32_t protocol); ++int32_t rpc_call_close(rpc_queue *queue, int32_t fd); ++int32_t rpc_call_shutdown(rpc_queue *queue, int fd, int how); ++int32_t rpc_call_bind(rpc_queue *queue, int32_t fd, const struct sockaddr *addr, socklen_t addrlen); ++int32_t rpc_call_listen(rpc_queue *queue, int s, int backlog); ++int32_t rpc_call_accept(rpc_queue *queue, int fd, struct sockaddr *addr, socklen_t *addrlen, int flags); ++int32_t rpc_call_connect(rpc_queue *queue, int fd, const struct sockaddr *addr, socklen_t addrlen); ++int32_t rpc_call_send(rpc_queue *queue, int fd, const void *buf, size_t len, int flags); ++int32_t rpc_call_getpeername(rpc_queue *queue, int fd, struct sockaddr *addr, socklen_t *addrlen); ++int32_t rpc_call_getsockname(rpc_queue *queue, int fd, struct sockaddr *addr, socklen_t *addrlen); ++int32_t rpc_call_getsockopt(rpc_queue *queue, int fd, int level, int optname, void *optval, socklen_t *optlen); ++int32_t rpc_call_setsockopt(rpc_queue *queue, int fd, int level, int optname, const void *optval, socklen_t optlen); ++int32_t rpc_call_fcntl(rpc_queue *queue, int fd, int cmd, long val); ++int32_t rpc_call_ioctl(rpc_queue *queue, int fd, long cmd, void *argp); ++int32_t rpc_call_replenish(rpc_queue *queue, void *sock); ++int32_t rpc_call_mbufpoolsize(rpc_queue *queue); ++int32_t rpc_call_stack_exit(rpc_queue *queue); + +-static inline __attribute__((always_inline)) void rpc_call(lockless_queue *queue, struct rpc_msg *msg) ++static inline __attribute__((always_inline)) void rpc_call(rpc_queue *queue, struct rpc_msg *msg) + { + lockless_queue_mpsc_push(queue, &msg->queue_node); + } +diff --git a/src/lstack/netif/lstack_ethdev.c b/src/lstack/netif/lstack_ethdev.c +index 4d6f620..965de58 100644 +--- a/src/lstack/netif/lstack_ethdev.c ++++ b/src/lstack/netif/lstack_ethdev.c +@@ -529,7 +529,7 @@ void transfer_tcp_to_thread(struct rte_mbuf *mbuf, uint16_t stk_idx) + struct protocol_stack *stack = get_protocol_stack_group()->stacks[stk_idx]; + int ret = -1; + while(ret != 0) { +- ret = rpc_call_arp(stack, mbuf); ++ ret = rpc_call_arp(&stack->rpc_queue, mbuf); + printf("transfer_tcp_to_thread, ret : %d \n", ret); + } + } +@@ -550,10 +550,10 @@ void parse_arp_and_transefer(char* buf) + } + copy_mbuf(mbuf_copy, mbuf); + +- ret = rpc_call_arp(stack, mbuf_copy); ++ ret = rpc_call_arp(&stack->rpc_queue, mbuf_copy); + + while (ret != 0) { +- rpc_call_arp(stack, mbuf_copy);; ++ rpc_call_arp(&stack->rpc_queue, mbuf_copy); + } + } + } +diff --git a/src/ltran/ltran_dfx.c b/src/ltran/ltran_dfx.c +index 9f12096..bea0dc7 100644 +--- a/src/ltran/ltran_dfx.c ++++ b/src/ltran/ltran_dfx.c +@@ -646,8 +646,7 @@ static void show_lstack_stats(struct gazelle_stack_dfx_data *lstack_stat) + printf("call_alloc_fail: %-12"PRIu64" ", lstack_stat->data.pkts.call_alloc_fail); + printf("call_null: %-18"PRIu64" \n", lstack_stat->data.pkts.stack_stat.call_null); + printf("send_pkts_fail: %-13"PRIu64" ", lstack_stat->data.pkts.stack_stat.send_pkts_fail); +- printf("mbuf_pool_freecnt: %-10"PRIu32" ", lstack_stat->data.pkts.mbufpool_avail_cnt); +- printf("rpc_pool_freecnt: %-12"PRIu32" \n", lstack_stat->data.pkts.rpcpool_avail_cnt); ++ printf("mbuf_pool_freecnt: %-10"PRIu32" \n", lstack_stat->data.pkts.mbufpool_avail_cnt); + printf("accpet_fail: %-16"PRIu64" ", lstack_stat->data.pkts.stack_stat.accept_fail); + printf("sock_rx_drop: %-15"PRIu64" ", lstack_stat->data.pkts.stack_stat.sock_rx_drop); + printf("sock_tx_merge: %-16"PRIu64" \n", lstack_stat->data.pkts.stack_stat.sock_tx_merge); +-- +2.27.0 + diff --git a/0136-readv-return-1-errno-is-EAGAIN-when-recvring-no-data.patch b/0136-readv-return-1-errno-is-EAGAIN-when-recvring-no-data.patch new file mode 100644 index 0000000..0d311c8 --- /dev/null +++ b/0136-readv-return-1-errno-is-EAGAIN-when-recvring-no-data.patch @@ -0,0 +1,30 @@ +From 61888e1e0d4810d3f0dbe5aa1d43a2dbcf2ad0f5 Mon Sep 17 00:00:00 2001 +From: jiangheng +Date: Wed, 21 Feb 2024 07:44:59 +0800 +Subject: [PATCH] readv return -1, errno is EAGAIN when recvring no data + +--- + src/lstack/api/lstack_rtw_api.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/src/lstack/api/lstack_rtw_api.c b/src/lstack/api/lstack_rtw_api.c +index 8498b8e..e50fe37 100644 +--- a/src/lstack/api/lstack_rtw_api.c ++++ b/src/lstack/api/lstack_rtw_api.c +@@ -127,12 +127,7 @@ ssize_t rtw_readv(int s, const struct iovec *iov, int iovcnt) + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; +- ssize_t result = do_lwip_recvmsg_from_stack(s, &msg, 0); +- if (result == -1 && errno == EAGAIN) { +- errno = 0; +- return 0; +- } +- return result; ++ return do_lwip_recvmsg_from_stack(s, &msg, 0); + } + + ssize_t rtw_write(int s, const void *mem, size_t size) +-- +2.27.0 + diff --git a/0137-split-the-flow-fules-related-functions-into-separate.patch b/0137-split-the-flow-fules-related-functions-into-separate.patch new file mode 100644 index 0000000..1bf499d --- /dev/null +++ b/0137-split-the-flow-fules-related-functions-into-separate.patch @@ -0,0 +1,1707 @@ +From 409b6155a1ec9324bd68aae97a07e33560c19028 Mon Sep 17 00:00:00 2001 +From: jiangheng +Date: Wed, 21 Feb 2024 08:05:03 +0800 +Subject: [PATCH] split the flow fules related functions into separate file + +--- + src/lstack/core/lstack_init.c | 1 + + src/lstack/core/lstack_protocol_stack.c | 25 +- + src/lstack/include/lstack_ethdev.h | 27 - + src/lstack/include/lstack_flow.h | 51 ++ + src/lstack/include/lstack_vdev.h | 9 - + src/lstack/netif/dir.mk | 2 +- + src/lstack/netif/lstack_ethdev.c | 687 +----------------------- + src/lstack/netif/lstack_flow.c | 680 +++++++++++++++++++++++ + src/lstack/netif/lstack_vdev.c | 1 + + 9 files changed, 747 insertions(+), 736 deletions(-) + create mode 100644 src/lstack/include/lstack_flow.h + create mode 100644 src/lstack/netif/lstack_flow.c + +diff --git a/src/lstack/core/lstack_init.c b/src/lstack/core/lstack_init.c +index 31fd91d..d22a295 100644 +--- a/src/lstack/core/lstack_init.c ++++ b/src/lstack/core/lstack_init.c +@@ -48,6 +48,7 @@ + #include "lstack_protocol_stack.h" + #include "lstack_preload.h" + #include "lstack_wrap.h" ++#include "lstack_flow.h" + + static void check_process_start(void) + { +diff --git a/src/lstack/core/lstack_protocol_stack.c b/src/lstack/core/lstack_protocol_stack.c +index 18e5df7..a545b73 100644 +--- a/src/lstack/core/lstack_protocol_stack.c ++++ b/src/lstack/core/lstack_protocol_stack.c +@@ -454,14 +454,12 @@ int stack_polling(uint32_t wakeup_tick) + { + int force_quit; + struct cfg_params *cfg = get_global_cfg_params(); +- uint8_t use_ltran_flag = cfg->use_ltran; + #if RTE_VERSION < RTE_VERSION_NUM(23, 11, 0, 0) + bool kni_switch = cfg->kni_switch; + #endif + bool use_sockmap = cfg->use_sockmap; + bool stack_mode_rtc = cfg->stack_mode_rtc; + uint32_t rpc_number = cfg->rpc_number; +- uint32_t nic_read_number = cfg->nic_read_number; + uint32_t read_connect_number = cfg->read_connect_number; + struct protocol_stack *stack = get_protocol_stack(); + +@@ -469,7 +467,7 @@ int stack_polling(uint32_t wakeup_tick) + rpc_poll_msg(&stack->dfx_rpc_queue, 2); + force_quit = rpc_poll_msg(&stack->rpc_queue, rpc_number); + +- gazelle_eth_dev_poll(stack, use_ltran_flag, nic_read_number); ++ eth_dev_poll(); + sys_timer_run(); + if (cfg->low_power_mod != 0) { + low_power_idling(stack); +@@ -525,10 +523,6 @@ static void* gazelle_stack_thread(void *arg) + } + sem_post(&g_stack_group.sem_stack_setup); + +- if (!use_ltran() && queue_id == 0) { +- init_listen_and_user_ports(); +- } +- + LSTACK_LOG(INFO, LSTACK, "stack_%02hu init success\n", queue_id); + if (get_global_cfg_params()->stack_mode_rtc) { + return NULL; +@@ -545,12 +539,6 @@ static void* gazelle_stack_thread(void *arg) + return NULL; + } + +-static void gazelle_listen_thread(void *arg) +-{ +- struct cfg_params *cfg_param = get_global_cfg_params(); +- recv_pkts_from_other_process(cfg_param->process_idx, arg); +-} +- + int32_t stack_group_init_mempool(void) + { + struct cfg_params *global_cfg_parmas = get_global_cfg_params(); +@@ -611,17 +599,6 @@ int32_t stack_group_init(void) + } + } + +- /* run to completion mode does not currently support multiple process */ +- if (!use_ltran() && !get_global_cfg_params()->stack_mode_rtc) { +- char name[PATH_MAX]; +- sem_init(&stack_group->sem_listen_thread, 0, 0); +- sprintf_s(name, sizeof(name), "%s", "listen_thread"); +- struct sys_thread *thread = sys_thread_new(name, gazelle_listen_thread, +- (void*)(&stack_group->sem_listen_thread), 0, 0); +- free(thread); +- sem_wait(&stack_group->sem_listen_thread); +- } +- + return 0; + } + +diff --git a/src/lstack/include/lstack_ethdev.h b/src/lstack/include/lstack_ethdev.h +index 3252906..0c3d906 100644 +--- a/src/lstack/include/lstack_ethdev.h ++++ b/src/lstack/include/lstack_ethdev.h +@@ -16,25 +16,6 @@ + #include + #include + +-#define INVAILD_PROCESS_IDX 255 +- +-enum port_type { +- PORT_LISTEN, +- PORT_CONNECT, +-}; +- +-enum PACKET_TRANSFER_TYPE { +- TRANSFER_KERNEL = -1, +- TRANSFER_OTHER_THREAD, +- TRANSFER_CURRENT_THREAD, +-}; +- +-enum TRANSFER_MESSAGE_RESULT { +- CONNECT_ERROR = -2, +- REPLY_ERROR = -1, +- TRANSFER_SUCESS = 0, +-}; +- + struct protocol_stack; + struct rte_mbuf; + struct lstack_dev_ops { +@@ -44,21 +25,13 @@ struct lstack_dev_ops { + + int32_t ethdev_init(struct protocol_stack *stack); + int32_t eth_dev_poll(void); +-int32_t gazelle_eth_dev_poll(struct protocol_stack *stack, uint8_t use_ltran_flag, uint32_t nic_read_number); + void eth_dev_recv(struct rte_mbuf *mbuf, struct protocol_stack *stack); + +-int recv_pkts_from_other_process(int process_index, void* arg); +-int32_t check_params_from_primary(void); +- + #if RTE_VERSION < RTE_VERSION_NUM(23, 11, 0, 0) + void kni_handle_rx(uint16_t port_id); + void kni_handle_tx(struct rte_mbuf *mbuf); + #endif + +-void delete_user_process_port(uint16_t dst_port, enum port_type type); +-void add_user_process_port(uint16_t dst_port, uint8_t process_idx, enum port_type type); +-void delete_flow_director(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port); +-void config_flow_director(uint16_t queue_id, uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port); + void netif_poll(struct netif *netif); + + #endif /* __GAZELLE_ETHDEV_H__ */ +diff --git a/src/lstack/include/lstack_flow.h b/src/lstack/include/lstack_flow.h +new file mode 100644 +index 0000000..ad35cdf +--- /dev/null ++++ b/src/lstack/include/lstack_flow.h +@@ -0,0 +1,51 @@ ++/* ++* 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_FLOW_H__ ++#define __LSTACK_FLOW_H__ ++ ++#include ++ ++enum port_type { ++ PORT_LISTEN, ++ PORT_CONNECT, ++}; ++ ++enum PACKET_TRANSFER_TYPE { ++ TRANSFER_KERNEL = -1, ++ TRANSFER_OTHER_THREAD, ++ TRANSFER_CURRENT_THREAD, ++}; ++ ++enum TRANSFER_MESSAGE_RESULT { ++ CONNECT_ERROR = -2, ++ REPLY_ERROR = -1, ++ TRANSFER_SUCESS = 0, ++}; ++ ++int distribute_pakages(struct rte_mbuf *mbuf); ++void flow_init(void); ++int32_t check_params_from_primary(void); ++ ++int recv_pkts_from_other_process(int process_index, void* arg); ++void transfer_delete_rule_info_to_process0(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port); ++void transfer_create_rule_info_to_process0(uint16_t queue_id, uint32_t src_ip, ++ uint32_t dst_ip, uint16_t src_port, uint16_t dst_port); ++void transfer_add_or_delete_listen_port_to_process0(uint16_t listen_port, uint8_t process_idx, uint8_t is_add); ++void transfer_arp_to_other_process(struct rte_mbuf *mbuf); ++ ++void add_user_process_port(uint16_t dst_port, uint8_t process_idx, enum port_type type); ++void delete_user_process_port(uint16_t dst_port, enum port_type type); ++ ++void gazelle_listen_thread(void *arg); ++ ++#endif +diff --git a/src/lstack/include/lstack_vdev.h b/src/lstack/include/lstack_vdev.h +index 007eec7..4e5d191 100644 +--- a/src/lstack/include/lstack_vdev.h ++++ b/src/lstack/include/lstack_vdev.h +@@ -13,19 +13,10 @@ + #ifndef _GAZELLE_VDEV_H_ + #define _GAZELLE_VDEV_H_ + +-#include +- + struct lstack_dev_ops; + struct gazelle_quintuple; + enum reg_ring_type; + void vdev_dev_ops_init(struct lstack_dev_ops *dev_ops); + int vdev_reg_xmit(enum reg_ring_type type, struct gazelle_quintuple *qtuple); + +-int recv_pkts_from_other_process(int process_index, void* arg); +-void transfer_delete_rule_info_to_process0(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port); +-void transfer_create_rule_info_to_process0(uint16_t queue_id, uint32_t src_ip, +- uint32_t dst_ip, uint16_t src_port, uint16_t dst_port); +-void transfer_add_or_delete_listen_port_to_process0(uint16_t listen_port, uint8_t process_idx, uint8_t is_add); +-void init_listen_and_user_ports(); +- + #endif /* _GAZELLE_VDEV_H_ */ +diff --git a/src/lstack/netif/dir.mk b/src/lstack/netif/dir.mk +index ec7c4ad..20fb5d6 100644 +--- a/src/lstack/netif/dir.mk ++++ b/src/lstack/netif/dir.mk +@@ -8,5 +8,5 @@ + # PURPOSE. + # See the Mulan PSL v2 for more details. + +-SRC = lstack_ethdev.c lstack_vdev.c ++SRC = lstack_ethdev.c lstack_vdev.c lstack_flow.c + $(eval $(call register_dir, netif, $(SRC))) +diff --git a/src/lstack/netif/lstack_ethdev.c b/src/lstack/netif/lstack_ethdev.c +index 25c94eb..2e938b0 100644 +--- a/src/lstack/netif/lstack_ethdev.c ++++ b/src/lstack/netif/lstack_ethdev.c +@@ -10,74 +10,36 @@ + * See the Mulan PSL v2 for more details. + */ + +-#include +-#include +- + #include + #include + #if RTE_VERSION < RTE_VERSION_NUM(23, 11, 0, 0) + #include + #endif + #include +-#include +-#include + +-#include + #include + #include + #include + #include +-#include +-#include + + #include +-#include +-#include + ++#include "dpdk_common.h" + #include "lstack_cfg.h" + #include "lstack_vdev.h" + #include "lstack_stack_stat.h" + #include "lstack_log.h" + #include "lstack_dpdk.h" + #include "lstack_lwip.h" +-#include "dpdk_common.h" + #include "lstack_protocol_stack.h" + #include "lstack_thread_rpc.h" ++#include "lstack_flow.h" + #include "lstack_ethdev.h" + + /* FRAME_MTU + 14byte header */ + #define MBUF_MAX_LEN 1514 +-#define MAX_PATTERN_NUM 4 +-#define MAX_ACTION_NUM 2 +-#define FULL_MASK 0xffffffff /* full mask */ +-#define EMPTY_MASK 0x0 /* empty mask */ +-#define LSTACK_MBUF_LEN 64 +-#define TRANSFER_TCP_MUBF_LEN (LSTACK_MBUF_LEN + 3) +-#define DELETE_FLOWS_PARAMS_NUM 3 +-#define DELETE_FLOWS_PARAMS_LENGTH 30 +-#define CREATE_FLOWS_PARAMS_NUM 6 +-#define CREATE_FLOWS_PARAMS_LENGTH 60 +-#define ADD_OR_DELETE_LISTEN_PORT_PARAMS_LENGTH 25 +-#define ADD_OR_DELETE_LISTEN_PORT_PARAMS_NUM 3 +-#define REPLY_LEN 10 +-#define SUCCESS_REPLY "success" +-#define ERROR_REPLY "error" + #define PACKET_READ_SIZE 32 + +-#define GET_LSTACK_NUM 14 +-#define GET_LSTACK_NUM_STRING "get_lstack_num" +- +-#define SERVER_PATH "/var/run/gazelle/server.socket" +-#define SPLIT_DELIM "," +- +-#define UNIX_TCP_PORT_MAX 65535 +- +-#define IPV4_VERSION_OFFSET 4 +-#define IPV4_VERSION 4 +- +-static uint8_t g_user_ports[UNIX_TCP_PORT_MAX] = {INVAILD_PROCESS_IDX, }; +-static uint8_t g_listen_ports[UNIX_TCP_PORT_MAX] = {INVAILD_PROCESS_IDX, }; +- + void eth_dev_recv(struct rte_mbuf *mbuf, struct protocol_stack *stack) + { + int32_t ret; +@@ -126,636 +88,6 @@ void eth_dev_recv(struct rte_mbuf *mbuf, struct protocol_stack *stack) + } + } + +-int32_t eth_dev_poll(void) +-{ +- uint32_t nr_pkts; +- struct cfg_params *cfg = get_global_cfg_params(); +- struct protocol_stack *stack = get_protocol_stack(); +- +- nr_pkts = stack->dev_ops.rx_poll(stack, stack->pkts, cfg->nic_read_number); +- if (nr_pkts == 0) { +- return 0; +- } +- +- if (!cfg->use_ltran && get_protocol_stack_group()->latency_start) { +- uint64_t time_stamp = get_current_time(); +- time_stamp_into_mbuf(nr_pkts, stack->pkts, time_stamp); +- } +- +- for (uint32_t i = 0; i < nr_pkts; i++) { +- /* copy arp into other stack */ +- if (!cfg->use_ltran) { +- struct rte_ether_hdr *ethh = rte_pktmbuf_mtod(stack->pkts[i], struct rte_ether_hdr *); +- if (unlikely(RTE_BE16(RTE_ETHER_TYPE_ARP) == ethh->ether_type)) { +- stack_broadcast_arp(stack->pkts[i], stack); +- } +- } +- +- eth_dev_recv(stack->pkts[i], stack); +- } +- +- stack->stats.rx += nr_pkts; +- +- return nr_pkts; +-} +- +-/* flow rule map */ +-#define RULE_KEY_LEN 23 +-struct flow_rule { +- char rule_key[RULE_KEY_LEN]; +- struct rte_flow *flow; +- UT_hash_handle hh; +-}; +- +-static uint16_t g_flow_num = 0; +-struct flow_rule *g_flow_rules = NULL; +-struct flow_rule *find_rule(char *rule_key) +-{ +- struct flow_rule *fl; +- HASH_FIND_STR(g_flow_rules, rule_key, fl); +- return fl; +-} +- +-void add_rule(char* rule_key, struct rte_flow *flow) +-{ +- struct flow_rule *rule; +- HASH_FIND_STR(g_flow_rules, rule_key, rule); +- if (rule == NULL) { +- rule = (struct flow_rule*)malloc(sizeof(struct flow_rule)); +- strcpy_s(rule->rule_key, RULE_KEY_LEN, rule_key); +- HASH_ADD_STR(g_flow_rules, rule_key, rule); +- } +- rule->flow = flow; +-} +- +-void delete_rule(char* rule_key) +-{ +- struct flow_rule *rule = NULL; +- HASH_FIND_STR(g_flow_rules, rule_key, rule); +- if (rule != NULL) { +- HASH_DEL(g_flow_rules, rule); +- free(rule); +- } +-} +- +-void init_listen_and_user_ports(void) +-{ +- memset_s(g_user_ports, sizeof(g_user_ports), INVAILD_PROCESS_IDX, sizeof(g_user_ports)); +- memset_s(g_listen_ports, sizeof(g_listen_ports), INVAILD_PROCESS_IDX, sizeof(g_listen_ports)); +-} +- +-int transfer_pkt_to_other_process(char *buf, int process_index, int write_len, bool need_reply) +-{ +- /* other process queue_id */ +- struct sockaddr_un serun; +- int sockfd; +- int ret = 0; +- +- sockfd = posix_api->socket_fn(AF_UNIX, SOCK_STREAM, 0); +- memset_s(&serun, sizeof(serun), 0, sizeof(serun)); +- serun.sun_family = AF_UNIX; +- sprintf_s(serun.sun_path, PATH_MAX, "%s%d", SERVER_PATH, process_index); +- int32_t len = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path); +- if (posix_api->connect_fn(sockfd, (struct sockaddr *)&serun, len) < 0) { +- return CONNECT_ERROR; +- } +- posix_api->write_fn(sockfd, buf, write_len); +- if (need_reply) { +- char reply_message[REPLY_LEN]; +- int32_t read_result = posix_api->read_fn(sockfd, reply_message, REPLY_LEN); +- if (read_result > 0) { +- if (strcmp(reply_message, SUCCESS_REPLY) == 0) { +- ret = TRANSFER_SUCESS; +- } else if (strcmp(reply_message, ERROR_REPLY) == 0) { +- ret = REPLY_ERROR; +- } else { +- ret = atoi(reply_message); +- } +- } else { +- ret = REPLY_ERROR; +- } +- } +- posix_api->close_fn(sockfd); +- +- return ret; +-} +- +-int32_t check_params_from_primary(void) +-{ +- struct cfg_params *cfg = get_global_cfg_params(); +- if (cfg->is_primary) { +- return 0; +- } +- // check lstack num +- char get_lstack_num[GET_LSTACK_NUM]; +- sprintf_s(get_lstack_num, GET_LSTACK_NUM, "%s", GET_LSTACK_NUM_STRING); +- int32_t ret = transfer_pkt_to_other_process(get_lstack_num, 0, GET_LSTACK_NUM, true); +- if (ret != cfg->num_cpu) { +- return -1; +- } +- return 0; +-} +- +-struct rte_flow *create_flow_director(uint16_t port_id, uint16_t queue_id, +- uint32_t src_ip, uint32_t dst_ip, +- uint16_t src_port, uint16_t dst_port, +- struct rte_flow_error *error) +-{ +- struct rte_flow_attr attr; +- struct rte_flow_item pattern[MAX_PATTERN_NUM]; +- struct rte_flow_action action[MAX_ACTION_NUM]; +- struct rte_flow *flow = NULL; +- struct rte_flow_action_queue queue = { .index = queue_id }; +- struct rte_flow_item_ipv4 ip_spec; +- struct rte_flow_item_ipv4 ip_mask; +- +- struct rte_flow_item_tcp tcp_spec; +- struct rte_flow_item_tcp tcp_mask; +- int res; +- +- memset_s(pattern, sizeof(pattern), 0, sizeof(pattern)); +- memset_s(action, sizeof(action), 0, sizeof(action)); +- +- /* +- * set the rule attribute. +- * in this case only ingress packets will be checked. +- */ +- memset_s(&attr, sizeof(struct rte_flow_attr), 0, sizeof(struct rte_flow_attr)); +- attr.ingress = 1; +- +- /* +- * create the action sequence. +- * one action only, move packet to queue +- */ +- action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE; +- action[0].conf = &queue; +- action[1].type = RTE_FLOW_ACTION_TYPE_END; +- +- // not limit eth header +- pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; +- +- // ip header +- memset_s(&ip_spec, sizeof(struct rte_flow_item_ipv4), 0, sizeof(struct rte_flow_item_ipv4)); +- memset_s(&ip_mask, sizeof(struct rte_flow_item_ipv4), 0, sizeof(struct rte_flow_item_ipv4)); +- ip_spec.hdr.dst_addr = dst_ip; +- ip_mask.hdr.dst_addr = FULL_MASK; +- ip_spec.hdr.src_addr = src_ip; +- ip_mask.hdr.src_addr = FULL_MASK; +- pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; +- pattern[1].spec = &ip_spec; +- pattern[1].mask = &ip_mask; +- +- // tcp header, full mask 0xffff +- memset_s(&tcp_spec, sizeof(struct rte_flow_item_tcp), 0, sizeof(struct rte_flow_item_tcp)); +- memset_s(&tcp_mask, sizeof(struct rte_flow_item_tcp), 0, sizeof(struct rte_flow_item_tcp)); +- pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP; // 2: pattern 2 is tcp header +- tcp_spec.hdr.src_port = src_port; +- tcp_spec.hdr.dst_port = dst_port; +- tcp_mask.hdr.src_port = rte_flow_item_tcp_mask.hdr.src_port; +- tcp_mask.hdr.dst_port = rte_flow_item_tcp_mask.hdr.dst_port; +- pattern[2].spec = &tcp_spec; +- pattern[2].mask = &tcp_mask; +- +- /* the final level must be always type end */ +- pattern[3].type = RTE_FLOW_ITEM_TYPE_END; +- res = rte_flow_validate(port_id, &attr, pattern, action, error); +- if (!res) { +- flow = rte_flow_create(port_id, &attr, pattern, action, error); +- } else { +- LSTACK_LOG(ERR, LSTACK, "rte_flow_create.rte_flow_validate error, res %d \n", res); +- } +- +- return flow; +-} +- +-void config_flow_director(uint16_t queue_id, uint32_t src_ip, +- uint32_t dst_ip, uint16_t src_port, uint16_t dst_port) +-{ +- uint16_t port_id = get_protocol_stack_group()->port_id; +- char rule_key[RULE_KEY_LEN] = {0}; +- sprintf_s(rule_key, sizeof(rule_key), "%u_%u_%u", src_ip, src_port, dst_port); +- struct flow_rule *fl_exist = find_rule(rule_key); +- if (fl_exist != NULL) { +- return; +- } +- +- LSTACK_LOG(INFO, LSTACK, +- "config_flow_director, flow queue_id %u, src_ip %u,src_port_ntohs:%u, dst_port_ntohs:%u\n", +- queue_id, src_ip, ntohs(src_port), ntohs(dst_port)); +- +- struct rte_flow_error error; +- struct rte_flow *flow = create_flow_director(port_id, queue_id, src_ip, dst_ip, src_port, dst_port, &error); +- if (!flow) { +- LSTACK_LOG(ERR, LSTACK,"flow can not be created. queue_id %u, src_ip %u, src_port %u," +- "dst_port %u, dst_port_ntohs :%u, type %d. message: %s\n", +- queue_id, src_ip, src_port, dst_port, ntohs(dst_port), +- error.type, error.message ? error.message : "(no stated reason)"); +- return; +- } +- __sync_fetch_and_add(&g_flow_num, 1); +- add_rule(rule_key, flow); +-} +- +-void delete_flow_director(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port) +-{ +- uint16_t port_id = get_protocol_stack_group()->port_id; +- char rule_key[RULE_KEY_LEN] = {0}; +- sprintf_s(rule_key, RULE_KEY_LEN, "%u_%u_%u",dst_ip, dst_port, src_port); +- struct flow_rule *fl = find_rule(rule_key); +- +- if(fl != NULL){ +- struct rte_flow_error error; +- int ret = rte_flow_destroy(port_id, fl->flow, &error); +- if(ret != 0){ +- LSTACK_LOG(ERR, LSTACK, "Flow can't be delete %d message: %s\n", +- error.type, error.message ? error.message : "(no stated reason)"); +- } +- delete_rule(rule_key); +- __sync_fetch_and_sub(&g_flow_num, 1); +- } +-} +- +-/* if process 0, delete directly, else transfer 'dst_ip,src_port,dst_port' to process 0. */ +-void transfer_delete_rule_info_to_process0(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port) +-{ +- if (get_global_cfg_params()->is_primary) { +- delete_flow_director(dst_ip, src_port, dst_port); +- } else { +- char process_server_path[DELETE_FLOWS_PARAMS_LENGTH]; +- sprintf_s(process_server_path, DELETE_FLOWS_PARAMS_LENGTH, "%u%s%u%s%u", +- dst_ip, SPLIT_DELIM, src_port, SPLIT_DELIM, dst_port); +- int ret = transfer_pkt_to_other_process(process_server_path, 0, DELETE_FLOWS_PARAMS_LENGTH, false); +- if(ret != TRANSFER_SUCESS){ +- LSTACK_LOG(ERR, LSTACK, "error. tid %d. dst_ip %u, src_port: %u, dst_port %u\n", +- rte_gettid(), dst_ip, src_port, dst_port); +- } +- } +-} +- +-// if process 0, add directly, else transfer 'src_ip,dst_ip,src_port,dst_port,queue_id' to process 0. +-void transfer_create_rule_info_to_process0(uint16_t queue_id, uint32_t src_ip, +- uint32_t dst_ip, uint16_t src_port, +- uint16_t dst_port) +-{ +- char process_server_path[CREATE_FLOWS_PARAMS_LENGTH]; +- /* exchage src_ip and dst_ip, src_port and dst_port */ +- uint8_t process_idx = get_global_cfg_params()->process_idx; +- sprintf_s(process_server_path, CREATE_FLOWS_PARAMS_LENGTH, "%u%s%u%s%u%s%u%s%u%s%u", +- dst_ip, SPLIT_DELIM, src_ip, SPLIT_DELIM, +- dst_port, SPLIT_DELIM, src_port, SPLIT_DELIM, +- queue_id, SPLIT_DELIM, process_idx); +- int ret = transfer_pkt_to_other_process(process_server_path, 0, CREATE_FLOWS_PARAMS_LENGTH, true); +- if (ret != TRANSFER_SUCESS) { +- LSTACK_LOG(ERR, LSTACK, "error. tid %d. src_ip %u, dst_ip %u, src_port: %u, dst_port %u," +- "queue_id %u, process_idx %u\n", +- rte_gettid(), src_ip, dst_ip, src_port, dst_port, queue_id, process_idx); +- } +-} +- +-void transfer_add_or_delete_listen_port_to_process0(uint16_t listen_port, uint8_t process_idx, uint8_t is_add) +-{ +- char process_server_path[ADD_OR_DELETE_LISTEN_PORT_PARAMS_LENGTH]; +- sprintf_s(process_server_path, ADD_OR_DELETE_LISTEN_PORT_PARAMS_LENGTH, +- "%u%s%u%s%u", listen_port, SPLIT_DELIM, process_idx, SPLIT_DELIM, is_add); +- int ret = transfer_pkt_to_other_process(process_server_path, 0, ADD_OR_DELETE_LISTEN_PORT_PARAMS_LENGTH, true); +- if(ret != TRANSFER_SUCESS) { +- LSTACK_LOG(ERR, LSTACK, "error. tid %d. listen_port %u, process_idx %u\n", +- rte_gettid(), listen_port, process_idx); +- } +-} +- +-static int str_to_array(char *args, uint32_t *array, int size) +-{ +- int val; +- uint16_t cnt = 0; +- char *elem = NULL; +- char *next_token = NULL; +- +- memset_s(array, sizeof(*array) * size, 0, sizeof(*array) * size); +- elem = strtok_s((char *)args, SPLIT_DELIM, &next_token); +- while (elem != NULL) { +- if (cnt >= size) { +- return -1; +- } +- val = atoi(elem); +- if (val < 0) { +- return -1; +- } +- array[cnt] = (uint32_t)val; +- cnt++; +- +- elem = strtok_s(NULL, SPLIT_DELIM, &next_token); +- } +- +- return cnt; +-} +- +-void parse_and_delete_rule(char* buf) +-{ +- uint32_t array[DELETE_FLOWS_PARAMS_NUM]; +- str_to_array(buf, array, DELETE_FLOWS_PARAMS_NUM); +- uint32_t dst_ip = array[0]; +- uint16_t src_port = array[1]; +- uint16_t dst_port = array[2]; +- delete_flow_director(dst_ip, src_port, dst_port); +-} +- +-void add_user_process_port(uint16_t dst_port, uint8_t process_idx, enum port_type type) +-{ +- if (type == PORT_LISTEN) { +- g_listen_ports[dst_port] = process_idx; +- } else { +- g_user_ports[dst_port] = process_idx; +- } +-} +- +-void delete_user_process_port(uint16_t dst_port, enum port_type type) +-{ +- if (type == PORT_LISTEN) { +- g_listen_ports[dst_port] = INVAILD_PROCESS_IDX; +- } else { +- g_user_ports[dst_port] = INVAILD_PROCESS_IDX; +- } +-} +- +-void parse_and_create_rule(char* buf) +-{ +- uint32_t array[CREATE_FLOWS_PARAMS_NUM]; +- str_to_array(buf, array, CREATE_FLOWS_PARAMS_NUM); +- uint32_t src_ip = array[0]; +- uint32_t dst_ip = array[1]; +- uint16_t src_port = array[2]; +- uint16_t dst_port = array[3]; +- uint16_t queue_id = array[4]; +- uint8_t process_idx = array[5]; +- config_flow_director(queue_id, src_ip, dst_ip, src_port, dst_port); +- add_user_process_port(dst_port, process_idx, PORT_CONNECT); +-} +- +-void parse_and_add_or_delete_listen_port(char* buf) +-{ +- uint32_t array[ADD_OR_DELETE_LISTEN_PORT_PARAMS_NUM]; +- str_to_array(buf, array, ADD_OR_DELETE_LISTEN_PORT_PARAMS_NUM); +- uint16_t listen_port = array[0]; +- uint8_t process_idx = array[1]; +- uint8_t is_add = array[2]; +- if (is_add == 1) { +- add_user_process_port(listen_port, process_idx, PORT_LISTEN); +- } else { +- delete_user_process_port(listen_port, PORT_LISTEN); +- } +- +-} +- +-void transfer_arp_to_other_process(struct rte_mbuf *mbuf) +-{ +- struct cfg_params *cfgs = get_global_cfg_params(); +- +- for(int i = 1; i < cfgs->num_process; i++){ +- char arp_mbuf[LSTACK_MBUF_LEN] = {0}; +- sprintf_s(arp_mbuf, sizeof(arp_mbuf), "%lu", mbuf); +- int result = transfer_pkt_to_other_process(arp_mbuf, i, LSTACK_MBUF_LEN, false); +- if (result == CONNECT_ERROR) { +- LSTACK_LOG(INFO, LSTACK,"connect process %d failed, ensure the process is started.\n", i); +- } else if (result == REPLY_ERROR) { +- LSTACK_LOG(ERR, LSTACK,"transfer arp pakages to process %d error. %m\n", i); +- } +- } +-} +- +-void transfer_tcp_to_thread(struct rte_mbuf *mbuf, uint16_t stk_idx) +-{ +- /* current process queue_id */ +- struct protocol_stack *stack = get_protocol_stack_group()->stacks[stk_idx]; +- int ret = -1; +- while(ret != 0) { +- ret = rpc_call_arp(&stack->rpc_queue, mbuf); +- printf("transfer_tcp_to_thread, ret : %d \n", ret); +- } +-} +- +-void parse_arp_and_transefer(char* buf) +-{ +- struct rte_mbuf *mbuf = (struct rte_mbuf *)atoll(buf); +- struct protocol_stack_group *stack_group = get_protocol_stack_group(); +- struct rte_mbuf *mbuf_copy = NULL; +- struct protocol_stack *stack = NULL; +- int32_t ret; +- for (int32_t i = 0; i < stack_group->stack_num; i++) { +- stack = stack_group->stacks[i]; +- ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); +- while (ret != 0) { +- ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); +- stack->stats.rx_allocmbuf_fail++; +- } +- copy_mbuf(mbuf_copy, mbuf); +- +- ret = rpc_call_arp(&stack->rpc_queue, mbuf_copy); +- +- while (ret != 0) { +- rpc_call_arp(&stack->rpc_queue, mbuf_copy); +- } +- } +-} +- +-void parse_tcp_and_transefer(char* buf) +-{ +- char *next_token = NULL; +- char *elem = strtok_s(buf, SPLIT_DELIM, &next_token); +- struct rte_mbuf *mbuf = (struct rte_mbuf *) atoll(elem); +- elem = strtok_s(NULL, SPLIT_DELIM, &next_token); +- uint16_t queue_id = atoll(elem); +- +- struct protocol_stack_group *stack_group = get_protocol_stack_group(); +- uint16_t num_queue = get_global_cfg_params()->num_queue; +- uint16_t stk_index = queue_id % num_queue; +- struct rte_mbuf *mbuf_copy = NULL; +- struct protocol_stack *stack = stack_group->stacks[stk_index]; +- +- int32_t ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); +- while (ret != 0) { +- ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, true); +- stack->stats.rx_allocmbuf_fail++; +- } +- +- copy_mbuf(mbuf_copy,mbuf); +- +- transfer_tcp_to_thread(mbuf_copy, stk_index); +-} +- +-int recv_pkts_from_other_process(int process_index, void* arg) +-{ +- struct sockaddr_un serun, cliun; +- socklen_t cliun_len; +- int listenfd, connfd, size; +- char buf[132]; +- /* socket */ +- if ((listenfd = posix_api->socket_fn(AF_UNIX, SOCK_STREAM, 0)) < 0) { +- perror("socket error"); +- return -1; +- } +- /* bind */ +- memset_s(&serun, sizeof(serun), 0, sizeof(serun)); +- serun.sun_family = AF_UNIX; +- char process_server_path[PATH_MAX]; +- sprintf_s(process_server_path, sizeof(process_server_path), "%s%d", SERVER_PATH, process_index); +- strcpy_s(serun.sun_path, sizeof(serun.sun_path), process_server_path); +- size = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path); +- unlink(process_server_path); +- if (posix_api->bind_fn(listenfd, (struct sockaddr *)&serun, size) < 0) { +- perror("bind error"); +- return -1; +- } +- if (posix_api->listen_fn(listenfd, 20) < 0) { /* 20: max backlog */ +- perror("listen error"); +- return -1; +- } +- sem_post((sem_t *)arg); +- /* block */ +- while(1) { +- cliun_len = sizeof(cliun); +- if ((connfd = posix_api->accept_fn(listenfd, (struct sockaddr *)&cliun, &cliun_len)) < 0) { +- perror("accept error"); +- continue; +- } +- while(1) { +- int n = posix_api->read_fn(connfd, buf, sizeof(buf)); +- if (n < 0) { +- perror("read error"); +- break; +- } else if (n == 0) { +- break; +- } +- +- if(n == LSTACK_MBUF_LEN) { +- /* arp */ +- parse_arp_and_transefer(buf); +- } else if (n == TRANSFER_TCP_MUBF_LEN) { +- /* tcp. lstack_mbuf_queue_id */ +- parse_tcp_and_transefer(buf); +- } else if (n == DELETE_FLOWS_PARAMS_LENGTH) { +- /* delete rule */ +- parse_and_delete_rule(buf); +- } else if(n == CREATE_FLOWS_PARAMS_LENGTH) { +- /* add rule */ +- parse_and_create_rule(buf); +- char reply_buf[REPLY_LEN]; +- sprintf_s(reply_buf, sizeof(reply_buf), "%s", SUCCESS_REPLY); +- posix_api->write_fn(connfd, reply_buf, REPLY_LEN); +- } else if (n == GET_LSTACK_NUM) { +- char reply_buf[REPLY_LEN]; +- sprintf_s(reply_buf, sizeof(reply_buf), "%d", get_global_cfg_params()->num_cpu); +- posix_api->write_fn(connfd, reply_buf, REPLY_LEN); +- } else { +- /* add port */ +- parse_and_add_or_delete_listen_port(buf); +- char reply_buf[REPLY_LEN]; +- sprintf_s(reply_buf, sizeof(reply_buf), "%s", SUCCESS_REPLY); +- posix_api->write_fn(connfd, reply_buf, REPLY_LEN); +- } +- +- } +- posix_api->close_fn(connfd); +- } +- posix_api->close_fn(listenfd); +- return 0; +-} +- +-void concat_mbuf_and_queue_id(struct rte_mbuf *mbuf, uint16_t queue_id, +- char* mbuf_and_queue_id, int write_len) +-{ +- sprintf_s(mbuf_and_queue_id, write_len, "%lu%s%u", mbuf, SPLIT_DELIM, queue_id); +-} +- +-static int mbuf_to_idx(struct rte_mbuf *mbuf, uint16_t *dst_port) +-{ +- struct rte_ether_hdr *ethh = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *); +- u16_t type = rte_be_to_cpu_16(ethh->ether_type); +- uint32_t index = 0; +- if (type == RTE_ETHER_TYPE_IPV4) { +- struct rte_ipv4_hdr *iph = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr)); +- uint8_t ip_version = (iph->version_ihl & 0xf0) >> IPV4_VERSION_OFFSET; +- if (likely(ip_version == IPV4_VERSION)) { +- if (likely(iph->next_proto_id == IPPROTO_TCP)) { +- struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *, +- sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr)); +- *dst_port = tcp_hdr->dst_port; +- +- if (unlikely(tcp_hdr->tcp_flags == TCP_SYN)) { +- uint32_t src_ip = iph->src_addr; +- uint16_t src_port = tcp_hdr->src_port; +- index = rte_jhash_3words(src_ip, src_port | ((*dst_port) << 16), 0, 0); +- } else { +- return -1; +- } +- } +- } +- } else if (type == RTE_ETHER_TYPE_IPV6) { +- struct rte_ipv6_hdr *iph = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv6_hdr *, sizeof(struct rte_ether_hdr)); +- if (likely(iph->proto == IPPROTO_TCP)) { +- struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *, +- sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr)); +- *dst_port = tcp_hdr->dst_port; +- +- if (unlikely(tcp_hdr->tcp_flags == TCP_SYN)) { +- uint32_t *src_ip = (uint32_t *) &iph->src_addr; +- uint16_t src_port = tcp_hdr->src_port; +- uint32_t v = rte_jhash_3words(src_ip[0], src_ip[1], src_ip[2], 0); +- index = rte_jhash_3words(src_ip[3], src_port | ((*dst_port) << 16), v, 0); +- } else { +- return -1; +- } +- } +- } else { +- return -1; +- } +- return index; +-} +- +-int distribute_pakages(struct rte_mbuf *mbuf) +-{ +- uint16_t dst_port = 0; +- uint32_t index = mbuf_to_idx(mbuf, &dst_port); +- if (index == -1) { +- return TRANSFER_CURRENT_THREAD; +- } +- +- uint16_t queue_id = 0; +- uint32_t user_process_idx = 0; +- int each_process_queue_num = get_global_cfg_params()->num_queue; +- index = index % each_process_queue_num; +- if (g_listen_ports[dst_port] != INVAILD_PROCESS_IDX) { +- user_process_idx = g_listen_ports[dst_port]; +- } else { +- user_process_idx = g_user_ports[dst_port]; +- } +- +- if (user_process_idx == INVAILD_PROCESS_IDX) { +- return TRANSFER_KERNEL; +- } +- +- if (get_global_cfg_params()->seperate_send_recv) { +- queue_id = user_process_idx * each_process_queue_num + (index / 2) * 2; +- } else { +- queue_id = user_process_idx * each_process_queue_num + index; +- } +- if (queue_id != 0) { +- if (user_process_idx == 0) { +- transfer_tcp_to_thread(mbuf, queue_id); +- } else { +- char mbuf_and_queue_id[TRANSFER_TCP_MUBF_LEN]; +- concat_mbuf_and_queue_id(mbuf, queue_id, mbuf_and_queue_id, TRANSFER_TCP_MUBF_LEN); +- transfer_pkt_to_other_process(mbuf_and_queue_id, user_process_idx, +- TRANSFER_TCP_MUBF_LEN, false); +- } +- return TRANSFER_OTHER_THREAD; +- } else { +- return TRANSFER_CURRENT_THREAD; +- } +- +- return TRANSFER_KERNEL; +-} +- + #if RTE_VERSION < RTE_VERSION_NUM(23, 11, 0, 0) + void kni_handle_rx(uint16_t port_id) + { +@@ -797,17 +129,18 @@ void kni_handle_tx(struct rte_mbuf *mbuf) + } + #endif + +-/* optimized eth_dev_poll() in lstack */ +-int32_t gazelle_eth_dev_poll(struct protocol_stack *stack, uint8_t use_ltran_flag, uint32_t nic_read_number) ++int32_t eth_dev_poll(void) + { + uint32_t nr_pkts; ++ struct cfg_params *cfg = get_global_cfg_params(); ++ struct protocol_stack *stack = get_protocol_stack(); + +- nr_pkts = stack->dev_ops.rx_poll(stack, stack->pkts, nic_read_number); ++ nr_pkts = stack->dev_ops.rx_poll(stack, stack->pkts, cfg->nic_read_number); + if (nr_pkts == 0) { + return 0; + } + +- if (!use_ltran_flag && get_protocol_stack_group()->latency_start) { ++ if (!use_ltran() && get_protocol_stack_group()->latency_start) { + uint64_t time_stamp = get_current_time(); + time_stamp_into_mbuf(nr_pkts, stack->pkts, time_stamp); + } +@@ -816,7 +149,7 @@ int32_t gazelle_eth_dev_poll(struct protocol_stack *stack, uint8_t use_ltran_fla + /* 1 current thread recv; 0 other thread recv; -1 kni recv; */ + int transfer_type = TRANSFER_CURRENT_THREAD; + /* copy arp into other stack */ +- if (!use_ltran_flag) { ++ if (!use_ltran()) { + struct rte_ether_hdr *ethh = rte_pktmbuf_mtod(stack->pkts[i], struct rte_ether_hdr *); + u16_t type; + type = ethh->ether_type; +@@ -946,6 +279,10 @@ int32_t ethdev_init(struct protocol_stack *stack) + LSTACK_LOG(ERR, LSTACK, "fill mbuf to rx_ring failed ret=%d\n", ret); + return ret; + } ++ } else { ++ if (cfg->tuple_filter && stack->queue_id == 0) { ++ flow_init(); ++ } + } + + netif_set_default(&stack->netif); +diff --git a/src/lstack/netif/lstack_flow.c b/src/lstack/netif/lstack_flow.c +new file mode 100644 +index 0000000..4e04209 +--- /dev/null ++++ b/src/lstack/netif/lstack_flow.c +@@ -0,0 +1,680 @@ ++/* ++* 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 ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "dpdk_common.h" ++#include "lstack_log.h" ++#include "lstack_dpdk.h" ++#include "lstack_cfg.h" ++#include "lstack_protocol_stack.h" ++#include "lstack_flow.h" ++ ++#define MAX_PATTERN_NUM 4 ++#define MAX_ACTION_NUM 2 ++#define FULL_MASK 0xffffffff /* full mask */ ++#define EMPTY_MASK 0x0 /* empty mask */ ++#define LSTACK_MBUF_LEN 64 ++#define TRANSFER_TCP_MUBF_LEN (LSTACK_MBUF_LEN + 3) ++#define DELETE_FLOWS_PARAMS_NUM 3 ++#define DELETE_FLOWS_PARAMS_LENGTH 30 ++#define CREATE_FLOWS_PARAMS_NUM 6 ++#define CREATE_FLOWS_PARAMS_LENGTH 60 ++#define ADD_OR_DELETE_LISTEN_PORT_PARAMS_LENGTH 25 ++#define ADD_OR_DELETE_LISTEN_PORT_PARAMS_NUM 3 ++#define REPLY_LEN 10 ++#define SUCCESS_REPLY "success" ++#define ERROR_REPLY "error" ++ ++#define GET_LSTACK_NUM 14 ++#define GET_LSTACK_NUM_STRING "get_lstack_num" ++ ++#define SERVER_PATH "/var/run/gazelle/server.socket" ++#define SPLIT_DELIM "," ++ ++#define UNIX_TCP_PORT_MAX 65535 ++ ++#define INVAILD_PROCESS_IDX 255 ++ ++#define IPV4_VERSION_OFFSET 4 ++#define IPV4_VERSION 4 ++ ++static uint8_t g_user_ports[UNIX_TCP_PORT_MAX] = {INVAILD_PROCESS_IDX, }; ++static uint8_t g_listen_ports[UNIX_TCP_PORT_MAX] = {INVAILD_PROCESS_IDX, }; ++ ++/* flow rule map */ ++#define RULE_KEY_LEN 23 ++struct flow_rule { ++ char rule_key[RULE_KEY_LEN]; ++ struct rte_flow *flow; ++ UT_hash_handle hh; ++}; ++ ++static uint16_t g_flow_num = 0; ++static struct flow_rule *g_flow_rules = NULL; ++static struct flow_rule *find_rule(char *rule_key) ++{ ++ struct flow_rule *fl; ++ HASH_FIND_STR(g_flow_rules, rule_key, fl); ++ return fl; ++} ++ ++static void add_rule(char* rule_key, struct rte_flow *flow) ++{ ++ struct flow_rule *rule; ++ HASH_FIND_STR(g_flow_rules, rule_key, rule); ++ if (rule == NULL) { ++ rule = (struct flow_rule*)malloc(sizeof(struct flow_rule)); ++ strcpy_s(rule->rule_key, RULE_KEY_LEN, rule_key); ++ HASH_ADD_STR(g_flow_rules, rule_key, rule); ++ } ++ rule->flow = flow; ++} ++ ++static void delete_rule(char* rule_key) ++{ ++ struct flow_rule *rule = NULL; ++ HASH_FIND_STR(g_flow_rules, rule_key, rule); ++ if (rule != NULL) { ++ HASH_DEL(g_flow_rules, rule); ++ free(rule); ++ } ++} ++ ++static void init_listen_and_user_ports(void) ++{ ++ memset_s(g_user_ports, sizeof(g_user_ports), INVAILD_PROCESS_IDX, sizeof(g_user_ports)); ++ memset_s(g_listen_ports, sizeof(g_listen_ports), INVAILD_PROCESS_IDX, sizeof(g_listen_ports)); ++} ++ ++static int transfer_pkt_to_other_process(char *buf, int process_index, int write_len, bool need_reply) ++{ ++ /* other process queue_id */ ++ struct sockaddr_un serun; ++ int sockfd; ++ int ret = 0; ++ ++ sockfd = posix_api->socket_fn(AF_UNIX, SOCK_STREAM, 0); ++ memset_s(&serun, sizeof(serun), 0, sizeof(serun)); ++ serun.sun_family = AF_UNIX; ++ sprintf_s(serun.sun_path, PATH_MAX, "%s%d", SERVER_PATH, process_index); ++ int32_t len = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path); ++ if (posix_api->connect_fn(sockfd, (struct sockaddr *)&serun, len) < 0) { ++ return CONNECT_ERROR; ++ } ++ posix_api->write_fn(sockfd, buf, write_len); ++ if (need_reply) { ++ char reply_message[REPLY_LEN]; ++ int32_t read_result = posix_api->read_fn(sockfd, reply_message, REPLY_LEN); ++ if (read_result > 0) { ++ if (strcmp(reply_message, SUCCESS_REPLY) == 0) { ++ ret = TRANSFER_SUCESS; ++ } else if (strcmp(reply_message, ERROR_REPLY) == 0) { ++ ret = REPLY_ERROR; ++ } else { ++ ret = atoi(reply_message); ++ } ++ } else { ++ ret = REPLY_ERROR; ++ } ++ } ++ posix_api->close_fn(sockfd); ++ ++ return ret; ++} ++ ++int32_t check_params_from_primary(void) ++{ ++ struct cfg_params *cfg = get_global_cfg_params(); ++ if (cfg->is_primary) { ++ return 0; ++ } ++ // check lstack num ++ char get_lstack_num[GET_LSTACK_NUM]; ++ sprintf_s(get_lstack_num, GET_LSTACK_NUM, "%s", GET_LSTACK_NUM_STRING); ++ int32_t ret = transfer_pkt_to_other_process(get_lstack_num, 0, GET_LSTACK_NUM, true); ++ if (ret != cfg->num_cpu) { ++ return -1; ++ } ++ return 0; ++} ++ ++static struct rte_flow *create_flow_director(uint16_t port_id, uint16_t queue_id, ++ uint32_t src_ip, uint32_t dst_ip, ++ uint16_t src_port, uint16_t dst_port, ++ struct rte_flow_error *error) ++{ ++ struct rte_flow_attr attr; ++ struct rte_flow_item pattern[MAX_PATTERN_NUM]; ++ struct rte_flow_action action[MAX_ACTION_NUM]; ++ struct rte_flow *flow = NULL; ++ struct rte_flow_action_queue queue = { .index = queue_id }; ++ struct rte_flow_item_ipv4 ip_spec; ++ struct rte_flow_item_ipv4 ip_mask; ++ ++ struct rte_flow_item_tcp tcp_spec; ++ struct rte_flow_item_tcp tcp_mask; ++ int res; ++ ++ memset_s(pattern, sizeof(pattern), 0, sizeof(pattern)); ++ memset_s(action, sizeof(action), 0, sizeof(action)); ++ ++ /* ++ * set the rule attribute. ++ * in this case only ingress packets will be checked. ++ */ ++ memset_s(&attr, sizeof(struct rte_flow_attr), 0, sizeof(struct rte_flow_attr)); ++ attr.ingress = 1; ++ ++ /* ++ * create the action sequence. ++ * one action only, move packet to queue ++ */ ++ action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE; ++ action[0].conf = &queue; ++ action[1].type = RTE_FLOW_ACTION_TYPE_END; ++ ++ // not limit eth header ++ pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH; ++ ++ // ip header ++ memset_s(&ip_spec, sizeof(struct rte_flow_item_ipv4), 0, sizeof(struct rte_flow_item_ipv4)); ++ memset_s(&ip_mask, sizeof(struct rte_flow_item_ipv4), 0, sizeof(struct rte_flow_item_ipv4)); ++ ip_spec.hdr.dst_addr = dst_ip; ++ ip_mask.hdr.dst_addr = FULL_MASK; ++ ip_spec.hdr.src_addr = src_ip; ++ ip_mask.hdr.src_addr = FULL_MASK; ++ pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4; ++ pattern[1].spec = &ip_spec; ++ pattern[1].mask = &ip_mask; ++ ++ // tcp header, full mask 0xffff ++ memset_s(&tcp_spec, sizeof(struct rte_flow_item_tcp), 0, sizeof(struct rte_flow_item_tcp)); ++ memset_s(&tcp_mask, sizeof(struct rte_flow_item_tcp), 0, sizeof(struct rte_flow_item_tcp)); ++ pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP; // 2: pattern 2 is tcp header ++ tcp_spec.hdr.src_port = src_port; ++ tcp_spec.hdr.dst_port = dst_port; ++ tcp_mask.hdr.src_port = rte_flow_item_tcp_mask.hdr.src_port; ++ tcp_mask.hdr.dst_port = rte_flow_item_tcp_mask.hdr.dst_port; ++ pattern[2].spec = &tcp_spec; ++ pattern[2].mask = &tcp_mask; ++ ++ /* the final level must be always type end */ ++ pattern[3].type = RTE_FLOW_ITEM_TYPE_END; ++ res = rte_flow_validate(port_id, &attr, pattern, action, error); ++ if (!res) { ++ flow = rte_flow_create(port_id, &attr, pattern, action, error); ++ } else { ++ LSTACK_LOG(ERR, LSTACK, "rte_flow_create.rte_flow_validate error, res %d \n", res); ++ } ++ ++ return flow; ++} ++ ++static void config_flow_director(uint16_t queue_id, uint32_t src_ip, ++ uint32_t dst_ip, uint16_t src_port, uint16_t dst_port) ++{ ++ uint16_t port_id = get_protocol_stack_group()->port_id; ++ char rule_key[RULE_KEY_LEN] = {0}; ++ sprintf_s(rule_key, sizeof(rule_key), "%u_%u_%u", src_ip, src_port, dst_port); ++ struct flow_rule *fl_exist = find_rule(rule_key); ++ if (fl_exist != NULL) { ++ return; ++ } ++ ++ LSTACK_LOG(INFO, LSTACK, ++ "config_flow_director, flow queue_id %u, src_ip %u,src_port_ntohs:%u, dst_port_ntohs:%u\n", ++ queue_id, src_ip, ntohs(src_port), ntohs(dst_port)); ++ ++ struct rte_flow_error error; ++ struct rte_flow *flow = create_flow_director(port_id, queue_id, src_ip, dst_ip, src_port, dst_port, &error); ++ if (!flow) { ++ LSTACK_LOG(ERR, LSTACK,"flow can not be created. queue_id %u, src_ip %u, src_port %u," ++ "dst_port %u, dst_port_ntohs :%u, type %d. message: %s\n", ++ queue_id, src_ip, src_port, dst_port, ntohs(dst_port), ++ error.type, error.message ? error.message : "(no stated reason)"); ++ return; ++ } ++ __sync_fetch_and_add(&g_flow_num, 1); ++ add_rule(rule_key, flow); ++} ++ ++static void delete_flow_director(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port) ++{ ++ uint16_t port_id = get_protocol_stack_group()->port_id; ++ char rule_key[RULE_KEY_LEN] = {0}; ++ sprintf_s(rule_key, RULE_KEY_LEN, "%u_%u_%u",dst_ip, dst_port, src_port); ++ struct flow_rule *fl = find_rule(rule_key); ++ ++ if(fl != NULL) { ++ struct rte_flow_error error; ++ int ret = rte_flow_destroy(port_id, fl->flow, &error); ++ if (ret != 0) { ++ LSTACK_LOG(ERR, LSTACK, "Flow can't be delete %d message: %s\n", ++ error.type, error.message ? error.message : "(no stated reason)"); ++ } ++ delete_rule(rule_key); ++ __sync_fetch_and_sub(&g_flow_num, 1); ++ } ++} ++ ++/* if process 0, delete directly, else transfer 'dst_ip,src_port,dst_port' to process 0. */ ++void transfer_delete_rule_info_to_process0(uint32_t dst_ip, uint16_t src_port, uint16_t dst_port) ++{ ++ if (get_global_cfg_params()->is_primary) { ++ delete_flow_director(dst_ip, src_port, dst_port); ++ } else { ++ char process_server_path[DELETE_FLOWS_PARAMS_LENGTH]; ++ sprintf_s(process_server_path, DELETE_FLOWS_PARAMS_LENGTH, "%u%s%u%s%u", ++ dst_ip, SPLIT_DELIM, src_port, SPLIT_DELIM, dst_port); ++ int ret = transfer_pkt_to_other_process(process_server_path, 0, DELETE_FLOWS_PARAMS_LENGTH, false); ++ if (ret != TRANSFER_SUCESS) { ++ LSTACK_LOG(ERR, LSTACK, "error. tid %d. dst_ip %u, src_port: %u, dst_port %u\n", ++ rte_gettid(), dst_ip, src_port, dst_port); ++ } ++ } ++} ++ ++// if process 0, add directly, else transfer 'src_ip,dst_ip,src_port,dst_port,queue_id' to process 0. ++void transfer_create_rule_info_to_process0(uint16_t queue_id, uint32_t src_ip, ++ uint32_t dst_ip, uint16_t src_port, ++ uint16_t dst_port) ++{ ++ char process_server_path[CREATE_FLOWS_PARAMS_LENGTH]; ++ /* exchage src_ip and dst_ip, src_port and dst_port */ ++ uint8_t process_idx = get_global_cfg_params()->process_idx; ++ sprintf_s(process_server_path, CREATE_FLOWS_PARAMS_LENGTH, "%u%s%u%s%u%s%u%s%u%s%u", ++ dst_ip, SPLIT_DELIM, src_ip, SPLIT_DELIM, ++ dst_port, SPLIT_DELIM, src_port, SPLIT_DELIM, ++ queue_id, SPLIT_DELIM, process_idx); ++ int ret = transfer_pkt_to_other_process(process_server_path, 0, CREATE_FLOWS_PARAMS_LENGTH, true); ++ if (ret != TRANSFER_SUCESS) { ++ LSTACK_LOG(ERR, LSTACK, "error. tid %d. src_ip %u, dst_ip %u, src_port: %u, dst_port %u," ++ "queue_id %u, process_idx %u\n", ++ rte_gettid(), src_ip, dst_ip, src_port, dst_port, queue_id, process_idx); ++ } ++} ++ ++void transfer_add_or_delete_listen_port_to_process0(uint16_t listen_port, uint8_t process_idx, uint8_t is_add) ++{ ++ char process_server_path[ADD_OR_DELETE_LISTEN_PORT_PARAMS_LENGTH]; ++ sprintf_s(process_server_path, ADD_OR_DELETE_LISTEN_PORT_PARAMS_LENGTH, ++ "%u%s%u%s%u", listen_port, SPLIT_DELIM, process_idx, SPLIT_DELIM, is_add); ++ int ret = transfer_pkt_to_other_process(process_server_path, 0, ADD_OR_DELETE_LISTEN_PORT_PARAMS_LENGTH, true); ++ if (ret != TRANSFER_SUCESS) { ++ LSTACK_LOG(ERR, LSTACK, "error. tid %d. listen_port %u, process_idx %u\n", ++ rte_gettid(), listen_port, process_idx); ++ } ++} ++ ++static int str_to_array(char *args, uint32_t *array, int size) ++{ ++ int val; ++ uint16_t cnt = 0; ++ char *elem = NULL; ++ char *next_token = NULL; ++ ++ memset_s(array, sizeof(*array) * size, 0, sizeof(*array) * size); ++ elem = strtok_s((char *)args, SPLIT_DELIM, &next_token); ++ while (elem != NULL) { ++ if (cnt >= size) { ++ return -1; ++ } ++ val = atoi(elem); ++ if (val < 0) { ++ return -1; ++ } ++ array[cnt] = (uint32_t)val; ++ cnt++; ++ ++ elem = strtok_s(NULL, SPLIT_DELIM, &next_token); ++ } ++ ++ return cnt; ++} ++ ++static void parse_and_delete_rule(char* buf) ++{ ++ uint32_t array[DELETE_FLOWS_PARAMS_NUM]; ++ str_to_array(buf, array, DELETE_FLOWS_PARAMS_NUM); ++ uint32_t dst_ip = array[0]; ++ uint16_t src_port = array[1]; ++ uint16_t dst_port = array[2]; ++ delete_flow_director(dst_ip, src_port, dst_port); ++} ++ ++void add_user_process_port(uint16_t dst_port, uint8_t process_idx, enum port_type type) ++{ ++ if (type == PORT_LISTEN) { ++ g_listen_ports[dst_port] = process_idx; ++ } else { ++ g_user_ports[dst_port] = process_idx; ++ } ++} ++ ++void delete_user_process_port(uint16_t dst_port, enum port_type type) ++{ ++ if (type == PORT_LISTEN) { ++ g_listen_ports[dst_port] = INVAILD_PROCESS_IDX; ++ } else { ++ g_user_ports[dst_port] = INVAILD_PROCESS_IDX; ++ } ++} ++ ++static void parse_and_create_rule(char* buf) ++{ ++ uint32_t array[CREATE_FLOWS_PARAMS_NUM]; ++ str_to_array(buf, array, CREATE_FLOWS_PARAMS_NUM); ++ uint32_t src_ip = array[0]; ++ uint32_t dst_ip = array[1]; ++ uint16_t src_port = array[2]; ++ uint16_t dst_port = array[3]; ++ uint16_t queue_id = array[4]; ++ uint8_t process_idx = array[5]; ++ config_flow_director(queue_id, src_ip, dst_ip, src_port, dst_port); ++ add_user_process_port(dst_port, process_idx, PORT_CONNECT); ++} ++ ++static void parse_and_add_or_delete_listen_port(char* buf) ++{ ++ uint32_t array[ADD_OR_DELETE_LISTEN_PORT_PARAMS_NUM]; ++ str_to_array(buf, array, ADD_OR_DELETE_LISTEN_PORT_PARAMS_NUM); ++ uint16_t listen_port = array[0]; ++ uint8_t process_idx = array[1]; ++ uint8_t is_add = array[2]; ++ if (is_add == 1) { ++ add_user_process_port(listen_port, process_idx, PORT_LISTEN); ++ } else { ++ delete_user_process_port(listen_port, PORT_LISTEN); ++ } ++} ++ ++void transfer_arp_to_other_process(struct rte_mbuf *mbuf) ++{ ++ struct cfg_params *cfgs = get_global_cfg_params(); ++ ++ for (int i = 1; i < cfgs->num_process; i++) { ++ char arp_mbuf[LSTACK_MBUF_LEN] = {0}; ++ sprintf_s(arp_mbuf, sizeof(arp_mbuf), "%lu", mbuf); ++ int result = transfer_pkt_to_other_process(arp_mbuf, i, LSTACK_MBUF_LEN, false); ++ if (result == CONNECT_ERROR) { ++ LSTACK_LOG(INFO, LSTACK,"connect process %d failed, ensure the process is started.\n", i); ++ } else if (result == REPLY_ERROR) { ++ LSTACK_LOG(ERR, LSTACK,"transfer arp pakages to process %d error. %m\n", i); ++ } ++ } ++} ++ ++static void transfer_tcp_to_thread(struct rte_mbuf *mbuf, uint16_t stk_idx) ++{ ++ /* current process queue_id */ ++ struct protocol_stack *stack = get_protocol_stack_group()->stacks[stk_idx]; ++ int ret = -1; ++ while (ret != 0) { ++ ret = rpc_call_arp(&stack->rpc_queue, mbuf); ++ printf("transfer_tcp_to_thread, ret : %d \n", ret); ++ } ++} ++ ++static void parse_arp_and_transefer(char* buf) ++{ ++ struct rte_mbuf *mbuf = (struct rte_mbuf *)atoll(buf); ++ struct protocol_stack_group *stack_group = get_protocol_stack_group(); ++ struct rte_mbuf *mbuf_copy = NULL; ++ struct protocol_stack *stack = NULL; ++ int32_t ret; ++ for (int32_t i = 0; i < stack_group->stack_num; i++) { ++ stack = stack_group->stacks[i]; ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, false); ++ while (ret != 0) { ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, false); ++ stack->stats.rx_allocmbuf_fail++; ++ } ++ copy_mbuf(mbuf_copy, mbuf); ++ ++ ret = rpc_call_arp(&stack->rpc_queue, mbuf_copy); ++ ++ while (ret != 0) { ++ rpc_call_arp(&stack->rpc_queue, mbuf_copy); ++ } ++ } ++} ++ ++static void parse_tcp_and_transefer(char* buf) ++{ ++ char *next_token = NULL; ++ char *elem = strtok_s(buf, SPLIT_DELIM, &next_token); ++ struct rte_mbuf *mbuf = (struct rte_mbuf *) atoll(elem); ++ elem = strtok_s(NULL, SPLIT_DELIM, &next_token); ++ uint16_t queue_id = atoll(elem); ++ ++ struct protocol_stack_group *stack_group = get_protocol_stack_group(); ++ uint16_t num_queue = get_global_cfg_params()->num_queue; ++ uint16_t stk_index = queue_id % num_queue; ++ struct rte_mbuf *mbuf_copy = NULL; ++ struct protocol_stack *stack = stack_group->stacks[stk_index]; ++ ++ int32_t ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, false); ++ while (ret != 0) { ++ ret = dpdk_alloc_pktmbuf(stack->rxtx_mbuf_pool, &mbuf_copy, 1, false); ++ stack->stats.rx_allocmbuf_fail++; ++ } ++ ++ copy_mbuf(mbuf_copy,mbuf); ++ transfer_tcp_to_thread(mbuf_copy, stk_index); ++} ++ ++int recv_pkts_from_other_process(int process_index, void* arg) ++{ ++ struct sockaddr_un serun, cliun; ++ socklen_t cliun_len; ++ int listenfd, connfd, size; ++ char buf[132]; ++ /* socket */ ++ if ((listenfd = posix_api->socket_fn(AF_UNIX, SOCK_STREAM, 0)) < 0) { ++ perror("socket error"); ++ return -1; ++ } ++ /* bind */ ++ memset_s(&serun, sizeof(serun), 0, sizeof(serun)); ++ serun.sun_family = AF_UNIX; ++ char process_server_path[PATH_MAX]; ++ sprintf_s(process_server_path, sizeof(process_server_path), "%s%d", SERVER_PATH, process_index); ++ strcpy_s(serun.sun_path, sizeof(serun.sun_path), process_server_path); ++ size = offsetof(struct sockaddr_un, sun_path) + strlen(serun.sun_path); ++ unlink(process_server_path); ++ if (posix_api->bind_fn(listenfd, (struct sockaddr *)&serun, size) < 0) { ++ perror("bind error"); ++ return -1; ++ } ++ if (posix_api->listen_fn(listenfd, 20) < 0) { /* 20: max backlog */ ++ perror("listen error"); ++ return -1; ++ } ++ sem_post((sem_t *)arg); ++ /* block */ ++ while (1) { ++ cliun_len = sizeof(cliun); ++ if ((connfd = posix_api->accept_fn(listenfd, (struct sockaddr *)&cliun, &cliun_len)) < 0) { ++ perror("accept error"); ++ continue; ++ } ++ while (1) { ++ int n = posix_api->read_fn(connfd, buf, sizeof(buf)); ++ if (n < 0) { ++ perror("read error"); ++ break; ++ } else if (n == 0) { ++ break; ++ } ++ ++ if (n == LSTACK_MBUF_LEN) { ++ /* arp */ ++ parse_arp_and_transefer(buf); ++ } else if (n == TRANSFER_TCP_MUBF_LEN) { ++ /* tcp. lstack_mbuf_queue_id */ ++ parse_tcp_and_transefer(buf); ++ } else if (n == DELETE_FLOWS_PARAMS_LENGTH) { ++ /* delete rule */ ++ parse_and_delete_rule(buf); ++ } else if (n == CREATE_FLOWS_PARAMS_LENGTH) { ++ /* add rule */ ++ parse_and_create_rule(buf); ++ char reply_buf[REPLY_LEN]; ++ sprintf_s(reply_buf, sizeof(reply_buf), "%s", SUCCESS_REPLY); ++ posix_api->write_fn(connfd, reply_buf, REPLY_LEN); ++ } else if (n == GET_LSTACK_NUM) { ++ char reply_buf[REPLY_LEN]; ++ sprintf_s(reply_buf, sizeof(reply_buf), "%d", get_global_cfg_params()->num_cpu); ++ posix_api->write_fn(connfd, reply_buf, REPLY_LEN); ++ } else { ++ /* add port */ ++ parse_and_add_or_delete_listen_port(buf); ++ char reply_buf[REPLY_LEN]; ++ sprintf_s(reply_buf, sizeof(reply_buf), "%s", SUCCESS_REPLY); ++ posix_api->write_fn(connfd, reply_buf, REPLY_LEN); ++ } ++ ++ } ++ posix_api->close_fn(connfd); ++ } ++ posix_api->close_fn(listenfd); ++ return 0; ++} ++ ++void concat_mbuf_and_queue_id(struct rte_mbuf *mbuf, uint16_t queue_id, ++ char* mbuf_and_queue_id, int write_len) ++{ ++ sprintf_s(mbuf_and_queue_id, write_len, "%lu%s%u", mbuf, SPLIT_DELIM, queue_id); ++} ++ ++static int mbuf_to_idx(struct rte_mbuf *mbuf, uint16_t *dst_port) ++{ ++ struct rte_ether_hdr *ethh = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr *); ++ u16_t type = rte_be_to_cpu_16(ethh->ether_type); ++ uint32_t index = 0; ++ if (type == RTE_ETHER_TYPE_IPV4) { ++ struct rte_ipv4_hdr *iph = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr)); ++ uint8_t ip_version = (iph->version_ihl & 0xf0) >> IPV4_VERSION_OFFSET; ++ if (likely(ip_version == IPV4_VERSION)) { ++ if (likely(iph->next_proto_id == IPPROTO_TCP)) { ++ struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *, ++ sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr)); ++ *dst_port = tcp_hdr->dst_port; ++ ++ if (unlikely(tcp_hdr->tcp_flags == TCP_SYN)) { ++ uint32_t src_ip = iph->src_addr; ++ uint16_t src_port = tcp_hdr->src_port; ++ index = rte_jhash_3words(src_ip, src_port | ((*dst_port) << 16), 0, 0); ++ } else { ++ return -1; ++ } ++ } ++ } ++ } else if (type == RTE_ETHER_TYPE_IPV6) { ++ struct rte_ipv6_hdr *iph = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv6_hdr *, sizeof(struct rte_ether_hdr)); ++ if (likely(iph->proto == IPPROTO_TCP)) { ++ struct rte_tcp_hdr *tcp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr *, ++ sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv6_hdr)); ++ *dst_port = tcp_hdr->dst_port; ++ ++ if (unlikely(tcp_hdr->tcp_flags == TCP_SYN)) { ++ uint32_t *src_ip = (uint32_t *) &iph->src_addr; ++ uint16_t src_port = tcp_hdr->src_port; ++ uint32_t v = rte_jhash_3words(src_ip[0], src_ip[1], src_ip[2], 0); ++ index = rte_jhash_3words(src_ip[3], src_port | ((*dst_port) << 16), v, 0); ++ } else { ++ return -1; ++ } ++ } ++ } else { ++ return -1; ++ } ++ return index; ++} ++ ++int distribute_pakages(struct rte_mbuf *mbuf) ++{ ++ uint16_t dst_port = 0; ++ uint32_t index = mbuf_to_idx(mbuf, &dst_port); ++ if (index == -1) { ++ return TRANSFER_CURRENT_THREAD; ++ } ++ ++ uint16_t queue_id = 0; ++ uint32_t user_process_idx = 0; ++ int each_process_queue_num = get_global_cfg_params()->num_queue; ++ index = index % each_process_queue_num; ++ if (g_listen_ports[dst_port] != INVAILD_PROCESS_IDX) { ++ user_process_idx = g_listen_ports[dst_port]; ++ } else { ++ user_process_idx = g_user_ports[dst_port]; ++ } ++ ++ if (user_process_idx == INVAILD_PROCESS_IDX) { ++ return TRANSFER_KERNEL; ++ } ++ ++ if (get_global_cfg_params()->seperate_send_recv) { ++ queue_id = user_process_idx * each_process_queue_num + (index / 2) * 2; ++ } else { ++ queue_id = user_process_idx * each_process_queue_num + index; ++ } ++ if (queue_id != 0) { ++ if (user_process_idx == 0) { ++ transfer_tcp_to_thread(mbuf, queue_id); ++ } else { ++ char mbuf_and_queue_id[TRANSFER_TCP_MUBF_LEN]; ++ concat_mbuf_and_queue_id(mbuf, queue_id, mbuf_and_queue_id, TRANSFER_TCP_MUBF_LEN); ++ transfer_pkt_to_other_process(mbuf_and_queue_id, user_process_idx, ++ TRANSFER_TCP_MUBF_LEN, false); ++ } ++ return TRANSFER_OTHER_THREAD; ++ } else { ++ return TRANSFER_CURRENT_THREAD; ++ } ++ ++ return TRANSFER_KERNEL; ++} ++ ++void gazelle_listen_thread(void *arg) ++{ ++ struct cfg_params *cfg_param = get_global_cfg_params(); ++ recv_pkts_from_other_process(cfg_param->process_idx, arg); ++} ++ ++void flow_init(void) ++{ ++ struct protocol_stack_group *stack_group = get_protocol_stack_group(); ++ init_listen_and_user_ports(); ++ ++ /* run to completion mode does not currently support multiple process */ ++ if (!use_ltran() && !get_global_cfg_params()->stack_mode_rtc) { ++ char name[PATH_MAX]; ++ sem_init(&stack_group->sem_listen_thread, 0, 0); ++ sprintf_s(name, sizeof(name), "%s", "listen_thread"); ++ struct sys_thread *thread = sys_thread_new(name, gazelle_listen_thread, ++ (void*)(&stack_group->sem_listen_thread), 0, 0); ++ free(thread); ++ sem_wait(&stack_group->sem_listen_thread); ++ } ++} +diff --git a/src/lstack/netif/lstack_vdev.c b/src/lstack/netif/lstack_vdev.c +index f78e48a..3703092 100644 +--- a/src/lstack/netif/lstack_vdev.c ++++ b/src/lstack/netif/lstack_vdev.c +@@ -33,6 +33,7 @@ + #include "lstack_protocol_stack.h" + #include "gazelle_reg_msg.h" + #include "lstack_lwip.h" ++#include "lstack_flow.h" + #include "lstack_vdev.h" + + /* INUSE_TX_PKTS_WATERMARK < VDEV_RX_QUEUE_SZ; +-- +2.27.0 + diff --git a/0138-fix-coreddump-when-stack-setup-failed-in-rtc-mode.patch b/0138-fix-coreddump-when-stack-setup-failed-in-rtc-mode.patch new file mode 100644 index 0000000..1e4c192 --- /dev/null +++ b/0138-fix-coreddump-when-stack-setup-failed-in-rtc-mode.patch @@ -0,0 +1,66 @@ +From 52fafeafd51ed5363081064076dff4ed276a99c1 Mon Sep 17 00:00:00 2001 +From: jiangheng +Date: Thu, 22 Feb 2024 21:22:44 +0800 +Subject: [PATCH] fix coreddump when stack setup failed in rtc mode + +--- + src/lstack/api/lstack_rtc_api.c | 6 +++--- + src/lstack/core/lstack_init.c | 11 +++++------ + 2 files changed, 8 insertions(+), 9 deletions(-) + +diff --git a/src/lstack/api/lstack_rtc_api.c b/src/lstack/api/lstack_rtc_api.c +index d29e51e..2e10e30 100644 +--- a/src/lstack/api/lstack_rtc_api.c ++++ b/src/lstack/api/lstack_rtc_api.c +@@ -45,7 +45,7 @@ int rtc_socket(int domain, int type, int protocol) + int ret; + + if (stack_setup_app_thread() < 0) { +- LSTACK_EXIT(1, "stack_setup_app_thread failed!\n"); ++ exit(1); + } + + /* need call stack thread init function */ +@@ -74,7 +74,7 @@ int rtc_shutdown(int fd, int how) + int rtc_epoll_create(int flags) + { + if (stack_setup_app_thread() < 0) { +- LSTACK_EXIT(1, "stack_setup_app_thread failed!\n"); ++ exit(1); + } + + return lstack_epoll_create(flags); +@@ -83,7 +83,7 @@ int rtc_epoll_create(int flags) + int rtc_epoll_create1(int flags) + { + if (stack_setup_app_thread() < 0) { +- LSTACK_EXIT(1, "stack_setup_app_thread failed!\n"); ++ exit(1); + } + + return lstack_epoll_create1(flags); +diff --git a/src/lstack/core/lstack_init.c b/src/lstack/core/lstack_init.c +index 31fd91d..bd9ba8a 100644 +--- a/src/lstack/core/lstack_init.c ++++ b/src/lstack/core/lstack_init.c +@@ -109,12 +109,11 @@ static int32_t check_process_conflict(void) + + void gazelle_exit(void) + { +- if (!get_global_cfg_params()->stack_mode_rtc) { +- wrap_api_set_dummy(); +- /* 1: wait until app thread call send functio complete */ +- sleep(1); +- stack_group_exit(); +- } ++ wrap_api_set_dummy(); ++ /* 1: wait until app thread call send functio complete */ ++ sleep(1); ++ stack_group_exit(); ++ + if (!use_ltran()) { + #if RTE_VERSION < RTE_VERSION_NUM(23, 11, 0, 0) + dpdk_kni_release(); +-- +2.27.0 + diff --git a/0139-diff-udp-and-tcp-read-from-stack.patch b/0139-diff-udp-and-tcp-read-from-stack.patch new file mode 100644 index 0000000..ff642fe --- /dev/null +++ b/0139-diff-udp-and-tcp-read-from-stack.patch @@ -0,0 +1,277 @@ +From 472e2f00b3fda7dad4396704fd94715d91be4642 Mon Sep 17 00:00:00 2001 +From: jiangheng +Date: Wed, 21 Feb 2024 04:25:43 +0800 +Subject: [PATCH] diff udp and tcp read from stack + +--- + src/lstack/core/lstack_lwip.c | 211 +++++++++++++++++++++++----------- + 1 file changed, 146 insertions(+), 65 deletions(-) + +diff --git a/src/lstack/core/lstack_lwip.c b/src/lstack/core/lstack_lwip.c +index 50a3389..0b339fe 100644 +--- a/src/lstack/core/lstack_lwip.c ++++ b/src/lstack/core/lstack_lwip.c +@@ -831,74 +831,96 @@ static struct pbuf *pbuf_free_partial(struct pbuf *pbuf, uint16_t free_len) + return pbuf; + } + +-ssize_t do_lwip_read_from_stack(int32_t fd, void *buf, size_t len, int32_t flags, +- struct sockaddr *addr, socklen_t *addrlen) ++static bool recv_break_for_err(struct lwip_sock *sock) + { +- size_t recv_left = len; +- struct pbuf *pbuf = NULL; +- ssize_t recvd = 0; +- uint32_t copy_len; +- struct lwip_sock *sock = get_socket_by_fd(fd); +- bool latency_enable = get_protocol_stack_group()->latency_start; +- +- if (sock->errevent > 0 && !NETCONN_IS_DATAIN(sock)) { +- errno = err_to_errno(netconn_err(sock->conn)); +- return -1; +- } ++ bool break_wait = (sock->errevent > 0) && (!NETCONN_IS_DATAIN(sock)); ++ errno = err_to_errno(netconn_err(sock->conn)); ++ return break_wait; ++} + +- thread_bind_stack(sock); ++static void recv_block_wait(struct lwip_sock *sock) ++{ ++ lstack_block_wait(sock->wakeup); ++} + +- if (sock->same_node_rx_ring != NULL) { +- return gazelle_same_node_ring_recv(sock, buf, len, flags); ++/* ++ * return 0 on success, -1 on error ++ * pbuf maybe NULL(tcp fin packet) ++ */ ++static int recv_ring_get_one(struct lwip_sock *sock, bool noblock, struct pbuf **pbuf) ++{ ++ if (sock->recv_lastdata != NULL) { ++ *pbuf = sock->recv_lastdata; ++ sock->recv_lastdata = NULL; ++ return 0; + } + +- while (recv_left > 0) { +- if (sock->recv_lastdata) { +- pbuf = sock->recv_lastdata; +- sock->recv_lastdata = NULL; ++ if (noblock) { ++ if (gazelle_ring_read(sock->recv_ring, (void **)pbuf, 1) != 1) { ++ errno = EAGAIN; ++ return -1; + } else { +- if (netconn_is_nonblocking(sock->conn)) { +- if (gazelle_ring_read(sock->recv_ring, (void **)&pbuf, 1) != 1) { +- break; +- } +- } else { +- while (gazelle_ring_read(sock->recv_ring, (void **)&pbuf, 1) != 1 && recvd == 0) { +- /* if the connection is disconnected, recv return 0 */ +- if (sock->errevent > 0 && !NETCONN_IS_DATAIN(sock)) { +- errno = err_to_errno(netconn_err(sock->conn)); +- return -1; +- } +- +- lstack_block_wait(sock->wakeup); +- } ++ return 0; ++ } ++ } else { ++ while (gazelle_ring_read(sock->recv_ring, (void **)pbuf, 1) != 1) { ++ if (recv_break_for_err(sock)) { ++ return -1; + } ++ recv_block_wait(sock); + } ++ return 0; ++ } ++} + +- /* if udp recv a packet whose len is 0, return 0 */ +- if (NETCONN_IS_UDP(sock) && pbuf->tot_len == 0) { +- return 0; ++/* return true: fin is read to user, false: pend fin */ ++static bool recv_ring_handle_fin(struct lwip_sock *sock, struct pbuf *pbuf, ssize_t recvd) ++{ ++ if (pbuf == NULL) { ++ if (recvd > 0) { ++ /* handle data first, then handle fin */ ++ sock->recv_lastdata = (void *)&fin_packet; ++ gazelle_ring_read_over(sock->recv_ring); ++ return false; + } ++ gazelle_ring_read_over(sock->recv_ring); ++ return true; ++ } ++ /* pending fin */ ++ if (pbuf == (void *)&fin_packet) { ++ return true; ++ } + +- /* fin */ +- if (unlikely(pbuf == NULL)) { +- if (recvd > 0) { +- /* read data first, then read fin */ +- sock->recv_lastdata = (void *)&fin_packet; +- gazelle_ring_read_over(sock->recv_ring); +- break; +- } +- gazelle_ring_read_over(sock->recv_ring); +- return 0; ++ return false; ++} ++ ++static ssize_t recv_ring_tcp_read(struct lwip_sock *sock, void *buf, size_t len, bool noblock) ++{ ++ ssize_t recvd = 0; ++ size_t recv_left = len; ++ uint32_t copy_len; ++ struct pbuf *pbuf = NULL; ++ ++ if (len == 0) { ++ return 0; ++ } ++ ++ while (recv_left > 0) { ++ if (recv_ring_get_one(sock, noblock, &pbuf) != 0) { ++ break; + } + +- /* pending fin */ +- if (unlikely(pbuf == (void *)&fin_packet)) { +- return 0; ++ if (unlikely((pbuf == NULL) || (pbuf == (void *)&fin_packet))) { ++ if (recv_ring_handle_fin(sock, pbuf, recvd)) { ++ return 0; ++ } else { ++ break; /* recvd > 0, pending fin, handle data */ ++ } + } + + copy_len = (recv_left > pbuf->tot_len) ? pbuf->tot_len : recv_left; + if (copy_len > UINT16_MAX) { +- copy_len = UINT16_MAX; ++ copy_len = UINT16_MAX; /* it's impossible to get here */ + } + pbuf_copy_partial(pbuf, (char *)buf + recvd, copy_len, 0); + +@@ -907,39 +929,98 @@ ssize_t do_lwip_read_from_stack(int32_t fd, void *buf, size_t len, int32_t flags + + if (pbuf->tot_len > copy_len) { + sock->recv_lastdata = pbuf_free_partial(pbuf, copy_len); +- break; + } else { + if (sock->wakeup) { + sock->wakeup->stat.app_read_cnt += 1; + } +- if (latency_enable) { ++ ++ if (get_protocol_stack_group()->latency_start) { + calculate_lstack_latency(&sock->stack->latency, pbuf, GAZELLE_LATENCY_READ_LSTACK); + } +- gazelle_ring_read_over(sock->recv_ring); + +- /* in udp, if pbuf remaining len less than copy_len, discard these packets */ +- if (recvd > 0 && NETCONN_IS_UDP(sock)) { +- sock->stack->stats.sock_rx_drop++; +- break; +- } ++ gazelle_ring_read_over(sock->recv_ring); + } + } + +- /* rte_ring_count reduce lock */ +- if (sock->wakeup && sock->wakeup->type == WAKEUP_EPOLL && (sock->events & EPOLLIN) +- && (!NETCONN_IS_DATAIN(sock))) { +- del_sock_event(sock, EPOLLIN); ++ if (recvd > 0) { ++ errno = 0; ++ } else { ++ recvd = -1; + } + ++ return recvd; ++} ++ ++static ssize_t recv_ring_udp_read(struct lwip_sock *sock, void *buf, size_t len, bool noblock, ++ struct sockaddr *addr, socklen_t *addrlen) ++{ ++ size_t recv_left = len; ++ struct pbuf *pbuf = NULL; ++ uint32_t copy_len; ++ ++ sock->recv_lastdata = NULL; ++ ++ if (recv_ring_get_one(sock, noblock, &pbuf) != 0) { ++ /* errno have set */ ++ return -1; ++ } ++ ++ copy_len = (recv_left > pbuf->tot_len) ? pbuf->tot_len : recv_left; ++ pbuf_copy_partial(pbuf, (char *)buf, copy_len, 0); ++ /* drop remaining data if have */ ++ gazelle_ring_read_over(sock->recv_ring); ++ + if (pbuf && addr && addrlen) { + lwip_sock_make_addr(sock->conn, &(pbuf->addr), pbuf->port, addr, addrlen); + } + +- if (recvd == 0) { ++ if (copy_len < pbuf->tot_len) { ++ sock->stack->stats.sock_rx_drop++; ++ } ++ ++ if (sock->wakeup) { ++ sock->wakeup->stat.app_read_cnt++; ++ } ++ if (get_protocol_stack_group()->latency_start) { ++ calculate_lstack_latency(&sock->stack->latency, pbuf, GAZELLE_LATENCY_READ_LSTACK); ++ } ++ ++ return copy_len; ++} ++ ++ssize_t do_lwip_read_from_stack(int32_t fd, void *buf, size_t len, int32_t flags, ++ struct sockaddr *addr, socklen_t *addrlen) ++{ ++ ssize_t recvd = 0; ++ struct lwip_sock *sock = get_socket_by_fd(fd); ++ ++ if (recv_break_for_err(sock)) { ++ return -1; ++ } ++ ++ thread_bind_stack(sock); ++ ++ if (sock->same_node_rx_ring != NULL) { ++ return gazelle_same_node_ring_recv(sock, buf, len, flags); ++ } ++ ++ if (NETCONN_IS_UDP(sock)) { ++ recvd = recv_ring_udp_read(sock, buf, len, netconn_is_nonblocking(sock->conn), addr, addrlen); ++ } else { ++ recvd = recv_ring_tcp_read(sock, buf, len, netconn_is_nonblocking(sock->conn)); ++ } ++ ++ /* rte_ring_count reduce lock */ ++ if (sock->wakeup && sock->wakeup->type == WAKEUP_EPOLL && (sock->events & EPOLLIN) ++ && (!NETCONN_IS_DATAIN(sock))) { ++ del_sock_event(sock, EPOLLIN); ++ } ++ ++ if (recvd < 0) { + if (sock->wakeup) { + sock->wakeup->stat.read_null++; + } +- GAZELLE_RETURN(EAGAIN); ++ return -1; + } + return recvd; + } +-- +2.27.0 + diff --git a/0140-FAULT-INJECT-gazelle-add-packet-delay-and-packet-dro.patch b/0140-FAULT-INJECT-gazelle-add-packet-delay-and-packet-dro.patch new file mode 100644 index 0000000..cb42a61 --- /dev/null +++ b/0140-FAULT-INJECT-gazelle-add-packet-delay-and-packet-dro.patch @@ -0,0 +1,798 @@ +From f28b880f3be68377003c60005011a835eb18e105 Mon Sep 17 00:00:00 2001 +From: yinbin6 +Date: Sun, 18 Feb 2024 17:11:05 +0800 +Subject: [PATCH] FAULT INJECT: gazelle add packet delay and packet drop + +--- + src/common/gazelle_dfx_msg.h | 15 ++ + src/common/gazelle_fault_inject_common.h | 75 +++++++ + src/lstack/Makefile | 5 + + src/lstack/core/lstack_control_plane.c | 13 +- + src/lstack/include/lstack_fault_inject.h | 20 ++ + src/lstack/include/lstack_vdev.h | 1 + + src/lstack/netif/dir.mk | 3 + + src/lstack/netif/lstack_fault_inject.c | 187 ++++++++++++++++ + src/lstack/netif/lstack_vdev.c | 2 +- + src/ltran/CMakeLists.txt | 5 + + src/ltran/ltran_dfx.c | 274 ++++++++++++++++++++++- + 11 files changed, 595 insertions(+), 5 deletions(-) + create mode 100644 src/common/gazelle_fault_inject_common.h + create mode 100644 src/lstack/include/lstack_fault_inject.h + create mode 100644 src/lstack/netif/lstack_fault_inject.c + +diff --git a/src/common/gazelle_dfx_msg.h b/src/common/gazelle_dfx_msg.h +index 7f8422a..8d528d6 100644 +--- a/src/common/gazelle_dfx_msg.h ++++ b/src/common/gazelle_dfx_msg.h +@@ -18,6 +18,10 @@ + + #include + ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++#include "gazelle_fault_inject_common.h" ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ ++ + #define GAZELLE_CLIENT_NUM_MIN 1 + #define GAZELLE_LOG_LEVEL_MAX 10 + #define GAZELLECTL_TIMEOUT 5000 // millisecond +@@ -54,6 +58,11 @@ enum GAZELLE_STAT_MODE { + GAZELLE_STAT_LSTACK_SHOW_AGGREGATE, + GAZELLE_STAT_LSTACK_SHOW_NIC_FEATURES, + ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ GAZELLE_STAT_FAULT_INJECT_SET, ++ GAZELLE_STAT_FAULT_INJECT_UNSET, ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ ++ + GAZELLE_STAT_MODE_MAX, + }; + +@@ -277,6 +286,9 @@ struct gazelle_stack_dfx_data { + struct gazelle_stat_lstack_snmp snmp; + struct nic_eth_xstats nic_xstats; + struct nic_eth_features nic_features; ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ struct gazelle_fault_inject_data inject; ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ + } data; + }; + +@@ -307,6 +319,9 @@ struct gazelle_stat_msg_request { + union stat_param { + char log_level[GAZELLE_LOG_LEVEL_MAX]; + uint16_t low_power_mod; ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ struct gazelle_fault_inject_data inject; ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ + } data; + }; + +diff --git a/src/common/gazelle_fault_inject_common.h b/src/common/gazelle_fault_inject_common.h +new file mode 100644 +index 0000000..3a77f39 +--- /dev/null ++++ b/src/common/gazelle_fault_inject_common.h +@@ -0,0 +1,75 @@ ++/* ++* 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 __GAZELLE_INJECT_COMMON_H__ ++#define __GAZELLE_INJECT_COMMON_H__ ++ ++#include ++ ++enum GAZELLE_FAULT_INJECT_TYPE { ++ GAZELLE_FAULT_INJECT_TYPE_ERR = 0, ++ GAZELLE_FAULT_INJECT_PACKET_DELAY, ++ GAZELLE_FAULT_INJECT_PACKET_LOSS, ++ GAZELLE_FAULT_INJECT_PACKAET_DUPLICATE, ++ GAZELLE_FAULT_INJECT_PACKET_REORDER, ++ GAZELLE_FAULT_INJECT_TYPE_MAX, ++}; ++ ++enum GAZELLE_FAULT_INJECT_RULE { ++ INJECT_RULE_ERR = 0, ++ /* packet delay rule */ ++ INJECT_DELAY_RANDOM, ++ /* packet loss rule */ ++ INJECT_LOSS_RANDOM, ++ /* packet duplicate */ ++ INJECT_DUPLICATE_RANDOM, ++ /* packet reorder */ ++ INJECT_REORDER_RANDOM, ++}; ++ ++/* fault inject delay: packet delay's time and range, time unit is "ms" */ ++struct delay_data { ++ uint32_t delay_time; ++ uint32_t delay_range; ++}; ++ ++/* fault inject loss: packet loss rate */ ++struct loss_data { ++ double loss_rate; ++ uint32_t loss_sigle_count; ++}; ++ ++/* fault inject duplicate: packet duplicate rate and duplicate count */ ++struct duplicate_data { ++ double duplicate_rate; ++ uint32_t duplicate_sigle_count; ++}; ++ ++/* fault inject reorder: packet reorder rate and reorder count */ ++struct reorder_data { ++ double reorder_rate; ++ uint32_t reorder_sigle_count; ++}; ++ ++struct gazelle_fault_inject_data { ++ int32_t fault_inject_on; ++ enum GAZELLE_FAULT_INJECT_TYPE inject_type; ++ enum GAZELLE_FAULT_INJECT_RULE inject_rule; ++ union { ++ struct delay_data delay; ++ struct loss_data loss; ++ struct duplicate_data duplicate; ++ struct reorder_data reorder; ++ } inject_data; ++}; ++ ++#endif /* __GAZELLE_INJECT_COMMON_H__ */ +diff --git a/src/lstack/Makefile b/src/lstack/Makefile +index df1ddaa..d2c039d 100644 +--- a/src/lstack/Makefile ++++ b/src/lstack/Makefile +@@ -47,6 +47,11 @@ ifeq ($(GAZELLE_COVERAGE_ENABLE), 1) + CFLAGS += -fprofile-arcs -ftest-coverage + endif + ++ifeq ($(GAZELLE_FAULT_INJECT_ENABLE), 1) ++ LDFLAGS += -DGAZELLE_FAULT_INJECT_ENABLE ++ CFLAGS += -DGAZELLE_FAULT_INJECT_ENABLE ++endif ++ + ifeq ($(shell $(CC) -dumpmachine | cut -d"-" -f1), x86_64) + CFLAGS += -mssse3 + endif +diff --git a/src/lstack/core/lstack_control_plane.c b/src/lstack/core/lstack_control_plane.c +index 025291d..783f21c 100644 +--- a/src/lstack/core/lstack_control_plane.c ++++ b/src/lstack/core/lstack_control_plane.c +@@ -34,6 +34,10 @@ + #include "lstack_protocol_stack.h" + #include "lstack_control_plane.h" + ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++#include "lstack_fault_inject.h" ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ ++ + /* intervals between two connection attempts and two registration attempts, in second */ + #define CONNECT_TO_LTRAN_INFINITE (-1) + #define CONNECT_TO_LTRAN_RETRY_INTERVAL 1 +@@ -582,7 +586,14 @@ static int32_t handle_stat_request(int32_t sockfd) + LSTACK_LOG(ERR, LSTACK, "recv wrong stat mode %d\n", (int32_t)msg.stat_mode); + return 0; + } +- ++ ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ if (msg.stat_mode == GAZELLE_STAT_FAULT_INJECT_SET || ++ msg.stat_mode == GAZELLE_STAT_FAULT_INJECT_UNSET) { ++ return handle_fault_inject_cmd(sockfd, &msg); ++ } ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ ++ + if (msg.stat_mode == GAZELLE_STAT_LSTACK_LOG_LEVEL_SET || + msg.stat_mode == GAZELLE_STAT_LSTACK_LOW_POWER_MDF) { + return handle_proc_cmd(sockfd, &msg); +diff --git a/src/lstack/include/lstack_fault_inject.h b/src/lstack/include/lstack_fault_inject.h +new file mode 100644 +index 0000000..d54f1f2 +--- /dev/null ++++ b/src/lstack/include/lstack_fault_inject.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 __GAZELLE_INJECT_H__ ++#define __GAZELLE_INJECT_H__ ++ ++#include ++ ++int32_t handle_fault_inject_cmd(int32_t sockfd, struct gazelle_stat_msg_request *msg); ++ ++#endif /* __GAZELLE_INJECT_H__ */ +diff --git a/src/lstack/include/lstack_vdev.h b/src/lstack/include/lstack_vdev.h +index 4e5d191..1a8342a 100644 +--- a/src/lstack/include/lstack_vdev.h ++++ b/src/lstack/include/lstack_vdev.h +@@ -18,5 +18,6 @@ struct gazelle_quintuple; + enum reg_ring_type; + void vdev_dev_ops_init(struct lstack_dev_ops *dev_ops); + int vdev_reg_xmit(enum reg_ring_type type, struct gazelle_quintuple *qtuple); ++uint32_t vdev_tx_xmit(struct protocol_stack *stack, struct rte_mbuf **pkts, uint32_t nr_pkts); + + #endif /* _GAZELLE_VDEV_H_ */ +diff --git a/src/lstack/netif/dir.mk b/src/lstack/netif/dir.mk +index 20fb5d6..1e67734 100644 +--- a/src/lstack/netif/dir.mk ++++ b/src/lstack/netif/dir.mk +@@ -9,4 +9,7 @@ + # See the Mulan PSL v2 for more details. + + SRC = lstack_ethdev.c lstack_vdev.c lstack_flow.c ++ifeq ($(GAZELLE_FAULT_INJECT_ENABLE), 1) ++ SRC += lstack_fault_inject.c ++endif + $(eval $(call register_dir, netif, $(SRC))) +diff --git a/src/lstack/netif/lstack_fault_inject.c b/src/lstack/netif/lstack_fault_inject.c +new file mode 100644 +index 0000000..4daad10 +--- /dev/null ++++ b/src/lstack/netif/lstack_fault_inject.c +@@ -0,0 +1,187 @@ ++/* ++* 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 ++#include ++#include ++ ++#include ++ ++#include "lstack_cfg.h" ++#include "lstack_log.h" ++#include "lstack_vdev.h" ++ ++#define INJECT_MODULO 1000 /* used in modulus operator */ ++#define INJECT_US_TO_MS 1000 /* transefer time unit us to ms */ ++ ++typedef int32_t (*inject_xmit_func)(struct protocol_stack *stack, struct rte_mbuf **pkts, ++ uint32_t nr_pkts, struct gazelle_fault_inject_data data); ++struct inject_tbl { ++ struct gazelle_fault_inject_data inject_data; ++ inject_xmit_func inject_func; ++}; ++static struct inject_tbl g_inject_tbl[GAZELLE_FAULT_INJECT_TYPE_MAX]; ++ ++struct inject_func_tbl { ++ enum GAZELLE_FAULT_INJECT_TYPE type; ++ enum GAZELLE_FAULT_INJECT_RULE rule; ++ inject_xmit_func inject_func; ++}; ++ ++static int32_t inject_packet_delay_random(struct protocol_stack *stack, struct rte_mbuf **pkts, ++ uint32_t nr_pkts, struct gazelle_fault_inject_data data); ++static int32_t inject_packet_loss_random(struct protocol_stack *stack, struct rte_mbuf **pkts, ++ uint32_t nr_pkts, struct gazelle_fault_inject_data data); ++ ++static struct inject_func_tbl g_inject_func_tbl[] = { ++ {GAZELLE_FAULT_INJECT_PACKET_LOSS, INJECT_LOSS_RANDOM, inject_packet_loss_random}, ++ {GAZELLE_FAULT_INJECT_PACKET_DELAY, INJECT_DELAY_RANDOM, inject_packet_delay_random}, ++}; ++ ++static int32_t inject_func_tbl_update() ++{ ++ int32_t func_count = sizeof(g_inject_func_tbl) / sizeof(g_inject_func_tbl[0]); ++ ++ for (int32_t i = 0; i < GAZELLE_FAULT_INJECT_TYPE_MAX; ++i) { ++ if (!g_inject_tbl[i].inject_data.fault_inject_on) { ++ continue; ++ } ++ for (int32_t j = 0; j < func_count; ++j) { ++ if (g_inject_func_tbl[j].type == g_inject_tbl[i].inject_data.inject_type && ++ g_inject_func_tbl[j].rule == g_inject_tbl[i].inject_data.inject_rule) { ++ g_inject_tbl[i].inject_func = g_inject_func_tbl[j].inject_func; ++ } ++ } ++ } ++ return 0; ++} ++ ++static uint32_t inject_tx_xmit(struct protocol_stack *stack, struct rte_mbuf **pkts, uint32_t nr_pkts) ++{ ++ for (int32_t i = 0; i < GAZELLE_FAULT_INJECT_TYPE_MAX; ++i) { ++ if (g_inject_tbl[i].inject_data.fault_inject_on) { ++ int32_t xmit_pkts = 0; ++ xmit_pkts = g_inject_tbl[i].inject_func(stack, pkts, nr_pkts, ++ g_inject_tbl[i].inject_data); ++ if (xmit_pkts == nr_pkts) { ++ continue; ++ } ++ return xmit_pkts; ++ } ++ } ++ if (rte_mbuf_refcnt_read(*pkts) == 1) { ++ return nr_pkts; ++ } ++ return vdev_tx_xmit(stack, pkts, nr_pkts); ++} ++ ++static int32_t inject_strategy_update() ++{ ++ inject_func_tbl_update(); ++ ++ int32_t inject_on = 0; ++ for (int32_t i = 0; i < GAZELLE_FAULT_INJECT_TYPE_MAX; ++i) { ++ if (g_inject_tbl[i].inject_data.fault_inject_on) { ++ inject_on = 1; ++ break; ++ } ++ } ++ ++ struct protocol_stack_group *stack_group = get_protocol_stack_group(); ++ ++ if (inject_on) { ++ for (uint32_t i = 0; i < stack_group->stack_num; ++i) { ++ struct protocol_stack *stack = stack_group->stacks[i]; ++ stack->dev_ops.tx_xmit = inject_tx_xmit; ++ } ++ return 0; ++ } ++ ++ for (uint32_t i = 0; i < stack_group->stack_num; ++i) { ++ struct protocol_stack *stack = stack_group->stacks[i]; ++ vdev_dev_ops_init(&stack->dev_ops); ++ } ++ ++ return 0; ++} ++ ++static int32_t inject_packet_delay_random(struct protocol_stack *stack, struct rte_mbuf **pkts, ++ uint32_t nr_pkts, struct gazelle_fault_inject_data data) ++{ ++ /* while *pkts->refcnt == 1, other inject type is on, and the packets have been loss. */ ++ if (rte_mbuf_refcnt_read(*pkts) == 1) { ++ return nr_pkts; ++ } ++ int32_t delay_time = data.inject_data.delay.delay_time; ++ int32_t delay_range = data.inject_data.delay.delay_range; ++ int32_t rand_num = rte_rand(); ++ rand_num %= INJECT_MODULO; ++ delay_time += delay_range * rand_num / INJECT_MODULO; ++ rte_delay_us(delay_time * INJECT_US_TO_MS); ++ ++ return nr_pkts; ++} ++ ++static int32_t inject_packet_loss_random(struct protocol_stack *stack, struct rte_mbuf **pkts, ++ uint32_t nr_pkts, struct gazelle_fault_inject_data data) ++{ ++ double loss_rate = data.inject_data.loss.loss_rate; ++ int32_t boundary = (int32_t) (loss_rate * INJECT_MODULO); ++ ++ uint32_t rand_num = rte_rand(); ++ rand_num %= INJECT_MODULO; ++ ++ if (rand_num > boundary) { ++ return nr_pkts; ++ } ++ ++ for (int32_t i = 0; i < nr_pkts; ++i) { ++ rte_pktmbuf_free(pkts[i]); ++ } ++ return nr_pkts; ++} ++ ++int32_t handle_fault_inject_cmd(int32_t sockfd, struct gazelle_stat_msg_request *msg) ++{ ++ struct gazelle_stack_dfx_data rsp = {0}; ++ int32_t ret = 0; ++ ++ ret = memcpy_s(&g_inject_tbl[msg->data.inject.inject_type].inject_data, ++ sizeof(struct gazelle_fault_inject_data), ++ &msg->data.inject, sizeof(struct gazelle_fault_inject_data)); ++ if (ret != EOK) { ++ LSTACK_LOG(ERR, LSTACK, "fault inject memcpy_s error, ret = %d", ret); ++ return -1; ++ } ++ ++ inject_strategy_update(); ++ ++ for (int32_t i = 0; i < GAZELLE_FAULT_INJECT_TYPE_MAX; ++i) { ++ ret = memcpy_s(&rsp.data.inject, sizeof(struct gazelle_fault_inject_data), ++ &g_inject_tbl[i].inject_data, sizeof(struct gazelle_fault_inject_data)); ++ if (ret != EOK) { ++ LSTACK_LOG(ERR, LSTACK, "fault inject memcpy_s error, ret = %d", ret); ++ return -1; ++ } ++ if (i == GAZELLE_FAULT_INJECT_TYPE_MAX -1) { ++ rsp.eof = 1; ++ } ++ ret = (int32_t) posix_api->write_fn(sockfd, (void *)&rsp, sizeof(rsp)); ++ if (ret <= 0) { ++ LSTACK_LOG(ERR, LSTACK, "write msg from peer failed, errno %d. ret=%d\n", errno, ret); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ +diff --git a/src/lstack/netif/lstack_vdev.c b/src/lstack/netif/lstack_vdev.c +index 3703092..107ee8c 100644 +--- a/src/lstack/netif/lstack_vdev.c ++++ b/src/lstack/netif/lstack_vdev.c +@@ -150,7 +150,7 @@ static uint32_t ltran_tx_xmit(struct protocol_stack *stack, struct rte_mbuf **pk + return sent_pkts; + } + +-static uint32_t vdev_tx_xmit(struct protocol_stack *stack, struct rte_mbuf **pkts, uint32_t nr_pkts) ++uint32_t vdev_tx_xmit(struct protocol_stack *stack, struct rte_mbuf **pkts, uint32_t nr_pkts) + { + uint32_t sent_pkts = 0; + +diff --git a/src/ltran/CMakeLists.txt b/src/ltran/CMakeLists.txt +index f739ceb..a484ae3 100644 +--- a/src/ltran/CMakeLists.txt ++++ b/src/ltran/CMakeLists.txt +@@ -27,6 +27,11 @@ if($ENV{GAZELLE_COVERAGE_ENABLE}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs") + endif($ENV{GAZELLE_COVERAGE_ENABLE}) + ++if($ENV{GAZELLE_FAULT_INJECT_ENABLE}) ++ message("Enable Fault inject option") ++ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGAZELLE_FAULT_INJECT_ENABLE") ++endif($ENV{GAZELLE_FAULT_INJECT_ENABLE}) ++ + execute_process( + COMMAND rpm -qa dpdk + OUTPUT_VARIABLE DPDK_VERSION_FULL +diff --git a/src/ltran/ltran_dfx.c b/src/ltran/ltran_dfx.c +index 344afb2..413bf89 100644 +--- a/src/ltran/ltran_dfx.c ++++ b/src/ltran/ltran_dfx.c +@@ -60,6 +60,46 @@ static struct gazelle_stat_ltran_total g_last_ltran_total; + static struct gazelle_stat_lstack_total g_last_lstack_total[GAZELLE_MAX_STACK_ARRAY_SIZE]; + static struct gazelle_stack_dfx_data g_last_lstack_data[GAZELLE_MAX_STACK_ARRAY_SIZE]; + ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++#define INJECT_NAME_SIZE 32 ++#define INJECT_RULE_SIZE 32 ++ ++typedef int32_t (*inject_parse_digit_fun)(char*, char*, struct gazelle_stat_msg_request *req_msg); ++static int32_t parse_inject_packet_delay_digit(char *time, char *range, struct gazelle_stat_msg_request *req_msg); ++static int32_t parse_inject_packet_loss_digit(char *rate, char *count, struct gazelle_stat_msg_request *req_msg); ++static int32_t parse_inject_packet_duplicate_digit(char *rate, char *count, struct gazelle_stat_msg_request *req_msg); ++static int32_t parse_inject_packet_reorder_digit(char *rate, char *count, struct gazelle_stat_msg_request *req_msg); ++ ++struct gazelle_fault_inject_type_list { ++ char inject_type_item[INJECT_NAME_SIZE]; ++ enum GAZELLE_FAULT_INJECT_TYPE inject_type_parsed; ++ inject_parse_digit_fun parse_digit_func; ++}; ++ ++static struct gazelle_fault_inject_type_list inject_type_list[] = { ++ {"delay", GAZELLE_FAULT_INJECT_PACKET_DELAY, parse_inject_packet_delay_digit}, ++ {"loss", GAZELLE_FAULT_INJECT_PACKET_LOSS, parse_inject_packet_loss_digit}, ++ {"duplicate", GAZELLE_FAULT_INJECT_PACKAET_DUPLICATE, parse_inject_packet_duplicate_digit}, ++ {"reorder", GAZELLE_FAULT_INJECT_PACKET_REORDER, parse_inject_packet_reorder_digit}, ++}; ++ ++struct gazelle_fault_inject_rule_list { ++ char inject_rule_item[INJECT_RULE_SIZE]; ++ enum GAZELLE_FAULT_INJECT_RULE inject_rule_parsed; ++ enum GAZELLE_FAULT_INJECT_TYPE rule_parse_assit; ++}; ++ ++static struct gazelle_fault_inject_rule_list g_gazelle_fault_inject_rule_list[] = { ++ {"random", INJECT_DELAY_RANDOM, GAZELLE_FAULT_INJECT_PACKET_DELAY}, ++ {"random", INJECT_LOSS_RANDOM, GAZELLE_FAULT_INJECT_PACKET_LOSS}, ++ {"random", INJECT_DUPLICATE_RANDOM, GAZELLE_FAULT_INJECT_PACKAET_DUPLICATE}, ++ {"random", INJECT_REORDER_RANDOM, GAZELLE_FAULT_INJECT_PACKET_REORDER}, ++}; ++ ++static void gazelle_print_fault_inject_set_status(void *buf, const struct gazelle_stat_msg_request *req_msg); ++ ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ ++ + static bool g_use_ltran = false; + + static char* g_unix_prefix; +@@ -95,6 +135,11 @@ static void gazelle_print_lstack_xstats(void *buf, const struct gazelle_stat_msg + static void gazelle_print_lstack_aggregate(void *buf, const struct gazelle_stat_msg_request *req_msg); + static void gazelle_print_lstack_nic_features(void *buf, const struct gazelle_stat_msg_request *req_msg); + ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++static void gazelle_print_fault_inject_set_status(void *buf, const struct gazelle_stat_msg_request *req_msg); ++static void gazelle_print_fault_inject_unset_status(void *buf, const struct gazelle_stat_msg_request *req_msg); ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ ++ + static struct gazelle_dfx_list g_gazelle_dfx_tbl[] = { + {GAZELLE_STAT_LTRAN_SHOW, sizeof(struct gazelle_stat_ltran_total), gazelle_print_ltran_stat_total}, + {GAZELLE_STAT_LTRAN_SHOW_RATE, sizeof(struct gazelle_stat_ltran_total), gazelle_print_ltran_stat_rate}, +@@ -121,6 +166,11 @@ static struct gazelle_dfx_list g_gazelle_dfx_tbl[] = { + {GAZELLE_STAT_LSTACK_SHOW_XSTATS, sizeof(struct gazelle_stack_dfx_data), gazelle_print_lstack_xstats}, + {GAZELLE_STAT_LSTACK_SHOW_AGGREGATE, sizeof(struct gazelle_stack_dfx_data), gazelle_print_lstack_aggregate}, + {GAZELLE_STAT_LSTACK_SHOW_NIC_FEATURES, sizeof(struct gazelle_stack_dfx_data), gazelle_print_lstack_nic_features}, ++ ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ {GAZELLE_STAT_FAULT_INJECT_SET, sizeof(struct gazelle_stack_dfx_data), gazelle_print_fault_inject_set_status}, ++ {GAZELLE_STAT_FAULT_INJECT_UNSET, sizeof(struct gazelle_stack_dfx_data), gazelle_print_fault_inject_unset_status}, ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ + }; + + static int32_t g_wait_reply = 1; +@@ -1121,7 +1171,10 @@ static void show_usage(void) + { + printf("Usage: gazellectl [-h | help] \n" + " or: gazellectl ltran {quit | show | set} [LTRAN_OPTIONS] [-u UNIX_PREFIX]\n" +- " or: gazellectl lstack {show | set} ip [LSTACK_OPTIONS] [-u UNIX_PREFIX]\n \n" ++ " or: gazellectl lstack {show | set} ip [LSTACK_OPTIONS] [-u UNIX_PREFIX]\n\n" ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ " or: gazellectl inject [inject_type] [digit_param_1] [digit_param_2] [inject_rule]\n\n" ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ + " quit ltran process exit \n \n" + " where LTRAN_OPTIONS := \n" + " show: \n" +@@ -1146,7 +1199,13 @@ static void show_usage(void) + " set: \n" + " loglevel {error | info | debug} set lstack loglevel \n" + " lowpower {0 | 1} set lowpower enable \n" +- " [time] measure latency time default 1S, maximum 30mins \n"); ++ " [time] measure latency time default 1S, maximum 30mins \n\n" ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ " *inject params*\n" ++ " |inject_type | digit_param_1 | digit_param_2 | inject_rule |\n" ++ " | delay | delay_time(unit: ms) | delay_range(unit: ms) | random |\n" ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ ++ ); + } + + static int32_t parse_dfx_ltran_set_args(int32_t argc, char *argv[], struct gazelle_stat_msg_request *req_msg) +@@ -1436,6 +1495,211 @@ static int32_t parse_dfx_lstack_args(int32_t argc, char *argv[], struct gazelle_ + return num_cmd; + } + ++ ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ ++#define GAZELLE_SET_FAULT_INJECT_PARAM_COUNT 6 ++#define GAZELLE_UNSET_FAULT_INJECT_PARAM_COUNT 4 ++#define INJECT_TYPE_INDEX 2 ++#define INJECT_DIGITAL_FIRST_INDEX 3 ++#define INJECT_DIGITAL_SECOND_INDEX 4 ++#define INJECT_RULE_INDEX 5 ++ ++ ++static void gazelle_print_fault_inject_type_info(struct gazelle_fault_inject_data *inject) ++{ ++ if (!inject->fault_inject_on) { ++ return; ++ } ++ ++ if (inject->inject_type == GAZELLE_FAULT_INJECT_PACKET_DELAY) { ++ printf("\t| inject_type: delay | delay_time: %-7d | delay_range: %-3d | " ++ "inject_rule: random |\n", inject->inject_data.delay.delay_time, ++ inject->inject_data.delay.delay_range); ++ } ++ ++#define INJECT_PERCENT 100 ++ ++ if (inject->inject_type == GAZELLE_FAULT_INJECT_PACKET_LOSS) { ++ printf("\t| inject_type: loss | loss_rate: %-3.1f%% | loss_single_count: %-3d | " ++ "inject_rule: random |\n", inject->inject_data.loss.loss_rate * INJECT_PERCENT, ++ inject->inject_data.loss.loss_sigle_count); ++ } ++ printf("\n"); ++} ++ ++static void gazelle_print_fault_inject_set_status(void *buf, const struct gazelle_stat_msg_request *req_msg) ++{ ++ int32_t ret; ++ struct gazelle_stack_dfx_data *stat = (struct gazelle_stack_dfx_data *)buf; ++ struct gazelle_fault_inject_data *inject = &stat->data.inject; ++ ++ printf("\n\n\t\t\t\t\t **** FAULT INJECT INFO **** \n\n"); ++ do { ++ gazelle_print_fault_inject_type_info(inject); ++ if (stat->eof != 0) { ++ break; ++ } ++ ret = dfx_stat_read_from_ltran(buf, sizeof(struct gazelle_stack_dfx_data), req_msg->stat_mode); ++ if (ret != GAZELLE_OK) { ++ return; ++ } ++ } while (true); ++} ++ ++static void gazelle_print_fault_inject_unset_status(void *buf, const struct gazelle_stat_msg_request *req_msg) ++{ ++ return; ++} ++ ++static int32_t parse_inject_packet_delay_digit(char* time, char* range, struct gazelle_stat_msg_request *req_msg) ++{ ++ int32_t parse_success = 0; ++ int32_t delay_time = atoi(time); ++ if (delay_time <= 0) { ++ printf("FAULT INJECT error: delay time error -- %d, need positive integer.\n", delay_time); ++ return parse_success; ++ } ++ req_msg->data.inject.inject_data.delay.delay_time = (uint32_t) delay_time; ++ ++ int32_t delay_range = atoi(range); ++ if (delay_range < 0) { ++ printf("FAULT INJECT error: delay range error -- %d, need positive integer.\n", delay_range); ++ return parse_success; ++ } ++ if (delay_time - delay_range <= 0) { ++ printf("FAULT INJECT error: delay range should lower than delay time.\n"); ++ return parse_success; ++ } ++ req_msg->data.inject.inject_data.delay.delay_range = delay_range; ++ ++ return ++parse_success; ++} ++ ++#define INJECT_RATE_LOWER 0.001 ++ ++static int32_t parse_inject_packet_loss_digit(char *rate, char *count, struct gazelle_stat_msg_request *req_msg) ++{ ++ int32_t parse_success = 0; ++ double loss_rate = atof(rate); ++ if (loss_rate < INJECT_RATE_LOWER || loss_rate >= 1) { ++ printf("FAULT INJECT error: loss rate error, range in [0.001, 1), now is %f\n", loss_rate); ++ return parse_success; ++ } ++ req_msg->data.inject.inject_data.loss.loss_rate = loss_rate; ++ ++ int32_t loss_counts = atoi(count); ++ if (loss_counts <= 0) { ++ printf("FAULT INJECT error: single loss counts wrong --%d, need positive integer.", loss_counts); ++ return parse_success; ++ } ++ req_msg->data.inject.inject_data.loss.loss_sigle_count = loss_counts; ++ ++ return ++parse_success; ++} ++ ++static int32_t parse_inject_packet_duplicate_digit(char *rate, char *count, struct gazelle_stat_msg_request *req_msg) ++{ ++ int32_t parse_success = 0; ++ double duplicate_rate = atof(rate); ++ if (duplicate_rate < INJECT_RATE_LOWER || duplicate_rate >= 1) { ++ printf("FAULT INJECT error: duplicate rate error, range in [0.001, 1), now is %f\n", duplicate_rate); ++ return parse_success; ++ } ++ req_msg->data.inject.inject_data.duplicate.duplicate_rate = duplicate_rate; ++ ++ int32_t duplicate_counts = atoi(count); ++ if (duplicate_counts <= 0) { ++ printf("FAULT INJECT error: single duplicate counts wrong --%d, need positive integer.", duplicate_counts); ++ return parse_success; ++ } ++ req_msg->data.inject.inject_data.duplicate.duplicate_sigle_count = duplicate_counts; ++ ++ return ++parse_success; ++} ++ ++static int32_t parse_inject_packet_reorder_digit(char *rate, char *count, struct gazelle_stat_msg_request *req_msg) ++{ ++ int32_t parse_success = 0; ++ double reorder_rate = atof(rate); ++ if (reorder_rate < INJECT_RATE_LOWER || reorder_rate >= 1) { ++ printf("FAULT INJECT error: reorder rate error, range in [0.001, 1), now is %f\n", reorder_rate); ++ return parse_success; ++ } ++ req_msg->data.inject.inject_data.reorder.reorder_rate = reorder_rate; ++ ++ int32_t reorder_counts = atoi(count); ++ if (reorder_counts <= 0) { ++ printf("FAULT INJECT error: single duplicate counts wrong --%d, need positive integer.", reorder_counts); ++ return parse_success; ++ } ++ req_msg->data.inject.inject_data.reorder.reorder_sigle_count = reorder_counts; ++ ++ return ++parse_success; ++} ++ ++static int32_t parse_fault_inject_digital_data(char *argv[], struct gazelle_stat_msg_request *req_msg) ++{ ++ int32_t parse_success = 0; ++ int32_t func_count = sizeof(inject_type_list) / sizeof(inject_type_list[0]); ++ for (int32_t i = 0; i < func_count; ++i) { ++ if (inject_type_list[i].inject_type_parsed == req_msg->data.inject.inject_type) { ++ parse_success = inject_type_list[i].parse_digit_func(argv[INJECT_DIGITAL_FIRST_INDEX], ++ argv[INJECT_DIGITAL_SECOND_INDEX], req_msg); ++ break; ++ } ++ } ++ ++ return parse_success; ++} ++ ++static int32_t parse_dfx_fault_inject_args(int32_t argc, char *argv[], struct gazelle_stat_msg_request *req_msg) ++{ ++ int32_t num_cmd = 0; /* while parse error, num_cmd will return as 0, or num_cmd should be returned as 1. */ ++ ++ req_msg->data.inject.fault_inject_on = 1; /* set fault inject on */ ++ ++ if (argc == GAZELLE_SET_FAULT_INJECT_PARAM_COUNT) { ++ req_msg->stat_mode = GAZELLE_STAT_FAULT_INJECT_SET; ++ } else if (argc == GAZELLE_UNSET_FAULT_INJECT_PARAM_COUNT) { ++ req_msg->stat_mode = GAZELLE_STAT_FAULT_INJECT_UNSET; ++ } else { ++ printf("FAULT_INJECT error: Count of params wrong , correct count is 6 or 4, now is %d\n", argc); ++ return num_cmd; ++ } ++ ++ int32_t inject_type_count = sizeof(inject_type_list) / sizeof(inject_type_list[0]); ++ for (int32_t i = 0; i < inject_type_count; ++i) { ++ if (strcmp(inject_type_list[i].inject_type_item, argv[INJECT_TYPE_INDEX]) == 0) { ++ req_msg->data.inject.inject_type = inject_type_list[i].inject_type_parsed; ++ break; ++ } ++ } ++ if (req_msg->data.inject.inject_type == GAZELLE_FAULT_INJECT_TYPE_ERR) { ++ printf("FAULT_INJECT error: input inject type is wrong -- %s\n", argv[INJECT_TYPE_INDEX]); ++ return num_cmd; ++ } ++ ++ int32_t inject_rule_count = sizeof(g_gazelle_fault_inject_rule_list) / sizeof(g_gazelle_fault_inject_rule_list[0]); ++ for (int32_t i = 0; i < inject_rule_count; ++i) { ++ if (strcmp(g_gazelle_fault_inject_rule_list[i].inject_rule_item, argv[INJECT_RULE_INDEX]) == 0 && ++ g_gazelle_fault_inject_rule_list[i].rule_parse_assit == req_msg->data.inject.inject_type) { ++ req_msg->data.inject.inject_rule = g_gazelle_fault_inject_rule_list[i].inject_rule_parsed; ++ break; ++ } ++ } ++ if (req_msg->data.inject.inject_rule == INJECT_RULE_ERR) { ++ printf("FAULT_INJECT error: input inject rule is wrong -- %s\n", argv[INJECT_RULE_INDEX]); ++ return num_cmd; ++ } ++ ++ num_cmd = parse_fault_inject_digital_data(argv, req_msg); ++ ++ return num_cmd; ++} ++ ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ ++ + static int32_t parse_dfx_cmd_args(int32_t argc, char *argv[], struct gazelle_stat_msg_request *req_msg) + { + int32_t num_cmd = 0; +@@ -1451,7 +1715,11 @@ static int32_t parse_dfx_cmd_args(int32_t argc, char *argv[], struct gazelle_sta + if (strcmp(param, "lstack") == 0) { + num_cmd = parse_dfx_lstack_args(argc, argv, req_msg); + } +- ++#ifdef GAZELLE_FAULT_INJECT_ENABLE ++ if (strcmp(param, "inject") == 0) { ++ num_cmd = parse_dfx_fault_inject_args(argc, argv, req_msg); ++ } ++#endif /* GAZELLE_FAULT_INJECT_ENABLE */ + return num_cmd; + } + +-- +2.27.0 + diff --git a/gazelle.spec b/gazelle.spec index 7d0553f..e9ed1ad 100644 --- a/gazelle.spec +++ b/gazelle.spec @@ -2,7 +2,7 @@ Name: gazelle Version: 1.0.2 -Release: 27 +Release: 28 Summary: gazelle is a high performance user-mode stack License: MulanPSL-2.0 URL: https://gitee.com/openeuler/gazelle @@ -145,6 +145,15 @@ Patch9128: 0128-fix-t_params-double-free.patch Patch9129: 0129-fix-receive-fin-packet-process-error.patch Patch9130: 0130-support-netperf-UDP_STREAM-and-UDP_RR.patch Patch9131: 0131-adapt-lwip-2.2.0.patch +Patch9132: 0132-add-observable-method-of-data-aggregation.patch +Patch9133: 0133-try-to-ensure-arp-packet-can-be-sent.patch +Patch9134: 0134-gazellectl-support-send-latency-show.patch +Patch9135: 0135-rpc-function-does-not-depend-on-protocol-stack.patch +Patch9136: 0136-readv-return-1-errno-is-EAGAIN-when-recvring-no-data.patch +Patch9137: 0137-split-the-flow-fules-related-functions-into-separate.patch +Patch9138: 0138-fix-coreddump-when-stack-setup-failed-in-rtc-mode.patch +Patch9139: 0139-diff-udp-and-tcp-read-from-stack.patch +Patch9140: 0140-FAULT-INJECT-gazelle-add-packet-delay-and-packet-dro.patch %description %{name} is a high performance user-mode stack. @@ -186,6 +195,17 @@ install -Dpm 0640 %{_builddir}/%{name}-%{version}/src/ltran/ltran.conf %{b %config(noreplace) %{conf_path}/ltran.conf %changelog +* Thu Mar 14 2024 yinbin6 - 1.0.2-28 +- FAULT INJECT: gazelle add packet delay and packet drop +- diff udp and tcp read from stack +- fix coreddump when stack setup failed in rtc mode +- split the flow fules related functions into separate file +- readv return -1, errno is EAGAIN when recvring no data +- rpc function does not depend on protocol stack diff rpc queue and dfx rpc queue +- gazellectl: support send latency show +- try to ensure arp packet can be sent +- add observable method of data aggregation + * Wed Feb 07 2024 yibin6 - 1.0.2-27 - support netperf UDP_STREAM and UDP_RR