#include #include #include #include #include #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 typedef uint64_t get_val_func(struct thread_stat *thr_stat); static inline uint64_t get_dev_rx_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->dev_rx_pkts; } static inline uint64_t get_dev_rx_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->dev_rx_bytes; } static inline uint64_t get_dev_tx_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->dev_tx_pkts; } static inline uint64_t get_dev_tx_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->dev_tx_bytes; } static inline uint64_t get_keep_alive_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->keep_alive_pkts; } static inline uint64_t get_keep_alive_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->keep_alive_bytes; } static inline uint64_t get_raw_rx_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->raw_rx_pkts; } static inline uint64_t get_raw_rx_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->raw_rx_bytes; } static inline uint64_t get_raw_tx_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->raw_tx_pkts; } static inline uint64_t get_raw_tx_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->raw_tx_bytes; } static inline uint64_t get_drop_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->drop_pkts; } static inline uint64_t get_drop_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->drop_bytes; } static inline uint64_t get_inject_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->inject_pkts; } static inline uint64_t get_inject_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->inject_bytes; } static inline uint64_t get_ctrl_rx_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->ctrl_rx_pkts; } static inline uint64_t get_ctrl_rx_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->ctrl_rx_bytes; } static inline uint64_t get_ctrl_tx_pkts(struct thread_stat *thr_stat) { return thr_stat->packet_io->ctrl_tx_pkts; } static inline uint64_t get_ctrl_tx_bytes(struct thread_stat *thr_stat) { return thr_stat->packet_io->ctrl_tx_bytes; } static inline uint64_t get_ip4_flow_find(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_find; } static inline uint64_t get_ip4_flow_add(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_add; } static inline uint64_t get_ip4_flow_del(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_del; } static inline uint64_t get_ip4_flow_timeout(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_timeout; } static inline uint64_t get_ip4_flow_fail_no_space(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_fail_no_space; } static inline uint64_t get_ip4_flow_fail_overlap(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_fail_overlap; } static inline uint64_t get_ip4_flow_fail_many_frag(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_fail_many_frag; } static inline uint64_t get_ip4_flow_fail_invalid_length(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_fail_invalid_length; } static inline uint64_t get_ip4_flow_bypass_dup_fist_frag(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_bypass_dup_fist_frag; } static inline uint64_t get_ip4_flow_bypass_dup_last_frag(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip4_flow_bypass_dup_last_frag; } static inline uint64_t get_ip6_flow_find(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_find; } static inline uint64_t get_ip6_flow_add(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_add; } static inline uint64_t get_ip6_flow_del(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_del; } static inline uint64_t get_ip6_flow_timeout(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_timeout; } static inline uint64_t get_ip6_flow_fail_no_space(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_fail_no_space; } static inline uint64_t get_ip6_flow_fail_overlap(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_fail_overlap; } static inline uint64_t get_ip6_flow_fail_many_frag(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_fail_many_frag; } static inline uint64_t get_ip6_flow_fail_invalid_length(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_fail_invalid_length; } static inline uint64_t get_ip6_flow_bypass_dup_fist_frag(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_bypass_dup_fist_frag; } static inline uint64_t get_ip6_flow_bypass_dup_last_frag(struct thread_stat *thr_stat) { return thr_stat->ip_reassembly->ip6_flow_bypass_dup_last_frag; } static inline uint64_t get_total_nr_tcp_sess_used(struct thread_stat *thr_stat) { return thr_stat->session_mgr->total_nr_tcp_sess_used; } static inline uint64_t get_curr_nr_tcp_sess_used(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_tcp_sess_used; } static inline uint64_t get_curr_nr_tcp_sess_opening(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_tcp_sess_opening; } static inline uint64_t get_curr_nr_tcp_sess_active(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_tcp_sess_active; } static inline uint64_t get_curr_nr_tcp_sess_closing(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_tcp_sess_closing; } static inline uint64_t get_curr_nr_tcp_sess_discard(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_tcp_sess_discard; } static inline uint64_t get_curr_nr_tcp_sess_closed(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_tcp_sess_closed; } static inline uint64_t get_total_nr_udp_sess_used(struct thread_stat *thr_stat) { return thr_stat->session_mgr->total_nr_udp_sess_used; } static inline uint64_t get_curr_nr_udp_sess_used(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_udp_sess_used; } static inline uint64_t get_curr_nr_udp_sess_opening(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_udp_sess_opening; } static inline uint64_t get_curr_nr_udp_sess_active(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_udp_sess_active; } static inline uint64_t get_curr_nr_udp_sess_closing(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_udp_sess_closing; } static inline uint64_t get_curr_nr_udp_sess_discard(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_udp_sess_discard; } static inline uint64_t get_curr_nr_udp_sess_closed(struct thread_stat *thr_stat) { return thr_stat->session_mgr->curr_nr_udp_sess_closed; } static inline uint64_t get_nr_tcp_sess_evicted(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_sess_evicted; } static inline uint64_t get_nr_udp_sess_evicted(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_udp_sess_evicted; } static inline uint64_t get_nr_udp_pkts_nospace_bypass(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_udp_pkts_nospace_bypass; } static inline uint64_t get_nr_tcp_pkts_nospace_bypass(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_pkts_nospace_bypass; } static inline uint64_t get_nr_tcp_pkts_nosess_bypass(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_pkts_nosess_bypass; } static inline uint64_t get_nr_tcp_pkts_duped_bypass(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_pkts_duped_bypass; } static inline uint64_t get_nr_udp_pkts_duped_bypass(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_udp_pkts_duped_bypass; } static inline uint64_t get_nr_udp_pkts_evctd_bypass(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_udp_pkts_evctd_bypass; } static inline uint64_t get_nr_tcp_seg_received(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_received; } static inline uint64_t get_nr_tcp_seg_expired(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_expired; } static inline uint64_t get_nr_tcp_seg_retransmit(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_retransmit; } static inline uint64_t get_nr_tcp_seg_overlap(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_overlap; } static inline uint64_t get_nr_tcp_seg_no_space(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_no_space; } static inline uint64_t get_nr_tcp_seg_inorder(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_inorder; } static inline uint64_t get_nr_tcp_seg_reorded(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_reorded; } static inline uint64_t get_nr_tcp_seg_buffered(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_buffered; } static inline uint64_t get_nr_tcp_seg_released(struct thread_stat *thr_stat) { return thr_stat->session_mgr->nr_tcp_seg_released; } struct metric_schema { const char *name; get_val_func *get_val; } schemas[] = { // device packet {"dev_rx_pkts", get_dev_rx_pkts}, {"dev_rx_bytes", get_dev_rx_bytes}, {"dev_tx_pkts", get_dev_tx_pkts}, {"dev_tx_bytes", get_dev_tx_bytes}, // keep-alive packet {"keep_alive_pkts", get_keep_alive_pkts}, {"keep_alive_bytes", get_keep_alive_bytes}, // raw packet {"raw_rx_pkts", get_raw_rx_pkts}, {"raw_rx_bytes", get_raw_rx_bytes}, {"raw_tx_pkts", get_raw_tx_pkts}, {"raw_tx_bytes", get_raw_tx_bytes}, // drop packet {"drop_pkts", get_drop_pkts}, {"drop_bytes", get_drop_bytes}, // inject packet {"inject_pkts", get_inject_pkts}, {"inject_bytes", get_inject_bytes}, // ctrl packet {"ctrl_rx_pkts", get_ctrl_rx_pkts}, {"ctrl_rx_bytes", get_ctrl_rx_bytes}, {"ctrl_tx_pkts", get_ctrl_tx_pkts}, {"ctrl_tx_bytes", get_ctrl_tx_bytes}, // ipv4 reassembly {"ip4_flow_find", get_ip4_flow_find}, {"ip4_flow_add", get_ip4_flow_add}, {"ip4_flow_del", get_ip4_flow_del}, {"ip4_flow_timeout", get_ip4_flow_timeout}, {"ip4_flow_fail_no_space", get_ip4_flow_fail_no_space}, {"ip4_flow_fail_overlap", get_ip4_flow_fail_overlap}, {"ip4_flow_fail_many_frag", get_ip4_flow_fail_many_frag}, {"ip4_flow_fail_invalid_length", get_ip4_flow_fail_invalid_length}, {"ip4_flow_bypass_dup_fist_frag", get_ip4_flow_bypass_dup_fist_frag}, {"ip4_flow_bypass_dup_last_frag", get_ip4_flow_bypass_dup_last_frag}, // ipv6 reassembly {"ip6_flow_find", get_ip6_flow_find}, {"ip6_flow_add", get_ip6_flow_add}, {"ip6_flow_del", get_ip6_flow_del}, {"ip6_flow_timeout", get_ip6_flow_timeout}, {"ip6_flow_fail_no_space", get_ip6_flow_fail_no_space}, {"ip6_flow_fail_overlap", get_ip6_flow_fail_overlap}, {"ip6_flow_fail_many_frag", get_ip6_flow_fail_many_frag}, {"ip6_flow_fail_invalid_length", get_ip6_flow_fail_invalid_length}, {"ip6_flow_bypass_dup_fist_frag", get_ip6_flow_bypass_dup_fist_frag}, {"ip6_flow_bypass_dup_last_frag", get_ip6_flow_bypass_dup_last_frag}, // TCP session {"total_nr_tcp_sess_used", get_total_nr_tcp_sess_used}, {"curr_nr_tcp_sess_used", get_curr_nr_tcp_sess_used}, {"curr_nr_tcp_sess_opening", get_curr_nr_tcp_sess_opening}, {"curr_nr_tcp_sess_active", get_curr_nr_tcp_sess_active}, {"curr_nr_tcp_sess_closing", get_curr_nr_tcp_sess_closing}, {"curr_nr_tcp_sess_discard", get_curr_nr_tcp_sess_discard}, {"curr_nr_tcp_sess_closed", get_curr_nr_tcp_sess_closed}, // UDP session {"total_nr_udp_sess_used", get_total_nr_udp_sess_used}, {"curr_nr_udp_sess_used", get_curr_nr_udp_sess_used}, {"curr_nr_udp_sess_opening", get_curr_nr_udp_sess_opening}, {"curr_nr_udp_sess_active", get_curr_nr_udp_sess_active}, {"curr_nr_udp_sess_closing", get_curr_nr_udp_sess_closing}, {"curr_nr_udp_sess_discard", get_curr_nr_udp_sess_discard}, {"curr_nr_udp_sess_closed", get_curr_nr_udp_sess_closed}, // Evicted session {"nr_tcp_sess_evicted", get_nr_tcp_sess_evicted}, {"nr_udp_sess_evicted", get_nr_udp_sess_evicted}, // Packet {"nr_udp_pkts_nospace_bypass", get_nr_udp_pkts_nospace_bypass}, {"nr_tcp_pkts_nospace_bypass", get_nr_tcp_pkts_nospace_bypass}, {"nr_tcp_pkts_nosess_bypass", get_nr_tcp_pkts_nosess_bypass}, {"nr_tcp_pkts_duped_bypass", get_nr_tcp_pkts_duped_bypass}, {"nr_udp_pkts_duped_bypass", get_nr_udp_pkts_duped_bypass}, {"nr_udp_pkts_evctd_bypass", get_nr_udp_pkts_evctd_bypass}, // TCP segments {"nr_tcp_seg_received", get_nr_tcp_seg_received}, {"nr_tcp_seg_expired", get_nr_tcp_seg_expired}, {"nr_tcp_seg_retransmit", get_nr_tcp_seg_retransmit}, {"nr_tcp_seg_overlap", get_nr_tcp_seg_overlap}, {"nr_tcp_seg_no_space", get_nr_tcp_seg_no_space}, {"nr_tcp_seg_inorder", get_nr_tcp_seg_inorder}, {"nr_tcp_seg_reorded", get_nr_tcp_seg_reorded}, {"nr_tcp_seg_buffered", get_nr_tcp_seg_buffered}, {"nr_tcp_seg_released", get_nr_tcp_seg_released}, }; 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]; struct metric_map { uint64_t key; uint64_t val; } map[sizeof(schemas) / sizeof(struct metric_schema)]; }; // 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; } for (size_t i = 0; i < sizeof(schemas) / sizeof(struct metric_schema); i++) { stat->map[i].key = fieldstat_easy_register_counter(stat->fs, schemas[i].name); stat->map[i].val = 0; } 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]; for (size_t j = 0; j < sizeof(schemas) / sizeof(struct metric_schema); j++) { stat->map[j].val += schemas[j].get_val(thr_stat); } memset(thr_stat, 0, sizeof(struct thread_stat)); ATOMIC_SET(&(stat->flag[i]), IS_FREE); } } for (size_t j = 0; j < sizeof(schemas) / sizeof(struct metric_schema); j++) { fieldstat_easy_counter_set(stat->fs, 0, stat->map[j].key, NULL, 0, stat->map[j].val); } 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); } for (size_t j = 0; j < sizeof(schemas) / sizeof(struct metric_schema); j++) { stat->map[j].val = 0; } } 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); } }