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/infra/packet_io/packet_io.c
luwenpeng c2e9275a9e remove session_manager_subscribe_xxx() API; convert session closing events to pseudo packets
when a session is closed, use the packet manager to create a pseudo packet,
    set the session to be closed as packet Exdata, and schedule it to the packet forwarding stage.
    when the pseudo packet free, the session will be free.
2024-11-19 18:28:40 +08:00

363 lines
11 KiB
C

#include "pcap_io.h"
#include "mars_io.h"
#include "ip_reassembly.h"
#include "utils_internal.h"
#include "packet_internal.h"
#include "fieldstat/fieldstat_easy.h"
struct packet_io_cfg
{
char mode[64];
uint64_t thread_num; // range [1, MAX_THREAD_NUM]
// ip reassembly
uint64_t fail_action; // 0: bypass, 1: drop
uint64_t timeout_ms; // range: [1, 60000] (ms)
uint64_t frag_queue_num; // range: [1, 4294967295
uint64_t frag_queue_size; // range: [2, 65535]
};
struct packet_io
{
void *handle;
void *(*new_func)(const char *toml_file);
void (*free_func)(void *handle);
int (*done_func)(void *handle);
int (*init_func)(void *handle, uint16_t thr_idx);
int (*recv_func)(void *handle, uint16_t thr_idx, struct packet *pkts[], int nr_pkts);
void (*send_func)(void *handle, uint16_t thr_idx, struct packet *pkts[], int nr_pkts);
void (*drop_func)(void *handle, uint16_t thr_idx, struct packet *pkts[], int nr_pkts);
void (*yield_func)(void *handle, uint16_t thr_idx);
struct packet_io_stat *(*stat_func)(void *handle, uint16_t thr_idx);
struct packet_io_cfg *cfg;
struct ip_reassembly *ip_reass[MAX_THREAD_NUM];
struct fieldstat_easy *fs;
int pkt_io_fs_idx[PKT_IO_STAT_MAX];
int ip_reass_fs_idx[IP_REASS_STAT_MAX];
};
/******************************************************************************
* packet io cfg
******************************************************************************/
static void packet_io_cfg_free(struct packet_io_cfg *cfg)
{
if (cfg)
{
free(cfg);
cfg = NULL;
}
}
static struct packet_io_cfg *packet_io_cfg_new(const char *toml_file)
{
struct packet_io_cfg *cfg = (struct packet_io_cfg *)calloc(1, sizeof(struct packet_io_cfg));
if (cfg == NULL)
{
return NULL;
}
int ret = 0;
ret += load_toml_str_config(toml_file, "packet_io.mode", cfg->mode);
ret += load_toml_integer_config(toml_file, "packet_io.thread_num", &cfg->thread_num, 1, MAX_THREAD_NUM);
ret += load_toml_integer_config(toml_file, "packet_io.ip_reassembly.fail_action", &cfg->fail_action, 0, 1);
ret += load_toml_integer_config(toml_file, "packet_io.ip_reassembly.timeout_ms", &cfg->timeout_ms, 1, 60000);
ret += load_toml_integer_config(toml_file, "packet_io.ip_reassembly.frag_queue_num", &cfg->frag_queue_num, 1, 4294967295);
ret += load_toml_integer_config(toml_file, "packet_io.ip_reassembly.frag_queue_size", &cfg->frag_queue_size, 2, 65535);
if (strcmp(cfg->mode, "marsio") != 0 &&
strcmp(cfg->mode, "pcapfile") != 0 &&
strcmp(cfg->mode, "pcaplist") != 0)
{
PACKET_IO_LOG_ERROR("packet_io.mode invalid: %s", cfg->mode);
free(cfg);
return NULL;
}
if (ret != 0)
{
free(cfg);
return NULL;
}
return cfg;
}
static void packet_io_cfg_print(const struct packet_io_cfg *cfg)
{
if (cfg)
{
PACKET_IO_LOG_INFO("packet_io.mode : %s", cfg->mode);
PACKET_IO_LOG_INFO("packet_io.thread_num : %lu", cfg->thread_num);
PACKET_IO_LOG_INFO("packet_io.ip_reassembly.fail_action : %lu", cfg->fail_action);
PACKET_IO_LOG_INFO("packet_io.ip_reassembly.timeout_ms : %lu", cfg->timeout_ms);
PACKET_IO_LOG_INFO("packet_io.ip_reassembly.frag_queue_num : %lu", cfg->frag_queue_num);
PACKET_IO_LOG_INFO("packet_io.ip_reassembly.frag_queue_size : %lu", cfg->frag_queue_size);
}
}
/******************************************************************************
* packet io
******************************************************************************/
struct packet_io *packet_io_new(const char *toml_file)
{
struct packet_io *pkt_io = (struct packet_io *)calloc(1, sizeof(struct packet_io));
if (pkt_io == NULL)
{
PACKET_IO_LOG_ERROR("failed to allocate memory for packet_io");
return NULL;
}
pkt_io->cfg = packet_io_cfg_new(toml_file);
if (pkt_io->cfg == NULL)
{
PACKET_IO_LOG_ERROR("failed to create packet_io_cfg");
goto error_out;
}
packet_io_cfg_print(pkt_io->cfg);
if (strcmp(pkt_io->cfg->mode, "marsio") == 0)
{
pkt_io->new_func = mars_io_new;
pkt_io->free_func = mars_io_free;
pkt_io->done_func = mars_io_is_done;
pkt_io->init_func = mars_io_init;
pkt_io->recv_func = mars_io_recv;
pkt_io->send_func = mars_io_send;
pkt_io->drop_func = mars_io_drop;
pkt_io->yield_func = mars_io_yield;
pkt_io->stat_func = mars_io_stat;
}
else
{
pkt_io->new_func = pcap_io_new;
pkt_io->free_func = pcap_io_free;
pkt_io->done_func = pcap_io_is_done;
pkt_io->init_func = pcap_io_init;
pkt_io->recv_func = pcap_io_recv;
pkt_io->send_func = pcap_io_send;
pkt_io->drop_func = pcap_io_drop;
pkt_io->yield_func = pcap_io_yield;
pkt_io->stat_func = pcap_io_stat;
}
for (uint64_t i = 0; i < pkt_io->cfg->thread_num; i++)
{
pkt_io->ip_reass[i] = ip_reassembly_new(pkt_io->cfg->timeout_ms, pkt_io->cfg->frag_queue_num, pkt_io->cfg->frag_queue_size);
if (pkt_io->ip_reass[i] == NULL)
{
PACKET_IO_LOG_ERROR("failed to create ip_reassembly");
goto error_out;
}
}
pkt_io->fs = fieldstat_easy_new(pkt_io->cfg->thread_num, "packet_io", NULL, 0);
if (pkt_io->fs == NULL)
{
PACKET_IO_LOG_ERROR("failed to create fieldstat_easy");
goto error_out;
}
if (fieldstat_easy_enable_auto_output(pkt_io->fs, "metrics/packet_io.json", 2) != 0)
{
PACKET_IO_LOG_ERROR("failed to enable auto output for fieldstat_easy");
goto error_out;
}
for (int i = 0; i < PKT_IO_STAT_MAX; i++)
{
pkt_io->pkt_io_fs_idx[i] = fieldstat_easy_register_counter(pkt_io->fs, pkt_io_stat_str[i]);
}
for (int i = 0; i < IP_REASS_STAT_MAX; i++)
{
pkt_io->ip_reass_fs_idx[i] = fieldstat_easy_register_counter(pkt_io->fs, ip_reass_stat_str[i]);
}
pkt_io->handle = pkt_io->new_func(toml_file);
if (pkt_io->handle == NULL)
{
PACKET_IO_LOG_ERROR("failed to create packet_io handle");
goto error_out;
}
return pkt_io;
error_out:
packet_io_free(pkt_io);
return NULL;
}
void packet_io_free(struct packet_io *pkt_io)
{
if (pkt_io)
{
if (pkt_io->cfg)
{
for (uint64_t i = 0; i < pkt_io->cfg->thread_num; i++)
{
ip_reassembly_free(pkt_io->ip_reass[i]);
}
}
pkt_io->free_func(pkt_io->handle);
if (pkt_io->fs)
{
fieldstat_easy_free(pkt_io->fs);
}
packet_io_cfg_free(pkt_io->cfg);
free(pkt_io);
pkt_io = NULL;
}
}
int packet_io_is_done(struct packet_io *pkt_io)
{
return pkt_io->done_func(pkt_io->handle);
}
int packet_io_init(struct packet_io *pkt_io, uint16_t thr_idx)
{
return pkt_io->init_func(pkt_io->handle, thr_idx);
}
int packet_io_recv(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts[], int nr_pkts)
{
struct packet *pkt = NULL;
struct packet *defrag = NULL;
struct ip_reassembly *ip_reass = pkt_io->ip_reass[thr_idx];
uint64_t now_ms = clock_get_real_time_ms();
int nr_ret = 0;
int nr_recv = pkt_io->recv_func(pkt_io->handle, thr_idx, pkts, nr_pkts);
for (int i = 0; i < nr_recv; i++)
{
pkt = pkts[i];
if (packet_is_fragment(pkt))
{
defrag = ip_reassembly_defrag(ip_reass, pkt, now_ms);
if (defrag)
{
pkts[nr_ret++] = defrag;
}
}
else
{
pkts[nr_ret++] = pkt;
continue;
}
}
return nr_ret;
}
void packet_io_send(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts[], int nr_pkts)
{
struct packet *frag = NULL;
struct packet *pkt = NULL;
for (int i = 0; i < nr_pkts; i++)
{
pkt = pkts[i];
if (packet_is_defraged(pkt))
{
while ((frag = packet_pop_frag(pkt)))
{
// TODO check len vs MTU, if len > MTU, fragment it
pkt_io->send_func(pkt_io->handle, thr_idx, &frag, 1);
}
packet_free(pkt);
}
else
{
pkt_io->send_func(pkt_io->handle, thr_idx, &pkt, 1);
}
pkts[i] = NULL;
}
}
void packet_io_drop(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts[], int nr_pkts)
{
struct packet *frag = NULL;
struct packet *pkt = NULL;
for (int i = 0; i < nr_pkts; i++)
{
pkt = pkts[i];
if (packet_is_defraged(pkt))
{
while ((frag = packet_pop_frag(pkt)))
{
pkt_io->drop_func(pkt_io->handle, thr_idx, &frag, 1);
}
packet_free(pkt);
}
else
{
pkt_io->drop_func(pkt_io->handle, thr_idx, &pkt, 1);
}
pkts[i] = NULL;
}
}
void packet_io_yield(struct packet_io *pkt_io, uint16_t thr_idx)
{
pkt_io->yield_func(pkt_io->handle, thr_idx);
}
void packet_io_clean(struct packet_io *pkt_io, uint16_t thr_idx)
{
struct packet *pkt = NULL;
uint64_t now_ms = clock_get_real_time_ms();
struct ip_reassembly *ip_reass = pkt_io->ip_reass[thr_idx];
while ((pkt = ip_reassembly_clean(ip_reass, now_ms)))
{
if (pkt_io->cfg->fail_action == 0)
{
packet_io_send(pkt_io, thr_idx, &pkt, 1);
}
else
{
packet_io_drop(pkt_io, thr_idx, &pkt, 1);
}
}
static __thread uint64_t last_sync_stat_ms = 0;
static __thread struct packet_io_stat pkt_io_last_stat = {0};
static __thread struct ip_reassembly_stat ip_reass_last_stat = {0};
if (now_ms - last_sync_stat_ms >= SYNC_STAT_INTERVAL_MS)
{
struct packet_io_stat *pkt_io_curr_stat = pkt_io->stat_func(pkt_io->handle, thr_idx);
struct ip_reassembly_stat *ip_reass_curr_stat = ip_reassembly_get_stat(pkt_io->ip_reass[thr_idx]);
for (int i = 0; i < PKT_IO_STAT_MAX; i++)
{
uint64_t val = packet_io_stat_get(pkt_io_curr_stat, i) - packet_io_stat_get(&pkt_io_last_stat, i);
fieldstat_easy_counter_incrby(pkt_io->fs, thr_idx, pkt_io->pkt_io_fs_idx[i], NULL, 0, val);
}
for (int i = 0; i < IP_REASS_STAT_MAX; i++)
{
uint64_t val = ip_reassembly_stat_get(ip_reass_curr_stat, i) - ip_reassembly_stat_get(&ip_reass_last_stat, i);
fieldstat_easy_counter_incrby(pkt_io->fs, thr_idx, pkt_io->ip_reass_fs_idx[i], NULL, 0, val);
}
pkt_io_last_stat = *pkt_io_curr_stat;
ip_reass_last_stat = *ip_reass_curr_stat;
last_sync_stat_ms = now_ms;
}
}
uint64_t packet_io_stat_get(struct packet_io_stat *stat, enum pkt_io_stat_type type)
{
switch (type)
{
#define XX(_type, _name) case _type: return stat->_name;
PKT_IO_STAT_MAP(XX)
#undef XX
default:
return 0;
}
}