summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluwenpeng <[email protected]>2024-08-29 18:03:14 +0800
committerluwenpeng <[email protected]>2024-08-30 18:56:35 +0800
commit8935e5408b58885773e7db04403c2ae3fca590c7 (patch)
treefcdefaeab8e673e895f9b7149d2f8543413a6fad
parent338dcf93e5ac530d5216f834f5798bbe672e711c (diff)
IP reassembly parses IP frag related configuration items
-rw-r--r--conf/stellar.toml9
-rw-r--r--infra/core/stellar_config.c89
-rw-r--r--infra/core/stellar_config.h6
-rw-r--r--infra/core/stellar_core.c35
-rw-r--r--infra/ip_reassembly/ip_reassembly.c202
-rw-r--r--infra/ip_reassembly/ip_reassembly.h15
-rw-r--r--infra/ip_reassembly/test/gtest_ipv4_reassembly.cpp48
-rw-r--r--infra/ip_reassembly/test/gtest_ipv6_reassembly.cpp48
-rw-r--r--test/decoders/http/test_based_on_stellar/env/stellar.toml13
-rw-r--r--test/packet_inject/conf/stellar.toml13
10 files changed, 253 insertions, 225 deletions
diff --git a/conf/stellar.toml b/conf/stellar.toml
index ef9cb0c..360e6fe 100644
--- a/conf/stellar.toml
+++ b/conf/stellar.toml
@@ -15,10 +15,13 @@ cpu_mask = [5, 6, 7, 8, 9, 10, 11, 12]
[ip_reassembly]
enable = 1
-timeout = 10000 # range: [1, 60000] (ms)
bucket_entries = 32 # range: [1, 4294967295] (must be power of 2)
bucket_num = 1024 # range: [1, 4294967295]
+ip_frag_timeout_ms = 10000 # range: [1, 60000] (ms)
+ip_frag_expire_polling_interval_ms = 0 # range: [0, 60000] (ms)
+ip_frag_expire_polling_limit = 1024 # range: [1, 1024]
+
[session_manager]
# max session number
max_tcp_session_num = 50000
@@ -62,10 +65,6 @@ tcp_reassembly_max_timeout_ms = 10000 # range: [1, 60000] (ms)
tcp_reassembly_max_segments = 256 # range: [2, 4096]
[schedule]
-# Note: free_expired_ip_frag_interval determines the precision of ip_reassembly timeout
-free_expired_ip_frag_interval = 50 # range: [1, 60000] (ms)
-free_expired_ip_frag_batch = 1000 # range: [1, 60000]
-
merge_stat_interval = 500 # range: [1, 60000] (ms)
output_stat_interval = 2000 # range: [1, 60000] (ms)
diff --git a/infra/core/stellar_config.c b/infra/core/stellar_config.c
index 47bded2..d1511fe 100644
--- a/infra/core/stellar_config.c
+++ b/infra/core/stellar_config.c
@@ -170,55 +170,6 @@ error_out:
// 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)
{
const char *ptr;
@@ -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);
diff --git a/infra/core/stellar_config.h b/infra/core/stellar_config.h
index c91cd46..1e5f01e 100644
--- a/infra/core/stellar_config.h
+++ b/infra/core/stellar_config.h
@@ -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;
};
diff --git a/infra/core/stellar_core.c b/infra/core/stellar_core.c
index e43abc4..83e9531 100644
--- a/infra/core/stellar_core.c
+++ b/infra/core/stellar_core.c
@@ -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);
diff --git a/infra/ip_reassembly/ip_reassembly.c b/infra/ip_reassembly/ip_reassembly.c
index c6eb492..bfa228b 100644
--- a/infra/ip_reassembly/ip_reassembly.c
+++ b/infra/ip_reassembly/ip_reassembly.c
@@ -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)
+{
+ 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 (check_options(opts) == -1)
+ 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;
}
diff --git a/infra/ip_reassembly/ip_reassembly.h b/infra/ip_reassembly/ip_reassembly.h
index 456e09b..269b320 100644
--- a/infra/ip_reassembly/ip_reassembly.h
+++ b/infra/ip_reassembly/ip_reassembly.h
@@ -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);
/*
diff --git a/infra/ip_reassembly/test/gtest_ipv4_reassembly.cpp b/infra/ip_reassembly/test/gtest_ipv4_reassembly.cpp
index 5d96336..94a8254 100644
--- a/infra/ip_reassembly/test/gtest_ipv4_reassembly.cpp
+++ b/infra/ip_reassembly/test/gtest_ipv4_reassembly.cpp
@@ -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),
diff --git a/infra/ip_reassembly/test/gtest_ipv6_reassembly.cpp b/infra/ip_reassembly/test/gtest_ipv6_reassembly.cpp
index f7eae08..ca177b2 100644
--- a/infra/ip_reassembly/test/gtest_ipv6_reassembly.cpp
+++ b/infra/ip_reassembly/test/gtest_ipv6_reassembly.cpp
@@ -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),
diff --git a/test/decoders/http/test_based_on_stellar/env/stellar.toml b/test/decoders/http/test_based_on_stellar/env/stellar.toml
index da13527..210ce3d 100644
--- a/test/decoders/http/test_based_on_stellar/env/stellar.toml
+++ b/test/decoders/http/test_based_on_stellar/env/stellar.toml
@@ -15,9 +15,12 @@ cpu_mask = [5, 6, 7, 8, 9, 10, 11, 12]
[ip_reassembly]
enable = 1
-timeout = 10000 # range: [1, 60000] (ms)
-bucket_entries = 256 # range: [1, 4294967295] (must be power of 2)
-bucket_num = 4096 # range: [1, 4294967295]
+bucket_entries = 32 # range: [1, 4294967295] (must be power of 2)
+bucket_num = 1024 # range: [1, 4294967295]
+
+ip_frag_timeout_ms = 10000 # range: [1, 60000] (ms)
+ip_frag_expire_polling_interval_ms = 0 # range: [0, 60000] (ms)
+ip_frag_expire_polling_limit = 1024 # range: [1, 1024]
[session_manager]
# max session number
@@ -62,10 +65,6 @@ tcp_reassembly_max_timeout_ms = 10000 # range: [1, 60000] (ms)
tcp_reassembly_max_segments = 256 # range: [2, 4096]
[schedule]
-# Note: free_expired_ip_frag_interval determines the precision of ip_reassembly timeout
-free_expired_ip_frag_interval = 50 # range: [1, 60000] (ms)
-free_expired_ip_frag_batch = 100 # range: [1, 60000]
-
merge_stat_interval = 50 # range: [1, 60000] (ms)
output_stat_interval = 10 # range: [1, 60000] (ms)
diff --git a/test/packet_inject/conf/stellar.toml b/test/packet_inject/conf/stellar.toml
index 3860757..d039d0d 100644
--- a/test/packet_inject/conf/stellar.toml
+++ b/test/packet_inject/conf/stellar.toml
@@ -15,9 +15,12 @@ cpu_mask = [5]
[ip_reassembly]
enable = 1
-timeout = 10000 # range: [1, 60000] (ms)
-bucket_entries = 8 # range: [1, 4294967295] (must be power of 2)
-bucket_num = 1024 # range: [1, 4294967295]
+bucket_entries = 32 # range: [1, 4294967295] (must be power of 2)
+bucket_num = 1024 # range: [1, 4294967295]
+
+ip_frag_timeout_ms = 10000 # range: [1, 60000] (ms)
+ip_frag_expire_polling_interval_ms = 0 # range: [0, 60000] (ms)
+ip_frag_expire_polling_limit = 1024 # range: [1, 1024]
[session_manager]
# max session number
@@ -62,10 +65,6 @@ tcp_reassembly_max_timeout_ms = 10000 # range: [1, 60000] (ms)
tcp_reassembly_max_segments = 128 # range: [2, 4096]
[schedule]
-# Note: free_expired_ip_frag_interval determines the precision of ip_reassembly timeout
-free_expired_ip_frag_interval = 50 # range: [1, 60000] (ms)
-free_expired_ip_frag_batch = 1000 # range: [1, 60000]
-
merge_stat_interval = 50 # range: [1, 60000] (ms)
output_stat_interval = 2000 # range: [1, 60000] (ms)