IP reassembly parses IP frag related configuration items
This commit is contained in:
@@ -168,55 +168,6 @@ error_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// return 0: success
|
||||
// retuun -1: failed
|
||||
static int parse_ip_reassembly_section(toml_table_t *root, struct ip_reassembly_options *opts)
|
||||
{
|
||||
const char *ptr;
|
||||
toml_table_t *table;
|
||||
|
||||
table = toml_table_in(root, "ip_reassembly");
|
||||
if (table == NULL)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file missing ip_reassembly section");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = toml_raw_in(table, "enable");
|
||||
if (ptr == NULL)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file missing ip_reassembly->enable");
|
||||
return -1;
|
||||
}
|
||||
opts->enable = atoi(ptr);
|
||||
|
||||
ptr = toml_raw_in(table, "timeout");
|
||||
if (ptr == NULL)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file missing ip_reassembly->timeout");
|
||||
return -1;
|
||||
}
|
||||
opts->timeout = atoi(ptr);
|
||||
|
||||
ptr = toml_raw_in(table, "bucket_entries");
|
||||
if (ptr == NULL)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file missing ip_reassembly->bucket_entries");
|
||||
return -1;
|
||||
}
|
||||
opts->bucket_entries = atoi(ptr);
|
||||
|
||||
ptr = toml_raw_in(table, "bucket_num");
|
||||
if (ptr == NULL)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file missing ip_reassembly->bucket_num");
|
||||
return -1;
|
||||
}
|
||||
opts->bucket_num = atoi(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return 0: success
|
||||
// retuun -1: failed
|
||||
static int parse_schedule_options(toml_table_t *root, struct schedule_options *opts)
|
||||
@@ -231,32 +182,6 @@ static int parse_schedule_options(toml_table_t *root, struct schedule_options *o
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = toml_raw_in(table, "free_expired_ip_frag_interval");
|
||||
if (ptr == NULL)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file missing schedule->free_expired_ip_frag_interval");
|
||||
return -1;
|
||||
}
|
||||
opts->free_expired_ip_frag_interval = atoll(ptr);
|
||||
if (opts->free_expired_ip_frag_interval < 1 || opts->free_expired_ip_frag_interval > 60000)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file invalid schedule->free_expired_ip_frag_interval %ld, range [1, 60000]", opts->free_expired_ip_frag_interval);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = toml_raw_in(table, "free_expired_ip_frag_batch");
|
||||
if (ptr == NULL)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file missing schedule->free_expired_ip_frag_batch");
|
||||
return -1;
|
||||
}
|
||||
opts->free_expired_ip_frag_batch = atoll(ptr);
|
||||
if (opts->free_expired_ip_frag_batch < 1 || opts->free_expired_ip_frag_batch > 60000)
|
||||
{
|
||||
CONFIG_LOG_ERROR("config file invalid schedule->free_expired_ip_frag_batch %ld, range [1, 60000]", opts->free_expired_ip_frag_batch);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptr = toml_raw_in(table, "merge_stat_interval");
|
||||
if (ptr == NULL)
|
||||
{
|
||||
@@ -332,11 +257,6 @@ int stellar_config_load(struct stellar_config *config, const char *file)
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (parse_ip_reassembly_section(table, &config->ip_reass_opts) != 0)
|
||||
{
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (parse_schedule_options(table, &config->sched_opts) != 0)
|
||||
{
|
||||
goto error_out;
|
||||
@@ -367,7 +287,6 @@ void stellar_config_print(const struct stellar_config *config)
|
||||
|
||||
const struct packet_io_options *pkt_io_opts = &config->pkt_io_opts;
|
||||
const struct snowflake_options *snowflake_opts = &config->snowflake_opts;
|
||||
const struct ip_reassembly_options *ip_reass_opts = &config->ip_reass_opts;
|
||||
|
||||
// snowflake config
|
||||
CONFIG_LOG_DEBUG("snowflake->snowflake_base : %d", snowflake_opts->snowflake_base);
|
||||
@@ -390,15 +309,7 @@ void stellar_config_print(const struct stellar_config *config)
|
||||
CONFIG_LOG_DEBUG("packet_io->cpu_mask[%3d] : %d", i, pkt_io_opts->cpu_mask[i]);
|
||||
}
|
||||
|
||||
// ip reassemble config
|
||||
CONFIG_LOG_DEBUG("ip_reassembly->enable : %d", ip_reass_opts->enable);
|
||||
CONFIG_LOG_DEBUG("ip_reassembly->timeout : %d", ip_reass_opts->timeout);
|
||||
CONFIG_LOG_DEBUG("ip_reassembly->bucket_entries : %d", ip_reass_opts->bucket_entries);
|
||||
CONFIG_LOG_DEBUG("ip_reassembly->bucket_num : %d", ip_reass_opts->bucket_num);
|
||||
|
||||
// schedule config
|
||||
CONFIG_LOG_DEBUG("schedule->free_expired_ip_frag_interval : %ld", config->sched_opts.free_expired_ip_frag_interval);
|
||||
CONFIG_LOG_DEBUG("schedule->free_expired_ip_frag_batch : %ld", config->sched_opts.free_expired_ip_frag_batch);
|
||||
CONFIG_LOG_DEBUG("schedule->merge_stat_interval : %ld", config->sched_opts.merge_stat_interval);
|
||||
CONFIG_LOG_DEBUG("schedule->output_stat_interval : %ld", config->sched_opts.output_stat_interval);
|
||||
CONFIG_LOG_DEBUG("schedule->packet_io_yield_interval : %ld", config->sched_opts.packet_io_yield_interval);
|
||||
|
||||
@@ -6,14 +6,9 @@ extern "C"
|
||||
#endif
|
||||
|
||||
#include "packet_io.h"
|
||||
#include "ip_reassembly.h"
|
||||
|
||||
struct schedule_options
|
||||
{
|
||||
// Note: free_expired_ip_frag_interval determines the precision of ip_reassembly timeout
|
||||
uint64_t free_expired_ip_frag_interval; // range: [1, 60000] (ms)
|
||||
uint64_t free_expired_ip_frag_batch; // range: [1, 60000]
|
||||
|
||||
uint64_t merge_stat_interval; // range: [1, 60000] (ms)
|
||||
uint64_t output_stat_interval; // range: [1, 60000] (ms)
|
||||
|
||||
@@ -30,7 +25,6 @@ struct stellar_config
|
||||
{
|
||||
struct packet_io_options pkt_io_opts;
|
||||
struct snowflake_options snowflake_opts;
|
||||
struct ip_reassembly_options ip_reass_opts;
|
||||
struct schedule_options sched_opts;
|
||||
};
|
||||
|
||||
|
||||
@@ -42,10 +42,9 @@ struct stellar_thread
|
||||
pthread_t tid;
|
||||
uint16_t idx;
|
||||
uint64_t is_runing;
|
||||
uint64_t last_free_expired_ip_frag_timestamp;
|
||||
uint64_t last_merge_thread_stat_timestamp;
|
||||
struct snowflake *snowflake;
|
||||
struct ip_reassembly *ip_mgr;
|
||||
struct ip_reassembly *ip_reass;
|
||||
struct session_manager *sess_mgr;
|
||||
struct stellar *st;
|
||||
};
|
||||
@@ -60,6 +59,7 @@ struct stellar_runtime
|
||||
struct plugin_manager_schema *plug_mgr;
|
||||
struct stellar_thread threads[MAX_THREAD_NUM];
|
||||
struct session_manager_config *sess_mgr_cfg;
|
||||
struct ip_reassembly_config *ip_reass_cfg;
|
||||
};
|
||||
|
||||
struct stellar
|
||||
@@ -130,7 +130,7 @@ static void *worker_thread(void *arg)
|
||||
struct packet packets[RX_BURST_MAX];
|
||||
struct session *sess = NULL;
|
||||
struct stellar_thread *thread = (struct stellar_thread *)arg;
|
||||
struct ip_reassembly *ip_reass = thread->ip_mgr;
|
||||
struct ip_reassembly *ip_reass = thread->ip_reass;
|
||||
struct session_manager *sess_mgr = thread->sess_mgr;
|
||||
struct session_manager_stat *sess_stat = session_manager_stat(sess_mgr);
|
||||
struct stellar *st = thread->st;
|
||||
@@ -144,8 +144,6 @@ static void *worker_thread(void *arg)
|
||||
.session_mgr = session_manager_stat(sess_mgr),
|
||||
};
|
||||
|
||||
uint64_t free_expired_ip_frag_interval = config->sched_opts.free_expired_ip_frag_interval;
|
||||
uint64_t free_expired_ip_frag_batch = config->sched_opts.free_expired_ip_frag_batch;
|
||||
uint64_t merge_stat_interval = config->sched_opts.merge_stat_interval;
|
||||
uint64_t packet_io_yield_interval = config->sched_opts.packet_io_yield_interval;
|
||||
uint16_t thr_idx = thread->idx;
|
||||
@@ -290,6 +288,7 @@ static void *worker_thread(void *arg)
|
||||
|
||||
idle_tasks:
|
||||
clean_session(sess_mgr, now_ms);
|
||||
ip_reassembly_expire(ip_reass, now_ms);
|
||||
plugin_manager_on_polling(plug_mgr);
|
||||
|
||||
// per merge_stat_interval merge thread stat
|
||||
@@ -299,13 +298,6 @@ static void *worker_thread(void *arg)
|
||||
thread->last_merge_thread_stat_timestamp = now_ms;
|
||||
}
|
||||
|
||||
// per free_expired_ip_frag_interval MAX free_expired_ip_frag_batch ip fragments are released
|
||||
if (now_ms - thread->last_free_expired_ip_frag_timestamp >= free_expired_ip_frag_interval)
|
||||
{
|
||||
ip_reassembly_expire(ip_reass, free_expired_ip_frag_batch, now_ms);
|
||||
thread->last_free_expired_ip_frag_timestamp = now_ms;
|
||||
}
|
||||
|
||||
if (nr_pkt_received == 0)
|
||||
{
|
||||
packet_io_yield(packet_io, thr_idx, packet_io_yield_interval);
|
||||
@@ -359,7 +351,6 @@ static int stellar_thread_init(struct stellar *st)
|
||||
thread->idx = i;
|
||||
thread->is_runing = 0;
|
||||
|
||||
thread->last_free_expired_ip_frag_timestamp = now_ms;
|
||||
thread->last_merge_thread_stat_timestamp = now_ms;
|
||||
|
||||
thread->snowflake = snowflake_new(i, config->snowflake_opts.snowflake_base, config->snowflake_opts.snowflake_offset);
|
||||
@@ -368,6 +359,7 @@ static int stellar_thread_init(struct stellar *st)
|
||||
CORE_LOG_ERROR("unable to create snowflake id generator");
|
||||
return -1;
|
||||
}
|
||||
|
||||
thread->sess_mgr = session_manager_new(runtime->sess_mgr_cfg, now_ms);
|
||||
if (thread->sess_mgr == NULL)
|
||||
{
|
||||
@@ -375,8 +367,9 @@ static int stellar_thread_init(struct stellar *st)
|
||||
return -1;
|
||||
}
|
||||
session_manager_set_session_id_generator(thread->sess_mgr, stellar_generate_session_id);
|
||||
thread->ip_mgr = ip_reassembly_new(&config->ip_reass_opts);
|
||||
if (thread->ip_mgr == NULL)
|
||||
|
||||
thread->ip_reass = ip_reassembly_new(runtime->ip_reass_cfg, now_ms);
|
||||
if (thread->ip_reass == NULL)
|
||||
{
|
||||
CORE_LOG_ERROR("unable to create ip reassemble manager");
|
||||
return -1;
|
||||
@@ -398,7 +391,7 @@ static void stellar_thread_clean(struct stellar *st)
|
||||
struct stellar_thread *thread = &runtime->threads[i];
|
||||
if (ATOMIC_READ(&thread->is_runing) == 0)
|
||||
{
|
||||
ip_reassembly_free(thread->ip_mgr);
|
||||
ip_reassembly_free(thread->ip_reass);
|
||||
session_manager_free(thread->sess_mgr);
|
||||
snowflake_free(thread->snowflake);
|
||||
}
|
||||
@@ -490,8 +483,15 @@ struct stellar *stellar_new(const char *stellar_cfg_file, const char *plugin_cfg
|
||||
CORE_LOG_ERROR("unable to create session manager config");
|
||||
goto error_out;
|
||||
}
|
||||
session_manager_config_print(runtime->sess_mgr_cfg);
|
||||
runtime->ip_reass_cfg = ip_reassembly_config_new(st->stellar_cfg_file);
|
||||
if (runtime->ip_reass_cfg == NULL)
|
||||
{
|
||||
CORE_LOG_ERROR("unable to create ip reassembly config");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
session_manager_config_print(runtime->sess_mgr_cfg);
|
||||
ip_reassembly_config_print(runtime->ip_reass_cfg);
|
||||
if (stellar_config_load(config, st->stellar_cfg_file) != 0)
|
||||
{
|
||||
CORE_LOG_ERROR("unable to load config file");
|
||||
@@ -587,6 +587,7 @@ void stellar_free(struct stellar *st)
|
||||
packet_io_free(runtime->packet_io);
|
||||
plugin_manager_exit(runtime->plug_mgr);
|
||||
stellar_stat_free(runtime->stat);
|
||||
ip_reassembly_config_free(runtime->ip_reass_cfg);
|
||||
session_manager_config_free(runtime->sess_mgr_cfg);
|
||||
CORE_LOG_FATAL("stellar exit\n");
|
||||
log_free(runtime->logger);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "toml.h"
|
||||
#include "checksum.h"
|
||||
#include "crc32_hash.h"
|
||||
#include "log_private.h"
|
||||
@@ -13,6 +15,7 @@
|
||||
|
||||
#define IP_REASSEMBLE_DEBUG(format, ...) STELLAR_LOG_DEBUG(__thread_local_logger, "ip_reassembly", format, ##__VA_ARGS__)
|
||||
#define IP_REASSEMBLE_ERROR(format, ...) STELLAR_LOG_ERROR(__thread_local_logger, "ip_reassembly", format, ##__VA_ARGS__)
|
||||
#define IP_REASSEMBLE_INFO(format, ...) STELLAR_LOG_INFO(__thread_local_logger, "ip_reassembly", format, ##__VA_ARGS__)
|
||||
|
||||
#define IPV4_KEYLEN 1
|
||||
#define IPV6_KEYLEN 4
|
||||
@@ -112,15 +115,13 @@ struct ip_frag_pkt
|
||||
|
||||
struct ip_reassembly
|
||||
{
|
||||
// options
|
||||
bool enable;
|
||||
uint32_t timeout;
|
||||
uint32_t bucket_entries;
|
||||
struct ip_reassembly_config cfg;
|
||||
|
||||
// runtime
|
||||
uint32_t entry_used;
|
||||
uint32_t entry_total;
|
||||
uint32_t entry_mask;
|
||||
uint64_t last_clean_expired_frag_ts;
|
||||
|
||||
// stats
|
||||
struct ip_reassembly_stat stat;
|
||||
@@ -190,38 +191,6 @@ static inline int is_power_of_2(uint32_t n)
|
||||
return n && !(n & (n - 1));
|
||||
}
|
||||
|
||||
static int check_options(const struct ip_reassembly_options *opts)
|
||||
{
|
||||
if (opts == NULL)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG("invalid options");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opts->enable)
|
||||
{
|
||||
if (opts->timeout < 1 || opts->timeout > 60000)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG("invalid timeout: %u, supported range: [1, 60000]", opts->timeout);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opts->bucket_entries < 1 || is_power_of_2(opts->bucket_entries) == 0)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG("invalid bucket_entries: %u, must be power of 2", opts->bucket_entries);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opts->bucket_num == 0)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG("invalid bucket_num: %u, supported range: [1, 4294967295]", opts->bucket_num);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ip frag key
|
||||
******************************************************************************/
|
||||
@@ -517,9 +486,9 @@ static struct ip_frag_pkt *ip_reassembly_find_frag_pkt(struct ip_reassembly *ass
|
||||
// search in the bucket
|
||||
struct ip_frag_pkt *old = NULL;
|
||||
struct ip_frag_pkt *empty = NULL;
|
||||
uint64_t timeout = assy->timeout;
|
||||
uint32_t assoc = assy->bucket_entries;
|
||||
for (uint32_t i = 0; i != assoc; i++)
|
||||
uint64_t timeout = assy->cfg.ip_frag_timeout_ms;
|
||||
uint32_t entries = assy->cfg.bucket_entries;
|
||||
for (uint32_t i = 0; i != entries; i++)
|
||||
{
|
||||
if (ip_frag_key_cmp(key, &p1[i].key) == 0)
|
||||
{
|
||||
@@ -594,7 +563,7 @@ static struct ip_frag_pkt *ip_reassembly_update_frag_pkt(struct ip_reassembly *a
|
||||
else
|
||||
{
|
||||
// expired
|
||||
if (assy->timeout + frag_pkt->create_time <= now)
|
||||
if (assy->cfg.ip_frag_timeout_ms + frag_pkt->create_time <= now)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG1("add ip frag pkt success: reuse expired entry", key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_failed_timeout, key);
|
||||
@@ -757,29 +726,144 @@ error_out_overlap:
|
||||
* Public API
|
||||
******************************************************************************/
|
||||
|
||||
struct ip_reassembly *ip_reassembly_new(const struct ip_reassembly_options *opts)
|
||||
#define PARSE_AND_CHECK_NUM(table, key, val, min, max) \
|
||||
do \
|
||||
{ \
|
||||
const char *ptr = toml_raw_in(table, (key)); \
|
||||
if (ptr == NULL) \
|
||||
{ \
|
||||
IP_REASSEMBLE_ERROR("config file missing ip_reassembly.%s", (key)); \
|
||||
goto error_out; \
|
||||
} \
|
||||
(val) = atoll(ptr); \
|
||||
if ((val) < (min) || (val) > (max)) \
|
||||
{ \
|
||||
IP_REASSEMBLE_ERROR("invalid ip_reassembly.%s: %lu, supported range: [%lu, %lu]", (key), (val), (min), (max)); \
|
||||
goto error_out; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int ip_reassembly_config_load(struct ip_reassembly_config *cfg, const char *toml_file)
|
||||
{
|
||||
if (check_options(opts) == -1)
|
||||
int ret = -1;
|
||||
char errbuf[200];
|
||||
FILE *fp = NULL;
|
||||
toml_table_t *root = NULL;
|
||||
toml_table_t *table = NULL;
|
||||
uint64_t zero = 0; // make compiler happy
|
||||
|
||||
fp = fopen(toml_file, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR("config file %s open failed, %s", toml_file, strerror(errno));
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
root = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
||||
if (root == NULL)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR("config file %s parse failed, %s", toml_file, errbuf);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
table = toml_table_in(root, "ip_reassembly");
|
||||
if (table == NULL)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR("config file %s missing ip_reassembly", toml_file);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
PARSE_AND_CHECK_NUM(table, "enable", cfg->enable, zero, 1);
|
||||
|
||||
if (cfg->enable)
|
||||
{
|
||||
PARSE_AND_CHECK_NUM(table, "bucket_entries", cfg->bucket_entries, 1, 4294967295);
|
||||
PARSE_AND_CHECK_NUM(table, "bucket_num", cfg->bucket_num, 1, 4294967295);
|
||||
PARSE_AND_CHECK_NUM(table, "ip_frag_timeout_ms", cfg->ip_frag_timeout_ms, 1, 60000);
|
||||
PARSE_AND_CHECK_NUM(table, "ip_frag_expire_polling_interval_ms", cfg->ip_frag_expire_polling_interval_ms, zero, 60000);
|
||||
PARSE_AND_CHECK_NUM(table, "ip_frag_expire_polling_limit", cfg->ip_frag_expire_polling_limit, 1, 1024);
|
||||
|
||||
if (is_power_of_2(cfg->bucket_entries) == 0)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR("invalid ip_reassembly.bucket_entries: %lu, must be power of 2", cfg->bucket_entries);
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
error_out:
|
||||
if (root)
|
||||
{
|
||||
toml_free(root);
|
||||
}
|
||||
if (fp)
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct ip_reassembly_config *ip_reassembly_config_new(const char *toml_file)
|
||||
{
|
||||
if (toml_file == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ip_reassembly_config *cfg = (struct ip_reassembly_config *)calloc(1, sizeof(struct ip_reassembly_config));
|
||||
if (cfg == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ip_reassembly_config_load(cfg, toml_file) == -1)
|
||||
{
|
||||
ip_reassembly_config_free(cfg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
void ip_reassembly_config_free(struct ip_reassembly_config *cfg)
|
||||
{
|
||||
if (cfg)
|
||||
{
|
||||
free(cfg);
|
||||
cfg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ip_reassembly_config_print(const struct ip_reassembly_config *cfg)
|
||||
{
|
||||
if (cfg)
|
||||
{
|
||||
IP_REASSEMBLE_INFO("ip_reassembly.enable : %u", cfg->enable);
|
||||
IP_REASSEMBLE_INFO("ip_reassembly.bucket_entries : %u", cfg->bucket_entries);
|
||||
IP_REASSEMBLE_INFO("ip_reassembly.bucket_num : %u", cfg->bucket_num);
|
||||
IP_REASSEMBLE_INFO("ip_reassembly.ip_frag_timeout_ms : %lu", cfg->ip_frag_timeout_ms);
|
||||
IP_REASSEMBLE_INFO("ip_reassembly.ip_frag_expire_polling_interval_ms : %lu", cfg->ip_frag_expire_polling_interval_ms);
|
||||
IP_REASSEMBLE_INFO("ip_reassembly.ip_frag_expire_polling_limit : %lu", cfg->ip_frag_expire_polling_limit);
|
||||
}
|
||||
}
|
||||
|
||||
struct ip_reassembly *ip_reassembly_new(const struct ip_reassembly_config *cfg, uint64_t now_ms)
|
||||
{
|
||||
struct ip_reassembly *assy = (struct ip_reassembly *)calloc(1, sizeof(struct ip_reassembly));
|
||||
if (assy == NULL)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR("unable to allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
assy->enable = opts->enable;
|
||||
assy->timeout = opts->timeout;
|
||||
assy->bucket_entries = opts->bucket_entries;
|
||||
memcpy(&assy->cfg, cfg, sizeof(struct ip_reassembly_config));
|
||||
|
||||
if (!assy->enable)
|
||||
if (!assy->cfg.enable)
|
||||
{
|
||||
return assy;
|
||||
}
|
||||
|
||||
uint64_t entry_total = align32pow2(opts->bucket_num) * assy->bucket_entries * IP_FRAG_HASH_FNUM;
|
||||
uint64_t entry_total = align32pow2(assy->cfg.bucket_num) * assy->cfg.bucket_entries * IP_FRAG_HASH_FNUM;
|
||||
if (entry_total > UINT32_MAX)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR("bucket_num * bucket_entries is too large");
|
||||
@@ -787,8 +871,9 @@ struct ip_reassembly *ip_reassembly_new(const struct ip_reassembly_options *opts
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assy->last_clean_expired_frag_ts = now_ms;
|
||||
assy->entry_total = (uint32_t)entry_total;
|
||||
assy->entry_mask = (assy->entry_total - 1) & ~(assy->bucket_entries - 1);
|
||||
assy->entry_mask = (assy->entry_total - 1) & ~(assy->cfg.bucket_entries - 1);
|
||||
assy->table = (struct ip_frag_pkt *)calloc(assy->entry_total, sizeof(struct ip_frag_pkt));
|
||||
if (assy->table == NULL)
|
||||
{
|
||||
@@ -821,11 +906,20 @@ void ip_reassembly_free(struct ip_reassembly *assy)
|
||||
}
|
||||
}
|
||||
|
||||
void ip_reassembly_expire(struct ip_reassembly *assy, uint64_t max_free, uint64_t now)
|
||||
void ip_reassembly_expire(struct ip_reassembly *assy, uint64_t now)
|
||||
{
|
||||
uint64_t count = 0;
|
||||
if (now - assy->last_clean_expired_frag_ts >= assy->cfg.ip_frag_expire_polling_interval_ms)
|
||||
{
|
||||
assy->last_clean_expired_frag_ts = now;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t cleaned_frags = 0;
|
||||
struct ip_frag_pkt *frag_pkt = NULL;
|
||||
uint64_t timeout = assy->timeout;
|
||||
uint64_t timeout = assy->cfg.ip_frag_timeout_ms;
|
||||
TAILQ_FOREACH(frag_pkt, &assy->lru, lru)
|
||||
{
|
||||
if (timeout + frag_pkt->create_time <= now)
|
||||
@@ -833,9 +927,9 @@ void ip_reassembly_expire(struct ip_reassembly *assy, uint64_t max_free, uint64_
|
||||
IP_REASSEMBLE_DEBUG1("expire ip frag pkt: discarding old fragmented packets", &frag_pkt->key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_failed_timeout, &frag_pkt->key);
|
||||
ip_reassembly_del_frag_pkt(assy, frag_pkt);
|
||||
count++;
|
||||
cleaned_frags++;
|
||||
|
||||
if (count >= max_free)
|
||||
if (cleaned_frags >= assy->cfg.ip_frag_expire_polling_limit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -869,7 +963,7 @@ struct packet *ip_reassembly_packet(struct ip_reassembly *assy, const struct pac
|
||||
struct packet *pkt1;
|
||||
struct packet *pkt2;
|
||||
|
||||
if (!assy->enable)
|
||||
if (!assy->cfg.enable)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct ip_reassembly_options
|
||||
struct ip_reassembly_config
|
||||
{
|
||||
uint8_t enable;
|
||||
uint32_t timeout; // range: [1, 60000]
|
||||
uint32_t bucket_entries; // range: [1, 4294967295] (must be power of 2)
|
||||
uint32_t bucket_num; // range: [1, 4294967295]
|
||||
|
||||
uint64_t ip_frag_timeout_ms; // range: [1, 60000] (ms)
|
||||
uint64_t ip_frag_expire_polling_interval_ms; // range: [0, 60000] (ms)
|
||||
uint64_t ip_frag_expire_polling_limit; // range: [1, 1024]
|
||||
};
|
||||
|
||||
struct __attribute__((aligned(64))) ip_reassembly_stat
|
||||
@@ -46,9 +49,13 @@ struct __attribute__((aligned(64))) ip_reassembly_stat
|
||||
uint64_t ip6_frags_bypass_dup_last_frag;
|
||||
};
|
||||
|
||||
struct ip_reassembly *ip_reassembly_new(const struct ip_reassembly_options *opts);
|
||||
struct ip_reassembly_config *ip_reassembly_config_new(const char *toml_file);
|
||||
void ip_reassembly_config_free(struct ip_reassembly_config *cfg);
|
||||
void ip_reassembly_config_print(const struct ip_reassembly_config *cfg);
|
||||
|
||||
struct ip_reassembly *ip_reassembly_new(const struct ip_reassembly_config *cfg, uint64_t now);
|
||||
void ip_reassembly_free(struct ip_reassembly *assy);
|
||||
void ip_reassembly_expire(struct ip_reassembly *assy, uint64_t max_free, uint64_t now);
|
||||
void ip_reassembly_expire(struct ip_reassembly *assy, uint64_t now);
|
||||
struct ip_reassembly_stat *ip_reassembly_stat(struct ip_reassembly *assy);
|
||||
|
||||
/*
|
||||
|
||||
@@ -198,14 +198,16 @@ TEST(IPV4_REASSEMBLE, PADDING_ORDER)
|
||||
struct packet *new_pkt;
|
||||
const struct layer_private *layer;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -293,14 +295,16 @@ TEST(IPV4_REASSEMBLE, PADDING_UNORDER)
|
||||
struct packet *new_pkt;
|
||||
const struct layer_private *layer;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -387,14 +391,16 @@ TEST(IPV4_REASSEMBLE, EXPIRE)
|
||||
struct packet pkt;
|
||||
struct packet *new_pkt;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -441,14 +447,16 @@ TEST(IPV4_REASSEMBLE, DUP_FIRST_FRAG)
|
||||
struct packet *new_pkt;
|
||||
const struct layer_private *layer;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -548,14 +556,16 @@ TEST(IPV4_REASSEMBLE, DUP_LAST_FRAG)
|
||||
struct packet *new_pkt;
|
||||
const struct layer_private *layer;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -654,14 +664,16 @@ TEST(IPV4_REASSEMBLE, FULL)
|
||||
struct packet pkt;
|
||||
struct packet *new_pkt;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 1,
|
||||
.bucket_num = 1,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
|
||||
@@ -609,14 +609,16 @@ TEST(IPV6_REASSEMBLE, NORMAL)
|
||||
struct packet *new_pkt;
|
||||
const struct layer_private *layer;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -721,14 +723,16 @@ TEST(IPV6_REASSEMBLE, EXPIRE)
|
||||
struct packet pkt;
|
||||
struct packet *new_pkt;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -775,14 +779,16 @@ TEST(IPV6_REASSEMBLE, DUP_FIRST_FRAG)
|
||||
struct packet *new_pkt;
|
||||
const struct layer_private *layer;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -900,14 +906,16 @@ TEST(IPV6_REASSEMBLE, DUP_LAST_FRAG)
|
||||
struct packet *new_pkt;
|
||||
const struct layer_private *layer;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -1025,14 +1033,16 @@ TEST(IPV6_REASSEMBLE, FULL)
|
||||
struct packet *new_pkt;
|
||||
struct in6_addr src_addr;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 1,
|
||||
.bucket_num = 1,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
@@ -1095,14 +1105,16 @@ TEST(IPV6_REASSEMBLE, OVERLAP)
|
||||
struct packet pkt;
|
||||
struct packet *new_pkt;
|
||||
struct ip_reassembly *assy;
|
||||
struct ip_reassembly_options opts = {
|
||||
struct ip_reassembly_config cfg = {
|
||||
.enable = true,
|
||||
.timeout = 1,
|
||||
.bucket_entries = 16,
|
||||
.bucket_num = 8,
|
||||
.ip_frag_timeout_ms = 1,
|
||||
.ip_frag_expire_polling_interval_ms = 0,
|
||||
.ip_frag_expire_polling_limit = 1024,
|
||||
};
|
||||
|
||||
assy = ip_reassembly_new(&opts);
|
||||
assy = ip_reassembly_new(&cfg, 0);
|
||||
EXPECT_TRUE(assy != NULL);
|
||||
|
||||
check_stat(ip_reassembly_stat(assy),
|
||||
|
||||
Reference in New Issue
Block a user