when a session is closed, use the packet manager to create a pseudo packet,
set the session to be closed as packet Exdata, and schedule it to the packet forwarding stage.
when the pseudo packet free, the session will be free.
270 lines
6.4 KiB
C
270 lines
6.4 KiB
C
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <sys/prctl.h>
|
|
|
|
#include "stellar/stellar.h"
|
|
#include "stellar/module.h"
|
|
|
|
#include "packet_io.h"
|
|
#include "log_internal.h"
|
|
#include "utils_internal.h"
|
|
#include "packet_internal.h"
|
|
#include "packet_manager.h"
|
|
#include "module_manager_interna.h"
|
|
|
|
#define CORE_LOG_FATAL(format, ...) STELLAR_LOG_FATAL(__thread_local_logger, "core", format, ##__VA_ARGS__)
|
|
#define CORE_LOG_ERROR(format, ...) STELLAR_LOG_ERROR(__thread_local_logger, "core", format, ##__VA_ARGS__)
|
|
#define CORE_LOG_DEBUG(format, ...) STELLAR_LOG_DEBUG(__thread_local_logger, "core", format, ##__VA_ARGS__)
|
|
|
|
#ifdef STELLAR_GIT_VERSION
|
|
static __attribute__((__used__)) const char *version = STELLAR_GIT_VERSION;
|
|
#else
|
|
static __attribute__((__used__)) const char *version = "Unknown";
|
|
#endif
|
|
|
|
struct thread
|
|
{
|
|
pthread_t tid;
|
|
uint16_t idx;
|
|
uint64_t is_runing;
|
|
struct stellar *st;
|
|
};
|
|
|
|
struct stellar
|
|
{
|
|
uint16_t thread_num;
|
|
uint64_t need_exit;
|
|
struct logger *logger;
|
|
struct packet_io *pkt_io;
|
|
struct mq_schema *mq_schema;
|
|
struct module_manager *mod_mgr;
|
|
struct thread threads[MAX_THREAD_NUM];
|
|
};
|
|
|
|
static void *worker_thread(void *arg)
|
|
{
|
|
int nr_recv = 0;
|
|
char thread_name[16] = {0};
|
|
struct packet *pkt = NULL;
|
|
struct packet *pkts[RX_BURST_MAX] = {NULL};
|
|
struct thread *thread = (struct thread *)arg;
|
|
uint16_t thread_id = thread->idx;
|
|
struct stellar *st = thread->st;
|
|
struct packet_io *pkt_io = st->pkt_io;
|
|
struct module_manager *mod_mgr = st->mod_mgr;
|
|
struct mq_runtime *mq_rt = mq_runtime_new(st->mq_schema);
|
|
struct module *pkt_mgr_mod = module_manager_get_module(mod_mgr, PACKET_MANAGER_MODULE_NAME);
|
|
struct packet_manager *pkt_mgr = module_to_packet_manager(pkt_mgr_mod);
|
|
|
|
snprintf(thread_name, sizeof(thread_name), "stellar:%d", thread_id);
|
|
prctl(PR_SET_NAME, (unsigned long long)thread_name, NULL, NULL, NULL);
|
|
|
|
__thread_local_logger = st->logger;
|
|
module_manager_register_thread(mod_mgr, thread_id, mq_rt);
|
|
|
|
ATOMIC_SET(&thread->is_runing, 1);
|
|
CORE_LOG_FATAL("worker thread %d runing", thread_id);
|
|
|
|
while (ATOMIC_READ(&st->need_exit) == 0)
|
|
{
|
|
nr_recv = packet_io_recv(pkt_io, thread_id, pkts, RX_BURST_MAX);
|
|
for (int i = 0; i < nr_recv; i++)
|
|
{
|
|
packet_manager_ingress(pkt_mgr, thread_id, pkts[i]);
|
|
}
|
|
|
|
packet_manager_dispatch(pkt_mgr, thread_id);
|
|
while ((pkt = packet_manager_egress(pkt_mgr, thread_id)))
|
|
{
|
|
if (packet_get_action(pkt) == PACKET_ACTION_DROP)
|
|
{
|
|
packet_io_drop(pkt_io, thread_id, &pkt, 1);
|
|
}
|
|
else
|
|
{
|
|
packet_io_send(pkt_io, thread_id, &pkt, 1);
|
|
}
|
|
}
|
|
packet_io_clean(pkt_io, thread_id);
|
|
|
|
stellar_polling_dispatch(mod_mgr);
|
|
|
|
if (nr_recv == 0)
|
|
{
|
|
packet_io_yield(pkt_io, thread_id);
|
|
}
|
|
}
|
|
|
|
CORE_LOG_FATAL("worker thread %d cleaning", thread_id);
|
|
|
|
module_manager_unregister_thread(mod_mgr, thread_id);
|
|
mq_runtime_free(mq_rt);
|
|
|
|
ATOMIC_SET(&thread->is_runing, 0);
|
|
CORE_LOG_FATAL("worker thread %d exit", thread_id);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int stellar_thread_run(struct stellar *st)
|
|
{
|
|
for (uint64_t i = 0; i < st->thread_num; i++)
|
|
{
|
|
struct thread *thread = &st->threads[i];
|
|
thread->idx = i;
|
|
thread->is_runing = 0;
|
|
thread->st = st;
|
|
if (pthread_create(&thread->tid, NULL, worker_thread, (void *)thread) < 0)
|
|
{
|
|
CORE_LOG_ERROR("unable to create worker thread, error %d: %s", errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void stellar_thread_join(struct stellar *st)
|
|
{
|
|
for (uint64_t i = 0; i < st->thread_num; i++)
|
|
{
|
|
if (st->threads[i].is_runing == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
struct thread *thread = &st->threads[i];
|
|
pthread_join(thread->tid, NULL);
|
|
}
|
|
}
|
|
|
|
struct stellar *stellar_new(const char *toml_file)
|
|
{
|
|
if (toml_file == NULL)
|
|
{
|
|
printf("stellar config file is null\n");
|
|
return NULL;
|
|
}
|
|
|
|
struct stellar *st = (struct stellar *)calloc(1, sizeof(struct stellar));
|
|
if (st == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
st->logger = log_new(toml_file);
|
|
if (st->logger == NULL)
|
|
{
|
|
printf("unable to create logger");
|
|
goto error_out;
|
|
}
|
|
|
|
__thread_local_logger = st->logger;
|
|
CORE_LOG_FATAL("stellar start (version: %s)", version);
|
|
|
|
if (load_toml_integer_config(toml_file, "packet_io.thread_num", (uint64_t *)&st->thread_num, 1, MAX_THREAD_NUM) != 0)
|
|
{
|
|
CORE_LOG_ERROR("unable to get thread number from config file");
|
|
goto error_out;
|
|
}
|
|
|
|
st->mq_schema = mq_schema_new();
|
|
if (st->mq_schema == NULL)
|
|
{
|
|
CORE_LOG_ERROR("unable to create mq schema");
|
|
goto error_out;
|
|
}
|
|
|
|
st->mod_mgr = module_manager_new(toml_file, st->thread_num, st->mq_schema, st->logger);
|
|
if (st->mod_mgr == NULL)
|
|
{
|
|
CORE_LOG_ERROR("unable to create packet manager");
|
|
goto error_out;
|
|
}
|
|
|
|
st->pkt_io = packet_io_new(toml_file);
|
|
if (st->pkt_io == NULL)
|
|
{
|
|
CORE_LOG_ERROR("unable to create packet io");
|
|
goto error_out;
|
|
}
|
|
|
|
return st;
|
|
|
|
error_out:
|
|
stellar_free(st);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void stellar_run(struct stellar *st)
|
|
{
|
|
if (st == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (stellar_thread_run(st) != 0)
|
|
{
|
|
CORE_LOG_ERROR("unable to create worker thread");
|
|
return;
|
|
}
|
|
|
|
while (!ATOMIC_READ(&st->need_exit))
|
|
{
|
|
usleep(1000); // 1ms
|
|
|
|
// only available in pcap mode
|
|
if (packet_io_is_done(st->pkt_io))
|
|
{
|
|
ATOMIC_SET(&st->need_exit, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
stellar_thread_join(st);
|
|
}
|
|
|
|
void stellar_free(struct stellar *st)
|
|
{
|
|
if (st)
|
|
{
|
|
packet_io_free(st->pkt_io);
|
|
module_manager_free(st->mod_mgr);
|
|
mq_schema_free(st->mq_schema);
|
|
|
|
CORE_LOG_FATAL("stellar exit\n");
|
|
log_free(st->logger);
|
|
|
|
free(st);
|
|
st = NULL;
|
|
}
|
|
}
|
|
|
|
void stellar_loopbreak(struct stellar *st)
|
|
{
|
|
if (st)
|
|
{
|
|
ATOMIC_SET(&st->need_exit, 1);
|
|
}
|
|
}
|
|
|
|
void stellar_reload_log_level(struct stellar *st)
|
|
{
|
|
if (st)
|
|
{
|
|
log_reload_level(st->logger);
|
|
}
|
|
}
|
|
|
|
struct logger *stellar_get_logger(struct stellar *st)
|
|
{
|
|
if (st)
|
|
{
|
|
return st->logger;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
} |