2024-08-30 10:21:44 +08:00
|
|
|
#include "pcap_io.h"
|
2024-10-23 10:01:20 +08:00
|
|
|
#include "mars_io.h"
|
2024-10-31 16:25:37 +08:00
|
|
|
#include "ip_reassembly.h"
|
2024-10-23 10:01:20 +08:00
|
|
|
#include "utils_internal.h"
|
2024-10-31 16:25:37 +08:00
|
|
|
#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]
|
|
|
|
|
};
|
2024-08-30 10:21:44 +08:00
|
|
|
|
2024-02-28 16:30:03 +08:00
|
|
|
struct packet_io
|
|
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
void *handle;
|
|
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
void *(*new_func)(const char *toml_file);
|
2024-08-30 10:21:44 +08:00
|
|
|
void (*free_func)(void *handle);
|
2024-10-31 16:25:37 +08:00
|
|
|
int (*done_func)(void *handle);
|
2024-08-30 10:21:44 +08:00
|
|
|
|
|
|
|
|
int (*init_func)(void *handle, uint16_t thr_idx);
|
2024-10-23 10:01:20 +08:00
|
|
|
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);
|
2024-08-30 10:21:44 +08:00
|
|
|
void (*yield_func)(void *handle, uint16_t thr_idx);
|
|
|
|
|
struct packet_io_stat *(*stat_func)(void *handle, uint16_t thr_idx);
|
2024-10-31 16:25:37 +08:00
|
|
|
|
|
|
|
|
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];
|
2024-02-28 16:30:03 +08:00
|
|
|
};
|
|
|
|
|
|
2024-10-31 16:25:37 +08:00
|
|
|
/******************************************************************************
|
|
|
|
|
* 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
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
struct packet_io *packet_io_new(const char *toml_file)
|
2024-04-18 14:20:28 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
struct packet_io *pkt_io = (struct packet_io *)calloc(1, sizeof(struct packet_io));
|
|
|
|
|
if (pkt_io == NULL)
|
2024-04-18 14:20:28 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
PACKET_IO_LOG_ERROR("failed to allocate memory for packet_io");
|
2024-08-30 10:21:44 +08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-31 16:25:37 +08:00
|
|
|
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)
|
2024-09-20 18:41:07 +08:00
|
|
|
{
|
2024-10-23 10:01:20 +08:00
|
|
|
pkt_io->new_func = mars_io_new;
|
|
|
|
|
pkt_io->free_func = mars_io_free;
|
2024-10-31 16:25:37 +08:00
|
|
|
pkt_io->done_func = mars_io_is_done;
|
2024-10-23 10:01:20 +08:00
|
|
|
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;
|
2024-04-18 14:20:28 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
pkt_io->new_func = pcap_io_new;
|
|
|
|
|
pkt_io->free_func = pcap_io_free;
|
2024-10-31 16:25:37 +08:00
|
|
|
pkt_io->done_func = pcap_io_is_done;
|
2024-08-30 10:21:44 +08:00
|
|
|
pkt_io->init_func = pcap_io_init;
|
2024-10-23 10:01:20 +08:00
|
|
|
pkt_io->recv_func = pcap_io_recv;
|
|
|
|
|
pkt_io->send_func = pcap_io_send;
|
2024-08-30 10:21:44 +08:00
|
|
|
pkt_io->drop_func = pcap_io_drop;
|
|
|
|
|
pkt_io->yield_func = pcap_io_yield;
|
|
|
|
|
pkt_io->stat_func = pcap_io_stat;
|
2024-04-18 14:20:28 +08:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 16:25:37 +08:00
|
|
|
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;
|
|
|
|
|
}
|
2024-11-18 18:33:19 +08:00
|
|
|
if (fieldstat_easy_enable_auto_output(pkt_io->fs, "metrics/packet_io.json", 2) != 0)
|
2024-10-31 16:25:37 +08:00
|
|
|
{
|
|
|
|
|
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]);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
pkt_io->handle = pkt_io->new_func(toml_file);
|
2024-08-30 10:21:44 +08:00
|
|
|
if (pkt_io->handle == NULL)
|
2024-04-18 14:20:28 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
PACKET_IO_LOG_ERROR("failed to create packet_io handle");
|
|
|
|
|
goto error_out;
|
2024-04-18 14:20:28 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
|
|
|
|
|
return pkt_io;
|
2024-10-31 16:25:37 +08:00
|
|
|
|
|
|
|
|
error_out:
|
|
|
|
|
packet_io_free(pkt_io);
|
|
|
|
|
return NULL;
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void packet_io_free(struct packet_io *pkt_io)
|
|
|
|
|
{
|
|
|
|
|
if (pkt_io)
|
2024-04-18 14:20:28 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
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)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
fieldstat_easy_free(pkt_io->fs);
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
2024-10-31 16:25:37 +08:00
|
|
|
packet_io_cfg_free(pkt_io->cfg);
|
|
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
free(pkt_io);
|
|
|
|
|
pkt_io = NULL;
|
2024-04-18 14:20:28 +08:00
|
|
|
}
|
|
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
|
2024-10-31 16:25:37 +08:00
|
|
|
int packet_io_is_done(struct packet_io *pkt_io)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
return pkt_io->done_func(pkt_io->handle);
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int packet_io_init(struct packet_io *pkt_io, uint16_t thr_idx)
|
|
|
|
|
{
|
|
|
|
|
return pkt_io->init_func(pkt_io->handle, thr_idx);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
int packet_io_recv(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts[], int nr_pkts)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
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;
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
void packet_io_send(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts[], int nr_pkts)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
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;
|
|
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
2024-10-23 10:01:20 +08:00
|
|
|
void packet_io_drop(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts[], int nr_pkts)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
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;
|
|
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void packet_io_yield(struct packet_io *pkt_io, uint16_t thr_idx)
|
|
|
|
|
{
|
|
|
|
|
pkt_io->yield_func(pkt_io->handle, thr_idx);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-31 16:25:37 +08:00
|
|
|
void packet_io_clean(struct packet_io *pkt_io, uint16_t thr_idx)
|
2024-10-23 10:01:20 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
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;
|
|
|
|
|
}
|
2024-10-23 10:01:20 +08:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 16:25:37 +08:00
|
|
|
uint64_t packet_io_stat_get(struct packet_io_stat *stat, enum pkt_io_stat_type type)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-10-31 16:25:37 +08:00
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
#define XX(_type, _name) case _type: return stat->_name;
|
|
|
|
|
PKT_IO_STAT_MAP(XX)
|
|
|
|
|
#undef XX
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|