This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
stellar-stellar/src/core/stellar_stat.cpp

575 lines
20 KiB
C++
Raw Normal View History

2024-06-25 14:08:33 +08:00
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
2024-08-16 19:28:32 +08:00
#include <assert.h>
2024-06-25 14:08:33 +08:00
#include "log.h"
#include "stellar_stat.h"
#include "fieldstat/fieldstat_easy.h"
#include "fieldstat/fieldstat_exporter.h"
#define STAT_LOG_ERROR(format, ...) LOG_ERROR("stat", format, ##__VA_ARGS__)
#define IS_FREE 0
#define IS_BUSY 0xf
2024-08-16 19:28:32 +08:00
enum METRIC_TYPE
{
// device packet
METRIC_TYPE_PKTS_RX,
METRIC_TYPE_BYTES_RX,
METRIC_TYPE_PKTS_TX,
METRIC_TYPE_BYTES_TX,
// keep-alive packet
METRIC_TYPE_KEEP_ALIVE_PKTS,
METRIC_TYPE_KEEP_ALIVE_BYTES,
// raw packet
METRIC_TYPE_RAW_PKTS_RX,
METRIC_TYPE_RAW_BYTES_RX,
METRIC_TYPE_RAW_PKTS_TX,
METRIC_TYPE_RAW_BYTES_TX,
// drop packet
METRIC_TYPE_PKTS_DROPPED,
METRIC_TYPE_BYTES_DROPPED,
// inject packet
METRIC_TYPE_PKTS_INJECTED,
METRIC_TYPE_BYTES_INJECTED,
// ctrl packet
METRIC_TYPE_CTRL_PKTS_RX,
METRIC_TYPE_CTRL_BYTES_RX,
METRIC_TYPE_CTRL_PKTS_TX,
METRIC_TYPE_CTRL_BYTES_TX,
// ipv4 reassembly
METRIC_TYPE_IP4_FLOW_FIND,
METRIC_TYPE_IP4_FLOW_ADD,
METRIC_TYPE_IP4_FLOW_DEL,
METRIC_TYPE_IP4_FLOW_TIMEOUT,
METRIC_TYPE_IP4_FLOW_FAIL_NO_SPACE,
METRIC_TYPE_IP4_FLOW_FAIL_OVERLAP,
METRIC_TYPE_IP4_FLOW_FAIL_MANY_FRAG,
METRIC_TYPE_IP4_FLOW_FAIL_INVALID_LENGTH,
METRIC_TYPE_IP4_FLOW_BYPASS_DUP_FIST_FRAG,
METRIC_TYPE_IP4_FLOW_BYPASS_DUP_LAST_FRAG,
// ipv6 reassembly
METRIC_TYPE_IP6_FLOW_FIND,
METRIC_TYPE_IP6_FLOW_ADD,
METRIC_TYPE_IP6_FLOW_DEL,
METRIC_TYPE_IP6_FLOW_TIMEOUT,
METRIC_TYPE_IP6_FLOW_FAIL_NO_SPACE,
METRIC_TYPE_IP6_FLOW_FAIL_OVERLAP,
METRIC_TYPE_IP6_FLOW_FAIL_MANY_FRAG,
METRIC_TYPE_IP6_FLOW_FAIL_INVALID_LENGTH,
METRIC_TYPE_IP6_FLOW_BYPASS_DUP_FIST_FRAG,
METRIC_TYPE_IP6_FLOW_BYPASS_DUP_LAST_FRAG,
// TCP session
METRIC_TYPE_HISTORY_TCP_SESSIONS,
METRIC_TYPE_TCP_SESS_USED,
METRIC_TYPE_TCP_SESS_OPENING,
METRIC_TYPE_TCP_SESS_ACTIVE,
METRIC_TYPE_TCP_SESS_CLOSING,
METRIC_TYPE_TCP_SESS_DISCARD,
METRIC_TYPE_TCP_SESS_CLOSED,
// UDP session
METRIC_TYPE_HISTORY_UDP_SESSIONS,
METRIC_TYPE_UDP_SESS_USED,
METRIC_TYPE_UDP_SESS_OPENING,
METRIC_TYPE_UDP_SESS_ACTIVE,
METRIC_TYPE_UDP_SESS_CLOSING,
METRIC_TYPE_UDP_SESS_DISCARD,
METRIC_TYPE_UDP_SESS_CLOSED,
// Evicted session
METRIC_TYPE_TCP_SESS_EVICTED,
METRIC_TYPE_UDP_SESS_EVICTED,
// Packet
METRIC_TYPE_UDP_PKTS_BYPASS_TABLE_FULL,
METRIC_TYPE_TCP_PKTS_BYPASS_TABLE_FULL,
METRIC_TYPE_TCP_PKTS_BYPASS_SESSION_NOT_FOUND,
METRIC_TYPE_TCP_PKTS_BYPASS_DUPLICATED,
METRIC_TYPE_UDP_PKTS_BYPASS_DUPLICATED,
METRIC_TYPE_UDP_PKTS_BYPASS_SESSION_EVICTED,
// TCP segments
METRIC_TYPE_TCP_SEGS_INPUT,
METRIC_TYPE_TCP_SEGS_TIMEOUT,
METRIC_TYPE_TCP_SEGS_RETRANSMITED,
METRIC_TYPE_TCP_SEGS_OVERLAPPED,
METRIC_TYPE_TCP_SEGS_OMITTED_TOO_MANY,
METRIC_TYPE_TCP_SEGS_INORDER,
METRIC_TYPE_TCP_SEGS_REORDERED,
METRIC_TYPE_TCP_SEGS_BUFFERED,
METRIC_TYPE_TCP_SEGS_FREED,
// end
METRIC_TYPE_MAX,
};
const char *name[] = {
// device packet
"pkts_rx",
"bytes_rx",
"pkts_tx",
"bytes_tx",
// keep-alive packet
"keep_alive_pkts",
"keep_alive_bytes",
// raw packet
"raw_pkts_rx",
"raw_bytes_rx",
"raw_pkts_tx",
"raw_bytes_tx",
// drop packet
"pkts_dropped",
"bytes_dropped",
// inject packet
"pkts_injected",
"bytes_injected",
// ctrl packet
"ctrl_pkts_rx",
"ctrl_bytes_rx",
"ctrl_pkts_tx",
"ctrl_bytes_tx",
// ipv4 reassembly
// TODO rename
"ip4_flow_find",
"ip4_flow_add",
"ip4_flow_del",
"ip4_flow_timeout",
"ip4_flow_fail_no_space",
"ip4_flow_fail_overlap",
"ip4_flow_fail_many_frag",
"ip4_flow_fail_invalid_length",
"ip4_flow_bypass_dup_fist_frag",
"ip4_flow_bypass_dup_last_frag",
// ipv6 reassembly
// TODO rename
"ip6_flow_find",
"ip6_flow_add",
"ip6_flow_del",
"ip6_flow_timeout",
"ip6_flow_fail_no_space",
"ip6_flow_fail_overlap",
"ip6_flow_fail_many_frag",
"ip6_flow_fail_invalid_length",
"ip6_flow_bypass_dup_fist_frag",
"ip6_flow_bypass_dup_last_frag",
// TCP session
"history_tcp_sessions",
"tcp_sess_used",
"tcp_sess_opening",
"tcp_sess_active",
"tcp_sess_closing",
"tcp_sess_discard",
"tcp_sess_closed",
// UDP session
"history_udp_sessions",
"udp_sess_used",
"udp_sess_opening",
"udp_sess_active",
"udp_sess_closing",
"udp_sess_discard",
"udp_sess_closed",
// Evicted session
"tcp_sess_evicted",
"udp_sess_evicted",
// Packet
"udp_pkts_bypass_table_full",
"tcp_pkts_bypass_table_full",
"tcp_pkts_bypass_session_not_found",
"tcp_pkts_bypass_duplicated",
"udp_pkts_bypass_duplicated",
"udp_pkts_bypass_session_evicted",
// TCP segments
"tcp_segs_input",
"tcp_segs_timeout",
"tcp_segs_retransmited",
"tcp_segs_overlapped",
"tcp_segs_omitted_too_many",
"tcp_segs_inorder",
"tcp_segs_reordered",
"tcp_segs_buffered",
"tcp_segs_freed",
};
2024-06-25 14:08:33 +08:00
2024-08-16 17:44:23 +08:00
/*
* This naming convention maintains consistency by using a clear, structured pattern:
* tcp_sessions_ or ipv6_frags_ as the prefix to indicate the type of data.
* Action or status (e.g., bypassed, active, dropped) as the middle part.
* Cause or condition (e.g., full_table, buffer_limit) as the suffix for additional clarity.
*/
2024-06-25 14:08:33 +08:00
struct stellar_stat
{
uint16_t nr_thread;
char output_file[2048];
struct fieldstat_easy *fs;
int flag[MAX_THREAD_NUM]; // IS_FREE or IS_BUSY
struct thread_stat thr_stat[MAX_THREAD_NUM];
2024-08-16 19:28:32 +08:00
uint64_t metric_key[METRIC_TYPE_MAX];
uint64_t metric_val[METRIC_TYPE_MAX];
2024-06-25 14:08:33 +08:00
};
// python3 -m pip install prettytable
// python3 -m pip install jinja2
// /opt/MESA/bin/fieldstat_exporter.py local -j log/stellar_fs4.json -e -l --clear-screen
struct stellar_stat *stellar_stat_new(uint16_t nr_thread)
{
char cwd[1024] = {0};
struct stellar_stat *stat = (struct stellar_stat *)calloc(1, sizeof(struct stellar_stat));
if (stat == NULL)
{
return NULL;
}
if (getcwd(cwd, sizeof(cwd)) == NULL)
{
STAT_LOG_ERROR("failed to get current working directory: %s", strerror(errno));
goto error_out;
}
snprintf(stat->output_file, sizeof(stat->output_file), "%s/log/stellar_fs4.json", cwd);
stat->fs = fieldstat_easy_new(1, "stellar", NULL, 0);
if (stat->fs == NULL)
{
STAT_LOG_ERROR("failed to create fieldstat_easy");
goto error_out;
}
stat->nr_thread = nr_thread;
for (int i = 0; i < MAX_THREAD_NUM; i++)
{
stat->flag[i] = IS_FREE;
}
2024-08-16 19:28:32 +08:00
for (size_t i = 0; i < METRIC_TYPE_MAX; i++)
2024-06-25 14:08:33 +08:00
{
2024-08-16 19:28:32 +08:00
stat->metric_key[i] = fieldstat_easy_register_counter(stat->fs, name[i]);
2024-06-25 14:08:33 +08:00
}
return stat;
error_out:
stellar_stat_free(stat);
return NULL;
}
void stellar_stat_free(struct stellar_stat *stat)
{
if (stat)
{
if (stat->fs)
{
fieldstat_easy_free(stat->fs);
stat->fs = NULL;
}
free(stat);
stat = NULL;
}
}
void stellar_stat_output(struct stellar_stat *stat)
{
for (uint16_t i = 0; i < stat->nr_thread; i++)
{
if (ATOMIC_READ(&(stat->flag[i])) == IS_BUSY)
{
struct thread_stat *thr_stat = &stat->thr_stat[i];
2024-08-16 19:28:32 +08:00
for (size_t j = 0; j < METRIC_TYPE_MAX; j++)
2024-06-25 14:08:33 +08:00
{
2024-08-16 19:28:32 +08:00
switch (j)
{
// device packet
case METRIC_TYPE_PKTS_RX:
stat->metric_val[j] += thr_stat->packet_io->pkts_rx;
break;
case METRIC_TYPE_BYTES_RX:
stat->metric_val[j] += thr_stat->packet_io->bytes_rx;
break;
case METRIC_TYPE_PKTS_TX:
stat->metric_val[j] += thr_stat->packet_io->pkts_tx;
break;
case METRIC_TYPE_BYTES_TX:
stat->metric_val[j] += thr_stat->packet_io->bytes_tx;
break;
// keep-alive packet
case METRIC_TYPE_KEEP_ALIVE_PKTS:
stat->metric_val[j] += thr_stat->packet_io->keep_alive_pkts;
break;
case METRIC_TYPE_KEEP_ALIVE_BYTES:
stat->metric_val[j] += thr_stat->packet_io->keep_alive_bytes;
break;
// raw packet
case METRIC_TYPE_RAW_PKTS_RX:
stat->metric_val[j] += thr_stat->packet_io->raw_pkts_rx;
break;
case METRIC_TYPE_RAW_BYTES_RX:
stat->metric_val[j] += thr_stat->packet_io->raw_bytes_rx;
break;
case METRIC_TYPE_RAW_PKTS_TX:
stat->metric_val[j] += thr_stat->packet_io->raw_pkts_tx;
break;
case METRIC_TYPE_RAW_BYTES_TX:
stat->metric_val[j] += thr_stat->packet_io->raw_bytes_tx;
break;
// drop packet
case METRIC_TYPE_PKTS_DROPPED:
stat->metric_val[j] += thr_stat->packet_io->pkts_dropped;
break;
case METRIC_TYPE_BYTES_DROPPED:
stat->metric_val[j] += thr_stat->packet_io->bytes_dropped;
break;
// inject packet
case METRIC_TYPE_PKTS_INJECTED:
stat->metric_val[j] += thr_stat->packet_io->pkts_injected;
break;
case METRIC_TYPE_BYTES_INJECTED:
stat->metric_val[j] += thr_stat->packet_io->bytes_injected;
break;
// ctrl packet
case METRIC_TYPE_CTRL_PKTS_RX:
stat->metric_val[j] += thr_stat->packet_io->ctrl_pkts_rx;
break;
case METRIC_TYPE_CTRL_BYTES_RX:
stat->metric_val[j] += thr_stat->packet_io->ctrl_bytes_rx;
break;
case METRIC_TYPE_CTRL_PKTS_TX:
stat->metric_val[j] += thr_stat->packet_io->ctrl_pkts_tx;
break;
case METRIC_TYPE_CTRL_BYTES_TX:
stat->metric_val[j] += thr_stat->packet_io->ctrl_bytes_tx;
break;
// ipv4 reassembly
case METRIC_TYPE_IP4_FLOW_FIND:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_find;
break;
case METRIC_TYPE_IP4_FLOW_ADD:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_add;
break;
case METRIC_TYPE_IP4_FLOW_DEL:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_del;
break;
case METRIC_TYPE_IP4_FLOW_TIMEOUT:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_timeout;
break;
case METRIC_TYPE_IP4_FLOW_FAIL_NO_SPACE:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_fail_no_space;
break;
case METRIC_TYPE_IP4_FLOW_FAIL_OVERLAP:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_fail_overlap;
break;
case METRIC_TYPE_IP4_FLOW_FAIL_MANY_FRAG:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_fail_many_frag;
break;
case METRIC_TYPE_IP4_FLOW_FAIL_INVALID_LENGTH:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_fail_invalid_length;
break;
case METRIC_TYPE_IP4_FLOW_BYPASS_DUP_FIST_FRAG:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_bypass_dup_fist_frag;
break;
case METRIC_TYPE_IP4_FLOW_BYPASS_DUP_LAST_FRAG:
stat->metric_val[j] += thr_stat->ip_reassembly->ip4_flow_bypass_dup_last_frag;
break;
// ipv6 reassembly
case METRIC_TYPE_IP6_FLOW_FIND:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_find;
break;
case METRIC_TYPE_IP6_FLOW_ADD:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_add;
break;
case METRIC_TYPE_IP6_FLOW_DEL:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_del;
break;
case METRIC_TYPE_IP6_FLOW_TIMEOUT:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_timeout;
break;
case METRIC_TYPE_IP6_FLOW_FAIL_NO_SPACE:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_fail_no_space;
break;
case METRIC_TYPE_IP6_FLOW_FAIL_OVERLAP:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_fail_overlap;
break;
case METRIC_TYPE_IP6_FLOW_FAIL_MANY_FRAG:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_fail_many_frag;
break;
case METRIC_TYPE_IP6_FLOW_FAIL_INVALID_LENGTH:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_fail_invalid_length;
break;
case METRIC_TYPE_IP6_FLOW_BYPASS_DUP_FIST_FRAG:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_bypass_dup_fist_frag;
break;
case METRIC_TYPE_IP6_FLOW_BYPASS_DUP_LAST_FRAG:
stat->metric_val[j] += thr_stat->ip_reassembly->ip6_flow_bypass_dup_last_frag;
break;
// TCP session
case METRIC_TYPE_HISTORY_TCP_SESSIONS:
stat->metric_val[j] += thr_stat->session_mgr->history_tcp_sessions;
break;
case METRIC_TYPE_TCP_SESS_USED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_sess_used;
break;
case METRIC_TYPE_TCP_SESS_OPENING:
stat->metric_val[j] += thr_stat->session_mgr->tcp_sess_opening;
break;
case METRIC_TYPE_TCP_SESS_ACTIVE:
stat->metric_val[j] += thr_stat->session_mgr->tcp_sess_active;
break;
case METRIC_TYPE_TCP_SESS_CLOSING:
stat->metric_val[j] += thr_stat->session_mgr->tcp_sess_closing;
break;
case METRIC_TYPE_TCP_SESS_DISCARD:
stat->metric_val[j] += thr_stat->session_mgr->tcp_sess_discard;
break;
case METRIC_TYPE_TCP_SESS_CLOSED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_sess_closed;
break;
// UDP session
case METRIC_TYPE_HISTORY_UDP_SESSIONS:
stat->metric_val[j] += thr_stat->session_mgr->history_udp_sessions;
break;
case METRIC_TYPE_UDP_SESS_USED:
stat->metric_val[j] += thr_stat->session_mgr->udp_sess_used;
break;
case METRIC_TYPE_UDP_SESS_OPENING:
stat->metric_val[j] += thr_stat->session_mgr->udp_sess_opening;
break;
case METRIC_TYPE_UDP_SESS_ACTIVE:
stat->metric_val[j] += thr_stat->session_mgr->udp_sess_active;
break;
case METRIC_TYPE_UDP_SESS_CLOSING:
stat->metric_val[j] += thr_stat->session_mgr->udp_sess_closing;
break;
case METRIC_TYPE_UDP_SESS_DISCARD:
stat->metric_val[j] += thr_stat->session_mgr->udp_sess_discard;
break;
case METRIC_TYPE_UDP_SESS_CLOSED:
stat->metric_val[j] += thr_stat->session_mgr->udp_sess_closed;
break;
// Evicted session
case METRIC_TYPE_TCP_SESS_EVICTED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_sess_evicted;
break;
case METRIC_TYPE_UDP_SESS_EVICTED:
stat->metric_val[j] += thr_stat->session_mgr->udp_sess_evicted;
break;
// Packet
case METRIC_TYPE_UDP_PKTS_BYPASS_TABLE_FULL:
stat->metric_val[j] += thr_stat->session_mgr->udp_pkts_bypass_table_full;
break;
case METRIC_TYPE_TCP_PKTS_BYPASS_TABLE_FULL:
stat->metric_val[j] += thr_stat->session_mgr->tcp_pkts_bypass_table_full;
break;
case METRIC_TYPE_TCP_PKTS_BYPASS_SESSION_NOT_FOUND:
stat->metric_val[j] += thr_stat->session_mgr->tcp_pkts_bypass_session_not_found;
break;
case METRIC_TYPE_TCP_PKTS_BYPASS_DUPLICATED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_pkts_bypass_duplicated;
break;
case METRIC_TYPE_UDP_PKTS_BYPASS_DUPLICATED:
stat->metric_val[j] += thr_stat->session_mgr->udp_pkts_bypass_duplicated;
break;
case METRIC_TYPE_UDP_PKTS_BYPASS_SESSION_EVICTED:
stat->metric_val[j] += thr_stat->session_mgr->udp_pkts_bypass_session_evicted;
break;
// TCP segments
case METRIC_TYPE_TCP_SEGS_INPUT:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_input;
break;
case METRIC_TYPE_TCP_SEGS_TIMEOUT:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_timeout;
break;
case METRIC_TYPE_TCP_SEGS_RETRANSMITED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_retransmited;
break;
case METRIC_TYPE_TCP_SEGS_OVERLAPPED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_overlapped;
break;
case METRIC_TYPE_TCP_SEGS_OMITTED_TOO_MANY:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_omitted_too_many;
break;
case METRIC_TYPE_TCP_SEGS_INORDER:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_inorder;
break;
case METRIC_TYPE_TCP_SEGS_REORDERED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_reordered;
break;
case METRIC_TYPE_TCP_SEGS_BUFFERED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_buffered;
break;
case METRIC_TYPE_TCP_SEGS_FREED:
stat->metric_val[j] += thr_stat->session_mgr->tcp_segs_freed;
break;
default:
assert(0);
break;
}
2024-06-25 14:08:33 +08:00
}
memset(thr_stat, 0, sizeof(struct thread_stat));
ATOMIC_SET(&(stat->flag[i]), IS_FREE);
}
}
2024-08-16 19:28:32 +08:00
for (size_t j = 0; j < METRIC_TYPE_MAX; j++)
2024-06-25 14:08:33 +08:00
{
2024-08-16 19:28:32 +08:00
fieldstat_easy_counter_set(stat->fs, 0, stat->metric_key[j], NULL, 0, stat->metric_val[j]);
2024-06-25 14:08:33 +08:00
}
char *buff;
size_t len;
fieldstat_easy_output(stat->fs, &buff, &len);
if (buff)
{
FILE *fp = fopen(stat->output_file, "w+");
if (fp == NULL)
{
STAT_LOG_ERROR("failed to open file: %s, %s", stat->output_file, strerror(errno));
}
else
{
fwrite(buff, len, 1, fp);
fflush(fp);
fclose(fp);
}
free(buff);
}
2024-08-16 19:28:32 +08:00
for (size_t j = 0; j < METRIC_TYPE_MAX; j++)
2024-06-25 14:08:33 +08:00
{
2024-08-16 19:28:32 +08:00
stat->metric_val[j] = 0;
2024-06-25 14:08:33 +08:00
}
}
void stellar_stat_merge(struct stellar_stat *stat, const struct thread_stat *thr_stat, uint16_t thr_idx)
{
if (ATOMIC_READ(&(stat->flag[thr_idx])) == IS_FREE)
{
memcpy(&stat->thr_stat[thr_idx], thr_stat, sizeof(struct thread_stat));
ATOMIC_SET(&(stat->flag[thr_idx]), IS_BUSY);
}
}