From 3beb273528f360c7d6863990a5d0cdcb5ebcb407 Mon Sep 17 00:00:00 2001
From: ningjin <ningjin@kylinos.cn>
Date: Thu, 28 Mar 2024 16:05:01 +0800
Subject: [PATCH] gazellectl add lwip stats_proto print

---
 src/common/gazelle_dfx_msg.h           | 23 ++++++++++
 src/lstack/core/lstack_control_plane.c |  2 +-
 src/lstack/core/lstack_stack_stat.c    | 41 +++++++++++++++--
 src/lstack/include/lstack_stack_stat.h |  3 +-
 src/ltran/ltran_dfx.c                  | 61 +++++++++++++++++++++++++-
 src/ltran/ltran_monitor.c              |  1 +
 6 files changed, 124 insertions(+), 7 deletions(-)

diff --git a/src/common/gazelle_dfx_msg.h b/src/common/gazelle_dfx_msg.h
index d7ba80f..6cd90b1 100644
--- a/src/common/gazelle_dfx_msg.h
+++ b/src/common/gazelle_dfx_msg.h
@@ -24,6 +24,7 @@
 
 #define GAZELLE_CLIENT_NUM_MIN           1
 #define GAZELLE_LOG_LEVEL_MAX            10
+#define MAX_PROTOCOL_LENGTH              20
 #define GAZELLECTL_TIMEOUT               5000 // millisecond
 /* 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
@@ -46,6 +47,7 @@ enum GAZELLE_STAT_MODE {
     GAZELLE_STAT_LTRAN_SHOW_SOCKTABLE,
     GAZELLE_STAT_LTRAN_SHOW_CONNTABLE,
     GAZELLE_STAT_LTRAN_SHOW_LSTACK,
+    GAZELLE_STAT_LSTACK_SHOW_PROTOCOL,
 
     GAZELLE_STAT_LSTACK_SHOW,
     GAZELLE_STAT_LSTACK_LOG_LEVEL_SET,
@@ -193,6 +195,24 @@ struct gazelle_stat_lstack_snmp {
     uint32_t icmp_out_echo_reps;
 };
 
+/* same as define in lwip/stats.h - struct stats_proto */
+struct gazelle_stat_lstack_proto {
+    /* data */
+    uint16_t xmit;             /* Transmitted packets. */
+    uint16_t recv;             /* Received packets. */
+    uint16_t fw;               /* Forwarded packets. */
+    uint16_t drop;             /* Dropped packets. */
+    uint16_t chkerr;           /* Checksum error. */
+    uint16_t lenerr;           /* Invalid length error. */
+    uint16_t memerr;           /* Out of memory error. */
+    uint16_t rterr;            /* Routing error. */
+    uint16_t proterr;          /* Protocol error. */
+    uint16_t opterr;           /* Error in options. */
+    uint16_t err;              /* Misc error. */
+    uint16_t cachehit;
+};
+
+
 /* same as define in lwip/tcp.h - struct tcp_pcb_dp */
 struct gazelle_stat_lstack_conn_info {
     uint32_t state;
@@ -288,6 +308,8 @@ struct gazelle_stack_dfx_data {
         struct gazelle_stat_lstack_snmp snmp;
         struct nic_eth_xstats nic_xstats;
         struct nic_eth_features nic_features;
+        struct gazelle_stat_lstack_proto  proto_data;
+
 #ifdef GAZELLE_FAULT_INJECT_ENABLE
         struct gazelle_fault_inject_data inject;
 #endif /* GAZELLE_FAULT_INJECT_ENABLE */
@@ -321,6 +343,7 @@ struct gazelle_stat_msg_request {
     union stat_param {
         char log_level[GAZELLE_LOG_LEVEL_MAX];
         uint16_t low_power_mod;
+        char protocol[MAX_PROTOCOL_LENGTH];
 #ifdef GAZELLE_FAULT_INJECT_ENABLE
         struct gazelle_fault_inject_data inject;
 #endif /* GAZELLE_FAULT_INJECT_ENABLE */
diff --git a/src/lstack/core/lstack_control_plane.c b/src/lstack/core/lstack_control_plane.c
index 9f0c313..04858c7 100644
--- a/src/lstack/core/lstack_control_plane.c
+++ b/src/lstack/core/lstack_control_plane.c
@@ -601,7 +601,7 @@ static int32_t handle_stat_request(int32_t sockfd)
         msg.stat_mode == GAZELLE_STAT_LSTACK_SHOW_NIC_FEATURES) {
         return handle_dpdk_cmd(sockfd, msg.stat_mode);
     } else {
-        ret = handle_stack_cmd(sockfd, msg.stat_mode);
+        ret = handle_stack_cmd(sockfd, &msg);
         if (ret != 0) {
             LSTACK_LOG(ERR, LSTACK, "get_stats failed ret=%d\n", ret);
         }
diff --git a/src/lstack/core/lstack_stack_stat.c b/src/lstack/core/lstack_stack_stat.c
index 3e016b7..d439357 100644
--- a/src/lstack/core/lstack_stack_stat.c
+++ b/src/lstack/core/lstack_stack_stat.c
@@ -210,11 +210,42 @@ static void get_stack_stats(struct gazelle_stack_dfx_data *dfx, struct protocol_
     dfx->data.pkts.conn_num = stack->conn_num;
 }
 
+static void get_stack_dfx_data_proto(struct gazelle_stack_dfx_data *dfx, struct protocol_stack *stack,
+    struct gazelle_stat_msg_request *msg)
+{
+    int32_t ret = 0;
+    msg->data.protocol[MAX_PROTOCOL_LENGTH - 1] = '\0';
+    const char* proto_mode = msg->data.protocol;
+
+    if (strcmp(proto_mode, "UDP") == 0) {
+        ret = memcpy_s(&dfx->data.proto_data, sizeof(dfx->data.proto_data),
+                       &stack->lwip_stats->udp, sizeof(stack->lwip_stats->udp));
+    } else if (strcmp(proto_mode, "TCP") == 0) {
+        ret = memcpy_s(&dfx->data.proto_data, sizeof(dfx->data.proto_data),
+                       &stack->lwip_stats->tcp, sizeof(stack->lwip_stats->tcp));
+    } else if (strcmp(proto_mode, "IP") == 0) {
+        ret = memcpy_s(&dfx->data.proto_data, sizeof(dfx->data.proto_data),
+                       &stack->lwip_stats->ip, sizeof(stack->lwip_stats->ip));
+    } else if (strcmp(proto_mode, "ICMP") == 0) {
+        ret = memcpy_s(&dfx->data.proto_data, sizeof(dfx->data.proto_data),
+                       &stack->lwip_stats->icmp, sizeof(stack->lwip_stats->icmp));
+    } else if (strcmp(proto_mode, "ETHARP") == 0) {
+        ret = memcpy_s(&dfx->data.proto_data, sizeof(dfx->data.proto_data),
+                       &stack->lwip_stats->etharp, sizeof(stack->lwip_stats->etharp));
+    } else {
+        printf("Error: Invalid protocol\n");
+    }
+    if (ret != EOK) {
+        LSTACK_LOG(ERR, LSTACK, "memcpy_s err ret=%d \n", ret);
+    }
+}
+
 static void get_stack_dfx_data(struct gazelle_stack_dfx_data *dfx, struct protocol_stack *stack,
-    enum GAZELLE_STAT_MODE stat_mode)
+    struct gazelle_stat_msg_request *msg)
 {
     int32_t rpc_call_result;
     int32_t ret;
+    enum GAZELLE_STAT_MODE stat_mode = msg->stat_mode;
 
     switch (stat_mode) {
         case GAZELLE_STAT_LSTACK_SHOW:
@@ -255,6 +286,9 @@ static void get_stack_dfx_data(struct gazelle_stack_dfx_data *dfx, struct protoc
         case GAZELLE_STAT_LTRAN_STOP_LATENCY:
             set_latency_start_flag(false);
             break;
+        case GAZELLE_STAT_LSTACK_SHOW_PROTOCOL:
+            get_stack_dfx_data_proto(dfx, stack, msg);
+            break;
         default:
             break;
     }
@@ -298,16 +332,17 @@ int handle_dpdk_cmd(int fd, enum GAZELLE_STAT_MODE stat_mode)
     return 0;
 }
 
-int handle_stack_cmd(int fd, enum GAZELLE_STAT_MODE stat_mode)
+int handle_stack_cmd(int fd, struct gazelle_stat_msg_request *msg)
 {
     struct gazelle_stack_dfx_data dfx;
     struct protocol_stack_group *stack_group = get_protocol_stack_group();
+    enum GAZELLE_STAT_MODE stat_mode = msg->stat_mode;
 
     for (uint32_t i = 0; i < stack_group->stack_num; i++) {
         struct protocol_stack *stack = stack_group->stacks[i];
 
         memset_s(&dfx, sizeof(dfx), 0, sizeof(dfx));
-        get_stack_dfx_data(&dfx, stack, stat_mode);
+        get_stack_dfx_data(&dfx, stack, msg);
 
         if (!use_ltran() &&
             (stat_mode == GAZELLE_STAT_LTRAN_START_LATENCY || stat_mode == GAZELLE_STAT_LTRAN_STOP_LATENCY)) {
diff --git a/src/lstack/include/lstack_stack_stat.h b/src/lstack/include/lstack_stack_stat.h
index 87951aa..867f35b 100644
--- a/src/lstack/include/lstack_stack_stat.h
+++ b/src/lstack/include/lstack_stack_stat.handle
@@ -21,13 +21,14 @@ struct wakeup_poll;
 struct protocol_stack;
 enum GAZELLE_LATENCY_TYPE;
 enum GAZELLE_STAT_MODE;
+struct gazelle_stat_msg_request;
 
 void calculate_lstack_latency(struct gazelle_stack_latency *stack_latency, const struct pbuf *pbuf,
     enum GAZELLE_LATENCY_TYPE type, uint64_t time_record);
 void calculate_rpcmsg_latency(struct gazelle_stack_latency *stack_latency, struct rpc_msg *msg,
     enum GAZELLE_LATENCY_TYPE type);
 void stack_stat_init(void);
-int handle_stack_cmd(int fd, enum GAZELLE_STAT_MODE stat_mode);
+int handle_stack_cmd(int fd, struct gazelle_stat_msg_request *msg);
 int handle_dpdk_cmd(int fd, enum GAZELLE_STAT_MODE stat_mode);
 uint64_t get_current_time(void);
 void lstack_get_low_power_info(struct gazelle_stat_low_power_info *low_power_info);
diff --git a/src/ltran/ltran_dfx.c b/src/ltran/ltran_dfx.c
index 073dfa7..717744a 100644
--- a/src/ltran/ltran_dfx.c
+++ b/src/ltran/ltran_dfx.c
@@ -136,6 +136,7 @@ static void gazelle_print_ltran_conn(void *buf, const struct gazelle_stat_msg_re
 static void gazelle_print_lstack_xstats(void *buf, const struct gazelle_stat_msg_request *req_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);
+static void gazelle_print_lstack_stat_proto(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);
@@ -168,7 +169,8 @@ 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},
-
+    {GAZELLE_STAT_LSTACK_SHOW_PROTOCOL,    sizeof(struct gazelle_stack_dfx_data),  gazelle_print_lstack_stat_proto},
+    
 #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},
@@ -1083,6 +1085,20 @@ static void gazelle_print_lstack_stat_snmp_core(const struct gazelle_stack_dfx_d
     printf("icmp_out_echo_reps: %u\n", snmp->icmp_out_echo_reps);
 }
 
+static void gazelle_print_lstack_stat_proto_core(const struct gazelle_stack_dfx_data *stat,
+                                                 const struct gazelle_stat_lstack_proto *proto)
+{
+    printf("\n------ stack tid: %6u ------\n", stat->tid);
+    printf("xmit: %u\n",     proto->xmit);
+    printf("recv: %u\n",    proto->recv);
+    printf("fw: %u\n", proto->fw);
+    printf("drop: %u\n",    proto->drop);
+    printf("chkerr: %u\n",    proto->chkerr);
+    printf("lenerr: %u\n",       proto->lenerr);
+    printf("memerr: %u\n",   proto->memerr);
+    printf("rterr: %u\n",       proto->rterr);
+}
+
 static void gazelle_print_lstack_stat_snmp(void *buf, const struct gazelle_stat_msg_request *req_msg)
 {
     int32_t ret;
@@ -1102,6 +1118,26 @@ static void gazelle_print_lstack_stat_snmp(void *buf, const struct gazelle_stat_
     } while (true);
 }
 
+static void gazelle_print_lstack_stat_proto(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_stat_lstack_proto *proto = NULL;
+
+    proto = &stat->data.proto_data;
+    printf("Statistics of lstack proto:\n");
+    do {
+        gazelle_print_lstack_stat_proto_core(stat, proto);
+        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_keepalive_string(char* str, int buff_len, struct gazelle_stat_lstack_conn_info *conn_info)
 {
     if (conn_info->keepalive == 0) {
@@ -1240,6 +1276,7 @@ static void show_usage(void)
            "  loglevel        {error | info | debug}  set lstack loglevel \n"
            "  lowpower        {0 | 1}  set lowpower enable \n"
            "  [time]          measure latency time default 1S, maximum 30mins \n\n"
+           "  -p, protocol    {UDP | TCP | ICMP | IP | ETHARP | IP_FRAG} show lstack protocol statistics \n"
 #ifdef GAZELLE_FAULT_INJECT_ENABLE
            "                                     *inject params*\n"
            " |inject_type    |     digit_param_1      |      digit_param_2     |     inject_rule   |\n"
@@ -1444,6 +1481,25 @@ static int parse_delay_arg(int32_t argc, char *argv[], long int delay)
     return 0;
 }
 
+static int32_t parse_dfx_lstack_show_proto_args(int32_t argc, char *argv[], struct gazelle_stat_msg_request *req_msg)
+{
+    int32_t cmd_index = 0;
+    int32_t ret;
+
+    char *param = argv[GAZELLE_OPTIONS2_ARG_IDX];
+    if (strcmp(param, "UDP") != 0 && strcmp(param, "TCP") != 0 && strcmp(param, "IP") &&
+        strcmp(param, "ICMP") && strcmp(param, "ETHARP") != 0) {
+        return cmd_index;
+    }
+    ret = strncpy_s(req_msg[cmd_index].data.protocol, MAX_PROTOCOL_LENGTH, argv[GAZELLE_OPTIONS2_ARG_IDX],
+        MAX_PROTOCOL_LENGTH - 1);
+    if (ret != EOK) {
+        return -1;
+    }
+    req_msg[cmd_index++].stat_mode = GAZELLE_STAT_LSTACK_SHOW_PROTOCOL;
+    return cmd_index;
+}
+
 static int32_t parse_dfx_lstack_show_args(int32_t argc, char *argv[], struct gazelle_stat_msg_request *req_msg)
 {
     int32_t cmd_index = 0;
@@ -1490,8 +1546,9 @@ static int32_t parse_dfx_lstack_show_args(int32_t argc, char *argv[], struct gaz
         }
     } else if (strcmp(param, "-k") == 0 || strcmp(param, "nic-features") == 0) {
         req_msg[cmd_index++].stat_mode = GAZELLE_STAT_LSTACK_SHOW_NIC_FEATURES;
+    } else if (strcmp(param, "protocol") == 0 || strcmp(param, "-p") == 0) {
+	    cmd_index = parse_dfx_lstack_show_proto_args(argc, argv, req_msg);
     }
-
     return cmd_index;
 }
 
diff --git a/src/ltran/ltran_monitor.c b/src/ltran/ltran_monitor.c
index ea31e84..457e8c8 100644
--- a/src/ltran/ltran_monitor.c
+++ b/src/ltran/ltran_monitor.c
@@ -347,6 +347,7 @@ static int32_t lstack_req_mode_process(int32_t fd, const struct gazelle_stat_msg
         case GAZELLE_STAT_LSTACK_SHOW_CONN:
         case GAZELLE_STAT_LSTACK_SHOW_LATENCY:
         case GAZELLE_STAT_LSTACK_LOW_POWER_MDF:
+        case GAZELLE_STAT_LSTACK_SHOW_PROTOCOL:
             handle_resp_lstack_transfer(req_msg, fd);
             break;
         default:
-- 
2.33.0

