2024-08-30 10:21:44 +08:00
|
|
|
#include <errno.h>
|
2024-02-28 16:30:03 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
#include "toml.h"
|
|
|
|
|
#include "pcap_io.h"
|
2024-04-10 17:50:51 +08:00
|
|
|
#include "marsio_io.h"
|
2024-09-19 16:23:12 +08:00
|
|
|
#include "log_internal.h"
|
2024-08-30 10:21:44 +08:00
|
|
|
|
2024-10-09 10:01:20 +08:00
|
|
|
#define PACKET_IO_LOG_ERROR(format, ...) STELLAR_LOG_ERROR(__thread_local_logger, "packet io", format, ##__VA_ARGS__)
|
|
|
|
|
#define PACKET_IO_LOG_INFO(format, ...) STELLAR_LOG_INFO(__thread_local_logger, "packet io", format, ##__VA_ARGS__)
|
2024-02-28 16:30:03 +08:00
|
|
|
|
|
|
|
|
struct packet_io
|
|
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
struct packet_io_config *cfg;
|
2024-08-30 10:21:44 +08:00
|
|
|
void *handle;
|
|
|
|
|
|
|
|
|
|
void *(*new_func)(const struct packet_io_config *cfg);
|
|
|
|
|
void (*free_func)(void *handle);
|
|
|
|
|
int (*isbreak_func)(void *handle);
|
|
|
|
|
|
|
|
|
|
int (*init_func)(void *handle, uint16_t thr_idx);
|
2024-09-19 16:29:17 +08:00
|
|
|
uint16_t (*ingress_func)(void *handle, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts);
|
|
|
|
|
void (*egress_func)(void *handle, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts);
|
2024-08-30 10:21:44 +08:00
|
|
|
void (*drop_func)(void *handle, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts);
|
|
|
|
|
void (*yield_func)(void *handle, uint16_t thr_idx);
|
|
|
|
|
struct packet_io_stat *(*stat_func)(void *handle, uint16_t thr_idx);
|
2024-02-28 16:30:03 +08:00
|
|
|
};
|
|
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
static struct packet_io_config *packet_io_config_new(const char *toml_file)
|
2024-02-28 16:30:03 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
int ret = -1;
|
|
|
|
|
const char *ptr;
|
|
|
|
|
char *ptr_mode = NULL;
|
2024-08-30 18:33:41 +08:00
|
|
|
char *ptr_pcap_path = NULL;
|
2024-08-30 10:21:44 +08:00
|
|
|
char *ptr_app_symbol = NULL;
|
|
|
|
|
char *ptr_dev_symbol = NULL;
|
|
|
|
|
char errbuf[200];
|
|
|
|
|
FILE *fp = NULL;
|
|
|
|
|
toml_table_t *root = NULL;
|
|
|
|
|
toml_table_t *table = NULL;
|
|
|
|
|
toml_array_t *mask;
|
|
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
struct packet_io_config *cfg = (struct packet_io_config *)calloc(1, sizeof(struct packet_io_config));
|
|
|
|
|
if (cfg == NULL)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
fp = fopen(toml_file, "r");
|
|
|
|
|
if (fp == NULL)
|
2024-02-28 16:30:03 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file %s open failed, %s", toml_file, strerror(errno));
|
|
|
|
|
goto error_out;
|
2024-02-28 16:30:03 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
root = toml_parse_file(fp, errbuf, sizeof(errbuf));
|
|
|
|
|
if (root == NULL)
|
2024-02-28 16:30:03 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file %s parse failed, %s", toml_file, errbuf);
|
|
|
|
|
goto error_out;
|
2024-02-28 16:30:03 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
|
|
|
|
|
table = toml_table_in(root, "packet_io");
|
|
|
|
|
if (table == NULL)
|
2024-02-28 16:30:03 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file %s missing packet_io", toml_file);
|
|
|
|
|
goto error_out;
|
2024-02-28 16:30:03 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
|
|
|
|
|
ptr = toml_raw_in(table, "mode");
|
|
|
|
|
if (ptr == NULL || toml_rtos(ptr, &ptr_mode) != 0)
|
2024-02-28 16:30:03 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file missing packet_io.mode");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(ptr_mode, "pcapfile") == 0)
|
|
|
|
|
{
|
|
|
|
|
cfg->mode = PACKET_IO_PCAPFILE;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(ptr_mode, "pcaplist") == 0)
|
|
|
|
|
{
|
|
|
|
|
cfg->mode = PACKET_IO_PCAPLIST;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(ptr_mode, "marsio") == 0)
|
|
|
|
|
{
|
|
|
|
|
cfg->mode = PACKET_IO_MARSIO;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PACKET_IO_LOG_ERROR("config file invalid packet_io.mode %s", ptr);
|
2024-02-28 16:30:03 +08:00
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
if (cfg->mode == PACKET_IO_PCAPFILE || cfg->mode == PACKET_IO_PCAPLIST)
|
2024-02-28 16:30:03 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
ptr = toml_raw_in(table, "pcap_path");
|
2024-08-30 18:33:41 +08:00
|
|
|
if (ptr == NULL || toml_rtos(ptr, &ptr_pcap_path) != 0)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file missing packet_io.pcap_path");
|
|
|
|
|
goto error_out;
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-08-30 18:33:41 +08:00
|
|
|
strcpy(cfg->pcap_path, ptr_pcap_path);
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ptr = toml_raw_in(table, "app_symbol");
|
|
|
|
|
if (ptr == NULL || toml_rtos(ptr, &ptr_app_symbol) != 0)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file missing packet_io.app_symbol");
|
|
|
|
|
goto error_out;
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
strcpy(cfg->app_symbol, ptr_app_symbol);
|
|
|
|
|
|
|
|
|
|
ptr = toml_raw_in(table, "dev_symbol");
|
|
|
|
|
if (ptr == NULL || toml_rtos(ptr, &ptr_dev_symbol) != 0)
|
|
|
|
|
{
|
|
|
|
|
PACKET_IO_LOG_ERROR("config file missing packet_io.dev_symbol");
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
strcpy(cfg->dev_symbol, ptr_dev_symbol);
|
2024-02-28 16:30:03 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
ptr = toml_raw_in(table, "nr_worker_thread");
|
|
|
|
|
if (ptr == NULL)
|
2024-05-15 11:40:00 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file missing packet_io.nr_worker_thread");
|
|
|
|
|
goto error_out;
|
2024-05-15 11:40:00 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
cfg->nr_worker_thread = atoi(ptr);
|
|
|
|
|
if (cfg->nr_worker_thread == 0 || cfg->nr_worker_thread > MAX_THREAD_NUM)
|
2024-05-15 11:40:00 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file invalid packet_io.nr_worker_thread %d, range [1, %d]", cfg->nr_worker_thread, MAX_THREAD_NUM);
|
|
|
|
|
goto error_out;
|
2024-05-15 11:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
mask = toml_array_in(table, "cpu_mask");
|
|
|
|
|
if (mask == NULL)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file missing packet_io.cpu_mask");
|
|
|
|
|
goto error_out;
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
for (uint16_t i = 0; i < cfg->nr_worker_thread; i++)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
ptr = toml_raw_at(mask, i);
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
|
{
|
|
|
|
|
PACKET_IO_LOG_ERROR("config file missing packet_io.cpu_mask[%d]", i);
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
cfg->cpu_mask[i] = atoi(ptr);
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-02-28 16:30:03 +08:00
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
ptr = toml_raw_in(table, "idle_yield_interval_ms");
|
|
|
|
|
if (ptr == NULL)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file missing packet_io.idle_yield_interval_ms");
|
|
|
|
|
goto error_out;
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
cfg->idle_yield_interval_ms = atoll(ptr);
|
|
|
|
|
if (cfg->idle_yield_interval_ms > 60000)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_ERROR("config file invalid packet_io.idle_yield_interval_ms %d, range [0, %d]", cfg->idle_yield_interval_ms, 60000);
|
|
|
|
|
goto error_out;
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-02-28 16:30:03 +08:00
|
|
|
|
2024-08-30 10:21:44 +08:00
|
|
|
ret = 0;
|
|
|
|
|
error_out:
|
|
|
|
|
if (ptr_mode)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
free(ptr_mode);
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-08-30 18:33:41 +08:00
|
|
|
if (ptr_pcap_path)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-08-30 18:33:41 +08:00
|
|
|
free(ptr_pcap_path);
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
if (ptr_app_symbol)
|
|
|
|
|
{
|
|
|
|
|
free(ptr_app_symbol);
|
|
|
|
|
}
|
|
|
|
|
if (ptr_dev_symbol)
|
|
|
|
|
{
|
|
|
|
|
free(ptr_dev_symbol);
|
|
|
|
|
}
|
|
|
|
|
if (root)
|
|
|
|
|
{
|
|
|
|
|
toml_free(root);
|
|
|
|
|
}
|
|
|
|
|
if (fp)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
fclose(fp);
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
if (ret == -1)
|
2024-04-10 17:50:51 +08:00
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
free(cfg);
|
2024-08-30 10:21:44 +08:00
|
|
|
return NULL;
|
2024-04-10 17:50:51 +08:00
|
|
|
}
|
2024-09-20 18:41:07 +08:00
|
|
|
else
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-09-20 18:41:07 +08:00
|
|
|
return cfg;
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
2024-02-28 16:30:03 +08:00
|
|
|
}
|
2024-04-18 14:20:28 +08:00
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
static void packet_io_config_free(struct packet_io_config *cfg)
|
2024-04-25 15:34:46 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
if (cfg)
|
2024-04-25 15:34:46 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
free(cfg);
|
|
|
|
|
cfg = NULL;
|
2024-04-25 15:34:46 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
static void packet_io_config_print(const struct packet_io_config *cfg)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
|
|
|
|
if (cfg)
|
2024-04-25 15:34:46 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
PACKET_IO_LOG_INFO("packet_io.mode : %s", cfg->mode == PACKET_IO_PCAPFILE ? "pcapfile" : (cfg->mode == PACKET_IO_PCAPLIST ? "pcaplist" : "marsio"));
|
|
|
|
|
if (cfg->mode == PACKET_IO_PCAPFILE || cfg->mode == PACKET_IO_PCAPLIST)
|
|
|
|
|
{
|
|
|
|
|
PACKET_IO_LOG_INFO("packet_io.pcap_path : %s", cfg->pcap_path);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PACKET_IO_LOG_INFO("packet_io.app_symbol : %s", cfg->app_symbol);
|
|
|
|
|
PACKET_IO_LOG_INFO("packet_io.dev_symbol : %s", cfg->dev_symbol);
|
|
|
|
|
}
|
|
|
|
|
PACKET_IO_LOG_INFO("packet_io.nr_worker_thread : %d", cfg->nr_worker_thread);
|
|
|
|
|
for (uint16_t i = 0; i < cfg->nr_worker_thread; i++)
|
|
|
|
|
{
|
2024-09-29 16:50:25 +08:00
|
|
|
PACKET_IO_LOG_INFO("packet_io.cpu_mask[%03d] : %d", i, cfg->cpu_mask[i]);
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
PACKET_IO_LOG_INFO("packet_io.idle_yield_interval_ms : %lu", cfg->idle_yield_interval_ms);
|
2024-04-25 15:34:46 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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-08-30 10:21:44 +08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-20 18:41:07 +08:00
|
|
|
pkt_io->cfg = packet_io_config_new(toml_file);
|
|
|
|
|
if (pkt_io->cfg == NULL)
|
|
|
|
|
{
|
|
|
|
|
free(pkt_io);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
packet_io_config_print(pkt_io->cfg);
|
|
|
|
|
|
|
|
|
|
if (pkt_io->cfg->mode == PACKET_IO_MARSIO)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
|
|
|
|
pkt_io->new_func = marsio_io_new;
|
|
|
|
|
pkt_io->free_func = marsio_io_free;
|
|
|
|
|
pkt_io->isbreak_func = marsio_io_isbreak;
|
|
|
|
|
pkt_io->init_func = marsio_io_init;
|
2024-09-19 16:29:17 +08:00
|
|
|
pkt_io->ingress_func = marsio_io_ingress;
|
|
|
|
|
pkt_io->egress_func = marsio_io_egress;
|
2024-08-30 10:21:44 +08:00
|
|
|
pkt_io->drop_func = marsio_io_drop;
|
|
|
|
|
pkt_io->yield_func = marsio_io_yield;
|
|
|
|
|
pkt_io->stat_func = marsio_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;
|
|
|
|
|
pkt_io->isbreak_func = pcap_io_isbreak;
|
|
|
|
|
pkt_io->init_func = pcap_io_init;
|
2024-09-19 16:29:17 +08:00
|
|
|
pkt_io->ingress_func = pcap_io_ingress;
|
|
|
|
|
pkt_io->egress_func = pcap_io_egress;
|
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-09-20 18:41:07 +08:00
|
|
|
pkt_io->handle = pkt_io->new_func(pkt_io->cfg);
|
2024-08-30 10:21:44 +08:00
|
|
|
if (pkt_io->handle == NULL)
|
2024-04-18 14:20:28 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
packet_io_free(pkt_io);
|
|
|
|
|
return NULL;
|
2024-04-18 14:20:28 +08:00
|
|
|
}
|
2024-08-30 10:21:44 +08:00
|
|
|
|
|
|
|
|
return pkt_io;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void packet_io_free(struct packet_io *pkt_io)
|
|
|
|
|
{
|
|
|
|
|
if (pkt_io)
|
2024-04-18 14:20:28 +08:00
|
|
|
{
|
2024-08-30 10:21:44 +08:00
|
|
|
if (pkt_io->handle)
|
|
|
|
|
{
|
|
|
|
|
pkt_io->free_func(pkt_io->handle);
|
|
|
|
|
}
|
2024-09-20 18:41:07 +08:00
|
|
|
if (pkt_io->cfg)
|
|
|
|
|
{
|
|
|
|
|
packet_io_config_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
|
|
|
|
|
|
|
|
int packet_io_isbreak(struct packet_io *pkt_io)
|
|
|
|
|
{
|
|
|
|
|
return pkt_io->isbreak_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);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-19 16:29:17 +08:00
|
|
|
uint16_t packet_io_ingress(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-09-19 16:29:17 +08:00
|
|
|
return pkt_io->ingress_func(pkt_io->handle, thr_idx, pkts, nr_pkts);
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
2024-09-19 16:29:17 +08:00
|
|
|
void packet_io_egress(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts)
|
2024-08-30 10:21:44 +08:00
|
|
|
{
|
2024-09-19 16:29:17 +08:00
|
|
|
pkt_io->egress_func(pkt_io->handle, thr_idx, pkts, nr_pkts);
|
2024-08-30 10:21:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void packet_io_drop(struct packet_io *pkt_io, uint16_t thr_idx, struct packet *pkts, uint16_t nr_pkts)
|
|
|
|
|
{
|
|
|
|
|
pkt_io->drop_func(pkt_io->handle, thr_idx, pkts, nr_pkts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void packet_io_yield(struct packet_io *pkt_io, uint16_t thr_idx)
|
|
|
|
|
{
|
|
|
|
|
pkt_io->yield_func(pkt_io->handle, thr_idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct packet_io_stat *packet_io_stat(struct packet_io *pkt_io, uint16_t thr_idx)
|
|
|
|
|
{
|
|
|
|
|
return pkt_io->stat_func(pkt_io->handle, thr_idx);
|
|
|
|
|
}
|